aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2014-11-24 09:15:30 +0000
committerDimitry Andric <dim@FreeBSD.org>2014-11-24 09:15:30 +0000
commit9f4dbff6669c8037f3b036bcf580d14f1a4f12a5 (patch)
tree47df2c12b57214af6c31e47404b005675b8b7ffc /lib
parentf73d5f23a889b93d89ddef61ac0995df40286bb8 (diff)
downloadsrc-9f4dbff6669c8037f3b036bcf580d14f1a4f12a5.tar.gz
src-9f4dbff6669c8037f3b036bcf580d14f1a4f12a5.zip
Vendor import of clang RELEASE_350/final tag r216957 (effectively, 3.5.0 release):vendor/clang/clang-release_350-r216957
Notes
Notes: svn path=/vendor/clang/dist/; revision=274958 svn path=/vendor/clang/clang-release_350-r216957/; revision=274959; tag=vendor/clang/clang-release_350-r216957
Diffstat (limited to 'lib')
-rw-r--r--lib/ARCMigrate/ARCMT.cpp87
-rw-r--r--lib/ARCMigrate/CMakeLists.txt30
-rw-r--r--lib/ARCMigrate/FileRemapper.cpp43
-rw-r--r--lib/ARCMigrate/Internals.h9
-rw-r--r--lib/ARCMigrate/ObjCMT.cpp710
-rw-r--r--lib/ARCMigrate/PlistReporter.cpp113
-rw-r--r--lib/ARCMigrate/TransAPIUses.cpp16
-rw-r--r--lib/ARCMigrate/TransAutoreleasePool.cpp8
-rw-r--r--lib/ARCMigrate/TransBlockObjCVariable.cpp7
-rw-r--r--lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp24
-rw-r--r--lib/ARCMigrate/TransGCAttrs.cpp12
-rw-r--r--lib/ARCMigrate/TransGCCalls.cpp10
-rw-r--r--lib/ARCMigrate/TransProperties.cpp31
-rw-r--r--lib/ARCMigrate/TransProtectedScope.cpp2
-rw-r--r--lib/ARCMigrate/TransRetainReleaseDealloc.cpp18
-rw-r--r--lib/ARCMigrate/TransUnbridgedCasts.cpp15
-rw-r--r--lib/ARCMigrate/TransUnusedInitDelegate.cpp2
-rw-r--r--lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp34
-rw-r--r--lib/ARCMigrate/TransformActions.cpp64
-rw-r--r--lib/ARCMigrate/Transforms.cpp23
-rw-r--r--lib/ARCMigrate/Transforms.h12
-rw-r--r--lib/AST/APValue.cpp93
-rw-r--r--lib/AST/ASTContext.cpp1554
-rw-r--r--lib/AST/ASTDiagnostic.cpp357
-rw-r--r--lib/AST/ASTDumper.cpp379
-rw-r--r--lib/AST/ASTImporter.cpp678
-rw-r--r--lib/AST/ASTTypeTraits.cpp16
-rw-r--r--lib/AST/AttrImpl.cpp2
-rw-r--r--lib/AST/CMakeLists.txt23
-rw-r--r--lib/AST/CXXABI.h1
-rw-r--r--lib/AST/CXXInheritance.cpp80
-rw-r--r--lib/AST/Comment.cpp46
-rw-r--r--lib/AST/CommentCommandTraits.cpp71
-rw-r--r--lib/AST/CommentLexer.cpp13
-rw-r--r--lib/AST/CommentParser.cpp6
-rw-r--r--lib/AST/CommentSema.cpp79
-rw-r--r--lib/AST/Decl.cpp762
-rw-r--r--lib/AST/DeclBase.cpp182
-rw-r--r--lib/AST/DeclCXX.cpp387
-rw-r--r--lib/AST/DeclFriend.cpp16
-rw-r--r--lib/AST/DeclObjC.cpp717
-rw-r--r--lib/AST/DeclOpenMP.cpp17
-rw-r--r--lib/AST/DeclPrinter.cpp153
-rw-r--r--lib/AST/DeclTemplate.cpp276
-rw-r--r--lib/AST/DeclarationName.cpp37
-rw-r--r--lib/AST/Expr.cpp274
-rw-r--r--lib/AST/ExprCXX.cpp140
-rw-r--r--lib/AST/ExprClassification.cpp24
-rw-r--r--lib/AST/ExprConstant.cpp472
-rw-r--r--lib/AST/ExternalASTSource.cpp52
-rw-r--r--lib/AST/InheritViz.cpp15
-rw-r--r--lib/AST/ItaniumCXXABI.cpp28
-rw-r--r--lib/AST/ItaniumMangle.cpp306
-rw-r--r--lib/AST/Mangle.cpp14
-rw-r--r--lib/AST/MangleNumberingContext.cpp10
-rw-r--r--lib/AST/MicrosoftCXXABI.cpp132
-rw-r--r--lib/AST/MicrosoftMangle.cpp1127
-rw-r--r--lib/AST/NSAPI.cpp6
-rw-r--r--lib/AST/NestedNameSpecifier.cpp34
-rw-r--r--lib/AST/ParentMap.cpp8
-rw-r--r--lib/AST/RawCommentList.cpp17
-rw-r--r--lib/AST/RecordLayout.cpp25
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp1554
-rw-r--r--lib/AST/Stmt.cpp588
-rw-r--r--lib/AST/StmtIterator.cpp8
-rw-r--r--lib/AST/StmtPrinter.cpp457
-rw-r--r--lib/AST/StmtProfile.cpp187
-rw-r--r--lib/AST/TemplateBase.cpp33
-rw-r--r--lib/AST/TemplateName.cpp4
-rw-r--r--lib/AST/Type.cpp192
-rw-r--r--lib/AST/TypeLoc.cpp4
-rw-r--r--lib/AST/TypePrinter.cpp93
-rw-r--r--lib/AST/VTTBuilder.cpp22
-rw-r--r--lib/AST/VTableBuilder.cpp855
-rw-r--r--lib/ASTMatchers/ASTMatchFinder.cpp90
-rw-r--r--lib/ASTMatchers/ASTMatchersInternal.cpp20
-rw-r--r--lib/ASTMatchers/CMakeLists.txt14
-rw-r--r--lib/ASTMatchers/Dynamic/CMakeLists.txt9
-rw-r--r--lib/ASTMatchers/Dynamic/Diagnostics.cpp4
-rw-r--r--lib/ASTMatchers/Dynamic/Marshallers.h591
-rw-r--r--lib/ASTMatchers/Dynamic/Parser.cpp264
-rw-r--r--lib/ASTMatchers/Dynamic/Registry.cpp211
-rw-r--r--lib/ASTMatchers/Dynamic/VariantValue.cpp40
-rw-r--r--lib/Analysis/AnalysisDeclContext.cpp86
-rw-r--r--lib/Analysis/BodyFarm.cpp164
-rw-r--r--lib/Analysis/BodyFarm.h7
-rw-r--r--lib/Analysis/CFG.cpp845
-rw-r--r--lib/Analysis/CFGReachabilityAnalysis.cpp3
-rw-r--r--lib/Analysis/CFGStmtMap.cpp6
-rw-r--r--lib/Analysis/CMakeLists.txt23
-rw-r--r--lib/Analysis/CallGraph.cpp26
-rw-r--r--lib/Analysis/Consumed.cpp712
-rw-r--r--lib/Analysis/FormatString.cpp6
-rw-r--r--lib/Analysis/FormatStringParsing.h4
-rw-r--r--lib/Analysis/LiveVariables.cpp67
-rw-r--r--lib/Analysis/PostOrderCFGView.cpp2
-rw-r--r--lib/Analysis/PrintfFormatString.cpp6
-rw-r--r--lib/Analysis/ProgramPoint.cpp7
-rw-r--r--lib/Analysis/PseudoConstantAnalysis.cpp7
-rw-r--r--lib/Analysis/ReachableCode.cpp515
-rw-r--r--lib/Analysis/ScanfFormatString.cpp34
-rw-r--r--lib/Analysis/ThreadSafety.cpp791
-rw-r--r--lib/Analysis/ThreadSafetyCommon.cpp794
-rw-r--r--lib/Analysis/ThreadSafetyLogical.cpp112
-rw-r--r--lib/Analysis/ThreadSafetyTIL.cpp153
-rw-r--r--lib/Analysis/UninitializedValues.cpp40
-rw-r--r--lib/Basic/Attributes.cpp17
-rw-r--r--lib/Basic/Builtins.cpp57
-rw-r--r--lib/Basic/CMakeLists.txt46
-rw-r--r--lib/Basic/Diagnostic.cpp212
-rw-r--r--lib/Basic/DiagnosticIDs.cpp268
-rw-r--r--lib/Basic/FileManager.cpp226
-rw-r--r--lib/Basic/FileSystemStatCache.cpp46
-rw-r--r--lib/Basic/IdentifierTable.cpp24
-rw-r--r--lib/Basic/Module.cpp41
-rw-r--r--lib/Basic/OpenMPKinds.cpp229
-rw-r--r--lib/Basic/SourceLocation.cpp7
-rw-r--r--lib/Basic/SourceManager.cpp135
-rw-r--r--lib/Basic/TargetInfo.cpp70
-rw-r--r--lib/Basic/Targets.cpp2624
-rw-r--r--lib/Basic/TokenKinds.cpp24
-rw-r--r--lib/Basic/Version.cpp16
-rw-r--r--lib/Basic/VirtualFileSystem.cpp1209
-rw-r--r--lib/Basic/Warnings.cpp (renamed from lib/Frontend/Warnings.cpp)87
-rw-r--r--lib/CMakeLists.txt4
-rw-r--r--lib/CodeGen/ABIInfo.h2
-rw-r--r--lib/CodeGen/BackendUtil.cpp192
-rw-r--r--lib/CodeGen/CGAtomic.cpp303
-rw-r--r--lib/CodeGen/CGBlocks.cpp275
-rw-r--r--lib/CodeGen/CGBlocks.h18
-rw-r--r--lib/CodeGen/CGBuilder.h31
-rw-r--r--lib/CodeGen/CGBuiltin.cpp6219
-rw-r--r--lib/CodeGen/CGCUDANV.cpp4
-rw-r--r--lib/CodeGen/CGCUDARuntime.cpp7
-rw-r--r--lib/CodeGen/CGCXX.cpp80
-rw-r--r--lib/CodeGen/CGCXXABI.cpp67
-rw-r--r--lib/CodeGen/CGCXXABI.h153
-rw-r--r--lib/CodeGen/CGCall.cpp832
-rw-r--r--lib/CodeGen/CGCall.h30
-rw-r--r--lib/CodeGen/CGClass.cpp289
-rw-r--r--lib/CodeGen/CGCleanup.cpp36
-rw-r--r--lib/CodeGen/CGCleanup.h23
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp801
-rw-r--r--lib/CodeGen/CGDebugInfo.h94
-rw-r--r--lib/CodeGen/CGDecl.cpp199
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp208
-rw-r--r--lib/CodeGen/CGException.cpp226
-rw-r--r--lib/CodeGen/CGExpr.cpp542
-rw-r--r--lib/CodeGen/CGExprAgg.cpp86
-rw-r--r--lib/CodeGen/CGExprCXX.cpp739
-rw-r--r--lib/CodeGen/CGExprComplex.cpp17
-rw-r--r--lib/CodeGen/CGExprConstant.cpp111
-rw-r--r--lib/CodeGen/CGExprScalar.cpp217
-rw-r--r--lib/CodeGen/CGLoopInfo.cpp112
-rw-r--r--lib/CodeGen/CGLoopInfo.h136
-rw-r--r--lib/CodeGen/CGObjC.cpp196
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp546
-rw-r--r--lib/CodeGen/CGObjCMac.cpp1322
-rw-r--r--lib/CodeGen/CGObjCRuntime.cpp16
-rw-r--r--lib/CodeGen/CGObjCRuntime.h9
-rw-r--r--lib/CodeGen/CGOpenCLRuntime.cpp21
-rw-r--r--lib/CodeGen/CGOpenMPRuntime.cpp182
-rw-r--r--lib/CodeGen/CGOpenMPRuntime.h177
-rw-r--r--lib/CodeGen/CGRTTI.cpp977
-rw-r--r--lib/CodeGen/CGRecordLayout.h6
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp1428
-rw-r--r--lib/CodeGen/CGStmt.cpp524
-rw-r--r--lib/CodeGen/CGStmtOpenMP.cpp130
-rw-r--r--lib/CodeGen/CGVTT.cpp5
-rw-r--r--lib/CodeGen/CGVTables.cpp175
-rw-r--r--lib/CodeGen/CGVTables.h24
-rw-r--r--lib/CodeGen/CGValue.h27
-rw-r--r--lib/CodeGen/CMakeLists.txt55
-rw-r--r--lib/CodeGen/CodeGenABITypes.cpp20
-rw-r--r--lib/CodeGen/CodeGenAction.cpp447
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp374
-rw-r--r--lib/CodeGen/CodeGenFunction.h413
-rw-r--r--lib/CodeGen/CodeGenModule.cpp1561
-rw-r--r--lib/CodeGen/CodeGenModule.h818
-rw-r--r--lib/CodeGen/CodeGenPGO.cpp1011
-rw-r--r--lib/CodeGen/CodeGenPGO.h236
-rw-r--r--lib/CodeGen/CodeGenTBAA.cpp16
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp59
-rw-r--r--lib/CodeGen/CodeGenTypes.h19
-rw-r--r--lib/CodeGen/EHScopeStack.h20
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp1710
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp1872
-rw-r--r--lib/CodeGen/MicrosoftVBTables.cpp233
-rw-r--r--lib/CodeGen/MicrosoftVBTables.h129
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp106
-rw-r--r--lib/CodeGen/SanitizerBlacklist.cpp52
-rw-r--r--lib/CodeGen/SanitizerBlacklist.h46
-rw-r--r--lib/CodeGen/TargetInfo.cpp3005
-rw-r--r--lib/CodeGen/TargetInfo.h360
-rw-r--r--lib/Driver/Action.cpp30
-rw-r--r--lib/Driver/CC1AsOptions.cpp44
-rw-r--r--lib/Driver/CMakeLists.txt19
-rw-r--r--lib/Driver/Compilation.cpp21
-rw-r--r--lib/Driver/Driver.cpp324
-rw-r--r--lib/Driver/Job.cpp16
-rw-r--r--lib/Driver/Multilib.cpp334
-rw-r--r--lib/Driver/SanitizerArgs.cpp127
-rw-r--r--lib/Driver/ToolChain.cpp199
-rw-r--r--lib/Driver/ToolChains.cpp1573
-rw-r--r--lib/Driver/ToolChains.h615
-rw-r--r--lib/Driver/Tools.cpp2884
-rw-r--r--lib/Driver/Tools.h524
-rw-r--r--lib/Driver/Types.cpp2
-rw-r--r--lib/Driver/WindowsToolChain.cpp91
-rw-r--r--lib/Edit/CMakeLists.txt18
-rw-r--r--lib/Edit/Commit.cpp12
-rw-r--r--lib/Edit/EditedSource.cpp8
-rw-r--r--lib/Edit/RewriteObjCFoundationAPI.cpp9
-rw-r--r--lib/Format/BreakableToken.cpp60
-rw-r--r--lib/Format/BreakableToken.h63
-rw-r--r--lib/Format/CMakeLists.txt18
-rw-r--r--lib/Format/ContinuationIndenter.cpp759
-rw-r--r--lib/Format/ContinuationIndenter.h70
-rw-r--r--lib/Format/Encoding.h8
-rw-r--r--lib/Format/Format.cpp1192
-rw-r--r--lib/Format/FormatToken.cpp83
-rw-r--r--lib/Format/FormatToken.h99
-rw-r--r--lib/Format/TokenAnnotator.cpp804
-rw-r--r--lib/Format/TokenAnnotator.h19
-rw-r--r--lib/Format/UnwrappedLineParser.cpp483
-rw-r--r--lib/Format/UnwrappedLineParser.h25
-rw-r--r--lib/Format/WhitespaceManager.cpp150
-rw-r--r--lib/Format/WhitespaceManager.h28
-rw-r--r--lib/Frontend/ASTConsumers.cpp60
-rw-r--r--lib/Frontend/ASTMerge.cpp8
-rw-r--r--lib/Frontend/ASTUnit.cpp988
-rw-r--r--lib/Frontend/CMakeLists.txt27
-rw-r--r--lib/Frontend/CacheTokens.cpp96
-rw-r--r--lib/Frontend/ChainedIncludesSource.cpp134
-rw-r--r--lib/Frontend/CompilerInstance.cpp695
-rw-r--r--lib/Frontend/CompilerInvocation.cpp365
-rw-r--r--lib/Frontend/CreateInvocationFromCommandLine.cpp18
-rw-r--r--lib/Frontend/DependencyFile.cpp230
-rw-r--r--lib/Frontend/DependencyGraph.cpp20
-rw-r--r--lib/Frontend/DiagnosticRenderer.cpp24
-rw-r--r--lib/Frontend/FrontendAction.cpp180
-rw-r--r--lib/Frontend/FrontendActions.cpp227
-rw-r--r--lib/Frontend/HeaderIncludeGen.cpp12
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp100
-rw-r--r--lib/Frontend/InitPreprocessor.cpp335
-rw-r--r--lib/Frontend/LangStandards.cpp2
-rw-r--r--lib/Frontend/LogDiagnosticPrinter.cpp90
-rw-r--r--lib/Frontend/Makefile2
-rw-r--r--lib/Frontend/ModuleDependencyCollector.cpp116
-rw-r--r--lib/Frontend/MultiplexConsumer.cpp90
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp147
-rw-r--r--lib/Frontend/Rewrite/CMakeLists.txt22
-rw-r--r--lib/Frontend/Rewrite/FixItRewriter.cpp (renamed from lib/Rewrite/Frontend/FixItRewriter.cpp)10
-rw-r--r--lib/Frontend/Rewrite/FrontendActions.cpp (renamed from lib/Rewrite/Frontend/FrontendActions.cpp)30
-rw-r--r--lib/Frontend/Rewrite/HTMLPrint.cpp (renamed from lib/Rewrite/Frontend/HTMLPrint.cpp)4
-rw-r--r--lib/Frontend/Rewrite/InclusionRewriter.cpp (renamed from lib/Rewrite/Frontend/InclusionRewriter.cpp)85
-rw-r--r--lib/Frontend/Rewrite/Makefile (renamed from lib/Rewrite/Frontend/Makefile)4
-rw-r--r--lib/Frontend/Rewrite/RewriteMacros.cpp (renamed from lib/Rewrite/Frontend/RewriteMacros.cpp)2
-rw-r--r--lib/Frontend/Rewrite/RewriteModernObjC.cpp (renamed from lib/Rewrite/Frontend/RewriteModernObjC.cpp)683
-rw-r--r--lib/Frontend/Rewrite/RewriteObjC.cpp (renamed from lib/Rewrite/Frontend/RewriteObjC.cpp)509
-rw-r--r--lib/Frontend/Rewrite/RewriteTest.cpp (renamed from lib/Rewrite/Frontend/RewriteTest.cpp)0
-rw-r--r--lib/Frontend/SerializedDiagnosticPrinter.cpp98
-rw-r--r--lib/Frontend/TextDiagnostic.cpp62
-rw-r--r--lib/Frontend/TextDiagnosticBuffer.cpp38
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp11
-rw-r--r--lib/Frontend/VerifyDiagnosticConsumer.cpp162
-rw-r--r--lib/FrontendTool/CMakeLists.txt33
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp54
-rw-r--r--lib/FrontendTool/Makefile5
-rw-r--r--lib/Headers/CMakeLists.txt48
-rw-r--r--lib/Headers/Intrin.h320
-rw-r--r--lib/Headers/Makefile8
-rw-r--r--lib/Headers/altivec.h479
-rw-r--r--lib/Headers/arm_acle.h191
-rw-r--r--lib/Headers/avx2intrin.h34
-rw-r--r--lib/Headers/avxintrin.h25
-rw-r--r--lib/Headers/bmiintrin.h35
-rw-r--r--lib/Headers/cpuid.h1
-rw-r--r--lib/Headers/float.h2
-rw-r--r--lib/Headers/ia32intrin.h101
-rw-r--r--lib/Headers/immintrin.h2
-rw-r--r--lib/Headers/limits.h5
-rw-r--r--lib/Headers/module.modulemap (renamed from lib/Headers/module.map)0
-rw-r--r--lib/Headers/smmintrin.h20
-rw-r--r--lib/Headers/stdarg.h4
-rw-r--r--lib/Headers/stddef.h52
-rw-r--r--lib/Headers/stdint.h35
-rw-r--r--lib/Headers/x86intrin.h4
-rw-r--r--lib/Headers/xmmintrin.h10
-rw-r--r--lib/Index/CMakeLists.txt16
-rw-r--r--lib/Index/CommentToXML.cpp64
-rw-r--r--lib/Index/SimpleFormatContext.h9
-rw-r--r--lib/Index/USRGeneration.cpp142
-rw-r--r--lib/Lex/CMakeLists.txt9
-rw-r--r--lib/Lex/HeaderMap.cpp41
-rw-r--r--lib/Lex/HeaderSearch.cpp621
-rw-r--r--lib/Lex/Lexer.cpp223
-rw-r--r--lib/Lex/LiteralSupport.cpp148
-rw-r--r--lib/Lex/MacroArgs.cpp8
-rw-r--r--lib/Lex/MacroInfo.cpp86
-rw-r--r--lib/Lex/ModuleMap.cpp605
-rw-r--r--lib/Lex/PPCaching.cpp22
-rw-r--r--lib/Lex/PPConditionalDirectiveRecord.cpp4
-rw-r--r--lib/Lex/PPDirectives.cpp441
-rw-r--r--lib/Lex/PPExpressions.cpp28
-rw-r--r--lib/Lex/PPLexerChange.cpp128
-rw-r--r--lib/Lex/PPMacroExpansion.cpp210
-rw-r--r--lib/Lex/PTHLexer.cpp198
-rw-r--r--lib/Lex/Pragma.cpp184
-rw-r--r--lib/Lex/PreprocessingRecord.cpp10
-rw-r--r--lib/Lex/Preprocessor.cpp136
-rw-r--r--lib/Lex/ScratchBuffer.cpp5
-rw-r--r--lib/Lex/TokenLexer.cpp93
-rw-r--r--lib/Lex/UnicodeCharSets.h2
-rwxr-xr-xlib/Makefile6
-rw-r--r--lib/Parse/CMakeLists.txt26
-rw-r--r--lib/Parse/ParseAST.cpp11
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp142
-rw-r--r--lib/Parse/ParseDecl.cpp1611
-rw-r--r--lib/Parse/ParseDeclCXX.cpp845
-rw-r--r--lib/Parse/ParseExpr.cpp386
-rw-r--r--lib/Parse/ParseExprCXX.cpp464
-rw-r--r--lib/Parse/ParseInit.cpp84
-rw-r--r--lib/Parse/ParseObjc.cpp368
-rw-r--r--lib/Parse/ParseOpenMP.cpp513
-rw-r--r--lib/Parse/ParsePragma.cpp1062
-rw-r--r--lib/Parse/ParsePragma.h139
-rw-r--r--lib/Parse/ParseStmt.cpp1150
-rw-r--r--lib/Parse/ParseStmtAsm.cpp761
-rw-r--r--lib/Parse/ParseTemplate.cpp257
-rw-r--r--lib/Parse/ParseTentative.cpp400
-rw-r--r--lib/Parse/Parser.cpp439
-rw-r--r--lib/Parse/RAIIObjectsForParser.h16
-rw-r--r--lib/Rewrite/CMakeLists.txt18
-rw-r--r--lib/Rewrite/Core/CMakeLists.txt24
-rw-r--r--lib/Rewrite/Core/Makefile18
-rw-r--r--lib/Rewrite/DeltaTree.cpp (renamed from lib/Rewrite/Core/DeltaTree.cpp)4
-rw-r--r--lib/Rewrite/Frontend/CMakeLists.txt29
-rw-r--r--lib/Rewrite/HTMLRewrite.cpp (renamed from lib/Rewrite/Core/HTMLRewrite.cpp)4
-rw-r--r--lib/Rewrite/Makefile10
-rw-r--r--lib/Rewrite/RewriteRope.cpp (renamed from lib/Rewrite/Core/RewriteRope.cpp)35
-rw-r--r--lib/Rewrite/Rewriter.cpp (renamed from lib/Rewrite/Core/Rewriter.cpp)28
-rw-r--r--lib/Rewrite/TokenRewriter.cpp (renamed from lib/Rewrite/Core/TokenRewriter.cpp)0
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp604
-rw-r--r--lib/Sema/AttributeList.cpp72
-rw-r--r--lib/Sema/CMakeLists.txt28
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp11
-rw-r--r--lib/Sema/DeclSpec.cpp178
-rw-r--r--lib/Sema/DelayedDiagnostic.cpp24
-rw-r--r--lib/Sema/IdentifierResolver.cpp23
-rw-r--r--lib/Sema/JumpDiagnostics.cpp169
-rw-r--r--lib/Sema/MultiplexExternalSemaSource.cpp11
-rw-r--r--lib/Sema/Scope.cpp161
-rw-r--r--lib/Sema/ScopeInfo.cpp32
-rw-r--r--lib/Sema/Sema.cpp236
-rw-r--r--lib/Sema/SemaAccess.cpp109
-rw-r--r--lib/Sema/SemaAttr.cpp224
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp169
-rw-r--r--lib/Sema/SemaCast.cpp124
-rw-r--r--lib/Sema/SemaChecking.cpp1959
-rw-r--r--lib/Sema/SemaCodeComplete.cpp592
-rw-r--r--lib/Sema/SemaDecl.cpp2814
-rw-r--r--lib/Sema/SemaDeclAttr.cpp3054
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2327
-rw-r--r--lib/Sema/SemaDeclObjC.cpp883
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp134
-rw-r--r--lib/Sema/SemaExpr.cpp2250
-rw-r--r--lib/Sema/SemaExprCXX.cpp1162
-rw-r--r--lib/Sema/SemaExprMember.cpp470
-rw-r--r--lib/Sema/SemaExprObjC.cpp990
-rw-r--r--lib/Sema/SemaInit.cpp861
-rw-r--r--lib/Sema/SemaLambda.cpp460
-rw-r--r--lib/Sema/SemaLookup.cpp1352
-rw-r--r--lib/Sema/SemaObjCProperty.cpp581
-rw-r--r--lib/Sema/SemaOpenMP.cpp3628
-rw-r--r--lib/Sema/SemaOverload.cpp1092
-rw-r--r--lib/Sema/SemaPseudoObject.cpp249
-rw-r--r--lib/Sema/SemaStmt.cpp734
-rw-r--r--lib/Sema/SemaStmtAsm.cpp31
-rw-r--r--lib/Sema/SemaStmtAttr.cpp165
-rw-r--r--lib/Sema/SemaTemplate.cpp920
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp642
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp491
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp689
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp38
-rw-r--r--lib/Sema/SemaType.cpp942
-rw-r--r--lib/Sema/TargetAttributesSema.cpp353
-rw-r--r--lib/Sema/TargetAttributesSema.h27
-rw-r--r--lib/Sema/TreeTransform.h1737
-rw-r--r--lib/Sema/TypeLocBuilder.cpp2
-rw-r--r--lib/Sema/TypeLocBuilder.h2
-rw-r--r--lib/Serialization/ASTCommon.cpp12
-rw-r--r--lib/Serialization/ASTCommon.h7
-rw-r--r--lib/Serialization/ASTReader.cpp2025
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp851
-rw-r--r--lib/Serialization/ASTReaderInternals.h32
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp442
-rw-r--r--lib/Serialization/ASTWriter.cpp1104
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp159
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp300
-rw-r--r--lib/Serialization/CMakeLists.txt31
-rw-r--r--lib/Serialization/GeneratePCH.cpp2
-rw-r--r--lib/Serialization/GlobalModuleIndex.cpp116
-rw-r--r--lib/Serialization/Module.cpp30
-rw-r--r--lib/Serialization/ModuleManager.cpp96
-rw-r--r--lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp10
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp15
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp243
-rw-r--r--lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt22
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp167
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp13
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp219
-rw-r--r--lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp93
-rw-r--r--lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp11
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp45
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp41
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp108
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp10
-rw-r--r--lib/StaticAnalyzer/Checkers/Checkers.td20
-rw-r--r--lib/StaticAnalyzer/Checkers/ChrootChecker.cpp12
-rw-r--r--lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp42
-rw-r--r--lib/StaticAnalyzer/Checkers/DebugCheckers.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp22
-rw-r--r--lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp44
-rw-r--r--lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp10
-rw-r--r--lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp16
-rw-r--r--lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp11
-rw-r--r--lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp25
-rw-r--r--lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp737
-rw-r--r--lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp404
-rw-r--r--lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp97
-rw-r--r--lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp56
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp22
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp606
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp20
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp15
-rw-r--r--lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp63
-rw-r--r--lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp37
-rw-r--r--lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp28
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp15
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp17
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp10
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp42
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp43
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp11
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp223
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp434
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp10
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp16
-rw-r--r--lib/StaticAnalyzer/Checkers/SelectorExtras.h68
-rw-r--r--lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp18
-rw-r--r--lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp22
-rw-r--r--lib/StaticAnalyzer/Checkers/StreamChecker.cpp47
-rw-r--r--lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp264
-rw-r--r--lib/StaticAnalyzer/Checkers/TraversalChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp33
-rw-r--r--lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp23
-rw-r--r--lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp25
-rw-r--r--lib/StaticAnalyzer/Core/AnalyzerOptions.cpp19
-rw-r--r--lib/StaticAnalyzer/Core/BasicValueFactory.cpp12
-rw-r--r--lib/StaticAnalyzer/Core/BlockCounter.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp175
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp193
-rw-r--r--lib/StaticAnalyzer/Core/CMakeLists.txt18
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp122
-rw-r--r--lib/StaticAnalyzer/Core/Checker.cpp19
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp12
-rw-r--r--lib/StaticAnalyzer/Core/CheckerRegistry.cpp7
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp59
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp12
-rw-r--r--lib/StaticAnalyzer/Core/ExplodedGraph.cpp28
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp311
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp89
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp168
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp66
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineObjC.cpp6
-rw-r--r--lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp105
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp64
-rw-r--r--lib/StaticAnalyzer/Core/PathDiagnostic.cpp94
-rw-r--r--lib/StaticAnalyzer/Core/PlistDiagnostics.cpp140
-rw-r--r--lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h2
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp5
-rw-r--r--lib/StaticAnalyzer/Core/RangeConstraintManager.cpp54
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp67
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/SVals.cpp12
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.h4
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp47
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp10
-rw-r--r--lib/StaticAnalyzer/Core/SymbolManager.cpp12
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp164
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.h43
-rw-r--r--lib/StaticAnalyzer/Frontend/CMakeLists.txt28
-rw-r--r--lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp12
-rw-r--r--lib/StaticAnalyzer/Frontend/FrontendActions.cpp2
-rw-r--r--lib/Tooling/CMakeLists.txt21
-rw-r--r--lib/Tooling/CommonOptionsParser.cpp20
-rw-r--r--lib/Tooling/CompilationDatabase.cpp56
-rw-r--r--lib/Tooling/FileMatchTrie.cpp2
-rw-r--r--lib/Tooling/JSONCompilationDatabase.cpp59
-rw-r--r--lib/Tooling/Refactoring.cpp20
-rw-r--r--lib/Tooling/Tooling.cpp132
517 files changed, 80973 insertions, 50663 deletions
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp
index 3e429beded5d..8a13b2ee4f1d 100644
--- a/lib/ARCMigrate/ARCMT.cpp
+++ b/lib/ARCMigrate/ARCMT.cpp
@@ -103,8 +103,8 @@ public:
: Diags(diags), DiagClient(client), CapturedDiags(capturedDiags),
HasBegunSourceFile(false) { }
- virtual void BeginSourceFile(const LangOptions &Opts,
- const Preprocessor *PP) {
+ void BeginSourceFile(const LangOptions &Opts,
+ const Preprocessor *PP) override {
// Pass BeginSourceFile message onto DiagClient on first call.
// The corresponding EndSourceFile call will be made from an
// explicit call to FinishCapture.
@@ -128,8 +128,8 @@ public:
assert(!HasBegunSourceFile && "FinishCapture not called!");
}
- virtual void HandleDiagnostic(DiagnosticsEngine::Level level,
- const Diagnostic &Info) {
+ void HandleDiagnostic(DiagnosticsEngine::Level level,
+ const Diagnostic &Info) override {
if (DiagnosticIDs::isARCDiagnostic(Info.getID()) ||
level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) {
if (Info.getLocation().isValid())
@@ -167,7 +167,7 @@ static bool HasARCRuntime(CompilerInvocation &origCI) {
static CompilerInvocation *
createInvocationForMigration(CompilerInvocation &origCI) {
- OwningPtr<CompilerInvocation> CInvok;
+ std::unique_ptr<CompilerInvocation> CInvok;
CInvok.reset(new CompilerInvocation(origCI));
PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
if (!PPOpts.ImplicitPCHInclude.empty()) {
@@ -204,11 +204,11 @@ createInvocationForMigration(CompilerInvocation &origCI) {
WarnOpts.push_back(*I);
}
WarnOpts.push_back("error=arc-unsafe-retained-assign");
- CInvok->getDiagnosticOpts().Warnings = llvm_move(WarnOpts);
+ CInvok->getDiagnosticOpts().Warnings = std::move(WarnOpts);
CInvok->getLangOpts()->ObjCARCWeak = HasARCRuntime(origCI);
- return CInvok.take();
+ return CInvok.release();
}
static void emitPremigrationErrors(const CapturedDiagList &arcDiags,
@@ -246,7 +246,7 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
NoFinalizeRemoval);
assert(!transforms.empty());
- OwningPtr<CompilerInvocation> CInvok;
+ std::unique_ptr<CompilerInvocation> CInvok;
CInvok.reset(createInvocationForMigration(origCI));
CInvok->getFrontendOpts().Inputs.clear();
CInvok->getFrontendOpts().Inputs.push_back(Input);
@@ -263,8 +263,8 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
- OwningPtr<ASTUnit> Unit(
- ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags));
+ std::unique_ptr<ASTUnit> Unit(
+ ASTUnit::LoadFromCompilerInvocationAction(CInvok.release(), Diags));
if (!Unit) {
errRec.FinishCapture();
return true;
@@ -310,8 +310,10 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, capturedDiags,
ARCMTMacroLocs);
- pass.setNSAllocReallocError(NoNSAllocReallocError);
pass.setNoFinalizeRemoval(NoFinalizeRemoval);
+ if (!NoNSAllocReallocError)
+ Diags->setSeverity(diag::warn_arcmt_nsalloc_realloc, diag::Severity::Error,
+ SourceLocation());
for (unsigned i=0, e = transforms.size(); i != e; ++i)
transforms[i](pass);
@@ -416,44 +418,6 @@ bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > &
return false;
}
-bool arcmt::getFileRemappingsFromFileList(
- std::vector<std::pair<std::string,std::string> > &remap,
- ArrayRef<StringRef> remapFiles,
- DiagnosticConsumer *DiagClient) {
- bool hasErrorOccurred = false;
- llvm::StringMap<bool> Uniquer;
-
- IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, new DiagnosticOptions,
- DiagClient, /*ShouldOwnClient=*/false));
-
- for (ArrayRef<StringRef>::iterator
- I = remapFiles.begin(), E = remapFiles.end(); I != E; ++I) {
- StringRef file = *I;
-
- FileRemapper remapper;
- bool err = remapper.initFromFile(file, *Diags,
- /*ignoreIfFilesChanged=*/true);
- hasErrorOccurred = hasErrorOccurred || err;
- if (err)
- continue;
-
- PreprocessorOptions PPOpts;
- remapper.applyMappings(PPOpts);
- for (PreprocessorOptions::remapped_file_iterator
- RI = PPOpts.remapped_file_begin(), RE = PPOpts.remapped_file_end();
- RI != RE; ++RI) {
- bool &inserted = Uniquer[RI->first];
- if (inserted)
- continue;
- inserted = true;
- remap.push_back(*RI);
- }
- }
-
- return hasErrorOccurred;
-}
//===----------------------------------------------------------------------===//
// CollectTransformActions.
@@ -468,8 +432,8 @@ public:
ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs)
: ARCMTMacroLocs(ARCMTMacroLocs) { }
- virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD,
- SourceRange Range, const MacroArgs *Args) {
+ void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD,
+ SourceRange Range, const MacroArgs *Args) override {
if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName())
ARCMTMacroLocs.push_back(MacroNameTok.getLocation());
}
@@ -482,8 +446,8 @@ public:
ARCMTMacroTrackerAction(std::vector<SourceLocation> &ARCMTMacroLocs)
: ARCMTMacroLocs(ARCMTMacroLocs) { }
- virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+ ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override {
CI.getPreprocessor().addPPCallbacks(
new ARCMTMacroTrackerPPCallbacks(ARCMTMacroLocs));
return new ASTConsumer();
@@ -506,14 +470,14 @@ public:
Listener->finish();
}
- virtual void insert(SourceLocation loc, StringRef text) {
+ void insert(SourceLocation loc, StringRef text) override {
bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true,
/*indentNewLines=*/true);
if (!err && Listener)
Listener->insert(loc, text);
}
- virtual void remove(CharSourceRange range) {
+ void remove(CharSourceRange range) override {
Rewriter::RewriteOptions removeOpts;
removeOpts.IncludeInsertsAtBeginOfRange = false;
removeOpts.IncludeInsertsAtEndOfRange = false;
@@ -524,8 +488,8 @@ public:
Listener->remove(range);
}
- virtual void increaseIndentation(CharSourceRange range,
- SourceLocation parentIndent) {
+ void increaseIndentation(CharSourceRange range,
+ SourceLocation parentIndent) override {
rewriter.IncreaseIndentation(range, parentIndent);
}
};
@@ -550,7 +514,7 @@ MigrationProcess::MigrationProcess(const CompilerInvocation &CI,
bool MigrationProcess::applyTransform(TransformFn trans,
RewriteListener *listener) {
- OwningPtr<CompilerInvocation> CInvok;
+ std::unique_ptr<CompilerInvocation> CInvok;
CInvok.reset(createInvocationForMigration(OrigCI));
CInvok->getDiagnosticOpts().IgnoreWarnings = true;
@@ -569,12 +533,11 @@ bool MigrationProcess::applyTransform(TransformFn trans,
CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
- OwningPtr<ARCMTMacroTrackerAction> ASTAction;
+ std::unique_ptr<ARCMTMacroTrackerAction> ASTAction;
ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs));
- OwningPtr<ASTUnit> Unit(
- ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags,
- ASTAction.get()));
+ std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
+ CInvok.release(), Diags, ASTAction.get()));
if (!Unit) {
errRec.FinishCapture();
return true;
diff --git a/lib/ARCMigrate/CMakeLists.txt b/lib/ARCMigrate/CMakeLists.txt
index c55261277dd1..b716a20fe63f 100644
--- a/lib/ARCMigrate/CMakeLists.txt
+++ b/lib/ARCMigrate/CMakeLists.txt
@@ -1,3 +1,7 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
add_clang_library(clangARCMigrate
ARCMT.cpp
ARCMTActions.cpp
@@ -19,26 +23,16 @@ add_clang_library(clangARCMigrate
TransZeroOutPropsInDealloc.cpp
TransformActions.cpp
Transforms.cpp
- )
-add_dependencies(clangARCMigrate
- ClangAttrClasses
- ClangAttrList
- ClangAttrParsedAttrList
- ClangCommentNodes
- ClangDeclNodes
- ClangDiagnosticCommon
- ClangDiagnosticGroups
- ClangDiagnosticSema
- ClangStmtNodes
- )
-
-target_link_libraries(clangARCMigrate
- clangBasic
+ LINK_LIBS
clangAST
- clangParse
+ clangAnalysis
+ clangBasic
+ clangEdit
clangFrontend
- clangRewriteCore
- clangRewriteFrontend
+ clangLex
+ clangRewrite
+ clangSema
+ clangSerialization
clangStaticAnalyzerCheckers
)
diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp
index a14226e43fe0..40e606090064 100644
--- a/lib/ARCMigrate/FileRemapper.cpp
+++ b/lib/ARCMigrate/FileRemapper.cpp
@@ -36,8 +36,7 @@ void FileRemapper::clear(StringRef outputDir) {
assert(ToFromMappings.empty());
if (!outputDir.empty()) {
std::string infoFile = getRemapInfoFile(outputDir);
- bool existed;
- llvm::sys::fs::remove(infoFile, existed);
+ llvm::sys::fs::remove(infoFile);
}
}
@@ -65,13 +64,14 @@ bool FileRemapper::initFromFile(StringRef filePath, DiagnosticsEngine &Diag,
return false;
std::vector<std::pair<const FileEntry *, const FileEntry *> > pairs;
-
- OwningPtr<llvm::MemoryBuffer> fileBuf;
- if (llvm::MemoryBuffer::getFile(infoFile.c_str(), fileBuf))
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileBuf =
+ llvm::MemoryBuffer::getFile(infoFile.c_str());
+ if (!fileBuf)
return report("Error opening file: " + infoFile, Diag);
SmallVector<StringRef, 64> lines;
- fileBuf->getBuffer().split(lines, "\n");
+ fileBuf.get()->getBuffer().split(lines, "\n");
for (unsigned idx = 0; idx+3 <= lines.size(); idx += 3) {
StringRef fromFilename = lines[idx];
@@ -112,8 +112,7 @@ bool FileRemapper::initFromFile(StringRef filePath, DiagnosticsEngine &Diag,
bool FileRemapper::flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag) {
using namespace llvm::sys;
- bool existed;
- if (fs::create_directory(outputDir, existed) != llvm::errc::success)
+ if (fs::create_directory(outputDir))
return report("Could not create directory: " + outputDir, Diag);
std::string infoFile = getRemapInfoFile(outputDir);
@@ -125,8 +124,7 @@ bool FileRemapper::flushToFile(StringRef outputPath, DiagnosticsEngine &Diag) {
std::string errMsg;
std::string infoFile = outputPath;
- llvm::raw_fd_ostream infoOut(infoFile.c_str(), errMsg,
- llvm::sys::fs::F_Binary);
+ llvm::raw_fd_ostream infoOut(infoFile.c_str(), errMsg, llvm::sys::fs::F_None);
if (!errMsg.empty())
return report(errMsg, Diag);
@@ -182,8 +180,7 @@ bool FileRemapper::overwriteOriginal(DiagnosticsEngine &Diag,
Diag);
std::string errMsg;
- llvm::raw_fd_ostream Out(origFE->getName(), errMsg,
- llvm::sys::fs::F_Binary);
+ llvm::raw_fd_ostream Out(origFE->getName(), errMsg, llvm::sys::fs::F_None);
if (!errMsg.empty())
return report(errMsg, Diag);
@@ -210,22 +207,6 @@ void FileRemapper::applyMappings(PreprocessorOptions &PPOpts) const {
PPOpts.RetainRemappedFileBuffers = true;
}
-void FileRemapper::transferMappingsAndClear(PreprocessorOptions &PPOpts) {
- 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(StringRef filePath, llvm::MemoryBuffer *memBuf) {
remap(getOriginalFile(filePath), memBuf);
}
@@ -272,9 +253,7 @@ void FileRemapper::resetTarget(Target &targ) {
}
bool FileRemapper::report(const Twine &err, DiagnosticsEngine &Diag) {
- SmallString<128> buf;
- unsigned ID = Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Error,
- err.toStringRef(buf));
- Diag.Report(ID);
+ Diag.Report(Diag.getCustomDiagID(DiagnosticsEngine::Error, "%0"))
+ << err.str();
return true;
}
diff --git a/lib/ARCMigrate/Internals.h b/lib/ARCMigrate/Internals.h
index 3690c83d8457..a65b329c5b03 100644
--- a/lib/ARCMigrate/Internals.h
+++ b/lib/ARCMigrate/Internals.h
@@ -48,7 +48,6 @@ void writeARCDiagsToPlist(const std::string &outPath,
class TransformActions {
DiagnosticsEngine &Diags;
CapturedDiagList &CapturedDiags;
- bool ReportedErrors;
void *Impl; // TransformActionsImpl.
public:
@@ -95,6 +94,8 @@ public:
return CapturedDiags.hasDiagnostic(IDs, range);
}
+ DiagnosticBuilder report(SourceLocation loc, unsigned diagId,
+ SourceRange range = SourceRange());
void reportError(StringRef error, SourceLocation loc,
SourceRange range = SourceRange());
void reportWarning(StringRef warning, SourceLocation loc,
@@ -102,7 +103,9 @@ public:
void reportNote(StringRef note, SourceLocation loc,
SourceRange range = SourceRange());
- bool hasReportedErrors() const { return ReportedErrors; }
+ bool hasReportedErrors() const {
+ return Diags.hasUnrecoverableErrorOccurred();
+ }
class RewriteReceiver {
public:
@@ -161,8 +164,6 @@ public:
const CapturedDiagList &getDiags() const { return CapturedDiags; }
bool isGCMigration() const { return OrigGCMode != LangOptions::NonGC; }
- bool noNSAllocReallocError() const { return MigOptions.NoNSAllocReallocError; }
- void setNSAllocReallocError(bool val) { MigOptions.NoNSAllocReallocError = val; }
bool noFinalizeRemoval() const { return MigOptions.NoFinalizeRemoval; }
void setNoFinalizeRemoval(bool val) {MigOptions.NoFinalizeRemoval = val; }
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
index cac0fb0aed1b..1a2055e9c452 100644
--- a/lib/ARCMigrate/ObjCMT.cpp
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -8,12 +8,15 @@
//===----------------------------------------------------------------------===//
#include "Transforms.h"
+#include "clang/ARCMigrate/ARCMT.h"
#include "clang/ARCMigrate/ARCMTActions.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/NSAPI.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Edit/Commit.h"
#include "clang/Edit/EditedSource.h"
@@ -24,11 +27,11 @@
#include "clang/Lex/PPConditionalDirectiveRecord.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/StaticAnalyzer/Checkers/ObjCRetainCount.h"
-#include "clang/AST/Attr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/YAMLParser.h"
using namespace clang;
using namespace arcmt;
@@ -45,7 +48,6 @@ class ObjCMigrateASTConsumer : public ASTConsumer {
void migrateDecl(Decl *D);
void migrateObjCInterfaceDecl(ASTContext &Ctx, ObjCContainerDecl *D);
- void migrateDeprecatedAnnotation(ASTContext &Ctx, ObjCCategoryDecl *CatDecl);
void migrateProtocolConformance(ASTContext &Ctx,
const ObjCImplementationDecl *ImpDecl);
void CacheObjCNSIntegerTypedefed(const TypedefDecl *TypedefDcl);
@@ -76,14 +78,18 @@ class ObjCMigrateASTConsumer : public ASTConsumer {
void migrateAddMethodAnnotation(ASTContext &Ctx,
const ObjCMethodDecl *MethodDecl);
+
+ void inferDesignatedInitializers(ASTContext &Ctx,
+ const ObjCImplementationDecl *ImplD);
+
public:
std::string MigrateDir;
unsigned ASTMigrateActions;
FileID FileId;
const TypedefDecl *NSIntegerTypedefed;
const TypedefDecl *NSUIntegerTypedefed;
- OwningPtr<NSAPI> NSAPIObj;
- OwningPtr<edit::EditedSource> Editor;
+ std::unique_ptr<NSAPI> NSAPIObj;
+ std::unique_ptr<edit::EditedSource> Editor;
FileRemapper &Remapper;
FileManager &FileMgr;
const PPConditionalDirectiveRecord *PPRec;
@@ -103,7 +109,7 @@ public:
ArrayRef<std::string> WhiteList)
: MigrateDir(migrateDir),
ASTMigrateActions(astMigrateActions),
- NSIntegerTypedefed(0), NSUIntegerTypedefed(0),
+ NSIntegerTypedefed(nullptr), NSUIntegerTypedefed(nullptr),
Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP),
IsOutputFile(isOutputFile) {
@@ -114,26 +120,26 @@ public:
}
protected:
- virtual void Initialize(ASTContext &Context) {
+ void Initialize(ASTContext &Context) override {
NSAPIObj.reset(new NSAPI(Context));
Editor.reset(new edit::EditedSource(Context.getSourceManager(),
Context.getLangOpts(),
- PPRec, false));
+ PPRec));
}
- virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
+ bool HandleTopLevelDecl(DeclGroupRef DG) override {
for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
migrateDecl(*I);
return true;
}
- virtual void HandleInterestingDecl(DeclGroupRef DG) {
+ void HandleInterestingDecl(DeclGroupRef DG) override {
// Ignore decls from the PCH.
}
- virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
+ void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override {
ObjCMigrateASTConsumer::HandleTopLevelDecl(DG);
}
- virtual void HandleTranslationUnit(ASTContext &Ctx);
+ void HandleTranslationUnit(ASTContext &Ctx) override;
bool canModifyFile(StringRef Path) {
if (WhiteListFilenames.empty())
@@ -141,6 +147,30 @@ protected:
return WhiteListFilenames.find(llvm::sys::path::filename(Path))
!= WhiteListFilenames.end();
}
+ bool canModifyFile(const FileEntry *FE) {
+ if (!FE)
+ return false;
+ return canModifyFile(FE->getName());
+ }
+ bool canModifyFile(FileID FID) {
+ if (FID.isInvalid())
+ return false;
+ return canModifyFile(PP.getSourceManager().getFileEntryForID(FID));
+ }
+
+ bool canModify(const Decl *D) {
+ if (!D)
+ return false;
+ if (const ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(D))
+ return canModify(CatImpl->getCategoryDecl());
+ if (const ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(D))
+ return canModify(Impl->getClassInterface());
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+ return canModify(cast<Decl>(MD->getDeclContext()));
+
+ FileID FID = PP.getSourceManager().getFileID(D->getLocation());
+ return canModifyFile(FID);
+ }
};
}
@@ -150,7 +180,7 @@ ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction,
unsigned migrateAction)
: WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir),
ObjCMigAction(migrateAction),
- CompInst(0) {
+ CompInst(nullptr) {
if (MigrateDir.empty())
MigrateDir = "."; // user current directory if none is given.
}
@@ -223,7 +253,7 @@ public:
class BodyMigrator : public RecursiveASTVisitor<BodyMigrator> {
ObjCMigrateASTConsumer &Consumer;
- OwningPtr<ParentMap> PMap;
+ std::unique_ptr<ParentMap> PMap;
public:
BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
@@ -294,7 +324,9 @@ void MigrateBlockOrFunctionPointerTypeVariable(std::string & PropertyString,
static const char *PropertyMemoryAttribute(ASTContext &Context, QualType ArgType) {
Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime();
bool RetainableObject = ArgType->isObjCRetainableType();
- if (RetainableObject && propertyLifetime == Qualifiers::OCL_Strong) {
+ if (RetainableObject &&
+ (propertyLifetime == Qualifiers::OCL_Strong
+ || propertyLifetime == Qualifiers::OCL_None)) {
if (const ObjCObjectPointerType *ObjPtrTy =
ArgType->getAs<ObjCObjectPointerType>()) {
ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
@@ -302,7 +334,7 @@ static const char *PropertyMemoryAttribute(ASTContext &Context, QualType ArgType
IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying")))
return "copy";
else
- return "retain";
+ return "strong";
}
else if (ArgType->isBlockPointerType())
return "copy";
@@ -311,8 +343,8 @@ static const char *PropertyMemoryAttribute(ASTContext &Context, QualType ArgType
// looking into setter's implementation for backing weak ivar.
return "weak";
else if (RetainableObject)
- return ArgType->isBlockPointerType() ? "copy" : "retain";
- return 0;
+ return ArgType->isBlockPointerType() ? "copy" : "strong";
+ return nullptr;
}
static void rewriteToObjCProperty(const ObjCMethodDecl *Getter,
@@ -344,23 +376,23 @@ static void rewriteToObjCProperty(const ObjCMethodDecl *Getter,
PropertyString += PropertyNameString;
}
// Property with no setter may be suggested as a 'readonly' property.
- if (!Setter) {
+ if (!Setter)
append_attr(PropertyString, "readonly", LParenAdded);
- QualType ResType = Context.getCanonicalType(Getter->getResultType());
- if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ResType))
- append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
- }
+
// Short circuit 'delegate' properties that contain the name "delegate" or
// "dataSource", or have exact name "target" to have 'assign' attribute.
if (PropertyName.equals("target") ||
(PropertyName.find("delegate") != StringRef::npos) ||
(PropertyName.find("dataSource") != StringRef::npos)) {
- QualType QT = Getter->getResultType();
+ QualType QT = Getter->getReturnType();
if (!QT->isRealType())
append_attr(PropertyString, "assign", LParenAdded);
- }
- else if (Setter) {
+ } else if (!Setter) {
+ QualType ResType = Context.getCanonicalType(Getter->getReturnType());
+ if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ResType))
+ append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
+ } else {
const ParmVarDecl *argDecl = *Setter->param_begin();
QualType ArgType = Context.getCanonicalType(argDecl->getType());
if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ArgType))
@@ -368,7 +400,7 @@ static void rewriteToObjCProperty(const ObjCMethodDecl *Getter,
}
if (LParenAdded)
PropertyString += ')';
- QualType RT = Getter->getResultType();
+ QualType RT = Getter->getReturnType();
if (!isa<TypedefType>(RT)) {
// strip off any ARC lifetime qualifier.
QualType CanResultTy = Context.getCanonicalType(RT);
@@ -419,21 +451,27 @@ static void rewriteToObjCProperty(const ObjCMethodDecl *Getter,
// Get location past ';'
EndLoc = EndLoc.getLocWithOffset(1);
SourceLocation BeginOfSetterDclLoc = Setter->getLocStart();
- // FIXME. This assumes that setter decl; is immediately preceeded by eoln.
+ // FIXME. This assumes that setter decl; is immediately preceded by eoln.
// It is trying to remove the setter method decl. line entirely.
BeginOfSetterDclLoc = BeginOfSetterDclLoc.getLocWithOffset(-1);
commit.remove(SourceRange(BeginOfSetterDclLoc, EndLoc));
}
}
+static bool IsCategoryNameWithDeprecatedSuffix(ObjCContainerDecl *D) {
+ if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(D)) {
+ StringRef Name = CatDecl->getName();
+ return Name.endswith("Deprecated");
+ }
+ return false;
+}
+
void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx,
ObjCContainerDecl *D) {
- if (D->isDeprecated())
+ if (D->isDeprecated() || IsCategoryNameWithDeprecatedSuffix(D))
return;
-
- for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end();
- M != MEnd; ++M) {
- ObjCMethodDecl *Method = (*M);
+
+ for (auto *Method : D->methods()) {
if (Method->isDeprecated())
continue;
bool PropertyInferred = migrateProperty(Ctx, D, Method);
@@ -448,48 +486,13 @@ void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx,
if (!(ASTMigrateActions & FrontendOptions::ObjCMT_ReturnsInnerPointerProperty))
return;
- for (ObjCContainerDecl::prop_iterator P = D->prop_begin(),
- E = D->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
+ for (auto *Prop : D->properties()) {
if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
!Prop->isDeprecated())
migratePropertyNsReturnsInnerPointer(Ctx, Prop);
}
}
-void ObjCMigrateASTConsumer::migrateDeprecatedAnnotation(ASTContext &Ctx,
- ObjCCategoryDecl *CatDecl) {
- StringRef Name = CatDecl->getName();
- if (!Name.endswith("Deprecated"))
- return;
-
- if (!Ctx.Idents.get("DEPRECATED").hasMacroDefinition())
- return;
-
- ObjCContainerDecl *D = cast<ObjCContainerDecl>(CatDecl);
-
- for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end();
- M != MEnd; ++M) {
- ObjCMethodDecl *Method = (*M);
- if (Method->isDeprecated() || Method->isImplicit())
- continue;
- // Annotate with DEPRECATED
- edit::Commit commit(*Editor);
- commit.insertBefore(Method->getLocEnd(), " DEPRECATED");
- Editor->commit(commit);
- }
- for (ObjCContainerDecl::prop_iterator P = D->prop_begin(),
- E = D->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
- if (Prop->isDeprecated())
- continue;
- // Annotate with DEPRECATED
- edit::Commit commit(*Editor);
- commit.insertAfterToken(Prop->getLocEnd(), " DEPRECATED");
- Editor->commit(commit);
- }
-}
-
static bool
ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
const ObjCImplementationDecl *ImpDecl,
@@ -500,9 +503,7 @@ ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
// in class interface.
bool HasAtleastOneRequiredProperty = false;
if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition())
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Property = *P;
+ for (const auto *Property : PDecl->properties()) {
if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
continue;
HasAtleastOneRequiredProperty = true;
@@ -532,9 +533,7 @@ ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) {
if (PDecl->meth_begin() == PDecl->meth_end())
return HasAtleastOneRequiredProperty;
- for (ObjCContainerDecl::method_iterator M = PDecl->meth_begin(),
- MEnd = PDecl->meth_end(); M != MEnd; ++M) {
- ObjCMethodDecl *MD = (*M);
+ for (const auto *MD : PDecl->methods()) {
if (MD->isImplicit())
continue;
if (MD->getImplementationControl() == ObjCMethodDecl::Optional)
@@ -632,7 +631,7 @@ static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl,
/*IsDecl*/true);
if (!EndOfEnumDclLoc.isInvalid()) {
SourceLocation BeginOfEnumDclLoc = EnumDcl->getLocStart();
- // FIXME. This assumes that enum decl; is immediately preceeded by eoln.
+ // FIXME. This assumes that enum decl; is immediately preceded by eoln.
// It is trying to remove the enum decl. lines entirely.
BeginOfEnumDclLoc = BeginOfEnumDclLoc.getLocWithOffset(-1);
commit.remove(SourceRange(BeginOfEnumDclLoc, EndOfEnumDclLoc));
@@ -660,9 +659,7 @@ static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx,
bool PowerOfTwo = true;
bool AllHexdecimalEnumerator = true;
uint64_t MaxPowerOfTwoVal = 0;
- for (EnumDecl::enumerator_iterator EI = EnumDcl->enumerator_begin(),
- EE = EnumDcl->enumerator_end(); EI != EE; ++EI) {
- EnumConstantDecl *Enumerator = (*EI);
+ for (auto Enumerator : EnumDcl->enumerators()) {
const Expr *InitExpr = Enumerator->getInitExpr();
if (!InitExpr) {
PowerOfTwo = false;
@@ -749,6 +746,8 @@ void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx,
if (!DropIt)
MinimalConformingProtocols.push_back(TargetPDecl);
}
+ if (MinimalConformingProtocols.empty())
+ return;
edit::Commit commit(*Editor);
rewriteToObjCInterfaceDecl(IDecl, MinimalConformingProtocols,
*NSAPIObj, commit);
@@ -774,11 +773,11 @@ bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
if (!TypedefDcl) {
if (NSIntegerTypedefed) {
TypedefDcl = NSIntegerTypedefed;
- NSIntegerTypedefed = 0;
+ NSIntegerTypedefed = nullptr;
}
else if (NSUIntegerTypedefed) {
TypedefDcl = NSUIntegerTypedefed;
- NSUIntegerTypedefed = 0;
+ NSUIntegerTypedefed = nullptr;
}
else
return false;
@@ -831,11 +830,15 @@ bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
return Res;
}
-static void ReplaceWithInstancetype(const ObjCMigrateASTConsumer &ASTC,
+static void ReplaceWithInstancetype(ASTContext &Ctx,
+ const ObjCMigrateASTConsumer &ASTC,
ObjCMethodDecl *OM) {
+ if (OM->getReturnType() == Ctx.getObjCInstanceType())
+ return; // already has instancetype.
+
SourceRange R;
std::string ClassString;
- if (TypeSourceInfo *TSInfo = OM->getResultTypeSourceInfo()) {
+ if (TypeSourceInfo *TSInfo = OM->getReturnTypeSourceInfo()) {
TypeLoc TL = TSInfo->getTypeLoc();
R = SourceRange(TL.getBeginLoc(), TL.getEndLoc());
ClassString = "instancetype";
@@ -855,7 +858,7 @@ static void ReplaceWithClasstype(const ObjCMigrateASTConsumer &ASTC,
ObjCInterfaceDecl *IDecl = OM->getClassInterface();
SourceRange R;
std::string ClassString;
- if (TypeSourceInfo *TSInfo = OM->getResultTypeSourceInfo()) {
+ if (TypeSourceInfo *TSInfo = OM->getReturnTypeSourceInfo()) {
TypeLoc TL = TSInfo->getTypeLoc();
R = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); {
ClassString = IDecl->getName();
@@ -893,14 +896,14 @@ void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
migrateFactoryMethod(Ctx, CDecl, OM, OIT_Singleton);
return;
case OIT_Init:
- if (OM->getResultType()->isObjCIdType())
- ReplaceWithInstancetype(*this, OM);
+ if (OM->getReturnType()->isObjCIdType())
+ ReplaceWithInstancetype(Ctx, *this, OM);
return;
case OIT_ReturnsSelf:
migrateFactoryMethod(Ctx, CDecl, OM, OIT_ReturnsSelf);
return;
}
- if (!OM->getResultType()->isObjCIdType())
+ if (!OM->getReturnType()->isObjCIdType())
return;
ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
@@ -915,7 +918,7 @@ void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
migrateFactoryMethod(Ctx, CDecl, OM);
return;
}
- ReplaceWithInstancetype(*this, OM);
+ ReplaceWithInstancetype(Ctx, *this, OM);
}
static bool TypeIsInnerPointer(QualType T) {
@@ -1034,7 +1037,7 @@ bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx,
Method->param_size() != 0)
return false;
// Is this method candidate to be a getter?
- QualType GRT = Method->getResultType();
+ QualType GRT = Method->getReturnType();
if (GRT->isVoidType())
return false;
@@ -1087,7 +1090,7 @@ bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx,
return false;
// Is this a valid setter, matching the target getter?
- QualType SRT = SetterMethod->getResultType();
+ QualType SRT = SetterMethod->getReturnType();
if (!SRT->isVoidType())
return false;
const ParmVarDecl *argDecl = *SetterMethod->param_begin();
@@ -1109,7 +1112,7 @@ bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx,
// Try a non-void method with no argument (and no setter or property of same name
// as a 'readonly' property.
edit::Commit commit(*Editor);
- rewriteToObjCProperty(Method, 0 /*SetterMethod*/, *NSAPIObj, commit,
+ rewriteToObjCProperty(Method, nullptr /*SetterMethod*/, *NSAPIObj, commit,
LengthOfPrefix,
(ASTMigrateActions &
FrontendOptions::ObjCMT_AtomicProperty) != 0,
@@ -1128,8 +1131,8 @@ void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx,
!OM->isInstanceMethod() ||
OM->hasAttr<ObjCReturnsInnerPointerAttr>())
return;
-
- QualType RT = OM->getResultType();
+
+ QualType RT = OM->getReturnType();
if (!TypeIsInnerPointer(RT) ||
!Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition())
return;
@@ -1153,14 +1156,11 @@ void ObjCMigrateASTConsumer::migratePropertyNsReturnsInnerPointer(ASTContext &Ct
void ObjCMigrateASTConsumer::migrateAllMethodInstaceType(ASTContext &Ctx,
ObjCContainerDecl *CDecl) {
- if (CDecl->isDeprecated())
+ if (CDecl->isDeprecated() || IsCategoryNameWithDeprecatedSuffix(CDecl))
return;
// migrate methods which can have instancetype as their result type.
- for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(),
- MEnd = CDecl->meth_end();
- M != MEnd; ++M) {
- ObjCMethodDecl *Method = (*M);
+ for (auto *Method : CDecl->methods()) {
if (Method->isDeprecated())
continue;
migrateMethodInstanceType(Ctx, CDecl, Method);
@@ -1172,8 +1172,8 @@ void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
ObjCMethodDecl *OM,
ObjCInstanceTypeFamily OIT_Family) {
if (OM->isInstanceMethod() ||
- OM->getResultType() == Ctx.getObjCInstanceType() ||
- !OM->getResultType()->isObjCIdType())
+ OM->getReturnType() == Ctx.getObjCInstanceType() ||
+ !OM->getReturnType()->isObjCIdType())
return;
// Candidate factory methods are + (id) NaMeXXX : ... which belong to a class
@@ -1228,7 +1228,7 @@ void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
if (OIT_Family == OIT_ReturnsSelf)
ReplaceWithClasstype(*this, OM);
else
- ReplaceWithInstancetype(*this, OM);
+ ReplaceWithInstancetype(Ctx, *this, OM);
}
static bool IsVoidStarType(QualType Ty) {
@@ -1338,7 +1338,7 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
// Annotate function.
if (!ResultAnnotated) {
RetEffect Ret = CE.getReturnValue();
- const char *AnnotationString = 0;
+ const char *AnnotationString = nullptr;
if (Ret.getObjKind() == RetEffect::CF) {
if (Ret.isOwned() &&
Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition())
@@ -1359,19 +1359,19 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
Editor->commit(commit);
}
}
- llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
+ ArrayRef<ArgEffect> AEArgs = CE.getArgs();
unsigned i = 0;
for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
const ParmVarDecl *pd = *pi;
ArgEffect AE = AEArgs[i];
- if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
+ if (AE == DecRef && !pd->hasAttr<CFConsumedAttr>() &&
Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
edit::Commit commit(*Editor);
commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
Editor->commit(commit);
}
- else if (AE == DecRefMsg && !pd->getAttr<NSConsumedAttr>() &&
+ else if (AE == DecRefMsg && !pd->hasAttr<NSConsumedAttr>() &&
Ctx.Idents.get("NS_CONSUMED").hasMacroDefinition()) {
edit::Commit commit(*Editor);
commit.insertBefore(pd->getLocation(), "NS_CONSUMED ");
@@ -1389,11 +1389,11 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND
return CF_BRIDGING_NONE;
CallEffects CE = CallEffects::getEffect(FuncDecl);
- bool FuncIsReturnAnnotated = (FuncDecl->getAttr<CFReturnsRetainedAttr>() ||
- FuncDecl->getAttr<CFReturnsNotRetainedAttr>() ||
- FuncDecl->getAttr<NSReturnsRetainedAttr>() ||
- FuncDecl->getAttr<NSReturnsNotRetainedAttr>() ||
- FuncDecl->getAttr<NSReturnsAutoreleasedAttr>());
+ bool FuncIsReturnAnnotated = (FuncDecl->hasAttr<CFReturnsRetainedAttr>() ||
+ FuncDecl->hasAttr<CFReturnsNotRetainedAttr>() ||
+ FuncDecl->hasAttr<NSReturnsRetainedAttr>() ||
+ FuncDecl->hasAttr<NSReturnsNotRetainedAttr>() ||
+ FuncDecl->hasAttr<NSReturnsAutoreleasedAttr>());
// Trivial case of when funciton is annotated and has no argument.
if (FuncIsReturnAnnotated && FuncDecl->getNumParams() == 0)
@@ -1405,13 +1405,13 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND
if (Ret.getObjKind() == RetEffect::CF &&
(Ret.isOwned() || Ret.notOwned()))
ReturnCFAudited = true;
- else if (!AuditedType(FuncDecl->getResultType()))
+ else if (!AuditedType(FuncDecl->getReturnType()))
return CF_BRIDGING_NONE;
}
// At this point result type is audited for potential inclusion.
// Now, how about argument types.
- llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
+ ArrayRef<ArgEffect> AEArgs = CE.getArgs();
unsigned i = 0;
bool ArgCFAudited = false;
for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
@@ -1419,7 +1419,7 @@ ObjCMigrateASTConsumer::CF_BRIDGING_KIND
const ParmVarDecl *pd = *pi;
ArgEffect AE = AEArgs[i];
if (AE == DecRef /*CFConsumed annotated*/ || AE == IncRef) {
- if (AE == DecRef && !pd->getAttr<CFConsumedAttr>())
+ if (AE == DecRef && !pd->hasAttr<CFConsumedAttr>())
ArgCFAudited = true;
else if (AE == IncRef)
ArgCFAudited = true;
@@ -1444,12 +1444,8 @@ void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx,
return;
// migrate methods which can have instancetype as their result type.
- for (ObjCContainerDecl::method_iterator M = CDecl->meth_begin(),
- MEnd = CDecl->meth_end();
- M != MEnd; ++M) {
- ObjCMethodDecl *Method = (*M);
+ for (const auto *Method : CDecl->methods())
migrateCFAnnotation(Ctx, Method);
- }
}
void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
@@ -1459,7 +1455,7 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
// Annotate function.
if (!ResultAnnotated) {
RetEffect Ret = CE.getReturnValue();
- const char *AnnotationString = 0;
+ const char *AnnotationString = nullptr;
if (Ret.getObjKind() == RetEffect::CF) {
if (Ret.isOwned() &&
Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition())
@@ -1492,13 +1488,13 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
Editor->commit(commit);
}
}
- llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
+ ArrayRef<ArgEffect> AEArgs = CE.getArgs();
unsigned i = 0;
for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
const ParmVarDecl *pd = *pi;
ArgEffect AE = AEArgs[i];
- if (AE == DecRef && !pd->getAttr<CFConsumedAttr>() &&
+ if (AE == DecRef && !pd->hasAttr<CFConsumedAttr>() &&
Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) {
edit::Commit commit(*Editor);
commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
@@ -1514,14 +1510,14 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
return;
CallEffects CE = CallEffects::getEffect(MethodDecl);
- bool MethodIsReturnAnnotated = (MethodDecl->getAttr<CFReturnsRetainedAttr>() ||
- MethodDecl->getAttr<CFReturnsNotRetainedAttr>() ||
- MethodDecl->getAttr<NSReturnsRetainedAttr>() ||
- MethodDecl->getAttr<NSReturnsNotRetainedAttr>() ||
- MethodDecl->getAttr<NSReturnsAutoreleasedAttr>());
+ bool MethodIsReturnAnnotated = (MethodDecl->hasAttr<CFReturnsRetainedAttr>() ||
+ MethodDecl->hasAttr<CFReturnsNotRetainedAttr>() ||
+ MethodDecl->hasAttr<NSReturnsRetainedAttr>() ||
+ MethodDecl->hasAttr<NSReturnsNotRetainedAttr>() ||
+ MethodDecl->hasAttr<NSReturnsAutoreleasedAttr>());
if (CE.getReceiver() == DecRefMsg &&
- !MethodDecl->getAttr<NSConsumesSelfAttr>() &&
+ !MethodDecl->hasAttr<NSConsumesSelfAttr>() &&
MethodDecl->getMethodFamily() != OMF_init &&
MethodDecl->getMethodFamily() != OMF_release &&
Ctx.Idents.get("NS_CONSUMES_SELF").hasMacroDefinition()) {
@@ -1542,20 +1538,19 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
(Ret.isOwned() || Ret.notOwned())) {
AddCFAnnotations(Ctx, CE, MethodDecl, false);
return;
- }
- else if (!AuditedType(MethodDecl->getResultType()))
+ } else if (!AuditedType(MethodDecl->getReturnType()))
return;
}
// At this point result type is either annotated or audited.
// Now, how about argument types.
- llvm::ArrayRef<ArgEffect> AEArgs = CE.getArgs();
+ ArrayRef<ArgEffect> AEArgs = CE.getArgs();
unsigned i = 0;
for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
const ParmVarDecl *pd = *pi;
ArgEffect AE = AEArgs[i];
- if ((AE == DecRef && !pd->getAttr<CFConsumedAttr>()) || AE == IncRef ||
+ if ((AE == DecRef && !pd->hasAttr<CFConsumedAttr>()) || AE == IncRef ||
!AuditedType(pd->getType())) {
AddCFAnnotations(Ctx, CE, MethodDecl, MethodIsReturnAnnotated);
return;
@@ -1565,6 +1560,53 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
}
namespace {
+class SuperInitChecker : public RecursiveASTVisitor<SuperInitChecker> {
+public:
+ bool shouldVisitTemplateInstantiations() const { return false; }
+ bool shouldWalkTypesOfTypeLocs() const { return false; }
+
+ bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ if (E->getReceiverKind() == ObjCMessageExpr::SuperInstance) {
+ if (E->getMethodFamily() == OMF_init)
+ return false;
+ }
+ return true;
+ }
+};
+} // anonymous namespace
+
+static bool hasSuperInitCall(const ObjCMethodDecl *MD) {
+ return !SuperInitChecker().TraverseStmt(MD->getBody());
+}
+
+void ObjCMigrateASTConsumer::inferDesignatedInitializers(
+ ASTContext &Ctx,
+ const ObjCImplementationDecl *ImplD) {
+
+ const ObjCInterfaceDecl *IFace = ImplD->getClassInterface();
+ if (!IFace || IFace->hasDesignatedInitializers())
+ return;
+ if (!Ctx.Idents.get("NS_DESIGNATED_INITIALIZER").hasMacroDefinition())
+ return;
+
+ for (const auto *MD : ImplD->instance_methods()) {
+ if (MD->isDeprecated() ||
+ MD->getMethodFamily() != OMF_init ||
+ MD->isDesignatedInitializerForTheInterface())
+ continue;
+ const ObjCMethodDecl *IFaceM = IFace->getMethod(MD->getSelector(),
+ /*isInstance=*/true);
+ if (!IFaceM)
+ continue;
+ if (hasSuperInitCall(MD)) {
+ edit::Commit commit(*Editor);
+ commit.insert(IFaceM->getLocEnd(), " NS_DESIGNATED_INITIALIZER");
+ Editor->commit(commit);
+ }
+ }
+}
+
+namespace {
class RewritesReceiver : public edit::EditsReceiver {
Rewriter &Rewrite;
@@ -1572,42 +1614,92 @@ class RewritesReceiver : public edit::EditsReceiver {
public:
RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { }
- virtual void insert(SourceLocation loc, StringRef text) {
+ void insert(SourceLocation loc, StringRef text) override {
Rewrite.InsertText(loc, text);
}
- virtual void replace(CharSourceRange range, StringRef text) {
+ void replace(CharSourceRange range, StringRef text) override {
Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text);
}
};
-}
+class JSONEditWriter : public edit::EditsReceiver {
+ SourceManager &SourceMgr;
+ llvm::raw_ostream &OS;
-static bool
-IsReallyASystemHeader(ASTContext &Ctx, const FileEntry *file, FileID FID) {
- bool Invalid = false;
- const SrcMgr::SLocEntry &SEntry =
- Ctx.getSourceManager().getSLocEntry(FID, &Invalid);
- if (!Invalid && SEntry.isFile()) {
- const SrcMgr::FileInfo &FI = SEntry.getFile();
- if (!FI.hasLineDirectives()) {
- if (FI.getFileCharacteristic() == SrcMgr::C_ExternCSystem)
- return true;
- if (FI.getFileCharacteristic() == SrcMgr::C_System) {
- // This file is in a system header directory. Continue with commiting change
- // only if it is a user specified system directory because user put a
- // .system_framework file in the framework directory.
- StringRef Directory(file->getDir()->getName());
- size_t Ix = Directory.rfind(".framework");
- if (Ix == StringRef::npos)
- return true;
- std::string PatchToSystemFramework = Directory.slice(0, Ix+sizeof(".framework"));
- PatchToSystemFramework += ".system_framework";
- if (!llvm::sys::fs::exists(PatchToSystemFramework.data()))
- return true;
- }
+public:
+ JSONEditWriter(SourceManager &SM, llvm::raw_ostream &OS)
+ : SourceMgr(SM), OS(OS) {
+ OS << "[\n";
+ }
+ ~JSONEditWriter() {
+ OS << "]\n";
+ }
+
+private:
+ struct EntryWriter {
+ SourceManager &SourceMgr;
+ llvm::raw_ostream &OS;
+
+ EntryWriter(SourceManager &SM, llvm::raw_ostream &OS)
+ : SourceMgr(SM), OS(OS) {
+ OS << " {\n";
+ }
+ ~EntryWriter() {
+ OS << " },\n";
}
+
+ void writeLoc(SourceLocation Loc) {
+ FileID FID;
+ unsigned Offset;
+ std::tie(FID, Offset) = SourceMgr.getDecomposedLoc(Loc);
+ assert(!FID.isInvalid());
+ SmallString<200> Path =
+ StringRef(SourceMgr.getFileEntryForID(FID)->getName());
+ llvm::sys::fs::make_absolute(Path);
+ OS << " \"file\": \"";
+ OS.write_escaped(Path.str()) << "\",\n";
+ OS << " \"offset\": " << Offset << ",\n";
+ }
+
+ void writeRemove(CharSourceRange Range) {
+ assert(Range.isCharRange());
+ std::pair<FileID, unsigned> Begin =
+ SourceMgr.getDecomposedLoc(Range.getBegin());
+ std::pair<FileID, unsigned> End =
+ SourceMgr.getDecomposedLoc(Range.getEnd());
+ assert(Begin.first == End.first);
+ assert(Begin.second <= End.second);
+ unsigned Length = End.second - Begin.second;
+
+ OS << " \"remove\": " << Length << ",\n";
+ }
+
+ void writeText(StringRef Text) {
+ OS << " \"text\": \"";
+ OS.write_escaped(Text) << "\",\n";
+ }
+ };
+
+ void insert(SourceLocation Loc, StringRef Text) override {
+ EntryWriter Writer(SourceMgr, OS);
+ Writer.writeLoc(Loc);
+ Writer.writeText(Text);
}
- return false;
+
+ void replace(CharSourceRange Range, StringRef Text) override {
+ EntryWriter Writer(SourceMgr, OS);
+ Writer.writeLoc(Range.getBegin());
+ Writer.writeRemove(Range);
+ Writer.writeText(Text);
+ }
+
+ void remove(CharSourceRange Range) override {
+ EntryWriter Writer(SourceMgr, OS);
+ Writer.writeLoc(Range.getBegin());
+ Writer.writeRemove(Range);
+ }
+};
+
}
void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
@@ -1624,22 +1716,25 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
}
if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D))
- migrateObjCInterfaceDecl(Ctx, CDecl);
+ if (canModify(CDecl))
+ migrateObjCInterfaceDecl(Ctx, CDecl);
if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(*D)) {
- migrateObjCInterfaceDecl(Ctx, CatDecl);
- if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
- migrateDeprecatedAnnotation(Ctx, CatDecl);
+ if (canModify(CatDecl))
+ migrateObjCInterfaceDecl(Ctx, CatDecl);
}
else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D))
- ObjCProtocolDecls.insert(PDecl);
+ ObjCProtocolDecls.insert(PDecl->getCanonicalDecl());
else if (const ObjCImplementationDecl *ImpDecl =
dyn_cast<ObjCImplementationDecl>(*D)) {
- if (ASTMigrateActions & FrontendOptions::ObjCMT_ProtocolConformance)
+ if ((ASTMigrateActions & FrontendOptions::ObjCMT_ProtocolConformance) &&
+ canModify(ImpDecl))
migrateProtocolConformance(Ctx, ImpDecl);
}
else if (const EnumDecl *ED = dyn_cast<EnumDecl>(*D)) {
if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros))
continue;
+ if (!canModify(ED))
+ continue;
DeclContext::decl_iterator N = D;
if (++N != DEnd) {
const TypedefDecl *TD = dyn_cast<TypedefDecl>(*N);
@@ -1647,11 +1742,13 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
D++;
}
else
- migrateNSEnumDecl(Ctx, ED, /*TypedefDecl */0);
+ migrateNSEnumDecl(Ctx, ED, /*TypedefDecl */nullptr);
}
else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(*D)) {
if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros))
continue;
+ if (!canModify(TD))
+ continue;
DeclContext::decl_iterator N = D;
if (++N == DEnd)
continue;
@@ -1673,23 +1770,49 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
CacheObjCNSIntegerTypedefed(TD);
}
else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D)) {
- if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
+ if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
+ canModify(FD))
migrateCFAnnotation(Ctx, FD);
}
if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D)) {
+ bool CanModify = canModify(CDecl);
// migrate methods which can have instancetype as their result type.
- if (ASTMigrateActions & FrontendOptions::ObjCMT_Instancetype)
+ if ((ASTMigrateActions & FrontendOptions::ObjCMT_Instancetype) &&
+ CanModify)
migrateAllMethodInstaceType(Ctx, CDecl);
// annotate methods with CF annotations.
- if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
+ if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
+ CanModify)
migrateARCSafeAnnotation(Ctx, CDecl);
}
+
+ if (const ObjCImplementationDecl *
+ ImplD = dyn_cast<ObjCImplementationDecl>(*D)) {
+ if ((ASTMigrateActions & FrontendOptions::ObjCMT_DesignatedInitializer) &&
+ canModify(ImplD))
+ inferDesignatedInitializers(Ctx, ImplD);
+ }
}
if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
AnnotateImplicitBridging(Ctx);
}
+ if (IsOutputFile) {
+ std::string Error;
+ llvm::raw_fd_ostream OS(MigrateDir.c_str(), Error, llvm::sys::fs::F_None);
+ if (!Error.empty()) {
+ DiagnosticsEngine &Diags = Ctx.getDiagnostics();
+ Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0"))
+ << Error;
+ return;
+ }
+
+ JSONEditWriter Writer(Ctx.getSourceManager(), OS);
+ Editor->applyRewrites(Writer);
+ return;
+ }
+
Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
RewritesReceiver Rec(rewriter);
Editor->applyRewrites(Rec);
@@ -1700,10 +1823,6 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
RewriteBuffer &buf = I->second;
const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
assert(file);
- if (IsReallyASystemHeader(Ctx, file, FID))
- continue;
- if (!canModifyFile(file->getName()))
- continue;
SmallString<512> newText;
llvm::raw_svector_ostream vecOS(newText);
buf.write(vecOS);
@@ -1734,8 +1853,8 @@ static std::vector<std::string> getWhiteListFilenames(StringRef DirPath) {
std::vector<std::string> Filenames;
if (DirPath.empty() || !is_directory(DirPath))
return Filenames;
-
- llvm::error_code EC;
+
+ std::error_code EC;
directory_iterator DI = directory_iterator(DirPath, EC);
directory_iterator DE;
for (; !EC && DI != DE; DI = DI.increment(EC)) {
@@ -1773,3 +1892,246 @@ ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI,
/*isOutputFile=*/true,
WhiteList);
}
+
+namespace {
+struct EditEntry {
+ const FileEntry *File;
+ unsigned Offset;
+ unsigned RemoveLen;
+ std::string Text;
+
+ EditEntry() : File(), Offset(), RemoveLen() {}
+};
+}
+
+namespace llvm {
+template<> struct DenseMapInfo<EditEntry> {
+ static inline EditEntry getEmptyKey() {
+ EditEntry Entry;
+ Entry.Offset = unsigned(-1);
+ return Entry;
+ }
+ static inline EditEntry getTombstoneKey() {
+ EditEntry Entry;
+ Entry.Offset = unsigned(-2);
+ return Entry;
+ }
+ static unsigned getHashValue(const EditEntry& Val) {
+ llvm::FoldingSetNodeID ID;
+ ID.AddPointer(Val.File);
+ ID.AddInteger(Val.Offset);
+ ID.AddInteger(Val.RemoveLen);
+ ID.AddString(Val.Text);
+ return ID.ComputeHash();
+ }
+ static bool isEqual(const EditEntry &LHS, const EditEntry &RHS) {
+ return LHS.File == RHS.File &&
+ LHS.Offset == RHS.Offset &&
+ LHS.RemoveLen == RHS.RemoveLen &&
+ LHS.Text == RHS.Text;
+ }
+};
+}
+
+namespace {
+class RemapFileParser {
+ FileManager &FileMgr;
+
+public:
+ RemapFileParser(FileManager &FileMgr) : FileMgr(FileMgr) { }
+
+ bool parse(StringRef File, SmallVectorImpl<EditEntry> &Entries) {
+ using namespace llvm::yaml;
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr =
+ llvm::MemoryBuffer::getFile(File);
+ if (!FileBufOrErr)
+ return true;
+
+ llvm::SourceMgr SM;
+ Stream YAMLStream(FileBufOrErr.get().release(), SM);
+ document_iterator I = YAMLStream.begin();
+ if (I == YAMLStream.end())
+ return true;
+ Node *Root = I->getRoot();
+ if (!Root)
+ return true;
+
+ SequenceNode *SeqNode = dyn_cast<SequenceNode>(Root);
+ if (!SeqNode)
+ return true;
+
+ for (SequenceNode::iterator
+ AI = SeqNode->begin(), AE = SeqNode->end(); AI != AE; ++AI) {
+ MappingNode *MapNode = dyn_cast<MappingNode>(&*AI);
+ if (!MapNode)
+ continue;
+ parseEdit(MapNode, Entries);
+ }
+
+ return false;
+ }
+
+private:
+ void parseEdit(llvm::yaml::MappingNode *Node,
+ SmallVectorImpl<EditEntry> &Entries) {
+ using namespace llvm::yaml;
+ EditEntry Entry;
+ bool Ignore = false;
+
+ for (MappingNode::iterator
+ KVI = Node->begin(), KVE = Node->end(); KVI != KVE; ++KVI) {
+ ScalarNode *KeyString = dyn_cast<ScalarNode>((*KVI).getKey());
+ if (!KeyString)
+ continue;
+ SmallString<10> KeyStorage;
+ StringRef Key = KeyString->getValue(KeyStorage);
+
+ ScalarNode *ValueString = dyn_cast<ScalarNode>((*KVI).getValue());
+ if (!ValueString)
+ continue;
+ SmallString<64> ValueStorage;
+ StringRef Val = ValueString->getValue(ValueStorage);
+
+ if (Key == "file") {
+ const FileEntry *FE = FileMgr.getFile(Val);
+ if (!FE)
+ Ignore = true;
+ Entry.File = FE;
+ } else if (Key == "offset") {
+ if (Val.getAsInteger(10, Entry.Offset))
+ Ignore = true;
+ } else if (Key == "remove") {
+ if (Val.getAsInteger(10, Entry.RemoveLen))
+ Ignore = true;
+ } else if (Key == "text") {
+ Entry.Text = Val;
+ }
+ }
+
+ if (!Ignore)
+ Entries.push_back(Entry);
+ }
+};
+}
+
+static bool reportDiag(const Twine &Err, DiagnosticsEngine &Diag) {
+ Diag.Report(Diag.getCustomDiagID(DiagnosticsEngine::Error, "%0"))
+ << Err.str();
+ return true;
+}
+
+static std::string applyEditsToTemp(const FileEntry *FE,
+ ArrayRef<EditEntry> Edits,
+ FileManager &FileMgr,
+ DiagnosticsEngine &Diag) {
+ using namespace llvm::sys;
+
+ SourceManager SM(Diag, FileMgr);
+ FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);
+ LangOptions LangOpts;
+ edit::EditedSource Editor(SM, LangOpts);
+ for (ArrayRef<EditEntry>::iterator
+ I = Edits.begin(), E = Edits.end(); I != E; ++I) {
+ const EditEntry &Entry = *I;
+ assert(Entry.File == FE);
+ SourceLocation Loc =
+ SM.getLocForStartOfFile(FID).getLocWithOffset(Entry.Offset);
+ CharSourceRange Range;
+ if (Entry.RemoveLen != 0) {
+ Range = CharSourceRange::getCharRange(Loc,
+ Loc.getLocWithOffset(Entry.RemoveLen));
+ }
+
+ edit::Commit commit(Editor);
+ if (Range.isInvalid()) {
+ commit.insert(Loc, Entry.Text);
+ } else if (Entry.Text.empty()) {
+ commit.remove(Range);
+ } else {
+ commit.replace(Range, Entry.Text);
+ }
+ Editor.commit(commit);
+ }
+
+ Rewriter rewriter(SM, LangOpts);
+ RewritesReceiver Rec(rewriter);
+ Editor.applyRewrites(Rec);
+
+ const RewriteBuffer *Buf = rewriter.getRewriteBufferFor(FID);
+ SmallString<512> NewText;
+ llvm::raw_svector_ostream OS(NewText);
+ Buf->write(OS);
+ OS.flush();
+
+ SmallString<64> TempPath;
+ int FD;
+ if (fs::createTemporaryFile(path::filename(FE->getName()),
+ path::extension(FE->getName()), FD,
+ TempPath)) {
+ reportDiag("Could not create file: " + TempPath.str(), Diag);
+ return std::string();
+ }
+
+ llvm::raw_fd_ostream TmpOut(FD, /*shouldClose=*/true);
+ TmpOut.write(NewText.data(), NewText.size());
+ TmpOut.close();
+
+ return TempPath.str();
+}
+
+bool arcmt::getFileRemappingsFromFileList(
+ std::vector<std::pair<std::string,std::string> > &remap,
+ ArrayRef<StringRef> remapFiles,
+ DiagnosticConsumer *DiagClient) {
+ bool hasErrorOccurred = false;
+
+ FileSystemOptions FSOpts;
+ FileManager FileMgr(FSOpts);
+ RemapFileParser Parser(FileMgr);
+
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, new DiagnosticOptions,
+ DiagClient, /*ShouldOwnClient=*/false));
+
+ typedef llvm::DenseMap<const FileEntry *, std::vector<EditEntry> >
+ FileEditEntriesTy;
+ FileEditEntriesTy FileEditEntries;
+
+ llvm::DenseSet<EditEntry> EntriesSet;
+
+ for (ArrayRef<StringRef>::iterator
+ I = remapFiles.begin(), E = remapFiles.end(); I != E; ++I) {
+ SmallVector<EditEntry, 16> Entries;
+ if (Parser.parse(*I, Entries))
+ continue;
+
+ for (SmallVectorImpl<EditEntry>::iterator
+ EI = Entries.begin(), EE = Entries.end(); EI != EE; ++EI) {
+ EditEntry &Entry = *EI;
+ if (!Entry.File)
+ continue;
+ std::pair<llvm::DenseSet<EditEntry>::iterator, bool>
+ Insert = EntriesSet.insert(Entry);
+ if (!Insert.second)
+ continue;
+
+ FileEditEntries[Entry.File].push_back(Entry);
+ }
+ }
+
+ for (FileEditEntriesTy::iterator
+ I = FileEditEntries.begin(), E = FileEditEntries.end(); I != E; ++I) {
+ std::string TempFile = applyEditsToTemp(I->first, I->second,
+ FileMgr, *Diags);
+ if (TempFile.empty()) {
+ hasErrorOccurred = true;
+ continue;
+ }
+
+ remap.push_back(std::make_pair(I->first->getName(), TempFile));
+ }
+
+ return hasErrorOccurred;
+}
diff --git a/lib/ARCMigrate/PlistReporter.cpp b/lib/ARCMigrate/PlistReporter.cpp
index 144ba2e398ad..6b34ef0c2b9e 100644
--- a/lib/ARCMigrate/PlistReporter.cpp
+++ b/lib/ARCMigrate/PlistReporter.cpp
@@ -9,86 +9,27 @@
#include "Internals.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/PlistSupport.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
using namespace clang;
using namespace arcmt;
-
-// FIXME: This duplicates significant functionality from PlistDiagnostics.cpp,
-// it would be jolly good if there was a reusable PlistWriter or something.
-
-typedef llvm::DenseMap<FileID, unsigned> FIDMap;
-
-static void AddFID(FIDMap &FIDs, SmallVectorImpl<FileID> &V,
- const SourceManager &SM, SourceLocation L) {
-
- FileID FID = SM.getFileID(SM.getExpansionLoc(L));
- FIDMap::iterator I = FIDs.find(FID);
- if (I != FIDs.end()) return;
- FIDs[FID] = V.size();
- V.push_back(FID);
-}
-
-static unsigned GetFID(const FIDMap& FIDs, const SourceManager &SM,
- SourceLocation L) {
- FileID FID = SM.getFileID(SM.getExpansionLoc(L));
- FIDMap::const_iterator I = FIDs.find(FID);
- assert(I != FIDs.end());
- return I->second;
-}
-
-static raw_ostream& Indent(raw_ostream& o, const unsigned indent) {
- for (unsigned i = 0; i < indent; ++i) o << ' ';
- return o;
-}
-
-static void EmitLocation(raw_ostream& o, const SourceManager &SM,
- const LangOptions &LangOpts,
- SourceLocation L, const FIDMap &FM,
- unsigned indent, bool extend = false) {
-
- FullSourceLoc Loc(SM.getExpansionLoc(L), const_cast<SourceManager&>(SM));
-
- // Add in the length of the token, so that we cover multi-char tokens.
- unsigned offset =
- extend ? Lexer::MeasureTokenLength(Loc, SM, LangOpts) - 1 : 0;
-
- Indent(o, indent) << "<dict>\n";
- Indent(o, indent) << " <key>line</key><integer>"
- << Loc.getExpansionLineNumber() << "</integer>\n";
- Indent(o, indent) << " <key>col</key><integer>"
- << Loc.getExpansionColumnNumber() + offset << "</integer>\n";
- Indent(o, indent) << " <key>file</key><integer>"
- << GetFID(FM, SM, Loc) << "</integer>\n";
- Indent(o, indent) << "</dict>\n";
-}
-
-static void EmitRange(raw_ostream& o, const SourceManager &SM,
- const LangOptions &LangOpts,
- CharSourceRange R, const FIDMap &FM,
- unsigned indent) {
- Indent(o, indent) << "<array>\n";
- EmitLocation(o, SM, LangOpts, R.getBegin(), FM, indent+1);
- EmitLocation(o, SM, LangOpts, R.getEnd(), FM, indent+1, R.isTokenRange());
- Indent(o, indent) << "</array>\n";
-}
-
-static raw_ostream& EmitString(raw_ostream& o,
- StringRef s) {
- o << "<string>";
- for (StringRef::const_iterator I=s.begin(), E=s.end(); I!=E; ++I) {
- char c = *I;
- switch (c) {
- default: o << c; break;
- case '&': o << "&amp;"; break;
- case '<': o << "&lt;"; break;
- case '>': o << "&gt;"; break;
- case '\'': o << "&apos;"; break;
- case '\"': o << "&quot;"; break;
- }
+using namespace markup;
+
+static StringRef getLevelName(DiagnosticsEngine::Level Level) {
+ switch (Level) {
+ case DiagnosticsEngine::Ignored:
+ llvm_unreachable("ignored");
+ case DiagnosticsEngine::Note:
+ return "note";
+ case DiagnosticsEngine::Remark:
+ case DiagnosticsEngine::Warning:
+ return "warning";
+ case DiagnosticsEngine::Fatal:
+ case DiagnosticsEngine::Error:
+ return "error";
}
- o << "</string>";
- return o;
+ llvm_unreachable("Invalid DiagnosticsEngine level!");
}
void arcmt::writeARCDiagsToPlist(const std::string &outPath,
@@ -116,17 +57,13 @@ void arcmt::writeARCDiagsToPlist(const std::string &outPath,
}
std::string errMsg;
- llvm::raw_fd_ostream o(outPath.c_str(), errMsg);
+ llvm::raw_fd_ostream o(outPath.c_str(), errMsg, llvm::sys::fs::F_Text);
if (!errMsg.empty()) {
llvm::errs() << "error: could not create file: " << outPath << '\n';
return;
}
- // Write the plist header.
- o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
- "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
- "<plist version=\"1.0\">\n";
+ EmitPlistHeader(o);
// Write the root object: a <dict> containing...
// - "files", an <array> mapping from FIDs to file names
@@ -135,11 +72,8 @@ void arcmt::writeARCDiagsToPlist(const std::string &outPath,
" <key>files</key>\n"
" <array>\n";
- for (SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end();
- I!=E; ++I) {
- o << " ";
- EmitString(o, SM.getFileEntryForID(*I)->getName()) << '\n';
- }
+ for (FileID FID : Fids)
+ EmitString(o << " ", SM.getFileEntryForID(FID)->getName()) << '\n';
o << " </array>\n"
" <key>diagnostics</key>\n"
@@ -162,12 +96,7 @@ void arcmt::writeARCDiagsToPlist(const std::string &outPath,
EmitString(o, DiagIDs.getCategoryNameFromID(
DiagIDs.getCategoryNumberForDiag(D.getID()))) << '\n';
o << " <key>type</key>";
- if (D.getLevel() >= DiagnosticsEngine::Error)
- EmitString(o, "error") << '\n';
- else if (D.getLevel() == DiagnosticsEngine::Warning)
- EmitString(o, "warning") << '\n';
- else
- EmitString(o, "note") << '\n';
+ EmitString(o, getLevelName(D.getLevel())) << '\n';
// Output the location of the bug.
o << " <key>location</key>\n";
diff --git a/lib/ARCMigrate/TransAPIUses.cpp b/lib/ARCMigrate/TransAPIUses.cpp
index a0994a6b459a..544cb0addfcd 100644
--- a/lib/ARCMigrate/TransAPIUses.cpp
+++ b/lib/ARCMigrate/TransAPIUses.cpp
@@ -66,8 +66,7 @@ public:
selName = "getArgument";
else if (E->getSelector() == setArgumentSel)
selName = "setArgument";
-
- if (selName.empty())
+ else
return true;
Expr *parm = E->getArg(0)->IgnoreParenCasts();
@@ -75,13 +74,12 @@ public:
if (pointee.isNull())
return true;
- if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone) {
- std::string err = "NSInvocation's ";
- err += selName;
- err += " is not safe to be used with an object with ownership other "
- "than __unsafe_unretained";
- Pass.TA.reportError(err, parm->getLocStart(), parm->getSourceRange());
- }
+ if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone)
+ Pass.TA.report(parm->getLocStart(),
+ diag::err_arcmt_nsinvocation_ownership,
+ parm->getSourceRange())
+ << selName;
+
return true;
}
diff --git a/lib/ARCMigrate/TransAutoreleasePool.cpp b/lib/ARCMigrate/TransAutoreleasePool.cpp
index a2990e7226ab..a8a99fa712a3 100644
--- a/lib/ARCMigrate/TransAutoreleasePool.cpp
+++ b/lib/ARCMigrate/TransAutoreleasePool.cpp
@@ -70,7 +70,7 @@ class AutoreleasePoolRewriter
: public RecursiveASTVisitor<AutoreleasePoolRewriter> {
public:
AutoreleasePoolRewriter(MigrationPass &pass)
- : Body(0), Pass(pass) {
+ : Body(nullptr), Pass(pass) {
PoolII = &pass.Ctx.Idents.get("NSAutoreleasePool");
DrainSel = pass.Ctx.Selectors.getNullarySelector(
&pass.Ctx.Idents.get("drain"));
@@ -230,7 +230,7 @@ private:
bool IsFollowedBySimpleReturnStmt;
SmallVector<ObjCMessageExpr *, 4> Releases;
- PoolScope() : PoolVar(0), CompoundParent(0), Begin(), End(),
+ PoolScope() : PoolVar(nullptr), CompoundParent(nullptr), Begin(), End(),
IsFollowedBySimpleReturnStmt(false) { }
SourceRange getIndentedRange() const {
@@ -305,7 +305,7 @@ private:
// 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 ||
+ if ((retS->getRetValue() == nullptr ||
isa<DeclRefExpr>(retS->getRetValue()->IgnoreParenCasts())) &&
findLocationAfterSemi(retS->getLocEnd(), Pass.Ctx).isValid()) {
scope.IsFollowedBySimpleReturnStmt = true;
@@ -421,7 +421,7 @@ private:
ExprSet Refs;
SmallVector<PoolScope, 2> Scopes;
- PoolVarInfo() : Dcl(0) { }
+ PoolVarInfo() : Dcl(nullptr) { }
};
std::map<VarDecl *, PoolVarInfo> PoolVars;
diff --git a/lib/ARCMigrate/TransBlockObjCVariable.cpp b/lib/ARCMigrate/TransBlockObjCVariable.cpp
index 97c4e3480c15..fac6a84c45e5 100644
--- a/lib/ARCMigrate/TransBlockObjCVariable.cpp
+++ b/lib/ARCMigrate/TransBlockObjCVariable.cpp
@@ -78,10 +78,9 @@ public:
bool VisitBlockDecl(BlockDecl *block) {
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() &&
+ for (const auto &I : block->captures()) {
+ VarDecl *var = I.getVariable();
+ if (I.isByRef() &&
var->getType()->isObjCObjectPointerType() &&
isImplicitStrong(var->getType())) {
BlockVars.push_back(var);
diff --git a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
index ffb638f8a306..9689f40760cd 100644
--- a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
+++ b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
@@ -89,9 +89,8 @@ public:
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))
+ for (auto *I : S->body())
+ if (!Visit(I))
return false;
return true;
}
@@ -167,9 +166,8 @@ public:
}
bool VisitCompoundStmt(CompoundStmt *S) {
- for (CompoundStmt::body_iterator
- I = S->body_begin(), E = S->body_end(); I != E; ++I)
- check(*I);
+ for (auto *I : S->body())
+ check(I);
return true;
}
@@ -189,9 +187,8 @@ private:
static bool isBodyEmpty(CompoundStmt *body, ASTContext &Ctx,
std::vector<SourceLocation> &MacroLocs) {
- for (CompoundStmt::body_iterator
- I = body->body_begin(), E = body->body_end(); I != E; ++I)
- if (!EmptyChecker(Ctx, MacroLocs).Visit(*I))
+ for (auto *I : body->body())
+ if (!EmptyChecker(Ctx, MacroLocs).Visit(I))
return false;
return true;
@@ -208,12 +205,9 @@ static void cleanupDeallocOrFinalize(MigrationPass &pass) {
impl_iterator;
for (impl_iterator I = impl_iterator(DC->decls_begin()),
E = impl_iterator(DC->decls_end()); I != E; ++I) {
- ObjCMethodDecl *DeallocM = 0;
- ObjCMethodDecl *FinalizeM = 0;
- for (ObjCImplementationDecl::instmeth_iterator
- MI = I->instmeth_begin(),
- ME = I->instmeth_end(); MI != ME; ++MI) {
- ObjCMethodDecl *MD = *MI;
+ ObjCMethodDecl *DeallocM = nullptr;
+ ObjCMethodDecl *FinalizeM = nullptr;
+ for (auto *MD : I->instance_methods()) {
if (!MD->hasBody())
continue;
diff --git a/lib/ARCMigrate/TransGCAttrs.cpp b/lib/ARCMigrate/TransGCAttrs.cpp
index d8be1ae746ab..10fce19b6f19 100644
--- a/lib/ARCMigrate/TransGCAttrs.cpp
+++ b/lib/ARCMigrate/TransGCAttrs.cpp
@@ -80,7 +80,7 @@ public:
}
}
- bool handleAttr(AttributedTypeLoc TL, Decl *D = 0) {
+ bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {
if (TL.getAttrKind() != AttributedType::attr_objc_ownership)
return false;
@@ -134,8 +134,7 @@ public:
return hasObjCImpl(ContD);
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
- for (CXXRecordDecl::method_iterator
- MI = RD->method_begin(), ME = RD->method_end(); MI != ME; ++MI) {
+ for (const auto *MI : RD->methods()) {
if (MI->isOutOfLine())
return true;
}
@@ -150,9 +149,9 @@ public:
return false;
if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
- return ID->getImplementation() != 0;
+ return ID->getImplementation() != nullptr;
if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
- return CD->getImplementation() != 0;
+ return CD->getImplementation() != nullptr;
if (isa<ObjCImplDecl>(ContD))
return true;
return false;
@@ -164,8 +163,7 @@ public:
if (!D)
return false;
- for (Decl::redecl_iterator
- I = D->redecls_begin(), E = D->redecls_end(); I != E; ++I)
+ for (auto I : D->redecls())
if (!isInMainFile(I->getLocation()))
return false;
diff --git a/lib/ARCMigrate/TransGCCalls.cpp b/lib/ARCMigrate/TransGCCalls.cpp
index 249f20f01b22..3a236d34cd4b 100644
--- a/lib/ARCMigrate/TransGCCalls.cpp
+++ b/lib/ARCMigrate/TransGCCalls.cpp
@@ -38,14 +38,8 @@ public:
TransformActions &TA = MigrateCtx.Pass.TA;
if (MigrateCtx.isGCOwnedNonObjC(E->getType())) {
- if (MigrateCtx.Pass.noNSAllocReallocError())
- TA.reportWarning("call returns pointer to GC managed memory; "
- "it will become unmanaged in ARC",
- E->getLocStart(), E->getSourceRange());
- else
- TA.reportError("call returns pointer to GC managed memory; "
- "it will become unmanaged in ARC",
- E->getLocStart(), E->getSourceRange());
+ TA.report(E->getLocStart(), diag::warn_arcmt_nsalloc_realloc,
+ E->getSourceRange());
return true;
}
diff --git a/lib/ARCMigrate/TransProperties.cpp b/lib/ARCMigrate/TransProperties.cpp
index b6ddc43dd69f..ab128844b45f 100644
--- a/lib/ARCMigrate/TransProperties.cpp
+++ b/lib/ARCMigrate/TransProperties.cpp
@@ -61,7 +61,8 @@ class PropertiesRewriter {
ObjCIvarDecl *IvarD;
ObjCPropertyImplDecl *ImplD;
- PropData(ObjCPropertyDecl *propD) : PropD(propD), IvarD(0), ImplD(0) { }
+ PropData(ObjCPropertyDecl *propD)
+ : PropD(propD), IvarD(nullptr), ImplD(nullptr) {}
};
typedef SmallVector<PropData, 2> PropsTy;
@@ -74,18 +75,16 @@ public:
: MigrateCtx(MigrateCtx), Pass(MigrateCtx.Pass) { }
static void collectProperties(ObjCContainerDecl *D, AtPropDeclsTy &AtProps,
- AtPropDeclsTy *PrevAtProps = 0) {
- for (ObjCInterfaceDecl::prop_iterator
- propI = D->prop_begin(),
- propE = D->prop_end(); propI != propE; ++propI) {
- if (propI->getAtLoc().isInvalid())
+ AtPropDeclsTy *PrevAtProps = nullptr) {
+ for (auto *Prop : D->properties()) {
+ if (Prop->getAtLoc().isInvalid())
continue;
- unsigned RawLoc = propI->getAtLoc().getRawEncoding();
+ unsigned RawLoc = Prop->getAtLoc().getRawEncoding();
if (PrevAtProps)
if (PrevAtProps->find(RawLoc) != PrevAtProps->end())
continue;
PropsTy &props = AtProps[RawLoc];
- props.push_back(*propI);
+ props.push_back(Prop);
}
}
@@ -141,12 +140,8 @@ public:
AtPropDeclsTy AtExtProps;
// Look through extensions.
- for (ObjCInterfaceDecl::visible_extensions_iterator
- ext = iface->visible_extensions_begin(),
- extEnd = iface->visible_extensions_end();
- ext != extEnd; ++ext) {
- collectProperties(*ext, AtExtProps, &AtProps);
- }
+ for (auto *Ext : iface->visible_extensions())
+ collectProperties(Ext, AtExtProps, &AtProps);
for (AtPropDeclsTy::iterator
I = AtExtProps.begin(), E = AtExtProps.end(); I != E; ++I) {
@@ -353,14 +348,6 @@ private:
return false;
}
- bool hasAllIvarsBacked(PropsTy &props) const {
- for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
- if (!isUserDeclared(I->IvarD))
- return false;
-
- return true;
- }
-
// \brief Returns true if all declarations in the @property have GC __weak.
bool hasGCWeak(PropsTy &props, SourceLocation atLoc) const {
if (!Pass.isGCMigration())
diff --git a/lib/ARCMigrate/TransProtectedScope.cpp b/lib/ARCMigrate/TransProtectedScope.cpp
index 237aa42877e6..0fcbcbedfe04 100644
--- a/lib/ARCMigrate/TransProtectedScope.cpp
+++ b/lib/ARCMigrate/TransProtectedScope.cpp
@@ -47,7 +47,7 @@ struct CaseInfo {
St_Fixed
} State;
- CaseInfo() : SC(0), State(St_Unchecked) {}
+ CaseInfo() : SC(nullptr), State(St_Unchecked) {}
CaseInfo(SwitchCase *S, SourceRange Range)
: SC(S), Range(Range), State(St_Unchecked) {}
};
diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
index 446a284a286f..bcbc9e9612ba 100644
--- a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
+++ b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
@@ -38,13 +38,13 @@ class RetainReleaseDeallocRemover :
MigrationPass &Pass;
ExprSet Removables;
- OwningPtr<ParentMap> StmtMap;
+ std::unique_ptr<ParentMap> StmtMap;
Selector DelegateSel, FinalizeSel;
public:
RetainReleaseDeallocRemover(MigrationPass &pass)
- : Body(0), Pass(pass) {
+ : Body(nullptr), Pass(pass) {
DelegateSel =
Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("delegate"));
FinalizeSel =
@@ -70,7 +70,7 @@ public:
// 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.
+ // and emit an error to force the user to restructure their code.
Pass.TA.reportError("it is not safe to remove an unused 'autorelease' "
"message; its receiver may be destroyed immediately",
E->getLocStart(), E->getSourceRange());
@@ -212,7 +212,7 @@ private:
return false;
Stmt *prevStmt, *nextStmt;
- llvm::tie(prevStmt, nextStmt) = getPreviousAndNextStmt(E);
+ std::tie(prevStmt, nextStmt) = getPreviousAndNextStmt(E);
return isPlusOneAssignToVar(prevStmt, RefD) ||
isPlusOneAssignToVar(nextStmt, RefD);
@@ -248,7 +248,7 @@ private:
}
std::pair<Stmt *, Stmt *> getPreviousAndNextStmt(Expr *E) {
- Stmt *prevStmt = 0, *nextStmt = 0;
+ Stmt *prevStmt = nullptr, *nextStmt = nullptr;
if (!E)
return std::make_pair(prevStmt, nextStmt);
@@ -294,7 +294,7 @@ private:
Decl *getReferencedDecl(Expr *E) {
if (!E)
- return 0;
+ return nullptr;
E = E->IgnoreParenCasts();
if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
@@ -305,7 +305,7 @@ private:
case OMF_retain:
return getReferencedDecl(ME->getInstanceReceiver());
default:
- return 0;
+ return nullptr;
}
}
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
@@ -315,7 +315,7 @@ private:
if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(E))
return IRE->getDecl();
- return 0;
+ return nullptr;
}
/// \brief Check if the retain/release is due to a GCD/XPC macro that are
@@ -345,7 +345,7 @@ private:
if (!isGCDOrXPC)
return;
- StmtExpr *StmtE = 0;
+ StmtExpr *StmtE = nullptr;
Stmt *S = Msg;
while (S) {
if (StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp
index 7b360c640cfd..7ca49558a7f0 100644
--- a/lib/ARCMigrate/TransUnbridgedCasts.cpp
+++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp
@@ -60,13 +60,14 @@ namespace {
class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
MigrationPass &Pass;
IdentifierInfo *SelfII;
- OwningPtr<ParentMap> StmtMap;
+ std::unique_ptr<ParentMap> StmtMap;
Decl *ParentD;
Stmt *Body;
- mutable OwningPtr<ExprSet> Removables;
+ mutable std::unique_ptr<ExprSet> Removables;
public:
- UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0), Body(0) {
+ UnbridgedCastRewriter(MigrationPass &pass)
+ : Pass(pass), ParentD(nullptr), Body(nullptr) {
SelfII = &Pass.Ctx.Idents.get("self");
}
@@ -133,11 +134,11 @@ private:
Expr *inner = E->IgnoreParenCasts();
if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
if (FunctionDecl *FD = callE->getDirectCallee()) {
- if (FD->getAttr<CFReturnsRetainedAttr>()) {
+ if (FD->hasAttr<CFReturnsRetainedAttr>()) {
castToObjCObject(E, /*retained=*/true);
return;
}
- if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
+ if (FD->hasAttr<CFReturnsNotRetainedAttr>()) {
castToObjCObject(E, /*retained=*/false);
return;
}
@@ -283,7 +284,7 @@ private:
SourceLocation Loc = E->getExprLoc();
assert(Loc.isMacroID());
SourceLocation MacroBegin, MacroEnd;
- llvm::tie(MacroBegin, MacroEnd) = SM.getImmediateExpansionRange(Loc);
+ std::tie(MacroBegin, MacroEnd) = SM.getImmediateExpansionRange(Loc);
SourceRange SubRange = E->getSubExpr()->IgnoreParenImpCasts()->getSourceRange();
SourceLocation InnerBegin = SM.getImmediateMacroCallerLoc(SubRange.getBegin());
SourceLocation InnerEnd = SM.getImmediateMacroCallerLoc(SubRange.getEnd());
@@ -439,7 +440,7 @@ private:
}
if (i < callE->getNumArgs() && i < FD->getNumParams()) {
ParmVarDecl *PD = FD->getParamDecl(i);
- if (PD->getAttr<CFConsumedAttr>()) {
+ if (PD->hasAttr<CFConsumedAttr>()) {
isConsumed = true;
return true;
}
diff --git a/lib/ARCMigrate/TransUnusedInitDelegate.cpp b/lib/ARCMigrate/TransUnusedInitDelegate.cpp
index e316c73fc3cd..98571c035dd5 100644
--- a/lib/ARCMigrate/TransUnusedInitDelegate.cpp
+++ b/lib/ARCMigrate/TransUnusedInitDelegate.cpp
@@ -39,7 +39,7 @@ class UnusedInitRewriter : public RecursiveASTVisitor<UnusedInitRewriter> {
public:
UnusedInitRewriter(MigrationPass &pass)
- : Body(0), Pass(pass) { }
+ : Body(nullptr), Pass(pass) { }
void transformBody(Stmt *body, Decl *ParentD) {
Body = body;
diff --git a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
index 4d088e05bfab..76ce0ec90db3 100644
--- a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
+++ b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
@@ -35,7 +35,7 @@ class ZeroOutInDeallocRemover :
Selector FinalizeSel;
public:
- ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(0) {
+ ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(nullptr) {
FinalizeSel =
Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize"));
}
@@ -113,23 +113,21 @@ public:
// 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;
- }
+ for (auto *PID : IMD->property_impls()) {
+ 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.
@@ -137,7 +135,7 @@ public:
// clear out for next method.
SynthesizedProperties.clear();
- SelfD = 0;
+ SelfD = nullptr;
Removables.clear();
return true;
}
diff --git a/lib/ARCMigrate/TransformActions.cpp b/lib/ARCMigrate/TransformActions.cpp
index 2fd0619df9f8..6d178bea0907 100644
--- a/lib/ARCMigrate/TransformActions.cpp
+++ b/lib/ARCMigrate/TransformActions.cpp
@@ -601,7 +601,7 @@ TransformActions::RewriteReceiver::~RewriteReceiver() { }
TransformActions::TransformActions(DiagnosticsEngine &diag,
CapturedDiagList &capturedDiags,
ASTContext &ctx, Preprocessor &PP)
- : Diags(diag), CapturedDiags(capturedDiags), ReportedErrors(false) {
+ : Diags(diag), CapturedDiags(capturedDiags) {
Impl = new TransformActionsImpl(capturedDiags, ctx, PP);
}
@@ -673,60 +673,24 @@ void TransformActions::applyRewrites(RewriteReceiver &receiver) {
static_cast<TransformActionsImpl*>(Impl)->applyRewrites(receiver);
}
-void TransformActions::reportError(StringRef error, SourceLocation loc,
- SourceRange range) {
- assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() &&
+DiagnosticBuilder TransformActions::report(SourceLocation loc, unsigned diagId,
+ SourceRange range) {
+ assert(!static_cast<TransformActionsImpl *>(Impl)->isInTransaction() &&
"Errors should be emitted out of a transaction");
-
- SourceManager &SM = static_cast<TransformActionsImpl*>(Impl)->
- getASTContext().getSourceManager();
- if (SM.isInSystemHeader(SM.getExpansionLoc(loc)))
- return;
-
- // 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;
- ReportedErrors = true;
+ return Diags.Report(loc, diagId) << range;
}
-void TransformActions::reportWarning(StringRef warning, SourceLocation loc,
+void TransformActions::reportError(StringRef message, SourceLocation loc,
SourceRange range) {
- assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() &&
- "Warning should be emitted out of a transaction");
-
- SourceManager &SM = static_cast<TransformActionsImpl*>(Impl)->
- getASTContext().getSourceManager();
- if (SM.isInSystemHeader(SM.getExpansionLoc(loc)))
- return;
-
- // FIXME: Use a custom category name to distinguish rewriter errors.
- std::string rewriterWarn = "[rewriter] ";
- rewriterWarn += warning;
- unsigned diagID
- = Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Warning,
- rewriterWarn);
- Diags.Report(loc, diagID) << range;
+ report(loc, diag::err_mt_message, range) << message;
}
-void TransformActions::reportNote(StringRef note, SourceLocation loc,
- SourceRange range) {
- assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() &&
- "Errors should be emitted out of a transaction");
-
- SourceManager &SM = static_cast<TransformActionsImpl*>(Impl)->
- getASTContext().getSourceManager();
- if (SM.isInSystemHeader(SM.getExpansionLoc(loc)))
- return;
+void TransformActions::reportWarning(StringRef message, SourceLocation loc,
+ SourceRange range) {
+ report(loc, diag::warn_mt_message, range) << message;
+}
- // 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;
+void TransformActions::reportNote(StringRef message, SourceLocation loc,
+ SourceRange range) {
+ report(loc, diag::note_mt_message, range) << message;
}
diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp
index 679b924ba009..6ff7b6b9db87 100644
--- a/lib/ARCMigrate/Transforms.cpp
+++ b/lib/ARCMigrate/Transforms.cpp
@@ -88,7 +88,7 @@ bool trans::isPlusOne(const Expr *E) {
if (const CallExpr *
callE = dyn_cast<CallExpr>(E->IgnoreParenCasts())) {
if (const FunctionDecl *FD = callE->getDirectCallee()) {
- if (FD->getAttr<CFReturnsRetainedAttr>())
+ if (FD->hasAttr<CFReturnsRetainedAttr>())
return true;
if (FD->isGlobal() &&
@@ -264,9 +264,8 @@ public:
}
bool VisitCompoundStmt(CompoundStmt *S) {
- for (CompoundStmt::body_iterator
- I = S->body_begin(), E = S->body_end(); I != E; ++I)
- mark(*I);
+ for (auto *I : S->body())
+ mark(I);
return true;
}
@@ -414,8 +413,7 @@ bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr,
if (tok.isNot(tok::at)) return false;
lexer.LexFromRawLexer(tok);
if (tok.isNot(tok::raw_identifier)) return false;
- if (StringRef(tok.getRawIdentifierData(), tok.getLength())
- != "property")
+ if (tok.getRawIdentifier() != "property")
return false;
lexer.LexFromRawLexer(tok);
if (tok.isNot(tok::l_paren)) return false;
@@ -431,8 +429,7 @@ bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr,
while (1) {
if (tok.isNot(tok::raw_identifier)) return false;
- StringRef ident(tok.getRawIdentifierData(), tok.getLength());
- if (ident == fromAttr) {
+ if (tok.getRawIdentifier() == fromAttr) {
if (!toAttr.empty()) {
Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr);
return true;
@@ -497,8 +494,7 @@ bool MigrationContext::addPropertyAttribute(StringRef attr,
if (tok.isNot(tok::at)) return false;
lexer.LexFromRawLexer(tok);
if (tok.isNot(tok::raw_identifier)) return false;
- if (StringRef(tok.getRawIdentifierData(), tok.getLength())
- != "property")
+ if (tok.getRawIdentifier() != "property")
return false;
lexer.LexFromRawLexer(tok);
@@ -538,15 +534,12 @@ static void GCRewriteFinalize(MigrationPass &pass) {
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;
+ for (const auto *MD : I->instance_methods()) {
if (!MD->hasBody())
continue;
if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {
- ObjCMethodDecl *FinalizeM = MD;
+ const ObjCMethodDecl *FinalizeM = MD;
Transaction Trans(TA);
TA.insert(FinalizeM->getSourceRange().getBegin(),
"#if !__has_feature(objc_arc)\n");
diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h
index eab5e85d56b7..12551d261d36 100644
--- a/lib/ARCMigrate/Transforms.h
+++ b/lib/ARCMigrate/Transforms.h
@@ -127,29 +127,29 @@ public:
class PropertyRewriteTraverser : public ASTTraverser {
public:
- virtual void traverseObjCImplementation(ObjCImplementationContext &ImplCtx);
+ void traverseObjCImplementation(ObjCImplementationContext &ImplCtx) override;
};
class BlockObjCVariableTraverser : public ASTTraverser {
public:
- virtual void traverseBody(BodyContext &BodyCtx);
+ void traverseBody(BodyContext &BodyCtx) override;
};
class ProtectedScopeTraverser : public ASTTraverser {
public:
- virtual void traverseBody(BodyContext &BodyCtx);
+ void traverseBody(BodyContext &BodyCtx) override;
};
// GC transformations
class GCAttrsTraverser : public ASTTraverser {
public:
- virtual void traverseTU(MigrationContext &MigrateCtx);
+ void traverseTU(MigrationContext &MigrateCtx) override;
};
class GCCollectableCallsTraverser : public ASTTraverser {
public:
- virtual void traverseBody(BodyContext &BodyCtx);
+ void traverseBody(BodyContext &BodyCtx) override;
};
//===----------------------------------------------------------------------===//
@@ -189,7 +189,7 @@ class BodyTransform : public RecursiveASTVisitor<BodyTransform<BODY_TRANS> > {
typedef RecursiveASTVisitor<BodyTransform<BODY_TRANS> > base;
public:
- BodyTransform(MigrationPass &pass) : Pass(pass), ParentD(0) { }
+ BodyTransform(MigrationPass &pass) : Pass(pass), ParentD(nullptr) { }
bool TraverseStmt(Stmt *rootS) {
if (rootS)
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 541836b21b70..0fa0216d9dac 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -34,7 +34,7 @@ namespace {
struct APValue::LV : LVBase {
static const unsigned InlinePathSpace =
- (MaxSize - sizeof(LVBase)) / sizeof(LValuePathEntry);
+ (DataSize - sizeof(LVBase)) / sizeof(LValuePathEntry);
/// Path - The sequence of base classes, fields and array indices to follow to
/// walk from Base to the subobject. When performing GCC-style folding, there
@@ -75,7 +75,7 @@ namespace {
struct APValue::MemberPointerData : MemberPointerBase {
static const unsigned InlinePathSpace =
- (MaxSize - sizeof(MemberPointerBase)) / sizeof(const CXXRecordDecl*);
+ (DataSize - sizeof(MemberPointerBase)) / sizeof(const CXXRecordDecl*);
typedef const CXXRecordDecl *PathElem;
union {
PathElem Path[InlinePathSpace];
@@ -117,7 +117,7 @@ APValue::StructData::~StructData() {
delete [] Elts;
}
-APValue::UnionData::UnionData() : Field(0), Value(new APValue) {}
+APValue::UnionData::UnionData() : Field(nullptr), Value(new APValue) {}
APValue::UnionData::~UnionData () {
delete Value;
}
@@ -136,7 +136,7 @@ APValue::APValue(const APValue &RHS) : Kind(Uninitialized) {
break;
case Vector:
MakeVector();
- setVector(((const Vec *)(const char *)RHS.Data)->Elts,
+ setVector(((const Vec *)(const char *)RHS.Data.buffer)->Elts,
RHS.getVectorLength());
break;
case ComplexInt:
@@ -188,27 +188,27 @@ APValue::APValue(const APValue &RHS) : Kind(Uninitialized) {
void APValue::DestroyDataAndMakeUninit() {
if (Kind == Int)
- ((APSInt*)(char*)Data)->~APSInt();
+ ((APSInt*)(char*)Data.buffer)->~APSInt();
else if (Kind == Float)
- ((APFloat*)(char*)Data)->~APFloat();
+ ((APFloat*)(char*)Data.buffer)->~APFloat();
else if (Kind == Vector)
- ((Vec*)(char*)Data)->~Vec();
+ ((Vec*)(char*)Data.buffer)->~Vec();
else if (Kind == ComplexInt)
- ((ComplexAPSInt*)(char*)Data)->~ComplexAPSInt();
+ ((ComplexAPSInt*)(char*)Data.buffer)->~ComplexAPSInt();
else if (Kind == ComplexFloat)
- ((ComplexAPFloat*)(char*)Data)->~ComplexAPFloat();
+ ((ComplexAPFloat*)(char*)Data.buffer)->~ComplexAPFloat();
else if (Kind == LValue)
- ((LV*)(char*)Data)->~LV();
+ ((LV*)(char*)Data.buffer)->~LV();
else if (Kind == Array)
- ((Arr*)(char*)Data)->~Arr();
+ ((Arr*)(char*)Data.buffer)->~Arr();
else if (Kind == Struct)
- ((StructData*)(char*)Data)->~StructData();
+ ((StructData*)(char*)Data.buffer)->~StructData();
else if (Kind == Union)
- ((UnionData*)(char*)Data)->~UnionData();
+ ((UnionData*)(char*)Data.buffer)->~UnionData();
else if (Kind == MemberPointer)
- ((MemberPointerData*)(char*)Data)->~MemberPointerData();
+ ((MemberPointerData*)(char*)Data.buffer)->~MemberPointerData();
else if (Kind == AddrLabelDiff)
- ((AddrLabelDiffData*)(char*)Data)->~AddrLabelDiffData();
+ ((AddrLabelDiffData*)(char*)Data.buffer)->~AddrLabelDiffData();
Kind = Uninitialized;
}
@@ -239,19 +239,20 @@ bool APValue::needsCleanup() const {
"same size.");
return getComplexIntReal().needsCleanup();
case LValue:
- return reinterpret_cast<const LV *>(Data)->hasPathPtr();
+ return reinterpret_cast<const LV *>(Data.buffer)->hasPathPtr();
case MemberPointer:
- return reinterpret_cast<const MemberPointerData *>(Data)->hasPathPtr();
+ return reinterpret_cast<const MemberPointerData *>(Data.buffer)
+ ->hasPathPtr();
}
llvm_unreachable("Unknown APValue kind!");
}
void APValue::swap(APValue &RHS) {
std::swap(Kind, RHS.Kind);
- char TmpData[MaxSize];
- memcpy(TmpData, Data, MaxSize);
- memcpy(Data, RHS.Data, MaxSize);
- memcpy(RHS.Data, TmpData, MaxSize);
+ char TmpData[DataSize];
+ memcpy(TmpData, Data.buffer, DataSize);
+ memcpy(Data.buffer, RHS.Data.buffer, DataSize);
+ memcpy(RHS.Data.buffer, TmpData, DataSize);
}
void APValue::dump() const {
@@ -402,8 +403,13 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>())
Out << *VD;
- else
- Base.get<const Expr*>()->printPretty(Out, 0, Ctx.getPrintingPolicy());
+ else {
+ assert(Base.get<const Expr *>() != nullptr &&
+ "Expecting non-null Expr");
+ Base.get<const Expr*>()->printPretty(Out, nullptr,
+ Ctx.getPrintingPolicy());
+ }
+
if (!O.isZero()) {
Out << " + " << (O / S);
if (IsReference)
@@ -424,12 +430,13 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
ElemTy = VD->getType();
} else {
const Expr *E = Base.get<const Expr*>();
- E->printPretty(Out, 0, Ctx.getPrintingPolicy());
+ assert(E != nullptr && "Expecting non-null Expr");
+ E->printPretty(Out, nullptr, Ctx.getPrintingPolicy());
ElemTy = E->getType();
}
ArrayRef<LValuePathEntry> Path = getLValuePath();
- const CXXRecordDecl *CastToBase = 0;
+ const CXXRecordDecl *CastToBase = nullptr;
for (unsigned I = 0, N = Path.size(); I != N; ++I) {
if (ElemTy->getAs<RecordType>()) {
// The lvalue refers to a class type, so the next path entry is a base
@@ -498,8 +505,7 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
First = false;
}
}
- for (RecordDecl::field_iterator FI = RD->field_begin();
- FI != RD->field_end(); ++FI) {
+ for (const auto *FI : RD->fields()) {
if (!First)
Out << ", ";
if (FI->isUnnamedBitfield()) continue;
@@ -546,39 +552,39 @@ std::string APValue::getAsString(ASTContext &Ctx, QualType Ty) const {
const APValue::LValueBase APValue::getLValueBase() const {
assert(isLValue() && "Invalid accessor");
- return ((const LV*)(const void*)Data)->BaseAndIsOnePastTheEnd.getPointer();
+ return ((const LV*)(const void*)Data.buffer)->BaseAndIsOnePastTheEnd.getPointer();
}
bool APValue::isLValueOnePastTheEnd() const {
assert(isLValue() && "Invalid accessor");
- return ((const LV*)(const void*)Data)->BaseAndIsOnePastTheEnd.getInt();
+ return ((const LV*)(const void*)Data.buffer)->BaseAndIsOnePastTheEnd.getInt();
}
CharUnits &APValue::getLValueOffset() {
assert(isLValue() && "Invalid accessor");
- return ((LV*)(void*)Data)->Offset;
+ return ((LV*)(void*)Data.buffer)->Offset;
}
bool APValue::hasLValuePath() const {
assert(isLValue() && "Invalid accessor");
- return ((const LV*)(const char*)Data)->hasPath();
+ return ((const LV*)(const char*)Data.buffer)->hasPath();
}
ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const {
assert(isLValue() && hasLValuePath() && "Invalid accessor");
- const LV &LVal = *((const LV*)(const char*)Data);
+ const LV &LVal = *((const LV*)(const char*)Data.buffer);
return ArrayRef<LValuePathEntry>(LVal.getPath(), LVal.PathLength);
}
unsigned APValue::getLValueCallIndex() const {
assert(isLValue() && "Invalid accessor");
- return ((const LV*)(const char*)Data)->CallIndex;
+ return ((const LV*)(const char*)Data.buffer)->CallIndex;
}
void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath,
unsigned CallIndex) {
assert(isLValue() && "Invalid accessor");
- LV &LVal = *((LV*)(char*)Data);
+ LV &LVal = *((LV*)(char*)Data.buffer);
LVal.BaseAndIsOnePastTheEnd.setPointer(B);
LVal.BaseAndIsOnePastTheEnd.setInt(false);
LVal.Offset = O;
@@ -590,7 +596,7 @@ void APValue::setLValue(LValueBase B, const CharUnits &O,
ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd,
unsigned CallIndex) {
assert(isLValue() && "Invalid accessor");
- LV &LVal = *((LV*)(char*)Data);
+ LV &LVal = *((LV*)(char*)Data.buffer);
LVal.BaseAndIsOnePastTheEnd.setPointer(B);
LVal.BaseAndIsOnePastTheEnd.setInt(IsOnePastTheEnd);
LVal.Offset = O;
@@ -601,39 +607,42 @@ void APValue::setLValue(LValueBase B, const CharUnits &O,
const ValueDecl *APValue::getMemberPointerDecl() const {
assert(isMemberPointer() && "Invalid accessor");
- const MemberPointerData &MPD = *((const MemberPointerData*)(const char*)Data);
+ const MemberPointerData &MPD =
+ *((const MemberPointerData *)(const char *)Data.buffer);
return MPD.MemberAndIsDerivedMember.getPointer();
}
bool APValue::isMemberPointerToDerivedMember() const {
assert(isMemberPointer() && "Invalid accessor");
- const MemberPointerData &MPD = *((const MemberPointerData*)(const char*)Data);
+ const MemberPointerData &MPD =
+ *((const MemberPointerData *)(const char *)Data.buffer);
return MPD.MemberAndIsDerivedMember.getInt();
}
ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const {
assert(isMemberPointer() && "Invalid accessor");
- const MemberPointerData &MPD = *((const MemberPointerData*)(const char*)Data);
+ const MemberPointerData &MPD =
+ *((const MemberPointerData *)(const char *)Data.buffer);
return ArrayRef<const CXXRecordDecl*>(MPD.getPath(), MPD.PathLength);
}
void APValue::MakeLValue() {
assert(isUninit() && "Bad state change");
- assert(sizeof(LV) <= MaxSize && "LV too big");
- new ((void*)(char*)Data) LV();
+ static_assert(sizeof(LV) <= DataSize, "LV too big");
+ new ((void*)(char*)Data.buffer) LV();
Kind = LValue;
}
void APValue::MakeArray(unsigned InitElts, unsigned Size) {
assert(isUninit() && "Bad state change");
- new ((void*)(char*)Data) Arr(InitElts, Size);
+ new ((void*)(char*)Data.buffer) Arr(InitElts, Size);
Kind = Array;
}
void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
ArrayRef<const CXXRecordDecl*> Path) {
assert(isUninit() && "Bad state change");
- MemberPointerData *MPD = new ((void*)(char*)Data) MemberPointerData;
+ MemberPointerData *MPD = new ((void*)(char*)Data.buffer) MemberPointerData;
Kind = MemberPointer;
MPD->MemberAndIsDerivedMember.setPointer(Member);
MPD->MemberAndIsDerivedMember.setInt(IsDerivedMember);
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index a03cf9e7d47b..bccdae91d2eb 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -29,6 +29,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/AST/VTableBuilder.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -62,6 +63,13 @@ enum FloatingRank {
RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
if (!CommentsLoaded && ExternalSource) {
ExternalSource->ReadComments();
+
+#ifndef NDEBUG
+ ArrayRef<RawComment *> RawComments = Comments.getComments();
+ assert(std::is_sorted(RawComments.begin(), RawComments.end(),
+ BeforeThanCompare<RawComment>(SourceMgr)));
+#endif
+
CommentsLoaded = true;
}
@@ -69,23 +77,23 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
// User can not attach documentation to implicit declarations.
if (D->isImplicit())
- return NULL;
+ return nullptr;
// User can not attach documentation to implicit instantiations.
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
- return NULL;
+ return nullptr;
}
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (VD->isStaticDataMember() &&
VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
- return NULL;
+ return nullptr;
}
if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) {
if (CRD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
- return NULL;
+ return nullptr;
}
if (const ClassTemplateSpecializationDecl *CTSD =
@@ -93,35 +101,35 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
TemplateSpecializationKind TSK = CTSD->getSpecializationKind();
if (TSK == TSK_ImplicitInstantiation ||
TSK == TSK_Undeclared)
- return NULL;
+ return nullptr;
}
if (const EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
if (ED->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
- return NULL;
+ return nullptr;
}
if (const TagDecl *TD = dyn_cast<TagDecl>(D)) {
// When tag declaration (but not definition!) is part of the
// decl-specifier-seq of some other declaration, it doesn't get comment
if (TD->isEmbeddedInDeclarator() && !TD->isCompleteDefinition())
- return NULL;
+ return nullptr;
}
// TODO: handle comments for function parameters properly.
if (isa<ParmVarDecl>(D))
- return NULL;
+ return nullptr;
// TODO: we could look up template parameter documentation in the template
// documentation.
if (isa<TemplateTypeParmDecl>(D) ||
isa<NonTypeTemplateParmDecl>(D) ||
isa<TemplateTemplateParmDecl>(D))
- return NULL;
+ return nullptr;
ArrayRef<RawComment *> RawComments = Comments.getComments();
// If there are no comments anywhere, we won't find anything.
if (RawComments.empty())
- return NULL;
+ return nullptr;
// Find declaration location.
// For Objective-C declarations we generally don't expect to have multiple
@@ -137,17 +145,29 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
DeclLoc = D->getLocStart();
else {
DeclLoc = D->getLocation();
- // If location of the typedef name is in a macro, it is because being
- // declared via a macro. Try using declaration's starting location
- // as the "declaration location".
- if (DeclLoc.isMacroID() && isa<TypedefDecl>(D))
- DeclLoc = D->getLocStart();
+ if (DeclLoc.isMacroID()) {
+ if (isa<TypedefDecl>(D)) {
+ // If location of the typedef name is in a macro, it is because being
+ // declared via a macro. Try using declaration's starting location as
+ // the "declaration location".
+ DeclLoc = D->getLocStart();
+ } else if (const TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ // If location of the tag decl is inside a macro, but the spelling of
+ // the tag name comes from a macro argument, it looks like a special
+ // macro like NS_ENUM is being used to define the tag decl. In that
+ // case, adjust the source location to the expansion loc so that we can
+ // attach the comment to the tag decl.
+ if (SourceMgr.isMacroArgExpansion(DeclLoc) &&
+ TD->isCompleteDefinition())
+ DeclLoc = SourceMgr.getExpansionLoc(DeclLoc);
+ }
+ }
}
// If the declaration doesn't map directly to a location in a file, we
// can't find the comment.
if (DeclLoc.isInvalid() || !DeclLoc.isFileID())
- return NULL;
+ return nullptr;
// Find the comment that occurs just after this declaration.
ArrayRef<RawComment *>::iterator Comment;
@@ -201,12 +221,12 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
// The comment just after the declaration was not a trailing comment.
// Let's look at the previous comment.
if (Comment == RawComments.begin())
- return NULL;
+ return nullptr;
--Comment;
// Check that we actually have a non-member Doxygen comment.
if (!(*Comment)->isDocumentation() || (*Comment)->isTrailingComment())
- return NULL;
+ return nullptr;
// Decompose the end of the comment.
std::pair<FileID, unsigned> CommentEndDecomp
@@ -215,14 +235,14 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
// If the comment and the declaration aren't in the same file, then they
// aren't related.
if (DeclLocDecomp.first != CommentEndDecomp.first)
- return NULL;
+ return nullptr;
// Get the corresponding buffer.
bool Invalid = false;
const char *Buffer = SourceMgr.getBufferData(DeclLocDecomp.first,
&Invalid).data();
if (Invalid)
- return NULL;
+ return nullptr;
// Extract text between the comment and declaration.
StringRef Text(Buffer + CommentEndDecomp.second,
@@ -231,7 +251,7 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
// There should be no other declarations or preprocessor directives between
// comment and declaration.
if (Text.find_first_of(";{}#@") != StringRef::npos)
- return NULL;
+ return nullptr;
return *Comment;
}
@@ -329,13 +349,11 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl(
}
// Search for comments attached to declarations in the redeclaration chain.
- const RawComment *RC = NULL;
- const Decl *OriginalDeclForRC = NULL;
- for (Decl::redecl_iterator I = D->redecls_begin(),
- E = D->redecls_end();
- I != E; ++I) {
+ const RawComment *RC = nullptr;
+ const Decl *OriginalDeclForRC = nullptr;
+ for (auto I : D->redecls()) {
llvm::DenseMap<const Decl *, RawCommentAndCacheFlags>::iterator Pos =
- RedeclComments.find(*I);
+ RedeclComments.find(I);
if (Pos != RedeclComments.end()) {
const RawCommentAndCacheFlags &Raw = Pos->second;
if (Raw.getKind() != RawCommentAndCacheFlags::NoCommentInDecl) {
@@ -344,16 +362,16 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl(
break;
}
} else {
- RC = getRawCommentForDeclNoCache(*I);
- OriginalDeclForRC = *I;
+ RC = getRawCommentForDeclNoCache(I);
+ OriginalDeclForRC = I;
RawCommentAndCacheFlags Raw;
if (RC) {
Raw.setRaw(RC);
Raw.setKind(RawCommentAndCacheFlags::FromDecl);
} else
Raw.setKind(RawCommentAndCacheFlags::NoCommentInDecl);
- Raw.setOriginalDecl(*I);
- RedeclComments[*I] = Raw;
+ Raw.setOriginalDecl(I);
+ RedeclComments[I] = Raw;
if (RC)
break;
}
@@ -371,10 +389,8 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl(
Raw.setKind(RawCommentAndCacheFlags::FromRedecl);
Raw.setOriginalDecl(OriginalDeclForRC);
- for (Decl::redecl_iterator I = D->redecls_begin(),
- E = D->redecls_end();
- I != E; ++I) {
- RawCommentAndCacheFlags &R = RedeclComments[*I];
+ for (auto I : D->redecls()) {
+ RawCommentAndCacheFlags &R = RedeclComments[I];
if (R.getKind() == RawCommentAndCacheFlags::NoCommentInDecl)
R = Raw;
}
@@ -390,10 +406,7 @@ static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod,
if (!ID)
return;
// Add redeclared method here.
- for (ObjCInterfaceDecl::known_extensions_iterator
- Ext = ID->known_extensions_begin(),
- ExtEnd = ID->known_extensions_end();
- Ext != ExtEnd; ++Ext) {
+ for (const auto *Ext : ID->known_extensions()) {
if (ObjCMethodDecl *RedeclaredMethod =
Ext->getMethod(ObjCMethod->getSelector(),
ObjCMethod->isInstanceMethod()))
@@ -409,6 +422,8 @@ comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC,
ThisDeclInfo->IsFilled = false;
ThisDeclInfo->fill();
ThisDeclInfo->CommentDecl = FC->getDecl();
+ if (!ThisDeclInfo->TemplateParameters)
+ ThisDeclInfo->TemplateParameters = FC->getDeclInfo()->TemplateParameters;
comments::FullComment *CFC =
new (*this) comments::FullComment(FC->getBlocks(),
ThisDeclInfo);
@@ -418,14 +433,14 @@ comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC,
comments::FullComment *ASTContext::getLocalCommentForDeclUncached(const Decl *D) const {
const RawComment *RC = getRawCommentForDeclNoCache(D);
- return RC ? RC->parse(*this, 0, D) : 0;
+ return RC ? RC->parse(*this, nullptr, D) : nullptr;
}
comments::FullComment *ASTContext::getCommentForDecl(
const Decl *D,
const Preprocessor *PP) const {
if (D->isInvalidDecl())
- return NULL;
+ return nullptr;
D = adjustDeclToTemplate(D);
const Decl *Canonical = D->getCanonicalDecl();
@@ -482,13 +497,12 @@ comments::FullComment *ASTContext::getCommentForDecl(
}
else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
if (!(RD = RD->getDefinition()))
- return NULL;
+ return nullptr;
// Check non-virtual bases.
- for (CXXRecordDecl::base_class_const_iterator I =
- RD->bases_begin(), E = RD->bases_end(); I != E; ++I) {
- if (I->isVirtual() || (I->getAccessSpecifier() != AS_public))
+ for (const auto &I : RD->bases()) {
+ if (I.isVirtual() || (I.getAccessSpecifier() != AS_public))
continue;
- QualType Ty = I->getType();
+ QualType Ty = I.getType();
if (Ty.isNull())
continue;
if (const CXXRecordDecl *NonVirtualBase = Ty->getAsCXXRecordDecl()) {
@@ -500,11 +514,10 @@ comments::FullComment *ASTContext::getCommentForDecl(
}
}
// Check virtual bases.
- for (CXXRecordDecl::base_class_const_iterator I =
- RD->vbases_begin(), E = RD->vbases_end(); I != E; ++I) {
- if (I->getAccessSpecifier() != AS_public)
+ for (const auto &I : RD->vbases()) {
+ if (I.getAccessSpecifier() != AS_public)
continue;
- QualType Ty = I->getType();
+ QualType Ty = I.getType();
if (Ty.isNull())
continue;
if (const CXXRecordDecl *VirtualBase = Ty->getAsCXXRecordDecl()) {
@@ -515,7 +528,7 @@ comments::FullComment *ASTContext::getCommentForDecl(
}
}
}
- return NULL;
+ return nullptr;
}
// If the RawComment was attached to other redeclaration of this Decl, we
@@ -576,7 +589,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
// Check if we already have a canonical template template parameter.
llvm::FoldingSetNodeID ID;
CanonicalTemplateTemplateParm::Profile(ID, TTP);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
CanonicalTemplateTemplateParm *Canonical
= CanonTemplateTemplateParms.FindNodeOrInsertPos(ID, InsertPos);
if (Canonical)
@@ -595,7 +608,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
SourceLocation(),
SourceLocation(),
TTP->getDepth(),
- TTP->getIndex(), 0, false,
+ TTP->getIndex(), nullptr, false,
TTP->isParameterPack()));
else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*P)) {
@@ -615,7 +628,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
SourceLocation(),
SourceLocation(),
NTTP->getDepth(),
- NTTP->getPosition(), 0,
+ NTTP->getPosition(), nullptr,
T,
TInfo,
ExpandedTypes.data(),
@@ -626,7 +639,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
SourceLocation(),
SourceLocation(),
NTTP->getDepth(),
- NTTP->getPosition(), 0,
+ NTTP->getPosition(), nullptr,
T,
NTTP->isParameterPack(),
TInfo);
@@ -643,7 +656,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
SourceLocation(), TTP->getDepth(),
TTP->getPosition(),
TTP->isParameterPack(),
- 0,
+ nullptr,
TemplateParameterList::Create(*this, SourceLocation(),
SourceLocation(),
CanonParams.data(),
@@ -652,7 +665,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
// Get the new insert position for the node we care about.
Canonical = CanonTemplateTemplateParms.FindNodeOrInsertPos(ID, InsertPos);
- assert(Canonical == 0 && "Shouldn't be in the map!");
+ assert(!Canonical && "Shouldn't be in the map!");
(void)Canonical;
// Create the canonical template template parameter entry.
@@ -662,13 +675,13 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
}
CXXABI *ASTContext::createCXXABI(const TargetInfo &T) {
- if (!LangOpts.CPlusPlus) return 0;
+ if (!LangOpts.CPlusPlus) return nullptr;
switch (T.getCXXABI().getKind()) {
- case TargetCXXABI::GenericARM:
+ case TargetCXXABI::GenericARM: // Same as Itanium at this level
case TargetCXXABI::iOS:
- return CreateARMCXXABI(*this);
- case TargetCXXABI::GenericAArch64: // Same as Itanium at this level
+ case TargetCXXABI::iOS64:
+ case TargetCXXABI::GenericAArch64:
case TargetCXXABI::GenericItanium:
return CreateItaniumCXXABI(*this);
case TargetCXXABI::Microsoft:
@@ -710,47 +723,40 @@ static bool isAddrSpaceMapManglingEnabled(const TargetInfo &TI,
}
ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
- const TargetInfo *t,
IdentifierTable &idents, SelectorTable &sels,
- Builtin::Context &builtins,
- unsigned size_reserve,
- bool DelayInitialization)
+ Builtin::Context &builtins)
: FunctionProtoTypes(this_()),
TemplateSpecializationTypes(this_()),
DependentTemplateSpecializationTypes(this_()),
SubstTemplateTemplateParmPacks(this_()),
- GlobalNestedNameSpecifier(0),
- Int128Decl(0), UInt128Decl(0), Float128StubDecl(0),
- BuiltinVaListDecl(0),
- ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0), ObjCProtocolClassDecl(0),
- BOOLDecl(0),
- CFConstantStringTypeDecl(0), ObjCInstanceTypeDecl(0),
- FILEDecl(0),
- jmp_bufDecl(0), sigjmp_bufDecl(0), ucontext_tDecl(0),
- BlockDescriptorType(0), BlockDescriptorExtendedType(0),
- cudaConfigureCallDecl(0),
+ GlobalNestedNameSpecifier(nullptr),
+ Int128Decl(nullptr), UInt128Decl(nullptr), Float128StubDecl(nullptr),
+ BuiltinVaListDecl(nullptr),
+ ObjCIdDecl(nullptr), ObjCSelDecl(nullptr), ObjCClassDecl(nullptr),
+ ObjCProtocolClassDecl(nullptr), BOOLDecl(nullptr),
+ CFConstantStringTypeDecl(nullptr), ObjCInstanceTypeDecl(nullptr),
+ FILEDecl(nullptr),
+ jmp_bufDecl(nullptr), sigjmp_bufDecl(nullptr), ucontext_tDecl(nullptr),
+ BlockDescriptorType(nullptr), BlockDescriptorExtendedType(nullptr),
+ cudaConfigureCallDecl(nullptr),
NullTypeSourceInfo(QualType()),
FirstLocalImport(), LastLocalImport(),
SourceMgr(SM), LangOpts(LOpts),
- AddrSpaceMap(0), Target(t), PrintingPolicy(LOpts),
+ AddrSpaceMap(nullptr), Target(nullptr), PrintingPolicy(LOpts),
Idents(idents), Selectors(sels),
BuiltinInfo(builtins),
DeclarationNames(*this),
- ExternalSource(0), Listener(0),
+ ExternalSource(nullptr), Listener(nullptr),
Comments(SM), CommentsLoaded(false),
CommentCommandTraits(BumpAlloc, LOpts.CommentOpts),
- LastSDM(0, 0)
+ LastSDM(nullptr, 0)
{
- if (size_reserve > 0) Types.reserve(size_reserve);
TUDecl = TranslationUnitDecl::Create(*this);
-
- if (!DelayInitialization) {
- assert(t && "No target supplied for ASTContext initialization");
- InitBuiltinTypes(*t);
- }
}
ASTContext::~ASTContext() {
+ ReleaseParentMapEntries();
+
// Release the DenseMaps associated with DeclContext objects.
// FIXME: Is this the ideal solution?
ReleaseDeclContextMaps();
@@ -782,11 +788,19 @@ ASTContext::~ASTContext() {
A != AEnd; ++A)
A->second->~AttrVec();
- for (llvm::DenseMap<const DeclContext *, MangleNumberingContext *>::iterator
- I = MangleNumberingContexts.begin(),
- E = MangleNumberingContexts.end();
- I != E; ++I)
- delete I->second;
+ llvm::DeleteContainerSeconds(MangleNumberingContexts);
+}
+
+void ASTContext::ReleaseParentMapEntries() {
+ if (!AllParents) return;
+ for (const auto &Entry : *AllParents) {
+ if (Entry.second.is<ast_type_traits::DynTypedNode *>()) {
+ delete Entry.second.get<ast_type_traits::DynTypedNode *>();
+ } else {
+ assert(Entry.second.is<ParentVector *>());
+ delete Entry.second.get<ParentVector *>();
+ }
+ }
}
void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) {
@@ -794,8 +808,8 @@ void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) {
}
void
-ASTContext::setExternalSource(OwningPtr<ExternalASTSource> &Source) {
- ExternalSource.reset(Source.take());
+ASTContext::setExternalSource(IntrusiveRefCntPtr<ExternalASTSource> Source) {
+ ExternalSource = Source;
}
void ASTContext::PrintStats() const {
@@ -849,7 +863,7 @@ void ASTContext::PrintStats() const {
<< NumImplicitDestructors
<< " implicit destructors created\n";
- if (ExternalSource.get()) {
+ if (ExternalSource) {
llvm::errs() << "\n";
ExternalSource->PrintStats();
}
@@ -857,45 +871,47 @@ void ASTContext::PrintStats() const {
BumpAlloc.PrintStats();
}
+RecordDecl *ASTContext::buildImplicitRecord(StringRef Name,
+ RecordDecl::TagKind TK) const {
+ SourceLocation Loc;
+ RecordDecl *NewDecl;
+ if (getLangOpts().CPlusPlus)
+ NewDecl = CXXRecordDecl::Create(*this, TK, getTranslationUnitDecl(), Loc,
+ Loc, &Idents.get(Name));
+ else
+ NewDecl = RecordDecl::Create(*this, TK, getTranslationUnitDecl(), Loc, Loc,
+ &Idents.get(Name));
+ NewDecl->setImplicit();
+ return NewDecl;
+}
+
+TypedefDecl *ASTContext::buildImplicitTypedef(QualType T,
+ StringRef Name) const {
+ TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(T);
+ TypedefDecl *NewDecl = TypedefDecl::Create(
+ const_cast<ASTContext &>(*this), getTranslationUnitDecl(),
+ SourceLocation(), SourceLocation(), &Idents.get(Name), TInfo);
+ NewDecl->setImplicit();
+ return NewDecl;
+}
+
TypedefDecl *ASTContext::getInt128Decl() const {
- if (!Int128Decl) {
- TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(Int128Ty);
- Int128Decl = TypedefDecl::Create(const_cast<ASTContext &>(*this),
- getTranslationUnitDecl(),
- SourceLocation(),
- SourceLocation(),
- &Idents.get("__int128_t"),
- TInfo);
- }
-
+ if (!Int128Decl)
+ Int128Decl = buildImplicitTypedef(Int128Ty, "__int128_t");
return Int128Decl;
}
TypedefDecl *ASTContext::getUInt128Decl() const {
- if (!UInt128Decl) {
- TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(UnsignedInt128Ty);
- UInt128Decl = TypedefDecl::Create(const_cast<ASTContext &>(*this),
- getTranslationUnitDecl(),
- SourceLocation(),
- SourceLocation(),
- &Idents.get("__uint128_t"),
- TInfo);
- }
-
+ if (!UInt128Decl)
+ UInt128Decl = buildImplicitTypedef(UnsignedInt128Ty, "__uint128_t");
return UInt128Decl;
}
TypeDecl *ASTContext::getFloat128StubType() const {
assert(LangOpts.CPlusPlus && "should only be called for c++");
- if (!Float128StubDecl) {
- Float128StubDecl = CXXRecordDecl::Create(const_cast<ASTContext &>(*this),
- TTK_Struct,
- getTranslationUnitDecl(),
- SourceLocation(),
- SourceLocation(),
- &Idents.get("__float128"));
- }
-
+ if (!Float128StubDecl)
+ Float128StubDecl = buildImplicitRecord("__float128");
+
return Float128StubDecl;
}
@@ -1106,7 +1122,7 @@ FunctionDecl *ASTContext::getClassScopeSpecializationPattern(
llvm::DenseMap<const FunctionDecl*, FunctionDecl *>::const_iterator Pos
= ClassScopeSpecializationPattern.find(FD);
if (Pos == ClassScopeSpecializationPattern.end())
- return 0;
+ return nullptr;
return Pos->second;
}
@@ -1123,7 +1139,7 @@ ASTContext::getInstantiatedFromUsingDecl(UsingDecl *UUD) {
llvm::DenseMap<UsingDecl *, NamedDecl *>::const_iterator Pos
= InstantiatedFromUsingDecl.find(UUD);
if (Pos == InstantiatedFromUsingDecl.end())
- return 0;
+ return nullptr;
return Pos->second;
}
@@ -1143,7 +1159,7 @@ ASTContext::getInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst) {
llvm::DenseMap<UsingShadowDecl*, UsingShadowDecl*>::const_iterator Pos
= InstantiatedFromUsingShadowDecl.find(Inst);
if (Pos == InstantiatedFromUsingShadowDecl.end())
- return 0;
+ return nullptr;
return Pos->second;
}
@@ -1159,7 +1175,7 @@ FieldDecl *ASTContext::getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) {
llvm::DenseMap<FieldDecl *, FieldDecl *>::iterator Pos
= InstantiatedFromUnnamedFieldDecl.find(Field);
if (Pos == InstantiatedFromUnnamedFieldDecl.end())
- return 0;
+ return nullptr;
return Pos->second;
}
@@ -1179,7 +1195,7 @@ ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const {
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
= OverriddenMethods.find(Method->getCanonicalDecl());
if (Pos == OverriddenMethods.end())
- return 0;
+ return nullptr;
return Pos->second.begin();
}
@@ -1189,7 +1205,7 @@ ASTContext::overridden_methods_end(const CXXMethodDecl *Method) const {
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
= OverriddenMethods.find(Method->getCanonicalDecl());
if (Pos == OverriddenMethods.end())
- return 0;
+ return nullptr;
return Pos->second.end();
}
@@ -1293,13 +1309,14 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const {
} else if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
QualType T = VD->getType();
- if (const ReferenceType* RT = T->getAs<ReferenceType>()) {
+ if (const ReferenceType *RT = T->getAs<ReferenceType>()) {
if (ForAlignof)
T = RT->getPointeeType();
else
T = getPointerType(RT->getPointeeType());
}
- if (!T->isIncompleteType() && !T->isFunctionType()) {
+ QualType BaseT = getBaseElementType(T);
+ if (!BaseT->isIncompleteType() && !T->isFunctionType()) {
// Adjust alignments of declarations with array type by the
// large-array alignment on the target.
if (const ArrayType *arrayType = getAsArrayType(T)) {
@@ -1311,9 +1328,6 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const {
MinWidth <= getTypeSize(cast<ConstantArrayType>(arrayType)))
Align = std::max(Align, Target->getLargeArrayAlign());
}
-
- // Walk through any array types while we're at it.
- T = getBaseElementType(arrayType);
}
Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr()));
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
@@ -1618,7 +1632,7 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
}
case Type::MemberPointer: {
const MemberPointerType *MPT = cast<MemberPointerType>(T);
- llvm::tie(Width, Align) = ABI->getMemberPointerWidthAndAlign(MPT);
+ std::tie(Width, Align) = ABI->getMemberPointerWidthAndAlign(MPT);
break;
}
case Type::Complex: {
@@ -1632,8 +1646,9 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
}
case Type::ObjCObject:
return getTypeInfo(cast<ObjCObjectType>(T)->getBaseType().getTypePtr());
+ case Type::Adjusted:
case Type::Decayed:
- return getTypeInfo(cast<DecayedType>(T)->getDecayedType().getTypePtr());
+ return getTypeInfo(cast<AdjustedType>(T)->getAdjustedType().getTypePtr());
case Type::ObjCInterface: {
const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(T);
const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl());
@@ -1761,13 +1776,19 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const {
if (Target->getTriple().getArch() == llvm::Triple::xcore)
return ABIAlign; // Never overalign on XCore.
+ const TypedefType *TT = T->getAs<TypedefType>();
+
// Double and long long should be naturally aligned if possible.
- if (const ComplexType* CT = T->getAs<ComplexType>())
+ T = T->getBaseElementTypeUnsafe();
+ if (const ComplexType *CT = T->getAs<ComplexType>())
T = CT->getElementType().getTypePtr();
if (T->isSpecificBuiltinType(BuiltinType::Double) ||
T->isSpecificBuiltinType(BuiltinType::LongLong) ||
T->isSpecificBuiltinType(BuiltinType::ULongLong))
- return std::max(ABIAlign, (unsigned)getTypeSize(T));
+ // Don't increase the alignment if an alignment attribute was specified on a
+ // typedef declaration.
+ if (!TT || !TT->getDecl()->getMaxAlignment())
+ return std::max(ABIAlign, (unsigned)getTypeSize(T));
return ABIAlign;
}
@@ -1796,9 +1817,8 @@ void ASTContext::DeepCollectObjCIvars(const ObjCInterfaceDecl *OI,
if (const ObjCInterfaceDecl *SuperClass = OI->getSuperClass())
DeepCollectObjCIvars(SuperClass, false, Ivars);
if (!leafClass) {
- for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(),
- E = OI->ivar_end(); I != E; ++I)
- Ivars.push_back(*I);
+ for (const auto *I : OI->ivars())
+ Ivars.push_back(I);
} else {
ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(OI);
for (const ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv;
@@ -1814,24 +1834,17 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
if (const ObjCInterfaceDecl *OI = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
// We can use protocol_iterator here instead of
// all_referenced_protocol_iterator since we are walking all categories.
- for (ObjCInterfaceDecl::all_protocol_iterator P = OI->all_referenced_protocol_begin(),
- PE = OI->all_referenced_protocol_end(); P != PE; ++P) {
- ObjCProtocolDecl *Proto = (*P);
+ for (auto *Proto : OI->all_referenced_protocols()) {
Protocols.insert(Proto->getCanonicalDecl());
- for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
- PE = Proto->protocol_end(); P != PE; ++P) {
- Protocols.insert((*P)->getCanonicalDecl());
- CollectInheritedProtocols(*P, Protocols);
+ for (auto *P : Proto->protocols()) {
+ Protocols.insert(P->getCanonicalDecl());
+ CollectInheritedProtocols(P, Protocols);
}
}
// Categories of this Interface.
- for (ObjCInterfaceDecl::visible_categories_iterator
- Cat = OI->visible_categories_begin(),
- CatEnd = OI->visible_categories_end();
- Cat != CatEnd; ++Cat) {
- CollectInheritedProtocols(*Cat, Protocols);
- }
+ for (const auto *Cat : OI->visible_categories())
+ CollectInheritedProtocols(Cat, Protocols);
if (ObjCInterfaceDecl *SD = OI->getSuperClass())
while (SD) {
@@ -1839,22 +1852,16 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
SD = SD->getSuperClass();
}
} else if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) {
- for (ObjCCategoryDecl::protocol_iterator P = OC->protocol_begin(),
- PE = OC->protocol_end(); P != PE; ++P) {
- ObjCProtocolDecl *Proto = (*P);
+ for (auto *Proto : OC->protocols()) {
Protocols.insert(Proto->getCanonicalDecl());
- for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
- PE = Proto->protocol_end(); P != PE; ++P)
- CollectInheritedProtocols(*P, Protocols);
+ for (const auto *P : Proto->protocols())
+ CollectInheritedProtocols(P, Protocols);
}
} else if (const ObjCProtocolDecl *OP = dyn_cast<ObjCProtocolDecl>(CDecl)) {
- for (ObjCProtocolDecl::protocol_iterator P = OP->protocol_begin(),
- PE = OP->protocol_end(); P != PE; ++P) {
- ObjCProtocolDecl *Proto = (*P);
+ for (auto *Proto : OP->protocols()) {
Protocols.insert(Proto->getCanonicalDecl());
- for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
- PE = Proto->protocol_end(); P != PE; ++P)
- CollectInheritedProtocols(*P, Protocols);
+ for (const auto *P : Proto->protocols())
+ CollectInheritedProtocols(P, Protocols);
}
}
}
@@ -1862,12 +1869,8 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) const {
unsigned count = 0;
// Count ivars declared in class extension.
- for (ObjCInterfaceDecl::known_extensions_iterator
- Ext = OI->known_extensions_begin(),
- ExtEnd = OI->known_extensions_end();
- Ext != ExtEnd; ++Ext) {
+ for (const auto *Ext : OI->known_extensions())
count += Ext->ivar_size();
- }
// Count ivar defined in this class's implementation. This
// includes synthesized ivars.
@@ -1901,7 +1904,7 @@ ObjCImplementationDecl *ASTContext::getObjCImplementation(ObjCInterfaceDecl *D)
I = ObjCImpls.find(D);
if (I != ObjCImpls.end())
return cast<ObjCImplementationDecl>(I->second);
- return 0;
+ return nullptr;
}
/// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists.
ObjCCategoryImplDecl *ASTContext::getObjCImplementation(ObjCCategoryDecl *D) {
@@ -1909,7 +1912,7 @@ ObjCCategoryImplDecl *ASTContext::getObjCImplementation(ObjCCategoryDecl *D) {
I = ObjCImpls.find(D);
if (I != ObjCImpls.end())
return cast<ObjCCategoryImplDecl>(I->second);
- return 0;
+ return nullptr;
}
/// \brief Set the implementation of ObjCInterfaceDecl.
@@ -1937,7 +1940,7 @@ const ObjCInterfaceDecl *ASTContext::getObjContainingInterface(
dyn_cast<ObjCImplDecl>(ND->getDeclContext()))
return IMD->getClassInterface();
- return 0;
+ return nullptr;
}
/// \brief Get the copy initialization expression of VarDecl,or NULL if
@@ -1948,7 +1951,7 @@ Expr *ASTContext::getBlockVarCopyInits(const VarDecl*VD) {
"getBlockVarCopyInits - not __block var");
llvm::DenseMap<const VarDecl*, Expr*>::iterator
I = BlockVarCopyInits.find(VD);
- return (I != BlockVarCopyInits.end()) ? cast<Expr>(I->second) : 0;
+ return (I != BlockVarCopyInits.end()) ? cast<Expr>(I->second) : nullptr;
}
/// \brief Set the copy inialization expression of a block var decl.
@@ -1982,7 +1985,7 @@ TypeSourceInfo *ASTContext::getTrivialTypeSourceInfo(QualType T,
const ASTRecordLayout &
ASTContext::getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D) const {
- return getObjCLayout(D, 0);
+ return getObjCLayout(D, nullptr);
}
const ASTRecordLayout &
@@ -2003,7 +2006,7 @@ ASTContext::getExtQualType(const Type *baseType, Qualifiers quals) const {
// Check if we've already instantiated this type.
llvm::FoldingSetNodeID ID;
ExtQuals::Profile(ID, baseType, quals);
- void *insertPos = 0;
+ void *insertPos = nullptr;
if (ExtQuals *eq = ExtQualNodes.FindNodeOrInsertPos(ID, insertPos)) {
assert(eq->getQualifiers() == quals);
return QualType(eq, fastQuals);
@@ -2080,12 +2083,12 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
QualType Result;
if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(T)) {
- Result = getFunctionNoProtoType(FNPT->getResultType(), Info);
+ Result = getFunctionNoProtoType(FNPT->getReturnType(), Info);
} else {
const FunctionProtoType *FPT = cast<FunctionProtoType>(T);
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = Info;
- Result = getFunctionType(FPT->getResultType(), FPT->getArgTypes(), EPI);
+ Result = getFunctionType(FPT->getReturnType(), FPT->getParamTypes(), EPI);
}
return cast<FunctionType>(Result.getTypePtr());
@@ -2097,7 +2100,7 @@ void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD,
while (true) {
const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
- FD->setType(getFunctionType(ResultType, FPT->getArgTypes(), EPI));
+ FD->setType(getFunctionType(ResultType, FPT->getParamTypes(), EPI));
if (FunctionDecl *Next = FD->getPreviousDecl())
FD = Next;
else
@@ -2115,7 +2118,7 @@ QualType ASTContext::getComplexType(QualType T) const {
llvm::FoldingSetNodeID ID;
ComplexType::Profile(ID, T);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (ComplexType *CT = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(CT, 0);
@@ -2127,7 +2130,7 @@ QualType ASTContext::getComplexType(QualType T) const {
// Get the new insert position for the node we care about.
ComplexType *NewIP = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
+ assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
}
ComplexType *New = new (*this, TypeAlignment) ComplexType(T, Canonical);
Types.push_back(New);
@@ -2143,7 +2146,7 @@ QualType ASTContext::getPointerType(QualType T) const {
llvm::FoldingSetNodeID ID;
PointerType::Profile(ID, T);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (PointerType *PT = PointerTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(PT, 0);
@@ -2155,7 +2158,7 @@ QualType ASTContext::getPointerType(QualType T) const {
// Get the new insert position for the node we care about.
PointerType *NewIP = PointerTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
+ assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
}
PointerType *New = new (*this, TypeAlignment) PointerType(T, Canonical);
Types.push_back(New);
@@ -2163,15 +2166,30 @@ QualType ASTContext::getPointerType(QualType T) const {
return QualType(New, 0);
}
+QualType ASTContext::getAdjustedType(QualType Orig, QualType New) const {
+ llvm::FoldingSetNodeID ID;
+ AdjustedType::Profile(ID, Orig, New);
+ void *InsertPos = nullptr;
+ AdjustedType *AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
+ if (AT)
+ return QualType(AT, 0);
+
+ QualType Canonical = getCanonicalType(New);
+
+ // Get the new insert position for the node we care about.
+ AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!AT && "Shouldn't be in the map!");
+
+ AT = new (*this, TypeAlignment)
+ AdjustedType(Type::Adjusted, Orig, New, Canonical);
+ Types.push_back(AT);
+ AdjustedTypes.InsertNode(AT, InsertPos);
+ return QualType(AT, 0);
+}
+
QualType ASTContext::getDecayedType(QualType T) const {
assert((T->isArrayType() || T->isFunctionType()) && "T does not decay");
- llvm::FoldingSetNodeID ID;
- DecayedType::Profile(ID, T);
- void *InsertPos = 0;
- if (DecayedType *DT = DecayedTypes.FindNodeOrInsertPos(ID, InsertPos))
- return QualType(DT, 0);
-
QualType Decayed;
// C99 6.7.5.3p7:
@@ -2189,17 +2207,23 @@ QualType ASTContext::getDecayedType(QualType T) const {
if (T->isFunctionType())
Decayed = getPointerType(T);
+ llvm::FoldingSetNodeID ID;
+ AdjustedType::Profile(ID, T, Decayed);
+ void *InsertPos = nullptr;
+ AdjustedType *AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
+ if (AT)
+ return QualType(AT, 0);
+
QualType Canonical = getCanonicalType(Decayed);
// Get the new insert position for the node we care about.
- DecayedType *NewIP = DecayedTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
+ AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!AT && "Shouldn't be in the map!");
- DecayedType *New =
- new (*this, TypeAlignment) DecayedType(T, Decayed, Canonical);
- Types.push_back(New);
- DecayedTypes.InsertNode(New, InsertPos);
- return QualType(New, 0);
+ AT = new (*this, TypeAlignment) DecayedType(T, Decayed, Canonical);
+ Types.push_back(AT);
+ AdjustedTypes.InsertNode(AT, InsertPos);
+ return QualType(AT, 0);
}
/// getBlockPointerType - Return the uniqued reference to the type for
@@ -2211,7 +2235,7 @@ QualType ASTContext::getBlockPointerType(QualType T) const {
llvm::FoldingSetNodeID ID;
BlockPointerType::Profile(ID, T);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (BlockPointerType *PT =
BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(PT, 0);
@@ -2225,7 +2249,7 @@ QualType ASTContext::getBlockPointerType(QualType T) const {
// Get the new insert position for the node we care about.
BlockPointerType *NewIP =
BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
+ assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
}
BlockPointerType *New
= new (*this, TypeAlignment) BlockPointerType(T, Canonical);
@@ -2246,7 +2270,7 @@ ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) const {
llvm::FoldingSetNodeID ID;
ReferenceType::Profile(ID, T, SpelledAsLValue);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (LValueReferenceType *RT =
LValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(RT, 0);
@@ -2263,7 +2287,7 @@ ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) const {
// Get the new insert position for the node we care about.
LValueReferenceType *NewIP =
LValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
+ assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
}
LValueReferenceType *New
@@ -2283,7 +2307,7 @@ QualType ASTContext::getRValueReferenceType(QualType T) const {
llvm::FoldingSetNodeID ID;
ReferenceType::Profile(ID, T, false);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (RValueReferenceType *RT =
RValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(RT, 0);
@@ -2300,7 +2324,7 @@ QualType ASTContext::getRValueReferenceType(QualType T) const {
// Get the new insert position for the node we care about.
RValueReferenceType *NewIP =
RValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
+ assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
}
RValueReferenceType *New
@@ -2318,7 +2342,7 @@ QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) const {
llvm::FoldingSetNodeID ID;
MemberPointerType::Profile(ID, T, Cls);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (MemberPointerType *PT =
MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(PT, 0);
@@ -2332,7 +2356,7 @@ QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) const {
// Get the new insert position for the node we care about.
MemberPointerType *NewIP =
MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
+ assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
}
MemberPointerType *New
= new (*this, TypeAlignment) MemberPointerType(T, Cls, Canonical);
@@ -2360,7 +2384,7 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
llvm::FoldingSetNodeID ID;
ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, IndexTypeQuals);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (ConstantArrayType *ATP =
ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(ATP, 0);
@@ -2377,7 +2401,7 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
// Get the new insert position for the node we care about.
ConstantArrayType *NewIP =
ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
+ assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
}
ConstantArrayType *New = new(*this,TypeAlignment)
@@ -2495,7 +2519,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
const IncompleteArrayType *iat = cast<IncompleteArrayType>(ty);
result = getVariableArrayType(
getVariableArrayDecayedType(iat->getElementType()),
- /*size*/ 0,
+ /*size*/ nullptr,
ArrayType::Normal,
iat->getIndexTypeCVRQualifiers(),
SourceRange());
@@ -2507,7 +2531,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
const VariableArrayType *vat = cast<VariableArrayType>(ty);
result = getVariableArrayType(
getVariableArrayDecayedType(vat->getElementType()),
- /*size*/ 0,
+ /*size*/ nullptr,
ArrayType::Star,
vat->getIndexTypeCVRQualifiers(),
vat->getBracketsRange());
@@ -2577,7 +2601,7 @@ QualType ASTContext::getDependentSizedArrayType(QualType elementType,
SplitQualType canonElementType = getCanonicalType(elementType).split();
- void *insertPos = 0;
+ void *insertPos = nullptr;
llvm::FoldingSetNodeID ID;
DependentSizedArrayType::Profile(ID, *this,
QualType(canonElementType.Ty, 0),
@@ -2622,7 +2646,7 @@ QualType ASTContext::getIncompleteArrayType(QualType elementType,
llvm::FoldingSetNodeID ID;
IncompleteArrayType::Profile(ID, elementType, ASM, elementTypeQuals);
- void *insertPos = 0;
+ void *insertPos = nullptr;
if (IncompleteArrayType *iat =
IncompleteArrayTypes.FindNodeOrInsertPos(ID, insertPos))
return QualType(iat, 0);
@@ -2662,7 +2686,7 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts,
llvm::FoldingSetNodeID ID;
VectorType::Profile(ID, vecType, NumElts, Type::Vector, VecKind);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(VTP, 0);
@@ -2674,7 +2698,7 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts,
// Get the new insert position for the node we care about.
VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
+ assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
}
VectorType *New = new (*this, TypeAlignment)
VectorType(vecType, NumElts, Canonical, VecKind);
@@ -2693,7 +2717,7 @@ ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) const {
llvm::FoldingSetNodeID ID;
VectorType::Profile(ID, vecType, NumElts, Type::ExtVector,
VectorType::GenericVector);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(VTP, 0);
@@ -2705,7 +2729,7 @@ ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) const {
// Get the new insert position for the node we care about.
VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
+ assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
}
ExtVectorType *New = new (*this, TypeAlignment)
ExtVectorType(vecType, NumElts, Canonical);
@@ -2722,7 +2746,7 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType,
DependentSizedExtVectorType::Profile(ID, *this, getCanonicalType(vecType),
SizeExpr);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
DependentSizedExtVectorType *Canon
= DependentSizedExtVectorTypes.FindNodeOrInsertPos(ID, InsertPos);
DependentSizedExtVectorType *New;
@@ -2768,7 +2792,7 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy,
llvm::FoldingSetNodeID ID;
FunctionNoProtoType::Profile(ID, ResultTy, Info);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (FunctionNoProtoType *FT =
FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(FT, 0);
@@ -2780,7 +2804,7 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy,
// Get the new insert position for the node we care about.
FunctionNoProtoType *NewIP =
FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
+ assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
}
FunctionProtoType::ExtInfo newInfo = Info.withCallingConv(CallConv);
@@ -2798,8 +2822,6 @@ static bool isCanonicalResultType(QualType T) {
T.getObjCLifetime() == Qualifiers::OCL_ExplicitNone);
}
-/// getFunctionType - Return a normal function type with a typed argument
-/// list. isVariadic indicates whether the argument list includes '...'.
QualType
ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
const FunctionProtoType::ExtProtoInfo &EPI) const {
@@ -2811,7 +2833,7 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
FunctionProtoType::Profile(ID, ResultTy, ArgArray.begin(), NumArgs, EPI,
*this);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (FunctionProtoType *FTP =
FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(FTP, 0);
@@ -2851,7 +2873,7 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
// Get the new insert position for the node we care about.
FunctionProtoType *NewIP =
FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
+ assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
}
// FunctionProtoType objects are allocated with extra bytes after
@@ -2873,7 +2895,7 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
} else if (EPI.ExceptionSpecType == EST_Unevaluated) {
Size += sizeof(FunctionDecl*);
}
- if (EPI.ConsumedArguments)
+ if (EPI.ConsumedParameters)
Size += NumArgs * sizeof(bool);
FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
@@ -2995,7 +3017,7 @@ QualType ASTContext::getAttributedType(AttributedType::Kind attrKind,
llvm::FoldingSetNodeID id;
AttributedType::Profile(id, attrKind, modifiedType, equivalentType);
- void *insertPos = 0;
+ void *insertPos = nullptr;
AttributedType *type = AttributedTypes.FindNodeOrInsertPos(id, insertPos);
if (type) return QualType(type, 0);
@@ -3019,7 +3041,7 @@ ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm,
llvm::FoldingSetNodeID ID;
SubstTemplateTypeParmType::Profile(ID, Parm, Replacement);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
SubstTemplateTypeParmType *SubstParm
= SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -3038,17 +3060,15 @@ QualType ASTContext::getSubstTemplateTypeParmPackType(
const TemplateTypeParmType *Parm,
const TemplateArgument &ArgPack) {
#ifndef NDEBUG
- for (TemplateArgument::pack_iterator P = ArgPack.pack_begin(),
- PEnd = ArgPack.pack_end();
- P != PEnd; ++P) {
- assert(P->getKind() == TemplateArgument::Type &&"Pack contains a non-type");
- assert(P->getAsType().isCanonical() && "Pack contains non-canonical type");
+ for (const auto &P : ArgPack.pack_elements()) {
+ assert(P.getKind() == TemplateArgument::Type &&"Pack contains a non-type");
+ assert(P.getAsType().isCanonical() && "Pack contains non-canonical type");
}
#endif
llvm::FoldingSetNodeID ID;
SubstTemplateTypeParmPackType::Profile(ID, Parm, ArgPack);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (SubstTemplateTypeParmPackType *SubstParm
= SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(SubstParm, 0);
@@ -3077,7 +3097,7 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
TemplateTypeParmDecl *TTPDecl) const {
llvm::FoldingSetNodeID ID;
TemplateTypeParmType::Profile(ID, Depth, Index, ParameterPack, TTPDecl);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
TemplateTypeParmType *TypeParm
= TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -3218,7 +3238,7 @@ ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template,
TemplateSpecializationType::Profile(ID, CanonTemplate,
CanonArgs.data(), NumArgs, *this);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
TemplateSpecializationType *Spec
= TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -3246,7 +3266,7 @@ ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword,
llvm::FoldingSetNodeID ID;
ElaboratedType::Profile(ID, Keyword, NNS, NamedType);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
if (T)
return QualType(T, 0);
@@ -3270,7 +3290,7 @@ ASTContext::getParenType(QualType InnerType) const {
llvm::FoldingSetNodeID ID;
ParenType::Profile(ID, InnerType);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
ParenType *T = ParenTypes.FindNodeOrInsertPos(ID, InsertPos);
if (T)
return QualType(T, 0);
@@ -3293,8 +3313,6 @@ QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS,
const IdentifierInfo *Name,
QualType Canon) const {
- assert(NNS->isDependent() && "nested-name-specifier must be dependent");
-
if (Canon.isNull()) {
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
ElaboratedTypeKeyword CanonKeyword = Keyword;
@@ -3308,7 +3326,7 @@ QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
llvm::FoldingSetNodeID ID;
DependentNameType::Profile(ID, Keyword, NNS, Name);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
DependentNameType *T
= DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos);
if (T)
@@ -3349,7 +3367,7 @@ ASTContext::getDependentTemplateSpecializationType(
DependentTemplateSpecializationType::Profile(ID, *this, Keyword, NNS,
Name, NumArgs, Args);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
DependentTemplateSpecializationType *T
= DependentTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
if (T)
@@ -3395,7 +3413,7 @@ QualType ASTContext::getPackExpansionType(QualType Pattern,
assert(Pattern->containsUnexpandedParameterPack() &&
"Pack expansions must expand one or more parameter packs");
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
PackExpansionType *T
= PackExpansionTypes.FindNodeOrInsertPos(ID, InsertPos);
if (T)
@@ -3408,7 +3426,7 @@ QualType ASTContext::getPackExpansionType(QualType Pattern,
// contains an alias template specialization which ignores one of its
// parameters.
if (Canon->containsUnexpandedParameterPack()) {
- Canon = getPackExpansionType(getCanonicalType(Pattern), NumExpansions);
+ Canon = getPackExpansionType(Canon, NumExpansions);
// Find the insert position again, in case we inserted an element into
// PackExpansionTypes and invalidated our insert position.
@@ -3419,7 +3437,7 @@ QualType ASTContext::getPackExpansionType(QualType Pattern,
T = new (*this) PackExpansionType(Pattern, Canon, NumExpansions);
Types.push_back(T);
PackExpansionTypes.InsertNode(T, InsertPos);
- return QualType(T, 0);
+ return QualType(T, 0);
}
/// CmpProtocolNames - Comparison predicate for sorting protocols
@@ -3470,7 +3488,7 @@ QualType ASTContext::getObjCObjectType(QualType BaseType,
// Look in the folding set for an existing type.
llvm::FoldingSetNodeID ID;
ObjCObjectTypeImpl::Profile(ID, BaseType, Protocols, NumProtocols);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (ObjCObjectType *QT = ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(QT, 0);
@@ -3507,13 +3525,79 @@ QualType ASTContext::getObjCObjectType(QualType BaseType,
return QualType(T, 0);
}
+/// ObjCObjectAdoptsQTypeProtocols - Checks that protocols in IC's
+/// protocol list adopt all protocols in QT's qualified-id protocol
+/// list.
+bool ASTContext::ObjCObjectAdoptsQTypeProtocols(QualType QT,
+ ObjCInterfaceDecl *IC) {
+ if (!QT->isObjCQualifiedIdType())
+ return false;
+
+ if (const ObjCObjectPointerType *OPT = QT->getAs<ObjCObjectPointerType>()) {
+ // If both the right and left sides have qualifiers.
+ for (auto *Proto : OPT->quals()) {
+ if (!IC->ClassImplementsProtocol(Proto, false))
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+/// QIdProtocolsAdoptObjCObjectProtocols - Checks that protocols in
+/// QT's qualified-id protocol list adopt all protocols in IDecl's list
+/// of protocols.
+bool ASTContext::QIdProtocolsAdoptObjCObjectProtocols(QualType QT,
+ ObjCInterfaceDecl *IDecl) {
+ if (!QT->isObjCQualifiedIdType())
+ return false;
+ const ObjCObjectPointerType *OPT = QT->getAs<ObjCObjectPointerType>();
+ if (!OPT)
+ return false;
+ if (!IDecl->hasDefinition())
+ return false;
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 8> InheritedProtocols;
+ CollectInheritedProtocols(IDecl, InheritedProtocols);
+ if (InheritedProtocols.empty())
+ return false;
+ // Check that if every protocol in list of id<plist> conforms to a protcol
+ // of IDecl's, then bridge casting is ok.
+ bool Conforms = false;
+ for (auto *Proto : OPT->quals()) {
+ Conforms = false;
+ for (auto *PI : InheritedProtocols) {
+ if (ProtocolCompatibleWithProtocol(Proto, PI)) {
+ Conforms = true;
+ break;
+ }
+ }
+ if (!Conforms)
+ break;
+ }
+ if (Conforms)
+ return true;
+
+ for (auto *PI : InheritedProtocols) {
+ // If both the right and left sides have qualifiers.
+ bool Adopts = false;
+ for (auto *Proto : OPT->quals()) {
+ // return 'true' if 'PI' is in the inheritance hierarchy of Proto
+ if ((Adopts = ProtocolCompatibleWithProtocol(PI, Proto)))
+ break;
+ }
+ if (!Adopts)
+ return false;
+ }
+ return true;
+}
+
/// getObjCObjectPointerType - Return a ObjCObjectPointerType type for
/// the given object type.
QualType ASTContext::getObjCObjectPointerType(QualType ObjectT) const {
llvm::FoldingSetNodeID ID;
ObjCObjectPointerType::Profile(ID, ObjectT);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (ObjCObjectPointerType *QT =
ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(QT, 0);
@@ -3572,7 +3656,7 @@ QualType ASTContext::getTypeOfExprType(Expr *tofExpr) const {
llvm::FoldingSetNodeID ID;
DependentTypeOfExprType::Profile(ID, *this, tofExpr);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
DependentTypeOfExprType *Canon
= DependentTypeOfExprTypes.FindNodeOrInsertPos(ID, InsertPos);
if (Canon) {
@@ -3596,10 +3680,10 @@ QualType ASTContext::getTypeOfExprType(Expr *tofExpr) const {
}
/// getTypeOfType - Unlike many "get<Type>" functions, we don't unique
-/// TypeOfType AST's. The only motivation to unique these nodes would be
+/// TypeOfType nodes. The only motivation to unique these nodes would be
/// memory savings. Since typeof(t) is fairly uncommon, space shouldn't be
-/// an issue. This doesn't effect the type checker, since it operates
-/// on canonical type's (which are always unique).
+/// an issue. This doesn't affect the type checker, since it operates
+/// on canonical types (which are always unique).
QualType ASTContext::getTypeOfType(QualType tofType) const {
QualType Canonical = getCanonicalType(tofType);
TypeOfType *tot = new (*this, TypeAlignment) TypeOfType(tofType, Canonical);
@@ -3608,39 +3692,34 @@ QualType ASTContext::getTypeOfType(QualType tofType) const {
}
-/// getDecltypeType - Unlike many "get<Type>" functions, we don't unique
-/// DecltypeType AST's. The only motivation to unique these nodes would be
-/// memory savings. Since decltype(t) is fairly uncommon, space shouldn't be
-/// an issue. This doesn't effect the type checker, since it operates
-/// on canonical types (which are always unique).
+/// \brief Unlike many "get<Type>" functions, we don't unique DecltypeType
+/// nodes. This would never be helpful, since each such type has its own
+/// expression, and would not give a significant memory saving, since there
+/// is an Expr tree under each such type.
QualType ASTContext::getDecltypeType(Expr *e, QualType UnderlyingType) const {
DecltypeType *dt;
-
- // C++0x [temp.type]p2:
+
+ // C++11 [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).
+ // 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);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
DependentDecltypeType *Canon
= DependentDecltypeTypes.FindNodeOrInsertPos(ID, InsertPos);
- if (Canon) {
- // We already have a "canonical" version of an equivalent, dependent
- // decltype type. Use that as our canonical type.
- dt = new (*this, TypeAlignment) DecltypeType(e, UnderlyingType,
- QualType((DecltypeType*)Canon, 0));
- } else {
+ if (!Canon) {
// Build a new, canonical typeof(expr) type.
Canon = new (*this, TypeAlignment) DependentDecltypeType(*this, e);
DependentDecltypeTypes.InsertNode(Canon, InsertPos);
- dt = Canon;
}
+ dt = new (*this, TypeAlignment)
+ DecltypeType(e, UnderlyingType, QualType((DecltypeType *)Canon, 0));
} else {
- dt = new (*this, TypeAlignment) DecltypeType(e, UnderlyingType,
- getCanonicalType(UnderlyingType));
+ dt = new (*this, TypeAlignment)
+ DecltypeType(e, UnderlyingType, getCanonicalType(UnderlyingType));
}
Types.push_back(dt);
return QualType(dt, 0);
@@ -3670,7 +3749,7 @@ QualType ASTContext::getAutoType(QualType DeducedType, bool IsDecltypeAuto,
return getAutoDeductType();
// Look in the folding set for an existing type.
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
llvm::FoldingSetNodeID ID;
AutoType::Profile(ID, DeducedType, IsDecltypeAuto, IsDependent);
if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
@@ -3693,7 +3772,7 @@ QualType ASTContext::getAtomicType(QualType T) const {
llvm::FoldingSetNodeID ID;
AtomicType::Profile(ID, T);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (AtomicType *AT = AtomicTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(AT, 0);
@@ -3705,7 +3784,7 @@ QualType ASTContext::getAtomicType(QualType T) const {
// Get the new insert position for the node we care about.
AtomicType *NewIP = AtomicTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
+ assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
}
AtomicType *New = new (*this, TypeAlignment) AtomicType(T, Canonical);
Types.push_back(New);
@@ -4064,7 +4143,7 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
NestedNameSpecifier *
ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
if (!NNS)
- return 0;
+ return nullptr;
switch (NNS->getKind()) {
case NestedNameSpecifier::Identifier:
@@ -4076,13 +4155,13 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
case NestedNameSpecifier::Namespace:
// A namespace is canonical; build a nested-name-specifier with
// this namespace and no prefix.
- return NestedNameSpecifier::Create(*this, 0,
+ return NestedNameSpecifier::Create(*this, nullptr,
NNS->getAsNamespace()->getOriginalNamespace());
case NestedNameSpecifier::NamespaceAlias:
// A namespace is canonical; build a nested-name-specifier with
// this namespace and no prefix.
- return NestedNameSpecifier::Create(*this, 0,
+ return NestedNameSpecifier::Create(*this, nullptr,
NNS->getAsNamespaceAlias()->getNamespace()
->getOriginalNamespace());
@@ -4104,8 +4183,8 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
// Otherwise, just canonicalize the type, and force it to be a TypeSpec.
// FIXME: Why are TypeSpec and TypeSpecWithTemplate distinct in the
// first place?
- return NestedNameSpecifier::Create(*this, 0, false,
- const_cast<Type*>(T.getTypePtr()));
+ return NestedNameSpecifier::Create(*this, nullptr, false,
+ const_cast<Type *>(T.getTypePtr()));
}
case NestedNameSpecifier::Global:
@@ -4127,7 +4206,7 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const {
// Handle the common negative case fast.
if (!isa<ArrayType>(T.getCanonicalType()))
- return 0;
+ return nullptr;
// Apply any qualifiers from the array type to the element type. This
// implements C99 6.7.3p8: "If the specification of an array type includes
@@ -4142,7 +4221,7 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const {
// If we have a simple case, just return now.
const ArrayType *ATy = dyn_cast<ArrayType>(split.Ty);
- if (ATy == 0 || qs.empty())
+ if (!ATy || qs.empty())
return ATy;
// Otherwise, we have an array and we have qualifiers on it. Push the
@@ -4428,7 +4507,7 @@ static const Type *getIntegerTypeForEnum(const EnumType *ET) {
// FIXME: In C++, enum types are never integer types.
if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped())
return ET->getDecl()->getIntegerType().getTypePtr();
- return NULL;
+ return nullptr;
}
/// getIntegerTypeOrder - Returns the highest ranked integer type:
@@ -4479,22 +4558,10 @@ int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) const {
return 1;
}
-static RecordDecl *
-CreateRecordDecl(const ASTContext &Ctx, RecordDecl::TagKind TK,
- DeclContext *DC, IdentifierInfo *Id) {
- SourceLocation Loc;
- if (Ctx.getLangOpts().CPlusPlus)
- return CXXRecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id);
- else
- return RecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id);
-}
-
// getCFConstantStringType - Return the type used for constant CFStrings.
QualType ASTContext::getCFConstantStringType() const {
if (!CFConstantStringTypeDecl) {
- CFConstantStringTypeDecl =
- CreateRecordDecl(*this, TTK_Struct, TUDecl,
- &Idents.get("NSConstantString"));
+ CFConstantStringTypeDecl = buildImplicitRecord("NSConstantString");
CFConstantStringTypeDecl->startDefinition();
QualType FieldTypes[4];
@@ -4512,9 +4579,9 @@ QualType ASTContext::getCFConstantStringType() const {
for (unsigned i = 0; i < 4; ++i) {
FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl,
SourceLocation(),
- SourceLocation(), 0,
- FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0,
+ SourceLocation(), nullptr,
+ FieldTypes[i], /*TInfo=*/nullptr,
+ /*BitWidth=*/nullptr,
/*Mutable=*/false,
ICIS_NoInit);
Field->setAccess(AS_public);
@@ -4529,8 +4596,7 @@ QualType ASTContext::getCFConstantStringType() const {
QualType ASTContext::getObjCSuperType() const {
if (ObjCSuperType.isNull()) {
- RecordDecl *ObjCSuperTypeDecl =
- CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get("objc_super"));
+ RecordDecl *ObjCSuperTypeDecl = buildImplicitRecord("objc_super");
TUDecl->addDecl(ObjCSuperTypeDecl);
ObjCSuperType = getTagDeclType(ObjCSuperTypeDecl);
}
@@ -4547,12 +4613,11 @@ QualType ASTContext::getBlockDescriptorType() const {
if (BlockDescriptorType)
return getTagDeclType(BlockDescriptorType);
- RecordDecl *T;
+ RecordDecl *RD;
// FIXME: Needs the FlagAppleBlock bit.
- T = CreateRecordDecl(*this, TTK_Struct, TUDecl,
- &Idents.get("__block_descriptor"));
- T->startDefinition();
-
+ RD = buildImplicitRecord("__block_descriptor");
+ RD->startDefinition();
+
QualType FieldTypes[] = {
UnsignedLongTy,
UnsignedLongTy,
@@ -4564,20 +4629,17 @@ QualType ASTContext::getBlockDescriptorType() const {
};
for (size_t i = 0; i < 2; ++i) {
- FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
- SourceLocation(),
- &Idents.get(FieldNames[i]),
- FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0,
- /*Mutable=*/false,
- ICIS_NoInit);
+ FieldDecl *Field = FieldDecl::Create(
+ *this, RD, SourceLocation(), SourceLocation(),
+ &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/false, ICIS_NoInit);
Field->setAccess(AS_public);
- T->addDecl(Field);
+ RD->addDecl(Field);
}
- T->completeDefinition();
+ RD->completeDefinition();
- BlockDescriptorType = T;
+ BlockDescriptorType = RD;
return getTagDeclType(BlockDescriptorType);
}
@@ -4586,12 +4648,11 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
if (BlockDescriptorExtendedType)
return getTagDeclType(BlockDescriptorExtendedType);
- RecordDecl *T;
+ RecordDecl *RD;
// FIXME: Needs the FlagAppleBlock bit.
- T = CreateRecordDecl(*this, TTK_Struct, TUDecl,
- &Idents.get("__block_descriptor_withcopydispose"));
- T->startDefinition();
-
+ RD = buildImplicitRecord("__block_descriptor_withcopydispose");
+ RD->startDefinition();
+
QualType FieldTypes[] = {
UnsignedLongTy,
UnsignedLongTy,
@@ -4607,21 +4668,18 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
};
for (size_t i = 0; i < 4; ++i) {
- FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
- SourceLocation(),
- &Idents.get(FieldNames[i]),
- FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0,
- /*Mutable=*/false,
- ICIS_NoInit);
+ FieldDecl *Field = FieldDecl::Create(
+ *this, RD, SourceLocation(), SourceLocation(),
+ &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/nullptr,
+ /*BitWidth=*/nullptr,
+ /*Mutable=*/false, ICIS_NoInit);
Field->setAccess(AS_public);
- T->addDecl(Field);
+ RD->addDecl(Field);
}
- T->completeDefinition();
-
- BlockDescriptorExtendedType = T;
+ RD->completeDefinition();
+ BlockDescriptorExtendedType = RD;
return getTagDeclType(BlockDescriptorExtendedType);
}
@@ -4691,12 +4749,8 @@ bool ASTContext::getByrefLifetime(QualType Ty,
TypedefDecl *ASTContext::getObjCInstanceTypeDecl() {
if (!ObjCInstanceTypeDecl)
- ObjCInstanceTypeDecl = TypedefDecl::Create(*this,
- getTranslationUnitDecl(),
- SourceLocation(),
- SourceLocation(),
- &Idents.get("instancetype"),
- getTrivialTypeSourceInfo(getObjCIdType()));
+ ObjCInstanceTypeDecl =
+ buildImplicitTypedef(getObjCIdType(), "instancetype");
return ObjCInstanceTypeDecl;
}
@@ -4727,6 +4781,12 @@ CharUnits ASTContext::getObjCEncodingTypeSize(QualType type) const {
return sz;
}
+bool ASTContext::isMSStaticDataMemberInlineDefinition(const VarDecl *VD) const {
+ return getLangOpts().MSVCCompat && VD->isStaticDataMember() &&
+ VD->getType()->isIntegralOrEnumerationType() &&
+ !VD->getFirstDecl()->isOutOfLine() && VD->getFirstDecl()->hasInit();
+}
+
static inline
std::string charUnitsToString(const CharUnits &CU) {
return llvm::itostr(CU.getQuantity());
@@ -4742,21 +4802,19 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
Expr->getType()->getAs<BlockPointerType>()->getPointeeType();
// Encode result type.
if (getLangOpts().EncodeExtendedBlockSig)
- getObjCEncodingForMethodParameter(Decl::OBJC_TQ_None,
- BlockTy->getAs<FunctionType>()->getResultType(),
- S, true /*Extended*/);
+ getObjCEncodingForMethodParameter(
+ Decl::OBJC_TQ_None, BlockTy->getAs<FunctionType>()->getReturnType(), S,
+ true /*Extended*/);
else
- getObjCEncodingForType(BlockTy->getAs<FunctionType>()->getResultType(),
- S);
+ getObjCEncodingForType(BlockTy->getAs<FunctionType>()->getReturnType(), S);
// Compute size of all parameters.
// Start with computing size of a pointer in number of bytes.
// FIXME: There might(should) be a better way of doing this computation!
SourceLocation Loc;
CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy);
CharUnits ParmOffset = PtrSize;
- for (BlockDecl::param_const_iterator PI = Decl->param_begin(),
- E = Decl->param_end(); PI != E; ++PI) {
- QualType PType = (*PI)->getType();
+ for (auto PI : Decl->params()) {
+ QualType PType = PI->getType();
CharUnits sz = getObjCEncodingTypeSize(PType);
if (sz.isZero())
continue;
@@ -4770,9 +4828,7 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
// Argument types.
ParmOffset = PtrSize;
- for (BlockDecl::param_const_iterator PI = Decl->param_begin(), E =
- Decl->param_end(); PI != E; ++PI) {
- ParmVarDecl *PVDecl = *PI;
+ for (auto PVDecl : Decl->params()) {
QualType PType = PVDecl->getOriginalType();
if (const ArrayType *AT =
dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) {
@@ -4797,12 +4853,11 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
bool ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl,
std::string& S) {
// Encode result type.
- getObjCEncodingForType(Decl->getResultType(), S);
+ getObjCEncodingForType(Decl->getReturnType(), S);
CharUnits ParmOffset;
// Compute size of all parameters.
- for (FunctionDecl::param_const_iterator PI = Decl->param_begin(),
- E = Decl->param_end(); PI != E; ++PI) {
- QualType PType = (*PI)->getType();
+ for (auto PI : Decl->params()) {
+ QualType PType = PI->getType();
CharUnits sz = getObjCEncodingTypeSize(PType);
if (sz.isZero())
continue;
@@ -4815,9 +4870,7 @@ bool ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl,
ParmOffset = CharUnits::Zero();
// Argument types.
- for (FunctionDecl::param_const_iterator PI = Decl->param_begin(),
- E = Decl->param_end(); PI != E; ++PI) {
- ParmVarDecl *PVDecl = *PI;
+ for (auto PVDecl : Decl->params()) {
QualType PType = PVDecl->getOriginalType();
if (const ArrayType *AT =
dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) {
@@ -4844,7 +4897,7 @@ void ASTContext::getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT,
// Encode type qualifer, 'in', 'inout', etc. for the parameter.
getObjCEncodingForTypeQualifier(QT, S);
// Encode parameter type.
- getObjCEncodingForTypeImpl(T, S, true, true, 0,
+ getObjCEncodingForTypeImpl(T, S, true, true, nullptr,
true /*OutermostType*/,
false /*EncodingProperty*/,
false /*StructField*/,
@@ -4859,8 +4912,8 @@ bool ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
bool Extended) const {
// FIXME: This is not very efficient.
// Encode return type.
- getObjCEncodingForMethodParameter(Decl->getObjCDeclQualifier(),
- Decl->getResultType(), S, Extended);
+ getObjCEncodingForMethodParameter(Decl->getObjCDeclQualifier(),
+ Decl->getReturnType(), S, Extended);
// Compute size of all parameters.
// Start with computing size of a pointer in number of bytes.
// FIXME: There might(should) be a better way of doing this computation!
@@ -4907,6 +4960,26 @@ bool ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
return false;
}
+ObjCPropertyImplDecl *
+ASTContext::getObjCPropertyImplDeclForPropertyDecl(
+ const ObjCPropertyDecl *PD,
+ const Decl *Container) const {
+ if (!Container)
+ return nullptr;
+ if (const ObjCCategoryImplDecl *CID =
+ dyn_cast<ObjCCategoryImplDecl>(Container)) {
+ for (auto *PID : CID->property_impls())
+ if (PID->getPropertyDecl() == PD)
+ return PID;
+ } else {
+ const ObjCImplementationDecl *OID=cast<ObjCImplementationDecl>(Container);
+ for (auto *PID : OID->property_impls())
+ if (PID->getPropertyDecl() == PD)
+ return PID;
+ }
+ return nullptr;
+}
+
/// getObjCEncodingForPropertyDecl - Return the encoded type for this
/// property declaration. If non-NULL, Container must be either an
/// ObjCCategoryImplDecl or ObjCImplementationDecl; it should only be
@@ -4937,39 +5010,14 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
std::string& S) const {
// Collect information from the property implementation decl(s).
bool Dynamic = false;
- ObjCPropertyImplDecl *SynthesizePID = 0;
-
- // FIXME: Duplicated code due to poor abstraction.
- if (Container) {
- if (const ObjCCategoryImplDecl *CID =
- dyn_cast<ObjCCategoryImplDecl>(Container)) {
- for (ObjCCategoryImplDecl::propimpl_iterator
- i = CID->propimpl_begin(), e = CID->propimpl_end();
- i != e; ++i) {
- ObjCPropertyImplDecl *PID = *i;
- if (PID->getPropertyDecl() == PD) {
- if (PID->getPropertyImplementation()==ObjCPropertyImplDecl::Dynamic) {
- Dynamic = true;
- } else {
- SynthesizePID = PID;
- }
- }
- }
- } else {
- const ObjCImplementationDecl *OID=cast<ObjCImplementationDecl>(Container);
- for (ObjCCategoryImplDecl::propimpl_iterator
- i = OID->propimpl_begin(), e = OID->propimpl_end();
- i != e; ++i) {
- ObjCPropertyImplDecl *PID = *i;
- if (PID->getPropertyDecl() == PD) {
- if (PID->getPropertyImplementation()==ObjCPropertyImplDecl::Dynamic) {
- Dynamic = true;
- } else {
- SynthesizePID = PID;
- }
- }
- }
- }
+ ObjCPropertyImplDecl *SynthesizePID = nullptr;
+
+ if (ObjCPropertyImplDecl *PropertyImpDecl =
+ getObjCPropertyImplDeclForPropertyDecl(PD, Container)) {
+ if (PropertyImpDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
+ Dynamic = true;
+ else
+ SynthesizePID = PropertyImpDecl;
}
// FIXME: This is not very efficient.
@@ -4978,9 +5026,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
// Encode result type.
// GCC has some special rules regarding encoding of properties which
// closely resembles encoding of ivars.
- getObjCEncodingForTypeImpl(PD->getType(), S, true, true, 0,
- true /* outermost type */,
- true /* encoding for property */);
+ getObjCEncodingForPropertyType(PD->getType(), S);
if (PD->isReadOnly()) {
S += ",R";
@@ -4988,6 +5034,8 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
S += ",C";
if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain)
S += ",&";
+ if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)
+ S += ",W";
} else {
switch (PD->getSetterKind()) {
case ObjCPropertyDecl::Assign: break;
@@ -5051,6 +5099,16 @@ void ASTContext::getObjCEncodingForType(QualType T, std::string& S,
true /* outermost type */);
}
+void ASTContext::getObjCEncodingForPropertyType(QualType T,
+ std::string& S) const {
+ // Encode result type.
+ // GCC has some special rules regarding encoding of properties which
+ // closely resembles encoding of ivars.
+ getObjCEncodingForTypeImpl(T, S, true, true, nullptr,
+ true /* outermost type */,
+ true /* encoding property */);
+}
+
static char getObjCEncodingForPrimitiveKind(const ASTContext *C,
BuiltinType::Kind kind) {
switch (kind) {
@@ -5180,15 +5238,15 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
case Type::Complex: {
const ComplexType *CT = T->castAs<ComplexType>();
S += 'j';
- getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false,
- false);
+ getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, nullptr,
+ false, false);
return;
}
case Type::Atomic: {
const AtomicType *AT = T->castAs<AtomicType>();
S += 'A';
- getObjCEncodingForTypeImpl(AT->getValueType(), S, false, false, 0,
+ getObjCEncodingForTypeImpl(AT->getValueType(), S, false, false, nullptr,
false, false);
return;
}
@@ -5260,7 +5318,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
getLegacyIntegralTypeEncoding(PointeeTy);
getObjCEncodingForTypeImpl(PointeeTy, S, false, ExpandPointedToStructures,
- NULL);
+ nullptr);
return;
}
@@ -5322,9 +5380,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
if (!RDecl->isUnion()) {
getObjCEncodingForStructureImpl(RDecl, S, FD);
} else {
- for (RecordDecl::field_iterator Field = RDecl->field_begin(),
- FieldEnd = RDecl->field_end();
- Field != FieldEnd; ++Field) {
+ for (const auto *Field : RDecl->fields()) {
if (FD) {
S += '"';
S += Field->getNameAsString();
@@ -5334,7 +5390,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
// Special case bit-fields.
if (Field->isBitField()) {
getObjCEncodingForTypeImpl(Field->getType(), S, false, true,
- *Field);
+ Field);
} else {
QualType qt = Field->getType();
getLegacyIntegralTypeEncoding(qt);
@@ -5358,37 +5414,38 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
S += '<';
// Block return type
- getObjCEncodingForTypeImpl(FT->getResultType(), S,
- ExpandPointedToStructures, ExpandStructures,
- FD,
- false /* OutermostType */,
- EncodingProperty,
- false /* StructField */,
- EncodeBlockParameters,
- EncodeClassNames);
+ getObjCEncodingForTypeImpl(
+ FT->getReturnType(), S, ExpandPointedToStructures, ExpandStructures,
+ FD, false /* OutermostType */, EncodingProperty,
+ false /* StructField */, EncodeBlockParameters, EncodeClassNames);
// Block self
S += "@?";
// Block parameters
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT)) {
- for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin(),
- E = FPT->arg_type_end(); I && (I != E); ++I) {
- getObjCEncodingForTypeImpl(*I, S,
- ExpandPointedToStructures,
- ExpandStructures,
- FD,
- false /* OutermostType */,
- EncodingProperty,
- false /* StructField */,
- EncodeBlockParameters,
- EncodeClassNames);
- }
+ for (const auto &I : FPT->param_types())
+ getObjCEncodingForTypeImpl(
+ I, S, ExpandPointedToStructures, ExpandStructures, FD,
+ false /* OutermostType */, EncodingProperty,
+ false /* StructField */, EncodeBlockParameters, EncodeClassNames);
}
S += '>';
}
return;
}
- case Type::ObjCObject:
+ case Type::ObjCObject: {
+ // hack to match legacy encoding of *id and *Class
+ QualType Ty = getObjCObjectPointerType(CT);
+ if (Ty->isObjCIdType()) {
+ S += "{objc_object=}";
+ return;
+ }
+ else if (Ty->isObjCClassType()) {
+ S += "{objc_class=}";
+ return;
+ }
+ }
+
case Type::ObjCInterface: {
// Ignore protocol qualifiers when mangling at this level.
T = T->castAs<ObjCObjectType>()->getBaseType();
@@ -5440,10 +5497,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
// Note that we do extended encoding of protocol qualifer list
// Only when doing ivar or property encoding.
S += '"';
- for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
- E = OPT->qual_end(); I != E; ++I) {
+ for (const auto *I : OPT->quals()) {
S += '<';
- S += (*I)->getNameAsString();
+ S += I->getNameAsString();
S += '>';
}
S += '"';
@@ -5475,7 +5531,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
}
getObjCEncodingForTypeImpl(PointeeTy, S,
false, ExpandPointedToStructures,
- NULL,
+ nullptr,
false, false, false, false, false,
/*EncodePointerToObjCTypedef*/true);
return;
@@ -5486,10 +5542,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
(FD || EncodingProperty || EncodeClassNames)) {
S += '"';
S += OPT->getInterfaceDecl()->getIdentifier()->getName();
- for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
- E = OPT->qual_end(); I != E; ++I) {
+ for (const auto *I : OPT->quals()) {
S += '<';
- S += (*I)->getNameAsString();
+ S += I->getNameAsString();
S += '>';
}
S += '"';
@@ -5542,11 +5597,9 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
const ASTRecordLayout &layout = getASTRecordLayout(RDecl);
if (CXXRec) {
- for (CXXRecordDecl::base_class_iterator
- BI = CXXRec->bases_begin(),
- BE = CXXRec->bases_end(); BI != BE; ++BI) {
- if (!BI->isVirtual()) {
- CXXRecordDecl *base = BI->getType()->getAsCXXRecordDecl();
+ for (const auto &BI : CXXRec->bases()) {
+ if (!BI.isVirtual()) {
+ CXXRecordDecl *base = BI.getType()->getAsCXXRecordDecl();
if (base->isEmpty())
continue;
uint64_t offs = toBits(layout.getBaseClassOffset(base));
@@ -5566,10 +5619,8 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
}
if (CXXRec && includeVBases) {
- for (CXXRecordDecl::base_class_iterator
- BI = CXXRec->vbases_begin(),
- BE = CXXRec->vbases_end(); BI != BE; ++BI) {
- CXXRecordDecl *base = BI->getType()->getAsCXXRecordDecl();
+ for (const auto &BI : CXXRec->vbases()) {
+ CXXRecordDecl *base = BI.getType()->getAsCXXRecordDecl();
if (base->isEmpty())
continue;
uint64_t offs = toBits(layout.getVBaseClassOffset(base));
@@ -5587,7 +5638,9 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
size = layout.getSize();
}
+#ifndef NDEBUG
uint64_t CurOffs = 0;
+#endif
std::multimap<uint64_t, NamedDecl *>::iterator
CurLayObj = FieldOrBaseOffsets.begin();
@@ -5601,19 +5654,21 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
S += '"';
}
S += "^^?";
+#ifndef NDEBUG
CurOffs += getTypeSize(VoidPtrTy);
+#endif
}
if (!RDecl->hasFlexibleArrayMember()) {
// Mark the end of the structure.
uint64_t offs = toBits(size);
FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs),
- std::make_pair(offs, (NamedDecl*)0));
+ std::make_pair(offs, nullptr));
}
for (; CurLayObj != FieldOrBaseOffsets.end(); ++CurLayObj) {
+#ifndef NDEBUG
assert(CurOffs <= CurLayObj->first);
-
if (CurOffs < CurLayObj->first) {
uint64_t padding = CurLayObj->first - CurOffs;
// FIXME: There doesn't seem to be a way to indicate in the encoding that
@@ -5625,9 +5680,10 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
// longer then though.
CurOffs += padding;
}
+#endif
NamedDecl *dcl = CurLayObj->second;
- if (dcl == 0)
+ if (!dcl)
break; // reached end of structure.
if (CXXRecordDecl *base = dyn_cast<CXXRecordDecl>(dcl)) {
@@ -5637,7 +5693,9 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
// making the encoding type bigger than it really is.
getObjCEncodingForStructureImpl(base, S, FD, /*includeVBases*/false);
assert(!base->isEmpty());
+#ifndef NDEBUG
CurOffs += toBits(getASTRecordLayout(base).getNonVirtualSize());
+#endif
} else {
FieldDecl *field = cast<FieldDecl>(dcl);
if (FD) {
@@ -5648,7 +5706,9 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
if (field->isBitField()) {
EncodeBitField(this, S, field->getType(), field);
+#ifndef NDEBUG
CurOffs += field->getBitWidthValue(*this);
+#endif
} else {
QualType qt = field->getType();
getLegacyIntegralTypeEncoding(qt);
@@ -5656,7 +5716,9 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
/*OutermostType*/false,
/*EncodingProperty*/false,
/*StructField*/true);
+#ifndef NDEBUG
CurOffs += getTypeSize(field->getType());
+#endif
}
}
}
@@ -5680,41 +5742,27 @@ void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT,
TypedefDecl *ASTContext::getObjCIdDecl() const {
if (!ObjCIdDecl) {
- QualType T = getObjCObjectType(ObjCBuiltinIdTy, 0, 0);
+ QualType T = getObjCObjectType(ObjCBuiltinIdTy, nullptr, 0);
T = getObjCObjectPointerType(T);
- TypeSourceInfo *IdInfo = getTrivialTypeSourceInfo(T);
- ObjCIdDecl = TypedefDecl::Create(const_cast<ASTContext &>(*this),
- getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Idents.get("id"), IdInfo);
+ ObjCIdDecl = buildImplicitTypedef(T, "id");
}
-
return ObjCIdDecl;
}
TypedefDecl *ASTContext::getObjCSelDecl() const {
if (!ObjCSelDecl) {
- QualType SelT = getPointerType(ObjCBuiltinSelTy);
- TypeSourceInfo *SelInfo = getTrivialTypeSourceInfo(SelT);
- ObjCSelDecl = TypedefDecl::Create(const_cast<ASTContext &>(*this),
- getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Idents.get("SEL"), SelInfo);
+ QualType T = getPointerType(ObjCBuiltinSelTy);
+ ObjCSelDecl = buildImplicitTypedef(T, "SEL");
}
return ObjCSelDecl;
}
TypedefDecl *ASTContext::getObjCClassDecl() const {
if (!ObjCClassDecl) {
- QualType T = getObjCObjectType(ObjCBuiltinClassTy, 0, 0);
+ QualType T = getObjCObjectType(ObjCBuiltinClassTy, nullptr, 0);
T = getObjCObjectPointerType(T);
- TypeSourceInfo *ClassInfo = getTrivialTypeSourceInfo(T);
- ObjCClassDecl = TypedefDecl::Create(const_cast<ASTContext &>(*this),
- getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Idents.get("Class"), ClassInfo);
+ ObjCClassDecl = buildImplicitTypedef(T, "Class");
}
-
return ObjCClassDecl;
}
@@ -5724,7 +5772,7 @@ ObjCInterfaceDecl *ASTContext::getObjCProtocolDecl() const {
= ObjCInterfaceDecl::Create(*this, getTranslationUnitDecl(),
SourceLocation(),
&Idents.get("Protocol"),
- /*PrevDecl=*/0,
+ /*PrevDecl=*/nullptr,
SourceLocation(), true);
}
@@ -5737,56 +5785,30 @@ ObjCInterfaceDecl *ASTContext::getObjCProtocolDecl() const {
static TypedefDecl *CreateCharPtrBuiltinVaListDecl(const ASTContext *Context) {
// typedef char* __builtin_va_list;
- QualType CharPtrType = Context->getPointerType(Context->CharTy);
- TypeSourceInfo *TInfo
- = Context->getTrivialTypeSourceInfo(CharPtrType);
-
- TypedefDecl *VaListTypeDecl
- = TypedefDecl::Create(const_cast<ASTContext &>(*Context),
- Context->getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Context->Idents.get("__builtin_va_list"),
- TInfo);
- return VaListTypeDecl;
+ QualType T = Context->getPointerType(Context->CharTy);
+ return Context->buildImplicitTypedef(T, "__builtin_va_list");
}
static TypedefDecl *CreateVoidPtrBuiltinVaListDecl(const ASTContext *Context) {
// typedef void* __builtin_va_list;
- QualType VoidPtrType = Context->getPointerType(Context->VoidTy);
- TypeSourceInfo *TInfo
- = Context->getTrivialTypeSourceInfo(VoidPtrType);
-
- TypedefDecl *VaListTypeDecl
- = TypedefDecl::Create(const_cast<ASTContext &>(*Context),
- Context->getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Context->Idents.get("__builtin_va_list"),
- TInfo);
- return VaListTypeDecl;
+ QualType T = Context->getPointerType(Context->VoidTy);
+ return Context->buildImplicitTypedef(T, "__builtin_va_list");
}
static TypedefDecl *
CreateAArch64ABIBuiltinVaListDecl(const ASTContext *Context) {
- RecordDecl *VaListTagDecl;
+ // struct __va_list
+ RecordDecl *VaListTagDecl = Context->buildImplicitRecord("__va_list");
if (Context->getLangOpts().CPlusPlus) {
// namespace std { struct __va_list {
NamespaceDecl *NS;
NS = NamespaceDecl::Create(const_cast<ASTContext &>(*Context),
Context->getTranslationUnitDecl(),
- /*Inline*/false, SourceLocation(),
+ /*Inline*/ false, SourceLocation(),
SourceLocation(), &Context->Idents.get("std"),
- /*PrevDecl*/0);
-
- VaListTagDecl = CXXRecordDecl::Create(*Context, TTK_Struct,
- Context->getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Context->Idents.get("__va_list"));
+ /*PrevDecl*/ nullptr);
+ NS->setImplicit();
VaListTagDecl->setDeclContext(NS);
- } else {
- // struct __va_list
- VaListTagDecl = CreateRecordDecl(*Context, TTK_Struct,
- Context->getTranslationUnitDecl(),
- &Context->Idents.get("__va_list"));
}
VaListTagDecl->startDefinition();
@@ -5822,8 +5844,8 @@ CreateAArch64ABIBuiltinVaListDecl(const ASTContext *Context) {
SourceLocation(),
SourceLocation(),
&Context->Idents.get(FieldNames[i]),
- FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0,
+ FieldTypes[i], /*TInfo=*/nullptr,
+ /*BitWidth=*/nullptr,
/*Mutable=*/false,
ICIS_NoInit);
Field->setAccess(AS_public);
@@ -5834,23 +5856,14 @@ CreateAArch64ABIBuiltinVaListDecl(const ASTContext *Context) {
Context->VaListTagTy = VaListTagType;
// } __builtin_va_list;
- TypedefDecl *VaListTypedefDecl
- = TypedefDecl::Create(const_cast<ASTContext &>(*Context),
- Context->getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Context->Idents.get("__builtin_va_list"),
- Context->getTrivialTypeSourceInfo(VaListTagType));
-
- return VaListTypedefDecl;
+ return Context->buildImplicitTypedef(VaListTagType, "__builtin_va_list");
}
static TypedefDecl *CreatePowerABIBuiltinVaListDecl(const ASTContext *Context) {
// typedef struct __va_list_tag {
RecordDecl *VaListTagDecl;
- VaListTagDecl = CreateRecordDecl(*Context, TTK_Struct,
- Context->getTranslationUnitDecl(),
- &Context->Idents.get("__va_list_tag"));
+ VaListTagDecl = Context->buildImplicitRecord("__va_list_tag");
VaListTagDecl->startDefinition();
const size_t NumFields = 5;
@@ -5883,8 +5896,8 @@ static TypedefDecl *CreatePowerABIBuiltinVaListDecl(const ASTContext *Context) {
SourceLocation(),
SourceLocation(),
&Context->Idents.get(FieldNames[i]),
- FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0,
+ FieldTypes[i], /*TInfo=*/nullptr,
+ /*BitWidth=*/nullptr,
/*Mutable=*/false,
ICIS_NoInit);
Field->setAccess(AS_public);
@@ -5895,12 +5908,9 @@ static TypedefDecl *CreatePowerABIBuiltinVaListDecl(const ASTContext *Context) {
Context->VaListTagTy = VaListTagType;
// } __va_list_tag;
- TypedefDecl *VaListTagTypedefDecl
- = TypedefDecl::Create(const_cast<ASTContext &>(*Context),
- Context->getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Context->Idents.get("__va_list_tag"),
- Context->getTrivialTypeSourceInfo(VaListTagType));
+ TypedefDecl *VaListTagTypedefDecl =
+ Context->buildImplicitTypedef(VaListTagType, "__va_list_tag");
+
QualType VaListTagTypedefType =
Context->getTypedefType(VaListTagTypedefDecl);
@@ -5909,25 +5919,14 @@ static TypedefDecl *CreatePowerABIBuiltinVaListDecl(const ASTContext *Context) {
QualType VaListTagArrayType
= Context->getConstantArrayType(VaListTagTypedefType,
Size, ArrayType::Normal, 0);
- TypeSourceInfo *TInfo
- = Context->getTrivialTypeSourceInfo(VaListTagArrayType);
- TypedefDecl *VaListTypedefDecl
- = TypedefDecl::Create(const_cast<ASTContext &>(*Context),
- Context->getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Context->Idents.get("__builtin_va_list"),
- TInfo);
-
- return VaListTypedefDecl;
+ return Context->buildImplicitTypedef(VaListTagArrayType, "__builtin_va_list");
}
static TypedefDecl *
CreateX86_64ABIBuiltinVaListDecl(const ASTContext *Context) {
// typedef struct __va_list_tag {
RecordDecl *VaListTagDecl;
- VaListTagDecl = CreateRecordDecl(*Context, TTK_Struct,
- Context->getTranslationUnitDecl(),
- &Context->Idents.get("__va_list_tag"));
+ VaListTagDecl = Context->buildImplicitRecord("__va_list_tag");
VaListTagDecl->startDefinition();
const size_t NumFields = 4;
@@ -5957,8 +5956,8 @@ CreateX86_64ABIBuiltinVaListDecl(const ASTContext *Context) {
SourceLocation(),
SourceLocation(),
&Context->Idents.get(FieldNames[i]),
- FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0,
+ FieldTypes[i], /*TInfo=*/nullptr,
+ /*BitWidth=*/nullptr,
/*Mutable=*/false,
ICIS_NoInit);
Field->setAccess(AS_public);
@@ -5969,12 +5968,9 @@ CreateX86_64ABIBuiltinVaListDecl(const ASTContext *Context) {
Context->VaListTagTy = VaListTagType;
// } __va_list_tag;
- TypedefDecl *VaListTagTypedefDecl
- = TypedefDecl::Create(const_cast<ASTContext &>(*Context),
- Context->getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Context->Idents.get("__va_list_tag"),
- Context->getTrivialTypeSourceInfo(VaListTagType));
+ TypedefDecl *VaListTagTypedefDecl =
+ Context->buildImplicitTypedef(VaListTagType, "__va_list_tag");
+
QualType VaListTagTypedefType =
Context->getTypedefType(VaListTagTypedefDecl);
@@ -5983,16 +5979,7 @@ CreateX86_64ABIBuiltinVaListDecl(const ASTContext *Context) {
QualType VaListTagArrayType
= Context->getConstantArrayType(VaListTagTypedefType,
Size, ArrayType::Normal,0);
- TypeSourceInfo *TInfo
- = Context->getTrivialTypeSourceInfo(VaListTagArrayType);
- TypedefDecl *VaListTypedefDecl
- = TypedefDecl::Create(const_cast<ASTContext &>(*Context),
- Context->getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Context->Idents.get("__builtin_va_list"),
- TInfo);
-
- return VaListTypedefDecl;
+ return Context->buildImplicitTypedef(VaListTagArrayType, "__builtin_va_list");
}
static TypedefDecl *CreatePNaClABIBuiltinVaListDecl(const ASTContext *Context) {
@@ -6001,19 +5988,13 @@ static TypedefDecl *CreatePNaClABIBuiltinVaListDecl(const ASTContext *Context) {
QualType IntArrayType
= Context->getConstantArrayType(Context->IntTy,
Size, ArrayType::Normal, 0);
- TypedefDecl *VaListTypedefDecl
- = TypedefDecl::Create(const_cast<ASTContext &>(*Context),
- Context->getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Context->Idents.get("__builtin_va_list"),
- Context->getTrivialTypeSourceInfo(IntArrayType));
-
- return VaListTypedefDecl;
+ return Context->buildImplicitTypedef(IntArrayType, "__builtin_va_list");
}
static TypedefDecl *
CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) {
- RecordDecl *VaListDecl;
+ // struct __va_list
+ RecordDecl *VaListDecl = Context->buildImplicitRecord("__va_list");
if (Context->getLangOpts().CPlusPlus) {
// namespace std { struct __va_list {
NamespaceDecl *NS;
@@ -6021,20 +6002,9 @@ CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) {
Context->getTranslationUnitDecl(),
/*Inline*/false, SourceLocation(),
SourceLocation(), &Context->Idents.get("std"),
- /*PrevDecl*/0);
-
- VaListDecl = CXXRecordDecl::Create(*Context, TTK_Struct,
- Context->getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Context->Idents.get("__va_list"));
-
+ /*PrevDecl*/ nullptr);
+ NS->setImplicit();
VaListDecl->setDeclContext(NS);
-
- } else {
- // struct __va_list {
- VaListDecl = CreateRecordDecl(*Context, TTK_Struct,
- Context->getTranslationUnitDecl(),
- &Context->Idents.get("__va_list"));
}
VaListDecl->startDefinition();
@@ -6046,8 +6016,8 @@ CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) {
SourceLocation(),
&Context->Idents.get("__ap"),
Context->getPointerType(Context->VoidTy),
- /*TInfo=*/0,
- /*BitWidth=*/0,
+ /*TInfo=*/nullptr,
+ /*BitWidth=*/nullptr,
/*Mutable=*/false,
ICIS_NoInit);
Field->setAccess(AS_public);
@@ -6057,26 +6027,15 @@ CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) {
VaListDecl->completeDefinition();
// typedef struct __va_list __builtin_va_list;
- TypeSourceInfo *TInfo
- = Context->getTrivialTypeSourceInfo(Context->getRecordType(VaListDecl));
-
- TypedefDecl *VaListTypeDecl
- = TypedefDecl::Create(const_cast<ASTContext &>(*Context),
- Context->getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Context->Idents.get("__builtin_va_list"),
- TInfo);
-
- return VaListTypeDecl;
+ QualType T = Context->getRecordType(VaListDecl);
+ return Context->buildImplicitTypedef(T, "__builtin_va_list");
}
static TypedefDecl *
CreateSystemZBuiltinVaListDecl(const ASTContext *Context) {
// typedef struct __va_list_tag {
RecordDecl *VaListTagDecl;
- VaListTagDecl = CreateRecordDecl(*Context, TTK_Struct,
- Context->getTranslationUnitDecl(),
- &Context->Idents.get("__va_list_tag"));
+ VaListTagDecl = Context->buildImplicitRecord("__va_list_tag");
VaListTagDecl->startDefinition();
const size_t NumFields = 4;
@@ -6106,8 +6065,8 @@ CreateSystemZBuiltinVaListDecl(const ASTContext *Context) {
SourceLocation(),
SourceLocation(),
&Context->Idents.get(FieldNames[i]),
- FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0,
+ FieldTypes[i], /*TInfo=*/nullptr,
+ /*BitWidth=*/nullptr,
/*Mutable=*/false,
ICIS_NoInit);
Field->setAccess(AS_public);
@@ -6118,12 +6077,8 @@ CreateSystemZBuiltinVaListDecl(const ASTContext *Context) {
Context->VaListTagTy = VaListTagType;
// } __va_list_tag;
- TypedefDecl *VaListTagTypedefDecl
- = TypedefDecl::Create(const_cast<ASTContext &>(*Context),
- Context->getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Context->Idents.get("__va_list_tag"),
- Context->getTrivialTypeSourceInfo(VaListTagType));
+ TypedefDecl *VaListTagTypedefDecl =
+ Context->buildImplicitTypedef(VaListTagType, "__va_list_tag");
QualType VaListTagTypedefType =
Context->getTypedefType(VaListTagTypedefDecl);
@@ -6132,16 +6087,8 @@ CreateSystemZBuiltinVaListDecl(const ASTContext *Context) {
QualType VaListTagArrayType
= Context->getConstantArrayType(VaListTagTypedefType,
Size, ArrayType::Normal,0);
- TypeSourceInfo *TInfo
- = Context->getTrivialTypeSourceInfo(VaListTagArrayType);
- TypedefDecl *VaListTypedefDecl
- = TypedefDecl::Create(const_cast<ASTContext &>(*Context),
- Context->getTranslationUnitDecl(),
- SourceLocation(), SourceLocation(),
- &Context->Idents.get("__builtin_va_list"),
- TInfo);
- return VaListTypedefDecl;
+ return Context->buildImplicitTypedef(VaListTagArrayType, "__builtin_va_list");
}
static TypedefDecl *CreateVaListDecl(const ASTContext *Context,
@@ -6169,8 +6116,10 @@ static TypedefDecl *CreateVaListDecl(const ASTContext *Context,
}
TypedefDecl *ASTContext::getBuiltinVaListDecl() const {
- if (!BuiltinVaListDecl)
+ if (!BuiltinVaListDecl) {
BuiltinVaListDecl = CreateVaListDecl(this, Target->getBuiltinVaListKind());
+ assert(BuiltinVaListDecl->isImplicit());
+ }
return BuiltinVaListDecl;
}
@@ -6227,7 +6176,7 @@ ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
llvm::FoldingSetNodeID ID;
QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
QualifiedTemplateName *QTN =
QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
if (!QTN) {
@@ -6250,7 +6199,7 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
llvm::FoldingSetNodeID ID;
DependentTemplateName::Profile(ID, NNS, Name);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
DependentTemplateName *QTN =
DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
@@ -6285,8 +6234,8 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
llvm::FoldingSetNodeID ID;
DependentTemplateName::Profile(ID, NNS, Operator);
-
- void *InsertPos = 0;
+
+ void *InsertPos = nullptr;
DependentTemplateName *QTN
= DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
@@ -6317,8 +6266,8 @@ ASTContext::getSubstTemplateTemplateParm(TemplateTemplateParmDecl *param,
TemplateName replacement) const {
llvm::FoldingSetNodeID ID;
SubstTemplateTemplateParmStorage::Profile(ID, param, replacement);
-
- void *insertPos = 0;
+
+ void *insertPos = nullptr;
SubstTemplateTemplateParmStorage *subst
= SubstTemplateTemplateParms.FindNodeOrInsertPos(ID, insertPos);
@@ -6336,8 +6285,8 @@ ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param,
ASTContext &Self = const_cast<ASTContext &>(*this);
llvm::FoldingSetNodeID ID;
SubstTemplateTemplateParmPackStorage::Profile(ID, Self, Param, ArgPack);
-
- void *InsertPos = 0;
+
+ void *InsertPos = nullptr;
SubstTemplateTemplateParmPackStorage *Subst
= SubstTemplateTemplateParmPacks.FindNodeOrInsertPos(ID, InsertPos);
@@ -6454,9 +6403,8 @@ ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
ObjCProtocolDecl *rProto) const {
if (declaresSameEntity(lProto, rProto))
return true;
- for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(),
- E = rProto->protocol_end(); PI != E; ++PI)
- if (ProtocolCompatibleWithProtocol(lProto, *PI))
+ for (auto *PI : rProto->protocols())
+ if (ProtocolCompatibleWithProtocol(lProto, PI))
return true;
return false;
}
@@ -6469,13 +6417,9 @@ bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs,
const ObjCObjectPointerType *rhsOPT = rhs->getAs<ObjCObjectPointerType>();
assert ((lhsQID && rhsOPT) && "ObjCQualifiedClassTypesAreCompatible");
- for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
- E = lhsQID->qual_end(); I != E; ++I) {
+ for (auto *lhsProto : lhsQID->quals()) {
bool match = false;
- ObjCProtocolDecl *lhsProto = *I;
- for (ObjCObjectPointerType::qual_iterator J = rhsOPT->qual_begin(),
- E = rhsOPT->qual_end(); J != E; ++J) {
- ObjCProtocolDecl *rhsProto = *J;
+ for (auto *rhsProto : rhsOPT->quals()) {
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto)) {
match = true;
break;
@@ -6508,12 +6452,11 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
// If the RHS is a unqualified interface pointer "NSString*",
// make sure we check the class hierarchy.
if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
- for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
- E = lhsQID->qual_end(); I != E; ++I) {
+ for (auto *I : lhsQID->quals()) {
// when comparing an id<P> on lhs with a static type on rhs,
// see if static class implements all of id's protocols, directly or
// through its super class and categories.
- if (!rhsID->ClassImplementsProtocol(*I, true))
+ if (!rhsID->ClassImplementsProtocol(I, true))
return false;
}
}
@@ -6521,17 +6464,13 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
return true;
}
// Both the right and left sides have qualifiers.
- for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
- E = lhsQID->qual_end(); I != E; ++I) {
- ObjCProtocolDecl *lhsProto = *I;
+ for (auto *lhsProto : lhsQID->quals()) {
bool match = false;
// when comparing an id<P> on lhs with a static type on rhs,
// see if static class implements all of id's protocols, directly or
// through its super class and categories.
- for (ObjCObjectPointerType::qual_iterator J = rhsOPT->qual_begin(),
- E = rhsOPT->qual_end(); J != E; ++J) {
- ObjCProtocolDecl *rhsProto = *J;
+ for (auto *rhsProto : rhsOPT->quals()) {
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
(compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
match = true;
@@ -6541,12 +6480,11 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
// If the RHS is a qualified interface pointer "NSString<P>*",
// make sure we check the class hierarchy.
if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
- for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
- E = lhsQID->qual_end(); I != E; ++I) {
+ for (auto *I : lhsQID->quals()) {
// when comparing an id<P> on lhs with a static type on rhs,
// see if static class implements all of id's protocols, directly or
// through its super class and categories.
- if (rhsID->ClassImplementsProtocol(*I, true)) {
+ if (rhsID->ClassImplementsProtocol(I, true)) {
match = true;
break;
}
@@ -6565,9 +6503,7 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
if (const ObjCObjectPointerType *lhsOPT =
lhs->getAsObjCInterfacePointerType()) {
// If both the right and left sides have qualifiers.
- for (ObjCObjectPointerType::qual_iterator I = lhsOPT->qual_begin(),
- E = lhsOPT->qual_end(); I != E; ++I) {
- ObjCProtocolDecl *lhsProto = *I;
+ for (auto *lhsProto : lhsOPT->quals()) {
bool match = false;
// when comparing an id<P> on rhs with a static type on lhs,
@@ -6575,9 +6511,7 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
// through its super class and categories.
// First, lhs protocols in the qualifier list must be found, direct
// or indirect in rhs's qualifier list or it is a mismatch.
- for (ObjCObjectPointerType::qual_iterator J = rhsQID->qual_begin(),
- E = rhsQID->qual_end(); J != E; ++J) {
- ObjCProtocolDecl *rhsProto = *J;
+ for (auto *rhsProto : rhsQID->quals()) {
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
(compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
match = true;
@@ -6598,14 +6532,9 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
// assume that it is mismatch.
if (LHSInheritedProtocols.empty() && lhsOPT->qual_empty())
return false;
- for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I =
- LHSInheritedProtocols.begin(),
- E = LHSInheritedProtocols.end(); I != E; ++I) {
+ for (auto *lhsProto : LHSInheritedProtocols) {
bool match = false;
- ObjCProtocolDecl *lhsProto = (*I);
- for (ObjCObjectPointerType::qual_iterator J = rhsQID->qual_begin(),
- E = rhsQID->qual_end(); J != E; ++J) {
- ObjCProtocolDecl *rhsProto = *J;
+ for (auto *rhsProto : rhsQID->quals()) {
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
(compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
match = true;
@@ -6798,16 +6727,9 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS,
if (SuperClassInheritedProtocols.empty())
return false;
- for (ObjCObjectType::qual_iterator LHSPI = LHS->qual_begin(),
- LHSPE = LHS->qual_end();
- LHSPI != LHSPE; LHSPI++) {
- bool SuperImplementsProtocol = false;
- ObjCProtocolDecl *LHSProto = (*LHSPI);
-
- for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I =
- SuperClassInheritedProtocols.begin(),
- E = SuperClassInheritedProtocols.end(); I != E; ++I) {
- ObjCProtocolDecl *SuperClassProto = (*I);
+ for (const auto *LHSProto : LHS->quals()) {
+ bool SuperImplementsProtocol = false;
+ for (auto *SuperClassProto : SuperClassInheritedProtocols) {
if (SuperClassProto->lookupProtocolNamed(LHSProto->getIdentifier())) {
SuperImplementsProtocol = true;
break;
@@ -6821,17 +6743,13 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS,
return false;
}
- for (ObjCObjectType::qual_iterator LHSPI = LHS->qual_begin(),
- LHSPE = LHS->qual_end();
- LHSPI != LHSPE; LHSPI++) {
+ for (const auto *LHSPI : LHS->quals()) {
bool RHSImplementsProtocol = false;
// If the RHS doesn't implement the protocol on the left, the types
// are incompatible.
- for (ObjCObjectType::qual_iterator RHSPI = RHS->qual_begin(),
- RHSPE = RHS->qual_end();
- RHSPI != RHSPE; RHSPI++) {
- if ((*RHSPI)->lookupProtocolNamed((*LHSPI)->getIdentifier())) {
+ for (auto *RHSPI : RHS->quals()) {
+ if (RHSPI->lookupProtocolNamed(LHSPI->getIdentifier())) {
RHSImplementsProtocol = true;
break;
}
@@ -6891,9 +6809,8 @@ QualType ASTContext::mergeTransparentUnionType(QualType T, QualType SubType,
if (const RecordType *UT = T->getAsUnionType()) {
RecordDecl *UD = UT->getDecl();
if (UD->hasAttr<TransparentUnionAttr>()) {
- for (RecordDecl::field_iterator it = UD->field_begin(),
- itend = UD->field_end(); it != itend; ++it) {
- QualType ET = it->getType().getUnqualifiedType();
+ for (const auto *I : UD->fields()) {
+ QualType ET = I->getType().getUnqualifiedType();
QualType MT = mergeTypes(ET, SubType, OfBlockPointer, Unqualified);
if (!MT.isNull())
return MT;
@@ -6904,11 +6821,11 @@ QualType ASTContext::mergeTransparentUnionType(QualType T, QualType SubType,
return QualType();
}
-/// mergeFunctionArgumentTypes - merge two types which appear as function
-/// argument types
-QualType ASTContext::mergeFunctionArgumentTypes(QualType lhs, QualType rhs,
- bool OfBlockPointer,
- bool Unqualified) {
+/// mergeFunctionParameterTypes - merge two types which appear as function
+/// parameter types
+QualType ASTContext::mergeFunctionParameterTypes(QualType lhs, QualType rhs,
+ bool OfBlockPointer,
+ bool Unqualified) {
// GNU extension: two types are compatible if they appear as a function
// argument, one of the types is a transparent union type and the other
// type is compatible with a union member
@@ -6938,23 +6855,23 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
// Check return type
QualType retType;
if (OfBlockPointer) {
- QualType RHS = rbase->getResultType();
- QualType LHS = lbase->getResultType();
+ QualType RHS = rbase->getReturnType();
+ QualType LHS = lbase->getReturnType();
bool UnqualifiedResult = Unqualified;
if (!UnqualifiedResult)
UnqualifiedResult = (!RHS.hasQualifiers() && LHS.hasQualifiers());
retType = mergeTypes(LHS, RHS, true, UnqualifiedResult, true);
}
else
- retType = mergeTypes(lbase->getResultType(), rbase->getResultType(), false,
+ retType = mergeTypes(lbase->getReturnType(), rbase->getReturnType(), false,
Unqualified);
if (retType.isNull()) return QualType();
if (Unqualified)
retType = retType.getUnqualifiedType();
- CanQualType LRetType = getCanonicalType(lbase->getResultType());
- CanQualType RRetType = getCanonicalType(rbase->getResultType());
+ CanQualType LRetType = getCanonicalType(lbase->getReturnType());
+ CanQualType RRetType = getCanonicalType(rbase->getReturnType());
if (Unqualified) {
LRetType = LRetType.getUnqualifiedType();
RRetType = RRetType.getUnqualifiedType();
@@ -6998,11 +6915,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (lproto && rproto) { // two C99 style function prototypes
assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() &&
"C++ shouldn't be here");
- unsigned lproto_nargs = lproto->getNumArgs();
- unsigned rproto_nargs = rproto->getNumArgs();
-
- // Compatible functions must have the same number of arguments
- if (lproto_nargs != rproto_nargs)
+ // Compatible functions must have the same number of parameters
+ if (lproto->getNumParams() != rproto->getNumParams())
return QualType();
// Variadic and non-variadic functions aren't compatible
@@ -7015,29 +6929,29 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (LangOpts.ObjCAutoRefCount &&
!FunctionTypesMatchOnNSConsumedAttrs(rproto, lproto))
return QualType();
-
- // Check argument compatibility
+
+ // Check parameter type compatibility
SmallVector<QualType, 10> types;
- for (unsigned i = 0; i < lproto_nargs; i++) {
- QualType largtype = lproto->getArgType(i).getUnqualifiedType();
- QualType rargtype = rproto->getArgType(i).getUnqualifiedType();
- QualType argtype = mergeFunctionArgumentTypes(largtype, rargtype,
- OfBlockPointer,
- Unqualified);
- if (argtype.isNull()) return QualType();
-
+ for (unsigned i = 0, n = lproto->getNumParams(); i < n; i++) {
+ QualType lParamType = lproto->getParamType(i).getUnqualifiedType();
+ QualType rParamType = rproto->getParamType(i).getUnqualifiedType();
+ QualType paramType = mergeFunctionParameterTypes(
+ lParamType, rParamType, OfBlockPointer, Unqualified);
+ if (paramType.isNull())
+ return QualType();
+
if (Unqualified)
- argtype = argtype.getUnqualifiedType();
-
- types.push_back(argtype);
+ paramType = paramType.getUnqualifiedType();
+
+ types.push_back(paramType);
if (Unqualified) {
- largtype = largtype.getUnqualifiedType();
- rargtype = rargtype.getUnqualifiedType();
+ lParamType = lParamType.getUnqualifiedType();
+ rParamType = rParamType.getUnqualifiedType();
}
-
- if (getCanonicalType(argtype) != getCanonicalType(largtype))
+
+ if (getCanonicalType(paramType) != getCanonicalType(lParamType))
allLTypes = false;
- if (getCanonicalType(argtype) != getCanonicalType(rargtype))
+ if (getCanonicalType(paramType) != getCanonicalType(rParamType))
allRTypes = false;
}
@@ -7061,20 +6975,19 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
// The only types actually affected are promotable integer
// types and floats, which would be passed as a different
// type depending on whether the prototype is visible.
- unsigned proto_nargs = proto->getNumArgs();
- for (unsigned i = 0; i < proto_nargs; ++i) {
- QualType argTy = proto->getArgType(i);
-
+ for (unsigned i = 0, n = proto->getNumParams(); i < n; ++i) {
+ QualType paramTy = proto->getParamType(i);
+
// Look at the converted type of enum types, since that is the type used
// to pass enum values.
- if (const EnumType *Enum = argTy->getAs<EnumType>()) {
- argTy = Enum->getDecl()->getIntegerType();
- if (argTy.isNull())
+ if (const EnumType *Enum = paramTy->getAs<EnumType>()) {
+ paramTy = Enum->getDecl()->getIntegerType();
+ if (paramTy.isNull())
return QualType();
}
-
- if (argTy->isPromotableIntegerType() ||
- getCanonicalType(argTy).getUnqualifiedType() == FloatTy)
+
+ if (paramTy->isPromotableIntegerType() ||
+ getCanonicalType(paramTy).getUnqualifiedType() == FloatTy)
return QualType();
}
@@ -7083,7 +6996,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
FunctionProtoType::ExtProtoInfo EPI = proto->getExtProtoInfo();
EPI.ExtInfo = einfo;
- return getFunctionType(retType, proto->getArgTypes(), EPI);
+ return getFunctionType(retType, proto->getParamTypes(), EPI);
}
if (allLTypes) return lhs;
@@ -7387,18 +7300,16 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
bool ASTContext::FunctionTypesMatchOnNSConsumedAttrs(
const FunctionProtoType *FromFunctionType,
const FunctionProtoType *ToFunctionType) {
- if (FromFunctionType->hasAnyConsumedArgs() !=
- ToFunctionType->hasAnyConsumedArgs())
+ if (FromFunctionType->hasAnyConsumedParams() !=
+ ToFunctionType->hasAnyConsumedParams())
return false;
FunctionProtoType::ExtProtoInfo FromEPI =
FromFunctionType->getExtProtoInfo();
FunctionProtoType::ExtProtoInfo ToEPI =
ToFunctionType->getExtProtoInfo();
- if (FromEPI.ConsumedArguments && ToEPI.ConsumedArguments)
- for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumArgs();
- ArgIdx != NumArgs; ++ArgIdx) {
- if (FromEPI.ConsumedArguments[ArgIdx] !=
- ToEPI.ConsumedArguments[ArgIdx])
+ if (FromEPI.ConsumedParameters && ToEPI.ConsumedParameters)
+ for (unsigned i = 0, n = FromFunctionType->getNumParams(); i != n; ++i) {
+ if (FromEPI.ConsumedParameters[i] != ToEPI.ConsumedParameters[i])
return false;
}
return true;
@@ -7416,10 +7327,10 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
if (RHSCan->isFunctionType()) {
if (!LHSCan->isFunctionType())
return QualType();
- QualType OldReturnType =
- cast<FunctionType>(RHSCan.getTypePtr())->getResultType();
+ QualType OldReturnType =
+ cast<FunctionType>(RHSCan.getTypePtr())->getReturnType();
QualType NewReturnType =
- cast<FunctionType>(LHSCan.getTypePtr())->getResultType();
+ cast<FunctionType>(LHSCan.getTypePtr())->getReturnType();
QualType ResReturnType =
mergeObjCGCQualifiers(NewReturnType, OldReturnType);
if (ResReturnType.isNull())
@@ -7432,7 +7343,7 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = getFunctionExtInfo(LHS);
QualType ResultType =
- getFunctionType(OldReturnType, FPT->getArgTypes(), EPI);
+ getFunctionType(OldReturnType, FPT->getParamTypes(), EPI);
return ResultType;
}
}
@@ -7573,6 +7484,19 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
assert(HowLong <= 2 && "Can't have LLLL modifier");
++HowLong;
break;
+ case 'W':
+ // This modifier represents int64 type.
+ assert(HowLong == 0 && "Can't use both 'L' and 'W' modifiers!");
+ switch (Context.getTargetInfo().getInt64Type()) {
+ default:
+ llvm_unreachable("Unexpected integer type");
+ case TargetInfo::SignedLong:
+ HowLong = 1;
+ break;
+ case TargetInfo::SignedLongLong:
+ HowLong = 2;
+ break;
+ }
}
}
@@ -7834,7 +7758,8 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
return getFunctionType(ResType, ArgTypes, EPI);
}
-GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
+static GVALinkage basicGVALinkageForFunction(const ASTContext &Context,
+ const FunctionDecl *FD) {
if (!FD->isExternallyVisible())
return GVA_Internal;
@@ -7846,68 +7771,126 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
break;
case TSK_ExplicitInstantiationDefinition:
- return GVA_ExplicitTemplateInstantiation;
+ return GVA_StrongODR;
+ // C++11 [temp.explicit]p10:
+ // [ Note: The intent is that an inline function that is the subject of
+ // an explicit instantiation declaration will still be implicitly
+ // instantiated when used so that the body can be considered for
+ // inlining, but that no out-of-line copy of the inline function would be
+ // generated in the translation unit. -- end note ]
case TSK_ExplicitInstantiationDeclaration:
+ return GVA_AvailableExternally;
+
case TSK_ImplicitInstantiation:
- External = GVA_TemplateInstantiation;
+ External = GVA_DiscardableODR;
break;
}
if (!FD->isInlined())
return External;
- if ((!getLangOpts().CPlusPlus && !getLangOpts().MicrosoftMode) ||
+ if ((!Context.getLangOpts().CPlusPlus && !Context.getLangOpts().MSVCCompat &&
+ !FD->hasAttr<DLLExportAttr>()) ||
FD->hasAttr<GNUInlineAttr>()) {
+ // FIXME: This doesn't match gcc's behavior for dllexport inline functions.
+
// GNU or C99 inline semantics. Determine whether this symbol should be
// externally visible.
if (FD->isInlineDefinitionExternallyVisible())
return External;
// C99 inline semantics, where the symbol is not externally visible.
- return GVA_C99Inline;
+ return GVA_AvailableExternally;
}
- // C++0x [temp.explicit]p9:
- // [ Note: The intent is that an inline function that is the subject of
- // an explicit instantiation declaration will still be implicitly
- // instantiated when used so that the body can be considered for
- // inlining, but that no out-of-line copy of the inline function would be
- // generated in the translation unit. -- end note ]
- if (FD->getTemplateSpecializationKind()
- == TSK_ExplicitInstantiationDeclaration)
- return GVA_C99Inline;
+ // Functions specified with extern and inline in -fms-compatibility mode
+ // forcibly get emitted. While the body of the function cannot be later
+ // replaced, the function definition cannot be discarded.
+ if (FD->getMostRecentDecl()->isMSExternInline())
+ return GVA_StrongODR;
- return GVA_CXXInline;
+ return GVA_DiscardableODR;
}
-GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
+static GVALinkage adjustGVALinkageForDLLAttribute(GVALinkage L, const Decl *D) {
+ // See http://msdn.microsoft.com/en-us/library/xa0d9ste.aspx
+ // dllexport/dllimport on inline functions.
+ if (D->hasAttr<DLLImportAttr>()) {
+ if (L == GVA_DiscardableODR || L == GVA_StrongODR)
+ return GVA_AvailableExternally;
+ } else if (D->hasAttr<DLLExportAttr>()) {
+ if (L == GVA_DiscardableODR)
+ return GVA_StrongODR;
+ }
+ return L;
+}
+
+GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const {
+ return adjustGVALinkageForDLLAttribute(basicGVALinkageForFunction(*this, FD),
+ FD);
+}
+
+static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
+ const VarDecl *VD) {
if (!VD->isExternallyVisible())
return GVA_Internal;
+ if (VD->isStaticLocal()) {
+ GVALinkage StaticLocalLinkage = GVA_DiscardableODR;
+ const DeclContext *LexicalContext = VD->getParentFunctionOrMethod();
+ while (LexicalContext && !isa<FunctionDecl>(LexicalContext))
+ LexicalContext = LexicalContext->getLexicalParent();
+
+ // Let the static local variable inherit it's linkage from the nearest
+ // enclosing function.
+ if (LexicalContext)
+ StaticLocalLinkage =
+ Context.GetGVALinkageForFunction(cast<FunctionDecl>(LexicalContext));
+
+ // GVA_StrongODR function linkage is stronger than what we need,
+ // downgrade to GVA_DiscardableODR.
+ // This allows us to discard the variable if we never end up needing it.
+ return StaticLocalLinkage == GVA_StrongODR ? GVA_DiscardableODR
+ : StaticLocalLinkage;
+ }
+
+ // MSVC treats in-class initialized static data members as definitions.
+ // By giving them non-strong linkage, out-of-line definitions won't
+ // cause link errors.
+ if (Context.isMSStaticDataMemberInlineDefinition(VD))
+ return GVA_DiscardableODR;
+
switch (VD->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
return GVA_StrongExternal;
- case TSK_ExplicitInstantiationDeclaration:
- llvm_unreachable("Variable should not be instantiated");
- // Fall through to treat this like any other instantiation.
-
case TSK_ExplicitInstantiationDefinition:
- return GVA_ExplicitTemplateInstantiation;
+ return GVA_StrongODR;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ return GVA_AvailableExternally;
case TSK_ImplicitInstantiation:
- return GVA_TemplateInstantiation;
+ return GVA_DiscardableODR;
}
llvm_unreachable("Invalid Linkage!");
}
+GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
+ return adjustGVALinkageForDLLAttribute(basicGVALinkageForVariable(*this, VD),
+ VD);
+}
+
bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!VD->isFileVarDecl())
return false;
+ // Global named register variables (GNU extension) are never emitted.
+ if (VD->getStorageClass() == SC_Register)
+ return false;
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// We never need to emit an uninstantiated function template.
if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
@@ -7954,8 +7937,8 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
// static, static inline, always_inline, and extern inline functions can
// always be deferred. Normal inline functions can be deferred in C99/C++.
// Implicit template instantiations can also be deferred in C++.
- if (Linkage == GVA_Internal || Linkage == GVA_C99Inline ||
- Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation)
+ if (Linkage == GVA_Internal || Linkage == GVA_AvailableExternally ||
+ Linkage == GVA_DiscardableODR)
return false;
return true;
}
@@ -7963,12 +7946,14 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
const VarDecl *VD = cast<VarDecl>(D);
assert(VD->isFileVarDecl() && "Expected file scoped var");
- if (VD->isThisDeclarationADefinition() == VarDecl::DeclarationOnly)
+ if (VD->isThisDeclarationADefinition() == VarDecl::DeclarationOnly &&
+ !isMSStaticDataMemberInlineDefinition(VD))
return false;
// Variables that can be needed in other TUs are required.
GVALinkage L = GetGVALinkageForVariable(VD);
- if (L != GVA_Internal && L != GVA_TemplateInstantiation)
+ if (L != GVA_Internal && L != GVA_AvailableExternally &&
+ L != GVA_DiscardableODR)
return true;
// Variables that have destruction with side-effects are required.
@@ -7996,12 +7981,23 @@ bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const {
return ABI->isNearlyEmpty(RD);
}
+VTableContextBase *ASTContext::getVTableContext() {
+ if (!VTContext.get()) {
+ if (Target->getCXXABI().isMicrosoft())
+ VTContext.reset(new MicrosoftVTableContext(*this));
+ else
+ VTContext.reset(new ItaniumVTableContext(*this));
+ }
+ return VTContext.get();
+}
+
MangleContext *ASTContext::createMangleContext() {
switch (Target->getCXXABI().getKind()) {
case TargetCXXABI::GenericAArch64:
case TargetCXXABI::GenericItanium:
case TargetCXXABI::GenericARM:
case TargetCXXABI::iOS:
+ case TargetCXXABI::iOS64:
return ItaniumMangleContext::create(*this, getDiagnostics());
case TargetCXXABI::Microsoft:
return MicrosoftMangleContext::create(*this, getDiagnostics());
@@ -8071,6 +8067,17 @@ unsigned ASTContext::getManglingNumber(const NamedDecl *ND) const {
return I != MangleNumbers.end() ? I->second : 1;
}
+void ASTContext::setStaticLocalNumber(const VarDecl *VD, unsigned Number) {
+ if (Number > 1)
+ StaticLocalNumbers[VD] = Number;
+}
+
+unsigned ASTContext::getStaticLocalNumber(const VarDecl *VD) const {
+ llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I =
+ StaticLocalNumbers.find(VD);
+ return I != StaticLocalNumbers.end() ? I->second : 1;
+}
+
MangleNumberingContext &
ASTContext::getManglingNumberContext(const DeclContext *DC) {
assert(LangOpts.CPlusPlus); // We don't need mangling numbers for plain C.
@@ -8105,7 +8112,7 @@ ASTContext::getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E,
llvm::DenseMap<const MaterializeTemporaryExpr *, APValue>::iterator I =
MaterializedTemporaryValues.find(E);
- return I == MaterializedTemporaryValues.end() ? 0 : &I->second;
+ return I == MaterializedTemporaryValues.end() ? nullptr : &I->second;
}
bool ASTContext::AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const {
@@ -8168,18 +8175,45 @@ namespace {
template <typename T>
bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *)) {
- if (Node == NULL)
+ if (!Node)
return true;
- if (ParentStack.size() > 0)
- // FIXME: Currently we add the same parent multiple times, for example
- // when we visit all subexpressions of template instantiations; this is
- // suboptimal, bug benign: the only way to visit those is with
- // hasAncestor / hasParent, and those do not create new matches.
+ if (ParentStack.size() > 0) {
+ // FIXME: Currently we add the same parent multiple times, but only
+ // when no memoization data is available for the type.
+ // For example when we visit all subexpressions of template
+ // instantiations; this is suboptimal, but benign: the only way to
+ // visit those is with hasAncestor / hasParent, and those do not create
+ // new matches.
// The plan is to enable DynTypedNode to be storable in a map or hash
// map. The main problem there is to implement hash functions /
// comparison operators for all types that DynTypedNode supports that
// do not have pointer identity.
- (*Parents)[Node].push_back(ParentStack.back());
+ auto &NodeOrVector = (*Parents)[Node];
+ if (NodeOrVector.isNull()) {
+ NodeOrVector = new ast_type_traits::DynTypedNode(ParentStack.back());
+ } else {
+ if (NodeOrVector.template is<ast_type_traits::DynTypedNode *>()) {
+ auto *Node =
+ NodeOrVector.template get<ast_type_traits::DynTypedNode *>();
+ auto *Vector = new ASTContext::ParentVector(1, *Node);
+ NodeOrVector = Vector;
+ delete Node;
+ }
+ assert(NodeOrVector.template is<ASTContext::ParentVector *>());
+
+ auto *Vector =
+ NodeOrVector.template get<ASTContext::ParentVector *>();
+ // Skip duplicates for types that have memoization data.
+ // We must check that the type has memoization data before calling
+ // std::find() because DynTypedNode::operator== can't compare all
+ // types.
+ bool Found = ParentStack.back().getMemoizationData() &&
+ std::find(Vector->begin(), Vector->end(),
+ ParentStack.back()) != Vector->end();
+ if (!Found)
+ Vector->push_back(ParentStack.back());
+ }
+ }
ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));
bool Result = (this ->* traverse) (Node);
ParentStack.pop_back();
@@ -8217,7 +8251,11 @@ ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) {
if (I == AllParents->end()) {
return ParentVector();
}
- return I->second;
+ if (I->second.is<ast_type_traits::DynTypedNode *>()) {
+ return ParentVector(1, *I->second.get<ast_type_traits::DynTypedNode *>());
+ }
+ const auto &Parents = *I->second.get<ParentVector *>();
+ return ParentVector(Parents.begin(), Parents.end());
}
bool
@@ -8230,8 +8268,7 @@ ASTContext::ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,
if (MethodDecl->getObjCDeclQualifier() !=
MethodImpl->getObjCDeclQualifier())
return false;
- if (!hasSameType(MethodDecl->getResultType(),
- MethodImpl->getResultType()))
+ if (!hasSameType(MethodDecl->getReturnType(), MethodImpl->getReturnType()))
return false;
if (MethodDecl->param_size() != MethodImpl->param_size())
@@ -8251,3 +8288,12 @@ ASTContext::ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,
return (MethodDecl->isVariadic() == MethodImpl->isVariadic());
}
+
+// Explicitly instantiate this in case a Redeclarable<T> is used from a TU that
+// doesn't include ASTContext.h
+template
+clang::LazyGenerationalUpdatePtr<
+ const Decl *, Decl *, &ExternalASTSource::CompleteRedeclChain>::ValueType
+clang::LazyGenerationalUpdatePtr<
+ const Decl *, Decl *, &ExternalASTSource::CompleteRedeclChain>::makeValue(
+ const clang::ASTContext &Ctx, Decl *Value);
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index fce8f64b3328..8c8b1dff0cbf 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -12,6 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
@@ -51,6 +53,11 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
QT = AT->desugar();
continue;
}
+ // ...or an adjusted type...
+ if (const AdjustedType *AT = dyn_cast<AdjustedType>(Ty)) {
+ QT = AT->desugar();
+ continue;
+ }
// ... or an auto type.
if (const AutoType *AT = dyn_cast<AutoType>(Ty)) {
if (!AT->isSugared())
@@ -155,9 +162,8 @@ break; \
/// diagnostic message
static std::string
ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
- const DiagnosticsEngine::ArgumentValue *PrevArgs,
- unsigned NumPrevArgs,
- ArrayRef<intptr_t> QualTypeVals) {
+ ArrayRef<DiagnosticsEngine::ArgumentValue> PrevArgs,
+ ArrayRef<intptr_t> QualTypeVals) {
// FIXME: Playing with std::string is really slow.
bool ForceAKA = false;
QualType CanTy = Ty.getCanonicalType();
@@ -195,7 +201,7 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
// Check to see if we already desugared this type in this
// diagnostic. If so, don't do it again.
bool Repeated = false;
- for (unsigned i = 0; i != NumPrevArgs; ++i) {
+ for (unsigned i = 0, e = PrevArgs.size(); i != e; ++i) {
// TODO: Handle ak_declcontext case.
if (PrevArgs[i].first == DiagnosticsEngine::ak_qualtype) {
void *Ptr = (void*)PrevArgs[i].second;
@@ -222,6 +228,20 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
return S;
}
}
+
+ // Give some additional info on vector types. These are either not desugared
+ // or displaying complex __attribute__ expressions so add details of the
+ // type and element count.
+ if (Ty->isVectorType()) {
+ const VectorType *VTy = Ty->getAs<VectorType>();
+ std::string DecoratedString;
+ llvm::raw_string_ostream OS(DecoratedString);
+ const char *Values = VTy->getNumElements() > 1 ? "values" : "value";
+ OS << "'" << S << "' (vector of " << VTy->getNumElements() << " '"
+ << VTy->getElementType().getAsString(Context.getPrintingPolicy())
+ << "' " << Values << ")";
+ return OS.str();
+ }
}
S = "'" + S + "'";
@@ -236,12 +256,9 @@ static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType,
void clang::FormatASTNodeDiagnosticArgument(
DiagnosticsEngine::ArgumentKind Kind,
intptr_t Val,
- const char *Modifier,
- unsigned ModLen,
- const char *Argument,
- unsigned ArgLen,
- const DiagnosticsEngine::ArgumentValue *PrevArgs,
- unsigned NumPrevArgs,
+ StringRef Modifier,
+ StringRef Argument,
+ ArrayRef<DiagnosticsEngine::ArgumentValue> PrevArgs,
SmallVectorImpl<char> &Output,
void *Cookie,
ArrayRef<intptr_t> QualTypeVals) {
@@ -276,28 +293,26 @@ void clang::FormatASTNodeDiagnosticArgument(
// Attempting to do a template diff on non-templates. Set the variables
// and continue with regular type printing of the appropriate type.
Val = TDT.PrintFromType ? TDT.FromType : TDT.ToType;
- ModLen = 0;
- ArgLen = 0;
+ Modifier = StringRef();
+ Argument = StringRef();
// Fall through
}
case DiagnosticsEngine::ak_qualtype: {
- assert(ModLen == 0 && ArgLen == 0 &&
+ assert(Modifier.empty() && Argument.empty() &&
"Invalid modifier for QualType argument");
QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
- OS << ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs,
- QualTypeVals);
+ OS << ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, QualTypeVals);
NeedQuotes = false;
break;
}
case DiagnosticsEngine::ak_declarationname: {
- if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0)
+ if (Modifier == "objcclass" && Argument.empty())
OS << '+';
- else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12)
- && ArgLen==0)
+ else if (Modifier == "objcinstance" && Argument.empty())
OS << '-';
else
- assert(ModLen == 0 && ArgLen == 0 &&
+ assert(Modifier.empty() && Argument.empty() &&
"Invalid modifier for DeclarationName argument");
OS << DeclarationName::getFromOpaqueInteger(Val);
@@ -305,10 +320,10 @@ void clang::FormatASTNodeDiagnosticArgument(
}
case DiagnosticsEngine::ak_nameddecl: {
bool Qualified;
- if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
+ if (Modifier == "q" && Argument.empty())
Qualified = true;
else {
- assert(ModLen == 0 && ArgLen == 0 &&
+ assert(Modifier.empty() && Argument.empty() &&
"Invalid modifier for NamedDecl* argument");
Qualified = false;
}
@@ -325,7 +340,8 @@ void clang::FormatASTNodeDiagnosticArgument(
case DiagnosticsEngine::ak_declcontext: {
DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
assert(DC && "Should never have a null declaration context");
-
+ NeedQuotes = false;
+
if (DC->isTranslationUnit()) {
// FIXME: Get these strings from some localized place
if (Context.getLangOpts().CPlusPlus)
@@ -335,10 +351,17 @@ void clang::FormatASTNodeDiagnosticArgument(
} else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
OS << ConvertTypeToDiagnosticString(Context,
Context.getTypeDeclType(Type),
- PrevArgs, NumPrevArgs,
- QualTypeVals);
+ PrevArgs, QualTypeVals);
} else {
// FIXME: Get these strings from some localized place
+ if (isa<BlockDecl>(DC)) {
+ OS << "block literal";
+ break;
+ }
+ if (isLambdaCallOperator(DC)) {
+ OS << "lambda expression";
+ break;
+ }
NamedDecl *ND = cast<NamedDecl>(DC);
if (isa<NamespaceDecl>(ND))
OS << "namespace ";
@@ -351,9 +374,16 @@ void clang::FormatASTNodeDiagnosticArgument(
ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), true);
OS << '\'';
}
+ break;
+ }
+ case DiagnosticsEngine::ak_attr: {
+ const Attr *At = reinterpret_cast<Attr *>(Val);
+ assert(At && "Received null Attr object!");
+ OS << '\'' << At->getSpelling() << '\'';
NeedQuotes = false;
break;
}
+
}
OS.flush();
@@ -442,6 +472,9 @@ class TemplateDiff {
/// FromExpr, ToExpr - The expression arguments.
Expr *FromExpr, *ToExpr;
+ /// FromNullPtr, ToNullPtr - If the template argument is a nullptr
+ bool FromNullPtr, ToNullPtr;
+
/// FromTD, ToTD - The template decl for template template
/// arguments or the type arguments that are templates.
TemplateDecl *FromTD, *ToTD;
@@ -470,10 +503,12 @@ class TemplateDiff {
DiffNode(unsigned ParentNode = 0)
: Kind(Invalid), NextNode(0), ChildNode(0), ParentNode(ParentNode),
- FromType(), ToType(), FromExpr(0), ToExpr(0), FromTD(0), ToTD(0),
- IsValidFromInt(false), IsValidToInt(false), FromValueDecl(0),
- ToValueDecl(0), FromAddressOf(false), ToAddressOf(false),
- FromDefault(false), ToDefault(false), Same(false) { }
+ FromType(), ToType(), FromExpr(nullptr), ToExpr(nullptr),
+ FromNullPtr(false), ToNullPtr(false),
+ FromTD(nullptr), ToTD(nullptr), IsValidFromInt(false),
+ IsValidToInt(false), FromValueDecl(nullptr), ToValueDecl(nullptr),
+ FromAddressOf(false), ToAddressOf(false), FromDefault(false),
+ ToDefault(false), Same(false) {}
};
/// FlatTree - A flattened tree used to store the DiffNodes.
@@ -543,6 +578,12 @@ class TemplateDiff {
FlatTree[CurrentNode].Same = Same;
}
+ /// SetNullPtr - Sets the NullPtr flags of the current node.
+ void SetNullPtr(bool FromNullPtr, bool ToNullPtr) {
+ FlatTree[CurrentNode].FromNullPtr = FromNullPtr;
+ FlatTree[CurrentNode].ToNullPtr = ToNullPtr;
+ }
+
/// SetDefault - Sets FromDefault and ToDefault flags of the current node.
void SetDefault(bool FromDefault, bool ToDefault) {
FlatTree[CurrentNode].FromDefault = FromDefault;
@@ -665,6 +706,16 @@ class TemplateDiff {
return FlatTree[ReadNode].NextNode != 0;
}
+ /// FromNullPtr - Returns true if the from argument is null.
+ bool FromNullPtr() {
+ return FlatTree[ReadNode].FromNullPtr;
+ }
+
+ /// ToNullPtr - Returns true if the to argument is null.
+ bool ToNullPtr() {
+ return FlatTree[ReadNode].ToNullPtr;
+ }
+
/// FromDefault - Return true if the from argument is the default.
bool FromDefault() {
return FlatTree[ReadNode].FromDefault;
@@ -718,7 +769,7 @@ class TemplateDiff {
TSTiterator(ASTContext &Context, const TemplateSpecializationType *TST)
: TST(TST),
DesugarTST(GetTemplateSpecializationType(Context, TST->desugar())),
- Index(0), CurrentTA(0), EndTA(0) {
+ Index(0), CurrentTA(nullptr), EndTA(nullptr) {
if (isEnd()) return;
// Set to first template argument. If not a parameter pack, done.
@@ -809,13 +860,13 @@ class TemplateDiff {
const RecordType *RT = Ty->getAs<RecordType>();
if (!RT)
- return 0;
+ return nullptr;
const ClassTemplateSpecializationDecl *CTSD =
dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl());
if (!CTSD)
- return 0;
+ return nullptr;
Ty = Context.getTemplateSpecializationType(
TemplateName(CTSD->getSpecializedTemplate()),
@@ -887,9 +938,9 @@ class TemplateDiff {
// Handle Expressions
if (NonTypeTemplateParmDecl *DefaultNTTPD =
dyn_cast<NonTypeTemplateParmDecl>(ParamND)) {
- Expr *FromExpr = 0, *ToExpr = 0;
+ Expr *FromExpr = nullptr, *ToExpr = nullptr;
llvm::APSInt FromInt, ToInt;
- ValueDecl *FromValueDecl = 0, *ToValueDecl = 0;
+ ValueDecl *FromValueDecl = nullptr, *ToValueDecl = nullptr;
unsigned ParamWidth = 128; // Safe default
if (DefaultNTTPD->getType()->isIntegralOrEnumerationType())
ParamWidth = Context.getIntWidth(DefaultNTTPD->getType());
@@ -903,6 +954,10 @@ class TemplateDiff {
bool HasToValueDecl =
!ToIter.isEnd() &&
ToIter->getKind() == TemplateArgument::Declaration;
+ bool FromNullPtr = !FromIter.isEnd() &&
+ FromIter->getKind() == TemplateArgument::NullPtr;
+ bool ToNullPtr =
+ !ToIter.isEnd() && ToIter->getKind() == TemplateArgument::NullPtr;
assert(((!HasFromInt && !HasToInt) ||
(!HasFromValueDecl && !HasToValueDecl)) &&
@@ -912,41 +967,54 @@ class TemplateDiff {
FromInt = FromIter->getAsIntegral();
else if (HasFromValueDecl)
FromValueDecl = FromIter->getAsDecl();
- else
+ else if (!FromNullPtr)
FromExpr = GetExpr(FromIter, DefaultNTTPD);
if (HasToInt)
ToInt = ToIter->getAsIntegral();
else if (HasToValueDecl)
ToValueDecl = ToIter->getAsDecl();
- else
+ else if (!ToNullPtr)
ToExpr = GetExpr(ToIter, DefaultNTTPD);
+ bool TemplateArgumentIsPointerType =
+ DefaultNTTPD->getType()->isPointerType();
+ if (FromExpr && TemplateArgumentIsPointerType) {
+ FromNullPtr = CheckForNullPtr(FromExpr);
+ }
+ if (ToExpr && TemplateArgumentIsPointerType) {
+ ToNullPtr = CheckForNullPtr(ToExpr);
+ }
+
if (!HasFromInt && !HasToInt && !HasFromValueDecl && !HasToValueDecl) {
Tree.SetNode(FromExpr, ToExpr);
Tree.SetDefault(FromIter.isEnd() && FromExpr,
ToIter.isEnd() && ToExpr);
if (DefaultNTTPD->getType()->isIntegralOrEnumerationType()) {
if (FromExpr)
- FromInt = GetInt(FromIter, FromExpr);
+ HasFromInt = GetInt(FromIter, FromExpr, FromInt);
if (ToExpr)
- ToInt = GetInt(ToIter, ToExpr);
- Tree.SetNode(FromInt, ToInt, FromExpr, ToExpr);
+ HasToInt = GetInt(ToIter, ToExpr, ToInt);
+ }
+ if (HasFromInt && HasToInt) {
+ Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt));
Tree.SetKind(DiffTree::Integer);
+ } else if (HasFromInt || HasToInt) {
+ Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
+ Tree.SetSame(false);
+ Tree.SetKind(DiffTree::Integer);
} else {
- Tree.SetSame(IsEqualExpr(Context, ParamWidth, FromExpr, ToExpr));
+ Tree.SetSame(IsEqualExpr(Context, ParamWidth, FromExpr, ToExpr) ||
+ (FromNullPtr && ToNullPtr));
+ Tree.SetNullPtr(FromNullPtr, ToNullPtr);
Tree.SetKind(DiffTree::Expression);
}
} else if (HasFromInt || HasToInt) {
- if (!HasFromInt && FromExpr) {
- FromInt = GetInt(FromIter, FromExpr);
- HasFromInt = true;
- }
- if (!HasToInt && ToExpr) {
- ToInt = GetInt(ToIter, ToExpr);
- HasToInt = true;
- }
+ if (!HasFromInt && FromExpr)
+ HasFromInt = GetInt(FromIter, FromExpr, FromInt);
+ if (!HasToInt && ToExpr)
+ HasToInt = GetInt(ToIter, ToExpr, ToInt);
Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt));
Tree.SetDefault(FromIter.isEnd() && HasFromInt,
@@ -958,12 +1026,36 @@ class TemplateDiff {
if (!HasToValueDecl && ToExpr)
ToValueDecl = GetValueDecl(ToIter, ToExpr);
QualType ArgumentType = DefaultNTTPD->getType();
- bool FromAddressOf = FromValueDecl &&
- !ArgumentType->isReferenceType() &&
- !FromValueDecl->getType()->isArrayType();
- bool ToAddressOf = ToValueDecl &&
- !ArgumentType->isReferenceType() &&
- !ToValueDecl->getType()->isArrayType();
+ bool FromAddressOf = false;
+ if (FromValueDecl) {
+ if (FromExpr) {
+ if (UnaryOperator *UO =
+ dyn_cast<UnaryOperator>(FromExpr->IgnoreParens())) {
+ if (UO->getOpcode() == UO_AddrOf)
+ FromAddressOf = true;
+ }
+ } else {
+ if (!ArgumentType->isReferenceType()) {
+ FromAddressOf = true;
+ }
+ }
+ }
+ bool ToAddressOf = false;
+ if (ToValueDecl) {
+ if (ToExpr) {
+ if (UnaryOperator *UO =
+ dyn_cast<UnaryOperator>(ToExpr->IgnoreParens())) {
+ if (UO->getOpcode() == UO_AddrOf) {
+ ToAddressOf = true;
+ }
+ }
+ } else {
+ if (!ArgumentType->isReferenceType()) {
+ ToAddressOf = true;
+ }
+ }
+ }
+ Tree.SetNullPtr(FromNullPtr, ToNullPtr);
Tree.SetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf);
Tree.SetSame(FromValueDecl && ToValueDecl &&
FromValueDecl->getCanonicalDecl() ==
@@ -984,6 +1076,7 @@ class TemplateDiff {
Tree.SetSame(
FromDecl && ToDecl &&
FromDecl->getCanonicalDecl() == ToDecl->getCanonicalDecl());
+ Tree.SetDefault(FromIter.isEnd() && FromDecl, ToIter.isEnd() && ToDecl);
Tree.SetKind(DiffTree::TemplateTemplate);
}
@@ -1072,7 +1165,7 @@ class TemplateDiff {
/// GetExpr - Retrieves the template expression argument, including default
/// arguments.
Expr *GetExpr(const TSTiterator &Iter, NonTypeTemplateParmDecl *DefaultNTTPD) {
- Expr *ArgExpr = 0;
+ Expr *ArgExpr = nullptr;
bool isVariadic = DefaultNTTPD->isParameterPack();
if (!Iter.isEnd())
@@ -1090,20 +1183,28 @@ class TemplateDiff {
/// GetInt - Retrieves the template integer argument, including evaluating
/// default arguments.
- llvm::APInt GetInt(const TSTiterator &Iter, Expr *ArgExpr) {
+ bool GetInt(const TSTiterator &Iter, Expr *ArgExpr, llvm::APInt &Int) {
// Default, value-depenedent expressions require fetching
- // from the desugared TemplateArgument
- if (Iter.isEnd() && ArgExpr->isValueDependent())
+ // from the desugared TemplateArgument, otherwise expression needs to
+ // be evaluatable.
+ if (Iter.isEnd() && ArgExpr->isValueDependent()) {
switch (Iter.getDesugar().getKind()) {
case TemplateArgument::Integral:
- return Iter.getDesugar().getAsIntegral();
+ Int = Iter.getDesugar().getAsIntegral();
+ return true;
case TemplateArgument::Expression:
ArgExpr = Iter.getDesugar().getAsExpr();
- return ArgExpr->EvaluateKnownConstInt(Context);
+ Int = ArgExpr->EvaluateKnownConstInt(Context);
+ return true;
default:
- assert(0 && "Unexpected template argument kind");
+ llvm_unreachable("Unexpected template argument kind");
}
- return ArgExpr->EvaluateKnownConstInt(Context);
+ } else if (ArgExpr->isEvaluatable(Context)) {
+ Int = ArgExpr->EvaluateKnownConstInt(Context);
+ return true;
+ }
+
+ return false;
}
/// GetValueDecl - Retrieves the template Decl argument, including
@@ -1119,16 +1220,40 @@ class TemplateDiff {
ArgExpr = Iter.getDesugar().getAsExpr();
return cast<DeclRefExpr>(ArgExpr)->getDecl();
default:
- assert(0 && "Unexpected template argument kind");
+ llvm_unreachable("Unexpected template argument kind");
}
DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ArgExpr);
if (!DRE) {
- DRE = cast<DeclRefExpr>(cast<UnaryOperator>(ArgExpr)->getSubExpr());
+ UnaryOperator *UO = dyn_cast<UnaryOperator>(ArgExpr->IgnoreParens());
+ if (!UO)
+ return nullptr;
+ DRE = cast<DeclRefExpr>(UO->getSubExpr());
}
return DRE->getDecl();
}
+ /// CheckForNullPtr - returns true if the expression can be evaluated as
+ /// a null pointer
+ bool CheckForNullPtr(Expr *E) {
+ assert(E && "Expected expression");
+
+ E = E->IgnoreParenCasts();
+ if (E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
+ return true;
+
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
+ if (!DRE)
+ return false;
+
+ VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
+ if (!VD || !VD->hasInit())
+ return false;
+
+ return VD->getInit()->IgnoreParenCasts()->isNullPointerConstant(
+ Context, Expr::NPC_ValueDependentIsNull);
+ }
+
/// GetTemplateDecl - Retrieves the template template arguments, including
/// default arguments.
TemplateDecl *GetTemplateDecl(const TSTiterator &Iter,
@@ -1136,7 +1261,7 @@ class TemplateDiff {
bool isVariadic = DefaultTTPD->isParameterPack();
TemplateArgument TA = DefaultTTPD->getDefaultArgument().getArgument();
- TemplateDecl *DefaultTD = 0;
+ TemplateDecl *DefaultTD = nullptr;
if (TA.getKind() != TemplateArgument::Null)
DefaultTD = TA.getAsTemplate().getAsTemplateDecl();
@@ -1145,7 +1270,7 @@ class TemplateDiff {
if (!isVariadic)
return DefaultTD;
- return 0;
+ return nullptr;
}
/// IsSameConvertedInt - Returns true if both integers are equal when
@@ -1166,11 +1291,8 @@ class TemplateDiff {
if (!FromExpr || !ToExpr)
return false;
- FromExpr = FromExpr->IgnoreParens();
- ToExpr = ToExpr->IgnoreParens();
-
- DeclRefExpr *FromDRE = dyn_cast<DeclRefExpr>(FromExpr),
- *ToDRE = dyn_cast<DeclRefExpr>(ToExpr);
+ DeclRefExpr *FromDRE = dyn_cast<DeclRefExpr>(FromExpr->IgnoreParens()),
+ *ToDRE = dyn_cast<DeclRefExpr>(ToExpr->IgnoreParens());
if (FromDRE || ToDRE) {
if (!FromDRE || !ToDRE)
@@ -1180,8 +1302,12 @@ class TemplateDiff {
Expr::EvalResult FromResult, ToResult;
if (!FromExpr->EvaluateAsRValue(FromResult, Context) ||
- !ToExpr->EvaluateAsRValue(ToResult, Context))
- return false;
+ !ToExpr->EvaluateAsRValue(ToResult, Context)) {
+ llvm::FoldingSetNodeID FromID, ToID;
+ FromExpr->Profile(FromID, Context, true);
+ ToExpr->Profile(ToID, Context, true);
+ return FromID == ToID;
+ }
APValue &FromVal = FromResult.Val;
APValue &ToVal = ToResult.Val;
@@ -1235,8 +1361,8 @@ class TemplateDiff {
case DiffTree::Expression: {
Expr *FromExpr, *ToExpr;
Tree.GetNode(FromExpr, ToExpr);
- PrintExpr(FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(),
- Tree.NodeIsSame());
+ PrintExpr(FromExpr, ToExpr, Tree.FromNullPtr(), Tree.ToNullPtr(),
+ Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame());
return;
}
case DiffTree::TemplateTemplate: {
@@ -1262,7 +1388,8 @@ class TemplateDiff {
bool FromAddressOf, ToAddressOf;
Tree.GetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf);
PrintValueDecl(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf,
- Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame());
+ Tree.FromNullPtr(), Tree.ToNullPtr(), Tree.FromDefault(),
+ Tree.ToDefault(), Tree.NodeIsSame());
return;
}
case DiffTree::Template: {
@@ -1341,7 +1468,7 @@ class TemplateDiff {
"Only one template argument may be missing.");
if (Same) {
- OS << FromType.getAsString();
+ OS << FromType.getAsString(Policy);
return;
}
@@ -1349,22 +1476,22 @@ class TemplateDiff {
FromType.getLocalUnqualifiedType() ==
ToType.getLocalUnqualifiedType()) {
Qualifiers FromQual = FromType.getLocalQualifiers(),
- ToQual = ToType.getLocalQualifiers(),
- CommonQual;
+ ToQual = ToType.getLocalQualifiers();
PrintQualifiers(FromQual, ToQual);
FromType.getLocalUnqualifiedType().print(OS, Policy);
return;
}
std::string FromTypeStr = FromType.isNull() ? "(no argument)"
- : FromType.getAsString();
+ : FromType.getAsString(Policy);
std::string ToTypeStr = ToType.isNull() ? "(no argument)"
- : ToType.getAsString();
+ : ToType.getAsString(Policy);
// Switch to canonical typename if it is better.
// TODO: merge this with other aka printing above.
if (FromTypeStr == ToTypeStr) {
- std::string FromCanTypeStr = FromType.getCanonicalType().getAsString();
- std::string ToCanTypeStr = ToType.getCanonicalType().getAsString();
+ std::string FromCanTypeStr =
+ FromType.getCanonicalType().getAsString(Policy);
+ std::string ToCanTypeStr = ToType.getCanonicalType().getAsString(Policy);
if (FromCanTypeStr != ToCanTypeStr) {
FromTypeStr = FromCanTypeStr;
ToTypeStr = ToCanTypeStr;
@@ -1388,36 +1515,41 @@ class TemplateDiff {
/// PrintExpr - Prints out the expr template arguments, highlighting argument
/// differences.
- void PrintExpr(const Expr *FromExpr, const Expr *ToExpr,
- bool FromDefault, bool ToDefault, bool Same) {
+ void PrintExpr(const Expr *FromExpr, const Expr *ToExpr, bool FromNullPtr,
+ bool ToNullPtr, bool FromDefault, bool ToDefault, bool Same) {
assert((FromExpr || ToExpr) &&
"Only one template argument may be missing.");
if (Same) {
- PrintExpr(FromExpr);
+ PrintExpr(FromExpr, FromNullPtr);
} else if (!PrintTree) {
OS << (FromDefault ? "(default) " : "");
Bold();
- PrintExpr(FromExpr);
+ PrintExpr(FromExpr, FromNullPtr);
Unbold();
} else {
OS << (FromDefault ? "[(default) " : "[");
Bold();
- PrintExpr(FromExpr);
+ PrintExpr(FromExpr, FromNullPtr);
Unbold();
OS << " != " << (ToDefault ? "(default) " : "");
Bold();
- PrintExpr(ToExpr);
+ PrintExpr(ToExpr, ToNullPtr);
Unbold();
OS << ']';
}
}
/// PrintExpr - Actual formatting and printing of expressions.
- void PrintExpr(const Expr *E) {
- if (!E)
- OS << "(no argument)";
- else
- E->printPretty(OS, 0, Policy); return;
+ void PrintExpr(const Expr *E, bool NullPtr = false) {
+ if (E) {
+ E->printPretty(OS, nullptr, Policy);
+ return;
+ }
+ if (NullPtr) {
+ OS << "nullptr";
+ return;
+ }
+ OS << "(no argument)";
}
/// PrintTemplateTemplate - Handles printing of template template arguments,
@@ -1487,6 +1619,8 @@ class TemplateDiff {
Bold();
}
OS << Val.toString(10);
+ } else if (E) {
+ PrintExpr(E);
} else {
OS << "(no argument)";
}
@@ -1507,35 +1641,46 @@ class TemplateDiff {
return true;
}
+ void PrintValueDecl(ValueDecl *VD, bool AddressOf, bool NullPtr) {
+ if (VD) {
+ if (AddressOf)
+ OS << "&";
+ OS << VD->getName();
+ return;
+ }
+
+ if (NullPtr) {
+ OS << "nullptr";
+ return;
+ }
+
+ OS << "(no argument)";
+ }
+
/// PrintDecl - Handles printing of Decl arguments, highlighting
/// argument differences.
void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
- bool FromAddressOf, bool ToAddressOf, bool FromDefault,
- bool ToDefault, bool Same) {
- assert((FromValueDecl || ToValueDecl) &&
+ bool FromAddressOf, bool ToAddressOf, bool FromNullPtr,
+ bool ToNullPtr, bool FromDefault, bool ToDefault,
+ bool Same) {
+ assert((FromValueDecl || FromNullPtr || ToValueDecl || ToNullPtr) &&
"Only one Decl argument may be NULL");
if (Same) {
- OS << FromValueDecl->getName();
+ PrintValueDecl(FromValueDecl, FromAddressOf, FromNullPtr);
} else if (!PrintTree) {
OS << (FromDefault ? "(default) " : "");
Bold();
- if (FromAddressOf)
- OS << "&";
- OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)");
+ PrintValueDecl(FromValueDecl, FromAddressOf, FromNullPtr);
Unbold();
} else {
OS << (FromDefault ? "[(default) " : "[");
Bold();
- if (FromAddressOf)
- OS << "&";
- OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)");
+ PrintValueDecl(FromValueDecl, FromAddressOf, FromNullPtr);
Unbold();
OS << " != " << (ToDefault ? "(default) " : "");
Bold();
- if (ToAddressOf)
- OS << "&";
- OS << (ToValueDecl ? ToValueDecl->getName() : "(no argument)");
+ PrintValueDecl(ToValueDecl, ToAddressOf, ToNullPtr);
Unbold();
OS << ']';
}
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index 670fd0ed3a93..df7a2cb4712b 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -149,11 +149,43 @@ namespace {
}
};
+ class ChildDumper {
+ ASTDumper &Dumper;
+
+ const Decl *Prev;
+ bool PrevRef;
+ public:
+ ChildDumper(ASTDumper &Dumper) : Dumper(Dumper), Prev(nullptr) {}
+ ~ChildDumper() {
+ if (Prev) {
+ Dumper.lastChild();
+ dump(nullptr);
+ }
+ }
+
+ // FIXME: This should take an arbitrary callable as the dumping action.
+ void dump(const Decl *D, bool Ref = false) {
+ if (Prev) {
+ if (PrevRef)
+ Dumper.dumpDeclRef(Prev);
+ else
+ Dumper.dumpDecl(Prev);
+ }
+ Prev = D;
+ PrevRef = Ref;
+ }
+ void dumpRef(const Decl *D) { dump(D, true); }
+
+ // Give up ownership of the children of the node. By calling this,
+ // the caller takes back responsibility for calling lastChild().
+ void release() { dump(nullptr); }
+ };
+
public:
ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
const SourceManager *SM)
: OS(OS), Traits(Traits), SM(SM), IsFirstLine(true), MoreChildren(false),
- LastLocFilename(""), LastLocLine(~0U), FC(0),
+ LastLocFilename(""), LastLocLine(~0U), FC(nullptr),
ShowColors(SM && SM->getDiagnostics().getShowColors()) { }
ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
@@ -184,7 +216,7 @@ namespace {
void dumpBareType(QualType T);
void dumpType(QualType T);
void dumpBareDeclRef(const Decl *Node);
- void dumpDeclRef(const Decl *Node, const char *Label = 0);
+ void dumpDeclRef(const Decl *Node, const char *Label = nullptr);
void dumpName(const NamedDecl *D);
bool hasNodes(const DeclContext *DC);
void dumpDeclContext(const DeclContext *DC);
@@ -222,6 +254,13 @@ namespace {
void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D);
void VisitCXXRecordDecl(const CXXRecordDecl *D);
void VisitStaticAssertDecl(const StaticAssertDecl *D);
+ template<typename SpecializationDecl>
+ void VisitTemplateDeclSpecialization(ChildDumper &Children,
+ const SpecializationDecl *D,
+ bool DumpExplicitInst,
+ bool DumpRefOnly);
+ template<typename TemplateDecl>
+ void VisitTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst);
void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D);
void VisitClassTemplateDecl(const ClassTemplateDecl *D);
void VisitClassTemplateSpecializationDecl(
@@ -276,6 +315,7 @@ namespace {
void VisitIntegerLiteral(const IntegerLiteral *Node);
void VisitFloatingLiteral(const FloatingLiteral *Node);
void VisitStringLiteral(const StringLiteral *Str);
+ void VisitInitListExpr(const InitListExpr *ILE);
void VisitUnaryOperator(const UnaryOperator *Node);
void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Node);
void VisitMemberExpr(const MemberExpr *Node);
@@ -405,6 +445,9 @@ void ASTDumper::dumpPointer(const void *Ptr) {
}
void ASTDumper::dumpLocation(SourceLocation Loc) {
+ if (!SM)
+ return;
+
ColorScope Color(*this, LocationColor);
SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
@@ -511,17 +554,14 @@ bool ASTDumper::hasNodes(const DeclContext *DC) {
void ASTDumper::dumpDeclContext(const DeclContext *DC) {
if (!DC)
return;
- bool HasUndeserializedDecls = DC->hasExternalLexicalStorage();
- for (DeclContext::decl_iterator I = DC->noload_decls_begin(),
- E = DC->noload_decls_end();
- I != E; ++I) {
- DeclContext::decl_iterator Next = I;
- ++Next;
- if (Next == E && !HasUndeserializedDecls)
- lastChild();
- dumpDecl(*I);
- }
- if (HasUndeserializedDecls) {
+
+ ChildDumper Children(*this);
+ for (auto *D : DC->noload_decls())
+ Children.dump(D);
+
+ if (DC->hasExternalLexicalStorage()) {
+ Children.release();
+
lastChild();
IndentScope Indent(*this);
ColorScope Color(*this, UndeserializedColor);
@@ -580,6 +620,7 @@ void ASTDumper::dumpAttr(const Attr *A) {
IndentScope Indent(*this);
{
ColorScope Color(*this, AttrColor);
+
switch (A->getKind()) {
#define ATTR(X) case attr::X: OS << #X; break;
#include "clang/Basic/AttrList.inc"
@@ -589,6 +630,10 @@ void ASTDumper::dumpAttr(const Attr *A) {
}
dumpPointer(A);
dumpSourceRange(A->getRange());
+ if (A->isInherited())
+ OS << " Inherited";
+ if (A->isImplicit())
+ OS << " Implicit";
#include "clang/AST/AttrDump.inc"
}
@@ -753,13 +798,23 @@ void ASTDumper::dumpDecl(const Decl *D) {
OS << " parent " << cast<Decl>(D->getDeclContext());
dumpPreviousDecl(OS, D);
dumpSourceRange(D->getSourceRange());
+ OS << ' ';
+ dumpLocation(D->getLocation());
if (Module *M = D->getOwningModule())
OS << " in " << M->getFullModuleName();
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
if (ND->isHidden())
OS << " hidden";
+ if (D->isImplicit())
+ OS << " implicit";
+ if (D->isUsed())
+ OS << " used";
+ else if (D->isReferenced())
+ OS << " referenced";
+ if (D->isInvalidDecl())
+ OS << " invalid";
- bool HasAttrs = D->attr_begin() != D->attr_end();
+ bool HasAttrs = D->hasAttrs();
const FullComment *Comment =
D->getASTContext().getLocalCommentForDeclUncached(D);
// Decls within functions are visited by the body
@@ -781,9 +836,6 @@ void ASTDumper::dumpDecl(const Decl *D) {
lastChild();
dumpFullComment(Comment);
- if (D->isInvalidDecl())
- OS << " invalid";
-
setMoreChildren(false);
if (HasDeclContext)
dumpDeclContext(cast<DeclContext>(D));
@@ -835,13 +887,10 @@ void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) {
void ASTDumper::VisitIndirectFieldDecl(const IndirectFieldDecl *D) {
dumpName(D);
dumpType(D->getType());
- for (IndirectFieldDecl::chain_iterator I = D->chain_begin(),
- E = D->chain_end();
- I != E; ++I) {
- if (I + 1 == E)
- lastChild();
- dumpDeclRef(*I);
- }
+
+ ChildDumper Children(*this);
+ for (auto *Child : D->chain())
+ Children.dumpRef(Child);
}
void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) {
@@ -975,6 +1024,11 @@ void ASTDumper::VisitVarDecl(const VarDecl *D) {
if (D->isNRVOVariable())
OS << " nrvo";
if (D->hasInit()) {
+ switch (D->getInitStyle()) {
+ case VarDecl::CInit: OS << " cinit"; break;
+ case VarDecl::CallInit: OS << " callinit"; break;
+ case VarDecl::ListInit: OS << " listinit"; break;
+ }
lastChild();
dumpStmt(D->getInit());
}
@@ -1027,15 +1081,13 @@ void ASTDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) {
if (!D->isCompleteDefinition())
return;
- for (CXXRecordDecl::base_class_const_iterator I = D->bases_begin(),
- E = D->bases_end();
- I != E; ++I) {
+ for (const auto &I : D->bases()) {
IndentScope Indent(*this);
- if (I->isVirtual())
+ if (I.isVirtual())
OS << "virtual ";
- dumpAccessSpecifier(I->getAccessSpecifier());
- dumpType(I->getType());
- if (I->isPackExpansion())
+ dumpAccessSpecifier(I.getAccessSpecifier());
+ dumpType(I.getType());
+ if (I.isPackExpansion())
OS << "...";
}
}
@@ -1046,63 +1098,69 @@ void ASTDumper::VisitStaticAssertDecl(const StaticAssertDecl *D) {
dumpStmt(D->getMessage());
}
-void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
- dumpName(D);
- dumpTemplateParameters(D->getTemplateParameters());
- dumpDecl(D->getTemplatedDecl());
- for (FunctionTemplateDecl::spec_iterator I = D->spec_begin(),
- E = D->spec_end();
- I != E; ++I) {
- FunctionTemplateDecl::spec_iterator Next = I;
- ++Next;
- if (Next == E)
- lastChild();
- switch (I->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ImplicitInstantiation:
+template<typename SpecializationDecl>
+void ASTDumper::VisitTemplateDeclSpecialization(ChildDumper &Children,
+ const SpecializationDecl *D,
+ bool DumpExplicitInst,
+ bool DumpRefOnly) {
+ bool DumpedAny = false;
+ for (auto *RedeclWithBadType : D->redecls()) {
+ // FIXME: The redecls() range sometimes has elements of a less-specific
+ // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives
+ // us TagDecls, and should give CXXRecordDecls).
+ auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType);
+ if (!Redecl) {
+ // Found the injected-class-name for a class template. This will be dumped
+ // as part of its surrounding class so we don't need to dump it here.
+ assert(isa<CXXRecordDecl>(RedeclWithBadType) &&
+ "expected an injected-class-name");
+ continue;
+ }
+
+ switch (Redecl->getTemplateSpecializationKind()) {
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
- if (D == D->getCanonicalDecl())
- dumpDecl(*I);
- else
- dumpDeclRef(*I);
+ if (!DumpExplicitInst)
+ break;
+ // Fall through.
+ case TSK_Undeclared:
+ case TSK_ImplicitInstantiation:
+ Children.dump(Redecl, DumpRefOnly);
+ DumpedAny = true;
break;
case TSK_ExplicitSpecialization:
- dumpDeclRef(*I);
break;
}
}
+
+ // Ensure we dump at least one decl for each specialization.
+ if (!DumpedAny)
+ Children.dumpRef(D);
}
-void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
+template<typename TemplateDecl>
+void ASTDumper::VisitTemplateDecl(const TemplateDecl *D,
+ bool DumpExplicitInst) {
dumpName(D);
dumpTemplateParameters(D->getTemplateParameters());
- ClassTemplateDecl::spec_iterator I = D->spec_begin();
- ClassTemplateDecl::spec_iterator E = D->spec_end();
- if (I == E)
- lastChild();
- dumpDecl(D->getTemplatedDecl());
- for (; I != E; ++I) {
- ClassTemplateDecl::spec_iterator Next = I;
- ++Next;
- if (Next == E)
- lastChild();
- switch (I->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ImplicitInstantiation:
- if (D == D->getCanonicalDecl())
- dumpDecl(*I);
- else
- dumpDeclRef(*I);
- break;
- case TSK_ExplicitSpecialization:
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- dumpDeclRef(*I);
- break;
- }
- }
+ ChildDumper Children(*this);
+ Children.dump(D->getTemplatedDecl());
+
+ for (auto *Child : D->specializations())
+ VisitTemplateDeclSpecialization(Children, Child, DumpExplicitInst,
+ !D->isCanonicalDecl());
+}
+
+void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
+ // FIXME: We don't add a declaration of a function template specialization
+ // to its context when it's explicitly instantiated, so dump explicit
+ // instantiations when we dump the template itself.
+ VisitTemplateDecl(D, true);
+}
+
+void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
+ VisitTemplateDecl(D, false);
}
void ASTDumper::VisitClassTemplateSpecializationDecl(
@@ -1125,34 +1183,7 @@ void ASTDumper::VisitClassScopeFunctionSpecializationDecl(
}
void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) {
- dumpName(D);
- dumpTemplateParameters(D->getTemplateParameters());
-
- VarTemplateDecl::spec_iterator I = D->spec_begin();
- VarTemplateDecl::spec_iterator E = D->spec_end();
- if (I == E)
- lastChild();
- dumpDecl(D->getTemplatedDecl());
- for (; I != E; ++I) {
- VarTemplateDecl::spec_iterator Next = I;
- ++Next;
- if (Next == E)
- lastChild();
- switch (I->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ImplicitInstantiation:
- if (D == D->getCanonicalDecl())
- dumpDecl(*I);
- else
- dumpDeclRef(*I);
- break;
- case TSK_ExplicitSpecialization:
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- dumpDeclRef(*I);
- break;
- }
- }
+ VisitTemplateDecl(D, false);
}
void ASTDumper::VisitVarTemplateSpecializationDecl(
@@ -1175,8 +1206,10 @@ void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
if (D->isParameterPack())
OS << " ...";
dumpName(D);
- if (D->hasDefaultArgument())
- dumpType(D->getDefaultArgument());
+ if (D->hasDefaultArgument()) {
+ lastChild();
+ dumpTemplateArgument(D->getDefaultArgument());
+ }
}
void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
@@ -1184,8 +1217,10 @@ void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
if (D->isParameterPack())
OS << " ...";
dumpName(D);
- if (D->hasDefaultArgument())
- dumpStmt(D->getDefaultArgument());
+ if (D->hasDefaultArgument()) {
+ lastChild();
+ dumpTemplateArgument(D->getDefaultArgument());
+ }
}
void ASTDumper::VisitTemplateTemplateParmDecl(
@@ -1194,8 +1229,10 @@ void ASTDumper::VisitTemplateTemplateParmDecl(
OS << " ...";
dumpName(D);
dumpTemplateParameters(D->getTemplateParameters());
- if (D->hasDefaultArgument())
+ if (D->hasDefaultArgument()) {
+ lastChild();
dumpTemplateArgumentLoc(D->getDefaultArgument());
+ }
}
void ASTDumper::VisitUsingDecl(const UsingDecl *D) {
@@ -1252,8 +1289,6 @@ void ASTDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) {
dumpType(D->getType());
if (D->getSynthesize())
OS << " synthesize";
- if (D->getBackingIvarReferencedInAccessor())
- OS << " BackingIvarReferencedInAccessor";
switch (D->getAccessControl()) {
case ObjCIvarDecl::None:
@@ -1280,7 +1315,7 @@ void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
else
OS << " +";
dumpName(D);
- dumpType(D->getResultType());
+ dumpType(D->getReturnType());
bool OldMoreChildren = hasMoreChildren();
bool IsVariadic = D->isVariadic();
@@ -1338,28 +1373,20 @@ void ASTDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
dumpName(D);
- for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(),
- E = D->protocol_end();
- I != E; ++I) {
- if (I + 1 == E)
- lastChild();
- dumpDeclRef(*I);
- }
+
+ ChildDumper Children(*this);
+ for (auto *Child : D->protocols())
+ Children.dumpRef(Child);
}
void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
dumpName(D);
dumpDeclRef(D->getSuperClass(), "super");
- if (D->protocol_begin() == D->protocol_end())
- lastChild();
- dumpDeclRef(D->getImplementation());
- for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(),
- E = D->protocol_end();
- I != E; ++I) {
- if (I + 1 == E)
- lastChild();
- dumpDeclRef(*I);
- }
+
+ ChildDumper Children(*this);
+ Children.dumpRef(D->getImplementation());
+ for (auto *Child : D->protocols())
+ Children.dumpRef(Child);
}
void ASTDumper::VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
@@ -1438,9 +1465,8 @@ void ASTDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
}
void ASTDumper::VisitBlockDecl(const BlockDecl *D) {
- for (BlockDecl::param_const_iterator I = D->param_begin(), E = D->param_end();
- I != E; ++I)
- dumpDecl(*I);
+ for (auto I : D->params())
+ dumpDecl(I);
if (D->isVariadic()) {
IndentScope Indent(*this);
@@ -1451,20 +1477,19 @@ void ASTDumper::VisitBlockDecl(const BlockDecl *D) {
IndentScope Indent(*this);
OS << "capture this";
}
- for (BlockDecl::capture_iterator I = D->capture_begin(), E = D->capture_end();
- I != E; ++I) {
+ for (const auto &I : D->captures()) {
IndentScope Indent(*this);
OS << "capture";
- if (I->isByRef())
+ if (I.isByRef())
OS << " byref";
- if (I->isNested())
+ if (I.isNested())
OS << " nested";
- if (I->getVariable()) {
+ if (I.getVariable()) {
OS << ' ';
- dumpBareDeclRef(I->getVariable());
+ dumpBareDeclRef(I.getVariable());
}
- if (I->hasCopyExpr())
- dumpStmt(I->getCopyExpr());
+ if (I.hasCopyExpr())
+ dumpStmt(I.getCopyExpr());
}
lastChild();
dumpStmt(D->getBody());
@@ -1675,6 +1700,7 @@ void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) {
case PredefinedExpr::FuncDName: OS << " __FUNCDNAME__"; break;
case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break;
case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
+ case PredefinedExpr::FuncSig: OS << " __FUNCSIG__"; break;
}
}
@@ -1705,6 +1731,22 @@ void ASTDumper::VisitStringLiteral(const StringLiteral *Str) {
Str->outputString(OS);
}
+void ASTDumper::VisitInitListExpr(const InitListExpr *ILE) {
+ VisitExpr(ILE);
+ if (auto *Filler = ILE->getArrayFiller()) {
+ if (!ILE->getNumInits())
+ lastChild();
+ IndentScope Indent(*this);
+ OS << "array filler";
+ lastChild();
+ dumpStmt(Filler);
+ }
+ if (auto *Field = ILE->getInitializedFieldInUnion()) {
+ OS << " field ";
+ dumpBareDeclRef(Field);
+ }
+}
+
void ASTDumper::VisitUnaryOperator(const UnaryOperator *Node) {
VisitExpr(Node);
OS << " " << (Node->isPostfix() ? "postfix" : "prefix")
@@ -1849,7 +1891,8 @@ void ASTDumper::dumpCXXTemporary(const CXXTemporary *Temporary) {
void ASTDumper::VisitObjCMessageExpr(const ObjCMessageExpr *Node) {
VisitExpr(Node);
- OS << " selector=" << Node->getSelector().getAsString();
+ OS << " selector=";
+ Node->getSelector().print(OS);
switch (Node->getReceiverKind()) {
case ObjCMessageExpr::Instance:
break;
@@ -1871,7 +1914,8 @@ void ASTDumper::VisitObjCMessageExpr(const ObjCMessageExpr *Node) {
void ASTDumper::VisitObjCBoxedExpr(const ObjCBoxedExpr *Node) {
VisitExpr(Node);
- OS << " selector=" << Node->getBoxingMethod()->getSelector().getAsString();
+ OS << " selector=";
+ Node->getBoxingMethod()->getSelector().print(OS);
}
void ASTDumper::VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) {
@@ -1890,7 +1934,8 @@ void ASTDumper::VisitObjCEncodeExpr(const ObjCEncodeExpr *Node) {
void ASTDumper::VisitObjCSelectorExpr(const ObjCSelectorExpr *Node) {
VisitExpr(Node);
- OS << " " << Node->getSelector().getAsString();
+ OS << " ";
+ Node->getSelector().print(OS);
}
void ASTDumper::VisitObjCProtocolExpr(const ObjCProtocolExpr *Node) {
@@ -1904,13 +1949,13 @@ void ASTDumper::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node) {
if (Node->isImplicitProperty()) {
OS << " Kind=MethodRef Getter=\"";
if (Node->getImplicitPropertyGetter())
- OS << Node->getImplicitPropertyGetter()->getSelector().getAsString();
+ Node->getImplicitPropertyGetter()->getSelector().print(OS);
else
OS << "(null)";
OS << "\" Setter=\"";
if (ObjCMethodDecl *Setter = Node->getImplicitPropertySetter())
- OS << Setter->getSelector().getAsString();
+ Setter->getSelector().print(OS);
else
OS << "(null)";
OS << "\"";
@@ -1937,7 +1982,7 @@ void ASTDumper::VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node) {
else
OS << " Kind=DictionarySubscript GetterForDictionary=\"";
if (Node->getAtIndexMethodDecl())
- OS << Node->getAtIndexMethodDecl()->getSelector().getAsString();
+ Node->getAtIndexMethodDecl()->getSelector().print(OS);
else
OS << "(null)";
@@ -1946,7 +1991,7 @@ void ASTDumper::VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node) {
else
OS << "\" SetterForDictionary=\"";
if (Node->setAtIndexMethodDecl())
- OS << Node->setAtIndexMethodDecl()->getSelector().getAsString();
+ Node->setAtIndexMethodDecl()->getSelector().print(OS);
else
OS << "(null)";
}
@@ -1975,7 +2020,7 @@ void ASTDumper::dumpFullComment(const FullComment *C) {
FC = C;
dumpComment(C);
- FC = 0;
+ FC = nullptr;
}
void ASTDumper::dumpComment(const Comment *C) {
@@ -2065,7 +2110,7 @@ void ASTDumper::visitParamCommandComment(const ParamCommandComment *C) {
OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
}
- if (C->isParamIndexValid())
+ if (C->isParamIndexValid() && !C->isVarArgParam())
OS << " ParamIndex=" << C->getParamIndex();
}
@@ -2106,27 +2151,25 @@ void ASTDumper::visitVerbatimLineComment(const VerbatimLineComment *C) {
// Decl method implementations
//===----------------------------------------------------------------------===//
-void Decl::dump() const {
- dump(llvm::errs());
-}
+LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); }
-void Decl::dump(raw_ostream &OS) const {
+LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS) const {
ASTDumper P(OS, &getASTContext().getCommentCommandTraits(),
&getASTContext().getSourceManager());
P.dumpDecl(this);
}
-void Decl::dumpColor() const {
+LLVM_DUMP_METHOD void Decl::dumpColor() const {
ASTDumper P(llvm::errs(), &getASTContext().getCommentCommandTraits(),
&getASTContext().getSourceManager(), /*ShowColors*/true);
P.dumpDecl(this);
}
-void DeclContext::dumpLookups() const {
+LLVM_DUMP_METHOD void DeclContext::dumpLookups() const {
dumpLookups(llvm::errs());
}
-void DeclContext::dumpLookups(raw_ostream &OS) const {
+LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS) const {
const DeclContext *DC = this;
while (!DC->isTranslationUnit())
DC = DC->getParent();
@@ -2139,22 +2182,22 @@ void DeclContext::dumpLookups(raw_ostream &OS) const {
// Stmt method implementations
//===----------------------------------------------------------------------===//
-void Stmt::dump(SourceManager &SM) const {
+LLVM_DUMP_METHOD void Stmt::dump(SourceManager &SM) const {
dump(llvm::errs(), SM);
}
-void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
- ASTDumper P(OS, 0, &SM);
+LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
+ ASTDumper P(OS, nullptr, &SM);
P.dumpStmt(this);
}
-void Stmt::dump() const {
- ASTDumper P(llvm::errs(), 0, 0);
+LLVM_DUMP_METHOD void Stmt::dump() const {
+ ASTDumper P(llvm::errs(), nullptr, nullptr);
P.dumpStmt(this);
}
-void Stmt::dumpColor() const {
- ASTDumper P(llvm::errs(), 0, 0, /*ShowColors*/true);
+LLVM_DUMP_METHOD void Stmt::dumpColor() const {
+ ASTDumper P(llvm::errs(), nullptr, nullptr, /*ShowColors*/true);
P.dumpStmt(this);
}
@@ -2162,11 +2205,11 @@ void Stmt::dumpColor() const {
// Comment method implementations
//===----------------------------------------------------------------------===//
-void Comment::dump() const {
- dump(llvm::errs(), 0, 0);
+LLVM_DUMP_METHOD void Comment::dump() const {
+ dump(llvm::errs(), nullptr, nullptr);
}
-void Comment::dump(const ASTContext &Context) const {
+LLVM_DUMP_METHOD void Comment::dump(const ASTContext &Context) const {
dump(llvm::errs(), &Context.getCommentCommandTraits(),
&Context.getSourceManager());
}
@@ -2178,8 +2221,8 @@ void Comment::dump(raw_ostream &OS, const CommandTraits *Traits,
D.dumpFullComment(FC);
}
-void Comment::dumpColor() const {
+LLVM_DUMP_METHOD void Comment::dumpColor() const {
const FullComment *FC = dyn_cast<FullComment>(this);
- ASTDumper D(llvm::errs(), 0, 0, /*ShowColors*/true);
+ ASTDumper D(llvm::errs(), nullptr, nullptr, /*ShowColors*/true);
D.dumpFullComment(FC);
}
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index e16015b7c4ed..b0e0b1dc9e00 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -81,7 +81,7 @@ namespace clang {
bool ImportDeclParts(NamedDecl *D, DeclContext *&DC,
DeclContext *&LexicalDC, DeclarationName &Name,
SourceLocation &Loc);
- void ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD = 0);
+ void ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD = nullptr);
void ImportDeclarationNameLoc(const DeclarationNameInfo &From,
DeclarationNameInfo& To);
void ImportDeclContext(DeclContext *FromDC, bool ForceImport = false);
@@ -407,10 +407,11 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
break;
+ case Type::Adjusted:
case Type::Decayed:
if (!IsStructurallyEquivalent(Context,
- cast<DecayedType>(T1)->getPointeeType(),
- cast<DecayedType>(T2)->getPointeeType()))
+ cast<AdjustedType>(T1)->getOriginalType(),
+ cast<AdjustedType>(T2)->getOriginalType()))
return false;
break;
@@ -534,12 +535,11 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
case Type::FunctionProto: {
const FunctionProtoType *Proto1 = cast<FunctionProtoType>(T1);
const FunctionProtoType *Proto2 = cast<FunctionProtoType>(T2);
- if (Proto1->getNumArgs() != Proto2->getNumArgs())
+ if (Proto1->getNumParams() != Proto2->getNumParams())
return false;
- for (unsigned I = 0, N = Proto1->getNumArgs(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context,
- Proto1->getArgType(I),
- Proto2->getArgType(I)))
+ for (unsigned I = 0, N = Proto1->getNumParams(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Proto1->getParamType(I),
+ Proto2->getParamType(I)))
return false;
}
if (Proto1->isVariadic() != Proto2->isVariadic())
@@ -570,9 +570,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
case Type::FunctionNoProto: {
const FunctionType *Function1 = cast<FunctionType>(T1);
const FunctionType *Function2 = cast<FunctionType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Function1->getResultType(),
- Function2->getResultType()))
+ if (!IsStructurallyEquivalent(Context, Function1->getReturnType(),
+ Function2->getReturnType()))
return false;
if (Function1->getExtInfo() != Function2->getExtInfo())
return false;
@@ -931,10 +930,8 @@ static Optional<unsigned> findAnonymousStructOrUnionIndex(RecordDecl *Anon) {
return None;
unsigned Index = 0;
- for (DeclContext::decl_iterator D = Owner->noload_decls_begin(),
- DEnd = Owner->noload_decls_end();
- D != DEnd; ++D) {
- FieldDecl *F = dyn_cast<FieldDecl>(*D);
+ for (const auto *D : Owner->noload_decls()) {
+ const auto *F = dyn_cast<FieldDecl>(D);
if (!F || !F->isAnonymousStructOrUnion())
continue;
@@ -1586,7 +1583,7 @@ QualType
ASTNodeImporter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
// FIXME: What happens if we're importing a function without a prototype
// into C++? Should we make it variadic?
- QualType ToResultType = Importer.Import(T->getResultType());
+ QualType ToResultType = Importer.Import(T->getReturnType());
if (ToResultType.isNull())
return QualType();
@@ -1595,16 +1592,14 @@ ASTNodeImporter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
}
QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) {
- QualType ToResultType = Importer.Import(T->getResultType());
+ QualType ToResultType = Importer.Import(T->getReturnType());
if (ToResultType.isNull())
return QualType();
// Import argument types
SmallVector<QualType, 4> ArgTypes;
- for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(),
- AEnd = T->arg_type_end();
- A != AEnd; ++A) {
- QualType ArgType = Importer.Import(*A);
+ for (const auto &A : T->param_types()) {
+ QualType ArgType = Importer.Import(A);
if (ArgType.isNull())
return QualType();
ArgTypes.push_back(ArgType);
@@ -1612,10 +1607,8 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) {
// Import exception types
SmallVector<QualType, 4> ExceptionTypes;
- for (FunctionProtoType::exception_iterator E = T->exception_begin(),
- EEnd = T->exception_end();
- E != EEnd; ++E) {
- QualType ExceptionType = Importer.Import(*E);
+ for (const auto &E : T->exceptions()) {
+ QualType ExceptionType = Importer.Import(E);
if (ExceptionType.isNull())
return QualType();
ExceptionTypes.push_back(ExceptionType);
@@ -1631,7 +1624,7 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) {
ToEPI.RefQualifier = FromEPI.RefQualifier;
ToEPI.NumExceptions = ExceptionTypes.size();
ToEPI.Exceptions = ExceptionTypes.data();
- ToEPI.ConsumedArguments = FromEPI.ConsumedArguments;
+ ToEPI.ConsumedParameters = FromEPI.ConsumedParameters;
ToEPI.ExceptionSpecType = FromEPI.ExceptionSpecType;
ToEPI.NoexceptExpr = Importer.Import(FromEPI.NoexceptExpr);
ToEPI.ExceptionSpecDecl = cast_or_null<FunctionDecl>(
@@ -1756,7 +1749,7 @@ QualType ASTNodeImporter::VisitTemplateSpecializationType(
}
QualType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) {
- NestedNameSpecifier *ToQualifier = 0;
+ NestedNameSpecifier *ToQualifier = nullptr;
// Note: the qualifier in an ElaboratedType is optional.
if (T->getQualifier()) {
ToQualifier = Importer.Import(T->getQualifier());
@@ -1787,11 +1780,9 @@ QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) {
return QualType();
SmallVector<ObjCProtocolDecl *, 4> Protocols;
- for (ObjCObjectType::qual_iterator P = T->qual_begin(),
- PEnd = T->qual_end();
- P != PEnd; ++P) {
+ for (auto *P : T->quals()) {
ObjCProtocolDecl *Protocol
- = dyn_cast_or_null<ObjCProtocolDecl>(Importer.Import(*P));
+ = dyn_cast_or_null<ObjCProtocolDecl>(Importer.Import(P));
if (!Protocol)
return QualType();
Protocols.push_back(Protocol);
@@ -1909,11 +1900,8 @@ void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
return;
}
- for (DeclContext::decl_iterator From = FromDC->decls_begin(),
- FromEnd = FromDC->decls_end();
- From != FromEnd;
- ++From)
- Importer.Import(*From);
+ for (auto *From : FromDC->decls())
+ Importer.Import(From);
}
bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
@@ -1946,6 +1934,7 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
ToData.HasProtectedFields = FromData.HasProtectedFields;
ToData.HasPublicFields = FromData.HasPublicFields;
ToData.HasMutableFields = FromData.HasMutableFields;
+ ToData.HasVariantMembers = FromData.HasVariantMembers;
ToData.HasOnlyCMembers = FromData.HasOnlyCMembers;
ToData.HasInClassInitializer = FromData.HasInClassInitializer;
ToData.HasUninitializedReferenceMember
@@ -1986,29 +1975,25 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
ToData.IsLambda = FromData.IsLambda;
SmallVector<CXXBaseSpecifier *, 4> Bases;
- for (CXXRecordDecl::base_class_iterator
- Base1 = FromCXX->bases_begin(),
- FromBaseEnd = FromCXX->bases_end();
- Base1 != FromBaseEnd;
- ++Base1) {
- QualType T = Importer.Import(Base1->getType());
+ for (const auto &Base1 : FromCXX->bases()) {
+ QualType T = Importer.Import(Base1.getType());
if (T.isNull())
return true;
SourceLocation EllipsisLoc;
- if (Base1->isPackExpansion())
- EllipsisLoc = Importer.Import(Base1->getEllipsisLoc());
+ if (Base1.isPackExpansion())
+ EllipsisLoc = Importer.Import(Base1.getEllipsisLoc());
// Ensure that we have a definition for the base.
- ImportDefinitionIfNeeded(Base1->getType()->getAsCXXRecordDecl());
+ ImportDefinitionIfNeeded(Base1.getType()->getAsCXXRecordDecl());
Bases.push_back(
new (Importer.getToContext())
- CXXBaseSpecifier(Importer.Import(Base1->getSourceRange()),
- Base1->isVirtual(),
- Base1->isBaseOfClass(),
- Base1->getAccessSpecifierAsWritten(),
- Importer.Import(Base1->getTypeSourceInfo()),
+ CXXBaseSpecifier(Importer.Import(Base1.getSourceRange()),
+ Base1.isVirtual(),
+ Base1.isBaseOfClass(),
+ Base1.getAccessSpecifierAsWritten(),
+ Importer.Import(Base1.getTypeSourceInfo()),
EllipsisLoc));
}
if (!Bases.empty())
@@ -2075,8 +2060,8 @@ TemplateParameterList *ASTNodeImporter::ImportTemplateParameterList(
P != PEnd; ++P) {
Decl *To = Importer.Import(*P);
if (!To)
- return 0;
-
+ return nullptr;
+
ToParams.push_back(cast<NamedDecl>(To));
}
@@ -2236,7 +2221,7 @@ bool ASTNodeImporter::IsStructuralMatch(VarTemplateDecl *From,
Decl *ASTNodeImporter::VisitDecl(Decl *D) {
Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node)
<< D->getDeclKindName();
- return 0;
+ return nullptr;
}
Decl *ASTNodeImporter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
@@ -2254,9 +2239,9 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
- return 0;
-
- NamespaceDecl *MergeWithNamespace = 0;
+ return nullptr;
+
+ NamespaceDecl *MergeWithNamespace = nullptr;
if (!Name) {
// This is an anonymous namespace. Adopt an existing anonymous
// namespace if we can.
@@ -2296,7 +2281,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
D->isInline(),
Importer.Import(D->getLocStart()),
Loc, Name.getAsIdentifierInfo(),
- /*PrevDecl=*/0);
+ /*PrevDecl=*/nullptr);
ToNamespace->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToNamespace);
@@ -2322,8 +2307,8 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
- return 0;
-
+ return nullptr;
+
// If this typedef is not in block scope, determine whether we've
// seen a typedef with the same name (that we can merge with) or any
// other entity by that name (which name lookup could conflict with).
@@ -2350,15 +2335,15 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
ConflictingDecls.data(),
ConflictingDecls.size());
if (!Name)
- return 0;
+ return nullptr;
}
}
// Import the underlying type of this typedef;
QualType T = Importer.Import(D->getUnderlyingType());
if (T.isNull())
- return 0;
-
+ return nullptr;
+
// Create the new typedef node.
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
SourceLocation StartL = Importer.Import(D->getLocStart());
@@ -2396,8 +2381,8 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
- return 0;
-
+ return nullptr;
+
// Figure out what enum name we're looking for.
unsigned IDNS = Decl::IDNS_Tag;
DeclarationName SearchName = Name;
@@ -2440,7 +2425,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
// Create the enum declaration.
EnumDecl *D2 = EnumDecl::Create(Importer.getToContext(), DC,
Importer.Import(D->getLocStart()),
- Loc, Name.getAsIdentifierInfo(), 0,
+ Loc, Name.getAsIdentifierInfo(), nullptr,
D->isScoped(), D->isScopedUsingClassTag(),
D->isFixed());
// Import the qualifier, if any.
@@ -2453,12 +2438,12 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
// Import the integer type.
QualType ToIntegerType = Importer.Import(D->getIntegerType());
if (ToIntegerType.isNull())
- return 0;
+ return nullptr;
D2->setIntegerType(ToIntegerType);
// Import the definition
if (D->isCompleteDefinition() && ImportDefinition(D, D2))
- return 0;
+ return nullptr;
return D2;
}
@@ -2471,8 +2456,8 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
if (Definition && Definition != D) {
Decl *ImportedDef = Importer.Import(Definition);
if (!ImportedDef)
- return 0;
-
+ return nullptr;
+
return Importer.Imported(D, ImportedDef);
}
@@ -2481,8 +2466,8 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
- return 0;
-
+ return nullptr;
+
// Figure out what structure name we're looking for.
unsigned IDNS = Decl::IDNS_Tag;
DeclarationName SearchName = Name;
@@ -2493,7 +2478,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
IDNS |= Decl::IDNS_Ordinary;
// We may already have a record of the same name; try to find and match it.
- RecordDecl *AdoptDecl = 0;
+ RecordDecl *AdoptDecl = nullptr;
if (!DC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
SmallVector<NamedDecl *, 2> FoundDecls;
@@ -2538,6 +2523,21 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
} else if (!D->isCompleteDefinition()) {
// We have a forward declaration of this type, so adopt that forward
// declaration rather than building a new one.
+
+ // If one or both can be completed from external storage then try one
+ // last time to complete and compare them before doing this.
+
+ if (FoundRecord->hasExternalLexicalStorage() &&
+ !FoundRecord->isCompleteDefinition())
+ FoundRecord->getASTContext().getExternalSource()->CompleteType(FoundRecord);
+ if (D->hasExternalLexicalStorage())
+ D->getASTContext().getExternalSource()->CompleteType(D);
+
+ if (FoundRecord->isCompleteDefinition() &&
+ D->isCompleteDefinition() &&
+ !IsStructuralMatch(D, FoundRecord))
+ continue;
+
AdoptDecl = FoundRecord;
continue;
} else if (!SearchName) {
@@ -2581,8 +2581,8 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
Importer.Imported(D, D2);
if (D->isCompleteDefinition() && ImportDefinition(D, D2, IDK_Default))
- return 0;
-
+ return nullptr;
+
return D2;
}
@@ -2592,11 +2592,11 @@ Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) {
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
- return 0;
+ return nullptr;
QualType T = Importer.Import(D->getType());
if (T.isNull())
- return 0;
+ return nullptr;
// Determine whether there are any other declarations with the same name and
// in the same context.
@@ -2623,14 +2623,14 @@ Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) {
ConflictingDecls.data(),
ConflictingDecls.size());
if (!Name)
- return 0;
+ return nullptr;
}
}
Expr *Init = Importer.Import(D->getInitExpr());
if (D->getInitExpr() && !Init)
- return 0;
-
+ return nullptr;
+
EnumConstantDecl *ToEnumerator
= EnumConstantDecl::Create(Importer.getToContext(), cast<EnumDecl>(DC), Loc,
Name.getAsIdentifierInfo(), T,
@@ -2648,7 +2648,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
- return 0;
+ return nullptr;
// Try to find a function in our own ("to") context with the same name, same
// type, and in the same context as the function we're importing.
@@ -2694,7 +2694,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
ConflictingDecls.data(),
ConflictingDecls.size());
if (!Name)
- return 0;
+ return nullptr;
}
}
@@ -2716,7 +2716,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
FromEPI.NoexceptExpr) {
FunctionProtoType::ExtProtoInfo DefaultEPI;
FromTy = Importer.getFromContext().getFunctionType(
- FromFPT->getResultType(), FromFPT->getArgTypes(), DefaultEPI);
+ FromFPT->getReturnType(), FromFPT->getParamTypes(), DefaultEPI);
usedDifferentExceptionSpec = true;
}
}
@@ -2724,22 +2724,21 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// Import the type.
QualType T = Importer.Import(FromTy);
if (T.isNull())
- return 0;
-
+ return nullptr;
+
// Import the function parameters.
SmallVector<ParmVarDecl *, 8> Parameters;
- for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
- P != PEnd; ++P) {
- ParmVarDecl *ToP = cast_or_null<ParmVarDecl>(Importer.Import(*P));
+ for (auto P : D->params()) {
+ ParmVarDecl *ToP = cast_or_null<ParmVarDecl>(Importer.Import(P));
if (!ToP)
- return 0;
-
+ return nullptr;
+
Parameters.push_back(ToP);
}
// Create the imported function.
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
- FunctionDecl *ToFunction = 0;
+ FunctionDecl *ToFunction = nullptr;
if (CXXConstructorDecl *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) {
ToFunction = CXXConstructorDecl::Create(Importer.getToContext(),
cast<CXXRecordDecl>(DC),
@@ -2804,7 +2803,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// Update FunctionProtoType::ExtProtoInfo.
QualType T = Importer.Import(D->getType());
if (T.isNull())
- return 0;
+ return nullptr;
ToFunction->setType(T);
}
@@ -2838,10 +2837,8 @@ static unsigned getFieldIndex(Decl *F) {
return 0;
unsigned Index = 1;
- for (DeclContext::decl_iterator D = Owner->noload_decls_begin(),
- DEnd = Owner->noload_decls_end();
- D != DEnd; ++D) {
- if (*D == F)
+ for (const auto *D : Owner->noload_decls()) {
+ if (D == F)
return Index;
if (isa<FieldDecl>(*D) || isa<IndirectFieldDecl>(*D))
@@ -2857,8 +2854,8 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
- return 0;
-
+ return nullptr;
+
// Determine whether we've already imported this field.
SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
@@ -2878,20 +2875,20 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
<< Name << D->getType() << FoundField->getType();
Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here)
<< FoundField->getType();
- return 0;
+ return nullptr;
}
}
// Import the type.
QualType T = Importer.Import(D->getType());
if (T.isNull())
- return 0;
-
+ return nullptr;
+
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
Expr *BitWidth = Importer.Import(D->getBitWidth());
if (!BitWidth && D->getBitWidth())
- return 0;
-
+ return nullptr;
+
FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC,
Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
@@ -2913,7 +2910,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
- return 0;
+ return nullptr;
// Determine whether we've already imported this field.
SmallVector<NamedDecl *, 2> FoundDecls;
@@ -2940,24 +2937,23 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
<< Name << D->getType() << FoundField->getType();
Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here)
<< FoundField->getType();
- return 0;
+ return nullptr;
}
}
// Import the type.
QualType T = Importer.Import(D->getType());
if (T.isNull())
- return 0;
+ return nullptr;
NamedDecl **NamedChain =
new (Importer.getToContext())NamedDecl*[D->getChainingSize()];
unsigned i = 0;
- for (IndirectFieldDecl::chain_iterator PI = D->chain_begin(),
- PE = D->chain_end(); PI != PE; ++PI) {
- Decl* D = Importer.Import(*PI);
+ for (auto *PI : D->chain()) {
+ Decl *D = Importer.Import(PI);
if (!D)
- return 0;
+ return nullptr;
NamedChain[i++] = cast<NamedDecl>(D);
}
@@ -2978,8 +2974,8 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
- return 0;
-
+ return nullptr;
+
// Determine whether we've already imported this ivar
SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
@@ -2995,27 +2991,26 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
<< Name << D->getType() << FoundIvar->getType();
Importer.ToDiag(FoundIvar->getLocation(), diag::note_odr_value_here)
<< FoundIvar->getType();
- return 0;
+ return nullptr;
}
}
// Import the type.
QualType T = Importer.Import(D->getType());
if (T.isNull())
- return 0;
-
+ return nullptr;
+
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
Expr *BitWidth = Importer.Import(D->getBitWidth());
if (!BitWidth && D->getBitWidth())
- return 0;
-
+ return nullptr;
+
ObjCIvarDecl *ToIvar = ObjCIvarDecl::Create(Importer.getToContext(),
cast<ObjCContainerDecl>(DC),
Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getAccessControl(),
- BitWidth, D->getSynthesize(),
- D->getBackingIvarReferencedInAccessor());
+ BitWidth, D->getSynthesize());
ToIvar->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToIvar);
LexicalDC->addDeclInternal(ToIvar);
@@ -3029,12 +3024,12 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
- return 0;
-
+ return nullptr;
+
// Try to find a variable in our own ("to") context with the same name and
// in the same context as the variable we're importing.
if (D->isFileVarDecl()) {
- VarDecl *MergeWithVar = 0;
+ VarDecl *MergeWithVar = nullptr;
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
SmallVector<NamedDecl *, 2> FoundDecls;
@@ -3063,8 +3058,8 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
// Import the type.
QualType T = Importer.Import(D->getType());
if (T.isNull())
- return 0;
-
+ return nullptr;
+
FoundVar->setType(T);
MergeWithVar = FoundVar;
break;
@@ -3115,15 +3110,15 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
ConflictingDecls.data(),
ConflictingDecls.size());
if (!Name)
- return 0;
+ return nullptr;
}
}
// Import the type.
QualType T = Importer.Import(D->getType());
if (T.isNull())
- return 0;
-
+ return nullptr;
+
// Create the imported variable.
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC,
@@ -3139,7 +3134,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
// Merge the initializer.
if (ImportDefinition(D, ToVar))
- return 0;
+ return nullptr;
return ToVar;
}
@@ -3152,16 +3147,16 @@ Decl *ASTNodeImporter::VisitImplicitParamDecl(ImplicitParamDecl *D) {
// Import the name of this declaration.
DeclarationName Name = Importer.Import(D->getDeclName());
if (D->getDeclName() && !Name)
- return 0;
-
+ return nullptr;
+
// Import the location of this declaration.
SourceLocation Loc = Importer.Import(D->getLocation());
// Import the parameter's type.
QualType T = Importer.Import(D->getType());
if (T.isNull())
- return 0;
-
+ return nullptr;
+
// Create the imported parameter.
ImplicitParamDecl *ToParm
= ImplicitParamDecl::Create(Importer.getToContext(), DC,
@@ -3178,23 +3173,23 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
// Import the name of this declaration.
DeclarationName Name = Importer.Import(D->getDeclName());
if (D->getDeclName() && !Name)
- return 0;
-
+ return nullptr;
+
// Import the location of this declaration.
SourceLocation Loc = Importer.Import(D->getLocation());
// Import the parameter's type.
QualType T = Importer.Import(D->getType());
if (T.isNull())
- return 0;
-
+ return nullptr;
+
// Create the imported parameter.
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
ParmVarDecl *ToParm = ParmVarDecl::Create(Importer.getToContext(), DC,
Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getStorageClass(),
- /*FIXME: Default argument*/ 0);
+ /*FIXME: Default argument*/nullptr);
ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg());
return Importer.Imported(D, ToParm);
}
@@ -3205,8 +3200,8 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
- return 0;
-
+ return nullptr;
+
SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
@@ -3215,15 +3210,15 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
continue;
// Check return types.
- if (!Importer.IsStructurallyEquivalent(D->getResultType(),
- FoundMethod->getResultType())) {
+ if (!Importer.IsStructurallyEquivalent(D->getReturnType(),
+ FoundMethod->getReturnType())) {
Importer.ToDiag(Loc, diag::err_odr_objc_method_result_type_inconsistent)
- << D->isInstanceMethod() << Name
- << D->getResultType() << FoundMethod->getResultType();
+ << D->isInstanceMethod() << Name << D->getReturnType()
+ << FoundMethod->getReturnType();
Importer.ToDiag(FoundMethod->getLocation(),
diag::note_odr_objc_method_here)
<< D->isInstanceMethod() << Name;
- return 0;
+ return nullptr;
}
// Check the number of parameters.
@@ -3234,7 +3229,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
Importer.ToDiag(FoundMethod->getLocation(),
diag::note_odr_objc_method_here)
<< D->isInstanceMethod() << Name;
- return 0;
+ return nullptr;
}
// Check parameter types.
@@ -3249,7 +3244,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
<< (*P)->getType() << (*FoundP)->getType();
Importer.ToDiag((*FoundP)->getLocation(), diag::note_odr_value_here)
<< (*FoundP)->getType();
- return 0;
+ return nullptr;
}
}
@@ -3261,7 +3256,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
Importer.ToDiag(FoundMethod->getLocation(),
diag::note_odr_objc_method_here)
<< D->isInstanceMethod() << Name;
- return 0;
+ return nullptr;
}
// FIXME: Any other bits we need to merge?
@@ -3270,39 +3265,28 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
}
// Import the result type.
- QualType ResultTy = Importer.Import(D->getResultType());
+ QualType ResultTy = Importer.Import(D->getReturnType());
if (ResultTy.isNull())
- return 0;
+ return nullptr;
+
+ TypeSourceInfo *ReturnTInfo = Importer.Import(D->getReturnTypeSourceInfo());
- TypeSourceInfo *ResultTInfo = Importer.Import(D->getResultTypeSourceInfo());
-
- ObjCMethodDecl *ToMethod
- = ObjCMethodDecl::Create(Importer.getToContext(),
- Loc,
- Importer.Import(D->getLocEnd()),
- Name.getObjCSelector(),
- ResultTy, ResultTInfo, DC,
- D->isInstanceMethod(),
- D->isVariadic(),
- D->isPropertyAccessor(),
- D->isImplicit(),
- D->isDefined(),
- D->getImplementationControl(),
- D->hasRelatedResultType());
+ ObjCMethodDecl *ToMethod = ObjCMethodDecl::Create(
+ Importer.getToContext(), Loc, Importer.Import(D->getLocEnd()),
+ Name.getObjCSelector(), ResultTy, ReturnTInfo, DC, D->isInstanceMethod(),
+ D->isVariadic(), D->isPropertyAccessor(), D->isImplicit(), D->isDefined(),
+ D->getImplementationControl(), D->hasRelatedResultType());
// FIXME: When we decide to merge method definitions, we'll need to
// deal with implicit parameters.
// Import the parameters
SmallVector<ParmVarDecl *, 5> ToParams;
- for (ObjCMethodDecl::param_iterator FromP = D->param_begin(),
- FromPEnd = D->param_end();
- FromP != FromPEnd;
- ++FromP) {
- ParmVarDecl *ToP = cast_or_null<ParmVarDecl>(Importer.Import(*FromP));
+ for (auto *FromP : D->params()) {
+ ParmVarDecl *ToP = cast_or_null<ParmVarDecl>(Importer.Import(FromP));
if (!ToP)
- return 0;
-
+ return nullptr;
+
ToParams.push_back(ToP);
}
@@ -3327,13 +3311,13 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
- return 0;
-
+ return nullptr;
+
ObjCInterfaceDecl *ToInterface
= cast_or_null<ObjCInterfaceDecl>(Importer.Import(D->getClassInterface()));
if (!ToInterface)
- return 0;
-
+ return nullptr;
+
// Determine if we've already encountered this category.
ObjCCategoryDecl *MergeWithCategory
= ToInterface->FindCategoryDeclaration(Name.getAsIdentifierInfo());
@@ -3363,7 +3347,7 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
ObjCProtocolDecl *ToProto
= cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto));
if (!ToProto)
- return 0;
+ return nullptr;
Protocols.push_back(ToProto);
ProtocolLocs.push_back(Importer.Import(*FromProtoLoc));
}
@@ -3385,8 +3369,8 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
= cast_or_null<ObjCCategoryImplDecl>(
Importer.Import(D->getImplementation()));
if (!Impl)
- return 0;
-
+ return nullptr;
+
ToCategory->setImplementation(Impl);
}
@@ -3441,8 +3425,8 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
if (Definition && Definition != D) {
Decl *ImportedDef = Importer.Import(Definition);
if (!ImportedDef)
- return 0;
-
+ return nullptr;
+
return Importer.Imported(D, ImportedDef);
}
@@ -3451,9 +3435,9 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
- return 0;
+ return nullptr;
- ObjCProtocolDecl *MergeWithProtocol = 0;
+ ObjCProtocolDecl *MergeWithProtocol = nullptr;
SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
@@ -3469,7 +3453,7 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
ToProto = ObjCProtocolDecl::Create(Importer.getToContext(), DC,
Name.getAsIdentifierInfo(), Loc,
Importer.Import(D->getAtStartLoc()),
- /*PrevDecl=*/0);
+ /*PrevDecl=*/nullptr);
ToProto->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToProto);
}
@@ -3477,8 +3461,8 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
Importer.Imported(D, ToProto);
if (D->isThisDeclarationADefinition() && ImportDefinition(D, ToProto))
- return 0;
-
+ return nullptr;
+
return ToProto;
}
@@ -3558,12 +3542,8 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From,
// Import categories. When the categories themselves are imported, they'll
// hook themselves into this interface.
- for (ObjCInterfaceDecl::known_categories_iterator
- Cat = From->known_categories_begin(),
- CatEnd = From->known_categories_end();
- Cat != CatEnd; ++Cat) {
- Importer.Import(*Cat);
- }
+ for (auto *Cat : From->known_categories())
+ Importer.Import(Cat);
// If we have an @implementation, import it as well.
if (From->getImplementation()) {
@@ -3590,8 +3570,8 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
if (Definition && Definition != D) {
Decl *ImportedDef = Importer.Import(Definition);
if (!ImportedDef)
- return 0;
-
+ return nullptr;
+
return Importer.Imported(D, ImportedDef);
}
@@ -3600,10 +3580,10 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
- return 0;
+ return nullptr;
// Look for an existing interface with the same name.
- ObjCInterfaceDecl *MergeWithIface = 0;
+ ObjCInterfaceDecl *MergeWithIface = nullptr;
SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
@@ -3620,7 +3600,7 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC,
Importer.Import(D->getAtStartLoc()),
Name.getAsIdentifierInfo(),
- /*PrevDecl=*/0,Loc,
+ /*PrevDecl=*/nullptr, Loc,
D->isImplicitInterfaceDecl());
ToIface->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToIface);
@@ -3628,8 +3608,8 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
Importer.Imported(D, ToIface);
if (D->isThisDeclarationADefinition() && ImportDefinition(D, ToIface))
- return 0;
-
+ return nullptr;
+
return ToIface;
}
@@ -3637,14 +3617,14 @@ Decl *ASTNodeImporter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
ObjCCategoryDecl *Category = cast_or_null<ObjCCategoryDecl>(
Importer.Import(D->getCategoryDecl()));
if (!Category)
- return 0;
-
+ return nullptr;
+
ObjCCategoryImplDecl *ToImpl = Category->getImplementation();
if (!ToImpl) {
DeclContext *DC = Importer.ImportContext(D->getDeclContext());
if (!DC)
- return 0;
-
+ return nullptr;
+
SourceLocation CategoryNameLoc = Importer.Import(D->getCategoryNameLoc());
ToImpl = ObjCCategoryImplDecl::Create(Importer.getToContext(), DC,
Importer.Import(D->getIdentifier()),
@@ -3657,8 +3637,8 @@ Decl *ASTNodeImporter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
if (D->getDeclContext() != D->getLexicalDeclContext()) {
LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
if (!LexicalDC)
- return 0;
-
+ return nullptr;
+
ToImpl->setLexicalDeclContext(LexicalDC);
}
@@ -3676,15 +3656,15 @@ Decl *ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
ObjCInterfaceDecl *Iface = cast_or_null<ObjCInterfaceDecl>(
Importer.Import(D->getClassInterface()));
if (!Iface)
- return 0;
+ return nullptr;
// Import the superclass, if any.
- ObjCInterfaceDecl *Super = 0;
+ ObjCInterfaceDecl *Super = nullptr;
if (D->getSuperClass()) {
Super = cast_or_null<ObjCInterfaceDecl>(
Importer.Import(D->getSuperClass()));
if (!Super)
- return 0;
+ return nullptr;
}
ObjCImplementationDecl *Impl = Iface->getImplementation();
@@ -3704,7 +3684,7 @@ Decl *ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
DeclContext *LexicalDC
= Importer.ImportContext(D->getLexicalDeclContext());
if (!LexicalDC)
- return 0;
+ return nullptr;
Impl->setLexicalDeclContext(LexicalDC);
}
@@ -3717,28 +3697,29 @@ Decl *ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
// Verify that the existing @implementation has the same superclass.
if ((Super && !Impl->getSuperClass()) ||
(!Super && Impl->getSuperClass()) ||
- (Super && Impl->getSuperClass() &&
- !declaresSameEntity(Super->getCanonicalDecl(), Impl->getSuperClass()))) {
- Importer.ToDiag(Impl->getLocation(),
- diag::err_odr_objc_superclass_inconsistent)
- << Iface->getDeclName();
- // FIXME: It would be nice to have the location of the superclass
- // below.
- if (Impl->getSuperClass())
- Importer.ToDiag(Impl->getLocation(),
+ (Super && Impl->getSuperClass() &&
+ !declaresSameEntity(Super->getCanonicalDecl(),
+ Impl->getSuperClass()))) {
+ Importer.ToDiag(Impl->getLocation(),
+ diag::err_odr_objc_superclass_inconsistent)
+ << Iface->getDeclName();
+ // FIXME: It would be nice to have the location of the superclass
+ // below.
+ if (Impl->getSuperClass())
+ Importer.ToDiag(Impl->getLocation(),
+ diag::note_odr_objc_superclass)
+ << Impl->getSuperClass()->getDeclName();
+ else
+ Importer.ToDiag(Impl->getLocation(),
+ diag::note_odr_objc_missing_superclass);
+ if (D->getSuperClass())
+ Importer.FromDiag(D->getLocation(),
diag::note_odr_objc_superclass)
- << Impl->getSuperClass()->getDeclName();
- else
- Importer.ToDiag(Impl->getLocation(),
+ << D->getSuperClass()->getDeclName();
+ else
+ Importer.FromDiag(D->getLocation(),
diag::note_odr_objc_missing_superclass);
- if (D->getSuperClass())
- Importer.FromDiag(D->getLocation(),
- diag::note_odr_objc_superclass)
- << D->getSuperClass()->getDeclName();
- else
- Importer.FromDiag(D->getLocation(),
- diag::note_odr_objc_missing_superclass);
- return 0;
+ return nullptr;
}
}
@@ -3754,7 +3735,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
- return 0;
+ return nullptr;
// Check whether we have already imported this property.
SmallVector<NamedDecl *, 2> FoundDecls;
@@ -3769,7 +3750,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
<< Name << D->getType() << FoundProp->getType();
Importer.ToDiag(FoundProp->getLocation(), diag::note_odr_value_here)
<< FoundProp->getType();
- return 0;
+ return nullptr;
}
// FIXME: Check property attributes, getters, setters, etc.?
@@ -3783,7 +3764,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
// Import the type.
TypeSourceInfo *T = Importer.Import(D->getTypeSourceInfo());
if (!T)
- return 0;
+ return nullptr;
// Create the new property.
ObjCPropertyDecl *ToProperty
@@ -3815,31 +3796,31 @@ Decl *ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
ObjCPropertyDecl *Property = cast_or_null<ObjCPropertyDecl>(
Importer.Import(D->getPropertyDecl()));
if (!Property)
- return 0;
+ return nullptr;
DeclContext *DC = Importer.ImportContext(D->getDeclContext());
if (!DC)
- return 0;
-
+ return nullptr;
+
// Import the lexical declaration context.
DeclContext *LexicalDC = DC;
if (D->getDeclContext() != D->getLexicalDeclContext()) {
LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
if (!LexicalDC)
- return 0;
+ return nullptr;
}
ObjCImplDecl *InImpl = dyn_cast<ObjCImplDecl>(LexicalDC);
if (!InImpl)
- return 0;
+ return nullptr;
// Import the ivar (for an @synthesize).
- ObjCIvarDecl *Ivar = 0;
+ ObjCIvarDecl *Ivar = nullptr;
if (D->getPropertyIvarDecl()) {
Ivar = cast_or_null<ObjCIvarDecl>(
Importer.Import(D->getPropertyIvarDecl()));
if (!Ivar)
- return 0;
+ return nullptr;
}
ObjCPropertyImplDecl *ToImpl
@@ -3868,7 +3849,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
diag::note_odr_objc_property_impl_kind)
<< D->getPropertyDecl()->getDeclName()
<< (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic);
- return 0;
+ return nullptr;
}
// For @synthesize, check that we have the same
@@ -3882,7 +3863,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
Importer.FromDiag(D->getPropertyIvarDeclLoc(),
diag::note_odr_objc_synthesize_ivar_here)
<< D->getPropertyIvarDecl()->getDeclName();
- return 0;
+ return nullptr;
}
// Merge the existing implementation with the new implementation.
@@ -3914,21 +3895,21 @@ ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
// Import the name of this declaration.
DeclarationName Name = Importer.Import(D->getDeclName());
if (D->getDeclName() && !Name)
- return 0;
-
+ return nullptr;
+
// Import the location of this declaration.
SourceLocation Loc = Importer.Import(D->getLocation());
// Import the type of this declaration.
QualType T = Importer.Import(D->getType());
if (T.isNull())
- return 0;
-
+ return nullptr;
+
// Import type-source information.
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
if (D->getTypeSourceInfo() && !TInfo)
- return 0;
-
+ return nullptr;
+
// FIXME: Import default argument.
return NonTypeTemplateParmDecl::Create(Importer.getToContext(),
@@ -3944,8 +3925,8 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
// Import the name of this declaration.
DeclarationName Name = Importer.Import(D->getDeclName());
if (D->getDeclName() && !Name)
- return 0;
-
+ return nullptr;
+
// Import the location of this declaration.
SourceLocation Loc = Importer.Import(D->getLocation());
@@ -3953,8 +3934,8 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
TemplateParameterList *TemplateParams
= ImportTemplateParameterList(D->getTemplateParameters());
if (!TemplateParams)
- return 0;
-
+ return nullptr;
+
// FIXME: Import default argument.
return TemplateTemplateParmDecl::Create(Importer.getToContext(),
@@ -3975,8 +3956,8 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Decl *ImportedDef
= Importer.Import(Definition->getDescribedClassTemplate());
if (!ImportedDef)
- return 0;
-
+ return nullptr;
+
return Importer.Imported(D, ImportedDef);
}
@@ -3985,8 +3966,8 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
- return 0;
-
+ return nullptr;
+
// We may already have a template of the same name; try to find and match it.
if (!DC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
@@ -4019,7 +4000,7 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
}
if (!Name)
- return 0;
+ return nullptr;
}
CXXRecordDecl *DTemplated = D->getTemplatedDecl();
@@ -4039,12 +4020,12 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
TemplateParameterList *TemplateParams
= ImportTemplateParameterList(D->getTemplateParameters());
if (!TemplateParams)
- return 0;
-
+ return nullptr;
+
ClassTemplateDecl *D2 = ClassTemplateDecl::Create(Importer.getToContext(), DC,
Loc, Name, TemplateParams,
D2Templated,
- /*PrevDecl=*/0);
+ /*PrevDecl=*/nullptr);
D2Templated->setDescribedClassTemplate(D2);
D2->setAccess(D->getAccess());
@@ -4072,8 +4053,8 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
if (Definition && Definition != D) {
Decl *ImportedDef = Importer.Import(Definition);
if (!ImportedDef)
- return 0;
-
+ return nullptr;
+
return Importer.Imported(D, ImportedDef);
}
@@ -4081,18 +4062,18 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
= cast_or_null<ClassTemplateDecl>(Importer.Import(
D->getSpecializedTemplate()));
if (!ClassTemplate)
- return 0;
-
+ return nullptr;
+
// Import the context of this declaration.
DeclContext *DC = ClassTemplate->getDeclContext();
if (!DC)
- return 0;
-
+ return nullptr;
+
DeclContext *LexicalDC = DC;
if (D->getDeclContext() != D->getLexicalDeclContext()) {
LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
if (!LexicalDC)
- return 0;
+ return nullptr;
}
// Import the location of this declaration.
@@ -4104,13 +4085,12 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
if (ImportTemplateArguments(D->getTemplateArgs().data(),
D->getTemplateArgs().size(),
TemplateArgs))
- return 0;
-
+ return nullptr;
+
// Try to find an existing specialization with these template arguments.
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
ClassTemplateSpecializationDecl *D2
- = ClassTemplate->findSpecialization(TemplateArgs.data(),
- TemplateArgs.size(), InsertPos);
+ = ClassTemplate->findSpecialization(TemplateArgs, InsertPos);
if (D2) {
// We already have a class template specialization with these template
// arguments.
@@ -4133,7 +4113,7 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
ClassTemplate,
TemplateArgs.data(),
TemplateArgs.size(),
- /*PrevDecl=*/0);
+ /*PrevDecl=*/nullptr);
D2->setSpecializationKind(D->getSpecializationKind());
// Add this specialization to the class template.
@@ -4149,8 +4129,8 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
Importer.Imported(D, D2);
if (D->isCompleteDefinition() && ImportDefinition(D, D2))
- return 0;
-
+ return nullptr;
+
return D2;
}
@@ -4164,7 +4144,7 @@ Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
if (Definition && Definition != D->getTemplatedDecl()) {
Decl *ImportedDef = Importer.Import(Definition->getDescribedVarTemplate());
if (!ImportedDef)
- return 0;
+ return nullptr;
return Importer.Imported(D, ImportedDef);
}
@@ -4174,7 +4154,7 @@ Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
- return 0;
+ return nullptr;
// We may already have a template of the same name; try to find and match it.
assert(!DC->isFunctionOrMethod() &&
@@ -4206,14 +4186,14 @@ Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
}
if (!Name)
- return 0;
+ return nullptr;
VarDecl *DTemplated = D->getTemplatedDecl();
// Import the type.
QualType T = Importer.Import(DTemplated->getType());
if (T.isNull())
- return 0;
+ return nullptr;
// Create the declaration that is being templated.
SourceLocation StartLoc = Importer.Import(DTemplated->getLocStart());
@@ -4231,17 +4211,16 @@ Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
// Merge the initializer.
if (ImportDefinition(DTemplated, D2Templated))
- return 0;
+ return nullptr;
// Create the variable template declaration itself.
TemplateParameterList *TemplateParams =
ImportTemplateParameterList(D->getTemplateParameters());
if (!TemplateParams)
- return 0;
+ return nullptr;
VarTemplateDecl *D2 = VarTemplateDecl::Create(
- Importer.getToContext(), DC, Loc, Name, TemplateParams, D2Templated,
- /*PrevDecl=*/0);
+ Importer.getToContext(), DC, Loc, Name, TemplateParams, D2Templated);
D2Templated->setDescribedVarTemplate(D2);
D2->setAccess(D->getAccess());
@@ -4269,7 +4248,7 @@ Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl(
if (Definition && Definition != D) {
Decl *ImportedDef = Importer.Import(Definition);
if (!ImportedDef)
- return 0;
+ return nullptr;
return Importer.Imported(D, ImportedDef);
}
@@ -4277,18 +4256,18 @@ Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl(
VarTemplateDecl *VarTemplate = cast_or_null<VarTemplateDecl>(
Importer.Import(D->getSpecializedTemplate()));
if (!VarTemplate)
- return 0;
+ return nullptr;
// Import the context of this declaration.
DeclContext *DC = VarTemplate->getDeclContext();
if (!DC)
- return 0;
+ return nullptr;
DeclContext *LexicalDC = DC;
if (D->getDeclContext() != D->getLexicalDeclContext()) {
LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
if (!LexicalDC)
- return 0;
+ return nullptr;
}
// Import the location of this declaration.
@@ -4299,12 +4278,12 @@ Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl(
SmallVector<TemplateArgument, 2> TemplateArgs;
if (ImportTemplateArguments(D->getTemplateArgs().data(),
D->getTemplateArgs().size(), TemplateArgs))
- return 0;
+ return nullptr;
// Try to find an existing specialization with these template arguments.
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
VarTemplateSpecializationDecl *D2 = VarTemplate->findSpecialization(
- TemplateArgs.data(), TemplateArgs.size(), InsertPos);
+ TemplateArgs, InsertPos);
if (D2) {
// We already have a variable template specialization with these template
// arguments.
@@ -4325,7 +4304,7 @@ Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl(
// Import the type.
QualType T = Importer.Import(D->getType());
if (T.isNull())
- return 0;
+ return nullptr;
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
// Create a new specialization.
@@ -4348,7 +4327,7 @@ Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl(
Importer.Imported(D, D2);
if (D->isThisDeclarationADefinition() && ImportDefinition(D, D2))
- return 0;
+ return nullptr;
return D2;
}
@@ -4360,7 +4339,7 @@ Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl(
Stmt *ASTNodeImporter::VisitStmt(Stmt *S) {
Importer.FromDiag(S->getLocStart(), diag::err_unsupported_ast_node)
<< S->getStmtClassName();
- return 0;
+ return nullptr;
}
//----------------------------------------------------------------------------
@@ -4369,24 +4348,24 @@ Stmt *ASTNodeImporter::VisitStmt(Stmt *S) {
Expr *ASTNodeImporter::VisitExpr(Expr *E) {
Importer.FromDiag(E->getLocStart(), diag::err_unsupported_ast_node)
<< E->getStmtClassName();
- return 0;
+ return nullptr;
}
Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
ValueDecl *ToD = cast_or_null<ValueDecl>(Importer.Import(E->getDecl()));
if (!ToD)
- return 0;
+ return nullptr;
- NamedDecl *FoundD = 0;
+ NamedDecl *FoundD = nullptr;
if (E->getDecl() != E->getFoundDecl()) {
FoundD = cast_or_null<NamedDecl>(Importer.Import(E->getFoundDecl()));
if (!FoundD)
- return 0;
+ return nullptr;
}
QualType T = Importer.Import(E->getType());
if (T.isNull())
- return 0;
+ return nullptr;
DeclRefExpr *DRE = DeclRefExpr::Create(Importer.getToContext(),
Importer.Import(E->getQualifierLoc()),
@@ -4396,7 +4375,7 @@ Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
Importer.Import(E->getLocation()),
T, E->getValueKind(),
FoundD,
- /*FIXME:TemplateArgs=*/0);
+ /*FIXME:TemplateArgs=*/nullptr);
if (E->hadMultipleCandidates())
DRE->setHadMultipleCandidates(true);
return DRE;
@@ -4405,7 +4384,7 @@ Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
Expr *ASTNodeImporter::VisitIntegerLiteral(IntegerLiteral *E) {
QualType T = Importer.Import(E->getType());
if (T.isNull())
- return 0;
+ return nullptr;
return IntegerLiteral::Create(Importer.getToContext(),
E->getValue(), T,
@@ -4415,8 +4394,8 @@ Expr *ASTNodeImporter::VisitIntegerLiteral(IntegerLiteral *E) {
Expr *ASTNodeImporter::VisitCharacterLiteral(CharacterLiteral *E) {
QualType T = Importer.Import(E->getType());
if (T.isNull())
- return 0;
-
+ return nullptr;
+
return new (Importer.getToContext()) CharacterLiteral(E->getValue(),
E->getKind(), T,
Importer.Import(E->getLocation()));
@@ -4425,8 +4404,8 @@ Expr *ASTNodeImporter::VisitCharacterLiteral(CharacterLiteral *E) {
Expr *ASTNodeImporter::VisitParenExpr(ParenExpr *E) {
Expr *SubExpr = Importer.Import(E->getSubExpr());
if (!SubExpr)
- return 0;
-
+ return nullptr;
+
return new (Importer.getToContext())
ParenExpr(Importer.Import(E->getLParen()),
Importer.Import(E->getRParen()),
@@ -4436,12 +4415,12 @@ Expr *ASTNodeImporter::VisitParenExpr(ParenExpr *E) {
Expr *ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) {
QualType T = Importer.Import(E->getType());
if (T.isNull())
- return 0;
+ return nullptr;
Expr *SubExpr = Importer.Import(E->getSubExpr());
if (!SubExpr)
- return 0;
-
+ return nullptr;
+
return new (Importer.getToContext()) UnaryOperator(SubExpr, E->getOpcode(),
T, E->getValueKind(),
E->getObjectKind(),
@@ -4455,8 +4434,8 @@ Expr *ASTNodeImporter::VisitUnaryExprOrTypeTraitExpr(
if (E->isArgumentType()) {
TypeSourceInfo *TInfo = Importer.Import(E->getArgumentTypeInfo());
if (!TInfo)
- return 0;
-
+ return nullptr;
+
return new (Importer.getToContext()) UnaryExprOrTypeTraitExpr(E->getKind(),
TInfo, ResultType,
Importer.Import(E->getOperatorLoc()),
@@ -4465,8 +4444,8 @@ Expr *ASTNodeImporter::VisitUnaryExprOrTypeTraitExpr(
Expr *SubExpr = Importer.Import(E->getArgumentExpr());
if (!SubExpr)
- return 0;
-
+ return nullptr;
+
return new (Importer.getToContext()) UnaryExprOrTypeTraitExpr(E->getKind(),
SubExpr, ResultType,
Importer.Import(E->getOperatorLoc()),
@@ -4476,16 +4455,16 @@ Expr *ASTNodeImporter::VisitUnaryExprOrTypeTraitExpr(
Expr *ASTNodeImporter::VisitBinaryOperator(BinaryOperator *E) {
QualType T = Importer.Import(E->getType());
if (T.isNull())
- return 0;
+ return nullptr;
Expr *LHS = Importer.Import(E->getLHS());
if (!LHS)
- return 0;
-
+ return nullptr;
+
Expr *RHS = Importer.Import(E->getRHS());
if (!RHS)
- return 0;
-
+ return nullptr;
+
return new (Importer.getToContext()) BinaryOperator(LHS, RHS, E->getOpcode(),
T, E->getValueKind(),
E->getObjectKind(),
@@ -4496,24 +4475,24 @@ Expr *ASTNodeImporter::VisitBinaryOperator(BinaryOperator *E) {
Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
QualType T = Importer.Import(E->getType());
if (T.isNull())
- return 0;
-
+ return nullptr;
+
QualType CompLHSType = Importer.Import(E->getComputationLHSType());
if (CompLHSType.isNull())
- return 0;
-
+ return nullptr;
+
QualType CompResultType = Importer.Import(E->getComputationResultType());
if (CompResultType.isNull())
- return 0;
-
+ return nullptr;
+
Expr *LHS = Importer.Import(E->getLHS());
if (!LHS)
- return 0;
-
+ return nullptr;
+
Expr *RHS = Importer.Import(E->getRHS());
if (!RHS)
- return 0;
-
+ return nullptr;
+
return new (Importer.getToContext())
CompoundAssignOperator(LHS, RHS, E->getOpcode(),
T, E->getValueKind(),
@@ -4533,15 +4512,15 @@ static bool ImportCastPath(CastExpr *E, CXXCastPath &Path) {
Expr *ASTNodeImporter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
QualType T = Importer.Import(E->getType());
if (T.isNull())
- return 0;
+ return nullptr;
Expr *SubExpr = Importer.Import(E->getSubExpr());
if (!SubExpr)
- return 0;
+ return nullptr;
CXXCastPath BasePath;
if (ImportCastPath(E, BasePath))
- return 0;
+ return nullptr;
return ImplicitCastExpr::Create(Importer.getToContext(), T, E->getCastKind(),
SubExpr, &BasePath, E->getValueKind());
@@ -4550,19 +4529,19 @@ Expr *ASTNodeImporter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
Expr *ASTNodeImporter::VisitCStyleCastExpr(CStyleCastExpr *E) {
QualType T = Importer.Import(E->getType());
if (T.isNull())
- return 0;
-
+ return nullptr;
+
Expr *SubExpr = Importer.Import(E->getSubExpr());
if (!SubExpr)
- return 0;
+ return nullptr;
TypeSourceInfo *TInfo = Importer.Import(E->getTypeInfoAsWritten());
if (!TInfo && E->getTypeInfoAsWritten())
- return 0;
-
+ return nullptr;
+
CXXCastPath BasePath;
if (ImportCastPath(E, BasePath))
- return 0;
+ return nullptr;
return CStyleCastExpr::Create(Importer.getToContext(), T,
E->getValueKind(), E->getCastKind(),
@@ -4616,7 +4595,7 @@ TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) {
// on the type and a single location. Implement a real version of this.
QualType T = Import(FromTSI->getType());
if (T.isNull())
- return 0;
+ return nullptr;
return ToContext.getTrivialTypeSourceInfo(T,
FromTSI->getTypeLoc().getLocStart());
@@ -4624,7 +4603,7 @@ TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) {
Decl *ASTImporter::Import(Decl *FromD) {
if (!FromD)
- return 0;
+ return nullptr;
ASTNodeImporter Importer(*this);
@@ -4639,8 +4618,8 @@ Decl *ASTImporter::Import(Decl *FromD) {
// Import the type
Decl *ToD = Importer.Visit(FromD);
if (!ToD)
- return 0;
-
+ return nullptr;
+
// Record the imported declaration.
ImportedDecls[FromD] = ToD;
@@ -4675,8 +4654,8 @@ DeclContext *ASTImporter::ImportContext(DeclContext *FromDC) {
DeclContext *ToDC = cast_or_null<DeclContext>(Import(cast<Decl>(FromDC)));
if (!ToDC)
- return 0;
-
+ return nullptr;
+
// When we're using a record/enum/Objective-C class/protocol as a context, we
// need it to have a definition.
if (RecordDecl *ToRecord = dyn_cast<RecordDecl>(ToDC)) {
@@ -4726,14 +4705,14 @@ DeclContext *ASTImporter::ImportContext(DeclContext *FromDC) {
Expr *ASTImporter::Import(Expr *FromE) {
if (!FromE)
- return 0;
+ return nullptr;
return cast_or_null<Expr>(Import(cast<Stmt>(FromE)));
}
Stmt *ASTImporter::Import(Stmt *FromS) {
if (!FromS)
- return 0;
+ return nullptr;
// Check whether we've already imported this declaration.
llvm::DenseMap<Stmt *, Stmt *>::iterator Pos = ImportedStmts.find(FromS);
@@ -4744,8 +4723,8 @@ Stmt *ASTImporter::Import(Stmt *FromS) {
ASTNodeImporter Importer(*this);
Stmt *ToS = Importer.Visit(FromS);
if (!ToS)
- return 0;
-
+ return nullptr;
+
// Record the imported declaration.
ImportedStmts[FromS] = ToS;
return ToS;
@@ -4753,7 +4732,7 @@ Stmt *ASTImporter::Import(Stmt *FromS) {
NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) {
if (!FromNNS)
- return 0;
+ return nullptr;
NestedNameSpecifier *prefix = Import(FromNNS->getPrefix());
@@ -4762,21 +4741,21 @@ NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) {
if (IdentifierInfo *II = Import(FromNNS->getAsIdentifier())) {
return NestedNameSpecifier::Create(ToContext, prefix, II);
}
- return 0;
+ return nullptr;
case NestedNameSpecifier::Namespace:
if (NamespaceDecl *NS =
cast<NamespaceDecl>(Import(FromNNS->getAsNamespace()))) {
return NestedNameSpecifier::Create(ToContext, prefix, NS);
}
- return 0;
+ return nullptr;
case NestedNameSpecifier::NamespaceAlias:
if (NamespaceAliasDecl *NSAD =
cast<NamespaceAliasDecl>(Import(FromNNS->getAsNamespaceAlias()))) {
return NestedNameSpecifier::Create(ToContext, prefix, NSAD);
}
- return 0;
+ return nullptr;
case NestedNameSpecifier::Global:
return NestedNameSpecifier::GlobalSpecifier(ToContext);
@@ -4791,7 +4770,7 @@ NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) {
bTemplate, T.getTypePtr());
}
}
- return 0;
+ return nullptr;
}
llvm_unreachable("Invalid nested name specifier kind");
@@ -4943,8 +4922,7 @@ FileID ASTImporter::Import(FileID FromID) {
llvm::MemoryBuffer *ToBuf
= llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(),
FromBuf->getBufferIdentifier());
- ToID = ToSM.createFileIDForMemBuffer(ToBuf,
- FromSLoc.getFile().getFileCharacteristic());
+ ToID = ToSM.createFileID(ToBuf, FromSLoc.getFile().getFileCharacteristic());
}
@@ -5054,7 +5032,7 @@ DeclarationName ASTImporter::Import(DeclarationName FromName) {
IdentifierInfo *ASTImporter::Import(const IdentifierInfo *FromId) {
if (!FromId)
- return 0;
+ return nullptr;
return &ToContext.Idents.get(FromId->getName());
}
diff --git a/lib/AST/ASTTypeTraits.cpp b/lib/AST/ASTTypeTraits.cpp
index ae47ea98882b..baa8e48779a2 100644
--- a/lib/AST/ASTTypeTraits.cpp
+++ b/lib/AST/ASTTypeTraits.cpp
@@ -39,18 +39,24 @@ const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = {
#include "clang/AST/TypeNodes.def"
};
-bool ASTNodeKind::isBaseOf(ASTNodeKind Other) const {
- return isBaseOf(KindId, Other.KindId);
+bool ASTNodeKind::isBaseOf(ASTNodeKind Other, unsigned *Distance) const {
+ return isBaseOf(KindId, Other.KindId, Distance);
}
bool ASTNodeKind::isSame(ASTNodeKind Other) const {
return KindId != NKI_None && KindId == Other.KindId;
}
-bool ASTNodeKind::isBaseOf(NodeKindId Base, NodeKindId Derived) {
+bool ASTNodeKind::isBaseOf(NodeKindId Base, NodeKindId Derived,
+ unsigned *Distance) {
if (Base == NKI_None || Derived == NKI_None) return false;
- while (Derived != Base && Derived != NKI_None)
+ unsigned Dist = 0;
+ while (Derived != Base && Derived != NKI_None) {
Derived = AllKindInfo[Derived].ParentId;
+ ++Dist;
+ }
+ if (Distance)
+ *Distance = Dist;
return Derived == Base;
}
@@ -71,7 +77,7 @@ void DynTypedNode::print(llvm::raw_ostream &OS,
else if (const Decl *D = get<Decl>())
D->print(OS, PP);
else if (const Stmt *S = get<Stmt>())
- S->printPretty(OS, 0, PP);
+ S->printPretty(OS, nullptr, PP);
else if (const Type *T = get<Type>())
QualType(T, 0).print(OS, PP);
else
diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
index 7af3c8b16263..0bf6bcd9092e 100644
--- a/lib/AST/AttrImpl.cpp
+++ b/lib/AST/AttrImpl.cpp
@@ -24,6 +24,4 @@ void InheritableAttr::anchor() { }
void InheritableParamAttr::anchor() { }
-void MSInheritanceAttr::anchor() { }
-
#include "clang/AST/AttrImpl.inc"
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 461e8b3ac18e..9006be64f73f 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -57,29 +57,8 @@ add_clang_library(clangAST
TypePrinter.cpp
VTableBuilder.cpp
VTTBuilder.cpp
- )
-
-add_dependencies(clangAST
- ClangARMNeon
- ClangAttrClasses
- ClangAttrList
- ClangAttrImpl
- ClangAttrDump
- ClangCommentCommandInfo
- ClangCommentCommandList
- ClangCommentNodes
- ClangCommentHTMLTags
- ClangCommentHTMLTagsProperties
- ClangCommentHTMLNamedCharacterReferences
- ClangDeclNodes
- ClangDiagnosticAST
- ClangDiagnosticComment
- ClangDiagnosticCommon
- ClangDiagnosticSema
- ClangStmtNodes
- )
-target_link_libraries(clangAST
+ LINK_LIBS
clangBasic
clangLex
)
diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h
index 89203f18ca77..12b929b88db0 100644
--- a/lib/AST/CXXABI.h
+++ b/lib/AST/CXXABI.h
@@ -44,7 +44,6 @@ public:
};
/// Creates an instance of a C++ ABI class.
-CXXABI *CreateARMCXXABI(ASTContext &Ctx);
CXXABI *CreateItaniumCXXABI(ASTContext &Ctx);
CXXABI *CreateMicrosoftCXXABI(ASTContext &Ctx);
}
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index b51014b7428f..6e80ee7c28a1 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -35,16 +35,12 @@ void CXXBasePaths::ComputeDeclsFound() {
std::copy(Decls.begin(), Decls.end(), DeclsFound);
}
-CXXBasePaths::decl_iterator CXXBasePaths::found_decls_begin() {
+CXXBasePaths::decl_range CXXBasePaths::found_decls() {
if (NumDeclsFound == 0)
ComputeDeclsFound();
- return DeclsFound;
-}
-CXXBasePaths::decl_iterator CXXBasePaths::found_decls_end() {
- if (NumDeclsFound == 0)
- ComputeDeclsFound();
- return DeclsFound + NumDeclsFound;
+ return decl_range(decl_iterator(DeclsFound),
+ decl_iterator(DeclsFound + NumDeclsFound));
}
/// isAmbiguous - Determines whether the set of paths provided is
@@ -62,7 +58,7 @@ void CXXBasePaths::clear() {
Paths.clear();
ClassSubobjects.clear();
ScratchPath.clear();
- DetectedVirtual = 0;
+ DetectedVirtual = nullptr;
}
/// @brief Swaps the contents of this CXXBasePaths structure with the
@@ -141,9 +137,8 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
const CXXRecordDecl *Record = this;
bool AllMatches = true;
while (true) {
- for (CXXRecordDecl::base_class_const_iterator
- I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) {
- const RecordType *Ty = I->getType()->getAs<RecordType>();
+ for (const auto &I : Record->bases()) {
+ const RecordType *Ty = I.getType()->getAs<RecordType>();
if (!Ty) {
if (AllowShortCircuit) return false;
AllMatches = false;
@@ -186,14 +181,11 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
AccessSpecifier AccessToHere = ScratchPath.Access;
bool IsFirstStep = ScratchPath.empty();
- for (CXXRecordDecl::base_class_const_iterator BaseSpec = Record->bases_begin(),
- BaseSpecEnd = Record->bases_end();
- BaseSpec != BaseSpecEnd;
- ++BaseSpec) {
+ for (const auto &BaseSpec : Record->bases()) {
// Find the record of the base class subobjects for this type.
- QualType BaseType = Context.getCanonicalType(BaseSpec->getType())
- .getUnqualifiedType();
-
+ QualType BaseType =
+ Context.getCanonicalType(BaseSpec.getType()).getUnqualifiedType();
+
// C++ [temp.dep]p3:
// In the definition of a class template or a member of a class template,
// if a base class of the class template depends on a template-parameter,
@@ -208,10 +200,10 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType];
bool VisitBase = true;
bool SetVirtual = false;
- if (BaseSpec->isVirtual()) {
+ if (BaseSpec.isVirtual()) {
VisitBase = !Subobjects.first;
Subobjects.first = true;
- if (isDetectingVirtual() && DetectedVirtual == 0) {
+ if (isDetectingVirtual() && DetectedVirtual == nullptr) {
// If this is the first virtual we find, remember it. If it turns out
// there is no base path here, we'll reset it later.
DetectedVirtual = BaseType->getAs<RecordType>();
@@ -223,9 +215,9 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
if (isRecordingPaths()) {
// Add this base specifier to the current path.
CXXBasePathElement Element;
- Element.Base = &*BaseSpec;
+ Element.Base = &BaseSpec;
Element.Class = Record;
- if (BaseSpec->isVirtual())
+ if (BaseSpec.isVirtual())
Element.SubobjectNumber = 0;
else
Element.SubobjectNumber = Subobjects.second;
@@ -247,16 +239,16 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
// 3. Otherwise, overall access is determined by the most restrictive
// access in the sequence.
if (IsFirstStep)
- ScratchPath.Access = BaseSpec->getAccessSpecifier();
+ ScratchPath.Access = BaseSpec.getAccessSpecifier();
else
ScratchPath.Access = CXXRecordDecl::MergeAccess(AccessToHere,
- BaseSpec->getAccessSpecifier());
+ BaseSpec.getAccessSpecifier());
}
// Track whether there's a path involving this specific base.
bool FoundPathThroughBase = false;
- if (BaseMatches(BaseSpec, ScratchPath, UserData)) {
+ if (BaseMatches(&BaseSpec, ScratchPath, UserData)) {
// We've found a path that terminates at this base.
FoundPath = FoundPathThroughBase = true;
if (isRecordingPaths()) {
@@ -269,7 +261,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
}
} else if (VisitBase) {
CXXRecordDecl *BaseRecord
- = cast<CXXRecordDecl>(BaseSpec->getType()->castAs<RecordType>()
+ = cast<CXXRecordDecl>(BaseSpec.getType()->castAs<RecordType>()
->getDecl());
if (lookupInBases(Context, BaseRecord, BaseMatches, UserData)) {
// C++ [class.member.lookup]p2:
@@ -294,7 +286,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
// If we set a virtual earlier, and this isn't a path, forget it again.
if (SetVirtual && !FoundPathThroughBase) {
- DetectedVirtual = 0;
+ DetectedVirtual = nullptr;
}
}
@@ -333,7 +325,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
for (CXXBasePath::iterator PE = P->begin(), PEEnd = P->end();
PE != PEEnd && !Hidden; ++PE) {
if (PE->Base->isVirtual()) {
- CXXRecordDecl *VBase = 0;
+ CXXRecordDecl *VBase = nullptr;
if (const RecordType *Record = PE->Base->getType()->getAs<RecordType>())
VBase = cast<CXXRecordDecl>(Record->getDecl());
if (!VBase)
@@ -347,7 +339,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
HidingPEnd = Paths.end();
HidingP != HidingPEnd;
++HidingP) {
- CXXRecordDecl *HidingClass = 0;
+ CXXRecordDecl *HidingClass = nullptr;
if (const RecordType *Record
= HidingP->back().Base->getType()->getAs<RecordType>())
HidingClass = cast<CXXRecordDecl>(Record->getDecl());
@@ -501,14 +493,13 @@ void FinalOverriderCollector::Collect(const CXXRecordDecl *RD,
SubobjectNumber
= ++SubobjectCount[cast<CXXRecordDecl>(RD->getCanonicalDecl())];
- for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(),
- BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) {
- if (const RecordType *RT = Base->getType()->getAs<RecordType>()) {
+ for (const auto &Base : RD->bases()) {
+ if (const RecordType *RT = Base.getType()->getAs<RecordType>()) {
const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl());
if (!BaseDecl->isPolymorphic())
continue;
- if (Overriders.empty() && !Base->isVirtual()) {
+ if (Overriders.empty() && !Base.isVirtual()) {
// There are no other overriders of virtual member functions,
// so let the base class fill in our overriders for us.
Collect(BaseDecl, false, InVirtualSubobject, Overriders);
@@ -522,7 +513,7 @@ void FinalOverriderCollector::Collect(const CXXRecordDecl *RD,
// its base classes) more than once.
CXXFinalOverriderMap ComputedBaseOverriders;
CXXFinalOverriderMap *BaseOverriders = &ComputedBaseOverriders;
- if (Base->isVirtual()) {
+ if (Base.isVirtual()) {
CXXFinalOverriderMap *&MyVirtualOverriders = VirtualOverriders[BaseDecl];
BaseOverriders = MyVirtualOverriders;
if (!MyVirtualOverriders) {
@@ -551,10 +542,7 @@ void FinalOverriderCollector::Collect(const CXXRecordDecl *RD,
}
}
- for (CXXRecordDecl::method_iterator M = RD->method_begin(),
- MEnd = RD->method_end();
- M != MEnd;
- ++M) {
+ for (auto *M : RD->methods()) {
// We only care about virtual methods.
if (!M->isVirtual())
continue;
@@ -637,7 +625,7 @@ FinalOverriderCollector::~FinalOverriderCollector() {
void
CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {
FinalOverriderCollector Collector;
- Collector.Collect(this, false, 0, FinalOverriders);
+ Collector.Collect(this, false, nullptr, FinalOverriders);
// Weed out any final overriders that come from virtual base class
// subobjects that were hidden by other subobjects along any path.
@@ -702,13 +690,12 @@ AddIndirectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context,
if (Layout.isPrimaryBaseVirtual())
Bases.insert(Layout.getPrimaryBase());
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- assert(!I->getType()->isDependentType() &&
+ for (const auto &I : RD->bases()) {
+ assert(!I.getType()->isDependentType() &&
"Cannot get indirect primary bases for class with dependent bases.");
const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
// Only bases with virtual bases participate in computing the
// indirect primary virtual base classes.
@@ -725,13 +712,12 @@ CXXRecordDecl::getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const {
if (!getNumVBases())
return;
- for (CXXRecordDecl::base_class_const_iterator I = bases_begin(),
- E = bases_end(); I != E; ++I) {
- assert(!I->getType()->isDependentType() &&
+ for (const auto &I : bases()) {
+ assert(!I.getType()->isDependentType() &&
"Cannot get indirect primary bases for class with dependent bases.");
const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
// Only bases with virtual bases participate in computing the
// indirect primary virtual base classes.
diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp
index f24a23d34c57..4f433467f9bc 100644
--- a/lib/AST/Comment.cpp
+++ b/lib/AST/Comment.cpp
@@ -136,7 +136,7 @@ void DeclInfo::fill() {
IsInstanceMethod = false;
IsClassMethod = false;
ParamVars = None;
- TemplateParameters = NULL;
+ TemplateParameters = nullptr;
if (!CommentDecl) {
// If there is no declaration, the defaults is our only guess.
@@ -159,7 +159,7 @@ void DeclInfo::fill() {
Kind = FunctionKind;
ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
FD->getNumParams());
- ResultType = FD->getResultType();
+ ReturnType = FD->getReturnType();
unsigned NumLists = FD->getNumTemplateParameterLists();
if (NumLists != 0) {
TemplateKind = TemplateSpecialization;
@@ -180,7 +180,7 @@ void DeclInfo::fill() {
Kind = FunctionKind;
ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(),
MD->param_size());
- ResultType = MD->getResultType();
+ ReturnType = MD->getReturnType();
IsObjCMethod = true;
IsInstanceMethod = MD->isInstanceMethod();
IsClassMethod = !IsInstanceMethod;
@@ -193,7 +193,7 @@ void DeclInfo::fill() {
const FunctionDecl *FD = FTD->getTemplatedDecl();
ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
FD->getNumParams());
- ResultType = FD->getResultType();
+ ReturnType = FD->getReturnType();
TemplateParameters = FTD->getTemplateParameters();
break;
}
@@ -251,6 +251,16 @@ void DeclInfo::fill() {
TL = PointerTL.getPointeeLoc().getUnqualifiedLoc();
continue;
}
+ // Look through reference types.
+ if (ReferenceTypeLoc ReferenceTL = TL.getAs<ReferenceTypeLoc>()) {
+ TL = ReferenceTL.getPointeeLoc().getUnqualifiedLoc();
+ continue;
+ }
+ // Look through adjusted types.
+ if (AdjustedTypeLoc ATL = TL.getAs<AdjustedTypeLoc>()) {
+ TL = ATL.getOriginalLoc();
+ continue;
+ }
if (BlockPointerTypeLoc BlockPointerTL =
TL.getAs<BlockPointerTypeLoc>()) {
TL = BlockPointerTL.getPointeeLoc().getUnqualifiedLoc();
@@ -261,13 +271,39 @@ void DeclInfo::fill() {
TL = MemberPointerTL.getPointeeLoc().getUnqualifiedLoc();
continue;
}
+ if (ElaboratedTypeLoc ETL = TL.getAs<ElaboratedTypeLoc>()) {
+ TL = ETL.getNamedTypeLoc();
+ continue;
+ }
// Is this a typedef for a function type?
if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
Kind = FunctionKind;
ArrayRef<ParmVarDecl *> Params = FTL.getParams();
ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
Params.size());
- ResultType = FTL.getResultLoc().getType();
+ ReturnType = FTL.getReturnLoc().getType();
+ break;
+ }
+ if (TemplateSpecializationTypeLoc STL =
+ TL.getAs<TemplateSpecializationTypeLoc>()) {
+ // If we have a typedef to a template specialization with exactly one
+ // template argument of a function type, this looks like std::function,
+ // boost::function, or other function wrapper. Treat these typedefs as
+ // functions.
+ if (STL.getNumArgs() != 1)
+ break;
+ TemplateArgumentLoc MaybeFunction = STL.getArgLoc(0);
+ if (MaybeFunction.getArgument().getKind() != TemplateArgument::Type)
+ break;
+ TypeSourceInfo *MaybeFunctionTSI = MaybeFunction.getTypeSourceInfo();
+ TypeLoc TL = MaybeFunctionTSI->getTypeLoc().getUnqualifiedLoc();
+ if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
+ Kind = FunctionKind;
+ ArrayRef<ParmVarDecl *> Params = FTL.getParams();
+ ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
+ Params.size());
+ ReturnType = FTL.getReturnLoc().getType();
+ }
break;
}
break;
diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp
index 01bd12e5fefa..a7b07a40c985 100644
--- a/lib/AST/CommentCommandTraits.cpp
+++ b/lib/AST/CommentCommandTraits.cpp
@@ -43,47 +43,42 @@ const CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const {
return getRegisteredCommandInfo(CommandID);
}
-static void
-HelperTypoCorrectCommandInfo(SmallVectorImpl<const CommandInfo *> &BestCommand,
- StringRef Typo, const CommandInfo *Command) {
- const unsigned MaxEditDistance = 1;
- unsigned BestEditDistance = MaxEditDistance + 1;
- StringRef Name = Command->Name;
-
- unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
- if (MinPossibleEditDistance > 0 &&
- Typo.size() / MinPossibleEditDistance < 1)
- return;
- unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
- if (EditDistance > MaxEditDistance)
- return;
- if (EditDistance == BestEditDistance)
- BestCommand.push_back(Command);
- else if (EditDistance < BestEditDistance) {
- BestCommand.clear();
- BestCommand.push_back(Command);
- BestEditDistance = EditDistance;
- }
-}
-
const CommandInfo *
CommandTraits::getTypoCorrectCommandInfo(StringRef Typo) const {
- // single character command impostures, such as \t or \n must not go
+ // Single-character command impostures, such as \t or \n, should not go
// through the fixit logic.
if (Typo.size() <= 1)
- return NULL;
-
+ return nullptr;
+
+ // The maximum edit distance we're prepared to accept.
+ const unsigned MaxEditDistance = 1;
+
+ unsigned BestEditDistance = MaxEditDistance;
SmallVector<const CommandInfo *, 2> BestCommand;
-
- const int NumOfCommands = llvm::array_lengthof(Commands);
- for (int i = 0; i < NumOfCommands; i++)
- HelperTypoCorrectCommandInfo(BestCommand, Typo, &Commands[i]);
-
- for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i)
- if (!RegisteredCommands[i]->IsUnknownCommand)
- HelperTypoCorrectCommandInfo(BestCommand, Typo, RegisteredCommands[i]);
-
- return (BestCommand.size() != 1) ? NULL : BestCommand[0];
+
+ auto ConsiderCorrection = [&](const CommandInfo *Command) {
+ StringRef Name = Command->Name;
+
+ unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
+ if (MinPossibleEditDistance <= BestEditDistance) {
+ unsigned EditDistance = Typo.edit_distance(Name, true, BestEditDistance);
+ if (EditDistance < BestEditDistance) {
+ BestEditDistance = EditDistance;
+ BestCommand.clear();
+ }
+ if (EditDistance == BestEditDistance)
+ BestCommand.push_back(Command);
+ }
+ };
+
+ for (const auto &Command : Commands)
+ ConsiderCorrection(&Command);
+
+ for (const auto *Command : RegisteredCommands)
+ if (!Command->IsUnknownCommand)
+ ConsiderCorrection(Command);
+
+ return BestCommand.size() == 1 ? BestCommand[0] : nullptr;
}
CommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) {
@@ -118,7 +113,7 @@ const CommandInfo *CommandTraits::getBuiltinCommandInfo(
unsigned CommandID) {
if (CommandID < llvm::array_lengthof(Commands))
return &Commands[CommandID];
- return NULL;
+ return nullptr;
}
const CommandInfo *CommandTraits::getRegisteredCommandInfo(
@@ -127,7 +122,7 @@ const CommandInfo *CommandTraits::getRegisteredCommandInfo(
if (RegisteredCommands[i]->Name == Name)
return RegisteredCommands[i];
}
- return NULL;
+ return nullptr;
}
const CommandInfo *CommandTraits::getRegisteredCommandInfo(
diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp
index 01ed3ce80a66..792a8320449b 100644
--- a/lib/AST/CommentLexer.cpp
+++ b/lib/AST/CommentLexer.cpp
@@ -268,6 +268,19 @@ const char *findCCommentEnd(const char *BufferPtr, const char *BufferEnd) {
} // unnamed namespace
+void Lexer::formTokenWithChars(Token &Result, const char *TokEnd,
+ tok::TokenKind Kind) {
+ const unsigned TokLen = TokEnd - BufferPtr;
+ Result.setLocation(getSourceLocation(BufferPtr));
+ Result.setKind(Kind);
+ Result.setLength(TokLen);
+#ifndef NDEBUG
+ Result.TextPtr = "<UNSET>";
+ Result.IntVal = 7;
+#endif
+ BufferPtr = TokEnd;
+}
+
void Lexer::lexCommentText(Token &T) {
assert(CommentState == LCS_InsideBCPLComment ||
CommentState == LCS_InsideCComment);
diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp
index 03e01015b954..cb37ec35f4d3 100644
--- a/lib/AST/CommentParser.cpp
+++ b/lib/AST/CommentParser.cpp
@@ -311,9 +311,9 @@ void Parser::parseBlockCommandArgs(BlockCommandComment *BC,
BlockCommandComment *Parser::parseBlockCommand() {
assert(Tok.is(tok::backslash_command) || Tok.is(tok::at_command));
- ParamCommandComment *PC = 0;
- TParamCommandComment *TPC = 0;
- BlockCommandComment *BC = 0;
+ ParamCommandComment *PC = nullptr;
+ TParamCommandComment *TPC = nullptr;
+ BlockCommandComment *BC = nullptr;
const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
CommandMarkerKind CommandMarker =
Tok.is(tok::backslash_command) ? CMK_Backslash : CMK_At;
diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp
index 1c6222f9ec02..12823c37dfc6 100644
--- a/lib/AST/CommentSema.cpp
+++ b/lib/AST/CommentSema.cpp
@@ -29,7 +29,8 @@ Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
DiagnosticsEngine &Diags, CommandTraits &Traits,
const Preprocessor *PP) :
Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
- PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), HeaderfileCommand(NULL) {
+ PP(PP), ThisDeclInfo(nullptr), BriefCommand(nullptr),
+ HeaderfileCommand(nullptr) {
}
void Sema::setDecl(const Decl *D) {
@@ -68,8 +69,12 @@ void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
Command->setParagraph(Paragraph);
checkBlockCommandEmptyParagraph(Command);
checkBlockCommandDuplicate(Command);
- checkReturnsCommand(Command);
- checkDeprecatedCommand(Command);
+ if (ThisDeclInfo) {
+ // These checks only make sense if the comment is attached to a
+ // declaration.
+ checkReturnsCommand(Command);
+ checkDeprecatedCommand(Command);
+ }
}
ParamCommandComment *Sema::actOnParamCommandStart(
@@ -122,7 +127,7 @@ void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
<< (DiagSelect-1) << (DiagSelect-1)
<< Comment->getSourceRange();
}
-
+
void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
if (!Info->IsRecordLikeDeclarationCommand)
@@ -478,6 +483,7 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
if (isHTMLEndTagForbidden(TagName)) {
Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
<< TagName << HET->getSourceRange();
+ HET->setIsMalformed();
return HET;
}
@@ -493,14 +499,19 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
if (!FoundOpen) {
Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
<< HET->getSourceRange();
+ HET->setIsMalformed();
return HET;
}
while (!HTMLOpenTags.empty()) {
- const HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
+ HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
StringRef LastNotClosedTagName = HST->getTagName();
- if (LastNotClosedTagName == TagName)
+ if (LastNotClosedTagName == TagName) {
+ // If the start tag is malformed, end tag is malformed as well.
+ if (HST->isMalformed())
+ HET->setIsMalformed();
break;
+ }
if (isHTMLEndTagOptional(LastNotClosedTagName))
continue;
@@ -514,16 +525,18 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
HET->getLocation(),
&CloseLineInvalid);
- if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine)
+ if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
<< HST->getTagName() << HET->getTagName()
<< HST->getSourceRange() << HET->getSourceRange();
- else {
+ HST->setIsMalformed();
+ } else {
Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
<< HST->getTagName() << HET->getTagName()
<< HST->getSourceRange();
Diag(HET->getLocation(), diag::note_doc_html_end_tag)
<< HET->getSourceRange();
+ HST->setIsMalformed();
}
}
@@ -534,6 +547,18 @@ FullComment *Sema::actOnFullComment(
ArrayRef<BlockContentComment *> Blocks) {
FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
resolveParamCommandIndexes(FC);
+
+ // Complain about HTML tags that are not closed.
+ while (!HTMLOpenTags.empty()) {
+ HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
+ if (isHTMLEndTagOptional(HST->getTagName()))
+ continue;
+
+ Diag(HST->getLocation(), diag::warn_doc_html_missing_end_tag)
+ << HST->getTagName() << HST->getSourceRange();
+ HST->setIsMalformed();
+ }
+
return FC;
}
@@ -558,8 +583,11 @@ void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
return;
+
+ assert(ThisDeclInfo && "should not call this check on a bare comment");
+
if (isFunctionDecl()) {
- if (ThisDeclInfo->ResultType->isVoidType()) {
+ if (ThisDeclInfo->ReturnType->isVoidType()) {
unsigned DiagKind;
switch (ThisDeclInfo->CommentDecl->getKind()) {
default:
@@ -586,7 +614,7 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
}
else if (isObjCPropertyDecl())
return;
-
+
Diag(Command->getLocation(),
diag::warn_doc_returns_not_attached_to_a_function_decl)
<< Command->getCommandMarker()
@@ -596,7 +624,7 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
- const BlockCommandComment *PrevCommand = NULL;
+ const BlockCommandComment *PrevCommand = nullptr;
if (Info->IsBriefCommand) {
if (!BriefCommand) {
BriefCommand = Command;
@@ -636,6 +664,8 @@ void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
return;
+ assert(ThisDeclInfo && "should not call this check on a bare comment");
+
const Decl *D = ThisDeclInfo->CommentDecl;
if (!D)
return;
@@ -694,7 +724,7 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) {
SmallVector<ParamCommandComment *, 8> ParamVarDocs;
ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
- ParamVarDocs.resize(ParamVars.size(), NULL);
+ ParamVarDocs.resize(ParamVars.size(), nullptr);
// First pass over all \\param commands: resolve all parameter names.
for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end();
@@ -783,11 +813,14 @@ bool Sema::isAnyFunctionDecl() {
}
bool Sema::isFunctionOrMethodVariadic() {
- if (!isAnyFunctionDecl() && !isObjCMethodDecl())
+ if (!isAnyFunctionDecl() && !isObjCMethodDecl() && !isFunctionTemplateDecl())
return false;
if (const FunctionDecl *FD =
dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl))
return FD->isVariadic();
+ if (const FunctionTemplateDecl *FTD =
+ dyn_cast<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl))
+ return FTD->getTemplatedDecl()->isVariadic();
if (const ObjCMethodDecl *MD =
dyn_cast<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl))
return MD->isVariadic();
@@ -812,7 +845,7 @@ bool Sema::isFunctionPointerVarDecl() {
}
return false;
}
-
+
bool Sema::isObjCPropertyDecl() {
if (!ThisDeclInfo)
return false;
@@ -834,8 +867,8 @@ bool Sema::isRecordLikeDecl() {
return false;
if (!ThisDeclInfo->IsFilled)
inspectThisDecl();
- return isUnionDecl() || isClassOrStructDecl()
- || isObjCInterfaceDecl() || isObjCProtocolDecl();
+ return isUnionDecl() || isClassOrStructDecl() || isObjCInterfaceDecl() ||
+ isObjCProtocolDecl();
}
bool Sema::isUnionDecl() {
@@ -848,7 +881,7 @@ bool Sema::isUnionDecl() {
return RD->isUnion();
return false;
}
-
+
bool Sema::isClassOrStructDecl() {
if (!ThisDeclInfo)
return false;
@@ -858,7 +891,7 @@ bool Sema::isClassOrStructDecl() {
isa<RecordDecl>(ThisDeclInfo->CurrentDecl) &&
!isUnionDecl();
}
-
+
bool Sema::isClassTemplateDecl() {
if (!ThisDeclInfo)
return false;
@@ -874,7 +907,7 @@ bool Sema::isFunctionTemplateDecl() {
if (!ThisDeclInfo->IsFilled)
inspectThisDecl();
return ThisDeclInfo->CurrentDecl &&
- (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl));
+ (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl));
}
bool Sema::isObjCInterfaceDecl() {
@@ -885,7 +918,7 @@ bool Sema::isObjCInterfaceDecl() {
return ThisDeclInfo->CurrentDecl &&
isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
}
-
+
bool Sema::isObjCProtocolDecl() {
if (!ThisDeclInfo)
return false;
@@ -894,7 +927,7 @@ bool Sema::isObjCProtocolDecl() {
return ThisDeclInfo->CurrentDecl &&
isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
}
-
+
ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
if (!ThisDeclInfo->IsFilled)
inspectThisDecl();
@@ -930,7 +963,7 @@ class SimpleTypoCorrector {
public:
SimpleTypoCorrector(StringRef Typo) :
Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
- BestDecl(NULL), BestEditDistance(MaxEditDistance + 1),
+ BestDecl(nullptr), BestEditDistance(MaxEditDistance + 1),
BestIndex(0), NextIndex(0)
{ }
@@ -938,7 +971,7 @@ public:
const NamedDecl *getBestDecl() const {
if (BestEditDistance > MaxEditDistance)
- return NULL;
+ return nullptr;
return BestDecl;
}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 6bd985851a39..7448de2ffbc9 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
@@ -29,7 +30,6 @@
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/type_traits.h"
#include <algorithm>
using namespace clang;
@@ -158,8 +158,7 @@ static bool usesTypeVisibility(const NamedDecl *D) {
/// Does the given declaration have member specialization information,
/// and if so, is it an explicit specialization?
template <class T> static typename
-llvm::enable_if_c<!llvm::is_base_of<RedeclarableTemplateDecl, T>::value,
- bool>::type
+std::enable_if<!std::is_base_of<RedeclarableTemplateDecl, T>::value, bool>::type
isExplicitMemberSpecialization(const T *D) {
if (const MemberSpecializationInfo *member =
D->getMemberSpecializationInfo()) {
@@ -209,11 +208,8 @@ static Optional<Visibility> getVisibilityOf(const NamedDecl *D,
// If we're on Mac OS X, an 'availability' for Mac OS X attribute
// implies visibility(default).
if (D->getASTContext().getTargetInfo().getTriple().isOSDarwin()) {
- for (specific_attr_iterator<AvailabilityAttr>
- A = D->specific_attr_begin<AvailabilityAttr>(),
- AEnd = D->specific_attr_end<AvailabilityAttr>();
- A != AEnd; ++A)
- if ((*A)->getPlatform()->getName().equals("macosx"))
+ for (const auto *A : D->specific_attrs<AvailabilityAttr>())
+ if (A->getPlatform()->getName().equals("macosx"))
return DefaultVisibility;
}
@@ -231,23 +227,21 @@ getLVForType(const Type &T, LVComputationKind computation) {
/// template parameter list. For visibility purposes, template
/// parameters are part of the signature of a template.
static LinkageInfo
-getLVForTemplateParameterList(const TemplateParameterList *params,
+getLVForTemplateParameterList(const TemplateParameterList *Params,
LVComputationKind computation) {
LinkageInfo LV;
- for (TemplateParameterList::const_iterator P = params->begin(),
- PEnd = params->end();
- P != PEnd; ++P) {
-
+ for (const NamedDecl *P : *Params) {
// Template type parameters are the most common and never
// contribute to visibility, pack or not.
- if (isa<TemplateTypeParmDecl>(*P))
+ if (isa<TemplateTypeParmDecl>(P))
continue;
// Non-type template parameters can be restricted by the value type, e.g.
// template <enum X> class A { ... };
// We have to be careful here, though, because we can be dealing with
// dependent types.
- if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
+ if (const NonTypeTemplateParmDecl *NTTP =
+ dyn_cast<NonTypeTemplateParmDecl>(P)) {
// Handle the non-pack case first.
if (!NTTP->isExpandedParameterPack()) {
if (!NTTP->getType()->isDependentType()) {
@@ -267,7 +261,7 @@ getLVForTemplateParameterList(const TemplateParameterList *params,
// Template template parameters can be restricted by their
// template parameters, recursively.
- TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P);
+ const TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(P);
// Handle the non-pack case first.
if (!TTP->isExpandedParameterPack()) {
@@ -292,7 +286,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D,
LVComputationKind computation);
static const Decl *getOutermostFuncOrBlockContext(const Decl *D) {
- const Decl *Ret = NULL;
+ const Decl *Ret = nullptr;
const DeclContext *DC = D->getDeclContext();
while (DC->getDeclKind() != Decl::TranslationUnit) {
if (isa<FunctionDecl>(DC) || isa<BlockDecl>(DC))
@@ -307,43 +301,41 @@ static const Decl *getOutermostFuncOrBlockContext(const Decl *D) {
///
/// Note that we don't take an LVComputationKind because we always
/// want to honor the visibility of template arguments in the same way.
-static LinkageInfo
-getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args,
- LVComputationKind computation) {
+static LinkageInfo getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args,
+ LVComputationKind computation) {
LinkageInfo LV;
- for (unsigned i = 0, e = args.size(); i != e; ++i) {
- const TemplateArgument &arg = args[i];
- switch (arg.getKind()) {
+ for (const TemplateArgument &Arg : Args) {
+ switch (Arg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Expression:
continue;
case TemplateArgument::Type:
- LV.merge(getLVForType(*arg.getAsType(), computation));
+ LV.merge(getLVForType(*Arg.getAsType(), computation));
continue;
case TemplateArgument::Declaration:
- if (NamedDecl *ND = dyn_cast<NamedDecl>(arg.getAsDecl())) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(Arg.getAsDecl())) {
assert(!usesTypeVisibility(ND));
LV.merge(getLVForDecl(ND, computation));
}
continue;
case TemplateArgument::NullPtr:
- LV.merge(arg.getNullPtrType()->getLinkageAndVisibility());
+ LV.merge(Arg.getNullPtrType()->getLinkageAndVisibility());
continue;
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
- if (TemplateDecl *Template
- = arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl())
+ if (TemplateDecl *Template =
+ Arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl())
LV.merge(getLVForDecl(Template, computation));
continue;
case TemplateArgument::Pack:
- LV.merge(getLVForTemplateArgumentList(arg.getPackAsArray(), computation));
+ LV.merge(getLVForTemplateArgumentList(Arg.getPackAsArray(), computation));
continue;
}
llvm_unreachable("bad template argument kind");
@@ -479,6 +471,58 @@ static void mergeTemplateLV(LinkageInfo &LV,
LV.mergeExternalVisibility(argsLV);
}
+/// Should we consider visibility associated with the template
+/// arguments and parameters of the given variable template
+/// specialization? As usual, follow class template specialization
+/// logic up to initialization.
+static bool shouldConsiderTemplateVisibility(
+ const VarTemplateSpecializationDecl *spec,
+ LVComputationKind computation) {
+ // Include visibility from the template parameters and arguments
+ // only if this is not an explicit instantiation or specialization
+ // with direct explicit visibility (and note that implicit
+ // instantiations won't have a direct attribute).
+ if (!spec->isExplicitInstantiationOrSpecialization())
+ return true;
+
+ // An explicit variable specialization is an independent, top-level
+ // declaration. As such, if it has an explicit visibility attribute,
+ // that must directly express the user's intent, and we should honor
+ // it.
+ if (spec->isExplicitSpecialization() &&
+ hasExplicitVisibilityAlready(computation))
+ return false;
+
+ return !hasDirectVisibilityAttribute(spec, computation);
+}
+
+/// Merge in template-related linkage and visibility for the given
+/// variable template specialization. As usual, follow class template
+/// specialization logic up to initialization.
+static void mergeTemplateLV(LinkageInfo &LV,
+ const VarTemplateSpecializationDecl *spec,
+ LVComputationKind computation) {
+ bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation);
+
+ // Merge information from the template parameters, but ignore
+ // visibility if we're only considering template arguments.
+
+ VarTemplateDecl *temp = spec->getSpecializedTemplate();
+ LinkageInfo tempLV =
+ getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
+ LV.mergeMaybeWithVisibility(tempLV,
+ considerVisibility && !hasExplicitVisibilityAlready(computation));
+
+ // Merge information from the template arguments. We ignore
+ // template-argument visibility if we've got an explicit
+ // instantiation with a visibility attribute.
+ const TemplateArgumentList &templateArgs = spec->getTemplateArgs();
+ LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs, computation);
+ if (considerVisibility)
+ LV.mergeVisibility(argsLV);
+ LV.mergeExternalVisibility(argsLV);
+}
+
static bool useInlineVisibilityHidden(const NamedDecl *D) {
// FIXME: we should warn if -fvisibility-inlines-hidden is used with c.
const LangOptions &Opts = D->getASTContext().getLangOpts();
@@ -498,7 +542,7 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) {
TSK = MSI->getTemplateSpecializationKind();
}
- const FunctionDecl *Def = 0;
+ const FunctionDecl *Def = nullptr;
// InlineVisibilityHidden only applies to definitions, and
// isInlined() only gives meaningful answers on definitions
// anyway.
@@ -512,9 +556,9 @@ template <typename T> static bool isFirstInExternCContext(T *D) {
return First->isInExternCContext();
}
-static bool isSingleLineExternC(const Decl &D) {
+static bool isSingleLineLanguageLinkage(const Decl &D) {
if (const LinkageSpecDecl *SD = dyn_cast<LinkageSpecDecl>(D.getDeclContext()))
- if (SD->getLanguage() == LinkageSpecDecl::lang_c && !SD->hasBraces())
+ if (!SD->hasBraces())
return true;
return false;
}
@@ -548,7 +592,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
if (Var->getStorageClass() != SC_Extern &&
Var->getStorageClass() != SC_PrivateExtern &&
- !isSingleLineExternC(*Var))
+ !isSingleLineLanguageLinkage(*Var))
return LinkageInfo::internal();
}
@@ -561,16 +605,10 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
if (PrevVar->getStorageClass() == SC_Static)
return LinkageInfo::internal();
}
- } else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
+ } else if (const FunctionDecl *Function = D->getAsFunction()) {
// C++ [temp]p4:
// A non-member function template can have internal linkage; any
// other template name shall have external linkage.
- const FunctionDecl *Function = 0;
- if (const FunctionTemplateDecl *FunTmpl
- = dyn_cast<FunctionTemplateDecl>(D))
- Function = FunTmpl->getTemplatedDecl();
- else
- Function = cast<FunctionDecl>(D);
// Explicitly declared static.
if (Function->getCanonicalDecl()->getStorageClass() == SC_Static)
@@ -676,6 +714,14 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// C99 6.2.2p4 and propagating the visibility attribute, so we don't have
// to do it here.
+ // As per function and class template specializations (below),
+ // consider LV for the template and template arguments. We're at file
+ // scope, so we do not need to worry about nested specializations.
+ if (const VarTemplateSpecializationDecl *spec
+ = dyn_cast<VarTemplateSpecializationDecl>(Var)) {
+ mergeTemplateLV(LV, spec, computation);
+ }
+
// - a function, unless it has internal linkage; or
} else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
// In theory, we can modify the function's LV by the LV of its
@@ -782,11 +828,18 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
// really have linkage, but it's convenient to say they do for the
// purposes of calculating linkage of pointer-to-data-member
// template arguments.
+ //
+ // Templates also don't officially have linkage, but since we ignore
+ // the C++ standard and look at template arguments when determining
+ // linkage and visibility of a template specialization, we might hit
+ // a template template argument that way. If we do, we need to
+ // consider its linkage.
if (!(isa<CXXMethodDecl>(D) ||
isa<VarDecl>(D) ||
isa<FieldDecl>(D) ||
isa<IndirectFieldDecl>(D) ||
- isa<TagDecl>(D)))
+ isa<TagDecl>(D) ||
+ isa<TemplateDecl>(D)))
return LinkageInfo::none();
LinkageInfo LV;
@@ -825,7 +878,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
// we need to completely ignore the visibility from it.
// Specifically, if this decl exists and has an explicit attribute.
- const NamedDecl *explicitSpecSuppressor = 0;
+ const NamedDecl *explicitSpecSuppressor = nullptr;
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
// If the type of the function uses a type with unique-external
@@ -876,6 +929,10 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
// Static data members.
} else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (const VarTemplateSpecializationDecl *spec
+ = dyn_cast<VarTemplateSpecializationDecl>(VD))
+ mergeTemplateLV(LV, spec, computation);
+
// Modify the variable's linkage by its type, but ignore the
// type's visibility unless it's a definition.
LinkageInfo typeLV = getLVForType(*VD->getType(), computation);
@@ -989,6 +1046,10 @@ getExplicitVisibilityAux(const NamedDecl *ND,
return getVisibilityOf(InstantiatedFrom, kind);
}
+ if (const auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Var))
+ return getVisibilityOf(VTSD->getSpecializedTemplate()->getTemplatedDecl(),
+ kind);
+
return None;
}
// Also handle function template specializations.
@@ -1242,16 +1303,13 @@ public:
// We have just computed the linkage for this decl. By induction we know
// that all other computed linkages match, check that the one we just
- // computed
- // also does.
- NamedDecl *Old = NULL;
- for (NamedDecl::redecl_iterator I = D->redecls_begin(),
- E = D->redecls_end();
- I != E; ++I) {
- NamedDecl *T = cast<NamedDecl>(*I);
+ // computed also does.
+ NamedDecl *Old = nullptr;
+ for (auto I : D->redecls()) {
+ NamedDecl *T = cast<NamedDecl>(I);
if (T == D)
continue;
- if (T->hasCachedLinkage()) {
+ if (!T->isInvalidDecl() && T->hasCachedLinkage()) {
Old = T;
break;
}
@@ -1270,13 +1328,9 @@ static LinkageInfo getLVForDecl(const NamedDecl *D,
}
std::string NamedDecl::getQualifiedNameAsString() const {
- return getQualifiedNameAsString(getASTContext().getPrintingPolicy());
-}
-
-std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
std::string QualName;
llvm::raw_string_ostream OS(QualName);
- printQualifiedName(OS, P);
+ printQualifiedName(OS, getASTContext().getPrintingPolicy());
return OS.str();
}
@@ -1313,17 +1367,20 @@ void NamedDecl::printQualifiedName(raw_ostream &OS,
TemplateArgs.size(),
P);
} else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(*I)) {
+ if (P.SuppressUnwrittenScope &&
+ (ND->isAnonymousNamespace() || ND->isInline()))
+ continue;
if (ND->isAnonymousNamespace())
- OS << "<anonymous namespace>";
+ OS << "(anonymous namespace)";
else
OS << *ND;
} else if (const RecordDecl *RD = dyn_cast<RecordDecl>(*I)) {
if (!RD->getIdentifier())
- OS << "<anonymous " << RD->getKindName() << '>';
+ OS << "(anonymous " << RD->getKindName() << ')';
else
OS << *RD;
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
- const FunctionProtoType *FT = 0;
+ const FunctionProtoType *FT = nullptr;
if (FD->hasWrittenPrototype())
FT = dyn_cast<FunctionProtoType>(FD->getType()->castAs<FunctionType>());
@@ -1352,7 +1409,7 @@ void NamedDecl::printQualifiedName(raw_ostream &OS,
if (getDeclName())
OS << *this;
else
- OS << "<anonymous>";
+ OS << "(anonymous)";
}
void NamedDecl::getNameForDiagnostic(raw_ostream &OS,
@@ -1392,6 +1449,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
if (isa<ObjCMethodDecl>(this))
return false;
+ // FIXME: Is this correct if one of the decls comes from an inline namespace?
if (isa<ObjCInterfaceDecl>(this) && isa<ObjCCompatibleAliasDecl>(OldD))
return true;
@@ -1418,14 +1476,19 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
// A typedef of an Objective-C class type can replace an Objective-C class
// declaration or definition, and vice versa.
+ // FIXME: Is this correct if one of the decls comes from an inline namespace?
if ((isa<TypedefNameDecl>(this) && isa<ObjCInterfaceDecl>(OldD)) ||
(isa<ObjCInterfaceDecl>(this) && isa<TypedefNameDecl>(OldD)))
return true;
-
+
// For non-function declarations, if the declarations are of the
- // same kind then this must be a redeclaration, or semantic analysis
- // would not have given us the new declaration.
- return this->getKind() == OldD->getKind();
+ // same kind and have the same parent then this must be a redeclaration,
+ // or semantic analysis would not have given us the new declaration.
+ // Note that inline namespaces can give us two declarations with the same
+ // name and kind in the same scope but different contexts.
+ return this->getKind() == OldD->getKind() &&
+ this->getDeclContext()->getRedeclContext()->Equals(
+ OldD->getDeclContext()->getRedeclContext());
}
bool NamedDecl::hasLinkage() const {
@@ -1453,11 +1516,9 @@ bool NamedDecl::isCXXInstanceMember() const {
if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D) || isa<MSPropertyDecl>(D))
return true;
- if (isa<CXXMethodDecl>(D))
- return cast<CXXMethodDecl>(D)->isInstance();
- if (isa<FunctionTemplateDecl>(D))
- return cast<CXXMethodDecl>(cast<FunctionTemplateDecl>(D)
- ->getTemplatedDecl())->isInstance();
+ if (const CXXMethodDecl *MD =
+ dyn_cast_or_null<CXXMethodDecl>(D->getAsFunction()))
+ return MD->isInstance();
return false;
}
@@ -1574,7 +1635,9 @@ bool typeIsPostfix(clang::QualType QT) {
SourceRange DeclaratorDecl::getSourceRange() const {
SourceLocation RangeEnd = getLocation();
if (TypeSourceInfo *TInfo = getTypeSourceInfo()) {
- if (typeIsPostfix(TInfo->getType()))
+ // If the declaration has no name or the type extends past the name take the
+ // end location of the type.
+ if (!getDeclName() || typeIsPostfix(TInfo->getType()))
RangeEnd = TInfo->getTypeLoc().getSourceRange().getEnd();
}
return SourceRange(getOuterLocStart(), RangeEnd);
@@ -1584,13 +1647,13 @@ void
QualifierInfo::setTemplateParameterListsInfo(ASTContext &Context,
unsigned NumTPLists,
TemplateParameterList **TPLists) {
- assert((NumTPLists == 0 || TPLists != 0) &&
+ assert((NumTPLists == 0 || TPLists != nullptr) &&
"Empty array of template parameters with positive size!");
// Free previous template parameters (if any).
if (NumTemplParamLists > 0) {
Context.Deallocate(TemplParamLists);
- TemplParamLists = 0;
+ TemplParamLists = nullptr;
NumTemplParamLists = 0;
}
// Set info on matched template parameter lists (if any).
@@ -1620,12 +1683,16 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
llvm_unreachable("Invalid storage class");
}
-VarDecl::VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
- SourceLocation IdLoc, IdentifierInfo *Id, QualType T,
- TypeSourceInfo *TInfo, StorageClass SC)
- : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init() {
- assert(sizeof(VarDeclBitfields) <= sizeof(unsigned));
- assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned));
+VarDecl::VarDecl(Kind DK, ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
+ StorageClass SC)
+ : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc),
+ redeclarable_base(C), Init() {
+ static_assert(sizeof(VarDeclBitfields) <= sizeof(unsigned),
+ "VarDeclBitfields too large!");
+ static_assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned),
+ "ParmVarDeclBitfields too large!");
AllBits = 0;
VarDeclBits.SClass = SC;
// Everything else is implicitly initialized to false.
@@ -1635,13 +1702,13 @@ VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartL, SourceLocation IdL,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
StorageClass S) {
- return new (C) VarDecl(Var, DC, StartL, IdL, Id, T, TInfo, S);
+ return new (C, DC) VarDecl(Var, C, DC, StartL, IdL, Id, T, TInfo, S);
}
VarDecl *VarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(VarDecl));
- return new (Mem) VarDecl(Var, 0, SourceLocation(), SourceLocation(), 0,
- QualType(), 0, SC_None);
+ return new (C, ID)
+ VarDecl(Var, C, nullptr, SourceLocation(), SourceLocation(), nullptr,
+ QualType(), nullptr, SC_None);
}
void VarDecl::setStorageClass(StorageClass SC) {
@@ -1649,6 +1716,21 @@ void VarDecl::setStorageClass(StorageClass SC) {
VarDeclBits.SClass = SC;
}
+VarDecl::TLSKind VarDecl::getTLSKind() const {
+ switch (VarDeclBits.TSCSpec) {
+ case TSCS_unspecified:
+ if (hasAttr<ThreadAttr>())
+ return TLS_Static;
+ return TLS_None;
+ case TSCS___thread: // Fall through.
+ case TSCS__Thread_local:
+ return TLS_Static;
+ case TSCS_thread_local:
+ return TLS_Dynamic;
+ }
+ llvm_unreachable("Unknown thread storage class specifier!");
+}
+
SourceRange VarDecl::getSourceRange() const {
if (const Expr *Init = getInit()) {
SourceLocation InitEnd = Init->getLocEnd();
@@ -1661,7 +1743,7 @@ SourceRange VarDecl::getSourceRange() const {
}
template<typename T>
-static LanguageLinkage getLanguageLinkageTemplate(const T &D) {
+static LanguageLinkage getDeclLanguageLinkage(const T &D) {
// C++ [dcl.link]p1: All function types, function names with external linkage,
// and variable names with external linkage have a language linkage.
if (!D.hasExternalFormalLinkage())
@@ -1689,7 +1771,7 @@ static LanguageLinkage getLanguageLinkageTemplate(const T &D) {
}
template<typename T>
-static bool isExternCTemplate(const T &D) {
+static bool isDeclExternC(const T &D) {
// Since the context is ignored for class members, they can only have C++
// language linkage or no language linkage.
const DeclContext *DC = D.getDeclContext();
@@ -1702,11 +1784,11 @@ static bool isExternCTemplate(const T &D) {
}
LanguageLinkage VarDecl::getLanguageLinkage() const {
- return getLanguageLinkageTemplate(*this);
+ return getDeclLanguageLinkage(*this);
}
bool VarDecl::isExternC() const {
- return isExternCTemplate(*this);
+ return isDeclExternC(*this);
}
bool VarDecl::isInExternCContext() const {
@@ -1775,7 +1857,7 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
// A declaration directly contained in a linkage-specification is treated
// as if it contains the extern specifier for the purpose of determining
// the linkage of the declared name and whether it is a definition.
- if (isSingleLineExternC(*this))
+ if (isSingleLineLanguageLinkage(*this))
return DeclarationOnly;
// C99 6.9.2p2:
@@ -1794,38 +1876,35 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
VarDecl *VarDecl::getActingDefinition() {
DefinitionKind Kind = isThisDeclarationADefinition();
if (Kind != TentativeDefinition)
- return 0;
+ return nullptr;
- VarDecl *LastTentative = 0;
+ VarDecl *LastTentative = nullptr;
VarDecl *First = getFirstDecl();
- for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
- I != E; ++I) {
- Kind = (*I)->isThisDeclarationADefinition();
+ for (auto I : First->redecls()) {
+ Kind = I->isThisDeclarationADefinition();
if (Kind == Definition)
- return 0;
+ return nullptr;
else if (Kind == TentativeDefinition)
- LastTentative = *I;
+ LastTentative = I;
}
return LastTentative;
}
VarDecl *VarDecl::getDefinition(ASTContext &C) {
VarDecl *First = getFirstDecl();
- for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
- I != E; ++I) {
- if ((*I)->isThisDeclarationADefinition(C) == Definition)
- return *I;
+ for (auto I : First->redecls()) {
+ if (I->isThisDeclarationADefinition(C) == Definition)
+ return I;
}
- return 0;
+ return nullptr;
}
VarDecl::DefinitionKind VarDecl::hasDefinition(ASTContext &C) const {
DefinitionKind Kind = DeclarationOnly;
const VarDecl *First = getFirstDecl();
- for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
- I != E; ++I) {
- Kind = std::max(Kind, (*I)->isThisDeclarationADefinition(C));
+ for (auto I : First->redecls()) {
+ Kind = std::max(Kind, I->isThisDeclarationADefinition(C));
if (Kind == Definition)
break;
}
@@ -1834,15 +1913,13 @@ VarDecl::DefinitionKind VarDecl::hasDefinition(ASTContext &C) const {
}
const Expr *VarDecl::getAnyInitializer(const VarDecl *&D) const {
- redecl_iterator I = redecls_begin(), E = redecls_end();
- while (I != E && !I->getInit())
- ++I;
-
- if (I != E) {
- D = *I;
- return I->getInit();
+ for (auto I : redecls()) {
+ if (auto Expr = I->getInit()) {
+ D = I;
+ return Expr;
+ }
}
- return 0;
+ return nullptr;
}
bool VarDecl::isOutOfLine() const {
@@ -1863,15 +1940,14 @@ bool VarDecl::isOutOfLine() const {
VarDecl *VarDecl::getOutOfLineDefinition() {
if (!isStaticDataMember())
- return 0;
-
- for (VarDecl::redecl_iterator RD = redecls_begin(), RDEnd = redecls_end();
- RD != RDEnd; ++RD) {
+ return nullptr;
+
+ for (auto RD : redecls()) {
if (RD->getLexicalDeclContext()->isFileContext())
- return *RD;
+ return RD;
}
-
- return 0;
+
+ return nullptr;
}
void VarDecl::setInit(Expr *I) {
@@ -1948,7 +2024,7 @@ APValue *VarDecl::evaluateValue(
// first time it is evaluated. FIXME: The notes won't always be emitted the
// first time we try evaluation, so might not be produced at all.
if (Eval->WasEvaluated)
- return Eval->Evaluated.isUninit() ? 0 : &Eval->Evaluated;
+ return Eval->Evaluated.isUninit() ? nullptr : &Eval->Evaluated;
const Expr *Init = cast<Expr>(Eval->Value);
assert(!Init->isValueDependent());
@@ -1957,7 +2033,7 @@ APValue *VarDecl::evaluateValue(
// FIXME: Produce a diagnostic for self-initialization.
Eval->CheckedICE = true;
Eval->IsICE = false;
- return 0;
+ return nullptr;
}
Eval->IsEvaluating = true;
@@ -1983,7 +2059,7 @@ APValue *VarDecl::evaluateValue(
Eval->IsICE = Result && Notes.empty();
}
- return Result ? &Eval->Evaluated : 0;
+ return Result ? &Eval->Evaluated : nullptr;
}
bool VarDecl::checkInitIsICE() const {
@@ -2025,8 +2101,8 @@ bool VarDecl::checkInitIsICE() const {
VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
return cast<VarDecl>(MSI->getInstantiatedFrom());
-
- return 0;
+
+ return nullptr;
}
TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const {
@@ -2066,7 +2142,7 @@ MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const {
// return getASTContext().getInstantiatedFromStaticDataMember(this);
return getASTContext().getTemplateOrSpecializationInfo(this)
.dyn_cast<MemberSpecializationInfo *>();
- return 0;
+ return nullptr;
}
void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
@@ -2108,8 +2184,8 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
StorageClass S, Expr *DefArg) {
- return new (C) ParmVarDecl(ParmVar, DC, StartLoc, IdLoc, Id, T, TInfo,
- S, DefArg);
+ return new (C, DC) ParmVarDecl(ParmVar, C, DC, StartLoc, IdLoc, Id, T, TInfo,
+ S, DefArg);
}
QualType ParmVarDecl::getOriginalType() const {
@@ -2121,9 +2197,9 @@ QualType ParmVarDecl::getOriginalType() const {
}
ParmVarDecl *ParmVarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ParmVarDecl));
- return new (Mem) ParmVarDecl(ParmVar, 0, SourceLocation(), SourceLocation(),
- 0, QualType(), 0, SC_None, 0);
+ return new (C, ID)
+ ParmVarDecl(ParmVar, C, nullptr, SourceLocation(), SourceLocation(),
+ nullptr, QualType(), nullptr, SC_None, nullptr);
}
SourceRange ParmVarDecl::getSourceRange() const {
@@ -2196,9 +2272,9 @@ bool FunctionDecl::isVariadic() const {
}
bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const {
- for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
+ for (auto I : redecls()) {
if (I->Body || I->IsLateTemplateParsed) {
- Definition = *I;
+ Definition = I;
return true;
}
}
@@ -2221,10 +2297,10 @@ bool FunctionDecl::hasTrivialBody() const
}
bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
- for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
+ for (auto I : redecls()) {
if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed ||
I->hasAttr<AliasAttr>()) {
- Definition = I->IsDeleted ? I->getCanonicalDecl() : *I;
+ Definition = I->IsDeleted ? I->getCanonicalDecl() : I;
return true;
}
}
@@ -2234,12 +2310,12 @@ bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
if (!hasBody(Definition))
- return 0;
+ return nullptr;
if (Definition->Body)
return Definition->Body.get(getASTContext().getExternalSource());
- return 0;
+ return nullptr;
}
void FunctionDecl::setBody(Stmt *B) {
@@ -2303,11 +2379,12 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const {
getDeclName().getCXXOverloadedOperator() == OO_Array_New ||
getDeclName().getCXXOverloadedOperator() == OO_Array_Delete);
- if (isa<CXXRecordDecl>(getDeclContext())) return false;
- assert(getDeclContext()->getRedeclContext()->isTranslationUnit());
+ if (!getDeclContext()->getRedeclContext()->isTranslationUnit())
+ return false;
const FunctionProtoType *proto = getType()->castAs<FunctionProtoType>();
- if (proto->getNumArgs() != 2 || proto->isVariadic()) return false;
+ if (proto->getNumParams() != 2 || proto->isVariadic())
+ return false;
ASTContext &Context =
cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext())
@@ -2315,13 +2392,7 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const {
// The result type and first argument type are constant across all
// these operators. The second argument must be exactly void*.
- return (proto->getArgType(1).getCanonicalType() == Context.VoidPtrTy);
-}
-
-static bool isNamespaceStd(const DeclContext *DC) {
- const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC->getRedeclContext());
- return ND && isNamed(ND, "std") &&
- ND->getParent()->getRedeclContext()->isTranslationUnit();
+ return (proto->getParamType(1).getCanonicalType() == Context.VoidPtrTy);
}
bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
@@ -2335,20 +2406,23 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
if (isa<CXXRecordDecl>(getDeclContext()))
return false;
- assert(getDeclContext()->getRedeclContext()->isTranslationUnit());
+
+ // This can only fail for an invalid 'operator new' declaration.
+ if (!getDeclContext()->getRedeclContext()->isTranslationUnit())
+ return false;
const FunctionProtoType *FPT = getType()->castAs<FunctionProtoType>();
- if (FPT->getNumArgs() > 2 || FPT->isVariadic())
+ if (FPT->getNumParams() == 0 || FPT->getNumParams() > 2 || FPT->isVariadic())
return false;
// If this is a single-parameter function, it must be a replaceable global
// allocation or deallocation function.
- if (FPT->getNumArgs() == 1)
+ if (FPT->getNumParams() == 1)
return true;
// Otherwise, we're looking for a second parameter whose type is
// 'const std::nothrow_t &', or, in C++1y, 'std::size_t'.
- QualType Ty = FPT->getArgType(1);
+ QualType Ty = FPT->getParamType(1);
ASTContext &Ctx = getASTContext();
if (Ctx.getLangOpts().SizedDeallocation &&
Ctx.hasSameType(Ty, Ctx.getSizeType()))
@@ -2358,30 +2432,31 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
Ty = Ty->getPointeeType();
if (Ty.getCVRQualifiers() != Qualifiers::Const)
return false;
- // FIXME: Recognise nothrow_t in an inline namespace inside std?
const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
- return RD && isNamed(RD, "nothrow_t") && isNamespaceStd(RD->getDeclContext());
+ return RD && isNamed(RD, "nothrow_t") && RD->isInStdNamespace();
}
FunctionDecl *
FunctionDecl::getCorrespondingUnsizedGlobalDeallocationFunction() const {
ASTContext &Ctx = getASTContext();
if (!Ctx.getLangOpts().SizedDeallocation)
- return 0;
+ return nullptr;
if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName)
- return 0;
+ return nullptr;
if (getDeclName().getCXXOverloadedOperator() != OO_Delete &&
getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
- return 0;
+ return nullptr;
if (isa<CXXRecordDecl>(getDeclContext()))
- return 0;
- assert(getDeclContext()->getRedeclContext()->isTranslationUnit());
+ return nullptr;
+
+ if (!getDeclContext()->getRedeclContext()->isTranslationUnit())
+ return nullptr;
if (getNumParams() != 2 || isVariadic() ||
- !Ctx.hasSameType(getType()->castAs<FunctionProtoType>()->getArgType(1),
+ !Ctx.hasSameType(getType()->castAs<FunctionProtoType>()->getParamType(1),
Ctx.getSizeType()))
- return 0;
+ return nullptr;
// This is a sized deallocation function. Find the corresponding unsized
// deallocation function.
@@ -2391,15 +2466,15 @@ FunctionDecl::getCorrespondingUnsizedGlobalDeallocationFunction() const {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*RI))
if (FD->getNumParams() == 1 && !FD->isVariadic())
return FD;
- return 0;
+ return nullptr;
}
LanguageLinkage FunctionDecl::getLanguageLinkage() const {
- return getLanguageLinkageTemplate(*this);
+ return getDeclLanguageLinkage(*this);
}
bool FunctionDecl::isExternC() const {
- return isExternCTemplate(*this);
+ return isDeclExternC(*this);
}
bool FunctionDecl::isInExternCContext() const {
@@ -2442,7 +2517,7 @@ FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) {
FunctionTemplateDecl *PrevFunTmpl
- = PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0;
+ = PrevDecl? PrevDecl->getDescribedFunctionTemplate() : nullptr;
assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch");
FunTmpl->setPreviousDecl(PrevFunTmpl);
}
@@ -2488,7 +2563,7 @@ unsigned FunctionDecl::getBuiltinID() const {
// If the function is marked "overloadable", it has a different mangled name
// and is not the C library function.
- if (getAttr<OverloadableAttr>())
+ if (hasAttr<OverloadableAttr>())
return 0;
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
@@ -2510,16 +2585,13 @@ unsigned FunctionDecl::getBuiltinID() const {
/// based on its FunctionType. This is the length of the ParamInfo array
/// after it has been created.
unsigned FunctionDecl::getNumParams() const {
- const FunctionType *FT = getType()->castAs<FunctionType>();
- if (isa<FunctionNoProtoType>(FT))
- return 0;
- return cast<FunctionProtoType>(FT)->getNumArgs();
-
+ const FunctionProtoType *FPT = getType()->getAs<FunctionProtoType>();
+ return FPT ? FPT->getNumParams() : 0;
}
void FunctionDecl::setParams(ASTContext &C,
ArrayRef<ParmVarDecl *> NewParamInfo) {
- assert(ParamInfo == 0 && "Already has param info!");
+ assert(!ParamInfo && "Already has param info!");
assert(NewParamInfo.size() == getNumParams() && "Parameter count mismatch!");
// Zero params -> null pointer.
@@ -2536,44 +2608,67 @@ void FunctionDecl::setDeclsInPrototypeScope(ArrayRef<NamedDecl *> NewDecls) {
NamedDecl **A = new (getASTContext()) NamedDecl*[NewDecls.size()];
std::copy(NewDecls.begin(), NewDecls.end(), A);
DeclsInPrototypeScope = ArrayRef<NamedDecl *>(A, NewDecls.size());
+ // Move declarations introduced in prototype to the function context.
+ for (auto I : NewDecls) {
+ DeclContext *DC = I->getDeclContext();
+ // Forward-declared reference to an enumeration is not added to
+ // declaration scope, so skip declaration that is absent from its
+ // declaration contexts.
+ if (DC->containsDecl(I)) {
+ DC->removeDecl(I);
+ I->setDeclContext(this);
+ addDecl(I);
+ }
+ }
}
}
/// getMinRequiredArguments - Returns the minimum number of arguments
/// needed to call this function. This may be fewer than the number of
/// function parameters, if some of the parameters have default
-/// arguments (in C++) or the last parameter is a parameter pack.
+/// arguments (in C++) or are parameter packs (C++11).
unsigned FunctionDecl::getMinRequiredArguments() const {
if (!getASTContext().getLangOpts().CPlusPlus)
return getNumParams();
-
- unsigned NumRequiredArgs = getNumParams();
-
- // If the last parameter is a parameter pack, we don't need an argument for
- // it.
- if (NumRequiredArgs > 0 &&
- getParamDecl(NumRequiredArgs - 1)->isParameterPack())
- --NumRequiredArgs;
-
- // If this parameter has a default argument, we don't need an argument for
- // it.
- while (NumRequiredArgs > 0 &&
- getParamDecl(NumRequiredArgs-1)->hasDefaultArg())
- --NumRequiredArgs;
-
- // We might have parameter packs before the end. These can't be deduced,
- // but they can still handle multiple arguments.
- unsigned ArgIdx = NumRequiredArgs;
- while (ArgIdx > 0) {
- if (getParamDecl(ArgIdx - 1)->isParameterPack())
- NumRequiredArgs = ArgIdx;
-
- --ArgIdx;
- }
-
+
+ unsigned NumRequiredArgs = 0;
+ for (auto *Param : params())
+ if (!Param->isParameterPack() && !Param->hasDefaultArg())
+ ++NumRequiredArgs;
return NumRequiredArgs;
}
+/// \brief The combination of the extern and inline keywords under MSVC forces
+/// the function to be required.
+///
+/// Note: This function assumes that we will only get called when isInlined()
+/// would return true for this FunctionDecl.
+bool FunctionDecl::isMSExternInline() const {
+ assert(isInlined() && "expected to get called on an inlined function!");
+
+ const ASTContext &Context = getASTContext();
+ if (!Context.getLangOpts().MSVCCompat && !hasAttr<DLLExportAttr>())
+ return false;
+
+ for (const FunctionDecl *FD = this; FD; FD = FD->getPreviousDecl())
+ if (FD->getStorageClass() == SC_Extern)
+ return true;
+
+ return false;
+}
+
+static bool redeclForcesDefMSVC(const FunctionDecl *Redecl) {
+ if (Redecl->getStorageClass() != SC_Extern)
+ return false;
+
+ for (const FunctionDecl *FD = Redecl->getPreviousDecl(); FD;
+ FD = FD->getPreviousDecl())
+ if (FD->getStorageClass() == SC_Extern)
+ return false;
+
+ return true;
+}
+
static bool RedeclForcesDefC99(const FunctionDecl *Redecl) {
// Only consider file-scope declarations in this test.
if (!Redecl->getLexicalDeclContext()->isTranslationUnit())
@@ -2593,7 +2688,7 @@ static bool RedeclForcesDefC99(const FunctionDecl *Redecl) {
/// \brief For a function declaration in C or C++, determine whether this
/// declaration causes the definition to be externally visible.
///
-/// Specifically, this determines if adding the current declaration to the set
+/// For instance, this determines if adding the current declaration to the set
/// of redeclarations of the given functions causes
/// isInlineDefinitionExternallyVisible to change from false to true.
bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
@@ -2602,6 +2697,13 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
ASTContext &Context = getASTContext();
+ if (Context.getLangOpts().MSVCCompat) {
+ const FunctionDecl *Definition;
+ if (hasBody(Definition) && Definition->isInlined() &&
+ redeclForcesDefMSVC(this))
+ return true;
+ }
+
if (Context.getLangOpts().GNUInline || hasAttr<GNUInlineAttr>()) {
// With GNU inlining, a declaration with 'inline' but not 'extern', forces
// an externally visible definition.
@@ -2649,6 +2751,26 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
return FoundBody;
}
+SourceRange FunctionDecl::getReturnTypeSourceRange() const {
+ const TypeSourceInfo *TSI = getTypeSourceInfo();
+ if (!TSI)
+ return SourceRange();
+ FunctionTypeLoc FTL =
+ TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>();
+ if (!FTL)
+ return SourceRange();
+
+ // Skip self-referential return types.
+ const SourceManager &SM = getASTContext().getSourceManager();
+ SourceRange RTRange = FTL.getReturnLoc().getSourceRange();
+ SourceLocation Boundary = getNameInfo().getLocStart();
+ if (RTRange.isInvalid() || Boundary.isInvalid() ||
+ !SM.isBeforeInTranslationUnit(RTRange.getEnd(), Boundary))
+ return SourceRange();
+
+ return RTRange;
+}
+
/// \brief For an inline function definition in C, or for a gnu_inline function
/// in C++, determine whether the definition will be externally visible.
///
@@ -2683,9 +2805,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
// If any declaration is 'inline' but not 'extern', then this definition
// is externally visible.
- for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end();
- Redecl != RedeclEnd;
- ++Redecl) {
+ for (auto Redecl : redecls()) {
if (Redecl->isInlineSpecified() &&
Redecl->getStorageClass() != SC_Extern)
return true;
@@ -2702,10 +2822,8 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
// [...] If all of the file scope declarations for a function in a
// translation unit include the inline function specifier without extern,
// then the definition in that translation unit is an inline definition.
- for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end();
- Redecl != RedeclEnd;
- ++Redecl) {
- if (RedeclForcesDefC99(*Redecl))
+ for (auto Redecl : redecls()) {
+ if (RedeclForcesDefC99(Redecl))
return true;
}
@@ -2731,7 +2849,7 @@ const IdentifierInfo *FunctionDecl::getLiteralIdentifier() const {
if (getDeclName().getNameKind() == DeclarationName::CXXLiteralOperatorName)
return getDeclName().getCXXLiteralIdentifier();
else
- return 0;
+ return nullptr;
}
FunctionDecl::TemplatedKind FunctionDecl::getTemplatedKind() const {
@@ -2753,8 +2871,8 @@ FunctionDecl::TemplatedKind FunctionDecl::getTemplatedKind() const {
FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const {
if (MemberSpecializationInfo *Info = getMemberSpecializationInfo())
return cast<FunctionDecl>(Info->getInstantiatedFrom());
-
- return 0;
+
+ return nullptr;
}
void
@@ -2784,7 +2902,7 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
// It is possible to instantiate TSK_ExplicitSpecialization kind
// if the FunctionDecl has a class scope specialization pattern.
case TSK_ExplicitSpecialization:
- return getClassScopeSpecializationPattern() != 0;
+ return getClassScopeSpecializationPattern() != nullptr;
case TSK_ExplicitInstantiationDeclaration:
// Handled below.
@@ -2824,14 +2942,34 @@ FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
// Handle class scope explicit specialization special case.
if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
return getClassScopeSpecializationPattern();
-
+
+ // If this is a generic lambda call operator specialization, its
+ // instantiation pattern is always its primary template's pattern
+ // even if its primary template was instantiated from another
+ // member template (which happens with nested generic lambdas).
+ // Since a lambda's call operator's body is transformed eagerly,
+ // we don't have to go hunting for a prototype definition template
+ // (i.e. instantiated-from-member-template) to use as an instantiation
+ // pattern.
+
+ if (isGenericLambdaCallOperatorSpecialization(
+ dyn_cast<CXXMethodDecl>(this))) {
+ assert(getPrimaryTemplate() && "A generic lambda specialization must be "
+ "generated from a primary call operator "
+ "template");
+ assert(getPrimaryTemplate()->getTemplatedDecl()->getBody() &&
+ "A generic lambda call operator template must always have a body - "
+ "even if instantiated from a prototype (i.e. as written) member "
+ "template");
+ return getPrimaryTemplate()->getTemplatedDecl();
+ }
+
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
while (Primary->getInstantiatedFromMemberTemplate()) {
// If we have hit a point where the user provided a specialization of
// this template, we're done looking.
if (Primary->isMemberSpecialization())
break;
-
Primary = Primary->getInstantiatedFromMemberTemplate();
}
@@ -2847,7 +2985,7 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
.dyn_cast<FunctionTemplateSpecializationInfo*>()) {
return Info->Template.getPointer();
}
- return 0;
+ return nullptr;
}
FunctionDecl *FunctionDecl::getClassScopeSpecializationPattern() const {
@@ -2861,7 +2999,7 @@ FunctionDecl::getTemplateSpecializationArgs() const {
.dyn_cast<FunctionTemplateSpecializationInfo*>()) {
return Info->TemplateArguments;
}
- return 0;
+ return nullptr;
}
const ASTTemplateArgumentListInfo *
@@ -2871,7 +3009,7 @@ FunctionDecl::getTemplateSpecializationArgsAsWritten() const {
.dyn_cast<FunctionTemplateSpecializationInfo*>()) {
return Info->TemplateArgumentsAsWritten;
}
- return 0;
+ return nullptr;
}
void
@@ -3101,14 +3239,14 @@ FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC,
IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
InClassInitStyle InitStyle) {
- return new (C) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo,
- BW, Mutable, InitStyle);
+ return new (C, DC) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo,
+ BW, Mutable, InitStyle);
}
FieldDecl *FieldDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FieldDecl));
- return new (Mem) FieldDecl(Field, 0, SourceLocation(), SourceLocation(),
- 0, QualType(), 0, 0, false, ICIS_NoInit);
+ return new (C, ID) FieldDecl(Field, nullptr, SourceLocation(),
+ SourceLocation(), nullptr, QualType(), nullptr,
+ nullptr, false, ICIS_NoInit);
}
bool FieldDecl::isAnonymousStructOrUnion() const {
@@ -3180,8 +3318,10 @@ TagDecl *TagDecl::getCanonicalDecl() { return getFirstDecl(); }
void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) {
NamedDeclOrQualifier = TDD;
- if (TypeForDecl)
- assert(TypeForDecl->isLinkageValid());
+ if (const Type *T = getTypeForDecl()) {
+ (void)T;
+ assert(T->isLinkageValid());
+ }
assert(isLinkageValid());
}
@@ -3189,10 +3329,10 @@ void TagDecl::startDefinition() {
IsBeingDefined = true;
if (CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(this)) {
- struct CXXRecordDecl::DefinitionData *Data =
+ struct CXXRecordDecl::DefinitionData *Data =
new (getASTContext()) struct CXXRecordDecl::DefinitionData(D);
- for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I)
- cast<CXXRecordDecl>(*I)->DefinitionData = Data;
+ for (auto I : redecls())
+ cast<CXXRecordDecl>(I)->DefinitionData = Data;
}
}
@@ -3224,12 +3364,11 @@ TagDecl *TagDecl::getDefinition() const {
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(this))
return CXXRD->getDefinition();
- for (redecl_iterator R = redecls_begin(), REnd = redecls_end();
- R != REnd; ++R)
+ for (auto R : redecls())
if (R->isCompleteDefinition())
- return *R;
+ return R;
- return 0;
+ return nullptr;
}
void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
@@ -3244,7 +3383,7 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
if (hasExtInfo()) {
if (getExtInfo()->NumTemplParamLists == 0) {
getASTContext().Deallocate(getExtInfo());
- NamedDeclOrQualifier = (TypedefNameDecl*) 0;
+ NamedDeclOrQualifier = (TypedefNameDecl*)nullptr;
}
else
getExtInfo()->QualifierLoc = QualifierLoc;
@@ -3275,21 +3414,28 @@ EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC,
IdentifierInfo *Id,
EnumDecl *PrevDecl, bool IsScoped,
bool IsScopedUsingClassTag, bool IsFixed) {
- EnumDecl *Enum = new (C) EnumDecl(DC, StartLoc, IdLoc, Id, PrevDecl,
- IsScoped, IsScopedUsingClassTag, IsFixed);
+ EnumDecl *Enum = new (C, DC) EnumDecl(C, DC, StartLoc, IdLoc, Id, PrevDecl,
+ IsScoped, IsScopedUsingClassTag,
+ IsFixed);
Enum->MayHaveOutOfDateDef = C.getLangOpts().Modules;
C.getTypeDeclType(Enum, PrevDecl);
return Enum;
}
EnumDecl *EnumDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(EnumDecl));
- EnumDecl *Enum = new (Mem) EnumDecl(0, SourceLocation(), SourceLocation(),
- 0, 0, false, false, false);
+ EnumDecl *Enum =
+ new (C, ID) EnumDecl(C, nullptr, SourceLocation(), SourceLocation(),
+ nullptr, nullptr, false, false, false);
Enum->MayHaveOutOfDateDef = C.getLangOpts().Modules;
return Enum;
}
+SourceRange EnumDecl::getIntegerTypeRange() const {
+ if (const TypeSourceInfo *TI = getIntegerTypeSourceInfo())
+ return TI->getTypeLoc().getSourceRange();
+ return SourceRange();
+}
+
void EnumDecl::completeDefinition(QualType NewType,
QualType NewPromotionType,
unsigned NumPositiveBits,
@@ -3325,7 +3471,7 @@ EnumDecl *EnumDecl::getInstantiatedFromMemberEnum() const {
if (SpecializationInfo)
return cast<EnumDecl>(SpecializationInfo->getInstantiatedFrom());
- return 0;
+ return nullptr;
}
void EnumDecl::setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED,
@@ -3338,10 +3484,11 @@ void EnumDecl::setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED,
// RecordDecl Implementation
//===----------------------------------------------------------------------===//
-RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC,
- SourceLocation StartLoc, SourceLocation IdLoc,
- IdentifierInfo *Id, RecordDecl *PrevDecl)
- : TagDecl(DK, TK, DC, IdLoc, Id, PrevDecl, StartLoc) {
+RecordDecl::RecordDecl(Kind DK, TagKind TK, const ASTContext &C,
+ DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ RecordDecl *PrevDecl)
+ : TagDecl(DK, TK, C, DC, IdLoc, Id, PrevDecl, StartLoc) {
HasFlexibleArrayMember = false;
AnonymousStructOrUnion = false;
HasObjectMember = false;
@@ -3353,8 +3500,8 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC,
RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, RecordDecl* PrevDecl) {
- RecordDecl* R = new (C) RecordDecl(Record, TK, DC, StartLoc, IdLoc, Id,
- PrevDecl);
+ RecordDecl *R = new (C, DC) RecordDecl(Record, TK, C, DC,
+ StartLoc, IdLoc, Id, PrevDecl);
R->MayHaveOutOfDateDef = C.getLangOpts().Modules;
C.getTypeDeclType(R, PrevDecl);
@@ -3362,9 +3509,9 @@ RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC,
}
RecordDecl *RecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(RecordDecl));
- RecordDecl *R = new (Mem) RecordDecl(Record, TTK_Struct, 0, SourceLocation(),
- SourceLocation(), 0, 0);
+ RecordDecl *R =
+ new (C, ID) RecordDecl(Record, TTK_Struct, C, nullptr, SourceLocation(),
+ SourceLocation(), nullptr, nullptr);
R->MayHaveOutOfDateDef = C.getLangOpts().Modules;
return R;
}
@@ -3427,7 +3574,7 @@ void RecordDecl::LoadFieldsFromExternalStorage() const {
if (Decls.empty())
return;
- llvm::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls,
+ std::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls,
/*FieldsAlreadyLoaded=*/false);
}
@@ -3436,7 +3583,7 @@ void RecordDecl::LoadFieldsFromExternalStorage() const {
//===----------------------------------------------------------------------===//
void BlockDecl::setParams(ArrayRef<ParmVarDecl *> NewParamInfo) {
- assert(ParamInfo == 0 && "Already has param info!");
+ assert(!ParamInfo && "Already has param info!");
// Zero params -> null pointer.
if (!NewParamInfo.empty()) {
@@ -3454,7 +3601,7 @@ void BlockDecl::setCaptures(ASTContext &Context,
if (begin == end) {
NumCaptures = 0;
- Captures = 0;
+ Captures = nullptr;
return;
}
@@ -3469,10 +3616,9 @@ void BlockDecl::setCaptures(ASTContext &Context,
}
bool BlockDecl::capturesVariable(const VarDecl *variable) const {
- for (capture_const_iterator
- i = capture_begin(), e = capture_end(); i != e; ++i)
+ for (const auto &I : captures())
// Only auto vars can be captured, so no redeclaration worries.
- if (i->getVariable() == variable)
+ if (I.getVariable() == variable)
return true;
return false;
@@ -3489,33 +3635,33 @@ SourceRange BlockDecl::getSourceRange() const {
void TranslationUnitDecl::anchor() { }
TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) {
- return new (C) TranslationUnitDecl(C);
+ return new (C, (DeclContext *)nullptr) TranslationUnitDecl(C);
}
void LabelDecl::anchor() { }
LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation IdentL, IdentifierInfo *II) {
- return new (C) LabelDecl(DC, IdentL, II, 0, IdentL);
+ return new (C, DC) LabelDecl(DC, IdentL, II, nullptr, IdentL);
}
LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation IdentL, IdentifierInfo *II,
SourceLocation GnuLabelL) {
assert(GnuLabelL != IdentL && "Use this only for GNU local labels");
- return new (C) LabelDecl(DC, IdentL, II, 0, GnuLabelL);
+ return new (C, DC) LabelDecl(DC, IdentL, II, nullptr, GnuLabelL);
}
LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(LabelDecl));
- return new (Mem) LabelDecl(0, SourceLocation(), 0, 0, SourceLocation());
+ return new (C, ID) LabelDecl(nullptr, SourceLocation(), nullptr, nullptr,
+ SourceLocation());
}
void ValueDecl::anchor() { }
bool ValueDecl::isWeak() const {
- for (attr_iterator I = attr_begin(), E = attr_end(); I != E; ++I)
- if (isa<WeakAttr>(*I) || isa<WeakRefAttr>(*I))
+ for (const auto *I : attrs())
+ if (isa<WeakAttr>(I) || isa<WeakRefAttr>(I))
return true;
return isWeakImported();
@@ -3527,13 +3673,13 @@ ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation IdLoc,
IdentifierInfo *Id,
QualType Type) {
- return new (C) ImplicitParamDecl(DC, IdLoc, Id, Type);
+ return new (C, DC) ImplicitParamDecl(C, DC, IdLoc, Id, Type);
}
-ImplicitParamDecl *ImplicitParamDecl::CreateDeserialized(ASTContext &C,
+ImplicitParamDecl *ImplicitParamDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ImplicitParamDecl));
- return new (Mem) ImplicitParamDecl(0, SourceLocation(), 0, QualType());
+ return new (C, ID) ImplicitParamDecl(C, nullptr, SourceLocation(), nullptr,
+ QualType());
}
FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
@@ -3541,66 +3687,53 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
StorageClass SC,
- bool isInlineSpecified,
+ bool isInlineSpecified,
bool hasWrittenPrototype,
bool isConstexprSpecified) {
- FunctionDecl *New = new (C) FunctionDecl(Function, DC, StartLoc, NameInfo,
- T, TInfo, SC,
- isInlineSpecified,
- isConstexprSpecified);
+ FunctionDecl *New =
+ new (C, DC) FunctionDecl(Function, C, DC, StartLoc, NameInfo, T, TInfo,
+ SC, isInlineSpecified, isConstexprSpecified);
New->HasWrittenPrototype = hasWrittenPrototype;
return New;
}
FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FunctionDecl));
- return new (Mem) FunctionDecl(Function, 0, SourceLocation(),
- DeclarationNameInfo(), QualType(), 0,
- SC_None, false, false);
+ return new (C, ID) FunctionDecl(Function, C, nullptr, SourceLocation(),
+ DeclarationNameInfo(), QualType(), nullptr,
+ SC_None, false, false);
}
BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
- return new (C) BlockDecl(DC, L);
+ return new (C, DC) BlockDecl(DC, L);
}
BlockDecl *BlockDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(BlockDecl));
- return new (Mem) BlockDecl(0, SourceLocation());
-}
-
-MSPropertyDecl *MSPropertyDecl::CreateDeserialized(ASTContext &C,
- unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(MSPropertyDecl));
- return new (Mem) MSPropertyDecl(0, SourceLocation(), DeclarationName(),
- QualType(), 0, SourceLocation(),
- 0, 0);
+ return new (C, ID) BlockDecl(nullptr, SourceLocation());
}
CapturedDecl *CapturedDecl::Create(ASTContext &C, DeclContext *DC,
unsigned NumParams) {
- unsigned Size = sizeof(CapturedDecl) + NumParams * sizeof(ImplicitParamDecl*);
- return new (C.Allocate(Size)) CapturedDecl(DC, NumParams);
+ return new (C, DC, NumParams * sizeof(ImplicitParamDecl *))
+ CapturedDecl(DC, NumParams);
}
CapturedDecl *CapturedDecl::CreateDeserialized(ASTContext &C, unsigned ID,
- unsigned NumParams) {
- unsigned Size = sizeof(CapturedDecl) + NumParams * sizeof(ImplicitParamDecl*);
- void *Mem = AllocateDeserializedDecl(C, ID, Size);
- return new (Mem) CapturedDecl(0, NumParams);
+ unsigned NumParams) {
+ return new (C, ID, NumParams * sizeof(ImplicitParamDecl *))
+ CapturedDecl(nullptr, NumParams);
}
EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
SourceLocation L,
IdentifierInfo *Id, QualType T,
Expr *E, const llvm::APSInt &V) {
- return new (C) EnumConstantDecl(CD, L, Id, T, E, V);
+ return new (C, CD) EnumConstantDecl(CD, L, Id, T, E, V);
}
EnumConstantDecl *
EnumConstantDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(EnumConstantDecl));
- return new (Mem) EnumConstantDecl(0, SourceLocation(), 0, QualType(), 0,
- llvm::APSInt());
+ return new (C, ID) EnumConstantDecl(nullptr, SourceLocation(), nullptr,
+ QualType(), nullptr, llvm::APSInt());
}
void IndirectFieldDecl::anchor() { }
@@ -3609,14 +3742,14 @@ IndirectFieldDecl *
IndirectFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, QualType T, NamedDecl **CH,
unsigned CHS) {
- return new (C) IndirectFieldDecl(DC, L, Id, T, CH, CHS);
+ return new (C, DC) IndirectFieldDecl(DC, L, Id, T, CH, CHS);
}
IndirectFieldDecl *IndirectFieldDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(IndirectFieldDecl));
- return new (Mem) IndirectFieldDecl(0, SourceLocation(), DeclarationName(),
- QualType(), 0, 0);
+ return new (C, ID) IndirectFieldDecl(nullptr, SourceLocation(),
+ DeclarationName(), QualType(), nullptr,
+ 0);
}
SourceRange EnumConstantDecl::getSourceRange() const {
@@ -3631,26 +3764,26 @@ void TypeDecl::anchor() { }
TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, TypeSourceInfo *TInfo) {
- return new (C) TypedefDecl(DC, StartLoc, IdLoc, Id, TInfo);
+ return new (C, DC) TypedefDecl(C, DC, StartLoc, IdLoc, Id, TInfo);
}
void TypedefNameDecl::anchor() { }
TypedefDecl *TypedefDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TypedefDecl));
- return new (Mem) TypedefDecl(0, SourceLocation(), SourceLocation(), 0, 0);
+ return new (C, ID) TypedefDecl(C, nullptr, SourceLocation(), SourceLocation(),
+ nullptr, nullptr);
}
TypeAliasDecl *TypeAliasDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
TypeSourceInfo *TInfo) {
- return new (C) TypeAliasDecl(DC, StartLoc, IdLoc, Id, TInfo);
+ return new (C, DC) TypeAliasDecl(C, DC, StartLoc, IdLoc, Id, TInfo);
}
TypeAliasDecl *TypeAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TypeAliasDecl));
- return new (Mem) TypeAliasDecl(0, SourceLocation(), SourceLocation(), 0, 0);
+ return new (C, ID) TypeAliasDecl(C, nullptr, SourceLocation(),
+ SourceLocation(), nullptr, nullptr);
}
SourceRange TypedefDecl::getSourceRange() const {
@@ -3675,24 +3808,23 @@ FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC,
StringLiteral *Str,
SourceLocation AsmLoc,
SourceLocation RParenLoc) {
- return new (C) FileScopeAsmDecl(DC, Str, AsmLoc, RParenLoc);
+ return new (C, DC) FileScopeAsmDecl(DC, Str, AsmLoc, RParenLoc);
}
-FileScopeAsmDecl *FileScopeAsmDecl::CreateDeserialized(ASTContext &C,
+FileScopeAsmDecl *FileScopeAsmDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FileScopeAsmDecl));
- return new (Mem) FileScopeAsmDecl(0, 0, SourceLocation(), SourceLocation());
+ return new (C, ID) FileScopeAsmDecl(nullptr, nullptr, SourceLocation(),
+ SourceLocation());
}
void EmptyDecl::anchor() {}
EmptyDecl *EmptyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
- return new (C) EmptyDecl(DC, L);
+ return new (C, DC) EmptyDecl(DC, L);
}
EmptyDecl *EmptyDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(EmptyDecl));
- return new (Mem) EmptyDecl(0, SourceLocation());
+ return new (C, ID) EmptyDecl(nullptr, SourceLocation());
}
//===----------------------------------------------------------------------===//
@@ -3730,30 +3862,28 @@ ImportDecl::ImportDecl(DeclContext *DC, SourceLocation StartLoc,
*reinterpret_cast<SourceLocation *>(this + 1) = EndLoc;
}
-ImportDecl *ImportDecl::Create(ASTContext &C, DeclContext *DC,
+ImportDecl *ImportDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, Module *Imported,
ArrayRef<SourceLocation> IdentifierLocs) {
- void *Mem = C.Allocate(sizeof(ImportDecl) +
- IdentifierLocs.size() * sizeof(SourceLocation));
- return new (Mem) ImportDecl(DC, StartLoc, Imported, IdentifierLocs);
+ return new (C, DC, IdentifierLocs.size() * sizeof(SourceLocation))
+ ImportDecl(DC, StartLoc, Imported, IdentifierLocs);
}
-ImportDecl *ImportDecl::CreateImplicit(ASTContext &C, DeclContext *DC,
+ImportDecl *ImportDecl::CreateImplicit(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
- Module *Imported,
+ Module *Imported,
SourceLocation EndLoc) {
- void *Mem = C.Allocate(sizeof(ImportDecl) + sizeof(SourceLocation));
- ImportDecl *Import = new (Mem) ImportDecl(DC, StartLoc, Imported, EndLoc);
+ ImportDecl *Import =
+ new (C, DC, sizeof(SourceLocation)) ImportDecl(DC, StartLoc,
+ Imported, EndLoc);
Import->setImplicit();
return Import;
}
ImportDecl *ImportDecl::CreateDeserialized(ASTContext &C, unsigned ID,
unsigned NumLocations) {
- void *Mem = AllocateDeserializedDecl(C, ID,
- (sizeof(ImportDecl) +
- NumLocations * sizeof(SourceLocation)));
- return new (Mem) ImportDecl(EmptyShell());
+ return new (C, ID, NumLocations * sizeof(SourceLocation))
+ ImportDecl(EmptyShell());
}
ArrayRef<SourceLocation> ImportDecl::getIdentifierLocs() const {
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 121c5a671a29..2b1506d191d1 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -45,25 +45,30 @@ void Decl::updateOutOfDate(IdentifierInfo &II) const {
getASTContext().getExternalSource()->updateOutOfDateIdentifier(II);
}
-void *Decl::AllocateDeserializedDecl(const ASTContext &Context,
- unsigned ID,
- unsigned Size) {
+void *Decl::operator new(std::size_t Size, const ASTContext &Context,
+ unsigned ID, std::size_t Extra) {
// Allocate an extra 8 bytes worth of storage, which ensures that the
// resulting pointer will still be 8-byte aligned.
- void *Start = Context.Allocate(Size + 8);
+ void *Start = Context.Allocate(Size + Extra + 8);
void *Result = (char*)Start + 8;
-
+
unsigned *PrefixPtr = (unsigned *)Result - 2;
-
+
// Zero out the first 4 bytes; this is used to store the owning module ID.
PrefixPtr[0] = 0;
-
+
// Store the global declaration ID in the second 4 bytes.
PrefixPtr[1] = ID;
-
+
return Result;
}
+void *Decl::operator new(std::size_t Size, const ASTContext &Ctx,
+ DeclContext *Parent, std::size_t Extra) {
+ assert(!Parent || &Parent->getParentASTContext() == &Ctx);
+ return ::operator new(Size + Extra, Ctx);
+}
+
Module *Decl::getOwningModuleSlow() const {
assert(isFromASTFile() && "Not from AST file?");
return getASTContext().getExternalSource()->getModule(getOwningModuleID());
@@ -80,6 +85,7 @@ const char *Decl::getDeclKindName() const {
void Decl::setInvalidDecl(bool Invalid) {
InvalidDecl = Invalid;
+ assert(!isa<TagDecl>(this) || !cast<TagDecl>(this)->isCompleteDefinition());
if (Invalid && !isa<ParmVarDecl>(this)) {
// Defensive maneuver for ill-formed code: we're likely not to make it to
// a point where we set the access specifier, so default it to "public"
@@ -153,11 +159,12 @@ bool Decl::isParameterPack() const {
return isTemplateParameterPack();
}
-bool Decl::isFunctionOrFunctionTemplate() const {
- if (const UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(this))
- return UD->getTargetDecl()->isFunctionOrFunctionTemplate();
-
- return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this);
+FunctionDecl *Decl::getAsFunction() {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(this))
+ return FD;
+ if (const FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(this))
+ return FTD->getTemplatedDecl();
+ return nullptr;
}
bool Decl::isTemplateDecl() const {
@@ -171,7 +178,7 @@ const DeclContext *Decl::getParentFunctionOrMethod() const {
if (DC->isFunctionOrMethod())
return DC;
- return 0;
+ return nullptr;
}
@@ -244,6 +251,10 @@ bool Decl::isInAnonymousNamespace() const {
return false;
}
+bool Decl::isInStdNamespace() const {
+ return getDeclContext()->isStdNamespace();
+}
+
TranslationUnitDecl *Decl::getTranslationUnitDecl() {
if (TranslationUnitDecl *TUD = dyn_cast<TranslationUnitDecl>(this))
return TUD;
@@ -306,7 +317,7 @@ bool Decl::isReferenced() const {
return true;
// Check redeclarations.
- for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I)
+ for (auto I : redecls())
if (I->Referenced)
return true;
@@ -401,8 +412,8 @@ AvailabilityResult Decl::getAvailability(std::string *Message) const {
AvailabilityResult Result = AR_Available;
std::string ResultMessage;
- for (attr_iterator A = attr_begin(), AEnd = attr_end(); A != AEnd; ++A) {
- if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(*A)) {
+ for (const auto *A : attrs()) {
+ if (const auto *Deprecated = dyn_cast<DeprecatedAttr>(A)) {
if (Result >= AR_Deprecated)
continue;
@@ -413,13 +424,13 @@ AvailabilityResult Decl::getAvailability(std::string *Message) const {
continue;
}
- if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(*A)) {
+ if (const auto *Unavailable = dyn_cast<UnavailableAttr>(A)) {
if (Message)
*Message = Unavailable->getMessage();
return AR_Unavailable;
}
- if (AvailabilityAttr *Availability = dyn_cast<AvailabilityAttr>(*A)) {
+ if (const auto *Availability = dyn_cast<AvailabilityAttr>(A)) {
AvailabilityResult AR = CheckAvailability(getASTContext(), Availability,
Message);
@@ -475,13 +486,13 @@ bool Decl::isWeakImported() const {
if (!canBeWeakImported(IsDefinition))
return false;
- for (attr_iterator A = attr_begin(), AEnd = attr_end(); A != AEnd; ++A) {
- if (isa<WeakImportAttr>(*A))
+ for (const auto *A : attrs()) {
+ if (isa<WeakImportAttr>(A))
return true;
- if (AvailabilityAttr *Availability = dyn_cast<AvailabilityAttr>(*A)) {
- if (CheckAvailability(getASTContext(), Availability, 0)
- == AR_NotYetIntroduced)
+ if (const auto *Availability = dyn_cast<AvailabilityAttr>(A)) {
+ if (CheckAvailability(getASTContext(), Availability,
+ nullptr) == AR_NotYetIntroduced)
return true;
}
}
@@ -662,7 +673,7 @@ SourceLocation Decl::getBodyRBrace() const {
return SourceLocation();
}
-void Decl::CheckAccessDeclContext() const {
+bool Decl::AccessDeclContextSanity() const {
#ifndef NDEBUG
// Suppress this check if any of the following hold:
// 1. this is the translation unit (and thus has no parent)
@@ -684,16 +695,35 @@ void Decl::CheckAccessDeclContext() const {
// AS_none as access specifier.
isa<CXXRecordDecl>(this) ||
isa<ClassScopeFunctionSpecializationDecl>(this))
- return;
+ return true;
assert(Access != AS_none &&
"Access specifier is AS_none inside a record decl");
#endif
+ return true;
}
static Decl::Kind getKind(const Decl *D) { return D->getKind(); }
static Decl::Kind getKind(const DeclContext *DC) { return DC->getDeclKind(); }
+const FunctionType *Decl::getFunctionType(bool BlocksToo) const {
+ QualType Ty;
+ if (const ValueDecl *D = dyn_cast<ValueDecl>(this))
+ Ty = D->getType();
+ else if (const TypedefNameDecl *D = dyn_cast<TypedefNameDecl>(this))
+ Ty = D->getUnderlyingType();
+ else
+ return nullptr;
+
+ if (Ty->isFunctionPointerType())
+ Ty = Ty->getAs<PointerType>()->getPointeeType();
+ else if (BlocksToo && Ty->isBlockPointerType())
+ Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
+
+ return Ty->getAs<FunctionType>();
+}
+
+
/// Starting at a given context (a Decl or DeclContext), look for a
/// code context that is not a closure (a lambda, block, etc.).
template <class T> static Decl *getNonClosureContext(T *D) {
@@ -712,7 +742,7 @@ template <class T> static Decl *getNonClosureContext(T *D) {
} else if (CapturedDecl *CD = dyn_cast<CapturedDecl>(D)) {
return getNonClosureContext(CD->getParent());
} else {
- return 0;
+ return nullptr;
}
}
@@ -769,6 +799,22 @@ bool DeclContext::isInlineNamespace() const {
cast<NamespaceDecl>(this)->isInline();
}
+bool DeclContext::isStdNamespace() const {
+ if (!isNamespace())
+ return false;
+
+ const NamespaceDecl *ND = cast<NamespaceDecl>(this);
+ if (ND->isInline()) {
+ return ND->getParent()->isStdNamespace();
+ }
+
+ if (!getParent()->getRedeclContext()->isTranslationUnit())
+ return false;
+
+ const IdentifierInfo *II = ND->getIdentifier();
+ return II && II->isStr("std");
+}
+
bool DeclContext::isDependentContext() const {
if (isFileContext())
return false;
@@ -811,7 +857,7 @@ static bool isLinkageSpecContext(const DeclContext *DC,
while (DC->getDeclKind() != Decl::TranslationUnit) {
if (DC->getDeclKind() == Decl::LinkageSpec)
return cast<LinkageSpecDecl>(DC)->getLanguage() == ID;
- DC = DC->getParent();
+ DC = DC->getLexicalParent();
}
return false;
}
@@ -874,18 +920,17 @@ DeclContext *DeclContext::getPrimaryContext() {
// If this is a tag type that has a definition or is currently
// being defined, that definition is our primary context.
TagDecl *Tag = cast<TagDecl>(this);
- assert(isa<TagType>(Tag->TypeForDecl) ||
- isa<InjectedClassNameType>(Tag->TypeForDecl));
if (TagDecl *Def = Tag->getDefinition())
return Def;
- if (!isa<InjectedClassNameType>(Tag->TypeForDecl)) {
- const TagType *TagTy = cast<TagType>(Tag->TypeForDecl);
- if (TagTy->isBeingDefined())
- // FIXME: is it necessarily being defined in the decl
- // that owns the type?
- return TagTy->getDecl();
+ if (const TagType *TagTy = dyn_cast<TagType>(Tag->getTypeForDecl())) {
+ // Note, TagType::getDecl returns the (partial) definition one exists.
+ TagDecl *PossiblePartialDef = TagTy->getDecl();
+ if (PossiblePartialDef->isBeingDefined())
+ return PossiblePartialDef;
+ } else {
+ assert(isa<InjectedClassNameType>(Tag->getTypeForDecl()));
}
return Tag;
@@ -918,8 +963,8 @@ std::pair<Decl *, Decl *>
DeclContext::BuildDeclChain(ArrayRef<Decl*> Decls,
bool FieldsAlreadyLoaded) {
// Build up a chain of declarations via the Decl::NextInContextAndBits field.
- Decl *FirstNewDecl = 0;
- Decl *PrevDecl = 0;
+ Decl *FirstNewDecl = nullptr;
+ Decl *PrevDecl = nullptr;
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
if (FieldsAlreadyLoaded && isa<FieldDecl>(Decls[I]))
continue;
@@ -939,13 +984,12 @@ DeclContext::BuildDeclChain(ArrayRef<Decl*> Decls,
/// \brief We have just acquired external visible storage, and we already have
/// built a lookup map. For every name in the map, pull in the new names from
/// the external storage.
-void DeclContext::reconcileExternalVisibleStorage() {
+void DeclContext::reconcileExternalVisibleStorage() const {
assert(NeedToReconcileExternalVisibleStorage && LookupPtr.getPointer());
NeedToReconcileExternalVisibleStorage = false;
- StoredDeclsMap &Map = *LookupPtr.getPointer();
- for (StoredDeclsMap::iterator I = Map.begin(); I != Map.end(); ++I)
- I->second.setHasExternalDecls();
+ for (auto &Lookup : *LookupPtr.getPointer())
+ Lookup.second.setHasExternalDecls();
}
/// \brief Load the declarations within this lexical storage from an
@@ -982,8 +1026,8 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const {
// Splice the newly-read declarations into the beginning of the list
// of declarations.
Decl *ExternalFirst, *ExternalLast;
- llvm::tie(ExternalFirst, ExternalLast) = BuildDeclChain(Decls,
- FieldsAlreadyLoaded);
+ std::tie(ExternalFirst, ExternalLast) =
+ BuildDeclChain(Decls, FieldsAlreadyLoaded);
ExternalLast->NextInContextAndBits.setPointer(FirstDecl);
FirstDecl = ExternalFirst;
if (!LastDecl)
@@ -997,6 +1041,8 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC,
StoredDeclsMap *Map;
if (!(Map = DC->LookupPtr.getPointer()))
Map = DC->CreateStoredDeclsMap(Context);
+ if (DC->NeedToReconcileExternalVisibleStorage)
+ DC->reconcileExternalVisibleStorage();
(*Map)[Name].removeExternalDecls();
@@ -1011,6 +1057,8 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
StoredDeclsMap *Map;
if (!(Map = DC->LookupPtr.getPointer()))
Map = DC->CreateStoredDeclsMap(Context);
+ if (DC->NeedToReconcileExternalVisibleStorage)
+ DC->reconcileExternalVisibleStorage();
StoredDeclsList &List = (*Map)[Name];
@@ -1050,14 +1098,9 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
return List.getLookupResult();
}
-DeclContext::decl_iterator DeclContext::noload_decls_begin() const {
- return decl_iterator(FirstDecl);
-}
-
DeclContext::decl_iterator DeclContext::decls_begin() const {
if (hasExternalLexicalStorage())
LoadLexicalDeclsFromExternalStorage();
-
return decl_iterator(FirstDecl);
}
@@ -1082,7 +1125,7 @@ void DeclContext::removeDecl(Decl *D) {
// Remove D from the decl chain. This is O(n) but hopefully rare.
if (D == FirstDecl) {
if (D == LastDecl)
- FirstDecl = LastDecl = 0;
+ FirstDecl = LastDecl = nullptr;
else
FirstDecl = D->NextInContextAndBits.getPointer();
} else {
@@ -1097,7 +1140,7 @@ void DeclContext::removeDecl(Decl *D) {
}
// Mark that D is no longer in the decl chain.
- D->NextInContextAndBits.setPointer(0);
+ D->NextInContextAndBits.setPointer(nullptr);
// Remove D from the lookup table if necessary.
if (isa<NamedDecl>(D)) {
@@ -1187,6 +1230,10 @@ static bool shouldBeHidden(NamedDecl *D) {
/// buildLookup - Build the lookup data structure with all of the
/// declarations in this DeclContext (and any other contexts linked
/// to it or transparent contexts nested within it) and return it.
+///
+/// Note that the produced map may miss out declarations from an
+/// external source. If it does, those entries will be marked with
+/// the 'hasExternalDecls' flag.
StoredDeclsMap *DeclContext::buildLookup() {
assert(this == getPrimaryContext() && "buildLookup called on non-primary DC");
@@ -1202,7 +1249,6 @@ StoredDeclsMap *DeclContext::buildLookup() {
// We no longer have any lazy decls.
LookupPtr.setInt(false);
- NeedToReconcileExternalVisibleStorage = false;
return LookupPtr.getPointer();
}
@@ -1251,11 +1297,13 @@ DeclContext::lookup(DeclarationName Name) {
return PrimaryContext->lookup(Name);
if (hasExternalVisibleStorage()) {
+ if (NeedToReconcileExternalVisibleStorage)
+ reconcileExternalVisibleStorage();
+
StoredDeclsMap *Map = LookupPtr.getPointer();
+
if (LookupPtr.getInt())
Map = buildLookup();
- else if (NeedToReconcileExternalVisibleStorage)
- reconcileExternalVisibleStorage();
if (!Map)
Map = CreateStoredDeclsMap(getParentASTContext());
@@ -1267,7 +1315,7 @@ DeclContext::lookup(DeclarationName Name) {
return R.first->second.getLookupResult();
ExternalASTSource *Source = getParentASTContext().getExternalSource();
- if (Source->FindExternalVisibleDeclsByName(this, Name) || R.second) {
+ if (Source->FindExternalVisibleDeclsByName(this, Name) || !R.second) {
if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
StoredDeclsMap::iterator I = Map->find(Name);
if (I != Map->end())
@@ -1275,7 +1323,7 @@ DeclContext::lookup(DeclarationName Name) {
}
}
- return lookup_result(lookup_iterator(0), lookup_iterator(0));
+ return lookup_result(lookup_iterator(nullptr), lookup_iterator(nullptr));
}
StoredDeclsMap *Map = LookupPtr.getPointer();
@@ -1283,11 +1331,11 @@ DeclContext::lookup(DeclarationName Name) {
Map = buildLookup();
if (!Map)
- return lookup_result(lookup_iterator(0), lookup_iterator(0));
+ return lookup_result(lookup_iterator(nullptr), lookup_iterator(nullptr));
StoredDeclsMap::iterator I = Map->find(Name);
if (I == Map->end())
- return lookup_result(lookup_iterator(0), lookup_iterator(0));
+ return lookup_result(lookup_iterator(nullptr), lookup_iterator(nullptr));
return I->second.getLookupResult();
}
@@ -1324,12 +1372,12 @@ DeclContext::noload_lookup(DeclarationName Name) {
}
if (!Map)
- return lookup_result(lookup_iterator(0), lookup_iterator(0));
+ return lookup_result(lookup_iterator(nullptr), lookup_iterator(nullptr));
StoredDeclsMap::iterator I = Map->find(Name);
- return I != Map->end()
- ? I->second.getLookupResult()
- : lookup_result(lookup_iterator(0), lookup_iterator(0));
+ return I != Map->end() ? I->second.getLookupResult()
+ : lookup_result(lookup_iterator(nullptr),
+ lookup_iterator(nullptr));
}
void DeclContext::localUncachedLookup(DeclarationName Name,
@@ -1502,13 +1550,13 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) {
/// Returns iterator range [First, Last) of UsingDirectiveDecls stored within
/// this context.
-DeclContext::udir_iterator_range
-DeclContext::getUsingDirectives() const {
+DeclContext::udir_range DeclContext::using_directives() const {
// FIXME: Use something more efficient than normal lookup for using
// directives. In C++, using directives are looked up more than anything else.
lookup_const_result Result = lookup(UsingDirectiveDecl::getName());
- return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.begin()),
- reinterpret_cast<udir_iterator>(Result.end()));
+ return udir_range(
+ reinterpret_cast<UsingDirectiveDecl *const *>(Result.begin()),
+ reinterpret_cast<UsingDirectiveDecl *const *>(Result.end()));
}
//===----------------------------------------------------------------------===//
@@ -1568,7 +1616,7 @@ DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C,
// Allocate the copy of the PartialDiagnostic via the ASTContext's
// BumpPtrAllocator, rather than the ASTContext itself.
- PartialDiagnostic::Storage *DiagStorage = 0;
+ PartialDiagnostic::Storage *DiagStorage = nullptr;
if (PDiag.hasStorage())
DiagStorage = new (C) PartialDiagnostic::Storage;
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index a17abdd0ae2a..ed26c5262a7b 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -31,8 +31,7 @@ using namespace clang;
void AccessSpecDecl::anchor() { }
AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(AccessSpecDecl));
- return new (Mem) AccessSpecDecl(EmptyShell());
+ return new (C, ID) AccessSpecDecl(EmptyShell());
}
void LazyASTUnresolvedSet::getFromExternalSource(ASTContext &C) const {
@@ -51,7 +50,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
- HasMutableFields(false), HasOnlyCMembers(true),
+ HasMutableFields(false), HasVariantMembers(false), HasOnlyCMembers(true),
HasInClassInitializer(false), HasUninitializedReferenceMember(false),
NeedOverloadResolutionForMoveConstructor(false),
NeedOverloadResolutionForMoveAssignment(false),
@@ -71,7 +70,8 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
ImplicitCopyAssignmentHasConstParam(true),
HasDeclaredCopyConstructorWithConstParam(false),
HasDeclaredCopyAssignmentWithConstParam(false),
- IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(),
+ IsLambda(false), IsParsingBaseSpecifiers(false), NumBases(0), NumVBases(0),
+ Bases(), VBases(),
Definition(D), FirstFriend() {
}
@@ -83,20 +83,22 @@ CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getVBasesSlowCase() const {
return VBases.get(Definition->getASTContext().getExternalSource());
}
-CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
- SourceLocation StartLoc, SourceLocation IdLoc,
- IdentifierInfo *Id, CXXRecordDecl *PrevDecl)
- : RecordDecl(K, TK, DC, StartLoc, IdLoc, Id, PrevDecl),
- DefinitionData(PrevDecl ? PrevDecl->DefinitionData : 0),
- TemplateOrInstantiation() { }
+CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, const ASTContext &C,
+ DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ CXXRecordDecl *PrevDecl)
+ : RecordDecl(K, TK, C, DC, StartLoc, IdLoc, Id, PrevDecl),
+ DefinitionData(PrevDecl ? PrevDecl->DefinitionData
+ : DefinitionDataPtr(this)),
+ TemplateOrInstantiation() {}
CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
CXXRecordDecl* PrevDecl,
bool DelayTypeCreation) {
- CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, StartLoc, IdLoc,
- Id, PrevDecl);
+ CXXRecordDecl *R = new (C, DC) CXXRecordDecl(CXXRecord, TK, C, DC, StartLoc,
+ IdLoc, Id, PrevDecl);
R->MayHaveOutOfDateDef = C.getLangOpts().Modules;
// FIXME: DelayTypeCreation seems like such a hack
@@ -105,29 +107,29 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
return R;
}
-CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
- TypeSourceInfo *Info, SourceLocation Loc,
- bool Dependent, bool IsGeneric,
- LambdaCaptureDefault CaptureDefault) {
- CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TTK_Class, DC, Loc, Loc,
- 0, 0);
+CXXRecordDecl *
+CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
+ TypeSourceInfo *Info, SourceLocation Loc,
+ bool Dependent, bool IsGeneric,
+ LambdaCaptureDefault CaptureDefault) {
+ CXXRecordDecl *R =
+ new (C, DC) CXXRecordDecl(CXXRecord, TTK_Class, C, DC, Loc, Loc,
+ nullptr, nullptr);
R->IsBeingDefined = true;
- R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info,
- Dependent,
- IsGeneric,
- CaptureDefault);
+ R->DefinitionData =
+ new (C) struct LambdaDefinitionData(R, Info, Dependent, IsGeneric,
+ CaptureDefault);
R->MayHaveOutOfDateDef = false;
R->setImplicit(true);
- C.getTypeDeclType(R, /*PrevDecl=*/0);
+ C.getTypeDeclType(R, /*PrevDecl=*/nullptr);
return R;
}
CXXRecordDecl *
CXXRecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXRecordDecl));
- CXXRecordDecl *R = new (Mem) CXXRecordDecl(CXXRecord, TTK_Struct, 0,
- SourceLocation(), SourceLocation(),
- 0, 0);
+ CXXRecordDecl *R = new (C, ID) CXXRecordDecl(
+ CXXRecord, TTK_Struct, C, nullptr, SourceLocation(), SourceLocation(),
+ nullptr, nullptr);
R->MayHaveOutOfDateDef = false;
return R;
}
@@ -205,19 +207,17 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
data().HasNonLiteralTypeFieldsOrBases = true;
// Now go through all virtual bases of this base and add them.
- for (CXXRecordDecl::base_class_iterator VBase =
- BaseClassDecl->vbases_begin(),
- E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) {
+ for (const auto &VBase : BaseClassDecl->vbases()) {
// Add this base if it's not already in the list.
- if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType()))) {
- VBases.push_back(VBase);
+ if (SeenVBaseTypes.insert(C.getCanonicalType(VBase.getType()))) {
+ VBases.push_back(&VBase);
// C++11 [class.copy]p8:
// The implicitly-declared copy constructor for a class X will have
// the form 'X::X(const X&)' if each [...] virtual base class B of X
// has a copy constructor whose first parameter is of type
// 'const B&' or 'const volatile B&' [...]
- if (CXXRecordDecl *VBaseDecl = VBase->getType()->getAsCXXRecordDecl())
+ if (CXXRecordDecl *VBaseDecl = VBase.getType()->getAsCXXRecordDecl())
if (!VBaseDecl->hasCopyConstructorWithConstParam())
data().ImplicitCopyConstructorHasConstParam = false;
}
@@ -335,8 +335,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
addedClassSubobject(BaseClassDecl);
}
- if (VBases.empty())
+ if (VBases.empty()) {
+ data().IsParsingBaseSpecifiers = false;
return;
+ }
// Create base specifier for any direct or indirect virtual bases.
data().VBases = new (C) CXXBaseSpecifier[VBases.size()];
@@ -347,6 +349,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
addedClassSubobject(Type->getAsCXXRecordDecl());
data().getVBases()[I] = *VBases[I];
}
+
+ data().IsParsingBaseSpecifiers = false;
}
void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
@@ -391,7 +395,7 @@ bool CXXRecordDecl::hasAnyDependentBases() const {
if (!isDependentContext())
return false;
- return !forallBases(SawBase, 0);
+ return !forallBases(SawBase, nullptr);
}
bool CXXRecordDecl::isTriviallyCopyable() const {
@@ -532,8 +536,11 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) {
SMKind |= SMF_Destructor;
- if (!DD->isImplicit())
+ if (DD->isUserProvided())
data().HasIrrelevantDestructor = false;
+ // If the destructor is explicitly defaulted and not trivial or not public
+ // or if the destructor is deleted, we clear HasIrrelevantDestructor in
+ // finishedDefaultedOrDeletedMember.
// C++11 [class.dtor]p5:
// A destructor is trivial if [...] the destructor is not virtual.
@@ -656,7 +663,13 @@ void CXXRecordDecl::addedMember(Decl *D) {
// Keep track of the presence of mutable fields.
if (Field->isMutable())
data().HasMutableFields = true;
-
+
+ // C++11 [class.union]p8, DR1460:
+ // If X is a union, a non-static data member of X that is not an anonymous
+ // union is a variant member of X.
+ if (isUnion() && !Field->isAnonymousStructOrUnion())
+ data().HasVariantMembers = true;
+
// C++0x [class]p9:
// 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
@@ -692,7 +705,9 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (!T->isLiteralType(Context) || T.isVolatileQualified())
data().HasNonLiteralTypeFieldsOrBases = true;
- if (Field->hasInClassInitializer()) {
+ if (Field->hasInClassInitializer() ||
+ (Field->isAnonymousStructOrUnion() &&
+ Field->getType()->getAsCXXRecordDecl()->hasInClassInitializer())) {
data().HasInClassInitializer = true;
// C++11 [class]p5:
@@ -809,15 +824,13 @@ void CXXRecordDecl::addedMember(Decl *D) {
// Virtual bases and virtual methods make a class non-empty, but they
// also make it non-standard-layout so we needn't check here.
// A non-empty base class may leave the class standard-layout, but not
- // if we have arrived here, and have at least on non-static data
+ // if we have arrived here, and have at least one non-static data
// member. If IsStandardLayout remains true, then the first non-static
// data member must come through here with Empty still true, and Empty
// will subsequently be set to false below.
if (data().IsStandardLayout && data().Empty) {
- for (CXXRecordDecl::base_class_const_iterator BI = bases_begin(),
- BE = bases_end();
- BI != BE; ++BI) {
- if (Context.hasSameUnqualifiedType(BI->getType(), T)) {
+ for (const auto &BI : bases()) {
+ if (Context.hasSameUnqualifiedType(BI.getType(), T)) {
data().IsStandardLayout = false;
break;
}
@@ -862,6 +875,13 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (FieldRec->hasUninitializedReferenceMember() &&
!Field->hasInClassInitializer())
data().HasUninitializedReferenceMember = true;
+
+ // C++11 [class.union]p8, DR1460:
+ // a non-static data member of an anonymous union that is a member of
+ // X is also a variant member of X.
+ if (FieldRec->hasVariantMembers() &&
+ Field->isAnonymousStructOrUnion())
+ data().HasVariantMembers = true;
}
} else {
// Base element type of field is a non-class type.
@@ -928,9 +948,11 @@ void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) {
else if (Constructor->isConstexpr())
// We may now know that the constructor is constexpr.
data().HasConstexprNonCopyMoveConstructor = true;
- } else if (isa<CXXDestructorDecl>(D))
+ } else if (isa<CXXDestructorDecl>(D)) {
SMKind |= SMF_Destructor;
- else if (D->isCopyAssignmentOperator())
+ if (!D->isTrivial() || D->getAccess() != AS_public || D->isDeleted())
+ data().HasIrrelevantDestructor = false;
+ } else if (D->isCopyAssignmentOperator())
SMKind |= SMF_CopyAssignment;
else if (D->isMoveAssignmentOperator())
SMKind |= SMF_MoveAssignment;
@@ -959,7 +981,7 @@ bool CXXRecordDecl::isGenericLambda() const {
}
CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const {
- if (!isLambda()) return 0;
+ if (!isLambda()) return nullptr;
DeclarationName Name =
getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
DeclContext::lookup_const_result Calls = lookup(Name);
@@ -976,11 +998,11 @@ CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const {
}
CXXMethodDecl* CXXRecordDecl::getLambdaStaticInvoker() const {
- if (!isLambda()) return 0;
+ if (!isLambda()) return nullptr;
DeclarationName Name =
&getASTContext().Idents.get(getLambdaStaticInvokerName());
DeclContext::lookup_const_result Invoker = lookup(Name);
- if (Invoker.empty()) return 0;
+ if (Invoker.empty()) return nullptr;
assert(Invoker.size() == 1 && "More than one static invoker operator!");
NamedDecl *InvokerFun = Invoker.front();
if (FunctionTemplateDecl *InvokerTemplate =
@@ -994,11 +1016,11 @@ void CXXRecordDecl::getCaptureFields(
llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
FieldDecl *&ThisCapture) const {
Captures.clear();
- ThisCapture = 0;
+ ThisCapture = nullptr;
LambdaDefinitionData &Lambda = getLambdaData();
RecordDecl::field_iterator Field = field_begin();
- for (LambdaExpr::Capture *C = Lambda.Captures, *CEnd = C + Lambda.NumCaptures;
+ for (const LambdaCapture *C = Lambda.Captures, *CEnd = C + Lambda.NumCaptures;
C != CEnd; ++C, ++Field) {
if (C->capturesThis())
ThisCapture = *Field;
@@ -1010,21 +1032,17 @@ void CXXRecordDecl::getCaptureFields(
TemplateParameterList *
CXXRecordDecl::getGenericLambdaTemplateParameterList() const {
- if (!isLambda()) return 0;
+ if (!isLambda()) return nullptr;
CXXMethodDecl *CallOp = getLambdaCallOperator();
if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate())
return Tmpl->getTemplateParameters();
- return 0;
+ return nullptr;
}
static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
- QualType T;
- if (isa<UsingShadowDecl>(Conv))
- Conv = cast<UsingShadowDecl>(Conv)->getTargetDecl();
- if (FunctionTemplateDecl *ConvTemp = dyn_cast<FunctionTemplateDecl>(Conv))
- T = ConvTemp->getTemplatedDecl()->getResultType();
- else
- T = cast<CXXConversionDecl>(Conv)->getConversionType();
+ QualType T =
+ cast<CXXConversionDecl>(Conv->getUnderlyingDecl()->getAsFunction())
+ ->getConversionType();
return Context.getCanonicalType(T);
}
@@ -1087,14 +1105,13 @@ static void CollectVisibleConversions(ASTContext &Context,
}
// Collect information recursively from any base classes.
- for (CXXRecordDecl::base_class_iterator
- I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) {
- const RecordType *RT = I->getType()->getAs<RecordType>();
+ for (const auto &I : Record->bases()) {
+ const RecordType *RT = I.getType()->getAs<RecordType>();
if (!RT) continue;
AccessSpecifier BaseAccess
- = CXXRecordDecl::MergeAccess(Access, I->getAccessSpecifier());
- bool BaseInVirtual = InVirtual || I->isVirtual();
+ = CXXRecordDecl::MergeAccess(Access, I.getAccessSpecifier());
+ bool BaseInVirtual = InVirtual || I.isVirtual();
CXXRecordDecl *Base = cast<CXXRecordDecl>(RT->getDecl());
CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess,
@@ -1130,13 +1147,12 @@ static void CollectVisibleConversions(ASTContext &Context,
HiddenTypes.insert(GetConversionType(Context, ConvI.getDecl()));
// Recursively collect conversions from base classes.
- for (CXXRecordDecl::base_class_iterator
- I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) {
- const RecordType *RT = I->getType()->getAs<RecordType>();
+ for (const auto &I : Record->bases()) {
+ const RecordType *RT = I.getType()->getAs<RecordType>();
if (!RT) continue;
CollectVisibleConversions(Context, cast<CXXRecordDecl>(RT->getDecl()),
- I->isVirtual(), I->getAccessSpecifier(),
+ I.isVirtual(), I.getAccessSpecifier(),
HiddenTypes, Output, VBaseCs, HiddenVBaseCs);
}
@@ -1197,8 +1213,8 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const {
if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo())
return cast<CXXRecordDecl>(MSInfo->getInstantiatedFrom());
-
- return 0;
+
+ return nullptr;
}
void
@@ -1248,14 +1264,14 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const {
DeclContext::lookup_const_result R = lookup(Name);
if (R.empty())
- return 0;
+ return nullptr;
CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(R.front());
return Dtor;
}
void CXXRecordDecl::completeDefinition() {
- completeDefinition(0);
+ completeDefinition(nullptr);
}
void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
@@ -1317,11 +1333,9 @@ bool CXXRecordDecl::mayBeAbstract() const {
isDependentContext())
return false;
- for (CXXRecordDecl::base_class_const_iterator B = bases_begin(),
- BEnd = bases_end();
- B != BEnd; ++B) {
+ for (const auto &B : bases()) {
CXXRecordDecl *BaseDecl
- = cast<CXXRecordDecl>(B->getType()->getAs<RecordType>()->getDecl());
+ = cast<CXXRecordDecl>(B.getType()->getAs<RecordType>()->getDecl());
if (BaseDecl->isAbstract())
return true;
}
@@ -1369,7 +1383,7 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD,
if (MayBeBase && recursivelyOverrides(this, MD))
return MD;
}
- return NULL;
+ return nullptr;
}
lookup_const_result Candidates = RD->lookup(getDeclName());
@@ -1383,9 +1397,8 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD,
return MD;
}
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const RecordType *RT = I->getType()->getAs<RecordType>();
+ for (const auto &I : RD->bases()) {
+ const RecordType *RT = I.getType()->getAs<RecordType>();
if (!RT)
continue;
const CXXRecordDecl *Base = cast<CXXRecordDecl>(RT->getDecl());
@@ -1394,7 +1407,7 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD,
return T;
}
- return NULL;
+ return nullptr;
}
CXXMethodDecl *
@@ -1404,17 +1417,15 @@ CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
QualType T, TypeSourceInfo *TInfo,
StorageClass SC, bool isInline,
bool isConstexpr, SourceLocation EndLocation) {
- return new (C) CXXMethodDecl(CXXMethod, RD, StartLoc, NameInfo, T, TInfo,
- SC, isInline, isConstexpr,
- EndLocation);
+ return new (C, RD) CXXMethodDecl(CXXMethod, C, RD, StartLoc, NameInfo,
+ T, TInfo, SC, isInline, isConstexpr,
+ EndLocation);
}
CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXMethodDecl));
- return new (Mem) CXXMethodDecl(CXXMethod, 0, SourceLocation(),
- DeclarationNameInfo(), QualType(),
- 0, SC_None, false, false,
- SourceLocation());
+ return new (C, ID) CXXMethodDecl(CXXMethod, C, nullptr, SourceLocation(),
+ DeclarationNameInfo(), QualType(), nullptr,
+ SC_None, false, false, SourceLocation());
}
bool CXXMethodDecl::isUsualDeallocationFunction() const {
@@ -1511,12 +1522,12 @@ void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
}
CXXMethodDecl::method_iterator CXXMethodDecl::begin_overridden_methods() const {
- if (isa<CXXConstructorDecl>(this)) return 0;
+ if (isa<CXXConstructorDecl>(this)) return nullptr;
return getASTContext().overridden_methods_begin(this);
}
CXXMethodDecl::method_iterator CXXMethodDecl::end_overridden_methods() const {
- if (isa<CXXConstructorDecl>(this)) return 0;
+ if (isa<CXXConstructorDecl>(this)) return nullptr;
return getASTContext().overridden_methods_end(this);
}
@@ -1614,7 +1625,7 @@ CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
VarDecl **Indices,
unsigned NumIndices)
: Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
- LParenLoc(L), RParenLoc(R), IsVirtual(false),
+ LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false),
IsWritten(false), SourceOrderOrNumArrayIndices(NumIndices)
{
VarDecl **MyIndices = reinterpret_cast<VarDecl **> (this + 1);
@@ -1646,7 +1657,7 @@ const Type *CXXCtorInitializer::getBaseClass() const {
if (isBaseInitializer())
return Initializee.get<TypeSourceInfo*>()->getType().getTypePtr();
else
- return 0;
+ return nullptr;
}
SourceLocation CXXCtorInitializer::getSourceLocation() const {
@@ -1677,9 +1688,9 @@ void CXXConstructorDecl::anchor() { }
CXXConstructorDecl *
CXXConstructorDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXConstructorDecl));
- return new (Mem) CXXConstructorDecl(0, SourceLocation(),DeclarationNameInfo(),
- QualType(), 0, false, false, false,false);
+ return new (C, ID) CXXConstructorDecl(C, nullptr, SourceLocation(),
+ DeclarationNameInfo(), QualType(),
+ nullptr, false, false, false, false);
}
CXXConstructorDecl *
@@ -1692,9 +1703,9 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConstructorName &&
"Name must refer to a constructor");
- return new (C) CXXConstructorDecl(RD, StartLoc, NameInfo, T, TInfo,
- isExplicit, isInline, isImplicitlyDeclared,
- isConstexpr);
+ return new (C, RD) CXXConstructorDecl(C, RD, StartLoc, NameInfo, T, TInfo,
+ isExplicit, isInline,
+ isImplicitlyDeclared, isConstexpr);
}
CXXConstructorDecl *CXXConstructorDecl::getTargetConstructor() const {
@@ -1702,8 +1713,8 @@ CXXConstructorDecl *CXXConstructorDecl::getTargetConstructor() const {
Expr *E = (*init_begin())->getInit()->IgnoreImplicit();
if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(E))
return Construct->getConstructor();
-
- return 0;
+
+ return nullptr;
}
bool CXXConstructorDecl::isDefaultConstructor() const {
@@ -1739,8 +1750,8 @@ bool CXXConstructorDecl::isCopyOrMoveConstructor(unsigned &TypeQuals) const {
// all other parameters have default arguments.
if ((getNumParams() < 1) ||
(getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) ||
- (getPrimaryTemplate() != 0) ||
- (getDescribedFunctionTemplate() != 0))
+ (getPrimaryTemplate() != nullptr) ||
+ (getDescribedFunctionTemplate() != nullptr))
return false;
const ParmVarDecl *Param = getParamDecl(0);
@@ -1788,8 +1799,8 @@ bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const {
bool CXXConstructorDecl::isSpecializationCopyingObject() const {
if ((getNumParams() < 1) ||
(getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) ||
- (getPrimaryTemplate() == 0) ||
- (getDescribedFunctionTemplate() != 0))
+ (getPrimaryTemplate() == nullptr) ||
+ (getDescribedFunctionTemplate() != nullptr))
return false;
const ParmVarDecl *Param = getParamDecl(0);
@@ -1810,7 +1821,7 @@ const CXXConstructorDecl *CXXConstructorDecl::getInheritedConstructor() const {
// Hack: we store the inherited constructor in the overridden method table
method_iterator It = getASTContext().overridden_methods_begin(this);
if (It == getASTContext().overridden_methods_end(this))
- return 0;
+ return nullptr;
return cast<CXXConstructorDecl>(*It);
}
@@ -1827,9 +1838,9 @@ void CXXDestructorDecl::anchor() { }
CXXDestructorDecl *
CXXDestructorDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXDestructorDecl));
- return new (Mem) CXXDestructorDecl(0, SourceLocation(), DeclarationNameInfo(),
- QualType(), 0, false, false);
+ return new (C, ID)
+ CXXDestructorDecl(C, nullptr, SourceLocation(), DeclarationNameInfo(),
+ QualType(), nullptr, false, false);
}
CXXDestructorDecl *
@@ -1841,18 +1852,18 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXDestructorName &&
"Name must refer to a destructor");
- return new (C) CXXDestructorDecl(RD, StartLoc, NameInfo, T, TInfo, isInline,
- isImplicitlyDeclared);
+ return new (C, RD) CXXDestructorDecl(C, RD, StartLoc, NameInfo, T, TInfo,
+ isInline, isImplicitlyDeclared);
}
void CXXConversionDecl::anchor() { }
CXXConversionDecl *
CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXConversionDecl));
- return new (Mem) CXXConversionDecl(0, SourceLocation(), DeclarationNameInfo(),
- QualType(), 0, false, false, false,
- SourceLocation());
+ return new (C, ID) CXXConversionDecl(C, nullptr, SourceLocation(),
+ DeclarationNameInfo(), QualType(),
+ nullptr, false, false, false,
+ SourceLocation());
}
CXXConversionDecl *
@@ -1865,9 +1876,9 @@ CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConversionFunctionName &&
"Name must refer to a conversion function");
- return new (C) CXXConversionDecl(RD, StartLoc, NameInfo, T, TInfo,
- isInline, isExplicit, isConstexpr,
- EndLocation);
+ return new (C, RD) CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo,
+ isInline, isExplicit, isConstexpr,
+ EndLocation);
}
bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
@@ -1883,13 +1894,13 @@ LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
SourceLocation LangLoc,
LanguageIDs Lang,
bool HasBraces) {
- return new (C) LinkageSpecDecl(DC, ExternLoc, LangLoc, Lang, HasBraces);
+ return new (C, DC) LinkageSpecDecl(DC, ExternLoc, LangLoc, Lang, HasBraces);
}
-LinkageSpecDecl *LinkageSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(LinkageSpecDecl));
- return new (Mem) LinkageSpecDecl(0, SourceLocation(), SourceLocation(),
- lang_c, false);
+LinkageSpecDecl *LinkageSpecDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ return new (C, ID) LinkageSpecDecl(nullptr, SourceLocation(),
+ SourceLocation(), lang_c, false);
}
void UsingDirectiveDecl::anchor() { }
@@ -1903,16 +1914,16 @@ UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC,
DeclContext *CommonAncestor) {
if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Used))
Used = NS->getOriginalNamespace();
- return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierLoc,
- IdentLoc, Used, CommonAncestor);
+ return new (C, DC) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierLoc,
+ IdentLoc, Used, CommonAncestor);
}
-UsingDirectiveDecl *
-UsingDirectiveDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(UsingDirectiveDecl));
- return new (Mem) UsingDirectiveDecl(0, SourceLocation(), SourceLocation(),
- NestedNameSpecifierLoc(),
- SourceLocation(), 0, 0);
+UsingDirectiveDecl *UsingDirectiveDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ return new (C, ID) UsingDirectiveDecl(nullptr, SourceLocation(),
+ SourceLocation(),
+ NestedNameSpecifierLoc(),
+ SourceLocation(), nullptr, nullptr);
}
NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() {
@@ -1922,17 +1933,14 @@ NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() {
return cast_or_null<NamespaceDecl>(NominatedNamespace);
}
-void NamespaceDecl::anchor() { }
-
-NamespaceDecl::NamespaceDecl(DeclContext *DC, bool Inline,
- SourceLocation StartLoc,
- SourceLocation IdLoc, IdentifierInfo *Id,
- NamespaceDecl *PrevDecl)
- : NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace),
- LocStart(StartLoc), RBraceLoc(), AnonOrFirstNamespaceAndInline(0, Inline)
-{
+NamespaceDecl::NamespaceDecl(ASTContext &C, DeclContext *DC, bool Inline,
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ IdentifierInfo *Id, NamespaceDecl *PrevDecl)
+ : NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace),
+ redeclarable_base(C), LocStart(StartLoc), RBraceLoc(),
+ AnonOrFirstNamespaceAndInline(nullptr, Inline) {
setPreviousDecl(PrevDecl);
-
+
if (PrevDecl)
AnonOrFirstNamespaceAndInline.setPointer(PrevDecl->getOriginalNamespace());
}
@@ -1941,13 +1949,23 @@ NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
bool Inline, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
NamespaceDecl *PrevDecl) {
- return new (C) NamespaceDecl(DC, Inline, StartLoc, IdLoc, Id, PrevDecl);
+ return new (C, DC) NamespaceDecl(C, DC, Inline, StartLoc, IdLoc, Id,
+ PrevDecl);
}
NamespaceDecl *NamespaceDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(NamespaceDecl));
- return new (Mem) NamespaceDecl(0, false, SourceLocation(), SourceLocation(),
- 0, 0);
+ return new (C, ID) NamespaceDecl(C, nullptr, false, SourceLocation(),
+ SourceLocation(), nullptr, nullptr);
+}
+
+NamespaceDecl *NamespaceDecl::getNextRedeclarationImpl() {
+ return getNextRedeclaration();
+}
+NamespaceDecl *NamespaceDecl::getPreviousDeclImpl() {
+ return getPreviousDecl();
+}
+NamespaceDecl *NamespaceDecl::getMostRecentDeclImpl() {
+ return getMostRecentDecl();
}
void NamespaceAliasDecl::anchor() { }
@@ -1961,24 +1979,24 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
NamedDecl *Namespace) {
if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Namespace))
Namespace = NS->getOriginalNamespace();
- return new (C) NamespaceAliasDecl(DC, UsingLoc, AliasLoc, Alias,
- QualifierLoc, IdentLoc, Namespace);
+ return new (C, DC) NamespaceAliasDecl(DC, UsingLoc, AliasLoc, Alias,
+ QualifierLoc, IdentLoc, Namespace);
}
NamespaceAliasDecl *
NamespaceAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(NamespaceAliasDecl));
- return new (Mem) NamespaceAliasDecl(0, SourceLocation(), SourceLocation(), 0,
- NestedNameSpecifierLoc(),
- SourceLocation(), 0);
+ return new (C, ID) NamespaceAliasDecl(nullptr, SourceLocation(),
+ SourceLocation(), nullptr,
+ NestedNameSpecifierLoc(),
+ SourceLocation(), nullptr);
}
void UsingShadowDecl::anchor() { }
UsingShadowDecl *
UsingShadowDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(UsingShadowDecl));
- return new (Mem) UsingShadowDecl(0, SourceLocation(), 0, 0);
+ return new (C, ID) UsingShadowDecl(C, nullptr, SourceLocation(),
+ nullptr, nullptr);
}
UsingDecl *UsingShadowDecl::getUsingDecl() const {
@@ -2026,13 +2044,13 @@ UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UL,
NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
bool HasTypename) {
- return new (C) UsingDecl(DC, UL, QualifierLoc, NameInfo, HasTypename);
+ return new (C, DC) UsingDecl(DC, UL, QualifierLoc, NameInfo, HasTypename);
}
UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(UsingDecl));
- return new (Mem) UsingDecl(0, SourceLocation(), NestedNameSpecifierLoc(),
- DeclarationNameInfo(), false);
+ return new (C, ID) UsingDecl(nullptr, SourceLocation(),
+ NestedNameSpecifierLoc(), DeclarationNameInfo(),
+ false);
}
SourceRange UsingDecl::getSourceRange() const {
@@ -2048,16 +2066,16 @@ UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation UsingLoc,
NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo) {
- return new (C) UnresolvedUsingValueDecl(DC, C.DependentTy, UsingLoc,
- QualifierLoc, NameInfo);
+ return new (C, DC) UnresolvedUsingValueDecl(DC, C.DependentTy, UsingLoc,
+ QualifierLoc, NameInfo);
}
UnresolvedUsingValueDecl *
UnresolvedUsingValueDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(UnresolvedUsingValueDecl));
- return new (Mem) UnresolvedUsingValueDecl(0, QualType(), SourceLocation(),
- NestedNameSpecifierLoc(),
- DeclarationNameInfo());
+ return new (C, ID) UnresolvedUsingValueDecl(nullptr, QualType(),
+ SourceLocation(),
+ NestedNameSpecifierLoc(),
+ DeclarationNameInfo());
}
SourceRange UnresolvedUsingValueDecl::getSourceRange() const {
@@ -2075,20 +2093,16 @@ UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TargetNameLoc,
DeclarationName TargetName) {
- return new (C) UnresolvedUsingTypenameDecl(DC, UsingLoc, TypenameLoc,
- QualifierLoc, TargetNameLoc,
- TargetName.getAsIdentifierInfo());
+ return new (C, DC) UnresolvedUsingTypenameDecl(
+ DC, UsingLoc, TypenameLoc, QualifierLoc, TargetNameLoc,
+ TargetName.getAsIdentifierInfo());
}
UnresolvedUsingTypenameDecl *
UnresolvedUsingTypenameDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID,
- sizeof(UnresolvedUsingTypenameDecl));
- return new (Mem) UnresolvedUsingTypenameDecl(0, SourceLocation(),
- SourceLocation(),
- NestedNameSpecifierLoc(),
- SourceLocation(),
- 0);
+ return new (C, ID) UnresolvedUsingTypenameDecl(
+ nullptr, SourceLocation(), SourceLocation(), NestedNameSpecifierLoc(),
+ SourceLocation(), nullptr);
}
void StaticAssertDecl::anchor() { }
@@ -2099,15 +2113,30 @@ StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC,
StringLiteral *Message,
SourceLocation RParenLoc,
bool Failed) {
- return new (C) StaticAssertDecl(DC, StaticAssertLoc, AssertExpr, Message,
- RParenLoc, Failed);
+ return new (C, DC) StaticAssertDecl(DC, StaticAssertLoc, AssertExpr, Message,
+ RParenLoc, Failed);
}
-StaticAssertDecl *StaticAssertDecl::CreateDeserialized(ASTContext &C,
+StaticAssertDecl *StaticAssertDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(StaticAssertDecl));
- return new (Mem) StaticAssertDecl(0, SourceLocation(), 0, 0,
- SourceLocation(), false);
+ return new (C, ID) StaticAssertDecl(nullptr, SourceLocation(), nullptr,
+ nullptr, SourceLocation(), false);
+}
+
+MSPropertyDecl *MSPropertyDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, DeclarationName N,
+ QualType T, TypeSourceInfo *TInfo,
+ SourceLocation StartL,
+ IdentifierInfo *Getter,
+ IdentifierInfo *Setter) {
+ return new (C, DC) MSPropertyDecl(DC, L, N, T, TInfo, StartL, Getter, Setter);
+}
+
+MSPropertyDecl *MSPropertyDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ return new (C, ID) MSPropertyDecl(nullptr, SourceLocation(),
+ DeclarationName(), QualType(), nullptr,
+ SourceLocation(), nullptr, nullptr);
}
static const char *getAccessName(AccessSpecifier AS) {
diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp
index 1c639d676dc9..a996cab093af 100644
--- a/lib/AST/DeclFriend.cpp
+++ b/lib/AST/DeclFriend.cpp
@@ -46,25 +46,21 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
}
#endif
- std::size_t Size = sizeof(FriendDecl)
- + FriendTypeTPLists.size() * sizeof(TemplateParameterList*);
- void *Mem = C.Allocate(Size);
- FriendDecl *FD = new (Mem) FriendDecl(DC, L, Friend, FriendL,
- FriendTypeTPLists);
+ std::size_t Extra = FriendTypeTPLists.size() * sizeof(TemplateParameterList*);
+ FriendDecl *FD = new (C, DC, Extra) FriendDecl(DC, L, Friend, FriendL,
+ FriendTypeTPLists);
cast<CXXRecordDecl>(DC)->pushFriendDecl(FD);
return FD;
}
FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, unsigned ID,
unsigned FriendTypeNumTPLists) {
- std::size_t Size = sizeof(FriendDecl)
- + FriendTypeNumTPLists * sizeof(TemplateParameterList*);
- void *Mem = AllocateDeserializedDecl(C, ID, Size);
- return new (Mem) FriendDecl(EmptyShell(), FriendTypeNumTPLists);
+ std::size_t Extra = FriendTypeNumTPLists * sizeof(TemplateParameterList*);
+ return new (C, ID, Extra) FriendDecl(EmptyShell(), FriendTypeNumTPLists);
}
FriendDecl *CXXRecordDecl::getFirstFriend() const {
ExternalASTSource *Source = getParentASTContext().getExternalSource();
Decl *First = data().FirstFriend.get(Source);
- return First ? cast<FriendDecl>(First) : 0;
+ return First ? cast<FriendDecl>(First) : nullptr;
}
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index b2b5b70197b7..2204dff13739 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -25,7 +25,7 @@ using namespace clang;
//===----------------------------------------------------------------------===//
void ObjCListBase::set(void *const* InList, unsigned Elts, ASTContext &Ctx) {
- List = 0;
+ List = nullptr;
if (Elts == 0) return; // Setting to an empty list is a noop.
@@ -60,7 +60,7 @@ ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const {
if (ObjCIvarDecl *ivar = dyn_cast<ObjCIvarDecl>(*Ivar))
return ivar;
}
- return 0;
+ return nullptr;
}
// Get the local instance/class method declared in this interface.
@@ -72,7 +72,7 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance,
if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) {
if (const ObjCProtocolDecl *Def = Proto->getDefinition())
if (Def->isHidden() && !AllowHidden)
- return 0;
+ return nullptr;
}
// Since instance & class methods can have the same name, the loop below
@@ -90,7 +90,7 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance,
if (MD && MD->isInstanceMethod() == isInstance)
return MD;
}
- return 0;
+ return nullptr;
}
/// HasUserDeclaredSetterMethod - This routine returns 'true' if a user declared setter
@@ -112,11 +112,7 @@ ObjCContainerDecl::HasUserDeclaredSetterMethod(const ObjCPropertyDecl *Property)
if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(this)) {
// Also look into categories, including class extensions, looking
// for a user declared instance method.
- for (ObjCInterfaceDecl::visible_categories_iterator
- Cat = ID->visible_categories_begin(),
- CatEnd = ID->visible_categories_end();
- Cat != CatEnd;
- ++Cat) {
+ for (const auto *Cat : ID->visible_categories()) {
if (ObjCMethodDecl *MD = Cat->getInstanceMethod(Sel))
if (!MD->isImplicit())
return true;
@@ -125,8 +121,7 @@ ObjCContainerDecl::HasUserDeclaredSetterMethod(const ObjCPropertyDecl *Property)
// Also search through the categories looking for a 'readwrite' declaration
// of this property. If one found, presumably a setter will be provided
// (properties declared in categories will not get auto-synthesized).
- for (ObjCContainerDecl::prop_iterator P = Cat->prop_begin(),
- E = Cat->prop_end(); P != E; ++P)
+ for (const auto *P : Cat->properties())
if (P->getIdentifier() == Property->getIdentifier()) {
if (P->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite)
return true;
@@ -135,13 +130,10 @@ ObjCContainerDecl::HasUserDeclaredSetterMethod(const ObjCPropertyDecl *Property)
}
// Also look into protocols, for a user declared instance method.
- for (ObjCInterfaceDecl::all_protocol_iterator P =
- ID->all_referenced_protocol_begin(),
- PE = ID->all_referenced_protocol_end(); P != PE; ++P) {
- ObjCProtocolDecl *Proto = (*P);
+ for (const auto *Proto : ID->all_referenced_protocols())
if (Proto->HasUserDeclaredSetterMethod(Property))
return true;
- }
+
// And in its super class.
ObjCInterfaceDecl *OSC = ID->getSuperClass();
while (OSC) {
@@ -151,11 +143,9 @@ ObjCContainerDecl::HasUserDeclaredSetterMethod(const ObjCPropertyDecl *Property)
}
}
if (const ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(this))
- for (ObjCProtocolDecl::protocol_iterator PI = PD->protocol_begin(),
- E = PD->protocol_end(); PI != E; ++PI) {
- if ((*PI)->HasUserDeclaredSetterMethod(Property))
+ for (const auto *PI : PD->protocols())
+ if (PI->HasUserDeclaredSetterMethod(Property))
return true;
- }
return false;
}
@@ -167,7 +157,7 @@ ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC,
if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(DC)) {
if (const ObjCProtocolDecl *Def = Proto->getDefinition())
if (Def->isHidden())
- return 0;
+ return nullptr;
}
DeclContext::lookup_const_result R = DC->lookup(propertyID);
@@ -176,7 +166,7 @@ ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC,
if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(*I))
return PD;
- return 0;
+ return nullptr;
}
IdentifierInfo *
@@ -197,7 +187,7 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) {
if (const ObjCProtocolDecl *Def = Proto->getDefinition())
if (Def->isHidden())
- return 0;
+ return nullptr;
}
if (ObjCPropertyDecl *PD =
@@ -209,29 +199,23 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
break;
case Decl::ObjCProtocol: {
const ObjCProtocolDecl *PID = cast<ObjCProtocolDecl>(this);
- for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(),
- E = PID->protocol_end(); I != E; ++I)
- if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
+ for (const auto *I : PID->protocols())
+ if (ObjCPropertyDecl *P = I->FindPropertyDeclaration(PropertyId))
return P;
break;
}
case Decl::ObjCInterface: {
const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(this);
// Look through categories (but not extensions).
- for (ObjCInterfaceDecl::visible_categories_iterator
- Cat = OID->visible_categories_begin(),
- CatEnd = OID->visible_categories_end();
- Cat != CatEnd; ++Cat) {
+ for (const auto *Cat : OID->visible_categories()) {
if (!Cat->IsClassExtension())
if (ObjCPropertyDecl *P = Cat->FindPropertyDeclaration(PropertyId))
return P;
}
// Look through protocols.
- for (ObjCInterfaceDecl::all_protocol_iterator
- I = OID->all_referenced_protocol_begin(),
- E = OID->all_referenced_protocol_end(); I != E; ++I)
- if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
+ for (const auto *I : OID->all_referenced_protocols())
+ if (ObjCPropertyDecl *P = I->FindPropertyDeclaration(PropertyId))
return P;
// Finally, check the super class.
@@ -243,15 +227,13 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
const ObjCCategoryDecl *OCD = cast<ObjCCategoryDecl>(this);
// Look through protocols.
if (!OCD->IsClassExtension())
- for (ObjCCategoryDecl::protocol_iterator
- I = OCD->protocol_begin(), E = OCD->protocol_end(); I != E; ++I)
- if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
- return P;
-
+ for (const auto *I : OCD->protocols())
+ if (ObjCPropertyDecl *P = I->FindPropertyDeclaration(PropertyId))
+ return P;
break;
}
}
- return 0;
+ return nullptr;
}
void ObjCInterfaceDecl::anchor() { }
@@ -265,8 +247,8 @@ ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
IdentifierInfo *PropertyId) const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
- return 0;
-
+ return nullptr;
+
if (data().ExternallyCompleted)
LoadExternalDefinition();
@@ -275,27 +257,21 @@ ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
return PD;
// Look through protocols.
- for (ObjCInterfaceDecl::all_protocol_iterator
- I = all_referenced_protocol_begin(),
- E = all_referenced_protocol_end(); I != E; ++I)
- if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
+ for (const auto *I : all_referenced_protocols())
+ if (ObjCPropertyDecl *P = I->FindPropertyDeclaration(PropertyId))
return P;
- return 0;
+ return nullptr;
}
void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM,
PropertyDeclOrder &PO) const {
- for (ObjCContainerDecl::prop_iterator P = prop_begin(),
- E = prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
+ for (auto *Prop : properties()) {
PM[Prop->getIdentifier()] = Prop;
PO.push_back(Prop);
}
- for (ObjCInterfaceDecl::all_protocol_iterator
- PI = all_referenced_protocol_begin(),
- E = all_referenced_protocol_end(); PI != E; ++PI)
- (*PI)->collectPropertiesToImplement(PM, PO);
+ for (const auto *PI : all_referenced_protocols())
+ PI->collectPropertiesToImplement(PM, PO);
// Note, the properties declared only in class extensions are still copied
// into the main @interface's property list, and therefore we don't
// explicitly, have to search class extension properties.
@@ -318,7 +294,7 @@ const ObjCInterfaceDecl *ObjCInterfaceDecl::isObjCRequiresPropertyDefs() const {
return Class;
Class = Class->getSuperClass();
}
- return 0;
+ return nullptr;
}
void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
@@ -341,10 +317,7 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
for (unsigned i = 0; i < ExtNum; i++) {
bool protocolExists = false;
ObjCProtocolDecl *ProtoInExtension = ExtList[i];
- for (all_protocol_iterator
- p = all_referenced_protocol_begin(),
- e = all_referenced_protocol_end(); p != e; ++p) {
- ObjCProtocolDecl *Proto = (*p);
+ for (auto *Proto : all_referenced_protocols()) {
if (C.ProtocolCompatibleWithProtocol(ProtoInExtension, Proto)) {
protocolExists = true;
break;
@@ -360,14 +333,132 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
return;
// Merge ProtocolRefs into class's protocol list;
- for (all_protocol_iterator p = all_referenced_protocol_begin(),
- e = all_referenced_protocol_end(); p != e; ++p) {
- ProtocolRefs.push_back(*p);
+ for (auto *P : all_referenced_protocols()) {
+ ProtocolRefs.push_back(P);
}
data().AllReferencedProtocols.set(ProtocolRefs.data(), ProtocolRefs.size(),C);
}
+const ObjCInterfaceDecl *
+ObjCInterfaceDecl::findInterfaceWithDesignatedInitializers() const {
+ const ObjCInterfaceDecl *IFace = this;
+ while (IFace) {
+ if (IFace->hasDesignatedInitializers())
+ return IFace;
+ if (!IFace->inheritsDesignatedInitializers())
+ break;
+ IFace = IFace->getSuperClass();
+ }
+ return nullptr;
+}
+
+static bool isIntroducingInitializers(const ObjCInterfaceDecl *D) {
+ for (const auto *MD : D->instance_methods()) {
+ if (MD->getMethodFamily() == OMF_init && !MD->isOverriding())
+ return true;
+ }
+ for (const auto *Ext : D->visible_extensions()) {
+ for (const auto *MD : Ext->instance_methods()) {
+ if (MD->getMethodFamily() == OMF_init && !MD->isOverriding())
+ return true;
+ }
+ }
+ if (const auto *ImplD = D->getImplementation()) {
+ for (const auto *MD : ImplD->instance_methods()) {
+ if (MD->getMethodFamily() == OMF_init && !MD->isOverriding())
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ObjCInterfaceDecl::inheritsDesignatedInitializers() const {
+ switch (data().InheritedDesignatedInitializers) {
+ case DefinitionData::IDI_Inherited:
+ return true;
+ case DefinitionData::IDI_NotInherited:
+ return false;
+ case DefinitionData::IDI_Unknown: {
+ // If the class introduced initializers we conservatively assume that we
+ // don't know if any of them is a designated initializer to avoid possible
+ // misleading warnings.
+ if (isIntroducingInitializers(this)) {
+ data().InheritedDesignatedInitializers = DefinitionData::IDI_NotInherited;
+ } else {
+ if (auto SuperD = getSuperClass()) {
+ data().InheritedDesignatedInitializers =
+ SuperD->declaresOrInheritsDesignatedInitializers() ?
+ DefinitionData::IDI_Inherited :
+ DefinitionData::IDI_NotInherited;
+ } else {
+ data().InheritedDesignatedInitializers =
+ DefinitionData::IDI_NotInherited;
+ }
+ }
+ assert(data().InheritedDesignatedInitializers
+ != DefinitionData::IDI_Unknown);
+ return data().InheritedDesignatedInitializers ==
+ DefinitionData::IDI_Inherited;
+ }
+ }
+
+ llvm_unreachable("unexpected InheritedDesignatedInitializers value");
+}
+
+void ObjCInterfaceDecl::getDesignatedInitializers(
+ llvm::SmallVectorImpl<const ObjCMethodDecl *> &Methods) const {
+ // Check for a complete definition and recover if not so.
+ if (!isThisDeclarationADefinition())
+ return;
+ if (data().ExternallyCompleted)
+ LoadExternalDefinition();
+
+ const ObjCInterfaceDecl *IFace= findInterfaceWithDesignatedInitializers();
+ if (!IFace)
+ return;
+
+ for (const auto *MD : IFace->instance_methods())
+ if (MD->isThisDeclarationADesignatedInitializer())
+ Methods.push_back(MD);
+ for (const auto *Ext : IFace->visible_extensions()) {
+ for (const auto *MD : Ext->instance_methods())
+ if (MD->isThisDeclarationADesignatedInitializer())
+ Methods.push_back(MD);
+ }
+}
+
+bool ObjCInterfaceDecl::isDesignatedInitializer(Selector Sel,
+ const ObjCMethodDecl **InitMethod) const {
+ // Check for a complete definition and recover if not so.
+ if (!isThisDeclarationADefinition())
+ return false;
+ if (data().ExternallyCompleted)
+ LoadExternalDefinition();
+
+ const ObjCInterfaceDecl *IFace= findInterfaceWithDesignatedInitializers();
+ if (!IFace)
+ return false;
+
+ if (const ObjCMethodDecl *MD = IFace->getInstanceMethod(Sel)) {
+ if (MD->isThisDeclarationADesignatedInitializer()) {
+ if (InitMethod)
+ *InitMethod = MD;
+ return true;
+ }
+ }
+ for (const auto *Ext : IFace->visible_extensions()) {
+ if (const ObjCMethodDecl *MD = Ext->getInstanceMethod(Sel)) {
+ if (MD->isThisDeclarationADesignatedInitializer()) {
+ if (InitMethod)
+ *InitMethod = MD;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
void ObjCInterfaceDecl::allocateDefinitionData() {
assert(!hasDefinition() && "ObjC class already has a definition");
Data.setPointer(new (getASTContext()) DefinitionData());
@@ -382,9 +473,8 @@ void ObjCInterfaceDecl::startDefinition() {
allocateDefinitionData();
// Update all of the declarations with a pointer to the definition.
- for (redecl_iterator RD = redecls_begin(), RDEnd = redecls_end();
- RD != RDEnd; ++RD) {
- if (*RD != this)
+ for (auto RD : redecls()) {
+ if (RD != this)
RD->Data = Data;
}
}
@@ -393,22 +483,19 @@ ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
ObjCInterfaceDecl *&clsDeclared) {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
- return 0;
+ return nullptr;
if (data().ExternallyCompleted)
LoadExternalDefinition();
ObjCInterfaceDecl* ClassDecl = this;
- while (ClassDecl != NULL) {
+ while (ClassDecl != nullptr) {
if (ObjCIvarDecl *I = ClassDecl->getIvarDecl(ID)) {
clsDeclared = ClassDecl;
return I;
}
- for (ObjCInterfaceDecl::visible_extensions_iterator
- Ext = ClassDecl->visible_extensions_begin(),
- ExtEnd = ClassDecl->visible_extensions_end();
- Ext != ExtEnd; ++Ext) {
+ for (const auto *Ext : ClassDecl->visible_extensions()) {
if (ObjCIvarDecl *I = Ext->getIvarDecl(ID)) {
clsDeclared = ClassDecl;
return I;
@@ -417,7 +504,7 @@ ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
ClassDecl = ClassDecl->getSuperClass();
}
- return NULL;
+ return nullptr;
}
/// lookupInheritedClass - This method returns ObjCInterfaceDecl * of the super
@@ -427,29 +514,27 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass(
const IdentifierInfo*ICName) {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
- return 0;
+ return nullptr;
if (data().ExternallyCompleted)
LoadExternalDefinition();
ObjCInterfaceDecl* ClassDecl = this;
- while (ClassDecl != NULL) {
+ while (ClassDecl != nullptr) {
if (ClassDecl->getIdentifier() == ICName)
return ClassDecl;
ClassDecl = ClassDecl->getSuperClass();
}
- return NULL;
+ return nullptr;
}
ObjCProtocolDecl *
ObjCInterfaceDecl::lookupNestedProtocol(IdentifierInfo *Name) {
- for (ObjCInterfaceDecl::all_protocol_iterator P =
- all_referenced_protocol_begin(), PE = all_referenced_protocol_end();
- P != PE; ++P)
- if ((*P)->lookupProtocolNamed(Name))
- return (*P);
+ for (auto *P : all_referenced_protocols())
+ if (P->lookupProtocolNamed(Name))
+ return P;
ObjCInterfaceDecl *SuperClass = getSuperClass();
- return SuperClass ? SuperClass->lookupNestedProtocol(Name) : NULL;
+ return SuperClass ? SuperClass->lookupNestedProtocol(Name) : nullptr;
}
/// lookupMethod - This method returns an instance/class method by looking in
@@ -457,37 +542,34 @@ ObjCInterfaceDecl::lookupNestedProtocol(IdentifierInfo *Name) {
/// When argument category "C" is specified, any implicit method found
/// in this category is ignored.
ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
- bool isInstance,
- bool shallowCategoryLookup,
- const ObjCCategoryDecl *C) const {
+ bool isInstance,
+ bool shallowCategoryLookup,
+ bool followSuper,
+ const ObjCCategoryDecl *C) const
+{
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
- return 0;
+ return nullptr;
const ObjCInterfaceDecl* ClassDecl = this;
- ObjCMethodDecl *MethodDecl = 0;
+ ObjCMethodDecl *MethodDecl = nullptr;
if (data().ExternallyCompleted)
LoadExternalDefinition();
- while (ClassDecl != NULL) {
+ while (ClassDecl) {
if ((MethodDecl = ClassDecl->getMethod(Sel, isInstance)))
return MethodDecl;
// Didn't find one yet - look through protocols.
- for (ObjCInterfaceDecl::protocol_iterator I = ClassDecl->protocol_begin(),
- E = ClassDecl->protocol_end();
- I != E; ++I)
- if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance)))
+ for (const auto *I : ClassDecl->protocols())
+ if ((MethodDecl = I->lookupMethod(Sel, isInstance)))
return MethodDecl;
// Didn't find one yet - now look through categories.
- for (ObjCInterfaceDecl::visible_categories_iterator
- Cat = ClassDecl->visible_categories_begin(),
- CatEnd = ClassDecl->visible_categories_end();
- Cat != CatEnd; ++Cat) {
+ for (const auto *Cat : ClassDecl->visible_categories()) {
if ((MethodDecl = Cat->getMethod(Sel, isInstance)))
- if (C != (*Cat) || !MethodDecl->isImplicit())
+ if (C != Cat || !MethodDecl->isImplicit())
return MethodDecl;
if (!shallowCategoryLookup) {
@@ -497,14 +579,18 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
E = Protocols.end(); I != E; ++I)
if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance)))
- if (C != (*Cat) || !MethodDecl->isImplicit())
+ if (C != Cat || !MethodDecl->isImplicit())
return MethodDecl;
}
}
-
+
+ if (!followSuper)
+ return nullptr;
+
+ // Get the super class (if any).
ClassDecl = ClassDecl->getSuperClass();
}
- return NULL;
+ return nullptr;
}
// Will search "local" class/category implementations for a method decl.
@@ -515,12 +601,12 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod(
bool Instance) const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
- return 0;
+ return nullptr;
if (data().ExternallyCompleted)
LoadExternalDefinition();
- ObjCMethodDecl *Method = 0;
+ ObjCMethodDecl *Method = nullptr;
if (ObjCImplementationDecl *ImpDecl = getImplementation())
Method = Instance ? ImpDecl->getInstanceMethod(Sel)
: ImpDecl->getClassMethod(Sel);
@@ -550,31 +636,38 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod(
// ObjCMethodDecl
//===----------------------------------------------------------------------===//
-ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C,
- SourceLocation beginLoc,
- SourceLocation endLoc,
- Selector SelInfo, QualType T,
- TypeSourceInfo *ResultTInfo,
- DeclContext *contextDecl,
- bool isInstance,
- bool isVariadic,
- bool isPropertyAccessor,
- bool isImplicitlyDeclared,
- bool isDefined,
- ImplementationControl impControl,
- bool HasRelatedResultType) {
- return new (C) ObjCMethodDecl(beginLoc, endLoc,
- SelInfo, T, ResultTInfo, contextDecl,
- isInstance, isVariadic, isPropertyAccessor,
- isImplicitlyDeclared, isDefined,
- impControl,
- HasRelatedResultType);
+ObjCMethodDecl *ObjCMethodDecl::Create(
+ ASTContext &C, SourceLocation beginLoc, SourceLocation endLoc,
+ Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo,
+ DeclContext *contextDecl, bool isInstance, bool isVariadic,
+ bool isPropertyAccessor, bool isImplicitlyDeclared, bool isDefined,
+ ImplementationControl impControl, bool HasRelatedResultType) {
+ return new (C, contextDecl) ObjCMethodDecl(
+ beginLoc, endLoc, SelInfo, T, ReturnTInfo, contextDecl, isInstance,
+ isVariadic, isPropertyAccessor, isImplicitlyDeclared, isDefined,
+ impControl, HasRelatedResultType);
}
ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCMethodDecl));
- return new (Mem) ObjCMethodDecl(SourceLocation(), SourceLocation(),
- Selector(), QualType(), 0, 0);
+ return new (C, ID) ObjCMethodDecl(SourceLocation(), SourceLocation(),
+ Selector(), QualType(), nullptr, nullptr);
+}
+
+bool ObjCMethodDecl::isThisDeclarationADesignatedInitializer() const {
+ return getMethodFamily() == OMF_init &&
+ hasAttr<ObjCDesignatedInitializerAttr>();
+}
+
+bool ObjCMethodDecl::isDesignatedInitializerForTheInterface(
+ const ObjCMethodDecl **InitMethod) const {
+ if (getMethodFamily() != OMF_init)
+ return false;
+ const DeclContext *DC = getDeclContext();
+ if (isa<ObjCProtocolDecl>(DC))
+ return false;
+ if (const ObjCInterfaceDecl *ID = getClassInterface())
+ return ID->isDesignatedInitializer(getSelector(), InitMethod);
+ return false;
}
Stmt *ObjCMethodDecl::getBody() const {
@@ -591,7 +684,7 @@ void ObjCMethodDecl::setAsRedeclaration(const ObjCMethodDecl *PrevMethod) {
void ObjCMethodDecl::setParamsAndSelLocs(ASTContext &C,
ArrayRef<ParmVarDecl*> Params,
ArrayRef<SourceLocation> SelLocs) {
- ParamsAndSelLocs = 0;
+ ParamsAndSelLocs = nullptr;
NumParams = Params.size();
if (Params.empty() && SelLocs.empty())
return;
@@ -628,9 +721,9 @@ void ObjCMethodDecl::setMethodParams(ASTContext &C,
/// \brief A definition will return its interface declaration.
/// An interface declaration will return its definition.
/// Otherwise it will return itself.
-ObjCMethodDecl *ObjCMethodDecl::getNextRedeclaration() {
+ObjCMethodDecl *ObjCMethodDecl::getNextRedeclarationImpl() {
ASTContext &Ctx = getASTContext();
- ObjCMethodDecl *Redecl = 0;
+ ObjCMethodDecl *Redecl = nullptr;
if (HasRedeclaration)
Redecl = const_cast<ObjCMethodDecl*>(Ctx.getObjCMethodRedeclaration(this));
if (Redecl)
@@ -730,7 +823,7 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
// init only has a conventional meaning for an instance method, and
// it has to return an object.
case OMF_init:
- if (!isInstanceMethod() || !getResultType()->isObjCObjectPointerType())
+ if (!isInstanceMethod() || !getReturnType()->isObjCObjectPointerType())
family = OMF_None;
break;
@@ -740,7 +833,7 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
case OMF_copy:
case OMF_mutableCopy:
case OMF_new:
- if (!getResultType()->isObjCObjectPointerType())
+ if (!getReturnType()->isObjCObjectPointerType())
family = OMF_None;
break;
@@ -757,15 +850,14 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
break;
case OMF_performSelector:
- if (!isInstanceMethod() ||
- !getResultType()->isObjCIdType())
+ if (!isInstanceMethod() || !getReturnType()->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();
+ ObjCMethodDecl::param_type_iterator it = param_type_begin();
QualType ArgT = (*it);
if (!ArgT->isObjCSelType()) {
family = OMF_None;
@@ -838,7 +930,7 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
setSelfDecl(self);
if (selfIsConsumed)
- self->addAttr(new (Context) NSConsumedAttr(SourceLocation(), Context));
+ self->addAttr(NSConsumedAttr::CreateImplicit(Context));
if (selfIsPseudoStrong)
self->setARCPseudoStrong(true);
@@ -855,8 +947,8 @@ ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() {
return CD->getClassInterface();
if (ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(getDeclContext()))
return IMD->getClassInterface();
-
- assert(!isa<ObjCProtocolDecl>(getDeclContext()) && "It's a protocol method");
+ if (isa<ObjCProtocolDecl>(getDeclContext()))
+ return nullptr;
llvm_unreachable("unknown method context");
}
@@ -886,10 +978,8 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
return;
}
- for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
- PEnd = Category->protocol_end();
- P != PEnd; ++P)
- CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper);
+ for (const auto *P : Category->protocols())
+ CollectOverriddenMethodsRecurse(P, Method, Methods, MovedToSuper);
return;
}
@@ -906,26 +996,17 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
}
if (const ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)){
- for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(),
- PEnd = Protocol->protocol_end();
- P != PEnd; ++P)
- CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper);
+ for (const auto *P : Protocol->protocols())
+ CollectOverriddenMethodsRecurse(P, Method, Methods, MovedToSuper);
}
if (const ObjCInterfaceDecl *
Interface = dyn_cast<ObjCInterfaceDecl>(Container)) {
- for (ObjCInterfaceDecl::protocol_iterator P = Interface->protocol_begin(),
- PEnd = Interface->protocol_end();
- P != PEnd; ++P)
- CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper);
-
- for (ObjCInterfaceDecl::known_categories_iterator
- Cat = Interface->known_categories_begin(),
- CatEnd = Interface->known_categories_end();
- Cat != CatEnd; ++Cat) {
- CollectOverriddenMethodsRecurse(*Cat, Method, Methods,
- MovedToSuper);
- }
+ for (const auto *P : Interface->protocols())
+ CollectOverriddenMethodsRecurse(P, Method, Methods, MovedToSuper);
+
+ for (const auto *Cat : Interface->known_categories())
+ CollectOverriddenMethodsRecurse(Cat, Method, Methods, MovedToSuper);
if (const ObjCInterfaceDecl *Super = Interface->getSuperClass())
return CollectOverriddenMethodsRecurse(Super, Method, Methods,
@@ -1002,11 +1083,11 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
Selector Sel = getSelector();
unsigned NumArgs = Sel.getNumArgs();
if (NumArgs > 1)
- return 0;
+ return nullptr;
if (!isInstanceMethod() || getMethodFamily() != OMF_None)
- return 0;
-
+ return nullptr;
+
if (isPropertyAccessor()) {
const ObjCContainerDecl *Container = cast<ObjCContainerDecl>(getParent());
// If container is class extension, find its primary class.
@@ -1016,20 +1097,18 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
bool IsGetter = (NumArgs == 0);
- for (ObjCContainerDecl::prop_iterator I = Container->prop_begin(),
- E = Container->prop_end();
- I != E; ++I) {
- Selector NextSel = IsGetter ? (*I)->getGetterName()
- : (*I)->getSetterName();
+ for (const auto *I : Container->properties()) {
+ Selector NextSel = IsGetter ? I->getGetterName()
+ : I->getSetterName();
if (NextSel == Sel)
- return *I;
+ return I;
}
llvm_unreachable("Marked as a property accessor but no property found!");
}
if (!CheckOverrides)
- return 0;
+ return nullptr;
typedef SmallVector<const ObjCMethodDecl *, 8> OverridesTy;
OverridesTy Overrides;
@@ -1040,8 +1119,7 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
return Prop;
}
- return 0;
-
+ return nullptr;
}
//===----------------------------------------------------------------------===//
@@ -1055,37 +1133,38 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C,
ObjCInterfaceDecl *PrevDecl,
SourceLocation ClassLoc,
bool isInternal){
- ObjCInterfaceDecl *Result = new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc,
- PrevDecl, isInternal);
+ ObjCInterfaceDecl *Result = new (C, DC)
+ ObjCInterfaceDecl(C, DC, atLoc, Id, ClassLoc, PrevDecl, isInternal);
Result->Data.setInt(!C.getLangOpts().Modules);
C.getObjCInterfaceType(Result, PrevDecl);
return Result;
}
-ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(ASTContext &C,
+ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCInterfaceDecl));
- ObjCInterfaceDecl *Result = new (Mem) ObjCInterfaceDecl(0, SourceLocation(),
- 0, SourceLocation(),
- 0, false);
+ ObjCInterfaceDecl *Result = new (C, ID) ObjCInterfaceDecl(C, nullptr,
+ SourceLocation(),
+ nullptr,
+ SourceLocation(),
+ nullptr, false);
Result->Data.setInt(!C.getLangOpts().Modules);
return Result;
}
-ObjCInterfaceDecl::
-ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
- SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl,
- bool isInternal)
- : ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, atLoc),
- TypeForDecl(0), Data()
-{
+ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC,
+ SourceLocation AtLoc, IdentifierInfo *Id,
+ SourceLocation CLoc,
+ ObjCInterfaceDecl *PrevDecl,
+ bool IsInternal)
+ : ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, AtLoc),
+ redeclarable_base(C), TypeForDecl(nullptr), Data() {
setPreviousDecl(PrevDecl);
// Copy the 'data' pointer over.
if (PrevDecl)
Data = PrevDecl->Data;
- setImplicit(isInternal);
+ setImplicit(IsInternal);
}
void ObjCInterfaceDecl::LoadExternalDefinition() const {
@@ -1103,6 +1182,40 @@ void ObjCInterfaceDecl::setExternallyCompleted() {
data().ExternallyCompleted = true;
}
+void ObjCInterfaceDecl::setHasDesignatedInitializers() {
+ // Check for a complete definition and recover if not so.
+ if (!isThisDeclarationADefinition())
+ return;
+ data().HasDesignatedInitializers = true;
+}
+
+bool ObjCInterfaceDecl::hasDesignatedInitializers() const {
+ // Check for a complete definition and recover if not so.
+ if (!isThisDeclarationADefinition())
+ return false;
+ if (data().ExternallyCompleted)
+ LoadExternalDefinition();
+
+ return data().HasDesignatedInitializers;
+}
+
+StringRef
+ObjCInterfaceDecl::getObjCRuntimeNameAsString() const {
+ if (ObjCRuntimeNameAttr *ObjCRTName = getAttr<ObjCRuntimeNameAttr>())
+ return ObjCRTName->getMetadataName();
+
+ return getName();
+}
+
+StringRef
+ObjCImplementationDecl::getObjCRuntimeNameAsString() const {
+ if (ObjCInterfaceDecl *ID =
+ const_cast<ObjCImplementationDecl*>(this)->getClassInterface())
+ return ID->getObjCRuntimeNameAsString();
+
+ return getName();
+}
+
ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const {
if (const ObjCInterfaceDecl *Def = getDefinition()) {
if (data().ExternallyCompleted)
@@ -1113,7 +1226,7 @@ ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const {
}
// FIXME: Should make sure no callers ever do this.
- return 0;
+ return nullptr;
}
void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) {
@@ -1146,9 +1259,9 @@ namespace {
ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
- return 0;
-
- ObjCIvarDecl *curIvar = 0;
+ return nullptr;
+
+ ObjCIvarDecl *curIvar = nullptr;
if (!data().IvarList) {
if (!ivar_empty()) {
ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end();
@@ -1157,10 +1270,7 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
curIvar->setNextIvar(*I);
}
- for (ObjCInterfaceDecl::known_extensions_iterator
- Ext = known_extensions_begin(),
- ExtEnd = known_extensions_end();
- Ext != ExtEnd; ++Ext) {
+ for (const auto *Ext : known_extensions()) {
if (!Ext->ivar_empty()) {
ObjCCategoryDecl::ivar_iterator
I = Ext->ivar_begin(),
@@ -1184,19 +1294,17 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
data().IvarListMissingImplementation = false;
if (!ImplDecl->ivar_empty()) {
SmallVector<SynthesizeIvarChunk, 16> layout;
- for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
- E = ImplDecl->ivar_end(); I != E; ++I) {
- ObjCIvarDecl *IV = *I;
+ for (auto *IV : ImplDecl->ivars()) {
if (IV->getSynthesize() && !IV->isInvalidDecl()) {
layout.push_back(SynthesizeIvarChunk(
IV->getASTContext().getTypeSize(IV->getType()), IV));
continue;
}
if (!data().IvarList)
- data().IvarList = *I;
+ data().IvarList = IV;
else
- curIvar->setNextIvar(*I);
- curIvar = *I;
+ curIvar->setNextIvar(IV);
+ curIvar = IV;
}
if (!layout.empty()) {
@@ -1223,47 +1331,37 @@ ObjCCategoryDecl *
ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
- return 0;
+ return nullptr;
if (data().ExternallyCompleted)
LoadExternalDefinition();
- for (visible_categories_iterator Cat = visible_categories_begin(),
- CatEnd = visible_categories_end();
- Cat != CatEnd;
- ++Cat) {
+ for (auto *Cat : visible_categories())
if (Cat->getIdentifier() == CategoryId)
- return *Cat;
- }
-
- return 0;
+ return Cat;
+
+ return nullptr;
}
ObjCMethodDecl *
ObjCInterfaceDecl::getCategoryInstanceMethod(Selector Sel) const {
- for (visible_categories_iterator Cat = visible_categories_begin(),
- CatEnd = visible_categories_end();
- Cat != CatEnd;
- ++Cat) {
+ for (const auto *Cat : visible_categories()) {
if (ObjCCategoryImplDecl *Impl = Cat->getImplementation())
if (ObjCMethodDecl *MD = Impl->getInstanceMethod(Sel))
return MD;
}
- return 0;
+ return nullptr;
}
ObjCMethodDecl *ObjCInterfaceDecl::getCategoryClassMethod(Selector Sel) const {
- for (visible_categories_iterator Cat = visible_categories_begin(),
- CatEnd = visible_categories_end();
- Cat != CatEnd;
- ++Cat) {
+ for (const auto *Cat : visible_categories()) {
if (ObjCCategoryImplDecl *Impl = Cat->getImplementation())
if (ObjCMethodDecl *MD = Impl->getClassMethod(Sel))
return MD;
}
-
- return 0;
+
+ return nullptr;
}
/// ClassImplementsProtocol - Checks that 'lProto' protocol
@@ -1277,9 +1375,8 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto,
ObjCInterfaceDecl *IDecl = this;
// 1st, look up the class.
- for (ObjCInterfaceDecl::protocol_iterator
- PI = IDecl->protocol_begin(), E = IDecl->protocol_end(); PI != E; ++PI){
- if (getASTContext().ProtocolCompatibleWithProtocol(lProto, *PI))
+ for (auto *PI : IDecl->protocols()){
+ if (getASTContext().ProtocolCompatibleWithProtocol(lProto, PI))
return true;
// This is dubious and is added to be compatible with gcc. In gcc, it is
// also allowed assigning a protocol-qualified 'id' type to a LHS object
@@ -1288,20 +1385,15 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto,
// FIXME: Treat this as an extension, and flag this as an error when GCC
// extensions are not enabled.
if (RHSIsQualifiedID &&
- getASTContext().ProtocolCompatibleWithProtocol(*PI, lProto))
+ getASTContext().ProtocolCompatibleWithProtocol(PI, lProto))
return true;
}
// 2nd, look up the category.
if (lookupCategory)
- for (visible_categories_iterator Cat = visible_categories_begin(),
- CatEnd = visible_categories_end();
- Cat != CatEnd;
- ++Cat) {
- for (ObjCCategoryDecl::protocol_iterator PI = Cat->protocol_begin(),
- E = Cat->protocol_end();
- PI != E; ++PI)
- if (getASTContext().ProtocolCompatibleWithProtocol(lProto, *PI))
+ for (const auto *Cat : visible_categories()) {
+ for (auto *PI : Cat->protocols())
+ if (getASTContext().ProtocolCompatibleWithProtocol(lProto, PI))
return true;
}
@@ -1325,8 +1417,7 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
AccessControl ac, Expr *BW,
- bool synthesized,
- bool backingIvarReferencedInAccessor) {
+ bool synthesized) {
if (DC) {
// Ivar's can only appear in interfaces, implementations (via synthesized
// properties), and class extensions (via direct declaration, or synthesized
@@ -1350,17 +1441,17 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC,
else
ID = cast<ObjCCategoryDecl>(DC)->getClassInterface();
}
- ID->setIvarList(0);
+ ID->setIvarList(nullptr);
}
- return new (C) ObjCIvarDecl(DC, StartLoc, IdLoc, Id, T, TInfo,
- ac, BW, synthesized, backingIvarReferencedInAccessor);
+ return new (C, DC) ObjCIvarDecl(DC, StartLoc, IdLoc, Id, T, TInfo, ac, BW,
+ synthesized);
}
ObjCIvarDecl *ObjCIvarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCIvarDecl));
- return new (Mem) ObjCIvarDecl(0, SourceLocation(), SourceLocation(), 0,
- QualType(), 0, ObjCIvarDecl::None, 0, false, false);
+ return new (C, ID) ObjCIvarDecl(nullptr, SourceLocation(), SourceLocation(),
+ nullptr, QualType(), nullptr,
+ ObjCIvarDecl::None, nullptr, false);
}
const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const {
@@ -1397,14 +1488,14 @@ ObjCAtDefsFieldDecl
*ObjCAtDefsFieldDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, QualType T, Expr *BW) {
- return new (C) ObjCAtDefsFieldDecl(DC, StartLoc, IdLoc, Id, T, BW);
+ return new (C, DC) ObjCAtDefsFieldDecl(DC, StartLoc, IdLoc, Id, T, BW);
}
-ObjCAtDefsFieldDecl *ObjCAtDefsFieldDecl::CreateDeserialized(ASTContext &C,
+ObjCAtDefsFieldDecl *ObjCAtDefsFieldDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCAtDefsFieldDecl));
- return new (Mem) ObjCAtDefsFieldDecl(0, SourceLocation(), SourceLocation(),
- 0, QualType(), 0);
+ return new (C, ID) ObjCAtDefsFieldDecl(nullptr, SourceLocation(),
+ SourceLocation(), nullptr, QualType(),
+ nullptr);
}
//===----------------------------------------------------------------------===//
@@ -1413,12 +1504,12 @@ ObjCAtDefsFieldDecl *ObjCAtDefsFieldDecl::CreateDeserialized(ASTContext &C,
void ObjCProtocolDecl::anchor() { }
-ObjCProtocolDecl::ObjCProtocolDecl(DeclContext *DC, IdentifierInfo *Id,
- SourceLocation nameLoc,
+ObjCProtocolDecl::ObjCProtocolDecl(ASTContext &C, DeclContext *DC,
+ IdentifierInfo *Id, SourceLocation nameLoc,
SourceLocation atStartLoc,
ObjCProtocolDecl *PrevDecl)
- : ObjCContainerDecl(ObjCProtocol, DC, Id, nameLoc, atStartLoc), Data()
-{
+ : ObjCContainerDecl(ObjCProtocol, DC, Id, nameLoc, atStartLoc),
+ redeclarable_base(C), Data() {
setPreviousDecl(PrevDecl);
if (PrevDecl)
Data = PrevDecl->Data;
@@ -1429,17 +1520,17 @@ ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation nameLoc,
SourceLocation atStartLoc,
ObjCProtocolDecl *PrevDecl) {
- ObjCProtocolDecl *Result
- = new (C) ObjCProtocolDecl(DC, Id, nameLoc, atStartLoc, PrevDecl);
+ ObjCProtocolDecl *Result =
+ new (C, DC) ObjCProtocolDecl(C, DC, Id, nameLoc, atStartLoc, PrevDecl);
Result->Data.setInt(!C.getLangOpts().Modules);
return Result;
}
-ObjCProtocolDecl *ObjCProtocolDecl::CreateDeserialized(ASTContext &C,
+ObjCProtocolDecl *ObjCProtocolDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCProtocolDecl));
- ObjCProtocolDecl *Result = new (Mem) ObjCProtocolDecl(0, 0, SourceLocation(),
- SourceLocation(), 0);
+ ObjCProtocolDecl *Result =
+ new (C, ID) ObjCProtocolDecl(C, nullptr, nullptr, SourceLocation(),
+ SourceLocation(), nullptr);
Result->Data.setInt(!C.getLangOpts().Modules);
return Result;
}
@@ -1450,32 +1541,32 @@ ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) {
if (Name == getIdentifier())
return PDecl;
- for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I)
- if ((PDecl = (*I)->lookupProtocolNamed(Name)))
+ for (auto *I : protocols())
+ if ((PDecl = I->lookupProtocolNamed(Name)))
return PDecl;
- return NULL;
+ return nullptr;
}
// lookupMethod - Lookup a instance/class method in the protocol and protocols
// it inherited.
ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel,
bool isInstance) const {
- ObjCMethodDecl *MethodDecl = NULL;
+ ObjCMethodDecl *MethodDecl = nullptr;
// If there is no definition or the definition is hidden, we don't find
// anything.
const ObjCProtocolDecl *Def = getDefinition();
if (!Def || Def->isHidden())
- return NULL;
+ return nullptr;
if ((MethodDecl = getMethod(Sel, isInstance)))
return MethodDecl;
- for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I)
- if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance)))
+ for (const auto *I : protocols())
+ if ((MethodDecl = I->lookupMethod(Sel, isInstance)))
return MethodDecl;
- return NULL;
+ return nullptr;
}
void ObjCProtocolDecl::allocateDefinitionData() {
@@ -1488,8 +1579,7 @@ void ObjCProtocolDecl::startDefinition() {
allocateDefinitionData();
// Update all of the declarations with a pointer to the definition.
- for (redecl_iterator RD = redecls_begin(), RDEnd = redecls_end();
- RD != RDEnd; ++RD)
+ for (auto RD : redecls())
RD->Data = this->Data;
}
@@ -1497,17 +1587,14 @@ void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM,
PropertyDeclOrder &PO) const {
if (const ObjCProtocolDecl *PDecl = getDefinition()) {
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
+ for (auto *Prop : PDecl->properties()) {
// Insert into PM if not there already.
PM.insert(std::make_pair(Prop->getIdentifier(), Prop));
PO.push_back(Prop);
}
// Scan through protocol's protocols.
- for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
- E = PDecl->protocol_end(); PI != E; ++PI)
- (*PI)->collectPropertiesToImplement(PM, PO);
+ for (const auto *PI : PDecl->protocols())
+ PI->collectPropertiesToImplement(PM, PO);
}
}
@@ -1517,9 +1604,7 @@ void ObjCProtocolDecl::collectInheritedProtocolProperties(
ProtocolPropertyMap &PM) const {
if (const ObjCProtocolDecl *PDecl = getDefinition()) {
bool MatchFound = false;
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
+ for (auto *Prop : PDecl->properties()) {
if (Prop == Property)
continue;
if (Prop->getIdentifier() == Property->getIdentifier()) {
@@ -1530,12 +1615,19 @@ void ObjCProtocolDecl::collectInheritedProtocolProperties(
}
// Scan through protocol's protocols which did not have a matching property.
if (!MatchFound)
- for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
- E = PDecl->protocol_end(); PI != E; ++PI)
- (*PI)->collectInheritedProtocolProperties(Property, PM);
+ for (const auto *PI : PDecl->protocols())
+ PI->collectInheritedProtocolProperties(Property, PM);
}
}
+StringRef
+ObjCProtocolDecl::getObjCRuntimeNameAsString() const {
+ if (ObjCRuntimeNameAttr *ObjCRTName = getAttr<ObjCRuntimeNameAttr>())
+ return ObjCRTName->getMetadataName();
+
+ return getName();
+}
+
//===----------------------------------------------------------------------===//
// ObjCCategoryDecl
//===----------------------------------------------------------------------===//
@@ -1543,17 +1635,16 @@ void ObjCProtocolDecl::collectInheritedProtocolProperties(
void ObjCCategoryDecl::anchor() { }
ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation AtLoc,
+ SourceLocation AtLoc,
SourceLocation ClassNameLoc,
SourceLocation CategoryNameLoc,
IdentifierInfo *Id,
ObjCInterfaceDecl *IDecl,
SourceLocation IvarLBraceLoc,
SourceLocation IvarRBraceLoc) {
- ObjCCategoryDecl *CatDecl = new (C) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc,
- CategoryNameLoc, Id,
- IDecl,
- IvarLBraceLoc, IvarRBraceLoc);
+ ObjCCategoryDecl *CatDecl =
+ new (C, DC) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id,
+ IDecl, IvarLBraceLoc, IvarRBraceLoc);
if (IDecl) {
// Link this category into its class's category list.
CatDecl->NextClassCategory = IDecl->getCategoryListRaw();
@@ -1567,11 +1658,11 @@ ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
return CatDecl;
}
-ObjCCategoryDecl *ObjCCategoryDecl::CreateDeserialized(ASTContext &C,
+ObjCCategoryDecl *ObjCCategoryDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCCategoryDecl));
- return new (Mem) ObjCCategoryDecl(0, SourceLocation(), SourceLocation(),
- SourceLocation(), 0, 0);
+ return new (C, ID) ObjCCategoryDecl(nullptr, SourceLocation(),
+ SourceLocation(), SourceLocation(),
+ nullptr, nullptr);
}
ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const {
@@ -1599,22 +1690,22 @@ ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation CategoryNameLoc) {
if (ClassInterface && ClassInterface->hasDefinition())
ClassInterface = ClassInterface->getDefinition();
- return new (C) ObjCCategoryImplDecl(DC, Id, ClassInterface,
- nameLoc, atStartLoc, CategoryNameLoc);
+ return new (C, DC) ObjCCategoryImplDecl(DC, Id, ClassInterface, nameLoc,
+ atStartLoc, CategoryNameLoc);
}
ObjCCategoryImplDecl *ObjCCategoryImplDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCCategoryImplDecl));
- return new (Mem) ObjCCategoryImplDecl(0, 0, 0, SourceLocation(),
- SourceLocation(), SourceLocation());
+ return new (C, ID) ObjCCategoryImplDecl(nullptr, nullptr, nullptr,
+ SourceLocation(), SourceLocation(),
+ SourceLocation());
}
ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryDecl() const {
// The class interface might be NULL if we are working with invalid code.
if (const ObjCInterfaceDecl *ID = getClassInterface())
return ID->FindCategoryDeclaration(getIdentifier());
- return 0;
+ return nullptr;
}
@@ -1649,13 +1740,11 @@ void ObjCImplDecl::setClassInterface(ObjCInterfaceDecl *IFace) {
///
ObjCPropertyImplDecl *ObjCImplDecl::
FindPropertyImplIvarDecl(IdentifierInfo *ivarId) const {
- for (propimpl_iterator i = propimpl_begin(), e = propimpl_end(); i != e; ++i){
- ObjCPropertyImplDecl *PID = *i;
+ for (auto *PID : property_impls())
if (PID->getPropertyIvarDecl() &&
PID->getPropertyIvarDecl()->getIdentifier() == ivarId)
return PID;
- }
- return 0;
+ return nullptr;
}
/// FindPropertyImplDecl - This method looks up a previous ObjCPropertyImplDecl
@@ -1664,12 +1753,10 @@ FindPropertyImplIvarDecl(IdentifierInfo *ivarId) const {
///
ObjCPropertyImplDecl *ObjCImplDecl::
FindPropertyImplDecl(IdentifierInfo *Id) const {
- for (propimpl_iterator i = propimpl_begin(), e = propimpl_end(); i != e; ++i){
- ObjCPropertyImplDecl *PID = *i;
+ for (auto *PID : property_impls())
if (PID->getPropertyDecl()->getIdentifier() == Id)
return PID;
- }
- return 0;
+ return nullptr;
}
raw_ostream &clang::operator<<(raw_ostream &OS,
@@ -1695,16 +1782,15 @@ ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation IvarRBraceLoc) {
if (ClassInterface && ClassInterface->hasDefinition())
ClassInterface = ClassInterface->getDefinition();
- return new (C) ObjCImplementationDecl(DC, ClassInterface, SuperDecl,
- nameLoc, atStartLoc, superLoc,
- IvarLBraceLoc, IvarRBraceLoc);
+ return new (C, DC) ObjCImplementationDecl(DC, ClassInterface, SuperDecl,
+ nameLoc, atStartLoc, superLoc,
+ IvarLBraceLoc, IvarRBraceLoc);
}
ObjCImplementationDecl *
ObjCImplementationDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCImplementationDecl));
- return new (Mem) ObjCImplementationDecl(0, 0, 0, SourceLocation(),
- SourceLocation());
+ return new (C, ID) ObjCImplementationDecl(nullptr, nullptr, nullptr,
+ SourceLocation(), SourceLocation());
}
void ObjCImplementationDecl::setIvarInitializers(ASTContext &C,
@@ -1737,13 +1823,13 @@ ObjCCompatibleAliasDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
IdentifierInfo *Id,
ObjCInterfaceDecl* AliasedClass) {
- return new (C) ObjCCompatibleAliasDecl(DC, L, Id, AliasedClass);
+ return new (C, DC) ObjCCompatibleAliasDecl(DC, L, Id, AliasedClass);
}
ObjCCompatibleAliasDecl *
ObjCCompatibleAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCCompatibleAliasDecl));
- return new (Mem) ObjCCompatibleAliasDecl(0, SourceLocation(), 0, 0);
+ return new (C, ID) ObjCCompatibleAliasDecl(nullptr, SourceLocation(),
+ nullptr, nullptr);
}
//===----------------------------------------------------------------------===//
@@ -1759,15 +1845,14 @@ ObjCPropertyDecl *ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation LParenLoc,
TypeSourceInfo *T,
PropertyControl propControl) {
- return new (C) ObjCPropertyDecl(DC, L, Id, AtLoc, LParenLoc, T);
+ return new (C, DC) ObjCPropertyDecl(DC, L, Id, AtLoc, LParenLoc, T);
}
-ObjCPropertyDecl *ObjCPropertyDecl::CreateDeserialized(ASTContext &C,
+ObjCPropertyDecl *ObjCPropertyDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void * Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCPropertyDecl));
- return new (Mem) ObjCPropertyDecl(0, SourceLocation(), 0, SourceLocation(),
- SourceLocation(),
- 0);
+ return new (C, ID) ObjCPropertyDecl(nullptr, SourceLocation(), nullptr,
+ SourceLocation(), SourceLocation(),
+ nullptr);
}
//===----------------------------------------------------------------------===//
@@ -1782,15 +1867,15 @@ ObjCPropertyImplDecl *ObjCPropertyImplDecl::Create(ASTContext &C,
Kind PK,
ObjCIvarDecl *ivar,
SourceLocation ivarLoc) {
- return new (C) ObjCPropertyImplDecl(DC, atLoc, L, property, PK, ivar,
- ivarLoc);
+ return new (C, DC) ObjCPropertyImplDecl(DC, atLoc, L, property, PK, ivar,
+ ivarLoc);
}
-ObjCPropertyImplDecl *ObjCPropertyImplDecl::CreateDeserialized(ASTContext &C,
+ObjCPropertyImplDecl *ObjCPropertyImplDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCPropertyImplDecl));
- return new (Mem) ObjCPropertyImplDecl(0, SourceLocation(), SourceLocation(),
- 0, Dynamic, 0, SourceLocation());
+ return new (C, ID) ObjCPropertyImplDecl(nullptr, SourceLocation(),
+ SourceLocation(), nullptr, Dynamic,
+ nullptr, SourceLocation());
}
SourceRange ObjCPropertyImplDecl::getSourceRange() const {
diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp
index 0d195f74623d..5f8b42b3f964 100644
--- a/lib/AST/DeclOpenMP.cpp
+++ b/lib/AST/DeclOpenMP.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclBase.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/Expr.h"
@@ -29,12 +29,8 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
ArrayRef<Expr *> VL) {
- unsigned Size = sizeof(OMPThreadPrivateDecl) +
- (VL.size() * sizeof(Expr *));
-
- void *Mem = C.Allocate(Size, llvm::alignOf<OMPThreadPrivateDecl>());
- OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
- DC, L);
+ OMPThreadPrivateDecl *D = new (C, DC, VL.size() * sizeof(Expr *))
+ OMPThreadPrivateDecl(OMPThreadPrivate, DC, L);
D->NumVars = VL.size();
D->setVars(VL);
return D;
@@ -43,11 +39,8 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C,
unsigned ID,
unsigned N) {
- unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(Expr *));
-
- void *Mem = AllocateDeserializedDecl(C, ID, Size);
- OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
- 0, SourceLocation());
+ OMPThreadPrivateDecl *D = new (C, ID, N * sizeof(Expr *))
+ OMPThreadPrivateDecl(OMPThreadPrivate, nullptr, SourceLocation());
D->NumVars = N;
return D;
}
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 767f6620a295..e5e5130f695a 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -85,7 +85,7 @@ namespace {
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
void PrintTemplateParameters(const TemplateParameterList *Params,
- const TemplateArgumentList *Args = 0);
+ const TemplateArgumentList *Args = nullptr);
void prettyPrintAttributes(Decl *D);
};
}
@@ -114,7 +114,7 @@ static QualType GetBaseType(QualType T) {
else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType))
BaseType = ATy->getElementType();
else if (const FunctionType* FTy = BaseType->getAs<FunctionType>())
- BaseType = FTy->getResultType();
+ BaseType = FTy->getReturnType();
else if (const VectorType *VTy = BaseType->getAs<VectorType>())
BaseType = VTy->getElementType();
else if (const ReferenceType *RTy = BaseType->getAs<ReferenceType>())
@@ -167,7 +167,7 @@ void Decl::printGroup(Decl** Begin, unsigned NumDecls,
}
}
-void DeclContext::dumpDeclContext() const {
+LLVM_DUMP_METHOD void DeclContext::dumpDeclContext() const {
// Get the translation unit
const DeclContext *DC = this;
while (!DC->isTranslationUnit())
@@ -238,17 +238,6 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
if (D->isImplicit())
continue;
- // FIXME: Ugly hack so we don't pretty-print the builtin declaration
- // of __builtin_va_list or __[u]int128_t. There should be some other way
- // to check that.
- if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) {
- if (IdentifierInfo *II = ND->getIdentifier()) {
- if (II->isStr("__builtin_va_list") ||
- II->isStr("__int128_t") || II->isStr("__uint128_t"))
- continue;
- }
- }
-
// The next bits of code handles stuff like "struct {int x;} a,b"; we're
// forced to merge the declarations because there's no other way to
// refer to the struct in question. This limited merging is safe without
@@ -293,21 +282,21 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
Visit(*D);
// FIXME: Need to be able to tell the DeclPrinter when
- const char *Terminator = 0;
+ const char *Terminator = nullptr;
if (isa<OMPThreadPrivateDecl>(*D))
- Terminator = 0;
+ Terminator = nullptr;
else if (isa<FunctionDecl>(*D) &&
cast<FunctionDecl>(*D)->isThisDeclarationADefinition())
- Terminator = 0;
+ Terminator = nullptr;
else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->getBody())
- Terminator = 0;
+ Terminator = nullptr;
else if (isa<NamespaceDecl>(*D) || isa<LinkageSpecDecl>(*D) ||
isa<ObjCImplementationDecl>(*D) ||
isa<ObjCInterfaceDecl>(*D) ||
isa<ObjCProtocolDecl>(*D) ||
isa<ObjCCategoryImplDecl>(*D) ||
isa<ObjCCategoryDecl>(*D))
- Terminator = 0;
+ Terminator = nullptr;
else if (isa<EnumConstantDecl>(*D)) {
DeclContext::decl_iterator Next = D;
++Next;
@@ -390,12 +379,13 @@ void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) {
Out << *D;
if (Expr *Init = D->getInitExpr()) {
Out << " = ";
- Init->printPretty(Out, 0, Policy, Indentation);
+ Init->printPretty(Out, nullptr, Policy, Indentation);
}
}
void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
+ CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D);
if (!Policy.SuppressSpecifiers) {
switch (D->getStorageClass()) {
case SC_None: break;
@@ -409,7 +399,9 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->isInlineSpecified()) Out << "inline ";
if (D->isVirtualAsWritten()) Out << "virtual ";
if (D->isModulePrivate()) Out << "__module_private__ ";
- if (CDecl && CDecl->isExplicitSpecified())
+ if (D->isConstexpr() && !D->isExplicitlyDefaulted()) Out << "constexpr ";
+ if ((CDecl && CDecl->isExplicitSpecified()) ||
+ (ConversionDecl && ConversionDecl->isExplicit()))
Out << "explicit ";
}
@@ -423,9 +415,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Ty = PT->getInnerType();
}
- if (isa<FunctionType>(Ty)) {
- const FunctionType *AFT = Ty->getAs<FunctionType>();
- const FunctionProtoType *FT = 0;
+ if (const FunctionType *AFT = Ty->getAs<FunctionType>()) {
+ const FunctionProtoType *FT = nullptr;
if (D->hasWrittenPrototype())
FT = dyn_cast<FunctionProtoType>(AFT);
@@ -459,6 +450,17 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Proto += " volatile";
if (FT->isRestrict())
Proto += " restrict";
+
+ switch (FT->getRefQualifier()) {
+ case RQ_None:
+ break;
+ case RQ_LValue:
+ Proto += " &";
+ break;
+ case RQ_RValue:
+ Proto += " &&";
+ break;
+ }
}
if (FT && FT->hasDynamicExceptionSpec()) {
@@ -478,7 +480,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (FT->getExceptionSpecType() == EST_ComputedNoexcept) {
Proto += "(";
llvm::raw_string_ostream EOut(Proto);
- FT->getNoexceptExpr()->printPretty(EOut, 0, SubPolicy,
+ FT->getNoexceptExpr()->printPretty(EOut, nullptr, SubPolicy,
Indentation);
EOut.flush();
Proto += EOut.str();
@@ -488,10 +490,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (CDecl) {
bool HasInitializerList = false;
- for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
- E = CDecl->init_end();
- B != E; ++B) {
- CXXCtorInitializer *BMInitializer = (*B);
+ for (const auto *BMInitializer : CDecl->inits()) {
if (BMInitializer->isInClassMemberInitializer())
continue;
@@ -519,9 +518,9 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Init = Tmp->getSubExpr();
Init = Init->IgnoreParens();
-
- Expr *SimpleInit = 0;
- Expr **Args = 0;
+
+ Expr *SimpleInit = nullptr;
+ Expr **Args = nullptr;
unsigned NumArgs = 0;
if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
Args = ParenList->getExprs();
@@ -534,29 +533,32 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
SimpleInit = Init;
if (SimpleInit)
- SimpleInit->printPretty(Out, 0, Policy, Indentation);
+ SimpleInit->printPretty(Out, nullptr, Policy, Indentation);
else {
for (unsigned I = 0; I != NumArgs; ++I) {
+ assert(Args[I] != nullptr && "Expected non-null Expr");
if (isa<CXXDefaultArgExpr>(Args[I]))
break;
if (I)
Out << ", ";
- Args[I]->printPretty(Out, 0, Policy, Indentation);
+ Args[I]->printPretty(Out, nullptr, Policy, Indentation);
}
}
}
Out << ")";
+ if (BMInitializer->isPackExpansion())
+ Out << "...";
}
- if (!Proto.empty())
- Out << Proto;
- } else {
+ } else if (!ConversionDecl && !isa<CXXDestructorDecl>(D)) {
if (FT && FT->hasTrailingReturn()) {
Out << "auto " << Proto << " -> ";
Proto.clear();
}
- AFT->getResultType().print(Out, Policy, Proto);
+ AFT->getReturnType().print(Out, Policy, Proto);
+ Proto.clear();
}
+ Out << Proto;
} else {
Ty.print(Out, Policy, Proto);
}
@@ -585,7 +587,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
} else
Out << ' ';
- D->getBody()->printPretty(Out, 0, SubPolicy, Indentation);
+ if (D->getBody())
+ D->getBody()->printPretty(Out, nullptr, SubPolicy, Indentation);
Out << '\n';
}
}
@@ -626,7 +629,7 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
if (D->isBitField()) {
Out << " : ";
- D->getBitWidth()->printPretty(Out, 0, Policy, Indentation);
+ D->getBitWidth()->printPretty(Out, nullptr, Policy, Indentation);
}
Expr *Init = D->getInClassInitializer();
@@ -635,7 +638,7 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
Out << " ";
else
Out << " = ";
- Init->printPretty(Out, 0, Policy, Indentation);
+ Init->printPretty(Out, nullptr, Policy, Indentation);
}
prettyPrintAttributes(D);
}
@@ -690,7 +693,7 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
else if (D->getInitStyle() == VarDecl::CInit) {
Out << " = ";
}
- Init->printPretty(Out, 0, Policy, Indentation);
+ Init->printPretty(Out, nullptr, Policy, Indentation);
if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init))
Out << ")";
}
@@ -704,7 +707,7 @@ void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) {
void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
Out << "__asm (";
- D->getAsmString()->printPretty(Out, 0, Policy, Indentation);
+ D->getAsmString()->printPretty(Out, nullptr, Policy, Indentation);
Out << ")";
}
@@ -715,9 +718,9 @@ void DeclPrinter::VisitImportDecl(ImportDecl *D) {
void DeclPrinter::VisitStaticAssertDecl(StaticAssertDecl *D) {
Out << "static_assert(";
- D->getAssertExpr()->printPretty(Out, 0, Policy, Indentation);
+ D->getAssertExpr()->printPretty(Out, nullptr, Policy, Indentation);
Out << ", ";
- D->getMessage()->printPretty(Out, 0, Policy, Indentation);
+ D->getMessage()->printPretty(Out, nullptr, Policy, Indentation);
Out << ")";
}
@@ -855,7 +858,8 @@ void DeclPrinter::PrintTemplateParameters(const TemplateParameterList *Params,
Args->get(i).print(Policy, Out);
} else if (NTTP->hasDefaultArgument()) {
Out << " = ";
- NTTP->getDefaultArgument()->printPretty(Out, 0, Policy, Indentation);
+ NTTP->getDefaultArgument()->printPretty(Out, nullptr, Policy,
+ Indentation);
}
} else if (const TemplateTemplateParmDecl *TTPD =
dyn_cast<TemplateTemplateParmDecl>(Param)) {
@@ -884,10 +888,9 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
void DeclPrinter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
if (PrintInstantiation) {
TemplateParameterList *Params = D->getTemplateParameters();
- for (FunctionTemplateDecl::spec_iterator I = D->spec_begin(), E = D->spec_end();
- I != E; ++I) {
- PrintTemplateParameters(Params, (*I)->getTemplateSpecializationArgs());
- Visit(*I);
+ for (auto *I : D->specializations()) {
+ PrintTemplateParameters(Params, I->getTemplateSpecializationArgs());
+ Visit(I);
}
}
@@ -897,10 +900,9 @@ void DeclPrinter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
void DeclPrinter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (PrintInstantiation) {
TemplateParameterList *Params = D->getTemplateParameters();
- for (ClassTemplateDecl::spec_iterator I = D->spec_begin(), E = D->spec_end();
- I != E; ++I) {
- PrintTemplateParameters(Params, &(*I)->getTemplateArgs());
- Visit(*I);
+ for (auto *I : D->specializations()) {
+ PrintTemplateParameters(Params, &I->getTemplateArgs());
+ Visit(I);
Out << '\n';
}
}
@@ -917,19 +919,19 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
Out << "- ";
else
Out << "+ ";
- if (!OMD->getResultType().isNull())
- Out << '(' << OMD->getASTContext().getUnqualifiedObjCPointerType(OMD->getResultType()).
- getAsString(Policy) << ")";
+ if (!OMD->getReturnType().isNull())
+ Out << '(' << OMD->getASTContext()
+ .getUnqualifiedObjCPointerType(OMD->getReturnType())
+ .getAsString(Policy) << ")";
std::string name = OMD->getSelector().getAsString();
std::string::size_type pos, lastPos = 0;
- for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(),
- E = OMD->param_end(); PI != E; ++PI) {
+ for (const auto *PI : OMD->params()) {
// FIXME: selector is missing here!
pos = name.find_first_of(':', lastPos);
Out << " " << name.substr(lastPos, pos - lastPos);
- Out << ":(" << (*PI)->getASTContext().getUnqualifiedObjCPointerType((*PI)->getType()).
- getAsString(Policy) << ')' << **PI;
+ Out << ":(" << PI->getASTContext().getUnqualifiedObjCPointerType(PI->getType()).
+ getAsString(Policy) << ')' << *PI;
lastPos = pos + 1;
}
@@ -941,7 +943,7 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
if (OMD->getBody() && !Policy.TerseOutput) {
Out << ' ';
- OMD->getBody()->printPretty(Out, 0, Policy);
+ OMD->getBody()->printPretty(Out, nullptr, Policy);
Out << '\n';
}
else if (Policy.PolishForDeclaration)
@@ -960,10 +962,9 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
if (OID->ivar_size() > 0) {
Out << "{\n";
Indentation += Policy.Indentation;
- for (ObjCImplementationDecl::ivar_iterator I = OID->ivar_begin(),
- E = OID->ivar_end(); I != E; ++I) {
+ for (const auto *I : OID->ivars()) {
Indent() << I->getASTContext().getUnqualifiedObjCPointerType(I->getType()).
- getAsString(Policy) << ' ' << **I << ";\n";
+ getAsString(Policy) << ' ' << *I << ";\n";
}
Indentation -= Policy.Indentation;
Out << "}\n";
@@ -999,10 +1000,10 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
Out << "{\n";
eolnOut = true;
Indentation += Policy.Indentation;
- for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(),
- E = OID->ivar_end(); I != E; ++I) {
- Indent() << I->getASTContext().getUnqualifiedObjCPointerType(I->getType()).
- getAsString(Policy) << ' ' << **I << ";\n";
+ for (const auto *I : OID->ivars()) {
+ Indent() << I->getASTContext()
+ .getUnqualifiedObjCPointerType(I->getType())
+ .getAsString(Policy) << ' ' << *I << ";\n";
}
Indentation -= Policy.Indentation;
Out << "}\n";
@@ -1051,11 +1052,9 @@ void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
if (PID->ivar_size() > 0) {
Out << "{\n";
Indentation += Policy.Indentation;
- for (ObjCCategoryDecl::ivar_iterator I = PID->ivar_begin(),
- E = PID->ivar_end(); I != E; ++I) {
+ for (const auto *I : PID->ivars())
Indent() << I->getASTContext().getUnqualifiedObjCPointerType(I->getType()).
- getAsString(Policy) << ' ' << **I << ";\n";
- }
+ getAsString(Policy) << ' ' << *I << ";\n";
Indentation -= Policy.Indentation;
Out << "}\n";
}
@@ -1090,13 +1089,13 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
}
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) {
- Out << (first ? ' ' : ',') << "getter = "
- << PDecl->getGetterName().getAsString();
+ Out << (first ? ' ' : ',') << "getter = ";
+ PDecl->getGetterName().print(Out);
first = false;
}
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) {
- Out << (first ? ' ' : ',') << "setter = "
- << PDecl->getSetterName().getAsString();
+ Out << (first ? ' ' : ',') << "setter = ";
+ PDecl->getSetterName().print(Out);
first = false;
}
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 7172fb7b487f..0d1d2a4613dc 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -164,13 +164,13 @@ template <class EntryType>
typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType*
RedeclarableTemplateDecl::findSpecializationImpl(
llvm::FoldingSetVector<EntryType> &Specs,
- const TemplateArgument *Args, unsigned NumArgs,
+ ArrayRef<TemplateArgument> Args,
void *&InsertPos) {
typedef SpecEntryTraits<EntryType> SETraits;
llvm::FoldingSetNodeID ID;
- EntryType::Profile(ID,Args,NumArgs, getASTContext());
+ EntryType::Profile(ID,Args, getASTContext());
EntryType *Entry = Specs.FindNodeOrInsertPos(ID, InsertPos);
- return Entry ? SETraits::getMostRecentDecl(Entry) : 0;
+ return Entry ? SETraits::getMostRecentDecl(Entry) : nullptr;
}
/// \brief Generate the injected template arguments for the given template
@@ -229,14 +229,13 @@ FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C,
TemplateParameterList *Params,
NamedDecl *Decl) {
AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
- return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl);
+ return new (C, DC) FunctionTemplateDecl(C, DC, L, Name, Params, Decl);
}
FunctionTemplateDecl *FunctionTemplateDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FunctionTemplateDecl));
- return new (Mem) FunctionTemplateDecl(0, SourceLocation(), DeclarationName(),
- 0, 0);
+ return new (C, ID) FunctionTemplateDecl(C, nullptr, SourceLocation(),
+ DeclarationName(), nullptr, nullptr);
}
RedeclarableTemplateDecl::CommonBase *
@@ -251,7 +250,7 @@ void FunctionTemplateDecl::LoadLazySpecializations() const {
if (CommonPtr->LazySpecializations) {
ASTContext &Context = getASTContext();
uint32_t *Specs = CommonPtr->LazySpecializations;
- CommonPtr->LazySpecializations = 0;
+ CommonPtr->LazySpecializations = nullptr;
for (uint32_t I = 0, N = *Specs++; I != N; ++I)
(void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
}
@@ -264,9 +263,9 @@ FunctionTemplateDecl::getSpecializations() const {
}
FunctionDecl *
-FunctionTemplateDecl::findSpecialization(const TemplateArgument *Args,
- unsigned NumArgs, void *&InsertPos) {
- return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos);
+FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
+ void *&InsertPos) {
+ return findSpecializationImpl(getSpecializations(), Args, InsertPos);
}
void FunctionTemplateDecl::addSpecialization(
@@ -308,15 +307,16 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
NamedDecl *Decl,
ClassTemplateDecl *PrevDecl) {
AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
- ClassTemplateDecl *New = new (C) ClassTemplateDecl(DC, L, Name, Params, Decl);
+ ClassTemplateDecl *New = new (C, DC) ClassTemplateDecl(C, DC, L, Name,
+ Params, Decl);
New->setPreviousDecl(PrevDecl);
return New;
}
-ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
+ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ClassTemplateDecl));
- return new (Mem) ClassTemplateDecl(EmptyShell());
+ return new (C, ID) ClassTemplateDecl(C, nullptr, SourceLocation(),
+ DeclarationName(), nullptr, nullptr);
}
void ClassTemplateDecl::LoadLazySpecializations() const {
@@ -324,7 +324,7 @@ void ClassTemplateDecl::LoadLazySpecializations() const {
if (CommonPtr->LazySpecializations) {
ASTContext &Context = getASTContext();
uint32_t *Specs = CommonPtr->LazySpecializations;
- CommonPtr->LazySpecializations = 0;
+ CommonPtr->LazySpecializations = nullptr;
for (uint32_t I = 0, N = *Specs++; I != N; ++I)
(void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
}
@@ -350,9 +350,9 @@ ClassTemplateDecl::newCommon(ASTContext &C) const {
}
ClassTemplateSpecializationDecl *
-ClassTemplateDecl::findSpecialization(const TemplateArgument *Args,
- unsigned NumArgs, void *&InsertPos) {
- return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos);
+ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
+ void *&InsertPos) {
+ return findSpecializationImpl(getSpecializations(), Args, InsertPos);
}
void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
@@ -370,11 +370,9 @@ void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
}
ClassTemplatePartialSpecializationDecl *
-ClassTemplateDecl::findPartialSpecialization(const TemplateArgument *Args,
- unsigned NumArgs,
+ClassTemplateDecl::findPartialSpecialization(ArrayRef<TemplateArgument> Args,
void *&InsertPos) {
- return findSpecializationImpl(getPartialSpecializations(), Args, NumArgs,
- InsertPos);
+ return findSpecializationImpl(getPartialSpecializations(), Args, InsertPos);
}
void ClassTemplateDecl::AddPartialSpecialization(
@@ -418,7 +416,7 @@ ClassTemplateDecl::findPartialSpecialization(QualType T) {
return P->getMostRecentDecl();
}
- return 0;
+ return nullptr;
}
ClassTemplatePartialSpecializationDecl *
@@ -433,7 +431,7 @@ ClassTemplateDecl::findPartialSpecInstantiatedFromMember(
return P->getMostRecentDecl();
}
- return 0;
+ return nullptr;
}
QualType
@@ -471,17 +469,16 @@ TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC,
unsigned D, unsigned P, IdentifierInfo *Id,
bool Typename, bool ParameterPack) {
TemplateTypeParmDecl *TTPDecl =
- new (C) TemplateTypeParmDecl(DC, KeyLoc, NameLoc, Id, Typename);
+ new (C, DC) TemplateTypeParmDecl(DC, KeyLoc, NameLoc, Id, Typename);
QualType TTPType = C.getTemplateTypeParmType(D, P, ParameterPack, TTPDecl);
- TTPDecl->TypeForDecl = TTPType.getTypePtr();
+ TTPDecl->setTypeForDecl(TTPType.getTypePtr());
return TTPDecl;
}
TemplateTypeParmDecl *
TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TemplateTypeParmDecl));
- return new (Mem) TemplateTypeParmDecl(0, SourceLocation(), SourceLocation(),
- 0, false);
+ return new (C, ID) TemplateTypeParmDecl(nullptr, SourceLocation(),
+ SourceLocation(), nullptr, false);
}
SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const {
@@ -499,15 +496,15 @@ SourceRange TemplateTypeParmDecl::getSourceRange() const {
}
unsigned TemplateTypeParmDecl::getDepth() const {
- return TypeForDecl->getAs<TemplateTypeParmType>()->getDepth();
+ return getTypeForDecl()->getAs<TemplateTypeParmType>()->getDepth();
}
unsigned TemplateTypeParmDecl::getIndex() const {
- return TypeForDecl->getAs<TemplateTypeParmType>()->getIndex();
+ return getTypeForDecl()->getAs<TemplateTypeParmType>()->getIndex();
}
bool TemplateTypeParmDecl::isParameterPack() const {
- return TypeForDecl->getAs<TemplateTypeParmType>()->isParameterPack();
+ return getTypeForDecl()->getAs<TemplateTypeParmType>()->isParameterPack();
}
//===----------------------------------------------------------------------===//
@@ -525,7 +522,7 @@ NonTypeTemplateParmDecl::NonTypeTemplateParmDecl(DeclContext *DC,
unsigned NumExpandedTypes,
TypeSourceInfo **ExpandedTInfos)
: DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc),
- TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false),
+ TemplateParmPosition(D, P), DefaultArgumentAndInherited(nullptr, false),
ParameterPack(true), ExpandedParameterPack(true),
NumExpandedTypes(NumExpandedTypes)
{
@@ -544,8 +541,8 @@ NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
unsigned D, unsigned P, IdentifierInfo *Id,
QualType T, bool ParameterPack,
TypeSourceInfo *TInfo) {
- return new (C) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id,
- T, ParameterPack, TInfo);
+ return new (C, DC) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id,
+ T, ParameterPack, TInfo);
}
NonTypeTemplateParmDecl *
@@ -557,34 +554,26 @@ NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
const QualType *ExpandedTypes,
unsigned NumExpandedTypes,
TypeSourceInfo **ExpandedTInfos) {
- unsigned Size = sizeof(NonTypeTemplateParmDecl)
- + NumExpandedTypes * 2 * sizeof(void*);
- void *Mem = C.Allocate(Size);
- return new (Mem) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc,
- D, P, Id, T, TInfo,
- ExpandedTypes, NumExpandedTypes,
- ExpandedTInfos);
+ unsigned Extra = NumExpandedTypes * 2 * sizeof(void*);
+ return new (C, DC, Extra) NonTypeTemplateParmDecl(
+ DC, StartLoc, IdLoc, D, P, Id, T, TInfo,
+ ExpandedTypes, NumExpandedTypes, ExpandedTInfos);
}
NonTypeTemplateParmDecl *
NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(NonTypeTemplateParmDecl));
- return new (Mem) NonTypeTemplateParmDecl(0, SourceLocation(),
- SourceLocation(), 0, 0, 0,
- QualType(), false, 0);
+ return new (C, ID) NonTypeTemplateParmDecl(nullptr, SourceLocation(),
+ SourceLocation(), 0, 0, nullptr,
+ QualType(), false, nullptr);
}
NonTypeTemplateParmDecl *
NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
unsigned NumExpandedTypes) {
- unsigned Size = sizeof(NonTypeTemplateParmDecl)
- + NumExpandedTypes * 2 * sizeof(void*);
-
- void *Mem = AllocateDeserializedDecl(C, ID, Size);
- return new (Mem) NonTypeTemplateParmDecl(0, SourceLocation(),
- SourceLocation(), 0, 0, 0,
- QualType(), 0, 0, NumExpandedTypes,
- 0);
+ unsigned Extra = NumExpandedTypes * 2 * sizeof(void*);
+ return new (C, ID, Extra) NonTypeTemplateParmDecl(
+ nullptr, SourceLocation(), SourceLocation(), 0, 0, nullptr, QualType(),
+ nullptr, nullptr, NumExpandedTypes, nullptr);
}
SourceRange NonTypeTemplateParmDecl::getSourceRange() const {
@@ -624,8 +613,8 @@ TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
bool ParameterPack, IdentifierInfo *Id,
TemplateParameterList *Params) {
- return new (C) TemplateTemplateParmDecl(DC, L, D, P, ParameterPack, Id,
- Params);
+ return new (C, DC) TemplateTemplateParmDecl(DC, L, D, P, ParameterPack, Id,
+ Params);
}
TemplateTemplateParmDecl *
@@ -634,28 +623,23 @@ TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
IdentifierInfo *Id,
TemplateParameterList *Params,
ArrayRef<TemplateParameterList *> Expansions) {
- void *Mem = C.Allocate(sizeof(TemplateTemplateParmDecl) +
- sizeof(TemplateParameterList*) * Expansions.size());
- return new (Mem) TemplateTemplateParmDecl(DC, L, D, P, Id, Params,
- Expansions.size(),
- Expansions.data());
+ return new (C, DC, sizeof(TemplateParameterList*) * Expansions.size())
+ TemplateTemplateParmDecl(DC, L, D, P, Id, Params,
+ Expansions.size(), Expansions.data());
}
TemplateTemplateParmDecl *
TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TemplateTemplateParmDecl));
- return new (Mem) TemplateTemplateParmDecl(0, SourceLocation(), 0, 0, false,
- 0, 0);
+ return new (C, ID) TemplateTemplateParmDecl(nullptr, SourceLocation(), 0, 0,
+ false, nullptr, nullptr);
}
TemplateTemplateParmDecl *
TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
unsigned NumExpansions) {
- unsigned Size = sizeof(TemplateTemplateParmDecl) +
- sizeof(TemplateParameterList*) * NumExpansions;
- void *Mem = AllocateDeserializedDecl(C, ID, Size);
- return new (Mem) TemplateTemplateParmDecl(0, SourceLocation(), 0, 0, 0, 0,
- NumExpansions, 0);
+ return new (C, ID, sizeof(TemplateParameterList*) * NumExpansions)
+ TemplateTemplateParmDecl(nullptr, SourceLocation(), 0, 0, nullptr,
+ nullptr, NumExpansions, nullptr);
}
//===----------------------------------------------------------------------===//
@@ -682,7 +666,7 @@ FunctionTemplateSpecializationInfo::Create(ASTContext &C, FunctionDecl *FD,
const TemplateArgumentList *TemplateArgs,
const TemplateArgumentListInfo *TemplateArgsAsWritten,
SourceLocation POI) {
- const ASTTemplateArgumentListInfo *ArgsAsWritten = 0;
+ const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
if (TemplateArgsAsWritten)
ArgsAsWritten = ASTTemplateArgumentListInfo::Create(C,
*TemplateArgsAsWritten);
@@ -710,20 +694,20 @@ ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK,
const TemplateArgument *Args,
unsigned NumArgs,
ClassTemplateSpecializationDecl *PrevDecl)
- : CXXRecordDecl(DK, TK, DC, StartLoc, IdLoc,
+ : CXXRecordDecl(DK, TK, Context, DC, StartLoc, IdLoc,
SpecializedTemplate->getIdentifier(),
PrevDecl),
SpecializedTemplate(SpecializedTemplate),
- ExplicitInfo(0),
+ ExplicitInfo(nullptr),
TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args, NumArgs)),
SpecializationKind(TSK_Undeclared) {
}
-ClassTemplateSpecializationDecl::ClassTemplateSpecializationDecl(Kind DK)
- : CXXRecordDecl(DK, TTK_Struct, 0, SourceLocation(), SourceLocation(), 0, 0),
- ExplicitInfo(0),
- SpecializationKind(TSK_Undeclared) {
-}
+ClassTemplateSpecializationDecl::ClassTemplateSpecializationDecl(ASTContext &C,
+ Kind DK)
+ : CXXRecordDecl(DK, TTK_Struct, C, nullptr, SourceLocation(),
+ SourceLocation(), nullptr, nullptr),
+ ExplicitInfo(nullptr), SpecializationKind(TSK_Undeclared) {}
ClassTemplateSpecializationDecl *
ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
@@ -734,13 +718,10 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
const TemplateArgument *Args,
unsigned NumArgs,
ClassTemplateSpecializationDecl *PrevDecl) {
- ClassTemplateSpecializationDecl *Result
- = new (Context)ClassTemplateSpecializationDecl(Context,
- ClassTemplateSpecialization,
- TK, DC, StartLoc, IdLoc,
- SpecializedTemplate,
- Args, NumArgs,
- PrevDecl);
+ ClassTemplateSpecializationDecl *Result =
+ new (Context, DC) ClassTemplateSpecializationDecl(
+ Context, ClassTemplateSpecialization, TK, DC, StartLoc, IdLoc,
+ SpecializedTemplate, Args, NumArgs, PrevDecl);
Result->MayHaveOutOfDateDef = false;
Context.getTypeDeclType(Result, PrevDecl);
@@ -748,12 +729,10 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
}
ClassTemplateSpecializationDecl *
-ClassTemplateSpecializationDecl::CreateDeserialized(ASTContext &C,
+ClassTemplateSpecializationDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID,
- sizeof(ClassTemplateSpecializationDecl));
ClassTemplateSpecializationDecl *Result =
- new (Mem) ClassTemplateSpecializationDecl(ClassTemplateSpecialization);
+ new (C, ID) ClassTemplateSpecializationDecl(C, ClassTemplateSpecialization);
Result->MayHaveOutOfDateDef = false;
return Result;
}
@@ -797,7 +776,7 @@ ClassTemplateSpecializationDecl::getSourceRange() const {
typedef ClassTemplatePartialSpecializationDecl CTPSDecl;
CTPSDecl *ctpsd = const_cast<CTPSDecl*>(cast<CTPSDecl>(this));
CTPSDecl *inst_from = ctpsd->getInstantiatedFromMember();
- assert(inst_from != 0);
+ assert(inst_from != nullptr);
return inst_from->getSourceRange();
}
else {
@@ -836,7 +815,7 @@ ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK,
SpecializedTemplate,
Args, NumArgs, PrevDecl),
TemplateParams(Params), ArgsAsWritten(ArgInfos),
- InstantiatedFromMember(0, false)
+ InstantiatedFromMember(nullptr, false)
{
AdoptTemplateParameterList(Params, this);
}
@@ -855,14 +834,10 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC,
const ASTTemplateArgumentListInfo *ASTArgInfos =
ASTTemplateArgumentListInfo::Create(Context, ArgInfos);
- ClassTemplatePartialSpecializationDecl *Result
- = new (Context)ClassTemplatePartialSpecializationDecl(Context, TK, DC,
- StartLoc, IdLoc,
- Params,
- SpecializedTemplate,
- Args, NumArgs,
- ASTArgInfos,
- PrevDecl);
+ ClassTemplatePartialSpecializationDecl *Result = new (Context, DC)
+ ClassTemplatePartialSpecializationDecl(Context, TK, DC, StartLoc, IdLoc,
+ Params, SpecializedTemplate, Args,
+ NumArgs, ASTArgInfos, PrevDecl);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
Result->MayHaveOutOfDateDef = false;
@@ -873,10 +848,8 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC,
ClassTemplatePartialSpecializationDecl *
ClassTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID,
- sizeof(ClassTemplatePartialSpecializationDecl));
- ClassTemplatePartialSpecializationDecl *Result
- = new (Mem) ClassTemplatePartialSpecializationDecl();
+ ClassTemplatePartialSpecializationDecl *Result =
+ new (C, ID) ClassTemplatePartialSpecializationDecl(C);
Result->MayHaveOutOfDateDef = false;
return Result;
}
@@ -894,15 +867,13 @@ FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context,
TemplateParameterList **Params,
FriendUnion Friend,
SourceLocation FLoc) {
- FriendTemplateDecl *Result
- = new (Context) FriendTemplateDecl(DC, L, NParams, Params, Friend, FLoc);
- return Result;
+ return new (Context, DC) FriendTemplateDecl(DC, L, NParams, Params,
+ Friend, FLoc);
}
FriendTemplateDecl *FriendTemplateDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FriendTemplateDecl));
- return new (Mem) FriendTemplateDecl(EmptyShell());
+ return new (C, ID) FriendTemplateDecl(EmptyShell());
}
//===----------------------------------------------------------------------===//
@@ -916,14 +887,13 @@ TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C,
TemplateParameterList *Params,
NamedDecl *Decl) {
AdoptTemplateParameterList(Params, DC);
- return new (C) TypeAliasTemplateDecl(DC, L, Name, Params, Decl);
+ return new (C, DC) TypeAliasTemplateDecl(C, DC, L, Name, Params, Decl);
}
TypeAliasTemplateDecl *TypeAliasTemplateDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TypeAliasTemplateDecl));
- return new (Mem) TypeAliasTemplateDecl(0, SourceLocation(), DeclarationName(),
- 0, 0);
+ return new (C, ID) TypeAliasTemplateDecl(C, nullptr, SourceLocation(),
+ DeclarationName(), nullptr, nullptr);
}
void TypeAliasTemplateDecl::DeallocateCommon(void *Ptr) {
@@ -945,10 +915,8 @@ void ClassScopeFunctionSpecializationDecl::anchor() { }
ClassScopeFunctionSpecializationDecl *
ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID,
- sizeof(ClassScopeFunctionSpecializationDecl));
- return new (Mem) ClassScopeFunctionSpecializationDecl(0, SourceLocation(), 0,
- false, TemplateArgumentListInfo());
+ return new (C, ID) ClassScopeFunctionSpecializationDecl(
+ nullptr, SourceLocation(), nullptr, false, TemplateArgumentListInfo());
}
//===----------------------------------------------------------------------===//
@@ -966,33 +934,30 @@ VarTemplateDecl *VarTemplateDecl::getDefinition() {
return CurD;
CurD = CurD->getPreviousDecl();
}
- return 0;
+ return nullptr;
}
VarTemplateDecl *VarTemplateDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, DeclarationName Name,
TemplateParameterList *Params,
- NamedDecl *Decl,
- VarTemplateDecl *PrevDecl) {
- VarTemplateDecl *New = new (C) VarTemplateDecl(DC, L, Name, Params, Decl);
- New->setPreviousDecl(PrevDecl);
- return New;
+ VarDecl *Decl) {
+ return new (C, DC) VarTemplateDecl(C, DC, L, Name, Params, Decl);
}
VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(VarTemplateDecl));
- return new (Mem) VarTemplateDecl(EmptyShell());
+ return new (C, ID) VarTemplateDecl(C, nullptr, SourceLocation(),
+ DeclarationName(), nullptr, nullptr);
}
-// TODO: Unify accross class, function and variable templates?
+// TODO: Unify across class, function and variable templates?
// May require moving this and Common to RedeclarableTemplateDecl.
void VarTemplateDecl::LoadLazySpecializations() const {
Common *CommonPtr = getCommonPtr();
if (CommonPtr->LazySpecializations) {
ASTContext &Context = getASTContext();
uint32_t *Specs = CommonPtr->LazySpecializations;
- CommonPtr->LazySpecializations = 0;
+ CommonPtr->LazySpecializations = nullptr;
for (uint32_t I = 0, N = *Specs++; I != N; ++I)
(void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
}
@@ -1018,9 +983,9 @@ VarTemplateDecl::newCommon(ASTContext &C) const {
}
VarTemplateSpecializationDecl *
-VarTemplateDecl::findSpecialization(const TemplateArgument *Args,
- unsigned NumArgs, void *&InsertPos) {
- return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos);
+VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
+ void *&InsertPos) {
+ return findSpecializationImpl(getSpecializations(), Args, InsertPos);
}
void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
@@ -1038,10 +1003,9 @@ void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
}
VarTemplatePartialSpecializationDecl *
-VarTemplateDecl::findPartialSpecialization(const TemplateArgument *Args,
- unsigned NumArgs, void *&InsertPos) {
- return findSpecializationImpl(getPartialSpecializations(), Args, NumArgs,
- InsertPos);
+VarTemplateDecl::findPartialSpecialization(ArrayRef<TemplateArgument> Args,
+ void *&InsertPos) {
+ return findSpecializationImpl(getPartialSpecializations(), Args, InsertPos);
}
void VarTemplateDecl::AddPartialSpecialization(
@@ -1084,47 +1048,43 @@ VarTemplateDecl::findPartialSpecInstantiatedFromMember(
return P->getMostRecentDecl();
}
- return 0;
+ return nullptr;
}
//===----------------------------------------------------------------------===//
// VarTemplateSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(
- ASTContext &Context, Kind DK, DeclContext *DC, SourceLocation StartLoc,
+ Kind DK, ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T,
TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args,
unsigned NumArgs)
- : VarDecl(DK, DC, StartLoc, IdLoc, SpecializedTemplate->getIdentifier(), T,
- TInfo, S),
- SpecializedTemplate(SpecializedTemplate), ExplicitInfo(0),
+ : VarDecl(DK, Context, DC, StartLoc, IdLoc,
+ SpecializedTemplate->getIdentifier(), T, TInfo, S),
+ SpecializedTemplate(SpecializedTemplate), ExplicitInfo(nullptr),
TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args, NumArgs)),
SpecializationKind(TSK_Undeclared) {}
-VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(Kind DK)
- : VarDecl(DK, 0, SourceLocation(), SourceLocation(), 0, QualType(), 0,
- SC_None),
- ExplicitInfo(0), SpecializationKind(TSK_Undeclared) {}
+VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(Kind DK,
+ ASTContext &C)
+ : VarDecl(DK, C, nullptr, SourceLocation(), SourceLocation(), nullptr,
+ QualType(), nullptr, SC_None),
+ ExplicitInfo(nullptr), SpecializationKind(TSK_Undeclared) {}
VarTemplateSpecializationDecl *VarTemplateSpecializationDecl::Create(
ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T,
TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args,
unsigned NumArgs) {
- VarTemplateSpecializationDecl *Result = new (Context)
- VarTemplateSpecializationDecl(Context, VarTemplateSpecialization, DC,
- StartLoc, IdLoc, SpecializedTemplate, T,
- TInfo, S, Args, NumArgs);
- return Result;
+ return new (Context, DC) VarTemplateSpecializationDecl(
+ VarTemplateSpecialization, Context, DC, StartLoc, IdLoc,
+ SpecializedTemplate, T, TInfo, S, Args, NumArgs);
}
VarTemplateSpecializationDecl *
VarTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem =
- AllocateDeserializedDecl(C, ID, sizeof(VarTemplateSpecializationDecl));
- VarTemplateSpecializationDecl *Result =
- new (Mem) VarTemplateSpecializationDecl(VarTemplateSpecialization);
- return Result;
+ return new (C, ID)
+ VarTemplateSpecializationDecl(VarTemplateSpecialization, C);
}
void VarTemplateSpecializationDecl::getNameForDiagnostic(
@@ -1163,11 +1123,11 @@ VarTemplatePartialSpecializationDecl::VarTemplatePartialSpecializationDecl(
VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
StorageClass S, const TemplateArgument *Args, unsigned NumArgs,
const ASTTemplateArgumentListInfo *ArgInfos)
- : VarTemplateSpecializationDecl(Context, VarTemplatePartialSpecialization,
+ : VarTemplateSpecializationDecl(VarTemplatePartialSpecialization, Context,
DC, StartLoc, IdLoc, SpecializedTemplate, T,
TInfo, S, Args, NumArgs),
TemplateParams(Params), ArgsAsWritten(ArgInfos),
- InstantiatedFromMember(0, false) {
+ InstantiatedFromMember(nullptr, false) {
// TODO: The template parameters should be in DC by now. Verify.
// AdoptTemplateParameterList(Params, DC);
}
@@ -1183,7 +1143,7 @@ VarTemplatePartialSpecializationDecl::Create(
= ASTTemplateArgumentListInfo::Create(Context, ArgInfos);
VarTemplatePartialSpecializationDecl *Result =
- new (Context) VarTemplatePartialSpecializationDecl(
+ new (Context, DC) VarTemplatePartialSpecializationDecl(
Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo,
S, Args, NumArgs, ASTArgInfos);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
@@ -1193,9 +1153,5 @@ VarTemplatePartialSpecializationDecl::Create(
VarTemplatePartialSpecializationDecl *
VarTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- void *Mem = AllocateDeserializedDecl(
- C, ID, sizeof(VarTemplatePartialSpecializationDecl));
- VarTemplatePartialSpecializationDecl *Result =
- new (Mem) VarTemplatePartialSpecializationDecl();
- return Result;
+ return new (C, ID) VarTemplatePartialSpecializationDecl(C);
}
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index e064e23a0ae9..b7c287720027 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -143,13 +143,16 @@ raw_ostream &operator<<(raw_ostream &OS, DeclarationName N) {
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
- return OS << N.getObjCSelector().getAsString();
+ N.getObjCSelector().print(OS);
+ return OS;
case DeclarationName::CXXConstructorName: {
QualType ClassType = N.getCXXNameType();
if (const RecordType *ClassRec = ClassType->getAs<RecordType>())
return OS << *ClassRec->getDecl();
- return OS << ClassType.getAsString();
+ LangOptions LO;
+ LO.CPlusPlus = true;
+ return OS << ClassType.getAsString(PrintingPolicy(LO));
}
case DeclarationName::CXXDestructorName: {
@@ -157,12 +160,14 @@ raw_ostream &operator<<(raw_ostream &OS, DeclarationName N) {
QualType Type = N.getCXXNameType();
if (const RecordType *Rec = Type->getAs<RecordType>())
return OS << *Rec->getDecl();
- return OS << Type.getAsString();
+ LangOptions LO;
+ LO.CPlusPlus = true;
+ return OS << Type.getAsString(PrintingPolicy(LO));
}
case DeclarationName::CXXOperatorName: {
static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = {
- 0,
+ nullptr,
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
Spelling,
#include "clang/Basic/OperatorKinds.def"
@@ -184,7 +189,10 @@ raw_ostream &operator<<(raw_ostream &OS, DeclarationName N) {
QualType Type = N.getCXXNameType();
if (const RecordType *Rec = Type->getAs<RecordType>())
return OS << *Rec->getDecl();
- return OS << Type.getAsString();
+ LangOptions LO;
+ LO.CPlusPlus = true;
+ LO.Bool = true;
+ return OS << Type.getAsString(PrintingPolicy(LO));
}
case DeclarationName::CXXUsingDirective:
return OS << "<using-directive>";
@@ -265,7 +273,7 @@ IdentifierInfo *DeclarationName::getCXXLiteralIdentifier() const {
if (CXXLiteralOperatorIdName *CXXLit = getAsCXXLiteralOperatorIdName())
return CXXLit->ID;
else
- return 0;
+ return nullptr;
}
void *DeclarationName::getFETokenInfoAsVoidSlow() const {
@@ -338,7 +346,7 @@ DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) {
for (unsigned Op = 0; Op < NUM_OVERLOADED_OPERATORS; ++Op) {
CXXOperatorNames[Op].ExtraKindOrNumArgs
= Op + DeclarationNameExtra::CXXConversionFunction;
- CXXOperatorNames[Op].FETokenInfo = 0;
+ CXXOperatorNames[Op].FETokenInfo = nullptr;
}
}
@@ -399,14 +407,14 @@ DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind,
ID.AddInteger(EKind);
ID.AddPointer(Ty.getAsOpaquePtr());
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (CXXSpecialName *Name = SpecialNames->FindNodeOrInsertPos(ID, InsertPos))
return DeclarationName(Name);
CXXSpecialName *SpecialName = new (Ctx) CXXSpecialName;
SpecialName->ExtraKindOrNumArgs = EKind;
SpecialName->Type = Ty;
- SpecialName->FETokenInfo = 0;
+ SpecialName->FETokenInfo = nullptr;
SpecialNames->InsertNode(SpecialName, InsertPos);
return DeclarationName(SpecialName);
@@ -426,7 +434,7 @@ DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) {
llvm::FoldingSetNodeID ID;
ID.AddPointer(II);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (CXXLiteralOperatorIdName *Name =
LiteralNames->FindNodeOrInsertPos(ID, InsertPos))
return DeclarationName (Name);
@@ -434,7 +442,7 @@ DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) {
CXXLiteralOperatorIdName *LiteralName = new (Ctx) CXXLiteralOperatorIdName;
LiteralName->ExtraKindOrNumArgs = DeclarationNameExtra::CXXLiteralOperator;
LiteralName->ID = II;
- LiteralName->FETokenInfo = 0;
+ LiteralName->FETokenInfo = nullptr;
LiteralNames->InsertNode(LiteralName, InsertPos);
return DeclarationName(LiteralName);
@@ -447,7 +455,7 @@ DeclarationNameLoc::DeclarationNameLoc(DeclarationName Name) {
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
- NamedType.TInfo = 0;
+ NamedType.TInfo = nullptr;
break;
case DeclarationName::CXXOperatorName:
CXXOperatorName.BeginOpNameLoc = SourceLocation().getRawEncoding();
@@ -537,7 +545,10 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const {
OS << '~';
else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
OS << "operator ";
- OS << TInfo->getType().getAsString();
+ LangOptions LO;
+ LO.CPlusPlus = true;
+ LO.Bool = true;
+ OS << TInfo->getType().getAsString(PrintingPolicy(LO));
} else
OS << Name;
return;
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 9055ddac35e3..5f559b7e5ce3 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -44,7 +44,7 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const {
DerivedType = PTy->getPointeeType();
if (DerivedType->isDependentType())
- return NULL;
+ return nullptr;
const RecordType *Ty = DerivedType->castAs<RecordType>();
Decl *D = Ty->getDecl();
@@ -105,37 +105,6 @@ const Expr *Expr::skipRValueSubobjectAdjustments(
return E;
}
-const Expr *
-Expr::findMaterializedTemporary(const MaterializeTemporaryExpr *&MTE) const {
- const Expr *E = this;
-
- // This might be a default initializer for a reference member. Walk over the
- // wrapper node for that.
- if (const CXXDefaultInitExpr *DAE = dyn_cast<CXXDefaultInitExpr>(E))
- E = DAE->getExpr();
-
- // Look through single-element init lists that claim to be lvalues. They're
- // just syntactic wrappers in this case.
- if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) {
- if (ILE->getNumInits() == 1 && ILE->isGLValue()) {
- E = ILE->getInit(0);
- if (const CXXDefaultInitExpr *DAE = dyn_cast<CXXDefaultInitExpr>(E))
- E = DAE->getExpr();
- }
- }
-
- // Look through expressions for materialized temporaries (for now).
- if (const MaterializeTemporaryExpr *M
- = dyn_cast<MaterializeTemporaryExpr>(E)) {
- MTE = M;
- E = M->GetTemporaryExpr();
- }
-
- if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E))
- E = DAE->getExpr();
- return E;
-}
-
/// isKnownToHaveBooleanValue - Return true if this is an integer expression
/// that is known to return 0 or 1. This happens for _Bool/bool expressions
/// but also int expressions which are produced by things like comparisons in
@@ -152,6 +121,8 @@ bool Expr::isKnownToHaveBooleanValue() const {
switch (UO->getOpcode()) {
case UO_Plus:
return UO->getSubExpr()->isKnownToHaveBooleanValue();
+ case UO_LNot:
+ return true;
default:
return false;
}
@@ -431,7 +402,7 @@ DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
const TemplateArgumentListInfo *TemplateArgs) {
// Filter out cases where the found Decl is the same as the value refenenced.
if (D == FoundD)
- FoundD = 0;
+ FoundD = nullptr;
std::size_t Size = sizeof(DeclRefExpr);
if (QualifierLoc)
@@ -484,7 +455,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
if (IT == PredefinedExpr::FuncDName) {
if (const NamedDecl *ND = dyn_cast<NamedDecl>(CurrentDecl)) {
- OwningPtr<MangleContext> MC;
+ std::unique_ptr<MangleContext> MC;
MC.reset(Context.createMangleContext());
if (MC->shouldMangleDeclName(ND)) {
@@ -507,7 +478,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
return "";
}
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
- if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual)
+ if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual && IT != FuncSig)
return FD->getNameAsString();
SmallString<256> Name;
@@ -523,16 +494,28 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
PrintingPolicy Policy(Context.getLangOpts());
std::string Proto;
llvm::raw_string_ostream POut(Proto);
- FD->printQualifiedName(POut, Policy);
const FunctionDecl *Decl = FD;
if (const FunctionDecl* Pattern = FD->getTemplateInstantiationPattern())
Decl = Pattern;
const FunctionType *AFT = Decl->getType()->getAs<FunctionType>();
- const FunctionProtoType *FT = 0;
+ const FunctionProtoType *FT = nullptr;
if (FD->hasWrittenPrototype())
FT = dyn_cast<FunctionProtoType>(AFT);
+ if (IT == FuncSig) {
+ switch (FT->getCallConv()) {
+ case CC_C: POut << "__cdecl "; break;
+ case CC_X86StdCall: POut << "__stdcall "; break;
+ case CC_X86FastCall: POut << "__fastcall "; break;
+ case CC_X86ThisCall: POut << "__thiscall "; break;
+ // Only bother printing the conventions that MSVC knows about.
+ default: break;
+ }
+ }
+
+ FD->printQualifiedName(POut, Policy);
+
POut << "(";
if (FT) {
for (unsigned i = 0, e = Decl->getNumParams(); i != e; ++i) {
@@ -619,13 +602,15 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
// not a constructor or destructor.
if ((isa<CXXMethodDecl>(FD) &&
cast<CXXMethodDecl>(FD)->getParent()->isLambda()) ||
- (FT && FT->getResultType()->getAs<AutoType>()))
+ (FT && FT->getReturnType()->getAs<AutoType>()))
Proto = "auto " + Proto;
- else if (FT && FT->getResultType()->getAs<DecltypeType>())
- FT->getResultType()->getAs<DecltypeType>()->getUnderlyingType()
+ else if (FT && FT->getReturnType()->getAs<DecltypeType>())
+ FT->getReturnType()
+ ->getAs<DecltypeType>()
+ ->getUnderlyingType()
.getAsStringInternal(Proto, Policy);
else if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD))
- AFT->getResultType().getAsStringInternal(Proto, Policy);
+ AFT->getReturnType().getAsStringInternal(Proto, Policy);
Out << Proto;
@@ -658,7 +643,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
Out << '(' << *CID << ')';
Out << ' ';
- Out << MD->getSelector().getAsString();
+ MD->getSelector().print(Out);
Out << ']';
Out.flush();
@@ -810,6 +795,9 @@ StringLiteral *StringLiteral::Create(const ASTContext &C, StringRef Str,
StringKind Kind, bool Pascal, QualType Ty,
const SourceLocation *Loc,
unsigned NumStrs) {
+ assert(C.getAsConstantArrayType(Ty) &&
+ "StringLiteral must be of constant array type!");
+
// Allocate enough space for the StringLiteral plus an array of locations for
// any concatenated string tokens.
void *Mem = C.Allocate(sizeof(StringLiteral)+
@@ -1010,7 +998,7 @@ getLocationOfByte(unsigned ByteNo, const SourceManager &SM,
TheLexer.LexFromRawLexer(TheTok);
// Use the StringLiteralParser to compute the length of the string in bytes.
- StringLiteralParser SLP(&TheTok, 1, SM, Features, Target);
+ StringLiteralParser SLP(TheTok, SM, Features, Target);
unsigned TokNumBytes = SLP.GetStringLength();
// If the byte is in this token, return the location of the byte.
@@ -1144,7 +1132,7 @@ CallExpr::CallExpr(const ASTContext& C, Expr *fn, ArrayRef<Expr*> args,
}
CallExpr::CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty)
- : Expr(SC, Empty), SubExprs(0), NumArgs(0) {
+ : Expr(SC, Empty), SubExprs(nullptr), NumArgs(0) {
// FIXME: Why do we allocate this?
SubExprs = new (C) Stmt*[PREARGS_START];
CallExprBits.NumPreArgs = 0;
@@ -1152,7 +1140,7 @@ CallExpr::CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty)
CallExpr::CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs,
EmptyShell Empty)
- : Expr(SC, Empty), SubExprs(0), NumArgs(0) {
+ : Expr(SC, Empty), SubExprs(nullptr), NumArgs(0) {
// FIXME: Why do we allocate this?
SubExprs = new (C) Stmt*[PREARGS_START+NumPreArgs];
CallExprBits.NumPreArgs = NumPreArgs;
@@ -1179,7 +1167,7 @@ Decl *CallExpr::getCalleeDecl() {
if (MemberExpr *ME = dyn_cast<MemberExpr>(CEE))
return ME->getMemberDecl();
- return 0;
+ return nullptr;
}
FunctionDecl *CallExpr::getDirectCallee() {
@@ -1208,16 +1196,16 @@ void CallExpr::setNumArgs(const ASTContext& C, unsigned NumArgs) {
// Null out new args.
for (unsigned i = getNumArgs()+PREARGS_START+NumPreArgs;
i != NumArgs+PREARGS_START+NumPreArgs; ++i)
- NewSubExprs[i] = 0;
+ NewSubExprs[i] = nullptr;
if (SubExprs) C.Deallocate(SubExprs);
SubExprs = NewSubExprs;
this->NumArgs = NumArgs;
}
-/// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If
+/// getBuiltinCallee - If this is a call to a builtin, return the builtin ID. If
/// not, return 0.
-unsigned CallExpr::isBuiltinCall() const {
+unsigned CallExpr::getBuiltinCallee() const {
// All simple function calls (e.g. func()) are implicitly cast to pointer to
// function. As a result, we try and obtain the DeclRefExpr from the
// ImplicitCastExpr.
@@ -1240,7 +1228,7 @@ unsigned CallExpr::isBuiltinCall() const {
}
bool CallExpr::isUnevaluatedBuiltinCall(ASTContext &Ctx) const {
- if (unsigned BI = isBuiltinCall())
+ if (unsigned BI = getBuiltinCallee())
return Ctx.BuiltinInfo.isUnevaluated(BI);
return false;
}
@@ -1256,7 +1244,7 @@ QualType CallExpr::getCallReturnType() const {
CalleeType = Expr::findBoundMemberType(getCallee());
const FunctionType *FnType = CalleeType->castAs<FunctionType>();
- return FnType->getResultType();
+ return FnType->getReturnType();
}
SourceLocation CallExpr::getLocStart() const {
@@ -1421,7 +1409,7 @@ SourceLocation MemberExpr::getLocEnd() const {
return EndLoc;
}
-void CastExpr::CheckCastConsistency() const {
+bool CastExpr::CastConsistency() const {
switch (getCastKind()) {
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
@@ -1474,6 +1462,11 @@ void CastExpr::CheckCastConsistency() const {
assert(getSubExpr()->getType()->isFunctionType());
goto CheckNoBasePath;
+ case CK_AddressSpaceConversion:
+ assert(getType()->isPointerType());
+ assert(getSubExpr()->getType()->isPointerType());
+ assert(getType()->getPointeeType().getAddressSpace() !=
+ getSubExpr()->getType()->getPointeeType().getAddressSpace());
// These should not have an inheritance path.
case CK_Dynamic:
case CK_ToUnion:
@@ -1524,6 +1517,7 @@ void CastExpr::CheckCastConsistency() const {
assert(path_empty() && "Cast kind should not have a base path!");
break;
}
+ return true;
}
const char *CastExpr::getCastKindName() const {
@@ -1625,7 +1619,7 @@ const char *CastExpr::getCastKindName() const {
case CK_ARCReclaimReturnedObject:
return "ARCReclaimReturnedObject";
case CK_ARCExtendBlockObject:
- return "ARCCExtendBlockObject";
+ return "ARCExtendBlockObject";
case CK_AtomicToNonAtomic:
return "AtomicToNonAtomic";
case CK_NonAtomicToAtomic:
@@ -1636,13 +1630,15 @@ const char *CastExpr::getCastKindName() const {
return "BuiltinFnToFnPtr";
case CK_ZeroToOCLEvent:
return "ZeroToOCLEvent";
+ case CK_AddressSpaceConversion:
+ return "AddressSpaceConversion";
}
llvm_unreachable("Unhandled cast kind!");
}
Expr *CastExpr::getSubExprAsWritten() {
- Expr *SubExpr = 0;
+ Expr *SubExpr = nullptr;
CastExpr *E = this;
do {
SubExpr = E->getSubExpr();
@@ -1838,7 +1834,7 @@ InitListExpr::InitListExpr(const ASTContext &C, SourceLocation lbraceloc,
: Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false,
false, false),
InitExprs(C, initExprs.size()),
- LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(0, true)
+ LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(nullptr, true)
{
sawArrayRangeDesignator(false);
for (unsigned I = 0; I != initExprs.size(); ++I) {
@@ -1861,18 +1857,18 @@ void InitListExpr::reserveInits(const ASTContext &C, unsigned NumInits) {
}
void InitListExpr::resizeInits(const ASTContext &C, unsigned NumInits) {
- InitExprs.resize(C, NumInits, 0);
+ InitExprs.resize(C, NumInits, nullptr);
}
Expr *InitListExpr::updateInit(const ASTContext &C, unsigned Init, Expr *expr) {
if (Init >= InitExprs.size()) {
- InitExprs.insert(C, InitExprs.end(), Init - InitExprs.size() + 1, 0);
- InitExprs.back() = expr;
- return 0;
+ InitExprs.insert(C, InitExprs.end(), Init - InitExprs.size() + 1, nullptr);
+ setInit(Init, expr);
+ return nullptr;
}
Expr *Result = cast_or_null<Expr>(InitExprs[Init]);
- InitExprs[Init] = expr;
+ setInit(Init, expr);
return Result;
}
@@ -1882,7 +1878,7 @@ void InitListExpr::setArrayFiller(Expr *filler) {
// Fill out any "holes" in the array due to designated initializers.
Expr **inits = getInits();
for (unsigned i = 0, e = getNumInits(); i != e; ++i)
- if (inits[i] == 0)
+ if (inits[i] == nullptr)
inits[i] = filler;
}
@@ -1892,7 +1888,11 @@ bool InitListExpr::isStringLiteralInit() const {
const ArrayType *AT = getType()->getAsArrayTypeUnsafe();
if (!AT || !AT->getElementType()->isIntegerType())
return false;
- const Expr *Init = getInit(0)->IgnoreParens();
+ // It is possible for getInit() to return null.
+ const Expr *Init = getInit(0);
+ if (!Init)
+ return false;
+ Init = Init->IgnoreParens();
return isa<StringLiteral>(Init) || isa<ObjCEncodeExpr>(Init);
}
@@ -2078,15 +2078,25 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
return true;
case CXXOperatorCallExprClass: {
- // We warn about operator== and operator!= even when user-defined operator
+ // Warn about operator ==,!=,<,>,<=, and >= even when user-defined operator
// overloads as there is no reasonable way to define these such that they
// have non-trivial, desirable side-effects. See the -Wunused-comparison
- // warning: these operators are commonly typo'ed, and so warning on them
+ // warning: operators == and != are commonly typo'ed, and so warning on them
// provides additional value as well. If this list is updated,
// DiagnoseUnusedComparison should be as well.
const CXXOperatorCallExpr *Op = cast<CXXOperatorCallExpr>(this);
- if (Op->getOperator() == OO_EqualEqual ||
- Op->getOperator() == OO_ExclaimEqual) {
+ switch (Op->getOperator()) {
+ default:
+ break;
+ case OO_EqualEqual:
+ case OO_ExclaimEqual:
+ case OO_Less:
+ case OO_Greater:
+ case OO_GreaterEqual:
+ case OO_LessEqual:
+ if (Op->getCallReturnType()->isReferenceType() ||
+ Op->getCallReturnType()->isVoidType())
+ break;
WarnE = this;
Loc = Op->getOperatorLoc();
R1 = Op->getSourceRange();
@@ -2106,8 +2116,8 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
//
// Note: If new cases are added here, DiagnoseUnusedExprResult should be
// updated to match for QoI.
- if (FD->getAttr<WarnUnusedResultAttr>() ||
- FD->getAttr<PureAttr>() || FD->getAttr<ConstAttr>()) {
+ if (FD->hasAttr<WarnUnusedResultAttr>() ||
+ FD->hasAttr<PureAttr>() || FD->hasAttr<ConstAttr>()) {
WarnE = this;
Loc = CE->getCallee()->getLocStart();
R1 = CE->getCallee()->getSourceRange();
@@ -2151,12 +2161,15 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
return true;
}
- const ObjCMethodDecl *MD = ME->getMethodDecl();
- if (MD && MD->getAttr<WarnUnusedResultAttr>()) {
- WarnE = this;
- Loc = getExprLoc();
- return true;
- }
+ if (const ObjCMethodDecl *MD = ME->getMethodDecl())
+ if (MD->hasAttr<WarnUnusedResultAttr>() ||
+ (MD->isPropertyAccessor() && !MD->getReturnType()->isVoidType() &&
+ !ME->getReceiverType()->isObjCIdType())) {
+ WarnE = this;
+ Loc = getExprLoc();
+ return true;
+ }
+
return false;
}
@@ -2393,6 +2406,27 @@ Expr *Expr::IgnoreParenCasts() {
}
}
+Expr *Expr::IgnoreCasts() {
+ Expr *E = this;
+ while (true) {
+ if (CastExpr *P = dyn_cast<CastExpr>(E)) {
+ E = P->getSubExpr();
+ continue;
+ }
+ if (MaterializeTemporaryExpr *Materialize
+ = dyn_cast<MaterializeTemporaryExpr>(E)) {
+ E = Materialize->GetTemporaryExpr();
+ continue;
+ }
+ if (SubstNonTypeTemplateParmExpr *NTTP
+ = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) {
+ E = NTTP->getReplacement();
+ continue;
+ }
+ return E;
+ }
+}
+
/// IgnoreParenLValueCasts - Ignore parentheses and lvalue-to-rvalue
/// casts. This is intended purely as a temporary workaround for code
/// that hasn't yet been rewritten to do the right thing about those
@@ -2638,7 +2672,8 @@ bool Expr::hasAnyTypeDependentArguments(ArrayRef<Expr *> Exprs) {
return false;
}
-bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
+bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
+ const Expr **Culprit) const {
// This function is attempting whether an expression is an initializer
// which can be evaluated at compile-time. It very closely parallels
// ConstExprEmitter in CGExprConstant.cpp; if they don't match, it
@@ -2650,7 +2685,11 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
if (IsForRef) {
EvalResult Result;
- return EvaluateAsLValue(Result, Ctx) && !Result.HasSideEffects;
+ if (EvaluateAsLValue(Result, Ctx) && !Result.HasSideEffects)
+ return true;
+ if (Culprit)
+ *Culprit = this;
+ return false;
}
switch (getStmtClass()) {
@@ -2669,7 +2708,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
// Trivial copy constructor
assert(CE->getNumArgs() == 1 && "trivial ctor with > 1 argument");
- return CE->getArg(0)->isConstantInitializer(Ctx, false);
+ return CE->getArg(0)->isConstantInitializer(Ctx, false, Culprit);
}
break;
@@ -2679,14 +2718,14 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
// "struct x {int x;} x = (struct x) {};".
// FIXME: This accepts other cases it shouldn't!
const Expr *Exp = cast<CompoundLiteralExpr>(this)->getInitializer();
- return Exp->isConstantInitializer(Ctx, false);
+ return Exp->isConstantInitializer(Ctx, false, Culprit);
}
case InitListExprClass: {
const InitListExpr *ILE = cast<InitListExpr>(this);
if (ILE->getType()->isArrayType()) {
unsigned numInits = ILE->getNumInits();
for (unsigned i = 0; i < numInits; i++) {
- if (!ILE->getInit(i)->isConstantInitializer(Ctx, false))
+ if (!ILE->getInit(i)->isConstantInitializer(Ctx, false, Culprit))
return false;
}
return true;
@@ -2710,11 +2749,14 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
if (Field->isBitField()) {
// Bitfields have to evaluate to an integer.
llvm::APSInt ResultTmp;
- if (!Elt->EvaluateAsInt(ResultTmp, Ctx))
+ if (!Elt->EvaluateAsInt(ResultTmp, Ctx)) {
+ if (Culprit)
+ *Culprit = Elt;
return false;
+ }
} else {
bool RefType = Field->getType()->isReferenceType();
- if (!Elt->isConstantInitializer(Ctx, RefType))
+ if (!Elt->isConstantInitializer(Ctx, RefType, Culprit))
return false;
}
}
@@ -2728,19 +2770,22 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
return true;
case ParenExprClass:
return cast<ParenExpr>(this)->getSubExpr()
- ->isConstantInitializer(Ctx, IsForRef);
+ ->isConstantInitializer(Ctx, IsForRef, Culprit);
case GenericSelectionExprClass:
return cast<GenericSelectionExpr>(this)->getResultExpr()
- ->isConstantInitializer(Ctx, IsForRef);
+ ->isConstantInitializer(Ctx, IsForRef, Culprit);
case ChooseExprClass:
- if (cast<ChooseExpr>(this)->isConditionDependent())
+ if (cast<ChooseExpr>(this)->isConditionDependent()) {
+ if (Culprit)
+ *Culprit = this;
return false;
+ }
return cast<ChooseExpr>(this)->getChosenSubExpr()
- ->isConstantInitializer(Ctx, IsForRef);
+ ->isConstantInitializer(Ctx, IsForRef, Culprit);
case UnaryOperatorClass: {
const UnaryOperator* Exp = cast<UnaryOperator>(this);
if (Exp->getOpcode() == UO_Extension)
- return Exp->getSubExpr()->isConstantInitializer(Ctx, false);
+ return Exp->getSubExpr()->isConstantInitializer(Ctx, false, Culprit);
break;
}
case CXXFunctionalCastExprClass:
@@ -2760,25 +2805,29 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
CE->getCastKind() == CK_ConstructorConversion ||
CE->getCastKind() == CK_NonAtomicToAtomic ||
CE->getCastKind() == CK_AtomicToNonAtomic)
- return CE->getSubExpr()->isConstantInitializer(Ctx, false);
+ return CE->getSubExpr()->isConstantInitializer(Ctx, false, Culprit);
break;
}
case MaterializeTemporaryExprClass:
return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr()
- ->isConstantInitializer(Ctx, false);
+ ->isConstantInitializer(Ctx, false, Culprit);
case SubstNonTypeTemplateParmExprClass:
return cast<SubstNonTypeTemplateParmExpr>(this)->getReplacement()
- ->isConstantInitializer(Ctx, false);
+ ->isConstantInitializer(Ctx, false, Culprit);
case CXXDefaultArgExprClass:
return cast<CXXDefaultArgExpr>(this)->getExpr()
- ->isConstantInitializer(Ctx, false);
+ ->isConstantInitializer(Ctx, false, Culprit);
case CXXDefaultInitExprClass:
return cast<CXXDefaultInitExpr>(this)->getExpr()
- ->isConstantInitializer(Ctx, false);
+ ->isConstantInitializer(Ctx, false, Culprit);
}
- return isEvaluatable(Ctx);
+ if (isEvaluatable(Ctx))
+ return true;
+ if (Culprit)
+ *Culprit = this;
+ return false;
}
bool Expr::HasSideEffects(const ASTContext &Ctx) const {
@@ -2821,8 +2870,6 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
case CXXThisExprClass:
case CXXScalarValueInitExprClass:
case TypeTraitExprClass:
- case UnaryTypeTraitExprClass:
- case BinaryTypeTraitExprClass:
case ArrayTypeTraitExprClass:
case ExpressionTraitExprClass:
case CXXNoexceptExprClass:
@@ -3055,7 +3102,7 @@ Expr::NullPointerConstantKind
Expr::isNullPointerConstant(ASTContext &Ctx,
NullPointerConstantValueDependence NPC) const {
if (isValueDependent() &&
- (!Ctx.getLangOpts().CPlusPlus11 || Ctx.getLangOpts().MicrosoftMode)) {
+ (!Ctx.getLangOpts().CPlusPlus11 || Ctx.getLangOpts().MSVCCompat)) {
switch (NPC) {
case NPC_NeverValueDependent:
llvm_unreachable("Unexpected value dependent expression!");
@@ -3141,8 +3188,7 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
const IntegerLiteral *Lit = dyn_cast<IntegerLiteral>(this);
if (Lit && !Lit->getValue())
return NPCK_ZeroLiteral;
- else if (!Ctx.getLangOpts().MicrosoftMode ||
- !isCXX98IntegralConstantExpr(Ctx))
+ else if (!Ctx.getLangOpts().MSVCCompat || !isCXX98IntegralConstantExpr(Ctx))
return NPCK_NotNull;
} else {
// If we have an integer constant expression, we need to *evaluate* it and
@@ -3233,7 +3279,7 @@ FieldDecl *Expr::getSourceBitField() {
return BinOp->getRHS()->getSourceBitField();
}
- return 0;
+ return nullptr;
}
bool Expr::refersToVectorElement() const {
@@ -3339,8 +3385,9 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
Kind(IsInstanceSuper? SuperInstance : SuperClass),
- HasMethod(Method != 0), IsDelegateInitCall(false), IsImplicit(isImplicit),
- SuperLoc(SuperLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc)
+ HasMethod(Method != nullptr), IsDelegateInitCall(false),
+ IsImplicit(isImplicit), SuperLoc(SuperLoc), LBracLoc(LBracLoc),
+ RBracLoc(RBracLoc)
{
initArgsAndSelLocs(Args, SelLocs, SelLocsK);
setReceiverPointer(SuperType.getAsOpaquePtr());
@@ -3363,8 +3410,8 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
Kind(Class),
- HasMethod(Method != 0), IsDelegateInitCall(false), IsImplicit(isImplicit),
- LBracLoc(LBracLoc), RBracLoc(RBracLoc)
+ HasMethod(Method != nullptr), IsDelegateInitCall(false),
+ IsImplicit(isImplicit), LBracLoc(LBracLoc), RBracLoc(RBracLoc)
{
initArgsAndSelLocs(Args, SelLocs, SelLocsK);
setReceiverPointer(Receiver);
@@ -3388,8 +3435,8 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
Kind(Instance),
- HasMethod(Method != 0), IsDelegateInitCall(false), IsImplicit(isImplicit),
- LBracLoc(LBracLoc), RBracLoc(RBracLoc)
+ HasMethod(Method != nullptr), IsDelegateInitCall(false),
+ IsImplicit(isImplicit), LBracLoc(LBracLoc), RBracLoc(RBracLoc)
{
initArgsAndSelLocs(Args, SelLocs, SelLocsK);
setReceiverPointer(Receiver);
@@ -3571,7 +3618,7 @@ ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const {
if (const ObjCObjectType *Ty = T->getAs<ObjCObjectType>())
return Ty->getInterface();
- return 0;
+ return nullptr;
}
StringRef ObjCBridgedCastExpr::getBridgeKindName() const {
@@ -3806,30 +3853,21 @@ SourceLocation DesignatedInitExpr::getLocEnd() const {
Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) const {
assert(D.Kind == Designator::ArrayDesignator && "Requires array designator");
- char *Ptr = static_cast<char *>(
- const_cast<void *>(static_cast<const void *>(this)));
- Ptr += sizeof(DesignatedInitExpr);
- Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
+ Stmt *const *SubExprs = reinterpret_cast<Stmt *const *>(this + 1);
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
}
Expr *DesignatedInitExpr::getArrayRangeStart(const Designator &D) const {
assert(D.Kind == Designator::ArrayRangeDesignator &&
"Requires array range designator");
- char *Ptr = static_cast<char *>(
- const_cast<void *>(static_cast<const void *>(this)));
- Ptr += sizeof(DesignatedInitExpr);
- Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
+ Stmt *const *SubExprs = reinterpret_cast<Stmt *const *>(this + 1);
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
}
Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator &D) const {
assert(D.Kind == Designator::ArrayRangeDesignator &&
"Requires array range designator");
- char *Ptr = static_cast<char *>(
- const_cast<void *>(static_cast<const void *>(this)));
- Ptr += sizeof(DesignatedInitExpr);
- Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
+ Stmt *const *SubExprs = reinterpret_cast<Stmt *const *>(this + 1);
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 2));
}
@@ -3953,7 +3991,7 @@ PseudoObjectExpr::PseudoObjectExpr(QualType type, ExprValueKind VK,
ExprBits.ContainsUnexpandedParameterPack = true;
if (isa<OpaqueValueExpr>(E))
- assert(cast<OpaqueValueExpr>(E)->getSourceExpr() != 0 &&
+ assert(cast<OpaqueValueExpr>(E)->getSourceExpr() != nullptr &&
"opaque-value semantic expressions for pseudo-object "
"operations must have sources");
}
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 3738c0e4f2c9..64c21dd5c4fd 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -55,8 +55,8 @@ QualType CXXUuidofExpr::getTypeOperand(ASTContext &Context) const {
}
// static
-UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT,
- bool *RDHasMultipleGUIDsPtr) {
+const UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT,
+ bool *RDHasMultipleGUIDsPtr) {
// Optionally remove one level of pointer, reference or array indirection.
const Type *Ty = QT.getTypePtr();
if (QT->isPointerType() || QT->isReferenceType())
@@ -64,22 +64,23 @@ UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT,
else if (QT->isArrayType())
Ty = Ty->getBaseElementTypeUnsafe();
- // Loop all record redeclaration looking for an uuid attribute.
- CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
if (!RD)
- return 0;
+ return nullptr;
+
+ if (const UuidAttr *Uuid = RD->getMostRecentDecl()->getAttr<UuidAttr>())
+ return Uuid;
// __uuidof can grab UUIDs from template arguments.
- if (ClassTemplateSpecializationDecl *CTSD =
+ if (const ClassTemplateSpecializationDecl *CTSD =
dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
- UuidAttr *UuidForRD = 0;
+ const UuidAttr *UuidForRD = nullptr;
- for (unsigned I = 0, N = TAL.size(); I != N; ++I) {
- const TemplateArgument &TA = TAL[I];
+ for (const TemplateArgument &TA : TAL.asArray()) {
bool SeenMultipleGUIDs = false;
- UuidAttr *UuidForTA = 0;
+ const UuidAttr *UuidForTA = nullptr;
if (TA.getKind() == TemplateArgument::Type)
UuidForTA = GetUuidAttrOfType(TA.getAsType(), &SeenMultipleGUIDs);
else if (TA.getKind() == TemplateArgument::Declaration)
@@ -101,20 +102,14 @@ UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT,
if (SeenMultipleGUIDs) {
if (RDHasMultipleGUIDsPtr)
*RDHasMultipleGUIDsPtr = true;
- return 0;
+ return nullptr;
}
}
return UuidForRD;
}
- for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(),
- E = RD->redecls_end();
- I != E; ++I)
- if (UuidAttr *Uuid = I->getAttr<UuidAttr>())
- return Uuid;
-
- return 0;
+ return nullptr;
}
StringRef CXXUuidofExpr::getUuidAsStringRef(ASTContext &Context) const {
@@ -151,14 +146,15 @@ CXXNewExpr::CXXNewExpr(const ASTContext &C, bool globalNew,
ty->isDependentType(), ty->isDependentType(),
ty->isInstantiationDependentType(),
ty->containsUnexpandedParameterPack()),
- SubExprs(0), OperatorNew(operatorNew), OperatorDelete(operatorDelete),
+ SubExprs(nullptr), OperatorNew(operatorNew), OperatorDelete(operatorDelete),
AllocatedTypeInfo(allocatedTypeInfo), TypeIdParens(typeIdParens),
Range(Range), DirectInitRange(directInitRange),
GlobalNew(globalNew), UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) {
- assert((initializer != 0 || initializationStyle == NoInit) &&
+ assert((initializer != nullptr || initializationStyle == NoInit) &&
"Only NoInit can have no initializer.");
StoredInitializationStyle = initializer ? initializationStyle + 1 : 0;
- AllocateArgsArray(C, arraySize != 0, placementArgs.size(), initializer != 0);
+ AllocateArgsArray(C, arraySize != nullptr, placementArgs.size(),
+ initializer != nullptr);
unsigned i = 0;
if (Array) {
if (arraySize->isInstantiationDependent())
@@ -203,7 +199,7 @@ CXXNewExpr::CXXNewExpr(const ASTContext &C, bool globalNew,
void CXXNewExpr::AllocateArgsArray(const ASTContext &C, bool isArray,
unsigned numPlaceArgs, bool hasInitializer){
- assert(SubExprs == 0 && "SubExprs already allocated");
+ assert(SubExprs == nullptr && "SubExprs already allocated");
Array = isArray;
NumPlacementArgs = numPlaceArgs;
@@ -345,9 +341,9 @@ OverloadExpr::OverloadExpr(StmtClass K, const ASTContext &C,
QualifierLoc.getNestedNameSpecifier()
->containsUnexpandedParameterPack()))),
NameInfo(NameInfo), QualifierLoc(QualifierLoc),
- Results(0), NumResults(End - Begin),
- HasTemplateKWAndArgsInfo(TemplateArgs != 0 || TemplateKWLoc.isValid())
-{
+ Results(nullptr), NumResults(End - Begin),
+ HasTemplateKWAndArgsInfo(TemplateArgs != nullptr ||
+ TemplateKWLoc.isValid()) {
NumResults = End - Begin;
if (NumResults) {
// Determine whether this expression is type-dependent.
@@ -398,7 +394,7 @@ OverloadExpr::OverloadExpr(StmtClass K, const ASTContext &C,
void OverloadExpr::initializeResults(const ASTContext &C,
UnresolvedSetIterator Begin,
UnresolvedSetIterator End) {
- assert(Results == 0 && "Results already initialized!");
+ assert(!Results && "Results already initialized!");
NumResults = End - Begin;
if (NumResults) {
Results = static_cast<DeclAccessPair *>(
@@ -433,7 +429,7 @@ DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T,
QualifierLoc.getNestedNameSpecifier()
->containsUnexpandedParameterPack()))),
QualifierLoc(QualifierLoc), NameInfo(NameInfo),
- HasTemplateKWAndArgsInfo(Args != 0 || TemplateKWLoc.isValid())
+ HasTemplateKWAndArgsInfo(Args != nullptr || TemplateKWLoc.isValid())
{
if (Args) {
bool Dependent = true;
@@ -478,7 +474,7 @@ DependentScopeDeclRefExpr::CreateEmpty(const ASTContext &C,
DependentScopeDeclRefExpr *E
= new (Mem) DependentScopeDeclRefExpr(QualType(), NestedNameSpecifierLoc(),
SourceLocation(),
- DeclarationNameInfo(), 0);
+ DeclarationNameInfo(), nullptr);
E->HasTemplateKWAndArgsInfo = HasTemplateKWAndArgsInfo;
return E;
}
@@ -544,7 +540,7 @@ Expr *CXXMemberCallExpr::getImplicitObjectArgument() const {
return BO->getLHS();
// FIXME: Will eventually need to cope with member pointers.
- return 0;
+ return nullptr;
}
CXXMethodDecl *CXXMemberCallExpr::getMethodDecl() const {
@@ -553,14 +549,14 @@ CXXMethodDecl *CXXMemberCallExpr::getMethodDecl() const {
return cast<CXXMethodDecl>(MemExpr->getMemberDecl());
// FIXME: Will eventually need to cope with member pointers.
- return 0;
+ return nullptr;
}
CXXRecordDecl *CXXMemberCallExpr::getRecordDecl() const {
Expr* ThisArg = getImplicitObjectArgument();
if (!ThisArg)
- return 0;
+ return nullptr;
if (ThisArg->getType()->isAnyPointerType())
return ThisArg->getType()->getPointeeType()->getAsCXXRecordDecl();
@@ -810,13 +806,16 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(const ASTContext &C,
SourceRange ParenOrBraceRange,
bool HadMultipleCandidates,
bool ListInitialization,
+ bool StdInitListInitialization,
bool ZeroInitialization)
: CXXConstructExpr(C, CXXTemporaryObjectExprClass,
Type->getType().getNonReferenceType(),
Type->getTypeLoc().getBeginLoc(),
Cons, false, Args,
HadMultipleCandidates,
- ListInitialization, ZeroInitialization,
+ ListInitialization,
+ StdInitListInitialization,
+ ZeroInitialization,
CXXConstructExpr::CK_Complete, ParenOrBraceRange),
Type(Type) {
}
@@ -838,12 +837,14 @@ CXXConstructExpr *CXXConstructExpr::Create(const ASTContext &C, QualType T,
ArrayRef<Expr*> Args,
bool HadMultipleCandidates,
bool ListInitialization,
+ bool StdInitListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
SourceRange ParenOrBraceRange) {
return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D,
Elidable, Args,
HadMultipleCandidates, ListInitialization,
+ StdInitListInitialization,
ZeroInitialization, ConstructKind,
ParenOrBraceRange);
}
@@ -854,6 +855,7 @@ CXXConstructExpr::CXXConstructExpr(const ASTContext &C, StmtClass SC,
ArrayRef<Expr*> args,
bool HadMultipleCandidates,
bool ListInitialization,
+ bool StdInitListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
SourceRange ParenOrBraceRange)
@@ -865,8 +867,9 @@ CXXConstructExpr::CXXConstructExpr(const ASTContext &C, StmtClass SC,
NumArgs(args.size()),
Elidable(elidable), HadMultipleCandidates(HadMultipleCandidates),
ListInitialization(ListInitialization),
+ StdInitListInitialization(StdInitListInitialization),
ZeroInitialization(ZeroInitialization),
- ConstructKind(ConstructKind), Args(0)
+ ConstructKind(ConstructKind), Args(nullptr)
{
if (NumArgs) {
Args = new (C) Stmt*[args.size()];
@@ -886,7 +889,7 @@ CXXConstructExpr::CXXConstructExpr(const ASTContext &C, StmtClass SC,
}
}
-LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit,
+LambdaCapture::LambdaCapture(SourceLocation Loc, bool Implicit,
LambdaCaptureKind Kind, VarDecl *Var,
SourceLocation EllipsisLoc)
: DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc)
@@ -896,8 +899,8 @@ LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit,
Bits |= Capture_Implicit;
switch (Kind) {
- case LCK_This:
- assert(Var == 0 && "'this' capture cannot have a variable!");
+ case LCK_This:
+ assert(!Var && "'this' capture cannot have a variable!");
break;
case LCK_ByCopy:
@@ -910,7 +913,7 @@ LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit,
DeclAndBits.setInt(Bits);
}
-LambdaCaptureKind LambdaExpr::Capture::getCaptureKind() const {
+LambdaCaptureKind LambdaCapture::getCaptureKind() const {
Decl *D = DeclAndBits.getPointer();
if (!D)
return LCK_This;
@@ -1031,6 +1034,10 @@ LambdaExpr::capture_iterator LambdaExpr::capture_end() const {
return capture_begin() + NumCaptures;
}
+LambdaExpr::capture_range LambdaExpr::captures() const {
+ return capture_range(capture_begin(), capture_end());
+}
+
LambdaExpr::capture_iterator LambdaExpr::explicit_capture_begin() const {
return capture_begin();
}
@@ -1041,6 +1048,10 @@ LambdaExpr::capture_iterator LambdaExpr::explicit_capture_end() const {
return Data.Captures + Data.NumExplicitCaptures;
}
+LambdaExpr::capture_range LambdaExpr::explicit_captures() const {
+ return capture_range(explicit_capture_begin(), explicit_capture_end());
+}
+
LambdaExpr::capture_iterator LambdaExpr::implicit_capture_begin() const {
return explicit_capture_end();
}
@@ -1049,6 +1060,10 @@ LambdaExpr::capture_iterator LambdaExpr::implicit_capture_end() const {
return capture_end();
}
+LambdaExpr::capture_range LambdaExpr::implicit_captures() const {
+ return capture_range(implicit_capture_begin(), implicit_capture_end());
+}
+
ArrayRef<VarDecl *>
LambdaExpr::getCaptureInitIndexVars(capture_init_iterator Iter) const {
assert(HasArrayIndexVars && "No array index-var data?");
@@ -1187,7 +1202,8 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(const ASTContext &C,
->containsUnexpandedParameterPack()) ||
MemberNameInfo.containsUnexpandedParameterPack())),
Base(Base), BaseType(BaseType), IsArrow(IsArrow),
- HasTemplateKWAndArgsInfo(TemplateArgs != 0 || TemplateKWLoc.isValid()),
+ HasTemplateKWAndArgsInfo(TemplateArgs != nullptr ||
+ TemplateKWLoc.isValid()),
OperatorLoc(OperatorLoc), QualifierLoc(QualifierLoc),
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
MemberNameInfo(MemberNameInfo) {
@@ -1260,26 +1276,26 @@ CXXDependentScopeMemberExpr::CreateEmpty(const ASTContext &C,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
if (!HasTemplateKWAndArgsInfo)
- return new (C) CXXDependentScopeMemberExpr(C, 0, QualType(),
+ return new (C) CXXDependentScopeMemberExpr(C, nullptr, QualType(),
0, SourceLocation(),
- NestedNameSpecifierLoc(), 0,
- DeclarationNameInfo());
+ NestedNameSpecifierLoc(),
+ nullptr, DeclarationNameInfo());
std::size_t size = sizeof(CXXDependentScopeMemberExpr) +
ASTTemplateKWAndArgsInfo::sizeFor(NumTemplateArgs);
void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>());
CXXDependentScopeMemberExpr *E
- = new (Mem) CXXDependentScopeMemberExpr(C, 0, QualType(),
+ = new (Mem) CXXDependentScopeMemberExpr(C, nullptr, QualType(),
0, SourceLocation(),
NestedNameSpecifierLoc(),
- SourceLocation(), 0,
- DeclarationNameInfo(), 0);
+ SourceLocation(), nullptr,
+ DeclarationNameInfo(), nullptr);
E->HasTemplateKWAndArgsInfo = true;
return E;
}
bool CXXDependentScopeMemberExpr::isImplicitAccess() const {
- if (Base == 0)
+ if (!Base)
return true;
return cast<Expr>(Base)->isImplicitCXXThis();
@@ -1291,16 +1307,11 @@ static bool hasOnlyNonStaticMemberFunctions(UnresolvedSetIterator begin,
NamedDecl *decl = *begin;
if (isa<UnresolvedUsingValueDecl>(decl))
return false;
- if (isa<UsingShadowDecl>(decl))
- decl = cast<UsingShadowDecl>(decl)->getUnderlyingDecl();
// Unresolved member expressions should only contain methods and
// method templates.
- assert(isa<CXXMethodDecl>(decl) || isa<FunctionTemplateDecl>(decl));
-
- if (isa<FunctionTemplateDecl>(decl))
- decl = cast<FunctionTemplateDecl>(decl)->getTemplatedDecl();
- if (cast<CXXMethodDecl>(decl)->isStatic())
+ if (cast<CXXMethodDecl>(decl->getUnderlyingDecl()->getAsFunction())
+ ->isStatic())
return false;
} while (++begin != end);
@@ -1338,7 +1349,7 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(const ASTContext &C,
}
bool UnresolvedMemberExpr::isImplicitAccess() const {
- if (Base == 0)
+ if (!Base)
return true;
return cast<Expr>(Base)->isImplicitCXXThis();
@@ -1387,7 +1398,7 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const {
// If there was a nested name specifier, it names the naming class.
// It can't be dependent: after all, we were actually able to do the
// lookup.
- CXXRecordDecl *Record = 0;
+ CXXRecordDecl *Record = nullptr;
if (getQualifier()) {
const Type *T = getQualifier()->getAsType();
assert(T && "qualifier in member expression does not name type");
@@ -1450,7 +1461,26 @@ FunctionParmPackExpr::CreateEmpty(const ASTContext &Context,
unsigned NumParams) {
return new (Context.Allocate(sizeof(FunctionParmPackExpr) +
sizeof(ParmVarDecl*) * NumParams))
- FunctionParmPackExpr(QualType(), 0, SourceLocation(), 0, 0);
+ FunctionParmPackExpr(QualType(), nullptr, SourceLocation(), 0, nullptr);
+}
+
+void MaterializeTemporaryExpr::setExtendingDecl(const ValueDecl *ExtendedBy,
+ unsigned ManglingNumber) {
+ // We only need extra state if we have to remember more than just the Stmt.
+ if (!ExtendedBy)
+ return;
+
+ // We may need to allocate extra storage for the mangling number and the
+ // extended-by ValueDecl.
+ if (!State.is<ExtraState *>()) {
+ auto ES = new (ExtendedBy->getASTContext()) ExtraState;
+ ES->Temporary = State.get<Stmt *>();
+ State = ES;
+ }
+
+ auto ES = State.get<ExtraState *>();
+ ES->ExtendingDecl = ExtendedBy;
+ ES->ManglingNumber = ManglingNumber;
}
TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind,
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index 54f77efef0f9..d3d25308a386 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -165,8 +165,6 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::FloatingLiteralClass:
case Expr::CXXNoexceptExprClass:
case Expr::CXXScalarValueInitExprClass:
- case Expr::UnaryTypeTraitExprClass:
- case Expr::BinaryTypeTraitExprClass:
case Expr::TypeTraitExprClass:
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
@@ -348,7 +346,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::ObjCMessageExprClass:
if (const ObjCMethodDecl *Method =
cast<ObjCMessageExpr>(E)->getMethodDecl()) {
- Cl::Kinds kind = ClassifyUnnamed(Ctx, Method->getResultType());
+ Cl::Kinds kind = ClassifyUnnamed(Ctx, Method->getReturnType());
return (kind == Cl::CL_PRValue) ? Cl::CL_ObjCMessageRValue : kind;
}
return Cl::CL_PRValue;
@@ -543,10 +541,21 @@ static Cl::Kinds ClassifyConditional(ASTContext &Ctx, const Expr *True,
"This is only relevant for C++.");
// C++ [expr.cond]p2
- // If either the second or the third operand has type (cv) void, [...]
- // the result [...] is a prvalue.
- if (True->getType()->isVoidType() || False->getType()->isVoidType())
+ // If either the second or the third operand has type (cv) void,
+ // one of the following shall hold:
+ if (True->getType()->isVoidType() || False->getType()->isVoidType()) {
+ // The second or the third operand (but not both) is a (possibly
+ // parenthesized) throw-expression; the result is of the [...] value
+ // category of the other.
+ bool TrueIsThrow = isa<CXXThrowExpr>(True->IgnoreParenImpCasts());
+ bool FalseIsThrow = isa<CXXThrowExpr>(False->IgnoreParenImpCasts());
+ if (const Expr *NonThrow = TrueIsThrow ? (FalseIsThrow ? nullptr : False)
+ : (FalseIsThrow ? True : nullptr))
+ return ClassifyInternal(Ctx, NonThrow);
+
+ // [Otherwise] the result [...] is a prvalue.
return Cl::CL_PRValue;
+ }
// Note that at this point, we have already performed all conversions
// according to [expr.cond]p3.
@@ -584,7 +593,8 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
// Assignment to a property in ObjC is an implicit setter access. But a
// setter might not exist.
if (const ObjCPropertyRefExpr *Expr = dyn_cast<ObjCPropertyRefExpr>(E)) {
- if (Expr->isImplicitProperty() && Expr->getImplicitPropertySetter() == 0)
+ if (Expr->isImplicitProperty() &&
+ Expr->getImplicitPropertySetter() == nullptr)
return Cl::CM_NoSetterProperty;
}
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 4cac4fab8476..7d7ca9924c85 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -320,7 +320,7 @@ namespace {
APValue *getTemporary(const void *Key) {
MapTy::iterator I = Temporaries.find(Key);
- return I == Temporaries.end() ? 0 : &I->second;
+ return I == Temporaries.end() ? nullptr : &I->second;
}
APValue &createTemporary(const void *Key, bool IsLifetimeExtended);
};
@@ -347,7 +347,8 @@ namespace {
PartialDiagnostic *Diag;
public:
- explicit OptionalDiagnostic(PartialDiagnostic *Diag = 0) : Diag(Diag) {}
+ explicit OptionalDiagnostic(PartialDiagnostic *Diag = nullptr)
+ : Diag(Diag) {}
template<typename T>
OptionalDiagnostic &operator<<(const T &v) {
@@ -474,13 +475,30 @@ namespace {
/// Evaluate in any way we know how. Don't worry about side-effects that
/// can't be modeled.
- EM_IgnoreSideEffects
+ EM_IgnoreSideEffects,
+
+ /// Evaluate as a constant expression. Stop if we find that the expression
+ /// is not a constant expression. Some expressions can be retried in the
+ /// optimizer if we don't constant fold them here, but in an unevaluated
+ /// context we try to fold them immediately since the optimizer never
+ /// gets a chance to look at it.
+ EM_ConstantExpressionUnevaluated,
+
+ /// Evaluate as a potential constant expression. Keep going if we hit a
+ /// construct that we can't evaluate yet (because we don't yet know the
+ /// value of something) but stop if we hit something that could never be
+ /// a constant expression. Some expressions can be retried in the
+ /// optimizer if we don't constant fold them here, but in an unevaluated
+ /// context we try to fold them immediately since the optimizer never
+ /// gets a chance to look at it.
+ EM_PotentialConstantExpressionUnevaluated
} EvalMode;
/// Are we checking whether the expression is a potential constant
/// expression?
bool checkingPotentialConstantExpression() const {
- return EvalMode == EM_PotentialConstantExpression;
+ return EvalMode == EM_PotentialConstantExpression ||
+ EvalMode == EM_PotentialConstantExpressionUnevaluated;
}
/// Are we checking an expression for overflow?
@@ -489,12 +507,13 @@ namespace {
bool checkingForOverflow() { return EvalMode == EM_EvaluateForOverflow; }
EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode)
- : Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0),
+ : Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr),
CallStackDepth(0), NextCallIndex(1),
StepsLeft(getLangOpts().ConstexprStepLimit),
- BottomFrame(*this, SourceLocation(), 0, 0, 0),
- EvaluatingDecl((const ValueDecl*)0), EvaluatingDeclValue(0),
- HasActiveDiagnostic(false), EvalMode(Mode) {}
+ BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr),
+ EvaluatingDecl((const ValueDecl *)nullptr),
+ EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
+ EvalMode(Mode) {}
void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) {
EvaluatingDecl = Base;
@@ -527,7 +546,7 @@ namespace {
CallStackFrame *Frame = CurrentCall;
while (Frame->Index > CallIndex)
Frame = Frame->Caller;
- return (Frame->Index == CallIndex) ? Frame : 0;
+ return (Frame->Index == CallIndex) ? Frame : nullptr;
}
bool nextStep(const Stmt *S) {
@@ -573,6 +592,8 @@ namespace {
// some later problem.
case EM_ConstantExpression:
case EM_PotentialConstantExpression:
+ case EM_ConstantExpressionUnevaluated:
+ case EM_PotentialConstantExpressionUnevaluated:
HasActiveDiagnostic = false;
return OptionalDiagnostic();
}
@@ -644,11 +665,13 @@ namespace {
bool keepEvaluatingAfterSideEffect() {
switch (EvalMode) {
case EM_PotentialConstantExpression:
+ case EM_PotentialConstantExpressionUnevaluated:
case EM_EvaluateForOverflow:
case EM_IgnoreSideEffects:
return true;
case EM_ConstantExpression:
+ case EM_ConstantExpressionUnevaluated:
case EM_ConstantFold:
return false;
}
@@ -670,10 +693,12 @@ namespace {
switch (EvalMode) {
case EM_PotentialConstantExpression:
+ case EM_PotentialConstantExpressionUnevaluated:
case EM_EvaluateForOverflow:
return true;
case EM_ConstantExpression:
+ case EM_ConstantExpressionUnevaluated:
case EM_ConstantFold:
case EM_IgnoreSideEffects:
return false;
@@ -696,7 +721,9 @@ namespace {
Info.EvalStatus.Diag->empty() &&
!Info.EvalStatus.HasSideEffects),
OldMode(Info.EvalMode) {
- if (Enabled && Info.EvalMode == EvalInfo::EM_ConstantExpression)
+ if (Enabled &&
+ (Info.EvalMode == EvalInfo::EM_ConstantExpression ||
+ Info.EvalMode == EvalInfo::EM_ConstantExpressionUnevaluated))
Info.EvalMode = EvalInfo::EM_ConstantFold;
}
void keepDiagnostics() { Enabled = false; }
@@ -716,7 +743,7 @@ namespace {
public:
SpeculativeEvaluationRAII(EvalInfo &Info,
- SmallVectorImpl<PartialDiagnosticAt> *NewDiag = 0)
+ SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr)
: Info(Info), Old(Info.EvalStatus) {
Info.EvalStatus.Diag = NewDiag;
// If we're speculatively evaluating, we may have skipped over some
@@ -943,7 +970,7 @@ namespace {
// any object: we won't use such a designator for anything.
if (!Info.getLangOpts().CPlusPlus11)
Designator.setInvalid();
- return checkNullPointer(Info, E, CSK) &&
+ return (CSK == CSK_ArrayToPointer || checkNullPointer(Info, E, CSK)) &&
Designator.checkSubobject(Info, E, CSK);
}
@@ -961,7 +988,7 @@ namespace {
Designator.addComplexUnchecked(EltTy, Imag);
}
void adjustIndex(EvalInfo &Info, const Expr *E, uint64_t N) {
- if (checkNullPointer(Info, E, CSK_ArrayIndex))
+ if (N && checkNullPointer(Info, E, CSK_ArrayIndex))
Designator.adjustIndex(Info, E, N);
}
};
@@ -1141,7 +1168,7 @@ static int64_t getExtValue(const APSInt &Value) {
/// Should this call expression be treated as a string literal?
static bool IsStringLiteralCall(const CallExpr *E) {
- unsigned Builtin = E->isBuiltinCall();
+ unsigned Builtin = E->getBuiltinCallee();
return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
Builtin == Builtin::BI__builtin___NSStringMakeConstantString);
}
@@ -1242,11 +1269,29 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
LVal.getLValueCallIndex() == 0) &&
"have call index for global lvalue");
- // Check if this is a thread-local variable.
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) {
if (const VarDecl *Var = dyn_cast<const VarDecl>(VD)) {
+ // Check if this is a thread-local variable.
if (Var->getTLSKind())
return false;
+
+ // A dllimport variable never acts like a constant.
+ if (Var->hasAttr<DLLImportAttr>())
+ return false;
+ }
+ if (const auto *FD = dyn_cast<const FunctionDecl>(VD)) {
+ // __declspec(dllimport) must be handled very carefully:
+ // We must never initialize an expression with the thunk in C++.
+ // Doing otherwise would allow the same id-expression to yield
+ // different addresses for the same function in different translation
+ // units. However, this means that we must dynamically initialize the
+ // expression with the contents of the import address table at runtime.
+ //
+ // The C language has no notion of ODR; furthermore, it has no notion of
+ // dynamic initialization. This means that we are permitted to
+ // perform initialization with the address of the thunk.
+ if (Info.getLangOpts().CPlusPlus && FD->hasAttr<DLLImportAttr>())
+ return false;
}
}
@@ -1276,7 +1321,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
/// Check that this core constant expression is of literal type, and if not,
/// produce an appropriate diagnostic.
static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
- const LValue *This = 0) {
+ const LValue *This = nullptr) {
if (!E->isRValue() || E->getType()->isLiteralType(Info.Ctx))
return true;
@@ -1307,6 +1352,11 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
return false;
}
+ // We allow _Atomic(T) to be initialized from anything that T can be
+ // initialized from.
+ if (const AtomicType *AT = Type->getAs<AtomicType>())
+ Type = AT->getValueType();
+
// Core issue 1454: For a literal constant expression of array or class type,
// each subobject of its value shall have been initialized by a constant
// expression.
@@ -1338,8 +1388,7 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
return false;
}
}
- for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
- I != E; ++I) {
+ for (const auto *I : RD->fields()) {
if (!CheckConstantExpression(Info, DiagLoc, I->getType(),
Value.getStructField(I->getFieldIndex())))
return false;
@@ -1738,7 +1787,7 @@ static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result,
static bool HandleLValueDirectBase(EvalInfo &Info, const Expr *E, LValue &Obj,
const CXXRecordDecl *Derived,
const CXXRecordDecl *Base,
- const ASTRecordLayout *RL = 0) {
+ const ASTRecordLayout *RL = nullptr) {
if (!RL) {
if (Derived->isInvalidDecl()) return false;
RL = &Info.Ctx.getASTRecordLayout(Derived);
@@ -1791,7 +1840,7 @@ static bool HandleLValueBasePath(EvalInfo &Info, const CastExpr *E,
/// currently described by LVal.
static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal,
const FieldDecl *FD,
- const ASTRecordLayout *RL = 0) {
+ const ASTRecordLayout *RL = nullptr) {
if (!RL) {
if (FD->getParent()->isInvalidDecl()) return false;
RL = &Info.Ctx.getASTRecordLayout(FD->getParent());
@@ -1807,9 +1856,8 @@ static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal,
static bool HandleLValueIndirectMember(EvalInfo &Info, const Expr *E,
LValue &LVal,
const IndirectFieldDecl *IFD) {
- for (IndirectFieldDecl::chain_iterator C = IFD->chain_begin(),
- CE = IFD->chain_end(); C != CE; ++C)
- if (!HandleLValueMember(Info, E, LVal, cast<FieldDecl>(*C)))
+ for (const auto *C : IFD->chain())
+ if (!HandleLValueMember(Info, E, LVal, cast<FieldDecl>(C)))
return false;
return true;
}
@@ -2047,7 +2095,7 @@ struct CompleteObject {
/// The type of the complete object.
QualType Type;
- CompleteObject() : Value(0) {}
+ CompleteObject() : Value(nullptr) {}
CompleteObject(APValue *Value, QualType Type)
: Value(Value), Type(Type) {
assert(Value && "missing value for complete object");
@@ -2075,7 +2123,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
APValue *O = Obj.Value;
QualType ObjType = Obj.Type;
- const FieldDecl *LastField = 0;
+ const FieldDecl *LastField = nullptr;
// Walk the designator's path to find the subobject.
for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
@@ -2098,7 +2146,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
return true;
}
- LastField = 0;
+ LastField = nullptr;
if (ObjType->isArrayType()) {
// Next subobject is an array element.
const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(ObjType);
@@ -2381,7 +2429,7 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
return CompleteObject();
}
- CallStackFrame *Frame = 0;
+ CallStackFrame *Frame = nullptr;
if (LVal.CallIndex) {
Frame = Info.getCallFrame(LVal.CallIndex);
if (!Frame) {
@@ -2406,7 +2454,7 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
}
// Compute value storage location and type of base object.
- APValue *BaseVal = 0;
+ APValue *BaseVal = nullptr;
QualType BaseType = getType(LVal.Base);
if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl*>()) {
@@ -2776,7 +2824,7 @@ struct IncDecSubobjectHandler {
// if we're post-incrementing a complex.
if (Old) {
*Old = Subobj;
- Old = 0;
+ Old = nullptr;
}
switch (Subobj.getKind()) {
@@ -2913,6 +2961,7 @@ static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object,
if (Object->getType()->isLiteralType(Info.Ctx))
return EvaluateTemporary(Object, This, Info);
+ Info.Diag(Object, diag::note_constexpr_nonliteral) << Object->getType();
return false;
}
@@ -2934,14 +2983,14 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
bool IncludeMember = true) {
MemberPtr MemPtr;
if (!EvaluateMemberPointer(RHS, MemPtr, Info))
- return 0;
+ return nullptr;
// C++11 [expr.mptr.oper]p6: If the second operand is the null pointer to
// member value, the behavior is undefined.
if (!MemPtr.getDecl()) {
// FIXME: Specific diagnostic.
Info.Diag(RHS);
- return 0;
+ return nullptr;
}
if (MemPtr.isDerivedMember()) {
@@ -2951,7 +3000,7 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
if (LV.Designator.MostDerivedPathLength + MemPtr.Path.size() >
LV.Designator.Entries.size()) {
Info.Diag(RHS);
- return 0;
+ return nullptr;
}
unsigned PathLengthToMember =
LV.Designator.Entries.size() - MemPtr.Path.size();
@@ -2961,14 +3010,14 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
const CXXRecordDecl *MPDecl = MemPtr.Path[I];
if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl()) {
Info.Diag(RHS);
- return 0;
+ return nullptr;
}
}
// Truncate the lvalue to the appropriate derived class.
if (!CastToDerivedClass(Info, RHS, LV, MemPtr.getContainingRecord(),
PathLengthToMember))
- return 0;
+ return nullptr;
} else if (!MemPtr.Path.empty()) {
// Extend the LValue path with the member pointer's path.
LV.Designator.Entries.reserve(LV.Designator.Entries.size() +
@@ -2983,24 +3032,24 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
for (unsigned I = 1, N = MemPtr.Path.size(); I != N; ++I) {
const CXXRecordDecl *Base = MemPtr.Path[N - I - 1];
if (!HandleLValueDirectBase(Info, RHS, LV, RD, Base))
- return 0;
+ return nullptr;
RD = Base;
}
// Finally cast to the class containing the member.
if (!HandleLValueDirectBase(Info, RHS, LV, RD,
MemPtr.getContainingRecord()))
- return 0;
+ return nullptr;
}
// Add the member. Note that we cannot build bound member functions here.
if (IncludeMember) {
if (const FieldDecl *FD = dyn_cast<FieldDecl>(MemPtr.getDecl())) {
if (!HandleLValueMember(Info, RHS, LV, FD))
- return 0;
+ return nullptr;
} else if (const IndirectFieldDecl *IFD =
dyn_cast<IndirectFieldDecl>(MemPtr.getDecl())) {
if (!HandleLValueIndirectMember(Info, RHS, LV, IFD))
- return 0;
+ return nullptr;
} else {
llvm_unreachable("can't construct reference to bound member function");
}
@@ -3020,7 +3069,7 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
MemberPtr MemPtr;
EvaluateMemberPointer(BO->getRHS(), MemPtr, Info);
}
- return 0;
+ return nullptr;
}
return HandleMemberPointerAccess(Info, BO->getLHS()->getType(), LV,
@@ -3092,14 +3141,18 @@ static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {
Result.set(VD, Info.CurrentCall->Index);
APValue &Val = Info.CurrentCall->createTemporary(VD, true);
- if (!VD->getInit()) {
+ const Expr *InitE = VD->getInit();
+ if (!InitE) {
Info.Diag(D->getLocStart(), diag::note_constexpr_uninitialized)
<< false << VD->getType();
Val = APValue();
return false;
}
- if (!EvaluateInPlace(Val, Info, Result, VD->getInit())) {
+ if (InitE->isValueDependent())
+ return false;
+
+ if (!EvaluateInPlace(Val, Info, Result, InitE)) {
// Wipe out any partially-computed value, to allow tracking that this
// evaluation failed.
Val = APValue();
@@ -3120,12 +3173,13 @@ static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl,
}
static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
- const Stmt *S, const SwitchCase *SC = 0);
+ const Stmt *S,
+ const SwitchCase *SC = nullptr);
/// Evaluate the body of a loop, and translate the result as appropriate.
static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info,
const Stmt *Body,
- const SwitchCase *Case = 0) {
+ const SwitchCase *Case = nullptr) {
BlockScopeRAII Scope(Info);
switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body, Case)) {
case ESR_Break:
@@ -3159,7 +3213,7 @@ static EvalStmtResult EvaluateSwitch(APValue &Result, EvalInfo &Info,
// Find the switch case corresponding to the value of the condition.
// FIXME: Cache this lookup.
- const SwitchCase *Found = 0;
+ const SwitchCase *Found = nullptr;
for (const SwitchCase *SC = SS->getSwitchCaseList(); SC;
SC = SC->getNextSwitchCase()) {
if (isa<DefaultStmt>(SC)) {
@@ -3224,7 +3278,7 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
case Stmt::CaseStmtClass:
case Stmt::DefaultStmtClass:
if (Case == S)
- Case = 0;
+ Case = nullptr;
break;
case Stmt::IfStmtClass: {
@@ -3291,13 +3345,12 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
case Stmt::DeclStmtClass: {
const DeclStmt *DS = cast<DeclStmt>(S);
- for (DeclStmt::const_decl_iterator DclIt = DS->decl_begin(),
- DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) {
+ for (const auto *DclIt : DS->decls()) {
// Each declaration initialization is its own full-expression.
// FIXME: This isn't quite right; if we're performing aggregate
// initialization, each braced subexpression is its own full-expression.
FullExpressionRAII Scope(Info);
- if (!EvaluateDecl(Info, *DclIt) && !Info.keepEvaluatingAfterFailure())
+ if (!EvaluateDecl(Info, DclIt) && !Info.keepEvaluatingAfterFailure())
return ESR_Failed;
}
return ESR_Succeeded;
@@ -3315,11 +3368,10 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
BlockScopeRAII Scope(Info);
const CompoundStmt *CS = cast<CompoundStmt>(S);
- for (CompoundStmt::const_body_iterator BI = CS->body_begin(),
- BE = CS->body_end(); BI != BE; ++BI) {
- EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI, Case);
+ for (const auto *BI : CS->body()) {
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, BI, Case);
if (ESR == ESR_Succeeded)
- Case = 0;
+ Case = nullptr;
else if (ESR != ESR_CaseNotFound)
return ESR;
}
@@ -3368,7 +3420,7 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody(), Case);
if (ESR != ESR_Continue)
return ESR;
- Case = 0;
+ Case = nullptr;
FullExpressionRAII CondScope(Info);
if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info))
@@ -3593,7 +3645,7 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
EvalStmtResult ESR = EvaluateStmt(Result, Info, Body);
if (ESR == ESR_Succeeded) {
- if (Callee->getResultType()->isVoidType())
+ if (Callee->getReturnType()->isVoidType())
return true;
Info.Diag(Callee->getLocEnd(), diag::note_constexpr_no_return);
}
@@ -3659,15 +3711,14 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
#ifndef NDEBUG
CXXRecordDecl::base_class_const_iterator BaseIt = RD->bases_begin();
#endif
- for (CXXConstructorDecl::init_const_iterator I = Definition->init_begin(),
- E = Definition->init_end(); I != E; ++I) {
+ for (const auto *I : Definition->inits()) {
LValue Subobject = This;
APValue *Value = &Result;
// Determine the subobject to initialize.
- FieldDecl *FD = 0;
- if ((*I)->isBaseInitializer()) {
- QualType BaseType((*I)->getBaseClass(), 0);
+ FieldDecl *FD = nullptr;
+ if (I->isBaseInitializer()) {
+ QualType BaseType(I->getBaseClass(), 0);
#ifndef NDEBUG
// Non-virtual base classes are initialized in the order in the class
// definition. We have already checked for virtual base classes.
@@ -3676,12 +3727,12 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
"base class initializers not in expected order");
++BaseIt;
#endif
- if (!HandleLValueDirectBase(Info, (*I)->getInit(), Subobject, RD,
+ if (!HandleLValueDirectBase(Info, I->getInit(), Subobject, RD,
BaseType->getAsCXXRecordDecl(), &Layout))
return false;
Value = &Result.getStructBase(BasesSeen++);
- } else if ((FD = (*I)->getMember())) {
- if (!HandleLValueMember(Info, (*I)->getInit(), Subobject, FD, &Layout))
+ } else if ((FD = I->getMember())) {
+ if (!HandleLValueMember(Info, I->getInit(), Subobject, FD, &Layout))
return false;
if (RD->isUnion()) {
Result = APValue(FD);
@@ -3689,13 +3740,11 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
} else {
Value = &Result.getStructField(FD->getFieldIndex());
}
- } else if (IndirectFieldDecl *IFD = (*I)->getIndirectMember()) {
+ } else if (IndirectFieldDecl *IFD = I->getIndirectMember()) {
// Walk the indirect field decl's chain to find the object to initialize,
// and make sure we've initialized every step along it.
- for (IndirectFieldDecl::chain_iterator C = IFD->chain_begin(),
- CE = IFD->chain_end();
- C != CE; ++C) {
- FD = cast<FieldDecl>(*C);
+ for (auto *C : IFD->chain()) {
+ FD = cast<FieldDecl>(C);
CXXRecordDecl *CD = cast<CXXRecordDecl>(FD->getParent());
// Switch the union field if it differs. This happens if we had
// preceding zero-initialization, and we're now initializing a union
@@ -3710,7 +3759,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
*Value = APValue(APValue::UninitStruct(), CD->getNumBases(),
std::distance(CD->field_begin(), CD->field_end()));
}
- if (!HandleLValueMember(Info, (*I)->getInit(), Subobject, FD))
+ if (!HandleLValueMember(Info, I->getInit(), Subobject, FD))
return false;
if (CD->isUnion())
Value = &Value->getUnionValue();
@@ -3722,8 +3771,8 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
}
FullExpressionRAII InitScope(Info);
- if (!EvaluateInPlace(*Value, Info, Subobject, (*I)->getInit()) ||
- (FD && FD->isBitField() && !truncateBitfieldValue(Info, (*I)->getInit(),
+ if (!EvaluateInPlace(*Value, Info, Subobject, I->getInit()) ||
+ (FD && FD->isBitField() && !truncateBitfieldValue(Info, I->getInit(),
*Value, FD))) {
// If we're checking for a potential constant expression, evaluate all
// initializers even if some of them fail.
@@ -3742,15 +3791,14 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
//===----------------------------------------------------------------------===//
namespace {
-// FIXME: RetTy is always bool. Remove it.
-template <class Derived, typename RetTy=bool>
+template <class Derived>
class ExprEvaluatorBase
- : public ConstStmtVisitor<Derived, RetTy> {
+ : public ConstStmtVisitor<Derived, bool> {
private:
- RetTy DerivedSuccess(const APValue &V, const Expr *E) {
+ bool DerivedSuccess(const APValue &V, const Expr *E) {
return static_cast<Derived*>(this)->Success(V, E);
}
- RetTy DerivedZeroInitialization(const Expr *E) {
+ bool DerivedZeroInitialization(const Expr *E) {
return static_cast<Derived*>(this)->ZeroInitialization(E);
}
@@ -3795,14 +3843,14 @@ private:
protected:
EvalInfo &Info;
- typedef ConstStmtVisitor<Derived, RetTy> StmtVisitorTy;
+ typedef ConstStmtVisitor<Derived, bool> StmtVisitorTy;
typedef ExprEvaluatorBase ExprEvaluatorBaseTy;
OptionalDiagnostic CCEDiag(const Expr *E, diag::kind D) {
return Info.CCEDiag(E, D);
}
- RetTy ZeroInitialization(const Expr *E) { return Error(E); }
+ bool ZeroInitialization(const Expr *E) { return Error(E); }
public:
ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {}
@@ -3819,28 +3867,28 @@ public:
return Error(E, diag::note_invalid_subexpr_in_const_expr);
}
- RetTy VisitStmt(const Stmt *) {
+ bool VisitStmt(const Stmt *) {
llvm_unreachable("Expression evaluator should not be called on stmts");
}
- RetTy VisitExpr(const Expr *E) {
+ bool VisitExpr(const Expr *E) {
return Error(E);
}
- RetTy VisitParenExpr(const ParenExpr *E)
+ bool VisitParenExpr(const ParenExpr *E)
{ return StmtVisitorTy::Visit(E->getSubExpr()); }
- RetTy VisitUnaryExtension(const UnaryOperator *E)
+ bool VisitUnaryExtension(const UnaryOperator *E)
{ return StmtVisitorTy::Visit(E->getSubExpr()); }
- RetTy VisitUnaryPlus(const UnaryOperator *E)
+ bool VisitUnaryPlus(const UnaryOperator *E)
{ return StmtVisitorTy::Visit(E->getSubExpr()); }
- RetTy VisitChooseExpr(const ChooseExpr *E)
+ bool VisitChooseExpr(const ChooseExpr *E)
{ return StmtVisitorTy::Visit(E->getChosenSubExpr()); }
- RetTy VisitGenericSelectionExpr(const GenericSelectionExpr *E)
+ bool VisitGenericSelectionExpr(const GenericSelectionExpr *E)
{ return StmtVisitorTy::Visit(E->getResultExpr()); }
- RetTy VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E)
+ bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E)
{ return StmtVisitorTy::Visit(E->getReplacement()); }
- RetTy VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E)
+ bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E)
{ return StmtVisitorTy::Visit(E->getExpr()); }
- RetTy VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) {
+ bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) {
// The initializer may not have been parsed yet, or might be erroneous.
if (!E->getExpr())
return Error(E);
@@ -3848,19 +3896,19 @@ public:
}
// We cannot create any objects for which cleanups are required, so there is
// nothing to do here; all cleanups must come from unevaluated subexpressions.
- RetTy VisitExprWithCleanups(const ExprWithCleanups *E)
+ bool VisitExprWithCleanups(const ExprWithCleanups *E)
{ return StmtVisitorTy::Visit(E->getSubExpr()); }
- RetTy VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E) {
+ bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E) {
CCEDiag(E, diag::note_constexpr_invalid_cast) << 0;
return static_cast<Derived*>(this)->VisitCastExpr(E);
}
- RetTy VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E) {
+ bool VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E) {
CCEDiag(E, diag::note_constexpr_invalid_cast) << 1;
return static_cast<Derived*>(this)->VisitCastExpr(E);
}
- RetTy VisitBinaryOperator(const BinaryOperator *E) {
+ bool VisitBinaryOperator(const BinaryOperator *E) {
switch (E->getOpcode()) {
default:
return Error(E);
@@ -3882,7 +3930,7 @@ public:
}
}
- RetTy VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) {
+ bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) {
// Evaluate and cache the common expression. We treat it as a temporary,
// even though it's not quite the same thing.
if (!Evaluate(Info.CurrentCall->createTemporary(E->getOpaqueValue(), false),
@@ -3892,7 +3940,7 @@ public:
return HandleConditionalOperator(E);
}
- RetTy VisitConditionalOperator(const ConditionalOperator *E) {
+ bool VisitConditionalOperator(const ConditionalOperator *E) {
bool IsBcpCall = false;
// If the condition (ignoring parens) is a __builtin_constant_p call,
// the result is a constant expression if it can be folded without
@@ -3900,7 +3948,7 @@ public:
// for discussion.
if (const CallExpr *CallCE =
dyn_cast<CallExpr>(E->getCond()->IgnoreParenCasts()))
- if (CallCE->isBuiltinCall() == Builtin::BI__builtin_constant_p)
+ if (CallCE->getBuiltinCallee() == Builtin::BI__builtin_constant_p)
IsBcpCall = true;
// Always assume __builtin_constant_p(...) ? ... : ... is a potential
@@ -3917,7 +3965,7 @@ public:
return true;
}
- RetTy VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
+ bool VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
if (APValue *Value = Info.CurrentCall->getTemporary(E))
return DerivedSuccess(*Value, E);
@@ -3931,18 +3979,18 @@ public:
return StmtVisitorTy::Visit(Source);
}
- RetTy VisitCallExpr(const CallExpr *E) {
+ bool VisitCallExpr(const CallExpr *E) {
const Expr *Callee = E->getCallee()->IgnoreParens();
QualType CalleeType = Callee->getType();
- const FunctionDecl *FD = 0;
- LValue *This = 0, ThisVal;
+ const FunctionDecl *FD = nullptr;
+ LValue *This = nullptr, ThisVal;
ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs());
bool HasQualifier = false;
// Extract function decl and 'this' pointer from the callee.
if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) {
- const ValueDecl *Member = 0;
+ const ValueDecl *Member = nullptr;
if (const MemberExpr *ME = dyn_cast<MemberExpr>(Callee)) {
// Explicit bound member calls, such as x.f() or p->g();
if (!EvaluateObjectArgument(Info, ME->getBase(), ThisVal))
@@ -4004,7 +4052,7 @@ public:
isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isVirtual())
return Error(E, diag::note_constexpr_virtual_call);
- const FunctionDecl *Definition = 0;
+ const FunctionDecl *Definition = nullptr;
Stmt *Body = FD->getBody(Definition);
APValue Result;
@@ -4016,28 +4064,28 @@ public:
return DerivedSuccess(Result, E);
}
- RetTy VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
+ bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
return StmtVisitorTy::Visit(E->getInitializer());
}
- RetTy VisitInitListExpr(const InitListExpr *E) {
+ bool VisitInitListExpr(const InitListExpr *E) {
if (E->getNumInits() == 0)
return DerivedZeroInitialization(E);
if (E->getNumInits() == 1)
return StmtVisitorTy::Visit(E->getInit(0));
return Error(E);
}
- RetTy VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
+ bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
return DerivedZeroInitialization(E);
}
- RetTy VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) {
+ bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) {
return DerivedZeroInitialization(E);
}
- RetTy VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) {
+ bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) {
return DerivedZeroInitialization(E);
}
/// A member expression where the object is a prvalue is itself a prvalue.
- RetTy VisitMemberExpr(const MemberExpr *E) {
+ bool VisitMemberExpr(const MemberExpr *E) {
assert(!E->isArrow() && "missing call to bound member function?");
APValue Val;
@@ -4061,7 +4109,7 @@ public:
DerivedSuccess(Result, E);
}
- RetTy VisitCastExpr(const CastExpr *E) {
+ bool VisitCastExpr(const CastExpr *E) {
switch (E->getCastKind()) {
default:
break;
@@ -4093,13 +4141,13 @@ public:
return Error(E);
}
- RetTy VisitUnaryPostInc(const UnaryOperator *UO) {
+ bool VisitUnaryPostInc(const UnaryOperator *UO) {
return VisitUnaryPostIncDec(UO);
}
- RetTy VisitUnaryPostDec(const UnaryOperator *UO) {
+ bool VisitUnaryPostDec(const UnaryOperator *UO) {
return VisitUnaryPostIncDec(UO);
}
- RetTy VisitUnaryPostIncDec(const UnaryOperator *UO) {
+ bool VisitUnaryPostIncDec(const UnaryOperator *UO) {
if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure())
return Error(UO);
@@ -4113,7 +4161,7 @@ public:
return DerivedSuccess(RVal, UO);
}
- RetTy VisitStmtExpr(const StmtExpr *E) {
+ bool VisitStmtExpr(const StmtExpr *E) {
// We will have checked the full-expressions inside the statement expression
// when they were completed, and don't need to check them again now.
if (Info.checkingForOverflow())
@@ -4162,11 +4210,11 @@ public:
namespace {
template<class Derived>
class LValueExprEvaluatorBase
- : public ExprEvaluatorBase<Derived, bool> {
+ : public ExprEvaluatorBase<Derived> {
protected:
LValue &Result;
typedef LValueExprEvaluatorBase LValueExprEvaluatorBaseTy;
- typedef ExprEvaluatorBase<Derived, bool> ExprEvaluatorBaseTy;
+ typedef ExprEvaluatorBase<Derived> ExprEvaluatorBaseTy;
bool Success(APValue::LValueBase B) {
Result.set(B);
@@ -4356,7 +4404,7 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
}
bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
- CallStackFrame *Frame = 0;
+ CallStackFrame *Frame = nullptr;
if (VD->hasLocalStorage() && Info.CurrentCall->Index > 1)
Frame = Info.CurrentCall;
@@ -4533,7 +4581,7 @@ bool LValueExprEvaluator::VisitUnaryPreIncDec(const UnaryOperator *UO) {
return handleIncDec(
this->Info, UO, Result, UO->getSubExpr()->getType(),
- UO->isIncrementOp(), 0);
+ UO->isIncrementOp(), nullptr);
}
bool LValueExprEvaluator::VisitCompoundAssignOperator(
@@ -4584,7 +4632,7 @@ bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) {
namespace {
class PointerExprEvaluator
- : public ExprEvaluatorBase<PointerExprEvaluator, bool> {
+ : public ExprEvaluatorBase<PointerExprEvaluator> {
LValue &Result;
bool Success(const Expr *E) {
@@ -4601,7 +4649,7 @@ public:
return true;
}
bool ZeroInitialization(const Expr *E) {
- return Success((Expr*)0);
+ return Success((Expr*)nullptr);
}
bool VisitBinaryOperator(const BinaryOperator *E);
@@ -4623,8 +4671,13 @@ public:
// Can't look at 'this' when checking a potential constant expression.
if (Info.checkingPotentialConstantExpression())
return false;
- if (!Info.CurrentCall->This)
- return Error(E);
+ if (!Info.CurrentCall->This) {
+ if (Info.getLangOpts().CPlusPlus11)
+ Info.Diag(E, diag::note_constexpr_this) << E->isImplicit();
+ else
+ Info.Diag(E);
+ return false;
+ }
Result = *Info.CurrentCall->This;
return true;
}
@@ -4729,7 +4782,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
if (Value.isInt()) {
unsigned Size = Info.Ctx.getTypeSize(E->getType());
uint64_t N = Value.getInt().extOrTrunc(Size).getZExtValue();
- Result.Base = (Expr*)0;
+ Result.Base = (Expr*)nullptr;
Result.Offset = CharUnits::fromQuantity(N);
Result.CallIndex = 0;
Result.Designator.setInvalid();
@@ -4769,7 +4822,7 @@ bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (IsStringLiteralCall(E))
return Success(E);
- switch (E->isBuiltinCall()) {
+ switch (E->getBuiltinCallee()) {
case Builtin::BI__builtin_addressof:
return EvaluateLValue(E->getArg(0), Result, Info);
@@ -4784,7 +4837,7 @@ bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
namespace {
class MemberPointerExprEvaluator
- : public ExprEvaluatorBase<MemberPointerExprEvaluator, bool> {
+ : public ExprEvaluatorBase<MemberPointerExprEvaluator> {
MemberPtr &Result;
bool Success(const ValueDecl *D) {
@@ -4801,7 +4854,7 @@ public:
return true;
}
bool ZeroInitialization(const Expr *E) {
- return Success((const ValueDecl*)0);
+ return Success((const ValueDecl*)nullptr);
}
bool VisitCastExpr(const CastExpr *E);
@@ -4872,7 +4925,7 @@ bool MemberPointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
namespace {
class RecordExprEvaluator
- : public ExprEvaluatorBase<RecordExprEvaluator, bool> {
+ : public ExprEvaluatorBase<RecordExprEvaluator> {
const LValue &This;
APValue &Result;
public:
@@ -4925,14 +4978,13 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
}
}
- for (RecordDecl::field_iterator I = RD->field_begin(), End = RD->field_end();
- I != End; ++I) {
+ for (const auto *I : RD->fields()) {
// -- if T is a reference type, no initialization is performed.
if (I->getType()->isReferenceType())
continue;
LValue Subobject = This;
- if (!HandleLValueMember(Info, E, Subobject, *I, &Layout))
+ if (!HandleLValueMember(Info, E, Subobject, I, &Layout))
return false;
ImplicitValueInitExpr VIE(I->getType());
@@ -4952,7 +5004,7 @@ bool RecordExprEvaluator::ZeroInitialization(const Expr *E) {
// object's first non-static named data member is zero-initialized
RecordDecl::field_iterator I = RD->field_begin();
if (I == RD->field_end()) {
- Result = APValue((const FieldDecl*)0);
+ Result = APValue((const FieldDecl*)nullptr);
return true;
}
@@ -5040,8 +5092,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
std::distance(RD->field_begin(), RD->field_end()));
unsigned ElementNo = 0;
bool Success = true;
- for (RecordDecl::field_iterator Field = RD->field_begin(),
- FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) {
+ for (const auto *Field : RD->fields()) {
// Anonymous bit-fields are not considered members of the class for
// purposes of aggregate initialization.
if (Field->isUnnamedBitfield())
@@ -5054,7 +5105,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
// FIXME: Diagnostics here should point to the end of the initializer
// list, not the start.
if (!HandleLValueMember(Info, HaveInit ? E->getInit(ElementNo) : E,
- Subobject, *Field, &Layout))
+ Subobject, Field, &Layout))
return false;
// Perform an implicit value-initialization for members beyond the end of
@@ -5069,7 +5120,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
APValue &FieldVal = Result.getStructField(Field->getFieldIndex());
if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
(Field->isBitField() && !truncateBitfieldValue(Info, Init,
- FieldVal, *Field))) {
+ FieldVal, Field))) {
if (!Info.keepEvaluatingAfterFailure())
return false;
Success = false;
@@ -5100,7 +5151,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
return ZeroInitialization(E);
}
- const FunctionDecl *Definition = 0;
+ const FunctionDecl *Definition = nullptr;
FD->getBody(Definition);
if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition))
@@ -5234,7 +5285,7 @@ static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info) {
namespace {
class VectorExprEvaluator
- : public ExprEvaluatorBase<VectorExprEvaluator, bool> {
+ : public ExprEvaluatorBase<VectorExprEvaluator> {
APValue &Result;
public:
@@ -5415,7 +5466,7 @@ bool VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
namespace {
class ArrayExprEvaluator
- : public ExprEvaluatorBase<ArrayExprEvaluator, bool> {
+ : public ExprEvaluatorBase<ArrayExprEvaluator> {
const LValue &This;
APValue &Result;
public:
@@ -5487,7 +5538,7 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
unsigned NumEltsToInit = E->getNumInits();
unsigned NumElts = CAT->getSize().getZExtValue();
- const Expr *FillerExpr = E->hasArrayFiller() ? E->getArrayFiller() : 0;
+ const Expr *FillerExpr = E->hasArrayFiller() ? E->getArrayFiller() : nullptr;
// If the initializer might depend on the array index, run it for each
// array element. For now, just whitelist non-class value-initialization.
@@ -5582,7 +5633,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
return EvaluateInPlace(*Value, Info, Subobject, &VIE);
}
- const FunctionDecl *Definition = 0;
+ const FunctionDecl *Definition = nullptr;
FD->getBody(Definition);
if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition))
@@ -5610,7 +5661,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
namespace {
class IntExprEvaluator
- : public ExprEvaluatorBase<IntExprEvaluator, bool> {
+ : public ExprEvaluatorBase<IntExprEvaluator> {
APValue &Result;
public:
IntExprEvaluator(EvalInfo &info, APValue &result)
@@ -5716,14 +5767,6 @@ public:
return ZeroInitialization(E);
}
- bool VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) {
- return Success(E->getValue(), E);
- }
-
- bool VisitBinaryTypeTraitExpr(const BinaryTypeTraitExpr *E) {
- return Success(E->getValue(), E);
- }
-
bool VisitTypeTraitExpr(const TypeTraitExpr *E) {
return Success(E->getValue(), E);
}
@@ -5964,7 +6007,7 @@ bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E) {
}
bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
- switch (unsigned BuiltinOp = E->isBuiltinCall()) {
+ switch (unsigned BuiltinOp = E->getBuiltinCallee()) {
default:
return ExprEvaluatorBaseTy::VisitCallExpr(E);
@@ -5983,7 +6026,17 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
// Expression had no side effects, but we couldn't statically determine the
// size of the referenced object.
- return Error(E);
+ switch (Info.EvalMode) {
+ case EvalInfo::EM_ConstantExpression:
+ case EvalInfo::EM_PotentialConstantExpression:
+ case EvalInfo::EM_ConstantFold:
+ case EvalInfo::EM_EvaluateForOverflow:
+ case EvalInfo::EM_IgnoreSideEffects:
+ return Error(E);
+ case EvalInfo::EM_ConstantExpressionUnevaluated:
+ case EvalInfo::EM_PotentialConstantExpressionUnevaluated:
+ return Success(-1ULL, E);
+ }
}
case Builtin::BI__builtin_bswap16:
@@ -6005,7 +6058,8 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_clz:
case Builtin::BI__builtin_clzl:
- case Builtin::BI__builtin_clzll: {
+ case Builtin::BI__builtin_clzll:
+ case Builtin::BI__builtin_clzs: {
APSInt Val;
if (!EvaluateInteger(E->getArg(0), Val, Info))
return false;
@@ -6020,7 +6074,8 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_ctz:
case Builtin::BI__builtin_ctzl:
- case Builtin::BI__builtin_ctzll: {
+ case Builtin::BI__builtin_ctzll:
+ case Builtin::BI__builtin_ctzs: {
APSInt Val;
if (!EvaluateInteger(E->getArg(0), Val, Info))
return false;
@@ -6256,11 +6311,11 @@ class DataRecursiveIntBinOpEvaluator {
const Expr *E;
EvalResult LHSResult; // meaningful only for binary operator expression.
enum { AnyExprKind, BinOpKind, BinOpVisitedLHSKind } Kind;
-
- Job() : StoredInfo(0) { }
+
+ Job() : StoredInfo(nullptr) {}
void startSpeculativeEval(EvalInfo &Info) {
OldEvalStatus = Info.EvalStatus;
- Info.EvalStatus.Diag = 0;
+ Info.EvalStatus.Diag = nullptr;
StoredInfo = &Info;
}
~Job() {
@@ -6886,8 +6941,9 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
}
CharUnits IntExprEvaluator::GetAlignOfType(QualType T) {
- // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
- // result shall be the alignment of the referenced type."
+ // C++ [expr.alignof]p3:
+ // When alignof is applied to a reference type, the result is the
+ // alignment of the referenced type.
if (const ReferenceType *Ref = T->getAs<ReferenceType>())
T = Ref->getPointeeType();
@@ -6906,7 +6962,7 @@ CharUnits IntExprEvaluator::GetAlignOfExpr(const Expr *E) {
// alignof decl is always accepted, even if it doesn't make sense: we default
// to 1 in those cases.
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- return Info.Ctx.getDeclAlign(DRE->getDecl(),
+ return Info.Ctx.getDeclAlign(DRE->getDecl(),
/*RefAsPointee*/true);
if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
@@ -7109,6 +7165,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLEvent:
case CK_NonAtomicToAtomic:
+ case CK_AddressSpaceConversion:
llvm_unreachable("invalid cast kind for integral value");
case CK_BitCast:
@@ -7247,7 +7304,7 @@ bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
namespace {
class FloatExprEvaluator
- : public ExprEvaluatorBase<FloatExprEvaluator, bool> {
+ : public ExprEvaluatorBase<FloatExprEvaluator> {
APFloat &Result;
public:
FloatExprEvaluator(EvalInfo &info, APFloat &result)
@@ -7308,7 +7365,7 @@ static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
}
bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
- switch (E->isBuiltinCall()) {
+ switch (E->getBuiltinCallee()) {
default:
return ExprEvaluatorBaseTy::VisitCallExpr(E);
@@ -7463,7 +7520,7 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
namespace {
class ComplexExprEvaluator
- : public ExprEvaluatorBase<ComplexExprEvaluator, bool> {
+ : public ExprEvaluatorBase<ComplexExprEvaluator> {
ComplexValue &Result;
public:
@@ -7581,6 +7638,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLEvent:
case CK_NonAtomicToAtomic:
+ case CK_AddressSpaceConversion:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
@@ -7847,7 +7905,7 @@ bool ComplexExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
namespace {
class AtomicExprEvaluator :
- public ExprEvaluatorBase<AtomicExprEvaluator, bool> {
+ public ExprEvaluatorBase<AtomicExprEvaluator> {
APValue &Result;
public:
AtomicExprEvaluator(EvalInfo &Info, APValue &Result)
@@ -7887,7 +7945,7 @@ static bool EvaluateAtomic(const Expr *E, APValue &Result, EvalInfo &Info) {
namespace {
class VoidExprEvaluator
- : public ExprEvaluatorBase<VoidExprEvaluator, bool> {
+ : public ExprEvaluatorBase<VoidExprEvaluator> {
public:
VoidExprEvaluator(EvalInfo &Info) : ExprEvaluatorBaseTy(Info) {}
@@ -7902,6 +7960,16 @@ public:
return true;
}
}
+
+ bool VisitCallExpr(const CallExpr *E) {
+ switch (E->getBuiltinCallee()) {
+ default:
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ case Builtin::BI__assume:
+ // The argument is not evaluated!
+ return true;
+ }
+ }
};
} // end anonymous namespace
@@ -7989,6 +8057,8 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
/// an object can indirectly refer to subobjects which were initialized earlier.
static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
const Expr *E, bool AllowNonLiteralTypes) {
+ assert(!E->isValueDependent());
+
if (!AllowNonLiteralTypes && !CheckLiteralType(Info, E, &This))
return false;
@@ -8008,6 +8078,9 @@ static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
/// EvaluateAsRValue - Try to evaluate this expression, performing an implicit
/// lvalue-to-rvalue cast if it is an lvalue.
static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
+ if (E->getType().isNull())
+ return false;
+
if (!CheckLiteralType(Info, E))
return false;
@@ -8035,6 +8108,13 @@ static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result,
IsConst = true;
return true;
}
+
+ // This case should be rare, but we need to check it before we check on
+ // the type below.
+ if (Exp->getType().isNull()) {
+ IsConst = false;
+ return true;
+ }
// FIXME: Evaluating values of large array and record types can cause
// performance problems. Only do so in C++11 for now.
@@ -8292,10 +8372,20 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::MaterializeTemporaryExprClass:
case Expr::PseudoObjectExprClass:
case Expr::AtomicExprClass:
- case Expr::InitListExprClass:
case Expr::LambdaExprClass:
return ICEDiag(IK_NotICE, E->getLocStart());
+ case Expr::InitListExprClass: {
+ // C++03 [dcl.init]p13: If T is a scalar type, then a declaration of the
+ // form "T x = { a };" is equivalent to "T x = a;".
+ // Unless we're initializing a reference, T is a scalar as it is known to be
+ // of integral or enumeration type.
+ if (E->isRValue())
+ if (cast<InitListExpr>(E)->getNumInits() == 1)
+ return CheckICE(cast<InitListExpr>(E)->getInit(0), Ctx);
+ return ICEDiag(IK_NotICE, E->getLocStart());
+ }
+
case Expr::SizeOfPackExprClass:
case Expr::GNUNullExprClass:
// GCC considers the GNU __null value to be an integral constant expression.
@@ -8314,8 +8404,6 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::ObjCBoolLiteralExprClass:
case Expr::CXXBoolLiteralExprClass:
case Expr::CXXScalarValueInitExprClass:
- case Expr::UnaryTypeTraitExprClass:
- case Expr::BinaryTypeTraitExprClass:
case Expr::TypeTraitExprClass:
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
@@ -8327,7 +8415,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
// constant expressions, but they can never be ICEs because an ICE cannot
// contain an operand of (pointer to) function type.
const CallExpr *CE = cast<CallExpr>(E);
- if (CE->isBuiltinCall())
+ if (CE->getBuiltinCallee())
return CheckEvalInICE(E, Ctx);
return ICEDiag(IK_NotICE, E->getLocStart());
}
@@ -8544,7 +8632,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
// extension. See GCC PR38377 for discussion.
if (const CallExpr *CallCE
= dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts()))
- if (CallCE->isBuiltinCall() == Builtin::BI__builtin_constant_p)
+ if (CallCE->getBuiltinCallee() == Builtin::BI__builtin_constant_p)
return CheckEvalInICE(E, Ctx);
ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx);
if (CondResult.Kind == IK_NotICE)
@@ -8602,7 +8690,7 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx,
bool Expr::isIntegerConstantExpr(const ASTContext &Ctx,
SourceLocation *Loc) const {
if (Ctx.getLangOpts().CPlusPlus11)
- return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, 0, Loc);
+ return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, nullptr, Loc);
ICEDiag D = CheckICE(this, Ctx);
if (D.Kind != IK_ICE) {
@@ -8654,6 +8742,28 @@ bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result,
return IsConstExpr;
}
+bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
+ const FunctionDecl *Callee,
+ ArrayRef<const Expr*> Args) const {
+ Expr::EvalStatus Status;
+ EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpressionUnevaluated);
+
+ ArgVector ArgValues(Args.size());
+ for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
+ I != E; ++I) {
+ if (!Evaluate(ArgValues[I - Args.begin()], Info, *I))
+ // If evaluation fails, throw away the argument entirely.
+ ArgValues[I - Args.begin()] = APValue();
+ if (Info.EvalStatus.HasSideEffects)
+ return false;
+ }
+
+ // Build fake call to Callee.
+ CallStackFrame Frame(Info, Callee->getLocation(), Callee, /*This*/nullptr,
+ ArgValues.data());
+ return Evaluate(Value, Info, this) && !Info.EvalStatus.HasSideEffects;
+}
+
bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
SmallVectorImpl<
PartialDiagnosticAt> &Diags) {
@@ -8670,7 +8780,7 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
EvalInfo::EM_PotentialConstantExpression);
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
- const CXXRecordDecl *RD = MD ? MD->getParent()->getCanonicalDecl() : 0;
+ const CXXRecordDecl *RD = MD ? MD->getParent()->getCanonicalDecl() : nullptr;
// Fabricate an arbitrary expression on the stack and pretend that it
// is a temporary being used as the 'this' pointer.
@@ -8689,8 +8799,32 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
Info.setEvaluatingDecl(This.getLValueBase(), Scratch);
HandleConstructorCall(Loc, This, Args, CD, Info, Scratch);
} else
- HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : 0,
+ HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : nullptr,
Args, FD->getBody(), Info, Scratch);
return Diags.empty();
}
+
+bool Expr::isPotentialConstantExprUnevaluated(Expr *E,
+ const FunctionDecl *FD,
+ SmallVectorImpl<
+ PartialDiagnosticAt> &Diags) {
+ Expr::EvalStatus Status;
+ Status.Diag = &Diags;
+
+ EvalInfo Info(FD->getASTContext(), Status,
+ EvalInfo::EM_PotentialConstantExpressionUnevaluated);
+
+ // Fabricate a call stack frame to give the arguments a plausible cover story.
+ ArrayRef<const Expr*> Args;
+ ArgVector ArgValues(0);
+ bool Success = EvaluateArgs(Args, ArgValues, Info);
+ (void)Success;
+ assert(Success &&
+ "Failed to set up arguments for potential constant evaluation");
+ CallStackFrame Frame(Info, SourceLocation(), FD, nullptr, ArgValues.data());
+
+ APValue ResultScratch;
+ Evaluate(ResultScratch, Info, E);
+ return Diags.empty();
+}
diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp
index 96ebe92ce3ab..88941075dd06 100644
--- a/lib/AST/ExternalASTSource.cpp
+++ b/lib/AST/ExternalASTSource.cpp
@@ -14,16 +14,44 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ExternalASTSource.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclarationName.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
ExternalASTSource::~ExternalASTSource() { }
+void ExternalASTSource::FindFileRegionDecls(FileID File, unsigned Offset,
+ unsigned Length,
+ SmallVectorImpl<Decl *> &Decls) {}
+
+void ExternalASTSource::CompleteRedeclChain(const Decl *D) {}
+
+void ExternalASTSource::CompleteType(TagDecl *Tag) {}
+
+void ExternalASTSource::CompleteType(ObjCInterfaceDecl *Class) {}
+
+void ExternalASTSource::ReadComments() {}
+
+void ExternalASTSource::StartedDeserializing() {}
+
+void ExternalASTSource::FinishedDeserializing() {}
+
+void ExternalASTSource::StartTranslationUnit(ASTConsumer *Consumer) {}
+
void ExternalASTSource::PrintStats() { }
+bool ExternalASTSource::layoutRecordType(
+ const RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
+ llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets) {
+ return false;
+}
+
Decl *ExternalASTSource::GetExternalDecl(uint32_t ID) {
- return 0;
+ return nullptr;
}
Selector ExternalASTSource::GetExternalSelector(uint32_t ID) {
@@ -35,12 +63,12 @@ uint32_t ExternalASTSource::GetNumExternalSelectors() {
}
Stmt *ExternalASTSource::GetExternalDeclStmt(uint64_t Offset) {
- return 0;
+ return nullptr;
}
CXXBaseSpecifier *
ExternalASTSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
- return 0;
+ return nullptr;
}
bool
@@ -60,3 +88,21 @@ ExternalASTSource::FindExternalLexicalDecls(const DeclContext *DC,
}
void ExternalASTSource::getMemoryBufferSizes(MemoryBufferSizes &sizes) const { }
+
+uint32_t ExternalASTSource::incrementGeneration(ASTContext &C) {
+ uint32_t OldGeneration = CurrentGeneration;
+
+ // Make sure the generation of the topmost external source for the context is
+ // incremented. That might not be us.
+ auto *P = C.getExternalSource();
+ if (P && P != this)
+ CurrentGeneration = P->incrementGeneration(C);
+ else {
+ // FIXME: Only bump the generation counter if the current generation number
+ // has been observed?
+ if (!++CurrentGeneration)
+ llvm::report_fatal_error("generation counter overflowed", false);
+ }
+
+ return OldGeneration;
+}
diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp
index 3d64310dc56b..eb3020c5f518 100644
--- a/lib/AST/InheritViz.cpp
+++ b/lib/AST/InheritViz.cpp
@@ -93,26 +93,25 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) {
// Display the base classes.
const CXXRecordDecl *Decl
= static_cast<const CXXRecordDecl *>(Type->getAs<RecordType>()->getDecl());
- for (CXXRecordDecl::base_class_const_iterator Base = Decl->bases_begin();
- Base != Decl->bases_end(); ++Base) {
- QualType CanonBaseType = Context.getCanonicalType(Base->getType());
+ for (const auto &Base : Decl->bases()) {
+ QualType CanonBaseType = Context.getCanonicalType(Base.getType());
// If this is not virtual inheritance, bump the direct base
// count for the type.
- if (!Base->isVirtual())
+ if (!Base.isVirtual())
++DirectBaseCount[CanonBaseType];
// Write out the node (if we need to).
- WriteNode(Base->getType(), Base->isVirtual());
+ WriteNode(Base.getType(), Base.isVirtual());
// Write out the edge.
Out << " ";
WriteNodeReference(Type, FromVirtual);
Out << " -> ";
- WriteNodeReference(Base->getType(), Base->isVirtual());
+ WriteNodeReference(Base.getType(), Base.isVirtual());
// Write out edge attributes to show the kind of inheritance.
- if (Base->isVirtual()) {
+ if (Base.isVirtual()) {
Out << " [ style=\"dashed\" ]";
}
Out << ";";
@@ -140,7 +139,7 @@ void CXXRecordDecl::viewInheritance(ASTContext& Context) const {
int FD;
SmallString<128> Filename;
- error_code EC =
+ std::error_code EC =
sys::fs::createTemporaryFile(Self.getAsString(), "dot", FD, Filename);
if (EC) {
llvm::errs() << "Error: " << EC.message() << "\n";
diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp
index 578466028ce8..b5f8c0f4bc87 100644
--- a/lib/AST/ItaniumCXXABI.cpp
+++ b/lib/AST/ItaniumCXXABI.cpp
@@ -33,12 +33,17 @@ namespace {
/// literals within a particular context.
class ItaniumNumberingContext : public MangleNumberingContext {
llvm::DenseMap<IdentifierInfo*, unsigned> VarManglingNumbers;
+ llvm::DenseMap<IdentifierInfo*, unsigned> TagManglingNumbers;
public:
/// Variable decls are numbered by identifier.
- virtual unsigned getManglingNumber(const VarDecl *VD) {
+ unsigned getManglingNumber(const VarDecl *VD, unsigned) override {
return ++VarManglingNumbers[VD->getIdentifier()];
}
+
+ unsigned getManglingNumber(const TagDecl *TD, unsigned) override {
+ return ++TagManglingNumbers[TD->getIdentifier()];
+ }
};
class ItaniumCXXABI : public CXXABI {
@@ -48,7 +53,7 @@ public:
ItaniumCXXABI(ASTContext &Ctx) : Context(Ctx) { }
std::pair<uint64_t, unsigned>
- getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const {
+ getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const override {
const TargetInfo &Target = Context.getTargetInfo();
TargetInfo::IntType PtrDiff = Target.getPtrDiffType(0);
uint64_t Width = Target.getTypeWidth(PtrDiff);
@@ -58,13 +63,17 @@ public:
return std::make_pair(Width, Align);
}
- CallingConv getDefaultMethodCallConv(bool isVariadic) const {
+ CallingConv getDefaultMethodCallConv(bool isVariadic) const override {
+ const llvm::Triple &T = Context.getTargetInfo().getTriple();
+ if (!isVariadic && T.isWindowsGNUEnvironment() &&
+ T.getArch() == llvm::Triple::x86)
+ return CC_X86ThisCall;
return CC_C;
}
// We cheat and just check that the class has a vtable pointer, and that it's
// only big enough to have a vtable pointer and nothing more (or less).
- bool isNearlyEmpty(const CXXRecordDecl *RD) const {
+ bool isNearlyEmpty(const CXXRecordDecl *RD) const override {
// Check that the class has a vtable pointer.
if (!RD->isDynamicClass())
@@ -76,21 +85,12 @@ public:
return Layout.getNonVirtualSize() == PointerSize;
}
- virtual MangleNumberingContext *createMangleNumberingContext() const {
+ MangleNumberingContext *createMangleNumberingContext() const override {
return new ItaniumNumberingContext();
}
};
-
-class ARMCXXABI : public ItaniumCXXABI {
-public:
- ARMCXXABI(ASTContext &Ctx) : ItaniumCXXABI(Ctx) { }
-};
}
CXXABI *clang::CreateItaniumCXXABI(ASTContext &Ctx) {
return new ItaniumCXXABI(Ctx);
}
-
-CXXABI *clang::CreateARMCXXABI(ASTContext &Ctx) {
- return new ARMCXXABI(Ctx);
-}
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 0621d7b1ad86..977d6fca2c40 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -11,7 +11,7 @@
// which is used in GCC 3.2 and newer (and many compilers that are
// ABI-compatible with GCC):
//
-// http://www.codesourcery.com/public/cxx-abi/abi.html
+// http://mentorembedded.github.io/cxx-abi/abi.html#mangling
//
//===----------------------------------------------------------------------===//
#include "clang/AST/Mangle.h"
@@ -21,6 +21,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/TypeLoc.h"
@@ -87,7 +88,7 @@ static const RecordDecl *GetLocalClassDecl(const Decl *D) {
D = cast<Decl>(DC);
DC = getEffectiveDeclContext(D);
}
- return 0;
+ return nullptr;
}
static const FunctionDecl *getStructor(const FunctionDecl *fn) {
@@ -101,11 +102,18 @@ static const NamedDecl *getStructor(const NamedDecl *decl) {
const FunctionDecl *fn = dyn_cast_or_null<FunctionDecl>(decl);
return (fn ? getStructor(fn) : decl);
}
-
+
+static bool isLambda(const NamedDecl *ND) {
+ const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(ND);
+ if (!Record)
+ return false;
+
+ return Record->isLambda();
+}
+
static const unsigned UnknownArity = ~0U;
class ItaniumMangleContextImpl : public ItaniumMangleContext {
- llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds;
typedef std::pair<const DeclContext*, IdentifierInfo*> DiscriminatorKeyTy;
llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
@@ -115,52 +123,47 @@ public:
DiagnosticsEngine &Diags)
: ItaniumMangleContext(Context, Diags) {}
- uint64_t getAnonymousStructId(const TagDecl *TD) {
- std::pair<llvm::DenseMap<const TagDecl *,
- uint64_t>::iterator, bool> Result =
- AnonStructIds.insert(std::make_pair(TD, AnonStructIds.size()));
- return Result.first->second;
- }
-
/// @name Mangler Entry Points
/// @{
- bool shouldMangleCXXName(const NamedDecl *D);
- void mangleCXXName(const NamedDecl *D, raw_ostream &);
- void mangleThunk(const CXXMethodDecl *MD,
- const ThunkInfo &Thunk,
- raw_ostream &);
+ bool shouldMangleCXXName(const NamedDecl *D) override;
+ bool shouldMangleStringLiteral(const StringLiteral *) override {
+ return false;
+ }
+ void mangleCXXName(const NamedDecl *D, raw_ostream &) override;
+ void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk,
+ raw_ostream &) override;
void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
const ThisAdjustment &ThisAdjustment,
- raw_ostream &);
- void mangleReferenceTemporary(const VarDecl *D,
- raw_ostream &);
- void mangleCXXVTable(const CXXRecordDecl *RD,
- raw_ostream &);
- void mangleCXXVTT(const CXXRecordDecl *RD,
- raw_ostream &);
+ raw_ostream &) override;
+ void mangleReferenceTemporary(const VarDecl *D, unsigned ManglingNumber,
+ raw_ostream &) override;
+ void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) override;
+ void mangleCXXVTT(const CXXRecordDecl *RD, raw_ostream &) override;
void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
- const CXXRecordDecl *Type,
- raw_ostream &);
- void mangleCXXRTTI(QualType T, raw_ostream &);
- void mangleCXXRTTIName(QualType T, raw_ostream &);
- void mangleTypeName(QualType T, raw_ostream &);
+ const CXXRecordDecl *Type, raw_ostream &) override;
+ void mangleCXXRTTI(QualType T, raw_ostream &) override;
+ void mangleCXXRTTIName(QualType T, raw_ostream &) override;
+ void mangleTypeName(QualType T, raw_ostream &) override;
void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
- raw_ostream &);
+ raw_ostream &) override;
void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
- raw_ostream &);
+ raw_ostream &) override;
+
+ void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &) override;
+ void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
+ void mangleDynamicAtExitDestructor(const VarDecl *D,
+ raw_ostream &Out) override;
+ void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &) override;
+ void mangleItaniumThreadLocalWrapper(const VarDecl *D,
+ raw_ostream &) override;
- void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &);
- void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out);
- void mangleDynamicAtExitDestructor(const VarDecl *D, raw_ostream &Out);
- void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &);
- void mangleItaniumThreadLocalWrapper(const VarDecl *D, raw_ostream &);
+ void mangleStringLiteral(const StringLiteral *, raw_ostream &) override;
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
// Lambda closure types are already numbered.
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND))
- if (RD->isLambda())
- return false;
+ if (isLambda(ND))
+ return false;
// Anonymous tags are already numbered.
if (const TagDecl *Tag = dyn_cast<TagDecl>(ND)) {
@@ -250,7 +253,7 @@ class CXXNameMangler {
public:
CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out_,
- const NamedDecl *D = 0)
+ const NamedDecl *D = nullptr)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(0),
SeqID(0) {
// These can't be mangled without a ctor type or dtor type.
@@ -285,11 +288,13 @@ public:
void mangleNumber(int64_t Number);
void mangleFloat(const llvm::APFloat &F);
void mangleFunctionEncoding(const FunctionDecl *FD);
+ void mangleSeqID(unsigned SeqID);
void mangleName(const NamedDecl *ND);
void mangleType(QualType T);
void mangleNameOrStandardSubstitution(const NamedDecl *ND);
private:
+
bool mangleSubstitution(const NamedDecl *ND);
bool mangleSubstitution(QualType T);
bool mangleSubstitution(TemplateName Template);
@@ -454,6 +459,25 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
if (!Context.shouldMangleDeclName(FD))
return;
+ if (FD->hasAttr<EnableIfAttr>()) {
+ FunctionTypeDepthState Saved = FunctionTypeDepth.push();
+ Out << "Ua9enable_ifI";
+ // FIXME: specific_attr_iterator iterates in reverse order. Fix that and use
+ // it here.
+ for (AttrVec::const_reverse_iterator I = FD->getAttrs().rbegin(),
+ E = FD->getAttrs().rend();
+ I != E; ++I) {
+ EnableIfAttr *EIA = dyn_cast<EnableIfAttr>(*I);
+ if (!EIA)
+ continue;
+ Out << 'X';
+ mangleExpression(EIA->getCond());
+ Out << 'E';
+ }
+ Out << 'E';
+ FunctionTypeDepth.pop(Saved);
+ }
+
// Whether the mangling of a function type includes the return type depends on
// the context and the nature of the function. The rules for deciding whether
// the return type is included are:
@@ -535,15 +559,7 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
return Spec->getSpecializedTemplate();
}
- return 0;
-}
-
-static bool isLambda(const NamedDecl *ND) {
- const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(ND);
- if (!Record)
- return false;
-
- return Record->isLambda();
+ return nullptr;
}
void CXXNameMangler::mangleName(const NamedDecl *ND) {
@@ -570,7 +586,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
// Check if we have a template.
- const TemplateArgumentList *TemplateArgs = 0;
+ const TemplateArgumentList *TemplateArgs = nullptr;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleUnscopedTemplateName(TD);
mangleTemplateArgs(*TemplateArgs);
@@ -833,6 +849,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
switch (type->getTypeClass()) {
case Type::Builtin:
case Type::Complex:
+ case Type::Adjusted:
case Type::Decayed:
case Type::Pointer:
case Type::BlockPointer:
@@ -983,26 +1000,27 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
// Pretend we had a different nested name specifier.
newQualifier = NestedNameSpecifier::Create(getASTContext(),
- /*prefix*/ 0,
+ /*prefix*/ nullptr,
/*template*/ false,
type.getTypePtr());
} else if (NamespaceDecl *nspace =
dyn_cast<NamespaceDecl>(firstQualifierLookup)) {
newQualifier = NestedNameSpecifier::Create(getASTContext(),
- /*prefix*/ 0,
+ /*prefix*/ nullptr,
nspace);
} else if (NamespaceAliasDecl *alias =
dyn_cast<NamespaceAliasDecl>(firstQualifierLookup)) {
newQualifier = NestedNameSpecifier::Create(getASTContext(),
- /*prefix*/ 0,
+ /*prefix*/ nullptr,
alias);
} else {
// No sensible mangling to do here.
- newQualifier = 0;
+ newQualifier = nullptr;
}
if (newQualifier)
- return mangleUnresolvedPrefix(newQualifier, /*lookup*/ 0, recursive);
+ return mangleUnresolvedPrefix(newQualifier, /*lookup*/ nullptr,
+ recursive);
} else {
Out << "sr";
@@ -1025,26 +1043,25 @@ void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *qualifier,
DeclarationName name,
unsigned knownArity) {
if (qualifier) mangleUnresolvedPrefix(qualifier, firstQualifierLookup);
- mangleUnqualifiedName(0, name, knownArity);
+ mangleUnqualifiedName(nullptr, name, knownArity);
}
static const FieldDecl *FindFirstNamedDataMember(const RecordDecl *RD) {
assert(RD->isAnonymousStructOrUnion() &&
"Expected anonymous struct or union!");
- for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
- I != E; ++I) {
+ for (const auto *I : RD->fields()) {
if (I->getIdentifier())
- return *I;
+ return I;
if (const RecordType *RT = I->getType()->getAs<RecordType>())
if (const FieldDecl *NamedDataMember =
FindFirstNamedDataMember(RT->getDecl()))
return NamedDataMember;
- }
+ }
// We didn't find a named data member.
- return 0;
+ return nullptr;
}
void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
@@ -1148,7 +1165,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
}
// Get a unique id for the anonymous struct.
- uint64_t AnonStructId = Context.getAnonymousStructId(TD);
+ unsigned AnonStructId = Context.getAnonymousStructId(TD);
// Mangle it as a source name in the form
// [n] $_<id>
@@ -1250,7 +1267,7 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND,
}
// Check if we have a template.
- const TemplateArgumentList *TemplateArgs = 0;
+ const TemplateArgumentList *TemplateArgs = nullptr;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleTemplatePrefix(TD, NoFunction);
mangleTemplateArgs(*TemplateArgs);
@@ -1490,7 +1507,7 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
return;
// Check if we have a template.
- const TemplateArgumentList *TemplateArgs = 0;
+ const TemplateArgumentList *TemplateArgs = nullptr;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleTemplatePrefix(TD);
mangleTemplateArgs(*TemplateArgs);
@@ -1514,7 +1531,7 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
if (OverloadedTemplateStorage *Overloaded
= Template.getAsOverloadedTemplate()) {
- mangleUnqualifiedName(0, (*Overloaded->begin())->getDeclName(),
+ mangleUnqualifiedName(nullptr, (*Overloaded->begin())->getDeclName(),
UnknownArity);
return;
}
@@ -1556,8 +1573,8 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND,
void CXXNameMangler::mangleType(TemplateName TN) {
if (mangleSubstitution(TN))
return;
-
- TemplateDecl *TD = 0;
+
+ TemplateDecl *TD = nullptr;
switch (TN.getKind()) {
case TemplateName::QualifiedTemplate:
@@ -1584,7 +1601,7 @@ void CXXNameMangler::mangleType(TemplateName TN) {
// <class-enum-type> ::= <name>
// <name> ::= <nested-name>
- mangleUnresolvedPrefix(Dependent->getQualifier(), 0);
+ mangleUnresolvedPrefix(Dependent->getQualifier(), nullptr);
mangleSourceName(Dependent->getIdentifier());
break;
}
@@ -1919,7 +1936,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
// ::= x # long long, __int64
// ::= y # unsigned long long, __int64
// ::= n # __int128
- // UNSUPPORTED: ::= o # unsigned __int128
+ // ::= o # unsigned __int128
// ::= f # float
// ::= d # double
// ::= e # long double, __float80
@@ -2012,11 +2029,11 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
// <bare-function-type> ::= <signature type>+
if (MangleReturnType) {
FunctionTypeDepth.enterResultType();
- mangleType(Proto->getResultType());
+ mangleType(Proto->getReturnType());
FunctionTypeDepth.leaveResultType();
}
- if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) {
+ if (Proto->getNumParams() == 0 && !Proto->isVariadic()) {
// <builtin-type> ::= v # void
Out << 'v';
@@ -2024,10 +2041,8 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
return;
}
- for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
- ArgEnd = Proto->arg_type_end();
- Arg != ArgEnd; ++Arg)
- mangleType(Context.getASTContext().getSignatureParameterType(*Arg));
+ for (const auto &Arg : Proto->param_types())
+ mangleType(Context.getASTContext().getSignatureParameterType(Arg));
FunctionTypeDepth.pop(saved);
@@ -2158,11 +2173,20 @@ void CXXNameMangler::mangleType(const ComplexType *T) {
void CXXNameMangler::mangleNeonVectorType(const VectorType *T) {
QualType EltType = T->getElementType();
assert(EltType->isBuiltinType() && "Neon vector element not a BuiltinType");
- const char *EltName = 0;
+ const char *EltName = nullptr;
if (T->getVectorKind() == VectorType::NeonPolyVector) {
switch (cast<BuiltinType>(EltType)->getKind()) {
- case BuiltinType::SChar: EltName = "poly8_t"; break;
- case BuiltinType::Short: EltName = "poly16_t"; break;
+ case BuiltinType::SChar:
+ case BuiltinType::UChar:
+ EltName = "poly8_t";
+ break;
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ EltName = "poly16_t";
+ break;
+ case BuiltinType::ULongLong:
+ EltName = "poly64_t";
+ break;
default: llvm_unreachable("unexpected Neon polynomial vector element type");
}
} else {
@@ -2175,13 +2199,14 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) {
case BuiltinType::UInt: EltName = "uint32_t"; break;
case BuiltinType::LongLong: EltName = "int64_t"; break;
case BuiltinType::ULongLong: EltName = "uint64_t"; break;
+ case BuiltinType::Double: EltName = "float64_t"; break;
case BuiltinType::Float: EltName = "float32_t"; break;
case BuiltinType::Half: EltName = "float16_t";break;
default:
llvm_unreachable("unexpected Neon vector element type");
}
}
- const char *BaseName = 0;
+ const char *BaseName = nullptr;
unsigned BitSize = (T->getNumElements() *
getASTContext().getTypeSize(EltType));
if (BitSize == 64)
@@ -2202,6 +2227,7 @@ static StringRef mangleAArch64VectorBase(const BuiltinType *EltType) {
return "Int16";
case BuiltinType::Int:
return "Int32";
+ case BuiltinType::Long:
case BuiltinType::LongLong:
return "Int64";
case BuiltinType::UChar:
@@ -2210,6 +2236,7 @@ static StringRef mangleAArch64VectorBase(const BuiltinType *EltType) {
return "Uint16";
case BuiltinType::UInt:
return "Uint32";
+ case BuiltinType::ULong:
case BuiltinType::ULongLong:
return "Uint64";
case BuiltinType::Half:
@@ -2245,7 +2272,7 @@ void CXXNameMangler::mangleAArch64NeonVectorType(const VectorType *T) {
case BuiltinType::UShort:
EltName = "Poly16";
break;
- case BuiltinType::ULongLong:
+ case BuiltinType::ULong:
EltName = "Poly64";
break;
default:
@@ -2270,8 +2297,13 @@ void CXXNameMangler::mangleAArch64NeonVectorType(const VectorType *T) {
void CXXNameMangler::mangleType(const VectorType *T) {
if ((T->getVectorKind() == VectorType::NeonVector ||
T->getVectorKind() == VectorType::NeonPolyVector)) {
- if (getASTContext().getTargetInfo().getTriple().getArch() ==
- llvm::Triple::aarch64)
+ llvm::Triple Target = getASTContext().getTargetInfo().getTriple();
+ llvm::Triple::ArchType Arch =
+ getASTContext().getTargetInfo().getTriple().getArch();
+ if ((Arch == llvm::Triple::aarch64 ||
+ Arch == llvm::Triple::aarch64_be ||
+ Arch == llvm::Triple::arm64_be ||
+ Arch == llvm::Triple::arm64) && !Target.isOSDarwin())
mangleAArch64NeonVectorType(T);
else
mangleNeonVectorType(T);
@@ -2311,9 +2343,8 @@ void CXXNameMangler::mangleType(const ObjCObjectType *T) {
SmallString<64> QualStr;
llvm::raw_svector_ostream QualOS(QualStr);
QualOS << "objcproto";
- ObjCObjectType::qual_iterator i = T->qual_begin(), e = T->qual_end();
- for ( ; i != e; ++i) {
- StringRef name = (*i)->getName();
+ for (const auto *I : T->quals()) {
+ StringRef name = I->getName();
QualOS << name.size() << name;
}
QualOS.flush();
@@ -2352,10 +2383,37 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
}
void CXXNameMangler::mangleType(const DependentNameType *T) {
+ // Proposal by cxx-abi-dev, 2014-03-26
+ // <class-enum-type> ::= <name> # non-dependent or dependent type name or
+ // # dependent elaborated type specifier using
+ // # 'typename'
+ // ::= Ts <name> # dependent elaborated type specifier using
+ // # 'struct' or 'class'
+ // ::= Tu <name> # dependent elaborated type specifier using
+ // # 'union'
+ // ::= Te <name> # dependent elaborated type specifier using
+ // # 'enum'
+ switch (T->getKeyword()) {
+ case ETK_Typename:
+ break;
+ case ETK_Struct:
+ case ETK_Class:
+ case ETK_Interface:
+ Out << "Ts";
+ break;
+ case ETK_Union:
+ Out << "Tu";
+ break;
+ case ETK_Enum:
+ Out << "Te";
+ break;
+ default:
+ llvm_unreachable("unexpected keyword for dependent type name");
+ }
// Typename types are always nested
Out << 'N';
manglePrefix(T->getQualifier());
- mangleSourceName(T->getIdentifier());
+ mangleSourceName(T->getIdentifier());
Out << 'E';
}
@@ -2438,7 +2496,7 @@ void CXXNameMangler::mangleType(const AutoType *T) {
}
void CXXNameMangler::mangleType(const AtomicType *T) {
- // <type> ::= U <source-name> <type> # vendor extended type qualifier
+ // <type> ::= U <source-name> <type> # vendor extended type qualifier
// (Until there's a standardized mangling...)
Out << "U7_Atomic";
mangleType(T->getValueType());
@@ -2581,8 +2639,6 @@ recurse:
case Expr::ShuffleVectorExprClass:
case Expr::ConvertVectorExprClass:
case Expr::StmtExprClass:
- case Expr::UnaryTypeTraitExprClass:
- case Expr::BinaryTypeTraitExprClass:
case Expr::TypeTraitExprClass:
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
@@ -2618,7 +2674,6 @@ recurse:
llvm_unreachable("cannot mangle opaque value; mangling wrong thing?");
case Expr::InitListExprClass: {
- // Proposal by Jason Merrill, 2012-01-03
Out << "il";
const InitListExpr *InitList = cast<InitListExpr>(E);
for (unsigned i = 0, e = InitList->getNumInits(); i != e; ++i)
@@ -2683,7 +2738,6 @@ recurse:
Out << '_';
mangleType(New->getAllocatedType());
if (New->hasInitializer()) {
- // Proposal by Jason Merrill, 2012-01-03
if (New->getInitializationStyle() == CXXNewExpr::ListInit)
Out << "il";
else
@@ -2714,15 +2768,15 @@ recurse:
case Expr::MemberExprClass: {
const MemberExpr *ME = cast<MemberExpr>(E);
mangleMemberExpr(ME->getBase(), ME->isArrow(),
- ME->getQualifier(), 0, ME->getMemberDecl()->getDeclName(),
- Arity);
+ ME->getQualifier(), nullptr,
+ ME->getMemberDecl()->getDeclName(), Arity);
break;
}
case Expr::UnresolvedMemberExprClass: {
const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E);
mangleMemberExpr(ME->getBase(), ME->isArrow(),
- ME->getQualifier(), 0, ME->getMemberName(),
+ ME->getQualifier(), nullptr, ME->getMemberName(),
Arity);
if (ME->hasExplicitTemplateArgs())
mangleTemplateArgs(ME->getExplicitTemplateArgs());
@@ -2742,7 +2796,7 @@ recurse:
case Expr::UnresolvedLookupExprClass: {
const UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(E);
- mangleUnresolvedName(ULE->getQualifier(), 0, ULE->getName(), Arity);
+ mangleUnresolvedName(ULE->getQualifier(), nullptr, ULE->getName(), Arity);
// All the <unresolved-name> productions end in a
// base-unresolved-name, where <template-args> are just tacked
@@ -2769,7 +2823,6 @@ recurse:
const CXXConstructExpr *CE = cast<CXXConstructExpr>(E);
unsigned N = CE->getNumArgs();
- // Proposal by Jason Merrill, 2012-01-03
if (CE->isListInitialization())
Out << "tl";
else
@@ -3005,7 +3058,8 @@ recurse:
case Expr::DependentScopeDeclRefExprClass: {
const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E);
- mangleUnresolvedName(DRE->getQualifier(), 0, DRE->getDeclName(), Arity);
+ mangleUnresolvedName(DRE->getQualifier(), nullptr, DRE->getDeclName(),
+ Arity);
// All the <unresolved-name> productions end in a
// base-unresolved-name, where <template-args> are just tacked
@@ -3342,10 +3396,8 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
case TemplateArgument::Pack: {
// <template-arg> ::= J <template-arg>* E
Out << 'J';
- for (TemplateArgument::pack_iterator PA = A.pack_begin(),
- PAEnd = A.pack_end();
- PA != PAEnd; ++PA)
- mangleTemplateArg(*PA);
+ for (const auto &P : A.pack_elements())
+ mangleTemplateArg(P);
Out << 'E';
}
}
@@ -3360,6 +3412,27 @@ void CXXNameMangler::mangleTemplateParameter(unsigned Index) {
Out << 'T' << (Index - 1) << '_';
}
+void CXXNameMangler::mangleSeqID(unsigned SeqID) {
+ if (SeqID == 1)
+ Out << '0';
+ else if (SeqID > 1) {
+ SeqID--;
+
+ // <seq-id> is encoded in base-36, using digits and upper case letters.
+ char Buffer[7]; // log(2**32) / log(36) ~= 7
+ MutableArrayRef<char> BufferRef(Buffer);
+ MutableArrayRef<char>::reverse_iterator I = BufferRef.rbegin();
+
+ for (; SeqID != 0; SeqID /= 36) {
+ unsigned C = SeqID % 36;
+ *I++ = (C < 10 ? '0' + C : 'A' + C - 10);
+ }
+
+ Out.write(I.base(), I - BufferRef.rbegin());
+ }
+ Out << '_';
+}
+
void CXXNameMangler::mangleExistingSubstitution(QualType type) {
bool result = mangleSubstitution(type);
assert(result && "no existing substitution for type");
@@ -3416,30 +3489,8 @@ bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
return false;
unsigned SeqID = I->second;
- if (SeqID == 0)
- Out << "S_";
- else {
- SeqID--;
-
- // <seq-id> is encoded in base-36, using digits and upper case letters.
- char Buffer[10];
- char *BufferPtr = llvm::array_endof(Buffer);
-
- if (SeqID == 0) *--BufferPtr = '0';
-
- while (SeqID) {
- assert(BufferPtr > Buffer && "Buffer overflow!");
-
- char c = static_cast<char>(SeqID % 36);
-
- *--BufferPtr = (c < 10 ? '0' + c : 'A' + c - 10);
- SeqID /= 36;
- }
-
- Out << 'S'
- << StringRef(BufferPtr, llvm::array_endof(Buffer)-BufferPtr)
- << '_';
- }
+ Out << 'S';
+ mangleSeqID(SeqID);
return true;
}
@@ -3732,12 +3783,15 @@ ItaniumMangleContextImpl::mangleItaniumThreadLocalWrapper(const VarDecl *D,
}
void ItaniumMangleContextImpl::mangleReferenceTemporary(const VarDecl *D,
+ unsigned ManglingNumber,
raw_ostream &Out) {
// We match the GCC mangling here.
// <special-name> ::= GR <object name>
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZGR";
Mangler.mangleName(D);
+ assert(ManglingNumber > 0 && "Reference temporary mangling number is zero!");
+ Mangler.mangleSeqID(ManglingNumber - 1);
}
void ItaniumMangleContextImpl::mangleCXXVTable(const CXXRecordDecl *RD,
@@ -3789,6 +3843,10 @@ void ItaniumMangleContextImpl::mangleTypeName(QualType Ty, raw_ostream &Out) {
mangleCXXRTTIName(Ty, Out);
}
+void ItaniumMangleContextImpl::mangleStringLiteral(const StringLiteral *, raw_ostream &) {
+ llvm_unreachable("Can't mangle string literals");
+}
+
ItaniumMangleContext *
ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
return new ItaniumMangleContextImpl(Context, Diags);
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index 231ef036d829..fdc00e389350 100644
--- a/lib/AST/Mangle.cpp
+++ b/lib/AST/Mangle.cpp
@@ -11,13 +11,13 @@
//
//===----------------------------------------------------------------------===//
#include "clang/AST/Attr.h"
-#include "clang/AST/Mangle.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/Mangle.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -64,7 +64,7 @@ static bool isExternC(const NamedDecl *ND) {
static StdOrFastCC getStdOrFastCallMangling(const ASTContext &Context,
const NamedDecl *ND) {
const TargetInfo &TI = Context.getTargetInfo();
- llvm::Triple Triple = TI.getTriple();
+ const llvm::Triple &Triple = TI.getTriple();
if (!Triple.isOSWindows() || Triple.getArch() != llvm::Triple::x86)
return SOF_OTHER;
@@ -163,13 +163,9 @@ void MangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) {
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
if (!MD->isStatic())
++ArgWords;
- for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
- ArgEnd = Proto->arg_type_end();
- Arg != ArgEnd; ++Arg) {
- QualType AT = *Arg;
+ for (const auto &AT : Proto->param_types())
// Size should be aligned to DWORD boundary
ArgWords += llvm::RoundUpToAlignment(ASTContext.getTypeSize(AT), 32) / 32;
- }
Out << 4 * ArgWords;
}
@@ -246,7 +242,9 @@ void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD,
OS << (MD->isInstanceMethod() ? '-' : '+') << '[' << CD->getName();
if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD))
OS << '(' << *CID << ')';
- OS << ' ' << MD->getSelector().getAsString() << ']';
+ OS << ' ';
+ MD->getSelector().print(OS);
+ OS << ']';
Out << OS.str().size() << OS.str();
}
diff --git a/lib/AST/MangleNumberingContext.cpp b/lib/AST/MangleNumberingContext.cpp
index 91ef0e2240d8..5f40f0347d0e 100644
--- a/lib/AST/MangleNumberingContext.cpp
+++ b/lib/AST/MangleNumberingContext.cpp
@@ -24,7 +24,7 @@ MangleNumberingContext::getManglingNumber(const CXXMethodDecl *CallOperator) {
= CallOperator->getType()->getAs<FunctionProtoType>();
ASTContext &Context = CallOperator->getASTContext();
- QualType Key = Context.getFunctionType(Context.VoidTy, Proto->getArgTypes(),
+ QualType Key = Context.getFunctionType(Context.VoidTy, Proto->getParamTypes(),
FunctionProtoType::ExtProtoInfo());
Key = Context.getCanonicalType(Key);
return ++ManglingNumbers[Key->castAs<FunctionProtoType>()];
@@ -33,11 +33,13 @@ MangleNumberingContext::getManglingNumber(const CXXMethodDecl *CallOperator) {
unsigned
MangleNumberingContext::getManglingNumber(const BlockDecl *BD) {
// FIXME: Compute a BlockPointerType? Not obvious how.
- const Type *Ty = 0;
+ const Type *Ty = nullptr;
return ++ManglingNumbers[Ty];
}
unsigned
-MangleNumberingContext::getManglingNumber(const TagDecl *TD) {
- return ++TagManglingNumbers[TD->getIdentifier()];
+MangleNumberingContext::getStaticLocalNumber(const VarDecl *VD) {
+ // FIXME: Compute a BlockPointerType? Not obvious how.
+ const Type *Ty = nullptr;
+ return ++ManglingNumbers[Ty];
}
diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp
index 4a93ea1f417f..6870315b2160 100644
--- a/lib/AST/MicrosoftCXXABI.cpp
+++ b/lib/AST/MicrosoftCXXABI.cpp
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "CXXABI.h"
-#include "clang/AST/Attr.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/RecordLayout.h"
@@ -28,15 +28,15 @@ namespace {
/// \brief Numbers things which need to correspond across multiple TUs.
/// Typically these are things like static locals, lambdas, or blocks.
class MicrosoftNumberingContext : public MangleNumberingContext {
- unsigned NumStaticLocals;
-
public:
- MicrosoftNumberingContext() : NumStaticLocals(0) { }
+ unsigned getManglingNumber(const VarDecl *VD,
+ unsigned MSLocalManglingNumber) override {
+ return MSLocalManglingNumber;
+ }
- /// Static locals are numbered by source order.
- virtual unsigned getManglingNumber(const VarDecl *VD) {
- assert(VD->isStaticLocal());
- return ++NumStaticLocals;
+ unsigned getManglingNumber(const TagDecl *TD,
+ unsigned MSLocalManglingNumber) override {
+ return MSLocalManglingNumber;
}
};
@@ -46,16 +46,16 @@ public:
MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { }
std::pair<uint64_t, unsigned>
- getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const;
+ getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const override;
- CallingConv getDefaultMethodCallConv(bool isVariadic) const {
+ CallingConv getDefaultMethodCallConv(bool isVariadic) const override {
if (!isVariadic &&
Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
return CC_X86ThisCall;
return CC_C;
}
- bool isNearlyEmpty(const CXXRecordDecl *RD) const {
+ bool isNearlyEmpty(const CXXRecordDecl *RD) const override {
// FIXME: Audit the corners
if (!RD->isDynamicClass())
return false;
@@ -69,7 +69,7 @@ public:
Layout.getNonVirtualSize() == PointerSize * 2;
}
- MangleNumberingContext *createMangleNumberingContext() const {
+ MangleNumberingContext *createMangleNumberingContext() const override {
return new MicrosoftNumberingContext();
}
};
@@ -92,26 +92,27 @@ static bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) {
return false;
}
-static MSInheritanceModel MSInheritanceAttrToModel(attr::Kind Kind) {
- switch (Kind) {
- default: llvm_unreachable("expected MS inheritance attribute");
- case attr::SingleInheritance: return MSIM_Single;
- case attr::MultipleInheritance: return MSIM_Multiple;
- case attr::VirtualInheritance: return MSIM_Virtual;
- case attr::UnspecifiedInheritance: return MSIM_Unspecified;
- }
+MSInheritanceAttr::Spelling CXXRecordDecl::calculateInheritanceModel() const {
+ if (!hasDefinition() || isParsingBaseSpecifiers())
+ return MSInheritanceAttr::Keyword_unspecified_inheritance;
+ if (getNumVBases() > 0)
+ return MSInheritanceAttr::Keyword_virtual_inheritance;
+ if (usesMultipleInheritanceModel(this))
+ return MSInheritanceAttr::Keyword_multiple_inheritance;
+ return MSInheritanceAttr::Keyword_single_inheritance;
}
-MSInheritanceModel CXXRecordDecl::getMSInheritanceModel() const {
- if (Attr *IA = this->getAttr<MSInheritanceAttr>())
- return MSInheritanceAttrToModel(IA->getKind());
- // If there was no explicit attribute, the record must be defined already, and
- // we can figure out the inheritance model from its other properties.
- if (this->getNumVBases() > 0)
- return MSIM_Virtual;
- if (usesMultipleInheritanceModel(this))
- return this->isPolymorphic() ? MSIM_MultiplePolymorphic : MSIM_Multiple;
- return this->isPolymorphic() ? MSIM_SinglePolymorphic : MSIM_Single;
+MSInheritanceAttr::Spelling
+CXXRecordDecl::getMSInheritanceModel() const {
+ MSInheritanceAttr *IA = getAttr<MSInheritanceAttr>();
+ assert(IA && "Expected MSInheritanceAttr on the CXXRecordDecl!");
+ return IA->getSemanticSpelling();
+}
+
+MSVtorDispAttr::Mode CXXRecordDecl::getMSVtorDispMode() const {
+ if (MSVtorDispAttr *VDA = getAttr<MSVtorDispAttr>())
+ return VDA->getVtorDispMode();
+ return MSVtorDispAttr::Mode(getASTContext().getLangOpts().VtorDispMode);
}
// Returns the number of pointer and integer slots used to represent a member
@@ -133,49 +134,32 @@ MSInheritanceModel CXXRecordDecl::getMSInheritanceModel() const {
// // offset.
// int NonVirtualBaseAdjustment;
//
+// // The offset of the vb-table pointer within the object. Only needed for
+// // incomplete types.
+// int VBPtrOffset;
+//
// // An offset within the vb-table that selects the virtual base containing
// // the member. Loading from this offset produces a new offset that is
// // added to the address of the vb-table pointer to produce the base.
// int VirtualBaseAdjustmentOffset;
-//
-// // The offset of the vb-table pointer within the object. Only needed for
-// // incomplete types.
-// int VBPtrOffset;
// };
static std::pair<unsigned, unsigned>
getMSMemberPointerSlots(const MemberPointerType *MPT) {
- const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
- MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
- unsigned Ptrs;
+ const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
+ MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
+ unsigned Ptrs = 0;
unsigned Ints = 0;
- if (MPT->isMemberFunctionPointer()) {
- // Member function pointers are a struct of a function pointer followed by a
- // variable number of ints depending on the inheritance model used. The
- // function pointer is a real function if it is non-virtual and a vftable
- // slot thunk if it is virtual. The ints select the object base passed for
- // the 'this' pointer.
- Ptrs = 1; // First slot is always a function pointer.
- switch (Inheritance) {
- case MSIM_Unspecified: ++Ints; // VBTableOffset
- case MSIM_Virtual: ++Ints; // VirtualBaseAdjustmentOffset
- case MSIM_MultiplePolymorphic:
- case MSIM_Multiple: ++Ints; // NonVirtualBaseAdjustment
- case MSIM_SinglePolymorphic:
- case MSIM_Single: break; // Nothing
- }
- } else {
- // Data pointers are an aggregate of ints. The first int is an offset
- // followed by vbtable-related offsets.
- Ptrs = 0;
- switch (Inheritance) {
- case MSIM_Unspecified: ++Ints; // VBTableOffset
- case MSIM_Virtual: ++Ints; // VirtualBaseAdjustmentOffset
- case MSIM_MultiplePolymorphic:
- case MSIM_Multiple: // Nothing
- case MSIM_SinglePolymorphic:
- case MSIM_Single: ++Ints; // Field offset
- }
- }
+ if (MPT->isMemberFunctionPointer())
+ Ptrs = 1;
+ else
+ Ints = 1;
+ if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(),
+ Inheritance))
+ Ints++;
+ if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
+ Ints++;
+ if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
+ Ints++;
return std::make_pair(Ptrs, Ints);
}
@@ -185,14 +169,26 @@ std::pair<uint64_t, unsigned> MicrosoftCXXABI::getMemberPointerWidthAndAlign(
assert(Target.getTriple().getArch() == llvm::Triple::x86 ||
Target.getTriple().getArch() == llvm::Triple::x86_64);
unsigned Ptrs, Ints;
- llvm::tie(Ptrs, Ints) = getMSMemberPointerSlots(MPT);
+ std::tie(Ptrs, Ints) = getMSMemberPointerSlots(MPT);
// The nominal struct is laid out with pointers followed by ints and aligned
// to a pointer width if any are present and an int width otherwise.
unsigned PtrSize = Target.getPointerWidth(0);
unsigned IntSize = Target.getIntWidth();
uint64_t Width = Ptrs * PtrSize + Ints * IntSize;
- unsigned Align = Ptrs > 0 ? Target.getPointerAlign(0) : Target.getIntAlign();
- Width = llvm::RoundUpToAlignment(Width, Align);
+ unsigned Align;
+
+ // When MSVC does x86_32 record layout, it aligns aggregate member pointers to
+ // 8 bytes. However, __alignof usually returns 4 for data memptrs and 8 for
+ // function memptrs.
+ if (Ptrs + Ints > 1 && Target.getTriple().getArch() == llvm::Triple::x86)
+ Align = 8 * 8;
+ else if (Ptrs)
+ Align = Target.getPointerAlign(0);
+ else
+ Align = Target.getIntAlign();
+
+ if (Target.getTriple().getArch() == llvm::Triple::x86_64)
+ Width = llvm::RoundUpToAlignment(Width, Align);
return std::make_pair(Width, Align);
}
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 52565019d41d..e6a6d09b4845 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -14,17 +14,21 @@
#include "clang/AST/Mangle.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
-#include "clang/AST/CharUnits.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/VTableBuilder.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/MathExtras.h"
using namespace clang;
@@ -71,10 +75,114 @@ static const FunctionDecl *getStructor(const FunctionDecl *fn) {
return fn;
}
+static bool isLambda(const NamedDecl *ND) {
+ const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(ND);
+ if (!Record)
+ return false;
+
+ return Record->isLambda();
+}
+
+/// MicrosoftMangleContextImpl - Overrides the default MangleContext for the
+/// Microsoft Visual C++ ABI.
+class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
+ typedef std::pair<const DeclContext *, IdentifierInfo *> DiscriminatorKeyTy;
+ llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
+ llvm::DenseMap<const NamedDecl *, unsigned> Uniquifier;
+ llvm::DenseMap<const CXXRecordDecl *, unsigned> LambdaIds;
+
+public:
+ MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags)
+ : MicrosoftMangleContext(Context, Diags) {}
+ bool shouldMangleCXXName(const NamedDecl *D) override;
+ bool shouldMangleStringLiteral(const StringLiteral *SL) override;
+ void mangleCXXName(const NamedDecl *D, raw_ostream &Out) override;
+ void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
+ raw_ostream &) override;
+ void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk,
+ raw_ostream &) override;
+ void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
+ const ThisAdjustment &ThisAdjustment,
+ raw_ostream &) override;
+ void mangleCXXVFTable(const CXXRecordDecl *Derived,
+ ArrayRef<const CXXRecordDecl *> BasePath,
+ raw_ostream &Out) override;
+ void mangleCXXVBTable(const CXXRecordDecl *Derived,
+ ArrayRef<const CXXRecordDecl *> BasePath,
+ raw_ostream &Out) override;
+ void mangleCXXRTTI(QualType T, raw_ostream &Out) override;
+ void mangleCXXRTTIName(QualType T, raw_ostream &Out) override;
+ void mangleCXXRTTIBaseClassDescriptor(const CXXRecordDecl *Derived,
+ uint32_t NVOffset, int32_t VBPtrOffset,
+ uint32_t VBTableOffset, uint32_t Flags,
+ raw_ostream &Out) override;
+ void mangleCXXRTTIBaseClassArray(const CXXRecordDecl *Derived,
+ raw_ostream &Out) override;
+ void mangleCXXRTTIClassHierarchyDescriptor(const CXXRecordDecl *Derived,
+ raw_ostream &Out) override;
+ void
+ mangleCXXRTTICompleteObjectLocator(const CXXRecordDecl *Derived,
+ ArrayRef<const CXXRecordDecl *> BasePath,
+ raw_ostream &Out) override;
+ void mangleTypeName(QualType T, raw_ostream &) override;
+ void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
+ raw_ostream &) override;
+ void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
+ raw_ostream &) override;
+ void mangleReferenceTemporary(const VarDecl *, unsigned ManglingNumber,
+ raw_ostream &) override;
+ void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out) override;
+ void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
+ void mangleDynamicAtExitDestructor(const VarDecl *D,
+ raw_ostream &Out) override;
+ void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override;
+ bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
+ // Lambda closure types are already numbered.
+ if (isLambda(ND))
+ return false;
+
+ const DeclContext *DC = getEffectiveDeclContext(ND);
+ if (!DC->isFunctionOrMethod())
+ return false;
+
+ // Use the canonical number for externally visible decls.
+ if (ND->isExternallyVisible()) {
+ disc = getASTContext().getManglingNumber(ND);
+ return true;
+ }
+
+ // Anonymous tags are already numbered.
+ if (const TagDecl *Tag = dyn_cast<TagDecl>(ND)) {
+ if (Tag->getName().empty() && !Tag->getTypedefNameForAnonDecl())
+ return false;
+ }
+
+ // Make up a reasonable number for internal decls.
+ unsigned &discriminator = Uniquifier[ND];
+ if (!discriminator)
+ discriminator = ++Discriminator[std::make_pair(DC, ND->getIdentifier())];
+ disc = discriminator;
+ return true;
+ }
+
+ unsigned getLambdaId(const CXXRecordDecl *RD) {
+ assert(RD->isLambda() && "RD must be a lambda!");
+ assert(!RD->isExternallyVisible() && "RD must not be visible!");
+ assert(RD->getLambdaManglingNumber() == 0 &&
+ "RD must not have a mangling number!");
+ std::pair<llvm::DenseMap<const CXXRecordDecl *, unsigned>::iterator, bool>
+ Result = LambdaIds.insert(std::make_pair(RD, LambdaIds.size()));
+ return Result.first->second;
+ }
+
+private:
+ void mangleInitFiniStub(const VarDecl *D, raw_ostream &Out, char CharCode);
+};
+
/// MicrosoftCXXNameMangler - Manage the mangling of a single name for the
/// Microsoft Visual C++ ABI.
class MicrosoftCXXNameMangler {
- MangleContext &Context;
+ MicrosoftMangleContextImpl &Context;
raw_ostream &Out;
/// The "structor" is the top-level declaration being mangled, if
@@ -85,9 +193,8 @@ class MicrosoftCXXNameMangler {
typedef llvm::StringMap<unsigned> BackRefMap;
BackRefMap NameBackReferences;
- bool UseNameBackReferences;
- typedef llvm::DenseMap<void*, unsigned> ArgBackRefMap;
+ typedef llvm::DenseMap<void *, unsigned> ArgBackRefMap;
ArgBackRefMap TypeBackReferences;
ASTContext &getASTContext() const { return Context.getASTContext(); }
@@ -99,37 +206,38 @@ class MicrosoftCXXNameMangler {
public:
enum QualifierMangleMode { QMM_Drop, QMM_Mangle, QMM_Escape, QMM_Result };
- MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_)
- : Context(C), Out(Out_),
- Structor(0), StructorType(-1),
- UseNameBackReferences(true),
- PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
- 64) { }
+ MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_)
+ : Context(C), Out(Out_), Structor(nullptr), StructorType(-1),
+ PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
+ 64) {}
- MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_,
+ MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_,
const CXXDestructorDecl *D, CXXDtorType Type)
- : Context(C), Out(Out_),
- Structor(getStructor(D)), StructorType(Type),
- UseNameBackReferences(true),
- PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
- 64) { }
+ : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
+ PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
+ 64) {}
raw_ostream &getStream() const { return Out; }
void mangle(const NamedDecl *D, StringRef Prefix = "\01?");
void mangleName(const NamedDecl *ND);
- void mangleDeclaration(const NamedDecl *ND);
void mangleFunctionEncoding(const FunctionDecl *FD);
void mangleVariableEncoding(const VarDecl *VD);
+ void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD);
+ void mangleMemberFunctionPointer(const CXXRecordDecl *RD,
+ const CXXMethodDecl *MD);
+ void mangleVirtualMemPtrThunk(
+ const CXXMethodDecl *MD,
+ const MicrosoftVTableContext::MethodVFTableLocation &ML);
void mangleNumber(int64_t Number);
void mangleType(QualType T, SourceRange Range,
QualifierMangleMode QMM = QMM_Mangle);
- void mangleFunctionType(const FunctionType *T, const FunctionDecl *D = 0,
+ void mangleFunctionType(const FunctionType *T,
+ const FunctionDecl *D = nullptr,
bool ForceInstMethod = false);
- void manglePostfix(const DeclContext *DC, bool NoFunction = false);
+ void mangleNestedName(const NamedDecl *ND);
private:
- void disableBackReferences() { UseNameBackReferences = false; }
void mangleUnqualifiedName(const NamedDecl *ND) {
mangleUnqualifiedName(ND, ND->getDeclName());
}
@@ -138,13 +246,15 @@ private:
void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc);
void mangleCXXDtorType(CXXDtorType T);
void mangleQualifiers(Qualifiers Quals, bool IsMember);
- void manglePointerQualifiers(Qualifiers Quals);
+ void mangleRefQualifier(RefQualifierKind RefQualifier);
+ void manglePointerCVQualifiers(Qualifiers Quals);
+ void manglePointerExtQualifiers(Qualifiers Quals, const Type *PointeeType);
void mangleUnscopedTemplateName(const TemplateDecl *ND);
- void mangleTemplateInstantiationName(const TemplateDecl *TD,
- const TemplateArgumentList &TemplateArgs);
+ void
+ mangleTemplateInstantiationName(const TemplateDecl *TD,
+ const TemplateArgumentList &TemplateArgs);
void mangleObjCMethodName(const ObjCMethodDecl *MD);
- void mangleLocalName(const FunctionDecl *FD);
void mangleArgumentType(QualType T, SourceRange Range);
@@ -157,7 +267,7 @@ private:
#undef ABSTRACT_TYPE
#undef NON_CANONICAL_TYPE
#undef TYPE
-
+
void mangleType(const TagDecl *TD);
void mangleDecayedArrayType(const ArrayType *T);
void mangleArrayType(const ArrayType *T);
@@ -171,47 +281,6 @@ private:
const TemplateArgumentList &TemplateArgs);
void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA);
};
-
-/// MicrosoftMangleContextImpl - Overrides the default MangleContext for the
-/// Microsoft Visual C++ ABI.
-class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
-public:
- MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags)
- : MicrosoftMangleContext(Context, Diags) {}
- virtual bool shouldMangleCXXName(const NamedDecl *D);
- virtual void mangleCXXName(const NamedDecl *D, raw_ostream &Out);
- virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
- uint64_t OffsetInVFTable,
- raw_ostream &);
- virtual void mangleThunk(const CXXMethodDecl *MD,
- const ThunkInfo &Thunk,
- raw_ostream &);
- virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
- const ThisAdjustment &ThisAdjustment,
- raw_ostream &);
- virtual void mangleCXXVFTable(const CXXRecordDecl *Derived,
- ArrayRef<const CXXRecordDecl *> BasePath,
- raw_ostream &Out);
- virtual void mangleCXXVBTable(const CXXRecordDecl *Derived,
- ArrayRef<const CXXRecordDecl *> BasePath,
- raw_ostream &Out);
- virtual void mangleCXXRTTI(QualType T, raw_ostream &);
- virtual void mangleCXXRTTIName(QualType T, raw_ostream &);
- virtual void mangleTypeName(QualType T, raw_ostream &);
- virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
- raw_ostream &);
- virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
- raw_ostream &);
- virtual void mangleReferenceTemporary(const VarDecl *, raw_ostream &);
- virtual void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out);
- virtual void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out);
- virtual void mangleDynamicAtExitDestructor(const VarDecl *D,
- raw_ostream &Out);
-
-private:
- void mangleInitFiniStub(const VarDecl *D, raw_ostream &Out, char CharCode);
-};
-
}
bool MicrosoftMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
@@ -267,8 +336,14 @@ bool MicrosoftMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
return true;
}
-void MicrosoftCXXNameMangler::mangle(const NamedDecl *D,
- StringRef Prefix) {
+bool
+MicrosoftMangleContextImpl::shouldMangleStringLiteral(const StringLiteral *SL) {
+ return SL->isAscii() || SL->isWide();
+ // TODO: This needs to be updated when MSVC gains support for Unicode
+ // literals.
+}
+
+void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) {
// MSVC doesn't mangle C++ names the same way it mangles extern "C" names.
// Therefore it's really important that we don't decorate the
// name with leading underscores or leading/trailing at signs. So, by
@@ -286,10 +361,9 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D,
// TODO: Fields? Can MSVC even mangle them?
// Issue a diagnostic for now.
DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this declaration yet");
- Diags.Report(D->getLocation(), DiagID)
- << D->getSourceRange();
+ unsigned DiagID = Diags.getCustomDiagID(
+ DiagnosticsEngine::Error, "cannot mangle this declaration yet");
+ Diags.Report(D->getLocation(), DiagID) << D->getSourceRange();
}
}
@@ -324,7 +398,7 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
// ::= 2 # public static member
// ::= 3 # global
// ::= 4 # static local
-
+
// The first character in the encoding (after the name) is the storage class.
if (VD->isStaticDataMember()) {
// If it's a static member, it also encodes the access level.
@@ -344,13 +418,13 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
// ::= <type> <pointee-cvr-qualifiers> # pointers, references
// Pointers and references are odd. The type of 'int * const foo;' gets
// mangled as 'QAHA' instead of 'PAHB', for example.
- TypeLoc TL = VD->getTypeSourceInfo()->getTypeLoc();
- QualType Ty = TL.getType();
+ SourceRange SR = VD->getSourceRange();
+ QualType Ty = VD->getType();
if (Ty->isPointerType() || Ty->isReferenceType() ||
Ty->isMemberPointerType()) {
- mangleType(Ty, TL.getSourceRange(), QMM_Drop);
- if (PointersAre64Bit)
- Out << 'E';
+ mangleType(Ty, SR, QMM_Drop);
+ manglePointerExtQualifiers(
+ Ty.getDesugaredType(getASTContext()).getLocalQualifiers(), nullptr);
if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>()) {
mangleQualifiers(MPT->getPointeeType().getQualifiers(), true);
// Member pointers are suffixed with a back reference to the member
@@ -366,25 +440,137 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
else
mangleQualifiers(Ty.getQualifiers(), false);
} else {
- mangleType(Ty, TL.getSourceRange(), QMM_Drop);
+ mangleType(Ty, SR, QMM_Drop);
mangleQualifiers(Ty.getLocalQualifiers(), false);
}
}
+void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
+ const ValueDecl *VD) {
+ // <member-data-pointer> ::= <integer-literal>
+ // ::= $F <number> <number>
+ // ::= $G <number> <number> <number>
+
+ int64_t FieldOffset;
+ int64_t VBTableOffset;
+ MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel();
+ if (VD) {
+ FieldOffset = getASTContext().getFieldOffset(VD);
+ assert(FieldOffset % getASTContext().getCharWidth() == 0 &&
+ "cannot take address of bitfield");
+ FieldOffset /= getASTContext().getCharWidth();
+
+ VBTableOffset = 0;
+ } else {
+ FieldOffset = RD->nullFieldOffsetIsZero() ? 0 : -1;
+
+ VBTableOffset = -1;
+ }
+
+ char Code = '\0';
+ switch (IM) {
+ case MSInheritanceAttr::Keyword_single_inheritance: Code = '0'; break;
+ case MSInheritanceAttr::Keyword_multiple_inheritance: Code = '0'; break;
+ case MSInheritanceAttr::Keyword_virtual_inheritance: Code = 'F'; break;
+ case MSInheritanceAttr::Keyword_unspecified_inheritance: Code = 'G'; break;
+ }
+
+ Out << '$' << Code;
+
+ mangleNumber(FieldOffset);
+
+ // The C++ standard doesn't allow base-to-derived member pointer conversions
+ // in template parameter contexts, so the vbptr offset of data member pointers
+ // is always zero.
+ if (MSInheritanceAttr::hasVBPtrOffsetField(IM))
+ mangleNumber(0);
+ if (MSInheritanceAttr::hasVBTableOffsetField(IM))
+ mangleNumber(VBTableOffset);
+}
+
+void
+MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
+ const CXXMethodDecl *MD) {
+ // <member-function-pointer> ::= $1? <name>
+ // ::= $H? <name> <number>
+ // ::= $I? <name> <number> <number>
+ // ::= $J? <name> <number> <number> <number>
+
+ MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel();
+
+ char Code = '\0';
+ switch (IM) {
+ case MSInheritanceAttr::Keyword_single_inheritance: Code = '1'; break;
+ case MSInheritanceAttr::Keyword_multiple_inheritance: Code = 'H'; break;
+ case MSInheritanceAttr::Keyword_virtual_inheritance: Code = 'I'; break;
+ case MSInheritanceAttr::Keyword_unspecified_inheritance: Code = 'J'; break;
+ }
+
+ // If non-virtual, mangle the name. If virtual, mangle as a virtual memptr
+ // thunk.
+ uint64_t NVOffset = 0;
+ uint64_t VBTableOffset = 0;
+ uint64_t VBPtrOffset = 0;
+ if (MD) {
+ Out << '$' << Code << '?';
+ if (MD->isVirtual()) {
+ MicrosoftVTableContext *VTContext =
+ cast<MicrosoftVTableContext>(getASTContext().getVTableContext());
+ const MicrosoftVTableContext::MethodVFTableLocation &ML =
+ VTContext->getMethodVFTableLocation(GlobalDecl(MD));
+ mangleVirtualMemPtrThunk(MD, ML);
+ NVOffset = ML.VFPtrOffset.getQuantity();
+ VBTableOffset = ML.VBTableIndex * 4;
+ if (ML.VBase) {
+ const ASTRecordLayout &Layout = getASTContext().getASTRecordLayout(RD);
+ VBPtrOffset = Layout.getVBPtrOffset().getQuantity();
+ }
+ } else {
+ mangleName(MD);
+ mangleFunctionEncoding(MD);
+ }
+ } else {
+ // Null single inheritance member functions are encoded as a simple nullptr.
+ if (IM == MSInheritanceAttr::Keyword_single_inheritance) {
+ Out << "$0A@";
+ return;
+ }
+ if (IM == MSInheritanceAttr::Keyword_unspecified_inheritance)
+ VBTableOffset = -1;
+ Out << '$' << Code;
+ }
+
+ if (MSInheritanceAttr::hasNVOffsetField(/*IsMemberFunction=*/true, IM))
+ mangleNumber(NVOffset);
+ if (MSInheritanceAttr::hasVBPtrOffsetField(IM))
+ mangleNumber(VBPtrOffset);
+ if (MSInheritanceAttr::hasVBTableOffsetField(IM))
+ mangleNumber(VBTableOffset);
+}
+
+void MicrosoftCXXNameMangler::mangleVirtualMemPtrThunk(
+ const CXXMethodDecl *MD,
+ const MicrosoftVTableContext::MethodVFTableLocation &ML) {
+ // Get the vftable offset.
+ CharUnits PointerWidth = getASTContext().toCharUnitsFromBits(
+ getASTContext().getTargetInfo().getPointerWidth(0));
+ uint64_t OffsetInVFTable = ML.Index * PointerWidth.getQuantity();
+
+ Out << "?_9";
+ mangleName(MD->getParent());
+ Out << "$B";
+ mangleNumber(OffsetInVFTable);
+ Out << 'A';
+ Out << (PointersAre64Bit ? 'A' : 'E');
+}
+
void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) {
// <name> ::= <unscoped-name> {[<named-scope>]+ | [<nested-name>]}? @
- const DeclContext *DC = ND->getDeclContext();
// Always start with the unqualified name.
- mangleUnqualifiedName(ND);
-
- // If this is an extern variable declared locally, the relevant DeclContext
- // is that of the containing namespace, or the translation unit.
- if (isa<FunctionDecl>(DC) && ND->hasLinkage())
- while (!DC->isNamespace() && !DC->isTranslationUnit())
- DC = DC->getParent();
+ mangleUnqualifiedName(ND);
- manglePostfix(DC);
+ mangleNestedName(ND);
// Terminate the whole name with an '@'.
Out << '@';
@@ -412,8 +598,8 @@ void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) {
// in the range of ASCII characters 'A' to 'P'.
// The number 0x123450 would be encoded as 'BCDEFA'
char EncodedNumberBuffer[sizeof(uint64_t) * 2];
- llvm::MutableArrayRef<char> BufferRef(EncodedNumberBuffer);
- llvm::MutableArrayRef<char>::reverse_iterator I = BufferRef.rbegin();
+ MutableArrayRef<char> BufferRef(EncodedNumberBuffer);
+ MutableArrayRef<char>::reverse_iterator I = BufferRef.rbegin();
for (; Value != 0; Value >>= 4)
*I++ = 'A' + (Value & 0xf);
Out.write(I.base(), I - BufferRef.rbegin());
@@ -424,7 +610,7 @@ void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) {
static const TemplateDecl *
isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
// Check if we have a function template.
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
if (const TemplateDecl *TD = FD->getPrimaryTemplate()) {
TemplateArgs = FD->getTemplateSpecializationArgs();
return TD;
@@ -433,24 +619,30 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
// Check if we have a class template.
if (const ClassTemplateSpecializationDecl *Spec =
- dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
+ dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
+ TemplateArgs = &Spec->getTemplateArgs();
+ return Spec->getSpecializedTemplate();
+ }
+
+ // Check if we have a variable template.
+ if (const VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(ND)) {
TemplateArgs = &Spec->getTemplateArgs();
return Spec->getSpecializedTemplate();
}
- return 0;
+ return nullptr;
}
-void
-MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
- DeclarationName Name) {
+void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
+ DeclarationName Name) {
// <unqualified-name> ::= <operator-name>
// ::= <ctor-dtor-name>
// ::= <source-name>
// ::= <template-name>
// Check if we have a template.
- const TemplateArgumentList *TemplateArgs = 0;
+ const TemplateArgumentList *TemplateArgs = nullptr;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
// Function templates aren't considered for name back referencing. This
// makes sense since function templates aren't likely to occur multiple
@@ -458,10 +650,10 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// FIXME: Test alias template mangling with MSVC 2013.
if (!isa<ClassTemplateDecl>(TD)) {
mangleTemplateInstantiationName(TD, *TemplateArgs);
+ Out << '@';
return;
}
- // We have a class template.
// Here comes the tricky thing: if we need to mangle something like
// void foo(A::X<Y>, B::X<Y>),
// the X<Y> part is aliased. However, if you need to mangle
@@ -473,30 +665,17 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// type [ -> template-parameters]
// \-> namespace[s]
// What we do is we create a new mangler, mangle the same type (without
- // a namespace suffix) using the extra mangler with back references
- // disabled (to avoid infinite recursion) and then use the mangled type
- // name as a key to check the mangling of different types for aliasing.
-
- std::string BackReferenceKey;
- BackRefMap::iterator Found;
- if (UseNameBackReferences) {
- llvm::raw_string_ostream Stream(BackReferenceKey);
- MicrosoftCXXNameMangler Extra(Context, Stream);
- Extra.disableBackReferences();
- Extra.mangleUnqualifiedName(ND, Name);
- Stream.flush();
-
- Found = NameBackReferences.find(BackReferenceKey);
- }
- if (!UseNameBackReferences || Found == NameBackReferences.end()) {
- mangleTemplateInstantiationName(TD, *TemplateArgs);
- if (UseNameBackReferences && NameBackReferences.size() < 10) {
- size_t Size = NameBackReferences.size();
- NameBackReferences[BackReferenceKey] = Size;
- }
- } else {
- Out << Found->second;
- }
+ // a namespace suffix) to a string using the extra mangler and then use
+ // the mangled type name as a key to check the mangling of different types
+ // for aliasing.
+
+ llvm::SmallString<64> TemplateMangling;
+ llvm::raw_svector_ostream Stream(TemplateMangling);
+ MicrosoftCXXNameMangler Extra(Context, Stream);
+ Extra.mangleTemplateInstantiationName(TD, *TemplateArgs);
+ Stream.flush();
+
+ mangleSourceName(TemplateMangling);
return;
}
@@ -506,17 +685,31 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
mangleSourceName(II->getName());
break;
}
-
+
// Otherwise, an anonymous entity. We must have a declaration.
assert(ND && "mangling empty name without declaration");
-
+
if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
if (NS->isAnonymousNamespace()) {
Out << "?A@";
break;
}
}
-
+
+ if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
+ // We must have an anonymous union or struct declaration.
+ const CXXRecordDecl *RD = VD->getType()->getAsCXXRecordDecl();
+ assert(RD && "expected variable decl to have a record type");
+ // Anonymous types with no tag or typedef get the name of their
+ // declarator mangled in. If they have no declarator, number them with
+ // a $S prefix.
+ llvm::SmallString<64> Name("$S");
+ // Get a unique id for the anonymous struct.
+ Name += llvm::utostr(Context.getAnonymousStructId(RD) + 1);
+ mangleSourceName(Name.str());
+ break;
+ }
+
// We must have an anonymous struct.
const TagDecl *TD = cast<TagDecl>(ND);
if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) {
@@ -528,26 +721,43 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
break;
}
+ if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) {
+ if (Record->isLambda()) {
+ llvm::SmallString<10> Name("<lambda_");
+ unsigned LambdaId;
+ if (Record->getLambdaManglingNumber())
+ LambdaId = Record->getLambdaManglingNumber();
+ else
+ LambdaId = Context.getLambdaId(Record);
+
+ Name += llvm::utostr(LambdaId);
+ Name += ">";
+
+ mangleSourceName(Name);
+ break;
+ }
+ }
+
+ llvm::SmallString<64> Name("<unnamed-type-");
if (TD->hasDeclaratorForAnonDecl()) {
// Anonymous types with no tag or typedef get the name of their
- // declarator mangled in.
- llvm::SmallString<64> Name("<unnamed-type-");
+ // declarator mangled in if they have one.
Name += TD->getDeclaratorForAnonDecl()->getName();
- Name += ">";
- mangleSourceName(Name.str());
} else {
- // Anonymous types with no tag, no typedef, or declarator get
- // '<unnamed-tag>'.
- mangleSourceName("<unnamed-tag>");
+ // Otherwise, number the types using a $S prefix.
+ Name += "$S";
+ Name += llvm::utostr(Context.getAnonymousStructId(TD));
}
+ Name += ">";
+ mangleSourceName(Name.str());
break;
}
-
+
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
llvm_unreachable("Can't mangle Objective-C selector names here!");
-
+
case DeclarationName::CXXConstructorName:
if (ND == Structor) {
assert(StructorType == Ctor_Complete &&
@@ -555,7 +765,7 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
}
Out << "?0";
break;
-
+
case DeclarationName::CXXDestructorName:
if (ND == Structor)
// If the named decl is the C++ destructor we're mangling,
@@ -566,70 +776,69 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// class with a destructor is declared within a destructor.
mangleCXXDtorType(Dtor_Base);
break;
-
+
case DeclarationName::CXXConversionFunctionName:
// <operator-name> ::= ?B # (cast)
// The target type is encoded as the return type.
Out << "?B";
break;
-
+
case DeclarationName::CXXOperatorName:
mangleOperatorName(Name.getCXXOverloadedOperator(), ND->getLocation());
break;
-
+
case DeclarationName::CXXLiteralOperatorName: {
- // FIXME: Was this added in VS2010? Does MS even know how to mangle this?
- DiagnosticsEngine Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this literal operator yet");
- Diags.Report(ND->getLocation(), DiagID);
+ Out << "?__K";
+ mangleSourceName(Name.getCXXLiteralIdentifier()->getName());
break;
}
-
+
case DeclarationName::CXXUsingDirective:
llvm_unreachable("Can't mangle a using directive name!");
}
}
-void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC,
- bool NoFunction) {
+void MicrosoftCXXNameMangler::mangleNestedName(const NamedDecl *ND) {
// <postfix> ::= <unqualified-name> [<postfix>]
// ::= <substitution> [<postfix>]
-
- if (!DC) return;
-
- while (isa<LinkageSpecDecl>(DC))
- DC = DC->getParent();
-
- if (DC->isTranslationUnit())
+ if (isLambda(ND))
return;
- if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) {
- DiagnosticsEngine Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle a local inside this block yet");
- Diags.Report(BD->getLocation(), DiagID);
+ const DeclContext *DC = ND->getDeclContext();
- // FIXME: This is completely, utterly, wrong; see ItaniumMangle
- // for how this should be done.
- Out << "__block_invoke" << Context.getBlockId(BD, false);
- Out << '@';
- return manglePostfix(DC->getParent(), NoFunction);
- } else if (isa<CapturedDecl>(DC)) {
- // Skip CapturedDecl context.
- manglePostfix(DC->getParent(), NoFunction);
- return;
- }
+ while (!DC->isTranslationUnit()) {
+ if (isa<TagDecl>(ND) || isa<VarDecl>(ND)) {
+ unsigned Disc;
+ if (Context.getNextDiscriminator(ND, Disc)) {
+ Out << '?';
+ mangleNumber(Disc);
+ Out << '?';
+ }
+ }
- if (NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)))
- return;
- else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC))
- mangleObjCMethodName(Method);
- else if (const FunctionDecl *Func = dyn_cast<FunctionDecl>(DC))
- mangleLocalName(Func);
- else {
- mangleUnqualifiedName(cast<NamedDecl>(DC));
- manglePostfix(DC->getParent(), NoFunction);
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID =
+ Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle a local inside this block yet");
+ Diags.Report(BD->getLocation(), DiagID);
+
+ // FIXME: This is completely, utterly, wrong; see ItaniumMangle
+ // for how this should be done.
+ Out << "__block_invoke" << Context.getBlockId(BD, false);
+ Out << '@';
+ continue;
+ } else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) {
+ mangleObjCMethodName(Method);
+ } else if (isa<NamedDecl>(DC)) {
+ ND = cast<NamedDecl>(DC);
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
+ mangle(FD, "?");
+ break;
+ } else
+ mangleUnqualifiedName(ND);
+ }
+ DC = DC->getParent();
}
}
@@ -768,7 +977,7 @@ void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO,
case OO_Array_New: Out << "?_U"; break;
// <operator-name> ::= ?_V # delete[]
case OO_Array_Delete: Out << "?_V"; break;
-
+
case OO_Conditional: {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
@@ -776,7 +985,7 @@ void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO,
Diags.Report(Loc, DiagID);
break;
}
-
+
case OO_None:
case NUM_OVERLOADED_OPERATORS:
llvm_unreachable("Not an overloaded operator");
@@ -786,14 +995,19 @@ void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO,
void MicrosoftCXXNameMangler::mangleSourceName(StringRef Name) {
// <source name> ::= <identifier> @
BackRefMap::iterator Found;
- if (UseNameBackReferences)
+ if (NameBackReferences.size() < 10) {
+ size_t Size = NameBackReferences.size();
+ bool Inserted;
+ std::tie(Found, Inserted) =
+ NameBackReferences.insert(std::make_pair(Name, Size));
+ if (Inserted)
+ Found = NameBackReferences.end();
+ } else {
Found = NameBackReferences.find(Name);
- if (!UseNameBackReferences || Found == NameBackReferences.end()) {
+ }
+
+ if (Found == NameBackReferences.end()) {
Out << Name << '@';
- if (UseNameBackReferences && NameBackReferences.size() < 10) {
- size_t Size = NameBackReferences.size();
- NameBackReferences[Name] = Size;
- }
} else {
Out << Found->second;
}
@@ -803,47 +1017,8 @@ void MicrosoftCXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
Context.mangleObjCMethodName(MD, Out);
}
-// Find out how many function decls live above this one and return an integer
-// suitable for use as the number in a numbered anonymous scope.
-// TODO: Memoize.
-static unsigned getLocalNestingLevel(const FunctionDecl *FD) {
- const DeclContext *DC = FD->getParent();
- int level = 1;
-
- while (DC && !DC->isTranslationUnit()) {
- if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) level++;
- DC = DC->getParent();
- }
-
- return 2*level;
-}
-
-void MicrosoftCXXNameMangler::mangleLocalName(const FunctionDecl *FD) {
- // <nested-name> ::= <numbered-anonymous-scope> ? <mangled-name>
- // <numbered-anonymous-scope> ::= ? <number>
- // Even though the name is rendered in reverse order (e.g.
- // A::B::C is rendered as C@B@A), VC numbers the scopes from outermost to
- // innermost. So a method bar in class C local to function foo gets mangled
- // as something like:
- // ?bar@C@?1??foo@@YAXXZ@QAEXXZ
- // This is more apparent when you have a type nested inside a method of a
- // type nested inside a function. A method baz in class D local to method
- // bar of class C local to function foo gets mangled as:
- // ?baz@D@?3??bar@C@?1??foo@@YAXXZ@QAEXXZ@QAEXXZ
- // This scheme is general enough to support GCC-style nested
- // functions. You could have a method baz of class C inside a function bar
- // inside a function foo, like so:
- // ?baz@C@?3??bar@?1??foo@@YAXXZ@YAXXZ@QAEXXZ
- unsigned NestLevel = getLocalNestingLevel(FD);
- Out << '?';
- mangleNumber(NestLevel);
- Out << '?';
- mangle(FD, "?");
-}
-
void MicrosoftCXXNameMangler::mangleTemplateInstantiationName(
- const TemplateDecl *TD,
- const TemplateArgumentList &TemplateArgs) {
+ const TemplateDecl *TD, const TemplateArgumentList &TemplateArgs) {
// <template-name> ::= <unscoped-template-name> <template-args>
// ::= <substitution>
// Always start with the unqualified name.
@@ -869,9 +1044,8 @@ MicrosoftCXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *TD) {
mangleUnqualifiedName(TD);
}
-void
-MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value,
- bool IsBoolean) {
+void MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value,
+ bool IsBoolean) {
// <integer-literal> ::= $0 <number>
Out << "$0";
// Make sure booleans are encoded as 0/1.
@@ -881,8 +1055,7 @@ MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value,
mangleNumber(Value.getSExtValue());
}
-void
-MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
+void MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
// See if this is a constant expression.
llvm::APSInt Value;
if (E->isIntegerConstantExpr(Value, Context.getASTContext())) {
@@ -890,7 +1063,10 @@ MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
return;
}
- const CXXUuidofExpr *UE = 0;
+ // Look through no-op casts like template parameter substitutions.
+ E = E->IgnoreParenNoopCasts(Context.getASTContext());
+
+ const CXXUuidofExpr *UE = nullptr;
if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
if (UO->getOpcode() == UO_AddrOf)
UE = dyn_cast<CXXUuidofExpr>(UO->getSubExpr());
@@ -919,26 +1095,30 @@ MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
// As bad as this diagnostic is, it's better than crashing.
DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot yet mangle expression type %0");
- Diags.Report(E->getExprLoc(), DiagID)
- << E->getStmtClassName() << E->getSourceRange();
+ unsigned DiagID = Diags.getCustomDiagID(
+ DiagnosticsEngine::Error, "cannot yet mangle expression type %0");
+ Diags.Report(E->getExprLoc(), DiagID) << E->getStmtClassName()
+ << E->getSourceRange();
}
-void
-MicrosoftCXXNameMangler::mangleTemplateArgs(const TemplateDecl *TD,
- const TemplateArgumentList &TemplateArgs) {
- // <template-args> ::= {<type> | <integer-literal>}+ @
- unsigned NumTemplateArgs = TemplateArgs.size();
- for (unsigned i = 0; i < NumTemplateArgs; ++i) {
- const TemplateArgument &TA = TemplateArgs[i];
+void MicrosoftCXXNameMangler::mangleTemplateArgs(
+ const TemplateDecl *TD, const TemplateArgumentList &TemplateArgs) {
+ // <template-args> ::= <template-arg>+
+ for (const TemplateArgument &TA : TemplateArgs.asArray())
mangleTemplateArg(TD, TA);
- }
- Out << '@';
}
void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
const TemplateArgument &TA) {
+ // <template-arg> ::= <type>
+ // ::= <integer-literal>
+ // ::= <member-data-pointer>
+ // ::= <member-function-pointer>
+ // ::= $E? <name> <type-encoding>
+ // ::= $1? <name> <type-encoding>
+ // ::= $0A@
+ // ::= <template-args>
+
switch (TA.getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Can't mangle null template arguments!");
@@ -951,25 +1131,54 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
}
case TemplateArgument::Declaration: {
const NamedDecl *ND = cast<NamedDecl>(TA.getAsDecl());
- mangle(ND, TA.isDeclForReferenceParam() ? "$E?" : "$1?");
+ if (isa<FieldDecl>(ND) || isa<IndirectFieldDecl>(ND)) {
+ mangleMemberDataPointer(
+ cast<CXXRecordDecl>(ND->getDeclContext())->getMostRecentDecl(),
+ cast<ValueDecl>(ND));
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
+ if (MD && MD->isInstance())
+ mangleMemberFunctionPointer(MD->getParent()->getMostRecentDecl(), MD);
+ else
+ mangle(FD, "$1?");
+ } else {
+ mangle(ND, TA.isDeclForReferenceParam() ? "$E?" : "$1?");
+ }
break;
}
case TemplateArgument::Integral:
mangleIntegerLiteral(TA.getAsIntegral(),
TA.getIntegralType()->isBooleanType());
break;
- case TemplateArgument::NullPtr:
+ case TemplateArgument::NullPtr: {
+ QualType T = TA.getNullPtrType();
+ if (const MemberPointerType *MPT = T->getAs<MemberPointerType>()) {
+ const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
+ if (MPT->isMemberFunctionPointerType() && isa<ClassTemplateDecl>(TD)) {
+ mangleMemberFunctionPointer(RD, nullptr);
+ return;
+ }
+ if (MPT->isMemberDataPointer()) {
+ mangleMemberDataPointer(RD, nullptr);
+ return;
+ }
+ }
Out << "$0A@";
break;
+ }
case TemplateArgument::Expression:
mangleExpression(TA.getAsExpr());
break;
- case TemplateArgument::Pack:
- // Unlike Itanium, there is no character code to indicate an argument pack.
- for (TemplateArgument::pack_iterator I = TA.pack_begin(), E = TA.pack_end();
- I != E; ++I)
- mangleTemplateArg(TD, *I);
+ case TemplateArgument::Pack: {
+ ArrayRef<TemplateArgument> TemplateArgs = TA.getPackAsArray();
+ if (TemplateArgs.empty()) {
+ Out << "$S";
+ } else {
+ for (const TemplateArgument &PA : TemplateArgs)
+ mangleTemplateArg(TD, PA);
+ }
break;
+ }
case TemplateArgument::Template:
mangleType(cast<TagDecl>(
TA.getAsTemplate().getAsTemplateDecl()->getTemplatedDecl()));
@@ -1059,13 +1268,43 @@ void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals,
// FIXME: For now, just drop all extension qualifiers on the floor.
}
-void MicrosoftCXXNameMangler::manglePointerQualifiers(Qualifiers Quals) {
- // <pointer-cvr-qualifiers> ::= P # no qualifiers
- // ::= Q # const
- // ::= R # volatile
- // ::= S # const volatile
+void
+MicrosoftCXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) {
+ // <ref-qualifier> ::= G # lvalue reference
+ // ::= H # rvalue-reference
+ switch (RefQualifier) {
+ case RQ_None:
+ break;
+
+ case RQ_LValue:
+ Out << 'G';
+ break;
+
+ case RQ_RValue:
+ Out << 'H';
+ break;
+ }
+}
+
+void
+MicrosoftCXXNameMangler::manglePointerExtQualifiers(Qualifiers Quals,
+ const Type *PointeeType) {
+ bool HasRestrict = Quals.hasRestrict();
+ if (PointersAre64Bit && (!PointeeType || !PointeeType->isFunctionType()))
+ Out << 'E';
+
+ if (HasRestrict)
+ Out << 'I';
+}
+
+void MicrosoftCXXNameMangler::manglePointerCVQualifiers(Qualifiers Quals) {
+ // <pointer-cv-qualifiers> ::= P # no qualifiers
+ // ::= Q # const
+ // ::= R # volatile
+ // ::= S # const volatile
bool HasConst = Quals.hasConst(),
HasVolatile = Quals.hasVolatile();
+
if (HasConst && HasVolatile) {
Out << 'S';
} else if (HasVolatile) {
@@ -1165,8 +1404,10 @@ void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
}
// We have to mangle these now, while we still have enough information.
- if (IsPointer)
- manglePointerQualifiers(Quals);
+ if (IsPointer) {
+ manglePointerCVQualifiers(Quals);
+ manglePointerExtQualifiers(Quals, T->getPointeeType().getTypePtr());
+ }
const Type *ty = T.getTypePtr();
switch (ty->getTypeClass()) {
@@ -1254,7 +1495,7 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T,
case BuiltinType::OCLImage3d: Out << "PAUocl_image3d@@"; break;
case BuiltinType::OCLSampler: Out << "PAUocl_sampler@@"; break;
case BuiltinType::OCLEvent: Out << "PAUocl_event@@"; break;
-
+
case BuiltinType::NullPtr: Out << "$$T"; break;
case BuiltinType::Char16:
@@ -1306,9 +1547,10 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
// If this is a C++ instance method, mangle the CVR qualifiers for the
// this pointer.
if (IsInstMethod) {
- if (PointersAre64Bit)
- Out << 'E';
- mangleQualifiers(Qualifiers::fromCVRMask(Proto->getTypeQuals()), false);
+ Qualifiers Quals = Qualifiers::fromCVRMask(Proto->getTypeQuals());
+ manglePointerExtQualifiers(Quals, nullptr);
+ mangleRefQualifier(Proto->getRefQualifier());
+ mangleQualifiers(Quals, false);
}
mangleCallingConvention(T);
@@ -1327,23 +1569,30 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
}
Out << '@';
} else {
- QualType ResultType = Proto->getResultType();
- if (ResultType->isVoidType())
- ResultType = ResultType.getUnqualifiedType();
- mangleType(ResultType, Range, QMM_Result);
+ QualType ResultType = Proto->getReturnType();
+ if (const auto *AT =
+ dyn_cast_or_null<AutoType>(ResultType->getContainedAutoType())) {
+ Out << '?';
+ mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false);
+ Out << '?';
+ mangleSourceName(AT->isDecltypeAuto() ? "<decltype-auto>" : "<auto>");
+ Out << '@';
+ } else {
+ if (ResultType->isVoidType())
+ ResultType = ResultType.getUnqualifiedType();
+ mangleType(ResultType, Range, QMM_Result);
+ }
}
// <argument-list> ::= X # void
// ::= <type>+ @
// ::= <type>* Z # varargs
- if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) {
+ if (Proto->getNumParams() == 0 && !Proto->isVariadic()) {
Out << 'X';
} else {
// Happens for function pointer type arguments for example.
- for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
- ArgEnd = Proto->arg_type_end();
- Arg != ArgEnd; ++Arg)
- mangleArgumentType(*Arg, Range);
+ for (const QualType Arg : Proto->param_types())
+ mangleArgumentType(Arg, Range);
// <builtin-type> ::= Z # ellipsis
if (Proto->isVariadic())
Out << 'Z';
@@ -1465,7 +1714,7 @@ void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T,
// <union-type> ::= T <name>
// <struct-type> ::= U <name>
// <class-type> ::= V <name>
-// <enum-type> ::= W <size> <name>
+// <enum-type> ::= W4 <name>
void MicrosoftCXXNameMangler::mangleType(const EnumType *T, SourceRange) {
mangleType(cast<TagType>(T)->getDecl());
}
@@ -1485,9 +1734,7 @@ void MicrosoftCXXNameMangler::mangleType(const TagDecl *TD) {
Out << 'V';
break;
case TTK_Enum:
- Out << 'W';
- Out << getASTContext().getTypeSizeInChars(
- cast<EnumDecl>(TD)->getIntegerType()).getQuantity();
+ Out << "W4";
break;
}
mangleName(TD);
@@ -1503,7 +1750,7 @@ void MicrosoftCXXNameMangler::mangleType(const TagDecl *TD) {
void MicrosoftCXXNameMangler::mangleDecayedArrayType(const ArrayType *T) {
// This isn't a recursive mangling, so now we have to do it all in this
// one call.
- manglePointerQualifiers(T->getElementType().getQualifiers());
+ manglePointerCVQualifiers(T->getElementType().getQualifiers());
mangleType(T->getElementType(), SourceRange());
}
void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T,
@@ -1527,7 +1774,7 @@ void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) {
SmallVector<llvm::APInt, 3> Dimensions;
for (;;) {
if (const ConstantArrayType *CAT =
- getASTContext().getAsConstantArrayType(ElementTy)) {
+ getASTContext().getAsConstantArrayType(ElementTy)) {
Dimensions.push_back(CAT->getSize());
ElementTy = CAT->getElementType();
} else if (ElementTy->isVariableArrayType()) {
@@ -1550,7 +1797,7 @@ void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) {
<< DSAT->getBracketsRange();
return;
} else if (const IncompleteArrayType *IAT =
- getASTContext().getAsIncompleteArrayType(ElementTy)) {
+ getASTContext().getAsIncompleteArrayType(ElementTy)) {
Dimensions.push_back(llvm::APInt(32, 0));
ElementTy = IAT->getElementType();
}
@@ -1559,8 +1806,8 @@ void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) {
Out << 'Y';
// <dimension-count> ::= <number> # number of extra dimensions
mangleNumber(Dimensions.size());
- for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim)
- mangleNumber(Dimensions[Dim].getLimitedValue());
+ for (const llvm::APInt &Dimension : Dimensions)
+ mangleNumber(Dimension.getLimitedValue());
mangleType(ElementTy, SourceRange(), QMM_Escape);
}
@@ -1573,10 +1820,8 @@ void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T,
if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) {
Out << '8';
mangleName(T->getClass()->castAs<RecordType>()->getDecl());
- mangleFunctionType(FPT, 0, true);
+ mangleFunctionType(FPT, nullptr, true);
} else {
- if (PointersAre64Bit && !T->getPointeeType()->isFunctionType())
- Out << 'E';
mangleQualifiers(PointeeType.getQualifiers(), true);
mangleName(T->getClass()->castAs<RecordType>()->getDecl());
mangleType(PointeeType, Range, QMM_Drop);
@@ -1604,42 +1849,37 @@ void MicrosoftCXXNameMangler::mangleType(
// <type> ::= <pointer-type>
// <pointer-type> ::= E? <pointer-cvr-qualifiers> <cvr-qualifiers> <type>
-// # the E is required for 64-bit non static pointers
+// # the E is required for 64-bit non-static pointers
void MicrosoftCXXNameMangler::mangleType(const PointerType *T,
SourceRange Range) {
QualType PointeeTy = T->getPointeeType();
- if (PointersAre64Bit && !T->getPointeeType()->isFunctionType())
- Out << 'E';
mangleType(PointeeTy, Range);
}
void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T,
SourceRange Range) {
// Object pointers never have qualifiers.
Out << 'A';
- if (PointersAre64Bit && !T->getPointeeType()->isFunctionType())
- Out << 'E';
+ manglePointerExtQualifiers(Qualifiers(), T->getPointeeType().getTypePtr());
mangleType(T->getPointeeType(), Range);
}
// <type> ::= <reference-type>
// <reference-type> ::= A E? <cvr-qualifiers> <type>
-// # the E is required for 64-bit non static lvalue references
+// # the E is required for 64-bit non-static lvalue references
void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T,
SourceRange Range) {
Out << 'A';
- if (PointersAre64Bit && !T->getPointeeType()->isFunctionType())
- Out << 'E';
+ manglePointerExtQualifiers(Qualifiers(), T->getPointeeType().getTypePtr());
mangleType(T->getPointeeType(), Range);
}
// <type> ::= <r-value-reference-type>
// <r-value-reference-type> ::= $$Q E? <cvr-qualifiers> <type>
-// # the E is required for 64-bit non static rvalue references
+// # the E is required for 64-bit non-static rvalue references
void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T,
SourceRange Range) {
Out << "$$Q";
- if (PointersAre64Bit && !T->getPointeeType()->isFunctionType())
- Out << 'E';
+ manglePointerExtQualifiers(Qualifiers(), T->getPointeeType().getTypePtr());
mangleType(T->getPointeeType(), Range);
}
@@ -1804,6 +2044,8 @@ void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T,
}
void MicrosoftCXXNameMangler::mangleType(const AutoType *T, SourceRange Range) {
+ assert(T->getDeducedType().isNull() && "expecting a dependent type!");
+
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this 'auto' type yet");
@@ -1923,17 +2165,17 @@ static void mangleThunkThisAdjustment(const CXXMethodDecl *MD,
}
}
-void MicrosoftMangleContextImpl::mangleVirtualMemPtrThunk(
- const CXXMethodDecl *MD, uint64_t OffsetInVFTable, raw_ostream &Out) {
- bool Is64Bit = getASTContext().getTargetInfo().getPointerWidth(0) == 64;
+void
+MicrosoftMangleContextImpl::mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
+ raw_ostream &Out) {
+ MicrosoftVTableContext *VTContext =
+ cast<MicrosoftVTableContext>(getASTContext().getVTableContext());
+ const MicrosoftVTableContext::MethodVFTableLocation &ML =
+ VTContext->getMethodVFTableLocation(GlobalDecl(MD));
MicrosoftCXXNameMangler Mangler(*this, Out);
- Mangler.getStream() << "\01??_9";
- Mangler.mangleName(MD->getParent());
- Mangler.getStream() << "$B";
- Mangler.mangleNumber(OffsetInVFTable);
- Mangler.getStream() << "A";
- Mangler.getStream() << (Is64Bit ? "A" : "E");
+ Mangler.getStream() << "\01?";
+ Mangler.mangleVirtualMemPtrThunk(MD, ML);
}
void MicrosoftMangleContextImpl::mangleThunk(const CXXMethodDecl *MD,
@@ -1944,7 +2186,8 @@ void MicrosoftMangleContextImpl::mangleThunk(const CXXMethodDecl *MD,
Mangler.mangleName(MD);
mangleThunkThisAdjustment(MD, Thunk.This, Mangler, Out);
if (!Thunk.Return.isEmpty())
- assert(Thunk.Method != 0 && "Thunk info should hold the overridee decl");
+ assert(Thunk.Method != nullptr &&
+ "Thunk info should hold the overridee decl");
const CXXMethodDecl *DeclForFPT = Thunk.Method ? Thunk.Method : MD;
Mangler.mangleFunctionType(
@@ -1976,11 +2219,8 @@ void MicrosoftMangleContextImpl::mangleCXXVFTable(
Mangler.getStream() << "\01??_7";
Mangler.mangleName(Derived);
Mangler.getStream() << "6B"; // '6' for vftable, 'B' for const.
- for (ArrayRef<const CXXRecordDecl *>::iterator I = BasePath.begin(),
- E = BasePath.end();
- I != E; ++I) {
- Mangler.mangleName(*I);
- }
+ for (const CXXRecordDecl *RD : BasePath)
+ Mangler.mangleName(RD);
Mangler.getStream() << '@';
}
@@ -1995,28 +2235,68 @@ void MicrosoftMangleContextImpl::mangleCXXVBTable(
Mangler.getStream() << "\01??_8";
Mangler.mangleName(Derived);
Mangler.getStream() << "7B"; // '7' for vbtable, 'B' for const.
- for (ArrayRef<const CXXRecordDecl *>::iterator I = BasePath.begin(),
- E = BasePath.end();
- I != E; ++I) {
- Mangler.mangleName(*I);
- }
+ for (const CXXRecordDecl *RD : BasePath)
+ Mangler.mangleName(RD);
Mangler.getStream() << '@';
}
-void MicrosoftMangleContextImpl::mangleCXXRTTI(QualType T, raw_ostream &) {
- // FIXME: Give a location...
- unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle RTTI descriptors for type %0 yet");
- getDiags().Report(DiagID)
- << T.getBaseTypeIdentifier();
+void MicrosoftMangleContextImpl::mangleCXXRTTI(QualType T, raw_ostream &Out) {
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "\01??_R0";
+ Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
+ Mangler.getStream() << "@8";
}
-void MicrosoftMangleContextImpl::mangleCXXRTTIName(QualType T, raw_ostream &) {
- // FIXME: Give a location...
- unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle the name of type %0 into RTTI descriptors yet");
- getDiags().Report(DiagID)
- << T.getBaseTypeIdentifier();
+void MicrosoftMangleContextImpl::mangleCXXRTTIName(QualType T,
+ raw_ostream &Out) {
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << '.';
+ Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
+}
+
+void MicrosoftMangleContextImpl::mangleCXXRTTIBaseClassDescriptor(
+ const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset,
+ uint32_t VBTableOffset, uint32_t Flags, raw_ostream &Out) {
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "\01??_R1";
+ Mangler.mangleNumber(NVOffset);
+ Mangler.mangleNumber(VBPtrOffset);
+ Mangler.mangleNumber(VBTableOffset);
+ Mangler.mangleNumber(Flags);
+ Mangler.mangleName(Derived);
+ Mangler.getStream() << "8";
+}
+
+void MicrosoftMangleContextImpl::mangleCXXRTTIBaseClassArray(
+ const CXXRecordDecl *Derived, raw_ostream &Out) {
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "\01??_R2";
+ Mangler.mangleName(Derived);
+ Mangler.getStream() << "8";
+}
+
+void MicrosoftMangleContextImpl::mangleCXXRTTIClassHierarchyDescriptor(
+ const CXXRecordDecl *Derived, raw_ostream &Out) {
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "\01??_R3";
+ Mangler.mangleName(Derived);
+ Mangler.getStream() << "8";
+}
+
+void MicrosoftMangleContextImpl::mangleCXXRTTICompleteObjectLocator(
+ const CXXRecordDecl *Derived, ArrayRef<const CXXRecordDecl *> BasePath,
+ raw_ostream &Out) {
+ // <mangled-name> ::= ?_R4 <class-name> <storage-class>
+ // <cvr-qualifiers> [<name>] @
+ // NOTE: <cvr-qualifiers> here is always 'B' (const). <storage-class>
+ // is always '6' for vftables.
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "\01??_R4";
+ Mangler.mangleName(Derived);
+ Mangler.getStream() << "6B"; // '6' for vftable, 'B' for const.
+ for (const CXXRecordDecl *RD : BasePath)
+ Mangler.mangleName(RD);
+ Mangler.getStream() << '@';
}
void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) {
@@ -2042,6 +2322,7 @@ void MicrosoftMangleContextImpl::mangleCXXDtor(const CXXDestructorDecl *D,
}
void MicrosoftMangleContextImpl::mangleReferenceTemporary(const VarDecl *VD,
+ unsigned,
raw_ostream &) {
unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this reference temporary yet");
@@ -2050,7 +2331,16 @@ void MicrosoftMangleContextImpl::mangleReferenceTemporary(const VarDecl *VD,
void MicrosoftMangleContextImpl::mangleStaticGuardVariable(const VarDecl *VD,
raw_ostream &Out) {
- // <guard-name> ::= ?_B <postfix> @51
+ // TODO: This is not correct, especially with respect to MSVC2013. MSVC2013
+ // utilizes thread local variables to implement thread safe, re-entrant
+ // initialization for statics. They no longer differentiate between an
+ // externally visible and non-externally visible static with respect to
+ // mangling, they all get $TSS <number>.
+ //
+ // N.B. This means that they can get more than 32 static variable guards in a
+ // scope. It also means that they broke compatibility with their own ABI.
+
+ // <guard-name> ::= ?_B <postfix> @5 <scope-depth>
// ::= ?$S <guard-num> @ <postfix> @4IA
// The first mangling is what MSVC uses to guard static locals in inline
@@ -2064,8 +2354,17 @@ void MicrosoftMangleContextImpl::mangleStaticGuardVariable(const VarDecl *VD,
bool Visible = VD->isExternallyVisible();
// <operator-name> ::= ?_B # local static guard
Mangler.getStream() << (Visible ? "\01??_B" : "\01?$S1@");
- Mangler.manglePostfix(VD->getDeclContext());
- Mangler.getStream() << (Visible ? "@51" : "@4IA");
+ unsigned ScopeDepth = 0;
+ if (Visible && !getNextDiscriminator(VD, ScopeDepth))
+ // If we do not have a discriminator and are emitting a guard variable for
+ // use at global scope, then mangling the nested name will not be enough to
+ // remove ambiguities.
+ Mangler.mangle(VD, "");
+ else
+ Mangler.mangleNestedName(VD);
+ Mangler.getStream() << (Visible ? "@5" : "@4IA");
+ if (ScopeDepth)
+ Mangler.mangleNumber(ScopeDepth);
}
void MicrosoftMangleContextImpl::mangleInitFiniStub(const VarDecl *D,
@@ -2074,6 +2373,10 @@ void MicrosoftMangleContextImpl::mangleInitFiniStub(const VarDecl *D,
MicrosoftCXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "\01??__" << CharCode;
Mangler.mangleName(D);
+ if (D->isStaticDataMember()) {
+ Mangler.mangleVariableEncoding(D);
+ Mangler.getStream() << '@';
+ }
// This is the function class mangling. These stubs are global, non-variadic,
// cdecl functions that return void and take no args.
Mangler.getStream() << "YAXXZ";
@@ -2092,6 +2395,172 @@ MicrosoftMangleContextImpl::mangleDynamicAtExitDestructor(const VarDecl *D,
mangleInitFiniStub(D, Out, 'F');
}
+void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL,
+ raw_ostream &Out) {
+ // <char-type> ::= 0 # char
+ // ::= 1 # wchar_t
+ // ::= ??? # char16_t/char32_t will need a mangling too...
+ //
+ // <literal-length> ::= <non-negative integer> # the length of the literal
+ //
+ // <encoded-crc> ::= <hex digit>+ @ # crc of the literal including
+ // # null-terminator
+ //
+ // <encoded-string> ::= <simple character> # uninteresting character
+ // ::= '?$' <hex digit> <hex digit> # these two nibbles
+ // # encode the byte for the
+ // # character
+ // ::= '?' [a-z] # \xe1 - \xfa
+ // ::= '?' [A-Z] # \xc1 - \xda
+ // ::= '?' [0-9] # [,/\:. \n\t'-]
+ //
+ // <literal> ::= '??_C@_' <char-type> <literal-length> <encoded-crc>
+ // <encoded-string> '@'
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "\01??_C@_";
+
+ // <char-type>: The "kind" of string literal is encoded into the mangled name.
+ // TODO: This needs to be updated when MSVC gains support for unicode
+ // literals.
+ if (SL->isAscii())
+ Mangler.getStream() << '0';
+ else if (SL->isWide())
+ Mangler.getStream() << '1';
+ else
+ llvm_unreachable("unexpected string literal kind!");
+
+ // <literal-length>: The next part of the mangled name consists of the length
+ // of the string.
+ // The StringLiteral does not consider the NUL terminator byte(s) but the
+ // mangling does.
+ // N.B. The length is in terms of bytes, not characters.
+ Mangler.mangleNumber(SL->getByteLength() + SL->getCharByteWidth());
+
+ // We will use the "Rocksoft^tm Model CRC Algorithm" to describe the
+ // properties of our CRC:
+ // Width : 32
+ // Poly : 04C11DB7
+ // Init : FFFFFFFF
+ // RefIn : True
+ // RefOut : True
+ // XorOut : 00000000
+ // Check : 340BC6D9
+ uint32_t CRC = 0xFFFFFFFFU;
+
+ auto UpdateCRC = [&CRC](char Byte) {
+ for (unsigned i = 0; i < 8; ++i) {
+ bool Bit = CRC & 0x80000000U;
+ if (Byte & (1U << i))
+ Bit = !Bit;
+ CRC <<= 1;
+ if (Bit)
+ CRC ^= 0x04C11DB7U;
+ }
+ };
+
+ auto GetLittleEndianByte = [&Mangler, &SL](unsigned Index) {
+ unsigned CharByteWidth = SL->getCharByteWidth();
+ uint32_t CodeUnit = SL->getCodeUnit(Index / CharByteWidth);
+ unsigned OffsetInCodeUnit = Index % CharByteWidth;
+ return static_cast<char>((CodeUnit >> (8 * OffsetInCodeUnit)) & 0xff);
+ };
+
+ auto GetBigEndianByte = [&Mangler, &SL](unsigned Index) {
+ unsigned CharByteWidth = SL->getCharByteWidth();
+ uint32_t CodeUnit = SL->getCodeUnit(Index / CharByteWidth);
+ unsigned OffsetInCodeUnit = (CharByteWidth - 1) - (Index % CharByteWidth);
+ return static_cast<char>((CodeUnit >> (8 * OffsetInCodeUnit)) & 0xff);
+ };
+
+ // CRC all the bytes of the StringLiteral.
+ for (unsigned I = 0, E = SL->getByteLength(); I != E; ++I)
+ UpdateCRC(GetLittleEndianByte(I));
+
+ // The NUL terminator byte(s) were not present earlier,
+ // we need to manually process those bytes into the CRC.
+ for (unsigned NullTerminator = 0; NullTerminator < SL->getCharByteWidth();
+ ++NullTerminator)
+ UpdateCRC('\x00');
+
+ // The literature refers to the process of reversing the bits in the final CRC
+ // output as "reflection".
+ CRC = llvm::reverseBits(CRC);
+
+ // <encoded-crc>: The CRC is encoded utilizing the standard number mangling
+ // scheme.
+ Mangler.mangleNumber(CRC);
+
+ // <encoded-string>: The mangled name also contains the first 32 _characters_
+ // (including null-terminator bytes) of the StringLiteral.
+ // Each character is encoded by splitting them into bytes and then encoding
+ // the constituent bytes.
+ auto MangleByte = [&Mangler](char Byte) {
+ // There are five different manglings for characters:
+ // - [a-zA-Z0-9_$]: A one-to-one mapping.
+ // - ?[a-z]: The range from \xe1 to \xfa.
+ // - ?[A-Z]: The range from \xc1 to \xda.
+ // - ?[0-9]: The set of [,/\:. \n\t'-].
+ // - ?$XX: A fallback which maps nibbles.
+ if (isIdentifierBody(Byte, /*AllowDollar=*/true)) {
+ Mangler.getStream() << Byte;
+ } else if (isLetter(Byte & 0x7f)) {
+ Mangler.getStream() << '?' << static_cast<char>(Byte & 0x7f);
+ } else {
+ switch (Byte) {
+ case ',':
+ Mangler.getStream() << "?0";
+ break;
+ case '/':
+ Mangler.getStream() << "?1";
+ break;
+ case '\\':
+ Mangler.getStream() << "?2";
+ break;
+ case ':':
+ Mangler.getStream() << "?3";
+ break;
+ case '.':
+ Mangler.getStream() << "?4";
+ break;
+ case ' ':
+ Mangler.getStream() << "?5";
+ break;
+ case '\n':
+ Mangler.getStream() << "?6";
+ break;
+ case '\t':
+ Mangler.getStream() << "?7";
+ break;
+ case '\'':
+ Mangler.getStream() << "?8";
+ break;
+ case '-':
+ Mangler.getStream() << "?9";
+ break;
+ default:
+ Mangler.getStream() << "?$";
+ Mangler.getStream() << static_cast<char>('A' + ((Byte >> 4) & 0xf));
+ Mangler.getStream() << static_cast<char>('A' + (Byte & 0xf));
+ break;
+ }
+ }
+ };
+
+ // Enforce our 32 character max.
+ unsigned NumCharsToMangle = std::min(32U, SL->getLength());
+ for (unsigned I = 0, E = NumCharsToMangle * SL->getCharByteWidth(); I != E;
+ ++I)
+ MangleByte(GetBigEndianByte(I));
+
+ // Encode the NUL terminator if there is room.
+ if (NumCharsToMangle < 32)
+ for (unsigned NullTerminator = 0; NullTerminator < SL->getCharByteWidth();
+ ++NullTerminator)
+ MangleByte(0);
+
+ Mangler.getStream() << '@';
+}
+
MicrosoftMangleContext *
MicrosoftMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
return new MicrosoftMangleContextImpl(Context, Diags);
diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp
index a862630bbf8d..986b3b53983d 100644
--- a/lib/AST/NSAPI.cpp
+++ b/lib/AST/NSAPI.cpp
@@ -14,9 +14,9 @@
using namespace clang;
NSAPI::NSAPI(ASTContext &ctx)
- : Ctx(ctx), ClassIds(), BOOLId(0), NSIntegerId(0), NSUIntegerId(0),
- NSASCIIStringEncodingId(0), NSUTF8StringEncodingId(0) {
-}
+ : Ctx(ctx), ClassIds(), BOOLId(nullptr), NSIntegerId(nullptr),
+ NSUIntegerId(nullptr), NSASCIIStringEncodingId(nullptr),
+ NSUTF8StringEncodingId(nullptr) {}
IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const {
static const char *ClassName[NumClassIds] = {
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index b03c4e09fa46..1f041aa49542 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -30,7 +30,7 @@ NestedNameSpecifier::FindOrInsert(const ASTContext &Context,
llvm::FoldingSetNodeID ID;
Mockup.Profile(ID);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
NestedNameSpecifier *NNS
= Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos);
if (!NNS) {
@@ -61,7 +61,8 @@ NestedNameSpecifier::Create(const ASTContext &Context,
const NamespaceDecl *NS) {
assert(NS && "Namespace cannot be NULL");
assert((!Prefix ||
- (Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
+ (Prefix->getAsType() == nullptr &&
+ Prefix->getAsIdentifier() == nullptr)) &&
"Broken nested name specifier");
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
@@ -76,7 +77,8 @@ NestedNameSpecifier::Create(const ASTContext &Context,
NamespaceAliasDecl *Alias) {
assert(Alias && "Namespace alias cannot be NULL");
assert((!Prefix ||
- (Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
+ (Prefix->getAsType() == nullptr &&
+ Prefix->getAsIdentifier() == nullptr)) &&
"Broken nested name specifier");
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
@@ -101,7 +103,7 @@ NestedNameSpecifier *
NestedNameSpecifier::Create(const ASTContext &Context, IdentifierInfo *II) {
assert(II && "Identifier cannot be NULL");
NestedNameSpecifier Mockup;
- Mockup.Prefix.setPointer(0);
+ Mockup.Prefix.setPointer(nullptr);
Mockup.Prefix.setInt(StoredIdentifier);
Mockup.Specifier = II;
return FindOrInsert(Context, Mockup);
@@ -117,7 +119,7 @@ NestedNameSpecifier::GlobalSpecifier(const ASTContext &Context) {
}
NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const {
- if (Specifier == 0)
+ if (!Specifier)
return Global;
switch (Prefix.getInt()) {
@@ -144,7 +146,7 @@ NamespaceDecl *NestedNameSpecifier::getAsNamespace() const {
if (Prefix.getInt() == StoredNamespaceOrAlias)
return dyn_cast<NamespaceDecl>(static_cast<NamedDecl *>(Specifier));
- return 0;
+ return nullptr;
}
/// \brief Retrieve the namespace alias stored in this nested name
@@ -153,7 +155,7 @@ NamespaceAliasDecl *NestedNameSpecifier::getAsNamespaceAlias() const {
if (Prefix.getInt() == StoredNamespaceOrAlias)
return dyn_cast<NamespaceAliasDecl>(static_cast<NamedDecl *>(Specifier));
- return 0;
+ return nullptr;
}
@@ -437,7 +439,7 @@ namespace {
NestedNameSpecifierLocBuilder::
NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other)
- : Representation(Other.Representation), Buffer(0),
+ : Representation(Other.Representation), Buffer(nullptr),
BufferSize(0), BufferCapacity(0)
{
if (!Other.Buffer)
@@ -451,10 +453,8 @@ NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other)
}
// Deep copy
- BufferSize = Other.BufferSize;
- BufferCapacity = Other.BufferSize;
- Buffer = static_cast<char *>(malloc(BufferCapacity));
- memcpy(Buffer, Other.Buffer, BufferSize);
+ Append(Other.Buffer, Other.Buffer + Other.BufferSize, Buffer, BufferSize,
+ BufferCapacity);
}
NestedNameSpecifierLocBuilder &
@@ -477,7 +477,7 @@ operator=(const NestedNameSpecifierLocBuilder &Other) {
if (!Other.Buffer) {
// Empty.
- Buffer = 0;
+ Buffer = nullptr;
BufferSize = 0;
return *this;
}
@@ -490,10 +490,8 @@ operator=(const NestedNameSpecifierLocBuilder &Other) {
}
// Deep copy.
- BufferSize = Other.BufferSize;
- BufferCapacity = BufferSize;
- Buffer = static_cast<char *>(malloc(BufferSize));
- memcpy(Buffer, Other.Buffer, BufferSize);
+ Append(Other.Buffer, Other.Buffer + Other.BufferSize, Buffer, BufferSize,
+ BufferCapacity);
return *this;
}
@@ -599,7 +597,7 @@ void NestedNameSpecifierLocBuilder::Adopt(NestedNameSpecifierLoc Other) {
free(Buffer);
if (!Other) {
- Representation = 0;
+ Representation = nullptr;
BufferSize = 0;
return;
}
diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp
index ff44d938d3ae..a991302a2540 100644
--- a/lib/AST/ParentMap.cpp
+++ b/lib/AST/ParentMap.cpp
@@ -37,7 +37,7 @@ static void BuildParentMap(MapTy& M, Stmt* S,
// If we are rebuilding the map, clear out any existing state.
if (M[POE->getSyntacticForm()])
for (Stmt::child_range I = S->children(); I; ++I)
- M[*I] = 0;
+ M[*I] = nullptr;
M[POE->getSyntacticForm()] = S;
BuildParentMap(M, POE->getSyntacticForm(), OV_Transparent);
@@ -92,7 +92,7 @@ static void BuildParentMap(MapTy& M, Stmt* S,
}
}
-ParentMap::ParentMap(Stmt* S) : Impl(0) {
+ParentMap::ParentMap(Stmt *S) : Impl(nullptr) {
if (S) {
MapTy *M = new MapTy();
BuildParentMap(*M, S);
@@ -120,7 +120,7 @@ void ParentMap::setParent(const Stmt *S, const Stmt *Parent) {
Stmt* ParentMap::getParent(Stmt* S) const {
MapTy* M = (MapTy*) Impl;
MapTy::iterator I = M->find(S);
- return I == M->end() ? 0 : I->second;
+ return I == M->end() ? nullptr : I->second;
}
Stmt *ParentMap::getParentIgnoreParens(Stmt *S) const {
@@ -146,7 +146,7 @@ Stmt *ParentMap::getParentIgnoreParenImpCasts(Stmt *S) const {
}
Stmt *ParentMap::getOuterParenParent(Stmt *S) const {
- Stmt *Paren = 0;
+ Stmt *Paren = nullptr;
while (isa<ParenExpr>(S)) {
Paren = S;
S = getParent(S);
diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp
index 1fa7cea1d498..24b129a5c532 100644
--- a/lib/AST/RawCommentList.cpp
+++ b/lib/AST/RawCommentList.cpp
@@ -95,10 +95,9 @@ StringRef RawComment::getRawTextSlow(const SourceManager &SourceMgr) const {
unsigned BeginOffset;
unsigned EndOffset;
- llvm::tie(BeginFileID, BeginOffset) =
+ std::tie(BeginFileID, BeginOffset) =
SourceMgr.getDecomposedLoc(Range.getBegin());
- llvm::tie(EndFileID, EndOffset) =
- SourceMgr.getDecomposedLoc(Range.getEnd());
+ std::tie(EndFileID, EndOffset) = SourceMgr.getDecomposedLoc(Range.getEnd());
const unsigned Length = EndOffset - BeginOffset;
if (Length < 2)
@@ -252,3 +251,15 @@ void RawCommentList::addComment(const RawComment &RC,
Comments.push_back(new (Allocator) RawComment(RC));
}
}
+
+void RawCommentList::addDeserializedComments(ArrayRef<RawComment *> DeserializedComments) {
+ std::vector<RawComment *> MergedComments;
+ MergedComments.reserve(Comments.size() + DeserializedComments.size());
+
+ std::merge(Comments.begin(), Comments.end(),
+ DeserializedComments.begin(), DeserializedComments.end(),
+ std::back_inserter(MergedComments),
+ BeforeThanCompare<RawComment>(SourceMgr));
+ std::swap(Comments, MergedComments);
+}
+
diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp
index 71e44ecf9219..b2c244e3790e 100644
--- a/lib/AST/RecordLayout.cpp
+++ b/lib/AST/RecordLayout.cpp
@@ -21,19 +21,22 @@ void ASTRecordLayout::Destroy(ASTContext &Ctx) {
if (FieldOffsets)
Ctx.Deallocate(FieldOffsets);
if (CXXInfo) {
- Ctx.Deallocate(CXXInfo);
CXXInfo->~CXXRecordLayoutInfo();
+ Ctx.Deallocate(CXXInfo);
}
this->~ASTRecordLayout();
Ctx.Deallocate(this);
}
ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size,
- CharUnits alignment, CharUnits datasize,
+ CharUnits alignment,
+ CharUnits requiredAlignment,
+ CharUnits datasize,
const uint64_t *fieldoffsets,
unsigned fieldcount)
- : Size(size), DataSize(datasize), Alignment(alignment), FieldOffsets(0),
- FieldCount(fieldcount), CXXInfo(0) {
+ : Size(size), DataSize(datasize), Alignment(alignment),
+ RequiredAlignment(requiredAlignment), FieldOffsets(nullptr),
+ FieldCount(fieldcount), CXXInfo(nullptr) {
if (FieldCount > 0) {
FieldOffsets = new (Ctx) uint64_t[FieldCount];
memcpy(FieldOffsets, fieldoffsets, FieldCount * sizeof(*FieldOffsets));
@@ -43,21 +46,24 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size,
// Constructor for C++ records.
ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
CharUnits size, CharUnits alignment,
+ CharUnits requiredAlignment,
bool hasOwnVFPtr, bool hasExtendableVFPtr,
CharUnits vbptroffset,
CharUnits datasize,
const uint64_t *fieldoffsets,
unsigned fieldcount,
CharUnits nonvirtualsize,
- CharUnits nonvirtualalign,
+ CharUnits nonvirtualalignment,
CharUnits SizeOfLargestEmptySubobject,
const CXXRecordDecl *PrimaryBase,
bool IsPrimaryBaseVirtual,
const CXXRecordDecl *BaseSharingVBPtr,
- bool AlignAfterVBases,
+ bool HasZeroSizedSubObject,
+ bool LeadsWithZeroSizedBase,
const BaseOffsetsMapTy& BaseOffsets,
const VBaseOffsetsMapTy& VBaseOffsets)
- : Size(size), DataSize(datasize), Alignment(alignment), FieldOffsets(0),
+ : Size(size), DataSize(datasize), Alignment(alignment),
+ RequiredAlignment(requiredAlignment), FieldOffsets(nullptr),
FieldCount(fieldcount), CXXInfo(new (Ctx) CXXRecordLayoutInfo)
{
if (FieldCount > 0) {
@@ -68,7 +74,7 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
CXXInfo->PrimaryBase.setPointer(PrimaryBase);
CXXInfo->PrimaryBase.setInt(IsPrimaryBaseVirtual);
CXXInfo->NonVirtualSize = nonvirtualsize;
- CXXInfo->NonVirtualAlign = nonvirtualalign;
+ CXXInfo->NonVirtualAlignment = nonvirtualalignment;
CXXInfo->SizeOfLargestEmptySubobject = SizeOfLargestEmptySubobject;
CXXInfo->BaseOffsets = BaseOffsets;
CXXInfo->VBaseOffsets = VBaseOffsets;
@@ -76,7 +82,8 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
CXXInfo->VBPtrOffset = vbptroffset;
CXXInfo->HasExtendableVFPtr = hasExtendableVFPtr;
CXXInfo->BaseSharingVBPtr = BaseSharingVBPtr;
- CXXInfo->AlignAfterVBases = AlignAfterVBases;
+ CXXInfo->HasZeroSizedSubObject = HasZeroSizedSubObject;
+ CXXInfo->LeadsWithZeroSizedBase = LeadsWithZeroSizedBase;
#ifndef NDEBUG
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 4390e66c8b1c..b3deebaecfab 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -65,7 +65,7 @@ class EmptySubobjectMap {
const CXXRecordDecl *Class;
/// EmptyClassOffsets - A map from offsets to empty record decls.
- typedef SmallVector<const CXXRecordDecl *, 1> ClassVectorTy;
+ typedef llvm::TinyPtrVector<const CXXRecordDecl *> ClassVectorTy;
typedef llvm::DenseMap<CharUnits, ClassVectorTy> EmptyClassOffsetsMapTy;
EmptyClassOffsetsMapTy EmptyClassOffsets;
@@ -140,10 +140,8 @@ public:
void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
// Check the bases.
- for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(),
- E = Class->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ for (const CXXBaseSpecifier &Base : Class->bases()) {
+ const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
CharUnits EmptySize;
const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
@@ -160,18 +158,16 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
}
// Check the fields.
- for (CXXRecordDecl::field_iterator I = Class->field_begin(),
- E = Class->field_end(); I != E; ++I) {
-
+ for (const FieldDecl *FD : Class->fields()) {
const RecordType *RT =
- Context.getBaseElementType(I->getType())->getAs<RecordType>();
+ Context.getBaseElementType(FD->getType())->getAs<RecordType>();
// We only care about record types.
if (!RT)
continue;
CharUnits EmptySize;
- const CXXRecordDecl *MemberDecl = cast<CXXRecordDecl>(RT->getDecl());
+ const CXXRecordDecl *MemberDecl = RT->getAsCXXRecordDecl();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl);
if (MemberDecl->isEmpty()) {
// If the class decl is empty, get its size.
@@ -196,8 +192,8 @@ EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD,
EmptyClassOffsetsMapTy::const_iterator I = EmptyClassOffsets.find(Offset);
if (I == EmptyClassOffsets.end())
return true;
-
- const ClassVectorTy& Classes = I->second;
+
+ const ClassVectorTy &Classes = I->second;
if (std::find(Classes.begin(), Classes.end(), RD) == Classes.end())
return true;
@@ -213,7 +209,7 @@ void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD,
// If we have empty structures inside a union, we can assign both
// the same offset. Just avoid pushing them twice in the list.
- ClassVectorTy& Classes = EmptyClassOffsets[Offset];
+ ClassVectorTy &Classes = EmptyClassOffsets[Offset];
if (std::find(Classes.begin(), Classes.end(), RD) != Classes.end())
return;
@@ -237,8 +233,7 @@ EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
// Traverse all non-virtual bases.
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Info->Class);
- for (unsigned I = 0, E = Info->Bases.size(); I != E; ++I) {
- BaseSubobjectInfo* Base = Info->Bases[I];
+ for (const BaseSubobjectInfo *Base : Info->Bases) {
if (Base->IsVirtual)
continue;
@@ -263,12 +258,12 @@ EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
E = Info->Class->field_end(); I != E; ++I, ++FieldNo) {
if (I->isBitField())
continue;
-
+
CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo);
if (!CanPlaceFieldSubobjectAtOffset(*I, FieldOffset))
return false;
}
-
+
return true;
}
@@ -288,8 +283,7 @@ void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info,
// Traverse all non-virtual bases.
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Info->Class);
- for (unsigned I = 0, E = Info->Bases.size(); I != E; ++I) {
- BaseSubobjectInfo* Base = Info->Bases[I];
+ for (const BaseSubobjectInfo *Base : Info->Bases) {
if (Base->IsVirtual)
continue;
@@ -348,13 +342,11 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
// Traverse all non-virtual bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- if (I->isVirtual())
+ for (const CXXBaseSpecifier &Base : RD->bases()) {
+ if (Base.isVirtual())
continue;
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
if (!CanPlaceFieldSubobjectAtOffset(BaseDecl, Class, BaseOffset))
@@ -363,11 +355,9 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
if (RD == Class) {
// This is the most derived class, traverse virtual bases as well.
- for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
- E = RD->vbases_end(); I != E; ++I) {
- const CXXRecordDecl *VBaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
+ for (const CXXBaseSpecifier &Base : RD->vbases()) {
+ const CXXRecordDecl *VBaseDecl = Base.getType()->getAsCXXRecordDecl();
+
CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
if (!CanPlaceFieldSubobjectAtOffset(VBaseDecl, Class, VBaseOffset))
return false;
@@ -399,10 +389,8 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
return true;
QualType T = FD->getType();
- if (const RecordType *RT = T->getAs<RecordType>()) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
return CanPlaceFieldSubobjectAtOffset(RD, RD, Offset);
- }
// If we have an array type we need to look at every element.
if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
@@ -410,8 +398,8 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
const RecordType *RT = ElemTy->getAs<RecordType>();
if (!RT)
return true;
-
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ const CXXRecordDecl *RD = RT->getAsCXXRecordDecl();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
uint64_t NumElements = Context.getConstantArrayElementCount(AT);
@@ -460,13 +448,11 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
// Traverse all non-virtual bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- if (I->isVirtual())
+ for (const CXXBaseSpecifier &Base : RD->bases()) {
+ if (Base.isVirtual())
continue;
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
UpdateEmptyFieldSubobjects(BaseDecl, Class, BaseOffset);
@@ -474,11 +460,9 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
if (RD == Class) {
// This is the most derived class, traverse virtual bases as well.
- for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
- E = RD->vbases_end(); I != E; ++I) {
- const CXXRecordDecl *VBaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
+ for (const CXXBaseSpecifier &Base : RD->vbases()) {
+ const CXXRecordDecl *VBaseDecl = Base.getType()->getAsCXXRecordDecl();
+
CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
UpdateEmptyFieldSubobjects(VBaseDecl, Class, VBaseOffset);
}
@@ -500,8 +484,7 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD,
CharUnits Offset) {
QualType T = FD->getType();
- if (const RecordType *RT = T->getAs<RecordType>()) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) {
UpdateEmptyFieldSubobjects(RD, RD, Offset);
return;
}
@@ -512,8 +495,8 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD,
const RecordType *RT = ElemTy->getAs<RecordType>();
if (!RT)
return;
-
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ const CXXRecordDecl *RD = RT->getAsCXXRecordDecl();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
uint64_t NumElements = Context.getConstantArrayElementCount(AT);
@@ -649,9 +632,9 @@ protected:
MaxFieldAlignment(CharUnits::Zero()),
DataSize(0), NonVirtualSize(CharUnits::Zero()),
NonVirtualAlignment(CharUnits::One()),
- PrimaryBase(0), PrimaryBaseIsVirtual(false),
+ PrimaryBase(nullptr), PrimaryBaseIsVirtual(false),
HasOwnVFPtr(false),
- FirstNearlyEmptyVBase(0) { }
+ FirstNearlyEmptyVBase(nullptr) {}
/// Reset this RecordLayoutBuilder to a fresh state, using the given
/// alignment as the initial alignment. This is used for the
@@ -783,16 +766,14 @@ protected:
void
RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- assert(!I->getType()->isDependentType() &&
+ for (const auto &I : RD->bases()) {
+ assert(!I.getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *Base = I.getType()->getAsCXXRecordDecl();
// Check if this is a nearly empty virtual base.
- if (I->isVirtual() && Context.isNearlyEmpty(Base)) {
+ if (I.isVirtual() && Context.isNearlyEmpty(Base)) {
// If it's not an indirect primary base, then we've found our primary
// base.
if (!IndirectPrimaryBases.count(Base)) {
@@ -825,14 +806,12 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
// If the record has a dynamic base class, attempt to choose a primary base
// class. It is the first (in direct base class order) non-virtual dynamic
// base class, if one exists.
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
+ for (const auto &I : RD->bases()) {
// Ignore virtual bases.
- if (i->isVirtual())
+ if (I.isVirtual())
continue;
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *Base = I.getType()->getAsCXXRecordDecl();
if (Base->isDynamicClass()) {
// We found it.
@@ -885,11 +864,11 @@ RecordLayoutBuilder::ComputeBaseSubobjectInfo(const CXXRecordDecl *RD,
Info->Class = RD;
Info->IsVirtual = IsVirtual;
- Info->Derived = 0;
- Info->PrimaryVirtualBaseInfo = 0;
-
- const CXXRecordDecl *PrimaryVirtualBase = 0;
- BaseSubobjectInfo *PrimaryVirtualBaseInfo = 0;
+ Info->Derived = nullptr;
+ Info->PrimaryVirtualBaseInfo = nullptr;
+
+ const CXXRecordDecl *PrimaryVirtualBase = nullptr;
+ BaseSubobjectInfo *PrimaryVirtualBaseInfo = nullptr;
// Check if this base has a primary virtual base.
if (RD->getNumVBases()) {
@@ -906,8 +885,8 @@ RecordLayoutBuilder::ComputeBaseSubobjectInfo(const CXXRecordDecl *RD,
if (PrimaryVirtualBaseInfo->Derived) {
// We did have info about this primary base, and it turns out that it
// has already been claimed as a primary virtual base for another
- // base.
- PrimaryVirtualBase = 0;
+ // base.
+ PrimaryVirtualBase = nullptr;
} else {
// We can claim this base as our primary base.
Info->PrimaryVirtualBaseInfo = PrimaryVirtualBaseInfo;
@@ -918,13 +897,11 @@ RecordLayoutBuilder::ComputeBaseSubobjectInfo(const CXXRecordDecl *RD,
}
// Now go through all direct bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- bool IsVirtual = I->isVirtual();
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
+ for (const auto &I : RD->bases()) {
+ bool IsVirtual = I.isVirtual();
+
+ const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl();
+
Info->Bases.push_back(ComputeBaseSubobjectInfo(BaseDecl, IsVirtual, Info));
}
@@ -944,15 +921,14 @@ RecordLayoutBuilder::ComputeBaseSubobjectInfo(const CXXRecordDecl *RD,
}
void RecordLayoutBuilder::ComputeBaseSubobjectInfo(const CXXRecordDecl *RD) {
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- bool IsVirtual = I->isVirtual();
+ for (const auto &I : RD->bases()) {
+ bool IsVirtual = I.isVirtual();
+
+ const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl();
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
// Compute the base subobject info for this base.
- BaseSubobjectInfo *Info = ComputeBaseSubobjectInfo(BaseDecl, IsVirtual, 0);
+ BaseSubobjectInfo *Info = ComputeBaseSubobjectInfo(BaseDecl, IsVirtual,
+ nullptr);
if (IsVirtual) {
// ComputeBaseInfo has already added this base for us.
@@ -999,8 +975,8 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
// If the primary virtual base was a primary virtual base of some other
// base class we'll have to steal it.
BaseSubobjectInfo *PrimaryBaseInfo = VirtualBaseInfo.lookup(PrimaryBase);
- PrimaryBaseInfo->Derived = 0;
-
+ PrimaryBaseInfo->Derived = nullptr;
+
// We have a virtual primary base, insert it as an indirect primary base.
IndirectPrimaryBases.insert(PrimaryBase);
@@ -1033,15 +1009,13 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
}
// Now lay out the non-virtual bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
+ for (const auto &I : RD->bases()) {
// Ignore virtual bases.
- if (I->isVirtual())
+ if (I.isVirtual())
continue;
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl();
// Skip the primary base, because we've already laid it out. The
// !PrimaryBaseIsVirtual check is required because we might have a
@@ -1093,8 +1067,7 @@ RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
// Now go through all direct non-virtual bases.
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Info->Class);
- for (unsigned I = 0, E = Info->Bases.size(); I != E; ++I) {
- const BaseSubobjectInfo *Base = Info->Bases[I];
+ for (const BaseSubobjectInfo *Base : Info->Bases) {
if (Base->IsVirtual)
continue;
@@ -1118,15 +1091,13 @@ RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
PrimaryBaseIsVirtual = Layout.isPrimaryBaseVirtual();
}
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- assert(!I->getType()->isDependentType() &&
+ for (const CXXBaseSpecifier &Base : RD->bases()) {
+ assert(!Base.getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
- if (I->isVirtual()) {
+ if (Base.isVirtual()) {
if (PrimaryBase != BaseDecl || !PrimaryBaseIsVirtual) {
bool IndirectPrimaryBase = IndirectPrimaryBases.count(BaseDecl);
@@ -1191,7 +1162,7 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
}
}
- CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlign();
+ CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlignment();
CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign;
// If we have an empty base class, try to place it at offset 0.
@@ -1326,22 +1297,18 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
#ifndef NDEBUG
// Check that we have base offsets for all bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- if (I->isVirtual())
+ for (const CXXBaseSpecifier &Base : RD->bases()) {
+ if (Base.isVirtual())
continue;
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
assert(Bases.count(BaseDecl) && "Did not find base offset!");
}
// And all virtual bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
- E = RD->vbases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ for (const CXXBaseSpecifier &Base : RD->vbases()) {
+ const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
assert(VBases.count(BaseDecl) && "Did not find base offset!");
}
@@ -1374,9 +1341,8 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
// Layout each field, for now, just sequentially, respecting alignment. In
// the future, this will need to be tweakable by targets.
- for (RecordDecl::field_iterator Field = D->field_begin(),
- FieldEnd = D->field_end(); Field != FieldEnd; ++Field)
- LayoutField(*Field);
+ for (const auto *Field : D->fields())
+ LayoutField(Field);
}
void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
@@ -1396,14 +1362,13 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
};
QualType Type;
- for (unsigned I = 0, E = llvm::array_lengthof(IntegralPODTypes);
- I != E; ++I) {
- uint64_t Size = Context.getTypeSize(IntegralPODTypes[I]);
+ for (const QualType &QT : IntegralPODTypes) {
+ uint64_t Size = Context.getTypeSize(QT);
if (Size > FieldSize)
break;
- Type = IntegralPODTypes[I];
+ Type = QT;
}
assert(!Type.isNull() && "Did not find a type!");
@@ -1452,127 +1417,224 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
uint64_t TypeSize = FieldInfo.first;
unsigned FieldAlign = FieldInfo.second;
+ // UnfilledBitsInLastUnit is the difference between the end of the
+ // last allocated bitfield (i.e. the first bit offset available for
+ // bitfields) and the end of the current data size in bits (i.e. the
+ // first bit offset available for non-bitfields). The current data
+ // size in bits is always a multiple of the char size; additionally,
+ // for ms_struct records it's also a multiple of the
+ // LastBitfieldTypeSize (if set).
+
+ // The struct-layout algorithm is dictated by the platform ABI,
+ // which in principle could use almost any rules it likes. In
+ // practice, UNIXy targets tend to inherit the algorithm described
+ // in the System V generic ABI. The basic bitfield layout rule in
+ // System V is to place bitfields at the next available bit offset
+ // where the entire bitfield would fit in an aligned storage unit of
+ // the declared type; it's okay if an earlier or later non-bitfield
+ // is allocated in the same storage unit. However, some targets
+ // (those that !useBitFieldTypeAlignment(), e.g. ARM APCS) don't
+ // require this storage unit to be aligned, and therefore always put
+ // the bitfield at the next available bit offset.
+
+ // ms_struct basically requests a complete replacement of the
+ // platform ABI's struct-layout algorithm, with the high-level goal
+ // of duplicating MSVC's layout. For non-bitfields, this follows
+ // the the standard algorithm. The basic bitfield layout rule is to
+ // allocate an entire unit of the bitfield's declared type
+ // (e.g. 'unsigned long'), then parcel it up among successive
+ // bitfields whose declared types have the same size, making a new
+ // unit as soon as the last can no longer store the whole value.
+ // Since it completely replaces the platform ABI's algorithm,
+ // settings like !useBitFieldTypeAlignment() do not apply.
+
+ // A zero-width bitfield forces the use of a new storage unit for
+ // later bitfields. In general, this occurs by rounding up the
+ // current size of the struct as if the algorithm were about to
+ // place a non-bitfield of the field's formal type. Usually this
+ // does not change the alignment of the struct itself, but it does
+ // on some targets (those that useZeroLengthBitfieldAlignment(),
+ // e.g. ARM). In ms_struct layout, zero-width bitfields are
+ // ignored unless they follow a non-zero-width bitfield.
+
+ // A field alignment restriction (e.g. from #pragma pack) or
+ // specification (e.g. from __attribute__((aligned))) changes the
+ // formal alignment of the field. For System V, this alters the
+ // required alignment of the notional storage unit that must contain
+ // the bitfield. For ms_struct, this only affects the placement of
+ // new storage units. In both cases, the effect of #pragma pack is
+ // ignored on zero-width bitfields.
+
+ // On System V, a packed field (e.g. from #pragma pack or
+ // __attribute__((packed))) always uses the next available bit
+ // offset.
+
+ // In an ms_struct struct, the alignment of a fundamental type is
+ // always equal to its size. This is necessary in order to mimic
+ // the i386 alignment rules on targets which might not fully align
+ // all types (e.g. Darwin PPC32, where alignof(long long) == 4).
+
+ // First, some simple bookkeeping to perform for ms_struct structs.
if (IsMsStruct) {
- // The field alignment for integer types in ms_struct structs is
- // always the size.
+ // The field alignment for integer types is always the size.
FieldAlign = TypeSize;
- // Ignore zero-length bitfields after non-bitfields in ms_struct structs.
- if (!FieldSize && !LastBitfieldTypeSize)
- FieldAlign = 1;
- // If a bitfield is followed by a bitfield of a different size, don't
- // pack the bits together in ms_struct structs.
+
+ // If the previous field was not a bitfield, or was a bitfield
+ // with a different storage unit size, we're done with that
+ // storage unit.
if (LastBitfieldTypeSize != TypeSize) {
+ // Also, ignore zero-length bitfields after non-bitfields.
+ if (!LastBitfieldTypeSize && !FieldSize)
+ FieldAlign = 1;
+
UnfilledBitsInLastUnit = 0;
LastBitfieldTypeSize = 0;
}
}
- uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit;
- uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset;
-
- bool ZeroLengthBitfield = false;
- if (!Context.getTargetInfo().useBitFieldTypeAlignment() &&
- Context.getTargetInfo().useZeroLengthBitfieldAlignment() &&
- FieldSize == 0) {
- // The alignment of a zero-length bitfield affects the alignment
- // of the next member. The alignment is the max of the zero
- // length bitfield's alignment and a target specific fixed value.
- ZeroLengthBitfield = true;
- unsigned ZeroLengthBitfieldBoundary =
- Context.getTargetInfo().getZeroLengthBitfieldBoundary();
- if (ZeroLengthBitfieldBoundary > FieldAlign)
- FieldAlign = ZeroLengthBitfieldBoundary;
- }
-
+ // If the field is wider than its declared type, it follows
+ // different rules in all cases.
if (FieldSize > TypeSize) {
LayoutWideBitField(FieldSize, TypeSize, FieldPacked, D);
return;
}
- // The align if the field is not packed. This is to check if the attribute
- // was unnecessary (-Wpacked).
+ // Compute the next available bit offset.
+ uint64_t FieldOffset =
+ IsUnion ? 0 : (getDataSizeInBits() - UnfilledBitsInLastUnit);
+
+ // Handle targets that don't honor bitfield type alignment.
+ if (!IsMsStruct && !Context.getTargetInfo().useBitFieldTypeAlignment()) {
+ // Some such targets do honor it on zero-width bitfields.
+ if (FieldSize == 0 &&
+ Context.getTargetInfo().useZeroLengthBitfieldAlignment()) {
+ // The alignment to round up to is the max of the field's natural
+ // alignment and a target-specific fixed value (sometimes zero).
+ unsigned ZeroLengthBitfieldBoundary =
+ Context.getTargetInfo().getZeroLengthBitfieldBoundary();
+ FieldAlign = std::max(FieldAlign, ZeroLengthBitfieldBoundary);
+
+ // If that doesn't apply, just ignore the field alignment.
+ } else {
+ FieldAlign = 1;
+ }
+ }
+
+ // Remember the alignment we would have used if the field were not packed.
unsigned UnpackedFieldAlign = FieldAlign;
- uint64_t UnpackedFieldOffset = FieldOffset;
- if (!Context.getTargetInfo().useBitFieldTypeAlignment() && !ZeroLengthBitfield)
- UnpackedFieldAlign = 1;
- if (FieldPacked ||
- (!Context.getTargetInfo().useBitFieldTypeAlignment() && !ZeroLengthBitfield))
+ // Ignore the field alignment if the field is packed unless it has zero-size.
+ if (!IsMsStruct && FieldPacked && FieldSize != 0)
FieldAlign = 1;
- FieldAlign = std::max(FieldAlign, D->getMaxAlignment());
- UnpackedFieldAlign = std::max(UnpackedFieldAlign, D->getMaxAlignment());
- // The maximum field alignment overrides the aligned attribute.
- if (!MaxFieldAlignment.isZero() && FieldSize != 0) {
+ // But, if there's an 'aligned' attribute on the field, honor that.
+ if (unsigned ExplicitFieldAlign = D->getMaxAlignment()) {
+ FieldAlign = std::max(FieldAlign, ExplicitFieldAlign);
+ UnpackedFieldAlign = std::max(UnpackedFieldAlign, ExplicitFieldAlign);
+ }
+
+ // But, if there's a #pragma pack in play, that takes precedent over
+ // even the 'aligned' attribute, for non-zero-width bitfields.
+ if (!MaxFieldAlignment.isZero() && FieldSize) {
unsigned MaxFieldAlignmentInBits = Context.toBits(MaxFieldAlignment);
FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits);
}
- // ms_struct bitfields always have to start at a round alignment.
- if (IsMsStruct && !LastBitfieldTypeSize) {
- FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
- UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
- UnpackedFieldAlign);
- }
+ // For purposes of diagnostics, we're going to simultaneously
+ // compute the field offsets that we would have used if we weren't
+ // adding any alignment padding or if the field weren't packed.
+ uint64_t UnpaddedFieldOffset = FieldOffset;
+ uint64_t UnpackedFieldOffset = FieldOffset;
- // Check if we need to add padding to give the field the correct alignment.
- if (FieldSize == 0 ||
- (MaxFieldAlignment.isZero() &&
- (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize))
- FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
+ // Check if we need to add padding to fit the bitfield within an
+ // allocation unit with the right size and alignment. The rules are
+ // somewhat different here for ms_struct structs.
+ if (IsMsStruct) {
+ // If it's not a zero-width bitfield, and we can fit the bitfield
+ // into the active storage unit (and we haven't already decided to
+ // start a new storage unit), just do so, regardless of any other
+ // other consideration. Otherwise, round up to the right alignment.
+ if (FieldSize == 0 || FieldSize > UnfilledBitsInLastUnit) {
+ FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
+ UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
+ UnpackedFieldAlign);
+ UnfilledBitsInLastUnit = 0;
+ }
- if (FieldSize == 0 ||
- (MaxFieldAlignment.isZero() &&
- (UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize))
- UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
- UnpackedFieldAlign);
+ } else {
+ // #pragma pack, with any value, suppresses the insertion of padding.
+ bool AllowPadding = MaxFieldAlignment.isZero();
+
+ // Compute the real offset.
+ if (FieldSize == 0 ||
+ (AllowPadding &&
+ (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)) {
+ FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
+ }
- // Padding members don't affect overall alignment, unless zero length bitfield
- // alignment is enabled.
- if (!D->getIdentifier() &&
- !Context.getTargetInfo().useZeroLengthBitfieldAlignment() &&
- !IsMsStruct)
- FieldAlign = UnpackedFieldAlign = 1;
+ // Repeat the computation for diagnostic purposes.
+ if (FieldSize == 0 ||
+ (AllowPadding &&
+ (UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize))
+ UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
+ UnpackedFieldAlign);
+ }
+ // If we're using external layout, give the external layout a chance
+ // to override this information.
if (ExternalLayout)
FieldOffset = updateExternalFieldOffset(D, FieldOffset);
- // Place this field at the current location.
+ // Okay, place the bitfield at the calculated offset.
FieldOffsets.push_back(FieldOffset);
+ // Bookkeeping:
+
+ // Anonymous members don't affect the overall record alignment,
+ // except on targets where they do.
+ if (!IsMsStruct &&
+ !Context.getTargetInfo().useZeroLengthBitfieldAlignment() &&
+ !D->getIdentifier())
+ FieldAlign = UnpackedFieldAlign = 1;
+
+ // Diagnose differences in layout due to padding or packing.
if (!ExternalLayout)
CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, UnpackedFieldOffset,
UnpackedFieldAlign, FieldPacked, D);
// Update DataSize to include the last byte containing (part of) the bitfield.
+
+ // For unions, this is just a max operation, as usual.
if (IsUnion) {
// FIXME: I think FieldSize should be TypeSize here.
setDataSize(std::max(getDataSizeInBits(), FieldSize));
- } else {
- if (IsMsStruct && FieldSize) {
- // Under ms_struct, a bitfield always takes up space equal to the size
- // of the type. We can't just change the alignment computation on the
- // other codepath because of the way this interacts with #pragma pack:
- // in a packed struct, we need to allocate misaligned space in the
- // struct to hold the bitfield.
- if (!UnfilledBitsInLastUnit) {
- setDataSize(FieldOffset + TypeSize);
- UnfilledBitsInLastUnit = TypeSize - FieldSize;
- } else if (UnfilledBitsInLastUnit < FieldSize) {
- setDataSize(getDataSizeInBits() + TypeSize);
- UnfilledBitsInLastUnit = TypeSize - FieldSize;
- } else {
- UnfilledBitsInLastUnit -= FieldSize;
- }
- LastBitfieldTypeSize = TypeSize;
- } else {
- uint64_t NewSizeInBits = FieldOffset + FieldSize;
- uint64_t BitfieldAlignment = Context.getTargetInfo().getCharAlign();
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, BitfieldAlignment));
- UnfilledBitsInLastUnit = getDataSizeInBits() - NewSizeInBits;
- LastBitfieldTypeSize = 0;
+
+ // For non-zero-width bitfields in ms_struct structs, allocate a new
+ // storage unit if necessary.
+ } else if (IsMsStruct && FieldSize) {
+ // We should have cleared UnfilledBitsInLastUnit in every case
+ // where we changed storage units.
+ if (!UnfilledBitsInLastUnit) {
+ setDataSize(FieldOffset + TypeSize);
+ UnfilledBitsInLastUnit = TypeSize;
}
+ UnfilledBitsInLastUnit -= FieldSize;
+ LastBitfieldTypeSize = TypeSize;
+
+ // Otherwise, bump the data size up to include the bitfield,
+ // including padding up to char alignment, and then remember how
+ // bits we didn't use.
+ } else {
+ uint64_t NewSizeInBits = FieldOffset + FieldSize;
+ uint64_t CharAlignment = Context.getTargetInfo().getCharAlign();
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, CharAlignment));
+ UnfilledBitsInLastUnit = getDataSizeInBits() - NewSizeInBits;
+
+ // The only time we can get here for an ms_struct is if this is a
+ // zero-width bitfield, which doesn't count as anything for the
+ // purposes of unfilled bits.
+ LastBitfieldTypeSize = 0;
}
// Update the size.
@@ -1870,28 +1932,26 @@ static const CXXMethodDecl *computeKeyFunction(ASTContext &Context,
const CXXRecordDecl *RD) {
// If a class isn't polymorphic it doesn't have a key function.
if (!RD->isPolymorphic())
- return 0;
+ return nullptr;
// A class that is not externally visible doesn't have a key function. (Or
// at least, there's no point to assigning a key function to such a class;
// this doesn't affect the ABI.)
if (!RD->isExternallyVisible())
- return 0;
+ return nullptr;
- // Template instantiations don't have key functions,see Itanium C++ ABI 5.2.6.
+ // Template instantiations don't have key functions per Itanium C++ ABI 5.2.6.
// Same behavior as GCC.
TemplateSpecializationKind TSK = RD->getTemplateSpecializationKind();
if (TSK == TSK_ImplicitInstantiation ||
+ TSK == TSK_ExplicitInstantiationDeclaration ||
TSK == TSK_ExplicitInstantiationDefinition)
- return 0;
+ return nullptr;
bool allowInlineFunctions =
Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline();
- for (CXXRecordDecl::method_iterator I = RD->method_begin(),
- E = RD->method_end(); I != E; ++I) {
- const CXXMethodDecl *MD = *I;
-
+ for (const CXXMethodDecl *MD : RD->methods()) {
if (!MD->isVirtual())
continue;
@@ -1924,7 +1984,7 @@ static const CXXMethodDecl *computeKeyFunction(ASTContext &Context,
return MD;
}
- return 0;
+ return nullptr;
}
DiagnosticBuilder
@@ -1979,50 +2039,101 @@ static bool isMsLayout(const RecordDecl* D) {
}
// This section contains an implementation of struct layout that is, up to the
-// included tests, compatible with cl.exe (2012). The layout produced is
+// included tests, compatible with cl.exe (2013). The layout produced is
// significantly different than those produced by the Itanium ABI. Here we note
// the most important differences.
//
// * The alignment of bitfields in unions is ignored when computing the
// alignment of the union.
-// * The existance of zero-width bitfield that occurs after anything other than
+// * The existence of zero-width bitfield that occurs after anything other than
// a non-zero length bitfield is ignored.
+// * There is no explicit primary base for the purposes of layout. All bases
+// with vfptrs are laid out first, followed by all bases without vfptrs.
// * The Itanium equivalent vtable pointers are split into a vfptr (virtual
// function pointer) and a vbptr (virtual base pointer). They can each be
// shared with a, non-virtual bases. These bases need not be the same. vfptrs
-// always occur at offset 0. vbptrs can occur at an
-// arbitrary offset and are placed after non-virtual bases but before fields.
+// always occur at offset 0. vbptrs can occur at an arbitrary offset and are
+// placed after the lexiographically last non-virtual base. This placement
+// is always before fields but can be in the middle of the non-virtual bases
+// due to the two-pass layout scheme for non-virtual-bases.
// * Virtual bases sometimes require a 'vtordisp' field that is laid out before
// the virtual base and is used in conjunction with virtual overrides during
-// construction and destruction.
-// * vfptrs are allocated in a block of memory equal to the alignment of the
-// fields and non-virtual bases at offset 0 in 32 bit mode and in a pointer
-// sized block of memory in 64 bit mode.
-// * vbptrs are allocated in a block of memory equal to the alignment of the
-// fields and non-virtual bases. This block is at a potentially unaligned
-// offset. If the allocation slot is unaligned and the alignment is less than
-// or equal to the pointer size, additional space is allocated so that the
-// pointer can be aligned properly. This causes very strange effects on the
-// placement of objects after the allocated block. (see the code).
+// construction and destruction. This is always a 4 byte value and is used as
+// an alternative to constructor vtables.
// * vtordisps are allocated in a block of memory with size and alignment equal
// to the alignment of the completed structure (before applying __declspec(
// align())). The vtordisp always occur at the end of the allocation block,
// immediately prior to the virtual base.
-// * The last zero sized non-virtual base is allocated after the placement of
-// vbptr if one exists and can be placed at the end of the struct, potentially
-// aliasing either the first member or another struct allocated after this
-// one.
-// * The last zero size virtual base may be placed at the end of the struct.
-// and can potentially alias a zero sized type in the next struct.
-// * If the last field is a non-zero length bitfield and we have any virtual
-// bases then some extra padding is added before the virtual bases for no
-// obvious reason.
-// * When laying out empty non-virtual bases, an extra byte of padding is added
-// if the non-virtual base before the empty non-virtual base has a vbptr.
-
+// * vfptrs are injected after all bases and fields have been laid out. In
+// order to guarantee proper alignment of all fields, the vfptr injection
+// pushes all bases and fields back by the alignment imposed by those bases
+// and fields. This can potentially add a significant amount of padding.
+// vfptrs are always injected at offset 0.
+// * vbptrs are injected after all bases and fields have been laid out. In
+// order to guarantee proper alignment of all fields, the vfptr injection
+// pushes all bases and fields back by the alignment imposed by those bases
+// and fields. This can potentially add a significant amount of padding.
+// vbptrs are injected immediately after the last non-virtual base as
+// lexiographically ordered in the code. If this site isn't pointer aligned
+// the vbptr is placed at the next properly aligned location. Enough padding
+// is added to guarantee a fit.
+// * The last zero sized non-virtual base can be placed at the end of the
+// struct (potentially aliasing another object), or may alias with the first
+// field, even if they are of the same type.
+// * The last zero size virtual base may be placed at the end of the struct
+// potentially aliasing another object.
+// * The ABI attempts to avoid aliasing of zero sized bases by adding padding
+// between bases or vbases with specific properties. The criteria for
+// additional padding between two bases is that the first base is zero sized
+// or ends with a zero sized subobject and the second base is zero sized or
+// trails with a zero sized base or field (sharing of vfptrs can reorder the
+// layout of the so the leading base is not always the first one declared).
+// This rule does take into account fields that are not records, so padding
+// will occur even if the last field is, e.g. an int. The padding added for
+// bases is 1 byte. The padding added between vbases depends on the alignment
+// of the object but is at least 4 bytes (in both 32 and 64 bit modes).
+// * There is no concept of non-virtual alignment, non-virtual alignment and
+// alignment are always identical.
+// * There is a distinction between alignment and required alignment.
+// __declspec(align) changes the required alignment of a struct. This
+// alignment is _always_ obeyed, even in the presence of #pragma pack. A
+// record inherites required alignment from all of its fields an bases.
+// * __declspec(align) on bitfields has the effect of changing the bitfield's
+// alignment instead of its required alignment. This is the only known way
+// to make the alignment of a struct bigger than 8. Interestingly enough
+// this alignment is also immune to the effects of #pragma pack and can be
+// used to create structures with large alignment under #pragma pack.
+// However, because it does not impact required alignment, such a structure,
+// when used as a field or base, will not be aligned if #pragma pack is
+// still active at the time of use.
+//
+// Known incompatibilities:
+// * all: #pragma pack between fields in a record
+// * 2010 and back: If the last field in a record is a bitfield, every object
+// laid out after the record will have extra padding inserted before it. The
+// extra padding will have size equal to the size of the storage class of the
+// bitfield. 0 sized bitfields don't exhibit this behavior and the extra
+// padding can be avoided by adding a 0 sized bitfield after the non-zero-
+// sized bitfield.
+// * 2012 and back: In 64-bit mode, if the alignment of a record is 16 or
+// greater due to __declspec(align()) then a second layout phase occurs after
+// The locations of the vf and vb pointers are known. This layout phase
+// suffers from the "last field is a bitfield" bug in 2010 and results in
+// _every_ field getting padding put in front of it, potentially including the
+// vfptr, leaving the vfprt at a non-zero location which results in a fault if
+// anything tries to read the vftbl. The second layout phase also treats
+// bitfields as separate entities and gives them each storage rather than
+// packing them. Additionally, because this phase appears to perform a
+// (an unstable) sort on the members before laying them out and because merged
+// bitfields have the same address, the bitfields end up in whatever order
+// the sort left them in, a behavior we could never hope to replicate.
namespace {
struct MicrosoftRecordLayoutBuilder {
+ struct ElementInfo {
+ CharUnits Size;
+ CharUnits Alignment;
+ };
typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
MicrosoftRecordLayoutBuilder(const ASTContext &Context) : Context(Context) {}
private:
@@ -2030,19 +2141,20 @@ private:
LLVM_DELETED_FUNCTION;
void operator=(const MicrosoftRecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
public:
-
void layout(const RecordDecl *RD);
void cxxLayout(const CXXRecordDecl *RD);
/// \brief Initializes size and alignment and honors some flags.
void initializeLayout(const RecordDecl *RD);
/// \brief Initialized C++ layout, compute alignment and virtual alignment and
- /// existance of vfptrs and vbptrs. Alignment is needed before the vfptr is
+ /// existence of vfptrs and vbptrs. Alignment is needed before the vfptr is
/// laid out.
void initializeCXXLayout(const CXXRecordDecl *RD);
- void layoutVFPtr(const CXXRecordDecl *RD);
void layoutNonVirtualBases(const CXXRecordDecl *RD);
- void layoutNonVirtualBase(const CXXRecordDecl *RD);
- void layoutVBPtr(const CXXRecordDecl *RD);
+ void layoutNonVirtualBase(const CXXRecordDecl *BaseDecl,
+ const ASTRecordLayout &BaseLayout,
+ const ASTRecordLayout *&PreviousBaseLayout);
+ void injectVFPtr(const CXXRecordDecl *RD);
+ void injectVBPtr(const CXXRecordDecl *RD);
/// \brief Lays out the fields of the record. Also rounds size up to
/// alignment.
void layoutFields(const RecordDecl *RD);
@@ -2052,22 +2164,14 @@ public:
/// special cases associated with zero-width bit-fields.
void layoutZeroWidthBitField(const FieldDecl *FD);
void layoutVirtualBases(const CXXRecordDecl *RD);
- void layoutVirtualBase(const CXXRecordDecl *RD, bool HasVtordisp);
- /// \brief Flushes the lazy virtual base and conditionally rounds up to
- /// alignment.
- void finalizeCXXLayout(const CXXRecordDecl *RD);
- void honorDeclspecAlign(const RecordDecl *RD);
-
- /// \brief Updates the alignment of the type. This function doesn't take any
- /// properties (such as packedness) into account. getAdjustedFieldInfo()
- /// adjustes for packedness.
- void updateAlignment(CharUnits NewAlignment) {
- Alignment = std::max(Alignment, NewAlignment);
- }
- /// \brief Gets the size and alignment taking attributes into account.
- std::pair<CharUnits, CharUnits> getAdjustedFieldInfo(const FieldDecl *FD);
- /// \brief Places a field at offset 0.
- void placeFieldAtZero() { FieldOffsets.push_back(0); }
+ void finalizeLayout(const RecordDecl *RD);
+ /// \brief Gets the size and alignment of a base taking pragma pack and
+ /// __declspec(align) into account.
+ ElementInfo getAdjustedElementInfo(const ASTRecordLayout &Layout);
+ /// \brief Gets the size and alignment of a field taking pragma pack and
+ /// __declspec(align) into account. It also updates RequiredAlignment as a
+ /// side effect because it is most convenient to do so here.
+ ElementInfo getAdjustedElementInfo(const FieldDecl *FD);
/// \brief Places a field at an offset in CharUnits.
void placeFieldAtOffset(CharUnits FieldOffset) {
FieldOffsets.push_back(Context.toBits(FieldOffset));
@@ -2079,334 +2183,280 @@ public:
/// \brief Compute the set of virtual bases for which vtordisps are required.
llvm::SmallPtrSet<const CXXRecordDecl *, 2>
computeVtorDispSet(const CXXRecordDecl *RD);
-
const ASTContext &Context;
/// \brief The size of the record being laid out.
CharUnits Size;
+ /// \brief The non-virtual size of the record layout.
+ CharUnits NonVirtualSize;
+ /// \brief The data size of the record layout.
+ CharUnits DataSize;
/// \brief The current alignment of the record layout.
CharUnits Alignment;
- /// \brief The collection of field offsets.
- SmallVector<uint64_t, 16> FieldOffsets;
/// \brief The maximum allowed field alignment. This is set by #pragma pack.
CharUnits MaxFieldAlignment;
- /// \brief Alignment does not occur for virtual bases unless something
- /// forces it to by explicitly using __declspec(align())
- bool AlignAfterVBases : 1;
- bool IsUnion : 1;
- /// \brief True if the last field laid out was a bitfield and was not 0
- /// width.
- bool LastFieldIsNonZeroWidthBitfield : 1;
+ /// \brief The alignment that this record must obey. This is imposed by
+ /// __declspec(align()) on the record itself or one of its fields or bases.
+ CharUnits RequiredAlignment;
/// \brief The size of the allocation of the currently active bitfield.
/// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield
/// is true.
CharUnits CurrentBitfieldSize;
- /// \brief The number of remaining bits in our last bitfield allocation.
- /// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield is
- /// true.
- unsigned RemainingBitsInField;
-
- /// \brief The data alignment of the record layout.
- CharUnits DataSize;
- /// \brief The alignment of the non-virtual portion of the record layout
- /// without the impact of the virtual pointers.
- /// Only used for C++ layouts.
- CharUnits BasesAndFieldsAlignment;
- /// \brief The alignment of the non-virtual portion of the record layout
- /// Only used for C++ layouts.
- CharUnits NonVirtualAlignment;
- /// \brief The additional alignment imposed by the virtual bases.
- CharUnits VirtualAlignment;
+ /// \brief Offset to the virtual base table pointer (if one exists).
+ CharUnits VBPtrOffset;
+ /// \brief The size and alignment info of a pointer.
+ ElementInfo PointerInfo;
/// \brief The primary base class (if one exists).
const CXXRecordDecl *PrimaryBase;
/// \brief The class we share our vb-pointer with.
const CXXRecordDecl *SharedVBPtrBase;
- /// \brief True if the class has a vftable pointer that can be extended
- /// by this class or classes derived from it. Such a vfptr will always occur
- /// at offset 0.
- bool HasExtendableVFPtr : 1;
- /// \brief True if the class has a (not necessarily its own) vbtable pointer.
- bool HasVBPtr : 1;
- /// \brief Offset to the virtual base table pointer (if one exists).
- CharUnits VBPtrOffset;
+ /// \brief The collection of field offsets.
+ SmallVector<uint64_t, 16> FieldOffsets;
/// \brief Base classes and their offsets in the record.
BaseOffsetsMapTy Bases;
/// \brief virtual base classes and their offsets in the record.
ASTRecordLayout::VBaseOffsetsMapTy VBases;
- /// \brief The size of a pointer.
- CharUnits PointerSize;
- /// \brief The alignment of a pointer.
- CharUnits PointerAlignment;
- /// \brief Holds an empty base we haven't yet laid out.
- const CXXRecordDecl *LazyEmptyBase;
- /// \brief Lets us know if the last base we laid out was empty. Only used
- /// when adjusting the placement of a last zero-sized base in 64 bit mode.
- bool LastBaseWasEmpty;
- /// \brief Lets us know if we're in 64-bit mode
- bool Is64BitMode;
- /// \brief True if the last non-virtual base has a vbptr.
- bool LastNonVirtualBaseHasVBPtr;
+ /// \brief The number of remaining bits in our last bitfield allocation.
+ /// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield is
+ /// true.
+ unsigned RemainingBitsInField;
+ bool IsUnion : 1;
+ /// \brief True if the last field laid out was a bitfield and was not 0
+ /// width.
+ bool LastFieldIsNonZeroWidthBitfield : 1;
+ /// \brief True if the class has its own vftable pointer.
+ bool HasOwnVFPtr : 1;
+ /// \brief True if the class has a vbtable pointer.
+ bool HasVBPtr : 1;
+ /// \brief True if the last sub-object within the type is zero sized or the
+ /// object itself is zero sized. This *does not* count members that are not
+ /// records. Only used for MS-ABI.
+ bool EndsWithZeroSizedObject : 1;
+ /// \brief True if this class is zero sized or first base is zero sized or
+ /// has this property. Only used for MS-ABI.
+ bool LeadsWithZeroSizedBase : 1;
};
} // namespace
-std::pair<CharUnits, CharUnits>
-MicrosoftRecordLayoutBuilder::getAdjustedFieldInfo(const FieldDecl *FD) {
- std::pair<CharUnits, CharUnits> FieldInfo =
- Context.getTypeInfoInChars(FD->getType());
+MicrosoftRecordLayoutBuilder::ElementInfo
+MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
+ const ASTRecordLayout &Layout) {
+ ElementInfo Info;
+ Info.Alignment = Layout.getAlignment();
+ // Respect pragma pack.
+ if (!MaxFieldAlignment.isZero())
+ Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment);
+ // Track zero-sized subobjects here where it's already available.
+ EndsWithZeroSizedObject = Layout.hasZeroSizedSubObject();
+ // Respect required alignment, this is necessary because we may have adjusted
+ // the alignment in the case of pragam pack. Note that the required alignment
+ // doesn't actually apply to the struct alignment at this point.
+ Alignment = std::max(Alignment, Info.Alignment);
+ RequiredAlignment = std::max(RequiredAlignment, Layout.getRequiredAlignment());
+ Info.Alignment = std::max(Info.Alignment, Layout.getRequiredAlignment());
+ Info.Size = Layout.getNonVirtualSize();
+ return Info;
+}
- // If we're not on win32 and using ms_struct the field alignment will be wrong
- // for 64 bit types, so we fix that here.
- if (FD->getASTContext().getTargetInfo().getTriple().getOS() !=
- llvm::Triple::Win32) {
- QualType T = Context.getBaseElementType(FD->getType());
- if (const BuiltinType *BTy = T->getAs<BuiltinType>()) {
- CharUnits TypeSize = Context.getTypeSizeInChars(BTy);
- if (TypeSize > FieldInfo.second)
- FieldInfo.second = TypeSize;
+MicrosoftRecordLayoutBuilder::ElementInfo
+MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
+ const FieldDecl *FD) {
+ ElementInfo Info;
+ std::tie(Info.Size, Info.Alignment) =
+ Context.getTypeInfoInChars(FD->getType());
+ // Respect align attributes.
+ CharUnits FieldRequiredAlignment =
+ Context.toCharUnitsFromBits(FD->getMaxAlignment());
+ // Respect attributes applied to subobjects of the field.
+ if (FD->isBitField())
+ // For some reason __declspec align impacts alignment rather than required
+ // alignment when it is applied to bitfields.
+ Info.Alignment = std::max(Info.Alignment, FieldRequiredAlignment);
+ else {
+ if (auto RT =
+ FD->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
+ auto const &Layout = Context.getASTRecordLayout(RT->getDecl());
+ EndsWithZeroSizedObject = Layout.hasZeroSizedSubObject();
+ FieldRequiredAlignment = std::max(FieldRequiredAlignment,
+ Layout.getRequiredAlignment());
}
+ // Capture required alignment as a side-effect.
+ RequiredAlignment = std::max(RequiredAlignment, FieldRequiredAlignment);
}
-
- // Respect packed attribute.
+ // Respect pragma pack, attribute pack and declspec align
+ if (!MaxFieldAlignment.isZero())
+ Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment);
if (FD->hasAttr<PackedAttr>())
- FieldInfo.second = CharUnits::One();
- // Respect pack pragma.
- else if (!MaxFieldAlignment.isZero())
- FieldInfo.second = std::min(FieldInfo.second, MaxFieldAlignment);
- // Respect alignment attributes.
- if (unsigned fieldAlign = FD->getMaxAlignment()) {
- CharUnits FieldAlign = Context.toCharUnitsFromBits(fieldAlign);
- AlignAfterVBases = true;
- FieldInfo.second = std::max(FieldInfo.second, FieldAlign);
- }
- return FieldInfo;
-}
-
-void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
- IsUnion = RD->isUnion();
- Is64BitMode = Context.getTargetInfo().getPointerWidth(0) == 64;
-
- Size = CharUnits::Zero();
- Alignment = CharUnits::One();
- AlignAfterVBases = false;
-
- // Compute the maximum field alignment.
- MaxFieldAlignment = CharUnits::Zero();
- // Honor the default struct packing maximum alignment flag.
- if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct)
- MaxFieldAlignment = CharUnits::fromQuantity(DefaultMaxFieldAlignment);
- // Honor the packing attribute.
- if (const MaxFieldAlignmentAttr *MFAA = RD->getAttr<MaxFieldAlignmentAttr>())
- MaxFieldAlignment = Context.toCharUnitsFromBits(MFAA->getAlignment());
- // Packed attribute forces max field alignment to be 1.
- if (RD->hasAttr<PackedAttr>())
- MaxFieldAlignment = CharUnits::One();
+ Info.Alignment = CharUnits::One();
+ Info.Alignment = std::max(Info.Alignment, FieldRequiredAlignment);
+ return Info;
}
void MicrosoftRecordLayoutBuilder::layout(const RecordDecl *RD) {
initializeLayout(RD);
layoutFields(RD);
- honorDeclspecAlign(RD);
+ DataSize = Size = Size.RoundUpToAlignment(Alignment);
+ RequiredAlignment = std::max(
+ RequiredAlignment, Context.toCharUnitsFromBits(RD->getMaxAlignment()));
+ finalizeLayout(RD);
}
void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) {
initializeLayout(RD);
initializeCXXLayout(RD);
- layoutVFPtr(RD);
layoutNonVirtualBases(RD);
- layoutVBPtr(RD);
layoutFields(RD);
- DataSize = Size;
- NonVirtualAlignment = Alignment;
+ injectVBPtr(RD);
+ injectVFPtr(RD);
+ if (HasOwnVFPtr || (HasVBPtr && !SharedVBPtrBase))
+ Alignment = std::max(Alignment, PointerInfo.Alignment);
+ auto RoundingAlignment = Alignment;
+ if (!MaxFieldAlignment.isZero())
+ RoundingAlignment = std::min(RoundingAlignment, MaxFieldAlignment);
+ NonVirtualSize = Size = Size.RoundUpToAlignment(RoundingAlignment);
+ RequiredAlignment = std::max(
+ RequiredAlignment, Context.toCharUnitsFromBits(RD->getMaxAlignment()));
layoutVirtualBases(RD);
- finalizeCXXLayout(RD);
- honorDeclspecAlign(RD);
+ finalizeLayout(RD);
+}
+
+void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
+ IsUnion = RD->isUnion();
+ Size = CharUnits::Zero();
+ Alignment = CharUnits::One();
+ // In 64-bit mode we always perform an alignment step after laying out vbases.
+ // In 32-bit mode we do not. The check to see if we need to perform alignment
+ // checks the RequiredAlignment field and performs alignment if it isn't 0.
+ RequiredAlignment = Context.getTargetInfo().getPointerWidth(0) == 64 ?
+ CharUnits::One() : CharUnits::Zero();
+ // Compute the maximum field alignment.
+ MaxFieldAlignment = CharUnits::Zero();
+ // Honor the default struct packing maximum alignment flag.
+ if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct)
+ MaxFieldAlignment = CharUnits::fromQuantity(DefaultMaxFieldAlignment);
+ // Honor the packing attribute. The MS-ABI ignores pragma pack if its larger
+ // than the pointer size.
+ if (const MaxFieldAlignmentAttr *MFAA = RD->getAttr<MaxFieldAlignmentAttr>()){
+ unsigned PackedAlignment = MFAA->getAlignment();
+ if (PackedAlignment <= Context.getTargetInfo().getPointerWidth(0))
+ MaxFieldAlignment = Context.toCharUnitsFromBits(PackedAlignment);
+ }
+ // Packed attribute forces max field alignment to be 1.
+ if (RD->hasAttr<PackedAttr>())
+ MaxFieldAlignment = CharUnits::One();
}
void
MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) {
- // Calculate pointer size and alignment.
- PointerSize =
+ EndsWithZeroSizedObject = false;
+ LeadsWithZeroSizedBase = false;
+ HasOwnVFPtr = false;
+ HasVBPtr = false;
+ PrimaryBase = nullptr;
+ SharedVBPtrBase = nullptr;
+ // Calculate pointer size and alignment. These are used for vfptr and vbprt
+ // injection.
+ PointerInfo.Size =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
- PointerAlignment = PointerSize;
+ PointerInfo.Alignment = PointerInfo.Size;
+ // Respect pragma pack.
if (!MaxFieldAlignment.isZero())
- PointerAlignment = std::min(PointerAlignment, MaxFieldAlignment);
-
- // Initialize information about the bases.
- HasVBPtr = false;
- HasExtendableVFPtr = false;
- SharedVBPtrBase = 0;
- PrimaryBase = 0;
- VirtualAlignment = CharUnits::One();
- AlignAfterVBases = Is64BitMode;
+ PointerInfo.Alignment = std::min(PointerInfo.Alignment, MaxFieldAlignment);
+}
- // If the record has a dynamic base class, attempt to choose a primary base
- // class. It is the first (in direct base class order) non-virtual dynamic
- // base class, if one exists.
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end();
- i != e; ++i) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
- // Handle forced alignment.
- if (Layout.getAlignAfterVBases())
- AlignAfterVBases = true;
- // Handle virtual bases.
- if (i->isVirtual()) {
- VirtualAlignment = std::max(VirtualAlignment, Layout.getAlignment());
+void
+MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
+ // The MS-ABI lays out all bases that contain leading vfptrs before it lays
+ // out any bases that do not contain vfptrs. We implement this as two passes
+ // over the bases. This approach guarantees that the primary base is laid out
+ // first. We use these passes to calculate some additional aggregated
+ // information about the bases, such as reqruied alignment and the presence of
+ // zero sized members.
+ const ASTRecordLayout *PreviousBaseLayout = nullptr;
+ // Iterate through the bases and lay out the non-virtual ones.
+ for (const CXXBaseSpecifier &Base : RD->bases()) {
+ const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
+ const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(BaseDecl);
+ // Mark and skip virtual bases.
+ if (Base.isVirtual()) {
HasVBPtr = true;
continue;
}
- // We located a primary base class!
- if (!PrimaryBase && Layout.hasExtendableVFPtr()) {
- PrimaryBase = BaseDecl;
- HasExtendableVFPtr = true;
- }
- // We located a base to share a VBPtr with!
- if (!SharedVBPtrBase && Layout.hasVBPtr()) {
+ // Check fo a base to share a VBPtr with.
+ if (!SharedVBPtrBase && BaseLayout.hasVBPtr()) {
SharedVBPtrBase = BaseDecl;
HasVBPtr = true;
}
- updateAlignment(Layout.getAlignment());
+ // Only lay out bases with extendable VFPtrs on the first pass.
+ if (!BaseLayout.hasExtendableVFPtr())
+ continue;
+ // If we don't have a primary base, this one qualifies.
+ if (!PrimaryBase) {
+ PrimaryBase = BaseDecl;
+ LeadsWithZeroSizedBase = BaseLayout.leadsWithZeroSizedBase();
+ }
+ // Lay out the base.
+ layoutNonVirtualBase(BaseDecl, BaseLayout, PreviousBaseLayout);
}
-
- // Use LayoutFields to compute the alignment of the fields. The layout
- // is discarded. This is the simplest way to get all of the bit-field
- // behavior correct and is not actually very expensive.
- layoutFields(RD);
- Size = CharUnits::Zero();
- BasesAndFieldsAlignment = Alignment;
- FieldOffsets.clear();
-}
-
-void MicrosoftRecordLayoutBuilder::layoutVFPtr(const CXXRecordDecl *RD) {
- // If we have a primary base then our VFPtr was already laid out
- if (PrimaryBase)
- return;
-
- // Look at all of our methods to determine if we need a VFPtr. We need a
- // vfptr if we define a new virtual function.
- if (!HasExtendableVFPtr && RD->isDynamicClass())
+ // Figure out if we need a fresh VFPtr for this class.
+ if (!PrimaryBase && RD->isDynamicClass())
for (CXXRecordDecl::method_iterator i = RD->method_begin(),
e = RD->method_end();
- !HasExtendableVFPtr && i != e; ++i)
- HasExtendableVFPtr = i->isVirtual() && i->size_overridden_methods() == 0;
- if (!HasExtendableVFPtr)
- return;
-
- // MSVC 32 (but not 64) potentially over-aligns the vf-table pointer by giving
- // it the max alignment of all the non-virtual data in the class. The
- // resulting layout is essentially { vftbl, { nvdata } }. This is completely
- // unnecessary, but we're not here to pass judgment.
- updateAlignment(PointerAlignment);
- if (Is64BitMode)
- Size = Size.RoundUpToAlignment(PointerAlignment) + PointerSize;
- else
- Size = Size.RoundUpToAlignment(PointerAlignment) + Alignment;
-}
-
-void
-MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
- LazyEmptyBase = 0;
- LastBaseWasEmpty = false;
- LastNonVirtualBaseHasVBPtr = false;
-
- // Lay out the primary base first.
- if (PrimaryBase)
- layoutNonVirtualBase(PrimaryBase);
-
+ !HasOwnVFPtr && i != e; ++i)
+ HasOwnVFPtr = i->isVirtual() && i->size_overridden_methods() == 0;
+ // If we don't have a primary base then we have a leading object that could
+ // itself lead with a zero-sized object, something we track.
+ bool CheckLeadingLayout = !PrimaryBase;
// Iterate through the bases and lay out the non-virtual ones.
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end();
- i != e; ++i) {
- if (i->isVirtual())
+ for (const CXXBaseSpecifier &Base : RD->bases()) {
+ if (Base.isVirtual())
+ continue;
+ const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
+ const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(BaseDecl);
+ // Only lay out bases without extendable VFPtrs on the second pass.
+ if (BaseLayout.hasExtendableVFPtr()) {
+ VBPtrOffset = Bases[BaseDecl] + BaseLayout.getNonVirtualSize();
continue;
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(i->getType()->castAs<RecordType>()->getDecl());
- if (BaseDecl != PrimaryBase)
- layoutNonVirtualBase(BaseDecl);
- }
-}
-
-void
-MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(const CXXRecordDecl *RD) {
- const ASTRecordLayout *Layout = RD ? &Context.getASTRecordLayout(RD) : 0;
-
- // If we have a lazy empty base we haven't laid out yet, do that now.
- if (LazyEmptyBase) {
- const ASTRecordLayout &LazyLayout =
- Context.getASTRecordLayout(LazyEmptyBase);
- Size = Size.RoundUpToAlignment(LazyLayout.getAlignment());
- // If the last non-virtual base has a vbptr we add a byte of padding for no
- // obvious reason.
- if (LastNonVirtualBaseHasVBPtr)
- Size++;
- Bases.insert(std::make_pair(LazyEmptyBase, Size));
- // Empty bases only consume space when followed by another empty base.
- if (RD && Layout->getNonVirtualSize().isZero()) {
- LastBaseWasEmpty = true;
- Size++;
}
- LazyEmptyBase = 0;
- LastNonVirtualBaseHasVBPtr = false;
- }
-
- // RD is null when flushing the final lazy base.
- if (!RD)
- return;
-
- if (Layout->getNonVirtualSize().isZero()) {
- LazyEmptyBase = RD;
- return;
+ // If this is the first layout, check to see if it leads with a zero sized
+ // object. If it does, so do we.
+ if (CheckLeadingLayout) {
+ CheckLeadingLayout = false;
+ LeadsWithZeroSizedBase = BaseLayout.leadsWithZeroSizedBase();
+ }
+ // Lay out the base.
+ layoutNonVirtualBase(BaseDecl, BaseLayout, PreviousBaseLayout);
+ VBPtrOffset = Bases[BaseDecl] + BaseLayout.getNonVirtualSize();
}
-
- // Insert the base here.
- CharUnits BaseOffset = Size.RoundUpToAlignment(Layout->getAlignment());
- Bases.insert(std::make_pair(RD, BaseOffset));
- Size = BaseOffset + Layout->getDataSize();
- // Note: we don't update alignment here because it was accounted
- // for during initalization.
- LastBaseWasEmpty = false;
- LastNonVirtualBaseHasVBPtr = Layout->hasVBPtr();
-}
-
-void MicrosoftRecordLayoutBuilder::layoutVBPtr(const CXXRecordDecl *RD) {
+ // Set our VBPtroffset if we know it at this point.
if (!HasVBPtr)
VBPtrOffset = CharUnits::fromQuantity(-1);
else if (SharedVBPtrBase) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(SharedVBPtrBase);
VBPtrOffset = Bases[SharedVBPtrBase] + Layout.getVBPtrOffset();
- } else {
- VBPtrOffset = Size.RoundUpToAlignment(PointerAlignment);
- CharUnits OldSize = Size;
- Size = VBPtrOffset + PointerSize;
- if (BasesAndFieldsAlignment <= PointerAlignment) {
- // Handle strange padding rules for the lazily placed base. I have no
- // explanation for why the last virtual base is padded in such an odd way.
- // Two things to note about this padding are that the rules are different
- // if the alignment of the bases+fields is <= to the alignemnt of a
- // pointer and that the rule in 64-bit mode behaves differently depending
- // on if the second to last base was also zero sized.
- Size += OldSize % BasesAndFieldsAlignment.getQuantity();
- } else {
- if (Is64BitMode)
- Size += LastBaseWasEmpty ? CharUnits::One() : CharUnits::Zero();
- else
- Size = OldSize + BasesAndFieldsAlignment;
- }
- updateAlignment(PointerAlignment);
}
+}
- // Flush the lazy empty base.
- layoutNonVirtualBase(0);
+void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(
+ const CXXRecordDecl *BaseDecl,
+ const ASTRecordLayout &BaseLayout,
+ const ASTRecordLayout *&PreviousBaseLayout) {
+ // Insert padding between two bases if the left first one is zero sized or
+ // contains a zero sized subobject and the right is zero sized or one leads
+ // with a zero sized base.
+ if (PreviousBaseLayout && PreviousBaseLayout->hasZeroSizedSubObject() &&
+ BaseLayout.leadsWithZeroSizedBase())
+ Size++;
+ ElementInfo Info = getAdjustedElementInfo(BaseLayout);
+ CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
+ Bases.insert(std::make_pair(BaseDecl, BaseOffset));
+ Size = BaseOffset + BaseLayout.getNonVirtualSize();
+ PreviousBaseLayout = &BaseLayout;
}
void MicrosoftRecordLayoutBuilder::layoutFields(const RecordDecl *RD) {
LastFieldIsNonZeroWidthBitfield = false;
- for (RecordDecl::field_iterator Field = RD->field_begin(),
- FieldEnd = RD->field_end();
- Field != FieldEnd; ++Field)
- layoutField(*Field);
- Size = Size.RoundUpToAlignment(Alignment);
+ for (const FieldDecl *Field : RD->fields())
+ layoutField(Field);
}
void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) {
@@ -2415,20 +2465,15 @@ void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) {
return;
}
LastFieldIsNonZeroWidthBitfield = false;
-
- std::pair<CharUnits, CharUnits> FieldInfo = getAdjustedFieldInfo(FD);
- CharUnits FieldSize = FieldInfo.first;
- CharUnits FieldAlign = FieldInfo.second;
-
- updateAlignment(FieldAlign);
+ ElementInfo Info = getAdjustedElementInfo(FD);
+ Alignment = std::max(Alignment, Info.Alignment);
if (IsUnion) {
- placeFieldAtZero();
- Size = std::max(Size, FieldSize);
+ placeFieldAtOffset(CharUnits::Zero());
+ Size = std::max(Size, Info.Size);
} else {
- // Round up the current record size to the field's alignment boundary.
- CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign);
+ CharUnits FieldOffset = Size.RoundUpToAlignment(Info.Alignment);
placeFieldAtOffset(FieldOffset);
- Size = FieldOffset + FieldSize;
+ Size = FieldOffset + Info.Size;
}
}
@@ -2438,39 +2483,33 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {
layoutZeroWidthBitField(FD);
return;
}
-
- std::pair<CharUnits, CharUnits> FieldInfo = getAdjustedFieldInfo(FD);
- CharUnits FieldSize = FieldInfo.first;
- CharUnits FieldAlign = FieldInfo.second;
-
+ ElementInfo Info = getAdjustedElementInfo(FD);
// Clamp the bitfield to a containable size for the sake of being able
// to lay them out. Sema will throw an error.
- if (Width > Context.toBits(FieldSize))
- Width = Context.toBits(FieldSize);
-
+ if (Width > Context.toBits(Info.Size))
+ Width = Context.toBits(Info.Size);
// Check to see if this bitfield fits into an existing allocation. Note:
// MSVC refuses to pack bitfields of formal types with different sizes
// into the same allocation.
if (!IsUnion && LastFieldIsNonZeroWidthBitfield &&
- CurrentBitfieldSize == FieldSize && Width <= RemainingBitsInField) {
+ CurrentBitfieldSize == Info.Size && Width <= RemainingBitsInField) {
placeFieldAtBitOffset(Context.toBits(Size) - RemainingBitsInField);
RemainingBitsInField -= Width;
return;
}
-
LastFieldIsNonZeroWidthBitfield = true;
- CurrentBitfieldSize = FieldSize;
+ CurrentBitfieldSize = Info.Size;
if (IsUnion) {
- placeFieldAtZero();
- Size = std::max(Size, FieldSize);
+ placeFieldAtOffset(CharUnits::Zero());
+ Size = std::max(Size, Info.Size);
// TODO: Add a Sema warning that MS ignores bitfield alignment in unions.
} else {
// Allocate a new block of memory and place the bitfield in it.
- CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign);
+ CharUnits FieldOffset = Size.RoundUpToAlignment(Info.Alignment);
placeFieldAtOffset(FieldOffset);
- Size = FieldOffset + FieldSize;
- updateAlignment(FieldAlign);
- RemainingBitsInField = Context.toBits(FieldSize) - Width;
+ Size = FieldOffset + Info.Size;
+ Alignment = std::max(Alignment, Info.Alignment);
+ RemainingBitsInField = Context.toBits(Info.Size) - Width;
}
}
@@ -2478,201 +2517,220 @@ void
MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) {
// Zero-width bitfields are ignored unless they follow a non-zero-width
// bitfield.
- std::pair<CharUnits, CharUnits> FieldInfo = getAdjustedFieldInfo(FD);
- CharUnits FieldSize = FieldInfo.first;
- CharUnits FieldAlign = FieldInfo.second;
-
if (!LastFieldIsNonZeroWidthBitfield) {
placeFieldAtOffset(IsUnion ? CharUnits::Zero() : Size);
// TODO: Add a Sema warning that MS ignores alignment for zero
- // sized bitfields that occur after zero-size bitfields or non bitfields.
+ // sized bitfields that occur after zero-size bitfields or non-bitfields.
return;
}
-
LastFieldIsNonZeroWidthBitfield = false;
+ ElementInfo Info = getAdjustedElementInfo(FD);
if (IsUnion) {
- placeFieldAtZero();
- Size = std::max(Size, FieldSize);
+ placeFieldAtOffset(CharUnits::Zero());
+ Size = std::max(Size, Info.Size);
+ // TODO: Add a Sema warning that MS ignores bitfield alignment in unions.
} else {
// Round up the current record size to the field's alignment boundary.
- CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign);
+ CharUnits FieldOffset = Size.RoundUpToAlignment(Info.Alignment);
placeFieldAtOffset(FieldOffset);
Size = FieldOffset;
- updateAlignment(FieldAlign);
+ Alignment = std::max(Alignment, Info.Alignment);
}
}
+void MicrosoftRecordLayoutBuilder::injectVBPtr(const CXXRecordDecl *RD) {
+ if (!HasVBPtr || SharedVBPtrBase)
+ return;
+ // Inject the VBPointer at the injection site.
+ CharUnits InjectionSite = VBPtrOffset;
+ // But before we do, make sure it's properly aligned.
+ VBPtrOffset = VBPtrOffset.RoundUpToAlignment(PointerInfo.Alignment);
+ // Determine where the first field should be laid out after the vbptr.
+ CharUnits FieldStart = VBPtrOffset + PointerInfo.Size;
+ // Make sure that the amount we push the fields back by is a multiple of the
+ // alignment.
+ CharUnits Offset = (FieldStart - InjectionSite).RoundUpToAlignment(
+ std::max(RequiredAlignment, Alignment));
+ // Increase the size of the object and push back all fields by the offset
+ // amount.
+ Size += Offset;
+ for (uint64_t &FieldOffset : FieldOffsets)
+ FieldOffset += Context.toBits(Offset);
+ for (BaseOffsetsMapTy::value_type &Base : Bases)
+ if (Base.second >= InjectionSite)
+ Base.second += Offset;
+}
+
+void MicrosoftRecordLayoutBuilder::injectVFPtr(const CXXRecordDecl *RD) {
+ if (!HasOwnVFPtr)
+ return;
+ // Make sure that the amount we push the struct back by is a multiple of the
+ // alignment.
+ CharUnits Offset = PointerInfo.Size.RoundUpToAlignment(
+ std::max(RequiredAlignment, Alignment));
+ // Increase the size of the object and push back all fields, the vbptr and all
+ // bases by the offset amount.
+ Size += Offset;
+ for (uint64_t &FieldOffset : FieldOffsets)
+ FieldOffset += Context.toBits(Offset);
+ if (HasVBPtr)
+ VBPtrOffset += Offset;
+ for (BaseOffsetsMapTy::value_type &Base : Bases)
+ Base.second += Offset;
+}
+
void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
if (!HasVBPtr)
return;
-
- updateAlignment(VirtualAlignment);
-
- // Zero-sized v-bases obey the alignment attribute so apply it here. The
- // alignment attribute is normally accounted for in FinalizeLayout.
- if (unsigned MaxAlign = RD->getMaxAlignment())
- updateAlignment(Context.toCharUnitsFromBits(MaxAlign));
-
- llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordisp =
+ // Vtordisps are always 4 bytes (even in 64-bit mode)
+ CharUnits VtorDispSize = CharUnits::fromQuantity(4);
+ CharUnits VtorDispAlignment = VtorDispSize;
+ // vtordisps respect pragma pack.
+ if (!MaxFieldAlignment.isZero())
+ VtorDispAlignment = std::min(VtorDispAlignment, MaxFieldAlignment);
+ // The alignment of the vtordisp is at least the required alignment of the
+ // entire record. This requirement may be present to support vtordisp
+ // injection.
+ for (const CXXBaseSpecifier &VBase : RD->vbases()) {
+ const CXXRecordDecl *BaseDecl = VBase.getType()->getAsCXXRecordDecl();
+ const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(BaseDecl);
+ RequiredAlignment =
+ std::max(RequiredAlignment, BaseLayout.getRequiredAlignment());
+ }
+ VtorDispAlignment = std::max(VtorDispAlignment, RequiredAlignment);
+ // Compute the vtordisp set.
+ llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordispSet =
computeVtorDispSet(RD);
-
- // If the last field we laid out was a non-zero length bitfield then add some
- // extra padding for no obvious reason.
- if (LastFieldIsNonZeroWidthBitfield)
- Size += CurrentBitfieldSize;
-
// Iterate through the virtual bases and lay them out.
- for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(),
- e = RD->vbases_end();
- i != e; ++i) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(i->getType()->castAs<RecordType>()->getDecl());
- layoutVirtualBase(BaseDecl, HasVtordisp.count(BaseDecl));
- }
-}
-
-void MicrosoftRecordLayoutBuilder::layoutVirtualBase(const CXXRecordDecl *RD,
- bool HasVtordisp) {
- if (LazyEmptyBase) {
- const ASTRecordLayout &LazyLayout =
- Context.getASTRecordLayout(LazyEmptyBase);
- Size = Size.RoundUpToAlignment(LazyLayout.getAlignment());
- VBases.insert(
- std::make_pair(LazyEmptyBase, ASTRecordLayout::VBaseInfo(Size, false)));
- // Empty bases only consume space when followed by another empty base.
- // The space consumed is in an Alignment sized/aligned block and the v-base
- // is placed at its alignment offset into the chunk, unless its alignment
- // is less than 4 bytes, at which it is placed at 4 byte offset in the
- // chunk. We have no idea why.
- if (RD && Context.getASTRecordLayout(RD).getNonVirtualSize().isZero())
- Size = Size.RoundUpToAlignment(Alignment) + CharUnits::fromQuantity(4);
- LazyEmptyBase = 0;
- }
-
- // RD is null when flushing the final lazy virtual base.
- if (!RD)
- return;
-
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- if (Layout.getNonVirtualSize().isZero() && !HasVtordisp) {
- LazyEmptyBase = RD;
- return;
+ const ASTRecordLayout *PreviousBaseLayout = nullptr;
+ for (const CXXBaseSpecifier &VBase : RD->vbases()) {
+ const CXXRecordDecl *BaseDecl = VBase.getType()->getAsCXXRecordDecl();
+ const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(BaseDecl);
+ bool HasVtordisp = HasVtordispSet.count(BaseDecl);
+ // Insert padding between two bases if the left first one is zero sized or
+ // contains a zero sized subobject and the right is zero sized or one leads
+ // with a zero sized base. The padding between virtual bases is 4
+ // bytes (in both 32 and 64 bits modes) and always involves rounding up to
+ // the required alignment, we don't know why.
+ if ((PreviousBaseLayout && PreviousBaseLayout->hasZeroSizedSubObject() &&
+ BaseLayout.leadsWithZeroSizedBase()) || HasVtordisp) {
+ Size = Size.RoundUpToAlignment(VtorDispAlignment) + VtorDispSize;
+ Alignment = std::max(VtorDispAlignment, Alignment);
+ }
+ // Insert the virtual base.
+ ElementInfo Info = getAdjustedElementInfo(BaseLayout);
+ CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
+ VBases.insert(std::make_pair(BaseDecl,
+ ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp)));
+ Size = BaseOffset + BaseLayout.getNonVirtualSize();
+ PreviousBaseLayout = &BaseLayout;
}
-
- CharUnits BaseNVSize = Layout.getNonVirtualSize();
- CharUnits BaseAlign = Layout.getAlignment();
-
- // vtordisps are always 4 bytes (even in 64-bit mode)
- if (HasVtordisp)
- Size = Size.RoundUpToAlignment(Alignment) + CharUnits::fromQuantity(4);
- Size = Size.RoundUpToAlignment(BaseAlign);
-
- // Insert the base here.
- CharUnits BaseOffset = Size.RoundUpToAlignment(BaseAlign);
- VBases.insert(
- std::make_pair(RD, ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp)));
- Size = BaseOffset + BaseNVSize;
- // Note: we don't update alignment here because it was accounted for in
- // InitializeLayout.
}
-void MicrosoftRecordLayoutBuilder::finalizeCXXLayout(const CXXRecordDecl *RD) {
- // Flush the lazy virtual base.
- layoutVirtualBase(0, false);
-
- if (RD->vbases_begin() == RD->vbases_end() || AlignAfterVBases)
- Size = Size.RoundUpToAlignment(Alignment);
-
- if (Size.isZero())
+void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) {
+ // Respect required alignment. Note that in 32-bit mode Required alignment
+ // may be 0 nad cause size not to be updated.
+ DataSize = Size;
+ if (!RequiredAlignment.isZero()) {
+ Alignment = std::max(Alignment, RequiredAlignment);
+ auto RoundingAlignment = Alignment;
+ if (!MaxFieldAlignment.isZero())
+ RoundingAlignment = std::min(RoundingAlignment, MaxFieldAlignment);
+ RoundingAlignment = std::max(RoundingAlignment, RequiredAlignment);
+ Size = Size.RoundUpToAlignment(RoundingAlignment);
+ }
+ // Zero-sized structures have size equal to their alignment.
+ if (Size.isZero()) {
+ EndsWithZeroSizedObject = true;
+ LeadsWithZeroSizedBase = true;
Size = Alignment;
-}
-
-void MicrosoftRecordLayoutBuilder::honorDeclspecAlign(const RecordDecl *RD) {
- if (unsigned MaxAlign = RD->getMaxAlignment()) {
- AlignAfterVBases = true;
- updateAlignment(Context.toCharUnitsFromBits(MaxAlign));
- Size = Size.RoundUpToAlignment(Alignment);
}
}
+// Recursively walks the non-virtual bases of a class and determines if any of
+// them are in the bases with overridden methods set.
static bool
-RequiresVtordisp(const llvm::SmallPtrSet<const CXXRecordDecl *, 2> &HasVtordisp,
+RequiresVtordisp(const llvm::SmallPtrSetImpl<const CXXRecordDecl *> &
+ BasesWithOverriddenMethods,
const CXXRecordDecl *RD) {
- if (HasVtordisp.count(RD))
+ if (BasesWithOverriddenMethods.count(RD))
return true;
// If any of a virtual bases non-virtual bases (recursively) requires a
// vtordisp than so does this virtual base.
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end();
- i != e; ++i)
- if (!i->isVirtual() &&
- RequiresVtordisp(
- HasVtordisp,
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl())))
+ for (const CXXBaseSpecifier &Base : RD->bases())
+ if (!Base.isVirtual() &&
+ RequiresVtordisp(BasesWithOverriddenMethods,
+ Base.getType()->getAsCXXRecordDecl()))
return true;
return false;
}
llvm::SmallPtrSet<const CXXRecordDecl *, 2>
MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) {
- llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordisp;
+ llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordispSet;
+
+ // /vd2 or #pragma vtordisp(2): Always use vtordisps for virtual bases with
+ // vftables.
+ if (RD->getMSVtorDispMode() == MSVtorDispAttr::ForVFTable) {
+ for (const CXXBaseSpecifier &Base : RD->vbases()) {
+ const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
+ if (Layout.hasExtendableVFPtr())
+ HasVtordispSet.insert(BaseDecl);
+ }
+ return HasVtordispSet;
+ }
// If any of our bases need a vtordisp for this type, so do we. Check our
// direct bases for vtordisp requirements.
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end();
- i != e; ++i) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ for (const CXXBaseSpecifier &Base : RD->bases()) {
+ const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
- for (ASTRecordLayout::VBaseOffsetsMapTy::const_iterator
- bi = Layout.getVBaseOffsetsMap().begin(),
- be = Layout.getVBaseOffsetsMap().end();
- bi != be; ++bi)
- if (bi->second.hasVtorDisp())
- HasVtordisp.insert(bi->first);
- }
-
- // If we define a constructor or destructor and override a function that is
- // defined in a virtual base's vtable, that virtual bases need a vtordisp.
- // Here we collect a list of classes with vtables for which our virtual bases
- // actually live. The virtual bases with this property will require
- // vtordisps. In addition, virtual bases that contain non-virtual bases that
- // define functions we override also require vtordisps, this case is checked
- // explicitly below.
- if (RD->hasUserDeclaredConstructor() || RD->hasUserDeclaredDestructor()) {
- llvm::SmallPtrSet<const CXXMethodDecl *, 8> Work;
- // Seed the working set with our non-destructor virtual methods.
- for (CXXRecordDecl::method_iterator i = RD->method_begin(),
- e = RD->method_end();
- i != e; ++i)
- if ((*i)->isVirtual() && !isa<CXXDestructorDecl>(*i))
- Work.insert(*i);
- while (!Work.empty()) {
- const CXXMethodDecl *MD = *Work.begin();
- CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(),
- e = MD->end_overridden_methods();
- if (i == e)
- // If a virtual method has no-overrides it lives in its parent's vtable.
- HasVtordisp.insert(MD->getParent());
- else
- Work.insert(i, e);
- // We've finished processing this element, remove it from the working set.
- Work.erase(MD);
- }
+ for (const auto &bi : Layout.getVBaseOffsetsMap())
+ if (bi.second.hasVtorDisp())
+ HasVtordispSet.insert(bi.first);
+ }
+ // We don't introduce any additional vtordisps if either:
+ // * A user declared constructor or destructor aren't declared.
+ // * #pragma vtordisp(0) or the /vd0 flag are in use.
+ if ((!RD->hasUserDeclaredConstructor() && !RD->hasUserDeclaredDestructor()) ||
+ RD->getMSVtorDispMode() == MSVtorDispAttr::Never)
+ return HasVtordispSet;
+ // /vd1 or #pragma vtordisp(1): Try to guess based on whether we think it's
+ // possible for a partially constructed object with virtual base overrides to
+ // escape a non-trivial constructor.
+ assert(RD->getMSVtorDispMode() == MSVtorDispAttr::ForVBaseOverride);
+ // Compute a set of base classes which define methods we override. A virtual
+ // base in this set will require a vtordisp. A virtual base that transitively
+ // contains one of these bases as a non-virtual base will also require a
+ // vtordisp.
+ llvm::SmallPtrSet<const CXXMethodDecl *, 8> Work;
+ llvm::SmallPtrSet<const CXXRecordDecl *, 2> BasesWithOverriddenMethods;
+ // Seed the working set with our non-destructor virtual methods.
+ for (const CXXMethodDecl *MD : RD->methods())
+ if (MD->isVirtual() && !isa<CXXDestructorDecl>(MD))
+ Work.insert(MD);
+ while (!Work.empty()) {
+ const CXXMethodDecl *MD = *Work.begin();
+ CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(),
+ e = MD->end_overridden_methods();
+ // If a virtual method has no-overrides it lives in its parent's vtable.
+ if (i == e)
+ BasesWithOverriddenMethods.insert(MD->getParent());
+ else
+ Work.insert(i, e);
+ // We've finished processing this element, remove it from the working set.
+ Work.erase(MD);
}
-
- // Re-check all of our vbases for vtordisp requirements (in case their
- // non-virtual bases have vtordisp requirements).
- for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(),
- e = RD->vbases_end();
- i != e; ++i) {
- const CXXRecordDecl *BaseDecl = i->getType()->getAsCXXRecordDecl();
- if (!HasVtordisp.count(BaseDecl) && RequiresVtordisp(HasVtordisp, BaseDecl))
- HasVtordisp.insert(BaseDecl);
+ // For each of our virtual bases, check if it is in the set of overridden
+ // bases or if it transitively contains a non-virtual base that is.
+ for (const CXXBaseSpecifier &Base : RD->vbases()) {
+ const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
+ if (!HasVtordispSet.count(BaseDecl) &&
+ RequiresVtordisp(BasesWithOverriddenMethods, BaseDecl))
+ HasVtordispSet.insert(BaseDecl);
}
-
- return HasVtordisp;
+ return HasVtordispSet;
}
/// \brief Get or compute information about the layout of the specified record
@@ -2684,19 +2742,20 @@ ASTContext::BuildMicrosoftASTRecordLayout(const RecordDecl *D) const {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
Builder.cxxLayout(RD);
return new (*this) ASTRecordLayout(
- *this, Builder.Size, Builder.Alignment,
- Builder.HasExtendableVFPtr && !Builder.PrimaryBase,
- Builder.HasExtendableVFPtr,
- Builder.VBPtrOffset, Builder.DataSize, Builder.FieldOffsets.data(),
- Builder.FieldOffsets.size(), Builder.DataSize,
- Builder.NonVirtualAlignment, CharUnits::Zero(), Builder.PrimaryBase,
- false, Builder.SharedVBPtrBase, Builder.AlignAfterVBases, Builder.Bases,
- Builder.VBases);
+ *this, Builder.Size, Builder.Alignment, Builder.RequiredAlignment,
+ Builder.HasOwnVFPtr,
+ Builder.HasOwnVFPtr || Builder.PrimaryBase,
+ Builder.VBPtrOffset, Builder.NonVirtualSize, Builder.FieldOffsets.data(),
+ Builder.FieldOffsets.size(), Builder.NonVirtualSize,
+ Builder.Alignment, CharUnits::Zero(), Builder.PrimaryBase,
+ false, Builder.SharedVBPtrBase,
+ Builder.EndsWithZeroSizedObject, Builder.LeadsWithZeroSizedBase,
+ Builder.Bases, Builder.VBases);
} else {
Builder.layout(D);
return new (*this) ASTRecordLayout(
- *this, Builder.Size, Builder.Alignment, Builder.Size,
- Builder.FieldOffsets.data(), Builder.FieldOffsets.size());
+ *this, Builder.Size, Builder.Alignment, Builder.RequiredAlignment,
+ Builder.Size, Builder.FieldOffsets.data(), Builder.FieldOffsets.size());
}
}
@@ -2724,7 +2783,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
const ASTRecordLayout *Entry = ASTRecordLayouts[D];
if (Entry) return *Entry;
- const ASTRecordLayout *NewEntry = 0;
+ const ASTRecordLayout *NewEntry = nullptr;
if (isMsLayout(D) && !D->getASTContext().getExternalSource()) {
NewEntry = BuildMicrosoftASTRecordLayout(D);
@@ -2747,6 +2806,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
NewEntry =
new (*this) ASTRecordLayout(*this, Builder.getSize(),
Builder.Alignment,
+ /*RequiredAlignment : used by MS-ABI)*/
+ Builder.Alignment,
Builder.HasOwnVFPtr,
RD->isDynamicClass(),
CharUnits::fromQuantity(-1),
@@ -2758,15 +2819,17 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
EmptySubobjects.SizeOfLargestEmptySubobject,
Builder.PrimaryBase,
Builder.PrimaryBaseIsVirtual,
- 0, true,
+ nullptr, false, false,
Builder.Bases, Builder.VBases);
} else {
- RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
+ RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/nullptr);
Builder.Layout(D);
NewEntry =
new (*this) ASTRecordLayout(*this, Builder.getSize(),
Builder.Alignment,
+ /*RequiredAlignment : used by MS-ABI)*/
+ Builder.Alignment,
Builder.getSize(),
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
@@ -2784,16 +2847,25 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) {
if (!getTargetInfo().getCXXABI().hasKeyFunctions())
- return 0;
+ return nullptr;
assert(RD->getDefinition() && "Cannot get key function for forward decl!");
RD = cast<CXXRecordDecl>(RD->getDefinition());
- LazyDeclPtr &Entry = KeyFunctions[RD];
- if (!Entry)
- Entry = const_cast<CXXMethodDecl*>(computeKeyFunction(*this, RD));
+ // Beware:
+ // 1) computing the key function might trigger deserialization, which might
+ // invalidate iterators into KeyFunctions
+ // 2) 'get' on the LazyDeclPtr might also trigger deserialization and
+ // invalidate the LazyDeclPtr within the map itself
+ LazyDeclPtr Entry = KeyFunctions[RD];
+ const Decl *Result =
+ Entry ? Entry.get(getExternalSource()) : computeKeyFunction(*this, RD);
+
+ // Store it back if it changed.
+ if (Entry.isOffset() || Entry.isValid() != bool(Result))
+ KeyFunctions[RD] = const_cast<Decl*>(Result);
- return cast_or_null<CXXMethodDecl>(Entry.get(getExternalSource()));
+ return cast_or_null<CXXMethodDecl>(Result);
}
void ASTContext::setNonKeyFunction(const CXXMethodDecl *Method) {
@@ -2810,10 +2882,12 @@ void ASTContext::setNonKeyFunction(const CXXMethodDecl *Method) {
if (I == KeyFunctions.end()) return;
// If it is cached, check whether it's the target method, and if so,
- // remove it from the cache.
- if (I->second.get(getExternalSource()) == Method) {
+ // remove it from the cache. Note, the call to 'get' might invalidate
+ // the iterator and the LazyDeclPtr object within the map.
+ LazyDeclPtr Ptr = I->second;
+ if (Ptr.get(getExternalSource()) == Method) {
// FIXME: remember that we did this for module / chained PCH state?
- KeyFunctions.erase(I);
+ KeyFunctions.erase(Method->getParent());
}
}
@@ -2830,10 +2904,8 @@ uint64_t ASTContext::getFieldOffset(const ValueDecl *VD) const {
const IndirectFieldDecl *IFD = cast<IndirectFieldDecl>(VD);
OffsetInBits = 0;
- for (IndirectFieldDecl::chain_iterator CI = IFD->chain_begin(),
- CE = IFD->chain_end();
- CI != CE; ++CI)
- OffsetInBits += ::getFieldOffset(*this, cast<FieldDecl>(*CI));
+ for (const NamedDecl *ND : IFD->chain())
+ OffsetInBits += ::getFieldOffset(*this, cast<FieldDecl>(ND));
}
return OffsetInBits;
@@ -2867,15 +2939,17 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
// entries later; however we shouldn't look up implementations
// frequently.
if (SynthCount == 0)
- return getObjCLayout(D, 0);
+ return getObjCLayout(D, nullptr);
}
- RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
+ RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/nullptr);
Builder.Layout(D);
const ASTRecordLayout *NewEntry =
new (*this) ASTRecordLayout(*this, Builder.getSize(),
Builder.Alignment,
+ /*RequiredAlignment : used by MS-ABI)*/
+ Builder.Alignment,
Builder.getDataSize(),
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
@@ -2928,19 +3002,24 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
OS << '(' << *RD << " vftable pointer)\n";
}
- // Dump (non-virtual) bases
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- assert(!I->getType()->isDependentType() &&
+ // Collect nvbases.
+ SmallVector<const CXXRecordDecl *, 4> Bases;
+ for (const CXXBaseSpecifier &Base : RD->bases()) {
+ assert(!Base.getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
- if (I->isVirtual())
- continue;
+ if (!Base.isVirtual())
+ Bases.push_back(Base.getType()->getAsCXXRecordDecl());
+ }
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ // Sort nvbases by offset.
+ std::stable_sort(Bases.begin(), Bases.end(),
+ [&](const CXXRecordDecl *L, const CXXRecordDecl *R) {
+ return Layout.getBaseClassOffset(L) < Layout.getBaseClassOffset(R);
+ });
+ // Dump (non-virtual) bases
+ for (const CXXRecordDecl *Base : Bases) {
CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base);
-
DumpCXXRecordLayout(OS, Base, C, BaseOffset, IndentLevel,
Base == PrimaryBase ? "(primary base)" : "(base)",
/*IncludeVirtualBases=*/false);
@@ -2960,13 +3039,11 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
CharUnits FieldOffset = Offset +
C.toCharUnitsFromBits(Layout.getFieldOffset(FieldNo));
- if (const RecordType *RT = Field.getType()->getAs<RecordType>()) {
- if (const CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- DumpCXXRecordLayout(OS, D, C, FieldOffset, IndentLevel,
- Field.getName().data(),
- /*IncludeVirtualBases=*/true);
- continue;
- }
+ if (const CXXRecordDecl *D = Field.getType()->getAsCXXRecordDecl()) {
+ DumpCXXRecordLayout(OS, D, C, FieldOffset, IndentLevel,
+ Field.getName().data(),
+ /*IncludeVirtualBases=*/true);
+ continue;
}
PrintOffset(OS, FieldOffset, IndentLevel);
@@ -2979,11 +3056,9 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
// Dump virtual bases.
const ASTRecordLayout::VBaseOffsetsMapTy &vtordisps =
Layout.getVBaseOffsetsMap();
- for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
- E = RD->vbases_end(); I != E; ++I) {
- assert(I->isVirtual() && "Found non-virtual class!");
- const CXXRecordDecl *VBase =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ for (const CXXBaseSpecifier &Base : RD->vbases()) {
+ assert(Base.isVirtual() && "Found non-virtual class!");
+ const CXXRecordDecl *VBase = Base.getType()->getAsCXXRecordDecl();
CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBase);
@@ -3006,8 +3081,7 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
PrintIndentNoOffset(OS, IndentLevel - 1);
OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity();
- OS << ", nvalign=" << Layout.getNonVirtualAlign().getQuantity() << "]\n";
- OS << '\n';
+ OS << ", nvalign=" << Layout.getNonVirtualAlignment().getQuantity() << "]\n";
}
void ASTContext::DumpRecordLayout(const RecordDecl *RD,
@@ -3017,7 +3091,7 @@ void ASTContext::DumpRecordLayout(const RecordDecl *RD,
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
if (!Simple)
- return DumpCXXRecordLayout(OS, CXXRD, *this, CharUnits(), 0, 0,
+ return DumpCXXRecordLayout(OS, CXXRD, *this, CharUnits(), 0, nullptr,
/*IncludeVirtualBases=*/true);
OS << "Type: " << getTypeDeclType(RD).getAsString() << "\n";
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index de851615cb7a..a8483dc5bb99 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -65,13 +65,13 @@ void Stmt::PrintStats() {
unsigned sum = 0;
llvm::errs() << "\n*** Stmt/Expr Stats:\n";
for (int i = 0; i != Stmt::lastStmtConstant+1; i++) {
- if (StmtClassInfo[i].Name == 0) continue;
+ if (StmtClassInfo[i].Name == nullptr) continue;
sum += StmtClassInfo[i].Counter;
}
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].Name == nullptr) continue;
if (StmtClassInfo[i].Counter == 0) continue;
llvm::errs() << " " << StmtClassInfo[i].Counter << " "
<< StmtClassInfo[i].Name << ", " << StmtClassInfo[i].Size
@@ -260,7 +260,7 @@ CompoundStmt::CompoundStmt(const ASTContext &C, ArrayRef<Stmt*> Stmts,
"NumStmts doesn't fit in bits of CompoundStmtBits.NumStmts!");
if (Stmts.size() == 0) {
- Body = 0;
+ Body = nullptr;
return;
}
@@ -285,8 +285,8 @@ const char *LabelStmt::getName() const {
AttributedStmt *AttributedStmt::Create(const ASTContext &C, SourceLocation Loc,
ArrayRef<const Attr*> Attrs,
Stmt *SubStmt) {
- void *Mem = C.Allocate(sizeof(AttributedStmt) +
- sizeof(Attr*) * (Attrs.size() - 1),
+ assert(!Attrs.empty() && "Attrs should not be empty");
+ void *Mem = C.Allocate(sizeof(AttributedStmt) + sizeof(Attr *) * Attrs.size(),
llvm::alignOf<AttributedStmt>());
return new (Mem) AttributedStmt(Loc, Attrs, SubStmt);
}
@@ -294,8 +294,7 @@ AttributedStmt *AttributedStmt::Create(const ASTContext &C, SourceLocation Loc,
AttributedStmt *AttributedStmt::CreateEmpty(const ASTContext &C,
unsigned NumAttrs) {
assert(NumAttrs > 0 && "NumAttrs should be greater than zero");
- void *Mem = C.Allocate(sizeof(AttributedStmt) +
- sizeof(Attr*) * (NumAttrs - 1),
+ void *Mem = C.Allocate(sizeof(AttributedStmt) + sizeof(Attr *) * NumAttrs,
llvm::alignOf<AttributedStmt>());
return new (Mem) AttributedStmt(EmptyShell(), NumAttrs);
}
@@ -554,7 +553,7 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
// Find the ']'.
const char *NameEnd = (const char*)memchr(CurPtr, ']', StrEnd-CurPtr);
- if (NameEnd == 0)
+ if (NameEnd == nullptr)
return diag::err_asm_unterminated_symbolic_operand_name;
if (NameEnd == CurPtr)
return diag::err_asm_empty_symbolic_operand_name;
@@ -720,8 +719,7 @@ ObjCAtTryStmt::ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
Stmt **CatchStmts, unsigned NumCatchStmts,
Stmt *atFinallyStmt)
: Stmt(ObjCAtTryStmtClass), AtTryLoc(atTryLoc),
- NumCatchStmts(NumCatchStmts), HasFinally(atFinallyStmt != 0)
-{
+ NumCatchStmts(NumCatchStmts), HasFinally(atFinallyStmt != nullptr) {
Stmt **Stmts = getStmts();
Stmts[0] = atTryStmt;
for (unsigned I = 0; I != NumCatchStmts; ++I)
@@ -738,7 +736,7 @@ ObjCAtTryStmt *ObjCAtTryStmt::Create(const ASTContext &Context,
unsigned NumCatchStmts,
Stmt *atFinallyStmt) {
unsigned Size = sizeof(ObjCAtTryStmt) +
- (1 + NumCatchStmts + (atFinallyStmt != 0)) * sizeof(Stmt *);
+ (1 + NumCatchStmts + (atFinallyStmt != nullptr)) * sizeof(Stmt *);
void *Mem = Context.Allocate(Size, llvm::alignOf<ObjCAtTryStmt>());
return new (Mem) ObjCAtTryStmt(atTryLoc, atTryStmt, CatchStmts, NumCatchStmts,
atFinallyStmt);
@@ -803,7 +801,7 @@ CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt,
Expr *CXXForRangeStmt::getRangeInit() {
DeclStmt *RangeStmt = getRangeStmt();
VarDecl *RangeDecl = dyn_cast_or_null<VarDecl>(RangeStmt->getSingleDecl());
- assert(RangeDecl &&& "for-range should have a single var decl");
+ assert(RangeDecl && "for-range should have a single var decl");
return RangeDecl->getInit();
}
@@ -833,7 +831,7 @@ IfStmt::IfStmt(const ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
VarDecl *IfStmt::getConditionVariable() const {
if (!SubExprs[VAR])
- return 0;
+ return nullptr;
DeclStmt *DS = cast<DeclStmt>(SubExprs[VAR]);
return cast<VarDecl>(DS->getSingleDecl());
@@ -841,7 +839,7 @@ VarDecl *IfStmt::getConditionVariable() const {
void IfStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
if (!V) {
- SubExprs[VAR] = 0;
+ SubExprs[VAR] = nullptr;
return;
}
@@ -864,7 +862,7 @@ ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
VarDecl *ForStmt::getConditionVariable() const {
if (!SubExprs[CONDVAR])
- return 0;
+ return nullptr;
DeclStmt *DS = cast<DeclStmt>(SubExprs[CONDVAR]);
return cast<VarDecl>(DS->getSingleDecl());
@@ -872,7 +870,7 @@ VarDecl *ForStmt::getConditionVariable() const {
void ForStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
if (!V) {
- SubExprs[CONDVAR] = 0;
+ SubExprs[CONDVAR] = nullptr;
return;
}
@@ -882,16 +880,16 @@ void ForStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
}
SwitchStmt::SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond)
- : Stmt(SwitchStmtClass), FirstCase(0), AllEnumCasesCovered(0)
+ : Stmt(SwitchStmtClass), FirstCase(nullptr), AllEnumCasesCovered(0)
{
setConditionVariable(C, Var);
SubExprs[COND] = cond;
- SubExprs[BODY] = NULL;
+ SubExprs[BODY] = nullptr;
}
VarDecl *SwitchStmt::getConditionVariable() const {
if (!SubExprs[VAR])
- return 0;
+ return nullptr;
DeclStmt *DS = cast<DeclStmt>(SubExprs[VAR]);
return cast<VarDecl>(DS->getSingleDecl());
@@ -899,7 +897,7 @@ VarDecl *SwitchStmt::getConditionVariable() const {
void SwitchStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
if (!V) {
- SubExprs[VAR] = 0;
+ SubExprs[VAR] = nullptr;
return;
}
@@ -925,7 +923,7 @@ WhileStmt::WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
VarDecl *WhileStmt::getConditionVariable() const {
if (!SubExprs[VAR])
- return 0;
+ return nullptr;
DeclStmt *DS = cast<DeclStmt>(SubExprs[VAR]);
return cast<VarDecl>(DS->getSingleDecl());
@@ -933,7 +931,7 @@ VarDecl *WhileStmt::getConditionVariable() const {
void WhileStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
if (!V) {
- SubExprs[VAR] = 0;
+ SubExprs[VAR] = nullptr;
return;
}
@@ -947,7 +945,7 @@ LabelDecl *IndirectGotoStmt::getConstantTarget() {
if (AddrLabelExpr *E =
dyn_cast<AddrLabelExpr>(getTarget()->IgnoreParenImpCasts()))
return E->getLabel();
- return 0;
+ return nullptr;
}
// ReturnStmt
@@ -958,22 +956,20 @@ Expr* ReturnStmt::getRetValue() {
return cast_or_null<Expr>(RetExpr);
}
-SEHTryStmt::SEHTryStmt(bool IsCXXTry,
- SourceLocation TryLoc,
- Stmt *TryBlock,
- Stmt *Handler)
- : Stmt(SEHTryStmtClass),
- IsCXXTry(IsCXXTry),
- TryLoc(TryLoc)
-{
- Children[TRY] = TryBlock;
+SEHTryStmt::SEHTryStmt(bool IsCXXTry, SourceLocation TryLoc, Stmt *TryBlock,
+ Stmt *Handler, int HandlerIndex, int HandlerParentIndex)
+ : Stmt(SEHTryStmtClass), IsCXXTry(IsCXXTry), TryLoc(TryLoc),
+ HandlerIndex(HandlerIndex), HandlerParentIndex(HandlerParentIndex) {
+ Children[TRY] = TryBlock;
Children[HANDLER] = Handler;
}
-SEHTryStmt* SEHTryStmt::Create(const ASTContext &C, bool IsCXXTry,
+SEHTryStmt *SEHTryStmt::Create(const ASTContext &C, bool IsCXXTry,
SourceLocation TryLoc, Stmt *TryBlock,
- Stmt *Handler) {
- return new(C) SEHTryStmt(IsCXXTry,TryLoc,TryBlock,Handler);
+ Stmt *Handler, int HandlerIndex,
+ int HandlerParentIndex) {
+ return new (C) SEHTryStmt(IsCXXTry, TryLoc, TryBlock, Handler, HandlerIndex,
+ HandlerParentIndex);
}
SEHExceptStmt* SEHTryStmt::getExceptHandler() const {
@@ -1049,8 +1045,8 @@ CapturedStmt::CapturedStmt(Stmt *S, CapturedRegionKind Kind,
CapturedStmt::CapturedStmt(EmptyShell Empty, unsigned NumCaptures)
: Stmt(CapturedStmtClass, Empty), NumCaptures(NumCaptures),
- CapDeclAndKind(0, CR_Default), TheRecordDecl(0) {
- getStoredStmts()[NumCaptures] = 0;
+ CapDeclAndKind(nullptr, CR_Default), TheRecordDecl(nullptr) {
+ getStoredStmts()[NumCaptures] = nullptr;
}
CapturedStmt *CapturedStmt::Create(const ASTContext &Context, Stmt *S,
@@ -1100,15 +1096,14 @@ Stmt::child_range CapturedStmt::children() {
}
bool CapturedStmt::capturesVariable(const VarDecl *Var) const {
- for (const_capture_iterator I = capture_begin(),
- E = capture_end(); I != E; ++I) {
- if (!I->capturesVariable())
+ for (const auto &I : captures()) {
+ if (!I.capturesVariable())
continue;
// This does not handle variable redeclarations. This should be
// extended to capture variables with redeclarations, for example
// a thread-private variable in OpenMP.
- if (I->getCapturedVar() == Var)
+ if (I.getCapturedVar() == Var)
return true;
}
@@ -1130,8 +1125,9 @@ OMPPrivateClause *OMPPrivateClause::Create(const ASTContext &C,
SourceLocation LParenLoc,
SourceLocation EndLoc,
ArrayRef<Expr *> VL) {
- void *Mem = C.Allocate(sizeof(OMPPrivateClause) + sizeof(Expr *) * VL.size(),
- llvm::alignOf<OMPPrivateClause>());
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPPrivateClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * VL.size());
OMPPrivateClause *Clause = new (Mem) OMPPrivateClause(StartLoc, LParenLoc,
EndLoc, VL.size());
Clause->setVarRefs(VL);
@@ -1140,8 +1136,9 @@ OMPPrivateClause *OMPPrivateClause::Create(const ASTContext &C,
OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C,
unsigned N) {
- void *Mem = C.Allocate(sizeof(OMPPrivateClause) + sizeof(Expr *) * N,
- llvm::alignOf<OMPPrivateClause>());
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPPrivateClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * N);
return new (Mem) OMPPrivateClause(N);
}
@@ -1150,9 +1147,9 @@ OMPFirstprivateClause *OMPFirstprivateClause::Create(const ASTContext &C,
SourceLocation LParenLoc,
SourceLocation EndLoc,
ArrayRef<Expr *> VL) {
- void *Mem = C.Allocate(sizeof(OMPFirstprivateClause) +
- sizeof(Expr *) * VL.size(),
- llvm::alignOf<OMPFirstprivateClause>());
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * VL.size());
OMPFirstprivateClause *Clause = new (Mem) OMPFirstprivateClause(StartLoc,
LParenLoc,
EndLoc,
@@ -1163,18 +1160,42 @@ OMPFirstprivateClause *OMPFirstprivateClause::Create(const ASTContext &C,
OMPFirstprivateClause *OMPFirstprivateClause::CreateEmpty(const ASTContext &C,
unsigned N) {
- void *Mem = C.Allocate(sizeof(OMPFirstprivateClause) + sizeof(Expr *) * N,
- llvm::alignOf<OMPFirstprivateClause>());
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * N);
return new (Mem) OMPFirstprivateClause(N);
}
+OMPLastprivateClause *OMPLastprivateClause::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLastprivateClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * VL.size());
+ OMPLastprivateClause *Clause =
+ new (Mem) OMPLastprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ return Clause;
+}
+
+OMPLastprivateClause *OMPLastprivateClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLastprivateClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * N);
+ return new (Mem) OMPLastprivateClause(N);
+}
+
OMPSharedClause *OMPSharedClause::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc,
ArrayRef<Expr *> VL) {
- void *Mem = C.Allocate(sizeof(OMPSharedClause) + sizeof(Expr *) * VL.size(),
- llvm::alignOf<OMPSharedClause>());
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPSharedClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * VL.size());
OMPSharedClause *Clause = new (Mem) OMPSharedClause(StartLoc, LParenLoc,
EndLoc, VL.size());
Clause->setVarRefs(VL);
@@ -1183,15 +1204,148 @@ OMPSharedClause *OMPSharedClause::Create(const ASTContext &C,
OMPSharedClause *OMPSharedClause::CreateEmpty(const ASTContext &C,
unsigned N) {
- void *Mem = C.Allocate(sizeof(OMPSharedClause) + sizeof(Expr *) * N,
- llvm::alignOf<OMPSharedClause>());
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPSharedClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * N);
return new (Mem) OMPSharedClause(N);
}
+OMPLinearClause *OMPLinearClause::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL, Expr *Step) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLinearClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * (VL.size() + 1));
+ OMPLinearClause *Clause = new (Mem)
+ OMPLinearClause(StartLoc, LParenLoc, ColonLoc, EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ Clause->setStep(Step);
+ return Clause;
+}
+
+OMPLinearClause *OMPLinearClause::CreateEmpty(const ASTContext &C,
+ unsigned NumVars) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLinearClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * (NumVars + 1));
+ return new (Mem) OMPLinearClause(NumVars);
+}
+
+OMPAlignedClause *
+OMPAlignedClause::Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation ColonLoc,
+ SourceLocation EndLoc, ArrayRef<Expr *> VL, Expr *A) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPAlignedClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * (VL.size() + 1));
+ OMPAlignedClause *Clause = new (Mem)
+ OMPAlignedClause(StartLoc, LParenLoc, ColonLoc, EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ Clause->setAlignment(A);
+ return Clause;
+}
+
+OMPAlignedClause *OMPAlignedClause::CreateEmpty(const ASTContext &C,
+ unsigned NumVars) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPAlignedClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * (NumVars + 1));
+ return new (Mem) OMPAlignedClause(NumVars);
+}
+
+OMPCopyinClause *OMPCopyinClause::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyinClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * VL.size());
+ OMPCopyinClause *Clause = new (Mem) OMPCopyinClause(StartLoc, LParenLoc,
+ EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ return Clause;
+}
+
+OMPCopyinClause *OMPCopyinClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyinClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * N);
+ return new (Mem) OMPCopyinClause(N);
+}
+
+OMPCopyprivateClause *OMPCopyprivateClause::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyprivateClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * VL.size());
+ OMPCopyprivateClause *Clause =
+ new (Mem) OMPCopyprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ return Clause;
+}
+
+OMPCopyprivateClause *OMPCopyprivateClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyprivateClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * N);
+ return new (Mem) OMPCopyprivateClause(N);
+}
+
void OMPExecutableDirective::setClauses(ArrayRef<OMPClause *> Clauses) {
- assert(Clauses.size() == this->Clauses.size() &&
+ assert(Clauses.size() == getNumClauses() &&
"Number of clauses is not the same as the preallocated buffer");
- std::copy(Clauses.begin(), Clauses.end(), this->Clauses.begin());
+ std::copy(Clauses.begin(), Clauses.end(), getClauses().begin());
+}
+
+OMPReductionClause *OMPReductionClause::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL,
+ NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * VL.size());
+ OMPReductionClause *Clause = new (Mem) OMPReductionClause(
+ StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo);
+ Clause->setVarRefs(VL);
+ return Clause;
+}
+
+OMPReductionClause *OMPReductionClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * N);
+ return new (Mem) OMPReductionClause(N);
+}
+
+OMPFlushClause *OMPFlushClause::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFlushClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * VL.size());
+ OMPFlushClause *Clause =
+ new (Mem) OMPFlushClause(StartLoc, LParenLoc, EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ return Clause;
+}
+
+OMPFlushClause *OMPFlushClause::CreateEmpty(const ASTContext &C, unsigned N) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFlushClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * N);
+ return new (Mem) OMPFlushClause(N);
}
OMPParallelDirective *OMPParallelDirective::Create(
@@ -1200,9 +1354,10 @@ OMPParallelDirective *OMPParallelDirective::Create(
SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses,
Stmt *AssociatedStmt) {
- void *Mem = C.Allocate(sizeof(OMPParallelDirective) +
- sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *),
- llvm::alignOf<OMPParallelDirective>());
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem = C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
+ sizeof(Stmt *));
OMPParallelDirective *Dir = new (Mem) OMPParallelDirective(StartLoc, EndLoc,
Clauses.size());
Dir->setClauses(Clauses);
@@ -1211,10 +1366,315 @@ OMPParallelDirective *OMPParallelDirective::Create(
}
OMPParallelDirective *OMPParallelDirective::CreateEmpty(const ASTContext &C,
- unsigned N,
+ unsigned NumClauses,
+ EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem = C.Allocate(Size + sizeof(OMPClause *) * NumClauses +
+ sizeof(Stmt *));
+ return new (Mem) OMPParallelDirective(NumClauses);
+}
+
+OMPSimdDirective *
+OMPSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation EndLoc, unsigned CollapsedNum,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSimdDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
+ OMPSimdDirective *Dir = new (Mem)
+ OMPSimdDirective(StartLoc, EndLoc, CollapsedNum, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ return Dir;
+}
+
+OMPSimdDirective *OMPSimdDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum,
+ EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSimdDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
+ return new (Mem) OMPSimdDirective(CollapsedNum, NumClauses);
+}
+
+OMPForDirective *
+OMPForDirective::Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation EndLoc, unsigned CollapsedNum,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPForDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
+ OMPForDirective *Dir =
+ new (Mem) OMPForDirective(StartLoc, EndLoc, CollapsedNum, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ return Dir;
+}
+
+OMPForDirective *OMPForDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum,
+ EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPForDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
+ return new (Mem) OMPForDirective(CollapsedNum, NumClauses);
+}
+
+OMPSectionsDirective *OMPSectionsDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSectionsDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
+ OMPSectionsDirective *Dir =
+ new (Mem) OMPSectionsDirective(StartLoc, EndLoc, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ return Dir;
+}
+
+OMPSectionsDirective *OMPSectionsDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSectionsDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
+ return new (Mem) OMPSectionsDirective(NumClauses);
+}
+
+OMPSectionDirective *OMPSectionDirective::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ Stmt *AssociatedStmt) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSectionsDirective),
+ llvm::alignOf<Stmt *>());
+ void *Mem = C.Allocate(Size + sizeof(Stmt *));
+ OMPSectionDirective *Dir = new (Mem) OMPSectionDirective(StartLoc, EndLoc);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ return Dir;
+}
+
+OMPSectionDirective *OMPSectionDirective::CreateEmpty(const ASTContext &C,
+ EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSectionDirective),
+ llvm::alignOf<Stmt *>());
+ void *Mem = C.Allocate(Size + sizeof(Stmt *));
+ return new (Mem) OMPSectionDirective();
+}
+
+OMPSingleDirective *OMPSingleDirective::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSingleDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
+ OMPSingleDirective *Dir =
+ new (Mem) OMPSingleDirective(StartLoc, EndLoc, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ return Dir;
+}
+
+OMPSingleDirective *OMPSingleDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSingleDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
+ return new (Mem) OMPSingleDirective(NumClauses);
+}
+
+OMPMasterDirective *OMPMasterDirective::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ Stmt *AssociatedStmt) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPMasterDirective),
+ llvm::alignOf<Stmt *>());
+ void *Mem = C.Allocate(Size + sizeof(Stmt *));
+ OMPMasterDirective *Dir = new (Mem) OMPMasterDirective(StartLoc, EndLoc);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ return Dir;
+}
+
+OMPMasterDirective *OMPMasterDirective::CreateEmpty(const ASTContext &C,
+ EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPMasterDirective),
+ llvm::alignOf<Stmt *>());
+ void *Mem = C.Allocate(Size + sizeof(Stmt *));
+ return new (Mem) OMPMasterDirective();
+}
+
+OMPCriticalDirective *OMPCriticalDirective::Create(
+ const ASTContext &C, const DeclarationNameInfo &Name,
+ SourceLocation StartLoc, SourceLocation EndLoc, Stmt *AssociatedStmt) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPCriticalDirective),
+ llvm::alignOf<Stmt *>());
+ void *Mem = C.Allocate(Size + sizeof(Stmt *));
+ OMPCriticalDirective *Dir =
+ new (Mem) OMPCriticalDirective(Name, StartLoc, EndLoc);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ return Dir;
+}
+
+OMPCriticalDirective *OMPCriticalDirective::CreateEmpty(const ASTContext &C,
+ EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPCriticalDirective),
+ llvm::alignOf<Stmt *>());
+ void *Mem = C.Allocate(Size + sizeof(Stmt *));
+ return new (Mem) OMPCriticalDirective();
+}
+
+OMPParallelForDirective *
+OMPParallelForDirective::Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation EndLoc, unsigned CollapsedNum,
+ ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelForDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
+ OMPParallelForDirective *Dir = new (Mem)
+ OMPParallelForDirective(StartLoc, EndLoc, CollapsedNum, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ return Dir;
+}
+
+OMPParallelForDirective *
+OMPParallelForDirective::CreateEmpty(const ASTContext &C, unsigned NumClauses,
+ unsigned CollapsedNum, EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelForDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
+ return new (Mem) OMPParallelForDirective(CollapsedNum, NumClauses);
+}
+
+OMPParallelSectionsDirective *OMPParallelSectionsDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelSectionsDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
+ OMPParallelSectionsDirective *Dir =
+ new (Mem) OMPParallelSectionsDirective(StartLoc, EndLoc, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ return Dir;
+}
+
+OMPParallelSectionsDirective *
+OMPParallelSectionsDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses, EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelSectionsDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
+ return new (Mem) OMPParallelSectionsDirective(NumClauses);
+}
+
+OMPTaskDirective *OMPTaskDirective::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTaskDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *));
+ OMPTaskDirective *Dir =
+ new (Mem) OMPTaskDirective(StartLoc, EndLoc, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ return Dir;
+}
+
+OMPTaskDirective *OMPTaskDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTaskDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *));
+ return new (Mem) OMPTaskDirective(NumClauses);
+}
+
+OMPTaskyieldDirective *OMPTaskyieldDirective::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ void *Mem = C.Allocate(sizeof(OMPTaskyieldDirective));
+ OMPTaskyieldDirective *Dir =
+ new (Mem) OMPTaskyieldDirective(StartLoc, EndLoc);
+ return Dir;
+}
+
+OMPTaskyieldDirective *OMPTaskyieldDirective::CreateEmpty(const ASTContext &C,
+ EmptyShell) {
+ void *Mem = C.Allocate(sizeof(OMPTaskyieldDirective));
+ return new (Mem) OMPTaskyieldDirective();
+}
+
+OMPBarrierDirective *OMPBarrierDirective::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ void *Mem = C.Allocate(sizeof(OMPBarrierDirective));
+ OMPBarrierDirective *Dir = new (Mem) OMPBarrierDirective(StartLoc, EndLoc);
+ return Dir;
+}
+
+OMPBarrierDirective *OMPBarrierDirective::CreateEmpty(const ASTContext &C,
+ EmptyShell) {
+ void *Mem = C.Allocate(sizeof(OMPBarrierDirective));
+ return new (Mem) OMPBarrierDirective();
+}
+
+OMPTaskwaitDirective *OMPTaskwaitDirective::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ void *Mem = C.Allocate(sizeof(OMPTaskwaitDirective));
+ OMPTaskwaitDirective *Dir = new (Mem) OMPTaskwaitDirective(StartLoc, EndLoc);
+ return Dir;
+}
+
+OMPTaskwaitDirective *OMPTaskwaitDirective::CreateEmpty(const ASTContext &C,
EmptyShell) {
- void *Mem = C.Allocate(sizeof(OMPParallelDirective) +
- sizeof(OMPClause *) * N + sizeof(Stmt *),
- llvm::alignOf<OMPParallelDirective>());
- return new (Mem) OMPParallelDirective(N);
+ void *Mem = C.Allocate(sizeof(OMPTaskwaitDirective));
+ return new (Mem) OMPTaskwaitDirective();
+}
+
+OMPFlushDirective *OMPFlushDirective::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPFlushDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem = C.Allocate(Size + sizeof(OMPClause *) * Clauses.size());
+ OMPFlushDirective *Dir =
+ new (Mem) OMPFlushDirective(StartLoc, EndLoc, Clauses.size());
+ Dir->setClauses(Clauses);
+ return Dir;
+}
+
+OMPFlushDirective *OMPFlushDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ EmptyShell) {
+ unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPFlushDirective),
+ llvm::alignOf<OMPClause *>());
+ void *Mem = C.Allocate(Size + sizeof(OMPClause *) * NumClauses);
+ return new (Mem) OMPFlushDirective(NumClauses);
}
+
diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp
index 6e85375ed22f..1ccba04d9f5b 100644
--- a/lib/AST/StmtIterator.cpp
+++ b/lib/AST/StmtIterator.cpp
@@ -27,7 +27,7 @@ static inline const VariableArrayType *FindVA(const Type* t) {
t = vt->getElementType().getTypePtr();
}
- return NULL;
+ return nullptr;
}
void StmtIteratorBase::NextVA() {
@@ -54,7 +54,7 @@ void StmtIteratorBase::NextVA() {
}
void StmtIteratorBase::NextDecl(bool ImmediateAdvance) {
- assert (getVAPtr() == NULL);
+ assert(getVAPtr() == nullptr);
assert(inDeclGroup());
if (ImmediateAdvance)
@@ -93,12 +93,12 @@ bool StmtIteratorBase::HandleDecl(Decl* D) {
}
StmtIteratorBase::StmtIteratorBase(Decl** dgi, Decl** dge)
- : stmt(0), DGI(dgi), RawVAPtr(DeclGroupMode), DGE(dge) {
+ : stmt(nullptr), DGI(dgi), RawVAPtr(DeclGroupMode), DGE(dge) {
NextDecl(false);
}
StmtIteratorBase::StmtIteratorBase(const VariableArrayType* t)
- : stmt(0), DGI(0), RawVAPtr(SizeOfTypeVAMode) {
+ : stmt(nullptr), DGI(nullptr), RawVAPtr(SizeOfTypeVAMode) {
RawVAPtr |= reinterpret_cast<uintptr_t>(t);
}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index ae2cdf757461..1fdad9f4272c 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -70,6 +70,7 @@ namespace {
void PrintCallArgs(CallExpr *E);
void PrintRawSEHExceptHandler(SEHExceptStmt *S);
void PrintRawSEHFinallyStmt(SEHFinallyStmt *S);
+ void PrintOMPExecutableDirective(OMPExecutableDirective *S);
void PrintExpr(Expr *E) {
if (E)
@@ -89,7 +90,7 @@ namespace {
return;
else StmtVisitor<StmtPrinter>::Visit(S);
}
-
+
void VisitStmt(Stmt *Node) LLVM_ATTRIBUTE_UNUSED {
Indent() << "<<unknown stmt type>>\n";
}
@@ -113,9 +114,8 @@ namespace {
/// with no newline after the }.
void StmtPrinter::PrintRawCompoundStmt(CompoundStmt *Node) {
OS << "{\n";
- for (CompoundStmt::body_iterator I = Node->body_begin(), E = Node->body_end();
- I != E; ++I)
- PrintStmt(*I);
+ for (auto *I : Node->body())
+ PrintStmt(I);
Indent() << "}";
}
@@ -125,11 +125,7 @@ void StmtPrinter::PrintRawDecl(Decl *D) {
}
void StmtPrinter::PrintRawDeclStmt(const DeclStmt *S) {
- DeclStmt::const_decl_iterator Begin = S->decl_begin(), End = S->decl_end();
- SmallVector<Decl*, 2> Decls;
- for ( ; Begin != End; ++Begin)
- Decls.push_back(*Begin);
-
+ SmallVector<Decl*, 2> Decls(S->decls());
Decl::printGroup(Decls.data(), Decls.size(), OS, Policy, IndentLevel);
}
@@ -172,19 +168,10 @@ void StmtPrinter::VisitLabelStmt(LabelStmt *Node) {
}
void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) {
- OS << "[[";
- bool first = true;
- for (ArrayRef<const Attr*>::iterator it = Node->getAttrs().begin(),
- end = Node->getAttrs().end();
- it != end; ++it) {
- if (!first) {
- OS << ", ";
- first = false;
- }
- // TODO: check this
- (*it)->printPretty(OS, Policy);
+ for (const auto *Attr : Node->getAttrs()) {
+ Attr->printPretty(OS, Policy);
}
- OS << "]] ";
+
PrintStmt(Node->getSubStmt(), 0);
}
@@ -330,7 +317,8 @@ void StmtPrinter::VisitCXXForRangeStmt(CXXForRangeStmt *Node) {
PrintExpr(Node->getRangeInit());
OS << ") {\n";
PrintStmt(Node->getBody());
- Indent() << "}\n";
+ Indent() << "}";
+ if (Policy.IncludeNewlines) OS << "\n";
}
void StmtPrinter::VisitMSDependentExistsStmt(MSDependentExistsStmt *Node) {
@@ -350,21 +338,25 @@ void StmtPrinter::VisitMSDependentExistsStmt(MSDependentExistsStmt *Node) {
}
void StmtPrinter::VisitGotoStmt(GotoStmt *Node) {
- Indent() << "goto " << Node->getLabel()->getName() << ";\n";
+ Indent() << "goto " << Node->getLabel()->getName() << ";";
+ if (Policy.IncludeNewlines) OS << "\n";
}
void StmtPrinter::VisitIndirectGotoStmt(IndirectGotoStmt *Node) {
Indent() << "goto *";
PrintExpr(Node->getTarget());
- OS << ";\n";
+ OS << ";";
+ if (Policy.IncludeNewlines) OS << "\n";
}
void StmtPrinter::VisitContinueStmt(ContinueStmt *Node) {
- Indent() << "continue;\n";
+ Indent() << "continue;";
+ if (Policy.IncludeNewlines) OS << "\n";
}
void StmtPrinter::VisitBreakStmt(BreakStmt *Node) {
- Indent() << "break;\n";
+ Indent() << "break;";
+ if (Policy.IncludeNewlines) OS << "\n";
}
@@ -374,7 +366,8 @@ void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) {
OS << " ";
PrintExpr(Node->getRetValue());
}
- OS << ";\n";
+ OS << ";";
+ if (Policy.IncludeNewlines) OS << "\n";
}
@@ -437,7 +430,8 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) {
VisitStringLiteral(Node->getClobberStringLiteral(i));
}
- OS << ");\n";
+ OS << ");";
+ if (Policy.IncludeNewlines) OS << "\n";
}
void StmtPrinter::VisitMSAsmStmt(MSAsmStmt *Node) {
@@ -579,6 +573,11 @@ void StmtPrinter::VisitSEHFinallyStmt(SEHFinallyStmt *Node) {
OS << "\n";
}
+void StmtPrinter::VisitSEHLeaveStmt(SEHLeaveStmt *Node) {
+ Indent() << "__leave;";
+ if (Policy.IncludeNewlines) OS << "\n";
+}
+
//===----------------------------------------------------------------------===//
// OpenMP clauses printing methods
//===----------------------------------------------------------------------===//
@@ -586,29 +585,100 @@ void StmtPrinter::VisitSEHFinallyStmt(SEHFinallyStmt *Node) {
namespace {
class OMPClausePrinter : public OMPClauseVisitor<OMPClausePrinter> {
raw_ostream &OS;
+ const PrintingPolicy &Policy;
/// \brief Process clauses with list of variables.
template <typename T>
void VisitOMPClauseList(T *Node, char StartSym);
public:
- OMPClausePrinter(raw_ostream &OS) : OS(OS) { }
+ OMPClausePrinter(raw_ostream &OS, const PrintingPolicy &Policy)
+ : OS(OS), Policy(Policy) { }
#define OPENMP_CLAUSE(Name, Class) \
void Visit##Class(Class *S);
#include "clang/Basic/OpenMPKinds.def"
};
+void OMPClausePrinter::VisitOMPIfClause(OMPIfClause *Node) {
+ OS << "if(";
+ Node->getCondition()->printPretty(OS, nullptr, Policy, 0);
+ OS << ")";
+}
+
+void OMPClausePrinter::VisitOMPFinalClause(OMPFinalClause *Node) {
+ OS << "final(";
+ Node->getCondition()->printPretty(OS, nullptr, Policy, 0);
+ OS << ")";
+}
+
+void OMPClausePrinter::VisitOMPNumThreadsClause(OMPNumThreadsClause *Node) {
+ OS << "num_threads(";
+ Node->getNumThreads()->printPretty(OS, nullptr, Policy, 0);
+ OS << ")";
+}
+
+void OMPClausePrinter::VisitOMPSafelenClause(OMPSafelenClause *Node) {
+ OS << "safelen(";
+ Node->getSafelen()->printPretty(OS, nullptr, Policy, 0);
+ OS << ")";
+}
+
+void OMPClausePrinter::VisitOMPCollapseClause(OMPCollapseClause *Node) {
+ OS << "collapse(";
+ Node->getNumForLoops()->printPretty(OS, nullptr, Policy, 0);
+ OS << ")";
+}
+
void OMPClausePrinter::VisitOMPDefaultClause(OMPDefaultClause *Node) {
OS << "default("
<< getOpenMPSimpleClauseTypeName(OMPC_default, Node->getDefaultKind())
<< ")";
}
+void OMPClausePrinter::VisitOMPProcBindClause(OMPProcBindClause *Node) {
+ OS << "proc_bind("
+ << getOpenMPSimpleClauseTypeName(OMPC_proc_bind, Node->getProcBindKind())
+ << ")";
+}
+
+void OMPClausePrinter::VisitOMPScheduleClause(OMPScheduleClause *Node) {
+ OS << "schedule("
+ << getOpenMPSimpleClauseTypeName(OMPC_schedule, Node->getScheduleKind());
+ if (Node->getChunkSize()) {
+ OS << ", ";
+ Node->getChunkSize()->printPretty(OS, nullptr, Policy);
+ }
+ OS << ")";
+}
+
+void OMPClausePrinter::VisitOMPOrderedClause(OMPOrderedClause *) {
+ OS << "ordered";
+}
+
+void OMPClausePrinter::VisitOMPNowaitClause(OMPNowaitClause *) {
+ OS << "nowait";
+}
+
+void OMPClausePrinter::VisitOMPUntiedClause(OMPUntiedClause *) {
+ OS << "untied";
+}
+
+void OMPClausePrinter::VisitOMPMergeableClause(OMPMergeableClause *) {
+ OS << "mergeable";
+}
+
template<typename T>
void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) {
for (typename T::varlist_iterator I = Node->varlist_begin(),
E = Node->varlist_end();
- I != E; ++I)
- OS << (I == Node->varlist_begin() ? StartSym : ',')
- << *cast<NamedDecl>(cast<DeclRefExpr>(*I)->getDecl());
+ I != E; ++I) {
+ assert(*I && "Expected non-null Stmt");
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(*I)) {
+ OS << (I == Node->varlist_begin() ? StartSym : ',');
+ cast<NamedDecl>(DRE->getDecl())->printQualifiedName(OS);
+ } else {
+ OS << (I == Node->varlist_begin() ? StartSym : ',');
+ (*I)->printPretty(OS, nullptr, Policy, 0);
+ }
+ }
}
void OMPClausePrinter::VisitOMPPrivateClause(OMPPrivateClause *Node) {
@@ -627,6 +697,14 @@ void OMPClausePrinter::VisitOMPFirstprivateClause(OMPFirstprivateClause *Node) {
}
}
+void OMPClausePrinter::VisitOMPLastprivateClause(OMPLastprivateClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "lastprivate";
+ VisitOMPClauseList(Node, '(');
+ OS << ")";
+ }
+}
+
void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) {
if (!Node->varlist_empty()) {
OS << "shared";
@@ -635,17 +713,83 @@ void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) {
}
}
+void OMPClausePrinter::VisitOMPReductionClause(OMPReductionClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "reduction(";
+ NestedNameSpecifier *QualifierLoc =
+ Node->getQualifierLoc().getNestedNameSpecifier();
+ OverloadedOperatorKind OOK =
+ Node->getNameInfo().getName().getCXXOverloadedOperator();
+ if (QualifierLoc == nullptr && OOK != OO_None) {
+ // Print reduction identifier in C format
+ OS << getOperatorSpelling(OOK);
+ } else {
+ // Use C++ format
+ if (QualifierLoc != nullptr)
+ QualifierLoc->print(OS, Policy);
+ OS << Node->getNameInfo();
+ }
+ OS << ":";
+ VisitOMPClauseList(Node, ' ');
+ OS << ")";
+ }
+}
+
+void OMPClausePrinter::VisitOMPLinearClause(OMPLinearClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "linear";
+ VisitOMPClauseList(Node, '(');
+ if (Node->getStep() != nullptr) {
+ OS << ": ";
+ Node->getStep()->printPretty(OS, nullptr, Policy, 0);
+ }
+ OS << ")";
+ }
+}
+
+void OMPClausePrinter::VisitOMPAlignedClause(OMPAlignedClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "aligned";
+ VisitOMPClauseList(Node, '(');
+ if (Node->getAlignment() != nullptr) {
+ OS << ": ";
+ Node->getAlignment()->printPretty(OS, nullptr, Policy, 0);
+ }
+ OS << ")";
+ }
+}
+
+void OMPClausePrinter::VisitOMPCopyinClause(OMPCopyinClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "copyin";
+ VisitOMPClauseList(Node, '(');
+ OS << ")";
+ }
+}
+
+void OMPClausePrinter::VisitOMPCopyprivateClause(OMPCopyprivateClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "copyprivate";
+ VisitOMPClauseList(Node, '(');
+ OS << ")";
+ }
+}
+
+void OMPClausePrinter::VisitOMPFlushClause(OMPFlushClause *Node) {
+ if (!Node->varlist_empty()) {
+ VisitOMPClauseList(Node, '(');
+ OS << ")";
+ }
+}
}
//===----------------------------------------------------------------------===//
// OpenMP directives printing methods
//===----------------------------------------------------------------------===//
-void StmtPrinter::VisitOMPParallelDirective(OMPParallelDirective *Node) {
- Indent() << "#pragma omp parallel ";
-
- OMPClausePrinter Printer(OS);
- ArrayRef<OMPClause *> Clauses = Node->clauses();
+void StmtPrinter::PrintOMPExecutableDirective(OMPExecutableDirective *S) {
+ OMPClausePrinter Printer(OS, Policy);
+ ArrayRef<OMPClause *> Clauses = S->clauses();
for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end();
I != E; ++I)
if (*I && !(*I)->isImplicit()) {
@@ -653,13 +797,95 @@ void StmtPrinter::VisitOMPParallelDirective(OMPParallelDirective *Node) {
OS << ' ';
}
OS << "\n";
- if (Node->getAssociatedStmt()) {
- assert(isa<CapturedStmt>(Node->getAssociatedStmt()) &&
+ if (S->hasAssociatedStmt() && S->getAssociatedStmt()) {
+ assert(isa<CapturedStmt>(S->getAssociatedStmt()) &&
"Expected captured statement!");
- Stmt *CS = cast<CapturedStmt>(Node->getAssociatedStmt())->getCapturedStmt();
+ Stmt *CS = cast<CapturedStmt>(S->getAssociatedStmt())->getCapturedStmt();
PrintStmt(CS);
}
}
+
+void StmtPrinter::VisitOMPParallelDirective(OMPParallelDirective *Node) {
+ Indent() << "#pragma omp parallel ";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPSimdDirective(OMPSimdDirective *Node) {
+ Indent() << "#pragma omp simd ";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPForDirective(OMPForDirective *Node) {
+ Indent() << "#pragma omp for ";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPSectionsDirective(OMPSectionsDirective *Node) {
+ Indent() << "#pragma omp sections ";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPSectionDirective(OMPSectionDirective *Node) {
+ Indent() << "#pragma omp section";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPSingleDirective(OMPSingleDirective *Node) {
+ Indent() << "#pragma omp single ";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPMasterDirective(OMPMasterDirective *Node) {
+ Indent() << "#pragma omp master";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPCriticalDirective(OMPCriticalDirective *Node) {
+ Indent() << "#pragma omp critical";
+ if (Node->getDirectiveName().getName()) {
+ OS << " (";
+ Node->getDirectiveName().printName(OS);
+ OS << ")";
+ }
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPParallelForDirective(OMPParallelForDirective *Node) {
+ Indent() << "#pragma omp parallel for ";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPParallelSectionsDirective(
+ OMPParallelSectionsDirective *Node) {
+ Indent() << "#pragma omp parallel sections ";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPTaskDirective(OMPTaskDirective *Node) {
+ Indent() << "#pragma omp task ";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPTaskyieldDirective(OMPTaskyieldDirective *Node) {
+ Indent() << "#pragma omp taskyield";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPBarrierDirective(OMPBarrierDirective *Node) {
+ Indent() << "#pragma omp barrier";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *Node) {
+ Indent() << "#pragma omp taskwait";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPFlushDirective(OMPFlushDirective *Node) {
+ Indent() << "#pragma omp flush ";
+ PrintOMPExecutableDirective(Node);
+}
+
//===----------------------------------------------------------------------===//
// Expr printing methods.
//===----------------------------------------------------------------------===//
@@ -717,7 +943,7 @@ void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
}
if (Node->isImplicitProperty())
- OS << Node->getImplicitPropertyGetter()->getSelector().getAsString();
+ Node->getImplicitPropertyGetter()->getSelector().print(OS);
else
OS << Node->getExplicitProperty()->getName();
}
@@ -743,6 +969,9 @@ void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
case PredefinedExpr::FuncDName:
OS << "__FUNCDNAME__";
break;
+ case PredefinedExpr::FuncSig:
+ OS << "__FUNCSIG__";
+ break;
case PredefinedExpr::LFunction:
OS << "L__FUNCTION__";
break;
@@ -814,11 +1043,10 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
// Emit suffixes. Integer literals are always a builtin integer type.
switch (Node->getType()->getAs<BuiltinType>()->getKind()) {
default: llvm_unreachable("Unexpected type for integer literal!");
- // FIXME: The Short and UShort cases are to handle cases where a short
- // integeral literal is formed during template instantiation. They should
- // be removed when template instantiation no longer needs integer literals.
- case BuiltinType::Short:
- case BuiltinType::UShort:
+ case BuiltinType::SChar: OS << "i8"; break;
+ case BuiltinType::UChar: OS << "Ui8"; break;
+ case BuiltinType::Short: OS << "i16"; break;
+ case BuiltinType::UShort: OS << "Ui16"; break;
case BuiltinType::Int: break; // no suffix.
case BuiltinType::UInt: OS << 'U'; break;
case BuiltinType::Long: OS << 'L'; break;
@@ -1002,7 +1230,7 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
MemberExpr *ParentMember = dyn_cast<MemberExpr>(Node->getBase());
FieldDecl *ParentDecl = ParentMember
- ? dyn_cast<FieldDecl>(ParentMember->getMemberDecl()) : NULL;
+ ? dyn_cast<FieldDecl>(ParentMember->getMemberDecl()) : nullptr;
if (!ParentDecl || !ParentDecl->isAnonymousStructOrUnion())
OS << (Node->isArrow() ? "->" : ".");
@@ -1043,7 +1271,7 @@ void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) {
PrintExpr(Node->getInitializer());
}
void StmtPrinter::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
- // No need to print anything, simply forward to the sub expression.
+ // No need to print anything, simply forward to the subexpression.
PrintExpr(Node->getSubExpr());
}
void StmtPrinter::VisitBinaryOperator(BinaryOperator *Node) {
@@ -1144,10 +1372,12 @@ void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) {
DEnd = Node->designators_end();
D != DEnd; ++D) {
if (D->isFieldDesignator()) {
- if (D->getDotLoc().isInvalid())
- OS << D->getFieldName()->getName() << ":";
- else
+ if (D->getDotLoc().isInvalid()) {
+ if (IdentifierInfo *II = D->getFieldName())
+ OS << II->getName() << ":";
+ } else {
OS << "." << D->getFieldName()->getName();
+ }
} else {
OS << "[";
if (D->isArrayDesignator()) {
@@ -1194,7 +1424,7 @@ void StmtPrinter::VisitPseudoObjectExpr(PseudoObjectExpr *Node) {
}
void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) {
- const char *Name = 0;
+ const char *Name = nullptr;
switch (Node->getOp()) {
#define BUILTIN(ID, TYPE, ATTRS)
#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \
@@ -1281,6 +1511,12 @@ void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) {
}
void StmtPrinter::VisitCXXMemberCallExpr(CXXMemberCallExpr *Node) {
+ // If we have a conversion operator call only print the argument.
+ CXXMethodDecl *MD = Node->getMethodDecl();
+ if (MD && isa<CXXConversionDecl>(MD)) {
+ PrintExpr(Node->getImplicitObjectArgument());
+ return;
+ }
VisitCallExpr(cast<CallExpr>(Node));
}
@@ -1360,9 +1596,8 @@ void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) {
cast<FunctionDecl>(DRE->getDecl())->getTemplateSpecializationArgs();
assert(Args);
const TemplateArgument &Pack = Args->get(0);
- for (TemplateArgument::pack_iterator I = Pack.pack_begin(),
- E = Pack.pack_end(); I != E; ++I) {
- char C = (char)I->getAsIntegral().getZExtValue();
+ for (const auto &P : Pack.pack_elements()) {
+ char C = (char)P.getAsIntegral().getZExtValue();
OS << C;
}
break;
@@ -1400,7 +1635,7 @@ void StmtPrinter::VisitCXXThisExpr(CXXThisExpr *Node) {
}
void StmtPrinter::VisitCXXThrowExpr(CXXThrowExpr *Node) {
- if (Node->getSubExpr() == 0)
+ if (!Node->getSubExpr())
OS << "throw";
else {
OS << "throw ";
@@ -1492,16 +1727,14 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
OS << " (";
CXXMethodDecl *Method = Node->getCallOperator();
NeedComma = false;
- for (CXXMethodDecl::param_iterator P = Method->param_begin(),
- PEnd = Method->param_end();
- P != PEnd; ++P) {
+ for (auto P : Method->params()) {
if (NeedComma) {
OS << ", ";
} else {
NeedComma = true;
}
- std::string ParamStr = (*P)->getNameAsString();
- (*P)->getOriginalType().print(OS, Policy, ParamStr);
+ std::string ParamStr = P->getNameAsString();
+ P->getOriginalType().print(OS, Policy, ParamStr);
}
if (Method->isVariadic()) {
if (NeedComma)
@@ -1522,7 +1755,7 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
// Print the trailing return type if it was specified in the source.
if (Node->hasExplicitResultType()) {
OS << " -> ";
- Proto->getResultType().print(OS, Policy);
+ Proto->getReturnType().print(OS, Policy);
}
}
@@ -1627,7 +1860,7 @@ void StmtPrinter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
}
void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) {
- // Just forward to the sub expression.
+ // Just forward to the subexpression.
PrintExpr(E->getSubExpr());
}
@@ -1677,74 +1910,15 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
-static const char *getTypeTraitName(UnaryTypeTrait UTT) {
- switch (UTT) {
- case UTT_HasNothrowAssign: return "__has_nothrow_assign";
- case UTT_HasNothrowMoveAssign: return "__has_nothrow_move_assign";
- case UTT_HasNothrowConstructor: return "__has_nothrow_constructor";
- case UTT_HasNothrowCopy: return "__has_nothrow_copy";
- case UTT_HasTrivialAssign: return "__has_trivial_assign";
- case UTT_HasTrivialMoveAssign: return "__has_trivial_move_assign";
- case UTT_HasTrivialMoveConstructor: return "__has_trivial_move_constructor";
- case UTT_HasTrivialDefaultConstructor: return "__has_trivial_constructor";
- case UTT_HasTrivialCopy: return "__has_trivial_copy";
- case UTT_HasTrivialDestructor: return "__has_trivial_destructor";
- case UTT_HasVirtualDestructor: return "__has_virtual_destructor";
- case UTT_IsAbstract: return "__is_abstract";
- case UTT_IsArithmetic: return "__is_arithmetic";
- case UTT_IsArray: return "__is_array";
- case UTT_IsClass: return "__is_class";
- case UTT_IsCompleteType: return "__is_complete_type";
- case UTT_IsCompound: return "__is_compound";
- case UTT_IsConst: return "__is_const";
- case UTT_IsEmpty: return "__is_empty";
- case UTT_IsEnum: return "__is_enum";
- case UTT_IsFinal: return "__is_final";
- case UTT_IsFloatingPoint: return "__is_floating_point";
- case UTT_IsFunction: return "__is_function";
- case UTT_IsFundamental: return "__is_fundamental";
- case UTT_IsIntegral: return "__is_integral";
- case UTT_IsInterfaceClass: return "__is_interface_class";
- case UTT_IsLiteral: return "__is_literal";
- case UTT_IsLvalueReference: return "__is_lvalue_reference";
- case UTT_IsMemberFunctionPointer: return "__is_member_function_pointer";
- case UTT_IsMemberObjectPointer: return "__is_member_object_pointer";
- case UTT_IsMemberPointer: return "__is_member_pointer";
- case UTT_IsObject: return "__is_object";
- case UTT_IsPOD: return "__is_pod";
- case UTT_IsPointer: return "__is_pointer";
- case UTT_IsPolymorphic: return "__is_polymorphic";
- case UTT_IsReference: return "__is_reference";
- case UTT_IsRvalueReference: return "__is_rvalue_reference";
- case UTT_IsScalar: return "__is_scalar";
- case UTT_IsSealed: return "__is_sealed";
- case UTT_IsSigned: return "__is_signed";
- case UTT_IsStandardLayout: return "__is_standard_layout";
- case UTT_IsTrivial: return "__is_trivial";
- case UTT_IsTriviallyCopyable: return "__is_trivially_copyable";
- case UTT_IsUnion: return "__is_union";
- case UTT_IsUnsigned: return "__is_unsigned";
- case UTT_IsVoid: return "__is_void";
- case UTT_IsVolatile: return "__is_volatile";
- }
- llvm_unreachable("Type trait not covered by switch statement");
-}
-
-static const char *getTypeTraitName(BinaryTypeTrait BTT) {
- switch (BTT) {
- case BTT_IsBaseOf: return "__is_base_of";
- case BTT_IsConvertible: return "__is_convertible";
- case BTT_IsSame: return "__is_same";
- case BTT_TypeCompatible: return "__builtin_types_compatible_p";
- case BTT_IsConvertibleTo: return "__is_convertible_to";
- case BTT_IsTriviallyAssignable: return "__is_trivially_assignable";
- }
- llvm_unreachable("Binary type trait not covered by switch");
-}
-
static const char *getTypeTraitName(TypeTrait TT) {
switch (TT) {
- case clang::TT_IsTriviallyConstructible:return "__is_trivially_constructible";
+#define TYPE_TRAIT_1(Spelling, Name, Key) \
+case clang::UTT_##Name: return #Spelling;
+#define TYPE_TRAIT_2(Spelling, Name, Key) \
+case clang::BTT_##Name: return #Spelling;
+#define TYPE_TRAIT_N(Spelling, Name, Key) \
+ case clang::TT_##Name: return #Spelling;
+#include "clang/Basic/TokenKinds.def"
}
llvm_unreachable("Type trait not covered by switch");
}
@@ -1765,20 +1939,6 @@ static const char *getExpressionTraitName(ExpressionTrait ET) {
llvm_unreachable("Expression type trait not covered by switch");
}
-void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
- OS << getTypeTraitName(E->getTrait()) << '(';
- E->getQueriedType().print(OS, Policy);
- OS << ')';
-}
-
-void StmtPrinter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
- OS << getTypeTraitName(E->getTrait()) << '(';
- E->getLhsType().print(OS, Policy);
- OS << ',';
- E->getRhsType().print(OS, Policy);
- OS << ')';
-}
-
void StmtPrinter::VisitTypeTraitExpr(TypeTraitExpr *E) {
OS << getTypeTraitName(E->getTrait()) << "(";
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
@@ -1883,7 +2043,9 @@ void StmtPrinter::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
}
void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
- OS << "@selector(" << Node->getSelector().getAsString() << ')';
+ OS << "@selector(";
+ Node->getSelector().print(OS);
+ OS << ')';
}
void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
@@ -1989,18 +2151,13 @@ void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) {
//===----------------------------------------------------------------------===//
void Stmt::dumpPretty(const ASTContext &Context) const {
- printPretty(llvm::errs(), 0, PrintingPolicy(Context.getLangOpts()));
+ printPretty(llvm::errs(), nullptr, PrintingPolicy(Context.getLangOpts()));
}
void Stmt::printPretty(raw_ostream &OS,
PrinterHelper *Helper,
const PrintingPolicy &Policy,
unsigned Indentation) const {
- if (this == 0) {
- OS << "<NULL>";
- return;
- }
-
StmtPrinter P(OS, Helper, Policy, Indentation);
P.Visit(const_cast<Stmt*>(this));
}
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 6805e62befb0..f44f25c96aba 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -79,9 +79,8 @@ void StmtProfiler::VisitStmt(const Stmt *S) {
void StmtProfiler::VisitDeclStmt(const DeclStmt *S) {
VisitStmt(S);
- for (DeclStmt::const_decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
- D != DEnd; ++D)
- VisitDecl(*D);
+ for (const auto *D : S->decls())
+ VisitDecl(D);
}
void StmtProfiler::VisitNullStmt(const NullStmt *S) {
@@ -215,6 +214,10 @@ void StmtProfiler::VisitSEHExceptStmt(const SEHExceptStmt *S) {
VisitStmt(S);
}
+void StmtProfiler::VisitSEHLeaveStmt(const SEHLeaveStmt *S) {
+ VisitStmt(S);
+}
+
void StmtProfiler::VisitCapturedStmt(const CapturedStmt *S) {
VisitStmt(S);
}
@@ -265,14 +268,52 @@ public:
#include "clang/Basic/OpenMPKinds.def"
};
+void OMPClauseProfiler::VisitOMPIfClause(const OMPIfClause *C) {
+ if (C->getCondition())
+ Profiler->VisitStmt(C->getCondition());
+}
+
+void OMPClauseProfiler::VisitOMPFinalClause(const OMPFinalClause *C) {
+ if (C->getCondition())
+ Profiler->VisitStmt(C->getCondition());
+}
+
+void OMPClauseProfiler::VisitOMPNumThreadsClause(const OMPNumThreadsClause *C) {
+ if (C->getNumThreads())
+ Profiler->VisitStmt(C->getNumThreads());
+}
+
+void OMPClauseProfiler::VisitOMPSafelenClause(const OMPSafelenClause *C) {
+ if (C->getSafelen())
+ Profiler->VisitStmt(C->getSafelen());
+}
+
+void OMPClauseProfiler::VisitOMPCollapseClause(const OMPCollapseClause *C) {
+ if (C->getNumForLoops())
+ Profiler->VisitStmt(C->getNumForLoops());
+}
+
void OMPClauseProfiler::VisitOMPDefaultClause(const OMPDefaultClause *C) { }
+void OMPClauseProfiler::VisitOMPProcBindClause(const OMPProcBindClause *C) { }
+
+void OMPClauseProfiler::VisitOMPScheduleClause(const OMPScheduleClause *C) {
+ if (C->getChunkSize())
+ Profiler->VisitStmt(C->getChunkSize());
+}
+
+void OMPClauseProfiler::VisitOMPOrderedClause(const OMPOrderedClause *) {}
+
+void OMPClauseProfiler::VisitOMPNowaitClause(const OMPNowaitClause *) {}
+
+void OMPClauseProfiler::VisitOMPUntiedClause(const OMPUntiedClause *) {}
+
+void OMPClauseProfiler::VisitOMPMergeableClause(const OMPMergeableClause *) {}
+
template<typename T>
void OMPClauseProfiler::VisitOMPClauseList(T *Node) {
- for (typename T::varlist_const_iterator I = Node->varlist_begin(),
- E = Node->varlist_end();
- I != E; ++I)
- Profiler->VisitStmt(*I);
+ for (auto *I : Node->varlists())
+ Profiler->VisitStmt(I);
}
void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) {
@@ -282,13 +323,42 @@ void OMPClauseProfiler::VisitOMPFirstprivateClause(
const OMPFirstprivateClause *C) {
VisitOMPClauseList(C);
}
+void
+OMPClauseProfiler::VisitOMPLastprivateClause(const OMPLastprivateClause *C) {
+ VisitOMPClauseList(C);
+}
void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) {
VisitOMPClauseList(C);
}
+void OMPClauseProfiler::VisitOMPReductionClause(
+ const OMPReductionClause *C) {
+ Profiler->VisitNestedNameSpecifier(
+ C->getQualifierLoc().getNestedNameSpecifier());
+ Profiler->VisitName(C->getNameInfo().getName());
+ VisitOMPClauseList(C);
+}
+void OMPClauseProfiler::VisitOMPLinearClause(const OMPLinearClause *C) {
+ VisitOMPClauseList(C);
+ Profiler->VisitStmt(C->getStep());
+}
+void OMPClauseProfiler::VisitOMPAlignedClause(const OMPAlignedClause *C) {
+ VisitOMPClauseList(C);
+ Profiler->VisitStmt(C->getAlignment());
+}
+void OMPClauseProfiler::VisitOMPCopyinClause(const OMPCopyinClause *C) {
+ VisitOMPClauseList(C);
+}
+void
+OMPClauseProfiler::VisitOMPCopyprivateClause(const OMPCopyprivateClause *C) {
+ VisitOMPClauseList(C);
+}
+void OMPClauseProfiler::VisitOMPFlushClause(const OMPFlushClause *C) {
+ VisitOMPClauseList(C);
+}
}
void
-StmtProfiler::VisitOMPParallelDirective(const OMPParallelDirective *S) {
+StmtProfiler::VisitOMPExecutableDirective(const OMPExecutableDirective *S) {
VisitStmt(S);
OMPClauseProfiler P(this);
ArrayRef<OMPClause *> Clauses = S->clauses();
@@ -298,6 +368,69 @@ StmtProfiler::VisitOMPParallelDirective(const OMPParallelDirective *S) {
P.Visit(*I);
}
+void StmtProfiler::VisitOMPParallelDirective(const OMPParallelDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
+void StmtProfiler::VisitOMPSimdDirective(const OMPSimdDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
+void StmtProfiler::VisitOMPForDirective(const OMPForDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
+void StmtProfiler::VisitOMPSectionsDirective(const OMPSectionsDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
+void StmtProfiler::VisitOMPSectionDirective(const OMPSectionDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
+void StmtProfiler::VisitOMPSingleDirective(const OMPSingleDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
+void StmtProfiler::VisitOMPMasterDirective(const OMPMasterDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
+void StmtProfiler::VisitOMPCriticalDirective(const OMPCriticalDirective *S) {
+ VisitOMPExecutableDirective(S);
+ VisitName(S->getDirectiveName().getName());
+}
+
+void
+StmtProfiler::VisitOMPParallelForDirective(const OMPParallelForDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
+void StmtProfiler::VisitOMPParallelSectionsDirective(
+ const OMPParallelSectionsDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
+void StmtProfiler::VisitOMPTaskDirective(const OMPTaskDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
+void StmtProfiler::VisitOMPTaskyieldDirective(const OMPTaskyieldDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
+void StmtProfiler::VisitOMPBarrierDirective(const OMPBarrierDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
+void StmtProfiler::VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
+void StmtProfiler::VisitOMPFlushDirective(const OMPFlushDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
+
void StmtProfiler::VisitExpr(const Expr *S) {
VisitStmt(S);
}
@@ -529,7 +662,7 @@ void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) {
for (unsigned i = 0; i != S->getNumAssocs(); ++i) {
QualType T = S->getAssocType(i);
if (T.isNull())
- ID.AddPointer(0);
+ ID.AddPointer(nullptr);
else
VisitType(T);
VisitExpr(S->getAssocExpr(i));
@@ -585,11 +718,11 @@ static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S,
case OO_Star:
if (S->getNumArgs() == 1) {
- UnaryOp = UO_Minus;
+ UnaryOp = UO_Deref;
return Stmt::UnaryOperatorClass;
}
- BinaryOp = BO_Sub;
+ BinaryOp = BO_Mul;
return Stmt::BinaryOperatorClass;
case OO_Slash:
@@ -734,7 +867,7 @@ static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S,
llvm_unreachable("Invalid overloaded operator expression");
}
-
+
void StmtProfiler::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
if (S->isTypeDependent()) {
@@ -743,7 +876,7 @@ void StmtProfiler::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
UnaryOperatorKind UnaryOp = UO_Extension;
BinaryOperatorKind BinaryOp = BO_Comma;
Stmt::StmtClass SC = DecodeOperatorCall(S, UnaryOp, BinaryOp);
-
+
ID.AddInteger(SC);
for (unsigned I = 0, N = S->getNumArgs(); I != N; ++I)
Visit(S->getArg(I));
@@ -754,10 +887,10 @@ void StmtProfiler::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
ID.AddInteger(BinaryOp);
else
assert(SC == Stmt::ArraySubscriptExprClass);
-
+
return;
}
-
+
VisitCallExpr(S);
ID.AddInteger(S->getOperator());
}
@@ -923,10 +1056,10 @@ StmtProfiler::VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->isArrow());
VisitNestedNameSpecifier(S->getQualifier());
- ID.AddBoolean(S->getScopeTypeInfo() != 0);
+ ID.AddBoolean(S->getScopeTypeInfo() != nullptr);
if (S->getScopeTypeInfo())
VisitType(S->getScopeTypeInfo()->getType());
- ID.AddBoolean(S->getDestroyedTypeInfo() != 0);
+ ID.AddBoolean(S->getDestroyedTypeInfo() != nullptr);
if (S->getDestroyedTypeInfo())
VisitType(S->getDestroyedType());
else
@@ -948,19 +1081,6 @@ StmtProfiler::VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *S) {
VisitOverloadExpr(S);
}
-void StmtProfiler::VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *S) {
- VisitExpr(S);
- ID.AddInteger(S->getTrait());
- VisitType(S->getQueriedType());
-}
-
-void StmtProfiler::VisitBinaryTypeTraitExpr(const BinaryTypeTraitExpr *S) {
- VisitExpr(S);
- ID.AddInteger(S->getTrait());
- VisitType(S->getLhsType());
- VisitType(S->getRhsType());
-}
-
void StmtProfiler::VisitTypeTraitExpr(const TypeTraitExpr *S) {
VisitExpr(S);
ID.AddInteger(S->getTrait());
@@ -1200,7 +1320,7 @@ void StmtProfiler::VisitDecl(const Decl *D) {
}
}
- ID.AddPointer(D? D->getCanonicalDecl() : 0);
+ ID.AddPointer(D? D->getCanonicalDecl() : nullptr);
}
void StmtProfiler::VisitType(QualType T) {
@@ -1268,9 +1388,8 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
break;
case TemplateArgument::Pack:
- const TemplateArgument *Pack = Arg.pack_begin();
- for (unsigned i = 0, e = Arg.pack_size(); i != e; ++i)
- VisitTemplateArgument(Pack[i]);
+ for (const auto &P : Arg.pack_elements())
+ VisitTemplateArgument(P);
break;
}
}
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index 16efb790b68e..ac6a754fe733 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -114,11 +114,9 @@ bool TemplateArgument::isDependent() const {
return (getAsExpr()->isTypeDependent() || getAsExpr()->isValueDependent());
case Pack:
- for (pack_iterator P = pack_begin(), PEnd = pack_end(); P != PEnd; ++P) {
- if (P->isDependent())
+ for (const auto &P : pack_elements())
+ if (P.isDependent())
return true;
- }
-
return false;
}
@@ -155,11 +153,9 @@ bool TemplateArgument::isInstantiationDependent() const {
return getAsExpr()->isInstantiationDependent();
case Pack:
- for (pack_iterator P = pack_begin(), PEnd = pack_end(); P != PEnd; ++P) {
- if (P->isInstantiationDependent())
+ for (const auto &P : pack_elements())
+ if (P.isInstantiationDependent())
return true;
- }
-
return false;
}
@@ -214,8 +210,8 @@ bool TemplateArgument::containsUnexpandedParameterPack() const {
break;
case Pack:
- for (pack_iterator P = pack_begin(), PEnd = pack_end(); P != PEnd; ++P)
- if (P->containsUnexpandedParameterPack())
+ for (const auto &P : pack_elements())
+ if (P.containsUnexpandedParameterPack())
return true;
break;
@@ -248,7 +244,7 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
break;
case Declaration:
- ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : 0);
+ ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : nullptr);
break;
case Template:
@@ -345,7 +341,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
raw_ostream &Out) const {
switch (getKind()) {
case Null:
- Out << "<no value>";
+ Out << "(no value)";
break;
case Type: {
@@ -362,7 +358,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
// FIXME: distinguish between pointer and reference args?
ND->printQualifiedName(Out);
} else {
- Out << "<anonymous>";
+ Out << "(anonymous)";
}
break;
}
@@ -386,20 +382,19 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
}
case Expression:
- getAsExpr()->printPretty(Out, 0, Policy);
+ getAsExpr()->printPretty(Out, nullptr, Policy);
break;
case Pack:
Out << "<";
bool First = true;
- for (TemplateArgument::pack_iterator P = pack_begin(), PEnd = pack_end();
- P != PEnd; ++P) {
+ for (const auto &P : pack_elements()) {
if (First)
First = false;
else
Out << ", ";
- P->print(Policy, Out);
+ P.print(Policy, Out);
}
Out << ">";
break;
@@ -489,7 +484,7 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
LangOptions LangOpts;
LangOpts.CPlusPlus = true;
PrintingPolicy Policy(LangOpts);
- Arg.getAsExpr()->printPretty(OS, 0, Policy);
+ Arg.getAsExpr()->printPretty(OS, nullptr, Policy);
return DB << OS.str();
}
@@ -511,6 +506,8 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
const ASTTemplateArgumentListInfo *
ASTTemplateArgumentListInfo::Create(ASTContext &C,
const TemplateArgumentListInfo &List) {
+ assert(llvm::alignOf<ASTTemplateArgumentListInfo>() >=
+ llvm::alignOf<TemplateArgumentLoc>());
std::size_t size = ASTTemplateArgumentListInfo::sizeFor(List.size());
void *Mem = C.Allocate(size, llvm::alignOf<ASTTemplateArgumentListInfo>());
ASTTemplateArgumentListInfo *TAI = new (Mem) ASTTemplateArgumentListInfo();
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index 8767c635f675..77c8fd5d1e02 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -78,7 +78,7 @@ TemplateDecl *TemplateName::getAsTemplateDecl() const {
if (SubstTemplateTemplateParmStorage *sub = getAsSubstTemplateTemplateParm())
return sub->getReplacement().getAsTemplateDecl();
- return 0;
+ return nullptr;
}
bool TemplateName::isDependent() const {
@@ -121,7 +121,7 @@ bool TemplateName::containsUnexpandedParameterPack() const {
return DTN->getQualifier() &&
DTN->getQualifier()->containsUnexpandedParameterPack();
- return getAsSubstTemplateTemplateParmPack() != 0;
+ return getAsSubstTemplateTemplateParmPack() != nullptr;
}
void
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 7421bae7bf54..167787430294 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -45,7 +45,7 @@ bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const {
const IdentifierInfo* QualType::getBaseTypeIdentifier() const {
const Type* ty = getTypePtr();
- NamedDecl *ND = NULL;
+ NamedDecl *ND = nullptr;
if (ty->isPointerType() || ty->isReferenceType())
return ty->getPointeeType().getBaseTypeIdentifier();
else if (ty->isRecordType())
@@ -60,7 +60,7 @@ const IdentifierInfo* QualType::getBaseTypeIdentifier() const {
if (ND)
return ND->getIdentifier();
- return NULL;
+ return nullptr;
}
bool QualType::isConstant(QualType T, ASTContext &Ctx) {
@@ -202,7 +202,7 @@ const Type *Type::getArrayElementTypeNoTypeQual() const {
// If the canonical form of this type isn't the right kind, reject it.
if (!isa<ArrayType>(CanonicalType))
- return 0;
+ return nullptr;
// If this is a typedef for an array type, strip the typedef off without
// losing all typedef information.
@@ -410,7 +410,7 @@ const ComplexType *Type::getAsComplexIntegerType() const {
if (const ComplexType *Complex = getAs<ComplexType>())
if (Complex->getElementType()->isIntegerType())
return Complex;
- return 0;
+ return nullptr;
}
QualType Type::getPointeeType() const {
@@ -422,6 +422,10 @@ QualType Type::getPointeeType() const {
return BPT->getPointeeType();
if (const ReferenceType *RT = getAs<ReferenceType>())
return RT->getPointeeType();
+ if (const MemberPointerType *MPT = getAs<MemberPointerType>())
+ return MPT->getPointeeType();
+ if (const DecayedType *DT = getAs<DecayedType>())
+ return DT->getPointeeType();
return QualType();
}
@@ -435,13 +439,13 @@ const RecordType *Type::getAsStructureType() const {
// If the canonical form of this type isn't the right kind, reject it.
if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) {
if (!RT->getDecl()->isStruct())
- return 0;
+ return nullptr;
// If this is a typedef for a structure type, strip the typedef off without
// losing all typedef information.
return cast<RecordType>(getUnqualifiedDesugaredType());
}
- return 0;
+ return nullptr;
}
const RecordType *Type::getAsUnionType() const {
@@ -454,14 +458,14 @@ const RecordType *Type::getAsUnionType() const {
// If the canonical form of this type isn't the right kind, reject it.
if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) {
if (!RT->getDecl()->isUnion())
- return 0;
+ return nullptr;
// If this is a typedef for a union type, strip the typedef off without
// losing all typedef information.
return cast<RecordType>(getUnqualifiedDesugaredType());
}
- return 0;
+ return nullptr;
}
ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
@@ -485,11 +489,11 @@ const ObjCObjectType *Type::getAsObjCQualifiedInterfaceType() const {
if (const ObjCObjectType *T = getAs<ObjCObjectType>())
if (T->getNumProtocols() && T->getInterface())
return T;
- return 0;
+ return nullptr;
}
bool Type::isObjCQualifiedInterfaceType() const {
- return getAsObjCQualifiedInterfaceType() != 0;
+ return getAsObjCQualifiedInterfaceType() != nullptr;
}
const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const {
@@ -499,7 +503,7 @@ const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const {
if (OPT->isObjCQualifiedIdType())
return OPT;
}
- return 0;
+ return nullptr;
}
const ObjCObjectPointerType *Type::getAsObjCQualifiedClassType() const {
@@ -509,7 +513,7 @@ const ObjCObjectPointerType *Type::getAsObjCQualifiedClassType() const {
if (OPT->isObjCQualifiedClassType())
return OPT;
}
- return 0;
+ return nullptr;
}
const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const {
@@ -517,7 +521,7 @@ const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const {
if (OPT->getInterfaceType())
return OPT;
}
- return 0;
+ return nullptr;
}
const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const {
@@ -527,12 +531,12 @@ const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const {
else if (const ReferenceType *RT = getAs<ReferenceType>())
PointeeType = RT->getPointeeType();
else
- return 0;
+ return nullptr;
if (const RecordType *RT = PointeeType->getAs<RecordType>())
return dyn_cast<CXXRecordDecl>(RT->getDecl());
- return 0;
+ return nullptr;
}
CXXRecordDecl *Type::getAsCXXRecordDecl() const {
@@ -541,8 +545,8 @@ CXXRecordDecl *Type::getAsCXXRecordDecl() const {
else if (const InjectedClassNameType *Injected
= getAs<InjectedClassNameType>())
return Injected->getDecl();
-
- return 0;
+
+ return nullptr;
}
namespace {
@@ -552,7 +556,7 @@ namespace {
using TypeVisitor<GetContainedAutoVisitor, AutoType*>::Visit;
AutoType *Visit(QualType T) {
if (T.isNull())
- return 0;
+ return nullptr;
return Visit(T.getTypePtr());
}
@@ -585,7 +589,7 @@ namespace {
return Visit(T->getElementType());
}
AutoType *VisitFunctionType(const FunctionType *T) {
- return Visit(T->getResultType());
+ return Visit(T->getReturnType());
}
AutoType *VisitParenType(const ParenType *T) {
return Visit(T->getInnerType());
@@ -593,6 +597,9 @@ namespace {
AutoType *VisitAttributedType(const AttributedType *T) {
return Visit(T->getModifiedType());
}
+ AutoType *VisitAdjustedType(const AdjustedType *T) {
+ return Visit(T->getOriginalType());
+ }
};
}
@@ -688,7 +695,7 @@ bool Type::isChar32Type() const {
/// types.
bool Type::isAnyCharacterType() const {
const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType);
- if (BT == 0) return false;
+ if (!BT) return false;
switch (BT->getKind()) {
default: return false;
case BuiltinType::Char_U:
@@ -894,8 +901,8 @@ bool Type::isConstantSizeType() const {
/// determine its size.
bool Type::isIncompleteType(NamedDecl **Def) const {
if (Def)
- *Def = 0;
-
+ *Def = nullptr;
+
switch (CanonicalType->getTypeClass()) {
default: return false;
case Builtin:
@@ -1424,8 +1431,7 @@ TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) {
llvm_unreachable("Unknown elaborated type keyword.");
}
-const char*
-TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) {
+StringRef TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) {
switch (Keyword) {
case ETK_None: return "";
case ETK_Typename: return "typename";
@@ -1516,7 +1522,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
case ULong: return "unsigned long";
case ULongLong: return "unsigned long long";
case UInt128: return "unsigned __int128";
- case Half: return "half";
+ case Half: return Policy.Half ? "half" : "__fp16";
case Float: return "float";
case Double: return "double";
case LongDouble: return "long double";
@@ -1582,41 +1588,38 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
llvm_unreachable("Invalid calling convention.");
}
-FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> args,
+FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
QualType canonical,
const ExtProtoInfo &epi)
- : FunctionType(FunctionProto, result, epi.TypeQuals,
- canonical,
- result->isDependentType(),
- result->isInstantiationDependentType(),
- result->isVariablyModifiedType(),
- result->containsUnexpandedParameterPack(),
- epi.ExtInfo),
- NumArgs(args.size()), NumExceptions(epi.NumExceptions),
- ExceptionSpecType(epi.ExceptionSpecType),
- HasAnyConsumedArgs(epi.ConsumedArguments != 0),
- Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn),
- RefQualifier(epi.RefQualifier)
-{
- assert(NumArgs == args.size() && "function has too many parameters");
+ : FunctionType(FunctionProto, result, epi.TypeQuals, canonical,
+ result->isDependentType(),
+ result->isInstantiationDependentType(),
+ result->isVariablyModifiedType(),
+ result->containsUnexpandedParameterPack(), epi.ExtInfo),
+ NumParams(params.size()), NumExceptions(epi.NumExceptions),
+ ExceptionSpecType(epi.ExceptionSpecType),
+ HasAnyConsumedParams(epi.ConsumedParameters != nullptr),
+ Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn),
+ RefQualifier(epi.RefQualifier) {
+ assert(NumParams == params.size() && "function has too many parameters");
// Fill in the trailing argument array.
QualType *argSlot = reinterpret_cast<QualType*>(this+1);
- for (unsigned i = 0; i != NumArgs; ++i) {
- if (args[i]->isDependentType())
+ for (unsigned i = 0; i != NumParams; ++i) {
+ if (params[i]->isDependentType())
setDependent();
- else if (args[i]->isInstantiationDependentType())
+ else if (params[i]->isInstantiationDependentType())
setInstantiationDependent();
-
- if (args[i]->containsUnexpandedParameterPack())
+
+ if (params[i]->containsUnexpandedParameterPack())
setContainsUnexpandedParameterPack();
- argSlot[i] = args[i];
+ argSlot[i] = params[i];
}
if (getExceptionSpecType() == EST_Dynamic) {
// Fill in the exception array.
- QualType *exnSlot = argSlot + NumArgs;
+ QualType *exnSlot = argSlot + NumParams;
for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) {
if (epi.Exceptions[i]->isDependentType())
setDependent();
@@ -1630,7 +1633,7 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> args,
}
} else if (getExceptionSpecType() == EST_ComputedNoexcept) {
// Store the noexcept expression and context.
- Expr **noexSlot = reinterpret_cast<Expr**>(argSlot + NumArgs);
+ Expr **noexSlot = reinterpret_cast<Expr **>(argSlot + NumParams);
*noexSlot = epi.NoexceptExpr;
if (epi.NoexceptExpr) {
@@ -1643,7 +1646,8 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> args,
} else if (getExceptionSpecType() == EST_Uninstantiated) {
// Store the function decl from which we will resolve our
// exception specification.
- FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + NumArgs);
+ FunctionDecl **slot =
+ reinterpret_cast<FunctionDecl **>(argSlot + NumParams);
slot[0] = epi.ExceptionSpecDecl;
slot[1] = epi.ExceptionSpecTemplate;
// This exception specification doesn't make the type dependent, because
@@ -1651,14 +1655,15 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> args,
} else if (getExceptionSpecType() == EST_Unevaluated) {
// Store the function decl from which we will resolve our
// exception specification.
- FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + NumArgs);
+ FunctionDecl **slot =
+ reinterpret_cast<FunctionDecl **>(argSlot + NumParams);
slot[0] = epi.ExceptionSpecDecl;
}
- if (epi.ConsumedArguments) {
- bool *consumedArgs = const_cast<bool*>(getConsumedArgsBuffer());
- for (unsigned i = 0; i != NumArgs; ++i)
- consumedArgs[i] = epi.ConsumedArguments[i];
+ if (epi.ConsumedParameters) {
+ bool *consumedParams = const_cast<bool *>(getConsumedParamsBuffer());
+ for (unsigned i = 0; i != NumParams; ++i)
+ consumedParams[i] = epi.ConsumedParameters[i];
}
}
@@ -1678,7 +1683,7 @@ FunctionProtoType::getNoexceptSpec(const ASTContext &ctx) const {
return NR_Dependent;
llvm::APSInt value;
- bool isICE = noexceptExpr->isIntegerConstantExpr(value, ctx, 0,
+ bool isICE = noexceptExpr->isIntegerConstantExpr(value, ctx, nullptr,
/*evaluated*/false);
(void)isICE;
assert(isICE && "AST should not contain bad noexcept expressions.");
@@ -1686,16 +1691,41 @@ FunctionProtoType::getNoexceptSpec(const ASTContext &ctx) const {
return value.getBoolValue() ? NR_Nothrow : NR_Throw;
}
+bool FunctionProtoType::isNothrow(const ASTContext &Ctx,
+ bool ResultIfDependent) const {
+ ExceptionSpecificationType EST = getExceptionSpecType();
+ assert(EST != EST_Unevaluated && EST != EST_Uninstantiated);
+ if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
+ return true;
+
+ if (EST == EST_Dynamic && ResultIfDependent == true) {
+ // A dynamic exception specification is throwing unless every exception
+ // type is an (unexpanded) pack expansion type.
+ for (unsigned I = 0, N = NumExceptions; I != N; ++I)
+ if (!getExceptionType(I)->getAs<PackExpansionType>())
+ return false;
+ return ResultIfDependent;
+ }
+
+ if (EST != EST_ComputedNoexcept)
+ return false;
+
+ NoexceptResult NR = getNoexceptSpec(Ctx);
+ if (NR == NR_Dependent)
+ return ResultIfDependent;
+ return NR == NR_Nothrow;
+}
+
bool FunctionProtoType::isTemplateVariadic() const {
- for (unsigned ArgIdx = getNumArgs(); ArgIdx; --ArgIdx)
- if (isa<PackExpansionType>(getArgType(ArgIdx - 1)))
+ for (unsigned ArgIdx = getNumParams(); ArgIdx; --ArgIdx)
+ if (isa<PackExpansionType>(getParamType(ArgIdx - 1)))
return true;
return false;
}
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
- const QualType *ArgTys, unsigned NumArgs,
+ const QualType *ArgTys, unsigned NumParams,
const ExtProtoInfo &epi,
const ASTContext &Context) {
@@ -1717,7 +1747,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
// whether the following bool is the EH spec or part of the arguments.
ID.AddPointer(Result.getAsOpaquePtr());
- for (unsigned i = 0; i != NumArgs; ++i)
+ for (unsigned i = 0; i != NumParams; ++i)
ID.AddPointer(ArgTys[i].getAsOpaquePtr());
// This method is relatively performance sensitive, so as a performance
// shortcut, use one AddInteger call instead of four for the next four
@@ -1740,9 +1770,9 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
epi.ExceptionSpecType == EST_Unevaluated) {
ID.AddPointer(epi.ExceptionSpecDecl->getCanonicalDecl());
}
- if (epi.ConsumedArguments) {
- for (unsigned i = 0; i != NumArgs; ++i)
- ID.AddBoolean(epi.ConsumedArguments[i]);
+ if (epi.ConsumedParameters) {
+ for (unsigned i = 0; i != NumParams; ++i)
+ ID.AddBoolean(epi.ConsumedParameters[i]);
}
epi.ExtInfo.Profile(ID);
ID.AddBoolean(epi.HasTrailingReturn);
@@ -1750,7 +1780,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID,
const ASTContext &Ctx) {
- Profile(ID, getResultType(), arg_type_begin(), NumArgs, getExtProtoInfo(),
+ Profile(ID, getReturnType(), param_type_begin(), NumParams, getExtProtoInfo(),
Ctx);
}
@@ -1819,11 +1849,9 @@ TagType::TagType(TypeClass TC, const TagDecl *D, QualType can)
decl(const_cast<TagDecl*>(D)) {}
static TagDecl *getInterestingTagDecl(TagDecl *decl) {
- for (TagDecl::redecl_iterator I = decl->redecls_begin(),
- E = decl->redecls_end();
- I != E; ++I) {
+ for (auto I : decl->redecls()) {
if (I->isCompleteDefinition() || I->isBeingDefined())
- return *I;
+ return I;
}
// If there's no definition (not even in progress), return what we have.
return decl;
@@ -1896,7 +1924,7 @@ CXXRecordDecl *InjectedClassNameType::getDecl() const {
}
IdentifierInfo *TemplateTypeParmType::getIdentifier() const {
- return isCanonicalUnqualified() ? 0 : getDecl()->getIdentifier();
+ return isCanonicalUnqualified() ? nullptr : getDecl()->getIdentifier();
}
SubstTemplateTypeParmPackType::
@@ -1922,10 +1950,8 @@ void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID,
const TemplateArgument &ArgPack) {
ID.AddPointer(Replaced);
ID.AddInteger(ArgPack.pack_size());
- for (TemplateArgument::pack_iterator P = ArgPack.pack_begin(),
- PEnd = ArgPack.pack_end();
- P != PEnd; ++P)
- ID.AddPointer(P->getAsType().getAsOpaquePtr());
+ for (const auto &P : ArgPack.pack_elements())
+ ID.AddPointer(P.getAsType().getAsOpaquePtr());
}
bool TemplateSpecializationType::
@@ -2200,13 +2226,12 @@ static CachedProperties computeCachedProperties(const Type *T) {
case Type::ExtVector:
return Cache::get(cast<VectorType>(T)->getElementType());
case Type::FunctionNoProto:
- return Cache::get(cast<FunctionType>(T)->getResultType());
+ return Cache::get(cast<FunctionType>(T)->getReturnType());
case Type::FunctionProto: {
const FunctionProtoType *FPT = cast<FunctionProtoType>(T);
- CachedProperties result = Cache::get(FPT->getResultType());
- for (FunctionProtoType::arg_type_iterator ai = FPT->arg_type_begin(),
- ae = FPT->arg_type_end(); ai != ae; ++ai)
- result = merge(result, Cache::get(*ai));
+ CachedProperties result = Cache::get(FPT->getReturnType());
+ for (const auto &ai : FPT->param_types())
+ result = merge(result, Cache::get(ai));
return result;
}
case Type::ObjCInterface: {
@@ -2285,13 +2310,12 @@ static LinkageInfo computeLinkageInfo(const Type *T) {
case Type::ExtVector:
return computeLinkageInfo(cast<VectorType>(T)->getElementType());
case Type::FunctionNoProto:
- return computeLinkageInfo(cast<FunctionType>(T)->getResultType());
+ return computeLinkageInfo(cast<FunctionType>(T)->getReturnType());
case Type::FunctionProto: {
const FunctionProtoType *FPT = cast<FunctionProtoType>(T);
- LinkageInfo LV = computeLinkageInfo(FPT->getResultType());
- for (FunctionProtoType::arg_type_iterator ai = FPT->arg_type_begin(),
- ae = FPT->arg_type_end(); ai != ae; ++ai)
- LV.merge(computeLinkageInfo(*ai));
+ LinkageInfo LV = computeLinkageInfo(FPT->getReturnType());
+ for (const auto &ai : FPT->param_types())
+ LV.merge(computeLinkageInfo(ai));
return LV;
}
case Type::ObjCInterface:
@@ -2441,3 +2465,7 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) {
return DK_none;
}
+
+CXXRecordDecl *MemberPointerType::getMostRecentCXXRecordDecl() const {
+ return getClass()->getAsCXXRecordDecl()->getMostRecentDecl();
+}
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 22a51bc345ac..208d695632a0 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -55,7 +55,7 @@ namespace {
/// \brief Returns the alignment of the type source info data block.
unsigned TypeLoc::getLocalAlignmentForType(QualType Ty) {
if (Ty.isNull()) return 1;
- return TypeAligner().Visit(TypeLoc(Ty, 0));
+ return TypeAligner().Visit(TypeLoc(Ty, nullptr));
}
namespace {
@@ -73,7 +73,7 @@ namespace {
/// \brief Returns the size of the type source info data block.
unsigned TypeLoc::getFullDataSizeForType(QualType Ty) {
unsigned Total = 0;
- TypeLoc TyLoc(Ty, 0);
+ TypeLoc TyLoc(Ty, nullptr);
unsigned MaxAlign = 1;
while (!TyLoc.isNull()) {
unsigned Align = getLocalAlignmentForType(TyLoc.getType());
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 571e3db0289f..061473eb848d 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -204,6 +204,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
NeedARCStrongQualifier = true;
// Fall through
+ case Type::Adjusted:
case Type::Decayed:
case Type::Pointer:
case Type::BlockPointer:
@@ -429,7 +430,16 @@ void TypePrinter::printConstantArrayBefore(const ConstantArrayType *T,
}
void TypePrinter::printConstantArrayAfter(const ConstantArrayType *T,
raw_ostream &OS) {
- OS << '[' << T->getSize().getZExtValue() << ']';
+ OS << '[';
+ if (T->getIndexTypeQualifiers().hasQualifiers()) {
+ AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers());
+ OS << ' ';
+ }
+
+ if (T->getSizeModifier() == ArrayType::Static)
+ OS << "static ";
+
+ OS << T->getSize().getZExtValue() << ']';
printAfter(T->getElementType(), OS);
}
@@ -460,23 +470,32 @@ void TypePrinter::printVariableArrayAfter(const VariableArrayType *T,
}
if (T->getSizeModifier() == VariableArrayType::Static)
- OS << "static";
+ OS << "static ";
else if (T->getSizeModifier() == VariableArrayType::Star)
OS << '*';
if (T->getSizeExpr())
- T->getSizeExpr()->printPretty(OS, 0, Policy);
+ T->getSizeExpr()->printPretty(OS, nullptr, Policy);
OS << ']';
printAfter(T->getElementType(), OS);
}
+void TypePrinter::printAdjustedBefore(const AdjustedType *T, raw_ostream &OS) {
+ // Print the adjusted representation, otherwise the adjustment will be
+ // invisible.
+ printBefore(T->getAdjustedType(), OS);
+}
+void TypePrinter::printAdjustedAfter(const AdjustedType *T, raw_ostream &OS) {
+ printAfter(T->getAdjustedType(), OS);
+}
+
void TypePrinter::printDecayedBefore(const DecayedType *T, raw_ostream &OS) {
// Print as though it's a pointer.
- printBefore(T->getDecayedType(), OS);
+ printAdjustedBefore(T, OS);
}
void TypePrinter::printDecayedAfter(const DecayedType *T, raw_ostream &OS) {
- printAfter(T->getDecayedType(), OS);
+ printAdjustedAfter(T, OS);
}
void TypePrinter::printDependentSizedArrayBefore(
@@ -491,7 +510,7 @@ void TypePrinter::printDependentSizedArrayAfter(
raw_ostream &OS) {
OS << '[';
if (T->getSizeExpr())
- T->getSizeExpr()->printPretty(OS, 0, Policy);
+ T->getSizeExpr()->printPretty(OS, nullptr, Policy);
OS << ']';
printAfter(T->getElementType(), OS);
}
@@ -506,7 +525,7 @@ void TypePrinter::printDependentSizedExtVectorAfter(
raw_ostream &OS) {
OS << " __attribute__((ext_vector_type(";
if (T->getSizeExpr())
- T->getSizeExpr()->printPretty(OS, 0, Policy);
+ T->getSizeExpr()->printPretty(OS, nullptr, Policy);
OS << ")))";
printAfter(T->getElementType(), OS);
}
@@ -583,7 +602,8 @@ FunctionProtoType::printExceptionSpecification(raw_ostream &OS,
OS << " noexcept";
if (getExceptionSpecType() == EST_ComputedNoexcept) {
OS << '(';
- getNoexceptExpr()->printPretty(OS, 0, Policy);
+ if (getNoexceptExpr())
+ getNoexceptExpr()->printPretty(OS, nullptr, Policy);
OS << ')';
}
}
@@ -598,7 +618,7 @@ void TypePrinter::printFunctionProtoBefore(const FunctionProtoType *T,
} else {
// If needed for precedence reasons, wrap the inner part in grouping parens.
SaveAndRestore<bool> PrevPHIsEmpty(HasEmptyPlaceHolder, false);
- printBefore(T->getResultType(), OS);
+ printBefore(T->getReturnType(), OS);
if (!PrevPHIsEmpty.get())
OS << '(';
}
@@ -614,17 +634,17 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
OS << '(';
{
ParamPolicyRAII ParamPolicy(Policy);
- for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) {
+ for (unsigned i = 0, e = T->getNumParams(); i != e; ++i) {
if (i) OS << ", ";
- print(T->getArgType(i), OS, StringRef());
+ print(T->getParamType(i), OS, StringRef());
}
}
if (T->isVariadic()) {
- if (T->getNumArgs())
+ if (T->getNumParams())
OS << ", ";
OS << "...";
- } else if (T->getNumArgs() == 0 && !Policy.LangOpts.CPlusPlus) {
+ } else if (T->getNumParams() == 0 && !Policy.LangOpts.CPlusPlus) {
// Do not emit int() if we have a proto, emit 'int(void)'.
OS << "void";
}
@@ -703,17 +723,17 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
T->printExceptionSpecification(OS, Policy);
if (T->hasTrailingReturn()) {
- OS << " -> ";
- print(T->getResultType(), OS, StringRef());
+ OS << " -> ";
+ print(T->getReturnType(), OS, StringRef());
} else
- printAfter(T->getResultType(), OS);
+ printAfter(T->getReturnType(), OS);
}
void TypePrinter::printFunctionNoProtoBefore(const FunctionNoProtoType *T,
raw_ostream &OS) {
// If needed for precedence reasons, wrap the inner part in grouping parens.
SaveAndRestore<bool> PrevPHIsEmpty(HasEmptyPlaceHolder, false);
- printBefore(T->getResultType(), OS);
+ printBefore(T->getReturnType(), OS);
if (!PrevPHIsEmpty.get())
OS << '(';
}
@@ -727,7 +747,7 @@ void TypePrinter::printFunctionNoProtoAfter(const FunctionNoProtoType *T,
OS << "()";
if (T->getNoReturnAttr())
OS << " __attribute__((noreturn))";
- printAfter(T->getResultType(), OS);
+ printAfter(T->getReturnType(), OS);
}
void TypePrinter::printTypeSpec(const NamedDecl *D, raw_ostream &OS) {
@@ -751,7 +771,8 @@ void TypePrinter::printTypedefAfter(const TypedefType *T, raw_ostream &OS) { }
void TypePrinter::printTypeOfExprBefore(const TypeOfExprType *T,
raw_ostream &OS) {
OS << "typeof ";
- T->getUnderlyingExpr()->printPretty(OS, 0, Policy);
+ if (T->getUnderlyingExpr())
+ T->getUnderlyingExpr()->printPretty(OS, nullptr, Policy);
spaceBeforePlaceHolder(OS);
}
void TypePrinter::printTypeOfExprAfter(const TypeOfExprType *T,
@@ -767,7 +788,8 @@ void TypePrinter::printTypeOfAfter(const TypeOfType *T, raw_ostream &OS) { }
void TypePrinter::printDecltypeBefore(const DecltypeType *T, raw_ostream &OS) {
OS << "decltype(";
- T->getUnderlyingExpr()->printPretty(OS, 0, Policy);
+ if (T->getUnderlyingExpr())
+ T->getUnderlyingExpr()->printPretty(OS, nullptr, Policy);
OS << ')';
spaceBeforePlaceHolder(OS);
}
@@ -838,7 +860,7 @@ void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) {
if (NS->getIdentifier())
OS << NS->getName() << "::";
else
- OS << "<anonymous>::";
+ OS << "(anonymous namespace)::";
} else if (ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
IncludeStrongLifetimeRAII Strong(Policy);
@@ -890,13 +912,13 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {
OS << Typedef->getIdentifier()->getName();
} else {
// Make an unambiguous representation for anonymous types, e.g.
- // <anonymous enum at /usr/include/string.h:120:9>
+ // (anonymous enum at /usr/include/string.h:120:9)
if (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda()) {
- OS << "<lambda";
+ OS << "(lambda";
HasKindDecoration = true;
} else {
- OS << "<anonymous";
+ OS << "(anonymous";
}
if (Policy.AnonymousTagLocations) {
@@ -915,7 +937,7 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {
}
}
- OS << '>';
+ OS << ')';
}
// If this is a class template specialization, print the template
@@ -1249,13 +1271,12 @@ void TypePrinter::printObjCObjectBefore(const ObjCObjectType *T,
print(T->getBaseType(), OS, StringRef());
OS << '<';
bool isFirst = true;
- for (ObjCObjectType::qual_iterator
- I = T->qual_begin(), E = T->qual_end(); I != E; ++I) {
+ for (const auto *I : T->quals()) {
if (isFirst)
isFirst = false;
else
OS << ',';
- OS << (*I)->getName();
+ OS << I->getName();
}
OS << '>';
spaceBeforePlaceHolder(OS);
@@ -1271,12 +1292,12 @@ void TypePrinter::printObjCObjectPointerBefore(const ObjCObjectPointerType *T,
T->getPointeeType().getLocalQualifiers().print(OS, Policy,
/*appendSpaceIfNonEmpty=*/true);
+ assert(!T->isObjCSelType());
+
if (T->isObjCIdType() || T->isObjCQualifiedIdType())
OS << "id";
else if (T->isObjCClassType() || T->isObjCQualifiedClassType())
OS << "Class";
- else if (T->isObjCSelType())
- OS << "SEL";
else
OS << T->getInterfaceDecl()->getName();
@@ -1292,7 +1313,8 @@ void TypePrinter::printObjCObjectPointerBefore(const ObjCObjectPointerType *T,
OS << '>';
}
- if (!T->isObjCIdType() && !T->isObjCQualifiedIdType()) {
+ if (!T->isObjCIdType() && !T->isObjCQualifiedIdType() &&
+ !T->isObjCClassType() && !T->isObjCQualifiedClassType()) {
OS << " *"; // Don't forget the implicit pointer.
} else {
spaceBeforePlaceHolder(OS);
@@ -1413,13 +1435,10 @@ void QualType::dump(const char *msg) const {
print(llvm::errs(), PrintingPolicy(LO), "identifier");
llvm::errs() << '\n';
}
-void QualType::dump() const {
- dump(0);
-}
-void Type::dump() const {
- QualType(this, 0).dump();
-}
+LLVM_DUMP_METHOD void QualType::dump() const { dump(nullptr); }
+
+LLVM_DUMP_METHOD void Type::dump() const { QualType(this, 0).dump(); }
std::string Qualifiers::getAsString() const {
LangOptions LO;
diff --git a/lib/AST/VTTBuilder.cpp b/lib/AST/VTTBuilder.cpp
index 5ca4e862ef7b..c213d1cef6aa 100644
--- a/lib/AST/VTTBuilder.cpp
+++ b/lib/AST/VTTBuilder.cpp
@@ -56,15 +56,13 @@ void VTTBuilder::AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex,
void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) {
const CXXRecordDecl *RD = Base.getBase();
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
-
+ for (const auto &I : RD->bases()) {
// Don't layout virtual bases.
- if (I->isVirtual())
+ if (I.isVirtual())
continue;
const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
CharUnits BaseOffset = Base.getBaseOffset() +
@@ -88,10 +86,9 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
if (!RD->getNumVBases() && !BaseIsMorallyVirtual)
return;
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
+ for (const auto &I : RD->bases()) {
const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
// Itanium C++ ABI 2.6.2:
// Secondary virtual pointers are present for all bases with either
@@ -106,7 +103,7 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual;
bool BaseDeclIsNonVirtualPrimaryBase = false;
CharUnits BaseOffset;
- if (I->isVirtual()) {
+ if (I.isVirtual()) {
// Ignore virtual bases that we've already visited.
if (!VBases.insert(BaseDecl))
continue;
@@ -153,13 +150,12 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD,
VisitedVirtualBasesSetTy &VBases) {
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
+ for (const auto &I : RD->bases()) {
const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
// Check if this is a virtual base.
- if (I->isVirtual()) {
+ if (I.isVirtual()) {
// Check if we've seen this base before.
if (!VBases.insert(BaseDecl))
continue;
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index 5f7ae0f3ff4a..fa1127f58f9b 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -43,9 +44,9 @@ struct BaseOffset {
/// path from the derived class to the base class involves a virtual base
/// class.
CharUnits NonVirtualOffset;
-
- BaseOffset() : DerivedClass(0), VirtualBase(0),
- NonVirtualOffset(CharUnits::Zero()) { }
+
+ BaseOffset() : DerivedClass(nullptr), VirtualBase(nullptr),
+ NonVirtualOffset(CharUnits::Zero()) { }
BaseOffset(const CXXRecordDecl *DerivedClass,
const CXXRecordDecl *VirtualBase, CharUnits NonVirtualOffset)
: DerivedClass(DerivedClass), VirtualBase(VirtualBase),
@@ -63,10 +64,15 @@ public:
/// Method - The method decl of the overrider.
const CXXMethodDecl *Method;
+ /// VirtualBase - The virtual base class subobject of this overridder.
+ /// Note that this records the closest derived virtual base class subobject.
+ const CXXRecordDecl *VirtualBase;
+
/// Offset - the base offset of the overrider's parent in the layout class.
CharUnits Offset;
-
- OverriderInfo() : Method(0), Offset(CharUnits::Zero()) { }
+
+ OverriderInfo() : Method(nullptr), VirtualBase(nullptr),
+ Offset(CharUnits::Zero()) { }
};
private:
@@ -200,6 +206,7 @@ FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass,
Overrider.Offset = OverriderOffset;
Overrider.Method = Method.Method;
+ Overrider.VirtualBase = Method.InVirtualSubobject;
}
}
@@ -215,8 +222,8 @@ static BaseOffset ComputeBaseOffset(ASTContext &Context,
CharUnits NonVirtualOffset = CharUnits::Zero();
unsigned NonVirtualStart = 0;
- const CXXRecordDecl *VirtualBase = 0;
-
+ const CXXRecordDecl *VirtualBase = nullptr;
+
// First, look for the virtual base class.
for (int I = Path.size(), E = 0; I != E; --I) {
const CXXBasePathElement &Element = Path[I - 1];
@@ -268,11 +275,11 @@ ComputeReturnAdjustmentBaseOffset(ASTContext &Context,
const FunctionType *DerivedFT = DerivedMD->getType()->getAs<FunctionType>();
// Canonicalize the return types.
- CanQualType CanDerivedReturnType =
- Context.getCanonicalType(DerivedFT->getResultType());
- CanQualType CanBaseReturnType =
- Context.getCanonicalType(BaseFT->getResultType());
-
+ CanQualType CanDerivedReturnType =
+ Context.getCanonicalType(DerivedFT->getReturnType());
+ CanQualType CanBaseReturnType =
+ Context.getCanonicalType(BaseFT->getReturnType());
+
assert(CanDerivedReturnType->getTypeClass() ==
CanBaseReturnType->getTypeClass() &&
"Types must have same type class!");
@@ -337,13 +344,12 @@ FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual,
OffsetInLayoutClass;
// Traverse our bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
+ for (const auto &B : RD->bases()) {
+ const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
CharUnits BaseOffset;
CharUnits BaseOffsetInLayoutClass;
- if (I->isVirtual()) {
+ if (B.isVirtual()) {
// Check if we've visited this virtual base before.
if (SubobjectOffsets.count(std::make_pair(BaseDecl, 0)))
continue;
@@ -363,7 +369,7 @@ FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual,
}
ComputeBaseOffsets(BaseSubobject(BaseDecl, BaseOffset),
- I->isVirtual(), BaseOffsetInLayoutClass,
+ B.isVirtual(), BaseOffsetInLayoutClass,
SubobjectOffsets, SubobjectLayoutClassOffsets,
SubobjectCounts);
}
@@ -374,16 +380,15 @@ void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base,
const CXXRecordDecl *RD = Base.getBase();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
+ for (const auto &B : RD->bases()) {
+ const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
// Ignore bases that don't have any virtual member functions.
if (!BaseDecl->isPolymorphic())
continue;
CharUnits BaseOffset;
- if (I->isVirtual()) {
+ if (B.isVirtual()) {
if (!VisitedVirtualBases.insert(BaseDecl)) {
// We've visited this base before.
continue;
@@ -397,21 +402,22 @@ void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base,
dump(Out, BaseSubobject(BaseDecl, BaseOffset), VisitedVirtualBases);
}
- Out << "Final overriders for (" << RD->getQualifiedNameAsString() << ", ";
+ Out << "Final overriders for (";
+ RD->printQualifiedName(Out);
+ Out << ", ";
Out << Base.getBaseOffset().getQuantity() << ")\n";
// Now dump the overriders for this base subobject.
- for (CXXRecordDecl::method_iterator I = RD->method_begin(),
- E = RD->method_end(); I != E; ++I) {
- const CXXMethodDecl *MD = *I;
-
+ for (const auto *MD : RD->methods()) {
if (!MD->isVirtual())
continue;
OverriderInfo Overrider = getOverrider(MD, Base.getBaseOffset());
- Out << " " << MD->getQualifiedNameAsString() << " - (";
- Out << Overrider.Method->getQualifiedNameAsString();
+ Out << " ";
+ MD->printQualifiedName(Out);
+ Out << " - (";
+ Overrider.Method->printQualifiedName(Out);
Out << ", " << Overrider.Offset.getQuantity() << ')';
BaseOffset Offset;
@@ -420,8 +426,10 @@ void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base,
if (!Offset.isEmpty()) {
Out << " [ret-adj: ";
- if (Offset.VirtualBase)
- Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, ";
+ if (Offset.VirtualBase) {
+ Offset.VirtualBase->printQualifiedName(Out);
+ Out << " vbase, ";
+ }
Out << Offset.NonVirtualOffset.getQuantity() << " nv]";
}
@@ -472,10 +480,10 @@ static bool HasSameVirtualSignature(const CXXMethodDecl *LHS,
// list here because there isn't necessarily an inheritance
// relationship between the two methods.
if (LT->getTypeQuals() != RT->getTypeQuals() ||
- LT->getNumArgs() != RT->getNumArgs())
+ LT->getNumParams() != RT->getNumParams())
return false;
- for (unsigned I = 0, E = LT->getNumArgs(); I != E; ++I)
- if (LT->getArgType(I) != RT->getArgType(I))
+ for (unsigned I = 0, E = LT->getNumParams(); I != E; ++I)
+ if (LT->getParamType(I) != RT->getParamType(I))
return false;
return true;
}
@@ -684,10 +692,7 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
}
// Add the vcall offsets.
- for (CXXRecordDecl::method_iterator I = RD->method_begin(),
- E = RD->method_end(); I != E; ++I) {
- const CXXMethodDecl *MD = *I;
-
+ for (const auto *MD : RD->methods()) {
if (!MD->isVirtual())
continue;
@@ -715,13 +720,11 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
}
// And iterate over all non-virtual bases (ignoring the primary base).
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
-
- if (I->isVirtual())
+ for (const auto &B : RD->bases()) {
+ if (B.isVirtual())
continue;
- const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
+ const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
if (BaseDecl == PrimaryBase)
continue;
@@ -741,12 +744,11 @@ VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
Context.getASTRecordLayout(LayoutClass);
// Add vbase offsets.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
+ for (const auto &B : RD->bases()) {
+ const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
// Check if this is a virtual base that we haven't visited before.
- if (I->isVirtual() && VisitedVirtualBases.insert(BaseDecl)) {
+ if (B.isVirtual() && VisitedVirtualBases.insert(BaseDecl)) {
CharUnits Offset =
LayoutClassLayout.getVBaseClassOffset(BaseDecl) - OffsetInLayoutClass;
@@ -1294,7 +1296,7 @@ ThisAdjustment ItaniumVTableBuilder::ComputeThisAdjustment(
// We don't have vcall offsets for this virtual base, go ahead and
// build them.
VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass,
- /*FinalOverriders=*/0,
+ /*FinalOverriders=*/nullptr,
BaseSubobject(Offset.VirtualBase,
CharUnits::Zero()),
/*BaseIsVirtual=*/true,
@@ -1448,8 +1450,8 @@ FindNearestOverriddenMethod(const CXXMethodDecl *MD,
return OverriddenMD;
}
}
-
- return 0;
+
+ return nullptr;
}
void ItaniumVTableBuilder::AddMethods(
@@ -1503,16 +1505,13 @@ void ItaniumVTableBuilder::AddMethods(
llvm_unreachable("Found a duplicate primary base!");
}
- const CXXDestructorDecl *ImplicitVirtualDtor = 0;
+ const CXXDestructorDecl *ImplicitVirtualDtor = nullptr;
typedef llvm::SmallVector<const CXXMethodDecl *, 8> NewVirtualFunctionsTy;
NewVirtualFunctionsTy NewVirtualFunctions;
// Now go through all virtual member functions and add them.
- for (CXXRecordDecl::method_iterator I = RD->method_begin(),
- E = RD->method_end(); I != E; ++I) {
- const CXXMethodDecl *MD = *I;
-
+ for (const auto *MD : RD->methods()) {
if (!MD->isVirtual())
continue;
@@ -1759,13 +1758,12 @@ ItaniumVTableBuilder::LayoutSecondaryVTables(BaseSubobject Base,
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
+ for (const auto &B : RD->bases()) {
// Ignore virtual bases, we'll emit them later.
- if (I->isVirtual())
+ if (B.isVirtual())
continue;
- const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
+ const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
// Ignore bases that don't have a vtable.
if (!BaseDecl->isDynamicClass())
@@ -1838,13 +1836,12 @@ void ItaniumVTableBuilder::DeterminePrimaryVirtualBases(
}
// Traverse bases, looking for more primary virtual bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
+ for (const auto &B : RD->bases()) {
+ const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
CharUnits BaseOffsetInLayoutClass;
- if (I->isVirtual()) {
+ if (B.isVirtual()) {
if (!VBases.insert(BaseDecl))
continue;
@@ -1868,13 +1865,12 @@ void ItaniumVTableBuilder::LayoutVTablesForVirtualBases(
// Then come the virtual base virtual tables, also in inheritance graph
// order, and again excluding primary bases (which share virtual tables with
// the classes for which they are primary).
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
+ for (const auto &B : RD->bases()) {
+ const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
// Check if this base needs a vtable. (If it's virtual, not a primary base
// of some other class, and we haven't visited it before).
- if (I->isVirtual() && BaseDecl->isDynamicClass() &&
+ if (B.isVirtual() && BaseDecl->isDynamicClass() &&
!PrimaryVirtualBases.count(BaseDecl) && VBases.insert(BaseDecl)) {
const ASTRecordLayout &MostDerivedClassLayout =
Context.getASTRecordLayout(MostDerivedClass);
@@ -1900,21 +1896,6 @@ void ItaniumVTableBuilder::LayoutVTablesForVirtualBases(
}
}
-struct ItaniumThunkInfoComparator {
- bool operator() (const ThunkInfo &LHS, const ThunkInfo &RHS) {
- assert(LHS.Method == 0);
- assert(RHS.Method == 0);
-
- if (LHS.This != RHS.This)
- return LHS.This < RHS.This;
-
- if (LHS.Return != RHS.Return)
- return LHS.Return < RHS.Return;
-
- return false;
- }
-};
-
/// dumpLayout - Dump the vtable layout.
void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
// FIXME: write more tests that actually use the dumpLayout output to prevent
@@ -1922,12 +1903,13 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
if (isBuildingConstructorVTable()) {
Out << "Construction vtable for ('";
- Out << MostDerivedClass->getQualifiedNameAsString() << "', ";
+ MostDerivedClass->printQualifiedName(Out);
+ Out << "', ";
Out << MostDerivedClassOffset.getQuantity() << ") in '";
- Out << LayoutClass->getQualifiedNameAsString();
+ LayoutClass->printQualifiedName(Out);
} else {
Out << "Vtable for '";
- Out << MostDerivedClass->getQualifiedNameAsString();
+ MostDerivedClass->printQualifiedName(Out);
}
Out << "' (" << Components.size() << " entries).\n";
@@ -1973,7 +1955,8 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
break;
case VTableComponent::CK_RTTI:
- Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI";
+ Component.getRTTIDecl()->printQualifiedName(Out);
+ Out << " RTTI";
break;
case VTableComponent::CK_FunctionPointer: {
@@ -2028,7 +2011,7 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
const CXXDestructorDecl *DD = Component.getDestructorDecl();
- Out << DD->getQualifiedNameAsString();
+ DD->printQualifiedName(Out);
if (IsComplete)
Out << "() [complete]";
else
@@ -2078,7 +2061,8 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
const BaseSubobject &Base =
AddressPointsByIndex.find(NextIndex)->second;
- Out << " -- (" << Base.getBase()->getQualifiedNameAsString();
+ Out << " -- (";
+ Base.getBase()->printQualifiedName(Out);
Out << ", " << Base.getBaseOffset().getQuantity();
Out << ") vtable address --\n";
} else {
@@ -2124,7 +2108,8 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
}
Out << "Virtual base offset offsets for '";
- Out << MostDerivedClass->getQualifiedNameAsString() << "' (";
+ MostDerivedClass->printQualifiedName(Out);
+ Out << "' (";
Out << ClassNamesAndOffsets.size();
Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n";
@@ -2158,7 +2143,10 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
ThunkInfoVectorTy ThunksVector = Thunks[MD];
std::sort(ThunksVector.begin(), ThunksVector.end(),
- ItaniumThunkInfoComparator());
+ [](const ThunkInfo &LHS, const ThunkInfo &RHS) {
+ assert(LHS.Method == nullptr && RHS.Method == nullptr);
+ return std::tie(LHS.This, LHS.Return) < std::tie(RHS.This, RHS.Return);
+ });
Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
@@ -2203,10 +2191,7 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
// Store them in a map keyed by the index so we'll get a sorted table.
std::map<uint64_t, std::string> IndicesMap;
- for (CXXRecordDecl::method_iterator i = MostDerivedClass->method_begin(),
- e = MostDerivedClass->method_end(); i != e; ++i) {
- const CXXMethodDecl *MD = *i;
-
+ for (const auto *MD : MostDerivedClass->methods()) {
// We only want virtual member functions.
if (!MD->isVirtual())
continue;
@@ -2230,7 +2215,7 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
// Print the vtable indices for all the member functions.
if (!IndicesMap.empty()) {
Out << "VTable indices for '";
- Out << MostDerivedClass->getQualifiedNameAsString();
+ MostDerivedClass->printQualifiedName(Out);
Out << "' (" << IndicesMap.size() << " entries).\n";
for (std::map<uint64_t, std::string>::const_iterator I = IndicesMap.begin(),
@@ -2245,17 +2230,6 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
Out << '\n';
}
-
-struct VTableThunksComparator {
- bool operator()(const VTableLayout::VTableThunkTy &LHS,
- const VTableLayout::VTableThunkTy &RHS) {
- if (LHS.first == RHS.first) {
- assert(LHS.second == RHS.second &&
- "Different thunks should have unique indices!");
- }
- return LHS.first < RHS.first;
- }
-};
}
VTableLayout::VTableLayout(uint64_t NumVTableComponents,
@@ -2276,14 +2250,18 @@ VTableLayout::VTableLayout(uint64_t NumVTableComponents,
this->VTableThunks.get());
std::sort(this->VTableThunks.get(),
this->VTableThunks.get() + NumVTableThunks,
- VTableThunksComparator());
+ [](const VTableLayout::VTableThunkTy &LHS,
+ const VTableLayout::VTableThunkTy &RHS) {
+ assert((LHS.first != RHS.first || LHS.second == RHS.second) &&
+ "Different thunks should have unique indices!");
+ return LHS.first < RHS.first;
+ });
}
VTableLayout::~VTableLayout() { }
ItaniumVTableContext::ItaniumVTableContext(ASTContext &Context)
- : IsMicrosoftABI(Context.getTargetInfo().getCXXABI().isMicrosoft()) {
-}
+ : VTableContextBase(/*MS=*/false) {}
ItaniumVTableContext::~ItaniumVTableContext() {
llvm::DeleteContainerSeconds(VTableLayouts);
@@ -2312,8 +2290,8 @@ ItaniumVTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
VirtualBaseClassOffsetOffsets.find(ClassPair);
if (I != VirtualBaseClassOffsetOffsets.end())
return I->second;
-
- VCallAndVBaseOffsetBuilder Builder(RD, RD, /*FinalOverriders=*/0,
+
+ VCallAndVBaseOffsetBuilder Builder(RD, RD, /*FinalOverriders=*/nullptr,
BaseSubobject(RD, CharUnits::Zero()),
/*BaseIsVirtual=*/false,
/*OffsetInLayoutClass=*/CharUnits::Zero());
@@ -2348,8 +2326,6 @@ static VTableLayout *CreateVTableLayout(const ItaniumVTableBuilder &Builder) {
void
ItaniumVTableContext::computeVTableRelatedInformation(const CXXRecordDecl *RD) {
- assert(!IsMicrosoftABI && "Shouldn't be called in this ABI!");
-
const VTableLayout *&Entry = VTableLayouts[RD];
// Check if we've computed this information before.
@@ -2444,6 +2420,9 @@ public:
typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation>
MethodVFTableLocationsTy;
+ typedef llvm::iterator_range<MethodVFTableLocationsTy::const_iterator>
+ method_locations_range;
+
private:
/// VTables - Global vtable information.
MicrosoftVTableContext &VTables;
@@ -2457,7 +2436,7 @@ private:
const ASTRecordLayout &MostDerivedClassLayout;
- VFPtrInfo WhichVFPtr;
+ const VPtrInfo &WhichVFPtr;
/// FinalOverriders - The final overriders of the most derived class.
const FinalOverriders Overriders;
@@ -2467,6 +2446,9 @@ private:
MethodVFTableLocationsTy MethodVFTableLocations;
+ /// \brief Does this class have an RTTI component?
+ bool HasRTTIComponent;
+
/// MethodInfo - Contains information about a method in a vtable.
/// (Used for computing 'this' pointer adjustment thunks.
struct MethodInfo {
@@ -2521,11 +2503,8 @@ private:
}
/// ComputeThisOffset - Returns the 'this' argument offset for the given
- /// method in the given subobject, relative to the beginning of the
- /// MostDerivedClass.
- CharUnits ComputeThisOffset(const CXXMethodDecl *MD,
- BaseSubobject Base,
- FinalOverriders::OverriderInfo Overrider);
+ /// method, relative to the beginning of the MostDerivedClass.
+ CharUnits ComputeThisOffset(FinalOverriders::OverriderInfo Overrider);
void CalculateVtordispAdjustment(FinalOverriders::OverriderInfo Overrider,
CharUnits ThisOffset, ThisAdjustment &TA);
@@ -2533,17 +2512,21 @@ private:
/// AddMethod - Add a single virtual member function to the vftable
/// components vector.
void AddMethod(const CXXMethodDecl *MD, ThunkInfo TI) {
+ if (!TI.isEmpty()) {
+ VTableThunks[Components.size()] = TI;
+ AddThunk(MD, TI);
+ }
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
assert(TI.Return.isEmpty() &&
"Destructor can't have return adjustment!");
Components.push_back(VTableComponent::MakeDeletingDtor(DD));
} else {
- if (!TI.isEmpty())
- VTableThunks[Components.size()] = TI;
Components.push_back(VTableComponent::MakeFunction(MD));
}
}
+ bool NeedsReturnAdjustingThunk(const CXXMethodDecl *MD);
+
/// AddMethods - Add the methods of this base subobject and the relevant
/// subbases to the vftable we're currently laying out.
void AddMethods(BaseSubobject Base, unsigned BaseDepth,
@@ -2555,8 +2538,9 @@ private:
// pointing to the middle of a section.
BasesSetVectorTy VisitedBases;
- AddMethods(BaseSubobject(MostDerivedClass, CharUnits::Zero()), 0, 0,
+ AddMethods(BaseSubobject(MostDerivedClass, CharUnits::Zero()), 0, nullptr,
VisitedBases);
+ assert(Components.size() && "vftable can't be empty");
assert(MethodVFTableLocations.empty());
for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(),
@@ -2567,8 +2551,8 @@ private:
// and the entries shadowed by return adjusting thunks.
if (MD->getParent() != MostDerivedClass || MI.Shadowed)
continue;
- MethodVFTableLocation Loc(MI.VBTableIndex, WhichVFPtr.LastVBase,
- WhichVFPtr.VFPtrOffset, MI.VFTableIndex);
+ MethodVFTableLocation Loc(MI.VBTableIndex, WhichVFPtr.getVBaseWithVPtr(),
+ WhichVFPtr.NonVirtualOffset, MI.VFTableIndex);
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
MethodVFTableLocations[GlobalDecl(DD, Dtor_Deleting)] = Loc;
} else {
@@ -2586,13 +2570,20 @@ private:
public:
VFTableBuilder(MicrosoftVTableContext &VTables,
- const CXXRecordDecl *MostDerivedClass, VFPtrInfo Which)
+ const CXXRecordDecl *MostDerivedClass, const VPtrInfo *Which)
: VTables(VTables),
Context(MostDerivedClass->getASTContext()),
MostDerivedClass(MostDerivedClass),
MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)),
- WhichVFPtr(Which),
+ WhichVFPtr(*Which),
Overriders(MostDerivedClass, CharUnits(), MostDerivedClass) {
+ // Only include the RTTI component if we know that we will provide a
+ // definition of the vftable.
+ HasRTTIComponent = Context.getLangOpts().RTTIData &&
+ !MostDerivedClass->hasAttr<DLLImportAttr>();
+ if (HasRTTIComponent)
+ Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
+
LayoutVFTable();
if (Context.getLangOpts().DumpVTableLayouts)
@@ -2605,12 +2596,9 @@ public:
ThunksMapTy::const_iterator thunks_end() const { return Thunks.end(); }
- MethodVFTableLocationsTy::const_iterator vtable_indices_begin() const {
- return MethodVFTableLocations.begin();
- }
-
- MethodVFTableLocationsTy::const_iterator vtable_indices_end() const {
- return MethodVFTableLocations.end();
+ method_locations_range vtable_locations() const {
+ return method_locations_range(MethodVFTableLocations.begin(),
+ MethodVFTableLocations.end());
}
uint64_t getNumVTableComponents() const { return Components.size(); }
@@ -2634,6 +2622,8 @@ public:
void dumpLayout(raw_ostream &);
};
+} // end namespace
+
/// InitialOverriddenDefinitionCollector - Finds the set of least derived bases
/// that define the given method.
struct InitialOverriddenDefinitionCollector {
@@ -2655,14 +2645,18 @@ static bool BaseInSet(const CXXBaseSpecifier *Specifier,
}
CharUnits
-VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD,
- BaseSubobject Base,
- FinalOverriders::OverriderInfo Overrider) {
+VFTableBuilder::ComputeThisOffset(FinalOverriders::OverriderInfo Overrider) {
InitialOverriddenDefinitionCollector Collector;
- visitAllOverriddenMethods(MD, Collector);
+ visitAllOverriddenMethods(Overrider.Method, Collector);
+
+ // If there are no overrides then 'this' is located
+ // in the base that defines the method.
+ if (Collector.Bases.size() == 0)
+ return Overrider.Offset;
CXXBasePaths Paths;
- Base.getBase()->lookupInBases(BaseInSet, &Collector.Bases, Paths);
+ Overrider.Method->getParent()->lookupInBases(BaseInSet, &Collector.Bases,
+ Paths);
// This will hold the smallest this offset among overridees of MD.
// This implies that an offset of a non-virtual base will dominate an offset
@@ -2671,10 +2665,12 @@ VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD,
CharUnits Ret;
bool First = true;
+ const ASTRecordLayout &OverriderRDLayout =
+ Context.getASTRecordLayout(Overrider.Method->getParent());
for (CXXBasePaths::paths_iterator I = Paths.begin(), E = Paths.end();
I != E; ++I) {
const CXXBasePath &Path = (*I);
- CharUnits ThisOffset = Base.getBaseOffset();
+ CharUnits ThisOffset = Overrider.Offset;
CharUnits LastVBaseOffset;
// For each path from the overrider to the parents of the overridden methods,
@@ -2687,34 +2683,33 @@ VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD,
const ASTRecordLayout &Layout = Context.getASTRecordLayout(PrevRD);
if (Element.Base->isVirtual()) {
- LastVBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(CurRD);
- if (Overrider.Method->getParent() == PrevRD) {
- // This one's interesting. If the final overrider is in a vbase B of the
- // most derived class and it overrides a method of the B's own vbase A,
- // it uses A* as "this". In its prologue, it can cast A* to B* with
- // a static offset. This offset is used regardless of the actual
- // offset of A from B in the most derived class, requiring an
- // this-adjusting thunk in the vftable if A and B are laid out
- // differently in the most derived class.
- ThisOffset += Layout.getVBaseClassOffset(CurRD);
- } else {
- ThisOffset = LastVBaseOffset;
- }
+ // The interesting things begin when you have virtual inheritance.
+ // The final overrider will use a static adjustment equal to the offset
+ // of the vbase in the final overrider class.
+ // For example, if the final overrider is in a vbase B of the most
+ // derived class and it overrides a method of the B's own vbase A,
+ // it uses A* as "this". In its prologue, it can cast A* to B* with
+ // a static offset. This offset is used regardless of the actual
+ // offset of A from B in the most derived class, requiring an
+ // this-adjusting thunk in the vftable if A and B are laid out
+ // differently in the most derived class.
+ LastVBaseOffset = ThisOffset =
+ Overrider.Offset + OverriderRDLayout.getVBaseClassOffset(CurRD);
} else {
ThisOffset += Layout.getBaseClassOffset(CurRD);
}
}
- if (isa<CXXDestructorDecl>(MD)) {
+ if (isa<CXXDestructorDecl>(Overrider.Method)) {
if (LastVBaseOffset.isZero()) {
// If a "Base" class has at least one non-virtual base with a virtual
// destructor, the "Base" virtual destructor will take the address
// of the "Base" subobject as the "this" argument.
- return Base.getBaseOffset();
+ ThisOffset = Overrider.Offset;
} else {
// A virtual destructor of a virtual base takes the address of the
// virtual base subobject as the "this" argument.
- return LastVBaseOffset;
+ ThisOffset = LastVBaseOffset;
}
}
@@ -2734,39 +2729,35 @@ void VFTableBuilder::CalculateVtordispAdjustment(
const ASTRecordLayout::VBaseOffsetsMapTy &VBaseMap =
MostDerivedClassLayout.getVBaseOffsetsMap();
const ASTRecordLayout::VBaseOffsetsMapTy::const_iterator &VBaseMapEntry =
- VBaseMap.find(WhichVFPtr.LastVBase);
+ VBaseMap.find(WhichVFPtr.getVBaseWithVPtr());
assert(VBaseMapEntry != VBaseMap.end());
- // Check if we need a vtordisp adjustment at all.
- if (!VBaseMapEntry->second.hasVtorDisp())
+ // If there's no vtordisp or the final overrider is defined in the same vbase
+ // as the initial declaration, we don't need any vtordisp adjustment.
+ if (!VBaseMapEntry->second.hasVtorDisp() ||
+ Overrider.VirtualBase == WhichVFPtr.getVBaseWithVPtr())
return;
- CharUnits VFPtrVBaseOffset = VBaseMapEntry->second.VBaseOffset;
+ // OK, now we know we need to use a vtordisp thunk.
// The implicit vtordisp field is located right before the vbase.
+ CharUnits VFPtrVBaseOffset = VBaseMapEntry->second.VBaseOffset;
TA.Virtual.Microsoft.VtordispOffset =
- (VFPtrVBaseOffset - WhichVFPtr.VFPtrFullOffset).getQuantity() - 4;
-
- // If the final overrider is defined in either:
- // - the most derived class or its non-virtual base or
- // - the same vbase as the initial declaration,
- // a simple vtordisp thunk will suffice.
- const CXXRecordDecl *OverriderRD = Overrider.Method->getParent();
- if (OverriderRD == MostDerivedClass)
- return;
+ (VFPtrVBaseOffset - WhichVFPtr.FullOffsetInMDC).getQuantity() - 4;
- const CXXRecordDecl *OverriderVBase =
- ComputeBaseOffset(Context, OverriderRD, MostDerivedClass).VirtualBase;
- if (!OverriderVBase || OverriderVBase == WhichVFPtr.LastVBase)
+ // A simple vtordisp thunk will suffice if the final overrider is defined
+ // in either the most derived class or its non-virtual base.
+ if (Overrider.Method->getParent() == MostDerivedClass ||
+ !Overrider.VirtualBase)
return;
// Otherwise, we need to do use the dynamic offset of the final overrider
// in order to get "this" adjustment right.
TA.Virtual.Microsoft.VBPtrOffset =
- (VFPtrVBaseOffset + WhichVFPtr.VFPtrOffset -
+ (VFPtrVBaseOffset + WhichVFPtr.NonVirtualOffset -
MostDerivedClassLayout.getVBPtrOffset()).getQuantity();
TA.Virtual.Microsoft.VBOffsetOffset =
Context.getTypeSizeInChars(Context.IntTy).getQuantity() *
- VTables.getVBTableIndex(MostDerivedClass, OverriderVBase);
+ VTables.getVBTableIndex(MostDerivedClass, Overrider.VirtualBase);
TA.NonVirtual = (ThisOffset - Overrider.Offset).getQuantity();
}
@@ -2777,25 +2768,20 @@ static void GroupNewVirtualOverloads(
// Put the virtual methods into VirtualMethods in the proper order:
// 1) Group overloads by declaration name. New groups are added to the
// vftable in the order of their first declarations in this class
- // (including overrides).
+ // (including overrides and non-virtual methods).
// 2) In each group, new overloads appear in the reverse order of declaration.
typedef SmallVector<const CXXMethodDecl *, 1> MethodGroup;
SmallVector<MethodGroup, 10> Groups;
typedef llvm::DenseMap<DeclarationName, unsigned> VisitedGroupIndicesTy;
VisitedGroupIndicesTy VisitedGroupIndices;
- for (CXXRecordDecl::method_iterator I = RD->method_begin(),
- E = RD->method_end(); I != E; ++I) {
- const CXXMethodDecl *MD = *I;
- if (!MD->isVirtual())
- continue;
-
+ for (const auto *MD : RD->methods()) {
VisitedGroupIndicesTy::iterator J;
bool Inserted;
- llvm::tie(J, Inserted) = VisitedGroupIndices.insert(
+ std::tie(J, Inserted) = VisitedGroupIndices.insert(
std::make_pair(MD->getDeclName(), Groups.size()));
if (Inserted)
- Groups.push_back(MethodGroup(1, MD));
- else
+ Groups.push_back(MethodGroup());
+ if (MD->isVirtual())
Groups[J->second].push_back(MD);
}
@@ -2803,6 +2789,32 @@ static void GroupNewVirtualOverloads(
VirtualMethods.append(Groups[I].rbegin(), Groups[I].rend());
}
+/// We need a return adjusting thunk for this method if its return type is
+/// not trivially convertible to the return type of any of its overridden
+/// methods.
+bool VFTableBuilder::NeedsReturnAdjustingThunk(const CXXMethodDecl *MD) {
+ OverriddenMethodsSetTy OverriddenMethods;
+ ComputeAllOverriddenMethods(MD, OverriddenMethods);
+ for (OverriddenMethodsSetTy::iterator I = OverriddenMethods.begin(),
+ E = OverriddenMethods.end();
+ I != E; ++I) {
+ const CXXMethodDecl *OverriddenMD = *I;
+ BaseOffset Adjustment =
+ ComputeReturnAdjustmentBaseOffset(Context, MD, OverriddenMD);
+ if (!Adjustment.isEmpty())
+ return true;
+ }
+ return false;
+}
+
+static bool isDirectVBase(const CXXRecordDecl *Base, const CXXRecordDecl *RD) {
+ for (const auto &B : RD->bases()) {
+ if (B.isVirtual() && B.getType()->getAsCXXRecordDecl() == Base)
+ return true;
+ }
+ return false;
+}
+
void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
const CXXRecordDecl *LastVBase,
BasesSetVectorTy &VisitedBases) {
@@ -2814,11 +2826,11 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
// See if this class expands a vftable of the base we look at, which is either
// the one defined by the vfptr base path or the primary base of the current class.
- const CXXRecordDecl *NextBase = 0, *NextLastVBase = LastVBase;
+ const CXXRecordDecl *NextBase = nullptr, *NextLastVBase = LastVBase;
CharUnits NextBaseOffset;
- if (BaseDepth < WhichVFPtr.PathToBaseWithVFPtr.size()) {
- NextBase = WhichVFPtr.PathToBaseWithVFPtr[BaseDepth];
- if (Layout.getVBaseOffsetsMap().count(NextBase)) {
+ if (BaseDepth < WhichVFPtr.PathToBaseWithVPtr.size()) {
+ NextBase = WhichVFPtr.PathToBaseWithVPtr[BaseDepth];
+ if (isDirectVBase(NextBase, RD)) {
NextLastVBase = NextBase;
NextBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(NextBase);
} else {
@@ -2856,13 +2868,21 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
FinalOverriders::OverriderInfo Overrider =
Overriders.getOverrider(MD, Base.getBaseOffset());
- ThisAdjustment ThisAdjustmentOffset;
- bool ForceThunk = false;
+ const CXXMethodDecl *OverriderMD = Overrider.Method;
+ const CXXMethodDecl *OverriddenMD =
+ FindNearestOverriddenMethod(MD, VisitedBases);
- // Check if this virtual member function overrides
- // a method in one of the visited bases.
- if (const CXXMethodDecl *OverriddenMD =
- FindNearestOverriddenMethod(MD, VisitedBases)) {
+ ThisAdjustment ThisAdjustmentOffset;
+ bool ReturnAdjustingThunk = false;
+ CharUnits ThisOffset = ComputeThisOffset(Overrider);
+ ThisAdjustmentOffset.NonVirtual =
+ (ThisOffset - WhichVFPtr.FullOffsetInMDC).getQuantity();
+ if ((OverriddenMD || OverriderMD != MD) &&
+ WhichVFPtr.getVBaseWithVPtr())
+ CalculateVtordispAdjustment(Overrider, ThisOffset, ThisAdjustmentOffset);
+
+ if (OverriddenMD) {
+ // If MD overrides anything in this vftable, we need to update the entries.
MethodInfoMapTy::iterator OverriddenMDIterator =
MethodInfoMap.find(OverriddenMD);
@@ -2872,23 +2892,7 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
MethodInfo &OverriddenMethodInfo = OverriddenMDIterator->second;
- // Create a this-adjusting thunk if needed.
- CharUnits TI = ComputeThisOffset(MD, Base, Overrider);
- if (TI != WhichVFPtr.VFPtrFullOffset) {
- ThisAdjustmentOffset.NonVirtual =
- (TI - WhichVFPtr.VFPtrFullOffset).getQuantity();
- }
-
- if (WhichVFPtr.LastVBase)
- CalculateVtordispAdjustment(Overrider, TI, ThisAdjustmentOffset);
-
- if (!ThisAdjustmentOffset.isEmpty()) {
- VTableThunks[OverriddenMethodInfo.VFTableIndex].This =
- ThisAdjustmentOffset;
- AddThunk(MD, VTableThunks[OverriddenMethodInfo.VFTableIndex]);
- }
-
- if (MD->getResultType() == OverriddenMD->getResultType()) {
+ if (!NeedsReturnAdjustingThunk(MD)) {
// No return adjustment needed - just replace the overridden method info
// with the current info.
MethodInfo MI(OverriddenMethodInfo.VBTableIndex,
@@ -2899,33 +2903,17 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
"Should not have method info for this method yet!");
MethodInfoMap.insert(std::make_pair(MD, MI));
continue;
- } else {
- // In case we need a return adjustment, we'll add a new slot for
- // the overrider and put a return-adjusting thunk where the overridden
- // method was in the vftable.
- // For now, just mark the overriden method as shadowed by a new slot.
- OverriddenMethodInfo.Shadowed = true;
- ForceThunk = true;
-
- // Also apply this adjustment to the shadowed slots.
- if (!ThisAdjustmentOffset.isEmpty()) {
- // FIXME: this is O(N^2), can be O(N).
- const CXXMethodDecl *SubOverride = OverriddenMD;
- while ((SubOverride =
- FindNearestOverriddenMethod(SubOverride, VisitedBases))) {
- MethodInfoMapTy::iterator SubOverrideIterator =
- MethodInfoMap.find(SubOverride);
- if (SubOverrideIterator == MethodInfoMap.end())
- break;
- MethodInfo &SubOverrideMI = SubOverrideIterator->second;
- assert(SubOverrideMI.Shadowed);
- VTableThunks[SubOverrideMI.VFTableIndex].This =
- ThisAdjustmentOffset;
- AddThunk(MD, VTableThunks[SubOverrideMI.VFTableIndex]);
- }
- }
}
- } else if (Base.getBaseOffset() != WhichVFPtr.VFPtrFullOffset ||
+
+ // In case we need a return adjustment, we'll add a new slot for
+ // the overrider. Mark the overriden method as shadowed by the new slot.
+ OverriddenMethodInfo.Shadowed = true;
+
+ // Force a special name mangling for a return-adjusting thunk
+ // unless the method is the final overrider without this adjustment.
+ ReturnAdjustingThunk =
+ !(MD == OverriderMD && ThisAdjustmentOffset.isEmpty());
+ } else if (Base.getBaseOffset() != WhichVFPtr.FullOffsetInMDC ||
MD->size_overridden_methods()) {
// Skip methods that don't belong to the vftable of the current class,
// e.g. each method that wasn't seen in any of the visited sub-bases
@@ -2937,14 +2925,13 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
// it requires return adjustment. Insert the method info for this method.
unsigned VBIndex =
LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase) : 0;
- MethodInfo MI(VBIndex, Components.size());
+ MethodInfo MI(VBIndex,
+ HasRTTIComponent ? Components.size() - 1 : Components.size());
assert(!MethodInfoMap.count(MD) &&
"Should not have method info for this method yet!");
MethodInfoMap.insert(std::make_pair(MD, MI));
- const CXXMethodDecl *OverriderMD = Overrider.Method;
-
// Check if this overrider needs a return adjustment.
// We don't want to do this for pure virtual member functions.
BaseOffset ReturnAdjustmentOffset;
@@ -2954,7 +2941,7 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD);
}
if (!ReturnAdjustmentOffset.isEmpty()) {
- ForceThunk = true;
+ ReturnAdjustingThunk = true;
ReturnAdjustment.NonVirtual =
ReturnAdjustmentOffset.NonVirtualOffset.getQuantity();
if (ReturnAdjustmentOffset.VirtualBase) {
@@ -2969,40 +2956,30 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
}
AddMethod(OverriderMD, ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment,
- ForceThunk ? MD : 0));
+ ReturnAdjustingThunk ? MD : nullptr));
}
}
-void PrintBasePath(const VFPtrInfo::BasePath &Path, raw_ostream &Out) {
- for (VFPtrInfo::BasePath::const_reverse_iterator I = Path.rbegin(),
+static void PrintBasePath(const VPtrInfo::BasePath &Path, raw_ostream &Out) {
+ for (VPtrInfo::BasePath::const_reverse_iterator I = Path.rbegin(),
E = Path.rend(); I != E; ++I) {
- Out << "'" << (*I)->getQualifiedNameAsString() << "' in ";
+ Out << "'";
+ (*I)->printQualifiedName(Out);
+ Out << "' in ";
}
}
-struct MicrosoftThunkInfoStableSortComparator {
- bool operator() (const ThunkInfo &LHS, const ThunkInfo &RHS) {
- if (LHS.This != RHS.This)
- return LHS.This < RHS.This;
-
- if (LHS.Return != RHS.Return)
- return LHS.Return < RHS.Return;
-
- // Keep different thunks with the same adjustments in the order they
- // were put into the vector.
- return false;
- }
-};
-
static void dumpMicrosoftThunkAdjustment(const ThunkInfo &TI, raw_ostream &Out,
bool ContinueFirstLine) {
const ReturnAdjustment &R = TI.Return;
bool Multiline = false;
- const char *LinePrefix = "\n ";
- if (!R.isEmpty()) {
+ const char *LinePrefix = "\n ";
+ if (!R.isEmpty() || TI.Method) {
if (!ContinueFirstLine)
Out << LinePrefix;
- Out << "[return adjustment: ";
+ Out << "[return adjustment (to type '"
+ << TI.Method->getReturnType().getCanonicalType().getAsString()
+ << "'): ";
if (R.Virtual.Microsoft.VBPtrOffset)
Out << "vbptr at offset " << R.Virtual.Microsoft.VBPtrOffset << ", ";
if (R.Virtual.Microsoft.VBIndex)
@@ -3021,7 +2998,7 @@ static void dumpMicrosoftThunkAdjustment(const ThunkInfo &TI, raw_ostream &Out,
Out << "vtordisp at " << T.Virtual.Microsoft.VtordispOffset << ", ";
if (T.Virtual.Microsoft.VBPtrOffset) {
Out << "vbptr at " << T.Virtual.Microsoft.VBPtrOffset
- << " to the left, ";
+ << " to the left,";
assert(T.Virtual.Microsoft.VBOffsetOffset > 0);
Out << LinePrefix << " vboffset at "
<< T.Virtual.Microsoft.VBOffsetOffset << " in the vbtable, ";
@@ -3033,9 +3010,11 @@ static void dumpMicrosoftThunkAdjustment(const ThunkInfo &TI, raw_ostream &Out,
void VFTableBuilder::dumpLayout(raw_ostream &Out) {
Out << "VFTable for ";
- PrintBasePath(WhichVFPtr.PathToBaseWithVFPtr, Out);
- Out << "'" << MostDerivedClass->getQualifiedNameAsString();
- Out << "' (" << Components.size() << " entries).\n";
+ PrintBasePath(WhichVFPtr.PathToBaseWithVPtr, Out);
+ Out << "'";
+ MostDerivedClass->printQualifiedName(Out);
+ Out << "' (" << Components.size()
+ << (Components.size() == 1 ? " entry" : " entries") << ").\n";
for (unsigned I = 0, E = Components.size(); I != E; ++I) {
Out << llvm::format("%4d | ", I);
@@ -3045,12 +3024,15 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) {
// Dump the component.
switch (Component.getKind()) {
case VTableComponent::CK_RTTI:
- Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI";
+ Component.getRTTIDecl()->printQualifiedName(Out);
+ Out << " RTTI";
break;
case VTableComponent::CK_FunctionPointer: {
const CXXMethodDecl *MD = Component.getFunctionDecl();
+ // FIXME: Figure out how to print the real thunk type, since they can
+ // differ in the return type.
std::string Str = PredefinedExpr::ComputeName(
PredefinedExpr::PrettyFunctionNoVirtual, MD);
Out << Str;
@@ -3072,7 +3054,7 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) {
case VTableComponent::CK_DeletingDtorPointer: {
const CXXDestructorDecl *DD = Component.getDestructorDecl();
- Out << DD->getQualifiedNameAsString();
+ DD->printQualifiedName(Out);
Out << "() [scalar deleting]";
if (DD->isPure())
@@ -3124,7 +3106,11 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) {
ThunkInfoVectorTy ThunksVector = Thunks[MD];
std::stable_sort(ThunksVector.begin(), ThunksVector.end(),
- MicrosoftThunkInfoStableSortComparator());
+ [](const ThunkInfo &LHS, const ThunkInfo &RHS) {
+ // Keep different thunks with the same adjustments in the order they
+ // were put into the vector.
+ return std::tie(LHS.This, LHS.Return) < std::tie(RHS.This, RHS.Return);
+ });
Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
@@ -3140,123 +3126,170 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) {
Out << '\n';
}
}
-}
+
+ Out.flush();
}
-void MicrosoftVTableContext::enumerateVFPtrs(
- const CXXRecordDecl *MostDerivedClass,
- const ASTRecordLayout &MostDerivedClassLayout, BaseSubobject Base,
- const CXXRecordDecl *LastVBase,
- const VFPtrInfo::BasePath &PathFromCompleteClass,
- BasesSetVectorTy &VisitedVBases,
- VFPtrListTy &Result) {
- const CXXRecordDecl *CurrentClass = Base.getBase();
- CharUnits OffsetInCompleteClass = Base.getBaseOffset();
- const ASTRecordLayout &CurrentClassLayout =
- Context.getASTRecordLayout(CurrentClass);
-
- if (CurrentClassLayout.hasOwnVFPtr()) {
- if (LastVBase) {
- uint64_t VBIndex = getVBTableIndex(MostDerivedClass, LastVBase);
- assert(VBIndex > 0 && "vbases must have vbindex!");
- CharUnits VFPtrOffset =
- OffsetInCompleteClass -
- MostDerivedClassLayout.getVBaseClassOffset(LastVBase);
- Result.push_back(VFPtrInfo(VBIndex, LastVBase, VFPtrOffset,
- PathFromCompleteClass, OffsetInCompleteClass));
- } else {
- Result.push_back(VFPtrInfo(OffsetInCompleteClass, PathFromCompleteClass));
- }
+static bool setsIntersect(const llvm::SmallPtrSet<const CXXRecordDecl *, 4> &A,
+ const ArrayRef<const CXXRecordDecl *> &B) {
+ for (ArrayRef<const CXXRecordDecl *>::iterator I = B.begin(), E = B.end();
+ I != E; ++I) {
+ if (A.count(*I))
+ return true;
}
+ return false;
+}
- for (CXXRecordDecl::base_class_const_iterator I = CurrentClass->bases_begin(),
- E = CurrentClass->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
+static bool rebucketPaths(VPtrInfoVector &Paths);
- CharUnits NextBaseOffset;
- const CXXRecordDecl *NextLastVBase;
- if (I->isVirtual()) {
- if (!VisitedVBases.insert(BaseDecl))
- continue;
- NextBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
- NextLastVBase = BaseDecl;
- } else {
- NextBaseOffset = OffsetInCompleteClass +
- CurrentClassLayout.getBaseClassOffset(BaseDecl);
- NextLastVBase = LastVBase;
- }
+/// Produces MSVC-compatible vbtable data. The symbols produced by this
+/// algorithm match those produced by MSVC 2012 and newer, which is different
+/// from MSVC 2010.
+///
+/// MSVC 2012 appears to minimize the vbtable names using the following
+/// algorithm. First, walk the class hierarchy in the usual order, depth first,
+/// left to right, to find all of the subobjects which contain a vbptr field.
+/// Visiting each class node yields a list of inheritance paths to vbptrs. Each
+/// record with a vbptr creates an initially empty path.
+///
+/// To combine paths from child nodes, the paths are compared to check for
+/// ambiguity. Paths are "ambiguous" if multiple paths have the same set of
+/// components in the same order. Each group of ambiguous paths is extended by
+/// appending the class of the base from which it came. If the current class
+/// node produced an ambiguous path, its path is extended with the current class.
+/// After extending paths, MSVC again checks for ambiguity, and extends any
+/// ambiguous path which wasn't already extended. Because each node yields an
+/// unambiguous set of paths, MSVC doesn't need to extend any path more than once
+/// to produce an unambiguous set of paths.
+///
+/// TODO: Presumably vftables use the same algorithm.
+void MicrosoftVTableContext::computeVTablePaths(bool ForVBTables,
+ const CXXRecordDecl *RD,
+ VPtrInfoVector &Paths) {
+ assert(Paths.empty());
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- VFPtrInfo::BasePath NewPath = PathFromCompleteClass;
- NewPath.push_back(BaseDecl);
- BaseSubobject NextBase(BaseDecl, NextBaseOffset);
+ // Base case: this subobject has its own vptr.
+ if (ForVBTables ? Layout.hasOwnVBPtr() : Layout.hasOwnVFPtr())
+ Paths.push_back(new VPtrInfo(RD));
- enumerateVFPtrs(MostDerivedClass, MostDerivedClassLayout, NextBase,
- NextLastVBase, NewPath, VisitedVBases, Result);
- }
-}
+ // Recursive case: get all the vbtables from our bases and remove anything
+ // that shares a virtual base.
+ llvm::SmallPtrSet<const CXXRecordDecl*, 4> VBasesSeen;
+ for (const auto &B : RD->bases()) {
+ const CXXRecordDecl *Base = B.getType()->getAsCXXRecordDecl();
+ if (B.isVirtual() && VBasesSeen.count(Base))
+ continue;
-/// CalculatePathToMangle - Calculate the subset of records that should be used
-/// to mangle the vftable for the given vfptr.
-/// Should only be called if a class has multiple vftables.
-static void
-CalculatePathToMangle(const CXXRecordDecl *RD, VFPtrInfo &VFPtr) {
- // FIXME: In some rare cases this code produces a slightly incorrect mangling.
- // It's very likely that the vbtable mangling code can be adjusted to mangle
- // both vftables and vbtables correctly.
-
- VFPtrInfo::BasePath &FullPath = VFPtr.PathToBaseWithVFPtr;
- if (FullPath.empty()) {
- // Mangle the class's own vftable.
- assert(RD->getNumVBases() &&
- "Something's wrong: if the most derived "
- "class has more than one vftable, it can only have its own "
- "vftable if it has vbases");
- VFPtr.PathToMangle.push_back(RD);
- return;
- }
+ if (!Base->isDynamicClass())
+ continue;
+
+ const VPtrInfoVector &BasePaths =
+ ForVBTables ? enumerateVBTables(Base) : getVFPtrOffsets(Base);
- unsigned Begin = 0;
+ for (VPtrInfo *BaseInfo : BasePaths) {
+ // Don't include the path if it goes through a virtual base that we've
+ // already included.
+ if (setsIntersect(VBasesSeen, BaseInfo->ContainingVBases))
+ continue;
- // First, skip all the bases before the vbase.
- if (VFPtr.LastVBase) {
- while (FullPath[Begin] != VFPtr.LastVBase) {
- Begin++;
- assert(Begin < FullPath.size());
+ // Copy the path and adjust it as necessary.
+ VPtrInfo *P = new VPtrInfo(*BaseInfo);
+
+ // We mangle Base into the path if the path would've been ambiguous and it
+ // wasn't already extended with Base.
+ if (P->MangledPath.empty() || P->MangledPath.back() != Base)
+ P->NextBaseToMangle = Base;
+
+ // Keep track of the full path.
+ // FIXME: Why do we need this?
+ P->PathToBaseWithVPtr.insert(P->PathToBaseWithVPtr.begin(), Base);
+
+ // Keep track of which vtable the derived class is going to extend with
+ // new methods or bases. We append to either the vftable of our primary
+ // base, or the first non-virtual base that has a vbtable.
+ if (P->ReusingBase == Base &&
+ Base == (ForVBTables ? Layout.getBaseSharingVBPtr()
+ : Layout.getPrimaryBase()))
+ P->ReusingBase = RD;
+
+ // Keep track of the full adjustment from the MDC to this vtable. The
+ // adjustment is captured by an optional vbase and a non-virtual offset.
+ if (B.isVirtual())
+ P->ContainingVBases.push_back(Base);
+ else if (P->ContainingVBases.empty())
+ P->NonVirtualOffset += Layout.getBaseClassOffset(Base);
+
+ // Update the full offset in the MDC.
+ P->FullOffsetInMDC = P->NonVirtualOffset;
+ if (const CXXRecordDecl *VB = P->getVBaseWithVPtr())
+ P->FullOffsetInMDC += Layout.getVBaseClassOffset(VB);
+
+ Paths.push_back(P);
}
+
+ if (B.isVirtual())
+ VBasesSeen.insert(Base);
+
+ // After visiting any direct base, we've transitively visited all of its
+ // morally virtual bases.
+ for (const auto &VB : Base->vbases())
+ VBasesSeen.insert(VB.getType()->getAsCXXRecordDecl());
}
- // Then, put the rest of the base path in the reverse order.
- for (unsigned I = FullPath.size(); I != Begin; --I) {
- const CXXRecordDecl *CurBase = FullPath[I - 1],
- *ItsBase = (I == 1) ? RD : FullPath[I - 2];
- bool BaseIsVirtual = false;
- for (CXXRecordDecl::base_class_const_iterator J = ItsBase->bases_begin(),
- F = ItsBase->bases_end(); J != F; ++J) {
- if (J->getType()->getAsCXXRecordDecl() == CurBase) {
- BaseIsVirtual = J->isVirtual();
- break;
- }
- }
+ // Sort the paths into buckets, and if any of them are ambiguous, extend all
+ // paths in ambiguous buckets.
+ bool Changed = true;
+ while (Changed)
+ Changed = rebucketPaths(Paths);
+}
- // Should skip the current base if it is a non-virtual base with no siblings.
- if (BaseIsVirtual || ItsBase->getNumBases() != 1)
- VFPtr.PathToMangle.push_back(CurBase);
+static bool extendPath(VPtrInfo *P) {
+ if (P->NextBaseToMangle) {
+ P->MangledPath.push_back(P->NextBaseToMangle);
+ P->NextBaseToMangle = nullptr;// Prevent the path from being extended twice.
+ return true;
}
+ return false;
}
-void MicrosoftVTableContext::enumerateVFPtrs(
- const CXXRecordDecl *ForClass,
- MicrosoftVTableContext::VFPtrListTy &Result) {
- Result.clear();
- const ASTRecordLayout &ClassLayout = Context.getASTRecordLayout(ForClass);
- BasesSetVectorTy VisitedVBases;
- enumerateVFPtrs(ForClass, ClassLayout,
- BaseSubobject(ForClass, CharUnits::Zero()), 0,
- VFPtrInfo::BasePath(), VisitedVBases, Result);
- if (Result.size() > 1) {
- for (unsigned I = 0, E = Result.size(); I != E; ++I)
- CalculatePathToMangle(ForClass, Result[I]);
+static bool rebucketPaths(VPtrInfoVector &Paths) {
+ // What we're essentially doing here is bucketing together ambiguous paths.
+ // Any bucket with more than one path in it gets extended by NextBase, which
+ // is usually the direct base of the inherited the vbptr. This code uses a
+ // sorted vector to implement a multiset to form the buckets. Note that the
+ // ordering is based on pointers, but it doesn't change our output order. The
+ // current algorithm is designed to match MSVC 2012's names.
+ VPtrInfoVector PathsSorted(Paths);
+ std::sort(PathsSorted.begin(), PathsSorted.end(),
+ [](const VPtrInfo *LHS, const VPtrInfo *RHS) {
+ return LHS->MangledPath < RHS->MangledPath;
+ });
+ bool Changed = false;
+ for (size_t I = 0, E = PathsSorted.size(); I != E;) {
+ // Scan forward to find the end of the bucket.
+ size_t BucketStart = I;
+ do {
+ ++I;
+ } while (I != E && PathsSorted[BucketStart]->MangledPath ==
+ PathsSorted[I]->MangledPath);
+
+ // If this bucket has multiple paths, extend them all.
+ if (I - BucketStart > 1) {
+ for (size_t II = BucketStart; II != I; ++II)
+ Changed |= extendPath(PathsSorted[II]);
+ assert(Changed && "no paths were extended to fix ambiguity");
+ }
}
+ return Changed;
+}
+
+MicrosoftVTableContext::~MicrosoftVTableContext() {
+ for (auto &P : VFPtrLocations)
+ llvm::DeleteContainerPointers(*P.second);
+ llvm::DeleteContainerSeconds(VFPtrLocations);
+ llvm::DeleteContainerSeconds(VFTableLayouts);
+ llvm::DeleteContainerSeconds(VBaseInfo);
}
void MicrosoftVTableContext::computeVTableRelatedInformation(
@@ -3269,24 +3302,31 @@ void MicrosoftVTableContext::computeVTableRelatedInformation(
const VTableLayout::AddressPointsMapTy EmptyAddressPointsMap;
- VFPtrListTy &VFPtrs = VFPtrLocations[RD];
- enumerateVFPtrs(RD, VFPtrs);
+ VPtrInfoVector *VFPtrs = new VPtrInfoVector();
+ computeVTablePaths(/*ForVBTables=*/false, RD, *VFPtrs);
+ VFPtrLocations[RD] = VFPtrs;
MethodVFTableLocationsTy NewMethodLocations;
- for (VFPtrListTy::iterator I = VFPtrs.begin(), E = VFPtrs.end();
+ for (VPtrInfoVector::iterator I = VFPtrs->begin(), E = VFPtrs->end();
I != E; ++I) {
VFTableBuilder Builder(*this, RD, *I);
- VFTableIdTy id(RD, I->VFPtrFullOffset);
+ VFTableIdTy id(RD, (*I)->FullOffsetInMDC);
assert(VFTableLayouts.count(id) == 0);
SmallVector<VTableLayout::VTableThunkTy, 1> VTableThunks(
Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
VFTableLayouts[id] = new VTableLayout(
Builder.getNumVTableComponents(), Builder.vtable_component_begin(),
VTableThunks.size(), VTableThunks.data(), EmptyAddressPointsMap, true);
- NewMethodLocations.insert(Builder.vtable_indices_begin(),
- Builder.vtable_indices_end());
Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
+
+ for (const auto &Loc : Builder.vtable_locations()) {
+ GlobalDecl GD = Loc.first;
+ MethodVFTableLocation NewLoc = Loc.second;
+ auto M = NewMethodLocations.find(GD);
+ if (M == NewMethodLocations.end() || NewLoc < M->second)
+ NewMethodLocations[GD] = NewLoc;
+ }
}
MethodVFTableLocations.insert(NewMethodLocations.begin(),
@@ -3324,8 +3364,10 @@ void MicrosoftVTableContext::dumpMethodLocations(
// Print the vtable indices for all the member functions.
if (!IndicesMap.empty()) {
Out << "VFTable indices for ";
- Out << "'" << RD->getQualifiedNameAsString();
- Out << "' (" << IndicesMap.size() << " entries).\n";
+ Out << "'";
+ RD->printQualifiedName(Out);
+ Out << "' (" << IndicesMap.size()
+ << (IndicesMap.size() == 1 ? " entry" : " entries") << ").\n";
CharUnits LastVFPtrOffset = CharUnits::fromQuantity(-1);
uint64_t LastVBIndex = 0;
@@ -3352,49 +3394,66 @@ void MicrosoftVTableContext::dumpMethodLocations(
}
Out << '\n';
}
+
+ Out.flush();
}
-void MicrosoftVTableContext::computeVBTableRelatedInformation(
+const VirtualBaseInfo *MicrosoftVTableContext::computeVBTableRelatedInformation(
const CXXRecordDecl *RD) {
- if (ComputedVBTableIndices.count(RD))
- return;
- ComputedVBTableIndices.insert(RD);
+ VirtualBaseInfo *VBI;
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- BasesSetVectorTy VisitedBases;
+ {
+ // Get or create a VBI for RD. Don't hold a reference to the DenseMap cell,
+ // as it may be modified and rehashed under us.
+ VirtualBaseInfo *&Entry = VBaseInfo[RD];
+ if (Entry)
+ return Entry;
+ Entry = VBI = new VirtualBaseInfo();
+ }
+
+ computeVTablePaths(/*ForVBTables=*/true, RD, VBI->VBPtrPaths);
// First, see if the Derived class shared the vbptr with a non-virtual base.
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
if (const CXXRecordDecl *VBPtrBase = Layout.getBaseSharingVBPtr()) {
- // If the Derived class shares the vbptr with a non-virtual base,
- // it inherits its vbase indices.
- computeVBTableRelatedInformation(VBPtrBase);
- for (CXXRecordDecl::base_class_const_iterator I = VBPtrBase->vbases_begin(),
- E = VBPtrBase->vbases_end(); I != E; ++I) {
- const CXXRecordDecl *SubVBase = I->getType()->getAsCXXRecordDecl();
- assert(VBTableIndices.count(ClassPairTy(VBPtrBase, SubVBase)));
- VBTableIndices[ClassPairTy(RD, SubVBase)] =
- VBTableIndices[ClassPairTy(VBPtrBase, SubVBase)];
- VisitedBases.insert(SubVBase);
- }
+ // If the Derived class shares the vbptr with a non-virtual base, the shared
+ // virtual bases come first so that the layout is the same.
+ const VirtualBaseInfo *BaseInfo =
+ computeVBTableRelatedInformation(VBPtrBase);
+ VBI->VBTableIndices.insert(BaseInfo->VBTableIndices.begin(),
+ BaseInfo->VBTableIndices.end());
}
// New vbases are added to the end of the vbtable.
// Skip the self entry and vbases visited in the non-virtual base, if any.
- unsigned VBTableIndex = 1 + VisitedBases.size();
- for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
- E = RD->vbases_end(); I != E; ++I) {
- const CXXRecordDecl *CurVBase = I->getType()->getAsCXXRecordDecl();
- if (VisitedBases.insert(CurVBase))
- VBTableIndices[ClassPairTy(RD, CurVBase)] = VBTableIndex++;
+ unsigned VBTableIndex = 1 + VBI->VBTableIndices.size();
+ for (const auto &VB : RD->vbases()) {
+ const CXXRecordDecl *CurVBase = VB.getType()->getAsCXXRecordDecl();
+ if (!VBI->VBTableIndices.count(CurVBase))
+ VBI->VBTableIndices[CurVBase] = VBTableIndex++;
}
+
+ return VBI;
+}
+
+unsigned MicrosoftVTableContext::getVBTableIndex(const CXXRecordDecl *Derived,
+ const CXXRecordDecl *VBase) {
+ const VirtualBaseInfo *VBInfo = computeVBTableRelatedInformation(Derived);
+ assert(VBInfo->VBTableIndices.count(VBase));
+ return VBInfo->VBTableIndices.find(VBase)->second;
+}
+
+const VPtrInfoVector &
+MicrosoftVTableContext::enumerateVBTables(const CXXRecordDecl *RD) {
+ return computeVBTableRelatedInformation(RD)->VBPtrPaths;
}
-const MicrosoftVTableContext::VFPtrListTy &
+const VPtrInfoVector &
MicrosoftVTableContext::getVFPtrOffsets(const CXXRecordDecl *RD) {
computeVTableRelatedInformation(RD);
assert(VFPtrLocations.count(RD) && "Couldn't find vfptr locations");
- return VFPtrLocations[RD];
+ return *VFPtrLocations[RD];
}
const VTableLayout &
diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp
index f6dcb9779aba..23708e2ff0c7 100644
--- a/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -58,11 +58,8 @@ struct MatchKey {
BoundNodesTreeBuilder BoundNodes;
bool operator<(const MatchKey &Other) const {
- if (MatcherID != Other.MatcherID)
- return MatcherID < Other.MatcherID;
- if (Node != Other.Node)
- return Node < Other.Node;
- return BoundNodes < Other.BoundNodes;
+ return std::tie(MatcherID, Node, BoundNodes) <
+ std::tie(Other.MatcherID, Other.Node, Other.BoundNodes);
}
};
@@ -140,7 +137,7 @@ public:
// of the public API of this class.
bool TraverseDecl(Decl *DeclNode) {
ScopedIncrement ScopedDepth(&CurrentDepth);
- return (DeclNode == NULL) || traverse(*DeclNode);
+ return (DeclNode == nullptr) || traverse(*DeclNode);
}
bool TraverseStmt(Stmt *StmtNode) {
ScopedIncrement ScopedDepth(&CurrentDepth);
@@ -148,11 +145,11 @@ public:
if (Traversal ==
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses) {
const Expr *ExprNode = dyn_cast_or_null<Expr>(StmtNode);
- if (ExprNode != NULL) {
+ if (ExprNode) {
StmtToTraverse = ExprNode->IgnoreParenImpCasts();
}
}
- return (StmtToTraverse == NULL) || traverse(*StmtToTraverse);
+ return (StmtToTraverse == nullptr) || traverse(*StmtToTraverse);
}
// We assume that the QualType and the contained type are on the same
// hierarchy level. Thus, we try to match either of them.
@@ -183,7 +180,7 @@ public:
}
bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
ScopedIncrement ScopedDepth(&CurrentDepth);
- return (NNS == NULL) || traverse(*NNS);
+ return (NNS == nullptr) || traverse(*NNS);
}
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
if (!NNS)
@@ -272,8 +269,8 @@ private:
// traversal should continue after this function returns.
template <typename T>
bool traverse(const T &Node) {
- TOOLING_COMPILE_ASSERT(IsBaseType<T>::value,
- traverse_can_only_be_instantiated_with_base_type);
+ static_assert(IsBaseType<T>::value,
+ "traverse can only be instantiated with base type");
if (!match(Node))
return false;
return baseTraverse(Node);
@@ -298,7 +295,7 @@ public:
MatchASTVisitor(
std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> > *
MatcherCallbackPairs)
- : MatcherCallbackPairs(MatcherCallbackPairs), ActiveASTContext(NULL) {}
+ : MatcherCallbackPairs(MatcherCallbackPairs), ActiveASTContext(nullptr) {}
void onStartOfTranslationUnit() {
for (std::vector<std::pair<internal::DynTypedMatcher,
@@ -410,36 +407,36 @@ public:
return Visitor.findMatch(Node);
}
- virtual bool classIsDerivedFrom(const CXXRecordDecl *Declaration,
- const Matcher<NamedDecl> &Base,
- BoundNodesTreeBuilder *Builder);
+ bool classIsDerivedFrom(const CXXRecordDecl *Declaration,
+ const Matcher<NamedDecl> &Base,
+ BoundNodesTreeBuilder *Builder) override;
// Implements ASTMatchFinder::matchesChildOf.
- virtual bool matchesChildOf(const ast_type_traits::DynTypedNode &Node,
- const DynTypedMatcher &Matcher,
- BoundNodesTreeBuilder *Builder,
- TraversalKind Traversal,
- BindKind Bind) {
+ bool matchesChildOf(const ast_type_traits::DynTypedNode &Node,
+ const DynTypedMatcher &Matcher,
+ BoundNodesTreeBuilder *Builder,
+ TraversalKind Traversal,
+ BindKind Bind) override {
if (ResultCache.size() > MaxMemoizationEntries)
ResultCache.clear();
return memoizedMatchesRecursively(Node, Matcher, Builder, 1, Traversal,
Bind);
}
// Implements ASTMatchFinder::matchesDescendantOf.
- virtual bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node,
- const DynTypedMatcher &Matcher,
- BoundNodesTreeBuilder *Builder,
- BindKind Bind) {
+ bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node,
+ const DynTypedMatcher &Matcher,
+ BoundNodesTreeBuilder *Builder,
+ BindKind Bind) override {
if (ResultCache.size() > MaxMemoizationEntries)
ResultCache.clear();
return memoizedMatchesRecursively(Node, Matcher, Builder, INT_MAX,
TK_AsIs, Bind);
}
// Implements ASTMatchFinder::matchesAncestorOf.
- virtual bool matchesAncestorOf(const ast_type_traits::DynTypedNode &Node,
- const DynTypedMatcher &Matcher,
- BoundNodesTreeBuilder *Builder,
- AncestorMatchMode MatchMode) {
+ bool matchesAncestorOf(const ast_type_traits::DynTypedNode &Node,
+ const DynTypedMatcher &Matcher,
+ BoundNodesTreeBuilder *Builder,
+ AncestorMatchMode MatchMode) override {
// Reset the cache outside of the recursive call to make sure we
// don't invalidate any iterators.
if (ResultCache.size() > MaxMemoizationEntries)
@@ -469,7 +466,7 @@ public:
}
// Implements ASTMatchFinder::getASTContext.
- virtual ASTContext &getASTContext() const { return *ActiveASTContext; }
+ ASTContext &getASTContext() const override { return *ActiveASTContext; }
bool shouldVisitTemplateInstantiations() const { return true; }
bool shouldVisitImplicitCode() const { return true; }
@@ -576,7 +573,7 @@ private:
: Context(Context),
Callback(Callback) {}
- virtual void visitMatch(const BoundNodes& BoundNodesView) {
+ void visitMatch(const BoundNodes& BoundNodesView) override {
Callback->run(MatchFinder::MatchResult(BoundNodesView, Context));
}
@@ -619,21 +616,21 @@ private:
static CXXRecordDecl *getAsCXXRecordDecl(const Type *TypeNode) {
// Type::getAs<...>() drills through typedefs.
- if (TypeNode->getAs<DependentNameType>() != NULL ||
- TypeNode->getAs<DependentTemplateSpecializationType>() != NULL ||
- TypeNode->getAs<TemplateTypeParmType>() != NULL)
+ if (TypeNode->getAs<DependentNameType>() != nullptr ||
+ TypeNode->getAs<DependentTemplateSpecializationType>() != nullptr ||
+ TypeNode->getAs<TemplateTypeParmType>() != nullptr)
// Dependent names and template TypeNode parameters will be matched when
// the template is instantiated.
- return NULL;
+ return nullptr;
TemplateSpecializationType const *TemplateType =
TypeNode->getAs<TemplateSpecializationType>();
- if (TemplateType == NULL) {
+ if (!TemplateType) {
return TypeNode->getAsCXXRecordDecl();
}
if (TemplateType->getTemplateName().isDependent())
// Dependent template specializations will be matched when the
// template is instantiated.
- return NULL;
+ return nullptr;
// For template specialization types which are specializing a template
// declaration which is an explicit or partial specialization of another
@@ -645,7 +642,7 @@ static CXXRecordDecl *getAsCXXRecordDecl(const Type *TypeNode) {
// another template declaration, getAsCXXRecordDecl() returns NULL and
// we get the CXXRecordDecl of the templated declaration.
CXXRecordDecl *SpecializationDecl = TemplateType->getAsCXXRecordDecl();
- if (SpecializationDecl != NULL) {
+ if (SpecializationDecl) {
return SpecializationDecl;
}
NamedDecl *Templated =
@@ -667,17 +664,14 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
BoundNodesTreeBuilder *Builder) {
if (!Declaration->hasDefinition())
return false;
- typedef CXXRecordDecl::base_class_const_iterator BaseIterator;
- for (BaseIterator It = Declaration->bases_begin(),
- End = Declaration->bases_end();
- It != End; ++It) {
- const Type *TypeNode = It->getType().getTypePtr();
+ for (const auto &It : Declaration->bases()) {
+ const Type *TypeNode = It.getType().getTypePtr();
if (typeHasMatchingAlias(TypeNode, Base, Builder))
return true;
CXXRecordDecl *ClassDecl = getAsCXXRecordDecl(TypeNode);
- if (ClassDecl == NULL)
+ if (!ClassDecl)
continue;
if (ClassDecl == Declaration) {
// This can happen for recursive template definitions; if the
@@ -696,7 +690,7 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
}
bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
- if (DeclNode == NULL) {
+ if (!DeclNode) {
return true;
}
match(*DeclNode);
@@ -704,7 +698,7 @@ bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
}
bool MatchASTVisitor::TraverseStmt(Stmt *StmtNode) {
- if (StmtNode == NULL) {
+ if (!StmtNode) {
return true;
}
match(*StmtNode);
@@ -749,8 +743,8 @@ public:
: Finder(Finder), ParsingDone(ParsingDone) {}
private:
- virtual void HandleTranslationUnit(ASTContext &Context) {
- if (ParsingDone != NULL) {
+ void HandleTranslationUnit(ASTContext &Context) override {
+ if (ParsingDone != nullptr) {
ParsingDone->run();
}
Finder->matchAST(Context);
@@ -771,7 +765,7 @@ MatchFinder::MatchResult::MatchResult(const BoundNodes &Nodes,
MatchFinder::MatchCallback::~MatchCallback() {}
MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {}
-MatchFinder::MatchFinder() : ParsingDone(NULL) {}
+MatchFinder::MatchFinder() : ParsingDone(nullptr) {}
MatchFinder::~MatchFinder() {}
diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp
index d15eb54002fe..47b8b6d2f27a 100644
--- a/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -34,6 +34,26 @@ void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) {
}
}
+bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode,
+ ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
+ ArrayRef<DynTypedMatcher> InnerMatchers) {
+ if (InnerMatchers.size() != 1)
+ return false;
+
+ // The 'unless' matcher will always discard the result:
+ // If the inner matcher doesn't match, unless returns true,
+ // but the inner matcher cannot have bound anything.
+ // If the inner matcher matches, the result is false, and
+ // any possible binding will be discarded.
+ // We still need to hand in all the bound nodes up to this
+ // point so the inner matcher can depend on bound nodes,
+ // and we need to actively discard the bound nodes, otherwise
+ // the inner matcher will reset the bound nodes if it doesn't
+ // match, but this would be inversed by 'unless'.
+ BoundNodesTreeBuilder Discard(*Builder);
+ return !InnerMatchers[0].matches(DynNode, Finder, &Discard);
+}
+
bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
diff --git a/lib/ASTMatchers/CMakeLists.txt b/lib/ASTMatchers/CMakeLists.txt
index 4a390a8fc3de..8a8e8c36569f 100644
--- a/lib/ASTMatchers/CMakeLists.txt
+++ b/lib/ASTMatchers/CMakeLists.txt
@@ -5,19 +5,7 @@ set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangASTMatchers
ASTMatchFinder.cpp
ASTMatchersInternal.cpp
- )
-
-add_dependencies(clangASTMatchers
- ClangAttrClasses
- ClangAttrImpl
- ClangAttrList
- ClangCommentNodes
- ClangDeclNodes
- ClangDiagnosticCommon
- ClangStmtNodes
- )
-target_link_libraries(clangASTMatchers
- clangBasic
+ LINK_LIBS
clangAST
)
diff --git a/lib/ASTMatchers/Dynamic/CMakeLists.txt b/lib/ASTMatchers/Dynamic/CMakeLists.txt
index 843341b29728..c0d80adaac0b 100644
--- a/lib/ASTMatchers/Dynamic/CMakeLists.txt
+++ b/lib/ASTMatchers/Dynamic/CMakeLists.txt
@@ -5,12 +5,9 @@ add_clang_library(clangDynamicASTMatchers
VariantValue.cpp
Parser.cpp
Registry.cpp
- )
-
-add_dependencies(clangDynamicASTMatchers
- clangASTMatchers
- )
-target_link_libraries(clangDynamicASTMatchers
+ LINK_LIBS
+ clangAST
clangASTMatchers
+ clangBasic
)
diff --git a/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/lib/ASTMatchers/Dynamic/Diagnostics.cpp
index da2ed9a1d270..b0abdc7cf810 100644
--- a/lib/ASTMatchers/Dynamic/Diagnostics.cpp
+++ b/lib/ASTMatchers/Dynamic/Diagnostics.cpp
@@ -87,7 +87,7 @@ StringRef contextTypeToFormatString(Diagnostics::ContextType Type) {
StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {
switch (Type) {
- case Diagnostics::ET_RegistryNotFound:
+ case Diagnostics::ET_RegistryMatcherNotFound:
return "Matcher not found: $0";
case Diagnostics::ET_RegistryWrongArgCount:
return "Incorrect argument count. (Expected = $0) != (Actual = $1)";
@@ -98,6 +98,8 @@ StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {
case Diagnostics::ET_RegistryAmbiguousOverload:
// TODO: Add type info about the overload error.
return "Ambiguous matcher overload.";
+ case Diagnostics::ET_RegistryValueNotFound:
+ return "Value not found: $0";
case Diagnostics::ET_ParserStringError:
return "Error parsing string token: <$0>";
diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h
index ae0c300d094a..6e144cd26ed9 100644
--- a/lib/ASTMatchers/Dynamic/Marshallers.h
+++ b/lib/ASTMatchers/Dynamic/Marshallers.h
@@ -20,14 +20,12 @@
#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H
#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H
-#include <string>
-
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/Support/type_traits.h"
+#include <string>
namespace clang {
namespace ast_matchers {
@@ -35,6 +33,46 @@ namespace dynamic {
namespace internal {
+struct ArgKind {
+ enum Kind {
+ AK_Matcher,
+ AK_Unsigned,
+ AK_String
+ };
+ ArgKind(Kind K)
+ : K(K) {}
+ ArgKind(ast_type_traits::ASTNodeKind MatcherKind)
+ : K(AK_Matcher), MatcherKind(MatcherKind) {}
+
+ std::string asString() const {
+ switch (getArgKind()) {
+ case AK_Matcher:
+ return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str();
+ case AK_Unsigned:
+ return "unsigned";
+ case AK_String:
+ return "string";
+ }
+ llvm_unreachable("unhandled ArgKind");
+ }
+
+ Kind getArgKind() const { return K; }
+ ast_type_traits::ASTNodeKind getMatcherKind() const {
+ assert(K == AK_Matcher);
+ return MatcherKind;
+ }
+
+ bool operator<(const ArgKind &Other) const {
+ if (K == AK_Matcher && Other.K == AK_Matcher)
+ return MatcherKind < Other.MatcherKind;
+ return K < Other.K;
+ }
+
+private:
+ Kind K;
+ ast_type_traits::ASTNodeKind MatcherKind;
+};
+
/// \brief Helper template class to just from argument type to the right is/get
/// functions in VariantValue.
/// Used to verify and extract the matcher arguments below.
@@ -43,11 +81,13 @@ template <class T> struct ArgTypeTraits<const T &> : public ArgTypeTraits<T> {
};
template <> struct ArgTypeTraits<std::string> {
- static StringRef asString() { return "String"; }
static bool is(const VariantValue &Value) { return Value.isString(); }
static const std::string &get(const VariantValue &Value) {
return Value.getString();
}
+ static ArgKind getKind() {
+ return ArgKind(ArgKind::AK_String);
+ }
};
template <>
@@ -55,46 +95,95 @@ struct ArgTypeTraits<StringRef> : public ArgTypeTraits<std::string> {
};
template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T> > {
- static std::string asString() {
- return (Twine("Matcher<") +
- ast_type_traits::ASTNodeKind::getFromNodeKind<T>().asStringRef() +
- ">").str();
- }
static bool is(const VariantValue &Value) {
return Value.isMatcher() && Value.getMatcher().hasTypedMatcher<T>();
}
static ast_matchers::internal::Matcher<T> get(const VariantValue &Value) {
return Value.getMatcher().getTypedMatcher<T>();
}
+ static ArgKind getKind() {
+ return ArgKind(ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
+ }
};
template <> struct ArgTypeTraits<unsigned> {
- static std::string asString() { return "Unsigned"; }
static bool is(const VariantValue &Value) { return Value.isUnsigned(); }
static unsigned get(const VariantValue &Value) {
return Value.getUnsigned();
}
+ static ArgKind getKind() {
+ return ArgKind(ArgKind::AK_Unsigned);
+ }
};
-/// \brief Generic MatcherCreate interface.
+/// \brief Matcher descriptor interface.
///
-/// Provides a \c run() method that constructs the matcher from the provided
-/// arguments.
-class MatcherCreateCallback {
+/// Provides a \c create() method that constructs the matcher from the provided
+/// arguments, and various other methods for type introspection.
+class MatcherDescriptor {
public:
- virtual ~MatcherCreateCallback() {}
- virtual VariantMatcher run(const SourceRange &NameRange,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) const = 0;
+ virtual ~MatcherDescriptor() {}
+ virtual VariantMatcher create(const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const = 0;
+
+ /// Returns whether the matcher is variadic. Variadic matchers can take any
+ /// number of arguments, but they must be of the same type.
+ virtual bool isVariadic() const = 0;
+
+ /// Returns the number of arguments accepted by the matcher if not variadic.
+ virtual unsigned getNumArgs() const = 0;
+
+ /// Given that the matcher is being converted to type \p ThisKind, append the
+ /// set of argument types accepted for argument \p ArgNo to \p ArgKinds.
+ // FIXME: We should provide the ability to constrain the output of this
+ // function based on the types of other matcher arguments.
+ virtual void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo,
+ std::vector<ArgKind> &ArgKinds) const = 0;
+
+ /// Returns whether this matcher is convertible to the given type. If it is
+ /// so convertible, store in *Specificity a value corresponding to the
+ /// "specificity" of the converted matcher to the given context, and in
+ /// *LeastDerivedKind the least derived matcher kind which would result in the
+ /// same matcher overload. Zero specificity indicates that this conversion
+ /// would produce a trivial matcher that will either always or never match.
+ /// Such matchers are excluded from code completion results.
+ virtual bool isConvertibleTo(
+ ast_type_traits::ASTNodeKind Kind, unsigned *Specificity = nullptr,
+ ast_type_traits::ASTNodeKind *LeastDerivedKind = nullptr) const = 0;
+
+ /// Returns whether the matcher will, given a matcher of any type T, yield a
+ /// matcher of type T.
+ virtual bool isPolymorphic() const { return false; }
};
+inline bool isRetKindConvertibleTo(
+ ArrayRef<ast_type_traits::ASTNodeKind> RetKinds,
+ ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
+ ast_type_traits::ASTNodeKind *LeastDerivedKind) {
+ for (ArrayRef<ast_type_traits::ASTNodeKind>::const_iterator
+ i = RetKinds.begin(),
+ e = RetKinds.end();
+ i != e; ++i) {
+ unsigned Distance;
+ if (i->isBaseOf(Kind, &Distance)) {
+ if (Specificity)
+ *Specificity = 100 - Distance;
+ if (LeastDerivedKind)
+ *LeastDerivedKind = *i;
+ return true;
+ }
+ }
+ return false;
+}
+
/// \brief Simple callback implementation. Marshaller and function are provided.
///
/// This class wraps a function of arbitrary signature and a marshaller
-/// function into a MatcherCreateCallback.
+/// function into a MatcherDescriptor.
/// The marshaller is in charge of taking the VariantValue arguments, checking
/// their types, unpacking them and calling the underlying function.
-class FixedArgCountMatcherCreateCallback : public MatcherCreateCallback {
+class FixedArgCountMatcherDescriptor : public MatcherDescriptor {
public:
typedef VariantMatcher (*MarshallerType)(void (*Func)(),
StringRef MatcherName,
@@ -105,46 +194,225 @@ public:
/// \param Marshaller Function to unpack the arguments and call \c Func
/// \param Func Matcher construct function. This is the function that
/// compile-time matcher expressions would use to create the matcher.
- FixedArgCountMatcherCreateCallback(MarshallerType Marshaller, void (*Func)(),
- StringRef MatcherName)
- : Marshaller(Marshaller), Func(Func), MatcherName(MatcherName) {}
-
- VariantMatcher run(const SourceRange &NameRange, ArrayRef<ParserValue> Args,
- Diagnostics *Error) const {
+ /// \param RetKinds The list of matcher types to which the matcher is
+ /// convertible.
+ /// \param ArgKinds The types of the arguments this matcher takes.
+ FixedArgCountMatcherDescriptor(
+ MarshallerType Marshaller, void (*Func)(), StringRef MatcherName,
+ ArrayRef<ast_type_traits::ASTNodeKind> RetKinds,
+ ArrayRef<ArgKind> ArgKinds)
+ : Marshaller(Marshaller), Func(Func), MatcherName(MatcherName),
+ RetKinds(RetKinds.begin(), RetKinds.end()),
+ ArgKinds(ArgKinds.begin(), ArgKinds.end()) {}
+
+ VariantMatcher create(const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args, Diagnostics *Error) const {
return Marshaller(Func, MatcherName, NameRange, Args, Error);
}
+ bool isVariadic() const { return false; }
+ unsigned getNumArgs() const { return ArgKinds.size(); }
+ void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo,
+ std::vector<ArgKind> &Kinds) const {
+ Kinds.push_back(ArgKinds[ArgNo]);
+ }
+ bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
+ ast_type_traits::ASTNodeKind *LeastDerivedKind) const {
+ return isRetKindConvertibleTo(RetKinds, Kind, Specificity,
+ LeastDerivedKind);
+ }
+
private:
const MarshallerType Marshaller;
void (* const Func)();
const std::string MatcherName;
+ const std::vector<ast_type_traits::ASTNodeKind> RetKinds;
+ const std::vector<ArgKind> ArgKinds;
};
-/// \brief Simple callback implementation. Free function is wrapped.
+/// \brief Helper methods to extract and merge all possible typed matchers
+/// out of the polymorphic object.
+template <class PolyMatcher>
+static void mergePolyMatchers(const PolyMatcher &Poly,
+ std::vector<DynTypedMatcher> &Out,
+ ast_matchers::internal::EmptyTypeList) {}
+
+template <class PolyMatcher, class TypeList>
+static void mergePolyMatchers(const PolyMatcher &Poly,
+ std::vector<DynTypedMatcher> &Out, TypeList) {
+ Out.push_back(ast_matchers::internal::Matcher<typename TypeList::head>(Poly));
+ mergePolyMatchers(Poly, Out, typename TypeList::tail());
+}
+
+/// \brief Convert the return values of the functions into a VariantMatcher.
///
-/// This class simply wraps a free function with the right signature to export
-/// it as a MatcherCreateCallback.
+/// There are 2 cases right now: The return value is a Matcher<T> or is a
+/// polymorphic matcher. For the former, we just construct the VariantMatcher.
+/// For the latter, we instantiate all the possible Matcher<T> of the poly
+/// matcher.
+static VariantMatcher outvalueToVariantMatcher(const DynTypedMatcher &Matcher) {
+ return VariantMatcher::SingleMatcher(Matcher);
+}
+
+template <typename T>
+static VariantMatcher outvalueToVariantMatcher(const T &PolyMatcher,
+ typename T::ReturnTypes * =
+ NULL) {
+ std::vector<DynTypedMatcher> Matchers;
+ mergePolyMatchers(PolyMatcher, Matchers, typename T::ReturnTypes());
+ VariantMatcher Out = VariantMatcher::PolymorphicMatcher(std::move(Matchers));
+ return Out;
+}
+
+template <typename T>
+inline void buildReturnTypeVectorFromTypeList(
+ std::vector<ast_type_traits::ASTNodeKind> &RetTypes) {
+ RetTypes.push_back(
+ ast_type_traits::ASTNodeKind::getFromNodeKind<typename T::head>());
+ buildReturnTypeVectorFromTypeList<typename T::tail>(RetTypes);
+}
+
+template <>
+inline void
+buildReturnTypeVectorFromTypeList<ast_matchers::internal::EmptyTypeList>(
+ std::vector<ast_type_traits::ASTNodeKind> &RetTypes) {}
+
+template <typename T>
+struct BuildReturnTypeVector {
+ static void build(std::vector<ast_type_traits::ASTNodeKind> &RetTypes) {
+ buildReturnTypeVectorFromTypeList<typename T::ReturnTypes>(RetTypes);
+ }
+};
+
+template <typename T>
+struct BuildReturnTypeVector<ast_matchers::internal::Matcher<T> > {
+ static void build(std::vector<ast_type_traits::ASTNodeKind> &RetTypes) {
+ RetTypes.push_back(ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
+ }
+};
+
+template <typename T>
+struct BuildReturnTypeVector<ast_matchers::internal::BindableMatcher<T> > {
+ static void build(std::vector<ast_type_traits::ASTNodeKind> &RetTypes) {
+ RetTypes.push_back(ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
+ }
+};
+
+/// \brief Variadic marshaller function.
+template <typename ResultT, typename ArgT,
+ ResultT (*Func)(ArrayRef<const ArgT *>)>
+VariantMatcher
+variadicMatcherDescriptor(StringRef MatcherName, const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args, Diagnostics *Error) {
+ ArgT **InnerArgs = new ArgT *[Args.size()]();
+
+ bool HasError = false;
+ for (size_t i = 0, e = Args.size(); i != e; ++i) {
+ typedef ArgTypeTraits<ArgT> ArgTraits;
+ const ParserValue &Arg = Args[i];
+ const VariantValue &Value = Arg.Value;
+ if (!ArgTraits::is(Value)) {
+ Error->addError(Arg.Range, Error->ET_RegistryWrongArgType)
+ << (i + 1) << ArgTraits::getKind().asString() << Value.getTypeAsString();
+ HasError = true;
+ break;
+ }
+ InnerArgs[i] = new ArgT(ArgTraits::get(Value));
+ }
+
+ VariantMatcher Out;
+ if (!HasError) {
+ Out = outvalueToVariantMatcher(
+ Func(ArrayRef<const ArgT *>(InnerArgs, Args.size())));
+ }
+
+ for (size_t i = 0, e = Args.size(); i != e; ++i) {
+ delete InnerArgs[i];
+ }
+ delete[] InnerArgs;
+ return Out;
+}
+
+/// \brief Matcher descriptor for variadic functions.
+///
+/// This class simply wraps a VariadicFunction with the right signature to export
+/// it as a MatcherDescriptor.
/// This allows us to have one implementation of the interface for as many free
/// functions as we want, reducing the number of symbols and size of the
/// object file.
-class FreeFuncMatcherCreateCallback : public MatcherCreateCallback {
+class VariadicFuncMatcherDescriptor : public MatcherDescriptor {
public:
typedef VariantMatcher (*RunFunc)(StringRef MatcherName,
const SourceRange &NameRange,
ArrayRef<ParserValue> Args,
Diagnostics *Error);
- FreeFuncMatcherCreateCallback(RunFunc Func, StringRef MatcherName)
- : Func(Func), MatcherName(MatcherName.str()) {}
+ template <typename ResultT, typename ArgT,
+ ResultT (*F)(ArrayRef<const ArgT *>)>
+ VariadicFuncMatcherDescriptor(llvm::VariadicFunction<ResultT, ArgT, F> Func,
+ StringRef MatcherName)
+ : Func(&variadicMatcherDescriptor<ResultT, ArgT, F>),
+ MatcherName(MatcherName.str()),
+ ArgsKind(ArgTypeTraits<ArgT>::getKind()) {
+ BuildReturnTypeVector<ResultT>::build(RetKinds);
+ }
- VariantMatcher run(const SourceRange &NameRange, ArrayRef<ParserValue> Args,
- Diagnostics *Error) const {
+ VariantMatcher create(const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args, Diagnostics *Error) const {
return Func(MatcherName, NameRange, Args, Error);
}
+ bool isVariadic() const { return true; }
+ unsigned getNumArgs() const { return 0; }
+ void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo,
+ std::vector<ArgKind> &Kinds) const {
+ Kinds.push_back(ArgsKind);
+ }
+ bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
+ ast_type_traits::ASTNodeKind *LeastDerivedKind) const {
+ return isRetKindConvertibleTo(RetKinds, Kind, Specificity,
+ LeastDerivedKind);
+ }
+
private:
const RunFunc Func;
const std::string MatcherName;
+ std::vector<ast_type_traits::ASTNodeKind> RetKinds;
+ const ArgKind ArgsKind;
+};
+
+/// \brief Return CK_Trivial when appropriate for VariadicDynCastAllOfMatchers.
+class DynCastAllOfMatcherDescriptor : public VariadicFuncMatcherDescriptor {
+public:
+ template <typename BaseT, typename DerivedT>
+ DynCastAllOfMatcherDescriptor(
+ ast_matchers::internal::VariadicDynCastAllOfMatcher<BaseT, DerivedT> Func,
+ StringRef MatcherName)
+ : VariadicFuncMatcherDescriptor(Func, MatcherName),
+ DerivedKind(ast_type_traits::ASTNodeKind::getFromNodeKind<DerivedT>()) {
+ }
+
+ bool
+ isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
+ ast_type_traits::ASTNodeKind *LeastDerivedKind) const override {
+ // If Kind is not a base of DerivedKind, either DerivedKind is a base of
+ // Kind (in which case the match will always succeed) or Kind and
+ // DerivedKind are unrelated (in which case it will always fail), so set
+ // Specificity to 0.
+ if (VariadicFuncMatcherDescriptor::isConvertibleTo(Kind, Specificity,
+ LeastDerivedKind)) {
+ if (Kind.isSame(DerivedKind) || !Kind.isBaseOf(DerivedKind)) {
+ if (Specificity)
+ *Specificity = 0;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+private:
+ const ast_type_traits::ASTNodeKind DerivedKind;
};
/// \brief Helper macros to check the arguments on all marshaller functions.
@@ -158,44 +426,11 @@ private:
#define CHECK_ARG_TYPE(index, type) \
if (!ArgTypeTraits<type>::is(Args[index].Value)) { \
Error->addError(Args[index].Range, Error->ET_RegistryWrongArgType) \
- << (index + 1) << ArgTypeTraits<type>::asString() \
+ << (index + 1) << ArgTypeTraits<type>::getKind().asString() \
<< Args[index].Value.getTypeAsString(); \
return VariantMatcher(); \
}
-/// \brief Helper methods to extract and merge all possible typed matchers
-/// out of the polymorphic object.
-template <class PolyMatcher>
-static void mergePolyMatchers(const PolyMatcher &Poly,
- std::vector<DynTypedMatcher> &Out,
- ast_matchers::internal::EmptyTypeList) {}
-
-template <class PolyMatcher, class TypeList>
-static void mergePolyMatchers(const PolyMatcher &Poly,
- std::vector<DynTypedMatcher> &Out, TypeList) {
- Out.push_back(ast_matchers::internal::Matcher<typename TypeList::head>(Poly));
- mergePolyMatchers(Poly, Out, typename TypeList::tail());
-}
-
-/// \brief Convert the return values of the functions into a VariantMatcher.
-///
-/// There are 2 cases right now: The return value is a Matcher<T> or is a
-/// polymorphic matcher. For the former, we just construct the VariantMatcher.
-/// For the latter, we instantiate all the possible Matcher<T> of the poly
-/// matcher.
-static VariantMatcher outvalueToVariantMatcher(const DynTypedMatcher &Matcher) {
- return VariantMatcher::SingleMatcher(Matcher);
-}
-
-template <typename T>
-static VariantMatcher outvalueToVariantMatcher(const T &PolyMatcher,
- typename T::ReturnTypes * =
- NULL) {
- std::vector<DynTypedMatcher> Matchers;
- mergePolyMatchers(PolyMatcher, Matchers, typename T::ReturnTypes());
- VariantMatcher Out = VariantMatcher::PolymorphicMatcher(Matchers);
- return Out;
-}
/// \brief 0-arg marshaller function.
template <typename ReturnType>
@@ -239,42 +474,6 @@ static VariantMatcher matcherMarshall2(void (*Func)(), StringRef MatcherName,
#undef CHECK_ARG_COUNT
#undef CHECK_ARG_TYPE
-/// \brief Variadic marshaller function.
-template <typename ResultT, typename ArgT,
- ResultT (*Func)(ArrayRef<const ArgT *>)>
-VariantMatcher
-variadicMatcherCreateCallback(StringRef MatcherName,
- const SourceRange &NameRange,
- ArrayRef<ParserValue> Args, Diagnostics *Error) {
- ArgT **InnerArgs = new ArgT *[Args.size()]();
-
- bool HasError = false;
- for (size_t i = 0, e = Args.size(); i != e; ++i) {
- typedef ArgTypeTraits<ArgT> ArgTraits;
- const ParserValue &Arg = Args[i];
- const VariantValue &Value = Arg.Value;
- if (!ArgTraits::is(Value)) {
- Error->addError(Arg.Range, Error->ET_RegistryWrongArgType)
- << (i + 1) << ArgTraits::asString() << Value.getTypeAsString();
- HasError = true;
- break;
- }
- InnerArgs[i] = new ArgT(ArgTraits::get(Value));
- }
-
- VariantMatcher Out;
- if (!HasError) {
- Out = outvalueToVariantMatcher(
- Func(ArrayRef<const ArgT *>(InnerArgs, Args.size())));
- }
-
- for (size_t i = 0, e = Args.size(); i != e; ++i) {
- delete InnerArgs[i];
- }
- delete[] InnerArgs;
- return Out;
-}
-
/// \brief Helper class used to collect all the possible overloads of an
/// argument adaptative matcher function.
template <template <typename ToArg, typename FromArg> class ArgumentAdapterT,
@@ -282,7 +481,7 @@ template <template <typename ToArg, typename FromArg> class ArgumentAdapterT,
class AdaptativeOverloadCollector {
public:
AdaptativeOverloadCollector(StringRef Name,
- std::vector<MatcherCreateCallback *> &Out)
+ std::vector<MatcherDescriptor *> &Out)
: Name(Name), Out(Out) {
collect(FromTypes());
}
@@ -296,33 +495,32 @@ private:
/// \brief Recursive case. Get the overload for the head of the list, and
/// recurse to the tail.
- template <typename FromTypeList> inline void collect(FromTypeList);
+ template <typename FromTypeList>
+ inline void collect(FromTypeList);
const StringRef Name;
- std::vector<MatcherCreateCallback *> &Out;
+ std::vector<MatcherDescriptor *> &Out;
};
-/// \brief MatcherCreateCallback that wraps multiple "overloads" of the same
+/// \brief MatcherDescriptor that wraps multiple "overloads" of the same
/// matcher.
///
/// It will try every overload and generate appropriate errors for when none or
/// more than one overloads match the arguments.
-class OverloadedMatcherCreateCallback : public MatcherCreateCallback {
+class OverloadedMatcherDescriptor : public MatcherDescriptor {
public:
- OverloadedMatcherCreateCallback(ArrayRef<MatcherCreateCallback *> Callbacks)
- : Overloads(Callbacks) {}
+ OverloadedMatcherDescriptor(ArrayRef<MatcherDescriptor *> Callbacks)
+ : Overloads(Callbacks.begin(), Callbacks.end()) {}
- virtual ~OverloadedMatcherCreateCallback() {
- llvm::DeleteContainerPointers(Overloads);
- }
+ virtual ~OverloadedMatcherDescriptor() {}
- virtual VariantMatcher run(const SourceRange &NameRange,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) const {
+ virtual VariantMatcher create(const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const {
std::vector<VariantMatcher> Constructed;
Diagnostics::OverloadContext Ctx(Error);
- for (size_t i = 0, e = Overloads.size(); i != e; ++i) {
- VariantMatcher SubMatcher = Overloads[i]->run(NameRange, Args, Error);
+ for (const auto &O : Overloads) {
+ VariantMatcher SubMatcher = O->create(NameRange, Args, Error);
if (!SubMatcher.isNull()) {
Constructed.push_back(SubMatcher);
}
@@ -339,20 +537,67 @@ public:
return Constructed[0];
}
+ bool isVariadic() const {
+ bool Overload0Variadic = Overloads[0]->isVariadic();
+#ifndef NDEBUG
+ for (const auto &O : Overloads) {
+ assert(Overload0Variadic == O->isVariadic());
+ }
+#endif
+ return Overload0Variadic;
+ }
+
+ unsigned getNumArgs() const {
+ unsigned Overload0NumArgs = Overloads[0]->getNumArgs();
+#ifndef NDEBUG
+ for (const auto &O : Overloads) {
+ assert(Overload0NumArgs == O->getNumArgs());
+ }
+#endif
+ return Overload0NumArgs;
+ }
+
+ void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo,
+ std::vector<ArgKind> &Kinds) const {
+ for (const auto &O : Overloads) {
+ if (O->isConvertibleTo(ThisKind))
+ O->getArgKinds(ThisKind, ArgNo, Kinds);
+ }
+ }
+
+ bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
+ ast_type_traits::ASTNodeKind *LeastDerivedKind) const {
+ for (const auto &O : Overloads) {
+ if (O->isConvertibleTo(Kind, Specificity, LeastDerivedKind))
+ return true;
+ }
+ return false;
+ }
+
private:
- std::vector<MatcherCreateCallback *> Overloads;
+ std::vector<std::unique_ptr<MatcherDescriptor>> Overloads;
};
/// \brief Variadic operator marshaller function.
-class VariadicOperatorMatcherCreateCallback : public MatcherCreateCallback {
+class VariadicOperatorMatcherDescriptor : public MatcherDescriptor {
public:
typedef ast_matchers::internal::VariadicOperatorFunction VarFunc;
- VariadicOperatorMatcherCreateCallback(VarFunc Func, StringRef MatcherName)
- : Func(Func), MatcherName(MatcherName) {}
+ VariadicOperatorMatcherDescriptor(unsigned MinCount, unsigned MaxCount,
+ VarFunc Func, StringRef MatcherName)
+ : MinCount(MinCount), MaxCount(MaxCount), Func(Func),
+ MatcherName(MatcherName) {}
+
+ virtual VariantMatcher create(const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) const {
+ if (Args.size() < MinCount || MaxCount < Args.size()) {
+ const std::string MaxStr =
+ (MaxCount == UINT_MAX ? "" : Twine(MaxCount)).str();
+ Error->addError(NameRange, Error->ET_RegistryWrongArgCount)
+ << ("(" + Twine(MinCount) + ", " + MaxStr + ")") << Args.size();
+ return VariantMatcher();
+ }
- virtual VariantMatcher run(const SourceRange &NameRange,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) const {
std::vector<VariantMatcher> InnerArgs;
for (size_t i = 0, e = Args.size(); i != e; ++i) {
const ParserValue &Arg = Args[i];
@@ -364,85 +609,123 @@ public:
}
InnerArgs.push_back(Value.getMatcher());
}
- return VariantMatcher::VariadicOperatorMatcher(Func, InnerArgs);
+ return VariantMatcher::VariadicOperatorMatcher(Func, std::move(InnerArgs));
}
+ bool isVariadic() const { return true; }
+ unsigned getNumArgs() const { return 0; }
+ void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo,
+ std::vector<ArgKind> &Kinds) const {
+ Kinds.push_back(ThisKind);
+ }
+ bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity,
+ ast_type_traits::ASTNodeKind *LeastDerivedKind) const {
+ if (Specificity)
+ *Specificity = 1;
+ if (LeastDerivedKind)
+ *LeastDerivedKind = Kind;
+ return true;
+ }
+ bool isPolymorphic() const override { return true; }
+
private:
+ const unsigned MinCount;
+ const unsigned MaxCount;
const VarFunc Func;
const StringRef MatcherName;
};
-
/// Helper functions to select the appropriate marshaller functions.
/// They detect the number of arguments, arguments types and return type.
/// \brief 0-arg overload
template <typename ReturnType>
-MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(),
- StringRef MatcherName) {
- return new FixedArgCountMatcherCreateCallback(
+MatcherDescriptor *makeMatcherAutoMarshall(ReturnType (*Func)(),
+ StringRef MatcherName) {
+ std::vector<ast_type_traits::ASTNodeKind> RetTypes;
+ BuildReturnTypeVector<ReturnType>::build(RetTypes);
+ return new FixedArgCountMatcherDescriptor(
matcherMarshall0<ReturnType>, reinterpret_cast<void (*)()>(Func),
- MatcherName);
+ MatcherName, RetTypes, None);
}
/// \brief 1-arg overload
template <typename ReturnType, typename ArgType1>
-MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1),
- StringRef MatcherName) {
- return new FixedArgCountMatcherCreateCallback(
+MatcherDescriptor *makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1),
+ StringRef MatcherName) {
+ std::vector<ast_type_traits::ASTNodeKind> RetTypes;
+ BuildReturnTypeVector<ReturnType>::build(RetTypes);
+ ArgKind AK = ArgTypeTraits<ArgType1>::getKind();
+ return new FixedArgCountMatcherDescriptor(
matcherMarshall1<ReturnType, ArgType1>,
- reinterpret_cast<void (*)()>(Func), MatcherName);
+ reinterpret_cast<void (*)()>(Func), MatcherName, RetTypes, AK);
}
/// \brief 2-arg overload
template <typename ReturnType, typename ArgType1, typename ArgType2>
-MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1,
- ArgType2),
- StringRef MatcherName) {
- return new FixedArgCountMatcherCreateCallback(
+MatcherDescriptor *makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1, ArgType2),
+ StringRef MatcherName) {
+ std::vector<ast_type_traits::ASTNodeKind> RetTypes;
+ BuildReturnTypeVector<ReturnType>::build(RetTypes);
+ ArgKind AKs[] = { ArgTypeTraits<ArgType1>::getKind(),
+ ArgTypeTraits<ArgType2>::getKind() };
+ return new FixedArgCountMatcherDescriptor(
matcherMarshall2<ReturnType, ArgType1, ArgType2>,
- reinterpret_cast<void (*)()>(Func), MatcherName);
+ reinterpret_cast<void (*)()>(Func), MatcherName, RetTypes, AKs);
}
/// \brief Variadic overload.
template <typename ResultT, typename ArgT,
ResultT (*Func)(ArrayRef<const ArgT *>)>
-MatcherCreateCallback *
+MatcherDescriptor *
makeMatcherAutoMarshall(llvm::VariadicFunction<ResultT, ArgT, Func> VarFunc,
StringRef MatcherName) {
- return new FreeFuncMatcherCreateCallback(
- &variadicMatcherCreateCallback<ResultT, ArgT, Func>, MatcherName);
+ return new VariadicFuncMatcherDescriptor(VarFunc, MatcherName);
+}
+
+/// \brief Overload for VariadicDynCastAllOfMatchers.
+///
+/// Not strictly necessary, but DynCastAllOfMatcherDescriptor gives us better
+/// completion results for that type of matcher.
+template <typename BaseT, typename DerivedT>
+MatcherDescriptor *
+makeMatcherAutoMarshall(ast_matchers::internal::VariadicDynCastAllOfMatcher<
+ BaseT, DerivedT> VarFunc,
+ StringRef MatcherName) {
+ return new DynCastAllOfMatcherDescriptor(VarFunc, MatcherName);
}
/// \brief Argument adaptative overload.
template <template <typename ToArg, typename FromArg> class ArgumentAdapterT,
typename FromTypes, typename ToTypes>
-MatcherCreateCallback *
+MatcherDescriptor *
makeMatcherAutoMarshall(ast_matchers::internal::ArgumentAdaptingMatcherFunc<
ArgumentAdapterT, FromTypes, ToTypes>,
StringRef MatcherName) {
- std::vector<MatcherCreateCallback *> Overloads;
+ std::vector<MatcherDescriptor *> Overloads;
AdaptativeOverloadCollector<ArgumentAdapterT, FromTypes, ToTypes>(MatcherName,
Overloads);
- return new OverloadedMatcherCreateCallback(Overloads);
+ return new OverloadedMatcherDescriptor(Overloads);
}
template <template <typename ToArg, typename FromArg> class ArgumentAdapterT,
typename FromTypes, typename ToTypes>
template <typename FromTypeList>
-inline void
-AdaptativeOverloadCollector<ArgumentAdapterT, FromTypes, ToTypes>::collect(
- FromTypeList) {
+inline void AdaptativeOverloadCollector<ArgumentAdapterT, FromTypes,
+ ToTypes>::collect(FromTypeList) {
Out.push_back(makeMatcherAutoMarshall(
&AdaptativeFunc::template create<typename FromTypeList::head>, Name));
collect(typename FromTypeList::tail());
}
/// \brief Variadic operator overload.
-MatcherCreateCallback *makeMatcherAutoMarshall(
- ast_matchers::internal::VariadicOperatorMatcherFunc Func,
- StringRef MatcherName) {
- return new VariadicOperatorMatcherCreateCallback(Func.Func, MatcherName);
+template <unsigned MinCount, unsigned MaxCount>
+MatcherDescriptor *
+makeMatcherAutoMarshall(ast_matchers::internal::VariadicOperatorMatcherFunc<
+ MinCount, MaxCount> Func,
+ StringRef MatcherName) {
+ return new VariadicOperatorMatcherDescriptor(MinCount, MaxCount, Func.Func,
+ MatcherName);
}
} // namespace internal
diff --git a/lib/ASTMatchers/Dynamic/Parser.cpp b/lib/ASTMatchers/Dynamic/Parser.cpp
index df9596e9b935..25629d99a7cc 100644
--- a/lib/ASTMatchers/Dynamic/Parser.cpp
+++ b/lib/ASTMatchers/Dynamic/Parser.cpp
@@ -12,13 +12,13 @@
///
//===----------------------------------------------------------------------===//
-#include <string>
-#include <vector>
-
#include "clang/ASTMatchers/Dynamic/Parser.h"
#include "clang/ASTMatchers/Dynamic/Registry.h"
#include "clang/Basic/CharInfo.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/Twine.h"
+#include <string>
+#include <vector>
namespace clang {
namespace ast_matchers {
@@ -28,15 +28,16 @@ namespace dynamic {
struct Parser::TokenInfo {
/// \brief Different possible tokens.
enum TokenKind {
- TK_Eof = 0,
- TK_OpenParen = 1,
- TK_CloseParen = 2,
- TK_Comma = 3,
- TK_Period = 4,
- TK_Literal = 5,
- TK_Ident = 6,
- TK_InvalidChar = 7,
- TK_Error = 8
+ TK_Eof,
+ TK_OpenParen,
+ TK_CloseParen,
+ TK_Comma,
+ TK_Period,
+ TK_Literal,
+ TK_Ident,
+ TK_InvalidChar,
+ TK_Error,
+ TK_CodeCompletion
};
/// \brief Some known identifiers.
@@ -56,7 +57,15 @@ const char* const Parser::TokenInfo::ID_Bind = "bind";
class Parser::CodeTokenizer {
public:
explicit CodeTokenizer(StringRef MatcherCode, Diagnostics *Error)
- : Code(MatcherCode), StartOfLine(MatcherCode), Line(1), Error(Error) {
+ : Code(MatcherCode), StartOfLine(MatcherCode), Line(1), Error(Error),
+ CodeCompletionLocation(nullptr) {
+ NextToken = getNextToken();
+ }
+
+ CodeTokenizer(StringRef MatcherCode, Diagnostics *Error,
+ unsigned CodeCompletionOffset)
+ : Code(MatcherCode), StartOfLine(MatcherCode), Line(1), Error(Error),
+ CodeCompletionLocation(MatcherCode.data() + CodeCompletionOffset) {
NextToken = getNextToken();
}
@@ -78,6 +87,13 @@ private:
TokenInfo Result;
Result.Range.Start = currentLocation();
+ if (CodeCompletionLocation && CodeCompletionLocation <= Code.data()) {
+ Result.Kind = TokenInfo::TK_CodeCompletion;
+ Result.Text = StringRef(CodeCompletionLocation, 0);
+ CodeCompletionLocation = nullptr;
+ return Result;
+ }
+
if (Code.empty()) {
Result.Kind = TokenInfo::TK_Eof;
Result.Text = "";
@@ -122,8 +138,21 @@ private:
if (isAlphanumeric(Code[0])) {
// Parse an identifier
size_t TokenLength = 1;
- while (TokenLength < Code.size() && isAlphanumeric(Code[TokenLength]))
+ while (1) {
+ // A code completion location in/immediately after an identifier will
+ // cause the portion of the identifier before the code completion
+ // location to become a code completion token.
+ if (CodeCompletionLocation == Code.data() + TokenLength) {
+ CodeCompletionLocation = nullptr;
+ Result.Kind = TokenInfo::TK_CodeCompletion;
+ Result.Text = Code.substr(0, TokenLength);
+ Code = Code.drop_front(TokenLength);
+ return Result;
+ }
+ if (TokenLength == Code.size() || !isAlphanumeric(Code[TokenLength]))
+ break;
++TokenLength;
+ }
Result.Kind = TokenInfo::TK_Ident;
Result.Text = Code.substr(0, TokenLength);
Code = Code.drop_front(TokenLength);
@@ -224,16 +253,68 @@ private:
unsigned Line;
Diagnostics *Error;
TokenInfo NextToken;
+ const char *CodeCompletionLocation;
};
Parser::Sema::~Sema() {}
+VariantValue Parser::Sema::getNamedValue(StringRef Name) {
+ return VariantValue();
+}
+
+struct Parser::ScopedContextEntry {
+ Parser *P;
+
+ ScopedContextEntry(Parser *P, MatcherCtor C) : P(P) {
+ P->ContextStack.push_back(std::make_pair(C, 0u));
+ }
+
+ ~ScopedContextEntry() {
+ P->ContextStack.pop_back();
+ }
+
+ void nextArg() {
+ ++P->ContextStack.back().second;
+ }
+};
+
+/// \brief Parse expressions that start with an identifier.
+///
+/// This function can parse named values and matchers.
+/// In case of failure it will try to determine the user's intent to give
+/// an appropriate error message.
+bool Parser::parseIdentifierPrefixImpl(VariantValue *Value) {
+ const TokenInfo NameToken = Tokenizer->consumeNextToken();
+
+ if (Tokenizer->nextTokenKind() != TokenInfo::TK_OpenParen) {
+ // Parse as a named value.
+ if (const VariantValue NamedValue = S->getNamedValue(NameToken.Text)) {
+ *Value = NamedValue;
+ return true;
+ }
+ // If the syntax is correct and the name is not a matcher either, report
+ // unknown named value.
+ if ((Tokenizer->nextTokenKind() == TokenInfo::TK_Comma ||
+ Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen ||
+ Tokenizer->nextTokenKind() == TokenInfo::TK_Eof) &&
+ !S->lookupMatcherCtor(NameToken.Text)) {
+ Error->addError(NameToken.Range, Error->ET_RegistryValueNotFound)
+ << NameToken.Text;
+ return false;
+ }
+ // Otherwise, fallback to the matcher parser.
+ }
+
+ // Parse as a matcher expression.
+ return parseMatcherExpressionImpl(NameToken, Value);
+}
+
/// \brief Parse and validate a matcher expression.
/// \return \c true on success, in which case \c Value has the matcher parsed.
/// If the input is malformed, or some argument has an error, it
/// returns \c false.
-bool Parser::parseMatcherExpressionImpl(VariantValue *Value) {
- const TokenInfo NameToken = Tokenizer->consumeNextToken();
+bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken,
+ VariantValue *Value) {
assert(NameToken.Kind == TokenInfo::TK_Ident);
const TokenInfo OpenToken = Tokenizer->consumeNextToken();
if (OpenToken.Kind != TokenInfo::TK_OpenParen) {
@@ -242,32 +323,49 @@ bool Parser::parseMatcherExpressionImpl(VariantValue *Value) {
return false;
}
+ llvm::Optional<MatcherCtor> Ctor = S->lookupMatcherCtor(NameToken.Text);
+
+ if (!Ctor) {
+ Error->addError(NameToken.Range, Error->ET_RegistryMatcherNotFound)
+ << NameToken.Text;
+ // Do not return here. We need to continue to give completion suggestions.
+ }
+
std::vector<ParserValue> Args;
TokenInfo EndToken;
- while (Tokenizer->nextTokenKind() != TokenInfo::TK_Eof) {
- if (Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen) {
- // End of args.
- EndToken = Tokenizer->consumeNextToken();
- break;
- }
- if (Args.size() > 0) {
- // We must find a , token to continue.
- const TokenInfo CommaToken = Tokenizer->consumeNextToken();
- if (CommaToken.Kind != TokenInfo::TK_Comma) {
- Error->addError(CommaToken.Range, Error->ET_ParserNoComma)
- << CommaToken.Text;
- return false;
+
+ {
+ ScopedContextEntry SCE(this, Ctor ? *Ctor : nullptr);
+
+ while (Tokenizer->nextTokenKind() != TokenInfo::TK_Eof) {
+ if (Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen) {
+ // End of args.
+ EndToken = Tokenizer->consumeNextToken();
+ break;
+ }
+ if (Args.size() > 0) {
+ // We must find a , token to continue.
+ const TokenInfo CommaToken = Tokenizer->consumeNextToken();
+ if (CommaToken.Kind != TokenInfo::TK_Comma) {
+ Error->addError(CommaToken.Range, Error->ET_ParserNoComma)
+ << CommaToken.Text;
+ return false;
+ }
}
- }
- Diagnostics::Context Ctx(Diagnostics::Context::MatcherArg, Error,
- NameToken.Text, NameToken.Range, Args.size() + 1);
- ParserValue ArgValue;
- ArgValue.Text = Tokenizer->peekNextToken().Text;
- ArgValue.Range = Tokenizer->peekNextToken().Range;
- if (!parseExpressionImpl(&ArgValue.Value)) return false;
+ Diagnostics::Context Ctx(Diagnostics::Context::MatcherArg, Error,
+ NameToken.Text, NameToken.Range,
+ Args.size() + 1);
+ ParserValue ArgValue;
+ ArgValue.Text = Tokenizer->peekNextToken().Text;
+ ArgValue.Range = Tokenizer->peekNextToken().Range;
+ if (!parseExpressionImpl(&ArgValue.Value)) {
+ return false;
+ }
- Args.push_back(ArgValue);
+ Args.push_back(ArgValue);
+ SCE.nextArg();
+ }
}
if (EndToken.Kind == TokenInfo::TK_Eof) {
@@ -280,6 +378,11 @@ bool Parser::parseMatcherExpressionImpl(VariantValue *Value) {
// Parse .bind("foo")
Tokenizer->consumeNextToken(); // consume the period.
const TokenInfo BindToken = Tokenizer->consumeNextToken();
+ if (BindToken.Kind == TokenInfo::TK_CodeCompletion) {
+ addCompletion(BindToken, "bind(\"", "bind");
+ return false;
+ }
+
const TokenInfo OpenToken = Tokenizer->consumeNextToken();
const TokenInfo IDToken = Tokenizer->consumeNextToken();
const TokenInfo CloseToken = Tokenizer->consumeNextToken();
@@ -306,19 +409,55 @@ bool Parser::parseMatcherExpressionImpl(VariantValue *Value) {
BindID = IDToken.Value.getString();
}
+ if (!Ctor)
+ return false;
+
// Merge the start and end infos.
Diagnostics::Context Ctx(Diagnostics::Context::ConstructMatcher, Error,
NameToken.Text, NameToken.Range);
SourceRange MatcherRange = NameToken.Range;
MatcherRange.End = EndToken.Range.End;
VariantMatcher Result = S->actOnMatcherExpression(
- NameToken.Text, MatcherRange, BindID, Args, Error);
+ *Ctor, MatcherRange, BindID, Args, Error);
if (Result.isNull()) return false;
*Value = Result;
return true;
}
+// If the prefix of this completion matches the completion token, add it to
+// Completions minus the prefix.
+void Parser::addCompletion(const TokenInfo &CompToken, StringRef TypedText,
+ StringRef Decl) {
+ if (TypedText.size() >= CompToken.Text.size() &&
+ TypedText.substr(0, CompToken.Text.size()) == CompToken.Text) {
+ Completions.push_back(
+ MatcherCompletion(TypedText.substr(CompToken.Text.size()), Decl));
+ }
+}
+
+void Parser::addExpressionCompletions() {
+ const TokenInfo CompToken = Tokenizer->consumeNextToken();
+ assert(CompToken.Kind == TokenInfo::TK_CodeCompletion);
+
+ // We cannot complete code if there is an invalid element on the context
+ // stack.
+ for (ContextStackTy::iterator I = ContextStack.begin(),
+ E = ContextStack.end();
+ I != E; ++I) {
+ if (!I->first)
+ return;
+ }
+
+ std::vector<MatcherCompletion> RegCompletions =
+ Registry::getCompletions(ContextStack);
+ for (std::vector<MatcherCompletion>::iterator I = RegCompletions.begin(),
+ E = RegCompletions.end();
+ I != E; ++I) {
+ addCompletion(CompToken, I->TypedText, I->MatcherDecl);
+ }
+}
+
/// \brief Parse an <Expresssion>
bool Parser::parseExpressionImpl(VariantValue *Value) {
switch (Tokenizer->nextTokenKind()) {
@@ -327,7 +466,11 @@ bool Parser::parseExpressionImpl(VariantValue *Value) {
return true;
case TokenInfo::TK_Ident:
- return parseMatcherExpressionImpl(Value);
+ return parseIdentifierPrefixImpl(Value);
+
+ case TokenInfo::TK_CodeCompletion:
+ addExpressionCompletions();
+ return false;
case TokenInfo::TK_Eof:
Error->addError(Tokenizer->consumeNextToken().Range,
@@ -355,22 +498,23 @@ Parser::Parser(CodeTokenizer *Tokenizer, Sema *S,
Diagnostics *Error)
: Tokenizer(Tokenizer), S(S), Error(Error) {}
-class RegistrySema : public Parser::Sema {
-public:
- virtual ~RegistrySema() {}
- VariantMatcher actOnMatcherExpression(StringRef MatcherName,
- const SourceRange &NameRange,
- StringRef BindID,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) {
- if (BindID.empty()) {
- return Registry::constructMatcher(MatcherName, NameRange, Args, Error);
- } else {
- return Registry::constructBoundMatcher(MatcherName, NameRange, BindID,
- Args, Error);
- }
+Parser::RegistrySema::~RegistrySema() {}
+
+llvm::Optional<MatcherCtor>
+Parser::RegistrySema::lookupMatcherCtor(StringRef MatcherName) {
+ return Registry::lookupMatcherCtor(MatcherName);
+}
+
+VariantMatcher Parser::RegistrySema::actOnMatcherExpression(
+ MatcherCtor Ctor, const SourceRange &NameRange, StringRef BindID,
+ ArrayRef<ParserValue> Args, Diagnostics *Error) {
+ if (BindID.empty()) {
+ return Registry::constructMatcher(Ctor, NameRange, Args, Error);
+ } else {
+ return Registry::constructBoundMatcher(Ctor, NameRange, BindID, Args,
+ Error);
}
-};
+}
bool Parser::parseExpression(StringRef Code, VariantValue *Value,
Diagnostics *Error) {
@@ -390,6 +534,18 @@ bool Parser::parseExpression(StringRef Code, Sema *S,
return true;
}
+std::vector<MatcherCompletion>
+Parser::completeExpression(StringRef Code, unsigned CompletionOffset) {
+ Diagnostics Error;
+ CodeTokenizer Tokenizer(Code, &Error, CompletionOffset);
+ RegistrySema S;
+ Parser P(&Tokenizer, &S, &Error);
+ VariantValue Dummy;
+ P.parseExpressionImpl(&Dummy);
+
+ return P.Completions;
+}
+
llvm::Optional<DynTypedMatcher>
Parser::parseMatcherExpression(StringRef Code, Diagnostics *Error) {
RegistrySema S;
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp
index 70e956e65465..4bc50a0f2a96 100644
--- a/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -13,23 +13,24 @@
//===------------------------------------------------------------===//
#include "clang/ASTMatchers/Dynamic/Registry.h"
-
-#include <utility>
-
#include "Marshallers.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ManagedStatic.h"
+#include <set>
+#include <utility>
+
+using namespace clang::ast_type_traits;
namespace clang {
namespace ast_matchers {
namespace dynamic {
namespace {
-using internal::MatcherCreateCallback;
+using internal::MatcherDescriptor;
-typedef llvm::StringMap<const MatcherCreateCallback *> ConstructorMap;
+typedef llvm::StringMap<const MatcherDescriptor *> ConstructorMap;
class RegistryMaps {
public:
RegistryMaps();
@@ -38,12 +39,12 @@ public:
const ConstructorMap &constructors() const { return Constructors; }
private:
- void registerMatcher(StringRef MatcherName, MatcherCreateCallback *Callback);
+ void registerMatcher(StringRef MatcherName, MatcherDescriptor *Callback);
ConstructorMap Constructors;
};
void RegistryMaps::registerMatcher(StringRef MatcherName,
- MatcherCreateCallback *Callback) {
+ MatcherDescriptor *Callback) {
assert(Constructors.find(MatcherName) == Constructors.end());
Constructors[MatcherName] = Callback;
}
@@ -58,14 +59,14 @@ void RegistryMaps::registerMatcher(StringRef MatcherName,
#define REGISTER_OVERLOADED_2(name) \
do { \
- MatcherCreateCallback *Callbacks[] = { \
+ MatcherDescriptor *Callbacks[] = { \
internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, 0), \
#name), \
internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, 1), \
#name) \
}; \
registerMatcher(#name, \
- new internal::OverloadedMatcherCreateCallback(Callbacks)); \
+ new internal::OverloadedMatcherDescriptor(Callbacks)); \
} while (0)
/// \brief Generate a registry map with all the known matchers.
@@ -76,11 +77,9 @@ RegistryMaps::RegistryMaps() {
// ofKind
//
// Polymorphic + argument overload:
- // unless
// findAll
//
// Other:
- // loc
// equals
// equalsNode
@@ -89,6 +88,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_OVERLOADED_2(hasType);
REGISTER_OVERLOADED_2(isDerivedFrom);
REGISTER_OVERLOADED_2(isSameOrDerivedFrom);
+ REGISTER_OVERLOADED_2(loc);
REGISTER_OVERLOADED_2(pointsTo);
REGISTER_OVERLOADED_2(references);
REGISTER_OVERLOADED_2(thisPointerType);
@@ -113,6 +113,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(builtinType);
REGISTER_MATCHER(cStyleCastExpr);
REGISTER_MATCHER(callExpr);
+ REGISTER_MATCHER(caseStmt);
REGISTER_MATCHER(castExpr);
REGISTER_MATCHER(catchStmt);
REGISTER_MATCHER(characterLiteral);
@@ -133,7 +134,9 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(declCountIs);
REGISTER_MATCHER(declRefExpr);
REGISTER_MATCHER(declStmt);
+ REGISTER_MATCHER(declaratorDecl);
REGISTER_MATCHER(defaultArgExpr);
+ REGISTER_MATCHER(defaultStmt);
REGISTER_MATCHER(deleteExpr);
REGISTER_MATCHER(dependentSizedArrayType);
REGISTER_MATCHER(destructorDecl);
@@ -143,15 +146,20 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(elaboratedType);
REGISTER_MATCHER(enumConstantDecl);
REGISTER_MATCHER(enumDecl);
+ REGISTER_MATCHER(equalsBoundNode);
REGISTER_MATCHER(explicitCastExpr);
REGISTER_MATCHER(expr);
+ REGISTER_MATCHER(exprWithCleanups);
REGISTER_MATCHER(fieldDecl);
REGISTER_MATCHER(floatLiteral);
REGISTER_MATCHER(forEach);
+ REGISTER_MATCHER(forEachConstructorInitializer);
REGISTER_MATCHER(forEachDescendant);
+ REGISTER_MATCHER(forEachSwitchCase);
REGISTER_MATCHER(forField);
REGISTER_MATCHER(forRangeStmt);
REGISTER_MATCHER(forStmt);
+ REGISTER_MATCHER(friendDecl);
REGISTER_MATCHER(functionDecl);
REGISTER_MATCHER(functionTemplateDecl);
REGISTER_MATCHER(functionType);
@@ -170,6 +178,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasBase);
REGISTER_MATCHER(hasBody);
REGISTER_MATCHER(hasCanonicalType);
+ REGISTER_MATCHER(hasCaseConstant);
REGISTER_MATCHER(hasCondition);
REGISTER_MATCHER(hasConditionVariableStatement);
REGISTER_MATCHER(hasDeclContext);
@@ -180,12 +189,14 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasEitherOperand);
REGISTER_MATCHER(hasElementType);
REGISTER_MATCHER(hasFalseExpression);
+ REGISTER_MATCHER(hasGlobalStorage);
REGISTER_MATCHER(hasImplicitDestinationType);
REGISTER_MATCHER(hasIncrement);
REGISTER_MATCHER(hasIndex);
REGISTER_MATCHER(hasInitializer);
REGISTER_MATCHER(hasLHS);
REGISTER_MATCHER(hasLocalQualifiers);
+ REGISTER_MATCHER(hasLocalStorage);
REGISTER_MATCHER(hasLoopInit);
REGISTER_MATCHER(hasMethod);
REGISTER_MATCHER(hasName);
@@ -203,6 +214,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasTargetDecl);
REGISTER_MATCHER(hasTemplateArgument);
REGISTER_MATCHER(hasTrueExpression);
+ REGISTER_MATCHER(hasTypeLoc);
REGISTER_MATCHER(hasUnaryOperand);
REGISTER_MATCHER(hasValueType);
REGISTER_MATCHER(ifStmt);
@@ -215,12 +227,15 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(innerType);
REGISTER_MATCHER(integerLiteral);
REGISTER_MATCHER(isArrow);
+ REGISTER_MATCHER(isConst);
REGISTER_MATCHER(isConstQualified);
REGISTER_MATCHER(isDefinition);
REGISTER_MATCHER(isExplicitTemplateSpecialization);
+ REGISTER_MATCHER(isExpr);
REGISTER_MATCHER(isExternC);
REGISTER_MATCHER(isImplicit);
REGISTER_MATCHER(isInteger);
+ REGISTER_MATCHER(isListInitialization);
REGISTER_MATCHER(isOverride);
REGISTER_MATCHER(isPrivate);
REGISTER_MATCHER(isProtected);
@@ -252,6 +267,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(operatorCallExpr);
REGISTER_MATCHER(parameterCountIs);
REGISTER_MATCHER(parenType);
+ REGISTER_MATCHER(parmVarDecl);
REGISTER_MATCHER(pointee);
REGISTER_MATCHER(pointerType);
REGISTER_MATCHER(qualType);
@@ -275,6 +291,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(switchCase);
REGISTER_MATCHER(switchStmt);
REGISTER_MATCHER(templateSpecializationType);
+ REGISTER_MATCHER(temporaryObjectExpr);
REGISTER_MATCHER(thisExpr);
REGISTER_MATCHER(throughUsingDecl);
REGISTER_MATCHER(throwExpr);
@@ -285,6 +302,10 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(typedefType);
REGISTER_MATCHER(unaryExprOrTypeTraitExpr);
REGISTER_MATCHER(unaryOperator);
+ REGISTER_MATCHER(unaryTransformType);
+ REGISTER_MATCHER(unless);
+ REGISTER_MATCHER(unresolvedConstructExpr);
+ REGISTER_MATCHER(unresolvedUsingValueDecl);
REGISTER_MATCHER(userDefinedLiteral);
REGISTER_MATCHER(usingDecl);
REGISTER_MATCHER(varDecl);
@@ -306,27 +327,175 @@ static llvm::ManagedStatic<RegistryMaps> RegistryData;
} // anonymous namespace
// static
-VariantMatcher Registry::constructMatcher(StringRef MatcherName,
- const SourceRange &NameRange,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) {
+llvm::Optional<MatcherCtor> Registry::lookupMatcherCtor(StringRef MatcherName) {
ConstructorMap::const_iterator it =
RegistryData->constructors().find(MatcherName);
- if (it == RegistryData->constructors().end()) {
- Error->addError(NameRange, Error->ET_RegistryNotFound) << MatcherName;
- return VariantMatcher();
+ return it == RegistryData->constructors().end()
+ ? llvm::Optional<MatcherCtor>()
+ : it->second;
+}
+
+namespace {
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ const std::set<ASTNodeKind> &KS) {
+ unsigned Count = 0;
+ for (std::set<ASTNodeKind>::const_iterator I = KS.begin(), E = KS.end();
+ I != E; ++I) {
+ if (I != KS.begin())
+ OS << "|";
+ if (Count++ == 3) {
+ OS << "...";
+ break;
+ }
+ OS << *I;
+ }
+ return OS;
+}
+
+struct ReverseSpecificityThenName {
+ bool operator()(const std::pair<unsigned, std::string> &A,
+ const std::pair<unsigned, std::string> &B) const {
+ return A.first > B.first || (A.first == B.first && A.second < B.second);
}
+};
+
+}
+
+std::vector<MatcherCompletion> Registry::getCompletions(
+ ArrayRef<std::pair<MatcherCtor, unsigned> > Context) {
+ ASTNodeKind InitialTypes[] = {
+ ASTNodeKind::getFromNodeKind<Decl>(),
+ ASTNodeKind::getFromNodeKind<QualType>(),
+ ASTNodeKind::getFromNodeKind<Type>(),
+ ASTNodeKind::getFromNodeKind<Stmt>(),
+ ASTNodeKind::getFromNodeKind<NestedNameSpecifier>(),
+ ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>(),
+ ASTNodeKind::getFromNodeKind<TypeLoc>()
+ };
+ ArrayRef<ASTNodeKind> InitialTypesRef(InitialTypes);
- return it->second->run(NameRange, Args, Error);
+ // Starting with the above seed of acceptable top-level matcher types, compute
+ // the acceptable type set for the argument indicated by each context element.
+ std::set<ASTNodeKind> TypeSet(InitialTypesRef.begin(), InitialTypesRef.end());
+ for (ArrayRef<std::pair<MatcherCtor, unsigned> >::iterator
+ CtxI = Context.begin(),
+ CtxE = Context.end();
+ CtxI != CtxE; ++CtxI) {
+ std::vector<internal::ArgKind> NextTypeSet;
+ for (std::set<ASTNodeKind>::iterator I = TypeSet.begin(), E = TypeSet.end();
+ I != E; ++I) {
+ if (CtxI->first->isConvertibleTo(*I) &&
+ (CtxI->first->isVariadic() ||
+ CtxI->second < CtxI->first->getNumArgs()))
+ CtxI->first->getArgKinds(*I, CtxI->second, NextTypeSet);
+ }
+ TypeSet.clear();
+ for (std::vector<internal::ArgKind>::iterator I = NextTypeSet.begin(),
+ E = NextTypeSet.end();
+ I != E; ++I) {
+ if (I->getArgKind() == internal::ArgKind::AK_Matcher)
+ TypeSet.insert(I->getMatcherKind());
+ }
+ }
+
+ typedef std::map<std::pair<unsigned, std::string>, MatcherCompletion,
+ ReverseSpecificityThenName> CompletionsTy;
+ CompletionsTy Completions;
+
+ // TypeSet now contains the list of acceptable types for the argument we are
+ // completing. Search the registry for acceptable matchers.
+ for (ConstructorMap::const_iterator I = RegistryData->constructors().begin(),
+ E = RegistryData->constructors().end();
+ I != E; ++I) {
+ std::set<ASTNodeKind> RetKinds;
+ unsigned NumArgs = I->second->isVariadic() ? 1 : I->second->getNumArgs();
+ bool IsPolymorphic = I->second->isPolymorphic();
+ std::vector<std::vector<internal::ArgKind> > ArgsKinds(NumArgs);
+ unsigned MaxSpecificity = 0;
+ for (std::set<ASTNodeKind>::iterator TI = TypeSet.begin(),
+ TE = TypeSet.end();
+ TI != TE; ++TI) {
+ unsigned Specificity;
+ ASTNodeKind LeastDerivedKind;
+ if (I->second->isConvertibleTo(*TI, &Specificity, &LeastDerivedKind)) {
+ if (MaxSpecificity < Specificity)
+ MaxSpecificity = Specificity;
+ RetKinds.insert(LeastDerivedKind);
+ for (unsigned Arg = 0; Arg != NumArgs; ++Arg)
+ I->second->getArgKinds(*TI, Arg, ArgsKinds[Arg]);
+ if (IsPolymorphic)
+ break;
+ }
+ }
+
+ if (!RetKinds.empty() && MaxSpecificity > 0) {
+ std::string Decl;
+ llvm::raw_string_ostream OS(Decl);
+
+ if (IsPolymorphic) {
+ OS << "Matcher<T> " << I->first() << "(Matcher<T>";
+ } else {
+ OS << "Matcher<" << RetKinds << "> " << I->first() << "(";
+ for (std::vector<std::vector<internal::ArgKind> >::iterator
+ KI = ArgsKinds.begin(),
+ KE = ArgsKinds.end();
+ KI != KE; ++KI) {
+ if (KI != ArgsKinds.begin())
+ OS << ", ";
+ // This currently assumes that a matcher may not overload a
+ // non-matcher, and all non-matcher overloads have identical
+ // arguments.
+ if ((*KI)[0].getArgKind() == internal::ArgKind::AK_Matcher) {
+ std::set<ASTNodeKind> MatcherKinds;
+ std::transform(
+ KI->begin(), KI->end(),
+ std::inserter(MatcherKinds, MatcherKinds.end()),
+ std::mem_fun_ref(&internal::ArgKind::getMatcherKind));
+ OS << "Matcher<" << MatcherKinds << ">";
+ } else {
+ OS << (*KI)[0].asString();
+ }
+ }
+ }
+ if (I->second->isVariadic())
+ OS << "...";
+ OS << ")";
+
+ std::string TypedText = I->first();
+ TypedText += "(";
+ if (ArgsKinds.empty())
+ TypedText += ")";
+ else if (ArgsKinds[0][0].getArgKind() == internal::ArgKind::AK_String)
+ TypedText += "\"";
+
+ Completions[std::make_pair(MaxSpecificity, I->first())] =
+ MatcherCompletion(TypedText, OS.str());
+ }
+ }
+
+ std::vector<MatcherCompletion> RetVal;
+ for (CompletionsTy::iterator I = Completions.begin(), E = Completions.end();
+ I != E; ++I)
+ RetVal.push_back(I->second);
+ return RetVal;
+}
+
+// static
+VariantMatcher Registry::constructMatcher(MatcherCtor Ctor,
+ const SourceRange &NameRange,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
+ return Ctor->create(NameRange, Args, Error);
}
// static
-VariantMatcher Registry::constructBoundMatcher(StringRef MatcherName,
+VariantMatcher Registry::constructBoundMatcher(MatcherCtor Ctor,
const SourceRange &NameRange,
StringRef BindID,
ArrayRef<ParserValue> Args,
Diagnostics *Error) {
- VariantMatcher Out = constructMatcher(MatcherName, NameRange, Args, Error);
+ VariantMatcher Out = constructMatcher(Ctor, NameRange, Args, Error);
if (Out.isNull()) return Out;
llvm::Optional<DynTypedMatcher> Result = Out.getSingleMatcher();
diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp
index 3e49e1b8ef03..18c989432f46 100644
--- a/lib/ASTMatchers/Dynamic/VariantValue.cpp
+++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp
@@ -13,7 +13,6 @@
//===----------------------------------------------------------------------===//
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
-
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/STLExtras.h"
@@ -38,7 +37,8 @@ public:
}
virtual void makeTypedMatcher(MatcherOps &Ops) const {
- if (Ops.canConstructFrom(Matcher))
+ bool Ignore;
+ if (Ops.canConstructFrom(Matcher, Ignore))
Ops.constructFrom(Matcher);
}
@@ -48,8 +48,8 @@ private:
class VariantMatcher::PolymorphicPayload : public VariantMatcher::Payload {
public:
- PolymorphicPayload(ArrayRef<DynTypedMatcher> MatchersIn)
- : Matchers(MatchersIn) {}
+ PolymorphicPayload(std::vector<DynTypedMatcher> MatchersIn)
+ : Matchers(std::move(MatchersIn)) {}
virtual ~PolymorphicPayload() {}
@@ -70,15 +70,25 @@ public:
}
virtual void makeTypedMatcher(MatcherOps &Ops) const {
- const DynTypedMatcher *Found = NULL;
+ bool FoundIsExact = false;
+ const DynTypedMatcher *Found = nullptr;
+ int NumFound = 0;
for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
- if (Ops.canConstructFrom(Matchers[i])) {
- if (Found)
- return;
+ bool IsExactMatch;
+ if (Ops.canConstructFrom(Matchers[i], IsExactMatch)) {
+ if (Found) {
+ if (FoundIsExact) {
+ assert(!IsExactMatch && "We should not have two exact matches.");
+ continue;
+ }
+ }
Found = &Matchers[i];
+ FoundIsExact = IsExactMatch;
+ ++NumFound;
}
}
- if (Found)
+ // We only succeed if we found exactly one, or if we found an exact match.
+ if (Found && (FoundIsExact || NumFound == 1))
Ops.constructFrom(*Found);
}
@@ -88,8 +98,8 @@ public:
class VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload {
public:
VariadicOpPayload(ast_matchers::internal::VariadicOperatorFunction Func,
- ArrayRef<VariantMatcher> Args)
- : Func(Func), Args(Args) {}
+ std::vector<VariantMatcher> Args)
+ : Func(Func), Args(std::move(Args)) {}
virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const {
return llvm::Optional<DynTypedMatcher>();
@@ -121,14 +131,14 @@ VariantMatcher VariantMatcher::SingleMatcher(const DynTypedMatcher &Matcher) {
}
VariantMatcher
-VariantMatcher::PolymorphicMatcher(ArrayRef<DynTypedMatcher> Matchers) {
- return VariantMatcher(new PolymorphicPayload(Matchers));
+VariantMatcher::PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers) {
+ return VariantMatcher(new PolymorphicPayload(std::move(Matchers)));
}
VariantMatcher VariantMatcher::VariadicOperatorMatcher(
ast_matchers::internal::VariadicOperatorFunction Func,
- ArrayRef<VariantMatcher> Args) {
- return VariantMatcher(new VariadicOpPayload(Func, Args));
+ std::vector<VariantMatcher> Args) {
+ return VariantMatcher(new VariadicOpPayload(Func, std::move(Args)));
}
llvm::Optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const {
diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp
index 465f0c383486..90d4b13b88be 100644
--- a/lib/Analysis/AnalysisDeclContext.cpp
+++ b/lib/Analysis/AnalysisDeclContext.cpp
@@ -28,8 +28,8 @@
#include "clang/Analysis/Support/BumpVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -41,11 +41,11 @@ AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
: Manager(Mgr),
D(d),
cfgBuildOptions(buildOptions),
- forcedBlkExprs(0),
+ forcedBlkExprs(nullptr),
builtCFG(false),
builtCompleteCFG(false),
- ReferencedBlockVars(0),
- ManagedAnalyses(0)
+ ReferencedBlockVars(nullptr),
+ ManagedAnalyses(nullptr)
{
cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs;
}
@@ -54,11 +54,11 @@ AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
const Decl *d)
: Manager(Mgr),
D(d),
- forcedBlkExprs(0),
+ forcedBlkExprs(nullptr),
builtCFG(false),
builtCompleteCFG(false),
- ReferencedBlockVars(0),
- ManagedAnalyses(0)
+ ReferencedBlockVars(nullptr),
+ ManagedAnalyses(nullptr)
{
cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs;
}
@@ -68,7 +68,8 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG,
bool addInitializers,
bool addTemporaryDtors,
bool synthesizeBodies,
- bool addStaticInitBranch)
+ bool addStaticInitBranch,
+ bool addCXXNewAllocator)
: SynthesizeBodies(synthesizeBodies)
{
cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
@@ -76,12 +77,11 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG,
cfgBuildOptions.AddInitializers = addInitializers;
cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors;
cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch;
+ cfgBuildOptions.AddCXXNewAllocator = addCXXNewAllocator;
}
void AnalysisDeclContextManager::clear() {
- for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I)
- delete I->second;
- Contexts.clear();
+ llvm::DeleteContainerSeconds(Contexts);
}
static BodyFarm &getBodyFarm(ASTContext &C) {
@@ -94,14 +94,21 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Stmt *Body = FD->getBody();
if (!Body && Manager && Manager->synthesizeBodies()) {
- IsAutosynthesized = true;
- return getBodyFarm(getASTContext()).getBody(FD);
+ Body = getBodyFarm(getASTContext()).getBody(FD);
+ if (Body)
+ IsAutosynthesized = true;
}
return Body;
}
- else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
- return MD->getBody();
- else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
+ else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ Stmt *Body = MD->getBody();
+ if (!Body && Manager && Manager->synthesizeBodies()) {
+ Body = getBodyFarm(getASTContext()).getBody(MD);
+ if (Body)
+ IsAutosynthesized = true;
+ }
+ return Body;
+ } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
return BD->getBody();
else if (const FunctionTemplateDecl *FunTmpl
= dyn_cast_or_null<FunctionTemplateDecl>(D))
@@ -126,15 +133,14 @@ const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
return MD->getSelfDecl();
if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
// See if 'self' was captured by the block.
- for (BlockDecl::capture_const_iterator it = BD->capture_begin(),
- et = BD->capture_end(); it != et; ++it) {
- const VarDecl *VD = it->getVariable();
+ for (const auto &I : BD->captures()) {
+ const VarDecl *VD = I.getVariable();
if (VD->getName() == "self")
return dyn_cast<ImplicitParamDecl>(VD);
}
}
- return NULL;
+ return nullptr;
}
void AnalysisDeclContext::registerForcedBlockExpression(const Stmt *stmt) {
@@ -183,6 +189,9 @@ CFG *AnalysisDeclContext::getCFG() {
if (PM)
addParentsForSyntheticStmts(cfg.get(), *PM);
+
+ // The Observer should only observe one build of the CFG.
+ getCFGBuildOptions().Observer = nullptr;
}
return cfg.get();
}
@@ -199,6 +208,9 @@ CFG *AnalysisDeclContext::getUnoptimizedCFG() {
if (PM)
addParentsForSyntheticStmts(completeCFG.get(), *PM);
+
+ // The Observer should only observe one build of the CFG.
+ getCFGBuildOptions().Observer = nullptr;
}
return completeCFG.get();
}
@@ -211,8 +223,8 @@ CFGStmtMap *AnalysisDeclContext::getCFGStmtMap() {
cfgStmtMap.reset(CFGStmtMap::Build(c, &getParentMap()));
return cfgStmtMap.get();
}
-
- return 0;
+
+ return nullptr;
}
CFGReverseBlockReachabilityAnalysis *AnalysisDeclContext::getCFGReachablityAnalysis() {
@@ -223,8 +235,8 @@ CFGReverseBlockReachabilityAnalysis *AnalysisDeclContext::getCFGReachablityAnaly
CFA.reset(new CFGReverseBlockReachabilityAnalysis(*c));
return CFA.get();
}
-
- return 0;
+
+ return nullptr;
}
void AnalysisDeclContext::dumpCFG(bool ShowColors) {
@@ -235,10 +247,8 @@ ParentMap &AnalysisDeclContext::getParentMap() {
if (!PM) {
PM.reset(new ParentMap(getBody()));
if (const CXXConstructorDecl *C = dyn_cast<CXXConstructorDecl>(getDecl())) {
- for (CXXConstructorDecl::init_const_iterator I = C->init_begin(),
- E = C->init_end();
- I != E; ++I) {
- PM->addStmt((*I)->getInit());
+ for (const auto *I : C->inits()) {
+ PM->addStmt(I->getInit());
}
}
if (builtCFG)
@@ -391,7 +401,7 @@ const StackFrameContext *LocationContext::getCurrentStackFrame() const {
return SFC;
LC = LC->getParent();
}
- return NULL;
+ return nullptr;
}
bool LocationContext::inTopFrame() const {
@@ -435,7 +445,7 @@ void LocationContext::dumpStack(raw_ostream &OS, StringRef Indent) const {
}
}
-void LocationContext::dumpStack() const {
+LLVM_DUMP_METHOD void LocationContext::dumpStack() const {
dumpStack(llvm::errs());
}
@@ -454,11 +464,6 @@ public:
BumpVectorContext &bc)
: BEVals(bevals), BC(bc) {}
- bool IsTrackedDecl(const VarDecl *VD) {
- const DeclContext *DC = VD->getDeclContext();
- return IgnoredContexts.count(DC) == 0;
- }
-
void VisitStmt(Stmt *S) {
for (Stmt::child_range I = S->children(); I; ++I)
if (Stmt *child = *I)
@@ -506,9 +511,8 @@ static DeclVec* LazyInitializeReferencedDecls(const BlockDecl *BD,
new (BV) DeclVec(BC, 10);
// Go through the capture list.
- for (BlockDecl::capture_const_iterator CI = BD->capture_begin(),
- CE = BD->capture_end(); CI != CE; ++CI) {
- BV->push_back(CI->getVariable(), BC);
+ for (const auto &CI : BD->captures()) {
+ BV->push_back(CI.getVariable(), BC);
}
// Find the referenced global/static variables.
@@ -548,15 +552,13 @@ AnalysisDeclContext::~AnalysisDeclContext() {
// Release the managed analyses.
if (ManagedAnalyses) {
ManagedAnalysisMap *M = (ManagedAnalysisMap*) ManagedAnalyses;
- for (ManagedAnalysisMap::iterator I = M->begin(), E = M->end(); I!=E; ++I)
- delete I->second;
+ llvm::DeleteContainerSeconds(*M);
delete M;
}
}
AnalysisDeclContextManager::~AnalysisDeclContextManager() {
- for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I)
- delete I->second;
+ llvm::DeleteContainerSeconds(Contexts);
}
LocationContext::~LocationContext() {}
diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp
index 4d5c2ee236f9..316a18b421b5 100644
--- a/lib/Analysis/BodyFarm.cpp
+++ b/lib/Analysis/BodyFarm.cpp
@@ -35,8 +35,7 @@ static bool isDispatchBlock(QualType Ty) {
// returns void.
const FunctionProtoType *FT =
BPT->getPointeeType()->getAs<FunctionProtoType>();
- if (!FT || !FT->getResultType()->isVoidType() ||
- FT->getNumArgs() != 0)
+ if (!FT || !FT->getReturnType()->isVoidType() || FT->getNumParams() != 0)
return false;
return true;
@@ -74,6 +73,9 @@ public:
/// Create an Objective-C bool literal.
ObjCBoolLiteralExpr *makeObjCBool(bool Val);
+
+ /// Create an Objective-C ivar reference.
+ ObjCIvarRefExpr *makeObjCIvarRef(const Expr *Base, const ObjCIvarDecl *IVar);
/// Create a Return statement.
ReturnStmt *makeReturn(const Expr *RetVal);
@@ -126,20 +128,20 @@ UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
- const_cast<Expr*>(Arg), 0, VK_RValue);
+ const_cast<Expr*>(Arg), nullptr, VK_RValue);
}
Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
if (Arg->getType() == Ty)
return const_cast<Expr*>(Arg);
-
+
return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast,
- const_cast<Expr*>(Arg), 0, VK_RValue);
+ const_cast<Expr*>(Arg), nullptr, VK_RValue);
}
ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) {
return ImplicitCastExpr::Create(C, C.BoolTy, CK_IntegralToBoolean,
- const_cast<Expr*>(Arg), 0, VK_RValue);
+ const_cast<Expr*>(Arg), nullptr, VK_RValue);
}
ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) {
@@ -147,8 +149,18 @@ ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) {
return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation());
}
+ObjCIvarRefExpr *ASTMaker::makeObjCIvarRef(const Expr *Base,
+ const ObjCIvarDecl *IVar) {
+ return new (C) ObjCIvarRefExpr(const_cast<ObjCIvarDecl*>(IVar),
+ IVar->getType(), SourceLocation(),
+ SourceLocation(), const_cast<Expr*>(Base),
+ /*arrow=*/true, /*free=*/false);
+}
+
+
ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) {
- return new (C) ReturnStmt(SourceLocation(), const_cast<Expr*>(RetVal), 0);
+ return new (C) ReturnStmt(SourceLocation(), const_cast<Expr*>(RetVal),
+ nullptr);
}
//===----------------------------------------------------------------------===//
@@ -161,24 +173,24 @@ typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
// Check if we have at least two parameters.
if (D->param_size() != 2)
- return 0;
+ return nullptr;
// Check if the first parameter is a pointer to integer type.
const ParmVarDecl *Predicate = D->getParamDecl(0);
QualType PredicateQPtrTy = Predicate->getType();
const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
if (!PredicatePtrTy)
- return 0;
+ return nullptr;
QualType PredicateTy = PredicatePtrTy->getPointeeType();
if (!PredicateTy->isIntegerType())
- return 0;
-
+ return nullptr;
+
// Check if the second parameter is the proper block type.
const ParmVarDecl *Block = D->getParamDecl(1);
QualType Ty = Block->getType();
if (!isDispatchBlock(Ty))
- return 0;
-
+ return nullptr;
+
// Everything checks out. Create a fakse body that checks the predicate,
// sets it, and calls the block. Basically, an AST dump of:
//
@@ -231,7 +243,7 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
SourceLocation());
// (5) Create the 'if' statement.
- IfStmt *If = new (C) IfStmt(C, SourceLocation(), 0, UO, CS);
+ IfStmt *If = new (C) IfStmt(C, SourceLocation(), nullptr, UO, CS);
return If;
}
@@ -239,14 +251,14 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
// Check if we have at least two parameters.
if (D->param_size() != 2)
- return 0;
-
+ return nullptr;
+
// Check if the second parameter is a block.
const ParmVarDecl *PV = D->getParamDecl(1);
QualType Ty = PV->getType();
if (!isDispatchBlock(Ty))
- return 0;
-
+ return nullptr;
+
// Everything checks out. Create a fake body that just calls the block.
// This is basically just an AST dump of:
//
@@ -266,8 +278,8 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
{
// There are exactly 3 arguments.
if (D->param_size() != 3)
- return 0;
-
+ return nullptr;
+
// Signature:
// _Bool OSAtomicCompareAndSwapPtr(void *__oldValue,
// void *__newValue,
@@ -278,12 +290,12 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
// return YES;
// }
// else return NO;
-
- QualType ResultTy = D->getResultType();
+
+ QualType ResultTy = D->getReturnType();
bool isBoolean = ResultTy->isBooleanType();
if (!isBoolean && !ResultTy->isIntegralType(C))
- return 0;
-
+ return nullptr;
+
const ParmVarDecl *OldValue = D->getParamDecl(0);
QualType OldValueTy = OldValue->getType();
@@ -296,7 +308,7 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
QualType TheValueTy = TheValue->getType();
const PointerType *PT = TheValueTy->getAs<PointerType>();
if (!PT)
- return 0;
+ return nullptr;
QualType PointeeTy = PT->getPointeeType();
ASTMaker M(C);
@@ -335,9 +347,9 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
/// Construct the If.
Stmt *If =
- new (C) IfStmt(C, SourceLocation(), 0, Comparison, Body,
+ new (C) IfStmt(C, SourceLocation(), nullptr, Comparison, Body,
SourceLocation(), Else);
-
+
return If;
}
@@ -347,15 +359,15 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) {
Optional<Stmt *> &Val = Bodies[D];
if (Val.hasValue())
return Val.getValue();
-
- Val = 0;
-
- if (D->getIdentifier() == 0)
- return 0;
+
+ Val = nullptr;
+
+ if (D->getIdentifier() == nullptr)
+ return nullptr;
StringRef Name = D->getName();
if (Name.empty())
- return 0;
+ return nullptr;
FunctionFarmer FF;
@@ -367,10 +379,94 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) {
FF = llvm::StringSwitch<FunctionFarmer>(Name)
.Case("dispatch_sync", create_dispatch_sync)
.Case("dispatch_once", create_dispatch_once)
- .Default(NULL);
+ .Default(nullptr);
}
if (FF) { Val = FF(C, D); }
return Val.getValue();
}
+static Stmt *createObjCPropertyGetter(ASTContext &Ctx,
+ const ObjCPropertyDecl *Prop) {
+ // First, find the backing ivar.
+ const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl();
+ if (!IVar)
+ return nullptr;
+
+ // Ignore weak variables, which have special behavior.
+ if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)
+ return nullptr;
+
+ // Look to see if Sema has synthesized a body for us. This happens in
+ // Objective-C++ because the return value may be a C++ class type with a
+ // non-trivial copy constructor. We can only do this if we can find the
+ // @synthesize for this property, though (or if we know it's been auto-
+ // synthesized).
+ const ObjCImplementationDecl *ImplDecl =
+ IVar->getContainingInterface()->getImplementation();
+ if (ImplDecl) {
+ for (const auto *I : ImplDecl->property_impls()) {
+ if (I->getPropertyDecl() != Prop)
+ continue;
+
+ if (I->getGetterCXXConstructor()) {
+ ASTMaker M(Ctx);
+ return M.makeReturn(I->getGetterCXXConstructor());
+ }
+ }
+ }
+
+ // Sanity check that the property is the same type as the ivar, or a
+ // reference to it, and that it is either an object pointer or trivially
+ // copyable.
+ if (!Ctx.hasSameUnqualifiedType(IVar->getType(),
+ Prop->getType().getNonReferenceType()))
+ return nullptr;
+ if (!IVar->getType()->isObjCLifetimeType() &&
+ !IVar->getType().isTriviallyCopyableType(Ctx))
+ return nullptr;
+
+ // Generate our body:
+ // return self->_ivar;
+ ASTMaker M(Ctx);
+
+ const VarDecl *selfVar = Prop->getGetterMethodDecl()->getSelfDecl();
+
+ Expr *loadedIVar =
+ M.makeObjCIvarRef(
+ M.makeLvalueToRvalue(
+ M.makeDeclRefExpr(selfVar),
+ selfVar->getType()),
+ IVar);
+
+ if (!Prop->getType()->isReferenceType())
+ loadedIVar = M.makeLvalueToRvalue(loadedIVar, IVar->getType());
+
+ return M.makeReturn(loadedIVar);
+}
+
+Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
+ // We currently only know how to synthesize property accessors.
+ if (!D->isPropertyAccessor())
+ return nullptr;
+
+ D = D->getCanonicalDecl();
+
+ Optional<Stmt *> &Val = Bodies[D];
+ if (Val.hasValue())
+ return Val.getValue();
+ Val = nullptr;
+
+ const ObjCPropertyDecl *Prop = D->findPropertyDecl();
+ if (!Prop)
+ return nullptr;
+
+ // For now, we only synthesize getters.
+ if (D->param_size() != 0)
+ return nullptr;
+
+ Val = createObjCPropertyGetter(C, Prop);
+
+ return Val.getValue();
+}
+
diff --git a/lib/Analysis/BodyFarm.h b/lib/Analysis/BodyFarm.h
index 96f61df40d7f..2d200fb755c1 100644
--- a/lib/Analysis/BodyFarm.h
+++ b/lib/Analysis/BodyFarm.h
@@ -24,6 +24,8 @@ namespace clang {
class ASTContext;
class Decl;
class FunctionDecl;
+class ObjCMethodDecl;
+class ObjCPropertyDecl;
class Stmt;
class BodyFarm {
@@ -32,7 +34,10 @@ public:
/// Factory method for creating bodies for ordinary functions.
Stmt *getBody(const FunctionDecl *D);
-
+
+ /// Factory method for creating bodies for Objective-C properties.
+ Stmt *getBody(const ObjCMethodDecl *D);
+
private:
typedef llvm::DenseMap<const Decl *, Optional<Stmt *> > BodyMap;
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 8b8c573feade..842a385fbcdb 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -21,7 +21,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Builtins.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/OwningPtr.h"
+#include <memory>
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Format.h"
@@ -112,7 +112,7 @@ public:
/// Incrementing invalid iterator is allowed and will result in invalid
/// iterator.
const_iterator()
- : Scope(NULL), VarIter(0) {}
+ : Scope(nullptr), VarIter(0) {}
/// Create valid iterator. In case when S.Prev is an invalid iterator and
/// I is equal to 0, this will create invalid iterator.
@@ -207,7 +207,7 @@ int LocalScope::const_iterator::distance(LocalScope::const_iterator L) {
/// build process. It consists of CFGBlock that specifies position in CFG graph
/// and LocalScope::const_iterator that specifies position in LocalScope graph.
struct BlockScopePosPair {
- BlockScopePosPair() : block(0) {}
+ BlockScopePosPair() : block(nullptr) {}
BlockScopePosPair(CFGBlock *b, LocalScope::const_iterator scopePos)
: block(b), scopePosition(scopePos) {}
@@ -291,7 +291,7 @@ class CFGBuilder {
typedef BlockScopePosPair JumpSource;
ASTContext *Context;
- OwningPtr<CFG> cfg;
+ std::unique_ptr<CFG> cfg;
CFGBlock *Block;
CFGBlock *Succ;
@@ -336,11 +336,11 @@ public:
explicit CFGBuilder(ASTContext *astContext,
const CFG::BuildOptions &buildOpts)
: Context(astContext), cfg(new CFG()), // crew a new CFG
- Block(NULL), Succ(NULL),
- SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL),
- TryTerminatedBlock(NULL), badCFG(false), BuildOpts(buildOpts),
- switchExclusivelyCovered(false), switchCond(0),
- cachedEntry(0), lastLookup(0) {}
+ Block(nullptr), Succ(nullptr),
+ SwitchTerminatedBlock(nullptr), DefaultCaseBlock(nullptr),
+ TryTerminatedBlock(nullptr), badCFG(false), BuildOpts(buildOpts),
+ switchExclusivelyCovered(false), switchCond(nullptr),
+ cachedEntry(nullptr), lastLookup(nullptr) {}
// buildCFG - Used by external clients to construct the CFG.
CFG* buildCFG(const Decl *D, Stmt *Statement);
@@ -363,6 +363,7 @@ private:
AddStmtChoice asc);
CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S);
CFGBlock *VisitCXXConstructExpr(CXXConstructExpr *C, AddStmtChoice asc);
+ CFGBlock *VisitCXXNewExpr(CXXNewExpr *DE, AddStmtChoice asc);
CFGBlock *VisitCXXDeleteExpr(CXXDeleteExpr *DE, AddStmtChoice asc);
CFGBlock *VisitCXXForRangeStmt(CXXForRangeStmt *S);
CFGBlock *VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E,
@@ -442,8 +443,9 @@ private:
LocalScope* createOrReuseLocalScope(LocalScope* Scope);
void addLocalScopeForStmt(Stmt *S);
- LocalScope* addLocalScopeForDeclStmt(DeclStmt *DS, LocalScope* Scope = NULL);
- LocalScope* addLocalScopeForVarDecl(VarDecl *VD, LocalScope* Scope = NULL);
+ LocalScope* addLocalScopeForDeclStmt(DeclStmt *DS,
+ LocalScope* Scope = nullptr);
+ LocalScope* addLocalScopeForVarDecl(VarDecl *VD, LocalScope* Scope = nullptr);
void addLocalScopeAndDtors(Stmt *S);
@@ -459,6 +461,9 @@ private:
void appendInitializer(CFGBlock *B, CXXCtorInitializer *I) {
B->appendInitializer(I, cfg->getBumpVectorContext());
}
+ void appendNewAllocator(CFGBlock *B, CXXNewExpr *NE) {
+ B->appendNewAllocator(NE, cfg->getBumpVectorContext());
+ }
void appendBaseDtor(CFGBlock *B, const CXXBaseSpecifier *BS) {
B->appendBaseDtor(BS, cfg->getBumpVectorContext());
}
@@ -479,8 +484,252 @@ private:
void prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk,
LocalScope::const_iterator B, LocalScope::const_iterator E);
- void addSuccessor(CFGBlock *B, CFGBlock *S) {
- B->addSuccessor(S, cfg->getBumpVectorContext());
+ void addSuccessor(CFGBlock *B, CFGBlock *S, bool IsReachable = true) {
+ B->addSuccessor(CFGBlock::AdjacentBlock(S, IsReachable),
+ cfg->getBumpVectorContext());
+ }
+
+ /// Add a reachable successor to a block, with the alternate variant that is
+ /// unreachable.
+ void addSuccessor(CFGBlock *B, CFGBlock *ReachableBlock, CFGBlock *AltBlock) {
+ B->addSuccessor(CFGBlock::AdjacentBlock(ReachableBlock, AltBlock),
+ cfg->getBumpVectorContext());
+ }
+
+ /// \brief Find a relational comparison with an expression evaluating to a
+ /// boolean and a constant other than 0 and 1.
+ /// e.g. if ((x < y) == 10)
+ TryResult checkIncorrectRelationalOperator(const BinaryOperator *B) {
+ const Expr *LHSExpr = B->getLHS()->IgnoreParens();
+ const Expr *RHSExpr = B->getRHS()->IgnoreParens();
+
+ const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr);
+ const Expr *BoolExpr = RHSExpr;
+ bool IntFirst = true;
+ if (!IntLiteral) {
+ IntLiteral = dyn_cast<IntegerLiteral>(RHSExpr);
+ BoolExpr = LHSExpr;
+ IntFirst = false;
+ }
+
+ if (!IntLiteral || !BoolExpr->isKnownToHaveBooleanValue())
+ return TryResult();
+
+ llvm::APInt IntValue = IntLiteral->getValue();
+ if ((IntValue == 1) || (IntValue == 0))
+ return TryResult();
+
+ bool IntLarger = IntLiteral->getType()->isUnsignedIntegerType() ||
+ !IntValue.isNegative();
+
+ BinaryOperatorKind Bok = B->getOpcode();
+ if (Bok == BO_GT || Bok == BO_GE) {
+ // Always true for 10 > bool and bool > -1
+ // Always false for -1 > bool and bool > 10
+ return TryResult(IntFirst == IntLarger);
+ } else {
+ // Always true for -1 < bool and bool < 10
+ // Always false for 10 < bool and bool < -1
+ return TryResult(IntFirst != IntLarger);
+ }
+ }
+
+ /// Find an incorrect equality comparison. Either with an expression
+ /// evaluating to a boolean and a constant other than 0 and 1.
+ /// e.g. if (!x == 10) or a bitwise and/or operation that always evaluates to
+ /// true/false e.q. (x & 8) == 4.
+ TryResult checkIncorrectEqualityOperator(const BinaryOperator *B) {
+ const Expr *LHSExpr = B->getLHS()->IgnoreParens();
+ const Expr *RHSExpr = B->getRHS()->IgnoreParens();
+
+ const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr);
+ const Expr *BoolExpr = RHSExpr;
+
+ if (!IntLiteral) {
+ IntLiteral = dyn_cast<IntegerLiteral>(RHSExpr);
+ BoolExpr = LHSExpr;
+ }
+
+ if (!IntLiteral)
+ return TryResult();
+
+ const BinaryOperator *BitOp = dyn_cast<BinaryOperator>(BoolExpr);
+ if (BitOp && (BitOp->getOpcode() == BO_And ||
+ BitOp->getOpcode() == BO_Or)) {
+ const Expr *LHSExpr2 = BitOp->getLHS()->IgnoreParens();
+ const Expr *RHSExpr2 = BitOp->getRHS()->IgnoreParens();
+
+ const IntegerLiteral *IntLiteral2 = dyn_cast<IntegerLiteral>(LHSExpr2);
+
+ if (!IntLiteral2)
+ IntLiteral2 = dyn_cast<IntegerLiteral>(RHSExpr2);
+
+ if (!IntLiteral2)
+ return TryResult();
+
+ llvm::APInt L1 = IntLiteral->getValue();
+ llvm::APInt L2 = IntLiteral2->getValue();
+ if ((BitOp->getOpcode() == BO_And && (L2 & L1) != L1) ||
+ (BitOp->getOpcode() == BO_Or && (L2 | L1) != L1)) {
+ if (BuildOpts.Observer)
+ BuildOpts.Observer->compareBitwiseEquality(B,
+ B->getOpcode() != BO_EQ);
+ TryResult(B->getOpcode() != BO_EQ);
+ }
+ } else if (BoolExpr->isKnownToHaveBooleanValue()) {
+ llvm::APInt IntValue = IntLiteral->getValue();
+ if ((IntValue == 1) || (IntValue == 0)) {
+ return TryResult();
+ }
+ return TryResult(B->getOpcode() != BO_EQ);
+ }
+
+ return TryResult();
+ }
+
+ TryResult analyzeLogicOperatorCondition(BinaryOperatorKind Relation,
+ const llvm::APSInt &Value1,
+ const llvm::APSInt &Value2) {
+ assert(Value1.isSigned() == Value2.isSigned());
+ switch (Relation) {
+ default:
+ return TryResult();
+ case BO_EQ:
+ return TryResult(Value1 == Value2);
+ case BO_NE:
+ return TryResult(Value1 != Value2);
+ case BO_LT:
+ return TryResult(Value1 < Value2);
+ case BO_LE:
+ return TryResult(Value1 <= Value2);
+ case BO_GT:
+ return TryResult(Value1 > Value2);
+ case BO_GE:
+ return TryResult(Value1 >= Value2);
+ }
+ }
+
+ /// \brief Find a pair of comparison expressions with or without parentheses
+ /// with a shared variable and constants and a logical operator between them
+ /// that always evaluates to either true or false.
+ /// e.g. if (x != 3 || x != 4)
+ TryResult checkIncorrectLogicOperator(const BinaryOperator *B) {
+ assert(B->isLogicalOp());
+ const BinaryOperator *LHS =
+ dyn_cast<BinaryOperator>(B->getLHS()->IgnoreParens());
+ const BinaryOperator *RHS =
+ dyn_cast<BinaryOperator>(B->getRHS()->IgnoreParens());
+ if (!LHS || !RHS)
+ return TryResult();
+
+ if (!LHS->isComparisonOp() || !RHS->isComparisonOp())
+ return TryResult();
+
+ BinaryOperatorKind BO1 = LHS->getOpcode();
+ const DeclRefExpr *Decl1 =
+ dyn_cast<DeclRefExpr>(LHS->getLHS()->IgnoreParenImpCasts());
+ const IntegerLiteral *Literal1 =
+ dyn_cast<IntegerLiteral>(LHS->getRHS()->IgnoreParens());
+ if (!Decl1 && !Literal1) {
+ if (BO1 == BO_GT)
+ BO1 = BO_LT;
+ else if (BO1 == BO_GE)
+ BO1 = BO_LE;
+ else if (BO1 == BO_LT)
+ BO1 = BO_GT;
+ else if (BO1 == BO_LE)
+ BO1 = BO_GE;
+ Decl1 = dyn_cast<DeclRefExpr>(LHS->getRHS()->IgnoreParenImpCasts());
+ Literal1 = dyn_cast<IntegerLiteral>(LHS->getLHS()->IgnoreParens());
+ }
+
+ if (!Decl1 || !Literal1)
+ return TryResult();
+
+ BinaryOperatorKind BO2 = RHS->getOpcode();
+ const DeclRefExpr *Decl2 =
+ dyn_cast<DeclRefExpr>(RHS->getLHS()->IgnoreParenImpCasts());
+ const IntegerLiteral *Literal2 =
+ dyn_cast<IntegerLiteral>(RHS->getRHS()->IgnoreParens());
+ if (!Decl2 && !Literal2) {
+ if (BO2 == BO_GT)
+ BO2 = BO_LT;
+ else if (BO2 == BO_GE)
+ BO2 = BO_LE;
+ else if (BO2 == BO_LT)
+ BO2 = BO_GT;
+ else if (BO2 == BO_LE)
+ BO2 = BO_GE;
+ Decl2 = dyn_cast<DeclRefExpr>(RHS->getRHS()->IgnoreParenImpCasts());
+ Literal2 = dyn_cast<IntegerLiteral>(RHS->getLHS()->IgnoreParens());
+ }
+
+ if (!Decl2 || !Literal2)
+ return TryResult();
+
+ // Check that it is the same variable on both sides.
+ if (Decl1->getDecl() != Decl2->getDecl())
+ return TryResult();
+
+ llvm::APSInt L1, L2;
+
+ if (!Literal1->EvaluateAsInt(L1, *Context) ||
+ !Literal2->EvaluateAsInt(L2, *Context))
+ return TryResult();
+
+ // Can't compare signed with unsigned or with different bit width.
+ if (L1.isSigned() != L2.isSigned() || L1.getBitWidth() != L2.getBitWidth())
+ return TryResult();
+
+ // Values that will be used to determine if result of logical
+ // operator is always true/false
+ const llvm::APSInt Values[] = {
+ // Value less than both Value1 and Value2
+ llvm::APSInt::getMinValue(L1.getBitWidth(), L1.isUnsigned()),
+ // L1
+ L1,
+ // Value between Value1 and Value2
+ ((L1 < L2) ? L1 : L2) + llvm::APSInt(llvm::APInt(L1.getBitWidth(), 1),
+ L1.isUnsigned()),
+ // L2
+ L2,
+ // Value greater than both Value1 and Value2
+ llvm::APSInt::getMaxValue(L1.getBitWidth(), L1.isUnsigned()),
+ };
+
+ // Check whether expression is always true/false by evaluating the following
+ // * variable x is less than the smallest literal.
+ // * variable x is equal to the smallest literal.
+ // * Variable x is between smallest and largest literal.
+ // * Variable x is equal to the largest literal.
+ // * Variable x is greater than largest literal.
+ bool AlwaysTrue = true, AlwaysFalse = true;
+ for (unsigned int ValueIndex = 0;
+ ValueIndex < sizeof(Values) / sizeof(Values[0]);
+ ++ValueIndex) {
+ llvm::APSInt Value = Values[ValueIndex];
+ TryResult Res1, Res2;
+ Res1 = analyzeLogicOperatorCondition(BO1, Value, L1);
+ Res2 = analyzeLogicOperatorCondition(BO2, Value, L2);
+
+ if (!Res1.isKnown() || !Res2.isKnown())
+ return TryResult();
+
+ if (B->getOpcode() == BO_LAnd) {
+ AlwaysTrue &= (Res1.isTrue() && Res2.isTrue());
+ AlwaysFalse &= !(Res1.isTrue() && Res2.isTrue());
+ } else {
+ AlwaysTrue &= (Res1.isTrue() || Res2.isTrue());
+ AlwaysFalse &= !(Res1.isTrue() || Res2.isTrue());
+ }
+ }
+
+ if (AlwaysTrue || AlwaysFalse) {
+ if (BuildOpts.Observer)
+ BuildOpts.Observer->compareAlwaysTrue(B, AlwaysTrue);
+ return TryResult(AlwaysTrue);
+ }
+ return TryResult();
}
/// Try and evaluate an expression to an integer constant.
@@ -565,10 +814,22 @@ private:
// is determined by the RHS: X && 0 -> 0, X || 1 -> 1.
if (RHS.isTrue() == (Bop->getOpcode() == BO_LOr))
return RHS.isTrue();
+ } else {
+ TryResult BopRes = checkIncorrectLogicOperator(Bop);
+ if (BopRes.isKnown())
+ return BopRes.isTrue();
}
}
return TryResult();
+ } else if (Bop->isEqualityOp()) {
+ TryResult BopRes = checkIncorrectEqualityOperator(Bop);
+ if (BopRes.isKnown())
+ return BopRes.isTrue();
+ } else if (Bop->isRelationalOp()) {
+ TryResult BopRes = checkIncorrectRelationalOperator(Bop);
+ if (BopRes.isKnown())
+ return BopRes.isTrue();
}
}
@@ -607,13 +868,13 @@ bool CFGBuilder::alwaysAdd(const Stmt *stmt) {
if (!fb) {
// No need to update 'cachedEntry', since it will always be null.
- assert(cachedEntry == 0);
+ assert(!cachedEntry);
return shouldAdd;
}
CFG::BuildOptions::ForcedBlkExprs::iterator itr = fb->find(stmt);
if (itr == fb->end()) {
- cachedEntry = 0;
+ cachedEntry = nullptr;
return shouldAdd;
}
@@ -632,7 +893,7 @@ static const VariableArrayType *FindVA(const Type *t) {
t = vt->getElementType().getTypePtr();
}
- return 0;
+ return nullptr;
}
/// BuildCFG - Constructs a CFG from an AST (a Stmt*). The AST can represent an
@@ -643,14 +904,14 @@ static const VariableArrayType *FindVA(const Type *t) {
CFG* CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
assert(cfg.get());
if (!Statement)
- return NULL;
+ return nullptr;
// Create an empty block that will serve as the exit block for the CFG. Since
// this is the first block added to the CFG, it will be implicitly registered
// as the exit block.
Succ = createBlock();
assert(Succ == &cfg->getExit());
- Block = NULL; // the EXIT block is empty. Create all other blocks lazily.
+ Block = nullptr; // the EXIT block is empty. Create all other blocks lazily.
if (BuildOpts.AddImplicitDtors)
if (const CXXDestructorDecl *DD = dyn_cast_or_null<CXXDestructorDecl>(D))
@@ -660,7 +921,7 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
CFGBlock *B = addStmt(Statement);
if (badCFG)
- return NULL;
+ return nullptr;
// For C++ constructor add initializers to CFG.
if (const CXXConstructorDecl *CD = dyn_cast_or_null<CXXConstructorDecl>(D)) {
@@ -668,7 +929,7 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
E = CD->init_rend(); I != E; ++I) {
B = addInitializer(*I);
if (badCFG)
- return NULL;
+ return nullptr;
}
}
@@ -712,7 +973,7 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
// Create an empty entry block that has no predecessors.
cfg->setEntry(createBlock());
- return cfg.take();
+ return cfg.release();
}
/// createBlock - Used to lazily create blocks that are connected
@@ -730,7 +991,7 @@ CFGBlock *CFGBuilder::createBlock(bool add_successor) {
CFGBlock *CFGBuilder::createNoReturnBlock() {
CFGBlock *B = createBlock(false);
B->setHasNoReturnElement();
- addSuccessor(B, &cfg->getExit());
+ addSuccessor(B, &cfg->getExit(), Succ);
return B;
}
@@ -868,30 +1129,27 @@ void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) {
const CXXRecordDecl *RD = DD->getParent();
// At the end destroy virtual base objects.
- for (CXXRecordDecl::base_class_const_iterator VI = RD->vbases_begin(),
- VE = RD->vbases_end(); VI != VE; ++VI) {
- const CXXRecordDecl *CD = VI->getType()->getAsCXXRecordDecl();
+ for (const auto &VI : RD->vbases()) {
+ const CXXRecordDecl *CD = VI.getType()->getAsCXXRecordDecl();
if (!CD->hasTrivialDestructor()) {
autoCreateBlock();
- appendBaseDtor(Block, VI);
+ appendBaseDtor(Block, &VI);
}
}
// Before virtual bases destroy direct base objects.
- for (CXXRecordDecl::base_class_const_iterator BI = RD->bases_begin(),
- BE = RD->bases_end(); BI != BE; ++BI) {
- if (!BI->isVirtual()) {
- const CXXRecordDecl *CD = BI->getType()->getAsCXXRecordDecl();
+ for (const auto &BI : RD->bases()) {
+ if (!BI.isVirtual()) {
+ const CXXRecordDecl *CD = BI.getType()->getAsCXXRecordDecl();
if (!CD->hasTrivialDestructor()) {
autoCreateBlock();
- appendBaseDtor(Block, BI);
+ appendBaseDtor(Block, &BI);
}
}
}
// First destroy member objects.
- for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
- FE = RD->field_end(); FI != FE; ++FI) {
+ for (auto *FI : RD->fields()) {
// Check for constant size array. Set type to array element type.
QualType QT = FI->getType();
if (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) {
@@ -903,7 +1161,7 @@ void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) {
if (const CXXRecordDecl *CD = QT->getAsCXXRecordDecl())
if (!CD->hasTrivialDestructor()) {
autoCreateBlock();
- appendMemberDtor(Block, *FI);
+ appendMemberDtor(Block, FI);
}
}
}
@@ -926,13 +1184,12 @@ void CFGBuilder::addLocalScopeForStmt(Stmt *S) {
if (!BuildOpts.AddImplicitDtors)
return;
- LocalScope *Scope = 0;
+ LocalScope *Scope = nullptr;
// For compound statement we will be creating explicit scope.
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) {
- for (CompoundStmt::body_iterator BI = CS->body_begin(), BE = CS->body_end()
- ; BI != BE; ++BI) {
- Stmt *SI = (*BI)->stripLabelLikeStatements();
+ for (auto *BI : CS->body()) {
+ Stmt *SI = BI->stripLabelLikeStatements();
if (DeclStmt *DS = dyn_cast<DeclStmt>(SI))
Scope = addLocalScopeForDeclStmt(DS, Scope);
}
@@ -952,11 +1209,9 @@ LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS,
if (!BuildOpts.AddImplicitDtors)
return Scope;
- for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end()
- ; DI != DE; ++DI) {
- if (VarDecl *VD = dyn_cast<VarDecl>(*DI))
+ for (auto *DI : DS->decls())
+ if (VarDecl *VD = dyn_cast<VarDecl>(DI))
Scope = addLocalScopeForVarDecl(VD, Scope);
- }
return Scope;
}
@@ -1051,7 +1306,7 @@ void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk,
CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
if (!S) {
badCFG = true;
- return 0;
+ return nullptr;
}
if (Expr *E = dyn_cast<Expr>(S))
@@ -1122,6 +1377,9 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
case Stmt::CXXConstructExprClass:
return VisitCXXConstructExpr(cast<CXXConstructExpr>(S), asc);
+ case Stmt::CXXNewExprClass:
+ return VisitCXXNewExpr(cast<CXXNewExpr>(S), asc);
+
case Stmt::CXXDeleteExprClass:
return VisitCXXDeleteExpr(cast<CXXDeleteExpr>(S), asc);
@@ -1273,9 +1531,10 @@ CFGBlock *CFGBuilder::VisitLogicalOperator(BinaryOperator *B) {
appendStmt(ConfluenceBlock, B);
if (badCFG)
- return 0;
+ return nullptr;
- return VisitLogicalOperator(B, 0, ConfluenceBlock, ConfluenceBlock).first;
+ return VisitLogicalOperator(B, nullptr, ConfluenceBlock,
+ ConfluenceBlock).first;
}
std::pair<CFGBlock*, CFGBlock*>
@@ -1293,7 +1552,7 @@ CFGBuilder::VisitLogicalOperator(BinaryOperator *B,
do {
if (BinaryOperator *B_RHS = dyn_cast<BinaryOperator>(RHS))
if (B_RHS->isLogicalOp()) {
- llvm::tie(RHSBlock, ExitBlock) =
+ std::tie(RHSBlock, ExitBlock) =
VisitLogicalOperator(B_RHS, Term, TrueBlock, FalseBlock);
break;
}
@@ -1311,8 +1570,10 @@ CFGBuilder::VisitLogicalOperator(BinaryOperator *B,
else {
RHSBlock->setTerminator(Term);
TryResult KnownVal = tryEvaluateBool(RHS);
- addSuccessor(RHSBlock, KnownVal.isFalse() ? NULL : TrueBlock);
- addSuccessor(RHSBlock, KnownVal.isTrue() ? NULL : FalseBlock);
+ if (!KnownVal.isKnown())
+ KnownVal = tryEvaluateBool(B);
+ addSuccessor(RHSBlock, TrueBlock, !KnownVal.isFalse());
+ addSuccessor(RHSBlock, FalseBlock, !KnownVal.isTrue());
}
Block = RHSBlock;
@@ -1321,7 +1582,7 @@ CFGBuilder::VisitLogicalOperator(BinaryOperator *B,
while (false);
if (badCFG)
- return std::make_pair((CFGBlock*)0, (CFGBlock*)0);
+ return std::make_pair(nullptr, nullptr);
// Generate the blocks for evaluating the LHS.
Expr *LHS = B->getLHS()->IgnoreParens();
@@ -1348,19 +1609,19 @@ CFGBuilder::VisitLogicalOperator(BinaryOperator *B,
CFGBlock *EntryLHSBlock = addStmt(LHS);
if (badCFG)
- return std::make_pair((CFGBlock*)0, (CFGBlock*)0);
+ return std::make_pair(nullptr, nullptr);
// See if this is a known constant.
TryResult KnownVal = tryEvaluateBool(LHS);
// Now link the LHSBlock with RHSBlock.
if (B->getOpcode() == BO_LOr) {
- addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : TrueBlock);
- addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : RHSBlock);
+ addSuccessor(LHSBlock, TrueBlock, !KnownVal.isFalse());
+ addSuccessor(LHSBlock, RHSBlock, !KnownVal.isTrue());
} else {
assert(B->getOpcode() == BO_LAnd);
- addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock);
- addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : FalseBlock);
+ addSuccessor(LHSBlock, RHSBlock, !KnownVal.isFalse());
+ addSuccessor(LHSBlock, FalseBlock, !KnownVal.isTrue());
}
return std::make_pair(EntryLHSBlock, ExitBlock);
@@ -1414,7 +1675,7 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
// "break" is a control-flow statement. Thus we stop processing the current
// block.
if (badCFG)
- return 0;
+ return nullptr;
// Now create a new block that ends with the break statement.
Block = createBlock(false);
@@ -1502,7 +1763,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
if (Block) {
Succ = Block;
if (badCFG)
- return 0;
+ return nullptr;
}
if (NoReturn)
@@ -1528,26 +1789,26 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
CFGBlock *ConfluenceBlock = Block ? Block : createBlock();
appendStmt(ConfluenceBlock, C);
if (badCFG)
- return 0;
+ return nullptr;
AddStmtChoice alwaysAdd = asc.withAlwaysAdd(true);
Succ = ConfluenceBlock;
- Block = NULL;
+ Block = nullptr;
CFGBlock *LHSBlock = Visit(C->getLHS(), alwaysAdd);
if (badCFG)
- return 0;
+ return nullptr;
Succ = ConfluenceBlock;
- Block = NULL;
+ Block = nullptr;
CFGBlock *RHSBlock = Visit(C->getRHS(), alwaysAdd);
if (badCFG)
- return 0;
+ return nullptr;
Block = createBlock(false);
// See if this is a known constant.
const TryResult& KnownVal = tryEvaluateBool(C->getCond());
- addSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock);
- addSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock);
+ addSuccessor(Block, KnownVal.isFalse() ? nullptr : LHSBlock);
+ addSuccessor(Block, KnownVal.isTrue() ? nullptr : RHSBlock);
Block->setTerminator(C);
return addStmt(C->getCond());
}
@@ -1565,7 +1826,7 @@ CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) {
LastBlock = newBlock;
if (badCFG)
- return NULL;
+ return nullptr;
}
return LastBlock;
@@ -1574,14 +1835,14 @@ CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) {
CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C,
AddStmtChoice asc) {
const BinaryConditionalOperator *BCO = dyn_cast<BinaryConditionalOperator>(C);
- const OpaqueValueExpr *opaqueValue = (BCO ? BCO->getOpaqueValue() : NULL);
+ const OpaqueValueExpr *opaqueValue = (BCO ? BCO->getOpaqueValue() : nullptr);
// Create the confluence block that will "merge" the results of the ternary
// expression.
CFGBlock *ConfluenceBlock = Block ? Block : createBlock();
appendStmt(ConfluenceBlock, C);
if (badCFG)
- return 0;
+ return nullptr;
AddStmtChoice alwaysAdd = asc.withAlwaysAdd(true);
@@ -1590,14 +1851,14 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C,
// value that is returned instead.
// e.g: x ?: y is shorthand for: x ? x : y;
Succ = ConfluenceBlock;
- Block = NULL;
- CFGBlock *LHSBlock = 0;
+ Block = nullptr;
+ CFGBlock *LHSBlock = nullptr;
const Expr *trueExpr = C->getTrueExpr();
if (trueExpr != opaqueValue) {
LHSBlock = Visit(C->getTrueExpr(), alwaysAdd);
if (badCFG)
- return 0;
- Block = NULL;
+ return nullptr;
+ Block = nullptr;
}
else
LHSBlock = ConfluenceBlock;
@@ -1606,7 +1867,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C,
Succ = ConfluenceBlock;
CFGBlock *RHSBlock = Visit(C->getFalseExpr(), alwaysAdd);
if (badCFG)
- return 0;
+ return nullptr;
// If the condition is a logical '&&' or '||', build a more accurate CFG.
if (BinaryOperator *Cond =
@@ -1619,8 +1880,8 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C,
// See if this is a known constant.
const TryResult& KnownVal = tryEvaluateBool(C->getCond());
- addSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock);
- addSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock);
+ addSuccessor(Block, LHSBlock, !KnownVal.isFalse());
+ addSuccessor(Block, RHSBlock, !KnownVal.isTrue());
Block->setTerminator(C);
Expr *condExpr = C->getCond();
@@ -1648,7 +1909,7 @@ CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
if (DS->isSingleDecl())
return VisitDeclSubExpr(DS);
- CFGBlock *B = 0;
+ CFGBlock *B = nullptr;
// Build an individual DeclStmt for each decl.
for (DeclStmt::reverse_decl_iterator I = DS->decl_rbegin(),
@@ -1689,16 +1950,16 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
bool HasTemporaries = false;
// Guard static initializers under a branch.
- CFGBlock *blockAfterStaticInit = 0;
+ CFGBlock *blockAfterStaticInit = nullptr;
if (BuildOpts.AddStaticInitBranches && VD->isStaticLocal()) {
// For static variables, we need to create a branch to track
// whether or not they are initialized.
if (Block) {
Succ = Block;
- Block = 0;
+ Block = nullptr;
if (badCFG)
- return 0;
+ return nullptr;
}
blockAfterStaticInit = Succ;
}
@@ -1741,7 +2002,7 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
// If the type of VD is a VLA, then we must process its size expressions.
for (const VariableArrayType* VA = FindVA(VD->getType().getTypePtr());
- VA != 0; VA = FindVA(VA->getElementType().getTypePtr())) {
+ VA != nullptr; VA = FindVA(VA->getElementType().getTypePtr())) {
if (CFGBlock *newBlock = addStmt(VA->getSizeExpr()))
LastBlock = newBlock;
}
@@ -1788,7 +2049,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
if (Block) {
Succ = Block;
if (badCFG)
- return 0;
+ return nullptr;
}
// Process the false branch.
@@ -1799,7 +2060,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
// NULL out Block so that the recursive call to Visit will
// create a new basic block.
- Block = NULL;
+ Block = nullptr;
// If branch is not a compound statement create implicit scope
// and add destructors.
@@ -1812,7 +2073,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
ElseBlock = sv.get();
else if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
}
}
@@ -1822,7 +2083,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
Stmt *Then = I->getThen();
assert(Then);
SaveAndRestore<CFGBlock*> sv(Succ);
- Block = NULL;
+ Block = nullptr;
// If branch is not a compound statement create implicit scope
// and add destructors.
@@ -1839,7 +2100,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
addSuccessor(ThenBlock, sv.get());
} else if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
}
}
@@ -1865,23 +2126,21 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
// See if this is a known constant.
const TryResult &KnownVal = tryEvaluateBool(I->getCond());
- // Now add the successors.
- addSuccessor(Block, KnownVal.isFalse() ? NULL : ThenBlock);
- addSuccessor(Block, KnownVal.isTrue()? NULL : ElseBlock);
+ // Add the successors. If we know that specific branches are
+ // unreachable, inform addSuccessor() of that knowledge.
+ addSuccessor(Block, ThenBlock, /* isReachable = */ !KnownVal.isFalse());
+ addSuccessor(Block, ElseBlock, /* isReachable = */ !KnownVal.isTrue());
// Add the condition as the last statement in the new block. This may create
// new blocks as the condition may contain control-flow. Any newly created
// blocks will be pointed to be "Block".
CFGBlock *LastBlock = addStmt(I->getCond());
- // Finally, if the IfStmt contains a condition variable, add both the IfStmt
- // and the condition variable initialization to the CFG.
- if (VarDecl *VD = I->getConditionVariable()) {
- if (Expr *Init = VD->getInit()) {
- autoCreateBlock();
- appendStmt(Block, I->getConditionVariableDeclStmt());
- LastBlock = addStmt(Init);
- }
+ // Finally, if the IfStmt contains a condition variable, add it and its
+ // initializer to the CFG.
+ if (const DeclStmt* DS = I->getConditionVariableDeclStmt()) {
+ autoCreateBlock();
+ LastBlock = addStmt(const_cast<DeclStmt *>(DS));
}
return LastBlock;
@@ -1929,10 +2188,10 @@ CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) {
// about.
LabelBlock->setLabel(L);
if (badCFG)
- return 0;
+ return nullptr;
// We set Block to NULL to allow lazy creation of a new block (if necessary);
- Block = NULL;
+ Block = nullptr;
// This block is now the implicit successor of other blocks.
Succ = LabelBlock;
@@ -1946,7 +2205,7 @@ CFGBlock *CFGBuilder::VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc) {
et = E->capture_init_end(); it != et; ++it) {
if (Expr *Init = *it) {
CFGBlock *Tmp = Visit(Init);
- if (Tmp != 0)
+ if (Tmp)
LastBlock = Tmp;
}
}
@@ -1976,7 +2235,7 @@ CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) {
}
CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
- CFGBlock *LoopSuccessor = NULL;
+ CFGBlock *LoopSuccessor = nullptr;
// Save local scope position because in case of condition variable ScopePos
// won't be restored when traversing AST.
@@ -1999,7 +2258,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
// block.
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
LoopSuccessor = Block;
} else
LoopSuccessor = Succ;
@@ -2009,7 +2268,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
SaveAndRestore<JumpTarget> save_break(BreakJumpTarget);
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
- CFGBlock *BodyBlock = 0, *TransitionBlock = 0;
+ CFGBlock *BodyBlock = nullptr, *TransitionBlock = nullptr;
// Now create the loop body.
{
@@ -2035,8 +2294,8 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
if (Block) {
assert(Block == Succ);
if (badCFG)
- return 0;
- Block = 0;
+ return nullptr;
+ Block = nullptr;
}
// The starting block for the loop increment is the block that should
@@ -2062,13 +2321,13 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
BodyBlock = ContinueJumpTarget.block;
}
else if (badCFG)
- return 0;
+ return nullptr;
}
// Because of short-circuit evaluation, the condition of the loop can span
// multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that
// evaluate the condition.
- CFGBlock *EntryConditionBlock = 0, *ExitConditionBlock = 0;
+ CFGBlock *EntryConditionBlock = nullptr, *ExitConditionBlock = nullptr;
do {
Expr *C = F->getCond();
@@ -2076,9 +2335,9 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
// Specially handle logical operators, which have a slightly
// more optimal CFG representation.
if (BinaryOperator *Cond =
- dyn_cast_or_null<BinaryOperator>(C ? C->IgnoreParens() : 0))
+ dyn_cast_or_null<BinaryOperator>(C ? C->IgnoreParens() : nullptr))
if (Cond->isLogicalOp()) {
- llvm::tie(EntryConditionBlock, ExitConditionBlock) =
+ std::tie(EntryConditionBlock, ExitConditionBlock) =
VisitLogicalOperator(Cond, F, BodyBlock, LoopSuccessor);
break;
}
@@ -2109,16 +2368,17 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
}
if (Block && badCFG)
- return 0;
+ return nullptr;
KnownVal = tryEvaluateBool(C);
}
// Add the loop body entry as a successor to the condition.
- addSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : BodyBlock);
+ addSuccessor(ExitConditionBlock, KnownVal.isFalse() ? nullptr : BodyBlock);
// Link up the condition block with the code that follows the loop. (the
// false branch).
- addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor);
+ addSuccessor(ExitConditionBlock,
+ KnownVal.isTrue() ? nullptr : LoopSuccessor);
} while (false);
@@ -2137,7 +2397,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
// There is no loop initialization. We are thus basically a while loop.
// NULL out Block to force lazy block construction.
- Block = NULL;
+ Block = nullptr;
Succ = EntryConditionBlock;
return EntryConditionBlock;
}
@@ -2183,13 +2443,13 @@ CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
// a DeclStmt and the other returns a DeclRefExpr.
//
- CFGBlock *LoopSuccessor = 0;
+ CFGBlock *LoopSuccessor = nullptr;
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
LoopSuccessor = Block;
- Block = 0;
+ Block = nullptr;
} else
LoopSuccessor = Succ;
@@ -2212,8 +2472,8 @@ CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
AddStmtChoice::NotAlwaysAdd);
if (Block) {
if (badCFG)
- return 0;
- Block = 0;
+ return nullptr;
+ Block = nullptr;
}
// The condition block is the implicit successor for the loop body as well as
@@ -2230,7 +2490,7 @@ CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
// Add an intermediate block between the BodyBlock and the
// EntryConditionBlock to represent the "loop back" transition, for looping
// back to the head of the loop.
- CFGBlock *LoopBackBlock = 0;
+ CFGBlock *LoopBackBlock = nullptr;
Succ = LoopBackBlock = createBlock();
LoopBackBlock->setLoopTarget(S);
@@ -2243,7 +2503,7 @@ CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
BodyBlock = ContinueJumpTarget.block; // can happen for "for (X in Y) ;"
else if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
}
// This new body block is a successor to our "exit" condition block.
@@ -2275,9 +2535,9 @@ CFGBlock *CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
// for diagnostic clients.
if (SyncBlock) {
if (badCFG)
- return 0;
+ return nullptr;
- Block = 0;
+ Block = nullptr;
Succ = SyncBlock;
}
@@ -2320,7 +2580,7 @@ CFGBlock *CFGBuilder::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
}
CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
- CFGBlock *LoopSuccessor = NULL;
+ CFGBlock *LoopSuccessor = nullptr;
// Save local scope position because in case of condition variable ScopePos
// won't be restored when traversing AST.
@@ -2338,14 +2598,14 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
// block.
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
LoopSuccessor = Block;
- Block = 0;
+ Block = nullptr;
} else {
LoopSuccessor = Succ;
}
- CFGBlock *BodyBlock = 0, *TransitionBlock = 0;
+ CFGBlock *BodyBlock = nullptr, *TransitionBlock = nullptr;
// Process the loop body.
{
@@ -2379,13 +2639,13 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
if (!BodyBlock)
BodyBlock = ContinueJumpTarget.block; // can happen for "while(...) ;"
else if (Block && badCFG)
- return 0;
+ return nullptr;
}
// Because of short-circuit evaluation, the condition of the loop can span
// multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that
// evaluate the condition.
- CFGBlock *EntryConditionBlock = 0, *ExitConditionBlock = 0;
+ CFGBlock *EntryConditionBlock = nullptr, *ExitConditionBlock = nullptr;
do {
Expr *C = W->getCond();
@@ -2394,9 +2654,8 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
// more optimal CFG representation.
if (BinaryOperator *Cond = dyn_cast<BinaryOperator>(C->IgnoreParens()))
if (Cond->isLogicalOp()) {
- llvm::tie(EntryConditionBlock, ExitConditionBlock) =
- VisitLogicalOperator(Cond, W, BodyBlock,
- LoopSuccessor);
+ std::tie(EntryConditionBlock, ExitConditionBlock) =
+ VisitLogicalOperator(Cond, W, BodyBlock, LoopSuccessor);
break;
}
@@ -2422,16 +2681,17 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
}
if (Block && badCFG)
- return 0;
+ return nullptr;
// See if this is a known constant.
const TryResult& KnownVal = tryEvaluateBool(C);
// Add the loop body entry as a successor to the condition.
- addSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : BodyBlock);
+ addSuccessor(ExitConditionBlock, KnownVal.isFalse() ? nullptr : BodyBlock);
// Link up the condition block with the code that follows the loop. (the
// false branch).
- addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor);
+ addSuccessor(ExitConditionBlock,
+ KnownVal.isTrue() ? nullptr : LoopSuccessor);
} while(false);
@@ -2440,7 +2700,7 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
// There can be no more statements in the condition block since we loop back
// to this block. NULL out Block to force lazy creation of another block.
- Block = NULL;
+ Block = nullptr;
// Return the condition block, which is the dominating block for the loop.
Succ = EntryConditionBlock;
@@ -2460,7 +2720,7 @@ CFGBlock *CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
// If we were in the middle of a block we stop processing that block.
if (badCFG)
- return 0;
+ return nullptr;
// Create the new block.
Block = createBlock(false);
@@ -2476,7 +2736,7 @@ CFGBlock *CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *T) {
// If we were in the middle of a block we stop processing that block.
if (badCFG)
- return 0;
+ return nullptr;
// Create the new block.
Block = createBlock(false);
@@ -2494,13 +2754,13 @@ CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *T) {
}
CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
- CFGBlock *LoopSuccessor = NULL;
+ CFGBlock *LoopSuccessor = nullptr;
// "do...while" is a control-flow statement. Thus we stop processing the
// current block.
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
LoopSuccessor = Block;
} else
LoopSuccessor = Succ;
@@ -2521,7 +2781,7 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
EntryConditionBlock = addStmt(C);
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
}
}
@@ -2532,7 +2792,7 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
const TryResult &KnownVal = tryEvaluateBool(D->getCond());
// Process the loop body.
- CFGBlock *BodyBlock = NULL;
+ CFGBlock *BodyBlock = nullptr;
{
assert(D->getBody());
@@ -2548,7 +2808,7 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
// NULL out Block to force lazy instantiation of blocks for the body.
- Block = NULL;
+ Block = nullptr;
// If body is not a compound statement create implicit scope
// and add destructors.
@@ -2562,7 +2822,7 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
BodyBlock = EntryConditionBlock; // can happen for "do ; while(...)"
else if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
}
if (!KnownVal.isFalse()) {
@@ -2571,7 +2831,7 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
// empty block to represent the transition block for looping back to the
// head of the loop.
// FIXME: Can we do this more efficiently without adding another block?
- Block = NULL;
+ Block = nullptr;
Succ = BodyBlock;
CFGBlock *LoopBackBlock = createBlock();
LoopBackBlock->setLoopTarget(D);
@@ -2580,16 +2840,16 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
addSuccessor(ExitConditionBlock, LoopBackBlock);
}
else
- addSuccessor(ExitConditionBlock, NULL);
+ addSuccessor(ExitConditionBlock, nullptr);
}
// Link up the condition block with the code that follows the loop.
// (the false branch).
- addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor);
+ addSuccessor(ExitConditionBlock, KnownVal.isTrue() ? nullptr : LoopSuccessor);
// There can be no more statements in the body block(s) since we loop back to
// the body. NULL out Block to force lazy creation of another block.
- Block = NULL;
+ Block = nullptr;
// Return the loop body, which is the dominating block for the loop.
Succ = BodyBlock;
@@ -2600,7 +2860,7 @@ CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *C) {
// "continue" is a control-flow statement. Thus we stop processing the
// current block.
if (badCFG)
- return 0;
+ return nullptr;
// Now create a new block that ends with the continue statement.
Block = createBlock(false);
@@ -2630,7 +2890,7 @@ CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
if (E->isArgumentType()) {
for (const VariableArrayType *VA =FindVA(E->getArgumentType().getTypePtr());
- VA != 0; VA = FindVA(VA->getElementType().getTypePtr()))
+ VA != nullptr; VA = FindVA(VA->getElementType().getTypePtr()))
lastBlock = addStmt(VA->getSizeExpr());
}
return lastBlock;
@@ -2649,7 +2909,7 @@ CFGBlock *CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) {
CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
// "switch" is a control-flow statement. Thus we stop processing the current
// block.
- CFGBlock *SwitchSuccessor = NULL;
+ CFGBlock *SwitchSuccessor = nullptr;
// Save local scope position because in case of condition variable ScopePos
// won't be restored when traversing AST.
@@ -2665,7 +2925,7 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
SwitchSuccessor = Block;
} else SwitchSuccessor = Succ;
@@ -2691,7 +2951,7 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
// up to the switch. We also don't keep a pointer to the body, since all
// control-flow from the switch goes to case/default statements.
assert(Terminator->getBody() && "switch must contain a non-NULL body");
- Block = NULL;
+ Block = nullptr;
// For pruning unreachable case statements, save the current state
// for tracking the condition value.
@@ -2703,7 +2963,7 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
Expr::EvalResult result;
bool b = tryEvaluate(Terminator->getCond(), result);
SaveAndRestore<Expr::EvalResult*> save_switchCond(switchCond,
- b ? &result : 0);
+ b ? &result : nullptr);
// If body is not a compound statement create implicit scope
// and add destructors.
@@ -2713,7 +2973,7 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
addStmt(Terminator->getBody());
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
}
// If we have no "default:" case, the default transition is to the code
@@ -2726,8 +2986,8 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
SwitchAlwaysHasSuccessor |= switchExclusivelyCovered;
SwitchAlwaysHasSuccessor |= Terminator->isAllEnumCasesCovered() &&
Terminator->getSwitchCaseList();
- addSuccessor(SwitchTerminatedBlock,
- SwitchAlwaysHasSuccessor ? 0 : DefaultCaseBlock);
+ addSuccessor(SwitchTerminatedBlock, DefaultCaseBlock,
+ !SwitchAlwaysHasSuccessor);
// Add the terminator and condition in the switch block.
SwitchTerminatedBlock->setTerminator(Terminator);
@@ -2786,7 +3046,7 @@ static bool shouldAddCase(bool &switchExclusivelyCovered,
CFGBlock *CFGBuilder::VisitCaseStmt(CaseStmt *CS) {
// CaseStmts are essentially labels, so they are the first statement in a
// block.
- CFGBlock *TopBlock = 0, *LastBlock = 0;
+ CFGBlock *TopBlock = nullptr, *LastBlock = nullptr;
if (Stmt *Sub = CS->getSubStmt()) {
// For deeply nested chains of CaseStmts, instead of doing a recursion
@@ -2804,7 +3064,7 @@ CFGBlock *CFGBuilder::VisitCaseStmt(CaseStmt *CS) {
addSuccessor(SwitchTerminatedBlock,
shouldAddCase(switchExclusivelyCovered, switchCond,
CS, *Context)
- ? currentBlock : 0);
+ ? currentBlock : nullptr);
LastBlock = currentBlock;
CS = cast<CaseStmt>(Sub);
@@ -2823,18 +3083,17 @@ CFGBlock *CFGBuilder::VisitCaseStmt(CaseStmt *CS) {
CaseBlock->setLabel(CS);
if (badCFG)
- return 0;
+ return nullptr;
// Add this block to the list of successors for the block with the switch
// statement.
assert(SwitchTerminatedBlock);
- addSuccessor(SwitchTerminatedBlock,
+ addSuccessor(SwitchTerminatedBlock, CaseBlock,
shouldAddCase(switchExclusivelyCovered, switchCond,
- CS, *Context)
- ? CaseBlock : 0);
+ CS, *Context));
// We set Block to NULL to allow lazy creation of a new block (if necessary)
- Block = NULL;
+ Block = nullptr;
if (TopBlock) {
addSuccessor(LastBlock, CaseBlock);
@@ -2861,7 +3120,7 @@ CFGBlock *CFGBuilder::VisitDefaultStmt(DefaultStmt *Terminator) {
DefaultCaseBlock->setLabel(Terminator);
if (badCFG)
- return 0;
+ return nullptr;
// Unlike case statements, we don't add the default block to the successors
// for the switch statement immediately. This is done when we finish
@@ -2870,7 +3129,7 @@ CFGBlock *CFGBuilder::VisitDefaultStmt(DefaultStmt *Terminator) {
// be the last successor of a switch-terminated block.
// We set Block to NULL to allow lazy creation of a new block (if necessary)
- Block = NULL;
+ Block = nullptr;
// This block is now the implicit successor of other blocks.
Succ = DefaultCaseBlock;
@@ -2881,11 +3140,11 @@ CFGBlock *CFGBuilder::VisitDefaultStmt(DefaultStmt *Terminator) {
CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
// "try"/"catch" is a control-flow statement. Thus we stop processing the
// current block.
- CFGBlock *TrySuccessor = NULL;
+ CFGBlock *TrySuccessor = nullptr;
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
TrySuccessor = Block;
} else TrySuccessor = Succ;
@@ -2901,13 +3160,13 @@ CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
// The code after the try is the implicit successor.
Succ = TrySuccessor;
CXXCatchStmt *CS = Terminator->getHandler(h);
- if (CS->getExceptionDecl() == 0) {
+ if (CS->getExceptionDecl() == nullptr) {
HasCatchAll = true;
}
- Block = NULL;
+ Block = nullptr;
CFGBlock *CatchBlock = VisitCXXCatchStmt(CS);
- if (CatchBlock == 0)
- return 0;
+ if (!CatchBlock)
+ return nullptr;
// Add this block to the list of successors for the block with the try
// statement.
addSuccessor(NewTryTerminatedBlock, CatchBlock);
@@ -2927,7 +3186,7 @@ CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
cfg->addTryDispatchBlock(TryTerminatedBlock);
assert(Terminator->getTryBlock() && "try must contain a non-NULL body");
- Block = NULL;
+ Block = nullptr;
return addStmt(Terminator->getTryBlock());
}
@@ -2966,10 +3225,10 @@ CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) {
// Bail out if the CFG is bad.
if (badCFG)
- return 0;
+ return nullptr;
// We set Block to NULL to allow lazy creation of a new block (if necessary)
- Block = NULL;
+ Block = nullptr;
return CatchBlock;
}
@@ -3002,10 +3261,10 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
// "for" is a control-flow statement. Thus we stop processing the current
// block.
- CFGBlock *LoopSuccessor = NULL;
+ CFGBlock *LoopSuccessor = nullptr;
if (Block) {
if (badCFG)
- return 0;
+ return nullptr;
LoopSuccessor = Block;
} else
LoopSuccessor = Succ;
@@ -3024,7 +3283,7 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
Block = ConditionBlock;
CFGBlock *BeginConditionBlock = addStmt(C);
if (badCFG)
- return 0;
+ return nullptr;
assert(BeginConditionBlock == ConditionBlock &&
"condition block in for-range was unexpectedly complex");
(void)BeginConditionBlock;
@@ -3050,7 +3309,7 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
// Generate increment code in its own basic block. This is the target of
// continue statements.
- Block = 0;
+ Block = nullptr;
Succ = addStmt(S->getInc());
ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos);
@@ -3061,9 +3320,8 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
// Finish up the increment block and prepare to start the loop body.
assert(Block);
if (badCFG)
- return 0;
- Block = 0;
-
+ return nullptr;
+ Block = nullptr;
// Add implicit scope and dtors for loop variable.
addLocalScopeAndDtors(S->getLoopVarStmt());
@@ -3071,18 +3329,19 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
// Populate a new block to contain the loop body and loop variable.
addStmt(S->getBody());
if (badCFG)
- return 0;
+ return nullptr;
CFGBlock *LoopVarStmtBlock = addStmt(S->getLoopVarStmt());
if (badCFG)
- return 0;
-
+ return nullptr;
+
// This new body block is a successor to our condition block.
- addSuccessor(ConditionBlock, KnownVal.isFalse() ? 0 : LoopVarStmtBlock);
+ addSuccessor(ConditionBlock,
+ KnownVal.isFalse() ? nullptr : LoopVarStmtBlock);
}
// Link up the condition block with the code that follows the loop (the
// false branch).
- addSuccessor(ConditionBlock, KnownVal.isTrue() ? 0 : LoopSuccessor);
+ addSuccessor(ConditionBlock, KnownVal.isTrue() ? nullptr : LoopSuccessor);
// Add the initialization statements.
Block = createBlock();
@@ -3124,6 +3383,23 @@ CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *C,
return VisitChildren(C);
}
+CFGBlock *CFGBuilder::VisitCXXNewExpr(CXXNewExpr *NE,
+ AddStmtChoice asc) {
+
+ autoCreateBlock();
+ appendStmt(Block, NE);
+
+ if (NE->getInitializer())
+ Block = Visit(NE->getInitializer());
+ if (BuildOpts.AddCXXNewAllocator)
+ appendNewAllocator(Block, NE);
+ if (NE->isArray())
+ Block = Visit(NE->getArraySize());
+ for (CXXNewExpr::arg_iterator I = NE->placement_arg_begin(),
+ E = NE->placement_arg_end(); I != E; ++I)
+ Block = Visit(*I);
+ return Block;
+}
CFGBlock *CFGBuilder::VisitCXXDeleteExpr(CXXDeleteExpr *DE,
AddStmtChoice asc) {
@@ -3179,7 +3455,7 @@ CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) {
// IndirectGoto is a control-flow statement. Thus we stop processing the
// current block and create a new one.
if (badCFG)
- return 0;
+ return nullptr;
Block = createBlock(false);
Block->setTerminator(I);
@@ -3193,7 +3469,7 @@ CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E, bool BindToTemporary) {
tryAgain:
if (!E) {
badCFG = true;
- return NULL;
+ return nullptr;
}
switch (E->getStmtClass()) {
default:
@@ -3219,10 +3495,35 @@ tryAgain:
case Stmt::ParenExprClass:
E = cast<ParenExpr>(E)->getSubExpr();
goto tryAgain;
-
+
case Stmt::MaterializeTemporaryExprClass:
E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr();
goto tryAgain;
+
+ case Stmt::BlockExprClass:
+ // Don't recurse into blocks; their subexpressions don't get evaluated
+ // here.
+ return Block;
+
+ case Stmt::LambdaExprClass: {
+ // For lambda expressions, only recurse into the capture initializers,
+ // and not the body.
+ auto *LE = cast<LambdaExpr>(E);
+ CFGBlock *B = Block;
+ for (Expr *Init : LE->capture_inits()) {
+ if (CFGBlock *R = VisitForTemporaryDtors(Init))
+ B = R;
+ }
+ return B;
+ }
+
+ case Stmt::CXXDefaultArgExprClass:
+ E = cast<CXXDefaultArgExpr>(E)->getExpr();
+ goto tryAgain;
+
+ case Stmt::CXXDefaultInitExprClass:
+ E = cast<CXXDefaultInitExpr>(E)->getExpr();
+ goto tryAgain;
}
}
@@ -3248,15 +3549,15 @@ CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(BinaryOperator *E) {
autoCreateBlock();
CFGBlock *ConfluenceBlock = VisitForTemporaryDtors(E->getLHS());
if (badCFG)
- return NULL;
+ return nullptr;
Succ = ConfluenceBlock;
- Block = NULL;
+ Block = nullptr;
CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS());
if (RHSBlock) {
if (badCFG)
- return NULL;
+ return nullptr;
// If RHS expression did produce destructors we need to connect created
// blocks to CFG in same manner as for binary operator itself.
@@ -3276,12 +3577,12 @@ CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(BinaryOperator *E) {
// Link LHSBlock with RHSBlock exactly the same way as for binary operator
// itself.
if (E->getOpcode() == BO_LOr) {
- addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock);
- addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock);
+ addSuccessor(LHSBlock, KnownVal.isTrue() ? nullptr : ConfluenceBlock);
+ addSuccessor(LHSBlock, KnownVal.isFalse() ? nullptr : RHSBlock);
} else {
assert (E->getOpcode() == BO_LAnd);
- addSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock);
- addSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock);
+ addSuccessor(LHSBlock, KnownVal.isFalse() ? nullptr : RHSBlock);
+ addSuccessor(LHSBlock, KnownVal.isTrue() ? nullptr : ConfluenceBlock);
}
Block = LHSBlock;
@@ -3320,10 +3621,12 @@ CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(
// a new block for the destructor which does not have as a successor
// anything built thus far. Control won't flow out of this block.
const CXXDestructorDecl *Dtor = E->getTemporary()->getDestructor();
- if (Dtor->isNoReturn())
+ if (Dtor->isNoReturn()) {
+ Succ = B;
Block = createNoReturnBlock();
- else
+ } else {
autoCreateBlock();
+ }
appendTemporaryDtor(Block, E);
B = Block;
@@ -3339,29 +3642,29 @@ CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
autoCreateBlock();
CFGBlock *ConfluenceBlock = VisitForTemporaryDtors(E->getCond());
if (badCFG)
- return NULL;
+ return nullptr;
if (BinaryConditionalOperator *BCO
= dyn_cast<BinaryConditionalOperator>(E)) {
ConfluenceBlock = VisitForTemporaryDtors(BCO->getCommon());
if (badCFG)
- return NULL;
+ return nullptr;
}
// Try to add block with destructors for LHS expression.
- CFGBlock *LHSBlock = NULL;
+ CFGBlock *LHSBlock = nullptr;
Succ = ConfluenceBlock;
- Block = NULL;
+ Block = nullptr;
LHSBlock = VisitForTemporaryDtors(E->getTrueExpr(), BindToTemporary);
if (badCFG)
- return NULL;
+ return nullptr;
// Try to add block with destructors for RHS expression;
Succ = ConfluenceBlock;
- Block = NULL;
+ Block = nullptr;
CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getFalseExpr(),
BindToTemporary);
if (badCFG)
- return NULL;
+ return nullptr;
if (!RHSBlock && !LHSBlock) {
// If neither LHS nor RHS expression had temporaries to destroy don't create
@@ -3372,14 +3675,15 @@ CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
Block = createBlock(false);
Block->setTerminator(CFGTerminator(E, true));
+ assert(Block->getTerminator().isTemporaryDtorsBranch());
// See if this is a known constant.
const TryResult &KnownVal = tryEvaluateBool(E->getCond());
if (LHSBlock) {
- addSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock);
+ addSuccessor(Block, LHSBlock, !KnownVal.isFalse());
} else if (KnownVal.isFalse()) {
- addSuccessor(Block, NULL);
+ addSuccessor(Block, nullptr);
} else {
addSuccessor(Block, ConfluenceBlock);
std::reverse(ConfluenceBlock->pred_begin(), ConfluenceBlock->pred_end());
@@ -3387,7 +3691,8 @@ CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
if (!RHSBlock)
RHSBlock = ConfluenceBlock;
- addSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock);
+
+ addSuccessor(Block, RHSBlock, !KnownVal.isTrue());
return Block;
}
@@ -3426,6 +3731,7 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
switch (getKind()) {
case CFGElement::Statement:
case CFGElement::Initializer:
+ case CFGElement::NewAllocator:
llvm_unreachable("getDestructorDecl should only be used with "
"ImplicitDtors");
case CFGElement::AutomaticObjectDtor: {
@@ -3458,7 +3764,7 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
case CFGElement::MemberDtor:
// Not yet supported.
- return 0;
+ return nullptr;
}
llvm_unreachable("getKind() returned bogus value");
}
@@ -3470,13 +3776,37 @@ bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const {
}
//===----------------------------------------------------------------------===//
-// Filtered walking of the CFG.
+// CFGBlock operations.
//===----------------------------------------------------------------------===//
+CFGBlock::AdjacentBlock::AdjacentBlock(CFGBlock *B, bool IsReachable)
+ : ReachableBlock(IsReachable ? B : nullptr),
+ UnreachableBlock(!IsReachable ? B : nullptr,
+ B && IsReachable ? AB_Normal : AB_Unreachable) {}
+
+CFGBlock::AdjacentBlock::AdjacentBlock(CFGBlock *B, CFGBlock *AlternateBlock)
+ : ReachableBlock(B),
+ UnreachableBlock(B == AlternateBlock ? nullptr : AlternateBlock,
+ B == AlternateBlock ? AB_Alternate : AB_Normal) {}
+
+void CFGBlock::addSuccessor(AdjacentBlock Succ,
+ BumpVectorContext &C) {
+ if (CFGBlock *B = Succ.getReachableBlock())
+ B->Preds.push_back(AdjacentBlock(this, Succ.isReachable()), C);
+
+ if (CFGBlock *UnreachableB = Succ.getPossiblyUnreachableBlock())
+ UnreachableB->Preds.push_back(AdjacentBlock(this, false), C);
+
+ Succs.push_back(Succ, C);
+}
+
bool CFGBlock::FilterEdge(const CFGBlock::FilterOptions &F,
const CFGBlock *From, const CFGBlock *To) {
- if (To && F.IgnoreDefaultsWithCoveredEnums) {
+ if (F.IgnoreNullPredecessors && !From)
+ return true;
+
+ if (To && From && F.IgnoreDefaultsWithCoveredEnums) {
// If the 'To' has no label or is labeled but the label isn't a
// CaseStmt then filter this edge.
if (const SwitchStmt *S =
@@ -3572,7 +3902,7 @@ public:
void setBlockID(signed i) { currentBlock = i; }
void setStmtID(unsigned i) { currStmt = i; }
- virtual bool handledStmt(Stmt *S, raw_ostream &OS) {
+ bool handledStmt(Stmt *S, raw_ostream &OS) override {
StmtMapTy::iterator I = StmtMap.find(S);
if (I == StmtMap.end())
@@ -3615,11 +3945,14 @@ class CFGBlockTerminatorPrint
public:
CFGBlockTerminatorPrint(raw_ostream &os, StmtPrinterHelper* helper,
const PrintingPolicy &Policy)
- : OS(os), Helper(helper), Policy(Policy) {}
+ : OS(os), Helper(helper), Policy(Policy) {
+ this->Policy.IncludeNewlines = false;
+ }
void VisitIfStmt(IfStmt *I) {
OS << "if ";
- I->getCond()->printPretty(OS,Helper,Policy);
+ if (Stmt *C = I->getCond())
+ C->printPretty(OS, Helper, Policy);
}
// Default case.
@@ -3667,19 +4000,22 @@ public:
}
void VisitAbstractConditionalOperator(AbstractConditionalOperator* C) {
- C->getCond()->printPretty(OS, Helper, Policy);
+ if (Stmt *Cond = C->getCond())
+ Cond->printPretty(OS, Helper, Policy);
OS << " ? ... : ...";
}
void VisitChooseExpr(ChooseExpr *C) {
OS << "__builtin_choose_expr( ";
- C->getCond()->printPretty(OS, Helper, Policy);
+ if (Stmt *Cond = C->getCond())
+ Cond->printPretty(OS, Helper, Policy);
OS << " )";
}
void VisitIndirectGotoStmt(IndirectGotoStmt *I) {
OS << "goto *";
- I->getTarget()->printPretty(OS, Helper, Policy);
+ if (Stmt *T = I->getTarget())
+ T->printPretty(OS, Helper, Policy);
}
void VisitBinaryOperator(BinaryOperator* B) {
@@ -3688,7 +4024,8 @@ public:
return;
}
- B->getLHS()->printPretty(OS, Helper, Policy);
+ if (B->getLHS())
+ B->getLHS()->printPretty(OS, Helper, Policy);
switch (B->getOpcode()) {
case BO_LOr:
@@ -3705,6 +4042,13 @@ public:
void VisitExpr(Expr *E) {
E->printPretty(OS, Helper, Policy);
}
+
+public:
+ void print(CFGTerminator T) {
+ if (T.isTemporaryDtorsBranch())
+ OS << "(Temp Dtor) ";
+ Visit(T.getStmt());
+ }
};
} // end anonymous namespace
@@ -3712,7 +4056,8 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
const CFGElement &E) {
if (Optional<CFGStmt> CS = E.getAs<CFGStmt>()) {
const Stmt *S = CS->getStmt();
-
+ assert(S != nullptr && "Expecting non-null Stmt");
+
// special printing for statement-expressions.
if (const StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
const CompoundStmt *Sub = SE->getSubStmt();
@@ -3787,6 +4132,11 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()";
OS << " (Implicit destructor)\n";
+ } else if (Optional<CFGNewAllocator> NE = E.getAs<CFGNewAllocator>()) {
+ OS << "CFGNewAllocator(";
+ if (const CXXNewExpr *AllocExpr = NE->getAllocatorExpr())
+ AllocExpr->getType().print(OS, PrintingPolicy(Helper.getLangOpts()));
+ OS << ")\n";
} else if (Optional<CFGDeleteDtor> DE = E.getAs<CFGDeleteDtor>()) {
const CXXRecordDecl *RD = DE->getCXXRecordDecl();
if (!RD)
@@ -3835,6 +4185,8 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
OS << " (EXIT)]\n";
else if (&B == cfg->getIndirectGotoBlock())
OS << " (INDIRECT GOTO DISPATCH)]\n";
+ else if (B.hasNoReturnElement())
+ OS << " (NORETURN)]\n";
else
OS << "]\n";
@@ -3851,8 +4203,9 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
OS << L->getName();
else if (CaseStmt *C = dyn_cast<CaseStmt>(Label)) {
OS << "case ";
- C->getLHS()->printPretty(OS, &Helper,
- PrintingPolicy(Helper.getLangOpts()));
+ if (C->getLHS())
+ C->getLHS()->printPretty(OS, &Helper,
+ PrintingPolicy(Helper.getLangOpts()));
if (C->getRHS()) {
OS << " ... ";
C->getRHS()->printPretty(OS, &Helper,
@@ -3903,7 +4256,7 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
PrintingPolicy PP(Helper.getLangOpts());
CFGBlockTerminatorPrint TPrinter(OS, &Helper, PP);
- TPrinter.Visit(const_cast<Stmt*>(B.getTerminator().getStmt()));
+ TPrinter.print(B.getTerminator());
OS << '\n';
if (ShowColors)
@@ -3931,7 +4284,16 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
if (i % 10 == 8)
OS << "\n ";
- OS << " B" << (*I)->getBlockID();
+ CFGBlock *B = *I;
+ bool Reachable = true;
+ if (!B) {
+ Reachable = false;
+ B = I->getPossiblyUnreachableBlock();
+ }
+
+ OS << " B" << B->getBlockID();
+ if (!Reachable)
+ OS << "(Unreachable)";
}
if (ShowColors)
@@ -3960,12 +4322,24 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
if (i % 10 == 8)
OS << "\n ";
- if (*I)
- OS << " B" << (*I)->getBlockID();
- else
- OS << " NULL";
+ CFGBlock *B = *I;
+
+ bool Reachable = true;
+ if (!B) {
+ Reachable = false;
+ B = I->getPossiblyUnreachableBlock();
+ }
+
+ if (B) {
+ OS << " B" << B->getBlockID();
+ if (!Reachable)
+ OS << "(Unreachable)";
+ }
+ else {
+ OS << " NULL";
+ }
}
-
+
if (ShowColors)
OS.resetColor();
OS << '\n';
@@ -4007,6 +4381,10 @@ void CFGBlock::dump(const CFG* cfg, const LangOptions &LO,
print(llvm::errs(), cfg, LO, ShowColors);
}
+void CFGBlock::dump() const {
+ dump(getParent(), LangOptions(), false);
+}
+
/// print - A simple pretty printer of a CFGBlock that outputs to an ostream.
/// Generally this will only be called from CFG::print.
void CFGBlock::print(raw_ostream &OS, const CFG* cfg,
@@ -4019,16 +4397,16 @@ void CFGBlock::print(raw_ostream &OS, const CFG* cfg,
/// printTerminator - A simple pretty printer of the terminator of a CFGBlock.
void CFGBlock::printTerminator(raw_ostream &OS,
const LangOptions &LO) const {
- CFGBlockTerminatorPrint TPrinter(OS, NULL, PrintingPolicy(LO));
- TPrinter.Visit(const_cast<Stmt*>(getTerminator().getStmt()));
+ CFGBlockTerminatorPrint TPrinter(OS, nullptr, PrintingPolicy(LO));
+ TPrinter.print(getTerminator());
}
-Stmt *CFGBlock::getTerminatorCondition() {
+Stmt *CFGBlock::getTerminatorCondition(bool StripParens) {
Stmt *Terminator = this->Terminator;
if (!Terminator)
- return NULL;
+ return nullptr;
- Expr *E = NULL;
+ Expr *E = nullptr;
switch (Terminator->getStmtClass()) {
default:
@@ -4082,7 +4460,10 @@ Stmt *CFGBlock::getTerminatorCondition() {
return Terminator;
}
- return E ? E->IgnoreParens() : NULL;
+ if (!StripParens)
+ return E;
+
+ return E ? E->IgnoreParens() : nullptr;
}
//===----------------------------------------------------------------------===//
@@ -4099,7 +4480,7 @@ void CFG::viewCFG(const LangOptions &LO) const {
StmtPrinterHelper H(this, LO);
GraphHelper = &H;
llvm::ViewGraph(this,"CFG");
- GraphHelper = NULL;
+ GraphHelper = nullptr;
#endif
}
diff --git a/lib/Analysis/CFGReachabilityAnalysis.cpp b/lib/Analysis/CFGReachabilityAnalysis.cpp
index 492e66fe8172..4ae135f1ea77 100644
--- a/lib/Analysis/CFGReachabilityAnalysis.cpp
+++ b/lib/Analysis/CFGReachabilityAnalysis.cpp
@@ -69,7 +69,8 @@ void CFGReverseBlockReachabilityAnalysis::mapReachability(const CFGBlock *Dst) {
// Add the predecessors to the worklist.
for (CFGBlock::const_pred_iterator i = block->pred_begin(),
e = block->pred_end(); i != e; ++i) {
- worklist.push_back(*i);
+ if (*i)
+ worklist.push_back(*i);
}
}
}
diff --git a/lib/Analysis/CFGStmtMap.cpp b/lib/Analysis/CFGStmtMap.cpp
index 87c2f5bdc130..19b80191f7a7 100644
--- a/lib/Analysis/CFGStmtMap.cpp
+++ b/lib/Analysis/CFGStmtMap.cpp
@@ -42,8 +42,8 @@ CFGBlock *CFGStmtMap::getBlock(Stmt *S) {
X = PM->getParentIgnoreParens(X);
}
-
- return 0;
+
+ return nullptr;
}
static void Accumulate(SMap &SM, CFGBlock *B) {
@@ -77,7 +77,7 @@ static void Accumulate(SMap &SM, CFGBlock *B) {
CFGStmtMap *CFGStmtMap::Build(CFG *C, ParentMap *PM) {
if (!C || !PM)
- return 0;
+ return nullptr;
SMap *SM = new SMap();
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index deab8f1f22fd..461ffb0900bb 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -1,3 +1,7 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
add_clang_library(clangAnalysis
AnalysisDeclContext.cpp
BodyFarm.cpp
@@ -18,20 +22,13 @@ add_clang_library(clangAnalysis
ReachableCode.cpp
ScanfFormatString.cpp
ThreadSafety.cpp
+ ThreadSafetyCommon.cpp
+ ThreadSafetyLogical.cpp
+ ThreadSafetyTIL.cpp
UninitializedValues.cpp
- )
-add_dependencies(clangAnalysis
- ClangAttrClasses
- ClangAttrList
- ClangCommentNodes
- ClangDiagnosticCommon
- ClangDeclNodes
- ClangDiagnosticAnalysis
- ClangStmtNodes
- )
-
-target_link_libraries(clangAnalysis
- clangBasic
+ LINK_LIBS
clangAST
+ clangBasic
+ clangLex
)
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
index 33870158b384..f41a96d30ea5 100644
--- a/lib/Analysis/CallGraph.cpp
+++ b/lib/Analysis/CallGraph.cpp
@@ -10,8 +10,6 @@
// This file defines the AST-based CallGraph.
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "CallGraph"
-
#include "clang/Analysis/CallGraph.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
@@ -22,6 +20,8 @@
using namespace clang;
+#define DEBUG_TYPE "CallGraph"
+
STATISTIC(NumObjCCallEdges, "Number of Objective-C method call edges");
STATISTIC(NumBlockCallEdges, "Number of block call edges");
@@ -49,7 +49,7 @@ public:
return Block->getBlockDecl();
}
- return 0;
+ return nullptr;
}
void addCalledDecl(Decl *D) {
@@ -70,7 +70,7 @@ public:
Selector Sel = ME->getSelector();
// Find the callee definition within the same translation unit.
- Decl *D = 0;
+ Decl *D = nullptr;
if (ME->isInstanceMessage())
D = IDecl->lookupPrivateMethod(Sel);
else
@@ -95,23 +95,17 @@ void CallGraph::addNodesForBlocks(DeclContext *D) {
if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
addNodeForDecl(BD, true);
- for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
- I!=E; ++I)
- if (DeclContext *DC = dyn_cast<DeclContext>(*I))
+ for (auto *I : D->decls())
+ if (auto *DC = dyn_cast<DeclContext>(I))
addNodesForBlocks(DC);
}
CallGraph::CallGraph() {
- Root = getOrInsertNode(0);
+ Root = getOrInsertNode(nullptr);
}
CallGraph::~CallGraph() {
- if (!FunctionMap.empty()) {
- for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end();
- I != E; ++I)
- delete I->second;
- FunctionMap.clear();
- }
+ llvm::DeleteContainerSeconds(FunctionMap);
}
bool CallGraph::includeInGraph(const Decl *D) {
@@ -153,7 +147,7 @@ void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) {
CallGraphNode *CallGraph::getNode(const Decl *F) const {
FunctionMapTy::const_iterator I = FunctionMap.find(F);
- if (I == FunctionMap.end()) return 0;
+ if (I == FunctionMap.end()) return nullptr;
return I->second;
}
@@ -164,7 +158,7 @@ CallGraphNode *CallGraph::getOrInsertNode(Decl *F) {
Node = new CallGraphNode(F);
// Make Root node a parent of all functions to make sure all are reachable.
- if (F != 0)
+ if (F)
Root->addCallee(Node, this);
return Node;
}
diff --git a/lib/Analysis/Consumed.cpp b/lib/Analysis/Consumed.cpp
index e5ec3e6b927d..2b2da2c69a41 100644
--- a/lib/Analysis/Consumed.cpp
+++ b/lib/Analysis/Consumed.cpp
@@ -17,20 +17,20 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/AST/StmtVisitor.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Type.h"
+#include "clang/Analysis/Analyses/Consumed.h"
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
-#include "clang/Analysis/Analyses/Consumed.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
+#include <memory>
// TODO: Adjust states of args to constructors in the same way that arguments to
// function calls are handled.
@@ -57,11 +57,9 @@ ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
// Find the source location of the first statement in the block, if the block
// is not empty.
- for (CFGBlock::const_iterator BI = Block->begin(), BE = Block->end();
- BI != BE; ++BI) {
- if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
+ for (const auto &B : *Block)
+ if (Optional<CFGStmt> CS = B.getAs<CFGStmt>())
return CS->getStmt()->getLocStart();
- }
// Block is empty.
// If we have one successor, return the first statement in that block
@@ -115,14 +113,10 @@ static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
static bool isCallableInState(const CallableWhenAttr *CWAttr,
ConsumedState State) {
- CallableWhenAttr::callableState_iterator I = CWAttr->callableState_begin(),
- E = CWAttr->callableState_end();
-
- for (; I != E; ++I) {
-
+ for (const auto &S : CWAttr->callableStates()) {
ConsumedState MappedAttrState = CS_None;
-
- switch (*I) {
+
+ switch (S) {
case CallableWhenAttr::Unknown:
MappedAttrState = CS_Unknown;
break;
@@ -143,6 +137,7 @@ static bool isCallableInState(const CallableWhenAttr *CWAttr,
return false;
}
+
static bool isConsumableType(const QualType &QT) {
if (QT->isPointerType() || QT->isReferenceType())
return false;
@@ -153,6 +148,23 @@ static bool isConsumableType(const QualType &QT) {
return false;
}
+static bool isAutoCastType(const QualType &QT) {
+ if (QT->isPointerType() || QT->isReferenceType())
+ return false;
+
+ if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
+ return RD->hasAttr<ConsumableAutoCastAttr>();
+
+ return false;
+}
+
+static bool isSetOnReadPtrType(const QualType &QT) {
+ if (const CXXRecordDecl *RD = QT->getPointeeCXXRecordDecl())
+ return RD->hasAttr<ConsumableSetOnReadAttr>();
+ return false;
+}
+
+
static bool isKnownState(ConsumedState State) {
switch (State) {
case CS_Unconsumed:
@@ -165,19 +177,16 @@ static bool isKnownState(ConsumedState State) {
llvm_unreachable("invalid enum");
}
-static bool isRValueRefish(QualType ParamType) {
- return ParamType->isRValueReferenceType() ||
- (ParamType->isLValueReferenceType() &&
- !cast<LValueReferenceType>(
- ParamType.getCanonicalType())->isSpelledAsLValue());
+static bool isRValueRef(QualType ParamType) {
+ return ParamType->isRValueReferenceType();
}
static bool isTestingFunction(const FunctionDecl *FunDecl) {
return FunDecl->hasAttr<TestTypestateAttr>();
}
-static bool isValueType(QualType ParamType) {
- return !(ParamType->isPointerType() || ParamType->isReferenceType());
+static bool isPointerOrRef(QualType ParamType) {
+ return ParamType->isPointerType() || ParamType->isReferenceType();
}
static ConsumedState mapConsumableAttrState(const QualType QT) {
@@ -455,15 +464,29 @@ class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
ConsumedAnalyzer &Analyzer;
ConsumedStateMap *StateMap;
MapType PropagationMap;
- void forwardInfo(const Stmt *From, const Stmt *To);
- bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl);
- void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun,
- QualType ReturnType);
+
+ InfoEntry findInfo(const Expr *E) {
+ return PropagationMap.find(E->IgnoreParens());
+ }
+ ConstInfoEntry findInfo(const Expr *E) const {
+ return PropagationMap.find(E->IgnoreParens());
+ }
+ void insertInfo(const Expr *E, const PropagationInfo &PI) {
+ PropagationMap.insert(PairType(E->IgnoreParens(), PI));
+ }
+
+ void forwardInfo(const Expr *From, const Expr *To);
+ void copyInfo(const Expr *From, const Expr *To, ConsumedState CS);
+ ConsumedState getInfo(const Expr *From);
+ void setInfo(const Expr *To, ConsumedState NS);
+ void propagateReturnType(const Expr *Call, const FunctionDecl *Fun);
public:
void checkCallability(const PropagationInfo &PInfo,
const FunctionDecl *FunDecl,
SourceLocation BlameLoc);
+ bool handleCall(const CallExpr *Call, const Expr *ObjArg,
+ const FunctionDecl *FunD);
void VisitBinaryOperator(const BinaryOperator *BinOp);
void VisitCallExpr(const CallExpr *Call);
@@ -485,8 +508,8 @@ public:
ConsumedStateMap *StateMap)
: AC(AC), Analyzer(Analyzer), StateMap(StateMap) {}
- PropagationInfo getInfo(const Stmt *StmtNode) const {
- ConstInfoEntry Entry = PropagationMap.find(StmtNode);
+ PropagationInfo getInfo(const Expr *StmtNode) const {
+ ConstInfoEntry Entry = findInfo(StmtNode);
if (Entry != PropagationMap.end())
return Entry->second;
@@ -499,76 +522,187 @@ public:
}
};
+
+void ConsumedStmtVisitor::forwardInfo(const Expr *From, const Expr *To) {
+ InfoEntry Entry = findInfo(From);
+ if (Entry != PropagationMap.end())
+ insertInfo(To, Entry->second);
+}
+
+
+// Create a new state for To, which is initialized to the state of From.
+// If NS is not CS_None, sets the state of From to NS.
+void ConsumedStmtVisitor::copyInfo(const Expr *From, const Expr *To,
+ ConsumedState NS) {
+ InfoEntry Entry = findInfo(From);
+ if (Entry != PropagationMap.end()) {
+ PropagationInfo& PInfo = Entry->second;
+ ConsumedState CS = PInfo.getAsState(StateMap);
+ if (CS != CS_None)
+ insertInfo(To, PropagationInfo(CS));
+ if (NS != CS_None && PInfo.isPointerToValue())
+ setStateForVarOrTmp(StateMap, PInfo, NS);
+ }
+}
+
+
+// Get the ConsumedState for From
+ConsumedState ConsumedStmtVisitor::getInfo(const Expr *From) {
+ InfoEntry Entry = findInfo(From);
+ if (Entry != PropagationMap.end()) {
+ PropagationInfo& PInfo = Entry->second;
+ return PInfo.getAsState(StateMap);
+ }
+ return CS_None;
+}
+
+
+// If we already have info for To then update it, otherwise create a new entry.
+void ConsumedStmtVisitor::setInfo(const Expr *To, ConsumedState NS) {
+ InfoEntry Entry = findInfo(To);
+ if (Entry != PropagationMap.end()) {
+ PropagationInfo& PInfo = Entry->second;
+ if (PInfo.isPointerToValue())
+ setStateForVarOrTmp(StateMap, PInfo, NS);
+ } else if (NS != CS_None) {
+ insertInfo(To, PropagationInfo(NS));
+ }
+}
+
+
+
void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
const FunctionDecl *FunDecl,
SourceLocation BlameLoc) {
assert(!PInfo.isTest());
-
- if (!FunDecl->hasAttr<CallableWhenAttr>())
- return;
-
+
const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
-
+ if (!CWAttr)
+ return;
+
if (PInfo.isVar()) {
ConsumedState VarState = StateMap->getState(PInfo.getVar());
-
+
if (VarState == CS_None || isCallableInState(CWAttr, VarState))
return;
-
+
Analyzer.WarningsHandler.warnUseInInvalidState(
FunDecl->getNameAsString(), PInfo.getVar()->getNameAsString(),
stateToString(VarState), BlameLoc);
-
+
} else {
ConsumedState TmpState = PInfo.getAsState(StateMap);
-
+
if (TmpState == CS_None || isCallableInState(CWAttr, TmpState))
return;
-
+
Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
FunDecl->getNameAsString(), stateToString(TmpState), BlameLoc);
}
}
-void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) {
- InfoEntry Entry = PropagationMap.find(From);
-
- if (Entry != PropagationMap.end())
- PropagationMap.insert(PairType(To, Entry->second));
-}
-bool ConsumedStmtVisitor::isLikeMoveAssignment(
- const CXXMethodDecl *MethodDecl) {
-
- return MethodDecl->isMoveAssignmentOperator() ||
- (MethodDecl->getOverloadedOperator() == OO_Equal &&
- MethodDecl->getNumParams() == 1 &&
- MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType());
+// Factors out common behavior for function, method, and operator calls.
+// Check parameters and set parameter state if necessary.
+// Returns true if the state of ObjArg is set, or false otherwise.
+bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg,
+ const FunctionDecl *FunD) {
+ unsigned Offset = 0;
+ if (isa<CXXOperatorCallExpr>(Call) && isa<CXXMethodDecl>(FunD))
+ Offset = 1; // first argument is 'this'
+
+ // check explicit parameters
+ for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
+ // Skip variable argument lists.
+ if (Index - Offset >= FunD->getNumParams())
+ break;
+
+ const ParmVarDecl *Param = FunD->getParamDecl(Index - Offset);
+ QualType ParamType = Param->getType();
+
+ InfoEntry Entry = findInfo(Call->getArg(Index));
+
+ if (Entry == PropagationMap.end() || Entry->second.isTest())
+ continue;
+ PropagationInfo PInfo = Entry->second;
+
+ // Check that the parameter is in the correct state.
+ if (ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>()) {
+ ConsumedState ParamState = PInfo.getAsState(StateMap);
+ ConsumedState ExpectedState = mapParamTypestateAttrState(PTA);
+
+ if (ParamState != ExpectedState)
+ Analyzer.WarningsHandler.warnParamTypestateMismatch(
+ Call->getArg(Index)->getExprLoc(),
+ stateToString(ExpectedState), stateToString(ParamState));
+ }
+
+ if (!(Entry->second.isVar() || Entry->second.isTmp()))
+ continue;
+
+ // Adjust state on the caller side.
+ if (isRValueRef(ParamType))
+ setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
+ else if (ReturnTypestateAttr *RT = Param->getAttr<ReturnTypestateAttr>())
+ setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT));
+ else if (isPointerOrRef(ParamType) &&
+ (!ParamType->getPointeeType().isConstQualified() ||
+ isSetOnReadPtrType(ParamType)))
+ setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown);
+ }
+
+ if (!ObjArg)
+ return false;
+
+ // check implicit 'self' parameter, if present
+ InfoEntry Entry = findInfo(ObjArg);
+ if (Entry != PropagationMap.end()) {
+ PropagationInfo PInfo = Entry->second;
+ checkCallability(PInfo, FunD, Call->getExprLoc());
+
+ if (SetTypestateAttr *STA = FunD->getAttr<SetTypestateAttr>()) {
+ if (PInfo.isVar()) {
+ StateMap->setState(PInfo.getVar(), mapSetTypestateAttrState(STA));
+ return true;
+ }
+ else if (PInfo.isTmp()) {
+ StateMap->setState(PInfo.getTmp(), mapSetTypestateAttrState(STA));
+ return true;
+ }
+ }
+ else if (isTestingFunction(FunD) && PInfo.isVar()) {
+ PropagationMap.insert(PairType(Call,
+ PropagationInfo(PInfo.getVar(), testsFor(FunD))));
+ }
+ }
+ return false;
}
-void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call,
- const FunctionDecl *Fun,
- QualType ReturnType) {
- if (isConsumableType(ReturnType)) {
-
+
+void ConsumedStmtVisitor::propagateReturnType(const Expr *Call,
+ const FunctionDecl *Fun) {
+ QualType RetType = Fun->getCallResultType();
+ if (RetType->isReferenceType())
+ RetType = RetType->getPointeeType();
+
+ if (isConsumableType(RetType)) {
ConsumedState ReturnState;
-
- if (Fun->hasAttr<ReturnTypestateAttr>())
- ReturnState = mapReturnTypestateAttrState(
- Fun->getAttr<ReturnTypestateAttr>());
+ if (ReturnTypestateAttr *RTA = Fun->getAttr<ReturnTypestateAttr>())
+ ReturnState = mapReturnTypestateAttrState(RTA);
else
- ReturnState = mapConsumableAttrState(ReturnType);
+ ReturnState = mapConsumableAttrState(RetType);
PropagationMap.insert(PairType(Call, PropagationInfo(ReturnState)));
}
}
+
void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
switch (BinOp->getOpcode()) {
case BO_LAnd:
case BO_LOr : {
- InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()),
- REntry = PropagationMap.find(BinOp->getRHS());
+ InfoEntry LEntry = findInfo(BinOp->getLHS()),
+ REntry = findInfo(BinOp->getRHS());
VarTestResult LTest, RTest;
@@ -576,7 +710,7 @@ void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
LTest = LEntry->second.getVarTest();
} else {
- LTest.Var = NULL;
+ LTest.Var = nullptr;
LTest.TestsFor = CS_None;
}
@@ -584,11 +718,11 @@ void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
RTest = REntry->second.getVarTest();
} else {
- RTest.Var = NULL;
+ RTest.Var = nullptr;
RTest.TestsFor = CS_None;
}
-
- if (!(LTest.Var == NULL && RTest.Var == NULL))
+
+ if (!(LTest.Var == nullptr && RTest.Var == nullptr))
PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
@@ -605,81 +739,21 @@ void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
}
}
-static bool isStdNamespace(const DeclContext *DC) {
- if (!DC->isNamespace()) return false;
- while (DC->getParent()->isNamespace())
- DC = DC->getParent();
- const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
-
- return ND && ND->getName() == "std" &&
- ND->getDeclContext()->isTranslationUnit();
-}
-
void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
- if (const FunctionDecl *FunDecl =
- dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) {
-
- // Special case for the std::move function.
- // TODO: Make this more specific. (Deferred)
- if (Call->getNumArgs() == 1 &&
- FunDecl->getNameAsString() == "move" &&
- isStdNamespace(FunDecl->getDeclContext())) {
- forwardInfo(Call->getArg(0), Call);
- return;
- }
-
- unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams();
-
- for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
- const ParmVarDecl *Param = FunDecl->getParamDecl(Index - Offset);
- QualType ParamType = Param->getType();
-
- InfoEntry Entry = PropagationMap.find(Call->getArg(Index));
-
- if (Entry == PropagationMap.end() || Entry->second.isTest())
- continue;
-
- PropagationInfo PInfo = Entry->second;
-
- // Check that the parameter is in the correct state.
-
- if (Param->hasAttr<ParamTypestateAttr>()) {
- ConsumedState ParamState = PInfo.getAsState(StateMap);
-
- ConsumedState ExpectedState =
- mapParamTypestateAttrState(Param->getAttr<ParamTypestateAttr>());
-
- if (ParamState != ExpectedState)
- Analyzer.WarningsHandler.warnParamTypestateMismatch(
- Call->getArg(Index - Offset)->getExprLoc(),
- stateToString(ExpectedState), stateToString(ParamState));
- }
-
- if (!(Entry->second.isVar() || Entry->second.isTmp()))
- continue;
-
- // Adjust state on the caller side.
-
- if (isRValueRefish(ParamType)) {
- setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
-
- } else if (Param->hasAttr<ReturnTypestateAttr>()) {
- setStateForVarOrTmp(StateMap, PInfo,
- mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>()));
-
- } else if (!isValueType(ParamType) &&
- !ParamType->getPointeeType().isConstQualified()) {
-
- setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown);
- }
- }
-
- QualType RetType = FunDecl->getCallResultType();
- if (RetType->isReferenceType())
- RetType = RetType->getPointeeType();
-
- propagateReturnType(Call, FunDecl, RetType);
+ const FunctionDecl *FunDecl = Call->getDirectCallee();
+ if (!FunDecl)
+ return;
+
+ // Special case for the std::move function.
+ // TODO: Make this more specific. (Deferred)
+ if (Call->getNumArgs() == 1 && FunDecl->getNameAsString() == "move" &&
+ FunDecl->isInStdNamespace()) {
+ copyInfo(Call->getArg(0), Call, CS_Consumed);
+ return;
}
+
+ handleCall(Call, nullptr, FunDecl);
+ propagateReturnType(Call, FunDecl);
}
void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
@@ -689,7 +763,7 @@ void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
const CXXBindTemporaryExpr *Temp) {
- InfoEntry Entry = PropagationMap.find(Temp->getSubExpr());
+ InfoEntry Entry = findInfo(Temp->getSubExpr());
if (Entry != PropagationMap.end() && !Entry->second.isTest()) {
StateMap->setState(Temp, Entry->second.getAsState(StateMap));
@@ -707,168 +781,60 @@ void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
return;
// FIXME: What should happen if someone annotates the move constructor?
- if (Constructor->hasAttr<ReturnTypestateAttr>()) {
- // TODO: Adjust state of args appropriately.
-
- ReturnTypestateAttr *RTAttr = Constructor->getAttr<ReturnTypestateAttr>();
- ConsumedState RetState = mapReturnTypestateAttrState(RTAttr);
+ if (ReturnTypestateAttr *RTA = Constructor->getAttr<ReturnTypestateAttr>()) {
+ // TODO: Adjust state of args appropriately.
+ ConsumedState RetState = mapReturnTypestateAttrState(RTA);
PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
-
} else if (Constructor->isDefaultConstructor()) {
-
PropagationMap.insert(PairType(Call,
PropagationInfo(consumed::CS_Consumed)));
-
} else if (Constructor->isMoveConstructor()) {
-
- InfoEntry Entry = PropagationMap.find(Call->getArg(0));
-
- if (Entry != PropagationMap.end()) {
- PropagationInfo PInfo = Entry->second;
-
- if (PInfo.isVar()) {
- const VarDecl* Var = PInfo.getVar();
-
- PropagationMap.insert(PairType(Call,
- PropagationInfo(StateMap->getState(Var))));
-
- StateMap->setState(Var, consumed::CS_Consumed);
-
- } else if (PInfo.isTmp()) {
- const CXXBindTemporaryExpr *Tmp = PInfo.getTmp();
-
- PropagationMap.insert(PairType(Call,
- PropagationInfo(StateMap->getState(Tmp))));
-
- StateMap->setState(Tmp, consumed::CS_Consumed);
-
- } else {
- PropagationMap.insert(PairType(Call, PInfo));
- }
- }
+ copyInfo(Call->getArg(0), Call, CS_Consumed);
} else if (Constructor->isCopyConstructor()) {
- forwardInfo(Call->getArg(0), Call);
-
+ // Copy state from arg. If setStateOnRead then set arg to CS_Unknown.
+ ConsumedState NS =
+ isSetOnReadPtrType(Constructor->getThisType(CurrContext)) ?
+ CS_Unknown : CS_None;
+ copyInfo(Call->getArg(0), Call, NS);
} else {
// TODO: Adjust state of args appropriately.
-
ConsumedState RetState = mapConsumableAttrState(ThisType);
PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
}
}
+
void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
- const CXXMemberCallExpr *Call) {
-
- VisitCallExpr(Call);
-
- InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens());
-
- if (Entry != PropagationMap.end()) {
- PropagationInfo PInfo = Entry->second;
- const CXXMethodDecl *MethodDecl = Call->getMethodDecl();
-
- checkCallability(PInfo, MethodDecl, Call->getExprLoc());
-
- if (PInfo.isVar()) {
- if (isTestingFunction(MethodDecl))
- PropagationMap.insert(PairType(Call,
- PropagationInfo(PInfo.getVar(), testsFor(MethodDecl))));
- else if (MethodDecl->hasAttr<SetTypestateAttr>())
- StateMap->setState(PInfo.getVar(),
- mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>()));
- } else if (PInfo.isTmp() && MethodDecl->hasAttr<SetTypestateAttr>()) {
- StateMap->setState(PInfo.getTmp(),
- mapSetTypestateAttrState(MethodDecl->getAttr<SetTypestateAttr>()));
- }
- }
+ const CXXMemberCallExpr *Call) {
+ CXXMethodDecl* MD = Call->getMethodDecl();
+ if (!MD)
+ return;
+
+ handleCall(Call, Call->getImplicitObjectArgument(), MD);
+ propagateReturnType(Call, MD);
}
+
void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
- const CXXOperatorCallExpr *Call) {
-
+ const CXXOperatorCallExpr *Call) {
+
const FunctionDecl *FunDecl =
dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
-
if (!FunDecl) return;
-
- if (isa<CXXMethodDecl>(FunDecl) &&
- isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) {
-
- InfoEntry LEntry = PropagationMap.find(Call->getArg(0));
- InfoEntry REntry = PropagationMap.find(Call->getArg(1));
-
- PropagationInfo LPInfo, RPInfo;
-
- if (LEntry != PropagationMap.end() &&
- REntry != PropagationMap.end()) {
-
- LPInfo = LEntry->second;
- RPInfo = REntry->second;
-
- if (LPInfo.isPointerToValue() && RPInfo.isPointerToValue()) {
- setStateForVarOrTmp(StateMap, LPInfo, RPInfo.getAsState(StateMap));
- PropagationMap.insert(PairType(Call, LPInfo));
- setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed);
-
- } else if (RPInfo.isState()) {
- setStateForVarOrTmp(StateMap, LPInfo, RPInfo.getState());
- PropagationMap.insert(PairType(Call, LPInfo));
-
- } else {
- setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed);
- }
-
- } else if (LEntry != PropagationMap.end() &&
- REntry == PropagationMap.end()) {
-
- LPInfo = LEntry->second;
-
- assert(!LPInfo.isTest());
-
- if (LPInfo.isPointerToValue()) {
- setStateForVarOrTmp(StateMap, LPInfo, consumed::CS_Unknown);
- PropagationMap.insert(PairType(Call, LPInfo));
-
- } else {
- PropagationMap.insert(PairType(Call,
- PropagationInfo(consumed::CS_Unknown)));
- }
-
- } else if (LEntry == PropagationMap.end() &&
- REntry != PropagationMap.end()) {
-
- RPInfo = REntry->second;
-
- if (RPInfo.isPointerToValue())
- setStateForVarOrTmp(StateMap, RPInfo, consumed::CS_Consumed);
- }
-
- } else {
-
- VisitCallExpr(Call);
-
- InfoEntry Entry = PropagationMap.find(Call->getArg(0));
-
- if (Entry != PropagationMap.end()) {
- PropagationInfo PInfo = Entry->second;
-
- checkCallability(PInfo, FunDecl, Call->getExprLoc());
-
- if (PInfo.isVar()) {
- if (isTestingFunction(FunDecl))
- PropagationMap.insert(PairType(Call,
- PropagationInfo(PInfo.getVar(), testsFor(FunDecl))));
- else if (FunDecl->hasAttr<SetTypestateAttr>())
- StateMap->setState(PInfo.getVar(),
- mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>()));
-
- } else if (PInfo.isTmp() && FunDecl->hasAttr<SetTypestateAttr>()) {
- StateMap->setState(PInfo.getTmp(),
- mapSetTypestateAttrState(FunDecl->getAttr<SetTypestateAttr>()));
- }
- }
+
+ if (Call->getOperator() == OO_Equal) {
+ ConsumedState CS = getInfo(Call->getArg(1));
+ if (!handleCall(Call, Call->getArg(0), FunDecl))
+ setInfo(Call->getArg(0), CS);
+ return;
}
+
+ if (const CXXMemberCallExpr *MCall = dyn_cast<CXXMemberCallExpr>(Call))
+ handleCall(MCall, MCall->getImplicitObjectArgument(), FunDecl);
+ else
+ handleCall(Call, Call->getArg(0), FunDecl);
+
+ propagateReturnType(Call, FunDecl);
}
void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
@@ -878,11 +844,9 @@ void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
}
void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
- for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(),
- DE = DeclS->decl_end(); DI != DE; ++DI) {
-
- if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI));
- }
+ for (const auto *DI : DeclS->decls())
+ if (isa<VarDecl>(DI))
+ VisitVarDecl(cast<VarDecl>(DI));
if (DeclS->isSingleDecl())
if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
@@ -904,22 +868,16 @@ void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
QualType ParamType = Param->getType();
ConsumedState ParamState = consumed::CS_None;
- if (Param->hasAttr<ParamTypestateAttr>()) {
- const ParamTypestateAttr *PTAttr = Param->getAttr<ParamTypestateAttr>();
- ParamState = mapParamTypestateAttrState(PTAttr);
-
- } else if (isConsumableType(ParamType)) {
- ParamState = mapConsumableAttrState(ParamType);
-
- } else if (isRValueRefish(ParamType) &&
- isConsumableType(ParamType->getPointeeType())) {
-
- ParamState = mapConsumableAttrState(ParamType->getPointeeType());
-
- } else if (ParamType->isReferenceType() &&
- isConsumableType(ParamType->getPointeeType())) {
+ if (const ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>())
+ ParamState = mapParamTypestateAttrState(PTA);
+ else if (isConsumableType(ParamType))
+ ParamState = mapConsumableAttrState(ParamType);
+ else if (isRValueRef(ParamType) &&
+ isConsumableType(ParamType->getPointeeType()))
+ ParamState = mapConsumableAttrState(ParamType->getPointeeType());
+ else if (ParamType->isReferenceType() &&
+ isConsumableType(ParamType->getPointeeType()))
ParamState = consumed::CS_Unknown;
- }
if (ParamState != CS_None)
StateMap->setState(Param, ParamState);
@@ -929,7 +887,7 @@ void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
if (ExpectedState != CS_None) {
- InfoEntry Entry = PropagationMap.find(Ret->getRetValue());
+ InfoEntry Entry = findInfo(Ret->getRetValue());
if (Entry != PropagationMap.end()) {
ConsumedState RetState = Entry->second.getAsState(StateMap);
@@ -946,7 +904,7 @@ void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
}
void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
- InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens());
+ InfoEntry Entry = findInfo(UOp->getSubExpr());
if (Entry == PropagationMap.end()) return;
switch (UOp->getOpcode()) {
@@ -968,8 +926,7 @@ void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
if (isConsumableType(Var->getType())) {
if (Var->hasInit()) {
- MapType::iterator VIT = PropagationMap.find(
- Var->getInit()->IgnoreImplicit());
+ MapType::iterator VIT = findInfo(Var->getInit()->IgnoreImplicit());
if (VIT != PropagationMap.end()) {
PropagationInfo PInfo = VIT->second;
ConsumedState St = PInfo.getAsState(StateMap);
@@ -1104,9 +1061,9 @@ void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
ConsumedStateMap *StateMap) {
-
- assert(Block != NULL && "Block pointer must not be NULL");
-
+
+ assert(Block && "Block pointer must not be NULL");
+
ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()];
if (Entry) {
@@ -1128,7 +1085,7 @@ ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
unsigned int BlockID = Block->getBlockID();
delete StateMapsArray[BlockID];
- StateMapsArray[BlockID] = NULL;
+ StateMapsArray[BlockID] = nullptr;
}
ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
@@ -1138,7 +1095,7 @@ ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
if (isBackEdgeTarget(Block)) {
return new ConsumedStateMap(*StateMap);
} else {
- StateMapsArray[Block->getBlockID()] = NULL;
+ StateMapsArray[Block->getBlockID()] = nullptr;
return StateMap;
}
}
@@ -1151,8 +1108,8 @@ bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
}
bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
- assert(Block != NULL && "Block pointer must not be NULL");
-
+ assert(Block && "Block pointer must not be NULL");
+
// Anything with less than two predecessors can't be the target of a back
// edge.
if (Block->pred_size() < 2)
@@ -1170,24 +1127,19 @@ bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
ConsumedWarningsHandlerBase &WarningsHandler) const {
- ConsumedState ExpectedState;
-
- for (VarMapType::const_iterator DMI = VarMap.begin(), DME = VarMap.end();
- DMI != DME; ++DMI) {
-
- if (isa<ParmVarDecl>(DMI->first)) {
- const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first);
+ for (const auto &DM : VarMap) {
+ if (isa<ParmVarDecl>(DM.first)) {
+ const ParmVarDecl *Param = cast<ParmVarDecl>(DM.first);
+ const ReturnTypestateAttr *RTA = Param->getAttr<ReturnTypestateAttr>();
- if (!Param->hasAttr<ReturnTypestateAttr>()) continue;
-
- ExpectedState =
- mapReturnTypestateAttrState(Param->getAttr<ReturnTypestateAttr>());
+ if (!RTA)
+ continue;
- if (DMI->second != ExpectedState) {
+ ConsumedState ExpectedState = mapReturnTypestateAttrState(RTA);
+ if (DM.second != ExpectedState)
WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
Param->getNameAsString(), stateToString(ExpectedState),
- stateToString(DMI->second));
- }
+ stateToString(DM.second));
}
}
}
@@ -1223,16 +1175,14 @@ void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
return;
}
- for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
- DME = Other->VarMap.end(); DMI != DME; ++DMI) {
-
- LocalState = this->getState(DMI->first);
+ for (const auto &DM : Other->VarMap) {
+ LocalState = this->getState(DM.first);
if (LocalState == CS_None)
continue;
- if (LocalState != DMI->second)
- VarMap[DMI->first] = CS_Unknown;
+ if (LocalState != DM.second)
+ VarMap[DM.first] = CS_Unknown;
}
}
@@ -1243,18 +1193,16 @@ void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
ConsumedState LocalState;
SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
- for (VarMapType::const_iterator DMI = LoopBackStates->VarMap.begin(),
- DME = LoopBackStates->VarMap.end(); DMI != DME; ++DMI) {
-
- LocalState = this->getState(DMI->first);
+ for (const auto &DM : LoopBackStates->VarMap) {
+ LocalState = this->getState(DM.first);
if (LocalState == CS_None)
continue;
- if (LocalState != DMI->second) {
- VarMap[DMI->first] = CS_Unknown;
- WarningsHandler.warnLoopStateMismatch(
- BlameLoc, DMI->first->getNameAsString());
+ if (LocalState != DM.second) {
+ VarMap[DM.first] = CS_Unknown;
+ WarningsHandler.warnLoopStateMismatch(BlameLoc,
+ DM.first->getNameAsString());
}
}
}
@@ -1274,18 +1222,14 @@ void ConsumedStateMap::setState(const CXXBindTemporaryExpr *Tmp,
TmpMap[Tmp] = State;
}
-void ConsumedStateMap::remove(const VarDecl *Var) {
- VarMap.erase(Var);
+void ConsumedStateMap::remove(const CXXBindTemporaryExpr *Tmp) {
+ TmpMap.erase(Tmp);
}
bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
- for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
- DME = Other->VarMap.end(); DMI != DME; ++DMI) {
-
- if (this->getState(DMI->first) != DMI->second)
- return true;
- }
-
+ for (const auto &DM : Other->VarMap)
+ if (this->getState(DM.first) != DM.second)
+ return true;
return false;
}
@@ -1298,9 +1242,7 @@ void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
} else
ReturnType = D->getCallResultType();
- if (D->hasAttr<ReturnTypestateAttr>()) {
- const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>();
-
+ if (const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>()) {
const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
if (!RD || !RD->hasAttr<ConsumableAttr>()) {
// FIXME: This should be removed when template instantiation propagates
@@ -1312,22 +1254,27 @@ void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
ExpectedReturnState = CS_None;
} else
ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
- } else if (isConsumableType(ReturnType))
- ExpectedReturnState = mapConsumableAttrState(ReturnType);
+ } else if (isConsumableType(ReturnType)) {
+ if (isAutoCastType(ReturnType)) // We can auto-cast the state to the
+ ExpectedReturnState = CS_None; // expected state.
+ else
+ ExpectedReturnState = mapConsumableAttrState(ReturnType);
+ }
else
ExpectedReturnState = CS_None;
}
bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
const ConsumedStmtVisitor &Visitor) {
-
- OwningPtr<ConsumedStateMap> FalseStates(new ConsumedStateMap(*CurrStates));
+
+ std::unique_ptr<ConsumedStateMap> FalseStates(
+ new ConsumedStateMap(*CurrStates));
PropagationInfo PInfo;
if (const IfStmt *IfNode =
dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
- const Stmt *Cond = IfNode->getCond();
+ const Expr *Cond = IfNode->getCond();
PInfo = Visitor.getInfo(Cond);
if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
@@ -1396,9 +1343,9 @@ bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
delete CurrStates;
if (*++SI)
- BlockInfo.addInfo(*SI, FalseStates.take());
-
- CurrStates = NULL;
+ BlockInfo.addInfo(*SI, FalseStates.release());
+
+ CurrStates = nullptr;
return true;
}
@@ -1422,18 +1369,12 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
// Add all trackable parameters to the state map.
- for (FunctionDecl::param_const_iterator PI = D->param_begin(),
- PE = D->param_end(); PI != PE; ++PI) {
- Visitor.VisitParmVarDecl(*PI);
- }
+ for (const auto *PI : D->params())
+ Visitor.VisitParmVarDecl(PI);
// Visit all of the function's basic blocks.
- for (PostOrderCFGView::iterator I = SortedGraph->begin(),
- E = SortedGraph->end(); I != E; ++I) {
-
- const CFGBlock *CurrBlock = *I;
-
- if (CurrStates == NULL)
+ for (const auto *CurrBlock : *SortedGraph) {
+ if (!CurrStates)
CurrStates = BlockInfo.getInfo(CurrBlock);
if (!CurrStates) {
@@ -1441,33 +1382,32 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
} else if (!CurrStates->isReachable()) {
delete CurrStates;
- CurrStates = NULL;
+ CurrStates = nullptr;
continue;
}
Visitor.reset(CurrStates);
// Visit all of the basic block's statements.
- for (CFGBlock::const_iterator BI = CurrBlock->begin(),
- BE = CurrBlock->end(); BI != BE; ++BI) {
-
- switch (BI->getKind()) {
+ for (const auto &B : *CurrBlock) {
+ switch (B.getKind()) {
case CFGElement::Statement:
- Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
+ Visitor.Visit(B.castAs<CFGStmt>().getStmt());
break;
case CFGElement::TemporaryDtor: {
- const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
+ const CFGTemporaryDtor &DTor = B.castAs<CFGTemporaryDtor>();
const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
Visitor.checkCallability(PropagationInfo(BTE),
DTor.getDestructorDecl(AC.getASTContext()),
BTE->getExprLoc());
+ CurrStates->remove(BTE);
break;
}
case CFGElement::AutomaticObjectDtor: {
- const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
+ const CFGAutomaticObjDtor &DTor = B.castAs<CFGAutomaticObjDtor>();
SourceLocation Loc = DTor.getTriggerStmt()->getLocEnd();
const VarDecl *Var = DTor.getVarDecl();
@@ -1482,13 +1422,11 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
}
}
- CurrStates->clearTemporaries();
-
// TODO: Handle other forms of branching with precision, including while-
// and for-loops. (Deferred)
if (!splitState(CurrBlock, Visitor)) {
- CurrStates->setSource(NULL);
-
+ CurrStates->setSource(nullptr);
+
if (CurrBlock->succ_size() > 1 ||
(CurrBlock->succ_size() == 1 &&
(*CurrBlock->succ_begin())->pred_size() > 1)) {
@@ -1497,9 +1435,9 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
SE = CurrBlock->succ_end(); SI != SE; ++SI) {
-
- if (*SI == NULL) continue;
-
+
+ if (*SI == nullptr) continue;
+
if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock,
CurrStates,
@@ -1514,8 +1452,8 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
if (!OwnershipTaken)
delete CurrStates;
-
- CurrStates = NULL;
+
+ CurrStates = nullptr;
}
}
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index 43ecc6682e3f..851b97e5bc1d 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -507,7 +507,7 @@ analyze_format_string::LengthModifier::toString() const {
case None:
return "";
}
- return NULL;
+ return nullptr;
}
//===----------------------------------------------------------------------===//
@@ -539,7 +539,7 @@ const char *ConversionSpecifier::toString() const {
case nArg: return "n";
case PercentArg: return "%";
case ScanListArg: return "[";
- case InvalidSpecifier: return NULL;
+ case InvalidSpecifier: return nullptr;
// POSIX unicode extensions.
case CArg: return "C";
@@ -551,7 +551,7 @@ const char *ConversionSpecifier::toString() const {
// GlibC specific specifiers.
case PrintErrno: return "m";
}
- return NULL;
+ return nullptr;
}
Optional<ConversionSpecifier>
diff --git a/lib/Analysis/FormatStringParsing.h b/lib/Analysis/FormatStringParsing.h
index 6b251230136a..fba318042cb0 100644
--- a/lib/Analysis/FormatStringParsing.h
+++ b/lib/Analysis/FormatStringParsing.h
@@ -53,14 +53,14 @@ template <typename T> class SpecifierResult {
bool Stop;
public:
SpecifierResult(bool stop = false)
- : Start(0), Stop(stop) {}
+ : Start(nullptr), Stop(stop) {}
SpecifierResult(const char *start,
const T &fs)
: FS(fs), Start(start), Stop(false) {}
const char *getStart() const { return Start; }
bool shouldStop() const { return Stop; }
- bool hasValue() const { return Start != 0; }
+ bool hasValue() const { return Start != nullptr; }
const T &getValue() const {
assert(hasValue());
return FS;
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index 9e5ec557bca2..3d6fc039fd77 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -37,7 +37,6 @@ public:
POV(Ctx.getAnalysis<PostOrderCFGView>()) {}
void enqueueBlock(const CFGBlock *block);
- void enqueueSuccessors(const CFGBlock *block);
void enqueuePredecessors(const CFGBlock *block);
const CFGBlock *dequeue();
@@ -53,19 +52,6 @@ void DataflowWorklist::enqueueBlock(const clang::CFGBlock *block) {
worklist.push_back(block);
}
}
-
-void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
- const unsigned OldWorklistSize = worklist.size();
- for (CFGBlock::const_succ_iterator I = block->succ_begin(),
- E = block->succ_end(); I != E; ++I) {
- enqueueBlock(*I);
- }
-
- if (OldWorklistSize == 0 || OldWorklistSize == worklist.size())
- return;
-
- sortWorklist();
-}
void DataflowWorklist::enqueuePredecessors(const clang::CFGBlock *block) {
const unsigned OldWorklistSize = worklist.size();
@@ -86,7 +72,7 @@ void DataflowWorklist::sortWorklist() {
const CFGBlock *DataflowWorklist::dequeue() {
if (worklist.empty())
- return 0;
+ return nullptr;
const CFGBlock *b = worklist.pop_back_val();
enqueuedBlocks[b->getBlockID()] = false;
return b;
@@ -108,10 +94,10 @@ public:
LiveVariables::LivenessValues
merge(LiveVariables::LivenessValues valsA,
LiveVariables::LivenessValues valsB);
-
- LiveVariables::LivenessValues runOnBlock(const CFGBlock *block,
- LiveVariables::LivenessValues val,
- LiveVariables::Observer *obs = 0);
+
+ LiveVariables::LivenessValues
+ runOnBlock(const CFGBlock *block, LiveVariables::LivenessValues val,
+ LiveVariables::Observer *obs = nullptr);
void dumpBlockLiveness(const SourceManager& M);
@@ -238,8 +224,8 @@ static const VariableArrayType *FindVA(QualType Ty) {
ty = VT->getElementType().getTypePtr();
}
-
- return 0;
+
+ return nullptr;
}
static const Stmt *LookThroughStmt(const Stmt *S) {
@@ -305,7 +291,7 @@ void TransferFunctions::Visit(Stmt *S) {
const DeclStmt *DS = cast<DeclStmt>(S);
if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl())) {
for (const VariableArrayType* VA = FindVA(VD->getType());
- VA != 0; VA = FindVA(VA->getElementType())) {
+ VA != nullptr; VA = FindVA(VA->getElementType())) {
AddLiveStmt(val.liveStmts, LV.SSetFact, VA->getSizeExpr());
}
}
@@ -372,7 +358,7 @@ void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) {
void TransferFunctions::VisitBlockExpr(BlockExpr *BE) {
AnalysisDeclContext::referenced_decls_iterator I, E;
- llvm::tie(I, E) =
+ std::tie(I, E) =
LV.analysisContext.getReferencedBlockVars(BE->getBlockDecl());
for ( ; I != E ; ++I) {
const VarDecl *VD = *I;
@@ -389,9 +375,8 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) {
}
void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
- for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE = DS->decl_end();
- DI != DE; ++DI)
- if (VarDecl *VD = dyn_cast<VarDecl>(*DI)) {
+ for (const auto *DI : DS->decls())
+ if (const auto *VD = dyn_cast<VarDecl>(DI)) {
if (!isAlwaysAlive(VD))
val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);
}
@@ -399,8 +384,8 @@ void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *OS) {
// Kill the iteration variable.
- DeclRefExpr *DR = 0;
- const VarDecl *VD = 0;
+ DeclRefExpr *DR = nullptr;
+ const VarDecl *VD = nullptr;
Stmt *element = OS->getElement();
if (DeclStmt *DS = dyn_cast<DeclStmt>(element)) {
@@ -508,12 +493,12 @@ LiveVariables::computeLiveness(AnalysisDeclContext &AC,
// No CFG? Bail out.
CFG *cfg = AC.getCFG();
if (!cfg)
- return 0;
+ return nullptr;
// The analysis currently has scalability issues for very large CFGs.
// Bail out if it looks too large.
if (cfg->getNumBlockIDs() > 300000)
- return 0;
+ return nullptr;
LiveVariablesImpl *LV = new LiveVariablesImpl(AC, killAtAssign);
@@ -581,16 +566,6 @@ LiveVariables::computeLiveness(AnalysisDeclContext &AC,
return new LiveVariables(LV);
}
-static bool compare_entries(const CFGBlock *A, const CFGBlock *B) {
- return A->getBlockID() < B->getBlockID();
-}
-
-static bool compare_vd_entries(const Decl *A, const Decl *B) {
- SourceLocation ALoc = A->getLocStart();
- SourceLocation BLoc = B->getLocStart();
- return ALoc.getRawEncoding() < BLoc.getRawEncoding();
-}
-
void LiveVariables::dumpBlockLiveness(const SourceManager &M) {
getImpl(impl).dumpBlockLiveness(M);
}
@@ -602,7 +577,9 @@ void LiveVariablesImpl::dumpBlockLiveness(const SourceManager &M) {
it != ei; ++it) {
vec.push_back(it->first);
}
- std::sort(vec.begin(), vec.end(), compare_entries);
+ std::sort(vec.begin(), vec.end(), [](const CFGBlock *A, const CFGBlock *B) {
+ return A->getBlockID() < B->getBlockID();
+ });
std::vector<const VarDecl*> declVec;
@@ -619,9 +596,11 @@ void LiveVariablesImpl::dumpBlockLiveness(const SourceManager &M) {
se = vals.liveDecls.end(); si != se; ++si) {
declVec.push_back(*si);
}
-
- std::sort(declVec.begin(), declVec.end(), compare_vd_entries);
-
+
+ std::sort(declVec.begin(), declVec.end(), [](const Decl *A, const Decl *B) {
+ return A->getLocStart() < B->getLocStart();
+ });
+
for (std::vector<const VarDecl*>::iterator di = declVec.begin(),
de = declVec.end(); di != de; ++di) {
llvm::errs() << " " << (*di)->getDeclName().getAsString()
diff --git a/lib/Analysis/PostOrderCFGView.cpp b/lib/Analysis/PostOrderCFGView.cpp
index cfd66f7aa1f2..5a3c8182a140 100644
--- a/lib/Analysis/PostOrderCFGView.cpp
+++ b/lib/Analysis/PostOrderCFGView.cpp
@@ -31,7 +31,7 @@ PostOrderCFGView::PostOrderCFGView(const CFG *cfg) {
PostOrderCFGView *PostOrderCFGView::create(AnalysisDeclContext &ctx) {
const CFG *cfg = ctx.getCFG();
if (!cfg)
- return 0;
+ return nullptr;
return new PostOrderCFGView(cfg);
}
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index f21b407bcb51..082a8327a346 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -60,7 +60,7 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
using namespace clang::analyze_printf;
const char *I = Beg;
- const char *Start = 0;
+ const char *Start = nullptr;
UpdateOnReturn <const char*> UpdateBeg(Beg, I);
// Look for a '%' character that indicates the start of a format specifier.
@@ -124,7 +124,7 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
// Look for the field width (if any).
if (ParseFieldWidth(H, FS, Start, I, E,
- FS.usesPositionalArg() ? 0 : &argIndex))
+ FS.usesPositionalArg() ? nullptr : &argIndex))
return true;
if (I == E) {
@@ -142,7 +142,7 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
}
if (ParsePrecision(H, FS, Start, I, E,
- FS.usesPositionalArg() ? 0 : &argIndex))
+ FS.usesPositionalArg() ? nullptr : &argIndex))
return true;
if (I == E) {
diff --git a/lib/Analysis/ProgramPoint.cpp b/lib/Analysis/ProgramPoint.cpp
index 7d67e8a91c8a..26b59bb71de2 100644
--- a/lib/Analysis/ProgramPoint.cpp
+++ b/lib/Analysis/ProgramPoint.cpp
@@ -43,9 +43,10 @@ ProgramPoint ProgramPoint::getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
}
}
-SimpleProgramPointTag::SimpleProgramPointTag(StringRef description)
- : desc(description) {}
+SimpleProgramPointTag::SimpleProgramPointTag(StringRef MsgProvider,
+ StringRef Msg)
+ : Desc((MsgProvider + " : " + Msg).str()) {}
StringRef SimpleProgramPointTag::getTagDescription() const {
- return desc;
+ return Desc;
}
diff --git a/lib/Analysis/PseudoConstantAnalysis.cpp b/lib/Analysis/PseudoConstantAnalysis.cpp
index 5d659ce5851f..3f96ca877f19 100644
--- a/lib/Analysis/PseudoConstantAnalysis.cpp
+++ b/lib/Analysis/PseudoConstantAnalysis.cpp
@@ -70,7 +70,7 @@ const Decl *PseudoConstantAnalysis::getDecl(const Expr *E) {
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
return DR->getDecl();
else
- return 0;
+ return nullptr;
}
void PseudoConstantAnalysis::RunAnalysis() {
@@ -171,10 +171,9 @@ void PseudoConstantAnalysis::RunAnalysis() {
case Stmt::DeclStmtClass: {
const DeclStmt *DS = cast<DeclStmt>(Head);
// Iterate over each decl and see if any of them contain reference decls
- for (DeclStmt::const_decl_iterator I = DS->decl_begin(),
- E = DS->decl_end(); I != E; ++I) {
+ for (const auto *I : DS->decls()) {
// We only care about VarDecls
- const VarDecl *VD = dyn_cast<VarDecl>(*I);
+ const VarDecl *VD = dyn_cast<VarDecl>(I);
if (!VD)
continue;
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index a2d19c050829..b4a72a7f8006 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -13,10 +13,12 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/ReachableCode.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/ParentMap.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Basic/SourceManager.h"
@@ -25,36 +27,352 @@
using namespace clang;
-namespace {
-class DeadCodeScan {
- llvm::BitVector Visited;
- llvm::BitVector &Reachable;
- SmallVector<const CFGBlock *, 10> WorkList;
-
- typedef SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12>
- DeferredLocsTy;
-
- DeferredLocsTy DeferredLocs;
-
-public:
- DeadCodeScan(llvm::BitVector &reachable)
- : Visited(reachable.size()),
- Reachable(reachable) {}
+//===----------------------------------------------------------------------===//
+// Core Reachability Analysis routines.
+//===----------------------------------------------------------------------===//
+
+static bool isEnumConstant(const Expr *Ex) {
+ const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex);
+ if (!DR)
+ return false;
+ return isa<EnumConstantDecl>(DR->getDecl());
+}
+
+static bool isTrivialExpression(const Expr *Ex) {
+ Ex = Ex->IgnoreParenCasts();
+ return isa<IntegerLiteral>(Ex) || isa<StringLiteral>(Ex) ||
+ isa<CXXBoolLiteralExpr>(Ex) || isa<ObjCBoolLiteralExpr>(Ex) ||
+ isa<CharacterLiteral>(Ex) ||
+ isEnumConstant(Ex);
+}
+
+static bool isTrivialDoWhile(const CFGBlock *B, const Stmt *S) {
+ // Check if the block ends with a do...while() and see if 'S' is the
+ // condition.
+ if (const Stmt *Term = B->getTerminator()) {
+ if (const DoStmt *DS = dyn_cast<DoStmt>(Term)) {
+ const Expr *Cond = DS->getCond()->IgnoreParenCasts();
+ return Cond == S && isTrivialExpression(Cond);
+ }
+ }
+ return false;
+}
+
+static bool isDeadReturn(const CFGBlock *B, const Stmt *S) {
+ // Look to see if the current control flow ends with a 'return', and see if
+ // 'S' is a substatement. The 'return' may not be the last element in the
+ // block, or may be in a subsequent block because of destructors.
+ const CFGBlock *Current = B;
+ while (true) {
+ for (CFGBlock::const_reverse_iterator I = Current->rbegin(),
+ E = Current->rend();
+ I != E; ++I) {
+ if (Optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
+ if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(CS->getStmt())) {
+ if (RS == S)
+ return true;
+ if (const Expr *RE = RS->getRetValue()) {
+ RE = RE->IgnoreParenCasts();
+ if (RE == S)
+ return true;
+ ParentMap PM(const_cast<Expr *>(RE));
+ // If 'S' is in the ParentMap, it is a subexpression of
+ // the return statement.
+ return PM.getParent(S);
+ }
+ }
+ break;
+ }
+ }
+ // Note also that we are restricting the search for the return statement
+ // to stop at control-flow; only part of a return statement may be dead,
+ // without the whole return statement being dead.
+ if (Current->getTerminator().isTemporaryDtorsBranch()) {
+ // Temporary destructors have a predictable control flow, thus we want to
+ // look into the next block for the return statement.
+ // We look into the false branch, as we know the true branch only contains
+ // the call to the destructor.
+ assert(Current->succ_size() == 2);
+ Current = *(Current->succ_begin() + 1);
+ } else if (!Current->getTerminator() && Current->succ_size() == 1) {
+ // If there is only one successor, we're not dealing with outgoing control
+ // flow. Thus, look into the next block.
+ Current = *Current->succ_begin();
+ if (Current->pred_size() > 1) {
+ // If there is more than one predecessor, we're dealing with incoming
+ // control flow - if the return statement is in that block, it might
+ // well be reachable via a different control flow, thus it's not dead.
+ return false;
+ }
+ } else {
+ // We hit control flow or a dead end. Stop searching.
+ return false;
+ }
+ }
+ llvm_unreachable("Broke out of infinite loop.");
+}
+
+static SourceLocation getTopMostMacro(SourceLocation Loc, SourceManager &SM) {
+ assert(Loc.isMacroID());
+ SourceLocation Last;
+ while (Loc.isMacroID()) {
+ Last = Loc;
+ Loc = SM.getImmediateMacroCallerLoc(Loc);
+ }
+ return Last;
+}
+
+/// Returns true if the statement is expanded from a configuration macro.
+static bool isExpandedFromConfigurationMacro(const Stmt *S,
+ Preprocessor &PP,
+ bool IgnoreYES_NO = false) {
+ // FIXME: This is not very precise. Here we just check to see if the
+ // value comes from a macro, but we can do much better. This is likely
+ // to be over conservative. This logic is factored into a separate function
+ // so that we can refine it later.
+ SourceLocation L = S->getLocStart();
+ if (L.isMacroID()) {
+ if (IgnoreYES_NO) {
+ // The Objective-C constant 'YES' and 'NO'
+ // are defined as macros. Do not treat them
+ // as configuration values.
+ SourceManager &SM = PP.getSourceManager();
+ SourceLocation TopL = getTopMostMacro(L, SM);
+ StringRef MacroName = PP.getImmediateMacroName(TopL);
+ if (MacroName == "YES" || MacroName == "NO")
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP);
+
+/// Returns true if the statement represents a configuration value.
+///
+/// A configuration value is something usually determined at compile-time
+/// to conditionally always execute some branch. Such guards are for
+/// "sometimes unreachable" code. Such code is usually not interesting
+/// to report as unreachable, and may mask truly unreachable code within
+/// those blocks.
+static bool isConfigurationValue(const Stmt *S,
+ Preprocessor &PP,
+ SourceRange *SilenceableCondVal = nullptr,
+ bool IncludeIntegers = true,
+ bool WrappedInParens = false) {
+ if (!S)
+ return false;
+
+ if (const Expr *Ex = dyn_cast<Expr>(S))
+ S = Ex->IgnoreCasts();
+
+ // Special case looking for the sigil '()' around an integer literal.
+ if (const ParenExpr *PE = dyn_cast<ParenExpr>(S))
+ if (!PE->getLocStart().isMacroID())
+ return isConfigurationValue(PE->getSubExpr(), PP, SilenceableCondVal,
+ IncludeIntegers, true);
+
+ if (const Expr *Ex = dyn_cast<Expr>(S))
+ S = Ex->IgnoreCasts();
+
+ bool IgnoreYES_NO = false;
+
+ switch (S->getStmtClass()) {
+ case Stmt::CallExprClass: {
+ const FunctionDecl *Callee =
+ dyn_cast_or_null<FunctionDecl>(cast<CallExpr>(S)->getCalleeDecl());
+ return Callee ? Callee->isConstexpr() : false;
+ }
+ case Stmt::DeclRefExprClass:
+ return isConfigurationValue(cast<DeclRefExpr>(S)->getDecl(), PP);
+ case Stmt::ObjCBoolLiteralExprClass:
+ IgnoreYES_NO = true;
+ // Fallthrough.
+ case Stmt::CXXBoolLiteralExprClass:
+ case Stmt::IntegerLiteralClass: {
+ const Expr *E = cast<Expr>(S);
+ if (IncludeIntegers) {
+ if (SilenceableCondVal && !SilenceableCondVal->getBegin().isValid())
+ *SilenceableCondVal = E->getSourceRange();
+ return WrappedInParens || isExpandedFromConfigurationMacro(E, PP, IgnoreYES_NO);
+ }
+ return false;
+ }
+ case Stmt::MemberExprClass:
+ return isConfigurationValue(cast<MemberExpr>(S)->getMemberDecl(), PP);
+ case Stmt::UnaryExprOrTypeTraitExprClass:
+ return true;
+ case Stmt::BinaryOperatorClass: {
+ const BinaryOperator *B = cast<BinaryOperator>(S);
+ // Only include raw integers (not enums) as configuration
+ // values if they are used in a logical or comparison operator
+ // (not arithmetic).
+ IncludeIntegers &= (B->isLogicalOp() || B->isComparisonOp());
+ return isConfigurationValue(B->getLHS(), PP, SilenceableCondVal,
+ IncludeIntegers) ||
+ isConfigurationValue(B->getRHS(), PP, SilenceableCondVal,
+ IncludeIntegers);
+ }
+ case Stmt::UnaryOperatorClass: {
+ const UnaryOperator *UO = cast<UnaryOperator>(S);
+ if (SilenceableCondVal)
+ *SilenceableCondVal = UO->getSourceRange();
+ return UO->getOpcode() == UO_LNot &&
+ isConfigurationValue(UO->getSubExpr(), PP, SilenceableCondVal,
+ IncludeIntegers, WrappedInParens);
+ }
+ default:
+ return false;
+ }
+}
+
+static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP) {
+ if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D))
+ return isConfigurationValue(ED->getInitExpr(), PP);
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ // As a heuristic, treat globals as configuration values. Note
+ // that we only will get here if Sema evaluated this
+ // condition to a constant expression, which means the global
+ // had to be declared in a way to be a truly constant value.
+ // We could generalize this to local variables, but it isn't
+ // clear if those truly represent configuration values that
+ // gate unreachable code.
+ if (!VD->hasLocalStorage())
+ return true;
+
+ // As a heuristic, locals that have been marked 'const' explicitly
+ // can be treated as configuration values as well.
+ return VD->getType().isLocalConstQualified();
+ }
+ return false;
+}
+
+/// Returns true if we should always explore all successors of a block.
+static bool shouldTreatSuccessorsAsReachable(const CFGBlock *B,
+ Preprocessor &PP) {
+ if (const Stmt *Term = B->getTerminator()) {
+ if (isa<SwitchStmt>(Term))
+ return true;
+ // Specially handle '||' and '&&'.
+ if (isa<BinaryOperator>(Term)) {
+ return isConfigurationValue(Term, PP);
+ }
+ }
+
+ const Stmt *Cond = B->getTerminatorCondition(/* stripParens */ false);
+ return isConfigurationValue(Cond, PP);
+}
+
+static unsigned scanFromBlock(const CFGBlock *Start,
+ llvm::BitVector &Reachable,
+ Preprocessor *PP,
+ bool IncludeSometimesUnreachableEdges) {
+ unsigned count = 0;
- void enqueue(const CFGBlock *block);
- unsigned scanBackwards(const CFGBlock *Start,
- clang::reachable_code::Callback &CB);
+ // Prep work queue
+ SmallVector<const CFGBlock*, 32> WL;
- bool isDeadCodeRoot(const CFGBlock *Block);
+ // The entry block may have already been marked reachable
+ // by the caller.
+ if (!Reachable[Start->getBlockID()]) {
+ ++count;
+ Reachable[Start->getBlockID()] = true;
+ }
- const Stmt *findDeadCode(const CFGBlock *Block);
+ WL.push_back(Start);
- void reportDeadCode(const Stmt *S,
- clang::reachable_code::Callback &CB);
-};
+ // Find the reachable blocks from 'Start'.
+ while (!WL.empty()) {
+ const CFGBlock *item = WL.pop_back_val();
+
+ // There are cases where we want to treat all successors as reachable.
+ // The idea is that some "sometimes unreachable" code is not interesting,
+ // and that we should forge ahead and explore those branches anyway.
+ // This allows us to potentially uncover some "always unreachable" code
+ // within the "sometimes unreachable" code.
+ // Look at the successors and mark then reachable.
+ Optional<bool> TreatAllSuccessorsAsReachable;
+ if (!IncludeSometimesUnreachableEdges)
+ TreatAllSuccessorsAsReachable = false;
+
+ for (CFGBlock::const_succ_iterator I = item->succ_begin(),
+ E = item->succ_end(); I != E; ++I) {
+ const CFGBlock *B = *I;
+ if (!B) do {
+ const CFGBlock *UB = I->getPossiblyUnreachableBlock();
+ if (!UB)
+ break;
+
+ if (!TreatAllSuccessorsAsReachable.hasValue()) {
+ assert(PP);
+ TreatAllSuccessorsAsReachable =
+ shouldTreatSuccessorsAsReachable(item, *PP);
+ }
+
+ if (TreatAllSuccessorsAsReachable.getValue()) {
+ B = UB;
+ break;
+ }
+ }
+ while (false);
+
+ if (B) {
+ unsigned blockID = B->getBlockID();
+ if (!Reachable[blockID]) {
+ Reachable.set(blockID);
+ WL.push_back(B);
+ ++count;
+ }
+ }
+ }
+ }
+ return count;
}
-void DeadCodeScan::enqueue(const CFGBlock *block) {
+static unsigned scanMaybeReachableFromBlock(const CFGBlock *Start,
+ Preprocessor &PP,
+ llvm::BitVector &Reachable) {
+ return scanFromBlock(Start, Reachable, &PP, true);
+}
+
+//===----------------------------------------------------------------------===//
+// Dead Code Scanner.
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class DeadCodeScan {
+ llvm::BitVector Visited;
+ llvm::BitVector &Reachable;
+ SmallVector<const CFGBlock *, 10> WorkList;
+ Preprocessor &PP;
+
+ typedef SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12>
+ DeferredLocsTy;
+
+ DeferredLocsTy DeferredLocs;
+
+ public:
+ DeadCodeScan(llvm::BitVector &reachable, Preprocessor &PP)
+ : Visited(reachable.size()),
+ Reachable(reachable),
+ PP(PP) {}
+
+ void enqueue(const CFGBlock *block);
+ unsigned scanBackwards(const CFGBlock *Start,
+ clang::reachable_code::Callback &CB);
+
+ bool isDeadCodeRoot(const CFGBlock *Block);
+
+ const Stmt *findDeadCode(const CFGBlock *Block);
+
+ void reportDeadCode(const CFGBlock *B,
+ const Stmt *S,
+ clang::reachable_code::Callback &CB);
+ };
+}
+
+void DeadCodeScan::enqueue(const CFGBlock *block) {
unsigned blockID = block->getBlockID();
if (Reachable[blockID] || Visited[blockID])
return;
@@ -64,9 +382,9 @@ void DeadCodeScan::enqueue(const CFGBlock *block) {
bool DeadCodeScan::isDeadCodeRoot(const clang::CFGBlock *Block) {
bool isDeadRoot = true;
-
+
for (CFGBlock::const_pred_iterator I = Block->pred_begin(),
- E = Block->pred_end(); I != E; ++I) {
+ E = Block->pred_end(); I != E; ++I) {
if (const CFGBlock *PredBlock = *I) {
unsigned blockID = PredBlock->getBlockID();
if (Visited[blockID]) {
@@ -81,7 +399,7 @@ bool DeadCodeScan::isDeadCodeRoot(const clang::CFGBlock *Block) {
}
}
}
-
+
return isDeadRoot;
}
@@ -100,14 +418,16 @@ const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {
if (isValidDeadStmt(S))
return S;
}
-
+
if (CFGTerminator T = Block->getTerminator()) {
- const Stmt *S = T.getStmt();
- if (isValidDeadStmt(S))
- return S;
+ if (!T.isTemporaryDtorsBranch()) {
+ const Stmt *S = T.getStmt();
+ if (isValidDeadStmt(S))
+ return S;
+ }
}
- return 0;
+ return nullptr;
}
static int SrcCmp(const std::pair<const CFGBlock *, const Stmt *> *p1,
@@ -124,7 +444,7 @@ unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start,
unsigned count = 0;
enqueue(Start);
-
+
while (!WorkList.empty()) {
const CFGBlock *Block = WorkList.pop_back_val();
@@ -135,7 +455,7 @@ unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start,
// Look for any dead code within the block.
const Stmt *S = findDeadCode(Block);
-
+
if (!S) {
// No dead code. Possibly an empty block. Look at dead predecessors.
for (CFGBlock::const_pred_iterator I = Block->pred_begin(),
@@ -145,16 +465,16 @@ unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start,
}
continue;
}
-
+
// Specially handle macro-expanded code.
if (S->getLocStart().isMacroID()) {
- count += clang::reachable_code::ScanReachableFromBlock(Block, Reachable);
+ count += scanMaybeReachableFromBlock(Block, PP, Reachable);
continue;
}
if (isDeadCodeRoot(Block)) {
- reportDeadCode(S, CB);
- count += clang::reachable_code::ScanReachableFromBlock(Block, Reachable);
+ reportDeadCode(Block, S, CB);
+ count += scanMaybeReachableFromBlock(Block, PP, Reachable);
}
else {
// Record this statement as the possibly best location in a
@@ -169,15 +489,15 @@ unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start,
if (!DeferredLocs.empty()) {
llvm::array_pod_sort(DeferredLocs.begin(), DeferredLocs.end(), SrcCmp);
for (DeferredLocsTy::iterator I = DeferredLocs.begin(),
- E = DeferredLocs.end(); I != E; ++I) {
- const CFGBlock *block = I->first;
- if (Reachable[block->getBlockID()])
+ E = DeferredLocs.end(); I != E; ++I) {
+ const CFGBlock *Block = I->first;
+ if (Reachable[Block->getBlockID()])
continue;
- reportDeadCode(I->second, CB);
- count += clang::reachable_code::ScanReachableFromBlock(block, Reachable);
+ reportDeadCode(Block, I->second, CB);
+ count += scanMaybeReachableFromBlock(Block, PP, Reachable);
}
}
-
+
return count;
}
@@ -208,7 +528,7 @@ static SourceLocation GetUnreachableLoc(const Stmt *S,
case Expr::BinaryConditionalOperatorClass:
case Expr::ConditionalOperatorClass: {
const AbstractConditionalOperator *CO =
- cast<AbstractConditionalOperator>(S);
+ cast<AbstractConditionalOperator>(S);
return CO->getQuestionLoc();
}
case Expr::MemberExprClass: {
@@ -246,61 +566,86 @@ static SourceLocation GetUnreachableLoc(const Stmt *S,
return S->getLocStart();
}
-void DeadCodeScan::reportDeadCode(const Stmt *S,
+void DeadCodeScan::reportDeadCode(const CFGBlock *B,
+ const Stmt *S,
clang::reachable_code::Callback &CB) {
+ // Classify the unreachable code found, or suppress it in some cases.
+ reachable_code::UnreachableKind UK = reachable_code::UK_Other;
+
+ if (isa<BreakStmt>(S)) {
+ UK = reachable_code::UK_Break;
+ }
+ else if (isTrivialDoWhile(B, S)) {
+ return;
+ }
+ else if (isDeadReturn(B, S)) {
+ UK = reachable_code::UK_Return;
+ }
+
+ SourceRange SilenceableCondVal;
+
+ if (UK == reachable_code::UK_Other) {
+ // Check if the dead code is part of the "loop target" of
+ // a for/for-range loop. This is the block that contains
+ // the increment code.
+ if (const Stmt *LoopTarget = B->getLoopTarget()) {
+ SourceLocation Loc = LoopTarget->getLocStart();
+ SourceRange R1(Loc, Loc), R2;
+
+ if (const ForStmt *FS = dyn_cast<ForStmt>(LoopTarget)) {
+ const Expr *Inc = FS->getInc();
+ Loc = Inc->getLocStart();
+ R2 = Inc->getSourceRange();
+ }
+
+ CB.HandleUnreachable(reachable_code::UK_Loop_Increment,
+ Loc, SourceRange(), SourceRange(Loc, Loc), R2);
+ return;
+ }
+
+ // Check if the dead block has a predecessor whose branch has
+ // a configuration value that *could* be modified to
+ // silence the warning.
+ CFGBlock::const_pred_iterator PI = B->pred_begin();
+ if (PI != B->pred_end()) {
+ if (const CFGBlock *PredBlock = PI->getPossiblyUnreachableBlock()) {
+ const Stmt *TermCond =
+ PredBlock->getTerminatorCondition(/* strip parens */ false);
+ isConfigurationValue(TermCond, PP, &SilenceableCondVal);
+ }
+ }
+ }
+
SourceRange R1, R2;
SourceLocation Loc = GetUnreachableLoc(S, R1, R2);
- CB.HandleUnreachable(Loc, R1, R2);
+ CB.HandleUnreachable(UK, Loc, SilenceableCondVal, R1, R2);
}
+//===----------------------------------------------------------------------===//
+// Reachability APIs.
+//===----------------------------------------------------------------------===//
+
namespace clang { namespace reachable_code {
-void Callback::anchor() { }
+void Callback::anchor() { }
unsigned ScanReachableFromBlock(const CFGBlock *Start,
llvm::BitVector &Reachable) {
- unsigned count = 0;
-
- // Prep work queue
- SmallVector<const CFGBlock*, 32> WL;
-
- // The entry block may have already been marked reachable
- // by the caller.
- if (!Reachable[Start->getBlockID()]) {
- ++count;
- Reachable[Start->getBlockID()] = true;
- }
-
- WL.push_back(Start);
-
- // Find the reachable blocks from 'Start'.
- while (!WL.empty()) {
- const CFGBlock *item = WL.pop_back_val();
-
- // Look at the successors and mark then reachable.
- for (CFGBlock::const_succ_iterator I = item->succ_begin(),
- E = item->succ_end(); I != E; ++I)
- if (const CFGBlock *B = *I) {
- unsigned blockID = B->getBlockID();
- if (!Reachable[blockID]) {
- Reachable.set(blockID);
- WL.push_back(B);
- ++count;
- }
- }
- }
- return count;
+ return scanFromBlock(Start, Reachable, /* SourceManager* */ nullptr, false);
}
-
-void FindUnreachableCode(AnalysisDeclContext &AC, Callback &CB) {
+
+void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP,
+ Callback &CB) {
+
CFG *cfg = AC.getCFG();
if (!cfg)
return;
- // Scan for reachable blocks from the entrance of the CFG.
+ // Scan for reachable blocks from the entrance of the CFG.
// If there are no unreachable blocks, we're done.
llvm::BitVector reachable(cfg->getNumBlockIDs());
- unsigned numReachable = ScanReachableFromBlock(&cfg->getEntry(), reachable);
+ unsigned numReachable =
+ scanMaybeReachableFromBlock(&cfg->getEntry(), PP, reachable);
if (numReachable == cfg->getNumBlockIDs())
return;
@@ -309,7 +654,7 @@ void FindUnreachableCode(AnalysisDeclContext &AC, Callback &CB) {
if (!AC.getCFGBuildOptions().AddEHEdges) {
for (CFG::try_block_iterator I = cfg->try_blocks_begin(),
E = cfg->try_blocks_end() ; I != E; ++I) {
- numReachable += ScanReachableFromBlock(*I, reachable);
+ numReachable += scanMaybeReachableFromBlock(*I, PP, reachable);
}
if (numReachable == cfg->getNumBlockIDs())
return;
@@ -323,7 +668,7 @@ void FindUnreachableCode(AnalysisDeclContext &AC, Callback &CB) {
if (reachable[block->getBlockID()])
continue;
- DeadCodeScan DS(reachable);
+ DeadCodeScan DS(reachable, PP);
numReachable += DS.scanBackwards(block, CB);
if (numReachable == cfg->getNumBlockIDs())
diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp
index f5ce84fe3615..ed286274950b 100644
--- a/lib/Analysis/ScanfFormatString.cpp
+++ b/lib/Analysis/ScanfFormatString.cpp
@@ -50,6 +50,15 @@ static bool ParseScanList(FormatStringHandler &H,
}
}
+ // Special case: "^]" are the first characters.
+ if (I + 1 != E && I[0] == '^' && I[1] == ']') {
+ I += 2;
+ if (I == E) {
+ H.HandleIncompleteScanList(start, I - 1);
+ return true;
+ }
+ }
+
// Look for a ']' character which denotes the end of the scan list.
while (*I != ']') {
if (++I == E) {
@@ -73,7 +82,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
using namespace clang::analyze_scanf;
const char *I = Beg;
- const char *Start = 0;
+ const char *Start = nullptr;
UpdateOnReturn <const char*> UpdateBeg(Beg, I);
// Look for a '%' character that indicates the start of a format specifier.
@@ -379,21 +388,23 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
return ArgType();
}
-bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
+bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
+ const LangOptions &LangOpt,
ASTContext &Ctx) {
- if (!QT->isPointerType())
- return false;
// %n is different from other conversion specifiers; don't try to fix it.
if (CS.getKind() == ConversionSpecifier::nArg)
return false;
+ if (!QT->isPointerType())
+ return false;
+
QualType PT = QT->getPointeeType();
// If it's an enum, get its underlying type.
- if (const EnumType *ETy = QT->getAs<EnumType>())
- QT = ETy->getDecl()->getIntegerType();
-
+ if (const EnumType *ETy = PT->getAs<EnumType>())
+ PT = ETy->getDecl()->getIntegerType();
+
const BuiltinType *BT = PT->getAs<BuiltinType>();
if (!BT)
return false;
@@ -405,6 +416,15 @@ bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
LM.setKind(LengthModifier::AsWideChar);
else
LM.setKind(LengthModifier::None);
+
+ // If we know the target array length, we can use it as a field width.
+ if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT)) {
+ if (CAT->getSizeModifier() == ArrayType::Normal)
+ FieldWidth = OptionalAmount(OptionalAmount::Constant,
+ CAT->getSize().getZExtValue() - 1,
+ "", 0, false);
+
+ }
return true;
}
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index 6e0e1732bae9..11df61f80fa0 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -10,18 +10,22 @@
// A intra-procedural analysis for thread safety (e.g. deadlocks and race
// conditions), based off of an annotation system.
//
-// See http://clang.llvm.org/docs/LanguageExtensions.html#thread-safety-annotation-checking
+// See http://clang.llvm.org/docs/ThreadSafetyAnalysis.html
// for more information.
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/Analyses/ThreadSafety.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+#include "clang/Analysis/Analyses/ThreadSafety.h"
+#include "clang/Analysis/Analyses/ThreadSafetyLogical.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
+#include "clang/Analysis/Analyses/ThreadSafetyCommon.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
@@ -172,12 +176,9 @@ private:
const Expr* const* FunArgs; // Function arguments
CallingContext* PrevCtx; // The previous context; or 0 if none.
- CallingContext(const NamedDecl *D = 0, const Expr *S = 0,
- unsigned N = 0, const Expr* const *A = 0,
- CallingContext *P = 0)
- : AttrDecl(D), SelfArg(S), SelfArrow(false),
- NumArgs(N), FunArgs(A), PrevCtx(P)
- { }
+ CallingContext(const NamedDecl *D)
+ : AttrDecl(D), SelfArg(nullptr), SelfArrow(false), NumArgs(0),
+ FunArgs(nullptr), PrevCtx(nullptr) {}
};
typedef SmallVector<SExprNode, 4> NodeVector;
@@ -188,44 +189,41 @@ private:
NodeVector NodeVec;
private:
+ unsigned make(ExprOp O, unsigned F = 0, const void *D = nullptr) {
+ NodeVec.push_back(SExprNode(O, F, D));
+ return NodeVec.size() - 1;
+ }
+
unsigned makeNop() {
- NodeVec.push_back(SExprNode(EOP_Nop, 0, 0));
- return NodeVec.size()-1;
+ return make(EOP_Nop);
}
unsigned makeWildcard() {
- NodeVec.push_back(SExprNode(EOP_Wildcard, 0, 0));
- return NodeVec.size()-1;
+ return make(EOP_Wildcard);
}
unsigned makeUniversal() {
- NodeVec.push_back(SExprNode(EOP_Universal, 0, 0));
- return NodeVec.size()-1;
+ return make(EOP_Universal);
}
unsigned makeNamedVar(const NamedDecl *D) {
- NodeVec.push_back(SExprNode(EOP_NVar, 0, D));
- return NodeVec.size()-1;
+ return make(EOP_NVar, 0, D);
}
unsigned makeLocalVar(const NamedDecl *D) {
- NodeVec.push_back(SExprNode(EOP_LVar, 0, D));
- return NodeVec.size()-1;
+ return make(EOP_LVar, 0, D);
}
unsigned makeThis() {
- NodeVec.push_back(SExprNode(EOP_This, 0, 0));
- return NodeVec.size()-1;
+ return make(EOP_This);
}
unsigned makeDot(const NamedDecl *D, bool Arrow) {
- NodeVec.push_back(SExprNode(EOP_Dot, Arrow ? 1 : 0, D));
- return NodeVec.size()-1;
+ return make(EOP_Dot, Arrow ? 1 : 0, D);
}
unsigned makeCall(unsigned NumArgs, const NamedDecl *D) {
- NodeVec.push_back(SExprNode(EOP_Call, NumArgs, D));
- return NodeVec.size()-1;
+ return make(EOP_Call, NumArgs, D);
}
// Grab the very first declaration of virtual method D
@@ -238,32 +236,27 @@ private:
return D; // Method does not override anything
D = *I; // FIXME: this does not work with multiple inheritance.
}
- return 0;
+ return nullptr;
}
unsigned makeMCall(unsigned NumArgs, const CXXMethodDecl *D) {
- NodeVec.push_back(SExprNode(EOP_MCall, NumArgs, getFirstVirtualDecl(D)));
- return NodeVec.size()-1;
+ return make(EOP_MCall, NumArgs, getFirstVirtualDecl(D));
}
unsigned makeIndex() {
- NodeVec.push_back(SExprNode(EOP_Index, 0, 0));
- return NodeVec.size()-1;
+ return make(EOP_Index);
}
unsigned makeUnary() {
- NodeVec.push_back(SExprNode(EOP_Unary, 0, 0));
- return NodeVec.size()-1;
+ return make(EOP_Unary);
}
unsigned makeBinary() {
- NodeVec.push_back(SExprNode(EOP_Binary, 0, 0));
- return NodeVec.size()-1;
+ return make(EOP_Binary);
}
unsigned makeUnknown(unsigned Arity) {
- NodeVec.push_back(SExprNode(EOP_Unknown, Arity, 0));
- return NodeVec.size()-1;
+ return make(EOP_Unknown, Arity);
}
inline bool isCalleeArrow(const Expr *E) {
@@ -277,10 +270,10 @@ private:
/// ensure that the original expression is a valid mutex expression.
///
/// NDeref returns the number of Derefence and AddressOf operations
- /// preceeding the Expr; this is used to decide whether to pretty-print
+ /// preceding the Expr; this is used to decide whether to pretty-print
/// SExprs with . or ->.
- unsigned buildSExpr(const Expr *Exp, CallingContext* CallCtx,
- int* NDeref = 0) {
+ unsigned buildSExpr(const Expr *Exp, CallingContext *CallCtx,
+ int *NDeref = nullptr) {
if (!Exp)
return 0;
@@ -377,7 +370,7 @@ private:
}
}
unsigned NumCallArgs = CE->getNumArgs();
- unsigned Root = makeCall(NumCallArgs, 0);
+ unsigned Root = makeCall(NumCallArgs, nullptr);
unsigned Sz = buildSExpr(CE->getCallee(), CallCtx);
const Expr* const* CallArgs = CE->getArgs();
for (unsigned i = 0; i < NumCallArgs; ++i) {
@@ -470,7 +463,7 @@ private:
/// occurs.
/// \param D The declaration to which the lock/unlock attribute is attached.
void buildSExprFromExpr(const Expr *MutexExp, const Expr *DeclExp,
- const NamedDecl *D, VarDecl *SelfDecl = 0) {
+ const NamedDecl *D, VarDecl *SelfDecl = nullptr) {
CallingContext CallCtx(D);
if (MutexExp) {
@@ -487,8 +480,8 @@ private:
}
// If we are processing a raw attribute expression, with no substitutions.
- if (DeclExp == 0) {
- buildSExpr(MutexExp, 0);
+ if (!DeclExp) {
+ buildSExpr(MutexExp, nullptr);
return;
}
@@ -508,7 +501,7 @@ private:
CallCtx.FunArgs = CE->getArgs();
} else if (const CXXConstructExpr *CE =
dyn_cast<CXXConstructExpr>(DeclExp)) {
- CallCtx.SelfArg = 0; // Will be set below
+ CallCtx.SelfArg = nullptr; // Will be set below
CallCtx.NumArgs = CE->getNumArgs();
CallCtx.FunArgs = CE->getArgs();
} else if (D && isa<CXXDestructorDecl>(D)) {
@@ -524,16 +517,16 @@ private:
CallCtx.SelfArg = &SelfDRE;
// If the attribute has no arguments, then assume the argument is "this".
- if (MutexExp == 0)
- buildSExpr(CallCtx.SelfArg, 0);
+ if (!MutexExp)
+ buildSExpr(CallCtx.SelfArg, nullptr);
else // For most attributes.
buildSExpr(MutexExp, &CallCtx);
return;
}
// If the attribute has no arguments, then assume the argument is "this".
- if (MutexExp == 0)
- buildSExpr(CallCtx.SelfArg, 0);
+ if (!MutexExp)
+ buildSExpr(CallCtx.SelfArg, nullptr);
else // For most attributes.
buildSExpr(MutexExp, &CallCtx);
}
@@ -551,8 +544,8 @@ public:
/// occurs.
/// \param D The declaration to which the lock/unlock attribute is attached.
/// Caller must check isValid() after construction.
- SExpr(const Expr* MutexExp, const Expr *DeclExp, const NamedDecl* D,
- VarDecl *SelfDecl=0) {
+ SExpr(const Expr *MutexExp, const Expr *DeclExp, const NamedDecl *D,
+ VarDecl *SelfDecl = nullptr) {
buildSExprFromExpr(MutexExp, DeclExp, D, SelfDecl);
}
@@ -575,15 +568,15 @@ public:
/// Issue a warning about an invalid lock expression
static void warnInvalidLock(ThreadSafetyHandler &Handler,
- const Expr *MutexExp,
- const Expr *DeclExp, const NamedDecl* D) {
+ const Expr *MutexExp, const Expr *DeclExp,
+ const NamedDecl *D, StringRef Kind) {
SourceLocation Loc;
if (DeclExp)
Loc = DeclExp->getExprLoc();
// FIXME: add a note about the attribute location in MutexExp or D
if (Loc.isValid())
- Handler.handleInvalidLockExp(Loc);
+ Handler.handleInvalidLockExp(Kind, Loc);
}
bool operator==(const SExpr &other) const {
@@ -716,27 +709,16 @@ public:
}
};
-
-
/// \brief A short list of SExprs
class MutexIDList : public SmallVector<SExpr, 3> {
public:
- /// \brief Return true if the list contains the specified SExpr
- /// Performs a linear search, because these lists are almost always very small.
- bool contains(const SExpr& M) {
- for (iterator I=begin(),E=end(); I != E; ++I)
- if ((*I) == M) return true;
- return false;
- }
-
- /// \brief Push M onto list, bud discard duplicates
+ /// \brief Push M onto list, but discard duplicates.
void push_back_nodup(const SExpr& M) {
- if (!contains(M)) push_back(M);
+ if (end() == std::find(begin(), end(), M))
+ push_back(M);
}
};
-
-
/// \brief This is a helper class that stores info about the most recent
/// accquire of a Lock.
///
@@ -867,44 +849,37 @@ public:
return false;
}
- // Returns an iterator
iterator findLockIter(FactManager &FM, const SExpr &M) {
- for (iterator I = begin(), E = end(); I != E; ++I) {
- const SExpr &Exp = FM[*I].MutID;
- if (Exp.matches(M))
- return I;
- }
- return end();
+ return std::find_if(begin(), end(), [&](FactID ID) {
+ return FM[ID].MutID.matches(M);
+ });
}
- LockData* findLock(FactManager &FM, const SExpr &M) const {
- for (const_iterator I = begin(), E = end(); I != E; ++I) {
- const SExpr &Exp = FM[*I].MutID;
- if (Exp.matches(M))
- return &FM[*I].LDat;
- }
- return 0;
- }
+ LockData *findLock(FactManager &FM, const SExpr &M) const {
+ auto I = std::find_if(begin(), end(), [&](FactID ID) {
+ return FM[ID].MutID.matches(M);
+ });
- LockData* findLockUniv(FactManager &FM, const SExpr &M) const {
- for (const_iterator I = begin(), E = end(); I != E; ++I) {
- const SExpr &Exp = FM[*I].MutID;
- if (Exp.matches(M) || Exp.isUniversal())
- return &FM[*I].LDat;
- }
- return 0;
+ return I != end() ? &FM[*I].LDat : nullptr;
}
- FactEntry* findPartialMatch(FactManager &FM, const SExpr &M) const {
- for (const_iterator I=begin(), E=end(); I != E; ++I) {
- const SExpr& Exp = FM[*I].MutID;
- if (Exp.partiallyMatches(M)) return &FM[*I];
- }
- return 0;
+ LockData *findLockUniv(FactManager &FM, const SExpr &M) const {
+ auto I = std::find_if(begin(), end(), [&](FactID ID) -> bool {
+ const SExpr &Expr = FM[ID].MutID;
+ return Expr.isUniversal() || Expr.matches(M);
+ });
+
+ return I != end() ? &FM[*I].LDat : nullptr;
}
-};
+ FactEntry *findPartialMatch(FactManager &FM, const SExpr &M) const {
+ auto I = std::find_if(begin(), end(), [&](FactID ID) {
+ return FM[ID].MutID.partiallyMatches(M);
+ });
+ return I != end() ? &FM[*I] : nullptr;
+ }
+};
/// A Lockset maps each SExpr (defined above) to information about how it has
/// been locked.
@@ -987,7 +962,7 @@ public:
// Create reference to previous definition
VarDefinition(const NamedDecl *D, unsigned R, Context C)
- : Dec(D), Exp(0), Ref(R), Ctx(C)
+ : Dec(D), Exp(nullptr), Ref(R), Ctx(C)
{ }
};
@@ -1000,14 +975,14 @@ private:
public:
LocalVariableMap() {
// index 0 is a placeholder for undefined variables (aka phi-nodes).
- VarDefinitions.push_back(VarDefinition(0, 0u, getEmptyContext()));
+ VarDefinitions.push_back(VarDefinition(nullptr, 0u, getEmptyContext()));
}
/// Look up a definition, within the given context.
const VarDefinition* lookup(const NamedDecl *D, Context Ctx) {
const unsigned *i = Ctx.lookup(D);
if (!i)
- return 0;
+ return nullptr;
assert(*i < VarDefinitions.size());
return &VarDefinitions[*i];
}
@@ -1018,7 +993,7 @@ public:
const Expr* lookupExpr(const NamedDecl *D, Context &Ctx) {
const unsigned *P = Ctx.lookup(D);
if (!P)
- return 0;
+ return nullptr;
unsigned i = *P;
while (i > 0) {
@@ -1028,7 +1003,7 @@ public:
}
i = VarDefinitions[i].Ref;
}
- return 0;
+ return nullptr;
}
Context getEmptyContext() { return ContextFactory.getEmptyMap(); }
@@ -1088,8 +1063,8 @@ public:
}
/// Builds the variable map.
- void traverseCFG(CFG *CFGraph, PostOrderCFGView *SortedGraph,
- std::vector<CFGBlockInfo> &BlockInfo);
+ void traverseCFG(CFG *CFGraph, const PostOrderCFGView *SortedGraph,
+ std::vector<CFGBlockInfo> &BlockInfo);
protected:
// Get the current context index
@@ -1102,7 +1077,7 @@ protected:
// Adds a new definition to the given context, and returns a new context.
// This method should be called when declaring a new variable.
- Context addDefinition(const NamedDecl *D, Expr *Exp, Context Ctx) {
+ Context addDefinition(const NamedDecl *D, const Expr *Exp, Context Ctx) {
assert(!Ctx.contains(D));
unsigned newID = VarDefinitions.size();
Context NewCtx = ContextFactory.add(Ctx, D, newID);
@@ -1183,9 +1158,9 @@ public:
void VarMapBuilder::VisitDeclStmt(DeclStmt *S) {
bool modifiedCtx = false;
DeclGroupRef DGrp = S->getDeclGroup();
- for (DeclGroupRef::iterator I = DGrp.begin(), E = DGrp.end(); I != E; ++I) {
- if (VarDecl *VD = dyn_cast_or_null<VarDecl>(*I)) {
- Expr *E = VD->getInit();
+ for (const auto *D : DGrp) {
+ if (const auto *VD = dyn_cast_or_null<VarDecl>(D)) {
+ const Expr *E = VD->getInit();
// Add local variables with trivial type to the variable map
QualType T = VD->getType();
@@ -1227,13 +1202,12 @@ void VarMapBuilder::VisitBinaryOperator(BinaryOperator *BO) {
LocalVariableMap::Context
LocalVariableMap::intersectContexts(Context C1, Context C2) {
Context Result = C1;
- for (Context::iterator I = C1.begin(), E = C1.end(); I != E; ++I) {
- const NamedDecl *Dec = I.getKey();
- unsigned i1 = I.getData();
+ for (const auto &P : C1) {
+ const NamedDecl *Dec = P.first;
const unsigned *i2 = C2.lookup(Dec);
if (!i2) // variable doesn't exist on second path
Result = removeDefinition(Dec, Result);
- else if (*i2 != i1) // variable exists, but has different definition
+ else if (*i2 != P.second) // variable exists, but has different definition
Result = clearDefinition(Dec, Result);
}
return Result;
@@ -1244,11 +1218,8 @@ LocalVariableMap::intersectContexts(Context C1, Context C2) {
// (We use this for a naive implementation of SSA on loop back-edges.)
LocalVariableMap::Context LocalVariableMap::createReferenceContext(Context C) {
Context Result = getEmptyContext();
- for (Context::iterator I = C.begin(), E = C.end(); I != E; ++I) {
- const NamedDecl *Dec = I.getKey();
- unsigned i = I.getData();
- Result = addReference(Dec, i, Result);
- }
+ for (const auto &P : C)
+ Result = addReference(P.first, P.second, Result);
return Result;
}
@@ -1256,13 +1227,12 @@ LocalVariableMap::Context LocalVariableMap::createReferenceContext(Context C) {
// altering the VarDefinitions. C1 must be the result of an earlier call to
// createReferenceContext.
void LocalVariableMap::intersectBackEdge(Context C1, Context C2) {
- for (Context::iterator I = C1.begin(), E = C1.end(); I != E; ++I) {
- const NamedDecl *Dec = I.getKey();
- unsigned i1 = I.getData();
+ for (const auto &P : C1) {
+ unsigned i1 = P.second;
VarDefinition *VDef = &VarDefinitions[i1];
assert(VDef->isReference());
- const unsigned *i2 = C2.lookup(Dec);
+ const unsigned *i2 = C2.lookup(P.first);
if (!i2 || (*i2 != i1))
VDef->Ref = 0; // Mark this variable as undefined
}
@@ -1308,15 +1278,13 @@ void LocalVariableMap::intersectBackEdge(Context C1, Context C2) {
// ... { y -> y1 | x3 = 2, x2 = 1, ... }
//
void LocalVariableMap::traverseCFG(CFG *CFGraph,
- PostOrderCFGView *SortedGraph,
+ const PostOrderCFGView *SortedGraph,
std::vector<CFGBlockInfo> &BlockInfo) {
PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
CtxIndices.resize(CFGraph->getNumBlockIDs());
- for (PostOrderCFGView::iterator I = SortedGraph->begin(),
- E = SortedGraph->end(); I!= E; ++I) {
- const CFGBlock *CurrBlock = *I;
+ for (const auto *CurrBlock : *SortedGraph) {
int CurrBlockID = CurrBlock->getBlockID();
CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
@@ -1328,7 +1296,7 @@ void LocalVariableMap::traverseCFG(CFG *CFGraph,
for (CFGBlock::const_pred_iterator PI = CurrBlock->pred_begin(),
PE = CurrBlock->pred_end(); PI != PE; ++PI) {
// if *PI -> CurrBlock is a back edge, so skip it
- if (*PI == 0 || !VisitedBlocks.alreadySet(*PI)) {
+ if (*PI == nullptr || !VisitedBlocks.alreadySet(*PI)) {
HasBackEdges = true;
continue;
}
@@ -1354,7 +1322,7 @@ void LocalVariableMap::traverseCFG(CFG *CFGraph,
createReferenceContext(CurrBlockInfo->EntryContext);
// Create a starting context index for the current block
- saveContext(0, CurrBlockInfo->EntryContext);
+ saveContext(nullptr, CurrBlockInfo->EntryContext);
CurrBlockInfo->EntryIndex = getContextIndex();
// Visit all the statements in the basic block.
@@ -1377,7 +1345,7 @@ void LocalVariableMap::traverseCFG(CFG *CFGraph,
for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
SE = CurrBlock->succ_end(); SI != SE; ++SI) {
// if CurrBlock -> *SI is *not* a back edge
- if (*SI == 0 || !VisitedBlocks.alreadySet(*SI))
+ if (*SI == nullptr || !VisitedBlocks.alreadySet(*SI))
continue;
CFGBlock *FirstLoopBlock = *SI;
@@ -1389,17 +1357,15 @@ void LocalVariableMap::traverseCFG(CFG *CFGraph,
// Put an extra entry at the end of the indexed context array
unsigned exitID = CFGraph->getExit().getBlockID();
- saveContext(0, BlockInfo[exitID].ExitContext);
+ saveContext(nullptr, BlockInfo[exitID].ExitContext);
}
/// Find the appropriate source locations to use when producing diagnostics for
/// each block in the CFG.
static void findBlockLocations(CFG *CFGraph,
- PostOrderCFGView *SortedGraph,
+ const PostOrderCFGView *SortedGraph,
std::vector<CFGBlockInfo> &BlockInfo) {
- for (PostOrderCFGView::iterator I = SortedGraph->begin(),
- E = SortedGraph->end(); I!= E; ++I) {
- const CFGBlock *CurrBlock = *I;
+ for (const auto *CurrBlock : *SortedGraph) {
CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlock->getBlockID()];
// Find the source location of the last statement in the block, if the
@@ -1450,13 +1416,14 @@ class ThreadSafetyAnalyzer {
public:
ThreadSafetyAnalyzer(ThreadSafetyHandler &H) : Handler(H) {}
- void addLock(FactSet &FSet, const SExpr &Mutex, const LockData &LDat);
- void removeLock(FactSet &FSet, const SExpr &Mutex,
- SourceLocation UnlockLoc, bool FullyRemove=false);
+ void addLock(FactSet &FSet, const SExpr &Mutex, const LockData &LDat,
+ StringRef DiagKind);
+ void removeLock(FactSet &FSet, const SExpr &Mutex, SourceLocation UnlockLoc,
+ bool FullyRemove, LockKind Kind, StringRef DiagKind);
template <typename AttrType>
void getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, Expr *Exp,
- const NamedDecl *D, VarDecl *SelfDecl=0);
+ const NamedDecl *D, VarDecl *SelfDecl = nullptr);
template <class AttrType>
void getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, Expr *Exp,
@@ -1485,12 +1452,89 @@ public:
void runAnalysis(AnalysisDeclContext &AC);
};
+/// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs.
+static const ValueDecl *getValueDecl(const Expr *Exp) {
+ if (const auto *CE = dyn_cast<ImplicitCastExpr>(Exp))
+ return getValueDecl(CE->getSubExpr());
+
+ if (const auto *DR = dyn_cast<DeclRefExpr>(Exp))
+ return DR->getDecl();
+
+ if (const auto *ME = dyn_cast<MemberExpr>(Exp))
+ return ME->getMemberDecl();
+
+ return nullptr;
+}
+
+template <typename Ty>
+class has_arg_iterator_range {
+ typedef char yes[1];
+ typedef char no[2];
+
+ template <typename Inner>
+ static yes& test(Inner *I, decltype(I->args()) * = nullptr);
+
+ template <typename>
+ static no& test(...);
+
+public:
+ static const bool value = sizeof(test<Ty>(nullptr)) == sizeof(yes);
+};
+
+static StringRef ClassifyDiagnostic(const CapabilityAttr *A) {
+ return A->getName();
+}
+
+static StringRef ClassifyDiagnostic(QualType VDT) {
+ // We need to look at the declaration of the type of the value to determine
+ // which it is. The type should either be a record or a typedef, or a pointer
+ // or reference thereof.
+ if (const auto *RT = VDT->getAs<RecordType>()) {
+ if (const auto *RD = RT->getDecl())
+ if (const auto *CA = RD->getAttr<CapabilityAttr>())
+ return ClassifyDiagnostic(CA);
+ } else if (const auto *TT = VDT->getAs<TypedefType>()) {
+ if (const auto *TD = TT->getDecl())
+ if (const auto *CA = TD->getAttr<CapabilityAttr>())
+ return ClassifyDiagnostic(CA);
+ } else if (VDT->isPointerType() || VDT->isReferenceType())
+ return ClassifyDiagnostic(VDT->getPointeeType());
+
+ return "mutex";
+}
+
+static StringRef ClassifyDiagnostic(const ValueDecl *VD) {
+ assert(VD && "No ValueDecl passed");
+
+ // The ValueDecl is the declaration of a mutex or role (hopefully).
+ return ClassifyDiagnostic(VD->getType());
+}
+
+template <typename AttrTy>
+static typename std::enable_if<!has_arg_iterator_range<AttrTy>::value,
+ StringRef>::type
+ClassifyDiagnostic(const AttrTy *A) {
+ if (const ValueDecl *VD = getValueDecl(A->getArg()))
+ return ClassifyDiagnostic(VD);
+ return "mutex";
+}
+
+template <typename AttrTy>
+static typename std::enable_if<has_arg_iterator_range<AttrTy>::value,
+ StringRef>::type
+ClassifyDiagnostic(const AttrTy *A) {
+ for (const auto *Arg : A->args()) {
+ if (const ValueDecl *VD = getValueDecl(Arg))
+ return ClassifyDiagnostic(VD);
+ }
+ return "mutex";
+}
/// \brief Add a new lock to the lockset, warning if the lock is already there.
/// \param Mutex -- the Mutex expression for the lock
/// \param LDat -- the LockData for the lock
void ThreadSafetyAnalyzer::addLock(FactSet &FSet, const SExpr &Mutex,
- const LockData &LDat) {
+ const LockData &LDat, StringRef DiagKind) {
// FIXME: deal with acquired before/after annotations.
// FIXME: Don't always warn when we have support for reentrant locks.
if (Mutex.shouldIgnore())
@@ -1498,7 +1542,7 @@ void ThreadSafetyAnalyzer::addLock(FactSet &FSet, const SExpr &Mutex,
if (FSet.findLock(FactMan, Mutex)) {
if (!LDat.Asserted)
- Handler.handleDoubleLock(Mutex.toString(), LDat.AcquireLoc);
+ Handler.handleDoubleLock(DiagKind, Mutex.toString(), LDat.AcquireLoc);
} else {
FSet.addLock(FactMan, Mutex, LDat);
}
@@ -1508,16 +1552,24 @@ void ThreadSafetyAnalyzer::addLock(FactSet &FSet, const SExpr &Mutex,
/// \brief Remove a lock from the lockset, warning if the lock is not there.
/// \param Mutex The lock expression corresponding to the lock to be removed
/// \param UnlockLoc The source location of the unlock (only used in error msg)
-void ThreadSafetyAnalyzer::removeLock(FactSet &FSet,
- const SExpr &Mutex,
+void ThreadSafetyAnalyzer::removeLock(FactSet &FSet, const SExpr &Mutex,
SourceLocation UnlockLoc,
- bool FullyRemove) {
+ bool FullyRemove, LockKind ReceivedKind,
+ StringRef DiagKind) {
if (Mutex.shouldIgnore())
return;
const LockData *LDat = FSet.findLock(FactMan, Mutex);
if (!LDat) {
- Handler.handleUnmatchedUnlock(Mutex.toString(), UnlockLoc);
+ Handler.handleUnmatchedUnlock(DiagKind, Mutex.toString(), UnlockLoc);
+ return;
+ }
+
+ // Generic lock removal doesn't care about lock kind mismatches, but
+ // otherwise diagnose when the lock kinds are mismatched.
+ if (ReceivedKind != LK_Generic && LDat->LKind != ReceivedKind) {
+ Handler.handleIncorrectUnlockKind(DiagKind, Mutex.toString(), LDat->LKind,
+ ReceivedKind, UnlockLoc);
return;
}
@@ -1532,8 +1584,8 @@ void ThreadSafetyAnalyzer::removeLock(FactSet &FSet,
// We're releasing the underlying mutex, but not destroying the
// managing object. Warn on dual release.
if (!FSet.findLock(FactMan, LDat->UnderlyingMutex)) {
- Handler.handleUnmatchedUnlock(LDat->UnderlyingMutex.toString(),
- UnlockLoc);
+ Handler.handleUnmatchedUnlock(
+ DiagKind, LDat->UnderlyingMutex.toString(), UnlockLoc);
}
FSet.removeLock(FactMan, LDat->UnderlyingMutex);
return;
@@ -1549,22 +1601,21 @@ template <typename AttrType>
void ThreadSafetyAnalyzer::getMutexIDs(MutexIDList &Mtxs, AttrType *Attr,
Expr *Exp, const NamedDecl *D,
VarDecl *SelfDecl) {
- typedef typename AttrType::args_iterator iterator_type;
-
if (Attr->args_size() == 0) {
// The mutex held is the "this" object.
- SExpr Mu(0, Exp, D, SelfDecl);
+ SExpr Mu(nullptr, Exp, D, SelfDecl);
if (!Mu.isValid())
- SExpr::warnInvalidLock(Handler, 0, Exp, D);
+ SExpr::warnInvalidLock(Handler, nullptr, Exp, D,
+ ClassifyDiagnostic(Attr));
else
Mtxs.push_back_nodup(Mu);
return;
}
- for (iterator_type I=Attr->args_begin(), E=Attr->args_end(); I != E; ++I) {
- SExpr Mu(*I, Exp, D, SelfDecl);
+ for (const auto *Arg : Attr->args()) {
+ SExpr Mu(Arg, Exp, D, SelfDecl);
if (!Mu.isValid())
- SExpr::warnInvalidLock(Handler, *I, Exp, D);
+ SExpr::warnInvalidLock(Handler, Arg, Exp, D, ClassifyDiagnostic(Attr));
else
Mtxs.push_back_nodup(Mu);
}
@@ -1581,23 +1632,22 @@ void ThreadSafetyAnalyzer::getMutexIDs(MutexIDList &Mtxs, AttrType *Attr,
const CFGBlock *CurrBlock,
Expr *BrE, bool Neg) {
// Find out which branch has the lock
- bool branch = 0;
- if (CXXBoolLiteralExpr *BLE = dyn_cast_or_null<CXXBoolLiteralExpr>(BrE)) {
+ bool branch = false;
+ if (CXXBoolLiteralExpr *BLE = dyn_cast_or_null<CXXBoolLiteralExpr>(BrE))
branch = BLE->getValue();
- }
- else if (IntegerLiteral *ILE = dyn_cast_or_null<IntegerLiteral>(BrE)) {
+ else if (IntegerLiteral *ILE = dyn_cast_or_null<IntegerLiteral>(BrE))
branch = ILE->getValue().getBoolValue();
- }
+
int branchnum = branch ? 0 : 1;
- if (Neg) branchnum = !branchnum;
+ if (Neg)
+ branchnum = !branchnum;
// If we've taken the trylock branch, then add the lock
int i = 0;
for (CFGBlock::const_succ_iterator SI = PredBlock->succ_begin(),
SE = PredBlock->succ_end(); SI != SE && i < 2; ++SI, ++i) {
- if (*SI == CurrBlock && i == branchnum) {
+ if (*SI == CurrBlock && i == branchnum)
getMutexIDs(Mtxs, Attr, Exp, D);
- }
}
}
@@ -1626,7 +1676,7 @@ const CallExpr* ThreadSafetyAnalyzer::getTrylockCallExpr(const Stmt *Cond,
LocalVarContext C,
bool &Negate) {
if (!Cond)
- return 0;
+ return nullptr;
if (const CallExpr *CallExp = dyn_cast<CallExpr>(Cond)) {
return CallExp;
@@ -1649,7 +1699,7 @@ const CallExpr* ThreadSafetyAnalyzer::getTrylockCallExpr(const Stmt *Cond,
Negate = !Negate;
return getTrylockCallExpr(UOP->getSubExpr(), C, Negate);
}
- return 0;
+ return nullptr;
}
else if (const BinaryOperator *BOP = dyn_cast<BinaryOperator>(Cond)) {
if (BOP->getOpcode() == BO_EQ || BOP->getOpcode() == BO_NE) {
@@ -1666,7 +1716,7 @@ const CallExpr* ThreadSafetyAnalyzer::getTrylockCallExpr(const Stmt *Cond,
if (!TCond) Negate = !Negate;
return getTrylockCallExpr(BOP->getRHS(), C, Negate);
}
- return 0;
+ return nullptr;
}
if (BOP->getOpcode() == BO_LAnd) {
// LHS must have been evaluated in a different block.
@@ -1675,9 +1725,9 @@ const CallExpr* ThreadSafetyAnalyzer::getTrylockCallExpr(const Stmt *Cond,
if (BOP->getOpcode() == BO_LOr) {
return getTrylockCallExpr(BOP->getRHS(), C, Negate);
}
- return 0;
+ return nullptr;
}
- return 0;
+ return nullptr;
}
@@ -1697,6 +1747,7 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result,
bool Negate = false;
const CFGBlockInfo *PredBlockInfo = &BlockInfo[PredBlock->getBlockID()];
const LocalVarContext &LVarCtx = PredBlockInfo->ExitContext;
+ StringRef CapDiagKind = "mutex";
CallExpr *Exp =
const_cast<CallExpr*>(getTrylockCallExpr(Cond, LVarCtx, Negate));
@@ -1711,15 +1762,14 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result,
MutexIDList SharedLocksToAdd;
// If the condition is a call to a Trylock function, then grab the attributes
- AttrVec &ArgAttrs = FunDecl->getAttrs();
- for (unsigned i = 0; i < ArgAttrs.size(); ++i) {
- Attr *Attr = ArgAttrs[i];
+ for (auto *Attr : FunDecl->getAttrs()) {
switch (Attr->getKind()) {
case attr::ExclusiveTrylockFunction: {
ExclusiveTrylockFunctionAttr *A =
cast<ExclusiveTrylockFunctionAttr>(Attr);
getMutexIDs(ExclusiveLocksToAdd, A, Exp, FunDecl,
PredBlock, CurrBlock, A->getSuccessValue(), Negate);
+ CapDiagKind = ClassifyDiagnostic(A);
break;
}
case attr::SharedTrylockFunction: {
@@ -1727,6 +1777,7 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result,
cast<SharedTrylockFunctionAttr>(Attr);
getMutexIDs(SharedLocksToAdd, A, Exp, FunDecl,
PredBlock, CurrBlock, A->getSuccessValue(), Negate);
+ CapDiagKind = ClassifyDiagnostic(A);
break;
}
default:
@@ -1736,17 +1787,13 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result,
// Add and remove locks.
SourceLocation Loc = Exp->getExprLoc();
- for (unsigned i=0,n=ExclusiveLocksToAdd.size(); i<n; ++i) {
- addLock(Result, ExclusiveLocksToAdd[i],
- LockData(Loc, LK_Exclusive));
- }
- for (unsigned i=0,n=SharedLocksToAdd.size(); i<n; ++i) {
- addLock(Result, SharedLocksToAdd[i],
- LockData(Loc, LK_Shared));
- }
+ for (const auto &ExclusiveLockToAdd : ExclusiveLocksToAdd)
+ addLock(Result, ExclusiveLockToAdd, LockData(Loc, LK_Exclusive),
+ CapDiagKind);
+ for (const auto &SharedLockToAdd : SharedLocksToAdd)
+ addLock(Result, SharedLockToAdd, LockData(Loc, LK_Shared), CapDiagKind);
}
-
/// \brief We use this class to visit different types of expressions in
/// CFGBlocks, and build up the lockset.
/// An expression may cause us to add or remove locks from the lockset, or else
@@ -1761,16 +1808,17 @@ class BuildLockset : public StmtVisitor<BuildLockset> {
unsigned CtxIndex;
// Helper functions
- const ValueDecl *getValueDecl(const Expr *Exp);
void warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp, AccessKind AK,
- Expr *MutexExp, ProtectedOperationKind POK);
- void warnIfMutexHeld(const NamedDecl *D, const Expr *Exp, Expr *MutexExp);
+ Expr *MutexExp, ProtectedOperationKind POK,
+ StringRef DiagKind);
+ void warnIfMutexHeld(const NamedDecl *D, const Expr *Exp, Expr *MutexExp,
+ StringRef DiagKind);
void checkAccess(const Expr *Exp, AccessKind AK);
void checkPtAccess(const Expr *Exp, AccessKind AK);
- void handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD = 0);
+ void handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD = nullptr);
public:
BuildLockset(ThreadSafetyAnalyzer *Anlzr, CFGBlockInfo &Info)
@@ -1789,31 +1837,17 @@ public:
void VisitDeclStmt(DeclStmt *S);
};
-
-/// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs
-const ValueDecl *BuildLockset::getValueDecl(const Expr *Exp) {
- if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(Exp))
- return getValueDecl(CE->getSubExpr());
-
- if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Exp))
- return DR->getDecl();
-
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp))
- return ME->getMemberDecl();
-
- return 0;
-}
-
/// \brief Warn if the LSet does not contain a lock sufficient to protect access
/// of at least the passed in AccessKind.
void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp,
AccessKind AK, Expr *MutexExp,
- ProtectedOperationKind POK) {
+ ProtectedOperationKind POK,
+ StringRef DiagKind) {
LockKind LK = getLockKindFromAccessKind(AK);
SExpr Mutex(MutexExp, Exp, D);
if (!Mutex.isValid()) {
- SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D);
+ SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D, DiagKind);
return;
} else if (Mutex.shouldIgnore()) {
return;
@@ -1829,40 +1863,38 @@ void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp,
LDat = &FEntry->LDat;
std::string PartMatchStr = FEntry->MutID.toString();
StringRef PartMatchName(PartMatchStr);
- Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK,
- Exp->getExprLoc(), &PartMatchName);
+ Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Mutex.toString(),
+ LK, Exp->getExprLoc(),
+ &PartMatchName);
} else {
// Warn that there's no match at all.
- Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK,
- Exp->getExprLoc());
+ Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Mutex.toString(),
+ LK, Exp->getExprLoc());
}
NoError = false;
}
// Make sure the mutex we found is the right kind.
if (NoError && LDat && !LDat->isAtLeast(LK))
- Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK,
+ Analyzer->Handler.handleMutexNotHeld(DiagKind, D, POK, Mutex.toString(), LK,
Exp->getExprLoc());
}
/// \brief Warn if the LSet contains the given lock.
-void BuildLockset::warnIfMutexHeld(const NamedDecl *D, const Expr* Exp,
- Expr *MutexExp) {
+void BuildLockset::warnIfMutexHeld(const NamedDecl *D, const Expr *Exp,
+ Expr *MutexExp,
+ StringRef DiagKind) {
SExpr Mutex(MutexExp, Exp, D);
if (!Mutex.isValid()) {
- SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D);
+ SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D, DiagKind);
return;
}
LockData* LDat = FSet.findLock(Analyzer->FactMan, Mutex);
- if (LDat) {
- std::string DeclName = D->getNameAsString();
- StringRef DeclNameSR (DeclName);
- Analyzer->Handler.handleFunExcludesLock(DeclNameSR, Mutex.toString(),
- Exp->getExprLoc());
- }
+ if (LDat)
+ Analyzer->Handler.handleFunExcludesLock(
+ DiagKind, D->getNameAsString(), Mutex.toString(), Exp->getExprLoc());
}
-
/// \brief Checks guarded_by and pt_guarded_by attributes.
/// Whenever we identify an access (read or write) to a DeclRefExpr that is
/// marked with guarded_by, we must ensure the appropriate mutexes are held.
@@ -1879,10 +1911,8 @@ void BuildLockset::checkAccess(const Expr *Exp, AccessKind AK) {
}
if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(Exp)) {
- if (Analyzer->Handler.issueBetaWarnings()) {
- checkPtAccess(AE->getLHS(), AK);
- return;
- }
+ checkPtAccess(AE->getLHS(), AK);
+ return;
}
if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
@@ -1896,55 +1926,48 @@ void BuildLockset::checkAccess(const Expr *Exp, AccessKind AK) {
if (!D || !D->hasAttrs())
return;
- if (D->getAttr<GuardedVarAttr>() && FSet.isEmpty())
- Analyzer->Handler.handleNoMutexHeld(D, POK_VarAccess, AK,
+ if (D->hasAttr<GuardedVarAttr>() && FSet.isEmpty())
+ Analyzer->Handler.handleNoMutexHeld("mutex", D, POK_VarAccess, AK,
Exp->getExprLoc());
- const AttrVec &ArgAttrs = D->getAttrs();
- for (unsigned i = 0, Size = ArgAttrs.size(); i < Size; ++i)
- if (GuardedByAttr *GBAttr = dyn_cast<GuardedByAttr>(ArgAttrs[i]))
- warnIfMutexNotHeld(D, Exp, AK, GBAttr->getArg(), POK_VarAccess);
+ for (const auto *I : D->specific_attrs<GuardedByAttr>())
+ warnIfMutexNotHeld(D, Exp, AK, I->getArg(), POK_VarAccess,
+ ClassifyDiagnostic(I));
}
/// \brief Checks pt_guarded_by and pt_guarded_var attributes.
void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK) {
- if (Analyzer->Handler.issueBetaWarnings()) {
- while (true) {
- if (const ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) {
- Exp = PE->getSubExpr();
- continue;
- }
- if (const CastExpr *CE = dyn_cast<CastExpr>(Exp)) {
- if (CE->getCastKind() == CK_ArrayToPointerDecay) {
- // If it's an actual array, and not a pointer, then it's elements
- // are protected by GUARDED_BY, not PT_GUARDED_BY;
- checkAccess(CE->getSubExpr(), AK);
- return;
- }
- Exp = CE->getSubExpr();
- continue;
+ while (true) {
+ if (const ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) {
+ Exp = PE->getSubExpr();
+ continue;
+ }
+ if (const CastExpr *CE = dyn_cast<CastExpr>(Exp)) {
+ if (CE->getCastKind() == CK_ArrayToPointerDecay) {
+ // If it's an actual array, and not a pointer, then it's elements
+ // are protected by GUARDED_BY, not PT_GUARDED_BY;
+ checkAccess(CE->getSubExpr(), AK);
+ return;
}
- break;
+ Exp = CE->getSubExpr();
+ continue;
}
+ break;
}
- else
- Exp = Exp->IgnoreParenCasts();
const ValueDecl *D = getValueDecl(Exp);
if (!D || !D->hasAttrs())
return;
- if (D->getAttr<PtGuardedVarAttr>() && FSet.isEmpty())
- Analyzer->Handler.handleNoMutexHeld(D, POK_VarDereference, AK,
+ if (D->hasAttr<PtGuardedVarAttr>() && FSet.isEmpty())
+ Analyzer->Handler.handleNoMutexHeld("mutex", D, POK_VarDereference, AK,
Exp->getExprLoc());
- const AttrVec &ArgAttrs = D->getAttrs();
- for (unsigned i = 0, Size = ArgAttrs.size(); i < Size; ++i)
- if (PtGuardedByAttr *GBAttr = dyn_cast<PtGuardedByAttr>(ArgAttrs[i]))
- warnIfMutexNotHeld(D, Exp, AK, GBAttr->getArg(), POK_VarDereference);
+ for (auto const *I : D->specific_attrs<PtGuardedByAttr>())
+ warnIfMutexNotHeld(D, Exp, AK, I->getArg(), POK_VarDereference,
+ ClassifyDiagnostic(I));
}
-
/// \brief Process a function call, method call, constructor call,
/// or destructor call. This involves looking at the attributes on the
/// corresponding function/method/constructor/destructor, issuing warnings,
@@ -1958,26 +1981,22 @@ void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK) {
void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
SourceLocation Loc = Exp->getExprLoc();
const AttrVec &ArgAttrs = D->getAttrs();
- MutexIDList ExclusiveLocksToAdd;
- MutexIDList SharedLocksToAdd;
- MutexIDList LocksToRemove;
+ MutexIDList ExclusiveLocksToAdd, SharedLocksToAdd;
+ MutexIDList ExclusiveLocksToRemove, SharedLocksToRemove, GenericLocksToRemove;
+ StringRef CapDiagKind = "mutex";
for(unsigned i = 0; i < ArgAttrs.size(); ++i) {
Attr *At = const_cast<Attr*>(ArgAttrs[i]);
switch (At->getKind()) {
- // When we encounter an exclusive lock function, we need to add the lock
- // to our lockset with kind exclusive.
- case attr::ExclusiveLockFunction: {
- ExclusiveLockFunctionAttr *A = cast<ExclusiveLockFunctionAttr>(At);
- Analyzer->getMutexIDs(ExclusiveLocksToAdd, A, Exp, D, VD);
- break;
- }
-
- // When we encounter a shared lock function, we need to add the lock
- // to our lockset with kind shared.
- case attr::SharedLockFunction: {
- SharedLockFunctionAttr *A = cast<SharedLockFunctionAttr>(At);
- Analyzer->getMutexIDs(SharedLocksToAdd, A, Exp, D, VD);
+ // When we encounter a lock function, we need to add the lock to our
+ // lockset.
+ case attr::AcquireCapability: {
+ auto *A = cast<AcquireCapabilityAttr>(At);
+ Analyzer->getMutexIDs(A->isShared() ? SharedLocksToAdd
+ : ExclusiveLocksToAdd,
+ A, Exp, D, VD);
+
+ CapDiagKind = ClassifyDiagnostic(A);
break;
}
@@ -1989,10 +2008,10 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
MutexIDList AssertLocks;
Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
- for (unsigned i=0,n=AssertLocks.size(); i<n; ++i) {
- Analyzer->addLock(FSet, AssertLocks[i],
- LockData(Loc, LK_Exclusive, false, true));
- }
+ for (const auto &AssertLock : AssertLocks)
+ Analyzer->addLock(FSet, AssertLock,
+ LockData(Loc, LK_Exclusive, false, true),
+ ClassifyDiagnostic(A));
break;
}
case attr::AssertSharedLock: {
@@ -2000,50 +2019,44 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
MutexIDList AssertLocks;
Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
- for (unsigned i=0,n=AssertLocks.size(); i<n; ++i) {
- Analyzer->addLock(FSet, AssertLocks[i],
- LockData(Loc, LK_Shared, false, true));
- }
+ for (const auto &AssertLock : AssertLocks)
+ Analyzer->addLock(FSet, AssertLock,
+ LockData(Loc, LK_Shared, false, true),
+ ClassifyDiagnostic(A));
break;
}
// When we encounter an unlock function, we need to remove unlocked
// mutexes from the lockset, and flag a warning if they are not there.
- case attr::UnlockFunction: {
- UnlockFunctionAttr *A = cast<UnlockFunctionAttr>(At);
- Analyzer->getMutexIDs(LocksToRemove, A, Exp, D, VD);
- break;
- }
-
- case attr::ExclusiveLocksRequired: {
- ExclusiveLocksRequiredAttr *A = cast<ExclusiveLocksRequiredAttr>(At);
+ case attr::ReleaseCapability: {
+ auto *A = cast<ReleaseCapabilityAttr>(At);
+ if (A->isGeneric())
+ Analyzer->getMutexIDs(GenericLocksToRemove, A, Exp, D, VD);
+ else if (A->isShared())
+ Analyzer->getMutexIDs(SharedLocksToRemove, A, Exp, D, VD);
+ else
+ Analyzer->getMutexIDs(ExclusiveLocksToRemove, A, Exp, D, VD);
- for (ExclusiveLocksRequiredAttr::args_iterator
- I = A->args_begin(), E = A->args_end(); I != E; ++I)
- warnIfMutexNotHeld(D, Exp, AK_Written, *I, POK_FunctionCall);
+ CapDiagKind = ClassifyDiagnostic(A);
break;
}
- case attr::SharedLocksRequired: {
- SharedLocksRequiredAttr *A = cast<SharedLocksRequiredAttr>(At);
-
- for (SharedLocksRequiredAttr::args_iterator I = A->args_begin(),
- E = A->args_end(); I != E; ++I)
- warnIfMutexNotHeld(D, Exp, AK_Read, *I, POK_FunctionCall);
+ case attr::RequiresCapability: {
+ RequiresCapabilityAttr *A = cast<RequiresCapabilityAttr>(At);
+ for (auto *Arg : A->args())
+ warnIfMutexNotHeld(D, Exp, A->isShared() ? AK_Read : AK_Written, Arg,
+ POK_FunctionCall, ClassifyDiagnostic(A));
break;
}
case attr::LocksExcluded: {
LocksExcludedAttr *A = cast<LocksExcludedAttr>(At);
-
- for (LocksExcludedAttr::args_iterator I = A->args_begin(),
- E = A->args_end(); I != E; ++I) {
- warnIfMutexHeld(D, Exp, *I);
- }
+ for (auto *Arg : A->args())
+ warnIfMutexHeld(D, Exp, Arg, ClassifyDiagnostic(A));
break;
}
- // Ignore other (non thread-safety) attributes
+ // Ignore attributes unrelated to thread-safety
default:
break;
}
@@ -2054,44 +2067,43 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
if (VD) {
if (const CXXConstructorDecl *CD = dyn_cast<const CXXConstructorDecl>(D)) {
const CXXRecordDecl* PD = CD->getParent();
- if (PD && PD->getAttr<ScopedLockableAttr>())
+ if (PD && PD->hasAttr<ScopedLockableAttr>())
isScopedVar = true;
}
}
// Add locks.
- for (unsigned i=0,n=ExclusiveLocksToAdd.size(); i<n; ++i) {
- Analyzer->addLock(FSet, ExclusiveLocksToAdd[i],
- LockData(Loc, LK_Exclusive, isScopedVar));
- }
- for (unsigned i=0,n=SharedLocksToAdd.size(); i<n; ++i) {
- Analyzer->addLock(FSet, SharedLocksToAdd[i],
- LockData(Loc, LK_Shared, isScopedVar));
- }
+ for (const auto &M : ExclusiveLocksToAdd)
+ Analyzer->addLock(FSet, M, LockData(Loc, LK_Exclusive, isScopedVar),
+ CapDiagKind);
+ for (const auto &M : SharedLocksToAdd)
+ Analyzer->addLock(FSet, M, LockData(Loc, LK_Shared, isScopedVar),
+ CapDiagKind);
// Add the managing object as a dummy mutex, mapped to the underlying mutex.
// FIXME -- this doesn't work if we acquire multiple locks.
if (isScopedVar) {
SourceLocation MLoc = VD->getLocation();
DeclRefExpr DRE(VD, false, VD->getType(), VK_LValue, VD->getLocation());
- SExpr SMutex(&DRE, 0, 0);
+ SExpr SMutex(&DRE, nullptr, nullptr);
- for (unsigned i=0,n=ExclusiveLocksToAdd.size(); i<n; ++i) {
- Analyzer->addLock(FSet, SMutex, LockData(MLoc, LK_Exclusive,
- ExclusiveLocksToAdd[i]));
- }
- for (unsigned i=0,n=SharedLocksToAdd.size(); i<n; ++i) {
- Analyzer->addLock(FSet, SMutex, LockData(MLoc, LK_Shared,
- SharedLocksToAdd[i]));
- }
+ for (const auto &M : ExclusiveLocksToAdd)
+ Analyzer->addLock(FSet, SMutex, LockData(MLoc, LK_Exclusive, M),
+ CapDiagKind);
+ for (const auto &M : SharedLocksToAdd)
+ Analyzer->addLock(FSet, SMutex, LockData(MLoc, LK_Shared, M),
+ CapDiagKind);
}
// Remove locks.
// FIXME -- should only fully remove if the attribute refers to 'this'.
bool Dtor = isa<CXXDestructorDecl>(D);
- for (unsigned i=0,n=LocksToRemove.size(); i<n; ++i) {
- Analyzer->removeLock(FSet, LocksToRemove[i], Loc, Dtor);
- }
+ for (const auto &M : ExclusiveLocksToRemove)
+ Analyzer->removeLock(FSet, M, Loc, Dtor, LK_Exclusive, CapDiagKind);
+ for (const auto &M : SharedLocksToRemove)
+ Analyzer->removeLock(FSet, M, Loc, Dtor, LK_Shared, CapDiagKind);
+ for (const auto &M : GenericLocksToRemove)
+ Analyzer->removeLock(FSet, M, Loc, Dtor, LK_Generic, CapDiagKind);
}
@@ -2168,11 +2180,9 @@ void BuildLockset::VisitCallExpr(CallExpr *Exp) {
case OO_Star:
case OO_Arrow:
case OO_Subscript: {
- if (Analyzer->Handler.issueBetaWarnings()) {
- const Expr *Obj = OE->getArg(0);
- checkAccess(Obj, AK_Read);
- checkPtAccess(Obj, AK_Read);
- }
+ const Expr *Obj = OE->getArg(0);
+ checkAccess(Obj, AK_Read);
+ checkPtAccess(Obj, AK_Read);
break;
}
default: {
@@ -2201,9 +2211,7 @@ void BuildLockset::VisitDeclStmt(DeclStmt *S) {
// adjust the context
LVarCtx = Analyzer->LocalVarMap.getNextContext(CtxIndex, S, LVarCtx);
- DeclGroupRef DGrp = S->getDeclGroup();
- for (DeclGroupRef::iterator I = DGrp.begin(), E = DGrp.end(); I != E; ++I) {
- Decl *D = *I;
+ for (auto *D : S->getDeclGroup()) {
if (VarDecl *VD = dyn_cast_or_null<VarDecl>(D)) {
Expr *E = VD->getInit();
// handle constructors that involve temporaries
@@ -2245,26 +2253,24 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
FactSet FSet1Orig = FSet1;
// Find locks in FSet2 that conflict or are not in FSet1, and warn.
- for (FactSet::const_iterator I = FSet2.begin(), E = FSet2.end();
- I != E; ++I) {
- const SExpr &FSet2Mutex = FactMan[*I].MutID;
- const LockData &LDat2 = FactMan[*I].LDat;
+ for (const auto &Fact : FSet2) {
+ const SExpr &FSet2Mutex = FactMan[Fact].MutID;
+ const LockData &LDat2 = FactMan[Fact].LDat;
FactSet::iterator I1 = FSet1.findLockIter(FactMan, FSet2Mutex);
if (I1 != FSet1.end()) {
const LockData* LDat1 = &FactMan[*I1].LDat;
if (LDat1->LKind != LDat2.LKind) {
- Handler.handleExclusiveAndShared(FSet2Mutex.toString(),
- LDat2.AcquireLoc,
- LDat1->AcquireLoc);
+ Handler.handleExclusiveAndShared("mutex", FSet2Mutex.toString(),
+ LDat2.AcquireLoc, LDat1->AcquireLoc);
if (Modify && LDat1->LKind != LK_Exclusive) {
// Take the exclusive lock, which is the one in FSet2.
- *I1 = *I;
+ *I1 = Fact;
}
}
else if (LDat1->Asserted && !LDat2.Asserted) {
// The non-asserted lock in FSet2 is the one we want to track.
- *I1 = *I;
+ *I1 = Fact;
}
} else {
if (LDat2.UnderlyingMutex.isValid()) {
@@ -2272,23 +2278,21 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
// If this is a scoped lock that manages another mutex, and if the
// underlying mutex is still held, then warn about the underlying
// mutex.
- Handler.handleMutexHeldEndOfScope(LDat2.UnderlyingMutex.toString(),
- LDat2.AcquireLoc,
- JoinLoc, LEK1);
+ Handler.handleMutexHeldEndOfScope("mutex",
+ LDat2.UnderlyingMutex.toString(),
+ LDat2.AcquireLoc, JoinLoc, LEK1);
}
}
else if (!LDat2.Managed && !FSet2Mutex.isUniversal() && !LDat2.Asserted)
- Handler.handleMutexHeldEndOfScope(FSet2Mutex.toString(),
- LDat2.AcquireLoc,
- JoinLoc, LEK1);
+ Handler.handleMutexHeldEndOfScope("mutex", FSet2Mutex.toString(),
+ LDat2.AcquireLoc, JoinLoc, LEK1);
}
}
// Find locks in FSet1 that are not in FSet2, and remove them.
- for (FactSet::const_iterator I = FSet1Orig.begin(), E = FSet1Orig.end();
- I != E; ++I) {
- const SExpr &FSet1Mutex = FactMan[*I].MutID;
- const LockData &LDat1 = FactMan[*I].LDat;
+ for (const auto &Fact : FSet1Orig) {
+ const SExpr &FSet1Mutex = FactMan[Fact].MutID;
+ const LockData &LDat1 = FactMan[Fact].LDat;
if (!FSet2.findLock(FactMan, FSet1Mutex)) {
if (LDat1.UnderlyingMutex.isValid()) {
@@ -2296,15 +2300,14 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
// If this is a scoped lock that manages another mutex, and if the
// underlying mutex is still held, then warn about the underlying
// mutex.
- Handler.handleMutexHeldEndOfScope(LDat1.UnderlyingMutex.toString(),
- LDat1.AcquireLoc,
- JoinLoc, LEK1);
+ Handler.handleMutexHeldEndOfScope("mutex",
+ LDat1.UnderlyingMutex.toString(),
+ LDat1.AcquireLoc, JoinLoc, LEK1);
}
}
else if (!LDat1.Managed && !FSet1Mutex.isUniversal() && !LDat1.Asserted)
- Handler.handleMutexHeldEndOfScope(FSet1Mutex.toString(),
- LDat1.AcquireLoc,
- JoinLoc, LEK2);
+ Handler.handleMutexHeldEndOfScope("mutex", FSet1Mutex.toString(),
+ LDat1.AcquireLoc, JoinLoc, LEK2);
if (Modify)
FSet1.removeLock(FactMan, FSet1Mutex);
}
@@ -2334,16 +2337,21 @@ inline bool neverReturns(const CFGBlock* B) {
/// at the end of each block, and issue warnings for thread safety violations.
/// Each block in the CFG is traversed exactly once.
void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
- CFG *CFGraph = AC.getCFG();
- if (!CFGraph) return;
- const NamedDecl *D = dyn_cast_or_null<NamedDecl>(AC.getDecl());
+ // TODO: this whole function needs be rewritten as a visitor for CFGWalker.
+ // For now, we just use the walker to set things up.
+ threadSafety::CFGWalker walker;
+ if (!walker.init(AC))
+ return;
// AC.dumpCFG(true);
+ // threadSafety::printSCFG(walker);
- if (!D)
- return; // Ignore anonymous functions for now.
- if (D->getAttr<NoThreadSafetyAnalysisAttr>())
+ CFG *CFGraph = walker.getGraph();
+ const NamedDecl *D = walker.getDecl();
+
+ if (D->hasAttr<NoThreadSafetyAnalysisAttr>())
return;
+
// FIXME: Do something a bit more intelligent inside constructor and
// destructor code. Constructors and destructors must assume unique access
// to 'this', so checks on member variable access is disabled, but we should
@@ -2359,7 +2367,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
// We need to explore the CFG via a "topological" ordering.
// That way, we will be guaranteed to have information about required
// predecessor locksets when exploring a new block.
- PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
+ const PostOrderCFGView *SortedGraph = walker.getSortedGraph();
PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
// Mark entry block as reachable
@@ -2385,35 +2393,31 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
MutexIDList ExclusiveLocksToAdd;
MutexIDList SharedLocksToAdd;
+ StringRef CapDiagKind = "mutex";
SourceLocation Loc = D->getLocation();
- for (unsigned i = 0; i < ArgAttrs.size(); ++i) {
- Attr *Attr = ArgAttrs[i];
+ for (const auto *Attr : ArgAttrs) {
Loc = Attr->getLocation();
- if (ExclusiveLocksRequiredAttr *A
- = dyn_cast<ExclusiveLocksRequiredAttr>(Attr)) {
- getMutexIDs(ExclusiveLocksToAdd, A, (Expr*) 0, D);
- } else if (SharedLocksRequiredAttr *A
- = dyn_cast<SharedLocksRequiredAttr>(Attr)) {
- getMutexIDs(SharedLocksToAdd, A, (Expr*) 0, D);
- } else if (UnlockFunctionAttr *A = dyn_cast<UnlockFunctionAttr>(Attr)) {
+ if (const auto *A = dyn_cast<RequiresCapabilityAttr>(Attr)) {
+ getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A,
+ nullptr, D);
+ CapDiagKind = ClassifyDiagnostic(A);
+ } else if (const auto *A = dyn_cast<ReleaseCapabilityAttr>(Attr)) {
// UNLOCK_FUNCTION() is used to hide the underlying lock implementation.
// We must ignore such methods.
if (A->args_size() == 0)
return;
// FIXME -- deal with exclusive vs. shared unlock functions?
- getMutexIDs(ExclusiveLocksToAdd, A, (Expr*) 0, D);
- getMutexIDs(LocksReleased, A, (Expr*) 0, D);
- } else if (ExclusiveLockFunctionAttr *A
- = dyn_cast<ExclusiveLockFunctionAttr>(Attr)) {
+ getMutexIDs(ExclusiveLocksToAdd, A, nullptr, D);
+ getMutexIDs(LocksReleased, A, nullptr, D);
+ CapDiagKind = ClassifyDiagnostic(A);
+ } else if (const auto *A = dyn_cast<AcquireCapabilityAttr>(Attr)) {
if (A->args_size() == 0)
return;
- getMutexIDs(ExclusiveLocksAcquired, A, (Expr*) 0, D);
- } else if (SharedLockFunctionAttr *A
- = dyn_cast<SharedLockFunctionAttr>(Attr)) {
- if (A->args_size() == 0)
- return;
- getMutexIDs(SharedLocksAcquired, A, (Expr*) 0, D);
+ getMutexIDs(A->isShared() ? SharedLocksAcquired
+ : ExclusiveLocksAcquired,
+ A, nullptr, D);
+ CapDiagKind = ClassifyDiagnostic(A);
} else if (isa<ExclusiveTrylockFunctionAttr>(Attr)) {
// Don't try to check trylock functions for now
return;
@@ -2424,19 +2428,15 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
}
// FIXME -- Loc can be wrong here.
- for (unsigned i=0,n=ExclusiveLocksToAdd.size(); i<n; ++i) {
- addLock(InitialLockset, ExclusiveLocksToAdd[i],
- LockData(Loc, LK_Exclusive));
- }
- for (unsigned i=0,n=SharedLocksToAdd.size(); i<n; ++i) {
- addLock(InitialLockset, SharedLocksToAdd[i],
- LockData(Loc, LK_Shared));
- }
+ for (const auto &ExclusiveLockToAdd : ExclusiveLocksToAdd)
+ addLock(InitialLockset, ExclusiveLockToAdd, LockData(Loc, LK_Exclusive),
+ CapDiagKind);
+ for (const auto &SharedLockToAdd : SharedLocksToAdd)
+ addLock(InitialLockset, SharedLockToAdd, LockData(Loc, LK_Shared),
+ CapDiagKind);
}
- for (PostOrderCFGView::iterator I = SortedGraph->begin(),
- E = SortedGraph->end(); I!= E; ++I) {
- const CFGBlock *CurrBlock = *I;
+ for (const auto *CurrBlock : *SortedGraph) {
int CurrBlockID = CurrBlock->getBlockID();
CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
@@ -2462,7 +2462,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
PE = CurrBlock->pred_end(); PI != PE; ++PI) {
// if *PI -> CurrBlock is a back edge
- if (*PI == 0 || !VisitedBlocks.alreadySet(*PI))
+ if (*PI == nullptr || !VisitedBlocks.alreadySet(*PI))
continue;
int PrevBlockID = (*PI)->getBlockID();
@@ -2505,9 +2505,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
// Process continue and break blocks. Assume that the lockset for the
// resulting block is unaffected by any discrepancies in them.
- for (unsigned SpecialI = 0, SpecialN = SpecialBlocks.size();
- SpecialI < SpecialN; ++SpecialI) {
- CFGBlock *PrevBlock = SpecialBlocks[SpecialI];
+ for (const auto *PrevBlock : SpecialBlocks) {
int PrevBlockID = PrevBlock->getBlockID();
CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
@@ -2576,7 +2574,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
SE = CurrBlock->succ_end(); SI != SE; ++SI) {
// if CurrBlock -> *SI is *not* a back edge
- if (*SI == 0 || !VisitedBlocks.alreadySet(*SI))
+ if (*SI == nullptr || !VisitedBlocks.alreadySet(*SI))
continue;
CFGBlock *FirstLoopBlock = *SI;
@@ -2603,17 +2601,14 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
// by *-LOCK_FUNCTION and UNLOCK_FUNCTION. The intersect below will then
// issue the appropriate warning.
// FIXME: the location here is not quite right.
- for (unsigned i=0,n=ExclusiveLocksAcquired.size(); i<n; ++i) {
- ExpectedExitSet.addLock(FactMan, ExclusiveLocksAcquired[i],
+ for (const auto &Lock : ExclusiveLocksAcquired)
+ ExpectedExitSet.addLock(FactMan, Lock,
LockData(D->getLocation(), LK_Exclusive));
- }
- for (unsigned i=0,n=SharedLocksAcquired.size(); i<n; ++i) {
- ExpectedExitSet.addLock(FactMan, SharedLocksAcquired[i],
+ for (const auto &Lock : SharedLocksAcquired)
+ ExpectedExitSet.addLock(FactMan, Lock,
LockData(D->getLocation(), LK_Shared));
- }
- for (unsigned i=0,n=LocksReleased.size(); i<n; ++i) {
- ExpectedExitSet.removeLock(FactMan, LocksReleased[i]);
- }
+ for (const auto &Lock : LocksReleased)
+ ExpectedExitSet.removeLock(FactMan, Lock);
// FIXME: Should we call this function for all blocks which exit the function?
intersectAndWarn(ExpectedExitSet, Final->ExitSet,
diff --git a/lib/Analysis/ThreadSafetyCommon.cpp b/lib/Analysis/ThreadSafetyCommon.cpp
new file mode 100644
index 000000000000..da88b78126fa
--- /dev/null
+++ b/lib/Analysis/ThreadSafetyCommon.cpp
@@ -0,0 +1,794 @@
+//===- ThreadSafetyCommon.cpp ----------------------------------*- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of the interfaces declared in ThreadSafetyCommon.h
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/ThreadSafetyCommon.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+
+#include <algorithm>
+#include <climits>
+#include <vector>
+
+
+namespace clang {
+namespace threadSafety {
+
+// From ThreadSafetyUtil.h
+std::string getSourceLiteralString(const clang::Expr *CE) {
+ switch (CE->getStmtClass()) {
+ case Stmt::IntegerLiteralClass:
+ return cast<IntegerLiteral>(CE)->getValue().toString(10, true);
+ case Stmt::StringLiteralClass: {
+ std::string ret("\"");
+ ret += cast<StringLiteral>(CE)->getString();
+ ret += "\"";
+ return ret;
+ }
+ case Stmt::CharacterLiteralClass:
+ case Stmt::CXXNullPtrLiteralExprClass:
+ case Stmt::GNUNullExprClass:
+ case Stmt::CXXBoolLiteralExprClass:
+ case Stmt::FloatingLiteralClass:
+ case Stmt::ImaginaryLiteralClass:
+ case Stmt::ObjCStringLiteralClass:
+ default:
+ return "#lit";
+ }
+}
+
+namespace til {
+
+// Return true if E is a variable that points to an incomplete Phi node.
+static bool isIncompleteVar(const SExpr *E) {
+ if (const auto *V = dyn_cast<Variable>(E)) {
+ if (const auto *Ph = dyn_cast<Phi>(V->definition()))
+ return Ph->status() == Phi::PH_Incomplete;
+ }
+ return false;
+}
+
+} // end namespace til
+
+
+typedef SExprBuilder::CallingContext CallingContext;
+
+
+til::SExpr *SExprBuilder::lookupStmt(const Stmt *S) {
+ auto It = SMap.find(S);
+ if (It != SMap.end())
+ return It->second;
+ return nullptr;
+}
+
+
+til::SCFG *SExprBuilder::buildCFG(CFGWalker &Walker) {
+ Walker.walk(*this);
+ return Scfg;
+}
+
+
+// Translate a clang statement or expression to a TIL expression.
+// Also performs substitution of variables; Ctx provides the context.
+// Dispatches on the type of S.
+til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
+ if (!S)
+ return nullptr;
+
+ // Check if S has already been translated and cached.
+ // This handles the lookup of SSA names for DeclRefExprs here.
+ if (til::SExpr *E = lookupStmt(S))
+ return E;
+
+ switch (S->getStmtClass()) {
+ case Stmt::DeclRefExprClass:
+ return translateDeclRefExpr(cast<DeclRefExpr>(S), Ctx);
+ case Stmt::CXXThisExprClass:
+ return translateCXXThisExpr(cast<CXXThisExpr>(S), Ctx);
+ case Stmt::MemberExprClass:
+ return translateMemberExpr(cast<MemberExpr>(S), Ctx);
+ case Stmt::CallExprClass:
+ return translateCallExpr(cast<CallExpr>(S), Ctx);
+ case Stmt::CXXMemberCallExprClass:
+ return translateCXXMemberCallExpr(cast<CXXMemberCallExpr>(S), Ctx);
+ case Stmt::CXXOperatorCallExprClass:
+ return translateCXXOperatorCallExpr(cast<CXXOperatorCallExpr>(S), Ctx);
+ case Stmt::UnaryOperatorClass:
+ return translateUnaryOperator(cast<UnaryOperator>(S), Ctx);
+ case Stmt::BinaryOperatorClass:
+ case Stmt::CompoundAssignOperatorClass:
+ return translateBinaryOperator(cast<BinaryOperator>(S), Ctx);
+
+ case Stmt::ArraySubscriptExprClass:
+ return translateArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Ctx);
+ case Stmt::ConditionalOperatorClass:
+ return translateConditionalOperator(cast<ConditionalOperator>(S), Ctx);
+ case Stmt::BinaryConditionalOperatorClass:
+ return translateBinaryConditionalOperator(
+ cast<BinaryConditionalOperator>(S), Ctx);
+
+ // We treat these as no-ops
+ case Stmt::ParenExprClass:
+ return translate(cast<ParenExpr>(S)->getSubExpr(), Ctx);
+ case Stmt::ExprWithCleanupsClass:
+ return translate(cast<ExprWithCleanups>(S)->getSubExpr(), Ctx);
+ case Stmt::CXXBindTemporaryExprClass:
+ return translate(cast<CXXBindTemporaryExpr>(S)->getSubExpr(), Ctx);
+
+ // Collect all literals
+ case Stmt::CharacterLiteralClass:
+ case Stmt::CXXNullPtrLiteralExprClass:
+ case Stmt::GNUNullExprClass:
+ case Stmt::CXXBoolLiteralExprClass:
+ case Stmt::FloatingLiteralClass:
+ case Stmt::ImaginaryLiteralClass:
+ case Stmt::IntegerLiteralClass:
+ case Stmt::StringLiteralClass:
+ case Stmt::ObjCStringLiteralClass:
+ return new (Arena) til::Literal(cast<Expr>(S));
+
+ case Stmt::DeclStmtClass:
+ return translateDeclStmt(cast<DeclStmt>(S), Ctx);
+ default:
+ break;
+ }
+ if (const CastExpr *CE = dyn_cast<CastExpr>(S))
+ return translateCastExpr(CE, Ctx);
+
+ return new (Arena) til::Undefined(S);
+}
+
+
+til::SExpr *SExprBuilder::translateDeclRefExpr(const DeclRefExpr *DRE,
+ CallingContext *Ctx) {
+ const ValueDecl *VD = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
+
+ // Function parameters require substitution and/or renaming.
+ if (const ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(VD)) {
+ const FunctionDecl *FD =
+ cast<FunctionDecl>(PV->getDeclContext())->getCanonicalDecl();
+ unsigned I = PV->getFunctionScopeIndex();
+
+ if (Ctx && Ctx->FunArgs && FD == Ctx->AttrDecl->getCanonicalDecl()) {
+ // Substitute call arguments for references to function parameters
+ assert(I < Ctx->NumArgs);
+ return translate(Ctx->FunArgs[I], Ctx->Prev);
+ }
+ // Map the param back to the param of the original function declaration
+ // for consistent comparisons.
+ VD = FD->getParamDecl(I);
+ }
+
+ // For non-local variables, treat it as a referenced to a named object.
+ return new (Arena) til::LiteralPtr(VD);
+}
+
+
+til::SExpr *SExprBuilder::translateCXXThisExpr(const CXXThisExpr *TE,
+ CallingContext *Ctx) {
+ // Substitute for 'this'
+ if (Ctx && Ctx->SelfArg)
+ return translate(Ctx->SelfArg, Ctx->Prev);
+ assert(SelfVar && "We have no variable for 'this'!");
+ return SelfVar;
+}
+
+
+til::SExpr *SExprBuilder::translateMemberExpr(const MemberExpr *ME,
+ CallingContext *Ctx) {
+ til::SExpr *E = translate(ME->getBase(), Ctx);
+ E = new (Arena) til::SApply(E);
+ return new (Arena) til::Project(E, ME->getMemberDecl());
+}
+
+
+til::SExpr *SExprBuilder::translateCallExpr(const CallExpr *CE,
+ CallingContext *Ctx) {
+ // TODO -- Lock returned
+ til::SExpr *E = translate(CE->getCallee(), Ctx);
+ for (const auto *Arg : CE->arguments()) {
+ til::SExpr *A = translate(Arg, Ctx);
+ E = new (Arena) til::Apply(E, A);
+ }
+ return new (Arena) til::Call(E, CE);
+}
+
+
+til::SExpr *SExprBuilder::translateCXXMemberCallExpr(
+ const CXXMemberCallExpr *ME, CallingContext *Ctx) {
+ return translateCallExpr(cast<CallExpr>(ME), Ctx);
+}
+
+
+til::SExpr *SExprBuilder::translateCXXOperatorCallExpr(
+ const CXXOperatorCallExpr *OCE, CallingContext *Ctx) {
+ return translateCallExpr(cast<CallExpr>(OCE), Ctx);
+}
+
+
+til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO,
+ CallingContext *Ctx) {
+ switch (UO->getOpcode()) {
+ case UO_PostInc:
+ case UO_PostDec:
+ case UO_PreInc:
+ case UO_PreDec:
+ return new (Arena) til::Undefined(UO);
+
+ // We treat these as no-ops
+ case UO_AddrOf:
+ case UO_Deref:
+ case UO_Plus:
+ return translate(UO->getSubExpr(), Ctx);
+
+ case UO_Minus:
+ return new (Arena)
+ til::UnaryOp(til::UOP_Minus, translate(UO->getSubExpr(), Ctx));
+ case UO_Not:
+ return new (Arena)
+ til::UnaryOp(til::UOP_BitNot, translate(UO->getSubExpr(), Ctx));
+ case UO_LNot:
+ return new (Arena)
+ til::UnaryOp(til::UOP_LogicNot, translate(UO->getSubExpr(), Ctx));
+
+ // Currently unsupported
+ case UO_Real:
+ case UO_Imag:
+ case UO_Extension:
+ return new (Arena) til::Undefined(UO);
+ }
+ return new (Arena) til::Undefined(UO);
+}
+
+
+til::SExpr *SExprBuilder::translateBinOp(til::TIL_BinaryOpcode Op,
+ const BinaryOperator *BO,
+ CallingContext *Ctx, bool Reverse) {
+ til::SExpr *E0 = translate(BO->getLHS(), Ctx);
+ til::SExpr *E1 = translate(BO->getRHS(), Ctx);
+ if (Reverse)
+ return new (Arena) til::BinaryOp(Op, E1, E0);
+ else
+ return new (Arena) til::BinaryOp(Op, E0, E1);
+}
+
+
+til::SExpr *SExprBuilder::translateBinAssign(til::TIL_BinaryOpcode Op,
+ const BinaryOperator *BO,
+ CallingContext *Ctx,
+ bool Assign) {
+ const Expr *LHS = BO->getLHS();
+ const Expr *RHS = BO->getRHS();
+ til::SExpr *E0 = translate(LHS, Ctx);
+ til::SExpr *E1 = translate(RHS, Ctx);
+
+ const ValueDecl *VD = nullptr;
+ til::SExpr *CV = nullptr;
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LHS)) {
+ VD = DRE->getDecl();
+ CV = lookupVarDecl(VD);
+ }
+
+ if (!Assign) {
+ til::SExpr *Arg = CV ? CV : new (Arena) til::Load(E0);
+ E1 = new (Arena) til::BinaryOp(Op, Arg, E1);
+ E1 = addStatement(E1, nullptr, VD);
+ }
+ if (VD && CV)
+ return updateVarDecl(VD, E1);
+ return new (Arena) til::Store(E0, E1);
+}
+
+
+til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO,
+ CallingContext *Ctx) {
+ switch (BO->getOpcode()) {
+ case BO_PtrMemD:
+ case BO_PtrMemI:
+ return new (Arena) til::Undefined(BO);
+
+ case BO_Mul: return translateBinOp(til::BOP_Mul, BO, Ctx);
+ case BO_Div: return translateBinOp(til::BOP_Div, BO, Ctx);
+ case BO_Rem: return translateBinOp(til::BOP_Rem, BO, Ctx);
+ case BO_Add: return translateBinOp(til::BOP_Add, BO, Ctx);
+ case BO_Sub: return translateBinOp(til::BOP_Sub, BO, Ctx);
+ case BO_Shl: return translateBinOp(til::BOP_Shl, BO, Ctx);
+ case BO_Shr: return translateBinOp(til::BOP_Shr, BO, Ctx);
+ case BO_LT: return translateBinOp(til::BOP_Lt, BO, Ctx);
+ case BO_GT: return translateBinOp(til::BOP_Lt, BO, Ctx, true);
+ case BO_LE: return translateBinOp(til::BOP_Leq, BO, Ctx);
+ case BO_GE: return translateBinOp(til::BOP_Leq, BO, Ctx, true);
+ case BO_EQ: return translateBinOp(til::BOP_Eq, BO, Ctx);
+ case BO_NE: return translateBinOp(til::BOP_Neq, BO, Ctx);
+ case BO_And: return translateBinOp(til::BOP_BitAnd, BO, Ctx);
+ case BO_Xor: return translateBinOp(til::BOP_BitXor, BO, Ctx);
+ case BO_Or: return translateBinOp(til::BOP_BitOr, BO, Ctx);
+ case BO_LAnd: return translateBinOp(til::BOP_LogicAnd, BO, Ctx);
+ case BO_LOr: return translateBinOp(til::BOP_LogicOr, BO, Ctx);
+
+ case BO_Assign: return translateBinAssign(til::BOP_Eq, BO, Ctx, true);
+ case BO_MulAssign: return translateBinAssign(til::BOP_Mul, BO, Ctx);
+ case BO_DivAssign: return translateBinAssign(til::BOP_Div, BO, Ctx);
+ case BO_RemAssign: return translateBinAssign(til::BOP_Rem, BO, Ctx);
+ case BO_AddAssign: return translateBinAssign(til::BOP_Add, BO, Ctx);
+ case BO_SubAssign: return translateBinAssign(til::BOP_Sub, BO, Ctx);
+ case BO_ShlAssign: return translateBinAssign(til::BOP_Shl, BO, Ctx);
+ case BO_ShrAssign: return translateBinAssign(til::BOP_Shr, BO, Ctx);
+ case BO_AndAssign: return translateBinAssign(til::BOP_BitAnd, BO, Ctx);
+ case BO_XorAssign: return translateBinAssign(til::BOP_BitXor, BO, Ctx);
+ case BO_OrAssign: return translateBinAssign(til::BOP_BitOr, BO, Ctx);
+
+ case BO_Comma:
+ // The clang CFG should have already processed both sides.
+ return translate(BO->getRHS(), Ctx);
+ }
+ return new (Arena) til::Undefined(BO);
+}
+
+
+til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
+ CallingContext *Ctx) {
+ clang::CastKind K = CE->getCastKind();
+ switch (K) {
+ case CK_LValueToRValue: {
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {
+ til::SExpr *E0 = lookupVarDecl(DRE->getDecl());
+ if (E0)
+ return E0;
+ }
+ til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
+ return new (Arena) til::Load(E0);
+ }
+ case CK_NoOp:
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase:
+ case CK_ArrayToPointerDecay:
+ case CK_FunctionToPointerDecay: {
+ til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
+ return E0;
+ }
+ default: {
+ // FIXME: handle different kinds of casts.
+ til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
+ return new (Arena) til::Cast(til::CAST_none, E0);
+ }
+ }
+}
+
+
+til::SExpr *
+SExprBuilder::translateArraySubscriptExpr(const ArraySubscriptExpr *E,
+ CallingContext *Ctx) {
+ til::SExpr *E0 = translate(E->getBase(), Ctx);
+ til::SExpr *E1 = translate(E->getIdx(), Ctx);
+ return new (Arena) til::ArrayIndex(E0, E1);
+}
+
+
+til::SExpr *
+SExprBuilder::translateConditionalOperator(const ConditionalOperator *C,
+ CallingContext *Ctx) {
+ return new (Arena) til::Undefined(C);
+}
+
+
+til::SExpr *SExprBuilder::translateBinaryConditionalOperator(
+ const BinaryConditionalOperator *C, CallingContext *Ctx) {
+ return new (Arena) til::Undefined(C);
+}
+
+
+til::SExpr *
+SExprBuilder::translateDeclStmt(const DeclStmt *S, CallingContext *Ctx) {
+ DeclGroupRef DGrp = S->getDeclGroup();
+ for (DeclGroupRef::iterator I = DGrp.begin(), E = DGrp.end(); I != E; ++I) {
+ if (VarDecl *VD = dyn_cast_or_null<VarDecl>(*I)) {
+ Expr *E = VD->getInit();
+ til::SExpr* SE = translate(E, Ctx);
+
+ // Add local variables with trivial type to the variable map
+ QualType T = VD->getType();
+ if (T.isTrivialType(VD->getASTContext())) {
+ return addVarDecl(VD, SE);
+ }
+ else {
+ // TODO: add alloca
+ }
+ }
+ }
+ return nullptr;
+}
+
+
+
+// If (E) is non-trivial, then add it to the current basic block, and
+// update the statement map so that S refers to E. Returns a new variable
+// that refers to E.
+// If E is trivial returns E.
+til::SExpr *SExprBuilder::addStatement(til::SExpr* E, const Stmt *S,
+ const ValueDecl *VD) {
+ if (!E)
+ return nullptr;
+ if (til::ThreadSafetyTIL::isTrivial(E))
+ return E;
+
+ til::Variable *V = new (Arena) til::Variable(E, VD);
+ CurrentInstructions.push_back(V);
+ if (S)
+ insertStmt(S, V);
+ return V;
+}
+
+
+// Returns the current value of VD, if known, and nullptr otherwise.
+til::SExpr *SExprBuilder::lookupVarDecl(const ValueDecl *VD) {
+ auto It = LVarIdxMap.find(VD);
+ if (It != LVarIdxMap.end()) {
+ assert(CurrentLVarMap[It->second].first == VD);
+ return CurrentLVarMap[It->second].second;
+ }
+ return nullptr;
+}
+
+
+// if E is a til::Variable, update its clangDecl.
+inline void maybeUpdateVD(til::SExpr *E, const ValueDecl *VD) {
+ if (!E)
+ return;
+ if (til::Variable *V = dyn_cast<til::Variable>(E)) {
+ if (!V->clangDecl())
+ V->setClangDecl(VD);
+ }
+}
+
+// Adds a new variable declaration.
+til::SExpr *SExprBuilder::addVarDecl(const ValueDecl *VD, til::SExpr *E) {
+ maybeUpdateVD(E, VD);
+ LVarIdxMap.insert(std::make_pair(VD, CurrentLVarMap.size()));
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.push_back(std::make_pair(VD, E));
+ return E;
+}
+
+
+// Updates a current variable declaration. (E.g. by assignment)
+til::SExpr *SExprBuilder::updateVarDecl(const ValueDecl *VD, til::SExpr *E) {
+ maybeUpdateVD(E, VD);
+ auto It = LVarIdxMap.find(VD);
+ if (It == LVarIdxMap.end()) {
+ til::SExpr *Ptr = new (Arena) til::LiteralPtr(VD);
+ til::SExpr *St = new (Arena) til::Store(Ptr, E);
+ return St;
+ }
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.elem(It->second).second = E;
+ return E;
+}
+
+
+// Make a Phi node in the current block for the i^th variable in CurrentVarMap.
+// If E != null, sets Phi[CurrentBlockInfo->ArgIndex] = E.
+// If E == null, this is a backedge and will be set later.
+void SExprBuilder::makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E) {
+ unsigned ArgIndex = CurrentBlockInfo->ProcessedPredecessors;
+ assert(ArgIndex > 0 && ArgIndex < NPreds);
+
+ til::Variable *V = dyn_cast<til::Variable>(CurrentLVarMap[i].second);
+ if (V && V->getBlockID() == CurrentBB->blockID()) {
+ // We already have a Phi node in the current block,
+ // so just add the new variable to the Phi node.
+ til::Phi *Ph = dyn_cast<til::Phi>(V->definition());
+ assert(Ph && "Expecting Phi node.");
+ if (E)
+ Ph->values()[ArgIndex] = E;
+ return;
+ }
+
+ // Make a new phi node: phi(..., E)
+ // All phi args up to the current index are set to the current value.
+ til::SExpr *CurrE = CurrentLVarMap[i].second;
+ til::Phi *Ph = new (Arena) til::Phi(Arena, NPreds);
+ Ph->values().setValues(NPreds, nullptr);
+ for (unsigned PIdx = 0; PIdx < ArgIndex; ++PIdx)
+ Ph->values()[PIdx] = CurrE;
+ if (E)
+ Ph->values()[ArgIndex] = E;
+ // If E is from a back-edge, or either E or CurrE are incomplete, then
+ // mark this node as incomplete; we may need to remove it later.
+ if (!E || isIncompleteVar(E) || isIncompleteVar(CurrE)) {
+ Ph->setStatus(til::Phi::PH_Incomplete);
+ }
+
+ // Add Phi node to current block, and update CurrentLVarMap[i]
+ auto *Var = new (Arena) til::Variable(Ph, CurrentLVarMap[i].first);
+ CurrentArguments.push_back(Var);
+ if (Ph->status() == til::Phi::PH_Incomplete)
+ IncompleteArgs.push_back(Var);
+
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.elem(i).second = Var;
+}
+
+
+// Merge values from Map into the current variable map.
+// This will construct Phi nodes in the current basic block as necessary.
+void SExprBuilder::mergeEntryMap(LVarDefinitionMap Map) {
+ assert(CurrentBlockInfo && "Not processing a block!");
+
+ if (!CurrentLVarMap.valid()) {
+ // Steal Map, using copy-on-write.
+ CurrentLVarMap = std::move(Map);
+ return;
+ }
+ if (CurrentLVarMap.sameAs(Map))
+ return; // Easy merge: maps from different predecessors are unchanged.
+
+ unsigned NPreds = CurrentBB->numPredecessors();
+ unsigned ESz = CurrentLVarMap.size();
+ unsigned MSz = Map.size();
+ unsigned Sz = std::min(ESz, MSz);
+
+ for (unsigned i=0; i<Sz; ++i) {
+ if (CurrentLVarMap[i].first != Map[i].first) {
+ // We've reached the end of variables in common.
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.downsize(i);
+ break;
+ }
+ if (CurrentLVarMap[i].second != Map[i].second)
+ makePhiNodeVar(i, NPreds, Map[i].second);
+ }
+ if (ESz > MSz) {
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.downsize(Map.size());
+ }
+}
+
+
+// Merge a back edge into the current variable map.
+// This will create phi nodes for all variables in the variable map.
+void SExprBuilder::mergeEntryMapBackEdge() {
+ // We don't have definitions for variables on the backedge, because we
+ // haven't gotten that far in the CFG. Thus, when encountering a back edge,
+ // we conservatively create Phi nodes for all variables. Unnecessary Phi
+ // nodes will be marked as incomplete, and stripped out at the end.
+ //
+ // An Phi node is unnecessary if it only refers to itself and one other
+ // variable, e.g. x = Phi(y, y, x) can be reduced to x = y.
+
+ assert(CurrentBlockInfo && "Not processing a block!");
+
+ if (CurrentBlockInfo->HasBackEdges)
+ return;
+ CurrentBlockInfo->HasBackEdges = true;
+
+ CurrentLVarMap.makeWritable();
+ unsigned Sz = CurrentLVarMap.size();
+ unsigned NPreds = CurrentBB->numPredecessors();
+
+ for (unsigned i=0; i < Sz; ++i) {
+ makePhiNodeVar(i, NPreds, nullptr);
+ }
+}
+
+
+// Update the phi nodes that were initially created for a back edge
+// once the variable definitions have been computed.
+// I.e., merge the current variable map into the phi nodes for Blk.
+void SExprBuilder::mergePhiNodesBackEdge(const CFGBlock *Blk) {
+ til::BasicBlock *BB = lookupBlock(Blk);
+ unsigned ArgIndex = BBInfo[Blk->getBlockID()].ProcessedPredecessors;
+ assert(ArgIndex > 0 && ArgIndex < BB->numPredecessors());
+
+ for (til::Variable *V : BB->arguments()) {
+ til::Phi *Ph = dyn_cast_or_null<til::Phi>(V->definition());
+ assert(Ph && "Expecting Phi Node.");
+ assert(Ph->values()[ArgIndex] == nullptr && "Wrong index for back edge.");
+ assert(V->clangDecl() && "No local variable for Phi node.");
+
+ til::SExpr *E = lookupVarDecl(V->clangDecl());
+ assert(E && "Couldn't find local variable for Phi node.");
+
+ Ph->values()[ArgIndex] = E;
+ }
+}
+
+void SExprBuilder::enterCFG(CFG *Cfg, const NamedDecl *D,
+ const CFGBlock *First) {
+ // Perform initial setup operations.
+ unsigned NBlocks = Cfg->getNumBlockIDs();
+ Scfg = new (Arena) til::SCFG(Arena, NBlocks);
+
+ // allocate all basic blocks immediately, to handle forward references.
+ BBInfo.resize(NBlocks);
+ BlockMap.resize(NBlocks, nullptr);
+ // create map from clang blockID to til::BasicBlocks
+ for (auto *B : *Cfg) {
+ auto *BB = new (Arena) til::BasicBlock(Arena);
+ BB->reserveInstructions(B->size());
+ BlockMap[B->getBlockID()] = BB;
+ }
+ CallCtx.reset(new SExprBuilder::CallingContext(D));
+
+ CurrentBB = lookupBlock(&Cfg->getEntry());
+ auto Parms = isa<ObjCMethodDecl>(D) ? cast<ObjCMethodDecl>(D)->parameters()
+ : cast<FunctionDecl>(D)->parameters();
+ for (auto *Pm : Parms) {
+ QualType T = Pm->getType();
+ if (!T.isTrivialType(Pm->getASTContext()))
+ continue;
+
+ // Add parameters to local variable map.
+ // FIXME: right now we emulate params with loads; that should be fixed.
+ til::SExpr *Lp = new (Arena) til::LiteralPtr(Pm);
+ til::SExpr *Ld = new (Arena) til::Load(Lp);
+ til::SExpr *V = addStatement(Ld, nullptr, Pm);
+ addVarDecl(Pm, V);
+ }
+}
+
+
+void SExprBuilder::enterCFGBlock(const CFGBlock *B) {
+ // Intialize TIL basic block and add it to the CFG.
+ CurrentBB = lookupBlock(B);
+ CurrentBB->reservePredecessors(B->pred_size());
+ Scfg->add(CurrentBB);
+
+ CurrentBlockInfo = &BBInfo[B->getBlockID()];
+
+ // CurrentLVarMap is moved to ExitMap on block exit.
+ // FIXME: the entry block will hold function parameters.
+ // assert(!CurrentLVarMap.valid() && "CurrentLVarMap already initialized.");
+}
+
+
+void SExprBuilder::handlePredecessor(const CFGBlock *Pred) {
+ // Compute CurrentLVarMap on entry from ExitMaps of predecessors
+
+ CurrentBB->addPredecessor(BlockMap[Pred->getBlockID()]);
+ BlockInfo *PredInfo = &BBInfo[Pred->getBlockID()];
+ assert(PredInfo->UnprocessedSuccessors > 0);
+
+ if (--PredInfo->UnprocessedSuccessors == 0)
+ mergeEntryMap(std::move(PredInfo->ExitMap));
+ else
+ mergeEntryMap(PredInfo->ExitMap.clone());
+
+ ++CurrentBlockInfo->ProcessedPredecessors;
+}
+
+
+void SExprBuilder::handlePredecessorBackEdge(const CFGBlock *Pred) {
+ mergeEntryMapBackEdge();
+}
+
+
+void SExprBuilder::enterCFGBlockBody(const CFGBlock *B) {
+ // The merge*() methods have created arguments.
+ // Push those arguments onto the basic block.
+ CurrentBB->arguments().reserve(
+ static_cast<unsigned>(CurrentArguments.size()), Arena);
+ for (auto *V : CurrentArguments)
+ CurrentBB->addArgument(V);
+}
+
+
+void SExprBuilder::handleStatement(const Stmt *S) {
+ til::SExpr *E = translate(S, CallCtx.get());
+ addStatement(E, S);
+}
+
+
+void SExprBuilder::handleDestructorCall(const VarDecl *VD,
+ const CXXDestructorDecl *DD) {
+ til::SExpr *Sf = new (Arena) til::LiteralPtr(VD);
+ til::SExpr *Dr = new (Arena) til::LiteralPtr(DD);
+ til::SExpr *Ap = new (Arena) til::Apply(Dr, Sf);
+ til::SExpr *E = new (Arena) til::Call(Ap);
+ addStatement(E, nullptr);
+}
+
+
+
+void SExprBuilder::exitCFGBlockBody(const CFGBlock *B) {
+ CurrentBB->instructions().reserve(
+ static_cast<unsigned>(CurrentInstructions.size()), Arena);
+ for (auto *V : CurrentInstructions)
+ CurrentBB->addInstruction(V);
+
+ // Create an appropriate terminator
+ unsigned N = B->succ_size();
+ auto It = B->succ_begin();
+ if (N == 1) {
+ til::BasicBlock *BB = *It ? lookupBlock(*It) : nullptr;
+ // TODO: set index
+ unsigned Idx = BB ? BB->findPredecessorIndex(CurrentBB) : 0;
+ til::SExpr *Tm = new (Arena) til::Goto(BB, Idx);
+ CurrentBB->setTerminator(Tm);
+ }
+ else if (N == 2) {
+ til::SExpr *C = translate(B->getTerminatorCondition(true), CallCtx.get());
+ til::BasicBlock *BB1 = *It ? lookupBlock(*It) : nullptr;
+ ++It;
+ til::BasicBlock *BB2 = *It ? lookupBlock(*It) : nullptr;
+ unsigned Idx1 = BB1 ? BB1->findPredecessorIndex(CurrentBB) : 0;
+ unsigned Idx2 = BB2 ? BB2->findPredecessorIndex(CurrentBB) : 0;
+ til::SExpr *Tm = new (Arena) til::Branch(C, BB1, BB2, Idx1, Idx2);
+ CurrentBB->setTerminator(Tm);
+ }
+}
+
+
+void SExprBuilder::handleSuccessor(const CFGBlock *Succ) {
+ ++CurrentBlockInfo->UnprocessedSuccessors;
+}
+
+
+void SExprBuilder::handleSuccessorBackEdge(const CFGBlock *Succ) {
+ mergePhiNodesBackEdge(Succ);
+ ++BBInfo[Succ->getBlockID()].ProcessedPredecessors;
+}
+
+
+void SExprBuilder::exitCFGBlock(const CFGBlock *B) {
+ CurrentArguments.clear();
+ CurrentInstructions.clear();
+ CurrentBlockInfo->ExitMap = std::move(CurrentLVarMap);
+ CurrentBB = nullptr;
+ CurrentBlockInfo = nullptr;
+}
+
+
+void SExprBuilder::exitCFG(const CFGBlock *Last) {
+ for (auto *V : IncompleteArgs) {
+ til::Phi *Ph = dyn_cast<til::Phi>(V->definition());
+ if (Ph && Ph->status() == til::Phi::PH_Incomplete)
+ simplifyIncompleteArg(V, Ph);
+ }
+
+ CurrentArguments.clear();
+ CurrentInstructions.clear();
+ IncompleteArgs.clear();
+}
+
+
+
+class TILPrinter : public til::PrettyPrinter<TILPrinter, llvm::raw_ostream> {};
+
+
+void printSCFG(CFGWalker &Walker) {
+ llvm::BumpPtrAllocator Bpa;
+ til::MemRegionRef Arena(&Bpa);
+ SExprBuilder builder(Arena);
+ til::SCFG *Cfg = builder.buildCFG(Walker);
+ TILPrinter::print(Cfg, llvm::errs());
+}
+
+
+
+} // end namespace threadSafety
+
+} // end namespace clang
diff --git a/lib/Analysis/ThreadSafetyLogical.cpp b/lib/Analysis/ThreadSafetyLogical.cpp
new file mode 100644
index 000000000000..facfa11a39ab
--- /dev/null
+++ b/lib/Analysis/ThreadSafetyLogical.cpp
@@ -0,0 +1,112 @@
+//===- ThreadSafetyLogical.cpp ---------------------------------*- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This file defines a representation for logical expressions with SExpr leaves
+// that are used as part of fact-checking capability expressions.
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/ThreadSafetyLogical.h"
+
+using namespace llvm;
+using namespace clang::threadSafety::lexpr;
+
+// Implication. We implement De Morgan's Laws by maintaining LNeg and RNeg
+// to keep track of whether LHS and RHS are negated.
+static bool implies(const LExpr *LHS, bool LNeg, const LExpr *RHS, bool RNeg) {
+ // In comments below, we write => for implication.
+
+ // Calculates the logical AND implication operator.
+ const auto LeftAndOperator = [=](const BinOp *A) {
+ return implies(A->left(), LNeg, RHS, RNeg) &&
+ implies(A->right(), LNeg, RHS, RNeg);
+ };
+ const auto RightAndOperator = [=](const BinOp *A) {
+ return implies(LHS, LNeg, A->left(), RNeg) &&
+ implies(LHS, LNeg, A->right(), RNeg);
+ };
+
+ // Calculates the logical OR implication operator.
+ const auto LeftOrOperator = [=](const BinOp *A) {
+ return implies(A->left(), LNeg, RHS, RNeg) ||
+ implies(A->right(), LNeg, RHS, RNeg);
+ };
+ const auto RightOrOperator = [=](const BinOp *A) {
+ return implies(LHS, LNeg, A->left(), RNeg) ||
+ implies(LHS, LNeg, A->right(), RNeg);
+ };
+
+ // Recurse on right.
+ switch (RHS->kind()) {
+ case LExpr::And:
+ // When performing right recursion:
+ // C => A & B [if] C => A and C => B
+ // When performing right recursion (negated):
+ // C => !(A & B) [if] C => !A | !B [===] C => !A or C => !B
+ return RNeg ? RightOrOperator(cast<And>(RHS))
+ : RightAndOperator(cast<And>(RHS));
+ case LExpr::Or:
+ // When performing right recursion:
+ // C => (A | B) [if] C => A or C => B
+ // When performing right recursion (negated):
+ // C => !(A | B) [if] C => !A & !B [===] C => !A and C => !B
+ return RNeg ? RightAndOperator(cast<Or>(RHS))
+ : RightOrOperator(cast<Or>(RHS));
+ case LExpr::Not:
+ // Note that C => !A is very different from !(C => A). It would be incorrect
+ // to return !implies(LHS, RHS).
+ return implies(LHS, LNeg, cast<Not>(RHS)->exp(), !RNeg);
+ case LExpr::Terminal:
+ // After reaching the terminal, it's time to recurse on the left.
+ break;
+ }
+
+ // RHS is now a terminal. Recurse on Left.
+ switch (LHS->kind()) {
+ case LExpr::And:
+ // When performing left recursion:
+ // A & B => C [if] A => C or B => C
+ // When performing left recursion (negated):
+ // !(A & B) => C [if] !A | !B => C [===] !A => C and !B => C
+ return LNeg ? LeftAndOperator(cast<And>(LHS))
+ : LeftOrOperator(cast<And>(LHS));
+ case LExpr::Or:
+ // When performing left recursion:
+ // A | B => C [if] A => C and B => C
+ // When performing left recursion (negated):
+ // !(A | B) => C [if] !A & !B => C [===] !A => C or !B => C
+ return LNeg ? LeftOrOperator(cast<Or>(LHS))
+ : LeftAndOperator(cast<Or>(LHS));
+ case LExpr::Not:
+ // Note that A => !C is very different from !(A => C). It would be incorrect
+ // to return !implies(LHS, RHS).
+ return implies(cast<Not>(LHS)->exp(), !LNeg, RHS, RNeg);
+ case LExpr::Terminal:
+ // After reaching the terminal, it's time to perform identity comparisons.
+ break;
+ }
+
+ // A => A
+ // !A => !A
+ if (LNeg != RNeg)
+ return false;
+
+ // FIXME -- this should compare SExprs for equality, not pointer equality.
+ return cast<Terminal>(LHS)->expr() == cast<Terminal>(RHS)->expr();
+}
+
+namespace clang {
+namespace threadSafety {
+namespace lexpr {
+
+bool implies(const LExpr *LHS, const LExpr *RHS) {
+ // Start out by assuming that LHS and RHS are not negated.
+ return ::implies(LHS, false, RHS, false);
+}
+}
+}
+}
diff --git a/lib/Analysis/ThreadSafetyTIL.cpp b/lib/Analysis/ThreadSafetyTIL.cpp
new file mode 100644
index 000000000000..f67cbb90e5ab
--- /dev/null
+++ b/lib/Analysis/ThreadSafetyTIL.cpp
@@ -0,0 +1,153 @@
+//===- ThreadSafetyTIL.cpp -------------------------------------*- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT in the llvm repository for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
+
+namespace clang {
+namespace threadSafety {
+namespace til {
+
+
+StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op) {
+ switch (Op) {
+ case UOP_Minus: return "-";
+ case UOP_BitNot: return "~";
+ case UOP_LogicNot: return "!";
+ }
+ return "";
+}
+
+
+StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op) {
+ switch (Op) {
+ case BOP_Mul: return "*";
+ case BOP_Div: return "/";
+ case BOP_Rem: return "%";
+ case BOP_Add: return "+";
+ case BOP_Sub: return "-";
+ case BOP_Shl: return "<<";
+ case BOP_Shr: return ">>";
+ case BOP_BitAnd: return "&";
+ case BOP_BitXor: return "^";
+ case BOP_BitOr: return "|";
+ case BOP_Eq: return "==";
+ case BOP_Neq: return "!=";
+ case BOP_Lt: return "<";
+ case BOP_Leq: return "<=";
+ case BOP_LogicAnd: return "&&";
+ case BOP_LogicOr: return "||";
+ }
+ return "";
+}
+
+
+unsigned BasicBlock::addPredecessor(BasicBlock *Pred) {
+ unsigned Idx = Predecessors.size();
+ Predecessors.reserveCheck(1, Arena);
+ Predecessors.push_back(Pred);
+ for (Variable *V : Args) {
+ if (Phi* Ph = dyn_cast<Phi>(V->definition())) {
+ Ph->values().reserveCheck(1, Arena);
+ Ph->values().push_back(nullptr);
+ }
+ }
+ return Idx;
+}
+
+void BasicBlock::reservePredecessors(unsigned NumPreds) {
+ Predecessors.reserve(NumPreds, Arena);
+ for (Variable *V : Args) {
+ if (Phi* Ph = dyn_cast<Phi>(V->definition())) {
+ Ph->values().reserve(NumPreds, Arena);
+ }
+ }
+}
+
+void BasicBlock::renumberVars() {
+ unsigned VID = 0;
+ for (Variable *V : Args) {
+ V->setID(BlockID, VID++);
+ }
+ for (Variable *V : Instrs) {
+ V->setID(BlockID, VID++);
+ }
+}
+
+void SCFG::renumberVars() {
+ for (BasicBlock *B : Blocks) {
+ B->renumberVars();
+ }
+}
+
+
+
+
+// If E is a variable, then trace back through any aliases or redundant
+// Phi nodes to find the canonical definition.
+SExpr *getCanonicalVal(SExpr *E) {
+ while (auto *V = dyn_cast<Variable>(E)) {
+ SExpr *D;
+ do {
+ if (V->kind() != Variable::VK_Let)
+ return V;
+ D = V->definition();
+ auto *V2 = dyn_cast<Variable>(D);
+ if (V2)
+ V = V2;
+ else
+ break;
+ } while (true);
+
+ if (ThreadSafetyTIL::isTrivial(D))
+ return D;
+
+ if (Phi *Ph = dyn_cast<Phi>(D)) {
+ if (Ph->status() == Phi::PH_Incomplete)
+ simplifyIncompleteArg(V, Ph);
+
+ if (Ph->status() == Phi::PH_SingleVal) {
+ E = Ph->values()[0];
+ continue;
+ }
+ }
+ return V;
+ }
+ return E;
+}
+
+
+// Trace the arguments of an incomplete Phi node to see if they have the same
+// canonical definition. If so, mark the Phi node as redundant.
+// getCanonicalVal() will recursively call simplifyIncompletePhi().
+void simplifyIncompleteArg(Variable *V, til::Phi *Ph) {
+ assert(Ph && Ph->status() == Phi::PH_Incomplete);
+
+ // eliminate infinite recursion -- assume that this node is not redundant.
+ Ph->setStatus(Phi::PH_MultiVal);
+
+ SExpr *E0 = getCanonicalVal(Ph->values()[0]);
+ for (unsigned i=1, n=Ph->values().size(); i<n; ++i) {
+ SExpr *Ei = getCanonicalVal(Ph->values()[i]);
+ if (Ei == V)
+ continue; // Recursive reference to itself. Don't count.
+ if (Ei != E0) {
+ return; // Status is already set to MultiVal.
+ }
+ }
+ Ph->setStatus(Phi::PH_SingleVal);
+ // Eliminate Redundant Phi node.
+ V->setDefinition(Ph->values()[0]);
+}
+
+
+} // end namespace til
+} // end namespace threadSafety
+} // end namespace clang
+
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index 332c02cf1852..f5c786ac3456 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -34,7 +34,7 @@ using namespace clang;
static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) {
if (vd->isLocalVarDecl() && !vd->hasGlobalStorage() &&
- !vd->isExceptionVariable() &&
+ !vd->isExceptionVariable() && !vd->isInitCapture() &&
vd->getDeclContext() == dc) {
QualType ty = vd->getType();
return ty->isScalarType() || ty->isVectorType();
@@ -236,7 +236,7 @@ void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
}
const CFGBlock *DataflowWorklist::dequeue() {
- const CFGBlock *B = 0;
+ const CFGBlock *B = nullptr;
// First dequeue from the worklist. This can represent
// updates along backedges that we want propagated as quickly as possible.
@@ -250,7 +250,7 @@ const CFGBlock *DataflowWorklist::dequeue() {
++PO_I;
}
else {
- return 0;
+ return nullptr;
}
assert(enqueuedBlocks[B->getBlockID()] == true);
@@ -295,7 +295,7 @@ static FindVarResult findVar(const Expr *E, const DeclContext *DC) {
if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
if (isTrackedVar(VD, DC))
return FindVarResult(VD, DRE);
- return FindVarResult(0, 0);
+ return FindVarResult(nullptr, nullptr);
}
/// \brief Classify each DeclRefExpr as an initialization or a use. Any
@@ -353,7 +353,7 @@ static const DeclRefExpr *getSelfInitExpr(VarDecl *VD) {
if (DRE && DRE->getDecl() == VD)
return DRE;
}
- return 0;
+ return nullptr;
}
void ClassifyRefs::classify(const Expr *E, Class C) {
@@ -373,9 +373,8 @@ void ClassifyRefs::classify(const Expr *E, Class C) {
}
void ClassifyRefs::VisitDeclStmt(DeclStmt *DS) {
- for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
- DI != DE; ++DI) {
- VarDecl *VD = dyn_cast<VarDecl>(*DI);
+ for (auto *DI : DS->decls()) {
+ VarDecl *VD = dyn_cast<VarDecl>(DI);
if (VD && isTrackedVar(VD))
if (const DeclRefExpr *DRE = getSelfInitExpr(VD))
Classification[DRE] = SelfInit;
@@ -535,12 +534,15 @@ public:
for (CFGBlock::const_pred_iterator I = B->pred_begin(), E = B->pred_end();
I != E; ++I) {
const CFGBlock *Pred = *I;
+ if (!Pred)
+ continue;
+
Value AtPredExit = vals.getValue(Pred, B, vd);
if (AtPredExit == Initialized)
// This block initializes the variable.
continue;
if (AtPredExit == MayUninitialized &&
- vals.getValue(B, 0, vd) == Uninitialized) {
+ vals.getValue(B, nullptr, vd) == Uninitialized) {
// This block declares the variable (uninitialized), and is reachable
// from a block that initializes the variable. We can't guarantee to
// give an earlier location for the diagnostic (and it appears that
@@ -630,12 +632,11 @@ void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS) {
void TransferFunctions::VisitBlockExpr(BlockExpr *be) {
const BlockDecl *bd = be->getBlockDecl();
- for (BlockDecl::capture_const_iterator i = bd->capture_begin(),
- e = bd->capture_end() ; i != e; ++i) {
- const VarDecl *vd = i->getVariable();
+ for (const auto &I : bd->captures()) {
+ const VarDecl *vd = I.getVariable();
if (!isTrackedVar(vd))
continue;
- if (i->isByRef()) {
+ if (I.isByRef()) {
vals[vd] = Initialized;
continue;
}
@@ -691,9 +692,8 @@ void TransferFunctions::VisitBinaryOperator(BinaryOperator *BO) {
}
void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
- for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
- DI != DE; ++DI) {
- VarDecl *VD = dyn_cast<VarDecl>(*DI);
+ for (auto *DI : DS->decls()) {
+ VarDecl *VD = dyn_cast<VarDecl>(DI);
if (VD && isTrackedVar(VD)) {
if (getSelfInitExpr(VD)) {
// If the initializer consists solely of a reference to itself, we
@@ -751,6 +751,8 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
for (CFGBlock::const_pred_iterator I = block->pred_begin(),
E = block->pred_end(); I != E; ++I) {
const CFGBlock *pred = *I;
+ if (!pred)
+ continue;
if (wasAnalyzed[pred->getBlockID()]) {
vals.mergeIntoScratch(vals.getValueVector(pred), isFirst);
isFirst = false;
@@ -787,8 +789,8 @@ struct PruneBlocksHandler : public UninitVariablesHandler {
/// The current block to scribble use information.
unsigned currentBlock;
- virtual void handleUseOfUninitVariable(const VarDecl *vd,
- const UninitUse &use) {
+ void handleUseOfUninitVariable(const VarDecl *vd,
+ const UninitUse &use) override {
hadUse[currentBlock] = true;
hadAnyUse = true;
}
@@ -796,7 +798,7 @@ struct PruneBlocksHandler : public UninitVariablesHandler {
/// Called when the uninitialized variable analysis detects the
/// idiom 'int x = x'. All other uses of 'x' within the initializer
/// are handled by handleUseOfUninitVariable.
- virtual void handleSelfInit(const VarDecl *vd) {
+ void handleSelfInit(const VarDecl *vd) override {
hadUse[currentBlock] = true;
hadAnyUse = true;
}
diff --git a/lib/Basic/Attributes.cpp b/lib/Basic/Attributes.cpp
new file mode 100644
index 000000000000..a05ad053db04
--- /dev/null
+++ b/lib/Basic/Attributes.cpp
@@ -0,0 +1,17 @@
+#include "clang/Basic/Attributes.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "llvm/ADT/StringSwitch.h"
+using namespace clang;
+
+bool clang::hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
+ const IdentifierInfo *Attr, const llvm::Triple &T,
+ const LangOptions &LangOpts) {
+ StringRef Name = Attr->getName();
+ // Normalize the attribute name, __foo__ becomes foo.
+ if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__"))
+ Name = Name.substr(2, Name.size() - 4);
+
+#include "clang/Basic/AttrHasAttributeImpl.inc"
+
+ return false;
+}
diff --git a/lib/Basic/Builtins.cpp b/lib/Basic/Builtins.cpp
index c84dd6dc38ff..8efcac6d7fe4 100644
--- a/lib/Basic/Builtins.cpp
+++ b/lib/Basic/Builtins.cpp
@@ -20,7 +20,7 @@
using namespace clang;
static const Builtin::Info BuiltinInfo[] = {
- { "not a builtin function", 0, 0, 0, ALL_LANGUAGES },
+ { "not a builtin function", nullptr, nullptr, nullptr, ALL_LANGUAGES},
#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
#define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) { #ID, TYPE, ATTRS, 0, BUILTIN_LANG },
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, BUILTIN_LANG) { #ID, TYPE, ATTRS, HEADER,\
@@ -37,7 +37,7 @@ const Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const {
Builtin::Context::Context() {
// Get the target specific builtins from the target.
- TSRecords = 0;
+ TSRecords = nullptr;
NumTSRecords = 0;
}
@@ -76,7 +76,7 @@ void Builtin::Context::InitializeBuiltins(IdentifierTable &Table,
// Step #2: Register target-specific builtins.
for (unsigned i = 0, e = NumTSRecords; i != e; ++i)
- if (!LangOpts.NoBuiltin || !strchr(TSRecords[i].Attributes, 'f'))
+ if (BuiltinIsSupported(TSRecords[i], LangOpts))
Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin);
}
@@ -97,40 +97,35 @@ void Builtin::Context::ForgetBuiltin(unsigned ID, IdentifierTable &Table) {
Table.get(GetRecord(ID).Name).setBuiltinID(0);
}
-bool
-Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx,
- bool &HasVAListArg) {
- const char *Printf = strpbrk(GetRecord(ID).Attributes, "pP");
- if (!Printf)
+bool Builtin::Context::isLike(unsigned ID, unsigned &FormatIdx,
+ bool &HasVAListArg, const char *Fmt) const {
+ assert(Fmt && "Not passed a format string");
+ assert(::strlen(Fmt) == 2 &&
+ "Format string needs to be two characters long");
+ assert(::toupper(Fmt[0]) == Fmt[1] &&
+ "Format string is not in the form \"xX\"");
+
+ const char *Like = ::strpbrk(GetRecord(ID).Attributes, Fmt);
+ if (!Like)
return false;
- HasVAListArg = (*Printf == 'P');
+ HasVAListArg = (*Like == Fmt[1]);
- ++Printf;
- assert(*Printf == ':' && "p or P specifier must have be followed by a ':'");
- ++Printf;
+ ++Like;
+ assert(*Like == ':' && "Format specifier must be followed by a ':'");
+ ++Like;
- assert(strchr(Printf, ':') && "printf specifier must end with a ':'");
- FormatIdx = strtol(Printf, 0, 10);
+ assert(::strchr(Like, ':') && "Format specifier must end with a ':'");
+ FormatIdx = ::strtol(Like, nullptr, 10);
return true;
}
-// FIXME: Refactor with isPrintfLike.
-bool
-Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx,
- bool &HasVAListArg) {
- const char *Scanf = strpbrk(GetRecord(ID).Attributes, "sS");
- if (!Scanf)
- return false;
-
- HasVAListArg = (*Scanf == 'S');
-
- ++Scanf;
- assert(*Scanf == ':' && "s or S specifier must have be followed by a ':'");
- ++Scanf;
-
- assert(strchr(Scanf, ':') && "printf specifier must end with a ':'");
- FormatIdx = strtol(Scanf, 0, 10);
- return true;
+bool Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx,
+ bool &HasVAListArg) {
+ return isLike(ID, FormatIdx, HasVAListArg, "pP");
}
+bool Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx,
+ bool &HasVAListArg) {
+ return isLike(ID, FormatIdx, HasVAListArg, "sS");
+}
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt
index 34111691c82e..0df82b3bc906 100644
--- a/lib/Basic/CMakeLists.txt
+++ b/lib/Basic/CMakeLists.txt
@@ -1,6 +1,10 @@
-set(LLVM_LINK_COMPONENTS mc)
+set(LLVM_LINK_COMPONENTS
+ MC
+ Support
+ )
add_clang_library(clangBasic
+ Attributes.cpp
Builtins.cpp
CharInfo.cpp
Diagnostic.cpp
@@ -20,6 +24,8 @@ add_clang_library(clangBasic
TokenKinds.cpp
Version.cpp
VersionTuple.cpp
+ VirtualFileSystem.cpp
+ Warnings.cpp
)
# Determine Subversion revision.
@@ -29,17 +35,15 @@ if( NOT IS_SYMLINK "${CLANG_SOURCE_DIR}" ) # See PR 8437
find_package(Subversion)
endif()
if (Subversion_FOUND AND EXISTS "${CLANG_SOURCE_DIR}/.svn")
- # Create custom target to generate the Subversion version include.
- add_custom_target(clang_revision_tag ALL
- COMMAND ${CMAKE_COMMAND} -DFIRST_SOURCE_DIR=${LLVM_MAIN_SRC_DIR}
- -DFIRST_REPOSITORY=LLVM_REPOSITORY
- -DSECOND_SOURCE_DIR=${CLANG_SOURCE_DIR}
- -DSECOND_REPOSITORY=SVN_REPOSITORY
- -DHEADER_FILE=${CMAKE_CURRENT_BINARY_DIR}/SVNVersion.inc
- -P ${LLVM_MAIN_SRC_DIR}/cmake/modules/GetSVN.cmake)
+ set(FIRST_SOURCE_DIR ${LLVM_MAIN_SRC_DIR})
+ set(FIRST_REPOSITORY LLVM_REPOSITORY)
+ set(SECOND_SOURCE_DIR ${CLANG_SOURCE_DIR})
+ set(SECOND_REPOSITORY SVN_REPOSITORY)
+ set(HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/SVNVersion.inc)
+ include(GetSVN)
# Mark the generated header as being generated.
-message(STATUS "Expecting header to go in ${CMAKE_CURRENT_BINARY_DIR}/SVNVersion.inc")
+ message(STATUS "Expecting header to go in ${CMAKE_CURRENT_BINARY_DIR}/SVNVersion.inc")
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/SVNVersion.inc
PROPERTIES GENERATED TRUE
HEADER_FILE_ONLY TRUE)
@@ -49,25 +53,3 @@ message(STATUS "Expecting header to go in ${CMAKE_CURRENT_BINARY_DIR}/SVNVersion
PROPERTIES COMPILE_DEFINITIONS "HAVE_SVN_VERSION_INC")
endif()
-
-add_dependencies(clangBasic
- ClangARMNeon
- ClangAttrList
- ClangDiagnosticAnalysis
- ClangDiagnosticAST
- ClangDiagnosticComment
- ClangDiagnosticCommon
- ClangDiagnosticDriver
- ClangDiagnosticFrontend
- ClangDiagnosticGroups
- ClangDiagnosticIndexName
- ClangDiagnosticLex
- ClangDiagnosticParse
- ClangDiagnosticSema
- ClangDiagnosticSerialization
- )
-
-# clangBasic depends on the version.
-if (Subversion_FOUND AND EXISTS "${CLANG_SOURCE_DIR}/.svn")
- add_dependencies(clangBasic clang_revision_tag)
-endif() \ No newline at end of file
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 45d4b539e8c2..4567e3267131 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -24,15 +24,13 @@
using namespace clang;
static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT,
- const char *Modifier, unsigned ML,
- const char *Argument, unsigned ArgLen,
- const DiagnosticsEngine::ArgumentValue *PrevArgs,
- unsigned NumPrevArgs,
- SmallVectorImpl<char> &Output,
- void *Cookie,
- ArrayRef<intptr_t> QualTypeVals) {
- const char *Str = "<can't format argument>";
- Output.append(Str, Str+strlen(Str));
+ StringRef Modifier, StringRef Argument,
+ ArrayRef<DiagnosticsEngine::ArgumentValue> PrevArgs,
+ SmallVectorImpl<char> &Output,
+ void *Cookie,
+ ArrayRef<intptr_t> QualTypeVals) {
+ StringRef Str = "<can't format argument>";
+ Output.append(Str.begin(), Str.end());
}
@@ -41,9 +39,9 @@ DiagnosticsEngine::DiagnosticsEngine(
DiagnosticOptions *DiagOpts,
DiagnosticConsumer *client, bool ShouldOwnClient)
: Diags(diags), DiagOpts(DiagOpts), Client(client),
- OwnsDiagClient(ShouldOwnClient), SourceMgr(0) {
+ OwnsDiagClient(ShouldOwnClient), SourceMgr(nullptr) {
ArgToStringFn = DummyArgToStringFn;
- ArgToStringCookie = 0;
+ ArgToStringCookie = nullptr;
AllExtensionsSilenced = 0;
IgnoreAllWarnings = false;
@@ -56,7 +54,7 @@ DiagnosticsEngine::DiagnosticsEngine(
PrintTemplateTree = false;
ShowColors = false;
ShowOverloads = Ovl_All;
- ExtBehavior = Ext_Ignore;
+ ExtBehavior = diag::Severity::Ignored;
ErrorLimit = 0;
TemplateBacktraceLimit = 0;
@@ -157,17 +155,17 @@ DiagnosticsEngine::GetDiagStatePointForLoc(SourceLocation L) const {
if (LastStateChangePos.isValid() &&
Loc.isBeforeInTranslationUnitThan(LastStateChangePos))
Pos = std::upper_bound(DiagStatePoints.begin(), DiagStatePoints.end(),
- DiagStatePoint(0, Loc));
+ DiagStatePoint(nullptr, Loc));
--Pos;
return Pos;
}
-void DiagnosticsEngine::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
- SourceLocation L) {
+void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map,
+ SourceLocation L) {
assert(Diag < diag::DIAG_UPPER_LIMIT &&
"Can only map builtin diagnostics");
assert((Diags->isBuiltinWarningOrExtension(Diag) ||
- (Map == diag::MAP_FATAL || Map == diag::MAP_ERROR)) &&
+ (Map == diag::Severity::Fatal || Map == diag::Severity::Error)) &&
"Cannot map errors into warnings!");
assert(!DiagStatePoints.empty());
assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location");
@@ -175,17 +173,17 @@ void DiagnosticsEngine::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
FullSourceLoc Loc = SourceMgr? FullSourceLoc(L, *SourceMgr) : FullSourceLoc();
FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
// Don't allow a mapping to a warning override an error/fatal mapping.
- if (Map == diag::MAP_WARNING) {
- DiagnosticMappingInfo &Info = GetCurDiagState()->getOrAddMappingInfo(Diag);
- if (Info.getMapping() == diag::MAP_ERROR ||
- Info.getMapping() == diag::MAP_FATAL)
- Map = Info.getMapping();
+ if (Map == diag::Severity::Warning) {
+ DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
+ if (Info.getSeverity() == diag::Severity::Error ||
+ Info.getSeverity() == diag::Severity::Fatal)
+ Map = Info.getSeverity();
}
- DiagnosticMappingInfo MappingInfo = makeMappingInfo(Map, L);
+ DiagnosticMapping Mapping = makeUserMapping(Map, L);
// Common case; setting all the diagnostics of a group in one place.
if (Loc.isInvalid() || Loc == LastStateChangePos) {
- GetCurDiagState()->setMappingInfo(Diag, MappingInfo);
+ GetCurDiagState()->setMapping(Diag, Mapping);
return;
}
@@ -198,7 +196,7 @@ void DiagnosticsEngine::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
// the new state became active.
DiagStates.push_back(*GetCurDiagState());
PushDiagStatePoint(&DiagStates.back(), Loc);
- GetCurDiagState()->setMappingInfo(Diag, MappingInfo);
+ GetCurDiagState()->setMapping(Diag, Mapping);
return;
}
@@ -211,81 +209,64 @@ void DiagnosticsEngine::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
// Update all diagnostic states that are active after the given location.
for (DiagStatePointsTy::iterator
I = Pos+1, E = DiagStatePoints.end(); I != E; ++I) {
- GetCurDiagState()->setMappingInfo(Diag, MappingInfo);
+ GetCurDiagState()->setMapping(Diag, Mapping);
}
// If the location corresponds to an existing point, just update its state.
if (Pos->Loc == Loc) {
- GetCurDiagState()->setMappingInfo(Diag, MappingInfo);
+ GetCurDiagState()->setMapping(Diag, Mapping);
return;
}
// Create a new state/point and fit it into the vector of DiagStatePoints
// so that the vector is always ordered according to location.
- Pos->Loc.isBeforeInTranslationUnitThan(Loc);
+ assert(Pos->Loc.isBeforeInTranslationUnitThan(Loc));
DiagStates.push_back(*Pos->State);
DiagState *NewState = &DiagStates.back();
- GetCurDiagState()->setMappingInfo(Diag, MappingInfo);
+ GetCurDiagState()->setMapping(Diag, Mapping);
DiagStatePoints.insert(Pos+1, DiagStatePoint(NewState,
FullSourceLoc(Loc, *SourceMgr)));
}
-bool DiagnosticsEngine::setDiagnosticGroupMapping(
- StringRef Group, diag::Mapping Map, SourceLocation Loc)
-{
+bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor,
+ StringRef Group, diag::Severity Map,
+ SourceLocation Loc) {
// Get the diagnostics in this group.
SmallVector<diag::kind, 8> GroupDiags;
- if (Diags->getDiagnosticsInGroup(Group, GroupDiags))
+ if (Diags->getDiagnosticsInGroup(Flavor, Group, GroupDiags))
return true;
// Set the mapping.
for (unsigned i = 0, e = GroupDiags.size(); i != e; ++i)
- setDiagnosticMapping(GroupDiags[i], Map, Loc);
+ setSeverity(GroupDiags[i], Map, Loc);
return false;
}
-void DiagnosticsEngine::setDiagnosticWarningAsError(diag::kind Diag,
- bool Enabled) {
- // If we are enabling this feature, just set the diagnostic mappings to map to
- // errors.
- if (Enabled)
- setDiagnosticMapping(Diag, diag::MAP_ERROR, SourceLocation());
-
- // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
- // potentially downgrade anything already mapped to be a warning.
- DiagnosticMappingInfo &Info = GetCurDiagState()->getOrAddMappingInfo(Diag);
-
- if (Info.getMapping() == diag::MAP_ERROR ||
- Info.getMapping() == diag::MAP_FATAL)
- Info.setMapping(diag::MAP_WARNING);
-
- Info.setNoWarningAsError(true);
-}
-
bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group,
bool Enabled) {
// If we are enabling this feature, just set the diagnostic mappings to map to
// errors.
if (Enabled)
- return setDiagnosticGroupMapping(Group, diag::MAP_ERROR);
+ return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
+ diag::Severity::Error);
// Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
// potentially downgrade anything already mapped to be a warning.
// Get the diagnostics in this group.
SmallVector<diag::kind, 8> GroupDiags;
- if (Diags->getDiagnosticsInGroup(Group, GroupDiags))
+ if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group,
+ GroupDiags))
return true;
// Perform the mapping change.
for (unsigned i = 0, e = GroupDiags.size(); i != e; ++i) {
- DiagnosticMappingInfo &Info = GetCurDiagState()->getOrAddMappingInfo(
- GroupDiags[i]);
+ DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(GroupDiags[i]);
- if (Info.getMapping() == diag::MAP_ERROR ||
- Info.getMapping() == diag::MAP_FATAL)
- Info.setMapping(diag::MAP_WARNING);
+ if (Info.getSeverity() == diag::Severity::Error ||
+ Info.getSeverity() == diag::Severity::Fatal)
+ Info.setSeverity(diag::Severity::Warning);
Info.setNoWarningAsError(true);
}
@@ -293,45 +274,29 @@ bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group,
return false;
}
-void DiagnosticsEngine::setDiagnosticErrorAsFatal(diag::kind Diag,
- bool Enabled) {
- // If we are enabling this feature, just set the diagnostic mappings to map to
- // errors.
- if (Enabled)
- setDiagnosticMapping(Diag, diag::MAP_FATAL, SourceLocation());
-
- // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
- // potentially downgrade anything already mapped to be a warning.
- DiagnosticMappingInfo &Info = GetCurDiagState()->getOrAddMappingInfo(Diag);
-
- if (Info.getMapping() == diag::MAP_FATAL)
- Info.setMapping(diag::MAP_ERROR);
-
- Info.setNoErrorAsFatal(true);
-}
-
bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
bool Enabled) {
// If we are enabling this feature, just set the diagnostic mappings to map to
// fatal errors.
if (Enabled)
- return setDiagnosticGroupMapping(Group, diag::MAP_FATAL);
+ return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
+ diag::Severity::Fatal);
// Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
// potentially downgrade anything already mapped to be an error.
// Get the diagnostics in this group.
SmallVector<diag::kind, 8> GroupDiags;
- if (Diags->getDiagnosticsInGroup(Group, GroupDiags))
+ if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group,
+ GroupDiags))
return true;
// Perform the mapping change.
for (unsigned i = 0, e = GroupDiags.size(); i != e; ++i) {
- DiagnosticMappingInfo &Info = GetCurDiagState()->getOrAddMappingInfo(
- GroupDiags[i]);
+ DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(GroupDiags[i]);
- if (Info.getMapping() == diag::MAP_FATAL)
- Info.setMapping(diag::MAP_ERROR);
+ if (Info.getSeverity() == diag::Severity::Fatal)
+ Info.setSeverity(diag::Severity::Error);
Info.setNoErrorAsFatal(true);
}
@@ -339,16 +304,17 @@ bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
return false;
}
-void DiagnosticsEngine::setMappingToAllDiagnostics(diag::Mapping Map,
- SourceLocation Loc) {
+void DiagnosticsEngine::setSeverityForAll(diag::Flavor Flavor,
+ diag::Severity Map,
+ SourceLocation Loc) {
// Get all the diagnostics.
SmallVector<diag::kind, 64> AllDiags;
- Diags->getAllDiagnostics(AllDiags);
+ Diags->getAllDiagnostics(Flavor, AllDiags);
// Set the mapping.
for (unsigned i = 0, e = AllDiags.size(); i != e; ++i)
if (Diags->isBuiltinWarningOrExtension(AllDiags[i]))
- setDiagnosticMapping(AllDiags[i], Map, Loc);
+ setSeverity(AllDiags[i], Map, Loc);
}
void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) {
@@ -358,22 +324,19 @@ void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) {
CurDiagID = storedDiag.getID();
NumDiagArgs = 0;
- NumDiagRanges = storedDiag.range_size();
- assert(NumDiagRanges < DiagnosticsEngine::MaxRanges &&
- "Too many arguments to diagnostic!");
- unsigned i = 0;
+ DiagRanges.clear();
+ DiagRanges.reserve(storedDiag.range_size());
for (StoredDiagnostic::range_iterator
RI = storedDiag.range_begin(),
RE = storedDiag.range_end(); RI != RE; ++RI)
- DiagRanges[i++] = *RI;
+ DiagRanges.push_back(*RI);
- assert(NumDiagRanges < DiagnosticsEngine::MaxFixItHints &&
- "Too many arguments to diagnostic!");
- NumDiagFixItHints = 0;
+ DiagFixItHints.clear();
+ DiagFixItHints.reserve(storedDiag.fixit_size());
for (StoredDiagnostic::fixit_iterator
FI = storedDiag.fixit_begin(),
FE = storedDiag.fixit_end(); FI != FE; ++FI)
- DiagFixItHints[NumDiagFixItHints++] = *FI;
+ DiagFixItHints.push_back(*FI);
assert(Client && "DiagnosticConsumer not set!");
Level DiagLevel = storedDiag.getLevel();
@@ -639,6 +602,17 @@ static void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo,
}
}
+/// \brief Returns the friendly description for a token kind that will appear
+/// without quotes in diagnostic messages. These strings may be translatable in
+/// future.
+static const char *getTokenDescForDiagnostic(tok::TokenKind Kind) {
+ switch (Kind) {
+ case tok::identifier:
+ return "identifier";
+ default:
+ return nullptr;
+ }
+}
/// FormatDiagnostic - Format this diagnostic into a string, substituting the
/// formal arguments into the %0 slots. The result is appended onto the Str
@@ -696,7 +670,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
// The digit is a number from 0-9 indicating which argument this comes from.
// The modifier is a string of digits from the set [-a-z]+, arguments is a
// brace enclosed string.
- const char *Modifier = 0, *Argument = 0;
+ const char *Modifier = nullptr, *Argument = nullptr;
unsigned ModifierLen = 0, ArgumentLen = 0;
// Check to see if we have a modifier. If so eat it.
@@ -812,6 +786,28 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
}
break;
}
+ // ---- TOKEN SPELLINGS ----
+ case DiagnosticsEngine::ak_tokenkind: {
+ tok::TokenKind Kind = static_cast<tok::TokenKind>(getRawArg(ArgNo));
+ assert(ModifierLen == 0 && "No modifiers for token kinds yet");
+
+ llvm::raw_svector_ostream Out(OutStr);
+ if (const char *S = tok::getPunctuatorSpelling(Kind))
+ // Quoted token spelling for punctuators.
+ Out << '\'' << S << '\'';
+ else if (const char *S = tok::getKeywordSpelling(Kind))
+ // Unquoted token spelling for keywords.
+ Out << S;
+ else if (const char *S = getTokenDescForDiagnostic(Kind))
+ // Unquoted translatable token name.
+ Out << S;
+ else if (const char *S = tok::getTokenName(Kind))
+ // Debug name, shouldn't appear in user-facing diagnostics.
+ Out << '<' << S << '>';
+ else
+ Out << "(null)";
+ break;
+ }
// ---- NAMES and TYPES ----
case DiagnosticsEngine::ak_identifierinfo: {
const IdentifierInfo *II = getArgIdentifier(ArgNo);
@@ -832,10 +828,11 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
case DiagnosticsEngine::ak_nameddecl:
case DiagnosticsEngine::ak_nestednamespec:
case DiagnosticsEngine::ak_declcontext:
+ case DiagnosticsEngine::ak_attr:
getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo),
- Modifier, ModifierLen,
- Argument, ArgumentLen,
- FormattedArgs.data(), FormattedArgs.size(),
+ StringRef(Modifier, ModifierLen),
+ StringRef(Argument, ArgumentLen),
+ FormattedArgs,
OutStr, QualTypeVals);
break;
case DiagnosticsEngine::ak_qualtype_pair:
@@ -857,10 +854,9 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
TDT.PrintFromType = true;
TDT.PrintTree = true;
getDiags()->ConvertArgToString(Kind, val,
- Modifier, ModifierLen,
- Argument, ArgumentLen,
- FormattedArgs.data(),
- FormattedArgs.size(),
+ StringRef(Modifier, ModifierLen),
+ StringRef(Argument, ArgumentLen),
+ FormattedArgs,
Tree, QualTypeVals);
// If there is no tree information, fall back to regular printing.
if (!Tree.empty()) {
@@ -881,9 +877,9 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
TDT.PrintTree = false;
TDT.PrintFromType = true;
getDiags()->ConvertArgToString(Kind, val,
- Modifier, ModifierLen,
- Argument, ArgumentLen,
- FormattedArgs.data(), FormattedArgs.size(),
+ StringRef(Modifier, ModifierLen),
+ StringRef(Argument, ArgumentLen),
+ FormattedArgs,
OutStr, QualTypeVals);
if (!TDT.TemplateDiffUsed)
FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype,
@@ -895,9 +891,9 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
// Append second type
TDT.PrintFromType = false;
getDiags()->ConvertArgToString(Kind, val,
- Modifier, ModifierLen,
- Argument, ArgumentLen,
- FormattedArgs.data(), FormattedArgs.size(),
+ StringRef(Modifier, ModifierLen),
+ StringRef(Argument, ArgumentLen),
+ FormattedArgs,
OutStr, QualTypeVals);
if (!TDT.TemplateDiffUsed)
FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype,
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index 9d99fbedd83c..ec244ccda3cb 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -15,8 +15,8 @@
#include "clang/Basic/AllDiagnostics.h"
#include "clang/Basic/DiagnosticCategories.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/ErrorHandling.h"
#include <map>
using namespace clang;
@@ -30,14 +30,15 @@ namespace {
// Diagnostic classes.
enum {
CLASS_NOTE = 0x01,
- CLASS_WARNING = 0x02,
- CLASS_EXTENSION = 0x03,
- CLASS_ERROR = 0x04
+ CLASS_REMARK = 0x02,
+ CLASS_WARNING = 0x03,
+ CLASS_EXTENSION = 0x04,
+ CLASS_ERROR = 0x05
};
struct StaticDiagInfoRec {
uint16_t DiagID;
- unsigned Mapping : 3;
+ unsigned DefaultSeverity : 3;
unsigned Class : 3;
unsigned SFINAE : 2;
unsigned WarnNoWerror : 1;
@@ -57,6 +58,11 @@ struct StaticDiagInfoRec {
return StringRef(DescriptionStr, DescriptionLen);
}
+ diag::Flavor getFlavor() const {
+ return Class == CLASS_REMARK ? diag::Flavor::Remark
+ : diag::Flavor::WarningOrError;
+ }
+
bool operator<(const StaticDiagInfoRec &RHS) const {
return DiagID < RHS.DiagID;
}
@@ -65,12 +71,13 @@ struct StaticDiagInfoRec {
} // namespace anonymous
static const StaticDiagInfoRec StaticDiagInfo[] = {
-#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \
- SFINAE,NOWERROR,SHOWINSYSHEADER,CATEGORY) \
- { diag::ENUM, DEFAULT_MAPPING, CLASS, \
- DiagnosticIDs::SFINAE, \
- NOWERROR, SHOWINSYSHEADER, CATEGORY, GROUP, \
- STR_SIZE(DESC, uint16_t), DESC },
+#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \
+ SHOWINSYSHEADER, CATEGORY) \
+ { \
+ diag::ENUM, DEFAULT_SEVERITY, CLASS, DiagnosticIDs::SFINAE, NOWERROR, \
+ SHOWINSYSHEADER, CATEGORY, GROUP, STR_SIZE(DESC, uint16_t), DESC \
+ } \
+ ,
#include "clang/Basic/DiagnosticCommonKinds.inc"
#include "clang/Basic/DiagnosticDriverKinds.inc"
#include "clang/Basic/DiagnosticFrontendKinds.inc"
@@ -108,10 +115,10 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
// Out of bounds diag. Can't be in the table.
using namespace diag;
if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON)
- return 0;
+ return nullptr;
// Compute the index of the requested diagnostic in the static table.
- // 1. Add the number of diagnostics in each category preceeding the
+ // 1. Add the number of diagnostics in each category preceding the
// diagnostic and of the category the diagnostic is in. This gives us
// the offset of the category in the table.
// 2. Subtract the number of IDs in each category from our ID. This gives us
@@ -138,7 +145,7 @@ CATEGORY(ANALYSIS, SEMA)
// Avoid out of bounds reads.
if (ID + Offset >= StaticDiagInfoSize)
- return 0;
+ return nullptr;
assert(ID < StaticDiagInfoSize && Offset < StaticDiagInfoSize);
@@ -147,28 +154,22 @@ CATEGORY(ANALYSIS, SEMA)
// happen when this function is called with an ID that points into a hole in
// the diagID space.
if (Found->DiagID != DiagID)
- return 0;
+ return nullptr;
return Found;
}
-static DiagnosticMappingInfo GetDefaultDiagMappingInfo(unsigned DiagID) {
- DiagnosticMappingInfo Info = DiagnosticMappingInfo::Make(
- diag::MAP_FATAL, /*IsUser=*/false, /*IsPragma=*/false);
+static DiagnosticMapping GetDefaultDiagMapping(unsigned DiagID) {
+ DiagnosticMapping Info = DiagnosticMapping::Make(
+ diag::Severity::Fatal, /*IsUser=*/false, /*IsPragma=*/false);
if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) {
- Info.setMapping((diag::Mapping) StaticInfo->Mapping);
+ Info.setSeverity((diag::Severity)StaticInfo->DefaultSeverity);
if (StaticInfo->WarnNoWerror) {
- assert(Info.getMapping() == diag::MAP_WARNING &&
+ assert(Info.getSeverity() == diag::Severity::Warning &&
"Unexpected mapping with no-Werror bit!");
Info.setNoWarningAsError(true);
}
-
- if (StaticInfo->WarnShowInSystemHeader) {
- assert(Info.getMapping() == diag::MAP_WARNING &&
- "Unexpected mapping with show-in-system-header bit!");
- Info.setShowInSystemHeader(true);
- }
}
return Info;
@@ -197,15 +198,14 @@ namespace {
// Unfortunately, the split between DiagnosticIDs and Diagnostic is not
// particularly clean, but for now we just implement this method here so we can
// access GetDefaultDiagMapping.
-DiagnosticMappingInfo &DiagnosticsEngine::DiagState::getOrAddMappingInfo(
- diag::kind Diag)
-{
- std::pair<iterator, bool> Result = DiagMap.insert(
- std::make_pair(Diag, DiagnosticMappingInfo()));
+DiagnosticMapping &
+DiagnosticsEngine::DiagState::getOrAddMapping(diag::kind Diag) {
+ std::pair<iterator, bool> Result =
+ DiagMap.insert(std::make_pair(Diag, DiagnosticMapping()));
// Initialize the entry if we added it.
if (Result.second)
- Result.first->second = GetDefaultDiagMappingInfo(Diag);
+ Result.first->second = GetDefaultDiagMapping(Diag);
return Result.first->second;
}
@@ -215,7 +215,7 @@ static const StaticDiagCategoryRec CategoryNameTable[] = {
#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) },
#include "clang/Basic/DiagnosticGroups.inc"
#undef GET_CATEGORY_TABLE
- { 0, 0 }
+ { nullptr, 0 }
};
/// getNumberOfCategories - Return the number of categories
@@ -264,14 +264,14 @@ namespace clang {
/// getDescription - Return the description of the specified custom
/// diagnostic.
StringRef getDescription(unsigned DiagID) const {
- assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
+ assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&
"Invalid diagnostic ID");
return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second;
}
/// getLevel - Return the level of the specified custom diagnostic.
DiagnosticIDs::Level getLevel(unsigned DiagID) const {
- assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
+ assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() &&
"Invalid diagnostic ID");
return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
}
@@ -300,9 +300,7 @@ namespace clang {
// Common Diagnostic implementation
//===----------------------------------------------------------------------===//
-DiagnosticIDs::DiagnosticIDs() {
- CustomDiagInfo = 0;
-}
+DiagnosticIDs::DiagnosticIDs() { CustomDiagInfo = nullptr; }
DiagnosticIDs::~DiagnosticIDs() {
delete CustomDiagInfo;
@@ -311,10 +309,13 @@ DiagnosticIDs::~DiagnosticIDs() {
/// getCustomDiagID - Return an ID for a diagnostic with the specified message
/// and level. If this is the first request for this diagnostic, it is
/// registered and created, otherwise the existing ID is returned.
-unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef Message) {
- if (CustomDiagInfo == 0)
+///
+/// \param FormatString A fixed diagnostic format string that will be hashed and
+/// mapped to a unique DiagID.
+unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef FormatString) {
+ if (!CustomDiagInfo)
CustomDiagInfo = new diag::CustomDiagInfo();
- return CustomDiagInfo->getOrCreateDiagID(L, Message, *this);
+ return CustomDiagInfo->getOrCreateDiagID(L, FormatString, *this);
}
@@ -344,9 +345,9 @@ bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
if (DiagID >= diag::DIAG_UPPER_LIMIT ||
getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
return false;
-
+
EnabledByDefault =
- GetDefaultDiagMappingInfo(DiagID).getMapping() != diag::MAP_IGNORE;
+ GetDefaultDiagMapping(DiagID).getSeverity() != diag::Severity::Ignored;
return true;
}
@@ -354,7 +355,7 @@ bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) {
if (DiagID >= diag::DIAG_UPPER_LIMIT)
return false;
- return GetDefaultDiagMappingInfo(DiagID).getMapping() == diag::MAP_ERROR;
+ return GetDefaultDiagMapping(DiagID).getSeverity() == diag::Severity::Error;
}
/// getDescription - Given a diagnostic ID, return a description of the
@@ -362,9 +363,26 @@ bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) {
StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
return Info->getDescription();
+ assert(CustomDiagInfo && "Invalid CustomDiagInfo");
return CustomDiagInfo->getDescription(DiagID);
}
+static DiagnosticIDs::Level toLevel(diag::Severity SV) {
+ switch (SV) {
+ case diag::Severity::Ignored:
+ return DiagnosticIDs::Ignored;
+ case diag::Severity::Remark:
+ return DiagnosticIDs::Remark;
+ case diag::Severity::Warning:
+ return DiagnosticIDs::Warning;
+ case diag::Severity::Error:
+ return DiagnosticIDs::Error;
+ case diag::Severity::Fatal:
+ return DiagnosticIDs::Fatal;
+ }
+ llvm_unreachable("unexpected severity");
+}
+
/// getDiagnosticLevel - Based on the way the client configured the
/// DiagnosticsEngine object, classify the specified diagnostic ID into a Level,
/// by consumable the DiagnosticClient.
@@ -372,12 +390,14 @@ DiagnosticIDs::Level
DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
const DiagnosticsEngine &Diag) const {
// Handle custom diagnostics, which cannot be mapped.
- if (DiagID >= diag::DIAG_UPPER_LIMIT)
+ if (DiagID >= diag::DIAG_UPPER_LIMIT) {
+ assert(CustomDiagInfo && "Invalid CustomDiagInfo");
return CustomDiagInfo->getLevel(DiagID);
+ }
unsigned DiagClass = getBuiltinDiagClass(DiagID);
if (DiagClass == CLASS_NOTE) return DiagnosticIDs::Note;
- return getDiagnosticLevel(DiagID, DiagClass, Loc, Diag);
+ return toLevel(getDiagnosticSeverity(DiagID, Loc, Diag));
}
/// \brief Based on the way the client configured the Diagnostic
@@ -386,41 +406,37 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
///
/// \param Loc The source location we are interested in finding out the
/// diagnostic state. Can be null in order to query the latest state.
-DiagnosticIDs::Level
-DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
- SourceLocation Loc,
- const DiagnosticsEngine &Diag) const {
+diag::Severity
+DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
+ const DiagnosticsEngine &Diag) const {
+ assert(getBuiltinDiagClass(DiagID) != CLASS_NOTE);
+
// Specific non-error diagnostics may be mapped to various levels from ignored
// to error. Errors can only be mapped to fatal.
- DiagnosticIDs::Level Result = DiagnosticIDs::Fatal;
+ diag::Severity Result = diag::Severity::Fatal;
DiagnosticsEngine::DiagStatePointsTy::iterator
Pos = Diag.GetDiagStatePointForLoc(Loc);
DiagnosticsEngine::DiagState *State = Pos->State;
// Get the mapping information, or compute it lazily.
- DiagnosticMappingInfo &MappingInfo = State->getOrAddMappingInfo(
- (diag::kind)DiagID);
-
- switch (MappingInfo.getMapping()) {
- case diag::MAP_IGNORE:
- Result = DiagnosticIDs::Ignored;
- break;
- case diag::MAP_WARNING:
- Result = DiagnosticIDs::Warning;
- break;
- case diag::MAP_ERROR:
- Result = DiagnosticIDs::Error;
- break;
- case diag::MAP_FATAL:
- Result = DiagnosticIDs::Fatal;
- break;
- }
+ DiagnosticMapping &Mapping = State->getOrAddMapping((diag::kind)DiagID);
+
+ // TODO: Can a null severity really get here?
+ if (Mapping.getSeverity() != diag::Severity())
+ Result = Mapping.getSeverity();
// Upgrade ignored diagnostics if -Weverything is enabled.
- if (Diag.EnableAllWarnings && Result == DiagnosticIDs::Ignored &&
- !MappingInfo.isUser())
- Result = DiagnosticIDs::Warning;
+ if (Diag.EnableAllWarnings && Result == diag::Severity::Ignored &&
+ !Mapping.isUser())
+ Result = diag::Severity::Warning;
+
+ // Diagnostics of class REMARK are either printed as remarks or in case they
+ // have been added to -Werror they are printed as errors.
+ // FIXME: Disregarding user-requested remark mappings like this is bogus.
+ if (Result == diag::Severity::Warning &&
+ getBuiltinDiagClass(DiagID) == CLASS_REMARK)
+ Result = diag::Severity::Remark;
// Ignore -pedantic diagnostics inside __extension__ blocks.
// (The diagnostics controlled by -pedantic are the extension diagnostics
@@ -428,62 +444,46 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
bool EnabledByDefault = false;
bool IsExtensionDiag = isBuiltinExtensionDiag(DiagID, EnabledByDefault);
if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault)
- return DiagnosticIDs::Ignored;
+ return diag::Severity::Ignored;
// For extension diagnostics that haven't been explicitly mapped, check if we
// should upgrade the diagnostic.
- if (IsExtensionDiag && !MappingInfo.isUser()) {
- switch (Diag.ExtBehavior) {
- case DiagnosticsEngine::Ext_Ignore:
- break;
- case DiagnosticsEngine::Ext_Warn:
- // Upgrade ignored diagnostics to warnings.
- if (Result == DiagnosticIDs::Ignored)
- Result = DiagnosticIDs::Warning;
- break;
- case DiagnosticsEngine::Ext_Error:
- // Upgrade ignored or warning diagnostics to errors.
- if (Result == DiagnosticIDs::Ignored || Result == DiagnosticIDs::Warning)
- Result = DiagnosticIDs::Error;
- break;
- }
- }
+ if (IsExtensionDiag && !Mapping.isUser())
+ Result = std::max(Result, Diag.ExtBehavior);
// At this point, ignored errors can no longer be upgraded.
- if (Result == DiagnosticIDs::Ignored)
+ if (Result == diag::Severity::Ignored)
return Result;
// Honor -w, which is lower in priority than pedantic-errors, but higher than
// -Werror.
- if (Result == DiagnosticIDs::Warning && Diag.IgnoreAllWarnings)
- return DiagnosticIDs::Ignored;
+ if (Result == diag::Severity::Warning && Diag.IgnoreAllWarnings)
+ return diag::Severity::Ignored;
// If -Werror is enabled, map warnings to errors unless explicitly disabled.
- if (Result == DiagnosticIDs::Warning) {
- if (Diag.WarningsAsErrors && !MappingInfo.hasNoWarningAsError())
- Result = DiagnosticIDs::Error;
+ if (Result == diag::Severity::Warning) {
+ if (Diag.WarningsAsErrors && !Mapping.hasNoWarningAsError())
+ Result = diag::Severity::Error;
}
// If -Wfatal-errors is enabled, map errors to fatal unless explicity
// disabled.
- if (Result == DiagnosticIDs::Error) {
- if (Diag.ErrorsAsFatal && !MappingInfo.hasNoErrorAsFatal())
- Result = DiagnosticIDs::Fatal;
+ if (Result == diag::Severity::Error) {
+ if (Diag.ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())
+ Result = diag::Severity::Fatal;
}
+ // Custom diagnostics always are emitted in system headers.
+ bool ShowInSystemHeader =
+ !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;
+
// If we are in a system header, we ignore it. We look at the diagnostic class
// because we also want to ignore extensions and warnings in -Werror and
// -pedantic-errors modes, which *map* warnings/extensions to errors.
- if (Result >= DiagnosticIDs::Warning &&
- DiagClass != CLASS_ERROR &&
- // Custom diagnostics always are emitted in system headers.
- DiagID < diag::DIAG_UPPER_LIMIT &&
- !MappingInfo.hasShowInSystemHeader() &&
- Diag.SuppressSystemWarnings &&
- Loc.isValid() &&
+ if (Diag.SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&
Diag.getSourceManager().isInSystemHeader(
Diag.getSourceManager().getExpansionLoc(Loc)))
- return DiagnosticIDs::Ignored;
+ return diag::Severity::Ignored;
return Result;
}
@@ -527,40 +527,57 @@ StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
return StringRef();
}
-static void getDiagnosticsInGroup(const WarningOption *Group,
+/// Return \c true if any diagnostics were found in this group, even if they
+/// were filtered out due to having the wrong flavor.
+static bool getDiagnosticsInGroup(diag::Flavor Flavor,
+ const WarningOption *Group,
SmallVectorImpl<diag::kind> &Diags) {
+ // An empty group is considered to be a warning group: we have empty groups
+ // for GCC compatibility, and GCC does not have remarks.
+ if (!Group->Members && !Group->SubGroups)
+ return Flavor == diag::Flavor::Remark ? true : false;
+
+ bool NotFound = true;
+
// Add the members of the option diagnostic set.
const int16_t *Member = DiagArrays + Group->Members;
- for (; *Member != -1; ++Member)
- Diags.push_back(*Member);
+ for (; *Member != -1; ++Member) {
+ if (GetDiagInfo(*Member)->getFlavor() == Flavor) {
+ NotFound = false;
+ Diags.push_back(*Member);
+ }
+ }
// Add the members of the subgroups.
const int16_t *SubGroups = DiagSubGroups + Group->SubGroups;
for (; *SubGroups != (int16_t)-1; ++SubGroups)
- getDiagnosticsInGroup(&OptionTable[(short)*SubGroups], Diags);
+ NotFound &= getDiagnosticsInGroup(Flavor, &OptionTable[(short)*SubGroups],
+ Diags);
+
+ return NotFound;
}
-bool DiagnosticIDs::getDiagnosticsInGroup(
- StringRef Group,
- SmallVectorImpl<diag::kind> &Diags) const {
- const WarningOption *Found =
- std::lower_bound(OptionTable, OptionTable + OptionTableSize, Group,
- WarningOptionCompare);
+bool
+DiagnosticIDs::getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group,
+ SmallVectorImpl<diag::kind> &Diags) const {
+ const WarningOption *Found = std::lower_bound(
+ OptionTable, OptionTable + OptionTableSize, Group, WarningOptionCompare);
if (Found == OptionTable + OptionTableSize ||
Found->getName() != Group)
return true; // Option not found.
- ::getDiagnosticsInGroup(Found, Diags);
- return false;
+ return ::getDiagnosticsInGroup(Flavor, Found, Diags);
}
-void DiagnosticIDs::getAllDiagnostics(
- SmallVectorImpl<diag::kind> &Diags) const {
+void DiagnosticIDs::getAllDiagnostics(diag::Flavor Flavor,
+ SmallVectorImpl<diag::kind> &Diags) const {
for (unsigned i = 0; i != StaticDiagInfoSize; ++i)
- Diags.push_back(StaticDiagInfo[i].DiagID);
+ if (StaticDiagInfo[i].getFlavor() == Flavor)
+ Diags.push_back(StaticDiagInfo[i].DiagID);
}
-StringRef DiagnosticIDs::getNearestWarningOption(StringRef Group) {
+StringRef DiagnosticIDs::getNearestOption(diag::Flavor Flavor,
+ StringRef Group) {
StringRef Best;
unsigned BestDistance = Group.size() + 1; // Sanity threshold.
for (const WarningOption *i = OptionTable, *e = OptionTable + OptionTableSize;
@@ -570,6 +587,14 @@ StringRef DiagnosticIDs::getNearestWarningOption(StringRef Group) {
continue;
unsigned Distance = i->getName().edit_distance(Group, true, BestDistance);
+ if (Distance > BestDistance)
+ continue;
+
+ // Don't suggest groups that are not of this kind.
+ llvm::SmallVector<diag::kind, 8> Diags;
+ if (::getDiagnosticsInGroup(Flavor, i, Diags) || Diags.empty())
+ continue;
+
if (Distance == BestDistance) {
// Two matches with the same distance, don't prefer one over the other.
Best = "";
@@ -677,6 +702,7 @@ void DiagnosticIDs::EmitDiag(DiagnosticsEngine &Diag, Level DiagLevel) const {
bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
if (DiagID >= diag::DIAG_UPPER_LIMIT) {
+ assert(CustomDiagInfo && "Invalid CustomDiagInfo");
// Custom diagnostics.
return CustomDiagInfo->getLevel(DiagID) >= DiagnosticIDs::Error;
}
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index af9b2663cbfa..94210320bff7 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -25,29 +25,13 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/system_error.h"
#include <map>
#include <set>
#include <string>
+#include <system_error>
-// FIXME: This is terrible, we need this for ::close.
-#if !defined(_MSC_VER) && !defined(__MINGW32__)
-#include <unistd.h>
-#include <sys/uio.h>
-#else
-#include <io.h>
-#ifndef S_ISFIFO
-#define S_ISFIFO(x) (0)
-#endif
-#endif
-#if defined(LLVM_ON_UNIX)
-#include <limits.h>
-#endif
using namespace clang;
-// FIXME: Enhance libsystem to support inode and other fields.
-#include <sys/stat.h>
-
/// NON_EXISTENT_DIR - A special value distinct from null that is used to
/// represent a dir name that doesn't exist on the disk.
#define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)
@@ -56,63 +40,24 @@ using namespace clang;
/// represent a filename that doesn't exist on the disk.
#define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)
-
-FileEntry::~FileEntry() {
- // If this FileEntry owns an open file descriptor that never got used, close
- // it.
- if (FD != -1) ::close(FD);
-}
-
-class FileManager::UniqueDirContainer {
- /// UniqueDirs - Cache from ID's to existing directories/files.
- std::map<llvm::sys::fs::UniqueID, DirectoryEntry> UniqueDirs;
-
-public:
- /// getDirectory - Return an existing DirectoryEntry with the given
- /// ID's if there is already one; otherwise create and return a
- /// default-constructed DirectoryEntry.
- DirectoryEntry &getDirectory(const llvm::sys::fs::UniqueID &UniqueID) {
- return UniqueDirs[UniqueID];
- }
-
- size_t size() const { return UniqueDirs.size(); }
-};
-
-class FileManager::UniqueFileContainer {
- /// UniqueFiles - Cache from ID's to existing directories/files.
- std::set<FileEntry> UniqueFiles;
-
-public:
- /// getFile - Return an existing FileEntry with the given ID's if
- /// there is already one; otherwise create and return a
- /// default-constructed FileEntry.
- FileEntry &getFile(llvm::sys::fs::UniqueID UniqueID, bool IsNamedPipe,
- bool InPCH) {
- return const_cast<FileEntry &>(
- *UniqueFiles.insert(FileEntry(UniqueID, IsNamedPipe, InPCH)).first);
- }
-
- size_t size() const { return UniqueFiles.size(); }
-
- void erase(const FileEntry *Entry) { UniqueFiles.erase(*Entry); }
-};
-
//===----------------------------------------------------------------------===//
// Common logic.
//===----------------------------------------------------------------------===//
-FileManager::FileManager(const FileSystemOptions &FSO)
- : FileSystemOpts(FSO),
- UniqueRealDirs(*new UniqueDirContainer()),
- UniqueRealFiles(*new UniqueFileContainer()),
+FileManager::FileManager(const FileSystemOptions &FSO,
+ IntrusiveRefCntPtr<vfs::FileSystem> FS)
+ : FS(FS), FileSystemOpts(FSO),
SeenDirEntries(64), SeenFileEntries(64), NextFileUID(0) {
NumDirLookups = NumFileLookups = 0;
NumDirCacheMisses = NumFileCacheMisses = 0;
+
+ // If the caller doesn't provide a virtual file system, just grab the real
+ // file system.
+ if (!FS)
+ this->FS = vfs::getRealFileSystem();
}
FileManager::~FileManager() {
- delete &UniqueRealDirs;
- delete &UniqueRealFiles;
for (unsigned i = 0, e = VirtualFileEntries.size(); i != e; ++i)
delete VirtualFileEntries[i];
for (unsigned i = 0, e = VirtualDirectoryEntries.size(); i != e; ++i)
@@ -122,8 +67,8 @@ FileManager::~FileManager() {
void FileManager::addStatCache(FileSystemStatCache *statCache,
bool AtBeginning) {
assert(statCache && "No stat cache provided?");
- if (AtBeginning || StatCache.get() == 0) {
- statCache->setNextStatCache(StatCache.take());
+ if (AtBeginning || !StatCache.get()) {
+ statCache->setNextStatCache(StatCache.release());
StatCache.reset(statCache);
return;
}
@@ -155,7 +100,7 @@ void FileManager::removeStatCache(FileSystemStatCache *statCache) {
}
void FileManager::clearStatCaches() {
- StatCache.reset(0);
+ StatCache.reset();
}
/// \brief Retrieve the directory that the given file name resides in.
@@ -164,10 +109,10 @@ static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
StringRef Filename,
bool CacheFailure) {
if (Filename.empty())
- return NULL;
+ return nullptr;
if (llvm::sys::path::is_separator(Filename[Filename.size() - 1]))
- return NULL; // If Filename is a directory.
+ return nullptr; // If Filename is a directory.
StringRef DirName = llvm::sys::path::parent_path(Filename);
// Use the current directory if file has no path component.
@@ -231,8 +176,8 @@ const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
// See if there was already an entry in the map. Note that the map
// contains both virtual and real directories.
if (NamedDirEnt.getValue())
- return NamedDirEnt.getValue() == NON_EXISTENT_DIR
- ? 0 : NamedDirEnt.getValue();
+ return NamedDirEnt.getValue() == NON_EXISTENT_DIR ? nullptr
+ : NamedDirEnt.getValue();
++NumDirCacheMisses;
@@ -245,19 +190,18 @@ const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
// Check to see if the directory exists.
FileData Data;
- if (getStatValue(InterndDirName, Data, false, 0 /*directory lookup*/)) {
+ if (getStatValue(InterndDirName, Data, false, nullptr /*directory lookup*/)) {
// There's no real directory at the given path.
if (!CacheFailure)
SeenDirEntries.erase(DirName);
- return 0;
+ return nullptr;
}
// It exists. See if we have already opened a directory with the
// same inode (this occurs on Unix-like systems when one dir is
// symlinked to another, for example) or the same path (on
// Windows).
- DirectoryEntry &UDE =
- UniqueRealDirs.getDirectory(Data.UniqueID);
+ DirectoryEntry &UDE = UniqueRealDirs[Data.UniqueID];
NamedDirEnt.setValue(&UDE);
if (!UDE.getName()) {
@@ -280,7 +224,7 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
// See if there is already an entry in the map.
if (NamedFileEnt.getValue())
return NamedFileEnt.getValue() == NON_EXISTENT_FILE
- ? 0 : NamedFileEnt.getValue();
+ ? nullptr : NamedFileEnt.getValue();
++NumFileCacheMisses;
@@ -298,56 +242,59 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
// without a 'sys' subdir will get a cached failure result.
const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename,
CacheFailure);
- if (DirInfo == 0) { // Directory doesn't exist, file can't exist.
+ if (DirInfo == nullptr) { // Directory doesn't exist, file can't exist.
if (!CacheFailure)
SeenFileEntries.erase(Filename);
-
- return 0;
+
+ return nullptr;
}
// FIXME: Use the directory info to prune this, before doing the stat syscall.
// FIXME: This will reduce the # syscalls.
// Nope, there isn't. Check to see if the file exists.
- int FileDescriptor = -1;
+ std::unique_ptr<vfs::File> F;
FileData Data;
- if (getStatValue(InterndFileName, Data, true,
- openFile ? &FileDescriptor : 0)) {
+ if (getStatValue(InterndFileName, Data, true, openFile ? &F : nullptr)) {
// There's no real file at the given path.
if (!CacheFailure)
SeenFileEntries.erase(Filename);
-
- return 0;
- }
- if (FileDescriptor != -1 && !openFile) {
- close(FileDescriptor);
- FileDescriptor = -1;
+ return nullptr;
}
+ assert((openFile || !F) && "undesired open file");
+
// It exists. See if we have already opened a file with the same inode.
// This occurs when one dir is symlinked to another, for example.
- FileEntry &UFE =
- UniqueRealFiles.getFile(Data.UniqueID, Data.IsNamedPipe, Data.InPCH);
+ FileEntry &UFE = UniqueRealFiles[Data.UniqueID];
NamedFileEnt.setValue(&UFE);
- if (UFE.getName()) { // Already have an entry with this inode, return it.
- // If the stat process opened the file, close it to avoid a FD leak.
- if (FileDescriptor != -1)
- close(FileDescriptor);
+ if (UFE.isValid()) { // Already have an entry with this inode, return it.
+
+ // FIXME: this hack ensures that if we look up a file by a virtual path in
+ // the VFS that the getDir() will have the virtual path, even if we found
+ // the file by a 'real' path first. This is required in order to find a
+ // module's structure when its headers/module map are mapped in the VFS.
+ // We should remove this as soon as we can properly support a file having
+ // multiple names.
+ if (DirInfo != UFE.Dir && Data.IsVFSMapped)
+ UFE.Dir = DirInfo;
return &UFE;
}
- // Otherwise, we don't have this directory yet, add it.
- // FIXME: Change the name to be a char* that points back to the
- // 'SeenFileEntries' key.
- UFE.Name = InterndFileName;
+ // Otherwise, we don't have this file yet, add it.
+ UFE.Name = Data.Name;
UFE.Size = Data.Size;
UFE.ModTime = Data.ModTime;
UFE.Dir = DirInfo;
UFE.UID = NextFileUID++;
- UFE.FD = FileDescriptor;
+ UFE.UniqueID = Data.UniqueID;
+ UFE.IsNamedPipe = Data.IsNamedPipe;
+ UFE.InPCH = Data.InPCH;
+ UFE.File = std::move(F);
+ UFE.IsValid = true;
return &UFE;
}
@@ -370,7 +317,7 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
NamedFileEnt.setValue(NON_EXISTENT_FILE);
addAncestorsAsVirtualDirs(Filename);
- FileEntry *UFE = 0;
+ FileEntry *UFE = nullptr;
// Now that all ancestors of Filename are in the cache, the
// following call is guaranteed to find the DirectoryEntry from the
@@ -383,24 +330,26 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
// Check to see if the file exists. If so, drop the virtual file
FileData Data;
const char *InterndFileName = NamedFileEnt.getKeyData();
- if (getStatValue(InterndFileName, Data, true, 0) == 0) {
+ if (getStatValue(InterndFileName, Data, true, nullptr) == 0) {
Data.Size = Size;
Data.ModTime = ModificationTime;
- UFE = &UniqueRealFiles.getFile(Data.UniqueID, Data.IsNamedPipe, Data.InPCH);
+ UFE = &UniqueRealFiles[Data.UniqueID];
NamedFileEnt.setValue(UFE);
// If we had already opened this file, close it now so we don't
// leak the descriptor. We're not going to use the file
// descriptor anyway, since this is a virtual file.
- if (UFE->FD != -1) {
- close(UFE->FD);
- UFE->FD = -1;
- }
+ if (UFE->File)
+ UFE->closeFile();
// If we already have an entry with this inode, return it.
- if (UFE->getName())
+ if (UFE->isValid())
return UFE;
+
+ UFE->UniqueID = Data.UniqueID;
+ UFE->IsNamedPipe = Data.IsNamedPipe;
+ UFE->InPCH = Data.InPCH;
}
if (!UFE) {
@@ -414,7 +363,7 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
UFE->ModTime = ModificationTime;
UFE->Dir = DirInfo;
UFE->UID = NextFileUID++;
- UFE->FD = -1;
+ UFE->File.reset();
return UFE;
}
@@ -432,9 +381,9 @@ void FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const {
llvm::MemoryBuffer *FileManager::
getBufferForFile(const FileEntry *Entry, std::string *ErrorStr,
- bool isVolatile) {
- OwningPtr<llvm::MemoryBuffer> Result;
- llvm::error_code ec;
+ bool isVolatile, bool ShouldCloseOpenFile) {
+ std::unique_ptr<llvm::MemoryBuffer> Result;
+ std::error_code ec;
uint64_t FileSize = Entry->getSize();
// If there's a high enough chance that the file have changed since we
@@ -444,50 +393,54 @@ getBufferForFile(const FileEntry *Entry, std::string *ErrorStr,
const char *Filename = Entry->getName();
// If the file is already open, use the open file descriptor.
- if (Entry->FD != -1) {
- ec = llvm::MemoryBuffer::getOpenFile(Entry->FD, Filename, Result, FileSize);
+ if (Entry->File) {
+ ec = Entry->File->getBuffer(Filename, Result, FileSize,
+ /*RequiresNullTerminator=*/true, isVolatile);
if (ErrorStr)
*ErrorStr = ec.message();
-
- close(Entry->FD);
- Entry->FD = -1;
- return Result.take();
+ // FIXME: we need a set of APIs that can make guarantees about whether a
+ // FileEntry is open or not.
+ if (ShouldCloseOpenFile)
+ Entry->closeFile();
+ return Result.release();
}
// Otherwise, open the file.
if (FileSystemOpts.WorkingDir.empty()) {
- ec = llvm::MemoryBuffer::getFile(Filename, Result, FileSize);
+ ec = FS->getBufferForFile(Filename, Result, FileSize,
+ /*RequiresNullTerminator=*/true, isVolatile);
if (ec && ErrorStr)
*ErrorStr = ec.message();
- return Result.take();
+ return Result.release();
}
SmallString<128> FilePath(Entry->getName());
FixupRelativePath(FilePath);
- ec = llvm::MemoryBuffer::getFile(FilePath.str(), Result, FileSize);
+ ec = FS->getBufferForFile(FilePath.str(), Result, FileSize,
+ /*RequiresNullTerminator=*/true, isVolatile);
if (ec && ErrorStr)
*ErrorStr = ec.message();
- return Result.take();
+ return Result.release();
}
llvm::MemoryBuffer *FileManager::
getBufferForFile(StringRef Filename, std::string *ErrorStr) {
- OwningPtr<llvm::MemoryBuffer> Result;
- llvm::error_code ec;
+ std::unique_ptr<llvm::MemoryBuffer> Result;
+ std::error_code ec;
if (FileSystemOpts.WorkingDir.empty()) {
- ec = llvm::MemoryBuffer::getFile(Filename, Result);
+ ec = FS->getBufferForFile(Filename, Result);
if (ec && ErrorStr)
*ErrorStr = ec.message();
- return Result.take();
+ return Result.release();
}
SmallString<128> FilePath(Filename);
FixupRelativePath(FilePath);
- ec = llvm::MemoryBuffer::getFile(FilePath.c_str(), Result);
+ ec = FS->getBufferForFile(FilePath.c_str(), Result);
if (ec && ErrorStr)
*ErrorStr = ec.message();
- return Result.take();
+ return Result.release();
}
/// getStatValue - Get the 'stat' information for the specified path,
@@ -496,26 +449,29 @@ getBufferForFile(StringRef Filename, std::string *ErrorStr) {
/// false if it's an existent real file. If FileDescriptor is NULL,
/// do directory look-up instead of file look-up.
bool FileManager::getStatValue(const char *Path, FileData &Data, bool isFile,
- int *FileDescriptor) {
+ std::unique_ptr<vfs::File> *F) {
// FIXME: FileSystemOpts shouldn't be passed in here, all paths should be
// absolute!
if (FileSystemOpts.WorkingDir.empty())
- return FileSystemStatCache::get(Path, Data, isFile, FileDescriptor,
- StatCache.get());
+ return FileSystemStatCache::get(Path, Data, isFile, F,StatCache.get(), *FS);
SmallString<128> FilePath(Path);
FixupRelativePath(FilePath);
- return FileSystemStatCache::get(FilePath.c_str(), Data, isFile,
- FileDescriptor, StatCache.get());
+ return FileSystemStatCache::get(FilePath.c_str(), Data, isFile, F,
+ StatCache.get(), *FS);
}
bool FileManager::getNoncachedStatValue(StringRef Path,
- llvm::sys::fs::file_status &Result) {
+ vfs::Status &Result) {
SmallString<128> FilePath(Path);
FixupRelativePath(FilePath);
- return llvm::sys::fs::status(FilePath.c_str(), Result);
+ llvm::ErrorOr<vfs::Status> S = FS->status(FilePath.c_str());
+ if (!S)
+ return true;
+ Result = *S;
+ return false;
}
void FileManager::invalidateCache(const FileEntry *Entry) {
@@ -526,7 +482,7 @@ void FileManager::invalidateCache(const FileEntry *Entry) {
// FileEntry invalidation should not block future optimizations in the file
// caches. Possible alternatives are cache truncation (invalidate last N) or
// invalidation of the whole cache.
- UniqueRealFiles.erase(Entry);
+ UniqueRealFiles.erase(Entry->getUniqueID());
}
diff --git a/lib/Basic/FileSystemStatCache.cpp b/lib/Basic/FileSystemStatCache.cpp
index 7a01bffcd95f..7515cfb440af 100644
--- a/lib/Basic/FileSystemStatCache.cpp
+++ b/lib/Basic/FileSystemStatCache.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/FileSystemStatCache.h"
-#include "llvm/Support/FileSystem.h"
+#include "clang/Basic/VirtualFileSystem.h"
#include "llvm/Support/Path.h"
// FIXME: This is terrible, we need this for ::close.
@@ -30,14 +30,16 @@ using namespace clang;
void FileSystemStatCache::anchor() { }
-static void copyStatusToFileData(const llvm::sys::fs::file_status &Status,
+static void copyStatusToFileData(const vfs::Status &Status,
FileData &Data) {
+ Data.Name = Status.getName();
Data.Size = Status.getSize();
Data.ModTime = Status.getLastModificationTime().toEpochTime();
Data.UniqueID = Status.getUniqueID();
- Data.IsDirectory = is_directory(Status);
- Data.IsNamedPipe = Status.type() == llvm::sys::fs::file_type::fifo_file;
+ Data.IsDirectory = Status.isDirectory();
+ Data.IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file;
Data.InPCH = false;
+ Data.IsVFSMapped = Status.IsVFSMapped;
}
/// FileSystemStatCache::get - Get the 'stat' information for the specified
@@ -50,22 +52,23 @@ static void copyStatusToFileData(const llvm::sys::fs::file_status &Status,
/// implementation can optionally fill in FileDescriptor with a valid
/// descriptor and the client guarantees that it will close it.
bool FileSystemStatCache::get(const char *Path, FileData &Data, bool isFile,
- int *FileDescriptor, FileSystemStatCache *Cache) {
+ std::unique_ptr<vfs::File> *F,
+ FileSystemStatCache *Cache, vfs::FileSystem &FS) {
LookupResult R;
bool isForDir = !isFile;
// If we have a cache, use it to resolve the stat query.
if (Cache)
- R = Cache->getStat(Path, Data, isFile, FileDescriptor);
- else if (isForDir || !FileDescriptor) {
+ R = Cache->getStat(Path, Data, isFile, F, FS);
+ else if (isForDir || !F) {
// If this is a directory or a file descriptor is not needed and we have
// no cache, just go to the file system.
- llvm::sys::fs::file_status Status;
- if (llvm::sys::fs::status(Path, Status)) {
+ llvm::ErrorOr<vfs::Status> Status = FS.status(Path);
+ if (!Status) {
R = CacheMissing;
} else {
R = CacheExists;
- copyStatusToFileData(Status, Data);
+ copyStatusToFileData(*Status, Data);
}
} else {
// Otherwise, we have to go to the filesystem. We can always just use
@@ -75,7 +78,8 @@ bool FileSystemStatCache::get(const char *Path, FileData &Data, bool isFile,
//
// Because of this, check to see if the file exists with 'open'. If the
// open succeeds, use fstat to get the stat info.
- llvm::error_code EC = llvm::sys::fs::openFileForRead(Path, *FileDescriptor);
+ std::unique_ptr<vfs::File> OwnedFile;
+ std::error_code EC = FS.openFileForRead(Path, OwnedFile);
if (EC) {
// If the open fails, our "stat" fails.
@@ -84,16 +88,16 @@ bool FileSystemStatCache::get(const char *Path, FileData &Data, bool isFile,
// Otherwise, the open succeeded. Do an fstat to get the information
// about the file. We'll end up returning the open file descriptor to the
// client to do what they please with it.
- llvm::sys::fs::file_status Status;
- if (!llvm::sys::fs::status(*FileDescriptor, Status)) {
+ llvm::ErrorOr<vfs::Status> Status = OwnedFile->status();
+ if (Status) {
R = CacheExists;
- copyStatusToFileData(Status, Data);
+ copyStatusToFileData(*Status, Data);
+ *F = std::move(OwnedFile);
} else {
// fstat rarely fails. If it does, claim the initial open didn't
// succeed.
R = CacheMissing;
- ::close(*FileDescriptor);
- *FileDescriptor = -1;
+ *F = nullptr;
}
}
}
@@ -105,10 +109,8 @@ bool FileSystemStatCache::get(const char *Path, FileData &Data, bool isFile,
// demands.
if (Data.IsDirectory != isForDir) {
// If not, close the file if opened.
- if (FileDescriptor && *FileDescriptor != -1) {
- ::close(*FileDescriptor);
- *FileDescriptor = -1;
- }
+ if (F)
+ *F = nullptr;
return true;
}
@@ -118,8 +120,8 @@ bool FileSystemStatCache::get(const char *Path, FileData &Data, bool isFile,
MemorizeStatCalls::LookupResult
MemorizeStatCalls::getStat(const char *Path, FileData &Data, bool isFile,
- int *FileDescriptor) {
- LookupResult Result = statChained(Path, Data, isFile, FileDescriptor);
+ std::unique_ptr<vfs::File> *F, vfs::FileSystem &FS) {
+ LookupResult Result = statChained(Path, Data, isFile, F, FS);
// Do not cache failed stats, it is easy to construct common inconsistent
// situations if we do, and they are not important for PCH performance (which
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 500e732eef34..219845996323 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -12,11 +12,13 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/OperatorKinds.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
@@ -42,8 +44,8 @@ IdentifierInfo::IdentifierInfo() {
RevertedTokenID = false;
OutOfDate = false;
IsModulesImport = false;
- FETokenInfo = 0;
- Entry = 0;
+ FETokenInfo = nullptr;
+ Entry = nullptr;
}
//===----------------------------------------------------------------------===//
@@ -60,7 +62,7 @@ namespace {
class EmptyLookupIterator : public IdentifierIterator
{
public:
- virtual StringRef Next() { return StringRef(); }
+ StringRef Next() override { return StringRef(); }
};
}
@@ -105,6 +107,7 @@ namespace {
KEYARC = 0x800,
KEYNOMS = 0x01000,
WCHARSUPPORT = 0x02000,
+ HALFSUPPORT = 0x04000,
KEYALL = (0xffff & ~KEYNOMS) // Because KEYNOMS is used to exclude.
};
}
@@ -129,6 +132,7 @@ static void AddKeyword(StringRef Keyword,
else if (LangOpts.MicrosoftExt && (Flags & KEYMS)) AddResult = 1;
else if (LangOpts.Borland && (Flags & KEYBORLAND)) AddResult = 1;
else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2;
+ else if (LangOpts.Half && (Flags & HALFSUPPORT)) AddResult = 2;
else if (LangOpts.WChar && (Flags & WCHARSUPPORT)) AddResult = 2;
else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2;
else if (LangOpts.OpenCL && (Flags & KEYOPENCL)) AddResult = 2;
@@ -139,8 +143,8 @@ static void AddKeyword(StringRef Keyword,
else if (LangOpts.ObjC2 && (Flags & KEYARC)) AddResult = 2;
else if (LangOpts.CPlusPlus && (Flags & KEYCXX11)) AddResult = 3;
- // Don't add this keyword under MicrosoftMode.
- if (LangOpts.MicrosoftMode && (Flags & KEYNOMS))
+ // Don't add this keyword under MSVCCompat.
+ if (LangOpts.MSVCCompat && (Flags & KEYNOMS))
return;
// Don't add this keyword if disabled in this language.
if (AddResult == 0) return;
@@ -398,6 +402,10 @@ std::string Selector::getAsString() const {
return getMultiKeywordSelector()->getName();
}
+void Selector::print(llvm::raw_ostream &OS) const {
+ OS << getAsString();
+}
+
/// Interpreting the given string using the normal CamelCase
/// conventions, determine whether the given string starts with the
/// given "word", which is assumed to end in a lowercase letter.
@@ -521,7 +529,7 @@ Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) {
llvm::FoldingSetNodeID ID;
MultiKeywordSelector::Profile(ID, IIV, nKeys);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (MultiKeywordSelector *SI =
SelTabImpl.Table.FindNodeOrInsertPos(ID, InsertPos))
return Selector(SI);
@@ -549,7 +557,7 @@ const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) {
switch (Operator) {
case OO_None:
case NUM_OVERLOADED_OPERATORS:
- return 0;
+ return nullptr;
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
case OO_##Name: return Spelling;
diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp
index d08cef1a1563..f689c733d9c0 100644
--- a/lib/Basic/Module.cpp
+++ b/lib/Basic/Module.cpp
@@ -24,20 +24,23 @@
using namespace clang;
-Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
- bool IsFramework, bool IsExplicit)
- : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent),
- Umbrella(), ASTFile(0), IsAvailable(true), IsFromModuleFile(false),
- IsFramework(IsFramework), IsExplicit(IsExplicit), IsSystem(false),
- InferSubmodules(false), InferExplicitSubmodules(false),
- InferExportWildcard(false), ConfigMacrosExhaustive(false),
- NameVisibility(Hidden)
-{
+Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
+ const FileEntry *File, bool IsFramework, bool IsExplicit)
+ : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), ModuleMap(File),
+ Umbrella(), ASTFile(nullptr), IsMissingRequirement(false),
+ IsAvailable(true), IsFromModuleFile(false), IsFramework(IsFramework),
+ IsExplicit(IsExplicit), IsSystem(false), IsExternC(false),
+ IsInferred(false), InferSubmodules(false), InferExplicitSubmodules(false),
+ InferExportWildcard(false), ConfigMacrosExhaustive(false),
+ NameVisibility(Hidden) {
if (Parent) {
if (!Parent->isAvailable())
IsAvailable = false;
if (Parent->IsSystem)
IsSystem = true;
+ if (Parent->IsExternC)
+ IsExternC = true;
+ IsMissingRequirement = Parent->IsMissingRequirement;
Parent->SubModuleIndex[Name] = Parent->SubModules.size();
Parent->SubModules.push_back(this);
@@ -69,11 +72,15 @@ static bool hasFeature(StringRef Feature, const LangOptions &LangOpts,
bool
Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
- Requirement &Req) const {
+ Requirement &Req, HeaderDirective &MissingHeader) const {
if (IsAvailable)
return true;
for (const Module *Current = this; Current; Current = Current->Parent) {
+ if (!Current->MissingHeaders.empty()) {
+ MissingHeader = Current->MissingHeaders.front();
+ return false;
+ }
for (unsigned I = 0, N = Current->Requirements.size(); I != N; ++I) {
if (hasFeature(Current->Requirements[I].first, LangOpts, Target) !=
Current->Requirements[I].second) {
@@ -86,7 +93,7 @@ Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
llvm_unreachable("could not find a reason why module is unavailable");
}
-bool Module::isSubModuleOf(Module *Other) const {
+bool Module::isSubModuleOf(const Module *Other) const {
const Module *This = this;
do {
if (This == Other)
@@ -155,6 +162,10 @@ void Module::addRequirement(StringRef Feature, bool RequiredState,
if (hasFeature(Feature, LangOpts, Target) == RequiredState)
return;
+ markUnavailable(/*MissingRequirement*/true);
+}
+
+void Module::markUnavailable(bool MissingRequirement) {
if (!IsAvailable)
return;
@@ -168,6 +179,7 @@ void Module::addRequirement(StringRef Feature, bool RequiredState,
continue;
Current->IsAvailable = false;
+ Current->IsMissingRequirement |= MissingRequirement;
for (submodule_iterator Sub = Current->submodule_begin(),
SubEnd = Current->submodule_end();
Sub != SubEnd; ++Sub) {
@@ -180,8 +192,8 @@ void Module::addRequirement(StringRef Feature, bool RequiredState,
Module *Module::findSubmodule(StringRef Name) const {
llvm::StringMap<unsigned>::const_iterator Pos = SubModuleIndex.find(Name);
if (Pos == SubModuleIndex.end())
- return 0;
-
+ return nullptr;
+
return SubModules[Pos->getValue()];
}
@@ -349,7 +361,8 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
for (submodule_const_iterator MI = submodule_begin(), MIEnd = submodule_end();
MI != MIEnd; ++MI)
- (*MI)->print(OS, Indent + 2);
+ if (!(*MI)->IsInferred)
+ (*MI)->print(OS, Indent + 2);
for (unsigned I = 0, N = Exports.size(); I != N; ++I) {
OS.indent(Indent + 2);
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
index 1350934d0e65..06f010f7ceb4 100644
--- a/lib/Basic/OpenMPKinds.cpp
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -22,46 +22,49 @@ using namespace clang;
OpenMPDirectiveKind clang::getOpenMPDirectiveKind(StringRef Str) {
return llvm::StringSwitch<OpenMPDirectiveKind>(Str)
-#define OPENMP_DIRECTIVE(Name) \
- .Case(#Name, OMPD_##Name)
+#define OPENMP_DIRECTIVE(Name) .Case(#Name, OMPD_##Name)
+#define OPENMP_DIRECTIVE_EXT(Name, Str) .Case(Str, OMPD_##Name)
#include "clang/Basic/OpenMPKinds.def"
- .Default(OMPD_unknown);
+ .Default(OMPD_unknown);
}
const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) {
- assert(Kind < NUM_OPENMP_DIRECTIVES);
+ assert(Kind <= OMPD_unknown);
switch (Kind) {
case OMPD_unknown:
return "unknown";
-#define OPENMP_DIRECTIVE(Name) \
- case OMPD_##Name : return #Name;
+#define OPENMP_DIRECTIVE(Name) \
+ case OMPD_##Name: \
+ return #Name;
+#define OPENMP_DIRECTIVE_EXT(Name, Str) \
+ case OMPD_##Name: \
+ return Str;
#include "clang/Basic/OpenMPKinds.def"
- case NUM_OPENMP_DIRECTIVES:
break;
}
llvm_unreachable("Invalid OpenMP directive kind");
}
OpenMPClauseKind clang::getOpenMPClauseKind(StringRef Str) {
+ if (Str == "flush")
+ return OMPC_unknown;
return llvm::StringSwitch<OpenMPClauseKind>(Str)
-#define OPENMP_CLAUSE(Name, Class) \
- .Case(#Name, OMPC_##Name)
+#define OPENMP_CLAUSE(Name, Class) .Case(#Name, OMPC_##Name)
#include "clang/Basic/OpenMPKinds.def"
- .Default(OMPC_unknown);
+ .Default(OMPC_unknown);
}
const char *clang::getOpenMPClauseName(OpenMPClauseKind Kind) {
- assert(Kind < NUM_OPENMP_CLAUSES);
+ assert(Kind <= OMPC_unknown);
switch (Kind) {
case OMPC_unknown:
return "unknown";
-#define OPENMP_CLAUSE(Name, Class) \
- case OMPC_##Name : return #Name;
+#define OPENMP_CLAUSE(Name, Class) \
+ case OMPC_##Name: \
+ return #Name;
#include "clang/Basic/OpenMPKinds.def"
case OMPC_threadprivate:
return "threadprivate or thread local";
- case NUM_OPENMP_CLAUSES:
- break;
}
llvm_unreachable("Invalid OpenMP clause kind");
}
@@ -71,16 +74,40 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
switch (Kind) {
case OMPC_default:
return llvm::StringSwitch<OpenMPDefaultClauseKind>(Str)
-#define OPENMP_DEFAULT_KIND(Name) \
- .Case(#Name, OMPC_DEFAULT_##Name)
+#define OPENMP_DEFAULT_KIND(Name) .Case(#Name, OMPC_DEFAULT_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+ .Default(OMPC_DEFAULT_unknown);
+ case OMPC_proc_bind:
+ return llvm::StringSwitch<OpenMPProcBindClauseKind>(Str)
+#define OPENMP_PROC_BIND_KIND(Name) .Case(#Name, OMPC_PROC_BIND_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+ .Default(OMPC_PROC_BIND_unknown);
+ case OMPC_schedule:
+ return llvm::StringSwitch<OpenMPScheduleClauseKind>(Str)
+#define OPENMP_SCHEDULE_KIND(Name) .Case(#Name, OMPC_SCHEDULE_##Name)
#include "clang/Basic/OpenMPKinds.def"
- .Default(OMPC_DEFAULT_unknown);
+ .Default(OMPC_SCHEDULE_unknown);
case OMPC_unknown:
case OMPC_threadprivate:
+ case OMPC_if:
+ case OMPC_final:
+ case OMPC_num_threads:
+ case OMPC_safelen:
+ case OMPC_collapse:
case OMPC_private:
case OMPC_firstprivate:
+ case OMPC_lastprivate:
case OMPC_shared:
- case NUM_OPENMP_CLAUSES:
+ case OMPC_reduction:
+ case OMPC_linear:
+ case OMPC_aligned:
+ case OMPC_copyin:
+ case OMPC_copyprivate:
+ case OMPC_ordered:
+ case OMPC_nowait:
+ case OMPC_untied:
+ case OMPC_mergeable:
+ case OMPC_flush:
break;
}
llvm_unreachable("Invalid OpenMP simple clause kind");
@@ -93,17 +120,53 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
switch (Type) {
case OMPC_DEFAULT_unknown:
return "unknown";
-#define OPENMP_DEFAULT_KIND(Name) \
- case OMPC_DEFAULT_##Name : return #Name;
+#define OPENMP_DEFAULT_KIND(Name) \
+ case OMPC_DEFAULT_##Name: \
+ return #Name;
#include "clang/Basic/OpenMPKinds.def"
}
llvm_unreachable("Invalid OpenMP 'default' clause type");
+ case OMPC_proc_bind:
+ switch (Type) {
+ case OMPC_PROC_BIND_unknown:
+ return "unknown";
+#define OPENMP_PROC_BIND_KIND(Name) \
+ case OMPC_PROC_BIND_##Name: \
+ return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+ }
+ llvm_unreachable("Invalid OpenMP 'proc_bind' clause type");
+ case OMPC_schedule:
+ switch (Type) {
+ case OMPC_SCHEDULE_unknown:
+ return "unknown";
+#define OPENMP_SCHEDULE_KIND(Name) \
+ case OMPC_SCHEDULE_##Name: \
+ return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+ }
+ llvm_unreachable("Invalid OpenMP 'schedule' clause type");
case OMPC_unknown:
case OMPC_threadprivate:
+ case OMPC_if:
+ case OMPC_final:
+ case OMPC_num_threads:
+ case OMPC_safelen:
+ case OMPC_collapse:
case OMPC_private:
case OMPC_firstprivate:
+ case OMPC_lastprivate:
case OMPC_shared:
- case NUM_OPENMP_CLAUSES:
+ case OMPC_reduction:
+ case OMPC_linear:
+ case OMPC_aligned:
+ case OMPC_copyin:
+ case OMPC_copyprivate:
+ case OMPC_ordered:
+ case OMPC_nowait:
+ case OMPC_untied:
+ case OMPC_mergeable:
+ case OMPC_flush:
break;
}
llvm_unreachable("Invalid OpenMP simple clause kind");
@@ -111,23 +174,133 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind) {
- assert(DKind < NUM_OPENMP_DIRECTIVES);
- assert(CKind < NUM_OPENMP_CLAUSES);
+ assert(DKind <= OMPD_unknown);
+ assert(CKind <= OMPC_unknown);
switch (DKind) {
case OMPD_parallel:
switch (CKind) {
-#define OPENMP_PARALLEL_CLAUSE(Name) \
- case OMPC_##Name: return true;
+#define OPENMP_PARALLEL_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
+ case OMPD_simd:
+ switch (CKind) {
+#define OPENMP_SIMD_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
+ case OMPD_for:
+ switch (CKind) {
+#define OPENMP_FOR_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
+ case OMPD_sections:
+ switch (CKind) {
+#define OPENMP_SECTIONS_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
+ case OMPD_single:
+ switch (CKind) {
+#define OPENMP_SINGLE_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
#include "clang/Basic/OpenMPKinds.def"
default:
break;
}
break;
+ case OMPD_parallel_for:
+ switch (CKind) {
+#define OPENMP_PARALLEL_FOR_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
+ case OMPD_parallel_sections:
+ switch (CKind) {
+#define OPENMP_PARALLEL_SECTIONS_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
+ case OMPD_task:
+ switch (CKind) {
+#define OPENMP_TASK_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
+ case OMPD_flush:
+ return CKind == OMPC_flush;
+ break;
case OMPD_unknown:
case OMPD_threadprivate:
- case OMPD_task:
- case NUM_OPENMP_DIRECTIVES:
+ case OMPD_section:
+ case OMPD_master:
+ case OMPD_critical:
+ case OMPD_taskyield:
+ case OMPD_barrier:
+ case OMPD_taskwait:
break;
}
return false;
}
+
+bool clang::isOpenMPLoopDirective(OpenMPDirectiveKind DKind) {
+ return DKind == OMPD_simd || DKind == OMPD_for ||
+ DKind == OMPD_parallel_for; // TODO add next directives.
+}
+
+bool clang::isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind) {
+ return DKind == OMPD_for || DKind == OMPD_sections || DKind == OMPD_section ||
+ DKind == OMPD_single || DKind == OMPD_parallel_for ||
+ DKind == OMPD_parallel_sections; // TODO add next directives.
+}
+
+bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) {
+ return DKind == OMPD_parallel || DKind == OMPD_parallel_for ||
+ DKind == OMPD_parallel_sections; // TODO add next directives.
+}
+
+bool clang::isOpenMPSimdDirective(OpenMPDirectiveKind DKind) {
+ return DKind == OMPD_simd; // TODO || DKind == OMPD_for_simd || ...
+}
+
+bool clang::isOpenMPPrivate(OpenMPClauseKind Kind) {
+ return Kind == OMPC_private || Kind == OMPC_firstprivate ||
+ Kind == OMPC_lastprivate || Kind == OMPC_linear ||
+ Kind == OMPC_reduction; // TODO add next clauses like 'reduction'.
+}
+
+bool clang::isOpenMPThreadPrivate(OpenMPClauseKind Kind) {
+ return Kind == OMPC_threadprivate ||
+ Kind == OMPC_copyin; // TODO add next clauses like 'copyprivate'.
+}
+
diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp
index 182209117966..0c06a48c123a 100644
--- a/lib/Basic/SourceLocation.cpp
+++ b/lib/Basic/SourceLocation.cpp
@@ -61,14 +61,15 @@ void SourceLocation::print(raw_ostream &OS, const SourceManager &SM)const{
OS << '>';
}
-std::string SourceLocation::printToString(const SourceManager &SM) const {
+LLVM_DUMP_METHOD std::string
+SourceLocation::printToString(const SourceManager &SM) const {
std::string S;
llvm::raw_string_ostream OS(S);
print(OS, SM);
return OS.str();
}
-void SourceLocation::dump(const SourceManager &SM) const {
+LLVM_DUMP_METHOD void SourceLocation::dump(const SourceManager &SM) const {
print(llvm::errs(), SM);
}
@@ -122,7 +123,7 @@ bool FullSourceLoc::isBeforeInTranslationUnitThan(SourceLocation Loc) const {
return SrcMgr->isBeforeInTranslationUnit(*this, Loc);
}
-void FullSourceLoc::dump() const {
+LLVM_DUMP_METHOD void FullSourceLoc::dump() const {
SourceLocation::dump(*SrcMgr);
}
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 9d79551f9118..61dfe35e2257 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -26,7 +26,6 @@
#include <algorithm>
#include <cstring>
#include <string>
-#include <sys/stat.h>
using namespace clang;
using namespace SrcMgr;
@@ -55,8 +54,8 @@ llvm::MemoryBuffer::BufferKind ContentCache::getMemoryBufferKind() const {
// Should be unreachable, but keep for sanity.
if (!Buffer.getPointer())
return llvm::MemoryBuffer::MemoryBuffer_Malloc;
-
- const llvm::MemoryBuffer *buf = Buffer.getPointer();
+
+ llvm::MemoryBuffer *buf = Buffer.getPointer();
return buf->getBufferKind();
}
@@ -69,8 +68,7 @@ unsigned ContentCache::getSize() const {
: (unsigned) ContentsEntry->getSize();
}
-void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B,
- bool DoNotFree) {
+void ContentCache::replaceBuffer(llvm::MemoryBuffer *B, bool DoNotFree) {
if (B && B == Buffer.getPointer()) {
assert(0 && "Replacing with the same buffer");
Buffer.setInt(DoNotFree? DoNotFreeFlag : 0);
@@ -83,13 +81,13 @@ void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B,
Buffer.setInt(DoNotFree? DoNotFreeFlag : 0);
}
-const llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag,
- const SourceManager &SM,
- SourceLocation Loc,
- bool *Invalid) const {
+llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag,
+ const SourceManager &SM,
+ SourceLocation Loc,
+ bool *Invalid) const {
// Lazily create the Buffer for ContentCaches that wrap files. If we already
// computed it, just return what we have.
- if (Buffer.getPointer() || ContentsEntry == 0) {
+ if (Buffer.getPointer() || !ContentsEntry) {
if (Invalid)
*Invalid = isBufferInvalid();
@@ -163,7 +161,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag,
.StartsWith("\x0E\xFE\xFF", "SDSU")
.StartsWith("\xFB\xEE\x28", "BOCU-1")
.StartsWith("\x84\x31\x95\x33", "GB-18030")
- .Default(0);
+ .Default(nullptr);
if (InvalidBOM) {
Diag.Report(Loc, diag::err_unsupported_bom)
@@ -272,7 +270,7 @@ const LineEntry *LineTableInfo::FindNearestLineEntry(FileID FID,
// Do a binary search to find the maximal element that is still before Offset.
std::vector<LineEntry>::const_iterator I =
std::upper_bound(Entries.begin(), Entries.end(), Offset);
- if (I == Entries.begin()) return 0;
+ if (I == Entries.begin()) return nullptr;
return &*--I;
}
@@ -286,7 +284,7 @@ void LineTableInfo::AddEntry(FileID FID,
/// getLineTableFilenameID - Return the uniqued ID for the specified filename.
///
unsigned SourceManager::getLineTableFilenameID(StringRef Name) {
- if (LineTable == 0)
+ if (!LineTable)
LineTable = new LineTableInfo();
return LineTable->getLineTableFilenameID(Name);
}
@@ -309,7 +307,7 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
// Remember that this file has #line directives now if it doesn't already.
const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
- if (LineTable == 0)
+ if (!LineTable)
LineTable = new LineTableInfo();
LineTable->AddLineNote(LocInfo.first, LocInfo.second, LineNo, FilenameID);
}
@@ -339,7 +337,7 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
// Remember that this file has #line directives now if it doesn't already.
const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
- if (LineTable == 0)
+ if (!LineTable)
LineTable = new LineTableInfo();
SrcMgr::CharacteristicKind FileKind;
@@ -361,7 +359,7 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
}
LineTableInfo &SourceManager::getLineTable() {
- if (LineTable == 0)
+ if (!LineTable)
LineTable = new LineTableInfo();
return *LineTable;
}
@@ -374,9 +372,9 @@ SourceManager::SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr,
bool UserFilesAreVolatile)
: Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true),
UserFilesAreVolatile(UserFilesAreVolatile),
- ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
- NumBinaryProbes(0), FakeBufferForRecovery(0),
- FakeContentCacheForRecovery(0) {
+ ExternalSLocEntries(nullptr), LineTable(nullptr), NumLinearScans(0),
+ NumBinaryProbes(0), FakeBufferForRecovery(nullptr),
+ FakeContentCacheForRecovery(nullptr) {
clearIDTables();
Diag.setSourceManager(this);
}
@@ -404,10 +402,7 @@ SourceManager::~SourceManager() {
delete FakeBufferForRecovery;
delete FakeContentCacheForRecovery;
- for (llvm::DenseMap<FileID, MacroArgsMap *>::iterator
- I = MacroArgsCacheMap.begin(),E = MacroArgsCacheMap.end(); I!=E; ++I) {
- delete I->second;
- }
+ llvm::DeleteContainerSeconds(MacroArgsCacheMap);
}
void SourceManager::clearIDTables() {
@@ -416,7 +411,7 @@ void SourceManager::clearIDTables() {
LoadedSLocEntryTable.clear();
SLocEntryLoaded.clear();
LastLineNoFileIDQuery = FileID();
- LastLineNoContentCache = 0;
+ LastLineNoContentCache = nullptr;
LastFileIDLookup = FileID();
if (LineTable)
@@ -439,12 +434,8 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt,
ContentCache *&Entry = FileInfos[FileEnt];
if (Entry) return Entry;
- // Nope, create a new Cache entry. Make sure it is at least 8-byte aligned
- // so that FileInfo can use the low 3 bits of the pointer for its own
- // nefarious purposes.
- unsigned EntryAlign = llvm::AlignOf<ContentCache>::Alignment;
- EntryAlign = std::max(8U, EntryAlign);
- Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign);
+ // Nope, create a new Cache entry.
+ Entry = ContentCacheAlloc.Allocate<ContentCache>();
if (OverriddenFilesInfo) {
// If the file contents are overridden with contents from another file,
@@ -469,14 +460,10 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt,
/// createMemBufferContentCache - Create a new ContentCache for the specified
/// memory buffer. This does no caching.
-const ContentCache*
-SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) {
- // Add a new ContentCache to the MemBufferInfos list and return it. Make sure
- // it is at least 8-byte aligned so that FileInfo can use the low 3 bits of
- // the pointer for its own nefarious purposes.
- unsigned EntryAlign = llvm::AlignOf<ContentCache>::Alignment;
- EntryAlign = std::max(8U, EntryAlign);
- ContentCache *Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign);
+const ContentCache *
+SourceManager::createMemBufferContentCache(llvm::MemoryBuffer *Buffer) {
+ // Add a new ContentCache to the MemBufferInfos list and return it.
+ ContentCache *Entry = ContentCacheAlloc.Allocate<ContentCache>();
new (Entry) ContentCache();
MemBufferInfos.push_back(Entry);
Entry->setBuffer(Buffer);
@@ -516,7 +503,7 @@ SourceManager::AllocateLoadedSLocEntries(unsigned NumSLocEntries,
/// \brief As part of recovering from missing or changed content, produce a
/// fake, non-empty buffer.
-const llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const {
+llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const {
if (!FakeBufferForRecovery)
FakeBufferForRecovery
= llvm::MemoryBuffer::getMemBuffer("<<<INVALID BUFFER>>");
@@ -655,16 +642,15 @@ SourceManager::createExpansionLocImpl(const ExpansionInfo &Info,
return SourceLocation::getMacroLoc(NextLocalOffset - (TokLength + 1));
}
-const llvm::MemoryBuffer *
-SourceManager::getMemoryBufferForFile(const FileEntry *File,
- bool *Invalid) {
+llvm::MemoryBuffer *SourceManager::getMemoryBufferForFile(const FileEntry *File,
+ bool *Invalid) {
const SrcMgr::ContentCache *IR = getOrCreateContentCache(File);
assert(IR && "getOrCreateContentCache() cannot return NULL");
return IR->getBuffer(Diag, *this, SourceLocation(), Invalid);
}
void SourceManager::overrideFileContents(const FileEntry *SourceFile,
- const llvm::MemoryBuffer *Buffer,
+ llvm::MemoryBuffer *Buffer,
bool DoNotFree) {
const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile);
assert(IR && "getOrCreateContentCache() cannot return NULL");
@@ -691,7 +677,7 @@ void SourceManager::disableFileContentsOverride(const FileEntry *File) {
return;
const SrcMgr::ContentCache *IR = getOrCreateContentCache(File);
- const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(0);
+ const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(nullptr);
const_cast<SrcMgr::ContentCache *>(IR)->ContentsEntry = IR->OrigEntry;
assert(OverriddenFilesInfo);
@@ -707,10 +693,9 @@ StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
*Invalid = true;
return "<<<<<INVALID SOURCE LOCATION>>>>>";
}
-
- const llvm::MemoryBuffer *Buf
- = SLoc.getFile().getContentCache()->getBuffer(Diag, *this, SourceLocation(),
- &MyInvalid);
+
+ llvm::MemoryBuffer *Buf = SLoc.getFile().getContentCache()->getBuffer(
+ Diag, *this, SourceLocation(), &MyInvalid);
if (Invalid)
*Invalid = MyInvalid;
@@ -1128,9 +1113,8 @@ const char *SourceManager::getCharacterData(SourceLocation SL,
return "<<<<INVALID BUFFER>>>>";
}
- const llvm::MemoryBuffer *Buffer
- = Entry.getFile().getContentCache()
- ->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid);
+ llvm::MemoryBuffer *Buffer = Entry.getFile().getContentCache()->getBuffer(
+ Diag, *this, SourceLocation(), &CharDataInvalid);
if (Invalid)
*Invalid = CharDataInvalid;
return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second);
@@ -1142,7 +1126,7 @@ const char *SourceManager::getCharacterData(SourceLocation SL,
unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos,
bool *Invalid) const {
bool MyInvalid = false;
- const llvm::MemoryBuffer *MemBuf = getBuffer(FID, &MyInvalid);
+ llvm::MemoryBuffer *MemBuf = getBuffer(FID, &MyInvalid);
if (Invalid)
*Invalid = MyInvalid;
@@ -1159,7 +1143,7 @@ unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos,
// See if we just calculated the line number for this FilePos and can use
// that to lookup the start of the line instead of searching for it.
if (LastLineNoFileIDQuery == FID &&
- LastLineNoContentCache->SourceLineCache != 0 &&
+ LastLineNoContentCache->SourceLineCache != nullptr &&
LastLineNoResult < LastLineNoContentCache->NumLines) {
unsigned *SourceLineCache = LastLineNoContentCache->SourceLineCache;
unsigned LineStart = SourceLineCache[LastLineNoResult - 1];
@@ -1216,8 +1200,7 @@ static void ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI,
llvm::BumpPtrAllocator &Alloc,
const SourceManager &SM, bool &Invalid) {
// Note that calling 'getBuffer()' may lazily page in the file.
- const MemoryBuffer *Buffer = FI->getBuffer(Diag, SM, SourceLocation(),
- &Invalid);
+ MemoryBuffer *Buffer = FI->getBuffer(Diag, SM, SourceLocation(), &Invalid);
if (Invalid)
return;
@@ -1323,7 +1306,7 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos,
// If this is the first use of line information for this buffer, compute the
/// SourceLineCache for it on demand.
- if (Content->SourceLineCache == 0) {
+ if (!Content->SourceLineCache) {
bool MyInvalid = false;
ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid);
if (Invalid)
@@ -1381,31 +1364,6 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos,
}
}
- // If the spread is large, do a "radix" test as our initial guess, based on
- // the assumption that lines average to approximately the same length.
- // NOTE: This is currently disabled, as it does not appear to be profitable in
- // initial measurements.
- if (0 && SourceLineCacheEnd-SourceLineCache > 20) {
- unsigned FileLen = Content->SourceLineCache[Content->NumLines-1];
-
- // Take a stab at guessing where it is.
- unsigned ApproxPos = Content->NumLines*QueriedFilePos / FileLen;
-
- // Check for -10 and +10 lines.
- unsigned LowerBound = std::max(int(ApproxPos-10), 0);
- unsigned UpperBound = std::min(ApproxPos+10, FileLen);
-
- // If the computed lower bound is less than the query location, move it in.
- if (SourceLineCache < SourceLineCacheStart+LowerBound &&
- SourceLineCacheStart[LowerBound] < QueriedFilePos)
- SourceLineCache = SourceLineCacheStart+LowerBound;
-
- // If the computed upper bound is greater than the query location, move it.
- if (SourceLineCacheEnd > SourceLineCacheStart+UpperBound &&
- SourceLineCacheStart[UpperBound] >= QueriedFilePos)
- SourceLineCacheEnd = SourceLineCacheStart+UpperBound;
- }
-
unsigned *Pos
= std::lower_bound(SourceLineCache, SourceLineCacheEnd, QueriedFilePos);
unsigned LineNo = Pos-SourceLineCacheStart;
@@ -1583,7 +1541,7 @@ bool SourceManager::isInMainFile(SourceLocation Loc) const {
return FI.getIncludeLoc().isInvalid();
}
-/// \brief The size of the SLocEnty that \arg FID represents.
+/// \brief The size of the SLocEntry that \p FID represents.
unsigned SourceManager::getFileIDSize(FileID FID) const {
bool Invalid = false;
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
@@ -1732,7 +1690,8 @@ FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
if (SLoc.isFile()) {
const ContentCache *FileContentCache
= SLoc.getFile().getContentCache();
- const FileEntry *Entry =FileContentCache? FileContentCache->OrigEntry : 0;
+ const FileEntry *Entry = FileContentCache ? FileContentCache->OrigEntry
+ : nullptr;
if (Entry &&
*SourceFileName == llvm::sys::path::filename(Entry->getName())) {
if (Optional<llvm::sys::fs::UniqueID> EntryUID =
@@ -1784,7 +1743,7 @@ SourceLocation SourceManager::translateLineCol(FileID FID,
// If this is the first use of line information for this buffer, compute the
// SourceLineCache for it on demand.
- if (Content->SourceLineCache == 0) {
+ if (!Content->SourceLineCache) {
bool MyInvalid = false;
ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid);
if (MyInvalid)
@@ -1798,7 +1757,7 @@ SourceLocation SourceManager::translateLineCol(FileID FID,
return FileLoc.getLocWithOffset(Size);
}
- const llvm::MemoryBuffer *Buffer = Content->getBuffer(Diag, *this);
+ llvm::MemoryBuffer *Buffer = Content->getBuffer(Diag, *this);
unsigned FilePos = Content->SourceLineCache[Line - 1];
const char *Buf = Buffer->getBufferStart() + FilePos;
unsigned BufLength = Buffer->getBufferSize() - FilePos;
@@ -1893,7 +1852,7 @@ void SourceManager::associateFileChunkWithMacroArgExp(
FileID SpellFID; // Current FileID in the spelling range.
unsigned SpellRelativeOffs;
- llvm::tie(SpellFID, SpellRelativeOffs) = getDecomposedLoc(SpellLoc);
+ std::tie(SpellFID, SpellRelativeOffs) = getDecomposedLoc(SpellLoc);
while (1) {
const SLocEntry &Entry = getSLocEntry(SpellFID);
unsigned SpellFIDBeginOffs = Entry.getOffset();
@@ -1972,7 +1931,7 @@ SourceManager::getMacroArgExpandedLocation(SourceLocation Loc) const {
FileID FID;
unsigned Offset;
- llvm::tie(FID, Offset) = getDecomposedLoc(Loc);
+ std::tie(FID, Offset) = getDecomposedLoc(Loc);
if (FID.isInvalid())
return Loc;
@@ -2160,7 +2119,7 @@ void SourceManager::PrintStats() const {
unsigned NumLineNumsComputed = 0;
unsigned NumFileBytesMapped = 0;
for (fileinfo_iterator I = fileinfo_begin(), E = fileinfo_end(); I != E; ++I){
- NumLineNumsComputed += I->second->SourceLineCache != 0;
+ NumLineNumsComputed += I->second->SourceLineCache != nullptr;
NumFileBytesMapped += I->second->getSizeBytesMapped();
}
unsigned NumMacroArgsComputed = MacroArgsCacheMap.size();
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index e993055cc881..aecf13b00854 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -52,7 +52,6 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
SizeType = UnsignedLong;
PtrDiffType = SignedLong;
IntMaxType = SignedLongLong;
- UIntMaxType = UnsignedLongLong;
IntPtrType = SignedLong;
WCharType = SignedInt;
WIntType = SignedInt;
@@ -69,8 +68,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
FloatFormat = &llvm::APFloat::IEEEsingle;
DoubleFormat = &llvm::APFloat::IEEEdouble;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
- DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-n32";
+ DescriptionString = nullptr;
UserLabelPrefix = "_";
MCountName = "mcount";
RegParmMax = 0;
@@ -83,8 +81,10 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
// Default to not using fp2ret for __Complex long double
ComplexLongDoubleUsesFP2Ret = false;
- // Default to using the Itanium ABI.
- TheCXXABI.set(TargetCXXABI::GenericItanium);
+ // Set the C++ ABI based on the triple.
+ TheCXXABI.set(Triple.isKnownWindowsMSVCEnvironment()
+ ? TargetCXXABI::Microsoft
+ : TargetCXXABI::GenericItanium);
// Default to an empty address space map.
AddrSpaceMap = &DefaultAddrSpaceMap;
@@ -103,7 +103,7 @@ TargetInfo::~TargetInfo() {}
const char *TargetInfo::getTypeName(IntType T) {
switch (T) {
default: llvm_unreachable("not an integer!");
- case SignedChar: return "char";
+ case SignedChar: return "signed char";
case UnsignedChar: return "unsigned char";
case SignedShort: return "short";
case UnsignedShort: return "unsigned short";
@@ -118,7 +118,7 @@ const char *TargetInfo::getTypeName(IntType T) {
/// getTypeConstantSuffix - Return the constant suffix for the specified
/// integer type enum. For example, SignedLong -> "L".
-const char *TargetInfo::getTypeConstantSuffix(IntType T) {
+const char *TargetInfo::getTypeConstantSuffix(IntType T) const {
switch (T) {
default: llvm_unreachable("not an integer!");
case SignedChar:
@@ -127,13 +127,36 @@ const char *TargetInfo::getTypeConstantSuffix(IntType T) {
case SignedLong: return "L";
case SignedLongLong: return "LL";
case UnsignedChar:
+ if (getCharWidth() < getIntWidth())
+ return "";
case UnsignedShort:
+ if (getShortWidth() < getIntWidth())
+ return "";
case UnsignedInt: return "U";
case UnsignedLong: return "UL";
case UnsignedLongLong: return "ULL";
}
}
+/// getTypeFormatModifier - Return the printf format modifier for the
+/// specified integer type enum. For example, SignedLong -> "l".
+
+const char *TargetInfo::getTypeFormatModifier(IntType T) {
+ switch (T) {
+ default: llvm_unreachable("not an integer!");
+ case SignedChar:
+ case UnsignedChar: return "hh";
+ case SignedShort:
+ case UnsignedShort: return "h";
+ case SignedInt:
+ case UnsignedInt: return "";
+ case SignedLong:
+ case UnsignedLong: return "l";
+ case SignedLongLong:
+ case UnsignedLongLong: return "ll";
+ }
+}
+
/// getTypeWidth - Return the width (in bits) of the specified integer type
/// enum. For example, SignedInt -> getIntWidth().
unsigned TargetInfo::getTypeWidth(IntType T) const {
@@ -167,6 +190,21 @@ TargetInfo::IntType TargetInfo::getIntTypeByWidth(
return NoInt;
}
+TargetInfo::IntType TargetInfo::getLeastIntTypeByWidth(unsigned BitWidth,
+ bool IsSigned) const {
+ if (getCharWidth() >= BitWidth)
+ return IsSigned ? SignedChar : UnsignedChar;
+ if (getShortWidth() >= BitWidth)
+ return IsSigned ? SignedShort : UnsignedShort;
+ if (getIntWidth() >= BitWidth)
+ return IsSigned ? SignedInt : UnsignedInt;
+ if (getLongWidth() >= BitWidth)
+ return IsSigned ? SignedLong : UnsignedLong;
+ if (getLongLongWidth() >= BitWidth)
+ return IsSigned ? SignedLongLong : UnsignedLongLong;
+ return NoInt;
+}
+
TargetInfo::RealType TargetInfo::getRealTypeByWidth(unsigned BitWidth) const {
if (getFloatWidth() == BitWidth)
return Float;
@@ -226,10 +264,10 @@ bool TargetInfo::isTypeSigned(IntType T) {
};
}
-/// setForcedLangOptions - Set forced language options.
+/// adjust - Set forced language options.
/// Apply changes to the target information with respect to certain
/// language options which change the target configuration.
-void TargetInfo::setForcedLangOptions(LangOptions &Opts) {
+void TargetInfo::adjust(const LangOptions &Opts) {
if (Opts.NoBitFieldTypeAlign)
UseBitFieldTypeAlignment = false;
if (Opts.ShortWChar)
@@ -245,7 +283,14 @@ void TargetInfo::setForcedLangOptions(LangOptions &Opts) {
LongLongWidth = LongLongAlign = 128;
HalfWidth = HalfAlign = 16;
FloatWidth = FloatAlign = 32;
- DoubleWidth = DoubleAlign = 64;
+
+ // Embedded 32-bit targets (OpenCL EP) might have double C type
+ // defined as float. Let's not override this as it might lead
+ // to generating illegal code that uses 64bit doubles.
+ if (DoubleWidth != FloatWidth) {
+ DoubleWidth = DoubleAlign = 64;
+ DoubleFormat = &llvm::APFloat::IEEEdouble;
+ }
LongDoubleWidth = LongDoubleAlign = 128;
assert(PointerWidth == 32 || PointerWidth == 64);
@@ -255,12 +300,10 @@ void TargetInfo::setForcedLangOptions(LangOptions &Opts) {
IntPtrType = Is32BitArch ? SignedInt : SignedLong;
IntMaxType = SignedLongLong;
- UIntMaxType = UnsignedLongLong;
Int64Type = SignedLong;
HalfFormat = &llvm::APFloat::IEEEhalf;
FloatFormat = &llvm::APFloat::IEEEsingle;
- DoubleFormat = &llvm::APFloat::IEEEdouble;
LongDoubleFormat = &llvm::APFloat::IEEEquad;
}
}
@@ -483,6 +526,9 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
ConstraintInfo &Info) const {
const char *Name = Info.ConstraintStr.c_str();
+ if (!*Name)
+ return false;
+
while (*Name) {
switch (*Name) {
default:
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index c8bfda7e6658..075f905cc359 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -20,7 +20,6 @@
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetOptions.h"
#include "llvm/ADT/APFloat.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
@@ -29,6 +28,7 @@
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
+#include <memory>
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -74,8 +74,8 @@ protected:
MacroBuilder &Builder) const=0;
public:
OSTargetInfo(const llvm::Triple &Triple) : TgtInfo(Triple) {}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
TgtInfo::getTargetDefines(Opts, Builder);
getOSDefines(Opts, TgtInfo::getTriple(), Builder);
}
@@ -90,7 +90,6 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
VersionTuple &PlatformMinVersion) {
Builder.defineMacro("__APPLE_CC__", "6000");
Builder.defineMacro("__APPLE__");
- Builder.defineMacro("__MACH__");
Builder.defineMacro("OBJC_NEW_PROPERTIES");
// AddressSanitizer doesn't play well with source fortification, which is on
// by default on Darwin.
@@ -138,39 +137,48 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
return;
}
- // If there's an environment specified in the triple, that means we're dealing
- // with an embedded variant of some sort and don't want the platform
- // version-min defines, so only add them if there's not one.
- if (Triple.getEnvironmentName().empty()) {
- // Set the appropriate OS version define.
- if (Triple.isiOS()) {
- assert(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!");
- char Str[6];
- Str[0] = '0' + Maj;
- Str[1] = '0' + (Min / 10);
- Str[2] = '0' + (Min % 10);
- Str[3] = '0' + (Rev / 10);
- Str[4] = '0' + (Rev % 10);
- Str[5] = '\0';
- Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__",
- Str);
- } else {
- // Note that the Driver allows versions which aren't representable in the
- // define (because we only get a single digit for the minor and micro
- // revision numbers). So, we limit them to the maximum representable
- // version.
- assert(Triple.getEnvironmentName().empty() && "Invalid environment!");
- assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!");
- char Str[5];
+ // Set the appropriate OS version define.
+ if (Triple.isiOS()) {
+ assert(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!");
+ char Str[6];
+ Str[0] = '0' + Maj;
+ Str[1] = '0' + (Min / 10);
+ Str[2] = '0' + (Min % 10);
+ Str[3] = '0' + (Rev / 10);
+ Str[4] = '0' + (Rev % 10);
+ Str[5] = '\0';
+ Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__",
+ Str);
+ } else if (Triple.isMacOSX()) {
+ // Note that the Driver allows versions which aren't representable in the
+ // define (because we only get a single digit for the minor and micro
+ // revision numbers). So, we limit them to the maximum representable
+ // version.
+ assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!");
+ char Str[7];
+ if (Maj < 10 || (Maj == 10 && Min < 10)) {
Str[0] = '0' + (Maj / 10);
Str[1] = '0' + (Maj % 10);
Str[2] = '0' + std::min(Min, 9U);
Str[3] = '0' + std::min(Rev, 9U);
Str[4] = '\0';
- Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str);
+ } else {
+ // Handle versions > 10.9.
+ Str[0] = '0' + (Maj / 10);
+ Str[1] = '0' + (Maj % 10);
+ Str[2] = '0' + (Min / 10);
+ Str[3] = '0' + (Min % 10);
+ Str[4] = '0' + (Rev / 10);
+ Str[5] = '0' + (Rev % 10);
+ Str[6] = '\0';
}
+ Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str);
}
+ // Tell users about the kernel if there is one.
+ if (Triple.isOSDarwin())
+ Builder.defineMacro("__MACH__");
+
PlatformMinVersion = VersionTuple(Maj, Min, Rev);
}
@@ -178,8 +186,8 @@ namespace {
template<typename Target>
class DarwinTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
getDarwinDefines(Builder, Opts, Triple, this->PlatformName,
this->PlatformMinVersion);
}
@@ -190,7 +198,7 @@ public:
this->MCountName = "\01mcount";
}
- virtual std::string isValidSectionSpecifier(StringRef SR) const {
+ std::string isValidSectionSpecifier(StringRef SR) const override {
// Let MCSectionMachO validate this.
StringRef Segment, Section;
unsigned TAA, StubSize;
@@ -199,7 +207,7 @@ public:
TAA, HasTAA, StubSize);
}
- virtual const char *getStaticInitSectionSpecifier() const {
+ const char *getStaticInitSectionSpecifier() const override {
// FIXME: We should return 0 when building kexts.
return "__TEXT,__StaticInit,regular,pure_instructions";
}
@@ -207,7 +215,7 @@ public:
/// Darwin does not support protected visibility. Darwin's "default"
/// is very similar to ELF's "protected"; Darwin requires a "weak"
/// attribute on declarations that can be dynamically replaced.
- virtual bool hasProtectedVisibility() const {
+ bool hasProtectedVisibility() const override {
return false;
}
};
@@ -217,8 +225,8 @@ public:
template<typename Target>
class DragonFlyBSDTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
// DragonFly defines; list based off of gcc output
Builder.defineMacro("__DragonFly__");
Builder.defineMacro("__DragonFly_cc_version", "100001");
@@ -246,8 +254,8 @@ public:
template<typename Target>
class FreeBSDTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
// FreeBSD defines; list based off of gcc output
unsigned Release = Triple.getOSMajorVersion();
@@ -293,8 +301,8 @@ public:
template<typename Target>
class KFreeBSDTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
// GNU/kFreeBSD defines; list based off of gcc output
DefineStd(Builder, "unix", Opts);
@@ -316,8 +324,8 @@ public:
template<typename Target>
class MinixTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
// Minix defines
Builder.defineMacro("__minix", "3");
@@ -340,8 +348,8 @@ public:
template<typename Target>
class LinuxTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
// Linux defines; list based off of gcc output
DefineStd(Builder, "unix", Opts);
DefineStd(Builder, "linux", Opts);
@@ -370,7 +378,7 @@ public:
}
}
- virtual const char *getStaticInitSectionSpecifier() const {
+ const char *getStaticInitSectionSpecifier() const override {
return ".text.startup";
}
};
@@ -379,14 +387,25 @@ public:
template<typename Target>
class NetBSDTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
// NetBSD defines; list based off of gcc output
Builder.defineMacro("__NetBSD__");
Builder.defineMacro("__unix__");
Builder.defineMacro("__ELF__");
if (Opts.POSIXThreads)
Builder.defineMacro("_POSIX_THREADS");
+
+ switch (Triple.getArch()) {
+ default:
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ Builder.defineMacro("__ARM_DWARF_EH__");
+ break;
+ }
}
public:
NetBSDTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
@@ -398,8 +417,8 @@ public:
template<typename Target>
class OpenBSDTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
// OpenBSD defines; list based off of gcc output
Builder.defineMacro("__OpenBSD__");
@@ -435,8 +454,8 @@ public:
template<typename Target>
class BitrigTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
// Bitrig defines; list based off of gcc output
Builder.defineMacro("__Bitrig__");
@@ -448,7 +467,6 @@ protected:
public:
BitrigTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
this->UserLabelPrefix = "";
- this->TLSSupported = false;
this->MCountName = "__mcount";
}
};
@@ -457,8 +475,8 @@ public:
template<typename Target>
class PSPTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
// PSP defines; list based on the output of the pspdev gcc toolchain.
Builder.defineMacro("PSP");
Builder.defineMacro("_PSP");
@@ -475,8 +493,8 @@ public:
template<typename Target>
class PS3PPUTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
// PS3 PPU defines.
Builder.defineMacro("__PPC__");
Builder.defineMacro("__PPU__");
@@ -492,28 +510,9 @@ public:
this->LongWidth = this->LongAlign = 32;
this->PointerWidth = this->PointerAlign = 32;
this->IntMaxType = TargetInfo::SignedLongLong;
- this->UIntMaxType = TargetInfo::UnsignedLongLong;
this->Int64Type = TargetInfo::SignedLongLong;
this->SizeType = TargetInfo::UnsignedInt;
- this->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";
- }
-};
-
-// FIXME: Need a real SPU target.
-// PS3 SPU Target
-template<typename Target>
-class PS3SPUTargetInfo : public OSTargetInfo<Target> {
-protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
- // PS3 PPU defines.
- Builder.defineMacro("__SPU__");
- Builder.defineMacro("__ELF__");
- }
-public:
- PS3SPUTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
- this->UserLabelPrefix = "";
+ this->DescriptionString = "E-m:e-p:32:32-i64:64-n32:64";
}
};
@@ -521,8 +520,8 @@ public:
template<typename Target>
class AuroraUXTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
DefineStd(Builder, "sun", Opts);
DefineStd(Builder, "unix", Opts);
Builder.defineMacro("__ELF__");
@@ -542,8 +541,8 @@ public:
template<typename Target>
class SolarisTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
DefineStd(Builder, "sun", Opts);
DefineStd(Builder, "unix", Opts);
Builder.defineMacro("__ELF__");
@@ -576,14 +575,14 @@ public:
template<typename Target>
class WindowsTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
Builder.defineMacro("_WIN32");
}
void getVisualStudioDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
if (Opts.CPlusPlus) {
- if (Opts.RTTI)
+ if (Opts.RTTIData)
Builder.defineMacro("_CPPRTTI");
if (Opts.Exceptions)
@@ -598,8 +597,13 @@ protected:
if (Opts.POSIXThreads)
Builder.defineMacro("_MT");
- if (Opts.MSCVersion != 0)
- Builder.defineMacro("_MSC_VER", Twine(Opts.MSCVersion));
+ if (Opts.MSCompatibilityVersion) {
+ Builder.defineMacro("_MSC_VER",
+ Twine(Opts.MSCompatibilityVersion / 100000));
+ Builder.defineMacro("_MSC_FULL_VER", Twine(Opts.MSCompatibilityVersion));
+ // FIXME We cannot encode the revision information into 32-bits
+ Builder.defineMacro("_MSC_BUILD", Twine(1));
+ }
if (Opts.MicrosoftExt) {
Builder.defineMacro("_MSC_EXTENSIONS");
@@ -622,8 +626,8 @@ public:
template <typename Target>
class NaClTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
if (Opts.POSIXThreads)
Builder.defineMacro("_REENTRANT");
if (Opts.CPlusPlus)
@@ -642,21 +646,32 @@ public:
this->PointerAlign = 32;
this->PointerWidth = 32;
this->IntMaxType = TargetInfo::SignedLongLong;
- this->UIntMaxType = TargetInfo::UnsignedLongLong;
this->Int64Type = TargetInfo::SignedLongLong;
this->DoubleAlign = 64;
this->LongDoubleWidth = 64;
this->LongDoubleAlign = 64;
+ this->LongLongWidth = 64;
+ this->LongLongAlign = 64;
this->SizeType = TargetInfo::UnsignedInt;
this->PtrDiffType = TargetInfo::SignedInt;
this->IntPtrType = TargetInfo::SignedInt;
// RegParmMax is inherited from the underlying architecture
this->LongDoubleFormat = &llvm::APFloat::IEEEdouble;
- this->DescriptionString = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"
- "f32:32:32-f64:64:64-p:32:32:32-v128:32:32";
+ if (Triple.getArch() == llvm::Triple::arm) {
+ this->DescriptionString = "e-m:e-p:32:32-i64:64-v128:64:128-n32-S128";
+ } else if (Triple.getArch() == llvm::Triple::x86) {
+ this->DescriptionString = "e-m:e-p:32:32-i64:64-n8:16:32-S128";
+ } else if (Triple.getArch() == llvm::Triple::x86_64) {
+ this->DescriptionString = "e-m:e-p:32:32-i64:64-n8:16:32:64-S128";
+ } else if (Triple.getArch() == llvm::Triple::mipsel) {
+ // Handled on mips' setDescriptionString.
+ } else {
+ assert(Triple.getArch() == llvm::Triple::le32);
+ this->DescriptionString = "e-p:32:32-i64:64";
+ }
}
- virtual typename Target::CallingConvCheckResult checkCallingConvention(
- CallingConv CC) const {
+ typename Target::CallingConvCheckResult checkCallingConvention(
+ CallingConv CC) const override {
return CC == CC_PnaclCall ? Target::CCCR_OK :
Target::checkCallingConvention(CC);
}
@@ -701,15 +716,16 @@ public:
ArchDefinePwr6 = 1 << 9,
ArchDefinePwr6x = 1 << 10,
ArchDefinePwr7 = 1 << 11,
- ArchDefineA2 = 1 << 12,
- ArchDefineA2q = 1 << 13
+ ArchDefinePwr8 = 1 << 12,
+ ArchDefineA2 = 1 << 13,
+ ArchDefineA2q = 1 << 14
} ArchDefineTypes;
// Note: GCC recognizes the following additional cpus:
// 401, 403, 405, 405fp, 440fp, 464, 464fp, 476, 476fp, 505, 740, 801,
// 821, 823, 8540, 8548, e300c2, e300c3, e500mc64, e6500, 860, cell,
// titan, rs64.
- virtual bool setCPU(const std::string &Name) {
+ bool setCPU(const std::string &Name) override {
bool CPUKnown = llvm::StringSwitch<bool>(Name)
.Case("generic", true)
.Case("440", true)
@@ -749,6 +765,8 @@ public:
.Case("pwr6x", true)
.Case("power7", true)
.Case("pwr7", true)
+ .Case("power8", true)
+ .Case("pwr8", true)
.Case("powerpc", true)
.Case("ppc", true)
.Case("powerpc64", true)
@@ -763,29 +781,29 @@ public:
return CPUKnown;
}
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {
+ void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const override {
Records = BuiltinInfo;
NumRecords = clang::PPC::LastTSBuiltin-Builtin::FirstTSBuiltin;
}
- virtual bool isCLZForZeroUndef() const { return false; }
+ bool isCLZForZeroUndef() const override { return false; }
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const;
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
- virtual void getDefaultFeatures(llvm::StringMap<bool> &Features) const;
+ void getDefaultFeatures(llvm::StringMap<bool> &Features) const override;
- virtual bool handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags);
- virtual bool hasFeature(StringRef Feature) const;
-
- virtual void getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const;
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const;
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const {
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override;
+ bool hasFeature(StringRef Feature) const override;
+
+ void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const override;
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override;
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
switch (*Name) {
default: return false;
case 'O': // Zero
@@ -807,6 +825,7 @@ public:
case 'f':// VSX vector register to hold vector float data
case 's':// VSX vector register to hold scalar float data
case 'a':// Any VSX register
+ case 'c':// An individual CR bit
break;
default:
return false;
@@ -882,10 +901,24 @@ public:
}
return true;
}
- virtual const char *getClobbers() const {
+ std::string convertConstraint(const char *&Constraint) const override {
+ std::string R;
+ switch (*Constraint) {
+ case 'e':
+ case 'w':
+ // Two-character constraint; add "^" hint for later parsing.
+ R = std::string("^") + std::string(Constraint, 2);
+ Constraint++;
+ break;
+ default:
+ return TargetInfo::convertConstraint(Constraint);
+ }
+ return R;
+ }
+ const char *getClobbers() const override {
return "";
}
- int getEHDataRegisterNumber(unsigned RegNo) const {
+ int getEHDataRegisterNumber(unsigned RegNo) const override {
if (RegNo == 0) return 3;
if (RegNo == 1) return 4;
return -1;
@@ -943,12 +976,11 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
// Target properties.
if (getTriple().getArch() == llvm::Triple::ppc64le) {
Builder.defineMacro("_LITTLE_ENDIAN");
- Builder.defineMacro("__LITTLE_ENDIAN__");
+ Builder.defineMacro("_CALL_ELF","2");
} else {
if (getTriple().getOS() != llvm::Triple::NetBSD &&
getTriple().getOS() != llvm::Triple::OpenBSD)
Builder.defineMacro("_BIG_ENDIAN");
- Builder.defineMacro("__BIG_ENDIAN__");
}
// Subtarget options.
@@ -997,7 +1029,10 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
| ArchDefinePpcsq)
.Case("pwr7", ArchDefineName | ArchDefinePwr6x | ArchDefinePwr6
| ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4
- | ArchDefinePwr6 | ArchDefinePpcgr | ArchDefinePpcsq)
+ | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("pwr8", ArchDefineName | ArchDefinePwr7 | ArchDefinePwr6x
+ | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5
+ | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
.Case("power3", ArchDefinePpcgr)
.Case("power4", ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
.Case("power5", ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr
@@ -1011,7 +1046,10 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
| ArchDefinePpcsq)
.Case("power7", ArchDefinePwr7 | ArchDefinePwr6x | ArchDefinePwr6
| ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4
- | ArchDefinePwr6 | ArchDefinePpcgr | ArchDefinePpcsq)
+ | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("power8", ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6x
+ | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5
+ | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
.Default(ArchDefineNone);
if (defs & ArchDefineName)
@@ -1038,6 +1076,8 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("_ARCH_PWR6X");
if (defs & ArchDefinePwr7)
Builder.defineMacro("_ARCH_PWR7");
+ if (defs & ArchDefinePwr8)
+ Builder.defineMacro("_ARCH_PWR8");
if (defs & ArchDefineA2)
Builder.defineMacro("_ARCH_A2");
if (defs & ArchDefineA2q) {
@@ -1086,6 +1126,7 @@ void PPCTargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
.Case("g5", true)
.Case("pwr6", true)
.Case("pwr7", true)
+ .Case("pwr8", true)
.Case("ppc64", true)
.Case("ppc64le", true)
.Default(false);
@@ -1206,8 +1247,7 @@ namespace {
class PPC32TargetInfo : public PPCTargetInfo {
public:
PPC32TargetInfo(const llvm::Triple &Triple) : PPCTargetInfo(Triple) {
- DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32";
+ DescriptionString = "E-m:e-p:32:32-i64:64-n32";
switch (getTriple().getOS()) {
case llvm::Triple::Linux:
@@ -1230,7 +1270,7 @@ public:
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
}
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ BuiltinVaListKind getBuiltinVaListKind() const override {
// This is the ELF definition, and is overridden by the Darwin sub-target
return TargetInfo::PowerABIBuiltinVaList;
}
@@ -1245,24 +1285,24 @@ public:
PPC64TargetInfo(const llvm::Triple &Triple) : PPCTargetInfo(Triple) {
LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
IntMaxType = SignedLong;
- UIntMaxType = UnsignedLong;
Int64Type = SignedLong;
if (getTriple().getOS() == llvm::Triple::FreeBSD) {
LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
- DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-"
- "v128:128:128-n32:64";
- } else
- DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-f128:128:128-"
- "v128:128:128-n32:64";
+ DescriptionString = "E-m:e-i64:64-n32:64";
+ } else {
+ if ((Triple.getArch() == llvm::Triple::ppc64le)) {
+ DescriptionString = "e-m:e-i64:64-n32:64";
+ } else {
+ DescriptionString = "E-m:e-i64:64-n32:64";
+ }
+}
// PPC64 supports atomics up to 8 bytes.
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
}
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::CharPtrBuiltinVaList;
}
};
@@ -1280,10 +1320,9 @@ public:
PtrDiffType = SignedInt; // for http://llvm.org/bugs/show_bug.cgi?id=15726
LongLongAlign = 32;
SuitableAlign = 128;
- DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:32:64-f32:32:32-f64:32:64-v128:128:128-n32";
+ DescriptionString = "E-m:o-p:32:32-f64:32:64-n32";
}
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::CharPtrBuiltinVaList;
}
};
@@ -1295,8 +1334,7 @@ public:
: DarwinTargetInfo<PPC64TargetInfo>(Triple) {
HasAlignMac68kSupport = true;
SuitableAlign = 128;
- DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32:64";
+ DescriptionString = "E-m:o-i64:64-n32:64";
}
};
} // end anonymous namespace.
@@ -1324,30 +1362,30 @@ namespace {
// These must be defined in sorted order!
NoAsmVariants = true;
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
Builder.defineMacro("__PTX__");
Builder.defineMacro("__NVPTX__");
}
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {
+ void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const override {
Records = BuiltinInfo;
NumRecords = clang::NVPTX::LastTSBuiltin-Builtin::FirstTSBuiltin;
}
- virtual bool hasFeature(StringRef Feature) const {
+ bool hasFeature(StringRef Feature) const override {
return Feature == "ptx" || Feature == "nvptx";
}
-
- virtual void getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const;
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const {
+
+ void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const override;
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override {
// No aliases.
- Aliases = 0;
+ Aliases = nullptr;
NumAliases = 0;
}
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const {
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
switch (*Name) {
default: return false;
case 'c':
@@ -1360,15 +1398,15 @@ namespace {
return true;
}
}
- virtual const char *getClobbers() const {
+ const char *getClobbers() const override {
// FIXME: Is this really right?
return "";
}
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ BuiltinVaListKind getBuiltinVaListKind() const override {
// FIXME: implement
return TargetInfo::CharPtrBuiltinVaList;
}
- virtual bool setCPU(const std::string &Name) {
+ bool setCPU(const std::string &Name) override {
bool Valid = llvm::StringSwitch<bool>(Name)
.Case("sm_20", true)
.Case("sm_21", true)
@@ -1401,11 +1439,9 @@ namespace {
public:
NVPTX32TargetInfo(const llvm::Triple &Triple) : NVPTXTargetInfo(Triple) {
PointerWidth = PointerAlign = 32;
- SizeType = PtrDiffType = IntPtrType = TargetInfo::UnsignedInt;
- 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-v16:16:16-v32:32:32-v64:64:64-v128:128:128-"
- "n16:32:64";
+ SizeType = PtrDiffType = TargetInfo::UnsignedInt;
+ IntPtrType = TargetInfo::SignedInt;
+ DescriptionString = "e-p:32:32-i64:64-v16:16-v32:32-n16:32:64";
}
};
@@ -1413,11 +1449,9 @@ namespace {
public:
NVPTX64TargetInfo(const llvm::Triple &Triple) : NVPTXTargetInfo(Triple) {
PointerWidth = PointerAlign = 64;
- SizeType = PtrDiffType = IntPtrType = TargetInfo::UnsignedLongLong;
- DescriptionString
- = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"
- "f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-"
- "n16:32:64";
+ SizeType = PtrDiffType = TargetInfo::UnsignedLongLong;
+ IntPtrType = TargetInfo::SignedLongLong;
+ DescriptionString = "e-i64:64-v16:16-v32:32-n16:32:64";
}
};
}
@@ -1434,31 +1468,21 @@ static const unsigned R600AddrSpaceMap[] = {
};
static const char *DescriptionStringR600 =
- "e"
- "-p:32:32:32"
- "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32"
- "-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128"
- "-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024-v2048:2048:2048"
- "-n32:64";
+ "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128"
+ "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64";
static const char *DescriptionStringR600DoubleOps =
- "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"
- "-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128"
- "-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024-v2048:2048:2048"
- "-n32:64";
+ "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128"
+ "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64";
static const char *DescriptionStringSI =
- "e"
- "-p:64:64:64"
- "-p3:32:32:32"
- "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64"
- "-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128"
- "-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024-v2048:2048:2048"
- "-n32:64";
+ "e-p:32:32-p1:64:64-p2:64:64-p3:32:32-p4:64:64-p5:32:32-p24:64:64"
+ "-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128"
+ "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64";
class R600TargetInfo : public TargetInfo {
+ static const Builtin::Info BuiltinInfo[];
+
/// \brief The GPU profiles supported by the R600 target.
enum GPUKind {
GK_NONE,
@@ -1482,44 +1506,43 @@ public:
UseAddrSpaceMapMangling = true;
}
- virtual const char * getClobbers() const {
+ const char * getClobbers() const override {
return "";
}
- virtual void getGCCRegNames(const char * const *&Names,
- unsigned &numNames) const {
- Names = NULL;
+ void getGCCRegNames(const char * const *&Names,
+ unsigned &numNames) const override {
+ Names = nullptr;
numNames = 0;
}
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const {
- Aliases = NULL;
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override {
+ Aliases = nullptr;
NumAliases = 0;
}
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const {
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override {
return true;
}
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {
- Records = NULL;
- NumRecords = 0;
+ void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const override {
+ Records = BuiltinInfo;
+ NumRecords = clang::R600::LastTSBuiltin - Builtin::FirstTSBuiltin;
}
-
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
Builder.defineMacro("__R600__");
}
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::CharPtrBuiltinVaList;
}
- virtual bool setCPU(const std::string &Name) {
+ bool setCPU(const std::string &Name) override {
GPU = llvm::StringSwitch<GPUKind>(Name)
.Case("r600" , GK_R600)
.Case("rv610", GK_R600)
@@ -1554,6 +1577,7 @@ public:
.Case("kabini", GK_SEA_ISLANDS)
.Case("kaveri", GK_SEA_ISLANDS)
.Case("hawaii", GK_SEA_ISLANDS)
+ .Case("mullins", GK_SEA_ISLANDS)
.Default(GK_NONE);
if (GPU == GK_NONE) {
@@ -1585,6 +1609,12 @@ public:
}
};
+const Builtin::Info R600TargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
+#include "clang/Basic/BuiltinsR600.def"
+};
+
} // end anonymous namespace
namespace {
@@ -1784,6 +1814,7 @@ class X86TargetInfo : public TargetInfo {
CK_BDVER1,
CK_BDVER2,
CK_BDVER3,
+ CK_BDVER4,
//@}
/// This specification is deprecated and will be removed in the future.
@@ -1817,57 +1848,57 @@ public:
BigEndian = false;
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended;
}
- virtual unsigned getFloatEvalMethod() const {
+ unsigned getFloatEvalMethod() const override {
// X87 evaluates with 80 bits "long double" precision.
return SSELevel == NoSSE ? 2 : 0;
}
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {
+ void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const override {
Records = BuiltinInfo;
NumRecords = clang::X86::LastTSBuiltin-Builtin::FirstTSBuiltin;
}
- virtual void getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const {
+ void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const override {
Names = GCCRegNames;
NumNames = llvm::array_lengthof(GCCRegNames);
}
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const {
- Aliases = 0;
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override {
+ Aliases = nullptr;
NumAliases = 0;
}
- virtual void getGCCAddlRegNames(const AddlRegName *&Names,
- unsigned &NumNames) const {
+ void getGCCAddlRegNames(const AddlRegName *&Names,
+ unsigned &NumNames) const override {
Names = AddlRegNames;
NumNames = llvm::array_lengthof(AddlRegNames);
}
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const;
- virtual std::string convertConstraint(const char *&Constraint) const;
- virtual const char *getClobbers() const {
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override;
+ std::string convertConstraint(const char *&Constraint) const override;
+ const char *getClobbers() const override {
return "~{dirflag},~{fpsr},~{flags}";
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const;
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
static void setSSELevel(llvm::StringMap<bool> &Features, X86SSEEnum Level,
bool Enabled);
static void setMMXLevel(llvm::StringMap<bool> &Features, MMX3DNowEnum Level,
bool Enabled);
static void setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level,
bool Enabled);
- virtual void setFeatureEnabled(llvm::StringMap<bool> &Features,
- StringRef Name, bool Enabled) const {
+ void setFeatureEnabled(llvm::StringMap<bool> &Features,
+ StringRef Name, bool Enabled) const override {
setFeatureEnabledImpl(Features, Name, Enabled);
}
// This exists purely to cut down on the number of virtual calls in
// getDefaultFeatures which calls this repeatedly.
static void setFeatureEnabledImpl(llvm::StringMap<bool> &Features,
StringRef Name, bool Enabled);
- virtual void getDefaultFeatures(llvm::StringMap<bool> &Features) const;
- virtual bool hasFeature(StringRef Feature) const;
- virtual bool handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags);
- virtual const char* getABI() const {
+ void getDefaultFeatures(llvm::StringMap<bool> &Features) const override;
+ bool hasFeature(StringRef Feature) const override;
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override;
+ StringRef getABI() const override {
if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX)
return "avx";
else if (getTriple().getArch() == llvm::Triple::x86 &&
@@ -1875,7 +1906,7 @@ public:
return "no-mmx";
return "";
}
- virtual bool setCPU(const std::string &Name) {
+ bool setCPU(const std::string &Name) override {
CPU = llvm::StringSwitch<CPUKind>(Name)
.Case("i386", CK_i386)
.Case("i486", CK_i486)
@@ -1927,6 +1958,7 @@ public:
.Case("bdver1", CK_BDVER1)
.Case("bdver2", CK_BDVER2)
.Case("bdver3", CK_BDVER3)
+ .Case("bdver4", CK_BDVER4)
.Case("x86-64", CK_x86_64)
.Case("geode", CK_Geode)
.Default(CK_Generic);
@@ -1996,15 +2028,16 @@ public:
case CK_BDVER1:
case CK_BDVER2:
case CK_BDVER3:
+ case CK_BDVER4:
case CK_x86_64:
return true;
}
llvm_unreachable("Unhandled CPU kind");
}
- virtual bool setFPMath(StringRef Name);
+ bool setFPMath(StringRef Name) override;
- virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
// We accept all non-ARM calling conventions
return (CC == CC_X86ThisCall ||
CC == CC_X86FastCall ||
@@ -2014,7 +2047,7 @@ public:
CC == CC_IntelOclBicc) ? CCCR_OK : CCCR_Warning;
}
- virtual CallingConv getDefaultCallingConv(CallingConvMethodType MT) const {
+ CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override {
return MT == CCMT_Member ? CC_X86ThisCall : CC_C;
}
};
@@ -2198,6 +2231,10 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
setFeatureEnabledImpl(Features, "prfchw", true);
setFeatureEnabledImpl(Features, "cx16", true);
break;
+ case CK_BDVER4:
+ setFeatureEnabledImpl(Features, "avx2", true);
+ setFeatureEnabledImpl(Features, "bmi2", true);
+ // FALLTHROUGH
case CK_BDVER2:
case CK_BDVER3:
setFeatureEnabledImpl(Features, "xop", true);
@@ -2701,13 +2738,15 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case CK_BDVER3:
defineCPUMacros(Builder, "bdver3");
break;
+ case CK_BDVER4:
+ defineCPUMacros(Builder, "bdver4");
+ break;
case CK_Geode:
defineCPUMacros(Builder, "geode");
break;
}
// Target properties.
- Builder.defineMacro("__LITTLE_ENDIAN__");
Builder.defineMacro("__REGISTER_PREFIX__", "");
// Define __NO_MATH_INLINES on linux/x86 so that we don't get inline
@@ -2900,6 +2939,13 @@ X86TargetInfo::validateAsmConstraint(const char *&Name,
case 'm': // any MMX register, when inter-unit moves enabled.
break; // falls through to setAllowsRegister.
}
+ case 'f': // any x87 floating point stack register.
+ // Constraint 'f' cannot be used for output operands.
+ if (Info.ConstraintStr[0] == '=')
+ return false;
+
+ Info.setAllowsRegister();
+ return true;
case 'a': // eax.
case 'b': // ebx.
case 'c': // ecx.
@@ -2907,7 +2953,6 @@ X86TargetInfo::validateAsmConstraint(const char *&Name,
case 'S': // esi.
case 'D': // edi.
case 'A': // edx:eax.
- case 'f': // any x87 floating point stack register.
case 't': // top of floating point stack.
case 'u': // second from top of floating point stack.
case 'q': // Any register accessible as [r]l: a, b, c, and d.
@@ -2960,9 +3005,7 @@ public:
LongDoubleWidth = 96;
LongDoubleAlign = 32;
SuitableAlign = 128;
- DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-"
- "a0:0:64-f80:32:32-n8:16:32-S128";
+ DescriptionString = "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128";
SizeType = UnsignedInt;
PtrDiffType = SignedInt;
IntPtrType = SignedInt;
@@ -2978,17 +3021,17 @@ public:
// MaxAtomicInlineWidth. (cmpxchg8b is an i586 instruction.)
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
}
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::CharPtrBuiltinVaList;
}
- int getEHDataRegisterNumber(unsigned RegNo) const {
+ int getEHDataRegisterNumber(unsigned RegNo) const override {
if (RegNo == 0) return 0;
if (RegNo == 1) return 2;
return -1;
}
- virtual bool validateInputSize(StringRef Constraint,
- unsigned Size) const {
+ bool validateInputSize(StringRef Constraint,
+ unsigned Size) const override {
switch (Constraint[0]) {
default: break;
case 'a':
@@ -3009,7 +3052,7 @@ public:
NetBSDI386TargetInfo(const llvm::Triple &Triple)
: NetBSDTargetInfo<X86_32TargetInfo>(Triple) {}
- virtual unsigned getFloatEvalMethod() const {
+ unsigned getFloatEvalMethod() const override {
unsigned Major, Minor, Micro;
getTriple().getOSVersion(Major, Minor, Micro);
// New NetBSD uses the default rounding mode.
@@ -3056,9 +3099,7 @@ public:
MaxVectorAlign = 256;
SizeType = UnsignedLong;
IntPtrType = SignedLong;
- DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-"
- "a0:0:64-f80:128:128-n8:16:32-S128";
+ DescriptionString = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128";
HasAlignMac68kSupport = true;
}
@@ -3071,32 +3112,26 @@ class WindowsX86_32TargetInfo : public WindowsTargetInfo<X86_32TargetInfo> {
public:
WindowsX86_32TargetInfo(const llvm::Triple &Triple)
: WindowsTargetInfo<X86_32TargetInfo>(Triple) {
- TLSSupported = false;
WCharType = UnsignedShort;
DoubleAlign = LongLongAlign = 64;
- DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-"
- "v128:128:128-a0:0:64-f80:32:32-n8:16:32-S32";
+ DescriptionString = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32";
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
WindowsTargetInfo<X86_32TargetInfo>::getTargetDefines(Opts, Builder);
}
};
-} // end anonymous namespace
-
-namespace {
// x86-32 Windows Visual Studio target
-class VisualStudioWindowsX86_32TargetInfo : public WindowsX86_32TargetInfo {
+class MicrosoftX86_32TargetInfo : public WindowsX86_32TargetInfo {
public:
- VisualStudioWindowsX86_32TargetInfo(const llvm::Triple &Triple)
+ MicrosoftX86_32TargetInfo(const llvm::Triple &Triple)
: WindowsX86_32TargetInfo(Triple) {
LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
WindowsX86_32TargetInfo::getVisualStudioDefines(Opts, Builder);
// The value of the following reflects processor type.
@@ -3107,29 +3142,46 @@ public:
};
} // end anonymous namespace
+static void addMinGWDefines(const LangOptions &Opts, MacroBuilder &Builder) {
+ Builder.defineMacro("__MSVCRT__");
+ Builder.defineMacro("__MINGW32__");
+
+ // Mingw defines __declspec(a) to __attribute__((a)). Clang supports
+ // __declspec natively under -fms-extensions, but we define a no-op __declspec
+ // macro anyway for pre-processor compatibility.
+ if (Opts.MicrosoftExt)
+ Builder.defineMacro("__declspec", "__declspec");
+ else
+ Builder.defineMacro("__declspec(a)", "__attribute__((a))");
+
+ if (!Opts.MicrosoftExt) {
+ // Provide macros for all the calling convention keywords. Provide both
+ // single and double underscore prefixed variants. These are available on
+ // x64 as well as x86, even though they have no effect.
+ const char *CCs[] = {"cdecl", "stdcall", "fastcall", "thiscall", "pascal"};
+ for (const char *CC : CCs) {
+ std::string GCCSpelling = "__attribute__((__";
+ GCCSpelling += CC;
+ GCCSpelling += "__))";
+ Builder.defineMacro(Twine("_") + CC, GCCSpelling);
+ Builder.defineMacro(Twine("__") + CC, GCCSpelling);
+ }
+ }
+}
+
namespace {
// x86-32 MinGW target
class MinGWX86_32TargetInfo : public WindowsX86_32TargetInfo {
public:
MinGWX86_32TargetInfo(const llvm::Triple &Triple)
: WindowsX86_32TargetInfo(Triple) {}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
DefineStd(Builder, "WIN32", Opts);
DefineStd(Builder, "WINNT", Opts);
Builder.defineMacro("_X86_");
- Builder.defineMacro("__MSVCRT__");
- Builder.defineMacro("__MINGW32__");
-
- // mingw32-gcc provides __declspec(a) as alias of __attribute__((a)).
- // In contrast, clang-cc1 provides __declspec(a) with -fms-extensions.
- if (Opts.MicrosoftExt)
- // Provide "as-is" __declspec.
- Builder.defineMacro("__declspec", "__declspec");
- else
- // Provide alias of __attribute__ like mingw32-gcc.
- Builder.defineMacro("__declspec(a)", "__attribute__((a))");
+ addMinGWDefines(Opts, Builder);
}
};
} // end anonymous namespace
@@ -3143,12 +3195,10 @@ public:
TLSSupported = false;
WCharType = UnsignedShort;
DoubleAlign = LongLongAlign = 64;
- DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
- "a0:0:64-f80:32:32-n8:16:32-S32";
+ DescriptionString = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32";
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
X86_32TargetInfo::getTargetDefines(Opts, Builder);
Builder.defineMacro("_X86_");
Builder.defineMacro("__CYGWIN__");
@@ -3172,8 +3222,8 @@ public:
this->UserLabelPrefix = "";
this->TLSSupported = false;
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
X86_32TargetInfo::getTargetDefines(Opts, Builder);
Builder.defineMacro("__INTEL__");
Builder.defineMacro("__HAIKU__");
@@ -3185,8 +3235,8 @@ public:
template<typename Target>
class RTEMSTargetInfo : public OSTargetInfo<Target> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
// RTEMS defines; list based off of gcc output
Builder.defineMacro("__rtems__");
@@ -3226,8 +3276,8 @@ public:
PtrDiffType = SignedLong;
this->UserLabelPrefix = "";
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
X86_32TargetInfo::getTargetDefines(Opts, Builder);
Builder.defineMacro("__INTEL__");
Builder.defineMacro("__rtems__");
@@ -3240,20 +3290,23 @@ namespace {
class X86_64TargetInfo : public X86TargetInfo {
public:
X86_64TargetInfo(const llvm::Triple &Triple) : X86TargetInfo(Triple) {
- LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
+ const bool IsX32 = getTriple().getEnvironment() == llvm::Triple::GNUX32;
+ LongWidth = LongAlign = PointerWidth = PointerAlign = IsX32 ? 32 : 64;
LongDoubleWidth = 128;
LongDoubleAlign = 128;
LargeArrayMinWidth = 128;
LargeArrayAlign = 128;
SuitableAlign = 128;
- IntMaxType = SignedLong;
- UIntMaxType = UnsignedLong;
- Int64Type = SignedLong;
+ SizeType = IsX32 ? UnsignedInt : UnsignedLong;
+ PtrDiffType = IsX32 ? SignedInt : SignedLong;
+ IntPtrType = IsX32 ? SignedInt : SignedLong;
+ IntMaxType = IsX32 ? SignedLongLong : SignedLong;
+ Int64Type = IsX32 ? SignedLongLong : SignedLong;
RegParmMax = 6;
- DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
- "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128";
+ DescriptionString = (IsX32)
+ ? "e-m:e-" "p:32:32-" "i64:64-f80:128-n8:16:32:64-S128"
+ : "e-m:e-" "i64:64-f80:128-n8:16:32:64-S128";
// Use fpret only for long double.
RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble);
@@ -3262,28 +3315,26 @@ public:
ComplexLongDoubleUsesFP2Ret = true;
// x86-64 has atomics up to 16 bytes.
- // FIXME: Once the backend is fixed, increase MaxAtomicInlineWidth to 128
- // on CPUs with cmpxchg16b
MaxAtomicPromoteWidth = 128;
- MaxAtomicInlineWidth = 64;
+ MaxAtomicInlineWidth = 128;
}
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::X86_64ABIBuiltinVaList;
}
- int getEHDataRegisterNumber(unsigned RegNo) const {
+ int getEHDataRegisterNumber(unsigned RegNo) const override {
if (RegNo == 0) return 0;
if (RegNo == 1) return 1;
return -1;
}
- virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
return (CC == CC_C ||
CC == CC_IntelOclBicc ||
CC == CC_X86_64Win64) ? CCCR_OK : CCCR_Warning;
}
- virtual CallingConv getDefaultCallingConv(CallingConvMethodType MT) const {
+ CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override {
return CC_C;
}
@@ -3296,27 +3347,25 @@ class WindowsX86_64TargetInfo : public WindowsTargetInfo<X86_64TargetInfo> {
public:
WindowsX86_64TargetInfo(const llvm::Triple &Triple)
: WindowsTargetInfo<X86_64TargetInfo>(Triple) {
- TLSSupported = false;
WCharType = UnsignedShort;
LongWidth = LongAlign = 32;
DoubleAlign = LongLongAlign = 64;
IntMaxType = SignedLongLong;
- UIntMaxType = UnsignedLongLong;
Int64Type = SignedLongLong;
SizeType = UnsignedLongLong;
PtrDiffType = SignedLongLong;
IntPtrType = SignedLongLong;
this->UserLabelPrefix = "";
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
WindowsTargetInfo<X86_64TargetInfo>::getTargetDefines(Opts, Builder);
Builder.defineMacro("_WIN64");
}
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::CharPtrBuiltinVaList;
}
- virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
return (CC == CC_C ||
CC == CC_IntelOclBicc ||
CC == CC_X86_64SysV) ? CCCR_OK : CCCR_Warning;
@@ -3326,15 +3375,15 @@ public:
namespace {
// x86-64 Windows Visual Studio target
-class VisualStudioWindowsX86_64TargetInfo : public WindowsX86_64TargetInfo {
+class MicrosoftX86_64TargetInfo : public WindowsX86_64TargetInfo {
public:
- VisualStudioWindowsX86_64TargetInfo(const llvm::Triple &Triple)
+ MicrosoftX86_64TargetInfo(const llvm::Triple &Triple)
: WindowsX86_64TargetInfo(Triple) {
LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
WindowsX86_64TargetInfo::getVisualStudioDefines(Opts, Builder);
Builder.defineMacro("_M_X64");
@@ -3349,22 +3398,12 @@ class MinGWX86_64TargetInfo : public WindowsX86_64TargetInfo {
public:
MinGWX86_64TargetInfo(const llvm::Triple &Triple)
: WindowsX86_64TargetInfo(Triple) {}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
DefineStd(Builder, "WIN64", Opts);
- Builder.defineMacro("__MSVCRT__");
- Builder.defineMacro("__MINGW32__");
Builder.defineMacro("__MINGW64__");
-
- // mingw32-gcc provides __declspec(a) as alias of __attribute__((a)).
- // In contrast, clang-cc1 provides __declspec(a) with -fms-extensions.
- if (Opts.MicrosoftExt)
- // Provide "as-is" __declspec.
- Builder.defineMacro("__declspec", "__declspec");
- else
- // Provide alias of __attribute__ like mingw32-gcc.
- Builder.defineMacro("__declspec(a)", "__attribute__((a))");
+ addMinGWDefines(Opts, Builder);
}
};
} // end anonymous namespace
@@ -3376,6 +3415,11 @@ public:
: DarwinTargetInfo<X86_64TargetInfo>(Triple) {
Int64Type = SignedLongLong;
MaxVectorAlign = 256;
+ // The 64-bit iOS simulator uses the builtin bool type for Objective-C.
+ llvm::Triple T = llvm::Triple(Triple);
+ if (T.getOS() == llvm::Triple::IOS)
+ UseSignedCharForObjCBool = false;
+ DescriptionString = "e-m:o-i64:64-f80:128-n8:16:32:64-S128";
}
};
} // end anonymous namespace
@@ -3386,7 +3430,6 @@ public:
OpenBSDX86_64TargetInfo(const llvm::Triple &Triple)
: OpenBSDTargetInfo<X86_64TargetInfo>(Triple) {
IntMaxType = SignedLongLong;
- UIntMaxType = UnsignedLongLong;
Int64Type = SignedLongLong;
}
};
@@ -3398,242 +3441,11 @@ public:
BitrigX86_64TargetInfo(const llvm::Triple &Triple)
: BitrigTargetInfo<X86_64TargetInfo>(Triple) {
IntMaxType = SignedLongLong;
- UIntMaxType = UnsignedLongLong;
Int64Type = SignedLongLong;
}
};
}
-namespace {
-class AArch64TargetInfo : public TargetInfo {
- static const char * const GCCRegNames[];
- static const TargetInfo::GCCRegAlias GCCRegAliases[];
-
- enum FPUModeEnum {
- FPUMode,
- NeonMode
- };
-
- unsigned FPU;
- unsigned Crypto;
- static const Builtin::Info BuiltinInfo[];
-
-public:
- AArch64TargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
- BigEndian = false;
- LongWidth = LongAlign = 64;
- LongDoubleWidth = LongDoubleAlign = 128;
- PointerWidth = PointerAlign = 64;
- SuitableAlign = 128;
- DescriptionString = "e-p:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-i128:128:128-f32:32:32-f64:64:64-"
- "f128:128:128-n32:64-S128";
-
- WCharType = UnsignedInt;
- LongDoubleFormat = &llvm::APFloat::IEEEquad;
-
- // AArch64 backend supports 64-bit operations at the moment. In principle
- // 128-bit is possible if register-pairs are used.
- MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
-
- TheCXXABI.set(TargetCXXABI::GenericAArch64);
- }
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- // GCC defines theses currently
- Builder.defineMacro("__aarch64__");
- Builder.defineMacro("__AARCH64EL__");
-
- // ACLE predefines. Many can only have one possible value on v8 AArch64.
- Builder.defineMacro("__ARM_ACLE", "200");
- Builder.defineMacro("__ARM_ARCH", "8");
- Builder.defineMacro("__ARM_ARCH_PROFILE", "'A'");
-
- Builder.defineMacro("__ARM_64BIT_STATE");
- Builder.defineMacro("__ARM_PCS_AAPCS64");
- Builder.defineMacro("__ARM_ARCH_ISA_A64");
-
- Builder.defineMacro("__ARM_FEATURE_UNALIGNED");
- Builder.defineMacro("__ARM_FEATURE_CLZ");
- Builder.defineMacro("__ARM_FEATURE_FMA");
- Builder.defineMacro("__ARM_FEATURE_DIV");
-
- Builder.defineMacro("__ARM_ALIGN_MAX_STACK_PWR", "4");
-
- // 0xe implies support for half, single and double precision operations.
- Builder.defineMacro("__ARM_FP", "0xe");
-
- // PCS specifies this for SysV variants, which is all we support. Other ABIs
- // may choose __ARM_FP16_FORMAT_ALTERNATIVE.
- Builder.defineMacro("__ARM_FP16_FORMAT_IEEE");
-
- if (Opts.FastMath || Opts.FiniteMathOnly)
- Builder.defineMacro("__ARM_FP_FAST");
-
- if ((Opts.C99 || Opts.C11) && !Opts.Freestanding)
- Builder.defineMacro("__ARM_FP_FENV_ROUNDING");
-
- Builder.defineMacro("__ARM_SIZEOF_WCHAR_T",
- Opts.ShortWChar ? "2" : "4");
-
- Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM",
- Opts.ShortEnums ? "1" : "4");
-
- if (BigEndian)
- Builder.defineMacro("__AARCH_BIG_ENDIAN");
-
- if (FPU == NeonMode) {
- Builder.defineMacro("__ARM_NEON");
- // 64-bit NEON supports half, single and double precision operations.
- Builder.defineMacro("__ARM_NEON_FP", "7");
- }
-
- if (Crypto) {
- Builder.defineMacro("__ARM_FEATURE_CRYPTO");
- }
- }
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {
- Records = BuiltinInfo;
- NumRecords = clang::AArch64::LastTSBuiltin-Builtin::FirstTSBuiltin;
- }
- virtual bool hasFeature(StringRef Feature) const {
- return Feature == "aarch64" || (Feature == "neon" && FPU == NeonMode);
- }
-
- virtual bool setCPU(const std::string &Name) {
- return llvm::StringSwitch<bool>(Name)
- .Case("generic", true)
- .Cases("cortex-a53", "cortex-a57", true)
- .Default(false);
- }
-
- virtual bool handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) {
- FPU = FPUMode;
- Crypto = 0;
- for (unsigned i = 0, e = Features.size(); i != e; ++i) {
- if (Features[i] == "+neon")
- FPU = NeonMode;
- if (Features[i] == "+crypto")
- Crypto = 1;
- }
- return true;
- }
-
- virtual void getGCCRegNames(const char *const *&Names,
- unsigned &NumNames) const;
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const;
-
- virtual bool isCLZForZeroUndef() const { return false; }
-
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const {
- switch (*Name) {
- default: return false;
- case 'w': // An FP/SIMD vector register
- Info.setAllowsRegister();
- return true;
- case 'I': // Constant that can be used with an ADD instruction
- case 'J': // Constant that can be used with a SUB instruction
- case 'K': // Constant that can be used with a 32-bit logical instruction
- case 'L': // Constant that can be used with a 64-bit logical instruction
- case 'M': // Constant that can be used as a 32-bit MOV immediate
- case 'N': // Constant that can be used as a 64-bit MOV immediate
- case 'Y': // Floating point constant zero
- case 'Z': // Integer constant zero
- return true;
- case 'Q': // A memory reference with base register and no offset
- Info.setAllowsMemory();
- return true;
- case 'S': // A symbolic address
- Info.setAllowsRegister();
- return true;
- case 'U':
- // Ump: A memory address suitable for ldp/stp in SI, DI, SF and DF modes, whatever they may be
- // Utf: A memory address suitable for ldp/stp in TF mode, whatever it may be
- // Usa: An absolute symbolic address
- // Ush: The high part (bits 32:12) of a pc-relative symbolic address
- llvm_unreachable("FIXME: Unimplemented support for bizarre constraints");
- }
- }
-
- virtual const char *getClobbers() const {
- // There are no AArch64 clobbers shared by all asm statements.
- return "";
- }
-
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
- return TargetInfo::AArch64ABIBuiltinVaList;
- }
-};
-
-const char * const AArch64TargetInfo::GCCRegNames[] = {
- "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
- "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
- "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
- "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wsp", "wzr",
-
- "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
- "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
- "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
- "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp", "xzr",
-
- "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",
- "b8", "b9", "b10", "b11", "b12", "b13", "b14", "b15",
- "b16", "b17", "b18", "b19", "b20", "b21", "b22", "b23",
- "b24", "b25", "b26", "b27", "b28", "b29", "b30", "b31",
-
- "h0", "h1", "h2", "h3", "h4", "h5", "h6", "h7",
- "h8", "h9", "h10", "h11", "h12", "h13", "h14", "h15",
- "h16", "h17", "h18", "h19", "h20", "h21", "h22", "h23",
- "h24", "h25", "h26", "h27", "h28", "h29", "h30", "h31",
-
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
- "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
- "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
-
- "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
- "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
- "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
- "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
-
- "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15",
- "q16", "q17", "q18", "q19", "q20", "q21", "q22", "q23",
- "q24", "q25", "q26", "q27", "q28", "q29", "q30", "q31"
-};
-
-void AArch64TargetInfo::getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const {
- Names = GCCRegNames;
- NumNames = llvm::array_lengthof(GCCRegNames);
-}
-
-const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = {
- { { "x16" }, "ip0"},
- { { "x17" }, "ip1"},
- { { "x29" }, "fp" },
- { { "x30" }, "lr" }
-};
-
-void AArch64TargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const {
- Aliases = GCCRegAliases;
- NumAliases = llvm::array_lengthof(GCCRegAliases);
-
-}
-
-const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = {
-#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\
- ALL_LANGUAGES },
-#include "clang/Basic/BuiltinsAArch64.def"
-};
-
-} // end anonymous namespace
namespace {
class ARMTargetInfo : public TargetInfo {
@@ -3678,55 +3490,177 @@ class ARMTargetInfo : public TargetInfo {
unsigned SoftFloatABI : 1;
unsigned CRC : 1;
+ unsigned Crypto : 1;
static const Builtin::Info BuiltinInfo[];
static bool shouldUseInlineAtomic(const llvm::Triple &T) {
- // On linux, binaries targeting old cpus call functions in libgcc to
- // perform atomic operations. The implementation in libgcc then calls into
- // the kernel which on armv6 and newer uses ldrex and strex. The net result
- // is that if we assume the kernel is at least as recent as the hardware,
- // it is safe to use atomic instructions on armv6 and newer.
- if (!T.isOSLinux() &&
- T.getOS() != llvm::Triple::FreeBSD &&
- T.getOS() != llvm::Triple::NetBSD &&
- T.getOS() != llvm::Triple::Bitrig)
- return false;
StringRef ArchName = T.getArchName();
- if (T.getArch() == llvm::Triple::arm) {
- if (!ArchName.startswith("armv"))
+ if (T.getArch() == llvm::Triple::arm ||
+ T.getArch() == llvm::Triple::armeb) {
+ StringRef VersionStr;
+ if (ArchName.startswith("armv"))
+ VersionStr = ArchName.substr(4, 1);
+ else if (ArchName.startswith("armebv"))
+ VersionStr = ArchName.substr(6, 1);
+ else
return false;
- StringRef VersionStr = ArchName.substr(4);
unsigned Version;
if (VersionStr.getAsInteger(10, Version))
return false;
return Version >= 6;
}
- assert(T.getArch() == llvm::Triple::thumb);
- if (!ArchName.startswith("thumbv"))
+ assert(T.getArch() == llvm::Triple::thumb ||
+ T.getArch() == llvm::Triple::thumbeb);
+ StringRef VersionStr;
+ if (ArchName.startswith("thumbv"))
+ VersionStr = ArchName.substr(6, 1);
+ else if (ArchName.startswith("thumbebv"))
+ VersionStr = ArchName.substr(8, 1);
+ else
return false;
- StringRef VersionStr = ArchName.substr(6);
unsigned Version;
if (VersionStr.getAsInteger(10, Version))
return false;
return Version >= 7;
}
-public:
- ARMTargetInfo(const llvm::Triple &Triple)
- : TargetInfo(Triple), ABI("aapcs-linux"), CPU("arm1136j-s"),
- FPMath(FP_Default), IsAAPCS(true) {
- BigEndian = false;
- switch (getTriple().getOS()) {
- case llvm::Triple::NetBSD:
+ void setABIAAPCS() {
+ IsAAPCS = true;
+
+ DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64;
+ const llvm::Triple &T = getTriple();
+
+ // size_t is unsigned long on Darwin and NetBSD.
+ if (T.isOSDarwin() || T.getOS() == llvm::Triple::NetBSD)
SizeType = UnsignedLong;
- PtrDiffType = SignedLong;
+ else
+ SizeType = UnsignedInt;
+
+ switch (T.getOS()) {
+ case llvm::Triple::NetBSD:
WCharType = SignedInt;
break;
+ case llvm::Triple::Win32:
+ WCharType = UnsignedShort;
+ break;
+ case llvm::Triple::Linux:
default:
// AAPCS 7.1.1, ARM-Linux ABI 2.4: type of wchar_t is unsigned int.
WCharType = UnsignedInt;
+ break;
+ }
+
+ UseBitFieldTypeAlignment = true;
+
+ ZeroLengthBitfieldBoundary = 0;
+
+ if (IsThumb) {
+ // Thumb1 add sp, #imm requires the immediate value be multiple of 4,
+ // so set preferred for small types to 32.
+ if (T.isOSBinFormatMachO()) {
+ DescriptionString = BigEndian ?
+ "E-m:o-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:64-"
+ "v128:64:128-a:0:32-n32-S64" :
+ "e-m:o-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:64-"
+ "v128:64:128-a:0:32-n32-S64";
+ } else if (T.isOSWindows()) {
+ // FIXME: this is invalid for WindowsCE
+ assert(!BigEndian && "Windows on ARM does not support big endian");
+ DescriptionString = "e"
+ "-m:e"
+ "-p:32:32"
+ "-i1:8:32-i8:8:32-i16:16:32-i64:64"
+ "-v128:64:128"
+ "-a:0:32"
+ "-n32"
+ "-S64";
+ } else {
+ DescriptionString = BigEndian ?
+ "E-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:64-"
+ "v128:64:128-a:0:32-n32-S64" :
+ "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:64-"
+ "v128:64:128-a:0:32-n32-S64";
+ }
+ } else {
+ if (T.isOSBinFormatMachO())
+ DescriptionString = BigEndian ?
+ "E-m:o-p:32:32-i64:64-v128:64:128-n32-S64" :
+ "e-m:o-p:32:32-i64:64-v128:64:128-n32-S64";
+ else
+ DescriptionString = BigEndian ?
+ "E-m:e-p:32:32-i64:64-v128:64:128-n32-S64" :
+ "e-m:e-p:32:32-i64:64-v128:64:128-n32-S64";
+ }
+
+ // FIXME: Enumerated types are variable width in straight AAPCS.
+ }
+
+ void setABIAPCS() {
+ const llvm::Triple &T = getTriple();
+
+ IsAAPCS = false;
+
+ DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32;
+
+ // size_t is unsigned int on FreeBSD.
+ if (T.getOS() == llvm::Triple::FreeBSD)
SizeType = UnsignedInt;
+ else
+ SizeType = UnsignedLong;
+
+ // Revert to using SignedInt on apcs-gnu to comply with existing behaviour.
+ WCharType = SignedInt;
+
+ // Do not respect the alignment of bit-field types when laying out
+ // structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc.
+ UseBitFieldTypeAlignment = false;
+
+ /// gcc forces the alignment to 4 bytes, regardless of the type of the
+ /// zero length bitfield. This corresponds to EMPTY_FIELD_BOUNDARY in
+ /// gcc.
+ ZeroLengthBitfieldBoundary = 32;
+
+ if (IsThumb) {
+ // Thumb1 add sp, #imm requires the immediate value be multiple of 4,
+ // so set preferred for small types to 32.
+ if (T.isOSBinFormatMachO())
+ DescriptionString = BigEndian ?
+ "E-m:o-p:32:32-i1:8:32-i8:8:32-i16:16:32-f64:32:64"
+ "-v64:32:64-v128:32:128-a:0:32-n32-S32" :
+ "e-m:o-p:32:32-i1:8:32-i8:8:32-i16:16:32-f64:32:64"
+ "-v64:32:64-v128:32:128-a:0:32-n32-S32";
+ else
+ DescriptionString = BigEndian ?
+ "E-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-f64:32:64"
+ "-v64:32:64-v128:32:128-a:0:32-n32-S32" :
+ "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-f64:32:64"
+ "-v64:32:64-v128:32:128-a:0:32-n32-S32";
+ } else {
+ if (T.isOSBinFormatMachO())
+ DescriptionString = BigEndian ?
+ "E-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" :
+ "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32";
+ else
+ DescriptionString = BigEndian ?
+ "E-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" :
+ "e-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32";
+ }
+
+ // FIXME: Override "preferred align" for double and long long.
+ }
+
+public:
+ ARMTargetInfo(const llvm::Triple &Triple, bool IsBigEndian)
+ : TargetInfo(Triple), CPU("arm1136j-s"), FPMath(FP_Default),
+ IsAAPCS(true) {
+ BigEndian = IsBigEndian;
+
+ switch (getTriple().getOS()) {
+ case llvm::Triple::NetBSD:
+ PtrDiffType = SignedLong;
+ break;
+ default:
PtrDiffType = SignedInt;
break;
}
@@ -3737,17 +3671,8 @@ public:
// FIXME: Should we just treat this as a feature?
IsThumb = getTriple().getArchName().startswith("thumb");
- if (IsThumb) {
- // 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:64:64-f32:32:32-f64:64:64-"
- "v64:64:64-v128:64:128-a0:0:32-n32-S64");
- } else {
- DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-"
- "v64:64:64-v128:64:128-a0:0:64-n32-S64");
- }
+
+ setABI("aapcs-linux");
// ARM targets default to using the ARM C++ ABI.
TheCXXABI.set(TargetCXXABI::GenericARM);
@@ -3763,8 +3688,8 @@ public:
// zero length bitfield.
UseZeroLengthBitfieldAlignment = true;
}
- virtual const char *getABI() const { return ABI.c_str(); }
- virtual bool setABI(const std::string &Name) {
+ StringRef getABI() const override { return ABI; }
+ bool setABI(const std::string &Name) override {
ABI = Name;
// The defaults (above) are for AAPCS, check if we need to change them.
@@ -3772,53 +3697,22 @@ public:
// FIXME: We need support for -meabi... we could just mangle it into the
// name.
if (Name == "apcs-gnu") {
- DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32;
- // size_t is unsigned int on FreeBSD.
- if (getTriple().getOS() != llvm::Triple::FreeBSD)
- SizeType = UnsignedLong;
-
- // Revert to using SignedInt on apcs-gnu to comply with existing behaviour.
- WCharType = SignedInt;
-
- // Do not respect the alignment of bit-field types when laying out
- // structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc.
- UseBitFieldTypeAlignment = false;
-
- /// gcc forces the alignment to 4 bytes, regardless of the type of the
- /// zero length bitfield. This corresponds to EMPTY_FIELD_BOUNDARY in
- /// gcc.
- ZeroLengthBitfieldBoundary = 32;
-
- IsAAPCS = false;
-
- if (IsThumb) {
- // 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:64-f32:32:32-f64:32:64-"
- "v64:32:64-v128:32:128-a0:0:32-n32-S32");
- } else {
- DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:32:64-f32:32:32-f64:32:64-"
- "v64:32:64-v128:32:128-a0:0:32-n32-S32");
- }
-
- // FIXME: Override "preferred align" for double and long long.
- } else if (Name == "aapcs" || Name == "aapcs-vfp") {
- // size_t is unsigned long on Darwin.
- if (getTriple().isOSDarwin())
- SizeType = UnsignedLong;
- IsAAPCS = true;
- // FIXME: Enumerated types are variable width in straight AAPCS.
- } else if (Name == "aapcs-linux") {
- IsAAPCS = true;
- } else
- return false;
-
- return true;
+ setABIAPCS();
+ return true;
+ }
+ if (Name == "aapcs" || Name == "aapcs-vfp" || Name == "aapcs-linux") {
+ setABIAAPCS();
+ return true;
+ }
+ return false;
}
- void getDefaultFeatures(llvm::StringMap<bool> &Features) const {
+ void getDefaultFeatures(llvm::StringMap<bool> &Features) const override {
+ if (IsAAPCS)
+ Features["aapcs"] = true;
+ else
+ Features["apcs"] = true;
+
StringRef ArchName = getTriple().getArchName();
if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore")
Features["vfp2"] = true;
@@ -3830,32 +3724,44 @@ public:
else if (CPU == "cortex-a5") {
Features["vfp4"] = true;
Features["neon"] = true;
- } else if (CPU == "swift" || CPU == "cortex-a7" || CPU == "cortex-a15") {
+ } else if (CPU == "swift" || CPU == "cortex-a7" ||
+ CPU == "cortex-a12" || CPU == "cortex-a15" ||
+ CPU == "krait") {
Features["vfp4"] = true;
Features["neon"] = true;
Features["hwdiv"] = true;
Features["hwdiv-arm"] = true;
+ } else if (CPU == "cyclone") {
+ Features["v8fp"] = true;
+ Features["neon"] = true;
+ Features["hwdiv"] = true;
+ Features["hwdiv-arm"] = true;
} else if (CPU == "cortex-a53" || CPU == "cortex-a57") {
Features["fp-armv8"] = true;
Features["neon"] = true;
Features["hwdiv"] = true;
Features["hwdiv-arm"] = true;
Features["crc"] = true;
- } else if (CPU == "cortex-r5" || CPU == "cortex-m3" ||
- CPU == "cortex-m4" ||
+ Features["crypto"] = true;
+ } else if (CPU == "cortex-r5" ||
// Enable the hwdiv extension for all v8a AArch32 cores by
// default.
ArchName == "armv8a" || ArchName == "armv8" ||
- ArchName == "thumbv8a" || ArchName == "thumbv8") {
+ ArchName == "armebv8a" || ArchName == "armebv8" ||
+ ArchName == "thumbv8a" || ArchName == "thumbv8" ||
+ ArchName == "thumbebv8a" || ArchName == "thumbebv8") {
Features["hwdiv"] = true;
Features["hwdiv-arm"] = true;
+ } else if (CPU == "cortex-m3" || CPU == "cortex-m4") {
+ Features["hwdiv"] = true;
}
}
- virtual bool handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) {
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override {
FPU = 0;
CRC = 0;
+ Crypto = 0;
SoftFloat = SoftFloatABI = false;
HWDiv = 0;
for (unsigned i = 0, e = Features.size(); i != e; ++i) {
@@ -3879,6 +3785,8 @@ public:
HWDiv |= HWDivARM;
else if (Features[i] == "+crc")
CRC = 1;
+ else if (Features[i] == "+crypto")
+ Crypto = 1;
}
if (!(FPU & NeonFPU) && FPMath == FP_Neon) {
@@ -3902,7 +3810,7 @@ public:
return true;
}
- virtual bool hasFeature(StringRef Feature) const {
+ bool hasFeature(StringRef Feature) const override {
return llvm::StringSwitch<bool>(Feature)
.Case("arm", true)
.Case("softfloat", SoftFloat)
@@ -3929,42 +3837,60 @@ public:
.Cases("arm1176jz-s", "arm1176jzf-s", "6ZK")
.Cases("arm1136jf-s", "mpcorenovfp", "mpcore", "6K")
.Cases("arm1156t2-s", "arm1156t2f-s", "6T2")
- .Cases("cortex-a5", "cortex-a7", "cortex-a8", "7A")
- .Cases("cortex-a9", "cortex-a12", "cortex-a15", "7A")
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "cortex-a9-mp", "7A")
+ .Cases("cortex-a9", "cortex-a12", "cortex-a15", "krait", "7A")
.Cases("cortex-r4", "cortex-r5", "7R")
- .Case("cortex-a9-mp", "7F")
.Case("swift", "7S")
- .Cases("cortex-m3", "cortex-m4", "7M")
+ .Case("cyclone", "8A")
+ .Case("cortex-m3", "7M")
+ .Case("cortex-m4", "7EM")
.Case("cortex-m0", "6M")
.Cases("cortex-a53", "cortex-a57", "8A")
- .Default(0);
+ .Default(nullptr);
}
static const char *getCPUProfile(StringRef Name) {
return llvm::StringSwitch<const char*>(Name)
.Cases("cortex-a5", "cortex-a7", "cortex-a8", "A")
- .Cases("cortex-a9", "cortex-a12", "cortex-a15", "A")
+ .Cases("cortex-a9", "cortex-a12", "cortex-a15", "krait", "A")
.Cases("cortex-a53", "cortex-a57", "A")
.Cases("cortex-m3", "cortex-m4", "cortex-m0", "M")
.Cases("cortex-r4", "cortex-r5", "R")
.Default("");
}
- virtual bool setCPU(const std::string &Name) {
+ bool setCPU(const std::string &Name) override {
if (!getCPUDefineSuffix(Name))
return false;
+ // Cortex M does not support 8 byte atomics, while general Thumb2 does.
+ StringRef Profile = getCPUProfile(Name);
+ if (Profile == "M" && MaxAtomicInlineWidth) {
+ MaxAtomicPromoteWidth = 32;
+ MaxAtomicInlineWidth = 32;
+ }
+
CPU = Name;
return true;
}
- virtual bool setFPMath(StringRef Name);
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ bool setFPMath(StringRef Name) override;
+ bool supportsThumb(StringRef ArchName, StringRef CPUArch,
+ unsigned CPUArchVer) const {
+ return CPUArchVer >= 7 || (CPUArch.find('T') != StringRef::npos) ||
+ (CPUArch.find('M') != StringRef::npos);
+ }
+ bool supportsThumb2(StringRef ArchName, StringRef CPUArch,
+ unsigned CPUArchVer) const {
+ // We check both CPUArchVer and ArchName because when only triple is
+ // specified, the default CPU is arm1136j-s.
+ return ArchName.endswith("v6t2") || ArchName.endswith("v7") ||
+ ArchName.endswith("v8") || CPUArch == "6T2" || CPUArchVer >= 7;
+ }
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
// Target identification.
Builder.defineMacro("__arm");
Builder.defineMacro("__arm__");
// Target properties.
- Builder.defineMacro("__ARMEL__");
- Builder.defineMacro("__LITTLE_ENDIAN__");
Builder.defineMacro("__REGISTER_PREFIX__", "");
StringRef CPUArch = getCPUDefineSuffix(CPU);
@@ -3973,21 +3899,53 @@ public:
llvm_unreachable("Invalid char for architecture version number");
}
Builder.defineMacro("__ARM_ARCH_" + CPUArch + "__");
- Builder.defineMacro("__ARM_ARCH", CPUArch.substr(0, 1));
+
+ // ACLE 6.4.1 ARM/Thumb instruction set architecture
StringRef CPUProfile = getCPUProfile(CPU);
+ StringRef ArchName = getTriple().getArchName();
+
+ // __ARM_ARCH is defined as an integer value indicating the current ARM ISA
+ Builder.defineMacro("__ARM_ARCH", CPUArch.substr(0, 1));
+
+ // __ARM_ARCH_ISA_ARM is defined to 1 if the core supports the ARM ISA. It
+ // is not defined for the M-profile.
+ // NOTE that the deffault profile is assumed to be 'A'
+ if (CPUProfile.empty() || CPUProfile != "M")
+ Builder.defineMacro("__ARM_ARCH_ISA_ARM", "1");
+
+ // __ARM_ARCH_ISA_THUMB is defined to 1 if the core supporst the original
+ // Thumb ISA (including v6-M). It is set to 2 if the core supports the
+ // Thumb-2 ISA as found in the v6T2 architecture and all v7 architecture.
+ if (supportsThumb2(ArchName, CPUArch, CPUArchVer))
+ Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "2");
+ else if (supportsThumb(ArchName, CPUArch, CPUArchVer))
+ Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "1");
+
+ // __ARM_32BIT_STATE is defined to 1 if code is being generated for a 32-bit
+ // instruction set such as ARM or Thumb.
+ Builder.defineMacro("__ARM_32BIT_STATE", "1");
+
+ // ACLE 6.4.2 Architectural Profile (A, R, M or pre-Cortex)
+
+ // __ARM_ARCH_PROFILE is defined as 'A', 'R', 'M' or 'S', or unset.
if (!CPUProfile.empty())
- Builder.defineMacro("__ARM_ARCH_PROFILE", CPUProfile);
-
+ Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + CPUProfile + "'");
+
+ // ACLE predefines.
+ Builder.defineMacro("__ARM_ACLE", "200");
+
// Subtarget options.
// FIXME: It's more complicated than this and we don't really support
// interworking.
- if (5 <= CPUArchVer && CPUArchVer <= 7)
+ // Windows on ARM does not "support" interworking
+ if (5 <= CPUArchVer && CPUArchVer <= 8 && !getTriple().isOSWindows())
Builder.defineMacro("__THUMB_INTERWORK__");
if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") {
// Embedded targets on Darwin follow AAPCS, but not EABI.
- if (!getTriple().isOSDarwin())
+ // Windows on ARM follows AAPCS VFP, but does not conform to EABI.
+ if (!getTriple().isOSDarwin() && !getTriple().isOSWindows())
Builder.defineMacro("__ARM_EABI__");
Builder.defineMacro("__ARM_PCS", "1");
@@ -4004,7 +3962,7 @@ public:
if (IsThumb) {
Builder.defineMacro("__THUMBEL__");
Builder.defineMacro("__thumb__");
- if (CPUArch == "6T2" || CPUArchVer == 7)
+ if (supportsThumb2(ArchName, CPUArch, CPUArchVer))
Builder.defineMacro("__thumb2__");
}
if (((HWDiv & HWDivThumb) && IsThumb) || ((HWDiv & HWDivARM) && !IsThumb))
@@ -4022,17 +3980,28 @@ public:
if (FPU & VFP4FPU)
Builder.defineMacro("__ARM_VFPV4__");
}
-
+
// This only gets set when Neon instructions are actually available, unlike
// the VFP define, hence the soft float and arch check. This is subtly
// different from gcc, we follow the intent which was that it should be set
// when Neon instructions are actually available.
- if ((FPU & NeonFPU) && !SoftFloat && CPUArchVer >= 7)
+ if ((FPU & NeonFPU) && !SoftFloat && CPUArchVer >= 7) {
+ Builder.defineMacro("__ARM_NEON");
Builder.defineMacro("__ARM_NEON__");
+ }
+
+ Builder.defineMacro("__ARM_SIZEOF_WCHAR_T",
+ Opts.ShortWChar ? "2" : "4");
+
+ Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM",
+ Opts.ShortEnums ? "1" : "4");
if (CRC)
Builder.defineMacro("__ARM_FEATURE_CRC32");
+ if (Crypto)
+ Builder.defineMacro("__ARM_FEATURE_CRYPTO");
+
if (CPUArchVer >= 6 && CPUArch != "6M") {
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
@@ -4040,21 +4009,21 @@ public:
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
}
}
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {
+ void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const override {
Records = BuiltinInfo;
NumRecords = clang::ARM::LastTSBuiltin-Builtin::FirstTSBuiltin;
}
- virtual bool isCLZForZeroUndef() const { return false; }
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ bool isCLZForZeroUndef() const override { return false; }
+ BuiltinVaListKind getBuiltinVaListKind() const override {
return IsAAPCS ? AAPCSABIBuiltinVaList : TargetInfo::VoidPtrBuiltinVaList;
}
- virtual void getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const;
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const;
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const {
+ void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const override;
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override;
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
switch (*Name) {
default: break;
case 'l': // r0-r7
@@ -4084,7 +4053,7 @@ public:
}
return false;
}
- virtual std::string convertConstraint(const char *&Constraint) const {
+ std::string convertConstraint(const char *&Constraint) const override {
std::string R;
switch (*Constraint) {
case 'U': // Two-character constraint; add "^" hint for later parsing.
@@ -4099,9 +4068,8 @@ public:
}
return R;
}
- virtual bool validateConstraintModifier(StringRef Constraint,
- const char Modifier,
- unsigned Size) const {
+ bool validateConstraintModifier(StringRef Constraint, const char Modifier,
+ unsigned Size) const override {
bool isOutput = (Constraint[0] == '=');
bool isInOut = (Constraint[0] == '+');
@@ -4126,16 +4094,16 @@ public:
return true;
}
- virtual const char *getClobbers() const {
+ const char *getClobbers() const override {
// FIXME: Is this really right?
return "";
}
- virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
+ CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
return (CC == CC_AAPCS || CC == CC_AAPCS_VFP) ? CCCR_OK : CCCR_Warning;
}
- virtual int getEHDataRegisterNumber(unsigned RegNo) const {
+ int getEHDataRegisterNumber(unsigned RegNo) const override {
if (RegNo == 0) return 0;
if (RegNo == 1) return 1;
return -1;
@@ -4213,25 +4181,123 @@ const Builtin::Info ARMTargetInfo::BuiltinInfo[] = {
#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\
ALL_LANGUAGES },
+#include "clang/Basic/BuiltinsNEON.def"
+
+#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
+#define LANGBUILTIN(ID, TYPE, ATTRS, LANG) { #ID, TYPE, ATTRS, 0, LANG },
+#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\
+ ALL_LANGUAGES },
#include "clang/Basic/BuiltinsARM.def"
};
+
+class ARMleTargetInfo : public ARMTargetInfo {
+public:
+ ARMleTargetInfo(const llvm::Triple &Triple)
+ : ARMTargetInfo(Triple, false) { }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__ARMEL__");
+ ARMTargetInfo::getTargetDefines(Opts, Builder);
+ }
+};
+
+class ARMbeTargetInfo : public ARMTargetInfo {
+public:
+ ARMbeTargetInfo(const llvm::Triple &Triple)
+ : ARMTargetInfo(Triple, true) { }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__ARMEB__");
+ Builder.defineMacro("__ARM_BIG_ENDIAN");
+ ARMTargetInfo::getTargetDefines(Opts, Builder);
+ }
+};
} // end anonymous namespace.
namespace {
+class WindowsARMTargetInfo : public WindowsTargetInfo<ARMleTargetInfo> {
+ const llvm::Triple Triple;
+public:
+ WindowsARMTargetInfo(const llvm::Triple &Triple)
+ : WindowsTargetInfo<ARMleTargetInfo>(Triple), Triple(Triple) {
+ TLSSupported = false;
+ WCharType = UnsignedShort;
+ SizeType = UnsignedInt;
+ UserLabelPrefix = "";
+ }
+ void getVisualStudioDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ WindowsTargetInfo<ARMleTargetInfo>::getVisualStudioDefines(Opts, Builder);
+
+ // FIXME: this is invalid for WindowsCE
+ Builder.defineMacro("_M_ARM_NT", "1");
+ Builder.defineMacro("_M_ARMT", "_M_ARM");
+ Builder.defineMacro("_M_THUMB", "_M_ARM");
+
+ assert((Triple.getArch() == llvm::Triple::arm ||
+ Triple.getArch() == llvm::Triple::thumb) &&
+ "invalid architecture for Windows ARM target info");
+ unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6;
+ Builder.defineMacro("_M_ARM", Triple.getArchName().substr(Offset));
+
+ // TODO map the complete set of values
+ // 31: VFPv3 40: VFPv4
+ Builder.defineMacro("_M_ARM_FP", "31");
+ }
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::CharPtrBuiltinVaList;
+ }
+};
+
+// Windows ARM + Itanium C++ ABI Target
+class ItaniumWindowsARMleTargetInfo : public WindowsARMTargetInfo {
+public:
+ ItaniumWindowsARMleTargetInfo(const llvm::Triple &Triple)
+ : WindowsARMTargetInfo(Triple) {
+ TheCXXABI.set(TargetCXXABI::GenericARM);
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ WindowsARMTargetInfo::getTargetDefines(Opts, Builder);
+
+ if (Opts.MSVCCompat)
+ WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder);
+ }
+};
+
+// Windows ARM, MS (C++) ABI
+class MicrosoftARMleTargetInfo : public WindowsARMTargetInfo {
+public:
+ MicrosoftARMleTargetInfo(const llvm::Triple &Triple)
+ : WindowsARMTargetInfo(Triple) {
+ TheCXXABI.set(TargetCXXABI::Microsoft);
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ WindowsARMTargetInfo::getTargetDefines(Opts, Builder);
+ WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder);
+ }
+};
+}
+
+
+namespace {
class DarwinARMTargetInfo :
- public DarwinTargetInfo<ARMTargetInfo> {
+ public DarwinTargetInfo<ARMleTargetInfo> {
protected:
- virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const {
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion);
}
public:
DarwinARMTargetInfo(const llvm::Triple &Triple)
- : DarwinTargetInfo<ARMTargetInfo>(Triple) {
+ : DarwinTargetInfo<ARMleTargetInfo>(Triple) {
HasAlignMac68kSupport = true;
// iOS always has 64-bit atomic instructions.
- // FIXME: This should be based off of the target features in ARMTargetInfo.
+ // FIXME: This should be based off of the target features in ARMleTargetInfo.
MaxAtomicInlineWidth = 64;
// Darwin on iOS uses a variant of the ARM C++ ABI.
@@ -4242,6 +4308,357 @@ public:
namespace {
+class AArch64TargetInfo : public TargetInfo {
+ virtual void setDescriptionString() = 0;
+ static const TargetInfo::GCCRegAlias GCCRegAliases[];
+ static const char *const GCCRegNames[];
+
+ enum FPUModeEnum {
+ FPUMode,
+ NeonMode
+ };
+
+ unsigned FPU;
+ unsigned CRC;
+ unsigned Crypto;
+
+ static const Builtin::Info BuiltinInfo[];
+
+ std::string ABI;
+
+public:
+ AArch64TargetInfo(const llvm::Triple &Triple)
+ : TargetInfo(Triple), ABI("aapcs") {
+
+ if (getTriple().getOS() == llvm::Triple::NetBSD) {
+ WCharType = SignedInt;
+
+ // NetBSD apparently prefers consistency across ARM targets to consistency
+ // across 64-bit targets.
+ Int64Type = SignedLongLong;
+ IntMaxType = SignedLongLong;
+ } else {
+ WCharType = UnsignedInt;
+ Int64Type = SignedLong;
+ IntMaxType = SignedLong;
+ }
+
+ LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
+ MaxVectorAlign = 128;
+ RegParmMax = 8;
+ MaxAtomicInlineWidth = 128;
+ MaxAtomicPromoteWidth = 128;
+
+ LongDoubleWidth = LongDoubleAlign = 128;
+ LongDoubleFormat = &llvm::APFloat::IEEEquad;
+
+ // {} in inline assembly are neon specifiers, not assembly variant
+ // specifiers.
+ NoAsmVariants = true;
+
+ // AArch64 targets default to using the ARM C++ ABI.
+ TheCXXABI.set(TargetCXXABI::GenericAArch64);
+ }
+
+ StringRef getABI() const override { return ABI; }
+ virtual bool setABI(const std::string &Name) {
+ if (Name != "aapcs" && Name != "darwinpcs")
+ return false;
+
+ ABI = Name;
+ return true;
+ }
+
+ virtual bool setCPU(const std::string &Name) {
+ bool CPUKnown = llvm::StringSwitch<bool>(Name)
+ .Case("generic", true)
+ .Cases("cortex-a53", "cortex-a57", true)
+ .Case("cyclone", true)
+ .Default(false);
+ return CPUKnown;
+ }
+
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ // Target identification.
+ Builder.defineMacro("__aarch64__");
+
+ // Target properties.
+ Builder.defineMacro("_LP64");
+ Builder.defineMacro("__LP64__");
+
+ // ACLE predefines. Many can only have one possible value on v8 AArch64.
+ Builder.defineMacro("__ARM_ACLE", "200");
+ Builder.defineMacro("__ARM_ARCH", "8");
+ Builder.defineMacro("__ARM_ARCH_PROFILE", "'A'");
+
+ Builder.defineMacro("__ARM_64BIT_STATE");
+ Builder.defineMacro("__ARM_PCS_AAPCS64");
+ Builder.defineMacro("__ARM_ARCH_ISA_A64");
+
+ Builder.defineMacro("__ARM_FEATURE_UNALIGNED");
+ Builder.defineMacro("__ARM_FEATURE_CLZ");
+ Builder.defineMacro("__ARM_FEATURE_FMA");
+ Builder.defineMacro("__ARM_FEATURE_DIV");
+
+ Builder.defineMacro("__ARM_ALIGN_MAX_STACK_PWR", "4");
+
+ // 0xe implies support for half, single and double precision operations.
+ Builder.defineMacro("__ARM_FP", "0xe");
+
+ // PCS specifies this for SysV variants, which is all we support. Other ABIs
+ // may choose __ARM_FP16_FORMAT_ALTERNATIVE.
+ Builder.defineMacro("__ARM_FP16_FORMAT_IEEE");
+
+ if (Opts.FastMath || Opts.FiniteMathOnly)
+ Builder.defineMacro("__ARM_FP_FAST");
+
+ if ((Opts.C99 || Opts.C11) && !Opts.Freestanding)
+ Builder.defineMacro("__ARM_FP_FENV_ROUNDING");
+
+ Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", Opts.ShortWChar ? "2" : "4");
+
+ Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM",
+ Opts.ShortEnums ? "1" : "4");
+
+ if (FPU == NeonMode) {
+ Builder.defineMacro("__ARM_NEON");
+ // 64-bit NEON supports half, single and double precision operations.
+ Builder.defineMacro("__ARM_NEON_FP", "0xe");
+ }
+
+ if (CRC)
+ Builder.defineMacro("__ARM_FEATURE_CRC32");
+
+ if (Crypto)
+ Builder.defineMacro("__ARM_FEATURE_CRYPTO");
+ }
+
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ Records = BuiltinInfo;
+ NumRecords = clang::AArch64::LastTSBuiltin - Builtin::FirstTSBuiltin;
+ }
+
+ virtual bool hasFeature(StringRef Feature) const {
+ return Feature == "aarch64" ||
+ Feature == "arm64" ||
+ (Feature == "neon" && FPU == NeonMode);
+ }
+
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override {
+ FPU = FPUMode;
+ CRC = 0;
+ Crypto = 0;
+ for (unsigned i = 0, e = Features.size(); i != e; ++i) {
+ if (Features[i] == "+neon")
+ FPU = NeonMode;
+ if (Features[i] == "+crc")
+ CRC = 1;
+ if (Features[i] == "+crypto")
+ Crypto = 1;
+ }
+
+ setDescriptionString();
+
+ return true;
+ }
+
+ virtual bool isCLZForZeroUndef() const { return false; }
+
+ virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ return TargetInfo::AArch64ABIBuiltinVaList;
+ }
+
+ virtual void getGCCRegNames(const char *const *&Names,
+ unsigned &NumNames) const;
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const;
+
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const {
+ switch (*Name) {
+ default:
+ return false;
+ case 'w': // Floating point and SIMD registers (V0-V31)
+ Info.setAllowsRegister();
+ return true;
+ case 'I': // Constant that can be used with an ADD instruction
+ case 'J': // Constant that can be used with a SUB instruction
+ case 'K': // Constant that can be used with a 32-bit logical instruction
+ case 'L': // Constant that can be used with a 64-bit logical instruction
+ case 'M': // Constant that can be used as a 32-bit MOV immediate
+ case 'N': // Constant that can be used as a 64-bit MOV immediate
+ case 'Y': // Floating point constant zero
+ case 'Z': // Integer constant zero
+ return true;
+ case 'Q': // A memory reference with base register and no offset
+ Info.setAllowsMemory();
+ return true;
+ case 'S': // A symbolic address
+ Info.setAllowsRegister();
+ return true;
+ case 'U':
+ // Ump: A memory address suitable for ldp/stp in SI, DI, SF and DF modes, whatever they may be
+ // Utf: A memory address suitable for ldp/stp in TF mode, whatever it may be
+ // Usa: An absolute symbolic address
+ // Ush: The high part (bits 32:12) of a pc-relative symbolic address
+ llvm_unreachable("FIXME: Unimplemented support for bizarre constraints");
+ case 'z': // Zero register, wzr or xzr
+ Info.setAllowsRegister();
+ return true;
+ case 'x': // Floating point and SIMD registers (V0-V15)
+ Info.setAllowsRegister();
+ return true;
+ }
+ return false;
+ }
+
+ virtual const char *getClobbers() const { return ""; }
+
+ int getEHDataRegisterNumber(unsigned RegNo) const {
+ if (RegNo == 0)
+ return 0;
+ if (RegNo == 1)
+ return 1;
+ return -1;
+ }
+};
+
+const char *const AArch64TargetInfo::GCCRegNames[] = {
+ // 32-bit Integer registers
+ "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10",
+ "w11", "w12", "w13", "w14", "w15", "w16", "w17", "w18", "w19", "w20", "w21",
+ "w22", "w23", "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wsp",
+
+ // 64-bit Integer registers
+ "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10",
+ "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21",
+ "x22", "x23", "x24", "x25", "x26", "x27", "x28", "fp", "lr", "sp",
+
+ // 32-bit floating point regsisters
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10",
+ "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21",
+ "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
+
+ // 64-bit floating point regsisters
+ "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
+ "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21",
+ "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
+
+ // Vector registers
+ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10",
+ "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21",
+ "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
+};
+
+void AArch64TargetInfo::getGCCRegNames(const char *const *&Names,
+ unsigned &NumNames) const {
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+}
+
+const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = {
+ { { "w31" }, "wsp" },
+ { { "x29" }, "fp" },
+ { { "x30" }, "lr" },
+ { { "x31" }, "sp" },
+ // The S/D/Q and W/X registers overlap, but aren't really aliases; we
+ // don't want to substitute one of these for a different-sized one.
+};
+
+void AArch64TargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ Aliases = GCCRegAliases;
+ NumAliases = llvm::array_lengthof(GCCRegAliases);
+}
+
+const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
+#include "clang/Basic/BuiltinsNEON.def"
+
+#define BUILTIN(ID, TYPE, ATTRS) \
+ { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
+#include "clang/Basic/BuiltinsAArch64.def"
+};
+
+class AArch64leTargetInfo : public AArch64TargetInfo {
+ void setDescriptionString() override {
+ if (getTriple().isOSBinFormatMachO())
+ DescriptionString = "e-m:o-i64:64-i128:128-n32:64-S128";
+ else
+ DescriptionString = "e-m:e-i64:64-i128:128-n32:64-S128";
+ }
+
+public:
+ AArch64leTargetInfo(const llvm::Triple &Triple)
+ : AArch64TargetInfo(Triple) {
+ BigEndian = false;
+ }
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ Builder.defineMacro("__AARCH64EL__");
+ AArch64TargetInfo::getTargetDefines(Opts, Builder);
+ }
+};
+
+class AArch64beTargetInfo : public AArch64TargetInfo {
+ void setDescriptionString() override {
+ assert(!getTriple().isOSBinFormatMachO());
+ DescriptionString = "E-m:e-i64:64-i128:128-n32:64-S128";
+ }
+
+public:
+ AArch64beTargetInfo(const llvm::Triple &Triple)
+ : AArch64TargetInfo(Triple) { }
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ Builder.defineMacro("__AARCH64EB__");
+ Builder.defineMacro("__AARCH_BIG_ENDIAN");
+ Builder.defineMacro("__ARM_BIG_ENDIAN");
+ AArch64TargetInfo::getTargetDefines(Opts, Builder);
+ }
+};
+} // end anonymous namespace.
+
+namespace {
+class DarwinAArch64TargetInfo : public DarwinTargetInfo<AArch64leTargetInfo> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ Builder.defineMacro("__AARCH64_SIMD__");
+ Builder.defineMacro("__ARM64_ARCH_8__");
+ Builder.defineMacro("__ARM_NEON__");
+ Builder.defineMacro("__LITTLE_ENDIAN__");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
+ Builder.defineMacro("__arm64", "1");
+ Builder.defineMacro("__arm64__", "1");
+
+ getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion);
+ }
+
+public:
+ DarwinAArch64TargetInfo(const llvm::Triple &Triple)
+ : DarwinTargetInfo<AArch64leTargetInfo>(Triple) {
+ Int64Type = SignedLongLong;
+ WCharType = SignedInt;
+ UseSignedCharForObjCBool = false;
+
+ LongDoubleWidth = LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble;
+
+ TheCXXABI.set(TargetCXXABI::iOS64);
+ }
+
+ virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ return TargetInfo::CharPtrBuiltinVaList;
+ }
+};
+} // end anonymous namespace
+
+namespace {
// Hexagon abstract base class
class HexagonTargetInfo : public TargetInfo {
static const Builtin::Info BuiltinInfo[];
@@ -4251,41 +4668,39 @@ class HexagonTargetInfo : public TargetInfo {
public:
HexagonTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
BigEndian = false;
- DescriptionString = ("e-p:32:32:32-"
- "i64:64:64-i32:32:32-i16:16:16-i1:32:32-"
- "f64:64:64-f32:32:32-a0:0-n32");
+ DescriptionString = "e-m:e-p:32:32-i1:32-i64:64-a:0-n32";
// {} in inline assembly are packet specifiers, not assembly variant
// specifiers.
NoAsmVariants = true;
}
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {
+ void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const override {
Records = BuiltinInfo;
NumRecords = clang::Hexagon::LastTSBuiltin-Builtin::FirstTSBuiltin;
}
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const {
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
return true;
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const;
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
- virtual bool hasFeature(StringRef Feature) const {
+ bool hasFeature(StringRef Feature) const override {
return Feature == "hexagon";
}
-
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::CharPtrBuiltinVaList;
}
- virtual void getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const;
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const;
- virtual const char *getClobbers() const {
+ void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const override;
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override;
+ const char *getClobbers() const override {
return "";
}
@@ -4293,10 +4708,10 @@ public:
return llvm::StringSwitch<const char*>(Name)
.Case("hexagonv4", "4")
.Case("hexagonv5", "5")
- .Default(0);
+ .Default(nullptr);
}
- virtual bool setCPU(const std::string &Name) {
+ bool setCPU(const std::string &Name) override {
if (!getHexagonCPUSuffix(Name))
return false;
@@ -4404,47 +4819,47 @@ class SparcTargetInfo : public TargetInfo {
public:
SparcTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {}
- virtual bool handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) {
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override {
SoftFloat = false;
for (unsigned i = 0, e = Features.size(); i != e; ++i)
if (Features[i] == "+soft-float")
SoftFloat = true;
return true;
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
DefineStd(Builder, "sparc", Opts);
Builder.defineMacro("__REGISTER_PREFIX__", "");
if (SoftFloat)
Builder.defineMacro("SOFT_FLOAT", "1");
}
-
- virtual bool hasFeature(StringRef Feature) const {
+
+ bool hasFeature(StringRef Feature) const override {
return llvm::StringSwitch<bool>(Feature)
.Case("softfloat", SoftFloat)
.Case("sparc", true)
.Default(false);
}
-
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {
+
+ void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const override {
// FIXME: Implement!
}
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::VoidPtrBuiltinVaList;
}
- virtual void getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const;
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const;
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const {
+ void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const override;
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override;
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override {
// FIXME: Implement!
return false;
}
- virtual const char *getClobbers() const {
+ const char *getClobbers() const override {
// FIXME: Implement!
return "";
}
@@ -4508,13 +4923,11 @@ void SparcTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
class SparcV8TargetInfo : public SparcTargetInfo {
public:
SparcV8TargetInfo(const llvm::Triple &Triple) : SparcTargetInfo(Triple) {
- // FIXME: Support Sparc quad-precision long double?
- DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64";
+ DescriptionString = "E-m:e-p:32:32-i64:64-f128:64-n32-S64";
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
SparcTargetInfo::getTargetDefines(Opts, Builder);
Builder.defineMacro("__sparcv8");
}
@@ -4525,24 +4938,27 @@ class SparcV9TargetInfo : public SparcTargetInfo {
public:
SparcV9TargetInfo(const llvm::Triple &Triple) : SparcTargetInfo(Triple) {
// FIXME: Support Sparc quad-precision long double?
- DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32:64-S128";
+ DescriptionString = "E-m:e-i64:64-n32:64-S128";
// This is an LP64 platform.
LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
// OpenBSD uses long long for int64_t and intmax_t.
- if (getTriple().getOS() == llvm::Triple::OpenBSD) {
+ if (getTriple().getOS() == llvm::Triple::OpenBSD)
IntMaxType = SignedLongLong;
- UIntMaxType = UnsignedLongLong;
- } else {
+ else
IntMaxType = SignedLong;
- UIntMaxType = UnsignedLong;
- }
Int64Type = IntMaxType;
+
+ // The SPARCv8 System V ABI has long double 128-bits in size, but 64-bit
+ // aligned. The SPARCv9 SCD 2.4.1 says 16-byte aligned.
+ LongDoubleWidth = 128;
+ LongDoubleAlign = 128;
+ LongDoubleFormat = &llvm::APFloat::IEEEquad;
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
SparcTargetInfo::getTargetDefines(Opts, Builder);
Builder.defineMacro("__sparcv9");
Builder.defineMacro("__arch64__");
@@ -4555,6 +4971,22 @@ public:
Builder.defineMacro("__sparcv9__");
}
}
+
+ bool setCPU(const std::string &Name) override {
+ bool CPUKnown = llvm::StringSwitch<bool>(Name)
+ .Case("v9", true)
+ .Case("ultrasparc", true)
+ .Case("ultrasparc3", true)
+ .Case("niagara", true)
+ .Case("niagara2", true)
+ .Case("niagara3", true)
+ .Case("niagara4", true)
+ .Default(false);
+
+ // No need to store the CPU yet. There aren't any CPU-specific
+ // macros to define.
+ return CPUKnown;
+ }
};
} // end anonymous namespace.
@@ -4579,109 +5011,108 @@ public:
} // end anonymous namespace.
namespace {
- class SystemZTargetInfo : public TargetInfo {
- static const char *const GCCRegNames[];
+class SystemZTargetInfo : public TargetInfo {
+ static const char *const GCCRegNames[];
- public:
- SystemZTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
- TLSSupported = true;
- IntWidth = IntAlign = 32;
- LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64;
- PointerWidth = PointerAlign = 64;
- LongDoubleWidth = 128;
- LongDoubleAlign = 64;
- LongDoubleFormat = &llvm::APFloat::IEEEquad;
- MinGlobalAlign = 16;
- DescriptionString = "E-p:64:64:64-i1:8:16-i8:8:16-i16:16-i32:32-i64:64"
- "-f32:32-f64:64-f128:64-a0:8:16-n32:64";
- MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
- }
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- Builder.defineMacro("__s390__");
- Builder.defineMacro("__s390x__");
- Builder.defineMacro("__zarch__");
- Builder.defineMacro("__LONG_DOUBLE_128__");
- }
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {
- // FIXME: Implement.
- Records = 0;
- NumRecords = 0;
- }
+public:
+ SystemZTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
+ TLSSupported = true;
+ IntWidth = IntAlign = 32;
+ LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64;
+ PointerWidth = PointerAlign = 64;
+ LongDoubleWidth = 128;
+ LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEquad;
+ MinGlobalAlign = 16;
+ DescriptionString = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64";
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
+ }
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ Builder.defineMacro("__s390__");
+ Builder.defineMacro("__s390x__");
+ Builder.defineMacro("__zarch__");
+ Builder.defineMacro("__LONG_DOUBLE_128__");
+ }
+ void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const override {
+ // FIXME: Implement.
+ Records = nullptr;
+ NumRecords = 0;
+ }
- virtual void getGCCRegNames(const char *const *&Names,
- unsigned &NumNames) const;
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const {
- // No aliases.
- Aliases = 0;
- NumAliases = 0;
- }
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const;
- virtual const char *getClobbers() const {
- // FIXME: Is this really right?
- return "";
- }
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
- return TargetInfo::SystemZBuiltinVaList;
- }
- virtual bool setCPU(const std::string &Name) {
- bool CPUKnown = llvm::StringSwitch<bool>(Name)
- .Case("z10", true)
- .Case("z196", true)
- .Case("zEC12", true)
- .Default(false);
+ void getGCCRegNames(const char *const *&Names,
+ unsigned &NumNames) const override;
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override {
+ // No aliases.
+ Aliases = nullptr;
+ NumAliases = 0;
+ }
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override;
+ const char *getClobbers() const override {
+ // FIXME: Is this really right?
+ return "";
+ }
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::SystemZBuiltinVaList;
+ }
+ bool setCPU(const std::string &Name) override {
+ bool CPUKnown = llvm::StringSwitch<bool>(Name)
+ .Case("z10", true)
+ .Case("z196", true)
+ .Case("zEC12", true)
+ .Default(false);
- // No need to store the CPU yet. There aren't any CPU-specific
- // macros to define.
- return CPUKnown;
- }
- };
+ // No need to store the CPU yet. There aren't any CPU-specific
+ // macros to define.
+ return CPUKnown;
+ }
+};
- const char *const SystemZTargetInfo::GCCRegNames[] = {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "f0", "f2", "f4", "f6", "f1", "f3", "f5", "f7",
- "f8", "f10", "f12", "f14", "f9", "f11", "f13", "f15"
- };
+const char *const SystemZTargetInfo::GCCRegNames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "f0", "f2", "f4", "f6", "f1", "f3", "f5", "f7",
+ "f8", "f10", "f12", "f14", "f9", "f11", "f13", "f15"
+};
- void SystemZTargetInfo::getGCCRegNames(const char *const *&Names,
- unsigned &NumNames) const {
- Names = GCCRegNames;
- NumNames = llvm::array_lengthof(GCCRegNames);
- }
+void SystemZTargetInfo::getGCCRegNames(const char *const *&Names,
+ unsigned &NumNames) const {
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+}
- bool SystemZTargetInfo::
- validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const {
- switch (*Name) {
- default:
- return false;
+bool SystemZTargetInfo::
+validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const {
+ switch (*Name) {
+ default:
+ return false;
- case 'a': // Address register
- case 'd': // Data register (equivalent to 'r')
- case 'f': // Floating-point register
- Info.setAllowsRegister();
- return true;
+ case 'a': // Address register
+ case 'd': // Data register (equivalent to 'r')
+ case 'f': // Floating-point register
+ Info.setAllowsRegister();
+ return true;
- case 'I': // Unsigned 8-bit constant
- case 'J': // Unsigned 12-bit constant
- case 'K': // Signed 16-bit constant
- case 'L': // Signed 20-bit displacement (on all targets we support)
- case 'M': // 0x7fffffff
- return true;
+ case 'I': // Unsigned 8-bit constant
+ case 'J': // Unsigned 12-bit constant
+ case 'K': // Signed 16-bit constant
+ case 'L': // Signed 20-bit displacement (on all targets we support)
+ case 'M': // 0x7fffffff
+ return true;
- case 'Q': // Memory with base and unsigned 12-bit displacement
- case 'R': // Likewise, plus an index
- case 'S': // Memory with base and signed 20-bit displacement
- case 'T': // Likewise, plus an index
- Info.setAllowsMemory();
- return true;
- }
+ case 'Q': // Memory with base and unsigned 12-bit displacement
+ case 'R': // Likewise, plus an index
+ case 'S': // Memory with base and signed 20-bit displacement
+ case 'T': // Likewise, plus an index
+ Info.setAllowsMemory();
+ return true;
}
}
+}
namespace {
class MSP430TargetInfo : public TargetInfo {
@@ -4697,45 +5128,44 @@ namespace {
SuitableAlign = 16;
SizeType = UnsignedInt;
IntMaxType = SignedLongLong;
- UIntMaxType = UnsignedLongLong;
IntPtrType = SignedInt;
PtrDiffType = SignedInt;
SigAtomicType = SignedLong;
- DescriptionString = "e-p:16:16:16-i8:8:8-i16:16:16-i32:16:32-n8:16";
- }
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ DescriptionString = "e-m:e-p:16:16-i32:16:32-n8:16";
+ }
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
Builder.defineMacro("MSP430");
Builder.defineMacro("__MSP430__");
// FIXME: defines for different 'flavours' of MCU
}
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {
- // FIXME: Implement.
- Records = 0;
+ void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const override {
+ // FIXME: Implement.
+ Records = nullptr;
NumRecords = 0;
}
- virtual bool hasFeature(StringRef Feature) const {
+ bool hasFeature(StringRef Feature) const override {
return Feature == "msp430";
}
- virtual void getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const;
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const {
+ void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const override;
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override {
// No aliases.
- Aliases = 0;
+ Aliases = nullptr;
NumAliases = 0;
}
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const {
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override {
// No target constraints for now.
return false;
}
- virtual const char *getClobbers() const {
+ const char *getClobbers() const override {
// FIXME: Is this really right?
return "";
}
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ BuiltinVaListKind getBuiltinVaListKind() const override {
// FIXME: implement
return TargetInfo::CharPtrBuiltinVaList;
}
@@ -4785,7 +5215,6 @@ namespace {
SuitableAlign = 32;
SizeType = UnsignedInt;
IntMaxType = SignedLong;
- UIntMaxType = UnsignedLong;
IntPtrType = SignedInt;
PtrDiffType = SignedInt;
FloatWidth = 32;
@@ -4797,40 +5226,38 @@ namespace {
FloatFormat = &llvm::APFloat::IEEEsingle;
DoubleFormat = &llvm::APFloat::IEEEsingle;
LongDoubleFormat = &llvm::APFloat::IEEEsingle;
- DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-"
- "i16:16:32-i32:32:32-i64:32:32-"
- "f32:32:32-f64:32:32-v64:32:32-"
- "v128:32:32-a0:0:32-n32";
+ DescriptionString = "E-p:32:32-i8:8:32-i16:16:32-i64:32"
+ "-f64:32-v64:32-v128:32-a:0:32-n32";
AddrSpaceMap = &TCEOpenCLAddrSpaceMap;
UseAddrSpaceMapMangling = true;
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
DefineStd(Builder, "tce", Opts);
Builder.defineMacro("__TCE__");
Builder.defineMacro("__TCE_V1__");
}
- virtual bool hasFeature(StringRef Feature) const {
+ bool hasFeature(StringRef Feature) const override {
return Feature == "tce";
}
-
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {}
- virtual const char *getClobbers() const {
+
+ void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const override {}
+ const char *getClobbers() const override {
return "";
}
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::VoidPtrBuiltinVaList;
}
- virtual void getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const {}
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const {
+ void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const override {}
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override{
return true;
}
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const {}
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override {}
};
}
@@ -4863,21 +5290,57 @@ public:
IsNan2008(false), IsSingleFloat(false), FloatABI(HardFloat),
DspRev(NoDSP), HasMSA(false), HasFP64(false), ABI(ABIStr) {}
- virtual const char *getABI() const { return ABI.c_str(); }
- virtual bool setABI(const std::string &Name) = 0;
- virtual bool setCPU(const std::string &Name) {
+ bool isNaN2008Default() const {
+ return CPU == "mips32r6" || CPU == "mips64r6";
+ }
+
+ bool isFP64Default() const {
+ return CPU == "mips32r6" || ABI == "n32" || ABI == "n64" || ABI == "64";
+ }
+
+ StringRef getABI() const override { return ABI; }
+ bool setCPU(const std::string &Name) override {
+ bool IsMips32 = getTriple().getArch() == llvm::Triple::mips ||
+ getTriple().getArch() == llvm::Triple::mipsel;
CPU = Name;
- return true;
+ return llvm::StringSwitch<bool>(Name)
+ .Case("mips1", IsMips32)
+ .Case("mips2", IsMips32)
+ .Case("mips3", true)
+ .Case("mips4", true)
+ .Case("mips5", true)
+ .Case("mips32", IsMips32)
+ .Case("mips32r2", IsMips32)
+ .Case("mips32r6", IsMips32)
+ .Case("mips64", true)
+ .Case("mips64r2", true)
+ .Case("mips64r6", true)
+ .Case("octeon", true)
+ .Default(false);
}
- void getDefaultFeatures(llvm::StringMap<bool> &Features) const {
+ const std::string& getCPU() const { return CPU; }
+ void getDefaultFeatures(llvm::StringMap<bool> &Features) const override {
+ // The backend enables certain ABI's by default according to the
+ // architecture.
+ // Disable both possible defaults so that we don't end up with multiple
+ // ABI's selected and trigger an assertion.
+ Features["o32"] = false;
+ Features["n64"] = false;
+
Features[ABI] = true;
- Features[CPU] = true;
+ if (CPU == "octeon")
+ Features["mips64r2"] = Features["cnmips"] = true;
+ else
+ Features[CPU] = true;
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- DefineStd(Builder, "mips", Opts);
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ Builder.defineMacro("__mips__");
Builder.defineMacro("_mips");
+ if (Opts.GNUMode)
+ Builder.defineMacro("mips");
+
Builder.defineMacro("__REGISTER_PREFIX__", "");
switch (FloatABI) {
@@ -4930,22 +5393,22 @@ public:
Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper());
}
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {
+ void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const override {
Records = BuiltinInfo;
NumRecords = clang::Mips::LastTSBuiltin - Builtin::FirstTSBuiltin;
}
- virtual bool hasFeature(StringRef Feature) const {
+ bool hasFeature(StringRef Feature) const override {
return llvm::StringSwitch<bool>(Feature)
.Case("mips", true)
.Case("fp64", HasFP64)
.Default(false);
}
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::VoidPtrBuiltinVaList;
}
- virtual void getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const {
+ void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const override {
static const char *const GCCRegNames[] = {
// CPU register names
// Must match second column of GCCRegAliases
@@ -4973,17 +5436,17 @@ public:
Names = GCCRegNames;
NumNames = llvm::array_lengthof(GCCRegNames);
}
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const = 0;
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const {
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override = 0;
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
switch (*Name) {
default:
return false;
case 'r': // CPU registers.
case 'd': // Equivalent to "r" unless generating MIPS16 code.
- case 'y': // Equivalent to "r", backwards compatibility only.
+ case 'y': // Equivalent to "r", backward compatibility only.
case 'f': // floating-point registers.
case 'c': // $25 for indirect jumps
case 'l': // lo register
@@ -4996,20 +5459,20 @@ public:
}
}
- virtual const char *getClobbers() const {
+ const char *getClobbers() const override {
// FIXME: Implement!
return "";
}
- virtual bool handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) {
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override {
IsMips16 = false;
IsMicromips = false;
- IsNan2008 = false;
+ IsNan2008 = isNaN2008Default();
IsSingleFloat = false;
FloatABI = HardFloat;
DspRev = NoDSP;
- HasFP64 = ABI == "n32" || ABI == "n64" || ABI == "64";
+ HasFP64 = isFP64Default();
for (std::vector<std::string>::iterator it = Features.begin(),
ie = Features.end(); it != ie; ++it) {
@@ -5033,6 +5496,8 @@ public:
HasFP64 = false;
else if (*it == "+nan2008")
IsNan2008 = true;
+ else if (*it == "-nan2008")
+ IsNan2008 = false;
}
// Remove front-end specific options.
@@ -5040,20 +5505,19 @@ public:
std::find(Features.begin(), Features.end(), "+soft-float");
if (it != Features.end())
Features.erase(it);
- it = std::find(Features.begin(), Features.end(), "+nan2008");
- if (it != Features.end())
- Features.erase(it);
setDescriptionString();
return true;
}
- virtual int getEHDataRegisterNumber(unsigned RegNo) const {
+ int getEHDataRegisterNumber(unsigned RegNo) const override {
if (RegNo == 0) return 4;
if (RegNo == 1) return 5;
return -1;
}
+
+ bool isCLZForZeroUndef() const override { return false; }
};
const Builtin::Info MipsTargetInfoBase::BuiltinInfo[] = {
@@ -5066,25 +5530,31 @@ const Builtin::Info MipsTargetInfoBase::BuiltinInfo[] = {
class Mips32TargetInfoBase : public MipsTargetInfoBase {
public:
Mips32TargetInfoBase(const llvm::Triple &Triple)
- : MipsTargetInfoBase(Triple, "o32", "mips32") {
+ : MipsTargetInfoBase(Triple, "o32", "mips32r2") {
SizeType = UnsignedInt;
PtrDiffType = SignedInt;
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
}
- virtual bool setABI(const std::string &Name) {
- if ((Name == "o32") || (Name == "eabi")) {
+ bool setABI(const std::string &Name) override {
+ if (Name == "o32" || Name == "eabi") {
ABI = Name;
return true;
- } else if (Name == "32") {
- ABI = "o32";
- return true;
- } else
- return false;
+ }
+ return false;
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
MipsTargetInfoBase::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("__mips", "32");
+ Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS32");
+
+ const std::string& CPUStr = getCPU();
+ if (CPUStr == "mips32")
+ Builder.defineMacro("__mips_isa_rev", "1");
+ else if (CPUStr == "mips32r2")
+ Builder.defineMacro("__mips_isa_rev", "2");
+
if (ABI == "o32") {
Builder.defineMacro("__mips_o32");
Builder.defineMacro("_ABIO32", "1");
@@ -5095,8 +5565,8 @@ public:
else
llvm_unreachable("Invalid ABI for Mips32.");
}
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const {
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override {
static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
{ { "at" }, "$1" },
{ { "v0" }, "$2" },
@@ -5136,17 +5606,16 @@ public:
};
class Mips32EBTargetInfo : public Mips32TargetInfoBase {
- virtual void setDescriptionString() {
- DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64";
+ void setDescriptionString() override {
+ DescriptionString = "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64";
}
public:
Mips32EBTargetInfo(const llvm::Triple &Triple)
: Mips32TargetInfoBase(Triple) {
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
DefineStd(Builder, "MIPSEB", Opts);
Builder.defineMacro("_MIPSEB");
Mips32TargetInfoBase::getTargetDefines(Opts, Builder);
@@ -5154,9 +5623,8 @@ public:
};
class Mips32ELTargetInfo : public Mips32TargetInfoBase {
- virtual void setDescriptionString() {
- DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64";
+ void setDescriptionString() override {
+ DescriptionString = "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64";
}
public:
@@ -5164,8 +5632,8 @@ public:
: Mips32TargetInfoBase(Triple) {
BigEndian = false;
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
DefineStd(Builder, "MIPSEL", Opts);
Builder.defineMacro("_MIPSEL");
Mips32TargetInfoBase::getTargetDefines(Opts, Builder);
@@ -5175,39 +5643,60 @@ public:
class Mips64TargetInfoBase : public MipsTargetInfoBase {
public:
Mips64TargetInfoBase(const llvm::Triple &Triple)
- : MipsTargetInfoBase(Triple, "n64", "mips64") {
- LongWidth = LongAlign = 64;
- PointerWidth = PointerAlign = 64;
+ : MipsTargetInfoBase(Triple, "n64", "mips64r2") {
LongDoubleWidth = LongDoubleAlign = 128;
LongDoubleFormat = &llvm::APFloat::IEEEquad;
if (getTriple().getOS() == llvm::Triple::FreeBSD) {
LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
}
+ setN64ABITypes();
SuitableAlign = 128;
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
}
- virtual bool setABI(const std::string &Name) {
+
+ void setN64ABITypes() {
+ LongWidth = LongAlign = 64;
+ PointerWidth = PointerAlign = 64;
+ SizeType = UnsignedLong;
+ PtrDiffType = SignedLong;
+ }
+
+ void setN32ABITypes() {
+ LongWidth = LongAlign = 32;
+ PointerWidth = PointerAlign = 32;
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+ }
+
+ bool setABI(const std::string &Name) override {
if (Name == "n32") {
- LongWidth = LongAlign = 32;
- PointerWidth = PointerAlign = 32;
+ setN32ABITypes();
ABI = Name;
return true;
- } else if (Name == "n64") {
+ }
+ if (Name == "n64") {
+ setN64ABITypes();
ABI = Name;
return true;
- } else if (Name == "64") {
- ABI = "n64";
- return true;
- } else
- return false;
+ }
+ return false;
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
MipsTargetInfoBase::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("__mips", "64");
Builder.defineMacro("__mips64");
Builder.defineMacro("__mips64__");
+ Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS64");
+
+ const std::string& CPUStr = getCPU();
+ if (CPUStr == "mips64")
+ Builder.defineMacro("__mips_isa_rev", "1");
+ else if (CPUStr == "mips64r2")
+ Builder.defineMacro("__mips_isa_rev", "2");
if (ABI == "n32") {
Builder.defineMacro("__mips_n32");
@@ -5222,8 +5711,8 @@ public:
else
llvm_unreachable("Invalid ABI for Mips64.");
}
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const {
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override {
static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
{ { "at" }, "$1" },
{ { "v0" }, "$2" },
@@ -5260,26 +5749,24 @@ public:
Aliases = GCCRegAliases;
NumAliases = llvm::array_lengthof(GCCRegAliases);
}
+
+ bool hasInt128Type() const override { return true; }
};
class Mips64EBTargetInfo : public Mips64TargetInfoBase {
- virtual void setDescriptionString() {
+ void setDescriptionString() override {
if (ABI == "n32")
- DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-f128:128:128-"
- "v64:64:64-n32:64-S128";
+ DescriptionString = "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32:64-S128";
else
- DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-f128:128:128-"
- "v64:64:64-n32:64-S128";
+ DescriptionString = "E-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128";
}
public:
Mips64EBTargetInfo(const llvm::Triple &Triple)
: Mips64TargetInfoBase(Triple) {}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
DefineStd(Builder, "MIPSEB", Opts);
Builder.defineMacro("_MIPSEB");
Mips64TargetInfoBase::getTargetDefines(Opts, Builder);
@@ -5287,15 +5774,11 @@ public:
};
class Mips64ELTargetInfo : public Mips64TargetInfoBase {
- virtual void setDescriptionString() {
+ void setDescriptionString() override {
if (ABI == "n32")
- DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-f128:128:128"
- "-v64:64:64-n32:64-S128";
+ DescriptionString = "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32:64-S128";
else
- DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-f128:128:128-"
- "v64:64:64-n32:64-S128";
+ DescriptionString = "e-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128";
}
public:
Mips64ELTargetInfo(const llvm::Triple &Triple)
@@ -5303,8 +5786,8 @@ public:
// Default ABI is n64.
BigEndian = false;
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
DefineStd(Builder, "MIPSEL", Opts);
Builder.defineMacro("_MIPSEL");
Mips64TargetInfoBase::getTargetDefines(Opts, Builder);
@@ -5323,7 +5806,6 @@ public:
this->PointerAlign = 32;
this->PointerWidth = 32;
this->IntMaxType = TargetInfo::SignedLongLong;
- this->UIntMaxType = TargetInfo::UnsignedLongLong;
this->Int64Type = TargetInfo::SignedLongLong;
this->DoubleAlign = 64;
this->LongDoubleWidth = 64;
@@ -5332,54 +5814,50 @@ public:
this->PtrDiffType = TargetInfo::SignedInt;
this->IntPtrType = TargetInfo::SignedInt;
this->RegParmMax = 0; // Disallow regparm
- DescriptionString = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"
- "f32:32:32-f64:64:64-p:32:32:32-v128:32:32";
}
- void getDefaultFeatures(llvm::StringMap<bool> &Features) const {
+ void getDefaultFeatures(llvm::StringMap<bool> &Features) const override {
}
- virtual void getArchDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getArchDefines(const LangOptions &Opts, MacroBuilder &Builder) const {
Builder.defineMacro("__le32__");
Builder.defineMacro("__pnacl__");
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- Builder.defineMacro("__LITTLE_ENDIAN__");
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
getArchDefines(Opts, Builder);
}
- virtual bool hasFeature(StringRef Feature) const {
+ bool hasFeature(StringRef Feature) const override {
return Feature == "pnacl";
}
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {
+ void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const override {
}
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::PNaClABIBuiltinVaList;
}
- virtual void getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const;
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const;
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const {
+ void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const override;
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override;
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
return false;
}
- virtual const char *getClobbers() const {
+ const char *getClobbers() const override {
return "";
}
};
void PNaClTargetInfo::getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const {
- Names = NULL;
+ Names = nullptr;
NumNames = 0;
}
void PNaClTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
unsigned &NumAliases) const {
- Aliases = NULL;
+ Aliases = nullptr;
NumAliases = 0;
}
} // end anonymous namespace.
@@ -5409,28 +5887,28 @@ namespace {
// These must be defined in sorted order!
NoAsmVariants = true;
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
DefineStd(Builder, "SPIR", Opts);
}
- virtual bool hasFeature(StringRef Feature) const {
+ bool hasFeature(StringRef Feature) const override {
return Feature == "spir";
}
-
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {}
- virtual const char *getClobbers() const {
+
+ void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const override {}
+ const char *getClobbers() const override {
return "";
}
- virtual void getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const {}
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const {
+ void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const override {}
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override {
return true;
}
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const {}
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override {}
+ BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::VoidPtrBuiltinVaList;
}
};
@@ -5443,13 +5921,11 @@ namespace {
SizeType = TargetInfo::UnsignedInt;
PtrDiffType = IntPtrType = TargetInfo::SignedInt;
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-v16:16:16-v24:32:32-v32:32:32-v48:64:64-"
- "v64:64:64-v96:128:128-v128:128:128-v192:256:256-v256:256:256-"
- "v512:512:512-v1024:1024:1024";
+ = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-"
+ "v96:128-v192:256-v256:256-v512:512-v1024:1024";
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
DefineStd(Builder, "SPIR32", Opts);
}
};
@@ -5460,14 +5936,11 @@ namespace {
PointerWidth = PointerAlign = 64;
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
- DescriptionString
- = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"
- "f32:32:32-f64:64:64-v16:16:16-v24:32:32-v32:32:32-v48:64:64-"
- "v64:64:64-v96:128:128-v128:128:128-v192:256:256-v256:256:256-"
- "v512:512:512-v1024:1024:1024";
+ DescriptionString = "e-i64:64-v16:16-v24:32-v32:32-v48:64-"
+ "v96:128-v192:256-v256:256-v512:512-v1024:1024";
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
DefineStd(Builder, "SPIR64", Opts);
}
};
@@ -5489,27 +5962,26 @@ public:
WCharType = UnsignedChar;
WIntType = UnsignedInt;
UseZeroLengthBitfieldAlignment = true;
- DescriptionString = "e-p:32:32:32-a0:0:32-n32"
- "-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32"
- "-f16:16:32-f32:32:32-f64:32:32";
+ DescriptionString = "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:32"
+ "-f64:32-a:0:32-n32";
}
- virtual void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const {
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
Builder.defineMacro("__XS1B__");
}
- virtual void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const {
+ void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const override {
Records = BuiltinInfo;
NumRecords = clang::XCore::LastTSBuiltin-Builtin::FirstTSBuiltin;
}
- virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::VoidPtrBuiltinVaList;
}
- virtual const char *getClobbers() const {
+ const char *getClobbers() const override {
return "";
}
- virtual void getGCCRegNames(const char * const *&Names,
- unsigned &NumNames) const {
+ void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const override {
static const char * const GCCRegNames[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "cp", "dp", "sp", "lr"
@@ -5517,15 +5989,19 @@ public:
Names = GCCRegNames;
NumNames = llvm::array_lengthof(GCCRegNames);
}
- virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const {
- Aliases = NULL;
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override {
+ Aliases = nullptr;
NumAliases = 0;
}
- virtual bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const {
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override {
return false;
}
+ int getEHDataRegisterNumber(unsigned RegNo) const override {
+ // R0=ExceptionPointerRegister R1=ExceptionSelectorRegister
+ return (RegNo < 2)? RegNo : -1;
+ }
};
const Builtin::Info XCoreTargetInfo::BuiltinInfo[] = {
@@ -5546,7 +6022,7 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
switch (Triple.getArch()) {
default:
- return NULL;
+ return nullptr;
case llvm::Triple::xcore:
return new XCoreTargetInfo(Triple);
@@ -5555,35 +6031,85 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
return new HexagonTargetInfo(Triple);
case llvm::Triple::aarch64:
+ case llvm::Triple::arm64:
+ if (Triple.isOSDarwin())
+ return new DarwinAArch64TargetInfo(Triple);
+
+ switch (os) {
+ case llvm::Triple::Linux:
+ return new LinuxTargetInfo<AArch64leTargetInfo>(Triple);
+ case llvm::Triple::NetBSD:
+ return new NetBSDTargetInfo<AArch64leTargetInfo>(Triple);
+ default:
+ return new AArch64leTargetInfo(Triple);
+ }
+
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm64_be:
switch (os) {
case llvm::Triple::Linux:
- return new LinuxTargetInfo<AArch64TargetInfo>(Triple);
+ return new LinuxTargetInfo<AArch64beTargetInfo>(Triple);
+ case llvm::Triple::NetBSD:
+ return new NetBSDTargetInfo<AArch64beTargetInfo>(Triple);
default:
- return new AArch64TargetInfo(Triple);
+ return new AArch64beTargetInfo(Triple);
}
case llvm::Triple::arm:
case llvm::Triple::thumb:
+ if (Triple.isOSBinFormatMachO())
+ return new DarwinARMTargetInfo(Triple);
+
+ switch (os) {
+ case llvm::Triple::Linux:
+ return new LinuxTargetInfo<ARMleTargetInfo>(Triple);
+ case llvm::Triple::FreeBSD:
+ return new FreeBSDTargetInfo<ARMleTargetInfo>(Triple);
+ case llvm::Triple::NetBSD:
+ return new NetBSDTargetInfo<ARMleTargetInfo>(Triple);
+ case llvm::Triple::OpenBSD:
+ return new OpenBSDTargetInfo<ARMleTargetInfo>(Triple);
+ case llvm::Triple::Bitrig:
+ return new BitrigTargetInfo<ARMleTargetInfo>(Triple);
+ case llvm::Triple::RTEMS:
+ return new RTEMSTargetInfo<ARMleTargetInfo>(Triple);
+ case llvm::Triple::NaCl:
+ return new NaClTargetInfo<ARMleTargetInfo>(Triple);
+ case llvm::Triple::Win32:
+ switch (Triple.getEnvironment()) {
+ default:
+ return new ARMleTargetInfo(Triple);
+ case llvm::Triple::Itanium:
+ return new ItaniumWindowsARMleTargetInfo(Triple);
+ case llvm::Triple::MSVC:
+ return new MicrosoftARMleTargetInfo(Triple);
+ }
+ default:
+ return new ARMleTargetInfo(Triple);
+ }
+
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumbeb:
if (Triple.isOSDarwin())
return new DarwinARMTargetInfo(Triple);
switch (os) {
case llvm::Triple::Linux:
- return new LinuxTargetInfo<ARMTargetInfo>(Triple);
+ return new LinuxTargetInfo<ARMbeTargetInfo>(Triple);
case llvm::Triple::FreeBSD:
- return new FreeBSDTargetInfo<ARMTargetInfo>(Triple);
+ return new FreeBSDTargetInfo<ARMbeTargetInfo>(Triple);
case llvm::Triple::NetBSD:
- return new NetBSDTargetInfo<ARMTargetInfo>(Triple);
+ return new NetBSDTargetInfo<ARMbeTargetInfo>(Triple);
case llvm::Triple::OpenBSD:
- return new OpenBSDTargetInfo<ARMTargetInfo>(Triple);
+ return new OpenBSDTargetInfo<ARMbeTargetInfo>(Triple);
case llvm::Triple::Bitrig:
- return new BitrigTargetInfo<ARMTargetInfo>(Triple);
+ return new BitrigTargetInfo<ARMbeTargetInfo>(Triple);
case llvm::Triple::RTEMS:
- return new RTEMSTargetInfo<ARMTargetInfo>(Triple);
+ return new RTEMSTargetInfo<ARMbeTargetInfo>(Triple);
case llvm::Triple::NaCl:
- return new NaClTargetInfo<ARMTargetInfo>(Triple);
+ return new NaClTargetInfo<ARMbeTargetInfo>(Triple);
default:
- return new ARMTargetInfo(Triple);
+ return new ARMbeTargetInfo(Triple);
}
case llvm::Triple::msp430:
@@ -5656,7 +6182,7 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
case llvm::Triple::NaCl:
return new NaClTargetInfo<PNaClTargetInfo>(Triple);
default:
- return NULL;
+ return nullptr;
}
case llvm::Triple::ppc:
@@ -5781,12 +6307,19 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
return new MinixTargetInfo<X86_32TargetInfo>(Triple);
case llvm::Triple::Solaris:
return new SolarisTargetInfo<X86_32TargetInfo>(Triple);
- case llvm::Triple::Cygwin:
- return new CygwinX86_32TargetInfo(Triple);
- case llvm::Triple::MinGW32:
- return new MinGWX86_32TargetInfo(Triple);
- case llvm::Triple::Win32:
- return new VisualStudioWindowsX86_32TargetInfo(Triple);
+ case llvm::Triple::Win32: {
+ switch (Triple.getEnvironment()) {
+ default:
+ return new X86_32TargetInfo(Triple);
+ case llvm::Triple::Cygnus:
+ return new CygwinX86_32TargetInfo(Triple);
+ case llvm::Triple::GNU:
+ return new MinGWX86_32TargetInfo(Triple);
+ case llvm::Triple::Itanium:
+ case llvm::Triple::MSVC:
+ return new MicrosoftX86_32TargetInfo(Triple);
+ }
+ }
case llvm::Triple::Haiku:
return new HaikuX86_32TargetInfo(Triple);
case llvm::Triple::RTEMS:
@@ -5798,7 +6331,7 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
}
case llvm::Triple::x86_64:
- if (Triple.isOSDarwin() || Triple.getEnvironment() == llvm::Triple::MachO)
+ if (Triple.isOSDarwin() || Triple.isOSBinFormatMachO())
return new DarwinX86_64TargetInfo(Triple);
switch (os) {
@@ -5820,10 +6353,16 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
return new KFreeBSDTargetInfo<X86_64TargetInfo>(Triple);
case llvm::Triple::Solaris:
return new SolarisTargetInfo<X86_64TargetInfo>(Triple);
- case llvm::Triple::MinGW32:
- return new MinGWX86_64TargetInfo(Triple);
- case llvm::Triple::Win32: // This is what Triple.h supports now.
- return new VisualStudioWindowsX86_64TargetInfo(Triple);
+ case llvm::Triple::Win32: {
+ switch (Triple.getEnvironment()) {
+ default:
+ return new X86_64TargetInfo(Triple);
+ case llvm::Triple::GNU:
+ return new MinGWX86_64TargetInfo(Triple);
+ case llvm::Triple::MSVC:
+ return new MicrosoftX86_64TargetInfo(Triple);
+ }
+ }
case llvm::Triple::NaCl:
return new NaClTargetInfo<X86_64TargetInfo>(Triple);
default:
@@ -5833,13 +6372,13 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
case llvm::Triple::spir: {
if (Triple.getOS() != llvm::Triple::UnknownOS ||
Triple.getEnvironment() != llvm::Triple::UnknownEnvironment)
- return NULL;
+ return nullptr;
return new SPIR32TargetInfo(Triple);
}
case llvm::Triple::spir64: {
if (Triple.getOS() != llvm::Triple::UnknownOS ||
Triple.getEnvironment() != llvm::Triple::UnknownEnvironment)
- return NULL;
+ return nullptr;
return new SPIR64TargetInfo(Triple);
}
}
@@ -5847,40 +6386,35 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
/// CreateTargetInfo - Return the target info object for the specified target
/// triple.
-TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
- TargetOptions *Opts) {
+TargetInfo *
+TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
+ const std::shared_ptr<TargetOptions> &Opts) {
llvm::Triple Triple(Opts->Triple);
// Construct the target
- OwningPtr<TargetInfo> Target(AllocateTarget(Triple));
+ std::unique_ptr<TargetInfo> Target(AllocateTarget(Triple));
if (!Target) {
Diags.Report(diag::err_target_unknown_triple) << Triple.str();
- return 0;
+ return nullptr;
}
- Target->setTargetOpts(Opts);
+ Target->TargetOpts = Opts;
// Set the target CPU if specified.
if (!Opts->CPU.empty() && !Target->setCPU(Opts->CPU)) {
Diags.Report(diag::err_target_unknown_cpu) << Opts->CPU;
- return 0;
+ return nullptr;
}
// Set the target ABI if specified.
if (!Opts->ABI.empty() && !Target->setABI(Opts->ABI)) {
Diags.Report(diag::err_target_unknown_abi) << Opts->ABI;
- return 0;
- }
-
- // Set the target C++ ABI.
- if (!Opts->CXXABI.empty() && !Target->setCXXABI(Opts->CXXABI)) {
- Diags.Report(diag::err_target_unknown_cxxabi) << Opts->CXXABI;
- return 0;
+ return nullptr;
}
// Set the fp math unit.
if (!Opts->FPMath.empty() && !Target->setFPMath(Opts->FPMath)) {
Diags.Report(diag::err_target_unknown_fpmath) << Opts->FPMath;
- return 0;
+ return nullptr;
}
// Compute the default target features, we need the target to handle this
@@ -5906,7 +6440,7 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
ie = Features.end(); it != ie; ++it)
Opts->Features.push_back((it->second ? "+" : "-") + it->first().str());
if (!Target->handleTargetFeatures(Opts->Features, Diags))
- return 0;
+ return nullptr;
- return Target.take();
+ return Target.release();
}
diff --git a/lib/Basic/TokenKinds.cpp b/lib/Basic/TokenKinds.cpp
index 6ce076e57a6c..3b1f8fe34bef 100644
--- a/lib/Basic/TokenKinds.cpp
+++ b/lib/Basic/TokenKinds.cpp
@@ -12,27 +12,37 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/TokenKinds.h"
-#include <cassert>
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
static const char * const TokNames[] = {
#define TOK(X) #X,
#define KEYWORD(X,Y) #X,
#include "clang/Basic/TokenKinds.def"
- 0
+ nullptr
};
-const char *tok::getTokenName(enum TokenKind Kind) {
- assert(Kind < tok::NUM_TOKENS);
- return TokNames[Kind];
+const char *tok::getTokenName(TokenKind Kind) {
+ if (Kind < tok::NUM_TOKENS)
+ return TokNames[Kind];
+ llvm_unreachable("unknown TokenKind");
+ return nullptr;
}
-const char *tok::getTokenSimpleSpelling(enum TokenKind Kind) {
+const char *tok::getPunctuatorSpelling(TokenKind Kind) {
switch (Kind) {
#define PUNCTUATOR(X,Y) case X: return Y;
#include "clang/Basic/TokenKinds.def"
default: break;
}
+ return nullptr;
+}
- return 0;
+const char *tok::getKeywordSpelling(TokenKind Kind) {
+ switch (Kind) {
+#define KEYWORD(X,Y) case kw_ ## X: return #X;
+#include "clang/Basic/TokenKinds.def"
+ default: break;
+ }
+ return nullptr;
}
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index 2006878349a1..87ecac17649b 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -13,7 +13,7 @@
#include "clang/Basic/Version.h"
#include "clang/Basic/LLVM.h"
-#include "llvm/Config/config.h"
+#include "clang/Config/config.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdlib>
#include <cstring>
@@ -36,7 +36,7 @@ std::string getClangRepositoryPath() {
// If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us
// pick up a tag in an SVN export, for example.
- StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_34/dot1-final/lib/Basic/Version.cpp $");
+ StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_350/final/lib/Basic/Version.cpp $");
if (URL.empty()) {
URL = SVNRepository.slice(SVNRepository.find(':'),
SVNRepository.find("/lib/Basic"));
@@ -102,11 +102,11 @@ std::string getClangFullRepositoryVersion() {
OS << Revision;
}
OS << ')';
- }
+ }
// Support LLVM in a separate repository.
std::string LLVMRev = getLLVMRevision();
if (!LLVMRev.empty() && LLVMRev != Revision) {
- OS << " (";
+ OS << " (";
std::string LLVMRepo = getLLVMRepositoryPath();
if (!LLVMRepo.empty())
OS << LLVMRepo << ' ';
@@ -116,17 +116,21 @@ std::string getClangFullRepositoryVersion() {
}
std::string getClangFullVersion() {
+ return getClangToolFullVersion("clang");
+}
+
+std::string getClangToolFullVersion(StringRef ToolName) {
std::string buf;
llvm::raw_string_ostream OS(buf);
#ifdef CLANG_VENDOR
OS << CLANG_VENDOR;
#endif
- OS << "clang version " CLANG_VERSION_STRING " "
+ OS << ToolName << " version " CLANG_VERSION_STRING " "
<< getClangFullRepositoryVersion();
// If vendor supplied, include the base LLVM version as well.
#ifdef CLANG_VENDOR
- OS << " (based on LLVM " << PACKAGE_VERSION << ")";
+ OS << " (based on " << BACKEND_PACKAGE_STRING << ")";
#endif
return OS.str();
diff --git a/lib/Basic/VirtualFileSystem.cpp b/lib/Basic/VirtualFileSystem.cpp
new file mode 100644
index 000000000000..a5c83b88af50
--- /dev/null
+++ b/lib/Basic/VirtualFileSystem.cpp
@@ -0,0 +1,1209 @@
+//===- VirtualFileSystem.cpp - Virtual File System Layer --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This file implements the VirtualFileSystem interface.
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/VirtualFileSystem.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/YAMLParser.h"
+#include <atomic>
+#include <memory>
+
+using namespace clang;
+using namespace clang::vfs;
+using namespace llvm;
+using llvm::sys::fs::file_status;
+using llvm::sys::fs::file_type;
+using llvm::sys::fs::perms;
+using llvm::sys::fs::UniqueID;
+
+Status::Status(const file_status &Status)
+ : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()),
+ User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()),
+ Type(Status.type()), Perms(Status.permissions()), IsVFSMapped(false) {}
+
+Status::Status(StringRef Name, StringRef ExternalName, UniqueID UID,
+ sys::TimeValue MTime, uint32_t User, uint32_t Group,
+ uint64_t Size, file_type Type, perms Perms)
+ : Name(Name), UID(UID), MTime(MTime), User(User), Group(Group), Size(Size),
+ Type(Type), Perms(Perms), IsVFSMapped(false) {}
+
+bool Status::equivalent(const Status &Other) const {
+ return getUniqueID() == Other.getUniqueID();
+}
+bool Status::isDirectory() const {
+ return Type == file_type::directory_file;
+}
+bool Status::isRegularFile() const {
+ return Type == file_type::regular_file;
+}
+bool Status::isOther() const {
+ return exists() && !isRegularFile() && !isDirectory() && !isSymlink();
+}
+bool Status::isSymlink() const {
+ return Type == file_type::symlink_file;
+}
+bool Status::isStatusKnown() const {
+ return Type != file_type::status_error;
+}
+bool Status::exists() const {
+ return isStatusKnown() && Type != file_type::file_not_found;
+}
+
+File::~File() {}
+
+FileSystem::~FileSystem() {}
+
+std::error_code FileSystem::getBufferForFile(
+ const llvm::Twine &Name, std::unique_ptr<MemoryBuffer> &Result,
+ int64_t FileSize, bool RequiresNullTerminator, bool IsVolatile) {
+ std::unique_ptr<File> F;
+ if (std::error_code EC = openFileForRead(Name, F))
+ return EC;
+
+ std::error_code EC =
+ F->getBuffer(Name, Result, FileSize, RequiresNullTerminator, IsVolatile);
+ return EC;
+}
+
+//===-----------------------------------------------------------------------===/
+// RealFileSystem implementation
+//===-----------------------------------------------------------------------===/
+
+namespace {
+/// \brief Wrapper around a raw file descriptor.
+class RealFile : public File {
+ int FD;
+ Status S;
+ friend class RealFileSystem;
+ RealFile(int FD) : FD(FD) {
+ assert(FD >= 0 && "Invalid or inactive file descriptor");
+ }
+
+public:
+ ~RealFile();
+ ErrorOr<Status> status() override;
+ std::error_code getBuffer(const Twine &Name,
+ std::unique_ptr<MemoryBuffer> &Result,
+ int64_t FileSize = -1,
+ bool RequiresNullTerminator = true,
+ bool IsVolatile = false) override;
+ std::error_code close() override;
+ void setName(StringRef Name) override;
+};
+} // end anonymous namespace
+RealFile::~RealFile() { close(); }
+
+ErrorOr<Status> RealFile::status() {
+ assert(FD != -1 && "cannot stat closed file");
+ if (!S.isStatusKnown()) {
+ file_status RealStatus;
+ if (std::error_code EC = sys::fs::status(FD, RealStatus))
+ return EC;
+ Status NewS(RealStatus);
+ NewS.setName(S.getName());
+ S = std::move(NewS);
+ }
+ return S;
+}
+
+std::error_code RealFile::getBuffer(const Twine &Name,
+ std::unique_ptr<MemoryBuffer> &Result,
+ int64_t FileSize,
+ bool RequiresNullTerminator,
+ bool IsVolatile) {
+ assert(FD != -1 && "cannot get buffer for closed file");
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
+ MemoryBuffer::getOpenFile(FD, Name.str().c_str(), FileSize,
+ RequiresNullTerminator, IsVolatile);
+ if (std::error_code EC = BufferOrErr.getError())
+ return EC;
+ Result = std::move(BufferOrErr.get());
+ return std::error_code();
+}
+
+// FIXME: This is terrible, we need this for ::close.
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#include <unistd.h>
+#include <sys/uio.h>
+#else
+#include <io.h>
+#ifndef S_ISFIFO
+#define S_ISFIFO(x) (0)
+#endif
+#endif
+std::error_code RealFile::close() {
+ if (::close(FD))
+ return std::error_code(errno, std::generic_category());
+ FD = -1;
+ return std::error_code();
+}
+
+void RealFile::setName(StringRef Name) {
+ S.setName(Name);
+}
+
+namespace {
+/// \brief The file system according to your operating system.
+class RealFileSystem : public FileSystem {
+public:
+ ErrorOr<Status> status(const Twine &Path) override;
+ std::error_code openFileForRead(const Twine &Path,
+ std::unique_ptr<File> &Result) override;
+ directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
+};
+} // end anonymous namespace
+
+ErrorOr<Status> RealFileSystem::status(const Twine &Path) {
+ sys::fs::file_status RealStatus;
+ if (std::error_code EC = sys::fs::status(Path, RealStatus))
+ return EC;
+ Status Result(RealStatus);
+ Result.setName(Path.str());
+ return Result;
+}
+
+std::error_code RealFileSystem::openFileForRead(const Twine &Name,
+ std::unique_ptr<File> &Result) {
+ int FD;
+ if (std::error_code EC = sys::fs::openFileForRead(Name, FD))
+ return EC;
+ Result.reset(new RealFile(FD));
+ Result->setName(Name.str());
+ return std::error_code();
+}
+
+IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
+ static IntrusiveRefCntPtr<FileSystem> FS = new RealFileSystem();
+ return FS;
+}
+
+namespace {
+class RealFSDirIter : public clang::vfs::detail::DirIterImpl {
+ std::string Path;
+ llvm::sys::fs::directory_iterator Iter;
+public:
+ RealFSDirIter(const Twine &_Path, std::error_code &EC)
+ : Path(_Path.str()), Iter(Path, EC) {
+ if (!EC && Iter != llvm::sys::fs::directory_iterator()) {
+ llvm::sys::fs::file_status S;
+ EC = Iter->status(S);
+ if (!EC) {
+ CurrentEntry = Status(S);
+ CurrentEntry.setName(Iter->path());
+ }
+ }
+ }
+
+ std::error_code increment() override {
+ std::error_code EC;
+ Iter.increment(EC);
+ if (EC) {
+ return EC;
+ } else if (Iter == llvm::sys::fs::directory_iterator()) {
+ CurrentEntry = Status();
+ } else {
+ llvm::sys::fs::file_status S;
+ EC = Iter->status(S);
+ CurrentEntry = Status(S);
+ CurrentEntry.setName(Iter->path());
+ }
+ return EC;
+ }
+};
+}
+
+directory_iterator RealFileSystem::dir_begin(const Twine &Dir,
+ std::error_code &EC) {
+ return directory_iterator(std::make_shared<RealFSDirIter>(Dir, EC));
+}
+
+//===-----------------------------------------------------------------------===/
+// OverlayFileSystem implementation
+//===-----------------------------------------------------------------------===/
+OverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) {
+ pushOverlay(BaseFS);
+}
+
+void OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr<FileSystem> FS) {
+ FSList.push_back(FS);
+}
+
+ErrorOr<Status> OverlayFileSystem::status(const Twine &Path) {
+ // FIXME: handle symlinks that cross file systems
+ for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
+ ErrorOr<Status> Status = (*I)->status(Path);
+ if (Status || Status.getError() != llvm::errc::no_such_file_or_directory)
+ return Status;
+ }
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
+std::error_code
+OverlayFileSystem::openFileForRead(const llvm::Twine &Path,
+ std::unique_ptr<File> &Result) {
+ // FIXME: handle symlinks that cross file systems
+ for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
+ std::error_code EC = (*I)->openFileForRead(Path, Result);
+ if (!EC || EC != llvm::errc::no_such_file_or_directory)
+ return EC;
+ }
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
+clang::vfs::detail::DirIterImpl::~DirIterImpl() { }
+
+namespace {
+class OverlayFSDirIterImpl : public clang::vfs::detail::DirIterImpl {
+ OverlayFileSystem &Overlays;
+ std::string Path;
+ OverlayFileSystem::iterator CurrentFS;
+ directory_iterator CurrentDirIter;
+ llvm::StringSet<> SeenNames;
+
+ std::error_code incrementFS() {
+ assert(CurrentFS != Overlays.overlays_end() && "incrementing past end");
+ ++CurrentFS;
+ for (auto E = Overlays.overlays_end(); CurrentFS != E; ++CurrentFS) {
+ std::error_code EC;
+ CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
+ if (EC && EC != errc::no_such_file_or_directory)
+ return EC;
+ if (CurrentDirIter != directory_iterator())
+ break; // found
+ }
+ return std::error_code();
+ }
+
+ std::error_code incrementDirIter(bool IsFirstTime) {
+ assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
+ "incrementing past end");
+ std::error_code EC;
+ if (!IsFirstTime)
+ CurrentDirIter.increment(EC);
+ if (!EC && CurrentDirIter == directory_iterator())
+ EC = incrementFS();
+ return EC;
+ }
+
+ std::error_code incrementImpl(bool IsFirstTime) {
+ while (true) {
+ std::error_code EC = incrementDirIter(IsFirstTime);
+ if (EC || CurrentDirIter == directory_iterator()) {
+ CurrentEntry = Status();
+ return EC;
+ }
+ CurrentEntry = *CurrentDirIter;
+ StringRef Name = llvm::sys::path::filename(CurrentEntry.getName());
+ if (SeenNames.insert(Name))
+ return EC; // name not seen before
+ }
+ llvm_unreachable("returned above");
+ }
+
+public:
+ OverlayFSDirIterImpl(const Twine &Path, OverlayFileSystem &FS,
+ std::error_code &EC)
+ : Overlays(FS), Path(Path.str()), CurrentFS(Overlays.overlays_begin()) {
+ CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
+ EC = incrementImpl(true);
+ }
+
+ std::error_code increment() override { return incrementImpl(false); }
+};
+} // end anonymous namespace
+
+directory_iterator OverlayFileSystem::dir_begin(const Twine &Dir,
+ std::error_code &EC) {
+ return directory_iterator(
+ std::make_shared<OverlayFSDirIterImpl>(Dir, *this, EC));
+}
+
+//===-----------------------------------------------------------------------===/
+// VFSFromYAML implementation
+//===-----------------------------------------------------------------------===/
+
+// Allow DenseMap<StringRef, ...>. This is useful below because we know all the
+// strings are literals and will outlive the map, and there is no reason to
+// store them.
+namespace llvm {
+ template<>
+ struct DenseMapInfo<StringRef> {
+ // This assumes that "" will never be a valid key.
+ static inline StringRef getEmptyKey() { return StringRef(""); }
+ static inline StringRef getTombstoneKey() { return StringRef(); }
+ static unsigned getHashValue(StringRef Val) { return HashString(Val); }
+ static bool isEqual(StringRef LHS, StringRef RHS) { return LHS == RHS; }
+ };
+}
+
+namespace {
+
+enum EntryKind {
+ EK_Directory,
+ EK_File
+};
+
+/// \brief A single file or directory in the VFS.
+class Entry {
+ EntryKind Kind;
+ std::string Name;
+
+public:
+ virtual ~Entry();
+ Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {}
+ StringRef getName() const { return Name; }
+ EntryKind getKind() const { return Kind; }
+};
+
+class DirectoryEntry : public Entry {
+ std::vector<Entry *> Contents;
+ Status S;
+
+public:
+ virtual ~DirectoryEntry();
+ DirectoryEntry(StringRef Name, std::vector<Entry *> Contents, Status S)
+ : Entry(EK_Directory, Name), Contents(std::move(Contents)),
+ S(std::move(S)) {}
+ Status getStatus() { return S; }
+ typedef std::vector<Entry *>::iterator iterator;
+ iterator contents_begin() { return Contents.begin(); }
+ iterator contents_end() { return Contents.end(); }
+ static bool classof(const Entry *E) { return E->getKind() == EK_Directory; }
+};
+
+class FileEntry : public Entry {
+public:
+ enum NameKind {
+ NK_NotSet,
+ NK_External,
+ NK_Virtual
+ };
+private:
+ std::string ExternalContentsPath;
+ NameKind UseName;
+public:
+ FileEntry(StringRef Name, StringRef ExternalContentsPath, NameKind UseName)
+ : Entry(EK_File, Name), ExternalContentsPath(ExternalContentsPath),
+ UseName(UseName) {}
+ StringRef getExternalContentsPath() const { return ExternalContentsPath; }
+ /// \brief whether to use the external path as the name for this file.
+ bool useExternalName(bool GlobalUseExternalName) const {
+ return UseName == NK_NotSet ? GlobalUseExternalName
+ : (UseName == NK_External);
+ }
+ static bool classof(const Entry *E) { return E->getKind() == EK_File; }
+};
+
+class VFSFromYAML;
+
+class VFSFromYamlDirIterImpl : public clang::vfs::detail::DirIterImpl {
+ std::string Dir;
+ VFSFromYAML &FS;
+ DirectoryEntry::iterator Current, End;
+public:
+ VFSFromYamlDirIterImpl(const Twine &Path, VFSFromYAML &FS,
+ DirectoryEntry::iterator Begin,
+ DirectoryEntry::iterator End, std::error_code &EC);
+ std::error_code increment() override;
+};
+
+/// \brief A virtual file system parsed from a YAML file.
+///
+/// Currently, this class allows creating virtual directories and mapping
+/// virtual file paths to existing external files, available in \c ExternalFS.
+///
+/// The basic structure of the parsed file is:
+/// \verbatim
+/// {
+/// 'version': <version number>,
+/// <optional configuration>
+/// 'roots': [
+/// <directory entries>
+/// ]
+/// }
+/// \endverbatim
+///
+/// All configuration options are optional.
+/// 'case-sensitive': <boolean, default=true>
+/// 'use-external-names': <boolean, default=true>
+///
+/// Virtual directories are represented as
+/// \verbatim
+/// {
+/// 'type': 'directory',
+/// 'name': <string>,
+/// 'contents': [ <file or directory entries> ]
+/// }
+/// \endverbatim
+///
+/// The default attributes for virtual directories are:
+/// \verbatim
+/// MTime = now() when created
+/// Perms = 0777
+/// User = Group = 0
+/// Size = 0
+/// UniqueID = unspecified unique value
+/// \endverbatim
+///
+/// Re-mapped files are represented as
+/// \verbatim
+/// {
+/// 'type': 'file',
+/// 'name': <string>,
+/// 'use-external-name': <boolean> # Optional
+/// 'external-contents': <path to external file>)
+/// }
+/// \endverbatim
+///
+/// and inherit their attributes from the external contents.
+///
+/// In both cases, the 'name' field may contain multiple path components (e.g.
+/// /path/to/file). However, any directory that contains more than one child
+/// must be uniquely represented by a directory entry.
+class VFSFromYAML : public vfs::FileSystem {
+ std::vector<Entry *> Roots; ///< The root(s) of the virtual file system.
+ /// \brief The file system to use for external references.
+ IntrusiveRefCntPtr<FileSystem> ExternalFS;
+
+ /// @name Configuration
+ /// @{
+
+ /// \brief Whether to perform case-sensitive comparisons.
+ ///
+ /// Currently, case-insensitive matching only works correctly with ASCII.
+ bool CaseSensitive;
+
+ /// \brief Whether to use to use the value of 'external-contents' for the
+ /// names of files. This global value is overridable on a per-file basis.
+ bool UseExternalNames;
+ /// @}
+
+ friend class VFSFromYAMLParser;
+
+private:
+ VFSFromYAML(IntrusiveRefCntPtr<FileSystem> ExternalFS)
+ : ExternalFS(ExternalFS), CaseSensitive(true), UseExternalNames(true) {}
+
+ /// \brief Looks up \p Path in \c Roots.
+ ErrorOr<Entry *> lookupPath(const Twine &Path);
+
+ /// \brief Looks up the path <tt>[Start, End)</tt> in \p From, possibly
+ /// recursing into the contents of \p From if it is a directory.
+ ErrorOr<Entry *> lookupPath(sys::path::const_iterator Start,
+ sys::path::const_iterator End, Entry *From);
+
+ /// \brief Get the status of a given an \c Entry.
+ ErrorOr<Status> status(const Twine &Path, Entry *E);
+
+public:
+ ~VFSFromYAML();
+
+ /// \brief Parses \p Buffer, which is expected to be in YAML format and
+ /// returns a virtual file system representing its contents.
+ ///
+ /// Takes ownership of \p Buffer.
+ static VFSFromYAML *create(MemoryBuffer *Buffer,
+ SourceMgr::DiagHandlerTy DiagHandler,
+ void *DiagContext,
+ IntrusiveRefCntPtr<FileSystem> ExternalFS);
+
+ ErrorOr<Status> status(const Twine &Path) override;
+ std::error_code openFileForRead(const Twine &Path,
+ std::unique_ptr<File> &Result) override;
+
+ directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override{
+ ErrorOr<Entry *> E = lookupPath(Dir);
+ if (!E) {
+ EC = E.getError();
+ return directory_iterator();
+ }
+ ErrorOr<Status> S = status(Dir, *E);
+ if (!S) {
+ EC = S.getError();
+ return directory_iterator();
+ }
+ if (!S->isDirectory()) {
+ EC = std::error_code(static_cast<int>(errc::not_a_directory),
+ std::system_category());
+ return directory_iterator();
+ }
+
+ DirectoryEntry *D = cast<DirectoryEntry>(*E);
+ return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(Dir,
+ *this, D->contents_begin(), D->contents_end(), EC));
+ }
+};
+
+/// \brief A helper class to hold the common YAML parsing state.
+class VFSFromYAMLParser {
+ yaml::Stream &Stream;
+
+ void error(yaml::Node *N, const Twine &Msg) {
+ Stream.printError(N, Msg);
+ }
+
+ // false on error
+ bool parseScalarString(yaml::Node *N, StringRef &Result,
+ SmallVectorImpl<char> &Storage) {
+ yaml::ScalarNode *S = dyn_cast<yaml::ScalarNode>(N);
+ if (!S) {
+ error(N, "expected string");
+ return false;
+ }
+ Result = S->getValue(Storage);
+ return true;
+ }
+
+ // false on error
+ bool parseScalarBool(yaml::Node *N, bool &Result) {
+ SmallString<5> Storage;
+ StringRef Value;
+ if (!parseScalarString(N, Value, Storage))
+ return false;
+
+ if (Value.equals_lower("true") || Value.equals_lower("on") ||
+ Value.equals_lower("yes") || Value == "1") {
+ Result = true;
+ return true;
+ } else if (Value.equals_lower("false") || Value.equals_lower("off") ||
+ Value.equals_lower("no") || Value == "0") {
+ Result = false;
+ return true;
+ }
+
+ error(N, "expected boolean value");
+ return false;
+ }
+
+ struct KeyStatus {
+ KeyStatus(bool Required=false) : Required(Required), Seen(false) {}
+ bool Required;
+ bool Seen;
+ };
+ typedef std::pair<StringRef, KeyStatus> KeyStatusPair;
+
+ // false on error
+ bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key,
+ DenseMap<StringRef, KeyStatus> &Keys) {
+ if (!Keys.count(Key)) {
+ error(KeyNode, "unknown key");
+ return false;
+ }
+ KeyStatus &S = Keys[Key];
+ if (S.Seen) {
+ error(KeyNode, Twine("duplicate key '") + Key + "'");
+ return false;
+ }
+ S.Seen = true;
+ return true;
+ }
+
+ // false on error
+ bool checkMissingKeys(yaml::Node *Obj, DenseMap<StringRef, KeyStatus> &Keys) {
+ for (DenseMap<StringRef, KeyStatus>::iterator I = Keys.begin(),
+ E = Keys.end();
+ I != E; ++I) {
+ if (I->second.Required && !I->second.Seen) {
+ error(Obj, Twine("missing key '") + I->first + "'");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ Entry *parseEntry(yaml::Node *N) {
+ yaml::MappingNode *M = dyn_cast<yaml::MappingNode>(N);
+ if (!M) {
+ error(N, "expected mapping node for file or directory entry");
+ return nullptr;
+ }
+
+ KeyStatusPair Fields[] = {
+ KeyStatusPair("name", true),
+ KeyStatusPair("type", true),
+ KeyStatusPair("contents", false),
+ KeyStatusPair("external-contents", false),
+ KeyStatusPair("use-external-name", false),
+ };
+
+ DenseMap<StringRef, KeyStatus> Keys(
+ &Fields[0], Fields + sizeof(Fields)/sizeof(Fields[0]));
+
+ bool HasContents = false; // external or otherwise
+ std::vector<Entry *> EntryArrayContents;
+ std::string ExternalContentsPath;
+ std::string Name;
+ FileEntry::NameKind UseExternalName = FileEntry::NK_NotSet;
+ EntryKind Kind;
+
+ for (yaml::MappingNode::iterator I = M->begin(), E = M->end(); I != E;
+ ++I) {
+ StringRef Key;
+ // Reuse the buffer for key and value, since we don't look at key after
+ // parsing value.
+ SmallString<256> Buffer;
+ if (!parseScalarString(I->getKey(), Key, Buffer))
+ return nullptr;
+
+ if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys))
+ return nullptr;
+
+ StringRef Value;
+ if (Key == "name") {
+ if (!parseScalarString(I->getValue(), Value, Buffer))
+ return nullptr;
+ Name = Value;
+ } else if (Key == "type") {
+ if (!parseScalarString(I->getValue(), Value, Buffer))
+ return nullptr;
+ if (Value == "file")
+ Kind = EK_File;
+ else if (Value == "directory")
+ Kind = EK_Directory;
+ else {
+ error(I->getValue(), "unknown value for 'type'");
+ return nullptr;
+ }
+ } else if (Key == "contents") {
+ if (HasContents) {
+ error(I->getKey(),
+ "entry already has 'contents' or 'external-contents'");
+ return nullptr;
+ }
+ HasContents = true;
+ yaml::SequenceNode *Contents =
+ dyn_cast<yaml::SequenceNode>(I->getValue());
+ if (!Contents) {
+ // FIXME: this is only for directories, what about files?
+ error(I->getValue(), "expected array");
+ return nullptr;
+ }
+
+ for (yaml::SequenceNode::iterator I = Contents->begin(),
+ E = Contents->end();
+ I != E; ++I) {
+ if (Entry *E = parseEntry(&*I))
+ EntryArrayContents.push_back(E);
+ else
+ return nullptr;
+ }
+ } else if (Key == "external-contents") {
+ if (HasContents) {
+ error(I->getKey(),
+ "entry already has 'contents' or 'external-contents'");
+ return nullptr;
+ }
+ HasContents = true;
+ if (!parseScalarString(I->getValue(), Value, Buffer))
+ return nullptr;
+ ExternalContentsPath = Value;
+ } else if (Key == "use-external-name") {
+ bool Val;
+ if (!parseScalarBool(I->getValue(), Val))
+ return nullptr;
+ UseExternalName = Val ? FileEntry::NK_External : FileEntry::NK_Virtual;
+ } else {
+ llvm_unreachable("key missing from Keys");
+ }
+ }
+
+ if (Stream.failed())
+ return nullptr;
+
+ // check for missing keys
+ if (!HasContents) {
+ error(N, "missing key 'contents' or 'external-contents'");
+ return nullptr;
+ }
+ if (!checkMissingKeys(N, Keys))
+ return nullptr;
+
+ // check invalid configuration
+ if (Kind == EK_Directory && UseExternalName != FileEntry::NK_NotSet) {
+ error(N, "'use-external-name' is not supported for directories");
+ return nullptr;
+ }
+
+ // Remove trailing slash(es), being careful not to remove the root path
+ StringRef Trimmed(Name);
+ size_t RootPathLen = sys::path::root_path(Trimmed).size();
+ while (Trimmed.size() > RootPathLen &&
+ sys::path::is_separator(Trimmed.back()))
+ Trimmed = Trimmed.slice(0, Trimmed.size()-1);
+ // Get the last component
+ StringRef LastComponent = sys::path::filename(Trimmed);
+
+ Entry *Result = nullptr;
+ switch (Kind) {
+ case EK_File:
+ Result = new FileEntry(LastComponent, std::move(ExternalContentsPath),
+ UseExternalName);
+ break;
+ case EK_Directory:
+ Result = new DirectoryEntry(LastComponent, std::move(EntryArrayContents),
+ Status("", "", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0,
+ 0, file_type::directory_file, sys::fs::all_all));
+ break;
+ }
+
+ StringRef Parent = sys::path::parent_path(Trimmed);
+ if (Parent.empty())
+ return Result;
+
+ // if 'name' contains multiple components, create implicit directory entries
+ for (sys::path::reverse_iterator I = sys::path::rbegin(Parent),
+ E = sys::path::rend(Parent);
+ I != E; ++I) {
+ Result = new DirectoryEntry(*I, llvm::makeArrayRef(Result),
+ Status("", "", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0,
+ 0, file_type::directory_file, sys::fs::all_all));
+ }
+ return Result;
+ }
+
+public:
+ VFSFromYAMLParser(yaml::Stream &S) : Stream(S) {}
+
+ // false on error
+ bool parse(yaml::Node *Root, VFSFromYAML *FS) {
+ yaml::MappingNode *Top = dyn_cast<yaml::MappingNode>(Root);
+ if (!Top) {
+ error(Root, "expected mapping node");
+ return false;
+ }
+
+ KeyStatusPair Fields[] = {
+ KeyStatusPair("version", true),
+ KeyStatusPair("case-sensitive", false),
+ KeyStatusPair("use-external-names", false),
+ KeyStatusPair("roots", true),
+ };
+
+ DenseMap<StringRef, KeyStatus> Keys(
+ &Fields[0], Fields + sizeof(Fields)/sizeof(Fields[0]));
+
+ // Parse configuration and 'roots'
+ for (yaml::MappingNode::iterator I = Top->begin(), E = Top->end(); I != E;
+ ++I) {
+ SmallString<10> KeyBuffer;
+ StringRef Key;
+ if (!parseScalarString(I->getKey(), Key, KeyBuffer))
+ return false;
+
+ if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys))
+ return false;
+
+ if (Key == "roots") {
+ yaml::SequenceNode *Roots = dyn_cast<yaml::SequenceNode>(I->getValue());
+ if (!Roots) {
+ error(I->getValue(), "expected array");
+ return false;
+ }
+
+ for (yaml::SequenceNode::iterator I = Roots->begin(), E = Roots->end();
+ I != E; ++I) {
+ if (Entry *E = parseEntry(&*I))
+ FS->Roots.push_back(E);
+ else
+ return false;
+ }
+ } else if (Key == "version") {
+ StringRef VersionString;
+ SmallString<4> Storage;
+ if (!parseScalarString(I->getValue(), VersionString, Storage))
+ return false;
+ int Version;
+ if (VersionString.getAsInteger<int>(10, Version)) {
+ error(I->getValue(), "expected integer");
+ return false;
+ }
+ if (Version < 0) {
+ error(I->getValue(), "invalid version number");
+ return false;
+ }
+ if (Version != 0) {
+ error(I->getValue(), "version mismatch, expected 0");
+ return false;
+ }
+ } else if (Key == "case-sensitive") {
+ if (!parseScalarBool(I->getValue(), FS->CaseSensitive))
+ return false;
+ } else if (Key == "use-external-names") {
+ if (!parseScalarBool(I->getValue(), FS->UseExternalNames))
+ return false;
+ } else {
+ llvm_unreachable("key missing from Keys");
+ }
+ }
+
+ if (Stream.failed())
+ return false;
+
+ if (!checkMissingKeys(Top, Keys))
+ return false;
+ return true;
+ }
+};
+} // end of anonymous namespace
+
+Entry::~Entry() {}
+DirectoryEntry::~DirectoryEntry() { llvm::DeleteContainerPointers(Contents); }
+
+VFSFromYAML::~VFSFromYAML() { llvm::DeleteContainerPointers(Roots); }
+
+VFSFromYAML *VFSFromYAML::create(MemoryBuffer *Buffer,
+ SourceMgr::DiagHandlerTy DiagHandler,
+ void *DiagContext,
+ IntrusiveRefCntPtr<FileSystem> ExternalFS) {
+
+ SourceMgr SM;
+ yaml::Stream Stream(Buffer, SM);
+
+ SM.setDiagHandler(DiagHandler, DiagContext);
+ yaml::document_iterator DI = Stream.begin();
+ yaml::Node *Root = DI->getRoot();
+ if (DI == Stream.end() || !Root) {
+ SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node");
+ return nullptr;
+ }
+
+ VFSFromYAMLParser P(Stream);
+
+ std::unique_ptr<VFSFromYAML> FS(new VFSFromYAML(ExternalFS));
+ if (!P.parse(Root, FS.get()))
+ return nullptr;
+
+ return FS.release();
+}
+
+ErrorOr<Entry *> VFSFromYAML::lookupPath(const Twine &Path_) {
+ SmallString<256> Path;
+ Path_.toVector(Path);
+
+ // Handle relative paths
+ if (std::error_code EC = sys::fs::make_absolute(Path))
+ return EC;
+
+ if (Path.empty())
+ return make_error_code(llvm::errc::invalid_argument);
+
+ sys::path::const_iterator Start = sys::path::begin(Path);
+ sys::path::const_iterator End = sys::path::end(Path);
+ for (std::vector<Entry *>::iterator I = Roots.begin(), E = Roots.end();
+ I != E; ++I) {
+ ErrorOr<Entry *> Result = lookupPath(Start, End, *I);
+ if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
+ return Result;
+ }
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
+ErrorOr<Entry *> VFSFromYAML::lookupPath(sys::path::const_iterator Start,
+ sys::path::const_iterator End,
+ Entry *From) {
+ if (Start->equals("."))
+ ++Start;
+
+ // FIXME: handle ..
+ if (CaseSensitive ? !Start->equals(From->getName())
+ : !Start->equals_lower(From->getName()))
+ // failure to match
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+
+ ++Start;
+
+ if (Start == End) {
+ // Match!
+ return From;
+ }
+
+ DirectoryEntry *DE = dyn_cast<DirectoryEntry>(From);
+ if (!DE)
+ return make_error_code(llvm::errc::not_a_directory);
+
+ for (DirectoryEntry::iterator I = DE->contents_begin(),
+ E = DE->contents_end();
+ I != E; ++I) {
+ ErrorOr<Entry *> Result = lookupPath(Start, End, *I);
+ if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
+ return Result;
+ }
+ return make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
+ErrorOr<Status> VFSFromYAML::status(const Twine &Path, Entry *E) {
+ assert(E != nullptr);
+ std::string PathStr(Path.str());
+ if (FileEntry *F = dyn_cast<FileEntry>(E)) {
+ ErrorOr<Status> S = ExternalFS->status(F->getExternalContentsPath());
+ assert(!S || S->getName() == F->getExternalContentsPath());
+ if (S && !F->useExternalName(UseExternalNames))
+ S->setName(PathStr);
+ if (S)
+ S->IsVFSMapped = true;
+ return S;
+ } else { // directory
+ DirectoryEntry *DE = cast<DirectoryEntry>(E);
+ Status S = DE->getStatus();
+ S.setName(PathStr);
+ return S;
+ }
+}
+
+ErrorOr<Status> VFSFromYAML::status(const Twine &Path) {
+ ErrorOr<Entry *> Result = lookupPath(Path);
+ if (!Result)
+ return Result.getError();
+ return status(Path, *Result);
+}
+
+std::error_code
+VFSFromYAML::openFileForRead(const Twine &Path,
+ std::unique_ptr<vfs::File> &Result) {
+ ErrorOr<Entry *> E = lookupPath(Path);
+ if (!E)
+ return E.getError();
+
+ FileEntry *F = dyn_cast<FileEntry>(*E);
+ if (!F) // FIXME: errc::not_a_file?
+ return make_error_code(llvm::errc::invalid_argument);
+
+ if (std::error_code EC =
+ ExternalFS->openFileForRead(F->getExternalContentsPath(), Result))
+ return EC;
+
+ if (!F->useExternalName(UseExternalNames))
+ Result->setName(Path.str());
+
+ return std::error_code();
+}
+
+IntrusiveRefCntPtr<FileSystem>
+vfs::getVFSFromYAML(MemoryBuffer *Buffer, SourceMgr::DiagHandlerTy DiagHandler,
+ void *DiagContext,
+ IntrusiveRefCntPtr<FileSystem> ExternalFS) {
+ return VFSFromYAML::create(Buffer, DiagHandler, DiagContext, ExternalFS);
+}
+
+UniqueID vfs::getNextVirtualUniqueID() {
+ static std::atomic<unsigned> UID;
+ unsigned ID = ++UID;
+ // The following assumes that uint64_t max will never collide with a real
+ // dev_t value from the OS.
+ return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
+}
+
+#ifndef NDEBUG
+static bool pathHasTraversal(StringRef Path) {
+ using namespace llvm::sys;
+ for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path)))
+ if (Comp == "." || Comp == "..")
+ return true;
+ return false;
+}
+#endif
+
+void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
+ assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute");
+ assert(sys::path::is_absolute(RealPath) && "real path not absolute");
+ assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported");
+ Mappings.emplace_back(VirtualPath, RealPath);
+}
+
+namespace {
+class JSONWriter {
+ llvm::raw_ostream &OS;
+ SmallVector<StringRef, 16> DirStack;
+ inline unsigned getDirIndent() { return 4 * DirStack.size(); }
+ inline unsigned getFileIndent() { return 4 * (DirStack.size() + 1); }
+ bool containedIn(StringRef Parent, StringRef Path);
+ StringRef containedPart(StringRef Parent, StringRef Path);
+ void startDirectory(StringRef Path);
+ void endDirectory();
+ void writeEntry(StringRef VPath, StringRef RPath);
+
+public:
+ JSONWriter(llvm::raw_ostream &OS) : OS(OS) {}
+ void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> IsCaseSensitive);
+};
+}
+
+bool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
+ using namespace llvm::sys;
+ // Compare each path component.
+ auto IParent = path::begin(Parent), EParent = path::end(Parent);
+ for (auto IChild = path::begin(Path), EChild = path::end(Path);
+ IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
+ if (*IParent != *IChild)
+ return false;
+ }
+ // Have we exhausted the parent path?
+ return IParent == EParent;
+}
+
+StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
+ assert(!Parent.empty());
+ assert(containedIn(Parent, Path));
+ return Path.slice(Parent.size() + 1, StringRef::npos);
+}
+
+void JSONWriter::startDirectory(StringRef Path) {
+ StringRef Name =
+ DirStack.empty() ? Path : containedPart(DirStack.back(), Path);
+ DirStack.push_back(Path);
+ unsigned Indent = getDirIndent();
+ OS.indent(Indent) << "{\n";
+ OS.indent(Indent + 2) << "'type': 'directory',\n";
+ OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(Name) << "\",\n";
+ OS.indent(Indent + 2) << "'contents': [\n";
+}
+
+void JSONWriter::endDirectory() {
+ unsigned Indent = getDirIndent();
+ OS.indent(Indent + 2) << "]\n";
+ OS.indent(Indent) << "}";
+
+ DirStack.pop_back();
+}
+
+void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
+ unsigned Indent = getFileIndent();
+ OS.indent(Indent) << "{\n";
+ OS.indent(Indent + 2) << "'type': 'file',\n";
+ OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(VPath) << "\",\n";
+ OS.indent(Indent + 2) << "'external-contents': \""
+ << llvm::yaml::escape(RPath) << "\"\n";
+ OS.indent(Indent) << "}";
+}
+
+void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries,
+ Optional<bool> IsCaseSensitive) {
+ using namespace llvm::sys;
+
+ OS << "{\n"
+ " 'version': 0,\n";
+ if (IsCaseSensitive.hasValue())
+ OS << " 'case-sensitive': '"
+ << (IsCaseSensitive.getValue() ? "true" : "false") << "',\n";
+ OS << " 'roots': [\n";
+
+ if (!Entries.empty()) {
+ const YAMLVFSEntry &Entry = Entries.front();
+ startDirectory(path::parent_path(Entry.VPath));
+ writeEntry(path::filename(Entry.VPath), Entry.RPath);
+
+ for (const auto &Entry : Entries.slice(1)) {
+ StringRef Dir = path::parent_path(Entry.VPath);
+ if (Dir == DirStack.back())
+ OS << ",\n";
+ else {
+ while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) {
+ OS << "\n";
+ endDirectory();
+ }
+ OS << ",\n";
+ startDirectory(Dir);
+ }
+ writeEntry(path::filename(Entry.VPath), Entry.RPath);
+ }
+
+ while (!DirStack.empty()) {
+ OS << "\n";
+ endDirectory();
+ }
+ OS << "\n";
+ }
+
+ OS << " ]\n"
+ << "}\n";
+}
+
+void YAMLVFSWriter::write(llvm::raw_ostream &OS) {
+ std::sort(Mappings.begin(), Mappings.end(),
+ [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) {
+ return LHS.VPath < RHS.VPath;
+ });
+
+ JSONWriter(OS).write(Mappings, IsCaseSensitive);
+}
+
+VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl(const Twine &_Path,
+ VFSFromYAML &FS,
+ DirectoryEntry::iterator Begin,
+ DirectoryEntry::iterator End,
+ std::error_code &EC)
+ : Dir(_Path.str()), FS(FS), Current(Begin), End(End) {
+ if (Current != End) {
+ SmallString<128> PathStr(Dir);
+ llvm::sys::path::append(PathStr, (*Current)->getName());
+ llvm::ErrorOr<vfs::Status> S = FS.status(PathStr.str());
+ if (S)
+ CurrentEntry = *S;
+ else
+ EC = S.getError();
+ }
+}
+
+std::error_code VFSFromYamlDirIterImpl::increment() {
+ assert(Current != End && "cannot iterate past end");
+ if (++Current != End) {
+ SmallString<128> PathStr(Dir);
+ llvm::sys::path::append(PathStr, (*Current)->getName());
+ llvm::ErrorOr<vfs::Status> S = FS.status(PathStr.str());
+ if (!S)
+ return S.getError();
+ CurrentEntry = *S;
+ } else {
+ CurrentEntry = Status();
+ }
+ return std::error_code();
+}
+
+vfs::recursive_directory_iterator::recursive_directory_iterator(FileSystem &FS_,
+ const Twine &Path,
+ std::error_code &EC)
+ : FS(&FS_) {
+ directory_iterator I = FS->dir_begin(Path, EC);
+ if (!EC && I != directory_iterator()) {
+ State = std::make_shared<IterState>();
+ State->push(I);
+ }
+}
+
+vfs::recursive_directory_iterator &
+recursive_directory_iterator::increment(std::error_code &EC) {
+ assert(FS && State && !State->empty() && "incrementing past end");
+ assert(State->top()->isStatusKnown() && "non-canonical end iterator");
+ vfs::directory_iterator End;
+ if (State->top()->isDirectory()) {
+ vfs::directory_iterator I = FS->dir_begin(State->top()->getName(), EC);
+ if (EC)
+ return *this;
+ if (I != End) {
+ State->push(I);
+ return *this;
+ }
+ }
+
+ while (!State->empty() && State->top().increment(EC) == End)
+ State->pop();
+
+ if (State->empty())
+ State.reset(); // end iterator
+
+ return *this;
+}
diff --git a/lib/Frontend/Warnings.cpp b/lib/Basic/Warnings.cpp
index 767096a1c990..6306ceabc638 100644
--- a/lib/Frontend/Warnings.cpp
+++ b/lib/Basic/Warnings.cpp
@@ -20,12 +20,11 @@
// Given a warning option 'foo', the following are valid:
// -Wfoo, -Wno-foo, -Werror=foo, -Wfatal-errors=foo
//
-#include "clang/Frontend/Utils.h"
+// Remark options are also handled here, analogously, except that they are much
+// simpler because a remark can't be promoted to an error.
+#include "clang/Basic/AllDiagnostics.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
-#include "clang/Lex/LexDiagnostic.h"
-#include "clang/Sema/SemaDiagnostic.h"
#include <algorithm>
#include <cstring>
#include <utility>
@@ -34,17 +33,12 @@ using namespace clang;
// EmitUnknownDiagWarning - Emit a warning and typo hint for unknown warning
// opts
static void EmitUnknownDiagWarning(DiagnosticsEngine &Diags,
- StringRef Prefix, StringRef Opt,
- bool isPositive) {
- StringRef Suggestion = DiagnosticIDs::getNearestWarningOption(Opt);
- if (!Suggestion.empty())
- Diags.Report(isPositive? diag::warn_unknown_warning_option_suggest :
- diag::warn_unknown_negative_warning_option_suggest)
- << (Prefix.str() += Opt) << (Prefix.str() += Suggestion);
- else
- Diags.Report(isPositive? diag::warn_unknown_warning_option :
- diag::warn_unknown_negative_warning_option)
- << (Prefix.str() += Opt);
+ diag::Flavor Flavor, StringRef Prefix,
+ StringRef Opt) {
+ StringRef Suggestion = DiagnosticIDs::getNearestOption(Flavor, Opt);
+ Diags.Report(diag::warn_unknown_diag_option)
+ << (Flavor == diag::Flavor::WarningOrError ? 0 : 1) << (Prefix.str() += Opt)
+ << !Suggestion.empty() << (Prefix.str() += Suggestion);
}
void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
@@ -70,11 +64,11 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
// extension diagnostics onto WARNING or ERROR unless the user has futz'd
// around with them explicitly.
if (Opts.PedanticErrors)
- Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Error);
+ Diags.setExtensionHandlingBehavior(diag::Severity::Error);
else if (Opts.Pedantic)
- Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Warn);
+ Diags.setExtensionHandlingBehavior(diag::Severity::Warning);
else
- Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Ignore);
+ Diags.setExtensionHandlingBehavior(diag::Severity::Ignored);
SmallVector<diag::kind, 10> _Diags;
const IntrusiveRefCntPtr< DiagnosticIDs > DiagIDs =
@@ -92,6 +86,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
break;
for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) {
+ const auto Flavor = diag::Flavor::WarningOrError;
StringRef Opt = Opts.Warnings[i];
StringRef OrigOpt = Opts.Warnings[i];
@@ -109,8 +104,9 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
// Figure out how this option affects the warning. If -Wfoo, map the
// diagnostic to a warning, if -Wno-foo, map it to ignore.
- diag::Mapping Mapping = isPositive ? diag::MAP_WARNING : diag::MAP_IGNORE;
-
+ diag::Severity Mapping =
+ isPositive ? diag::Severity::Warning : diag::Severity::Ignored;
+
// -Wsystem-headers is a special case, not driven by the option table. It
// cannot be controlled with -Werror.
if (Opt == "system-headers") {
@@ -127,7 +123,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
Diags.setEnableAllWarnings(true);
} else {
Diags.setEnableAllWarnings(false);
- Diags.setMappingToAllDiagnostics(diag::MAP_IGNORE);
+ Diags.setSeverityForAll(Flavor, diag::Severity::Ignored);
}
}
continue;
@@ -156,8 +152,8 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
if (SetDiagnostic) {
// Set the warning as error flag for this specifier.
Diags.setDiagnosticGroupWarningAsError(Specifier, isPositive);
- } else if (DiagIDs->getDiagnosticsInGroup(Specifier, _Diags)) {
- EmitUnknownDiagWarning(Diags, "-Werror=", Specifier, isPositive);
+ } else if (DiagIDs->getDiagnosticsInGroup(Flavor, Specifier, _Diags)) {
+ EmitUnknownDiagWarning(Diags, Flavor, "-Werror=", Specifier);
}
continue;
}
@@ -184,19 +180,50 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
if (SetDiagnostic) {
// Set the error as fatal flag for this specifier.
Diags.setDiagnosticGroupErrorAsFatal(Specifier, isPositive);
- } else if (DiagIDs->getDiagnosticsInGroup(Specifier, _Diags)) {
- EmitUnknownDiagWarning(Diags, "-Wfatal-errors=", Specifier,
- isPositive);
+ } else if (DiagIDs->getDiagnosticsInGroup(Flavor, Specifier, _Diags)) {
+ EmitUnknownDiagWarning(Diags, Flavor, "-Wfatal-errors=", Specifier);
}
continue;
}
if (Report) {
- if (DiagIDs->getDiagnosticsInGroup(Opt, _Diags))
- EmitUnknownDiagWarning(Diags, isPositive ? "-W" : "-Wno-", Opt,
- isPositive);
+ if (DiagIDs->getDiagnosticsInGroup(Flavor, Opt, _Diags))
+ EmitUnknownDiagWarning(Diags, Flavor, isPositive ? "-W" : "-Wno-",
+ Opt);
+ } else {
+ Diags.setSeverityForGroup(Flavor, Opt, Mapping);
+ }
+ }
+
+ for (unsigned i = 0, e = Opts.Remarks.size(); i != e; ++i) {
+ StringRef Opt = Opts.Remarks[i];
+ const auto Flavor = diag::Flavor::Remark;
+
+ // Check to see if this warning starts with "no-", if so, this is a
+ // negative form of the option.
+ bool IsPositive = !Opt.startswith("no-");
+ if (!IsPositive) Opt = Opt.substr(3);
+
+ auto Severity = IsPositive ? diag::Severity::Remark
+ : diag::Severity::Ignored;
+
+ // -Reverything sets the state of all remarks. Note that all remarks are
+ // in remark groups, so we don't need a separate 'all remarks enabled'
+ // flag.
+ if (Opt == "everything") {
+ if (SetDiagnostic)
+ Diags.setSeverityForAll(Flavor, Severity);
+ continue;
+ }
+
+ if (Report) {
+ if (DiagIDs->getDiagnosticsInGroup(Flavor, Opt, _Diags))
+ EmitUnknownDiagWarning(Diags, Flavor, IsPositive ? "-R" : "-Rno-",
+ Opt);
} else {
- Diags.setDiagnosticGroupMapping(Opt, Mapping);
+ Diags.setSeverityForGroup(Flavor, Opt,
+ IsPositive ? diag::Severity::Remark
+ : diag::Severity::Ignored);
}
}
}
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 7bb65e923e2c..dfd819a407e9 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -3,9 +3,7 @@ add_subdirectory(Basic)
add_subdirectory(Lex)
add_subdirectory(Parse)
add_subdirectory(AST)
-if(CLANG_ENABLE_REWRITER)
- add_subdirectory(ASTMatchers)
-endif()
+add_subdirectory(ASTMatchers)
add_subdirectory(Sema)
add_subdirectory(CodeGen)
add_subdirectory(Analysis)
diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h
index 468fe0439967..d3ec46c4c4a1 100644
--- a/lib/CodeGen/ABIInfo.h
+++ b/lib/CodeGen/ABIInfo.h
@@ -11,8 +11,8 @@
#define CLANG_CODEGEN_ABIINFO_H
#include "clang/AST/Type.h"
-#include "llvm/IR/Type.h"
#include "llvm/IR/CallingConv.h"
+#include "llvm/IR/Type.h"
namespace llvm {
class Value;
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 90b0f68bd693..cec48f35a2e9 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -13,13 +13,15 @@
#include "clang/Basic/TargetOptions.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
-#include "llvm/Analysis/Verifier.h"
-#include "llvm/Assembly/PrintModulePass.h"
-#include "llvm/Bitcode/ReaderWriter.h"
+#include "clang/Frontend/Utils.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/PassManager.h"
#include "llvm/Support/CommandLine.h"
@@ -36,6 +38,7 @@
#include "llvm/Transforms/Instrumentation.h"
#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Scalar.h"
+#include <memory>
using namespace clang;
using namespace llvm;
@@ -55,38 +58,37 @@ class EmitAssemblyHelper {
mutable FunctionPassManager *PerFunctionPasses;
private:
- PassManager *getCodeGenPasses(TargetMachine *TM) const {
+ PassManager *getCodeGenPasses() const {
if (!CodeGenPasses) {
CodeGenPasses = new PassManager();
- CodeGenPasses->add(new DataLayout(TheModule));
+ CodeGenPasses->add(new DataLayoutPass(TheModule));
if (TM)
TM->addAnalysisPasses(*CodeGenPasses);
}
return CodeGenPasses;
}
- PassManager *getPerModulePasses(TargetMachine *TM) const {
+ PassManager *getPerModulePasses() const {
if (!PerModulePasses) {
PerModulePasses = new PassManager();
- PerModulePasses->add(new DataLayout(TheModule));
+ PerModulePasses->add(new DataLayoutPass(TheModule));
if (TM)
TM->addAnalysisPasses(*PerModulePasses);
}
return PerModulePasses;
}
- FunctionPassManager *getPerFunctionPasses(TargetMachine *TM) const {
+ FunctionPassManager *getPerFunctionPasses() const {
if (!PerFunctionPasses) {
PerFunctionPasses = new FunctionPassManager(TheModule);
- PerFunctionPasses->add(new DataLayout(TheModule));
+ PerFunctionPasses->add(new DataLayoutPass(TheModule));
if (TM)
TM->addAnalysisPasses(*PerFunctionPasses);
}
return PerFunctionPasses;
}
-
- void CreatePasses(TargetMachine *TM);
+ void CreatePasses();
/// CreateTargetMachine - Generates the TargetMachine.
/// Returns Null if it is unable to create the target machine.
@@ -101,8 +103,7 @@ private:
/// AddEmitPasses - Add passes necessary to emit assembly or LLVM IR.
///
/// \return True on success.
- bool AddEmitPasses(BackendAction Action, formatted_raw_ostream &OS,
- TargetMachine *TM);
+ bool AddEmitPasses(BackendAction Action, formatted_raw_ostream &OS);
public:
EmitAssemblyHelper(DiagnosticsEngine &_Diags,
@@ -112,14 +113,19 @@ public:
Module *M)
: Diags(_Diags), CodeGenOpts(CGOpts), TargetOpts(TOpts), LangOpts(LOpts),
TheModule(M), CodeGenerationTime("Code Generation Time"),
- CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) {}
+ CodeGenPasses(nullptr), PerModulePasses(nullptr),
+ PerFunctionPasses(nullptr) {}
~EmitAssemblyHelper() {
delete CodeGenPasses;
delete PerModulePasses;
delete PerFunctionPasses;
+ if (CodeGenOpts.DisableFree)
+ BuryPointer(TM.release());
}
+ std::unique_ptr<TargetMachine> TM;
+
void EmitAssembly(BackendAction Action, raw_ostream *OS);
};
@@ -162,6 +168,11 @@ static void addSampleProfileLoaderPass(const PassManagerBuilder &Builder,
PM.add(createSampleProfileLoaderPass(CGOpts.SampleProfileFile));
}
+static void addAddDiscriminatorsPass(const PassManagerBuilder &Builder,
+ PassManagerBase &PM) {
+ PM.add(createAddDiscriminatorsPass());
+}
+
static void addBoundsCheckingPass(const PassManagerBuilder &Builder,
PassManagerBase &PM) {
PM.add(createBoundsCheckingPass());
@@ -169,20 +180,8 @@ static void addBoundsCheckingPass(const PassManagerBuilder &Builder,
static void addAddressSanitizerPasses(const PassManagerBuilder &Builder,
PassManagerBase &PM) {
- const PassManagerBuilderWrapper &BuilderWrapper =
- static_cast<const PassManagerBuilderWrapper&>(Builder);
- const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
- const LangOptions &LangOpts = BuilderWrapper.getLangOpts();
- PM.add(createAddressSanitizerFunctionPass(
- LangOpts.Sanitize.InitOrder,
- LangOpts.Sanitize.UseAfterReturn,
- LangOpts.Sanitize.UseAfterScope,
- CGOpts.SanitizerBlacklistFile,
- CGOpts.SanitizeAddressZeroBaseShadow));
- PM.add(createAddressSanitizerModulePass(
- LangOpts.Sanitize.InitOrder,
- CGOpts.SanitizerBlacklistFile,
- CGOpts.SanitizeAddressZeroBaseShadow));
+ PM.add(createAddressSanitizerFunctionPass());
+ PM.add(createAddressSanitizerModulePass());
}
static void addMemorySanitizerPass(const PassManagerBuilder &Builder,
@@ -190,8 +189,7 @@ static void addMemorySanitizerPass(const PassManagerBuilder &Builder,
const PassManagerBuilderWrapper &BuilderWrapper =
static_cast<const PassManagerBuilderWrapper&>(Builder);
const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
- PM.add(createMemorySanitizerPass(CGOpts.SanitizeMemoryTrackOrigins,
- CGOpts.SanitizerBlacklistFile));
+ PM.add(createMemorySanitizerPass(CGOpts.SanitizeMemoryTrackOrigins));
// MemorySanitizer inserts complex instrumentation that mostly follows
// the logic of the original code, but operates on "shadow" values.
@@ -208,10 +206,7 @@ static void addMemorySanitizerPass(const PassManagerBuilder &Builder,
static void addThreadSanitizerPass(const PassManagerBuilder &Builder,
PassManagerBase &PM) {
- const PassManagerBuilderWrapper &BuilderWrapper =
- static_cast<const PassManagerBuilderWrapper&>(Builder);
- const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
- PM.add(createThreadSanitizerPass(CGOpts.SanitizerBlacklistFile));
+ PM.add(createThreadSanitizerPass());
}
static void addDataFlowSanitizerPass(const PassManagerBuilder &Builder,
@@ -222,7 +217,7 @@ static void addDataFlowSanitizerPass(const PassManagerBuilder &Builder,
PM.add(createDataFlowSanitizerPass(CGOpts.SanitizerBlacklistFile));
}
-void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
+void EmitAssemblyHelper::CreatePasses() {
unsigned OptLevel = CodeGenOpts.OptimizationLevel;
CodeGenOptions::InliningMethod Inlining = CodeGenOpts.getInlining();
@@ -240,10 +235,14 @@ void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
PMBuilder.SLPVectorize = CodeGenOpts.VectorizeSLP;
PMBuilder.LoopVectorize = CodeGenOpts.VectorizeLoop;
+ PMBuilder.DisableTailCalls = CodeGenOpts.DisableTailCalls;
PMBuilder.DisableUnitAtATime = !CodeGenOpts.UnitAtATime;
PMBuilder.DisableUnrollLoops = !CodeGenOpts.UnrollLoops;
PMBuilder.RerollLoops = CodeGenOpts.RerollLoops;
+ PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible,
+ addAddDiscriminatorsPass);
+
if (!CodeGenOpts.SampleProfileFile.empty())
PMBuilder.addExtension(PassManagerBuilder::EP_EarlyAsPossible,
addSampleProfileLoaderPass);
@@ -298,19 +297,12 @@ void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
PMBuilder.LibraryInfo = new TargetLibraryInfo(TargetTriple);
if (!CodeGenOpts.SimplifyLibCalls)
PMBuilder.LibraryInfo->disableAllFunctions();
-
+
switch (Inlining) {
case CodeGenOptions::NoInlining: break;
case CodeGenOptions::NormalInlining: {
- // FIXME: Derive these constants in a principled fashion.
- unsigned Threshold = 225;
- if (CodeGenOpts.OptimizeSize == 1) // -Os
- Threshold = 75;
- else if (CodeGenOpts.OptimizeSize == 2) // -Oz
- Threshold = 25;
- else if (OptLevel > 2)
- Threshold = 275;
- PMBuilder.Inliner = createFunctionInliningPass(Threshold);
+ PMBuilder.Inliner =
+ createFunctionInliningPass(OptLevel, CodeGenOpts.OptimizeSize);
break;
}
case CodeGenOptions::OnlyAlwaysInlining:
@@ -324,13 +316,15 @@ void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
}
// Set up the per-function pass manager.
- FunctionPassManager *FPM = getPerFunctionPasses(TM);
+ FunctionPassManager *FPM = getPerFunctionPasses();
if (CodeGenOpts.VerifyModule)
FPM->add(createVerifierPass());
PMBuilder.populateFunctionPassManager(*FPM);
// Set up the per-module pass manager.
- PassManager *MPM = getPerModulePasses(TM);
+ PassManager *MPM = getPerModulePasses();
+ if (CodeGenOpts.VerifyModule)
+ MPM->add(createDebugInfoVerifierPass());
if (!CodeGenOpts.DisableGCov &&
(CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes)) {
@@ -360,32 +354,19 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
if (!TheTarget) {
if (MustCreateTM)
Diags.Report(diag::err_fe_unable_to_create_target) << Error;
- return 0;
+ return nullptr;
}
- // FIXME: Expose these capabilities via actual APIs!!!! Aside from just
- // being gross, this is also totally broken if we ever care about
- // concurrency.
-
- TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose);
-
- TargetMachine::setFunctionSections(CodeGenOpts.FunctionSections);
- TargetMachine::setDataSections (CodeGenOpts.DataSections);
-
- // FIXME: Parse this earlier.
- llvm::CodeModel::Model CM;
- if (CodeGenOpts.CodeModel == "small") {
- CM = llvm::CodeModel::Small;
- } else if (CodeGenOpts.CodeModel == "kernel") {
- CM = llvm::CodeModel::Kernel;
- } else if (CodeGenOpts.CodeModel == "medium") {
- CM = llvm::CodeModel::Medium;
- } else if (CodeGenOpts.CodeModel == "large") {
- CM = llvm::CodeModel::Large;
- } else {
- assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!");
- CM = llvm::CodeModel::Default;
- }
+ unsigned CodeModel =
+ llvm::StringSwitch<unsigned>(CodeGenOpts.CodeModel)
+ .Case("small", llvm::CodeModel::Small)
+ .Case("kernel", llvm::CodeModel::Kernel)
+ .Case("medium", llvm::CodeModel::Medium)
+ .Case("large", llvm::CodeModel::Large)
+ .Case("default", llvm::CodeModel::Default)
+ .Default(~0u);
+ assert(CodeModel != ~0u && "invalid code model!");
+ llvm::CodeModel::Model CM = static_cast<llvm::CodeModel::Model>(CodeModel);
SmallVector<const char *, 16> BackendArgs;
BackendArgs.push_back("clang"); // Fake program name.
@@ -402,8 +383,8 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
for (unsigned i = 0, e = CodeGenOpts.BackendOptions.size(); i != e; ++i)
BackendArgs.push_back(CodeGenOpts.BackendOptions[i].c_str());
if (CodeGenOpts.NoGlobalMerge)
- BackendArgs.push_back("-global-merge=false");
- BackendArgs.push_back(0);
+ BackendArgs.push_back("-enable-global-merge=false");
+ BackendArgs.push_back(nullptr);
llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1,
BackendArgs.data());
@@ -437,6 +418,12 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
llvm::TargetOptions Options;
+ if (CodeGenOpts.DisableIntegratedAS)
+ Options.DisableIntegratedAS = true;
+
+ if (CodeGenOpts.CompressDebugSections)
+ Options.CompressDebugSections = true;
+
// Set frame pointer elimination mode.
if (!CodeGenOpts.DisableFPElim) {
Options.NoFramePointerElim = false;
@@ -482,32 +469,27 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
Options.DisableTailCalls = CodeGenOpts.DisableTailCalls;
Options.TrapFuncName = CodeGenOpts.TrapFuncName;
Options.PositionIndependentExecutable = LangOpts.PIELevel != 0;
- Options.EnableSegmentedStacks = CodeGenOpts.EnableSegmentedStacks;
+ Options.FunctionSections = CodeGenOpts.FunctionSections;
+ Options.DataSections = CodeGenOpts.DataSections;
+
+ Options.MCOptions.MCRelaxAll = CodeGenOpts.RelaxAll;
+ Options.MCOptions.MCSaveTempLabels = CodeGenOpts.SaveTempLabels;
+ Options.MCOptions.MCUseDwarfDirectory = !CodeGenOpts.NoDwarfDirectoryAsm;
+ Options.MCOptions.MCNoExecStack = CodeGenOpts.NoExecStack;
+ Options.MCOptions.AsmVerbose = CodeGenOpts.AsmVerbose;
TargetMachine *TM = TheTarget->createTargetMachine(Triple, TargetOpts.CPU,
FeaturesStr, Options,
RM, CM, OptLevel);
- if (CodeGenOpts.RelaxAll)
- TM->setMCRelaxAll(true);
- if (CodeGenOpts.SaveTempLabels)
- TM->setMCSaveTempLabels(true);
- if (CodeGenOpts.NoDwarf2CFIAsm)
- TM->setMCUseCFI(false);
- if (!CodeGenOpts.NoDwarfDirectoryAsm)
- TM->setMCUseDwarfDirectory(true);
- if (CodeGenOpts.NoExecStack)
- TM->setMCNoExecStack(true);
-
return TM;
}
bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
- formatted_raw_ostream &OS,
- TargetMachine *TM) {
+ formatted_raw_ostream &OS) {
// Create the code generator passes.
- PassManager *PM = getCodeGenPasses(TM);
+ PassManager *PM = getCodeGenPasses();
// Add LibraryInfo.
llvm::Triple TargetTriple(TheModule->getTargetTriple());
@@ -546,33 +528,34 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
}
void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) {
- TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : 0);
+ TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : nullptr);
llvm::formatted_raw_ostream FormattedOS;
bool UsesCodeGen = (Action != Backend_EmitNothing &&
Action != Backend_EmitBC &&
Action != Backend_EmitLL);
- TargetMachine *TM = CreateTargetMachine(UsesCodeGen);
+ if (!TM)
+ TM.reset(CreateTargetMachine(UsesCodeGen));
+
if (UsesCodeGen && !TM) return;
- llvm::OwningPtr<TargetMachine> TMOwner(CodeGenOpts.DisableFree ? 0 : TM);
- CreatePasses(TM);
+ CreatePasses();
switch (Action) {
case Backend_EmitNothing:
break;
case Backend_EmitBC:
- getPerModulePasses(TM)->add(createBitcodeWriterPass(*OS));
+ getPerModulePasses()->add(createBitcodeWriterPass(*OS));
break;
case Backend_EmitLL:
FormattedOS.setStream(*OS, formatted_raw_ostream::PRESERVE_STREAM);
- getPerModulePasses(TM)->add(createPrintModulePass(&FormattedOS));
+ getPerModulePasses()->add(createPrintModulePass(FormattedOS));
break;
default:
FormattedOS.setStream(*OS, formatted_raw_ostream::PRESERVE_STREAM);
- if (!AddEmitPasses(Action, FormattedOS, TM))
+ if (!AddEmitPasses(Action, FormattedOS))
return;
}
@@ -607,10 +590,23 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) {
void clang::EmitBackendOutput(DiagnosticsEngine &Diags,
const CodeGenOptions &CGOpts,
const clang::TargetOptions &TOpts,
- const LangOptions &LOpts,
- Module *M,
- BackendAction Action, raw_ostream *OS) {
+ const LangOptions &LOpts, StringRef TDesc,
+ Module *M, BackendAction Action,
+ raw_ostream *OS) {
EmitAssemblyHelper AsmHelper(Diags, CGOpts, TOpts, LOpts, M);
AsmHelper.EmitAssembly(Action, OS);
+
+ // If an optional clang TargetInfo description string was passed in, use it to
+ // verify the LLVM TargetMachine's DataLayout.
+ if (AsmHelper.TM && !TDesc.empty()) {
+ std::string DLDesc =
+ AsmHelper.TM->getDataLayout()->getStringRepresentation();
+ if (DLDesc != TDesc) {
+ unsigned DiagID = Diags.getCustomDiagID(
+ DiagnosticsEngine::Error, "backend data layout '%0' does not match "
+ "expected target description '%1'");
+ Diags.Report(DiagID) << DLDesc << TDesc;
+ }
+ }
}
diff --git a/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp
index 0df2a4000e28..89bde2ce20d9 100644
--- a/lib/CodeGen/CGAtomic.cpp
+++ b/lib/CodeGen/CGAtomic.cpp
@@ -24,16 +24,6 @@
using namespace clang;
using namespace CodeGen;
-// The ABI values for various atomic memory orderings.
-enum AtomicOrderingKind {
- AO_ABI_memory_order_relaxed = 0,
- AO_ABI_memory_order_consume = 1,
- AO_ABI_memory_order_acquire = 2,
- AO_ABI_memory_order_release = 3,
- AO_ABI_memory_order_acq_rel = 4,
- AO_ABI_memory_order_seq_cst = 5
-};
-
namespace {
class AtomicInfo {
CodeGenFunction &CGF;
@@ -57,10 +47,10 @@ namespace {
ASTContext &C = CGF.getContext();
uint64_t valueAlignInBits;
- llvm::tie(ValueSizeInBits, valueAlignInBits) = C.getTypeInfo(ValueTy);
+ std::tie(ValueSizeInBits, valueAlignInBits) = C.getTypeInfo(ValueTy);
uint64_t atomicAlignInBits;
- llvm::tie(AtomicSizeInBits, atomicAlignInBits) = C.getTypeInfo(AtomicTy);
+ std::tie(AtomicSizeInBits, atomicAlignInBits) = C.getTypeInfo(AtomicTy);
assert(ValueSizeInBits <= AtomicSizeInBits);
assert(valueAlignInBits <= atomicAlignInBits);
@@ -184,10 +174,139 @@ bool AtomicInfo::emitMemSetZeroIfNecessary(LValue dest) const {
return true;
}
-static void
-EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest,
- llvm::Value *Ptr, llvm::Value *Val1, llvm::Value *Val2,
- uint64_t Size, unsigned Align, llvm::AtomicOrdering Order) {
+static void emitAtomicCmpXchg(CodeGenFunction &CGF, AtomicExpr *E, bool IsWeak,
+ llvm::Value *Dest, llvm::Value *Ptr,
+ llvm::Value *Val1, llvm::Value *Val2,
+ uint64_t Size, unsigned Align,
+ llvm::AtomicOrdering SuccessOrder,
+ llvm::AtomicOrdering FailureOrder) {
+ // Note that cmpxchg doesn't support weak cmpxchg, at least at the moment.
+ llvm::LoadInst *Expected = CGF.Builder.CreateLoad(Val1);
+ Expected->setAlignment(Align);
+ llvm::LoadInst *Desired = CGF.Builder.CreateLoad(Val2);
+ Desired->setAlignment(Align);
+
+ llvm::AtomicCmpXchgInst *Pair = CGF.Builder.CreateAtomicCmpXchg(
+ Ptr, Expected, Desired, SuccessOrder, FailureOrder);
+ Pair->setVolatile(E->isVolatile());
+ Pair->setWeak(IsWeak);
+
+ // Cmp holds the result of the compare-exchange operation: true on success,
+ // false on failure.
+ llvm::Value *Old = CGF.Builder.CreateExtractValue(Pair, 0);
+ llvm::Value *Cmp = CGF.Builder.CreateExtractValue(Pair, 1);
+
+ // This basic block is used to hold the store instruction if the operation
+ // failed.
+ llvm::BasicBlock *StoreExpectedBB =
+ CGF.createBasicBlock("cmpxchg.store_expected", CGF.CurFn);
+
+ // This basic block is the exit point of the operation, we should end up
+ // here regardless of whether or not the operation succeeded.
+ llvm::BasicBlock *ContinueBB =
+ CGF.createBasicBlock("cmpxchg.continue", CGF.CurFn);
+
+ // Update Expected if Expected isn't equal to Old, otherwise branch to the
+ // exit point.
+ CGF.Builder.CreateCondBr(Cmp, ContinueBB, StoreExpectedBB);
+
+ CGF.Builder.SetInsertPoint(StoreExpectedBB);
+ // Update the memory at Expected with Old's value.
+ llvm::StoreInst *StoreExpected = CGF.Builder.CreateStore(Old, Val1);
+ StoreExpected->setAlignment(Align);
+ // Finally, branch to the exit point.
+ CGF.Builder.CreateBr(ContinueBB);
+
+ CGF.Builder.SetInsertPoint(ContinueBB);
+ // Update the memory at Dest with Cmp's value.
+ CGF.EmitStoreOfScalar(Cmp, CGF.MakeAddrLValue(Dest, E->getType()));
+ return;
+}
+
+/// Given an ordering required on success, emit all possible cmpxchg
+/// instructions to cope with the provided (but possibly only dynamically known)
+/// FailureOrder.
+static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E,
+ bool IsWeak, llvm::Value *Dest,
+ llvm::Value *Ptr, llvm::Value *Val1,
+ llvm::Value *Val2,
+ llvm::Value *FailureOrderVal,
+ uint64_t Size, unsigned Align,
+ llvm::AtomicOrdering SuccessOrder) {
+ llvm::AtomicOrdering FailureOrder;
+ if (llvm::ConstantInt *FO = dyn_cast<llvm::ConstantInt>(FailureOrderVal)) {
+ switch (FO->getSExtValue()) {
+ default:
+ FailureOrder = llvm::Monotonic;
+ break;
+ case AtomicExpr::AO_ABI_memory_order_consume:
+ case AtomicExpr::AO_ABI_memory_order_acquire:
+ FailureOrder = llvm::Acquire;
+ break;
+ case AtomicExpr::AO_ABI_memory_order_seq_cst:
+ FailureOrder = llvm::SequentiallyConsistent;
+ break;
+ }
+ if (FailureOrder >= SuccessOrder) {
+ // Don't assert on undefined behaviour.
+ FailureOrder =
+ llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(SuccessOrder);
+ }
+ emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, Size, Align,
+ SuccessOrder, FailureOrder);
+ return;
+ }
+
+ // Create all the relevant BB's
+ llvm::BasicBlock *MonotonicBB = nullptr, *AcquireBB = nullptr,
+ *SeqCstBB = nullptr;
+ MonotonicBB = CGF.createBasicBlock("monotonic_fail", CGF.CurFn);
+ if (SuccessOrder != llvm::Monotonic && SuccessOrder != llvm::Release)
+ AcquireBB = CGF.createBasicBlock("acquire_fail", CGF.CurFn);
+ if (SuccessOrder == llvm::SequentiallyConsistent)
+ SeqCstBB = CGF.createBasicBlock("seqcst_fail", CGF.CurFn);
+
+ llvm::BasicBlock *ContBB = CGF.createBasicBlock("atomic.continue", CGF.CurFn);
+
+ llvm::SwitchInst *SI = CGF.Builder.CreateSwitch(FailureOrderVal, MonotonicBB);
+
+ // Emit all the different atomics
+
+ // MonotonicBB is arbitrarily chosen as the default case; in practice, this
+ // doesn't matter unless someone is crazy enough to use something that
+ // doesn't fold to a constant for the ordering.
+ CGF.Builder.SetInsertPoint(MonotonicBB);
+ emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2,
+ Size, Align, SuccessOrder, llvm::Monotonic);
+ CGF.Builder.CreateBr(ContBB);
+
+ if (AcquireBB) {
+ CGF.Builder.SetInsertPoint(AcquireBB);
+ emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2,
+ Size, Align, SuccessOrder, llvm::Acquire);
+ CGF.Builder.CreateBr(ContBB);
+ SI->addCase(CGF.Builder.getInt32(AtomicExpr::AO_ABI_memory_order_consume),
+ AcquireBB);
+ SI->addCase(CGF.Builder.getInt32(AtomicExpr::AO_ABI_memory_order_acquire),
+ AcquireBB);
+ }
+ if (SeqCstBB) {
+ CGF.Builder.SetInsertPoint(SeqCstBB);
+ emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2,
+ Size, Align, SuccessOrder, llvm::SequentiallyConsistent);
+ CGF.Builder.CreateBr(ContBB);
+ SI->addCase(CGF.Builder.getInt32(AtomicExpr::AO_ABI_memory_order_seq_cst),
+ SeqCstBB);
+ }
+
+ CGF.Builder.SetInsertPoint(ContBB);
+}
+
+static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest,
+ llvm::Value *Ptr, llvm::Value *Val1, llvm::Value *Val2,
+ llvm::Value *IsWeak, llvm::Value *FailureOrder,
+ uint64_t Size, unsigned Align,
+ llvm::AtomicOrdering Order) {
llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
@@ -196,25 +315,43 @@ EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest,
llvm_unreachable("Already handled!");
case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+ emitAtomicCmpXchgFailureSet(CGF, E, false, Dest, Ptr, Val1, Val2,
+ FailureOrder, Size, Align, Order);
+ return;
case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ emitAtomicCmpXchgFailureSet(CGF, E, true, Dest, Ptr, Val1, Val2,
+ FailureOrder, Size, Align, Order);
+ return;
case AtomicExpr::AO__atomic_compare_exchange:
case AtomicExpr::AO__atomic_compare_exchange_n: {
- // Note that cmpxchg only supports specifying one ordering and
- // doesn't support weak cmpxchg, at least at the moment.
- llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
- LoadVal1->setAlignment(Align);
- llvm::LoadInst *LoadVal2 = CGF.Builder.CreateLoad(Val2);
- LoadVal2->setAlignment(Align);
- llvm::AtomicCmpXchgInst *CXI =
- CGF.Builder.CreateAtomicCmpXchg(Ptr, LoadVal1, LoadVal2, Order);
- CXI->setVolatile(E->isVolatile());
- llvm::StoreInst *StoreVal1 = CGF.Builder.CreateStore(CXI, Val1);
- StoreVal1->setAlignment(Align);
- llvm::Value *Cmp = CGF.Builder.CreateICmpEQ(CXI, LoadVal1);
- CGF.EmitStoreOfScalar(Cmp, CGF.MakeAddrLValue(Dest, E->getType()));
+ if (llvm::ConstantInt *IsWeakC = dyn_cast<llvm::ConstantInt>(IsWeak)) {
+ emitAtomicCmpXchgFailureSet(CGF, E, IsWeakC->getZExtValue(), Dest, Ptr,
+ Val1, Val2, FailureOrder, Size, Align, Order);
+ } else {
+ // Create all the relevant BB's
+ llvm::BasicBlock *StrongBB =
+ CGF.createBasicBlock("cmpxchg.strong", CGF.CurFn);
+ llvm::BasicBlock *WeakBB = CGF.createBasicBlock("cmxchg.weak", CGF.CurFn);
+ llvm::BasicBlock *ContBB =
+ CGF.createBasicBlock("cmpxchg.continue", CGF.CurFn);
+
+ llvm::SwitchInst *SI = CGF.Builder.CreateSwitch(IsWeak, WeakBB);
+ SI->addCase(CGF.Builder.getInt1(false), StrongBB);
+
+ CGF.Builder.SetInsertPoint(StrongBB);
+ emitAtomicCmpXchgFailureSet(CGF, E, false, Dest, Ptr, Val1, Val2,
+ FailureOrder, Size, Align, Order);
+ CGF.Builder.CreateBr(ContBB);
+
+ CGF.Builder.SetInsertPoint(WeakBB);
+ emitAtomicCmpXchgFailureSet(CGF, E, true, Dest, Ptr, Val1, Val2,
+ FailureOrder, Size, Align, Order);
+ CGF.Builder.CreateBr(ContBB);
+
+ CGF.Builder.SetInsertPoint(ContBB);
+ }
return;
}
-
case AtomicExpr::AO__c11_atomic_load:
case AtomicExpr::AO__atomic_load_n:
case AtomicExpr::AO__atomic_load: {
@@ -351,17 +488,18 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
bool UseLibcall = (Size != Align ||
getContext().toBits(sizeChars) > MaxInlineWidthInBits);
- llvm::Value *Ptr, *Order, *OrderFail = 0, *Val1 = 0, *Val2 = 0;
- Ptr = EmitScalarExpr(E->getPtr());
+ llvm::Value *IsWeak = nullptr, *OrderFail = nullptr, *Val1 = nullptr,
+ *Val2 = nullptr;
+ llvm::Value *Ptr = EmitScalarExpr(E->getPtr());
if (E->getOp() == AtomicExpr::AO__c11_atomic_init) {
assert(!Dest && "Init does not return a value");
LValue lvalue = LValue::MakeAddr(Ptr, AtomicTy, alignChars, getContext());
EmitAtomicInit(E->getVal1(), lvalue);
- return RValue::get(0);
+ return RValue::get(nullptr);
}
- Order = EmitScalarExpr(E->getOrder());
+ llvm::Value *Order = EmitScalarExpr(E->getOrder());
switch (E->getOp()) {
case AtomicExpr::AO__c11_atomic_init:
@@ -394,9 +532,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
else
Val2 = EmitValToTemp(*this, E->getVal2());
OrderFail = EmitScalarExpr(E->getOrderFail());
- // Evaluate and discard the 'weak' argument.
if (E->getNumSubExprs() == 6)
- EmitScalarExpr(E->getWeak());
+ IsWeak = EmitScalarExpr(E->getWeak());
break;
case AtomicExpr::AO__c11_atomic_fetch_add:
@@ -476,6 +613,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
Args.add(RValue::get(EmitCastToVoidPtr(Ptr)), getContext().VoidPtrTy);
std::string LibCallName;
+ QualType LoweredMemTy =
+ MemTy->isPointerType() ? getContext().getIntPtrType() : MemTy;
QualType RetTy;
bool HaveRetTy = false;
switch (E->getOp()) {
@@ -531,7 +670,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
case AtomicExpr::AO__c11_atomic_fetch_add:
case AtomicExpr::AO__atomic_fetch_add:
LibCallName = "__atomic_fetch_add";
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, MemTy,
+ AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, LoweredMemTy,
E->getExprLoc());
break;
// T __atomic_fetch_and_N(T *mem, T val, int order)
@@ -552,7 +691,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
case AtomicExpr::AO__c11_atomic_fetch_sub:
case AtomicExpr::AO__atomic_fetch_sub:
LibCallName = "__atomic_fetch_sub";
- AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, MemTy,
+ AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1, LoweredMemTy,
E->getExprLoc());
break;
// T __atomic_fetch_xor_N(T *mem, T val, int order)
@@ -593,7 +732,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
if (!RetTy->isVoidType())
return Res;
if (E->getType()->isVoidType())
- return RValue::get(0);
+ return RValue::get(nullptr);
return convertTempToRValue(Dest, E->getType(), E->getExprLoc());
}
@@ -615,32 +754,32 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
if (isa<llvm::ConstantInt>(Order)) {
int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
switch (ord) {
- case AO_ABI_memory_order_relaxed:
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Monotonic);
+ case AtomicExpr::AO_ABI_memory_order_relaxed:
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail,
+ Size, Align, llvm::Monotonic);
break;
- case AO_ABI_memory_order_consume:
- case AO_ABI_memory_order_acquire:
+ case AtomicExpr::AO_ABI_memory_order_consume:
+ case AtomicExpr::AO_ABI_memory_order_acquire:
if (IsStore)
break; // Avoid crashing on code with undefined behavior
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Acquire);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail,
+ Size, Align, llvm::Acquire);
break;
- case AO_ABI_memory_order_release:
+ case AtomicExpr::AO_ABI_memory_order_release:
if (IsLoad)
break; // Avoid crashing on code with undefined behavior
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Release);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail,
+ Size, Align, llvm::Release);
break;
- case AO_ABI_memory_order_acq_rel:
+ case AtomicExpr::AO_ABI_memory_order_acq_rel:
if (IsLoad || IsStore)
break; // Avoid crashing on code with undefined behavior
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::AcquireRelease);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail,
+ Size, Align, llvm::AcquireRelease);
break;
- case AO_ABI_memory_order_seq_cst:
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::SequentiallyConsistent);
+ case AtomicExpr::AO_ABI_memory_order_seq_cst:
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail,
+ Size, Align, llvm::SequentiallyConsistent);
break;
default: // invalid order
// We should not ever get here normally, but it's hard to
@@ -648,15 +787,16 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
break;
}
if (E->getType()->isVoidType())
- return RValue::get(0);
+ return RValue::get(nullptr);
return convertTempToRValue(OrigDest, E->getType(), E->getExprLoc());
}
// Long case, when Order isn't obviously constant.
// Create all the relevant BB's
- llvm::BasicBlock *MonotonicBB = 0, *AcquireBB = 0, *ReleaseBB = 0,
- *AcqRelBB = 0, *SeqCstBB = 0;
+ llvm::BasicBlock *MonotonicBB = nullptr, *AcquireBB = nullptr,
+ *ReleaseBB = nullptr, *AcqRelBB = nullptr,
+ *SeqCstBB = nullptr;
MonotonicBB = createBasicBlock("monotonic", CurFn);
if (!IsStore)
AcquireBB = createBasicBlock("acquire", CurFn);
@@ -676,41 +816,46 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
// Emit all the different atomics
Builder.SetInsertPoint(MonotonicBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Monotonic);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail,
+ Size, Align, llvm::Monotonic);
Builder.CreateBr(ContBB);
if (!IsStore) {
Builder.SetInsertPoint(AcquireBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Acquire);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail,
+ Size, Align, llvm::Acquire);
Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(1), AcquireBB);
- SI->addCase(Builder.getInt32(2), AcquireBB);
+ SI->addCase(Builder.getInt32(AtomicExpr::AO_ABI_memory_order_consume),
+ AcquireBB);
+ SI->addCase(Builder.getInt32(AtomicExpr::AO_ABI_memory_order_acquire),
+ AcquireBB);
}
if (!IsLoad) {
Builder.SetInsertPoint(ReleaseBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Release);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail,
+ Size, Align, llvm::Release);
Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(3), ReleaseBB);
+ SI->addCase(Builder.getInt32(AtomicExpr::AO_ABI_memory_order_release),
+ ReleaseBB);
}
if (!IsLoad && !IsStore) {
Builder.SetInsertPoint(AcqRelBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::AcquireRelease);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail,
+ Size, Align, llvm::AcquireRelease);
Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(4), AcqRelBB);
+ SI->addCase(Builder.getInt32(AtomicExpr::AO_ABI_memory_order_acq_rel),
+ AcqRelBB);
}
Builder.SetInsertPoint(SeqCstBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::SequentiallyConsistent);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail,
+ Size, Align, llvm::SequentiallyConsistent);
Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(5), SeqCstBB);
+ SI->addCase(Builder.getInt32(AtomicExpr::AO_ABI_memory_order_seq_cst),
+ SeqCstBB);
// Cleanup and return
Builder.SetInsertPoint(ContBB);
if (E->getType()->isVoidType())
- return RValue::get(0);
+ return RValue::get(nullptr);
return convertTempToRValue(OrigDest, E->getType(), E->getExprLoc());
}
@@ -761,8 +906,8 @@ RValue CodeGenFunction::EmitAtomicLoad(LValue src, SourceLocation loc,
getContext().VoidPtrTy);
args.add(RValue::get(EmitCastToVoidPtr(tempAddr)),
getContext().VoidPtrTy);
- args.add(RValue::get(llvm::ConstantInt::get(IntTy,
- AO_ABI_memory_order_seq_cst)),
+ args.add(RValue::get(llvm::ConstantInt::get(
+ IntTy, AtomicExpr::AO_ABI_memory_order_seq_cst)),
getContext().IntTy);
emitAtomicLibcall(*this, "__atomic_load", getContext().VoidTy, args);
@@ -788,7 +933,7 @@ RValue CodeGenFunction::EmitAtomicLoad(LValue src, SourceLocation loc,
// If we're ignoring an aggregate return, don't do anything.
if (atomics.getEvaluationKind() == TEK_Aggregate && resultSlot.isIgnored())
- return RValue::getAggregate(0, false);
+ return RValue::getAggregate(nullptr, false);
// The easiest way to do this this is to go through memory, but we
// try not to in some easy cases.
@@ -911,8 +1056,8 @@ void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest, bool isInit) {
getContext().VoidPtrTy);
args.add(RValue::get(EmitCastToVoidPtr(srcAddr)),
getContext().VoidPtrTy);
- args.add(RValue::get(llvm::ConstantInt::get(IntTy,
- AO_ABI_memory_order_seq_cst)),
+ args.add(RValue::get(llvm::ConstantInt::get(
+ IntTy, AtomicExpr::AO_ABI_memory_order_seq_cst)),
getContext().IntTy);
emitAtomicLibcall(*this, "__atomic_store", getContext().VoidTy, args);
return;
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 692f9a0dd63f..72fde9dc55f1 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -18,9 +18,9 @@
#include "CodeGenModule.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/IR/CallSite.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Module.h"
-#include "llvm/Support/CallSite.h"
#include <algorithm>
#include <cstdio>
@@ -30,9 +30,9 @@ using namespace CodeGen;
CGBlockInfo::CGBlockInfo(const BlockDecl *block, StringRef name)
: Name(name), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false),
HasCXXObject(false), UsesStret(false), HasCapturedVariableLayout(false),
- StructureType(0), Block(block),
- DominatingIP(0) {
-
+ StructureType(nullptr), Block(block),
+ DominatingIP(nullptr) {
+
// Skip asm prefix, if any. 'name' is usually taken directly from
// the mangled name of the enclosing function.
if (!name.empty() && name[0] == '\01')
@@ -53,7 +53,7 @@ static llvm::Constant *buildCopyHelper(CodeGenModule &CGM,
return CodeGenFunction(CGM).GenerateCopyHelperFunction(blockInfo);
}
-/// Build the helper function to dipose of a block.
+/// Build the helper function to dispose of a block.
static llvm::Constant *buildDisposeHelper(CodeGenModule &CGM,
const CGBlockInfo &blockInfo) {
return CodeGenFunction(CGM).GenerateDestroyHelperFunction(blockInfo);
@@ -78,7 +78,13 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM,
ASTContext &C = CGM.getContext();
llvm::Type *ulong = CGM.getTypes().ConvertType(C.UnsignedLongTy);
- llvm::Type *i8p = CGM.getTypes().ConvertType(C.VoidPtrTy);
+ llvm::Type *i8p = NULL;
+ if (CGM.getLangOpts().OpenCL)
+ i8p =
+ llvm::Type::getInt8PtrTy(
+ CGM.getLLVMContext(), C.getTargetAddressSpace(LangAS::opencl_constant));
+ else
+ i8p = CGM.getTypes().ConvertType(C.VoidPtrTy);
SmallVector<llvm::Constant*, 6> elements;
@@ -246,7 +252,7 @@ static bool isSafeForCXXConstantCapture(QualType type) {
// Only records can be unsafe.
if (!recordType) return true;
- const CXXRecordDecl *record = cast<CXXRecordDecl>(recordType->getDecl());
+ const auto *record = cast<CXXRecordDecl>(recordType->getDecl());
// Maintain semantics for classes with non-trivial dtors or copy ctors.
if (!record->hasTrivialDestructor()) return false;
@@ -269,7 +275,7 @@ static llvm::Constant *tryCaptureAsConstant(CodeGenModule &CGM,
QualType type = var->getType();
// We can only do this if the variable is const.
- if (!type.isConstQualified()) return 0;
+ if (!type.isConstQualified()) return nullptr;
// Furthermore, in C++ we have to worry about mutable fields:
// C++ [dcl.type.cv]p4:
@@ -277,13 +283,13 @@ static llvm::Constant *tryCaptureAsConstant(CodeGenModule &CGM,
// modified, any attempt to modify a const object during its
// lifetime results in undefined behavior.
if (CGM.getLangOpts().CPlusPlus && !isSafeForCXXConstantCapture(type))
- return 0;
+ return nullptr;
// If the variable doesn't have any initializer (shouldn't this be
// invalid?), it's not clear what we should do. Maybe capture as
// zero?
const Expr *init = var->getInit();
- if (!init) return 0;
+ if (!init) return nullptr;
return CGM.EmitConstantInit(*var, CGF);
}
@@ -300,8 +306,8 @@ static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info,
// The header is basically a 'struct { void *; int; int; void *; void *; }'.
CharUnits ptrSize, ptrAlign, intSize, intAlign;
- llvm::tie(ptrSize, ptrAlign) = C.getTypeInfoInChars(C.VoidPtrTy);
- llvm::tie(intSize, intAlign) = C.getTypeInfoInChars(C.IntTy);
+ std::tie(ptrSize, ptrAlign) = C.getTypeInfoInChars(C.VoidPtrTy);
+ std::tie(intSize, intAlign) = C.getTypeInfoInChars(C.IntTy);
// Are there crazy embedded platforms where this isn't true?
assert(intSize <= ptrSize && "layout assumptions horribly violated");
@@ -366,15 +372,14 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
layout.push_back(BlockLayoutChunk(tinfo.second, tinfo.first,
Qualifiers::OCL_None,
- 0, llvmType));
+ nullptr, llvmType));
}
// Next, all the block captures.
- for (BlockDecl::capture_const_iterator ci = block->capture_begin(),
- ce = block->capture_end(); ci != ce; ++ci) {
- const VarDecl *variable = ci->getVariable();
+ for (const auto &CI : block->captures()) {
+ const VarDecl *variable = CI.getVariable();
- if (ci->isByRef()) {
+ if (CI.isByRef()) {
// We have to copy/dispose of the __block reference.
info.NeedsCopyDispose = true;
@@ -387,8 +392,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
maxFieldAlign = std::max(maxFieldAlign, tinfo.second);
layout.push_back(BlockLayoutChunk(tinfo.second, tinfo.first,
- Qualifiers::OCL_None,
- &*ci, llvmType));
+ Qualifiers::OCL_None, &CI, llvmType));
continue;
}
@@ -422,7 +426,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
lifetime = Qualifiers::OCL_Strong;
// So do types that require non-trivial copy construction.
- } else if (ci->hasCopyExpr()) {
+ } else if (CI.hasCopyExpr()) {
info.NeedsCopyDispose = true;
info.HasCXXObject = true;
@@ -446,7 +450,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
llvm::Type *llvmType =
CGM.getTypes().ConvertTypeForMem(VT);
- layout.push_back(BlockLayoutChunk(align, size, lifetime, &*ci, llvmType));
+ layout.push_back(BlockLayoutChunk(align, size, lifetime, &CI, llvmType));
}
// If that was everything, we're done here.
@@ -581,14 +585,13 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) {
// Walk through the captures (in order) and find the ones not
// captured by constant.
- for (BlockDecl::capture_const_iterator ci = block->capture_begin(),
- ce = block->capture_end(); ci != ce; ++ci) {
+ for (const auto &CI : block->captures()) {
// Ignore __block captures; there's nothing special in the
// on-stack block that we need to do for them.
- if (ci->isByRef()) continue;
+ if (CI.isByRef()) continue;
// Ignore variables that are constant-captured.
- const VarDecl *variable = ci->getVariable();
+ const VarDecl *variable = CI.getVariable();
CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
if (capture.isConstant()) continue;
@@ -664,7 +667,7 @@ void CodeGenFunction::destroyBlockInfos(CGBlockInfo *head) {
CGBlockInfo *cur = head;
head = cur->NextBlockInfo;
delete cur;
- } while (head != 0);
+ } while (head != nullptr);
}
/// Emit a block literal expression in the current function.
@@ -679,7 +682,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
}
// Find the block info for this block and take ownership of it.
- OwningPtr<CGBlockInfo> blockInfo;
+ std::unique_ptr<CGBlockInfo> blockInfo;
blockInfo.reset(findAndRemoveBlockInfo(&FirstBlockInfo,
blockExpr->getBlockDecl()));
@@ -741,9 +744,8 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
}
// Next, captured variables.
- for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(),
- ce = blockDecl->capture_end(); ci != ce; ++ci) {
- const VarDecl *variable = ci->getVariable();
+ for (const auto &CI : blockDecl->captures()) {
+ const VarDecl *variable = CI.getVariable();
const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
// Ignore constant captures.
@@ -761,7 +763,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
// Compute the address of the thing we're going to move into the
// block literal.
llvm::Value *src;
- if (BlockInfo && ci->isNested()) {
+ if (BlockInfo && CI.isNested()) {
// We need to use the capture from the enclosing block.
const CGBlockInfo::Capture &enclosingCapture =
BlockInfo->getCapture(variable);
@@ -773,15 +775,15 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
} else if (blockDecl->isConversionFromLambda()) {
// The lambda capture in a lambda's conversion-to-block-pointer is
// special; we'll simply emit it directly.
- src = 0;
+ src = nullptr;
} else {
// Just look it up in the locals map, which will give us back a
// [[type]]*. If that doesn't work, do the more elaborate DRE
// emission.
src = LocalDeclMap.lookup(variable);
if (!src) {
- DeclRefExpr declRef(const_cast<VarDecl*>(variable),
- /*refersToEnclosing*/ ci->isNested(), type,
+ DeclRefExpr declRef(const_cast<VarDecl *>(variable),
+ /*refersToEnclosing*/ CI.isNested(), type,
VK_LValue, SourceLocation());
src = EmitDeclRefLValue(&declRef).getAddress();
}
@@ -791,9 +793,9 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
// the block field. There's no need to chase the forwarding
// pointer at this point, since we're building something that will
// live a shorter life than the stack byref anyway.
- if (ci->isByRef()) {
+ if (CI.isByRef()) {
// Get a void* that points to the byref struct.
- if (ci->isNested())
+ if (CI.isNested())
src = Builder.CreateAlignedLoad(src, align.getQuantity(),
"byref.capture");
else
@@ -803,7 +805,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
Builder.CreateAlignedStore(src, blockField, align.getQuantity());
// If we have a copy constructor, evaluate that into the block field.
- } else if (const Expr *copyExpr = ci->getCopyExpr()) {
+ } else if (const Expr *copyExpr = CI.getCopyExpr()) {
if (blockDecl->isConversionFromLambda()) {
// If we have a lambda conversion, emit the expression
// directly into the block instead.
@@ -845,13 +847,14 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
} 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);
+ ImplicitParamDecl blockFieldPseudoVar(getContext(), /*DC*/ nullptr,
+ SourceLocation(), /*name*/ nullptr,
+ type);
// We use one of these or the other depending on whether the
// reference is nested.
DeclRefExpr declRef(const_cast<VarDecl*>(variable),
- /*refersToEnclosing*/ ci->isNested(), type,
+ /*refersToEnclosing*/ CI.isNested(), type,
VK_LValue, SourceLocation());
ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, type, CK_LValueToRValue,
@@ -862,7 +865,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
}
// Activate the cleanup if layout pushed one.
- if (!ci->isByRef()) {
+ if (!CI.isByRef()) {
EHScopeStack::stable_iterator cleanup = capture.getCleanup();
if (cleanup.isValid())
ActivateCleanupBlock(cleanup, blockInfo.DominatingIP);
@@ -1023,7 +1026,7 @@ CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *blockExpr,
blockInfo.BlockExpression = blockExpr;
// Compute information about the layout, etc., of this block.
- computeBlockInfo(*this, 0, blockInfo);
+ computeBlockInfo(*this, nullptr, blockInfo);
// Using that metadata, generate the actual block function.
llvm::Constant *blockFn;
@@ -1097,7 +1100,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
// to be local to this function as well, in case they're directly
// referenced in a block.
for (DeclMapTy::const_iterator i = ldm.begin(), e = ldm.end(); i != e; ++i) {
- const VarDecl *var = dyn_cast<VarDecl>(i->first);
+ const auto *var = dyn_cast<VarDecl>(i->first);
if (var && !var->hasLocalStorage())
LocalDeclMap[var] = i->second;
}
@@ -1112,35 +1115,32 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
QualType selfTy = getContext().VoidPtrTy;
IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor");
- ImplicitParamDecl selfDecl(const_cast<BlockDecl*>(blockDecl),
+ ImplicitParamDecl selfDecl(getContext(), const_cast<BlockDecl*>(blockDecl),
SourceLocation(), II, selfTy);
args.push_back(&selfDecl);
// Now add the rest of the parameters.
- for (BlockDecl::param_const_iterator i = blockDecl->param_begin(),
- e = blockDecl->param_end(); i != e; ++i)
- args.push_back(*i);
+ for (auto i : blockDecl->params())
+ args.push_back(i);
// Create the function declaration.
const FunctionProtoType *fnType = blockInfo.getBlockExpr()->getFunctionType();
- const CGFunctionInfo &fnInfo =
- CGM.getTypes().arrangeFunctionDeclaration(fnType->getResultType(), args,
- fnType->getExtInfo(),
- fnType->isVariadic());
- if (CGM.ReturnTypeUsesSRet(fnInfo))
+ const CGFunctionInfo &fnInfo = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ fnType->getReturnType(), args, fnType->getExtInfo(),
+ fnType->isVariadic());
+ if (CGM.ReturnSlotInterferesWithArgs(fnInfo))
blockInfo.UsesStret = true;
llvm::FunctionType *fnLLVMType = CGM.getTypes().GetFunctionType(fnInfo);
- MangleBuffer name;
- CGM.getBlockMangledName(GD, name, blockDecl);
- llvm::Function *fn =
- llvm::Function::Create(fnLLVMType, llvm::GlobalValue::InternalLinkage,
- name.getString(), &CGM.getModule());
+ StringRef name = CGM.getBlockMangledName(GD, blockDecl);
+ llvm::Function *fn = llvm::Function::Create(
+ fnLLVMType, llvm::GlobalValue::InternalLinkage, name, &CGM.getModule());
CGM.SetInternalFunctionAttributes(blockDecl, fn, fnInfo);
// Begin generating the function.
- StartFunction(blockDecl, fnType->getResultType(), fn, fnInfo, args,
+ StartFunction(blockDecl, fnType->getReturnType(), fn, fnInfo, args,
+ blockDecl->getLocation(),
blockInfo.getBlockExpr()->getBody()->getLocStart());
// Okay. Undo some of what StartFunction did.
@@ -1177,9 +1177,8 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
}
// Also force all the constant captures.
- for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(),
- ce = blockDecl->capture_end(); ci != ce; ++ci) {
- const VarDecl *variable = ci->getVariable();
+ for (const auto &CI : blockDecl->captures()) {
+ const VarDecl *variable = CI.getVariable();
const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
if (!capture.isConstant()) continue;
@@ -1201,8 +1200,14 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
if (IsLambdaConversionToBlock)
EmitLambdaBlockInvokeBody();
- else
+ else {
+ PGO.assignRegionCounters(blockDecl, fn);
+ RegionCounter Cnt = getPGORegionCounter(blockDecl->getBody());
+ Cnt.beginRegion(Builder);
EmitStmt(blockDecl->getBody());
+ PGO.emitInstrumentationData();
+ PGO.destroyRegionCounters();
+ }
// Remember where we were...
llvm::BasicBlock *resume = Builder.GetInsertBlock();
@@ -1214,9 +1219,8 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
// Emit debug information for all the DeclRefExprs.
// FIXME: also for 'this'
if (CGDebugInfo *DI = getDebugInfo()) {
- for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(),
- ce = blockDecl->capture_end(); ci != ce; ++ci) {
- const VarDecl *variable = ci->getVariable();
+ for (const auto &CI : blockDecl->captures()) {
+ const VarDecl *variable = CI.getVariable();
DI->EmitLocation(Builder, variable->getLocation());
if (CGM.getCodeGenOpts().getDebugInfo()
@@ -1238,7 +1242,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
}
// And resume where we left off.
- if (resume == 0)
+ if (resume == nullptr)
Builder.ClearInsertionPoint();
else
Builder.SetInsertPoint(resume);
@@ -1280,15 +1284,15 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
ASTContext &C = getContext();
FunctionArgList args;
- ImplicitParamDecl dstDecl(0, SourceLocation(), 0, C.VoidPtrTy);
+ ImplicitParamDecl dstDecl(getContext(), nullptr, SourceLocation(), nullptr,
+ C.VoidPtrTy);
args.push_back(&dstDecl);
- ImplicitParamDecl srcDecl(0, SourceLocation(), 0, C.VoidPtrTy);
+ ImplicitParamDecl srcDecl(getContext(), nullptr, SourceLocation(), nullptr,
+ C.VoidPtrTy);
args.push_back(&srcDecl);
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeFunctionDeclaration(C.VoidTy, args,
- FunctionType::ExtInfo(),
- /*variadic*/ false);
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ C.VoidTy, args, FunctionType::ExtInfo(), /*variadic=*/false);
// FIXME: it would be nice if these were mergeable with things with
// identical semantics.
@@ -1304,13 +1308,13 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
FunctionDecl *FD = FunctionDecl::Create(C,
C.getTranslationUnitDecl(),
SourceLocation(),
- SourceLocation(), II, C.VoidTy, 0,
- SC_Static,
+ SourceLocation(), II, C.VoidTy,
+ nullptr, SC_Static,
false,
false);
// Create a scope with an artificial location for the body of this function.
ArtificialLocation AL(*this, Builder);
- StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
+ StartFunction(FD, C.VoidTy, Fn, FI, args);
AL.Emit();
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
@@ -1325,25 +1329,24 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
const BlockDecl *blockDecl = blockInfo.getBlockDecl();
- for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(),
- ce = blockDecl->capture_end(); ci != ce; ++ci) {
- const VarDecl *variable = ci->getVariable();
+ for (const auto &CI : blockDecl->captures()) {
+ const VarDecl *variable = CI.getVariable();
QualType type = variable->getType();
const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
if (capture.isConstant()) continue;
- const Expr *copyExpr = ci->getCopyExpr();
+ const Expr *copyExpr = CI.getCopyExpr();
BlockFieldFlags flags;
bool useARCWeakCopy = false;
bool useARCStrongCopy = false;
if (copyExpr) {
- assert(!ci->isByRef());
+ assert(!CI.isByRef());
// don't bother computing flags
- } else if (ci->isByRef()) {
+ } else if (CI.isByRef()) {
flags = BLOCK_FIELD_IS_BYREF;
if (type.isObjCGCWeak())
flags |= BLOCK_FIELD_IS_WEAK;
@@ -1400,7 +1403,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
// storeStrong doesn't over-release) and then call storeStrong.
// This is a workaround to not having an initStrong call.
if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
- llvm::PointerType *ty = cast<llvm::PointerType>(srcValue->getType());
+ auto *ty = cast<llvm::PointerType>(srcValue->getType());
llvm::Value *null = llvm::ConstantPointerNull::get(ty);
Builder.CreateStore(null, dstField);
EmitARCStoreStrongCall(dstField, srcValue, true);
@@ -1423,7 +1426,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
};
bool copyCanThrow = false;
- if (ci->isByRef() && variable->getType()->getAsCXXRecordDecl()) {
+ if (CI.isByRef() && variable->getType()->getAsCXXRecordDecl()) {
const Expr *copyExpr =
CGM.getContext().getBlockVarCopyInits(variable);
if (copyExpr) {
@@ -1457,13 +1460,12 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
ASTContext &C = getContext();
FunctionArgList args;
- ImplicitParamDecl srcDecl(0, SourceLocation(), 0, C.VoidPtrTy);
+ ImplicitParamDecl srcDecl(getContext(), nullptr, SourceLocation(), nullptr,
+ C.VoidPtrTy);
args.push_back(&srcDecl);
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeFunctionDeclaration(C.VoidTy, args,
- FunctionType::ExtInfo(),
- /*variadic*/ false);
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ C.VoidTy, args, FunctionType::ExtInfo(), /*variadic=*/false);
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
@@ -1478,12 +1480,12 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
FunctionDecl *FD = FunctionDecl::Create(C, C.getTranslationUnitDecl(),
SourceLocation(),
- SourceLocation(), II, C.VoidTy, 0,
- SC_Static,
+ SourceLocation(), II, C.VoidTy,
+ nullptr, SC_Static,
false, false);
// Create a scope with an artificial location for the body of this function.
ArtificialLocation AL(*this, Builder);
- StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
+ StartFunction(FD, C.VoidTy, Fn, FI, args);
AL.Emit();
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
@@ -1496,21 +1498,20 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
CodeGenFunction::RunCleanupsScope cleanups(*this);
- for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(),
- ce = blockDecl->capture_end(); ci != ce; ++ci) {
- const VarDecl *variable = ci->getVariable();
+ for (const auto &CI : blockDecl->captures()) {
+ const VarDecl *variable = CI.getVariable();
QualType type = variable->getType();
const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
if (capture.isConstant()) continue;
BlockFieldFlags flags;
- const CXXDestructorDecl *dtor = 0;
+ const CXXDestructorDecl *dtor = nullptr;
bool useARCWeakDestroy = false;
bool useARCStrongDestroy = false;
- if (ci->isByRef()) {
+ if (CI.isByRef()) {
flags = BLOCK_FIELD_IS_BYREF;
if (type.isObjCGCWeak())
flags |= BLOCK_FIELD_IS_WEAK;
@@ -1587,7 +1588,7 @@ public:
: ByrefHelpers(alignment), Flags(flags) {}
void emitCopy(CodeGenFunction &CGF, llvm::Value *destField,
- llvm::Value *srcField) {
+ llvm::Value *srcField) override {
destField = CGF.Builder.CreateBitCast(destField, CGF.VoidPtrTy);
srcField = CGF.Builder.CreateBitCast(srcField, CGF.VoidPtrPtrTy);
@@ -1602,14 +1603,14 @@ public:
CGF.EmitNounwindRuntimeCall(fn, args);
}
- void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
+ void emitDispose(CodeGenFunction &CGF, llvm::Value *field) override {
field = CGF.Builder.CreateBitCast(field, CGF.Int8PtrTy->getPointerTo(0));
llvm::Value *value = CGF.Builder.CreateLoad(field);
CGF.BuildBlockRelease(value, Flags | BLOCK_BYREF_CALLER);
}
- void profileImpl(llvm::FoldingSetNodeID &id) const {
+ void profileImpl(llvm::FoldingSetNodeID &id) const override {
id.AddInteger(Flags.getBitMask());
}
};
@@ -1620,15 +1621,15 @@ public:
ARCWeakByrefHelpers(CharUnits alignment) : ByrefHelpers(alignment) {}
void emitCopy(CodeGenFunction &CGF, llvm::Value *destField,
- llvm::Value *srcField) {
+ llvm::Value *srcField) override {
CGF.EmitARCMoveWeak(destField, srcField);
}
- void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
+ void emitDispose(CodeGenFunction &CGF, llvm::Value *field) override {
CGF.EmitARCDestroyWeak(field);
}
- void profileImpl(llvm::FoldingSetNodeID &id) const {
+ void profileImpl(llvm::FoldingSetNodeID &id) const override {
// 0 is distinguishable from all pointers and byref flags
id.AddInteger(0);
}
@@ -1641,7 +1642,7 @@ public:
ARCStrongByrefHelpers(CharUnits alignment) : ByrefHelpers(alignment) {}
void emitCopy(CodeGenFunction &CGF, llvm::Value *destField,
- llvm::Value *srcField) {
+ llvm::Value *srcField) override {
// Do a "move" by copying the value and then zeroing out the old
// variable.
@@ -1665,11 +1666,11 @@ public:
store->setAlignment(Alignment.getQuantity());
}
- void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
+ void emitDispose(CodeGenFunction &CGF, llvm::Value *field) override {
CGF.EmitARCDestroyStrong(field, ARCImpreciseLifetime);
}
- void profileImpl(llvm::FoldingSetNodeID &id) const {
+ void profileImpl(llvm::FoldingSetNodeID &id) const override {
// 1 is distinguishable from all pointers and byref flags
id.AddInteger(1);
}
@@ -1682,7 +1683,7 @@ public:
ARCStrongBlockByrefHelpers(CharUnits alignment) : ByrefHelpers(alignment) {}
void emitCopy(CodeGenFunction &CGF, llvm::Value *destField,
- llvm::Value *srcField) {
+ llvm::Value *srcField) override {
// Do the copy with objc_retainBlock; that's all that
// _Block_object_assign would do anyway, and we'd have to pass the
// right arguments to make sure it doesn't get no-op'ed.
@@ -1695,11 +1696,11 @@ public:
store->setAlignment(Alignment.getQuantity());
}
- void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
+ void emitDispose(CodeGenFunction &CGF, llvm::Value *field) override {
CGF.EmitARCDestroyStrong(field, ARCImpreciseLifetime);
}
- void profileImpl(llvm::FoldingSetNodeID &id) const {
+ void profileImpl(llvm::FoldingSetNodeID &id) const override {
// 2 is distinguishable from all pointers and byref flags
id.AddInteger(2);
}
@@ -1716,20 +1717,20 @@ public:
const Expr *copyExpr)
: ByrefHelpers(alignment), VarType(type), CopyExpr(copyExpr) {}
- bool needsCopy() const { return CopyExpr != 0; }
+ bool needsCopy() const override { return CopyExpr != nullptr; }
void emitCopy(CodeGenFunction &CGF, llvm::Value *destField,
- llvm::Value *srcField) {
+ llvm::Value *srcField) override {
if (!CopyExpr) return;
CGF.EmitSynthesizedCXXCopyCtor(destField, srcField, CopyExpr);
}
- void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
+ void emitDispose(CodeGenFunction &CGF, llvm::Value *field) override {
EHScopeStack::stable_iterator cleanupDepth = CGF.EHStack.stable_begin();
CGF.PushDestructorCleanup(VarType, field);
CGF.PopCleanupBlocks(cleanupDepth);
}
- void profileImpl(llvm::FoldingSetNodeID &id) const {
+ void profileImpl(llvm::FoldingSetNodeID &id) const override {
id.AddPointer(VarType.getCanonicalType().getAsOpaquePtr());
}
};
@@ -1745,16 +1746,16 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
QualType R = Context.VoidTy;
FunctionArgList args;
- ImplicitParamDecl dst(0, SourceLocation(), 0, Context.VoidPtrTy);
+ ImplicitParamDecl dst(CGF.getContext(), nullptr, SourceLocation(), nullptr,
+ Context.VoidPtrTy);
args.push_back(&dst);
- ImplicitParamDecl src(0, SourceLocation(), 0, Context.VoidPtrTy);
+ ImplicitParamDecl src(CGF.getContext(), nullptr, SourceLocation(), nullptr,
+ Context.VoidPtrTy);
args.push_back(&src);
- const CGFunctionInfo &FI =
- CGF.CGM.getTypes().arrangeFunctionDeclaration(R, args,
- FunctionType::ExtInfo(),
- /*variadic*/ false);
+ const CGFunctionInfo &FI = CGF.CGM.getTypes().arrangeFreeFunctionDeclaration(
+ R, args, FunctionType::ExtInfo(), /*variadic=*/false);
CodeGenTypes &Types = CGF.CGM.getTypes();
llvm::FunctionType *LTy = Types.GetFunctionType(FI);
@@ -1771,11 +1772,11 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
FunctionDecl *FD = FunctionDecl::Create(Context,
Context.getTranslationUnitDecl(),
SourceLocation(),
- SourceLocation(), II, R, 0,
+ SourceLocation(), II, R, nullptr,
SC_Static,
false, false);
- CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
+ CGF.StartFunction(FD, R, Fn, FI, args);
if (byrefInfo.needsCopy()) {
llvm::Type *byrefPtrType = byrefType.getPointerTo(0);
@@ -1819,13 +1820,12 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
QualType R = Context.VoidTy;
FunctionArgList args;
- ImplicitParamDecl src(0, SourceLocation(), 0, Context.VoidPtrTy);
+ ImplicitParamDecl src(CGF.getContext(), nullptr, SourceLocation(), nullptr,
+ Context.VoidPtrTy);
args.push_back(&src);
- const CGFunctionInfo &FI =
- CGF.CGM.getTypes().arrangeFunctionDeclaration(R, args,
- FunctionType::ExtInfo(),
- /*variadic*/ false);
+ const CGFunctionInfo &FI = CGF.CGM.getTypes().arrangeFreeFunctionDeclaration(
+ R, args, FunctionType::ExtInfo(), /*variadic=*/false);
CodeGenTypes &Types = CGF.CGM.getTypes();
llvm::FunctionType *LTy = Types.GetFunctionType(FI);
@@ -1843,10 +1843,10 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
FunctionDecl *FD = FunctionDecl::Create(Context,
Context.getTranslationUnitDecl(),
SourceLocation(),
- SourceLocation(), II, R, 0,
+ SourceLocation(), II, R, nullptr,
SC_Static,
false, false);
- CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
+ CGF.StartFunction(FD, R, Fn, FI, args);
if (byrefInfo.needsDispose()) {
llvm::Value *V = CGF.GetAddrOfLocalVar(&src);
@@ -1913,7 +1913,7 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) {
const Expr *copyExpr = CGM.getContext().getBlockVarCopyInits(&var);
- if (!copyExpr && record->hasTrivialDestructor()) return 0;
+ if (!copyExpr && record->hasTrivialDestructor()) return nullptr;
CXXByrefHelpers byrefInfo(emission.Alignment, type, copyExpr);
return ::buildByrefHelpers(CGM, byrefType, byrefValueIndex, byrefInfo);
@@ -1921,7 +1921,7 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
// 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;
+ if (!type->isObjCRetainableType()) return nullptr;
Qualifiers qs = type.getQualifiers();
@@ -1935,7 +1935,7 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
// These are just bits as far as the runtime is concerned.
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Autoreleasing:
- return 0;
+ return nullptr;
// Tell the runtime that this is ARC __weak, called by the
// byref routines.
@@ -1969,7 +1969,7 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
type->isObjCObjectPointerType()) {
flags |= BLOCK_FIELD_IS_OBJECT;
} else {
- return 0;
+ return nullptr;
}
if (type.isObjCGCWeak())
@@ -2218,7 +2218,7 @@ namespace {
llvm::Value *Addr;
CallBlockRelease(llvm::Value *Addr) : Addr(Addr) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
// Should we be passing FIELD_IS_WEAK here?
CGF.BuildBlockRelease(Addr, BLOCK_FIELD_IS_BYREF);
}
@@ -2242,9 +2242,8 @@ static void configureBlocksRuntimeObject(CodeGenModule &CGM,
llvm::Constant *C) {
if (!CGM.getLangOpts().BlocksRuntimeOptional) return;
- llvm::GlobalValue *GV = cast<llvm::GlobalValue>(C->stripPointerCasts());
- if (GV->isDeclaration() &&
- GV->getLinkage() == llvm::GlobalValue::ExternalLinkage)
+ auto *GV = cast<llvm::GlobalValue>(C->stripPointerCasts());
+ if (GV->isDeclaration() && GV->hasExternalLinkage())
GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
}
@@ -2277,7 +2276,8 @@ llvm::Constant *CodeGenModule::getNSConcreteGlobalBlock() {
return NSConcreteGlobalBlock;
NSConcreteGlobalBlock = GetOrCreateLLVMGlobal("_NSConcreteGlobalBlock",
- Int8PtrTy->getPointerTo(), 0);
+ Int8PtrTy->getPointerTo(),
+ nullptr);
configureBlocksRuntimeObject(*this, NSConcreteGlobalBlock);
return NSConcreteGlobalBlock;
}
@@ -2287,7 +2287,8 @@ llvm::Constant *CodeGenModule::getNSConcreteStackBlock() {
return NSConcreteStackBlock;
NSConcreteStackBlock = GetOrCreateLLVMGlobal("_NSConcreteStackBlock",
- Int8PtrTy->getPointerTo(), 0);
+ Int8PtrTy->getPointerTo(),
+ nullptr);
configureBlocksRuntimeObject(*this, NSConcreteStackBlock);
return NSConcreteStackBlock;
}
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 020638a55810..0031e32c9daf 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -28,15 +28,15 @@
#include "llvm/IR/Module.h"
namespace llvm {
- class Module;
- class Constant;
- class Function;
- class GlobalValue;
- class DataLayout;
- class FunctionType;
- class PointerType;
- class Value;
- class LLVMContext;
+class Module;
+class Constant;
+class Function;
+class GlobalValue;
+class DataLayout;
+class FunctionType;
+class PointerType;
+class Value;
+class LLVMContext;
}
namespace clang {
diff --git a/lib/CodeGen/CGBuilder.h b/lib/CodeGen/CGBuilder.h
index fd21e7e26a3b..f113b970b7b7 100644
--- a/lib/CodeGen/CGBuilder.h
+++ b/lib/CodeGen/CGBuilder.h
@@ -15,12 +15,39 @@
namespace clang {
namespace CodeGen {
+class CodeGenFunction;
+
+/// \brief This is an IRBuilder insertion helper that forwards to
+/// CodeGenFunction::InsertHelper, which adds nesessary metadata to
+/// instructions.
+template <bool PreserveNames>
+class CGBuilderInserter
+ : protected llvm::IRBuilderDefaultInserter<PreserveNames> {
+public:
+ CGBuilderInserter() : CGF(nullptr) {}
+ explicit CGBuilderInserter(CodeGenFunction *CGF) : CGF(CGF) {}
+
+protected:
+ /// \brief This forwards to CodeGenFunction::InsertHelper.
+ void InsertHelper(llvm::Instruction *I, const llvm::Twine &Name,
+ llvm::BasicBlock *BB,
+ llvm::BasicBlock::iterator InsertPt) const;
+private:
+ void operator=(const CGBuilderInserter &) LLVM_DELETED_FUNCTION;
+
+ CodeGenFunction *CGF;
+};
+
// Don't preserve names on values in an optimized build.
#ifdef NDEBUG
-typedef llvm::IRBuilder<false> CGBuilderTy;
+#define PreserveNames false
#else
-typedef llvm::IRBuilder<> CGBuilderTy;
+#define PreserveNames true
#endif
+typedef CGBuilderInserter<PreserveNames> CGBuilderInserterTy;
+typedef llvm::IRBuilder<PreserveNames, llvm::ConstantFolder,
+ CGBuilderInserterTy> CGBuilderTy;
+#undef PreserveNames
} // end namespace CodeGen
} // end namespace clang
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 7726ad309d8a..4f68b347dbf0 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -212,11 +212,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
default: break; // Handle intrinsics and libm functions below.
case Builtin::BI__builtin___CFStringMakeConstantString:
case Builtin::BI__builtin___NSStringMakeConstantString:
- return RValue::get(CGM.EmitConstantExpr(E, E->getType(), 0));
+ return RValue::get(CGM.EmitConstantExpr(E, E->getType(), nullptr));
case Builtin::BI__builtin_stdarg_start:
case Builtin::BI__builtin_va_start:
+ case Builtin::BI__va_start:
case Builtin::BI__builtin_va_end: {
- Value *ArgValue = EmitVAListRef(E->getArg(0));
+ Value *ArgValue = (BuiltinID == Builtin::BI__va_start)
+ ? EmitScalarExpr(E->getArg(0))
+ : EmitVAListRef(E->getArg(0));
llvm::Type *DestType = Int8PtrTy;
if (ArgValue->getType() != DestType)
ArgValue = Builder.CreateBitCast(ArgValue, DestType,
@@ -429,6 +432,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *F = CGM.getIntrinsic(Intrinsic::readcyclecounter);
return RValue::get(Builder.CreateCall(F));
}
+ case Builtin::BI__builtin___clear_cache: {
+ Value *Begin = EmitScalarExpr(E->getArg(0));
+ Value *End = EmitScalarExpr(E->getArg(1));
+ Value *F = CGM.getIntrinsic(Intrinsic::clear_cache);
+ return RValue::get(Builder.CreateCall2(F, Begin, End));
+ }
case Builtin::BI__builtin_trap: {
Value *F = CGM.getIntrinsic(Intrinsic::trap);
return RValue::get(Builder.CreateCall(F));
@@ -438,17 +447,18 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Builder.CreateCall(F));
}
case Builtin::BI__builtin_unreachable: {
- if (SanOpts->Unreachable)
+ if (SanOpts->Unreachable) {
+ SanitizerScope SanScope(this);
EmitCheck(Builder.getFalse(), "builtin_unreachable",
EmitCheckSourceLocation(E->getExprLoc()),
ArrayRef<llvm::Value *>(), CRK_Unrecoverable);
- else
+ } else
Builder.CreateUnreachable();
// We do need to preserve an insertion point.
EmitBlock(createBasicBlock("unreachable.cont"));
- return RValue::get(0);
+ return RValue::get(nullptr);
}
case Builtin::BI__builtin_powi:
@@ -781,7 +791,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// We do need to preserve an insertion point.
EmitBlock(createBasicBlock("builtin_eh_return.cont"));
- return RValue::get(0);
+ return RValue::get(nullptr);
}
case Builtin::BI__builtin_unwind_init: {
Value *F = CGM.getIntrinsic(Intrinsic::eh_unwind_init);
@@ -847,7 +857,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// We do need to preserve an insertion point.
EmitBlock(createBasicBlock("longjmp.cont"));
- return RValue::get(0);
+ return RValue::get(nullptr);
}
case Builtin::BI__sync_fetch_and_add:
case Builtin::BI__sync_fetch_and_sub:
@@ -964,7 +974,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Args[2] = EmitToInt(*this, EmitScalarExpr(E->getArg(2)), T, IntType);
Value *Result = Builder.CreateAtomicCmpXchg(Args[0], Args[1], Args[2],
+ llvm::SequentiallyConsistent,
llvm::SequentiallyConsistent);
+ Result = Builder.CreateExtractValue(Result, 0);
Result = EmitFromInt(*this, Result, T, ValueType);
return RValue::get(Result);
}
@@ -988,10 +1000,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Args[1] = EmitToInt(*this, EmitScalarExpr(E->getArg(1)), T, IntType);
Args[2] = EmitToInt(*this, EmitScalarExpr(E->getArg(2)), T, IntType);
- Value *OldVal = Args[1];
- Value *PrevVal = Builder.CreateAtomicCmpXchg(Args[0], Args[1], Args[2],
- llvm::SequentiallyConsistent);
- Value *Result = Builder.CreateICmpEQ(PrevVal, OldVal);
+ Value *Pair = Builder.CreateAtomicCmpXchg(Args[0], Args[1], Args[2],
+ llvm::SequentiallyConsistent,
+ llvm::SequentiallyConsistent);
+ Value *Result = Builder.CreateExtractValue(Pair, 1);
// zext bool to int.
Result = Builder.CreateZExt(Result, ConvertType(E->getType()));
return RValue::get(Result);
@@ -1026,7 +1038,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Builder.CreateStore(llvm::Constant::getNullValue(ITy), Ptr);
Store->setAlignment(StoreSize.getQuantity());
Store->setAtomic(llvm::Release);
- return RValue::get(0);
+ return RValue::get(nullptr);
}
case Builtin::BI__sync_synchronize: {
@@ -1038,7 +1050,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// to use it with non-atomic loads and stores to get acquire/release
// semantics.
Builder.CreateFence(llvm::SequentiallyConsistent);
- return RValue::get(0);
+ return RValue::get(nullptr);
}
case Builtin::BI__c11_atomic_is_lock_free:
@@ -1079,7 +1091,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *Order = EmitScalarExpr(E->getArg(1));
if (isa<llvm::ConstantInt>(Order)) {
int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
- AtomicRMWInst *Result = 0;
+ AtomicRMWInst *Result = nullptr;
switch (ord) {
case 0: // memory_order_relaxed
default: // invalid order
@@ -1179,7 +1191,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Store->setOrdering(llvm::SequentiallyConsistent);
break;
}
- return RValue::get(0);
+ return RValue::get(nullptr);
}
llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
@@ -1209,7 +1221,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
SI->addCase(Builder.getInt32(5), BBs[2]);
Builder.SetInsertPoint(ContBB);
- return RValue::get(0);
+ return RValue::get(nullptr);
}
case Builtin::BI__atomic_thread_fence:
@@ -1243,7 +1255,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Builder.CreateFence(llvm::SequentiallyConsistent, Scope);
break;
}
- return RValue::get(0);
+ return RValue::get(nullptr);
}
llvm::BasicBlock *AcquireBB, *ReleaseBB, *AcqRelBB, *SeqCstBB;
@@ -1278,7 +1290,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
SI->addCase(Builder.getInt32(5), SeqCstBB);
Builder.SetInsertPoint(ContBB);
- return RValue::get(0);
+ return RValue::get(nullptr);
}
// Library functions with special handling.
@@ -1311,7 +1323,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
llvm::Type *ArgType = Base->getType();
Value *F = CGM.getIntrinsic(Intrinsic::pow, ArgType);
return RValue::get(Builder.CreateCall2(F, Base, Exponent));
- break;
}
case Builtin::BIfma:
@@ -1498,8 +1509,84 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
}
case Builtin::BI__builtin_addressof:
return RValue::get(EmitLValue(E->getArg(0)).getAddress());
+ case Builtin::BI__builtin_operator_new:
+ return EmitBuiltinNewDeleteCall(FD->getType()->castAs<FunctionProtoType>(),
+ E->getArg(0), false);
+ case Builtin::BI__builtin_operator_delete:
+ return EmitBuiltinNewDeleteCall(FD->getType()->castAs<FunctionProtoType>(),
+ E->getArg(0), true);
case Builtin::BI__noop:
- return RValue::get(0);
+ // __noop always evaluates to an integer literal zero.
+ return RValue::get(ConstantInt::get(IntTy, 0));
+ case Builtin::BI__assume:
+ // Until LLVM supports assumptions at the IR level, this becomes nothing.
+ return RValue::get(nullptr);
+ case Builtin::BI_InterlockedExchange:
+ case Builtin::BI_InterlockedExchangePointer:
+ return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Xchg, E);
+ case Builtin::BI_InterlockedCompareExchangePointer: {
+ llvm::Type *RTy;
+ llvm::IntegerType *IntType =
+ IntegerType::get(getLLVMContext(),
+ getContext().getTypeSize(E->getType()));
+ llvm::Type *IntPtrType = IntType->getPointerTo();
+
+ llvm::Value *Destination =
+ Builder.CreateBitCast(EmitScalarExpr(E->getArg(0)), IntPtrType);
+
+ llvm::Value *Exchange = EmitScalarExpr(E->getArg(1));
+ RTy = Exchange->getType();
+ Exchange = Builder.CreatePtrToInt(Exchange, IntType);
+
+ llvm::Value *Comparand =
+ Builder.CreatePtrToInt(EmitScalarExpr(E->getArg(2)), IntType);
+
+ auto Result = Builder.CreateAtomicCmpXchg(Destination, Comparand, Exchange,
+ SequentiallyConsistent,
+ SequentiallyConsistent);
+ Result->setVolatile(true);
+
+ return RValue::get(Builder.CreateIntToPtr(Builder.CreateExtractValue(Result,
+ 0),
+ RTy));
+ }
+ case Builtin::BI_InterlockedCompareExchange: {
+ AtomicCmpXchgInst *CXI = Builder.CreateAtomicCmpXchg(
+ EmitScalarExpr(E->getArg(0)),
+ EmitScalarExpr(E->getArg(2)),
+ EmitScalarExpr(E->getArg(1)),
+ SequentiallyConsistent,
+ SequentiallyConsistent);
+ CXI->setVolatile(true);
+ return RValue::get(Builder.CreateExtractValue(CXI, 0));
+ }
+ case Builtin::BI_InterlockedIncrement: {
+ AtomicRMWInst *RMWI = Builder.CreateAtomicRMW(
+ AtomicRMWInst::Add,
+ EmitScalarExpr(E->getArg(0)),
+ ConstantInt::get(Int32Ty, 1),
+ llvm::SequentiallyConsistent);
+ RMWI->setVolatile(true);
+ return RValue::get(Builder.CreateAdd(RMWI, ConstantInt::get(Int32Ty, 1)));
+ }
+ case Builtin::BI_InterlockedDecrement: {
+ AtomicRMWInst *RMWI = Builder.CreateAtomicRMW(
+ AtomicRMWInst::Sub,
+ EmitScalarExpr(E->getArg(0)),
+ ConstantInt::get(Int32Ty, 1),
+ llvm::SequentiallyConsistent);
+ RMWI->setVolatile(true);
+ return RValue::get(Builder.CreateSub(RMWI, ConstantInt::get(Int32Ty, 1)));
+ }
+ case Builtin::BI_InterlockedExchangeAdd: {
+ AtomicRMWInst *RMWI = Builder.CreateAtomicRMW(
+ AtomicRMWInst::Add,
+ EmitScalarExpr(E->getArg(0)),
+ EmitScalarExpr(E->getArg(1)),
+ llvm::SequentiallyConsistent);
+ RMWI->setVolatile(true);
+ return RValue::get(RMWI);
+ }
}
// If this is an alias for a lib function (e.g. __builtin_sin), emit
@@ -1518,8 +1605,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
const char *Name = getContext().BuiltinInfo.GetName(BuiltinID);
Intrinsic::ID IntrinsicID = Intrinsic::not_intrinsic;
if (const char *Prefix =
- llvm::Triple::getArchTypePrefix(getTarget().getTriple().getArch()))
+ llvm::Triple::getArchTypePrefix(getTarget().getTriple().getArch())) {
IntrinsicID = Intrinsic::getIntrinsicForGCCBuiltin(Prefix, Name);
+ // NOTE we dont need to perform a compatibility flag check here since the
+ // intrinsics are declared in Builtins*.def via LANGBUILTIN which filter the
+ // MS builtins via ALL_MS_LANGUAGES and are filtered earlier.
+ if (IntrinsicID == Intrinsic::not_intrinsic)
+ IntrinsicID = Intrinsic::getIntrinsicForMSBuiltin(Prefix, Name);
+ }
if (IntrinsicID != Intrinsic::not_intrinsic) {
SmallVector<Value*, 16> Args;
@@ -1590,11 +1683,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
switch (getTarget().getTriple().getArch()) {
- case llvm::Triple::aarch64:
- return EmitAArch64BuiltinExpr(BuiltinID, E);
case llvm::Triple::arm:
+ case llvm::Triple::armeb:
case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
return EmitARMBuiltinExpr(BuiltinID, E);
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm64:
+ case llvm::Triple::arm64_be:
+ return EmitAArch64BuiltinExpr(BuiltinID, E);
case llvm::Triple::x86:
case llvm::Triple::x86_64:
return EmitX86BuiltinExpr(BuiltinID, E);
@@ -1602,8 +1700,10 @@ Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
return EmitPPCBuiltinExpr(BuiltinID, E);
+ case llvm::Triple::r600:
+ return EmitR600BuiltinExpr(BuiltinID, E);
default:
- return 0;
+ return nullptr;
}
}
@@ -1624,6 +1724,11 @@ static llvm::VectorType *GetNeonType(CodeGenFunction *CGF,
case NeonTypeFlags::Int64:
case NeonTypeFlags::Poly64:
return llvm::VectorType::get(CGF->Int64Ty, V1Ty ? 1 : (1 << IsQuad));
+ case NeonTypeFlags::Poly128:
+ // FIXME: i128 and f128 doesn't get fully support in Clang and llvm.
+ // There is a lot of i128 and f128 API missing.
+ // so we use v16i8 to represent poly128 and get pattern matched.
+ return llvm::VectorType::get(CGF->Int8Ty, 16);
case NeonTypeFlags::Float32:
return llvm::VectorType::get(CGF->FloatTy, V1Ty ? 1 : (2 << IsQuad));
case NeonTypeFlags::Float64:
@@ -1749,2182 +1854,1232 @@ CodeGenFunction::EmitPointerWithAlignment(const Expr *Addr) {
return std::make_pair(EmitScalarExpr(Addr), Align);
}
-static Value *EmitAArch64ScalarBuiltinExpr(CodeGenFunction &CGF,
- unsigned BuiltinID,
- const CallExpr *E) {
- unsigned int Int = 0;
- // Scalar result generated across vectors
- bool AcrossVec = false;
- // Extend element of one-element vector
- bool ExtendEle = false;
- bool OverloadInt = false;
- bool OverloadCmpInt = false;
- bool IsFpCmpZInt = false;
- bool OverloadCvtInt = false;
- bool OverloadWideInt = false;
- bool OverloadNarrowInt = false;
- const char *s = NULL;
-
- SmallVector<Value *, 4> Ops;
- for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) {
- Ops.push_back(CGF.EmitScalarExpr(E->getArg(i)));
- }
-
- // AArch64 scalar builtins are not overloaded, they do not have an extra
- // argument that specifies the vector type, need to handle each case.
- switch (BuiltinID) {
- default: break;
- case AArch64::BI__builtin_neon_vdups_lane_f32:
- case AArch64::BI__builtin_neon_vdupd_lane_f64:
- case AArch64::BI__builtin_neon_vdups_laneq_f32:
- case AArch64::BI__builtin_neon_vdupd_laneq_f64: {
- return CGF.Builder.CreateExtractElement(Ops[0], Ops[1], "vdup_lane");
- }
- case AArch64::BI__builtin_neon_vdupb_lane_i8:
- case AArch64::BI__builtin_neon_vduph_lane_i16:
- case AArch64::BI__builtin_neon_vdups_lane_i32:
- case AArch64::BI__builtin_neon_vdupd_lane_i64:
- case AArch64::BI__builtin_neon_vdupb_laneq_i8:
- case AArch64::BI__builtin_neon_vduph_laneq_i16:
- case AArch64::BI__builtin_neon_vdups_laneq_i32:
- case AArch64::BI__builtin_neon_vdupd_laneq_i64: {
- // The backend treats Neon scalar types as v1ix types
- // So we want to dup lane from any vector to v1ix vector
- // with shufflevector
- s = "vdup_lane";
- Value* SV = llvm::ConstantVector::getSplat(1, cast<ConstantInt>(Ops[1]));
- Value *Result = CGF.Builder.CreateShuffleVector(Ops[0], Ops[0], SV, s);
- llvm::Type *Ty = CGF.ConvertType(E->getCallReturnType());
- // AArch64 intrinsic one-element vector type cast to
- // scalar type expected by the builtin
- return CGF.Builder.CreateBitCast(Result, Ty, s);
- }
- case AArch64::BI__builtin_neon_vqdmlalh_lane_s16 :
- case AArch64::BI__builtin_neon_vqdmlalh_laneq_s16 :
- case AArch64::BI__builtin_neon_vqdmlals_lane_s32 :
- case AArch64::BI__builtin_neon_vqdmlals_laneq_s32 :
- case AArch64::BI__builtin_neon_vqdmlslh_lane_s16 :
- case AArch64::BI__builtin_neon_vqdmlslh_laneq_s16 :
- case AArch64::BI__builtin_neon_vqdmlsls_lane_s32 :
- case AArch64::BI__builtin_neon_vqdmlsls_laneq_s32 : {
- Int = Intrinsic::arm_neon_vqadds;
- if (BuiltinID == AArch64::BI__builtin_neon_vqdmlslh_lane_s16 ||
- BuiltinID == AArch64::BI__builtin_neon_vqdmlslh_laneq_s16 ||
- BuiltinID == AArch64::BI__builtin_neon_vqdmlsls_lane_s32 ||
- BuiltinID == AArch64::BI__builtin_neon_vqdmlsls_laneq_s32) {
- Int = Intrinsic::arm_neon_vqsubs;
- }
- // create vqdmull call with b * c[i]
- llvm::Type *Ty = CGF.ConvertType(E->getArg(1)->getType());
- llvm::VectorType *OpVTy = llvm::VectorType::get(Ty, 1);
- Ty = CGF.ConvertType(E->getArg(0)->getType());
- llvm::VectorType *ResVTy = llvm::VectorType::get(Ty, 1);
- Value *F = CGF.CGM.getIntrinsic(Intrinsic::arm_neon_vqdmull, ResVTy);
- Value *V = UndefValue::get(OpVTy);
- llvm::Constant *CI = ConstantInt::get(CGF.Int32Ty, 0);
- SmallVector<Value *, 2> MulOps;
- MulOps.push_back(Ops[1]);
- MulOps.push_back(Ops[2]);
- MulOps[0] = CGF.Builder.CreateInsertElement(V, MulOps[0], CI);
- MulOps[1] = CGF.Builder.CreateExtractElement(MulOps[1], Ops[3], "extract");
- MulOps[1] = CGF.Builder.CreateInsertElement(V, MulOps[1], CI);
- Value *MulRes = CGF.Builder.CreateCall2(F, MulOps[0], MulOps[1]);
- // create vqadds call with a +/- vqdmull result
- F = CGF.CGM.getIntrinsic(Int, ResVTy);
- SmallVector<Value *, 2> AddOps;
- AddOps.push_back(Ops[0]);
- AddOps.push_back(MulRes);
- V = UndefValue::get(ResVTy);
- AddOps[0] = CGF.Builder.CreateInsertElement(V, AddOps[0], CI);
- Value *AddRes = CGF.Builder.CreateCall2(F, AddOps[0], AddOps[1]);
- return CGF.Builder.CreateBitCast(AddRes, Ty);
- }
- case AArch64::BI__builtin_neon_vfmas_lane_f32:
- case AArch64::BI__builtin_neon_vfmas_laneq_f32:
- case AArch64::BI__builtin_neon_vfmad_lane_f64:
- case AArch64::BI__builtin_neon_vfmad_laneq_f64: {
- llvm::Type *Ty = CGF.ConvertType(E->getCallReturnType());
- Value *F = CGF.CGM.getIntrinsic(Intrinsic::fma, Ty);
- Ops[2] = CGF.Builder.CreateExtractElement(Ops[2], Ops[3], "extract");
- return CGF.Builder.CreateCall3(F, Ops[1], Ops[2], Ops[0]);
- }
- // Scalar Floating-point Multiply Extended
- case AArch64::BI__builtin_neon_vmulxs_f32:
- case AArch64::BI__builtin_neon_vmulxd_f64: {
- Int = Intrinsic::aarch64_neon_vmulx;
- llvm::Type *Ty = CGF.ConvertType(E->getCallReturnType());
- return CGF.EmitNeonCall(CGF.CGM.getIntrinsic(Int, Ty), Ops, "vmulx");
- }
- case AArch64::BI__builtin_neon_vmul_n_f64: {
- // v1f64 vmul_n_f64 should be mapped to Neon scalar mul lane
- llvm::Type *VTy = GetNeonType(&CGF,
- NeonTypeFlags(NeonTypeFlags::Float64, false, false));
- Ops[0] = CGF.Builder.CreateBitCast(Ops[0], VTy);
- llvm::Value *Idx = llvm::ConstantInt::get(CGF.Int32Ty, 0);
- Ops[0] = CGF.Builder.CreateExtractElement(Ops[0], Idx, "extract");
- Value *Result = CGF.Builder.CreateFMul(Ops[0], Ops[1]);
- return CGF.Builder.CreateBitCast(Result, VTy);
- }
- case AArch64::BI__builtin_neon_vget_lane_i8:
- case AArch64::BI__builtin_neon_vget_lane_i16:
- case AArch64::BI__builtin_neon_vget_lane_i32:
- case AArch64::BI__builtin_neon_vget_lane_i64:
- case AArch64::BI__builtin_neon_vget_lane_f32:
- case AArch64::BI__builtin_neon_vget_lane_f64:
- case AArch64::BI__builtin_neon_vgetq_lane_i8:
- case AArch64::BI__builtin_neon_vgetq_lane_i16:
- case AArch64::BI__builtin_neon_vgetq_lane_i32:
- case AArch64::BI__builtin_neon_vgetq_lane_i64:
- case AArch64::BI__builtin_neon_vgetq_lane_f32:
- case AArch64::BI__builtin_neon_vgetq_lane_f64:
- return CGF.EmitARMBuiltinExpr(ARM::BI__builtin_neon_vget_lane_i8, E);
- case AArch64::BI__builtin_neon_vset_lane_i8:
- case AArch64::BI__builtin_neon_vset_lane_i16:
- case AArch64::BI__builtin_neon_vset_lane_i32:
- case AArch64::BI__builtin_neon_vset_lane_i64:
- case AArch64::BI__builtin_neon_vset_lane_f32:
- case AArch64::BI__builtin_neon_vset_lane_f64:
- case AArch64::BI__builtin_neon_vsetq_lane_i8:
- case AArch64::BI__builtin_neon_vsetq_lane_i16:
- case AArch64::BI__builtin_neon_vsetq_lane_i32:
- case AArch64::BI__builtin_neon_vsetq_lane_i64:
- case AArch64::BI__builtin_neon_vsetq_lane_f32:
- case AArch64::BI__builtin_neon_vsetq_lane_f64:
- return CGF.EmitARMBuiltinExpr(ARM::BI__builtin_neon_vset_lane_i8, E);
- // Crypto
- case AArch64::BI__builtin_neon_vsha1h_u32:
- Int = Intrinsic::arm_neon_sha1h;
- s = "sha1h"; OverloadInt = true; break;
- case AArch64::BI__builtin_neon_vsha1cq_u32:
- Int = Intrinsic::aarch64_neon_sha1c;
- s = "sha1c"; break;
- case AArch64::BI__builtin_neon_vsha1pq_u32:
- Int = Intrinsic::aarch64_neon_sha1p;
- s = "sha1p"; break;
- case AArch64::BI__builtin_neon_vsha1mq_u32:
- Int = Intrinsic::aarch64_neon_sha1m;
- s = "sha1m"; break;
- // Scalar Add
- case AArch64::BI__builtin_neon_vaddd_s64:
- Int = Intrinsic::aarch64_neon_vaddds;
- s = "vaddds"; break;
- case AArch64::BI__builtin_neon_vaddd_u64:
- Int = Intrinsic::aarch64_neon_vadddu;
- s = "vadddu"; break;
- // Scalar Sub
- case AArch64::BI__builtin_neon_vsubd_s64:
- Int = Intrinsic::aarch64_neon_vsubds;
- s = "vsubds"; break;
- case AArch64::BI__builtin_neon_vsubd_u64:
- Int = Intrinsic::aarch64_neon_vsubdu;
- s = "vsubdu"; break;
- // Scalar Saturating Add
- case AArch64::BI__builtin_neon_vqaddb_s8:
- case AArch64::BI__builtin_neon_vqaddh_s16:
- case AArch64::BI__builtin_neon_vqadds_s32:
- case AArch64::BI__builtin_neon_vqaddd_s64:
- Int = Intrinsic::arm_neon_vqadds;
- s = "vqadds"; OverloadInt = true; break;
- case AArch64::BI__builtin_neon_vqaddb_u8:
- case AArch64::BI__builtin_neon_vqaddh_u16:
- case AArch64::BI__builtin_neon_vqadds_u32:
- case AArch64::BI__builtin_neon_vqaddd_u64:
- Int = Intrinsic::arm_neon_vqaddu;
- s = "vqaddu"; OverloadInt = true; break;
- // Scalar Saturating Sub
- case AArch64::BI__builtin_neon_vqsubb_s8:
- case AArch64::BI__builtin_neon_vqsubh_s16:
- case AArch64::BI__builtin_neon_vqsubs_s32:
- case AArch64::BI__builtin_neon_vqsubd_s64:
- Int = Intrinsic::arm_neon_vqsubs;
- s = "vqsubs"; OverloadInt = true; break;
- case AArch64::BI__builtin_neon_vqsubb_u8:
- case AArch64::BI__builtin_neon_vqsubh_u16:
- case AArch64::BI__builtin_neon_vqsubs_u32:
- case AArch64::BI__builtin_neon_vqsubd_u64:
- Int = Intrinsic::arm_neon_vqsubu;
- s = "vqsubu"; OverloadInt = true; break;
- // Scalar Shift Left
- case AArch64::BI__builtin_neon_vshld_s64:
- Int = Intrinsic::aarch64_neon_vshlds;
- s = "vshlds"; break;
- case AArch64::BI__builtin_neon_vshld_u64:
- Int = Intrinsic::aarch64_neon_vshldu;
- s = "vshldu"; break;
- // Scalar Saturating Shift Left
- case AArch64::BI__builtin_neon_vqshlb_s8:
- case AArch64::BI__builtin_neon_vqshlh_s16:
- case AArch64::BI__builtin_neon_vqshls_s32:
- case AArch64::BI__builtin_neon_vqshld_s64:
- Int = Intrinsic::aarch64_neon_vqshls;
- s = "vqshls"; OverloadInt = true; break;
- case AArch64::BI__builtin_neon_vqshlb_u8:
- case AArch64::BI__builtin_neon_vqshlh_u16:
- case AArch64::BI__builtin_neon_vqshls_u32:
- case AArch64::BI__builtin_neon_vqshld_u64:
- Int = Intrinsic::aarch64_neon_vqshlu;
- s = "vqshlu"; OverloadInt = true; break;
- // Scalar Rouding Shift Left
- case AArch64::BI__builtin_neon_vrshld_s64:
- Int = Intrinsic::aarch64_neon_vrshlds;
- s = "vrshlds"; break;
- case AArch64::BI__builtin_neon_vrshld_u64:
- Int = Intrinsic::aarch64_neon_vrshldu;
- s = "vrshldu"; break;
- // Scalar Saturating Rouding Shift Left
- case AArch64::BI__builtin_neon_vqrshlb_s8:
- case AArch64::BI__builtin_neon_vqrshlh_s16:
- case AArch64::BI__builtin_neon_vqrshls_s32:
- case AArch64::BI__builtin_neon_vqrshld_s64:
- Int = Intrinsic::aarch64_neon_vqrshls;
- s = "vqrshls"; OverloadInt = true; break;
- case AArch64::BI__builtin_neon_vqrshlb_u8:
- case AArch64::BI__builtin_neon_vqrshlh_u16:
- case AArch64::BI__builtin_neon_vqrshls_u32:
- case AArch64::BI__builtin_neon_vqrshld_u64:
- Int = Intrinsic::aarch64_neon_vqrshlu;
- s = "vqrshlu"; OverloadInt = true; break;
- // Scalar Reduce Pairwise Add
- case AArch64::BI__builtin_neon_vpaddd_s64:
- case AArch64::BI__builtin_neon_vpaddd_u64:
- Int = Intrinsic::aarch64_neon_vpadd; s = "vpadd";
- break;
- case AArch64::BI__builtin_neon_vpadds_f32:
- Int = Intrinsic::aarch64_neon_vpfadd; s = "vpfadd";
- break;
- case AArch64::BI__builtin_neon_vpaddd_f64:
- Int = Intrinsic::aarch64_neon_vpfaddq; s = "vpfaddq";
- break;
- // Scalar Reduce Pairwise Floating Point Max
- case AArch64::BI__builtin_neon_vpmaxs_f32:
- Int = Intrinsic::aarch64_neon_vpmax; s = "vpmax";
- break;
- case AArch64::BI__builtin_neon_vpmaxqd_f64:
- Int = Intrinsic::aarch64_neon_vpmaxq; s = "vpmaxq";
- break;
- // Scalar Reduce Pairwise Floating Point Min
- case AArch64::BI__builtin_neon_vpmins_f32:
- Int = Intrinsic::aarch64_neon_vpmin; s = "vpmin";
- break;
- case AArch64::BI__builtin_neon_vpminqd_f64:
- Int = Intrinsic::aarch64_neon_vpminq; s = "vpminq";
- break;
- // Scalar Reduce Pairwise Floating Point Maxnm
- case AArch64::BI__builtin_neon_vpmaxnms_f32:
- Int = Intrinsic::aarch64_neon_vpfmaxnm; s = "vpfmaxnm";
- break;
- case AArch64::BI__builtin_neon_vpmaxnmqd_f64:
- Int = Intrinsic::aarch64_neon_vpfmaxnmq; s = "vpfmaxnmq";
- break;
- // Scalar Reduce Pairwise Floating Point Minnm
- case AArch64::BI__builtin_neon_vpminnms_f32:
- Int = Intrinsic::aarch64_neon_vpfminnm; s = "vpfminnm";
- break;
- case AArch64::BI__builtin_neon_vpminnmqd_f64:
- Int = Intrinsic::aarch64_neon_vpfminnmq; s = "vpfminnmq";
- break;
- // The followings are intrinsics with scalar results generated AcrossVec vectors
- case AArch64::BI__builtin_neon_vaddlv_s8:
- case AArch64::BI__builtin_neon_vaddlv_s16:
- case AArch64::BI__builtin_neon_vaddlvq_s8:
- case AArch64::BI__builtin_neon_vaddlvq_s16:
- case AArch64::BI__builtin_neon_vaddlvq_s32:
- Int = Intrinsic::aarch64_neon_saddlv;
- AcrossVec = true; ExtendEle = true; s = "saddlv"; break;
- case AArch64::BI__builtin_neon_vaddlv_u8:
- case AArch64::BI__builtin_neon_vaddlv_u16:
- case AArch64::BI__builtin_neon_vaddlvq_u8:
- case AArch64::BI__builtin_neon_vaddlvq_u16:
- case AArch64::BI__builtin_neon_vaddlvq_u32:
- Int = Intrinsic::aarch64_neon_uaddlv;
- AcrossVec = true; ExtendEle = true; s = "uaddlv"; break;
- case AArch64::BI__builtin_neon_vmaxv_s8:
- case AArch64::BI__builtin_neon_vmaxv_s16:
- case AArch64::BI__builtin_neon_vmaxvq_s8:
- case AArch64::BI__builtin_neon_vmaxvq_s16:
- case AArch64::BI__builtin_neon_vmaxvq_s32:
- Int = Intrinsic::aarch64_neon_smaxv;
- AcrossVec = true; ExtendEle = false; s = "smaxv"; break;
- case AArch64::BI__builtin_neon_vmaxv_u8:
- case AArch64::BI__builtin_neon_vmaxv_u16:
- case AArch64::BI__builtin_neon_vmaxvq_u8:
- case AArch64::BI__builtin_neon_vmaxvq_u16:
- case AArch64::BI__builtin_neon_vmaxvq_u32:
- Int = Intrinsic::aarch64_neon_umaxv;
- AcrossVec = true; ExtendEle = false; s = "umaxv"; break;
- case AArch64::BI__builtin_neon_vminv_s8:
- case AArch64::BI__builtin_neon_vminv_s16:
- case AArch64::BI__builtin_neon_vminvq_s8:
- case AArch64::BI__builtin_neon_vminvq_s16:
- case AArch64::BI__builtin_neon_vminvq_s32:
- Int = Intrinsic::aarch64_neon_sminv;
- AcrossVec = true; ExtendEle = false; s = "sminv"; break;
- case AArch64::BI__builtin_neon_vminv_u8:
- case AArch64::BI__builtin_neon_vminv_u16:
- case AArch64::BI__builtin_neon_vminvq_u8:
- case AArch64::BI__builtin_neon_vminvq_u16:
- case AArch64::BI__builtin_neon_vminvq_u32:
- Int = Intrinsic::aarch64_neon_uminv;
- AcrossVec = true; ExtendEle = false; s = "uminv"; break;
- case AArch64::BI__builtin_neon_vaddv_s8:
- case AArch64::BI__builtin_neon_vaddv_s16:
- case AArch64::BI__builtin_neon_vaddvq_s8:
- case AArch64::BI__builtin_neon_vaddvq_s16:
- case AArch64::BI__builtin_neon_vaddvq_s32:
- case AArch64::BI__builtin_neon_vaddvq_s64:
- case AArch64::BI__builtin_neon_vaddv_u8:
- case AArch64::BI__builtin_neon_vaddv_u16:
- case AArch64::BI__builtin_neon_vaddvq_u8:
- case AArch64::BI__builtin_neon_vaddvq_u16:
- case AArch64::BI__builtin_neon_vaddvq_u32:
- case AArch64::BI__builtin_neon_vaddvq_u64:
- case AArch64::BI__builtin_neon_vaddv_f32:
- case AArch64::BI__builtin_neon_vaddvq_f32:
- case AArch64::BI__builtin_neon_vaddvq_f64:
- Int = Intrinsic::aarch64_neon_vaddv;
- AcrossVec = true; ExtendEle = false; s = "vaddv"; break;
- case AArch64::BI__builtin_neon_vmaxv_f32:
- case AArch64::BI__builtin_neon_vmaxvq_f32:
- case AArch64::BI__builtin_neon_vmaxvq_f64:
- Int = Intrinsic::aarch64_neon_vmaxv;
- AcrossVec = true; ExtendEle = false; s = "vmaxv"; break;
- case AArch64::BI__builtin_neon_vminv_f32:
- case AArch64::BI__builtin_neon_vminvq_f32:
- case AArch64::BI__builtin_neon_vminvq_f64:
- Int = Intrinsic::aarch64_neon_vminv;
- AcrossVec = true; ExtendEle = false; s = "vminv"; break;
- case AArch64::BI__builtin_neon_vmaxnmv_f32:
- case AArch64::BI__builtin_neon_vmaxnmvq_f32:
- case AArch64::BI__builtin_neon_vmaxnmvq_f64:
- Int = Intrinsic::aarch64_neon_vmaxnmv;
- AcrossVec = true; ExtendEle = false; s = "vmaxnmv"; break;
- case AArch64::BI__builtin_neon_vminnmv_f32:
- case AArch64::BI__builtin_neon_vminnmvq_f32:
- case AArch64::BI__builtin_neon_vminnmvq_f64:
- Int = Intrinsic::aarch64_neon_vminnmv;
- AcrossVec = true; ExtendEle = false; s = "vminnmv"; break;
- // Scalar Integer Saturating Doubling Multiply Half High
- case AArch64::BI__builtin_neon_vqdmulhh_s16:
- case AArch64::BI__builtin_neon_vqdmulhs_s32:
- Int = Intrinsic::arm_neon_vqdmulh;
- s = "vqdmulh"; OverloadInt = true; break;
- // Scalar Integer Saturating Rounding Doubling Multiply Half High
- case AArch64::BI__builtin_neon_vqrdmulhh_s16:
- case AArch64::BI__builtin_neon_vqrdmulhs_s32:
- Int = Intrinsic::arm_neon_vqrdmulh;
- s = "vqrdmulh"; OverloadInt = true; break;
- // Scalar Floating-point Reciprocal Step and
- case AArch64::BI__builtin_neon_vrecpss_f32:
- case AArch64::BI__builtin_neon_vrecpsd_f64:
- Int = Intrinsic::arm_neon_vrecps;
- s = "vrecps"; OverloadInt = true; break;
- // Scalar Floating-point Reciprocal Square Root Step
- case AArch64::BI__builtin_neon_vrsqrtss_f32:
- case AArch64::BI__builtin_neon_vrsqrtsd_f64:
- Int = Intrinsic::arm_neon_vrsqrts;
- s = "vrsqrts"; OverloadInt = true; break;
- // Scalar Signed Integer Convert To Floating-point
- case AArch64::BI__builtin_neon_vcvts_f32_s32:
- Int = Intrinsic::aarch64_neon_vcvtf32_s32,
- s = "vcvtf"; OverloadInt = false; break;
- case AArch64::BI__builtin_neon_vcvtd_f64_s64:
- Int = Intrinsic::aarch64_neon_vcvtf64_s64,
- s = "vcvtf"; OverloadInt = false; break;
- // Scalar Unsigned Integer Convert To Floating-point
- case AArch64::BI__builtin_neon_vcvts_f32_u32:
- Int = Intrinsic::aarch64_neon_vcvtf32_u32,
- s = "vcvtf"; OverloadInt = false; break;
- case AArch64::BI__builtin_neon_vcvtd_f64_u64:
- Int = Intrinsic::aarch64_neon_vcvtf64_u64,
- s = "vcvtf"; OverloadInt = false; break;
- // Scalar Floating-point Converts
- case AArch64::BI__builtin_neon_vcvtxd_f32_f64:
- Int = Intrinsic::aarch64_neon_fcvtxn;
- s = "vcvtxn"; OverloadCvtInt = true; break;
- case AArch64::BI__builtin_neon_vcvtas_s32_f32:
- case AArch64::BI__builtin_neon_vcvtad_s64_f64:
- Int = Intrinsic::aarch64_neon_fcvtas;
- s = "vcvtas"; OverloadCvtInt = true; break;
- case AArch64::BI__builtin_neon_vcvtas_u32_f32:
- case AArch64::BI__builtin_neon_vcvtad_u64_f64:
- Int = Intrinsic::aarch64_neon_fcvtau;
- s = "vcvtau"; OverloadCvtInt = true; break;
- case AArch64::BI__builtin_neon_vcvtms_s32_f32:
- case AArch64::BI__builtin_neon_vcvtmd_s64_f64:
- Int = Intrinsic::aarch64_neon_fcvtms;
- s = "vcvtms"; OverloadCvtInt = true; break;
- case AArch64::BI__builtin_neon_vcvtms_u32_f32:
- case AArch64::BI__builtin_neon_vcvtmd_u64_f64:
- Int = Intrinsic::aarch64_neon_fcvtmu;
- s = "vcvtmu"; OverloadCvtInt = true; break;
- case AArch64::BI__builtin_neon_vcvtns_s32_f32:
- case AArch64::BI__builtin_neon_vcvtnd_s64_f64:
- Int = Intrinsic::aarch64_neon_fcvtns;
- s = "vcvtns"; OverloadCvtInt = true; break;
- case AArch64::BI__builtin_neon_vcvtns_u32_f32:
- case AArch64::BI__builtin_neon_vcvtnd_u64_f64:
- Int = Intrinsic::aarch64_neon_fcvtnu;
- s = "vcvtnu"; OverloadCvtInt = true; break;
- case AArch64::BI__builtin_neon_vcvtps_s32_f32:
- case AArch64::BI__builtin_neon_vcvtpd_s64_f64:
- Int = Intrinsic::aarch64_neon_fcvtps;
- s = "vcvtps"; OverloadCvtInt = true; break;
- case AArch64::BI__builtin_neon_vcvtps_u32_f32:
- case AArch64::BI__builtin_neon_vcvtpd_u64_f64:
- Int = Intrinsic::aarch64_neon_fcvtpu;
- s = "vcvtpu"; OverloadCvtInt = true; break;
- case AArch64::BI__builtin_neon_vcvts_s32_f32:
- case AArch64::BI__builtin_neon_vcvtd_s64_f64:
- Int = Intrinsic::aarch64_neon_fcvtzs;
- s = "vcvtzs"; OverloadCvtInt = true; break;
- case AArch64::BI__builtin_neon_vcvts_u32_f32:
- case AArch64::BI__builtin_neon_vcvtd_u64_f64:
- Int = Intrinsic::aarch64_neon_fcvtzu;
- s = "vcvtzu"; OverloadCvtInt = true; break;
- // Scalar Floating-point Reciprocal Estimate
- case AArch64::BI__builtin_neon_vrecpes_f32:
- case AArch64::BI__builtin_neon_vrecped_f64:
- Int = Intrinsic::arm_neon_vrecpe;
- s = "vrecpe"; OverloadInt = true; break;
- // Scalar Floating-point Reciprocal Exponent
- case AArch64::BI__builtin_neon_vrecpxs_f32:
- case AArch64::BI__builtin_neon_vrecpxd_f64:
- Int = Intrinsic::aarch64_neon_vrecpx;
- s = "vrecpx"; OverloadInt = true; break;
- // Scalar Floating-point Reciprocal Square Root Estimate
- case AArch64::BI__builtin_neon_vrsqrtes_f32:
- case AArch64::BI__builtin_neon_vrsqrted_f64:
- Int = Intrinsic::arm_neon_vrsqrte;
- s = "vrsqrte"; OverloadInt = true; break;
- // Scalar Compare Equal
- case AArch64::BI__builtin_neon_vceqd_s64:
- case AArch64::BI__builtin_neon_vceqd_u64:
- Int = Intrinsic::aarch64_neon_vceq; s = "vceq";
- OverloadCmpInt = true; break;
- // Scalar Compare Equal To Zero
- case AArch64::BI__builtin_neon_vceqzd_s64:
- case AArch64::BI__builtin_neon_vceqzd_u64:
- Int = Intrinsic::aarch64_neon_vceq; s = "vceq";
- // Add implicit zero operand.
- Ops.push_back(llvm::Constant::getNullValue(Ops[0]->getType()));
- OverloadCmpInt = true; break;
- // Scalar Compare Greater Than or Equal
- case AArch64::BI__builtin_neon_vcged_s64:
- Int = Intrinsic::aarch64_neon_vcge; s = "vcge";
- OverloadCmpInt = true; break;
- case AArch64::BI__builtin_neon_vcged_u64:
- Int = Intrinsic::aarch64_neon_vchs; s = "vcge";
- OverloadCmpInt = true; break;
- // Scalar Compare Greater Than or Equal To Zero
- case AArch64::BI__builtin_neon_vcgezd_s64:
- Int = Intrinsic::aarch64_neon_vcge; s = "vcge";
- // Add implicit zero operand.
- Ops.push_back(llvm::Constant::getNullValue(Ops[0]->getType()));
- OverloadCmpInt = true; break;
- // Scalar Compare Greater Than
- case AArch64::BI__builtin_neon_vcgtd_s64:
- Int = Intrinsic::aarch64_neon_vcgt; s = "vcgt";
- OverloadCmpInt = true; break;
- case AArch64::BI__builtin_neon_vcgtd_u64:
- Int = Intrinsic::aarch64_neon_vchi; s = "vcgt";
- OverloadCmpInt = true; break;
- // Scalar Compare Greater Than Zero
- case AArch64::BI__builtin_neon_vcgtzd_s64:
- Int = Intrinsic::aarch64_neon_vcgt; s = "vcgt";
- // Add implicit zero operand.
- Ops.push_back(llvm::Constant::getNullValue(Ops[0]->getType()));
- OverloadCmpInt = true; break;
- // Scalar Compare Less Than or Equal
- case AArch64::BI__builtin_neon_vcled_s64:
- Int = Intrinsic::aarch64_neon_vcge; s = "vcge";
- OverloadCmpInt = true; std::swap(Ops[0], Ops[1]); break;
- case AArch64::BI__builtin_neon_vcled_u64:
- Int = Intrinsic::aarch64_neon_vchs; s = "vchs";
- OverloadCmpInt = true; std::swap(Ops[0], Ops[1]); break;
- // Scalar Compare Less Than or Equal To Zero
- case AArch64::BI__builtin_neon_vclezd_s64:
- Int = Intrinsic::aarch64_neon_vclez; s = "vcle";
- // Add implicit zero operand.
- Ops.push_back(llvm::Constant::getNullValue(Ops[0]->getType()));
- OverloadCmpInt = true; break;
- // Scalar Compare Less Than
- case AArch64::BI__builtin_neon_vcltd_s64:
- Int = Intrinsic::aarch64_neon_vcgt; s = "vcgt";
- OverloadCmpInt = true; std::swap(Ops[0], Ops[1]); break;
- case AArch64::BI__builtin_neon_vcltd_u64:
- Int = Intrinsic::aarch64_neon_vchi; s = "vchi";
- OverloadCmpInt = true; std::swap(Ops[0], Ops[1]); break;
- // Scalar Compare Less Than Zero
- case AArch64::BI__builtin_neon_vcltzd_s64:
- Int = Intrinsic::aarch64_neon_vcltz; s = "vclt";
- // Add implicit zero operand.
- Ops.push_back(llvm::Constant::getNullValue(Ops[0]->getType()));
- OverloadCmpInt = true; break;
- // Scalar Floating-point Compare Equal
- case AArch64::BI__builtin_neon_vceqs_f32:
- case AArch64::BI__builtin_neon_vceqd_f64:
- Int = Intrinsic::aarch64_neon_vceq; s = "vceq";
- OverloadCmpInt = true; break;
- // Scalar Floating-point Compare Equal To Zero
- case AArch64::BI__builtin_neon_vceqzs_f32:
- case AArch64::BI__builtin_neon_vceqzd_f64:
- Int = Intrinsic::aarch64_neon_vceq; s = "vceq";
- // Add implicit zero operand.
- Ops.push_back(llvm::Constant::getNullValue(CGF.FloatTy));
- IsFpCmpZInt = true;
- OverloadCmpInt = true; break;
- // Scalar Floating-point Compare Greater Than Or Equal
- case AArch64::BI__builtin_neon_vcges_f32:
- case AArch64::BI__builtin_neon_vcged_f64:
- Int = Intrinsic::aarch64_neon_vcge; s = "vcge";
- OverloadCmpInt = true; break;
- // Scalar Floating-point Compare Greater Than Or Equal To Zero
- case AArch64::BI__builtin_neon_vcgezs_f32:
- case AArch64::BI__builtin_neon_vcgezd_f64:
- Int = Intrinsic::aarch64_neon_vcge; s = "vcge";
- // Add implicit zero operand.
- Ops.push_back(llvm::Constant::getNullValue(CGF.FloatTy));
- IsFpCmpZInt = true;
- OverloadCmpInt = true; break;
- // Scalar Floating-point Compare Greather Than
- case AArch64::BI__builtin_neon_vcgts_f32:
- case AArch64::BI__builtin_neon_vcgtd_f64:
- Int = Intrinsic::aarch64_neon_vcgt; s = "vcgt";
- OverloadCmpInt = true; break;
- // Scalar Floating-point Compare Greather Than Zero
- case AArch64::BI__builtin_neon_vcgtzs_f32:
- case AArch64::BI__builtin_neon_vcgtzd_f64:
- Int = Intrinsic::aarch64_neon_vcgt; s = "vcgt";
- // Add implicit zero operand.
- Ops.push_back(llvm::Constant::getNullValue(CGF.FloatTy));
- IsFpCmpZInt = true;
- OverloadCmpInt = true; break;
- // Scalar Floating-point Compare Less Than or Equal
- case AArch64::BI__builtin_neon_vcles_f32:
- case AArch64::BI__builtin_neon_vcled_f64:
- Int = Intrinsic::aarch64_neon_vcge; s = "vcge";
- OverloadCmpInt = true; break;
- // Scalar Floating-point Compare Less Than Or Equal To Zero
- case AArch64::BI__builtin_neon_vclezs_f32:
- case AArch64::BI__builtin_neon_vclezd_f64:
- Int = Intrinsic::aarch64_neon_vclez; s = "vcle";
- // Add implicit zero operand.
- Ops.push_back(llvm::Constant::getNullValue(CGF.FloatTy));
- IsFpCmpZInt = true;
- OverloadCmpInt = true; break;
- // Scalar Floating-point Compare Less Than Zero
- case AArch64::BI__builtin_neon_vclts_f32:
- case AArch64::BI__builtin_neon_vcltd_f64:
- Int = Intrinsic::aarch64_neon_vcgt; s = "vcgt";
- OverloadCmpInt = true; std::swap(Ops[0], Ops[1]); break;
- // Scalar Floating-point Compare Less Than Zero
- case AArch64::BI__builtin_neon_vcltzs_f32:
- case AArch64::BI__builtin_neon_vcltzd_f64:
- Int = Intrinsic::aarch64_neon_vcltz; s = "vclt";
- // Add implicit zero operand.
- Ops.push_back(llvm::Constant::getNullValue(CGF.FloatTy));
- IsFpCmpZInt = true;
- OverloadCmpInt = true; break;
- // Scalar Floating-point Absolute Compare Greater Than Or Equal
- case AArch64::BI__builtin_neon_vcages_f32:
- case AArch64::BI__builtin_neon_vcaged_f64:
- Int = Intrinsic::aarch64_neon_vcage; s = "vcage";
- OverloadCmpInt = true; break;
- // Scalar Floating-point Absolute Compare Greater Than
- case AArch64::BI__builtin_neon_vcagts_f32:
- case AArch64::BI__builtin_neon_vcagtd_f64:
- Int = Intrinsic::aarch64_neon_vcagt; s = "vcagt";
- OverloadCmpInt = true; break;
- // Scalar Floating-point Absolute Compare Less Than Or Equal
- case AArch64::BI__builtin_neon_vcales_f32:
- case AArch64::BI__builtin_neon_vcaled_f64:
- Int = Intrinsic::aarch64_neon_vcage; s = "vcage";
- OverloadCmpInt = true; std::swap(Ops[0], Ops[1]); break;
- // Scalar Floating-point Absolute Compare Less Than
- case AArch64::BI__builtin_neon_vcalts_f32:
- case AArch64::BI__builtin_neon_vcaltd_f64:
- Int = Intrinsic::aarch64_neon_vcagt; s = "vcalt";
- OverloadCmpInt = true; std::swap(Ops[0], Ops[1]); break;
- // Scalar Compare Bitwise Test Bits
- case AArch64::BI__builtin_neon_vtstd_s64:
- case AArch64::BI__builtin_neon_vtstd_u64:
- Int = Intrinsic::aarch64_neon_vtstd; s = "vtst";
- OverloadCmpInt = true; break;
- // Scalar Absolute Value
- case AArch64::BI__builtin_neon_vabsd_s64:
- Int = Intrinsic::aarch64_neon_vabs;
- s = "vabs"; OverloadInt = false; break;
- // Scalar Absolute Difference
- case AArch64::BI__builtin_neon_vabds_f32:
- case AArch64::BI__builtin_neon_vabdd_f64:
- Int = Intrinsic::aarch64_neon_vabd;
- s = "vabd"; OverloadInt = true; break;
- // Scalar Signed Saturating Absolute Value
- case AArch64::BI__builtin_neon_vqabsb_s8:
- case AArch64::BI__builtin_neon_vqabsh_s16:
- case AArch64::BI__builtin_neon_vqabss_s32:
- case AArch64::BI__builtin_neon_vqabsd_s64:
- Int = Intrinsic::arm_neon_vqabs;
- s = "vqabs"; OverloadInt = true; break;
- // Scalar Negate
- case AArch64::BI__builtin_neon_vnegd_s64:
- Int = Intrinsic::aarch64_neon_vneg;
- s = "vneg"; OverloadInt = false; break;
- // Scalar Signed Saturating Negate
- case AArch64::BI__builtin_neon_vqnegb_s8:
- case AArch64::BI__builtin_neon_vqnegh_s16:
- case AArch64::BI__builtin_neon_vqnegs_s32:
- case AArch64::BI__builtin_neon_vqnegd_s64:
- Int = Intrinsic::arm_neon_vqneg;
- s = "vqneg"; OverloadInt = true; break;
- // Scalar Signed Saturating Accumulated of Unsigned Value
- case AArch64::BI__builtin_neon_vuqaddb_s8:
- case AArch64::BI__builtin_neon_vuqaddh_s16:
- case AArch64::BI__builtin_neon_vuqadds_s32:
- case AArch64::BI__builtin_neon_vuqaddd_s64:
- Int = Intrinsic::aarch64_neon_vuqadd;
- s = "vuqadd"; OverloadInt = true; break;
- // Scalar Unsigned Saturating Accumulated of Signed Value
- case AArch64::BI__builtin_neon_vsqaddb_u8:
- case AArch64::BI__builtin_neon_vsqaddh_u16:
- case AArch64::BI__builtin_neon_vsqadds_u32:
- case AArch64::BI__builtin_neon_vsqaddd_u64:
- Int = Intrinsic::aarch64_neon_vsqadd;
- s = "vsqadd"; OverloadInt = true; break;
- // Signed Saturating Doubling Multiply-Add Long
- case AArch64::BI__builtin_neon_vqdmlalh_s16:
- case AArch64::BI__builtin_neon_vqdmlals_s32:
- Int = Intrinsic::aarch64_neon_vqdmlal;
- s = "vqdmlal"; OverloadWideInt = true; break;
- // Signed Saturating Doubling Multiply-Subtract Long
- case AArch64::BI__builtin_neon_vqdmlslh_s16:
- case AArch64::BI__builtin_neon_vqdmlsls_s32:
- Int = Intrinsic::aarch64_neon_vqdmlsl;
- s = "vqdmlsl"; OverloadWideInt = true; break;
- // Signed Saturating Doubling Multiply Long
- case AArch64::BI__builtin_neon_vqdmullh_s16:
- case AArch64::BI__builtin_neon_vqdmulls_s32:
- Int = Intrinsic::arm_neon_vqdmull;
- s = "vqdmull"; OverloadWideInt = true; break;
- // Scalar Signed Saturating Extract Unsigned Narrow
- case AArch64::BI__builtin_neon_vqmovunh_s16:
- case AArch64::BI__builtin_neon_vqmovuns_s32:
- case AArch64::BI__builtin_neon_vqmovund_s64:
- Int = Intrinsic::arm_neon_vqmovnsu;
- s = "vqmovun"; OverloadNarrowInt = true; break;
- // Scalar Signed Saturating Extract Narrow
- case AArch64::BI__builtin_neon_vqmovnh_s16:
- case AArch64::BI__builtin_neon_vqmovns_s32:
- case AArch64::BI__builtin_neon_vqmovnd_s64:
- Int = Intrinsic::arm_neon_vqmovns;
- s = "vqmovn"; OverloadNarrowInt = true; break;
- // Scalar Unsigned Saturating Extract Narrow
- case AArch64::BI__builtin_neon_vqmovnh_u16:
- case AArch64::BI__builtin_neon_vqmovns_u32:
- case AArch64::BI__builtin_neon_vqmovnd_u64:
- Int = Intrinsic::arm_neon_vqmovnu;
- s = "vqmovn"; OverloadNarrowInt = true; break;
- // Scalar Signed Shift Right (Immediate)
- case AArch64::BI__builtin_neon_vshrd_n_s64:
- Int = Intrinsic::aarch64_neon_vshrds_n;
- s = "vsshr"; OverloadInt = false; break;
- // Scalar Unsigned Shift Right (Immediate)
- case AArch64::BI__builtin_neon_vshrd_n_u64:
- Int = Intrinsic::aarch64_neon_vshrdu_n;
- s = "vushr"; OverloadInt = false; break;
- // Scalar Signed Rounding Shift Right (Immediate)
- case AArch64::BI__builtin_neon_vrshrd_n_s64:
- Int = Intrinsic::aarch64_neon_vsrshr;
- s = "vsrshr"; OverloadInt = true; break;
- // Scalar Unsigned Rounding Shift Right (Immediate)
- case AArch64::BI__builtin_neon_vrshrd_n_u64:
- Int = Intrinsic::aarch64_neon_vurshr;
- s = "vurshr"; OverloadInt = true; break;
- // Scalar Signed Shift Right and Accumulate (Immediate)
- case AArch64::BI__builtin_neon_vsrad_n_s64:
- Int = Intrinsic::aarch64_neon_vsrads_n;
- s = "vssra"; OverloadInt = false; break;
- // Scalar Unsigned Shift Right and Accumulate (Immediate)
- case AArch64::BI__builtin_neon_vsrad_n_u64:
- Int = Intrinsic::aarch64_neon_vsradu_n;
- s = "vusra"; OverloadInt = false; break;
- // Scalar Signed Rounding Shift Right and Accumulate (Immediate)
- case AArch64::BI__builtin_neon_vrsrad_n_s64:
- Int = Intrinsic::aarch64_neon_vrsrads_n;
- s = "vsrsra"; OverloadInt = false; break;
- // Scalar Unsigned Rounding Shift Right and Accumulate (Immediate)
- case AArch64::BI__builtin_neon_vrsrad_n_u64:
- Int = Intrinsic::aarch64_neon_vrsradu_n;
- s = "vursra"; OverloadInt = false; break;
- // Scalar Signed/Unsigned Shift Left (Immediate)
- case AArch64::BI__builtin_neon_vshld_n_s64:
- case AArch64::BI__builtin_neon_vshld_n_u64:
- Int = Intrinsic::aarch64_neon_vshld_n;
- s = "vshl"; OverloadInt = false; break;
- // Signed Saturating Shift Left (Immediate)
- case AArch64::BI__builtin_neon_vqshlb_n_s8:
- case AArch64::BI__builtin_neon_vqshlh_n_s16:
- case AArch64::BI__builtin_neon_vqshls_n_s32:
- case AArch64::BI__builtin_neon_vqshld_n_s64:
- Int = Intrinsic::aarch64_neon_vqshls_n;
- s = "vsqshl"; OverloadInt = true; break;
- // Unsigned Saturating Shift Left (Immediate)
- case AArch64::BI__builtin_neon_vqshlb_n_u8:
- case AArch64::BI__builtin_neon_vqshlh_n_u16:
- case AArch64::BI__builtin_neon_vqshls_n_u32:
- case AArch64::BI__builtin_neon_vqshld_n_u64:
- Int = Intrinsic::aarch64_neon_vqshlu_n;
- s = "vuqshl"; OverloadInt = true; break;
- // Signed Saturating Shift Left Unsigned (Immediate)
- case AArch64::BI__builtin_neon_vqshlub_n_s8:
- case AArch64::BI__builtin_neon_vqshluh_n_s16:
- case AArch64::BI__builtin_neon_vqshlus_n_s32:
- case AArch64::BI__builtin_neon_vqshlud_n_s64:
- Int = Intrinsic::aarch64_neon_vsqshlu;
- s = "vsqshlu"; OverloadInt = true; break;
- // Shift Right And Insert (Immediate)
- case AArch64::BI__builtin_neon_vsrid_n_s64:
- case AArch64::BI__builtin_neon_vsrid_n_u64:
- Int = Intrinsic::aarch64_neon_vsri;
- s = "vsri"; OverloadInt = true; break;
- // Shift Left And Insert (Immediate)
- case AArch64::BI__builtin_neon_vslid_n_s64:
- case AArch64::BI__builtin_neon_vslid_n_u64:
- Int = Intrinsic::aarch64_neon_vsli;
- s = "vsli"; OverloadInt = true; break;
- // Signed Saturating Shift Right Narrow (Immediate)
- case AArch64::BI__builtin_neon_vqshrnh_n_s16:
- case AArch64::BI__builtin_neon_vqshrns_n_s32:
- case AArch64::BI__builtin_neon_vqshrnd_n_s64:
- Int = Intrinsic::aarch64_neon_vsqshrn;
- s = "vsqshrn"; OverloadInt = true; break;
- // Unsigned Saturating Shift Right Narrow (Immediate)
- case AArch64::BI__builtin_neon_vqshrnh_n_u16:
- case AArch64::BI__builtin_neon_vqshrns_n_u32:
- case AArch64::BI__builtin_neon_vqshrnd_n_u64:
- Int = Intrinsic::aarch64_neon_vuqshrn;
- s = "vuqshrn"; OverloadInt = true; break;
- // Signed Saturating Rounded Shift Right Narrow (Immediate)
- case AArch64::BI__builtin_neon_vqrshrnh_n_s16:
- case AArch64::BI__builtin_neon_vqrshrns_n_s32:
- case AArch64::BI__builtin_neon_vqrshrnd_n_s64:
- Int = Intrinsic::aarch64_neon_vsqrshrn;
- s = "vsqrshrn"; OverloadInt = true; break;
- // Unsigned Saturating Rounded Shift Right Narrow (Immediate)
- case AArch64::BI__builtin_neon_vqrshrnh_n_u16:
- case AArch64::BI__builtin_neon_vqrshrns_n_u32:
- case AArch64::BI__builtin_neon_vqrshrnd_n_u64:
- Int = Intrinsic::aarch64_neon_vuqrshrn;
- s = "vuqrshrn"; OverloadInt = true; break;
- // Signed Saturating Shift Right Unsigned Narrow (Immediate)
- case AArch64::BI__builtin_neon_vqshrunh_n_s16:
- case AArch64::BI__builtin_neon_vqshruns_n_s32:
- case AArch64::BI__builtin_neon_vqshrund_n_s64:
- Int = Intrinsic::aarch64_neon_vsqshrun;
- s = "vsqshrun"; OverloadInt = true; break;
- // Signed Saturating Rounded Shift Right Unsigned Narrow (Immediate)
- case AArch64::BI__builtin_neon_vqrshrunh_n_s16:
- case AArch64::BI__builtin_neon_vqrshruns_n_s32:
- case AArch64::BI__builtin_neon_vqrshrund_n_s64:
- Int = Intrinsic::aarch64_neon_vsqrshrun;
- s = "vsqrshrun"; OverloadInt = true; break;
- // Scalar Signed Fixed-point Convert To Floating-Point (Immediate)
- case AArch64::BI__builtin_neon_vcvts_n_f32_s32:
- Int = Intrinsic::aarch64_neon_vcvtf32_n_s32;
- s = "vcvtf"; OverloadInt = false; break;
- case AArch64::BI__builtin_neon_vcvtd_n_f64_s64:
- Int = Intrinsic::aarch64_neon_vcvtf64_n_s64;
- s = "vcvtf"; OverloadInt = false; break;
- // Scalar Unsigned Fixed-point Convert To Floating-Point (Immediate)
- case AArch64::BI__builtin_neon_vcvts_n_f32_u32:
- Int = Intrinsic::aarch64_neon_vcvtf32_n_u32;
- s = "vcvtf"; OverloadInt = false; break;
- case AArch64::BI__builtin_neon_vcvtd_n_f64_u64:
- Int = Intrinsic::aarch64_neon_vcvtf64_n_u64;
- s = "vcvtf"; OverloadInt = false; break;
- // Scalar Floating-point Convert To Signed Fixed-point (Immediate)
- case AArch64::BI__builtin_neon_vcvts_n_s32_f32:
- Int = Intrinsic::aarch64_neon_vcvts_n_s32_f32;
- s = "fcvtzs"; OverloadInt = false; break;
- case AArch64::BI__builtin_neon_vcvtd_n_s64_f64:
- Int = Intrinsic::aarch64_neon_vcvtd_n_s64_f64;
- s = "fcvtzs"; OverloadInt = false; break;
- // Scalar Floating-point Convert To Unsigned Fixed-point (Immediate)
- case AArch64::BI__builtin_neon_vcvts_n_u32_f32:
- Int = Intrinsic::aarch64_neon_vcvts_n_u32_f32;
- s = "fcvtzu"; OverloadInt = false; break;
- case AArch64::BI__builtin_neon_vcvtd_n_u64_f64:
- Int = Intrinsic::aarch64_neon_vcvtd_n_u64_f64;
- s = "fcvtzu"; OverloadInt = false; break;
- }
-
- if (!Int)
- return 0;
-
- // AArch64 scalar builtin that returns scalar type
- // and should be mapped to AArch64 intrinsic that returns
- // one-element vector type.
- Function *F = 0;
- if (AcrossVec) {
- // Gen arg type
- const Expr *Arg = E->getArg(E->getNumArgs()-1);
- llvm::Type *Ty = CGF.ConvertType(Arg->getType());
- llvm::VectorType *VTy = cast<llvm::VectorType>(Ty);
- llvm::Type *ETy = VTy->getElementType();
- llvm::VectorType *RTy = llvm::VectorType::get(ETy, 1);
-
- if (ExtendEle) {
- assert(!ETy->isFloatingPointTy());
- RTy = llvm::VectorType::getExtendedElementVectorType(RTy);
- }
-
- llvm::Type *Tys[2] = {RTy, VTy};
- F = CGF.CGM.getIntrinsic(Int, Tys);
- assert(E->getNumArgs() == 1);
- } else if (OverloadInt) {
- // Determine the type of this overloaded AArch64 intrinsic
- llvm::Type *Ty = CGF.ConvertType(E->getCallReturnType());
- llvm::VectorType *VTy = llvm::VectorType::get(Ty, 1);
- assert(VTy);
-
- F = CGF.CGM.getIntrinsic(Int, VTy);
- } else if (OverloadWideInt || OverloadNarrowInt) {
- // Determine the type of this overloaded AArch64 intrinsic
- const Expr *Arg = E->getArg(E->getNumArgs()-1);
- llvm::Type *Ty = CGF.ConvertType(Arg->getType());
- llvm::VectorType *VTy = llvm::VectorType::get(Ty, 1);
- llvm::VectorType *RTy = OverloadWideInt ?
- llvm::VectorType::getExtendedElementVectorType(VTy) :
- llvm::VectorType::getTruncatedElementVectorType(VTy);
- F = CGF.CGM.getIntrinsic(Int, RTy);
- } else if (OverloadCmpInt) {
- // Determine the types of this overloaded AArch64 intrinsic
- SmallVector<llvm::Type *, 3> Tys;
- const Expr *Arg = E->getArg(E->getNumArgs()-1);
- llvm::Type *Ty = CGF.ConvertType(E->getCallReturnType());
- llvm::VectorType *VTy = llvm::VectorType::get(Ty, 1);
- Tys.push_back(VTy);
- Ty = CGF.ConvertType(Arg->getType());
- VTy = llvm::VectorType::get(Ty, 1);
- Tys.push_back(VTy);
- if(IsFpCmpZInt)
- VTy = llvm::VectorType::get(CGF.FloatTy, 1);
- Tys.push_back(VTy);
-
- F = CGF.CGM.getIntrinsic(Int, Tys);
- } else if (OverloadCvtInt) {
- // Determine the types of this overloaded AArch64 intrinsic
- SmallVector<llvm::Type *, 2> Tys;
- const Expr *Arg = E->getArg(E->getNumArgs()-1);
- llvm::Type *Ty = CGF.ConvertType(E->getCallReturnType());
- llvm::VectorType *VTy = llvm::VectorType::get(Ty, 1);
- Tys.push_back(VTy);
- Ty = CGF.ConvertType(Arg->getType());
- VTy = llvm::VectorType::get(Ty, 1);
- Tys.push_back(VTy);
-
- F = CGF.CGM.getIntrinsic(Int, Tys);
- } else
- F = CGF.CGM.getIntrinsic(Int);
-
- Value *Result = CGF.EmitNeonCall(F, Ops, s);
- llvm::Type *ResultType = CGF.ConvertType(E->getType());
- // AArch64 intrinsic one-element vector type cast to
- // scalar type expected by the builtin
- return CGF.Builder.CreateBitCast(Result, ResultType, s);
+enum {
+ AddRetType = (1 << 0),
+ Add1ArgType = (1 << 1),
+ Add2ArgTypes = (1 << 2),
+
+ VectorizeRetType = (1 << 3),
+ VectorizeArgTypes = (1 << 4),
+
+ InventFloatType = (1 << 5),
+ UnsignedAlts = (1 << 6),
+
+ Use64BitVectors = (1 << 7),
+ Use128BitVectors = (1 << 8),
+
+ Vectorize1ArgType = Add1ArgType | VectorizeArgTypes,
+ VectorRet = AddRetType | VectorizeRetType,
+ VectorRetGetArgs01 =
+ AddRetType | Add2ArgTypes | VectorizeRetType | VectorizeArgTypes,
+ FpCmpzModifiers =
+ AddRetType | VectorizeRetType | Add1ArgType | InventFloatType
+};
+
+ struct NeonIntrinsicInfo {
+ unsigned BuiltinID;
+ unsigned LLVMIntrinsic;
+ unsigned AltLLVMIntrinsic;
+ const char *NameHint;
+ unsigned TypeModifier;
+
+ bool operator<(unsigned RHSBuiltinID) const {
+ return BuiltinID < RHSBuiltinID;
+ }
+};
+
+#define NEONMAP0(NameBase) \
+ { NEON::BI__builtin_neon_ ## NameBase, 0, 0, #NameBase, 0 }
+
+#define NEONMAP1(NameBase, LLVMIntrinsic, TypeModifier) \
+ { NEON:: BI__builtin_neon_ ## NameBase, \
+ Intrinsic::LLVMIntrinsic, 0, #NameBase, TypeModifier }
+
+#define NEONMAP2(NameBase, LLVMIntrinsic, AltLLVMIntrinsic, TypeModifier) \
+ { NEON:: BI__builtin_neon_ ## NameBase, \
+ Intrinsic::LLVMIntrinsic, Intrinsic::AltLLVMIntrinsic, \
+ #NameBase, TypeModifier }
+
+static NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = {
+ NEONMAP2(vabd_v, arm_neon_vabdu, arm_neon_vabds, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vabdq_v, arm_neon_vabdu, arm_neon_vabds, Add1ArgType | UnsignedAlts),
+ NEONMAP1(vabs_v, arm_neon_vabs, 0),
+ NEONMAP1(vabsq_v, arm_neon_vabs, 0),
+ NEONMAP0(vaddhn_v),
+ NEONMAP1(vaesdq_v, arm_neon_aesd, 0),
+ NEONMAP1(vaeseq_v, arm_neon_aese, 0),
+ NEONMAP1(vaesimcq_v, arm_neon_aesimc, 0),
+ NEONMAP1(vaesmcq_v, arm_neon_aesmc, 0),
+ NEONMAP1(vbsl_v, arm_neon_vbsl, AddRetType),
+ NEONMAP1(vbslq_v, arm_neon_vbsl, AddRetType),
+ NEONMAP1(vcage_v, arm_neon_vacge, 0),
+ NEONMAP1(vcageq_v, arm_neon_vacge, 0),
+ NEONMAP1(vcagt_v, arm_neon_vacgt, 0),
+ NEONMAP1(vcagtq_v, arm_neon_vacgt, 0),
+ NEONMAP1(vcale_v, arm_neon_vacge, 0),
+ NEONMAP1(vcaleq_v, arm_neon_vacge, 0),
+ NEONMAP1(vcalt_v, arm_neon_vacgt, 0),
+ NEONMAP1(vcaltq_v, arm_neon_vacgt, 0),
+ NEONMAP1(vcls_v, arm_neon_vcls, Add1ArgType),
+ NEONMAP1(vclsq_v, arm_neon_vcls, Add1ArgType),
+ NEONMAP1(vclz_v, ctlz, Add1ArgType),
+ NEONMAP1(vclzq_v, ctlz, Add1ArgType),
+ NEONMAP1(vcnt_v, ctpop, Add1ArgType),
+ NEONMAP1(vcntq_v, ctpop, Add1ArgType),
+ NEONMAP1(vcvt_f16_v, arm_neon_vcvtfp2hf, 0),
+ NEONMAP1(vcvt_f32_f16, arm_neon_vcvthf2fp, 0),
+ NEONMAP0(vcvt_f32_v),
+ NEONMAP2(vcvt_n_f32_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0),
+ NEONMAP1(vcvt_n_s32_v, arm_neon_vcvtfp2fxs, 0),
+ NEONMAP1(vcvt_n_s64_v, arm_neon_vcvtfp2fxs, 0),
+ NEONMAP1(vcvt_n_u32_v, arm_neon_vcvtfp2fxu, 0),
+ NEONMAP1(vcvt_n_u64_v, arm_neon_vcvtfp2fxu, 0),
+ NEONMAP0(vcvt_s32_v),
+ NEONMAP0(vcvt_s64_v),
+ NEONMAP0(vcvt_u32_v),
+ NEONMAP0(vcvt_u64_v),
+ NEONMAP1(vcvta_s32_v, arm_neon_vcvtas, 0),
+ NEONMAP1(vcvta_s64_v, arm_neon_vcvtas, 0),
+ NEONMAP1(vcvta_u32_v, arm_neon_vcvtau, 0),
+ NEONMAP1(vcvta_u64_v, arm_neon_vcvtau, 0),
+ NEONMAP1(vcvtaq_s32_v, arm_neon_vcvtas, 0),
+ NEONMAP1(vcvtaq_s64_v, arm_neon_vcvtas, 0),
+ NEONMAP1(vcvtaq_u32_v, arm_neon_vcvtau, 0),
+ NEONMAP1(vcvtaq_u64_v, arm_neon_vcvtau, 0),
+ NEONMAP1(vcvtm_s32_v, arm_neon_vcvtms, 0),
+ NEONMAP1(vcvtm_s64_v, arm_neon_vcvtms, 0),
+ NEONMAP1(vcvtm_u32_v, arm_neon_vcvtmu, 0),
+ NEONMAP1(vcvtm_u64_v, arm_neon_vcvtmu, 0),
+ NEONMAP1(vcvtmq_s32_v, arm_neon_vcvtms, 0),
+ NEONMAP1(vcvtmq_s64_v, arm_neon_vcvtms, 0),
+ NEONMAP1(vcvtmq_u32_v, arm_neon_vcvtmu, 0),
+ NEONMAP1(vcvtmq_u64_v, arm_neon_vcvtmu, 0),
+ NEONMAP1(vcvtn_s32_v, arm_neon_vcvtns, 0),
+ NEONMAP1(vcvtn_s64_v, arm_neon_vcvtns, 0),
+ NEONMAP1(vcvtn_u32_v, arm_neon_vcvtnu, 0),
+ NEONMAP1(vcvtn_u64_v, arm_neon_vcvtnu, 0),
+ NEONMAP1(vcvtnq_s32_v, arm_neon_vcvtns, 0),
+ NEONMAP1(vcvtnq_s64_v, arm_neon_vcvtns, 0),
+ NEONMAP1(vcvtnq_u32_v, arm_neon_vcvtnu, 0),
+ NEONMAP1(vcvtnq_u64_v, arm_neon_vcvtnu, 0),
+ NEONMAP1(vcvtp_s32_v, arm_neon_vcvtps, 0),
+ NEONMAP1(vcvtp_s64_v, arm_neon_vcvtps, 0),
+ NEONMAP1(vcvtp_u32_v, arm_neon_vcvtpu, 0),
+ NEONMAP1(vcvtp_u64_v, arm_neon_vcvtpu, 0),
+ NEONMAP1(vcvtpq_s32_v, arm_neon_vcvtps, 0),
+ NEONMAP1(vcvtpq_s64_v, arm_neon_vcvtps, 0),
+ NEONMAP1(vcvtpq_u32_v, arm_neon_vcvtpu, 0),
+ NEONMAP1(vcvtpq_u64_v, arm_neon_vcvtpu, 0),
+ NEONMAP0(vcvtq_f32_v),
+ NEONMAP2(vcvtq_n_f32_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0),
+ NEONMAP1(vcvtq_n_s32_v, arm_neon_vcvtfp2fxs, 0),
+ NEONMAP1(vcvtq_n_s64_v, arm_neon_vcvtfp2fxs, 0),
+ NEONMAP1(vcvtq_n_u32_v, arm_neon_vcvtfp2fxu, 0),
+ NEONMAP1(vcvtq_n_u64_v, arm_neon_vcvtfp2fxu, 0),
+ NEONMAP0(vcvtq_s32_v),
+ NEONMAP0(vcvtq_s64_v),
+ NEONMAP0(vcvtq_u32_v),
+ NEONMAP0(vcvtq_u64_v),
+ NEONMAP0(vext_v),
+ NEONMAP0(vextq_v),
+ NEONMAP0(vfma_v),
+ NEONMAP0(vfmaq_v),
+ NEONMAP2(vhadd_v, arm_neon_vhaddu, arm_neon_vhadds, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vhaddq_v, arm_neon_vhaddu, arm_neon_vhadds, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vhsub_v, arm_neon_vhsubu, arm_neon_vhsubs, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vhsubq_v, arm_neon_vhsubu, arm_neon_vhsubs, Add1ArgType | UnsignedAlts),
+ NEONMAP0(vld1_dup_v),
+ NEONMAP1(vld1_v, arm_neon_vld1, 0),
+ NEONMAP0(vld1q_dup_v),
+ NEONMAP1(vld1q_v, arm_neon_vld1, 0),
+ NEONMAP1(vld2_lane_v, arm_neon_vld2lane, 0),
+ NEONMAP1(vld2_v, arm_neon_vld2, 0),
+ NEONMAP1(vld2q_lane_v, arm_neon_vld2lane, 0),
+ NEONMAP1(vld2q_v, arm_neon_vld2, 0),
+ NEONMAP1(vld3_lane_v, arm_neon_vld3lane, 0),
+ NEONMAP1(vld3_v, arm_neon_vld3, 0),
+ NEONMAP1(vld3q_lane_v, arm_neon_vld3lane, 0),
+ NEONMAP1(vld3q_v, arm_neon_vld3, 0),
+ NEONMAP1(vld4_lane_v, arm_neon_vld4lane, 0),
+ NEONMAP1(vld4_v, arm_neon_vld4, 0),
+ NEONMAP1(vld4q_lane_v, arm_neon_vld4lane, 0),
+ NEONMAP1(vld4q_v, arm_neon_vld4, 0),
+ NEONMAP2(vmax_v, arm_neon_vmaxu, arm_neon_vmaxs, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vmaxq_v, arm_neon_vmaxu, arm_neon_vmaxs, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vmin_v, arm_neon_vminu, arm_neon_vmins, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vminq_v, arm_neon_vminu, arm_neon_vmins, Add1ArgType | UnsignedAlts),
+ NEONMAP0(vmovl_v),
+ NEONMAP0(vmovn_v),
+ NEONMAP1(vmul_v, arm_neon_vmulp, Add1ArgType),
+ NEONMAP0(vmull_v),
+ NEONMAP1(vmulq_v, arm_neon_vmulp, Add1ArgType),
+ NEONMAP2(vpadal_v, arm_neon_vpadalu, arm_neon_vpadals, UnsignedAlts),
+ NEONMAP2(vpadalq_v, arm_neon_vpadalu, arm_neon_vpadals, UnsignedAlts),
+ NEONMAP1(vpadd_v, arm_neon_vpadd, Add1ArgType),
+ NEONMAP2(vpaddl_v, arm_neon_vpaddlu, arm_neon_vpaddls, UnsignedAlts),
+ NEONMAP2(vpaddlq_v, arm_neon_vpaddlu, arm_neon_vpaddls, UnsignedAlts),
+ NEONMAP1(vpaddq_v, arm_neon_vpadd, Add1ArgType),
+ NEONMAP2(vpmax_v, arm_neon_vpmaxu, arm_neon_vpmaxs, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vpmin_v, arm_neon_vpminu, arm_neon_vpmins, Add1ArgType | UnsignedAlts),
+ NEONMAP1(vqabs_v, arm_neon_vqabs, Add1ArgType),
+ NEONMAP1(vqabsq_v, arm_neon_vqabs, Add1ArgType),
+ NEONMAP2(vqadd_v, arm_neon_vqaddu, arm_neon_vqadds, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqaddq_v, arm_neon_vqaddu, arm_neon_vqadds, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqdmlal_v, arm_neon_vqdmull, arm_neon_vqadds, 0),
+ NEONMAP2(vqdmlsl_v, arm_neon_vqdmull, arm_neon_vqsubs, 0),
+ NEONMAP1(vqdmulh_v, arm_neon_vqdmulh, Add1ArgType),
+ NEONMAP1(vqdmulhq_v, arm_neon_vqdmulh, Add1ArgType),
+ NEONMAP1(vqdmull_v, arm_neon_vqdmull, Add1ArgType),
+ NEONMAP2(vqmovn_v, arm_neon_vqmovnu, arm_neon_vqmovns, Add1ArgType | UnsignedAlts),
+ NEONMAP1(vqmovun_v, arm_neon_vqmovnsu, Add1ArgType),
+ NEONMAP1(vqneg_v, arm_neon_vqneg, Add1ArgType),
+ NEONMAP1(vqnegq_v, arm_neon_vqneg, Add1ArgType),
+ NEONMAP1(vqrdmulh_v, arm_neon_vqrdmulh, Add1ArgType),
+ NEONMAP1(vqrdmulhq_v, arm_neon_vqrdmulh, Add1ArgType),
+ NEONMAP2(vqrshl_v, arm_neon_vqrshiftu, arm_neon_vqrshifts, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqrshlq_v, arm_neon_vqrshiftu, arm_neon_vqrshifts, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqshl_n_v, arm_neon_vqshiftu, arm_neon_vqshifts, UnsignedAlts),
+ NEONMAP2(vqshl_v, arm_neon_vqshiftu, arm_neon_vqshifts, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqshlq_n_v, arm_neon_vqshiftu, arm_neon_vqshifts, UnsignedAlts),
+ NEONMAP2(vqshlq_v, arm_neon_vqshiftu, arm_neon_vqshifts, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqsub_v, arm_neon_vqsubu, arm_neon_vqsubs, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqsubq_v, arm_neon_vqsubu, arm_neon_vqsubs, Add1ArgType | UnsignedAlts),
+ NEONMAP1(vraddhn_v, arm_neon_vraddhn, Add1ArgType),
+ NEONMAP2(vrecpe_v, arm_neon_vrecpe, arm_neon_vrecpe, 0),
+ NEONMAP2(vrecpeq_v, arm_neon_vrecpe, arm_neon_vrecpe, 0),
+ NEONMAP1(vrecps_v, arm_neon_vrecps, Add1ArgType),
+ NEONMAP1(vrecpsq_v, arm_neon_vrecps, Add1ArgType),
+ NEONMAP2(vrhadd_v, arm_neon_vrhaddu, arm_neon_vrhadds, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vrhaddq_v, arm_neon_vrhaddu, arm_neon_vrhadds, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vrshl_v, arm_neon_vrshiftu, arm_neon_vrshifts, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vrshlq_v, arm_neon_vrshiftu, arm_neon_vrshifts, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vrsqrte_v, arm_neon_vrsqrte, arm_neon_vrsqrte, 0),
+ NEONMAP2(vrsqrteq_v, arm_neon_vrsqrte, arm_neon_vrsqrte, 0),
+ NEONMAP1(vrsqrts_v, arm_neon_vrsqrts, Add1ArgType),
+ NEONMAP1(vrsqrtsq_v, arm_neon_vrsqrts, Add1ArgType),
+ NEONMAP1(vrsubhn_v, arm_neon_vrsubhn, Add1ArgType),
+ NEONMAP1(vsha1su0q_v, arm_neon_sha1su0, 0),
+ NEONMAP1(vsha1su1q_v, arm_neon_sha1su1, 0),
+ NEONMAP1(vsha256h2q_v, arm_neon_sha256h2, 0),
+ NEONMAP1(vsha256hq_v, arm_neon_sha256h, 0),
+ NEONMAP1(vsha256su0q_v, arm_neon_sha256su0, 0),
+ NEONMAP1(vsha256su1q_v, arm_neon_sha256su1, 0),
+ NEONMAP0(vshl_n_v),
+ NEONMAP2(vshl_v, arm_neon_vshiftu, arm_neon_vshifts, Add1ArgType | UnsignedAlts),
+ NEONMAP0(vshll_n_v),
+ NEONMAP0(vshlq_n_v),
+ NEONMAP2(vshlq_v, arm_neon_vshiftu, arm_neon_vshifts, Add1ArgType | UnsignedAlts),
+ NEONMAP0(vshr_n_v),
+ NEONMAP0(vshrn_n_v),
+ NEONMAP0(vshrq_n_v),
+ NEONMAP1(vst1_v, arm_neon_vst1, 0),
+ NEONMAP1(vst1q_v, arm_neon_vst1, 0),
+ NEONMAP1(vst2_lane_v, arm_neon_vst2lane, 0),
+ NEONMAP1(vst2_v, arm_neon_vst2, 0),
+ NEONMAP1(vst2q_lane_v, arm_neon_vst2lane, 0),
+ NEONMAP1(vst2q_v, arm_neon_vst2, 0),
+ NEONMAP1(vst3_lane_v, arm_neon_vst3lane, 0),
+ NEONMAP1(vst3_v, arm_neon_vst3, 0),
+ NEONMAP1(vst3q_lane_v, arm_neon_vst3lane, 0),
+ NEONMAP1(vst3q_v, arm_neon_vst3, 0),
+ NEONMAP1(vst4_lane_v, arm_neon_vst4lane, 0),
+ NEONMAP1(vst4_v, arm_neon_vst4, 0),
+ NEONMAP1(vst4q_lane_v, arm_neon_vst4lane, 0),
+ NEONMAP1(vst4q_v, arm_neon_vst4, 0),
+ NEONMAP0(vsubhn_v),
+ NEONMAP0(vtrn_v),
+ NEONMAP0(vtrnq_v),
+ NEONMAP0(vtst_v),
+ NEONMAP0(vtstq_v),
+ NEONMAP0(vuzp_v),
+ NEONMAP0(vuzpq_v),
+ NEONMAP0(vzip_v),
+ NEONMAP0(vzipq_v)
+};
+
+static NeonIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
+ NEONMAP1(vabs_v, aarch64_neon_abs, 0),
+ NEONMAP1(vabsq_v, aarch64_neon_abs, 0),
+ NEONMAP0(vaddhn_v),
+ NEONMAP1(vaesdq_v, aarch64_crypto_aesd, 0),
+ NEONMAP1(vaeseq_v, aarch64_crypto_aese, 0),
+ NEONMAP1(vaesimcq_v, aarch64_crypto_aesimc, 0),
+ NEONMAP1(vaesmcq_v, aarch64_crypto_aesmc, 0),
+ NEONMAP1(vcage_v, aarch64_neon_facge, 0),
+ NEONMAP1(vcageq_v, aarch64_neon_facge, 0),
+ NEONMAP1(vcagt_v, aarch64_neon_facgt, 0),
+ NEONMAP1(vcagtq_v, aarch64_neon_facgt, 0),
+ NEONMAP1(vcale_v, aarch64_neon_facge, 0),
+ NEONMAP1(vcaleq_v, aarch64_neon_facge, 0),
+ NEONMAP1(vcalt_v, aarch64_neon_facgt, 0),
+ NEONMAP1(vcaltq_v, aarch64_neon_facgt, 0),
+ NEONMAP1(vcls_v, aarch64_neon_cls, Add1ArgType),
+ NEONMAP1(vclsq_v, aarch64_neon_cls, Add1ArgType),
+ NEONMAP1(vclz_v, ctlz, Add1ArgType),
+ NEONMAP1(vclzq_v, ctlz, Add1ArgType),
+ NEONMAP1(vcnt_v, ctpop, Add1ArgType),
+ NEONMAP1(vcntq_v, ctpop, Add1ArgType),
+ NEONMAP1(vcvt_f16_v, aarch64_neon_vcvtfp2hf, 0),
+ NEONMAP1(vcvt_f32_f16, aarch64_neon_vcvthf2fp, 0),
+ NEONMAP0(vcvt_f32_v),
+ NEONMAP2(vcvt_n_f32_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
+ NEONMAP2(vcvt_n_f64_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
+ NEONMAP1(vcvt_n_s32_v, aarch64_neon_vcvtfp2fxs, 0),
+ NEONMAP1(vcvt_n_s64_v, aarch64_neon_vcvtfp2fxs, 0),
+ NEONMAP1(vcvt_n_u32_v, aarch64_neon_vcvtfp2fxu, 0),
+ NEONMAP1(vcvt_n_u64_v, aarch64_neon_vcvtfp2fxu, 0),
+ NEONMAP0(vcvtq_f32_v),
+ NEONMAP2(vcvtq_n_f32_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
+ NEONMAP2(vcvtq_n_f64_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
+ NEONMAP1(vcvtq_n_s32_v, aarch64_neon_vcvtfp2fxs, 0),
+ NEONMAP1(vcvtq_n_s64_v, aarch64_neon_vcvtfp2fxs, 0),
+ NEONMAP1(vcvtq_n_u32_v, aarch64_neon_vcvtfp2fxu, 0),
+ NEONMAP1(vcvtq_n_u64_v, aarch64_neon_vcvtfp2fxu, 0),
+ NEONMAP1(vcvtx_f32_v, aarch64_neon_fcvtxn, AddRetType | Add1ArgType),
+ NEONMAP0(vext_v),
+ NEONMAP0(vextq_v),
+ NEONMAP0(vfma_v),
+ NEONMAP0(vfmaq_v),
+ NEONMAP2(vhadd_v, aarch64_neon_uhadd, aarch64_neon_shadd, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vhaddq_v, aarch64_neon_uhadd, aarch64_neon_shadd, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vhsub_v, aarch64_neon_uhsub, aarch64_neon_shsub, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vhsubq_v, aarch64_neon_uhsub, aarch64_neon_shsub, Add1ArgType | UnsignedAlts),
+ NEONMAP0(vmovl_v),
+ NEONMAP0(vmovn_v),
+ NEONMAP1(vmul_v, aarch64_neon_pmul, Add1ArgType),
+ NEONMAP1(vmulq_v, aarch64_neon_pmul, Add1ArgType),
+ NEONMAP1(vpadd_v, aarch64_neon_addp, Add1ArgType),
+ NEONMAP2(vpaddl_v, aarch64_neon_uaddlp, aarch64_neon_saddlp, UnsignedAlts),
+ NEONMAP2(vpaddlq_v, aarch64_neon_uaddlp, aarch64_neon_saddlp, UnsignedAlts),
+ NEONMAP1(vpaddq_v, aarch64_neon_addp, Add1ArgType),
+ NEONMAP1(vqabs_v, aarch64_neon_sqabs, Add1ArgType),
+ NEONMAP1(vqabsq_v, aarch64_neon_sqabs, Add1ArgType),
+ NEONMAP2(vqadd_v, aarch64_neon_uqadd, aarch64_neon_sqadd, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqaddq_v, aarch64_neon_uqadd, aarch64_neon_sqadd, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqdmlal_v, aarch64_neon_sqdmull, aarch64_neon_sqadd, 0),
+ NEONMAP2(vqdmlsl_v, aarch64_neon_sqdmull, aarch64_neon_sqsub, 0),
+ NEONMAP1(vqdmulh_v, aarch64_neon_sqdmulh, Add1ArgType),
+ NEONMAP1(vqdmulhq_v, aarch64_neon_sqdmulh, Add1ArgType),
+ NEONMAP1(vqdmull_v, aarch64_neon_sqdmull, Add1ArgType),
+ NEONMAP2(vqmovn_v, aarch64_neon_uqxtn, aarch64_neon_sqxtn, Add1ArgType | UnsignedAlts),
+ NEONMAP1(vqmovun_v, aarch64_neon_sqxtun, Add1ArgType),
+ NEONMAP1(vqneg_v, aarch64_neon_sqneg, Add1ArgType),
+ NEONMAP1(vqnegq_v, aarch64_neon_sqneg, Add1ArgType),
+ NEONMAP1(vqrdmulh_v, aarch64_neon_sqrdmulh, Add1ArgType),
+ NEONMAP1(vqrdmulhq_v, aarch64_neon_sqrdmulh, Add1ArgType),
+ NEONMAP2(vqrshl_v, aarch64_neon_uqrshl, aarch64_neon_sqrshl, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqrshlq_v, aarch64_neon_uqrshl, aarch64_neon_sqrshl, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqshl_n_v, aarch64_neon_uqshl, aarch64_neon_sqshl, UnsignedAlts),
+ NEONMAP2(vqshl_v, aarch64_neon_uqshl, aarch64_neon_sqshl, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqshlq_n_v, aarch64_neon_uqshl, aarch64_neon_sqshl,UnsignedAlts),
+ NEONMAP2(vqshlq_v, aarch64_neon_uqshl, aarch64_neon_sqshl, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqsub_v, aarch64_neon_uqsub, aarch64_neon_sqsub, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vqsubq_v, aarch64_neon_uqsub, aarch64_neon_sqsub, Add1ArgType | UnsignedAlts),
+ NEONMAP1(vraddhn_v, aarch64_neon_raddhn, Add1ArgType),
+ NEONMAP2(vrecpe_v, aarch64_neon_frecpe, aarch64_neon_urecpe, 0),
+ NEONMAP2(vrecpeq_v, aarch64_neon_frecpe, aarch64_neon_urecpe, 0),
+ NEONMAP1(vrecps_v, aarch64_neon_frecps, Add1ArgType),
+ NEONMAP1(vrecpsq_v, aarch64_neon_frecps, Add1ArgType),
+ NEONMAP2(vrhadd_v, aarch64_neon_urhadd, aarch64_neon_srhadd, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vrhaddq_v, aarch64_neon_urhadd, aarch64_neon_srhadd, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vrshl_v, aarch64_neon_urshl, aarch64_neon_srshl, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vrshlq_v, aarch64_neon_urshl, aarch64_neon_srshl, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vrsqrte_v, aarch64_neon_frsqrte, aarch64_neon_ursqrte, 0),
+ NEONMAP2(vrsqrteq_v, aarch64_neon_frsqrte, aarch64_neon_ursqrte, 0),
+ NEONMAP1(vrsqrts_v, aarch64_neon_frsqrts, Add1ArgType),
+ NEONMAP1(vrsqrtsq_v, aarch64_neon_frsqrts, Add1ArgType),
+ NEONMAP1(vrsubhn_v, aarch64_neon_rsubhn, Add1ArgType),
+ NEONMAP1(vsha1su0q_v, aarch64_crypto_sha1su0, 0),
+ NEONMAP1(vsha1su1q_v, aarch64_crypto_sha1su1, 0),
+ NEONMAP1(vsha256h2q_v, aarch64_crypto_sha256h2, 0),
+ NEONMAP1(vsha256hq_v, aarch64_crypto_sha256h, 0),
+ NEONMAP1(vsha256su0q_v, aarch64_crypto_sha256su0, 0),
+ NEONMAP1(vsha256su1q_v, aarch64_crypto_sha256su1, 0),
+ NEONMAP0(vshl_n_v),
+ NEONMAP2(vshl_v, aarch64_neon_ushl, aarch64_neon_sshl, Add1ArgType | UnsignedAlts),
+ NEONMAP0(vshll_n_v),
+ NEONMAP0(vshlq_n_v),
+ NEONMAP2(vshlq_v, aarch64_neon_ushl, aarch64_neon_sshl, Add1ArgType | UnsignedAlts),
+ NEONMAP0(vshr_n_v),
+ NEONMAP0(vshrn_n_v),
+ NEONMAP0(vshrq_n_v),
+ NEONMAP0(vsubhn_v),
+ NEONMAP0(vtst_v),
+ NEONMAP0(vtstq_v),
+};
+
+static NeonIntrinsicInfo AArch64SISDIntrinsicMap[] = {
+ NEONMAP1(vabdd_f64, aarch64_sisd_fabd, Add1ArgType),
+ NEONMAP1(vabds_f32, aarch64_sisd_fabd, Add1ArgType),
+ NEONMAP1(vabsd_s64, aarch64_neon_abs, Add1ArgType),
+ NEONMAP1(vaddlv_s32, aarch64_neon_saddlv, AddRetType | Add1ArgType),
+ NEONMAP1(vaddlv_u32, aarch64_neon_uaddlv, AddRetType | Add1ArgType),
+ NEONMAP1(vaddlvq_s32, aarch64_neon_saddlv, AddRetType | Add1ArgType),
+ NEONMAP1(vaddlvq_u32, aarch64_neon_uaddlv, AddRetType | Add1ArgType),
+ NEONMAP1(vaddv_f32, aarch64_neon_faddv, AddRetType | Add1ArgType),
+ NEONMAP1(vaddv_s32, aarch64_neon_saddv, AddRetType | Add1ArgType),
+ NEONMAP1(vaddv_u32, aarch64_neon_uaddv, AddRetType | Add1ArgType),
+ NEONMAP1(vaddvq_f32, aarch64_neon_faddv, AddRetType | Add1ArgType),
+ NEONMAP1(vaddvq_f64, aarch64_neon_faddv, AddRetType | Add1ArgType),
+ NEONMAP1(vaddvq_s32, aarch64_neon_saddv, AddRetType | Add1ArgType),
+ NEONMAP1(vaddvq_s64, aarch64_neon_saddv, AddRetType | Add1ArgType),
+ NEONMAP1(vaddvq_u32, aarch64_neon_uaddv, AddRetType | Add1ArgType),
+ NEONMAP1(vaddvq_u64, aarch64_neon_uaddv, AddRetType | Add1ArgType),
+ NEONMAP1(vcaged_f64, aarch64_neon_facge, AddRetType | Add1ArgType),
+ NEONMAP1(vcages_f32, aarch64_neon_facge, AddRetType | Add1ArgType),
+ NEONMAP1(vcagtd_f64, aarch64_neon_facgt, AddRetType | Add1ArgType),
+ NEONMAP1(vcagts_f32, aarch64_neon_facgt, AddRetType | Add1ArgType),
+ NEONMAP1(vcaled_f64, aarch64_neon_facge, AddRetType | Add1ArgType),
+ NEONMAP1(vcales_f32, aarch64_neon_facge, AddRetType | Add1ArgType),
+ NEONMAP1(vcaltd_f64, aarch64_neon_facgt, AddRetType | Add1ArgType),
+ NEONMAP1(vcalts_f32, aarch64_neon_facgt, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtad_s64_f64, aarch64_neon_fcvtas, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtad_u64_f64, aarch64_neon_fcvtau, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtas_s32_f32, aarch64_neon_fcvtas, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtas_u32_f32, aarch64_neon_fcvtau, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtd_n_f64_s64, aarch64_neon_vcvtfxs2fp, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtd_n_f64_u64, aarch64_neon_vcvtfxu2fp, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtd_n_s64_f64, aarch64_neon_vcvtfp2fxs, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtd_n_u64_f64, aarch64_neon_vcvtfp2fxu, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtmd_s64_f64, aarch64_neon_fcvtms, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtmd_u64_f64, aarch64_neon_fcvtmu, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtms_s32_f32, aarch64_neon_fcvtms, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtms_u32_f32, aarch64_neon_fcvtmu, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtnd_s64_f64, aarch64_neon_fcvtns, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtnd_u64_f64, aarch64_neon_fcvtnu, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtns_s32_f32, aarch64_neon_fcvtns, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtns_u32_f32, aarch64_neon_fcvtnu, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtpd_s64_f64, aarch64_neon_fcvtps, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtpd_u64_f64, aarch64_neon_fcvtpu, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtps_s32_f32, aarch64_neon_fcvtps, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtps_u32_f32, aarch64_neon_fcvtpu, AddRetType | Add1ArgType),
+ NEONMAP1(vcvts_n_f32_s32, aarch64_neon_vcvtfxs2fp, AddRetType | Add1ArgType),
+ NEONMAP1(vcvts_n_f32_u32, aarch64_neon_vcvtfxu2fp, AddRetType | Add1ArgType),
+ NEONMAP1(vcvts_n_s32_f32, aarch64_neon_vcvtfp2fxs, AddRetType | Add1ArgType),
+ NEONMAP1(vcvts_n_u32_f32, aarch64_neon_vcvtfp2fxu, AddRetType | Add1ArgType),
+ NEONMAP1(vcvtxd_f32_f64, aarch64_sisd_fcvtxn, 0),
+ NEONMAP1(vmaxnmv_f32, aarch64_neon_fmaxnmv, AddRetType | Add1ArgType),
+ NEONMAP1(vmaxnmvq_f32, aarch64_neon_fmaxnmv, AddRetType | Add1ArgType),
+ NEONMAP1(vmaxnmvq_f64, aarch64_neon_fmaxnmv, AddRetType | Add1ArgType),
+ NEONMAP1(vmaxv_f32, aarch64_neon_fmaxv, AddRetType | Add1ArgType),
+ NEONMAP1(vmaxv_s32, aarch64_neon_smaxv, AddRetType | Add1ArgType),
+ NEONMAP1(vmaxv_u32, aarch64_neon_umaxv, AddRetType | Add1ArgType),
+ NEONMAP1(vmaxvq_f32, aarch64_neon_fmaxv, AddRetType | Add1ArgType),
+ NEONMAP1(vmaxvq_f64, aarch64_neon_fmaxv, AddRetType | Add1ArgType),
+ NEONMAP1(vmaxvq_s32, aarch64_neon_smaxv, AddRetType | Add1ArgType),
+ NEONMAP1(vmaxvq_u32, aarch64_neon_umaxv, AddRetType | Add1ArgType),
+ NEONMAP1(vminnmv_f32, aarch64_neon_fminnmv, AddRetType | Add1ArgType),
+ NEONMAP1(vminnmvq_f32, aarch64_neon_fminnmv, AddRetType | Add1ArgType),
+ NEONMAP1(vminnmvq_f64, aarch64_neon_fminnmv, AddRetType | Add1ArgType),
+ NEONMAP1(vminv_f32, aarch64_neon_fminv, AddRetType | Add1ArgType),
+ NEONMAP1(vminv_s32, aarch64_neon_sminv, AddRetType | Add1ArgType),
+ NEONMAP1(vminv_u32, aarch64_neon_uminv, AddRetType | Add1ArgType),
+ NEONMAP1(vminvq_f32, aarch64_neon_fminv, AddRetType | Add1ArgType),
+ NEONMAP1(vminvq_f64, aarch64_neon_fminv, AddRetType | Add1ArgType),
+ NEONMAP1(vminvq_s32, aarch64_neon_sminv, AddRetType | Add1ArgType),
+ NEONMAP1(vminvq_u32, aarch64_neon_uminv, AddRetType | Add1ArgType),
+ NEONMAP1(vmull_p64, aarch64_neon_pmull64, 0),
+ NEONMAP1(vmulxd_f64, aarch64_neon_fmulx, Add1ArgType),
+ NEONMAP1(vmulxs_f32, aarch64_neon_fmulx, Add1ArgType),
+ NEONMAP1(vpaddd_s64, aarch64_neon_uaddv, AddRetType | Add1ArgType),
+ NEONMAP1(vpaddd_u64, aarch64_neon_uaddv, AddRetType | Add1ArgType),
+ NEONMAP1(vpmaxnmqd_f64, aarch64_neon_fmaxnmv, AddRetType | Add1ArgType),
+ NEONMAP1(vpmaxnms_f32, aarch64_neon_fmaxnmv, AddRetType | Add1ArgType),
+ NEONMAP1(vpmaxqd_f64, aarch64_neon_fmaxv, AddRetType | Add1ArgType),
+ NEONMAP1(vpmaxs_f32, aarch64_neon_fmaxv, AddRetType | Add1ArgType),
+ NEONMAP1(vpminnmqd_f64, aarch64_neon_fminnmv, AddRetType | Add1ArgType),
+ NEONMAP1(vpminnms_f32, aarch64_neon_fminnmv, AddRetType | Add1ArgType),
+ NEONMAP1(vpminqd_f64, aarch64_neon_fminv, AddRetType | Add1ArgType),
+ NEONMAP1(vpmins_f32, aarch64_neon_fminv, AddRetType | Add1ArgType),
+ NEONMAP1(vqabsb_s8, aarch64_neon_sqabs, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqabsd_s64, aarch64_neon_sqabs, Add1ArgType),
+ NEONMAP1(vqabsh_s16, aarch64_neon_sqabs, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqabss_s32, aarch64_neon_sqabs, Add1ArgType),
+ NEONMAP1(vqaddb_s8, aarch64_neon_sqadd, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqaddb_u8, aarch64_neon_uqadd, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqaddd_s64, aarch64_neon_sqadd, Add1ArgType),
+ NEONMAP1(vqaddd_u64, aarch64_neon_uqadd, Add1ArgType),
+ NEONMAP1(vqaddh_s16, aarch64_neon_sqadd, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqaddh_u16, aarch64_neon_uqadd, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqadds_s32, aarch64_neon_sqadd, Add1ArgType),
+ NEONMAP1(vqadds_u32, aarch64_neon_uqadd, Add1ArgType),
+ NEONMAP1(vqdmulhh_s16, aarch64_neon_sqdmulh, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqdmulhs_s32, aarch64_neon_sqdmulh, Add1ArgType),
+ NEONMAP1(vqdmullh_s16, aarch64_neon_sqdmull, VectorRet | Use128BitVectors),
+ NEONMAP1(vqdmulls_s32, aarch64_neon_sqdmulls_scalar, 0),
+ NEONMAP1(vqmovnd_s64, aarch64_neon_scalar_sqxtn, AddRetType | Add1ArgType),
+ NEONMAP1(vqmovnd_u64, aarch64_neon_scalar_uqxtn, AddRetType | Add1ArgType),
+ NEONMAP1(vqmovnh_s16, aarch64_neon_sqxtn, VectorRet | Use64BitVectors),
+ NEONMAP1(vqmovnh_u16, aarch64_neon_uqxtn, VectorRet | Use64BitVectors),
+ NEONMAP1(vqmovns_s32, aarch64_neon_sqxtn, VectorRet | Use64BitVectors),
+ NEONMAP1(vqmovns_u32, aarch64_neon_uqxtn, VectorRet | Use64BitVectors),
+ NEONMAP1(vqmovund_s64, aarch64_neon_scalar_sqxtun, AddRetType | Add1ArgType),
+ NEONMAP1(vqmovunh_s16, aarch64_neon_sqxtun, VectorRet | Use64BitVectors),
+ NEONMAP1(vqmovuns_s32, aarch64_neon_sqxtun, VectorRet | Use64BitVectors),
+ NEONMAP1(vqnegb_s8, aarch64_neon_sqneg, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqnegd_s64, aarch64_neon_sqneg, Add1ArgType),
+ NEONMAP1(vqnegh_s16, aarch64_neon_sqneg, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqnegs_s32, aarch64_neon_sqneg, Add1ArgType),
+ NEONMAP1(vqrdmulhh_s16, aarch64_neon_sqrdmulh, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqrdmulhs_s32, aarch64_neon_sqrdmulh, Add1ArgType),
+ NEONMAP1(vqrshlb_s8, aarch64_neon_sqrshl, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqrshlb_u8, aarch64_neon_uqrshl, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqrshld_s64, aarch64_neon_sqrshl, Add1ArgType),
+ NEONMAP1(vqrshld_u64, aarch64_neon_uqrshl, Add1ArgType),
+ NEONMAP1(vqrshlh_s16, aarch64_neon_sqrshl, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqrshlh_u16, aarch64_neon_uqrshl, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqrshls_s32, aarch64_neon_sqrshl, Add1ArgType),
+ NEONMAP1(vqrshls_u32, aarch64_neon_uqrshl, Add1ArgType),
+ NEONMAP1(vqrshrnd_n_s64, aarch64_neon_sqrshrn, AddRetType),
+ NEONMAP1(vqrshrnd_n_u64, aarch64_neon_uqrshrn, AddRetType),
+ NEONMAP1(vqrshrnh_n_s16, aarch64_neon_sqrshrn, VectorRet | Use64BitVectors),
+ NEONMAP1(vqrshrnh_n_u16, aarch64_neon_uqrshrn, VectorRet | Use64BitVectors),
+ NEONMAP1(vqrshrns_n_s32, aarch64_neon_sqrshrn, VectorRet | Use64BitVectors),
+ NEONMAP1(vqrshrns_n_u32, aarch64_neon_uqrshrn, VectorRet | Use64BitVectors),
+ NEONMAP1(vqrshrund_n_s64, aarch64_neon_sqrshrun, AddRetType),
+ NEONMAP1(vqrshrunh_n_s16, aarch64_neon_sqrshrun, VectorRet | Use64BitVectors),
+ NEONMAP1(vqrshruns_n_s32, aarch64_neon_sqrshrun, VectorRet | Use64BitVectors),
+ NEONMAP1(vqshlb_n_s8, aarch64_neon_sqshl, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqshlb_n_u8, aarch64_neon_uqshl, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqshlb_s8, aarch64_neon_sqshl, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqshlb_u8, aarch64_neon_uqshl, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqshld_s64, aarch64_neon_sqshl, Add1ArgType),
+ NEONMAP1(vqshld_u64, aarch64_neon_uqshl, Add1ArgType),
+ NEONMAP1(vqshlh_n_s16, aarch64_neon_sqshl, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqshlh_n_u16, aarch64_neon_uqshl, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqshlh_s16, aarch64_neon_sqshl, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqshlh_u16, aarch64_neon_uqshl, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqshls_n_s32, aarch64_neon_sqshl, Add1ArgType),
+ NEONMAP1(vqshls_n_u32, aarch64_neon_uqshl, Add1ArgType),
+ NEONMAP1(vqshls_s32, aarch64_neon_sqshl, Add1ArgType),
+ NEONMAP1(vqshls_u32, aarch64_neon_uqshl, Add1ArgType),
+ NEONMAP1(vqshlub_n_s8, aarch64_neon_sqshlu, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqshluh_n_s16, aarch64_neon_sqshlu, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqshlus_n_s32, aarch64_neon_sqshlu, Add1ArgType),
+ NEONMAP1(vqshrnd_n_s64, aarch64_neon_sqshrn, AddRetType),
+ NEONMAP1(vqshrnd_n_u64, aarch64_neon_uqshrn, AddRetType),
+ NEONMAP1(vqshrnh_n_s16, aarch64_neon_sqshrn, VectorRet | Use64BitVectors),
+ NEONMAP1(vqshrnh_n_u16, aarch64_neon_uqshrn, VectorRet | Use64BitVectors),
+ NEONMAP1(vqshrns_n_s32, aarch64_neon_sqshrn, VectorRet | Use64BitVectors),
+ NEONMAP1(vqshrns_n_u32, aarch64_neon_uqshrn, VectorRet | Use64BitVectors),
+ NEONMAP1(vqshrund_n_s64, aarch64_neon_sqshrun, AddRetType),
+ NEONMAP1(vqshrunh_n_s16, aarch64_neon_sqshrun, VectorRet | Use64BitVectors),
+ NEONMAP1(vqshruns_n_s32, aarch64_neon_sqshrun, VectorRet | Use64BitVectors),
+ NEONMAP1(vqsubb_s8, aarch64_neon_sqsub, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqsubb_u8, aarch64_neon_uqsub, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqsubd_s64, aarch64_neon_sqsub, Add1ArgType),
+ NEONMAP1(vqsubd_u64, aarch64_neon_uqsub, Add1ArgType),
+ NEONMAP1(vqsubh_s16, aarch64_neon_sqsub, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqsubh_u16, aarch64_neon_uqsub, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vqsubs_s32, aarch64_neon_sqsub, Add1ArgType),
+ NEONMAP1(vqsubs_u32, aarch64_neon_uqsub, Add1ArgType),
+ NEONMAP1(vrecped_f64, aarch64_neon_frecpe, Add1ArgType),
+ NEONMAP1(vrecpes_f32, aarch64_neon_frecpe, Add1ArgType),
+ NEONMAP1(vrecpxd_f64, aarch64_neon_frecpx, Add1ArgType),
+ NEONMAP1(vrecpxs_f32, aarch64_neon_frecpx, Add1ArgType),
+ NEONMAP1(vrshld_s64, aarch64_neon_srshl, Add1ArgType),
+ NEONMAP1(vrshld_u64, aarch64_neon_urshl, Add1ArgType),
+ NEONMAP1(vrsqrted_f64, aarch64_neon_frsqrte, Add1ArgType),
+ NEONMAP1(vrsqrtes_f32, aarch64_neon_frsqrte, Add1ArgType),
+ NEONMAP1(vrsqrtsd_f64, aarch64_neon_frsqrts, Add1ArgType),
+ NEONMAP1(vrsqrtss_f32, aarch64_neon_frsqrts, Add1ArgType),
+ NEONMAP1(vsha1cq_u32, aarch64_crypto_sha1c, 0),
+ NEONMAP1(vsha1h_u32, aarch64_crypto_sha1h, 0),
+ NEONMAP1(vsha1mq_u32, aarch64_crypto_sha1m, 0),
+ NEONMAP1(vsha1pq_u32, aarch64_crypto_sha1p, 0),
+ NEONMAP1(vshld_s64, aarch64_neon_sshl, Add1ArgType),
+ NEONMAP1(vshld_u64, aarch64_neon_ushl, Add1ArgType),
+ NEONMAP1(vslid_n_s64, aarch64_neon_vsli, Vectorize1ArgType),
+ NEONMAP1(vslid_n_u64, aarch64_neon_vsli, Vectorize1ArgType),
+ NEONMAP1(vsqaddb_u8, aarch64_neon_usqadd, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vsqaddd_u64, aarch64_neon_usqadd, Add1ArgType),
+ NEONMAP1(vsqaddh_u16, aarch64_neon_usqadd, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vsqadds_u32, aarch64_neon_usqadd, Add1ArgType),
+ NEONMAP1(vsrid_n_s64, aarch64_neon_vsri, Vectorize1ArgType),
+ NEONMAP1(vsrid_n_u64, aarch64_neon_vsri, Vectorize1ArgType),
+ NEONMAP1(vuqaddb_s8, aarch64_neon_suqadd, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vuqaddd_s64, aarch64_neon_suqadd, Add1ArgType),
+ NEONMAP1(vuqaddh_s16, aarch64_neon_suqadd, Vectorize1ArgType | Use64BitVectors),
+ NEONMAP1(vuqadds_s32, aarch64_neon_suqadd, Add1ArgType),
+};
+
+#undef NEONMAP0
+#undef NEONMAP1
+#undef NEONMAP2
+
+static bool NEONSIMDIntrinsicsProvenSorted = false;
+
+static bool AArch64SIMDIntrinsicsProvenSorted = false;
+static bool AArch64SISDIntrinsicsProvenSorted = false;
+
+
+static const NeonIntrinsicInfo *
+findNeonIntrinsicInMap(ArrayRef<NeonIntrinsicInfo> IntrinsicMap,
+ unsigned BuiltinID, bool &MapProvenSorted) {
+
+#ifndef NDEBUG
+ if (!MapProvenSorted) {
+ // FIXME: use std::is_sorted once C++11 is allowed
+ for (unsigned i = 0; i < IntrinsicMap.size() - 1; ++i)
+ assert(IntrinsicMap[i].BuiltinID <= IntrinsicMap[i + 1].BuiltinID);
+ MapProvenSorted = true;
+ }
+#endif
+
+ const NeonIntrinsicInfo *Builtin =
+ std::lower_bound(IntrinsicMap.begin(), IntrinsicMap.end(), BuiltinID);
+
+ if (Builtin != IntrinsicMap.end() && Builtin->BuiltinID == BuiltinID)
+ return Builtin;
+
+ return nullptr;
}
-Value *CodeGenFunction::EmitAArch64CompareBuiltinExpr(
- Value *Op, llvm::Type *Ty, const CmpInst::Predicate Fp,
- const CmpInst::Predicate Ip, const Twine &Name) {
- llvm::Type *OTy = ((llvm::User *)Op)->getOperand(0)->getType();
- if (OTy->isPointerTy())
- OTy = Ty;
- Op = Builder.CreateBitCast(Op, OTy);
- if (((llvm::VectorType *)OTy)->getElementType()->isFloatingPointTy()) {
- Op = Builder.CreateFCmp(Fp, Op, ConstantAggregateZero::get(OTy));
- } else {
- Op = Builder.CreateICmp(Ip, Op, ConstantAggregateZero::get(OTy));
- }
- return Builder.CreateZExt(Op, Ty, Name);
-}
+Function *CodeGenFunction::LookupNeonLLVMIntrinsic(unsigned IntrinsicID,
+ unsigned Modifier,
+ llvm::Type *ArgType,
+ const CallExpr *E) {
+ int VectorSize = 0;
+ if (Modifier & Use64BitVectors)
+ VectorSize = 64;
+ else if (Modifier & Use128BitVectors)
+ VectorSize = 128;
-static Value *packTBLDVectorList(CodeGenFunction &CGF, ArrayRef<Value *> Ops,
- Value *ExtOp, Value *IndexOp,
- llvm::Type *ResTy, unsigned IntID,
- const char *Name) {
- SmallVector<Value *, 2> TblOps;
- if (ExtOp)
- TblOps.push_back(ExtOp);
+ // Return type.
+ SmallVector<llvm::Type *, 3> Tys;
+ if (Modifier & AddRetType) {
+ llvm::Type *Ty = ConvertType(E->getCallReturnType());
+ if (Modifier & VectorizeRetType)
+ Ty = llvm::VectorType::get(
+ Ty, VectorSize ? VectorSize / Ty->getPrimitiveSizeInBits() : 1);
- // Build a vector containing sequential number like (0, 1, 2, ..., 15)
- SmallVector<Constant*, 16> Indices;
- llvm::VectorType *TblTy = cast<llvm::VectorType>(Ops[0]->getType());
- for (unsigned i = 0, e = TblTy->getNumElements(); i != e; ++i) {
- Indices.push_back(ConstantInt::get(CGF.Int32Ty, 2*i));
- Indices.push_back(ConstantInt::get(CGF.Int32Ty, 2*i+1));
+ Tys.push_back(Ty);
}
- Value *SV = llvm::ConstantVector::get(Indices);
- int PairPos = 0, End = Ops.size() - 1;
- while (PairPos < End) {
- TblOps.push_back(CGF.Builder.CreateShuffleVector(Ops[PairPos],
- Ops[PairPos+1], SV, Name));
- PairPos += 2;
+ // Arguments.
+ if (Modifier & VectorizeArgTypes) {
+ int Elts = VectorSize ? VectorSize / ArgType->getPrimitiveSizeInBits() : 1;
+ ArgType = llvm::VectorType::get(ArgType, Elts);
}
- // If there's an odd number of 64-bit lookup table, fill the high 64-bit
- // of the 128-bit lookup table with zero.
- if (PairPos == End) {
- Value *ZeroTbl = ConstantAggregateZero::get(TblTy);
- TblOps.push_back(CGF.Builder.CreateShuffleVector(Ops[PairPos],
- ZeroTbl, SV, Name));
- }
+ if (Modifier & (Add1ArgType | Add2ArgTypes))
+ Tys.push_back(ArgType);
- TblTy = llvm::VectorType::get(TblTy->getElementType(),
- 2*TblTy->getNumElements());
- llvm::Type *Tys[2] = { ResTy, TblTy };
+ if (Modifier & Add2ArgTypes)
+ Tys.push_back(ArgType);
- Function *TblF;
- TblOps.push_back(IndexOp);
- TblF = CGF.CGM.getIntrinsic(IntID, Tys);
-
- return CGF.EmitNeonCall(TblF, TblOps, Name);
+ if (Modifier & InventFloatType)
+ Tys.push_back(FloatTy);
+
+ return CGM.getIntrinsic(IntrinsicID, Tys);
}
-static Value *EmitAArch64TblBuiltinExpr(CodeGenFunction &CGF,
- unsigned BuiltinID,
- const CallExpr *E) {
- unsigned int Int = 0;
- const char *s = NULL;
+static Value *EmitCommonNeonSISDBuiltinExpr(CodeGenFunction &CGF,
+ const NeonIntrinsicInfo &SISDInfo,
+ SmallVectorImpl<Value *> &Ops,
+ const CallExpr *E) {
+ unsigned BuiltinID = SISDInfo.BuiltinID;
+ unsigned int Int = SISDInfo.LLVMIntrinsic;
+ unsigned Modifier = SISDInfo.TypeModifier;
+ const char *s = SISDInfo.NameHint;
- unsigned TblPos;
switch (BuiltinID) {
- default:
- return 0;
- case AArch64::BI__builtin_neon_vtbl1_v:
- case AArch64::BI__builtin_neon_vqtbl1_v:
- case AArch64::BI__builtin_neon_vqtbl1q_v:
- case AArch64::BI__builtin_neon_vtbl2_v:
- case AArch64::BI__builtin_neon_vqtbl2_v:
- case AArch64::BI__builtin_neon_vqtbl2q_v:
- case AArch64::BI__builtin_neon_vtbl3_v:
- case AArch64::BI__builtin_neon_vqtbl3_v:
- case AArch64::BI__builtin_neon_vqtbl3q_v:
- case AArch64::BI__builtin_neon_vtbl4_v:
- case AArch64::BI__builtin_neon_vqtbl4_v:
- case AArch64::BI__builtin_neon_vqtbl4q_v:
- TblPos = 0;
- break;
- case AArch64::BI__builtin_neon_vtbx1_v:
- case AArch64::BI__builtin_neon_vqtbx1_v:
- case AArch64::BI__builtin_neon_vqtbx1q_v:
- case AArch64::BI__builtin_neon_vtbx2_v:
- case AArch64::BI__builtin_neon_vqtbx2_v:
- case AArch64::BI__builtin_neon_vqtbx2q_v:
- case AArch64::BI__builtin_neon_vtbx3_v:
- case AArch64::BI__builtin_neon_vqtbx3_v:
- case AArch64::BI__builtin_neon_vqtbx3q_v:
- case AArch64::BI__builtin_neon_vtbx4_v:
- case AArch64::BI__builtin_neon_vqtbx4_v:
- case AArch64::BI__builtin_neon_vqtbx4q_v:
- TblPos = 1;
+ case NEON::BI__builtin_neon_vcled_s64:
+ case NEON::BI__builtin_neon_vcled_u64:
+ case NEON::BI__builtin_neon_vcles_f32:
+ case NEON::BI__builtin_neon_vcled_f64:
+ case NEON::BI__builtin_neon_vcltd_s64:
+ case NEON::BI__builtin_neon_vcltd_u64:
+ case NEON::BI__builtin_neon_vclts_f32:
+ case NEON::BI__builtin_neon_vcltd_f64:
+ case NEON::BI__builtin_neon_vcales_f32:
+ case NEON::BI__builtin_neon_vcaled_f64:
+ case NEON::BI__builtin_neon_vcalts_f32:
+ case NEON::BI__builtin_neon_vcaltd_f64:
+ // Only one direction of comparisons actually exist, cmle is actually a cmge
+ // with swapped operands. The table gives us the right intrinsic but we
+ // still need to do the swap.
+ std::swap(Ops[0], Ops[1]);
break;
}
- assert(E->getNumArgs() >= 3);
-
- // Get the last argument, which specifies the vector type.
- llvm::APSInt Result;
- const Expr *Arg = E->getArg(E->getNumArgs() - 1);
- if (!Arg->isIntegerConstantExpr(Result, CGF.getContext()))
- return 0;
-
- // Determine the type of this overloaded NEON intrinsic.
- NeonTypeFlags Type(Result.getZExtValue());
- llvm::VectorType *VTy = GetNeonType(&CGF, Type);
- llvm::Type *Ty = VTy;
- if (!Ty)
- return 0;
-
- SmallVector<Value *, 4> Ops;
- for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++) {
- Ops.push_back(CGF.EmitScalarExpr(E->getArg(i)));
- }
-
- Arg = E->getArg(TblPos);
- llvm::Type *TblTy = CGF.ConvertType(Arg->getType());
- llvm::VectorType *VTblTy = cast<llvm::VectorType>(TblTy);
- llvm::Type *Tys[2] = { Ty, VTblTy };
- unsigned nElts = VTy->getNumElements();
+ assert(Int && "Generic code assumes a valid intrinsic");
- // AArch64 scalar builtins are not overloaded, they do not have an extra
- // argument that specifies the vector type, need to handle each case.
- SmallVector<Value *, 2> TblOps;
- switch (BuiltinID) {
- case AArch64::BI__builtin_neon_vtbl1_v: {
- TblOps.push_back(Ops[0]);
- return packTBLDVectorList(CGF, TblOps, 0, Ops[1], Ty,
- Intrinsic::aarch64_neon_vtbl1, "vtbl1");
- }
- case AArch64::BI__builtin_neon_vtbl2_v: {
- TblOps.push_back(Ops[0]);
- TblOps.push_back(Ops[1]);
- return packTBLDVectorList(CGF, TblOps, 0, Ops[2], Ty,
- Intrinsic::aarch64_neon_vtbl1, "vtbl1");
- }
- case AArch64::BI__builtin_neon_vtbl3_v: {
- TblOps.push_back(Ops[0]);
- TblOps.push_back(Ops[1]);
- TblOps.push_back(Ops[2]);
- return packTBLDVectorList(CGF, TblOps, 0, Ops[3], Ty,
- Intrinsic::aarch64_neon_vtbl2, "vtbl2");
- }
- case AArch64::BI__builtin_neon_vtbl4_v: {
- TblOps.push_back(Ops[0]);
- TblOps.push_back(Ops[1]);
- TblOps.push_back(Ops[2]);
- TblOps.push_back(Ops[3]);
- return packTBLDVectorList(CGF, TblOps, 0, Ops[4], Ty,
- Intrinsic::aarch64_neon_vtbl2, "vtbl2");
- }
- case AArch64::BI__builtin_neon_vtbx1_v: {
- TblOps.push_back(Ops[1]);
- Value *TblRes = packTBLDVectorList(CGF, TblOps, 0, Ops[2], Ty,
- Intrinsic::aarch64_neon_vtbl1, "vtbl1");
-
- llvm::Constant *Eight = ConstantInt::get(VTy->getElementType(), 8);
- Value* EightV = llvm::ConstantVector::getSplat(nElts, Eight);
- Value *CmpRes = CGF.Builder.CreateICmp(ICmpInst::ICMP_UGE, Ops[2], EightV);
- CmpRes = CGF.Builder.CreateSExt(CmpRes, Ty);
+ // Determine the type(s) of this overloaded AArch64 intrinsic.
+ const Expr *Arg = E->getArg(0);
+ llvm::Type *ArgTy = CGF.ConvertType(Arg->getType());
+ Function *F = CGF.LookupNeonLLVMIntrinsic(Int, Modifier, ArgTy, E);
- SmallVector<Value *, 4> BslOps;
- BslOps.push_back(CmpRes);
- BslOps.push_back(Ops[0]);
- BslOps.push_back(TblRes);
- Function *BslF = CGF.CGM.getIntrinsic(Intrinsic::arm_neon_vbsl, Ty);
- return CGF.EmitNeonCall(BslF, BslOps, "vbsl");
- }
- case AArch64::BI__builtin_neon_vtbx2_v: {
- TblOps.push_back(Ops[1]);
- TblOps.push_back(Ops[2]);
- return packTBLDVectorList(CGF, TblOps, Ops[0], Ops[3], Ty,
- Intrinsic::aarch64_neon_vtbx1, "vtbx1");
- }
- case AArch64::BI__builtin_neon_vtbx3_v: {
- TblOps.push_back(Ops[1]);
- TblOps.push_back(Ops[2]);
- TblOps.push_back(Ops[3]);
- Value *TblRes = packTBLDVectorList(CGF, TblOps, 0, Ops[4], Ty,
- Intrinsic::aarch64_neon_vtbl2, "vtbl2");
+ int j = 0;
+ ConstantInt *C0 = ConstantInt::get(CGF.SizeTy, 0);
+ for (Function::const_arg_iterator ai = F->arg_begin(), ae = F->arg_end();
+ ai != ae; ++ai, ++j) {
+ llvm::Type *ArgTy = ai->getType();
+ if (Ops[j]->getType()->getPrimitiveSizeInBits() ==
+ ArgTy->getPrimitiveSizeInBits())
+ continue;
- llvm::Constant *TwentyFour = ConstantInt::get(VTy->getElementType(), 24);
- Value* TwentyFourV = llvm::ConstantVector::getSplat(nElts, TwentyFour);
- Value *CmpRes = CGF.Builder.CreateICmp(ICmpInst::ICMP_UGE, Ops[4],
- TwentyFourV);
- CmpRes = CGF.Builder.CreateSExt(CmpRes, Ty);
-
- SmallVector<Value *, 4> BslOps;
- BslOps.push_back(CmpRes);
- BslOps.push_back(Ops[0]);
- BslOps.push_back(TblRes);
- Function *BslF = CGF.CGM.getIntrinsic(Intrinsic::arm_neon_vbsl, Ty);
- return CGF.EmitNeonCall(BslF, BslOps, "vbsl");
- }
- case AArch64::BI__builtin_neon_vtbx4_v: {
- TblOps.push_back(Ops[1]);
- TblOps.push_back(Ops[2]);
- TblOps.push_back(Ops[3]);
- TblOps.push_back(Ops[4]);
- return packTBLDVectorList(CGF, TblOps, Ops[0], Ops[5], Ty,
- Intrinsic::aarch64_neon_vtbx2, "vtbx2");
- }
- case AArch64::BI__builtin_neon_vqtbl1_v:
- case AArch64::BI__builtin_neon_vqtbl1q_v:
- Int = Intrinsic::aarch64_neon_vtbl1; s = "vtbl1"; break;
- case AArch64::BI__builtin_neon_vqtbl2_v:
- case AArch64::BI__builtin_neon_vqtbl2q_v: {
- Int = Intrinsic::aarch64_neon_vtbl2; s = "vtbl2"; break;
- case AArch64::BI__builtin_neon_vqtbl3_v:
- case AArch64::BI__builtin_neon_vqtbl3q_v:
- Int = Intrinsic::aarch64_neon_vtbl3; s = "vtbl3"; break;
- case AArch64::BI__builtin_neon_vqtbl4_v:
- case AArch64::BI__builtin_neon_vqtbl4q_v:
- Int = Intrinsic::aarch64_neon_vtbl4; s = "vtbl4"; break;
- case AArch64::BI__builtin_neon_vqtbx1_v:
- case AArch64::BI__builtin_neon_vqtbx1q_v:
- Int = Intrinsic::aarch64_neon_vtbx1; s = "vtbx1"; break;
- case AArch64::BI__builtin_neon_vqtbx2_v:
- case AArch64::BI__builtin_neon_vqtbx2q_v:
- Int = Intrinsic::aarch64_neon_vtbx2; s = "vtbx2"; break;
- case AArch64::BI__builtin_neon_vqtbx3_v:
- case AArch64::BI__builtin_neon_vqtbx3q_v:
- Int = Intrinsic::aarch64_neon_vtbx3; s = "vtbx3"; break;
- case AArch64::BI__builtin_neon_vqtbx4_v:
- case AArch64::BI__builtin_neon_vqtbx4q_v:
- Int = Intrinsic::aarch64_neon_vtbx4; s = "vtbx4"; break;
- }
+ assert(ArgTy->isVectorTy() && !Ops[j]->getType()->isVectorTy());
+ // The constant argument to an _n_ intrinsic always has Int32Ty, so truncate
+ // it before inserting.
+ Ops[j] =
+ CGF.Builder.CreateTruncOrBitCast(Ops[j], ArgTy->getVectorElementType());
+ Ops[j] =
+ CGF.Builder.CreateInsertElement(UndefValue::get(ArgTy), Ops[j], C0);
}
- if (!Int)
- return 0;
+ Value *Result = CGF.EmitNeonCall(F, Ops, s);
+ llvm::Type *ResultType = CGF.ConvertType(E->getType());
+ if (ResultType->getPrimitiveSizeInBits() <
+ Result->getType()->getPrimitiveSizeInBits())
+ return CGF.Builder.CreateExtractElement(Result, C0);
- Function *F = CGF.CGM.getIntrinsic(Int, Tys);
- return CGF.EmitNeonCall(F, Ops, s);
+ return CGF.Builder.CreateBitCast(Result, ResultType, s);
}
-Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
- const CallExpr *E) {
- // Process AArch64 scalar builtins
- if (Value *Result = EmitAArch64ScalarBuiltinExpr(*this, BuiltinID, E))
- return Result;
-
- // Process AArch64 table lookup builtins
- if (Value *Result = EmitAArch64TblBuiltinExpr(*this, BuiltinID, E))
- return Result;
-
- if (BuiltinID == AArch64::BI__clear_cache) {
- assert(E->getNumArgs() == 2 &&
- "Variadic __clear_cache slipped through on AArch64");
-
- const FunctionDecl *FD = E->getDirectCallee();
- SmallVector<Value *, 2> Ops;
- for (unsigned i = 0; i < E->getNumArgs(); i++)
- Ops.push_back(EmitScalarExpr(E->getArg(i)));
- llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType());
- llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
- StringRef Name = FD->getName();
- return EmitNounwindRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name), Ops);
- }
-
- SmallVector<Value *, 4> Ops;
- llvm::Value *Align = 0; // Alignment for load/store
- for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++) {
- if (i == 0) {
- switch (BuiltinID) {
- case AArch64::BI__builtin_neon_vst1_x2_v:
- case AArch64::BI__builtin_neon_vst1q_x2_v:
- case AArch64::BI__builtin_neon_vst1_x3_v:
- case AArch64::BI__builtin_neon_vst1q_x3_v:
- case AArch64::BI__builtin_neon_vst1_x4_v:
- case AArch64::BI__builtin_neon_vst1q_x4_v:
- // Handle ld1/st1 lane in this function a little different from ARM.
- case AArch64::BI__builtin_neon_vld1_lane_v:
- case AArch64::BI__builtin_neon_vld1q_lane_v:
- case AArch64::BI__builtin_neon_vst1_lane_v:
- case AArch64::BI__builtin_neon_vst1q_lane_v:
- // Get the alignment for the argument in addition to the value;
- // we'll use it later.
- std::pair<llvm::Value *, unsigned> Src =
- EmitPointerWithAlignment(E->getArg(0));
- Ops.push_back(Src.first);
- Align = Builder.getInt32(Src.second);
- continue;
- }
- }
- if (i == 1) {
- switch (BuiltinID) {
- case AArch64::BI__builtin_neon_vld1_x2_v:
- case AArch64::BI__builtin_neon_vld1q_x2_v:
- case AArch64::BI__builtin_neon_vld1_x3_v:
- case AArch64::BI__builtin_neon_vld1q_x3_v:
- case AArch64::BI__builtin_neon_vld1_x4_v:
- case AArch64::BI__builtin_neon_vld1q_x4_v:
- // Handle ld1/st1 dup lane in this function a little different from ARM.
- case AArch64::BI__builtin_neon_vld2_dup_v:
- case AArch64::BI__builtin_neon_vld2q_dup_v:
- case AArch64::BI__builtin_neon_vld3_dup_v:
- case AArch64::BI__builtin_neon_vld3q_dup_v:
- case AArch64::BI__builtin_neon_vld4_dup_v:
- case AArch64::BI__builtin_neon_vld4q_dup_v:
- case AArch64::BI__builtin_neon_vld2_lane_v:
- case AArch64::BI__builtin_neon_vld2q_lane_v:
- // Get the alignment for the argument in addition to the value;
- // we'll use it later.
- std::pair<llvm::Value *, unsigned> Src =
- EmitPointerWithAlignment(E->getArg(1));
- Ops.push_back(Src.first);
- Align = Builder.getInt32(Src.second);
- continue;
- }
- }
- Ops.push_back(EmitScalarExpr(E->getArg(i)));
- }
-
+Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
+ unsigned BuiltinID, unsigned LLVMIntrinsic, unsigned AltLLVMIntrinsic,
+ const char *NameHint, unsigned Modifier, const CallExpr *E,
+ SmallVectorImpl<llvm::Value *> &Ops, llvm::Value *Align) {
// Get the last argument, which specifies the vector type.
- llvm::APSInt Result;
+ llvm::APSInt NeonTypeConst;
const Expr *Arg = E->getArg(E->getNumArgs() - 1);
- if (!Arg->isIntegerConstantExpr(Result, getContext()))
- return 0;
+ if (!Arg->isIntegerConstantExpr(NeonTypeConst, getContext()))
+ return nullptr;
// Determine the type of this overloaded NEON intrinsic.
- NeonTypeFlags Type(Result.getZExtValue());
- bool usgn = Type.isUnsigned();
- bool quad = Type.isQuad();
+ NeonTypeFlags Type(NeonTypeConst.getZExtValue());
+ bool Usgn = Type.isUnsigned();
+ bool Quad = Type.isQuad();
llvm::VectorType *VTy = GetNeonType(this, Type);
llvm::Type *Ty = VTy;
if (!Ty)
- return 0;
+ return nullptr;
+
+ unsigned Int = LLVMIntrinsic;
+ if ((Modifier & UnsignedAlts) && !Usgn)
+ Int = AltLLVMIntrinsic;
- unsigned Int;
switch (BuiltinID) {
- default:
- return 0;
-
- // AArch64 builtins mapping to legacy ARM v7 builtins.
- // FIXME: the mapped builtins listed correspond to what has been tested
- // in aarch64-neon-intrinsics.c so far.
- case AArch64::BI__builtin_neon_vuzp_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vuzp_v, E);
- case AArch64::BI__builtin_neon_vuzpq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vuzpq_v, E);
- case AArch64::BI__builtin_neon_vzip_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vzip_v, E);
- case AArch64::BI__builtin_neon_vzipq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vzipq_v, E);
- case AArch64::BI__builtin_neon_vtrn_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vtrn_v, E);
- case AArch64::BI__builtin_neon_vtrnq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vtrnq_v, E);
- case AArch64::BI__builtin_neon_vext_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vext_v, E);
- case AArch64::BI__builtin_neon_vextq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vextq_v, E);
- case AArch64::BI__builtin_neon_vmul_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vmul_v, E);
- case AArch64::BI__builtin_neon_vmulq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vmulq_v, E);
- case AArch64::BI__builtin_neon_vabd_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vabd_v, E);
- case AArch64::BI__builtin_neon_vabdq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vabdq_v, E);
- case AArch64::BI__builtin_neon_vfma_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vfma_v, E);
- case AArch64::BI__builtin_neon_vfmaq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vfmaq_v, E);
- case AArch64::BI__builtin_neon_vbsl_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vbsl_v, E);
- case AArch64::BI__builtin_neon_vbslq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vbslq_v, E);
- case AArch64::BI__builtin_neon_vrsqrts_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrsqrts_v, E);
- case AArch64::BI__builtin_neon_vrsqrtsq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrsqrtsq_v, E);
- case AArch64::BI__builtin_neon_vrecps_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrecps_v, E);
- case AArch64::BI__builtin_neon_vrecpsq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrecpsq_v, E);
- case AArch64::BI__builtin_neon_vcale_v:
- if (VTy->getVectorNumElements() == 1) {
- std::swap(Ops[0], Ops[1]);
- } else {
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcale_v, E);
- }
- case AArch64::BI__builtin_neon_vcage_v:
- if (VTy->getVectorNumElements() == 1) {
- // Determine the types of this overloaded AArch64 intrinsic
- SmallVector<llvm::Type *, 3> Tys;
- Tys.push_back(VTy);
- VTy = llvm::VectorType::get(DoubleTy, 1);
- Tys.push_back(VTy);
- Tys.push_back(VTy);
- Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_vcage, Tys);
- return EmitNeonCall(F, Ops, "vcage");
- }
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcage_v, E);
- case AArch64::BI__builtin_neon_vcaleq_v:
- std::swap(Ops[0], Ops[1]);
- case AArch64::BI__builtin_neon_vcageq_v: {
- Function *F;
- if (VTy->getElementType()->isIntegerTy(64))
- F = CGM.getIntrinsic(Intrinsic::aarch64_neon_vacgeq);
- else
- F = CGM.getIntrinsic(Intrinsic::arm_neon_vacgeq);
- return EmitNeonCall(F, Ops, "vcage");
+ default: break;
+ case NEON::BI__builtin_neon_vabs_v:
+ case NEON::BI__builtin_neon_vabsq_v:
+ if (VTy->getElementType()->isFloatingPointTy())
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::fabs, Ty), Ops, "vabs");
+ return EmitNeonCall(CGM.getIntrinsic(LLVMIntrinsic, Ty), Ops, "vabs");
+ case NEON::BI__builtin_neon_vaddhn_v: {
+ llvm::VectorType *SrcTy =
+ llvm::VectorType::getExtendedElementVectorType(VTy);
+
+ // %sum = add <4 x i32> %lhs, %rhs
+ Ops[0] = Builder.CreateBitCast(Ops[0], SrcTy);
+ Ops[1] = Builder.CreateBitCast(Ops[1], SrcTy);
+ Ops[0] = Builder.CreateAdd(Ops[0], Ops[1], "vaddhn");
+
+ // %high = lshr <4 x i32> %sum, <i32 16, i32 16, i32 16, i32 16>
+ Constant *ShiftAmt = ConstantInt::get(SrcTy->getElementType(),
+ SrcTy->getScalarSizeInBits() / 2);
+ ShiftAmt = ConstantVector::getSplat(VTy->getNumElements(), ShiftAmt);
+ Ops[0] = Builder.CreateLShr(Ops[0], ShiftAmt, "vaddhn");
+
+ // %res = trunc <4 x i32> %high to <4 x i16>
+ return Builder.CreateTrunc(Ops[0], VTy, "vaddhn");
}
- case AArch64::BI__builtin_neon_vcalt_v:
- if (VTy->getVectorNumElements() == 1) {
- std::swap(Ops[0], Ops[1]);
- } else {
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcalt_v, E);
- }
- case AArch64::BI__builtin_neon_vcagt_v:
- if (VTy->getVectorNumElements() == 1) {
- // Determine the types of this overloaded AArch64 intrinsic
- SmallVector<llvm::Type *, 3> Tys;
- Tys.push_back(VTy);
- VTy = llvm::VectorType::get(DoubleTy, 1);
- Tys.push_back(VTy);
- Tys.push_back(VTy);
- Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_vcagt, Tys);
- return EmitNeonCall(F, Ops, "vcagt");
- }
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcagt_v, E);
- case AArch64::BI__builtin_neon_vcaltq_v:
+ case NEON::BI__builtin_neon_vcale_v:
+ case NEON::BI__builtin_neon_vcaleq_v:
+ case NEON::BI__builtin_neon_vcalt_v:
+ case NEON::BI__builtin_neon_vcaltq_v:
std::swap(Ops[0], Ops[1]);
- case AArch64::BI__builtin_neon_vcagtq_v: {
- Function *F;
- if (VTy->getElementType()->isIntegerTy(64))
- F = CGM.getIntrinsic(Intrinsic::aarch64_neon_vacgtq);
- else
- F = CGM.getIntrinsic(Intrinsic::arm_neon_vacgtq);
- return EmitNeonCall(F, Ops, "vcagt");
- }
- case AArch64::BI__builtin_neon_vtst_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vtst_v, E);
- case AArch64::BI__builtin_neon_vtstq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vtstq_v, E);
- case AArch64::BI__builtin_neon_vhadd_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vhadd_v, E);
- case AArch64::BI__builtin_neon_vhaddq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vhaddq_v, E);
- case AArch64::BI__builtin_neon_vhsub_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vhsub_v, E);
- case AArch64::BI__builtin_neon_vhsubq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vhsubq_v, E);
- case AArch64::BI__builtin_neon_vrhadd_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrhadd_v, E);
- case AArch64::BI__builtin_neon_vrhaddq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrhaddq_v, E);
- case AArch64::BI__builtin_neon_vqadd_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqadd_v, E);
- case AArch64::BI__builtin_neon_vqaddq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqaddq_v, E);
- case AArch64::BI__builtin_neon_vqsub_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqsub_v, E);
- case AArch64::BI__builtin_neon_vqsubq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqsubq_v, E);
- case AArch64::BI__builtin_neon_vshl_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vshl_v, E);
- case AArch64::BI__builtin_neon_vshlq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vshlq_v, E);
- case AArch64::BI__builtin_neon_vqshl_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqshl_v, E);
- case AArch64::BI__builtin_neon_vqshlq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqshlq_v, E);
- case AArch64::BI__builtin_neon_vrshl_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrshl_v, E);
- case AArch64::BI__builtin_neon_vrshlq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrshlq_v, E);
- case AArch64::BI__builtin_neon_vqrshl_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqrshl_v, E);
- case AArch64::BI__builtin_neon_vqrshlq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqrshlq_v, E);
- case AArch64::BI__builtin_neon_vaddhn_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vaddhn_v, E);
- case AArch64::BI__builtin_neon_vraddhn_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vraddhn_v, E);
- case AArch64::BI__builtin_neon_vsubhn_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vsubhn_v, E);
- case AArch64::BI__builtin_neon_vrsubhn_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrsubhn_v, E);
- case AArch64::BI__builtin_neon_vmull_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vmull_v, E);
- case AArch64::BI__builtin_neon_vqdmull_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqdmull_v, E);
- case AArch64::BI__builtin_neon_vqdmlal_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqdmlal_v, E);
- case AArch64::BI__builtin_neon_vqdmlsl_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqdmlsl_v, E);
- case AArch64::BI__builtin_neon_vmax_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vmax_v, E);
- case AArch64::BI__builtin_neon_vmaxq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vmaxq_v, E);
- case AArch64::BI__builtin_neon_vmin_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vmin_v, E);
- case AArch64::BI__builtin_neon_vminq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vminq_v, E);
- case AArch64::BI__builtin_neon_vpmax_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vpmax_v, E);
- case AArch64::BI__builtin_neon_vpmin_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vpmin_v, E);
- case AArch64::BI__builtin_neon_vpadd_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vpadd_v, E);
- case AArch64::BI__builtin_neon_vqdmulh_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqdmulh_v, E);
- case AArch64::BI__builtin_neon_vqdmulhq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqdmulhq_v, E);
- case AArch64::BI__builtin_neon_vqrdmulh_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqrdmulh_v, E);
- case AArch64::BI__builtin_neon_vqrdmulhq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqrdmulhq_v, E);
-
- // Shift by immediate
- case AArch64::BI__builtin_neon_vshr_n_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vshr_n_v, E);
- case AArch64::BI__builtin_neon_vshrq_n_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vshrq_n_v, E);
- case AArch64::BI__builtin_neon_vrshr_n_v:
- case AArch64::BI__builtin_neon_vrshrq_n_v:
- Int = usgn ? Intrinsic::aarch64_neon_vurshr
- : Intrinsic::aarch64_neon_vsrshr;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrshr_n");
- case AArch64::BI__builtin_neon_vsra_n_v:
- if (VTy->getElementType()->isIntegerTy(64)) {
- Int = usgn ? Intrinsic::aarch64_neon_vsradu_n
- : Intrinsic::aarch64_neon_vsrads_n;
- return EmitNeonCall(CGM.getIntrinsic(Int), Ops, "vsra_n");
- }
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vsra_n_v, E);
- case AArch64::BI__builtin_neon_vsraq_n_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vsraq_n_v, E);
- case AArch64::BI__builtin_neon_vrsra_n_v:
- if (VTy->getElementType()->isIntegerTy(64)) {
- Int = usgn ? Intrinsic::aarch64_neon_vrsradu_n
- : Intrinsic::aarch64_neon_vrsrads_n;
- return EmitNeonCall(CGM.getIntrinsic(Int), Ops, "vrsra_n");
- }
- // fall through
- case AArch64::BI__builtin_neon_vrsraq_n_v: {
+ case NEON::BI__builtin_neon_vcage_v:
+ case NEON::BI__builtin_neon_vcageq_v:
+ case NEON::BI__builtin_neon_vcagt_v:
+ case NEON::BI__builtin_neon_vcagtq_v: {
+ llvm::Type *VecFlt = llvm::VectorType::get(
+ VTy->getScalarSizeInBits() == 32 ? FloatTy : DoubleTy,
+ VTy->getNumElements());
+ llvm::Type *Tys[] = { VTy, VecFlt };
+ Function *F = CGM.getIntrinsic(LLVMIntrinsic, Tys);
+ return EmitNeonCall(F, Ops, NameHint);
+ }
+ case NEON::BI__builtin_neon_vclz_v:
+ case NEON::BI__builtin_neon_vclzq_v:
+ // We generate target-independent intrinsic, which needs a second argument
+ // for whether or not clz of zero is undefined; on ARM it isn't.
+ Ops.push_back(Builder.getInt1(getTarget().isCLZForZeroUndef()));
+ break;
+ case NEON::BI__builtin_neon_vcvt_f32_v:
+ case NEON::BI__builtin_neon_vcvtq_f32_v:
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Int = usgn ? Intrinsic::aarch64_neon_vurshr
- : Intrinsic::aarch64_neon_vsrshr;
- Ops[1] = Builder.CreateCall2(CGM.getIntrinsic(Int, Ty), Ops[1], Ops[2]);
- return Builder.CreateAdd(Ops[0], Ops[1], "vrsra_n");
- }
- case AArch64::BI__builtin_neon_vshl_n_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vshl_n_v, E);
- case AArch64::BI__builtin_neon_vshlq_n_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vshlq_n_v, E);
- case AArch64::BI__builtin_neon_vqshl_n_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqshl_n_v, E);
- case AArch64::BI__builtin_neon_vqshlq_n_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqshlq_n_v, E);
- case AArch64::BI__builtin_neon_vqshlu_n_v:
- case AArch64::BI__builtin_neon_vqshluq_n_v:
- Int = Intrinsic::aarch64_neon_vsqshlu;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshlu_n");
- case AArch64::BI__builtin_neon_vsri_n_v:
- case AArch64::BI__builtin_neon_vsriq_n_v:
- Int = Intrinsic::aarch64_neon_vsri;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vsri_n");
- case AArch64::BI__builtin_neon_vsli_n_v:
- case AArch64::BI__builtin_neon_vsliq_n_v:
- Int = Intrinsic::aarch64_neon_vsli;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vsli_n");
- case AArch64::BI__builtin_neon_vshll_n_v: {
- llvm::Type *SrcTy = llvm::VectorType::getTruncatedElementVectorType(VTy);
- Ops[0] = Builder.CreateBitCast(Ops[0], SrcTy);
- if (usgn)
- Ops[0] = Builder.CreateZExt(Ops[0], VTy);
- else
- Ops[0] = Builder.CreateSExt(Ops[0], VTy);
- Ops[1] = EmitNeonShiftVector(Ops[1], VTy, false);
- return Builder.CreateShl(Ops[0], Ops[1], "vshll_n");
- }
- case AArch64::BI__builtin_neon_vshrn_n_v: {
- llvm::Type *SrcTy = llvm::VectorType::getExtendedElementVectorType(VTy);
- Ops[0] = Builder.CreateBitCast(Ops[0], SrcTy);
- Ops[1] = EmitNeonShiftVector(Ops[1], SrcTy, false);
- if (usgn)
- Ops[0] = Builder.CreateLShr(Ops[0], Ops[1]);
- else
- Ops[0] = Builder.CreateAShr(Ops[0], Ops[1]);
- return Builder.CreateTrunc(Ops[0], Ty, "vshrn_n");
- }
- case AArch64::BI__builtin_neon_vqshrun_n_v:
- Int = Intrinsic::aarch64_neon_vsqshrun;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshrun_n");
- case AArch64::BI__builtin_neon_vrshrn_n_v:
- Int = Intrinsic::aarch64_neon_vrshrn;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrshrn_n");
- case AArch64::BI__builtin_neon_vqrshrun_n_v:
- Int = Intrinsic::aarch64_neon_vsqrshrun;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshrun_n");
- case AArch64::BI__builtin_neon_vqshrn_n_v:
- Int = usgn ? Intrinsic::aarch64_neon_vuqshrn
- : Intrinsic::aarch64_neon_vsqshrn;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshrn_n");
- case AArch64::BI__builtin_neon_vqrshrn_n_v:
- Int = usgn ? Intrinsic::aarch64_neon_vuqrshrn
- : Intrinsic::aarch64_neon_vsqrshrn;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshrn_n");
-
- // Convert
- case AArch64::BI__builtin_neon_vmovl_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vmovl_v, E);
- case AArch64::BI__builtin_neon_vcvt_n_f32_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvt_n_f32_v, E);
- case AArch64::BI__builtin_neon_vcvtq_n_f32_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvtq_n_f32_v, E);
- case AArch64::BI__builtin_neon_vcvt_n_f64_v:
- case AArch64::BI__builtin_neon_vcvtq_n_f64_v: {
+ Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, Quad));
+ return Usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt")
+ : Builder.CreateSIToFP(Ops[0], Ty, "vcvt");
+ case NEON::BI__builtin_neon_vcvt_n_f32_v:
+ case NEON::BI__builtin_neon_vcvt_n_f64_v:
+ case NEON::BI__builtin_neon_vcvtq_n_f32_v:
+ case NEON::BI__builtin_neon_vcvtq_n_f64_v: {
+ bool Double =
+ (cast<llvm::IntegerType>(VTy->getElementType())->getBitWidth() == 64);
llvm::Type *FloatTy =
- GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float64, false, quad));
+ GetNeonType(this, NeonTypeFlags(Double ? NeonTypeFlags::Float64
+ : NeonTypeFlags::Float32,
+ false, Quad));
llvm::Type *Tys[2] = { FloatTy, Ty };
- Int = usgn ? Intrinsic::arm_neon_vcvtfxu2fp
- : Intrinsic::arm_neon_vcvtfxs2fp;
+ Int = Usgn ? LLVMIntrinsic : AltLLVMIntrinsic;
Function *F = CGM.getIntrinsic(Int, Tys);
return EmitNeonCall(F, Ops, "vcvt_n");
}
- case AArch64::BI__builtin_neon_vcvt_n_s32_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvt_n_s32_v, E);
- case AArch64::BI__builtin_neon_vcvtq_n_s32_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvtq_n_s32_v, E);
- case AArch64::BI__builtin_neon_vcvt_n_u32_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvt_n_u32_v, E);
- case AArch64::BI__builtin_neon_vcvtq_n_u32_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvtq_n_u32_v, E);
- case AArch64::BI__builtin_neon_vcvt_n_s64_v:
- case AArch64::BI__builtin_neon_vcvt_n_u64_v:
- case AArch64::BI__builtin_neon_vcvtq_n_s64_v:
- case AArch64::BI__builtin_neon_vcvtq_n_u64_v: {
+ case NEON::BI__builtin_neon_vcvt_n_s32_v:
+ case NEON::BI__builtin_neon_vcvt_n_u32_v:
+ case NEON::BI__builtin_neon_vcvt_n_s64_v:
+ case NEON::BI__builtin_neon_vcvt_n_u64_v:
+ case NEON::BI__builtin_neon_vcvtq_n_s32_v:
+ case NEON::BI__builtin_neon_vcvtq_n_u32_v:
+ case NEON::BI__builtin_neon_vcvtq_n_s64_v:
+ case NEON::BI__builtin_neon_vcvtq_n_u64_v: {
+ bool Double =
+ (cast<llvm::IntegerType>(VTy->getElementType())->getBitWidth() == 64);
llvm::Type *FloatTy =
- GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float64, false, quad));
+ GetNeonType(this, NeonTypeFlags(Double ? NeonTypeFlags::Float64
+ : NeonTypeFlags::Float32,
+ false, Quad));
llvm::Type *Tys[2] = { Ty, FloatTy };
- Int = usgn ? Intrinsic::arm_neon_vcvtfp2fxu
- : Intrinsic::arm_neon_vcvtfp2fxs;
- Function *F = CGM.getIntrinsic(Int, Tys);
+ Function *F = CGM.getIntrinsic(LLVMIntrinsic, Tys);
return EmitNeonCall(F, Ops, "vcvt_n");
}
+ case NEON::BI__builtin_neon_vcvt_s32_v:
+ case NEON::BI__builtin_neon_vcvt_u32_v:
+ case NEON::BI__builtin_neon_vcvt_s64_v:
+ case NEON::BI__builtin_neon_vcvt_u64_v:
+ case NEON::BI__builtin_neon_vcvtq_s32_v:
+ case NEON::BI__builtin_neon_vcvtq_u32_v:
+ case NEON::BI__builtin_neon_vcvtq_s64_v:
+ case NEON::BI__builtin_neon_vcvtq_u64_v: {
+ bool Double =
+ (cast<llvm::IntegerType>(VTy->getElementType())->getBitWidth() == 64);
+ llvm::Type *FloatTy =
+ GetNeonType(this, NeonTypeFlags(Double ? NeonTypeFlags::Float64
+ : NeonTypeFlags::Float32,
+ false, Quad));
+ Ops[0] = Builder.CreateBitCast(Ops[0], FloatTy);
+ return Usgn ? Builder.CreateFPToUI(Ops[0], Ty, "vcvt")
+ : Builder.CreateFPToSI(Ops[0], Ty, "vcvt");
+ }
+ case NEON::BI__builtin_neon_vcvta_s32_v:
+ case NEON::BI__builtin_neon_vcvta_s64_v:
+ case NEON::BI__builtin_neon_vcvta_u32_v:
+ case NEON::BI__builtin_neon_vcvta_u64_v:
+ case NEON::BI__builtin_neon_vcvtaq_s32_v:
+ case NEON::BI__builtin_neon_vcvtaq_s64_v:
+ case NEON::BI__builtin_neon_vcvtaq_u32_v:
+ case NEON::BI__builtin_neon_vcvtaq_u64_v:
+ case NEON::BI__builtin_neon_vcvtn_s32_v:
+ case NEON::BI__builtin_neon_vcvtn_s64_v:
+ case NEON::BI__builtin_neon_vcvtn_u32_v:
+ case NEON::BI__builtin_neon_vcvtn_u64_v:
+ case NEON::BI__builtin_neon_vcvtnq_s32_v:
+ case NEON::BI__builtin_neon_vcvtnq_s64_v:
+ case NEON::BI__builtin_neon_vcvtnq_u32_v:
+ case NEON::BI__builtin_neon_vcvtnq_u64_v:
+ case NEON::BI__builtin_neon_vcvtp_s32_v:
+ case NEON::BI__builtin_neon_vcvtp_s64_v:
+ case NEON::BI__builtin_neon_vcvtp_u32_v:
+ case NEON::BI__builtin_neon_vcvtp_u64_v:
+ case NEON::BI__builtin_neon_vcvtpq_s32_v:
+ case NEON::BI__builtin_neon_vcvtpq_s64_v:
+ case NEON::BI__builtin_neon_vcvtpq_u32_v:
+ case NEON::BI__builtin_neon_vcvtpq_u64_v:
+ case NEON::BI__builtin_neon_vcvtm_s32_v:
+ case NEON::BI__builtin_neon_vcvtm_s64_v:
+ case NEON::BI__builtin_neon_vcvtm_u32_v:
+ case NEON::BI__builtin_neon_vcvtm_u64_v:
+ case NEON::BI__builtin_neon_vcvtmq_s32_v:
+ case NEON::BI__builtin_neon_vcvtmq_s64_v:
+ case NEON::BI__builtin_neon_vcvtmq_u32_v:
+ case NEON::BI__builtin_neon_vcvtmq_u64_v: {
+ bool Double =
+ (cast<llvm::IntegerType>(VTy->getElementType())->getBitWidth() == 64);
+ llvm::Type *InTy =
+ GetNeonType(this,
+ NeonTypeFlags(Double ? NeonTypeFlags::Float64
+ : NeonTypeFlags::Float32, false, Quad));
+ llvm::Type *Tys[2] = { Ty, InTy };
+ return EmitNeonCall(CGM.getIntrinsic(LLVMIntrinsic, Tys), Ops, NameHint);
+ }
+ case NEON::BI__builtin_neon_vext_v:
+ case NEON::BI__builtin_neon_vextq_v: {
+ int CV = cast<ConstantInt>(Ops[2])->getSExtValue();
+ SmallVector<Constant*, 16> Indices;
+ for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i)
+ Indices.push_back(ConstantInt::get(Int32Ty, i+CV));
- // Load/Store
- case AArch64::BI__builtin_neon_vld1_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld1_v, E);
- case AArch64::BI__builtin_neon_vld1q_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld1q_v, E);
- case AArch64::BI__builtin_neon_vld2_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld2_v, E);
- case AArch64::BI__builtin_neon_vld2q_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld2q_v, E);
- case AArch64::BI__builtin_neon_vld3_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld3_v, E);
- case AArch64::BI__builtin_neon_vld3q_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld3q_v, E);
- case AArch64::BI__builtin_neon_vld4_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld4_v, E);
- case AArch64::BI__builtin_neon_vld4q_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld4q_v, E);
- case AArch64::BI__builtin_neon_vst1_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst1_v, E);
- case AArch64::BI__builtin_neon_vst1q_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst1q_v, E);
- case AArch64::BI__builtin_neon_vst2_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst2_v, E);
- case AArch64::BI__builtin_neon_vst2q_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst2q_v, E);
- case AArch64::BI__builtin_neon_vst3_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst3_v, E);
- case AArch64::BI__builtin_neon_vst3q_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst3q_v, E);
- case AArch64::BI__builtin_neon_vst4_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst4_v, E);
- case AArch64::BI__builtin_neon_vst4q_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst4q_v, E);
- case AArch64::BI__builtin_neon_vld1_x2_v:
- case AArch64::BI__builtin_neon_vld1q_x2_v:
- case AArch64::BI__builtin_neon_vld1_x3_v:
- case AArch64::BI__builtin_neon_vld1q_x3_v:
- case AArch64::BI__builtin_neon_vld1_x4_v:
- case AArch64::BI__builtin_neon_vld1q_x4_v: {
- unsigned Int;
- switch (BuiltinID) {
- case AArch64::BI__builtin_neon_vld1_x2_v:
- case AArch64::BI__builtin_neon_vld1q_x2_v:
- Int = Intrinsic::aarch64_neon_vld1x2;
- break;
- case AArch64::BI__builtin_neon_vld1_x3_v:
- case AArch64::BI__builtin_neon_vld1q_x3_v:
- Int = Intrinsic::aarch64_neon_vld1x3;
- break;
- case AArch64::BI__builtin_neon_vld1_x4_v:
- case AArch64::BI__builtin_neon_vld1q_x4_v:
- Int = Intrinsic::aarch64_neon_vld1x4;
- break;
- }
- Function *F = CGM.getIntrinsic(Int, Ty);
- Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld1xN");
- Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- return Builder.CreateStore(Ops[1], Ops[0]);
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+ Value *SV = llvm::ConstantVector::get(Indices);
+ return Builder.CreateShuffleVector(Ops[0], Ops[1], SV, "vext");
+ }
+ case NEON::BI__builtin_neon_vfma_v:
+ case NEON::BI__builtin_neon_vfmaq_v: {
+ Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+ Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
+
+ // NEON intrinsic puts accumulator first, unlike the LLVM fma.
+ return Builder.CreateCall3(F, Ops[1], Ops[2], Ops[0]);
}
- case AArch64::BI__builtin_neon_vst1_x2_v:
- case AArch64::BI__builtin_neon_vst1q_x2_v:
- case AArch64::BI__builtin_neon_vst1_x3_v:
- case AArch64::BI__builtin_neon_vst1q_x3_v:
- case AArch64::BI__builtin_neon_vst1_x4_v:
- case AArch64::BI__builtin_neon_vst1q_x4_v: {
+ case NEON::BI__builtin_neon_vld1_v:
+ case NEON::BI__builtin_neon_vld1q_v:
Ops.push_back(Align);
- unsigned Int;
- switch (BuiltinID) {
- case AArch64::BI__builtin_neon_vst1_x2_v:
- case AArch64::BI__builtin_neon_vst1q_x2_v:
- Int = Intrinsic::aarch64_neon_vst1x2;
- break;
- case AArch64::BI__builtin_neon_vst1_x3_v:
- case AArch64::BI__builtin_neon_vst1q_x3_v:
- Int = Intrinsic::aarch64_neon_vst1x3;
- break;
- case AArch64::BI__builtin_neon_vst1_x4_v:
- case AArch64::BI__builtin_neon_vst1q_x4_v:
- Int = Intrinsic::aarch64_neon_vst1x4;
- break;
- }
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "");
+ return EmitNeonCall(CGM.getIntrinsic(LLVMIntrinsic, Ty), Ops, "vld1");
+ case NEON::BI__builtin_neon_vld2_v:
+ case NEON::BI__builtin_neon_vld2q_v:
+ case NEON::BI__builtin_neon_vld3_v:
+ case NEON::BI__builtin_neon_vld3q_v:
+ case NEON::BI__builtin_neon_vld4_v:
+ case NEON::BI__builtin_neon_vld4q_v: {
+ Function *F = CGM.getIntrinsic(LLVMIntrinsic, Ty);
+ Ops[1] = Builder.CreateCall2(F, Ops[1], Align, NameHint);
+ Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ return Builder.CreateStore(Ops[1], Ops[0]);
}
- case AArch64::BI__builtin_neon_vld1_lane_v:
- case AArch64::BI__builtin_neon_vld1q_lane_v: {
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+ case NEON::BI__builtin_neon_vld1_dup_v:
+ case NEON::BI__builtin_neon_vld1q_dup_v: {
+ Value *V = UndefValue::get(Ty);
Ty = llvm::PointerType::getUnqual(VTy->getElementType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
LoadInst *Ld = Builder.CreateLoad(Ops[0]);
Ld->setAlignment(cast<ConstantInt>(Align)->getZExtValue());
- return Builder.CreateInsertElement(Ops[1], Ld, Ops[2], "vld1_lane");
- }
- case AArch64::BI__builtin_neon_vld2_lane_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld2q_lane_v, E);
- case AArch64::BI__builtin_neon_vld2q_lane_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld2q_lane_v, E);
- case AArch64::BI__builtin_neon_vld3_lane_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld3_lane_v, E);
- case AArch64::BI__builtin_neon_vld3q_lane_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld3q_lane_v, E);
- case AArch64::BI__builtin_neon_vld4_lane_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld4_lane_v, E);
- case AArch64::BI__builtin_neon_vld4q_lane_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld4q_lane_v, E);
- case AArch64::BI__builtin_neon_vst1_lane_v:
- case AArch64::BI__builtin_neon_vst1q_lane_v: {
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[1] = Builder.CreateExtractElement(Ops[1], Ops[2]);
- Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
- StoreInst *St =
- Builder.CreateStore(Ops[1], Builder.CreateBitCast(Ops[0], Ty));
- St->setAlignment(cast<ConstantInt>(Align)->getZExtValue());
- return St;
+ llvm::Constant *CI = ConstantInt::get(SizeTy, 0);
+ Ops[0] = Builder.CreateInsertElement(V, Ld, CI);
+ return EmitNeonSplat(Ops[0], CI);
}
- case AArch64::BI__builtin_neon_vst2_lane_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst2_lane_v, E);
- case AArch64::BI__builtin_neon_vst2q_lane_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst2q_lane_v, E);
- case AArch64::BI__builtin_neon_vst3_lane_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst3_lane_v, E);
- case AArch64::BI__builtin_neon_vst3q_lane_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst3q_lane_v, E);
- case AArch64::BI__builtin_neon_vst4_lane_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst4_lane_v, E);
- case AArch64::BI__builtin_neon_vst4q_lane_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vst4q_lane_v, E);
- case AArch64::BI__builtin_neon_vld1_dup_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld1_dup_v, E);
- case AArch64::BI__builtin_neon_vld1q_dup_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vld1q_dup_v, E);
- case AArch64::BI__builtin_neon_vld2_dup_v:
- case AArch64::BI__builtin_neon_vld2q_dup_v:
- case AArch64::BI__builtin_neon_vld3_dup_v:
- case AArch64::BI__builtin_neon_vld3q_dup_v:
- case AArch64::BI__builtin_neon_vld4_dup_v:
- case AArch64::BI__builtin_neon_vld4q_dup_v: {
- // Handle 64-bit x 1 elements as a special-case. There is no "dup" needed.
- if (VTy->getElementType()->getPrimitiveSizeInBits() == 64 &&
- VTy->getNumElements() == 1) {
- switch (BuiltinID) {
- case AArch64::BI__builtin_neon_vld2_dup_v:
- Int = Intrinsic::arm_neon_vld2;
- break;
- case AArch64::BI__builtin_neon_vld3_dup_v:
- Int = Intrinsic::arm_neon_vld3;
- break;
- case AArch64::BI__builtin_neon_vld4_dup_v:
- Int = Intrinsic::arm_neon_vld4;
- break;
- default:
- llvm_unreachable("unknown vld_dup intrinsic?");
- }
- Function *F = CGM.getIntrinsic(Int, Ty);
- Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld_dup");
- Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- return Builder.CreateStore(Ops[1], Ops[0]);
- }
- switch (BuiltinID) {
- case AArch64::BI__builtin_neon_vld2_dup_v:
- case AArch64::BI__builtin_neon_vld2q_dup_v:
- Int = Intrinsic::arm_neon_vld2lane;
- break;
- case AArch64::BI__builtin_neon_vld3_dup_v:
- case AArch64::BI__builtin_neon_vld3q_dup_v:
- Int = Intrinsic::arm_neon_vld3lane;
- break;
- case AArch64::BI__builtin_neon_vld4_dup_v:
- case AArch64::BI__builtin_neon_vld4q_dup_v:
- Int = Intrinsic::arm_neon_vld4lane;
- break;
- }
- Function *F = CGM.getIntrinsic(Int, Ty);
- llvm::StructType *STy = cast<llvm::StructType>(F->getReturnType());
-
- SmallVector<Value *, 6> Args;
- Args.push_back(Ops[1]);
- Args.append(STy->getNumElements(), UndefValue::get(Ty));
-
- llvm::Constant *CI = ConstantInt::get(Int32Ty, 0);
- Args.push_back(CI);
- Args.push_back(Align);
-
- 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);
- Value *Elt = Builder.CreateBitCast(Val, Ty);
- Elt = EmitNeonSplat(Elt, CI);
- Elt = Builder.CreateBitCast(Elt, Val->getType());
- Ops[1] = Builder.CreateInsertValue(Ops[1], Elt, i);
- }
+ case NEON::BI__builtin_neon_vld2_lane_v:
+ case NEON::BI__builtin_neon_vld2q_lane_v:
+ case NEON::BI__builtin_neon_vld3_lane_v:
+ case NEON::BI__builtin_neon_vld3q_lane_v:
+ case NEON::BI__builtin_neon_vld4_lane_v:
+ case NEON::BI__builtin_neon_vld4q_lane_v: {
+ Function *F = CGM.getIntrinsic(LLVMIntrinsic, Ty);
+ for (unsigned I = 2; I < Ops.size() - 1; ++I)
+ Ops[I] = Builder.CreateBitCast(Ops[I], Ty);
+ Ops.push_back(Align);
+ Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), NameHint);
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
return Builder.CreateStore(Ops[1], Ops[0]);
}
+ case NEON::BI__builtin_neon_vmovl_v: {
+ llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy);
+ Ops[0] = Builder.CreateBitCast(Ops[0], DTy);
+ if (Usgn)
+ return Builder.CreateZExt(Ops[0], Ty, "vmovl");
+ return Builder.CreateSExt(Ops[0], Ty, "vmovl");
+ }
+ case NEON::BI__builtin_neon_vmovn_v: {
+ llvm::Type *QTy = llvm::VectorType::getExtendedElementVectorType(VTy);
+ Ops[0] = Builder.CreateBitCast(Ops[0], QTy);
+ return Builder.CreateTrunc(Ops[0], Ty, "vmovn");
+ }
+ case NEON::BI__builtin_neon_vmull_v:
+ // FIXME: the integer vmull operations could be emitted in terms of pure
+ // LLVM IR (2 exts followed by a mul). Unfortunately LLVM has a habit of
+ // hoisting the exts outside loops. Until global ISel comes along that can
+ // see through such movement this leads to bad CodeGen. So we need an
+ // intrinsic for now.
+ Int = Usgn ? Intrinsic::arm_neon_vmullu : Intrinsic::arm_neon_vmulls;
+ Int = Type.isPoly() ? (unsigned)Intrinsic::arm_neon_vmullp : Int;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmull");
+ case NEON::BI__builtin_neon_vpadal_v:
+ case NEON::BI__builtin_neon_vpadalq_v: {
+ // The source operand type has twice as many elements of half the size.
+ unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits();
+ llvm::Type *EltTy =
+ llvm::IntegerType::get(getLLVMContext(), EltBits / 2);
+ llvm::Type *NarrowTy =
+ llvm::VectorType::get(EltTy, VTy->getNumElements() * 2);
+ llvm::Type *Tys[2] = { Ty, NarrowTy };
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, NameHint);
+ }
+ case NEON::BI__builtin_neon_vpaddl_v:
+ case NEON::BI__builtin_neon_vpaddlq_v: {
+ // The source operand type has twice as many elements of half the size.
+ unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits();
+ llvm::Type *EltTy = llvm::IntegerType::get(getLLVMContext(), EltBits / 2);
+ llvm::Type *NarrowTy =
+ llvm::VectorType::get(EltTy, VTy->getNumElements() * 2);
+ llvm::Type *Tys[2] = { Ty, NarrowTy };
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vpaddl");
+ }
+ case NEON::BI__builtin_neon_vqdmlal_v:
+ case NEON::BI__builtin_neon_vqdmlsl_v: {
+ SmallVector<Value *, 2> MulOps(Ops.begin() + 1, Ops.end());
+ Value *Mul = EmitNeonCall(CGM.getIntrinsic(LLVMIntrinsic, Ty),
+ MulOps, "vqdmlal");
- // Crypto
- case AArch64::BI__builtin_neon_vaeseq_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_aese, Ty),
- Ops, "aese");
- case AArch64::BI__builtin_neon_vaesdq_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_aesd, Ty),
- Ops, "aesd");
- case AArch64::BI__builtin_neon_vaesmcq_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_aesmc, Ty),
- Ops, "aesmc");
- case AArch64::BI__builtin_neon_vaesimcq_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_aesimc, Ty),
- Ops, "aesimc");
- case AArch64::BI__builtin_neon_vsha1su1q_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha1su1, Ty),
- Ops, "sha1su1");
- case AArch64::BI__builtin_neon_vsha256su0q_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha256su0, Ty),
- Ops, "sha256su0");
- case AArch64::BI__builtin_neon_vsha1su0q_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha1su0, Ty),
- Ops, "sha1su0");
- case AArch64::BI__builtin_neon_vsha256hq_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha256h, Ty),
- Ops, "sha256h");
- case AArch64::BI__builtin_neon_vsha256h2q_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha256h2, Ty),
- Ops, "sha256h2");
- case AArch64::BI__builtin_neon_vsha256su1q_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha256su1, Ty),
- Ops, "sha256su1");
- case AArch64::BI__builtin_neon_vmul_lane_v:
- case AArch64::BI__builtin_neon_vmul_laneq_v: {
- // v1f64 vmul_lane should be mapped to Neon scalar mul lane
- bool Quad = false;
- if (BuiltinID == AArch64::BI__builtin_neon_vmul_laneq_v)
- Quad = true;
- Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy);
- llvm::Type *VTy = GetNeonType(this,
- NeonTypeFlags(NeonTypeFlags::Float64, false, Quad));
- Ops[1] = Builder.CreateBitCast(Ops[1], VTy);
- Ops[1] = Builder.CreateExtractElement(Ops[1], Ops[2], "extract");
- Value *Result = Builder.CreateFMul(Ops[0], Ops[1]);
- return Builder.CreateBitCast(Result, Ty);
+ SmallVector<Value *, 2> AccumOps;
+ AccumOps.push_back(Ops[0]);
+ AccumOps.push_back(Mul);
+ return EmitNeonCall(CGM.getIntrinsic(AltLLVMIntrinsic, Ty),
+ AccumOps, NameHint);
+ }
+ case NEON::BI__builtin_neon_vqshl_n_v:
+ case NEON::BI__builtin_neon_vqshlq_n_v:
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshl_n",
+ 1, false);
+ case NEON::BI__builtin_neon_vrecpe_v:
+ case NEON::BI__builtin_neon_vrecpeq_v:
+ case NEON::BI__builtin_neon_vrsqrte_v:
+ case NEON::BI__builtin_neon_vrsqrteq_v:
+ Int = Ty->isFPOrFPVectorTy() ? LLVMIntrinsic : AltLLVMIntrinsic;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, NameHint);
+
+ case NEON::BI__builtin_neon_vshl_n_v:
+ case NEON::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 NEON::BI__builtin_neon_vshll_n_v: {
+ llvm::Type *SrcTy = llvm::VectorType::getTruncatedElementVectorType(VTy);
+ Ops[0] = Builder.CreateBitCast(Ops[0], SrcTy);
+ if (Usgn)
+ Ops[0] = Builder.CreateZExt(Ops[0], VTy);
+ else
+ Ops[0] = Builder.CreateSExt(Ops[0], VTy);
+ Ops[1] = EmitNeonShiftVector(Ops[1], VTy, false);
+ return Builder.CreateShl(Ops[0], Ops[1], "vshll_n");
}
+ case NEON::BI__builtin_neon_vshrn_n_v: {
+ llvm::Type *SrcTy = llvm::VectorType::getExtendedElementVectorType(VTy);
+ Ops[0] = Builder.CreateBitCast(Ops[0], SrcTy);
+ Ops[1] = EmitNeonShiftVector(Ops[1], SrcTy, false);
+ if (Usgn)
+ Ops[0] = Builder.CreateLShr(Ops[0], Ops[1]);
+ else
+ Ops[0] = Builder.CreateAShr(Ops[0], Ops[1]);
+ return Builder.CreateTrunc(Ops[0], Ty, "vshrn_n");
+ }
+ case NEON::BI__builtin_neon_vshr_n_v:
+ case NEON::BI__builtin_neon_vshrq_n_v:
+ return EmitNeonRShiftImm(Ops[0], Ops[1], Ty, Usgn, "vshr_n");
+ case NEON::BI__builtin_neon_vst1_v:
+ case NEON::BI__builtin_neon_vst1q_v:
+ case NEON::BI__builtin_neon_vst2_v:
+ case NEON::BI__builtin_neon_vst2q_v:
+ case NEON::BI__builtin_neon_vst3_v:
+ case NEON::BI__builtin_neon_vst3q_v:
+ case NEON::BI__builtin_neon_vst4_v:
+ case NEON::BI__builtin_neon_vst4q_v:
+ case NEON::BI__builtin_neon_vst2_lane_v:
+ case NEON::BI__builtin_neon_vst2q_lane_v:
+ case NEON::BI__builtin_neon_vst3_lane_v:
+ case NEON::BI__builtin_neon_vst3q_lane_v:
+ case NEON::BI__builtin_neon_vst4_lane_v:
+ case NEON::BI__builtin_neon_vst4q_lane_v:
+ Ops.push_back(Align);
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "");
+ case NEON::BI__builtin_neon_vsubhn_v: {
+ llvm::VectorType *SrcTy =
+ llvm::VectorType::getExtendedElementVectorType(VTy);
- // AArch64-only builtins
- case AArch64::BI__builtin_neon_vfmaq_laneq_v: {
- Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+ // %sum = add <4 x i32> %lhs, %rhs
+ Ops[0] = Builder.CreateBitCast(Ops[0], SrcTy);
+ Ops[1] = Builder.CreateBitCast(Ops[1], SrcTy);
+ Ops[0] = Builder.CreateSub(Ops[0], Ops[1], "vsubhn");
- Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- Ops[2] = EmitNeonSplat(Ops[2], cast<ConstantInt>(Ops[3]));
- return Builder.CreateCall3(F, Ops[2], Ops[1], Ops[0]);
+ // %high = lshr <4 x i32> %sum, <i32 16, i32 16, i32 16, i32 16>
+ Constant *ShiftAmt = ConstantInt::get(SrcTy->getElementType(),
+ SrcTy->getScalarSizeInBits() / 2);
+ ShiftAmt = ConstantVector::getSplat(VTy->getNumElements(), ShiftAmt);
+ Ops[0] = Builder.CreateLShr(Ops[0], ShiftAmt, "vsubhn");
+
+ // %res = trunc <4 x i32> %high to <4 x i16>
+ return Builder.CreateTrunc(Ops[0], VTy, "vsubhn");
}
- case AArch64::BI__builtin_neon_vfmaq_lane_v: {
- Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ case NEON::BI__builtin_neon_vtrn_v:
+ case NEON::BI__builtin_neon_vtrnq_v: {
+ Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(Ty));
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+ Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
+ Value *SV = nullptr;
- llvm::VectorType *VTy = cast<llvm::VectorType>(Ty);
- llvm::Type *STy = llvm::VectorType::get(VTy->getElementType(),
- VTy->getNumElements() / 2);
- Ops[2] = Builder.CreateBitCast(Ops[2], STy);
- Value* SV = llvm::ConstantVector::getSplat(VTy->getNumElements(),
- cast<ConstantInt>(Ops[3]));
- Ops[2] = Builder.CreateShuffleVector(Ops[2], Ops[2], SV, "lane");
-
- return Builder.CreateCall3(F, Ops[2], Ops[1], Ops[0]);
- }
- case AArch64::BI__builtin_neon_vfma_lane_v: {
- llvm::VectorType *VTy = cast<llvm::VectorType>(Ty);
- // v1f64 fma should be mapped to Neon scalar f64 fma
- if (VTy && VTy->getElementType() == DoubleTy) {
- Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy);
- Ops[1] = Builder.CreateBitCast(Ops[1], DoubleTy);
- llvm::Type *VTy = GetNeonType(this,
- NeonTypeFlags(NeonTypeFlags::Float64, false, false));
- Ops[2] = Builder.CreateBitCast(Ops[2], VTy);
- Ops[2] = Builder.CreateExtractElement(Ops[2], Ops[3], "extract");
- Value *F = CGM.getIntrinsic(Intrinsic::fma, DoubleTy);
- Value *Result = Builder.CreateCall3(F, Ops[1], Ops[2], Ops[0]);
- return Builder.CreateBitCast(Result, Ty);
+ for (unsigned vi = 0; vi != 2; ++vi) {
+ SmallVector<Constant*, 16> Indices;
+ for (unsigned i = 0, e = VTy->getNumElements(); i != e; i += 2) {
+ Indices.push_back(Builder.getInt32(i+vi));
+ Indices.push_back(Builder.getInt32(i+e+vi));
+ }
+ Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ops[0], vi);
+ SV = llvm::ConstantVector::get(Indices);
+ SV = Builder.CreateShuffleVector(Ops[1], Ops[2], SV, "vtrn");
+ SV = Builder.CreateStore(SV, Addr);
}
- Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
+ return SV;
+ }
+ case NEON::BI__builtin_neon_vtst_v:
+ case NEON::BI__builtin_neon_vtstq_v: {
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
-
- Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- Ops[2] = EmitNeonSplat(Ops[2], cast<ConstantInt>(Ops[3]));
- return Builder.CreateCall3(F, Ops[2], Ops[1], Ops[0]);
+ Ops[0] = Builder.CreateAnd(Ops[0], Ops[1]);
+ Ops[0] = Builder.CreateICmp(ICmpInst::ICMP_NE, Ops[0],
+ ConstantAggregateZero::get(Ty));
+ return Builder.CreateSExt(Ops[0], Ty, "vtst");
}
- case AArch64::BI__builtin_neon_vfma_laneq_v: {
- llvm::VectorType *VTy = cast<llvm::VectorType>(Ty);
- // v1f64 fma should be mapped to Neon scalar f64 fma
- if (VTy && VTy->getElementType() == DoubleTy) {
- Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy);
- Ops[1] = Builder.CreateBitCast(Ops[1], DoubleTy);
- llvm::Type *VTy = GetNeonType(this,
- NeonTypeFlags(NeonTypeFlags::Float64, false, true));
- Ops[2] = Builder.CreateBitCast(Ops[2], VTy);
- Ops[2] = Builder.CreateExtractElement(Ops[2], Ops[3], "extract");
- Value *F = CGM.getIntrinsic(Intrinsic::fma, DoubleTy);
- Value *Result = Builder.CreateCall3(F, Ops[1], Ops[2], Ops[0]);
- return Builder.CreateBitCast(Result, Ty);
- }
- Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ case NEON::BI__builtin_neon_vuzp_v:
+ case NEON::BI__builtin_neon_vuzpq_v: {
+ Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(Ty));
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+ Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
+ Value *SV = nullptr;
- llvm::Type *STy = llvm::VectorType::get(VTy->getElementType(),
- VTy->getNumElements() * 2);
- Ops[2] = Builder.CreateBitCast(Ops[2], STy);
- Value* SV = llvm::ConstantVector::getSplat(VTy->getNumElements(),
- cast<ConstantInt>(Ops[3]));
- Ops[2] = Builder.CreateShuffleVector(Ops[2], Ops[2], SV, "lane");
+ for (unsigned vi = 0; vi != 2; ++vi) {
+ SmallVector<Constant*, 16> Indices;
+ for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i)
+ Indices.push_back(ConstantInt::get(Int32Ty, 2*i+vi));
- return Builder.CreateCall3(F, Ops[2], Ops[1], Ops[0]);
+ Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ops[0], vi);
+ SV = llvm::ConstantVector::get(Indices);
+ SV = Builder.CreateShuffleVector(Ops[1], Ops[2], SV, "vuzp");
+ SV = Builder.CreateStore(SV, Addr);
+ }
+ return SV;
}
- case AArch64::BI__builtin_neon_vfms_v:
- case AArch64::BI__builtin_neon_vfmsq_v: {
- Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ case NEON::BI__builtin_neon_vzip_v:
+ case NEON::BI__builtin_neon_vzipq_v: {
+ Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(Ty));
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[1] = Builder.CreateFNeg(Ops[1]);
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
+ Value *SV = nullptr;
- // LLVM's fma intrinsic puts the accumulator in the last position, but the
- // AArch64 intrinsic has it first.
- return Builder.CreateCall3(F, Ops[1], Ops[2], Ops[0]);
- }
- case AArch64::BI__builtin_neon_vmaxnm_v:
- case AArch64::BI__builtin_neon_vmaxnmq_v: {
- Int = Intrinsic::aarch64_neon_vmaxnm;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmaxnm");
- }
- case AArch64::BI__builtin_neon_vminnm_v:
- case AArch64::BI__builtin_neon_vminnmq_v: {
- Int = Intrinsic::aarch64_neon_vminnm;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vminnm");
- }
- case AArch64::BI__builtin_neon_vpmaxnm_v:
- case AArch64::BI__builtin_neon_vpmaxnmq_v: {
- Int = Intrinsic::aarch64_neon_vpmaxnm;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpmaxnm");
- }
- case AArch64::BI__builtin_neon_vpminnm_v:
- case AArch64::BI__builtin_neon_vpminnmq_v: {
- Int = Intrinsic::aarch64_neon_vpminnm;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpminnm");
- }
- case AArch64::BI__builtin_neon_vpmaxq_v: {
- Int = usgn ? Intrinsic::arm_neon_vpmaxu : Intrinsic::arm_neon_vpmaxs;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpmax");
- }
- case AArch64::BI__builtin_neon_vpminq_v: {
- Int = usgn ? Intrinsic::arm_neon_vpminu : Intrinsic::arm_neon_vpmins;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpmin");
- }
- case AArch64::BI__builtin_neon_vpaddq_v: {
- Int = Intrinsic::arm_neon_vpadd;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpadd");
- }
- case AArch64::BI__builtin_neon_vmulx_v:
- case AArch64::BI__builtin_neon_vmulxq_v: {
- Int = Intrinsic::aarch64_neon_vmulx;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmulx");
- }
- case AArch64::BI__builtin_neon_vpaddl_v:
- case AArch64::BI__builtin_neon_vpaddlq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vpaddl_v, E);
- case AArch64::BI__builtin_neon_vpadal_v:
- case AArch64::BI__builtin_neon_vpadalq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vpadal_v, E);
- case AArch64::BI__builtin_neon_vqabs_v:
- case AArch64::BI__builtin_neon_vqabsq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqabs_v, E);
- case AArch64::BI__builtin_neon_vqneg_v:
- case AArch64::BI__builtin_neon_vqnegq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqneg_v, E);
- case AArch64::BI__builtin_neon_vabs_v:
- case AArch64::BI__builtin_neon_vabsq_v: {
- if (VTy->getElementType()->isFloatingPointTy()) {
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::fabs, Ty), Ops, "vabs");
+ for (unsigned vi = 0; vi != 2; ++vi) {
+ SmallVector<Constant*, 16> Indices;
+ for (unsigned i = 0, e = VTy->getNumElements(); i != e; i += 2) {
+ Indices.push_back(ConstantInt::get(Int32Ty, (i + vi*e) >> 1));
+ Indices.push_back(ConstantInt::get(Int32Ty, ((i + vi*e) >> 1)+e));
+ }
+ Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ops[0], vi);
+ SV = llvm::ConstantVector::get(Indices);
+ SV = Builder.CreateShuffleVector(Ops[1], Ops[2], SV, "vzip");
+ SV = Builder.CreateStore(SV, Addr);
}
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vabs_v, E);
- }
- case AArch64::BI__builtin_neon_vsqadd_v:
- case AArch64::BI__builtin_neon_vsqaddq_v: {
- Int = Intrinsic::aarch64_neon_usqadd;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vsqadd");
- }
- case AArch64::BI__builtin_neon_vuqadd_v:
- case AArch64::BI__builtin_neon_vuqaddq_v: {
- Int = Intrinsic::aarch64_neon_suqadd;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vuqadd");
- }
- case AArch64::BI__builtin_neon_vcls_v:
- case AArch64::BI__builtin_neon_vclsq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcls_v, E);
- case AArch64::BI__builtin_neon_vclz_v:
- case AArch64::BI__builtin_neon_vclzq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vclz_v, E);
- case AArch64::BI__builtin_neon_vcnt_v:
- case AArch64::BI__builtin_neon_vcntq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcnt_v, E);
- case AArch64::BI__builtin_neon_vrbit_v:
- case AArch64::BI__builtin_neon_vrbitq_v:
- Int = Intrinsic::aarch64_neon_rbit;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrbit");
- case AArch64::BI__builtin_neon_vmovn_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vmovn_v, E);
- case AArch64::BI__builtin_neon_vqmovun_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqmovun_v, E);
- case AArch64::BI__builtin_neon_vqmovn_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vqmovn_v, E);
- case AArch64::BI__builtin_neon_vcvt_f16_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvt_f16_v, E);
- case AArch64::BI__builtin_neon_vcvt_f32_f16:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvt_f32_f16, E);
- case AArch64::BI__builtin_neon_vcvt_f32_f64: {
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, false));
- return Builder.CreateFPTrunc(Ops[0], Ty, "vcvt");
- }
- case AArch64::BI__builtin_neon_vcvtx_f32_v: {
- llvm::Type *EltTy = FloatTy;
- llvm::Type *ResTy = llvm::VectorType::get(EltTy, 2);
- llvm::Type *Tys[2] = { ResTy, Ty };
- Int = Intrinsic::aarch64_neon_fcvtxn;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtx_f32_f64");
- }
- case AArch64::BI__builtin_neon_vcvt_f64_f32: {
- llvm::Type *OpTy =
- GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, false));
- Ops[0] = Builder.CreateBitCast(Ops[0], OpTy);
- return Builder.CreateFPExt(Ops[0], Ty, "vcvt");
- }
- case AArch64::BI__builtin_neon_vcvt_f64_v:
- case AArch64::BI__builtin_neon_vcvtq_f64_v: {
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float64, false, quad));
- return usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt")
- : Builder.CreateSIToFP(Ops[0], Ty, "vcvt");
- }
- case AArch64::BI__builtin_neon_vrndn_v:
- case AArch64::BI__builtin_neon_vrndnq_v: {
- Int = Intrinsic::aarch64_neon_frintn;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndn");
- }
- case AArch64::BI__builtin_neon_vrnda_v:
- case AArch64::BI__builtin_neon_vrndaq_v: {
- Int = Intrinsic::round;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrnda");
- }
- case AArch64::BI__builtin_neon_vrndp_v:
- case AArch64::BI__builtin_neon_vrndpq_v: {
- Int = Intrinsic::ceil;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndp");
- }
- case AArch64::BI__builtin_neon_vrndm_v:
- case AArch64::BI__builtin_neon_vrndmq_v: {
- Int = Intrinsic::floor;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndm");
- }
- case AArch64::BI__builtin_neon_vrndx_v:
- case AArch64::BI__builtin_neon_vrndxq_v: {
- Int = Intrinsic::rint;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndx");
+ return SV;
}
- case AArch64::BI__builtin_neon_vrnd_v:
- case AArch64::BI__builtin_neon_vrndq_v: {
- Int = Intrinsic::trunc;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrnd");
}
- case AArch64::BI__builtin_neon_vrndi_v:
- case AArch64::BI__builtin_neon_vrndiq_v: {
- Int = Intrinsic::nearbyint;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndi");
+
+ assert(Int && "Expected valid intrinsic number");
+
+ // Determine the type(s) of this overloaded AArch64 intrinsic.
+ Function *F = LookupNeonLLVMIntrinsic(Int, Modifier, Ty, E);
+
+ Value *Result = EmitNeonCall(F, Ops, NameHint);
+ llvm::Type *ResultType = ConvertType(E->getType());
+ // AArch64 intrinsic one-element vector type cast to
+ // scalar type expected by the builtin
+ return Builder.CreateBitCast(Result, ResultType, NameHint);
+}
+
+Value *CodeGenFunction::EmitAArch64CompareBuiltinExpr(
+ Value *Op, llvm::Type *Ty, const CmpInst::Predicate Fp,
+ const CmpInst::Predicate Ip, const Twine &Name) {
+ llvm::Type *OTy = Op->getType();
+
+ // FIXME: this is utterly horrific. We should not be looking at previous
+ // codegen context to find out what needs doing. Unfortunately TableGen
+ // currently gives us exactly the same calls for vceqz_f32 and vceqz_s32
+ // (etc).
+ if (BitCastInst *BI = dyn_cast<BitCastInst>(Op))
+ OTy = BI->getOperand(0)->getType();
+
+ Op = Builder.CreateBitCast(Op, OTy);
+ if (OTy->getScalarType()->isFloatingPointTy()) {
+ Op = Builder.CreateFCmp(Fp, Op, Constant::getNullValue(OTy));
+ } else {
+ Op = Builder.CreateICmp(Ip, Op, Constant::getNullValue(OTy));
}
- case AArch64::BI__builtin_neon_vcvt_s32_v:
- case AArch64::BI__builtin_neon_vcvt_u32_v:
- case AArch64::BI__builtin_neon_vcvtq_s32_v:
- case AArch64::BI__builtin_neon_vcvtq_u32_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvtq_u32_v, E);
- case AArch64::BI__builtin_neon_vcvt_s64_v:
- case AArch64::BI__builtin_neon_vcvt_u64_v:
- case AArch64::BI__builtin_neon_vcvtq_s64_v:
- case AArch64::BI__builtin_neon_vcvtq_u64_v: {
- llvm::Type *DoubleTy =
- GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float64, false, quad));
- Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy);
- return usgn ? Builder.CreateFPToUI(Ops[0], Ty, "vcvt")
- : Builder.CreateFPToSI(Ops[0], Ty, "vcvt");
+ return Builder.CreateSExt(Op, Ty, Name);
+}
+
+static Value *packTBLDVectorList(CodeGenFunction &CGF, ArrayRef<Value *> Ops,
+ Value *ExtOp, Value *IndexOp,
+ llvm::Type *ResTy, unsigned IntID,
+ const char *Name) {
+ SmallVector<Value *, 2> TblOps;
+ if (ExtOp)
+ TblOps.push_back(ExtOp);
+
+ // Build a vector containing sequential number like (0, 1, 2, ..., 15)
+ SmallVector<Constant*, 16> Indices;
+ llvm::VectorType *TblTy = cast<llvm::VectorType>(Ops[0]->getType());
+ for (unsigned i = 0, e = TblTy->getNumElements(); i != e; ++i) {
+ Indices.push_back(ConstantInt::get(CGF.Int32Ty, 2*i));
+ Indices.push_back(ConstantInt::get(CGF.Int32Ty, 2*i+1));
}
- case AArch64::BI__builtin_neon_vcvtn_s32_v:
- case AArch64::BI__builtin_neon_vcvtnq_s32_v: {
- llvm::Type *OpTy = llvm::VectorType::get(FloatTy, VTy->getNumElements());
- llvm::Type *Tys[2] = { Ty, OpTy };
- Int = Intrinsic::aarch64_neon_fcvtns;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtns_f32");
- }
- case AArch64::BI__builtin_neon_vcvtn_s64_v:
- case AArch64::BI__builtin_neon_vcvtnq_s64_v: {
- llvm::Type *OpTy = llvm::VectorType::get(DoubleTy, VTy->getNumElements());
- llvm::Type *Tys[2] = { Ty, OpTy };
- Int = Intrinsic::aarch64_neon_fcvtns;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtns_f64");
- }
- case AArch64::BI__builtin_neon_vcvtn_u32_v:
- case AArch64::BI__builtin_neon_vcvtnq_u32_v: {
- llvm::Type *OpTy = llvm::VectorType::get(FloatTy, VTy->getNumElements());
- llvm::Type *Tys[2] = { Ty, OpTy };
- Int = Intrinsic::aarch64_neon_fcvtnu;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtnu_f32");
- }
- case AArch64::BI__builtin_neon_vcvtn_u64_v:
- case AArch64::BI__builtin_neon_vcvtnq_u64_v: {
- llvm::Type *OpTy = llvm::VectorType::get(DoubleTy, VTy->getNumElements());
- llvm::Type *Tys[2] = { Ty, OpTy };
- Int = Intrinsic::aarch64_neon_fcvtnu;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtnu_f64");
- }
- case AArch64::BI__builtin_neon_vcvtp_s32_v:
- case AArch64::BI__builtin_neon_vcvtpq_s32_v: {
- llvm::Type *OpTy = llvm::VectorType::get(FloatTy, VTy->getNumElements());
- llvm::Type *Tys[2] = { Ty, OpTy };
- Int = Intrinsic::aarch64_neon_fcvtps;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtps_f32");
- }
- case AArch64::BI__builtin_neon_vcvtp_s64_v:
- case AArch64::BI__builtin_neon_vcvtpq_s64_v: {
- llvm::Type *OpTy = llvm::VectorType::get(DoubleTy, VTy->getNumElements());
- llvm::Type *Tys[2] = { Ty, OpTy };
- Int = Intrinsic::aarch64_neon_fcvtps;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtps_f64");
- }
- case AArch64::BI__builtin_neon_vcvtp_u32_v:
- case AArch64::BI__builtin_neon_vcvtpq_u32_v: {
- llvm::Type *OpTy = llvm::VectorType::get(FloatTy, VTy->getNumElements());
- llvm::Type *Tys[2] = { Ty, OpTy };
- Int = Intrinsic::aarch64_neon_fcvtpu;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtpu_f32");
- }
- case AArch64::BI__builtin_neon_vcvtp_u64_v:
- case AArch64::BI__builtin_neon_vcvtpq_u64_v: {
- llvm::Type *OpTy = llvm::VectorType::get(DoubleTy, VTy->getNumElements());
- llvm::Type *Tys[2] = { Ty, OpTy };
- Int = Intrinsic::aarch64_neon_fcvtpu;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtpu_f64");
- }
- case AArch64::BI__builtin_neon_vcvtm_s32_v:
- case AArch64::BI__builtin_neon_vcvtmq_s32_v: {
- llvm::Type *OpTy = llvm::VectorType::get(FloatTy, VTy->getNumElements());
- llvm::Type *Tys[2] = { Ty, OpTy };
- Int = Intrinsic::aarch64_neon_fcvtms;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtms_f32");
- }
- case AArch64::BI__builtin_neon_vcvtm_s64_v:
- case AArch64::BI__builtin_neon_vcvtmq_s64_v: {
- llvm::Type *OpTy = llvm::VectorType::get(DoubleTy, VTy->getNumElements());
- llvm::Type *Tys[2] = { Ty, OpTy };
- Int = Intrinsic::aarch64_neon_fcvtms;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtms_f64");
- }
- case AArch64::BI__builtin_neon_vcvtm_u32_v:
- case AArch64::BI__builtin_neon_vcvtmq_u32_v: {
- llvm::Type *OpTy = llvm::VectorType::get(FloatTy, VTy->getNumElements());
- llvm::Type *Tys[2] = { Ty, OpTy };
- Int = Intrinsic::aarch64_neon_fcvtmu;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtmu_f32");
- }
- case AArch64::BI__builtin_neon_vcvtm_u64_v:
- case AArch64::BI__builtin_neon_vcvtmq_u64_v: {
- llvm::Type *OpTy = llvm::VectorType::get(DoubleTy, VTy->getNumElements());
- llvm::Type *Tys[2] = { Ty, OpTy };
- Int = Intrinsic::aarch64_neon_fcvtmu;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtmu_f64");
- }
- case AArch64::BI__builtin_neon_vcvta_s32_v:
- case AArch64::BI__builtin_neon_vcvtaq_s32_v: {
- llvm::Type *OpTy = llvm::VectorType::get(FloatTy, VTy->getNumElements());
- llvm::Type *Tys[2] = { Ty, OpTy };
- Int = Intrinsic::aarch64_neon_fcvtas;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtas_f32");
- }
- case AArch64::BI__builtin_neon_vcvta_s64_v:
- case AArch64::BI__builtin_neon_vcvtaq_s64_v: {
- llvm::Type *OpTy = llvm::VectorType::get(DoubleTy, VTy->getNumElements());
- llvm::Type *Tys[2] = { Ty, OpTy };
- Int = Intrinsic::aarch64_neon_fcvtas;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtas_f64");
- }
- case AArch64::BI__builtin_neon_vcvta_u32_v:
- case AArch64::BI__builtin_neon_vcvtaq_u32_v: {
- llvm::Type *OpTy = llvm::VectorType::get(FloatTy, VTy->getNumElements());
- llvm::Type *Tys[2] = { Ty, OpTy };
- Int = Intrinsic::aarch64_neon_fcvtau;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtau_f32");
- }
- case AArch64::BI__builtin_neon_vcvta_u64_v:
- case AArch64::BI__builtin_neon_vcvtaq_u64_v: {
- llvm::Type *OpTy = llvm::VectorType::get(DoubleTy, VTy->getNumElements());
- llvm::Type *Tys[2] = { Ty, OpTy };
- Int = Intrinsic::aarch64_neon_fcvtau;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtau_f64");
- }
- case AArch64::BI__builtin_neon_vrecpe_v:
- case AArch64::BI__builtin_neon_vrecpeq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrecpe_v, E);
- case AArch64::BI__builtin_neon_vrsqrte_v:
- case AArch64::BI__builtin_neon_vrsqrteq_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vrsqrte_v, E);
- case AArch64::BI__builtin_neon_vsqrt_v:
- case AArch64::BI__builtin_neon_vsqrtq_v: {
- Int = Intrinsic::sqrt;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vsqrt");
+ Value *SV = llvm::ConstantVector::get(Indices);
+
+ int PairPos = 0, End = Ops.size() - 1;
+ while (PairPos < End) {
+ TblOps.push_back(CGF.Builder.CreateShuffleVector(Ops[PairPos],
+ Ops[PairPos+1], SV, Name));
+ PairPos += 2;
}
- case AArch64::BI__builtin_neon_vcvt_f32_v:
- case AArch64::BI__builtin_neon_vcvtq_f32_v:
- return EmitARMBuiltinExpr(ARM::BI__builtin_neon_vcvt_f32_v, E);
- case AArch64::BI__builtin_neon_vceqz_v:
- case AArch64::BI__builtin_neon_vceqzq_v:
- return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OEQ,
- ICmpInst::ICMP_EQ, "vceqz");
- case AArch64::BI__builtin_neon_vcgez_v:
- case AArch64::BI__builtin_neon_vcgezq_v:
- return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OGE,
- ICmpInst::ICMP_SGE, "vcgez");
- case AArch64::BI__builtin_neon_vclez_v:
- case AArch64::BI__builtin_neon_vclezq_v:
- return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OLE,
- ICmpInst::ICMP_SLE, "vclez");
- case AArch64::BI__builtin_neon_vcgtz_v:
- case AArch64::BI__builtin_neon_vcgtzq_v:
- return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OGT,
- ICmpInst::ICMP_SGT, "vcgtz");
- case AArch64::BI__builtin_neon_vcltz_v:
- case AArch64::BI__builtin_neon_vcltzq_v:
- return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OLT,
- ICmpInst::ICMP_SLT, "vcltz");
+
+ // If there's an odd number of 64-bit lookup table, fill the high 64-bit
+ // of the 128-bit lookup table with zero.
+ if (PairPos == End) {
+ Value *ZeroTbl = ConstantAggregateZero::get(TblTy);
+ TblOps.push_back(CGF.Builder.CreateShuffleVector(Ops[PairPos],
+ ZeroTbl, SV, Name));
}
+
+ Function *TblF;
+ TblOps.push_back(IndexOp);
+ TblF = CGF.CGM.getIntrinsic(IntID, ResTy);
+
+ return CGF.EmitNeonCall(TblF, TblOps, Name);
}
Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
+ unsigned HintID = static_cast<unsigned>(-1);
+ switch (BuiltinID) {
+ default: break;
+ case ARM::BI__builtin_arm_nop:
+ HintID = 0;
+ break;
+ case ARM::BI__builtin_arm_yield:
+ case ARM::BI__yield:
+ HintID = 1;
+ break;
+ case ARM::BI__builtin_arm_wfe:
+ case ARM::BI__wfe:
+ HintID = 2;
+ break;
+ case ARM::BI__builtin_arm_wfi:
+ case ARM::BI__wfi:
+ HintID = 3;
+ break;
+ case ARM::BI__builtin_arm_sev:
+ case ARM::BI__sev:
+ HintID = 4;
+ break;
+ case ARM::BI__builtin_arm_sevl:
+ case ARM::BI__sevl:
+ HintID = 5;
+ break;
+ }
+
+ if (HintID != static_cast<unsigned>(-1)) {
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_hint);
+ return Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, HintID));
+ }
+
+ if (BuiltinID == ARM::BI__builtin_arm_rbit) {
+ return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_rbit),
+ EmitScalarExpr(E->getArg(0)),
+ "rbit");
+ }
+
if (BuiltinID == ARM::BI__clear_cache) {
assert(E->getNumArgs() == 2 && "__clear_cache takes 2 arguments");
const FunctionDecl *FD = E->getDirectCallee();
@@ -3938,9 +3093,23 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
if (BuiltinID == ARM::BI__builtin_arm_ldrexd ||
- (BuiltinID == ARM::BI__builtin_arm_ldrex &&
- getContext().getTypeSize(E->getType()) == 64)) {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_ldrexd);
+ ((BuiltinID == ARM::BI__builtin_arm_ldrex ||
+ BuiltinID == ARM::BI__builtin_arm_ldaex) &&
+ getContext().getTypeSize(E->getType()) == 64) ||
+ BuiltinID == ARM::BI__ldrexd) {
+ Function *F;
+
+ switch (BuiltinID) {
+ default: llvm_unreachable("unexpected builtin");
+ case ARM::BI__builtin_arm_ldaex:
+ F = CGM.getIntrinsic(Intrinsic::arm_ldaexd);
+ break;
+ case ARM::BI__builtin_arm_ldrexd:
+ case ARM::BI__builtin_arm_ldrex:
+ case ARM::BI__ldrexd:
+ F = CGM.getIntrinsic(Intrinsic::arm_ldrexd);
+ break;
+ }
Value *LdPtr = EmitScalarExpr(E->getArg(0));
Value *Val = Builder.CreateCall(F, Builder.CreateBitCast(LdPtr, Int8PtrTy),
@@ -3957,7 +3126,8 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return Builder.CreateBitCast(Val, ConvertType(E->getType()));
}
- if (BuiltinID == ARM::BI__builtin_arm_ldrex) {
+ if (BuiltinID == ARM::BI__builtin_arm_ldrex ||
+ BuiltinID == ARM::BI__builtin_arm_ldaex) {
Value *LoadAddr = EmitScalarExpr(E->getArg(0));
QualType Ty = E->getType();
@@ -3966,7 +3136,10 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
getContext().getTypeSize(Ty));
LoadAddr = Builder.CreateBitCast(LoadAddr, IntResTy->getPointerTo());
- Function *F = CGM.getIntrinsic(Intrinsic::arm_ldrex, LoadAddr->getType());
+ Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI__builtin_arm_ldaex
+ ? Intrinsic::arm_ldaex
+ : Intrinsic::arm_ldrex,
+ LoadAddr->getType());
Value *Val = Builder.CreateCall(F, LoadAddr, "ldrex");
if (RealResTy->isPointerTy())
@@ -3978,9 +3151,12 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
if (BuiltinID == ARM::BI__builtin_arm_strexd ||
- (BuiltinID == ARM::BI__builtin_arm_strex &&
+ ((BuiltinID == ARM::BI__builtin_arm_stlex ||
+ BuiltinID == ARM::BI__builtin_arm_strex) &&
getContext().getTypeSize(E->getArg(0)->getType()) == 64)) {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_strexd);
+ Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI__builtin_arm_stlex
+ ? Intrinsic::arm_stlexd
+ : Intrinsic::arm_strexd);
llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, NULL);
Value *Tmp = CreateMemTemp(E->getArg(0)->getType());
@@ -3996,7 +3172,8 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall3(F, Arg0, Arg1, StPtr, "strexd");
}
- if (BuiltinID == ARM::BI__builtin_arm_strex) {
+ if (BuiltinID == ARM::BI__builtin_arm_strex ||
+ BuiltinID == ARM::BI__builtin_arm_stlex) {
Value *StoreVal = EmitScalarExpr(E->getArg(0));
Value *StoreAddr = EmitScalarExpr(E->getArg(1));
@@ -4012,7 +3189,10 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
StoreVal = Builder.CreateZExtOrBitCast(StoreVal, Int32Ty);
}
- Function *F = CGM.getIntrinsic(Intrinsic::arm_strex, StoreAddr->getType());
+ Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI__builtin_arm_stlex
+ ? Intrinsic::arm_stlex
+ : Intrinsic::arm_strex,
+ StoreAddr->getType());
return Builder.CreateCall2(F, StoreVal, StoreAddr, "strex");
}
@@ -4021,11 +3201,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(F);
}
- if (BuiltinID == ARM::BI__builtin_arm_sevl) {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_sevl);
- return Builder.CreateCall(F);
- }
-
// CRC32
Intrinsic::ID CRCIntrinsicID = Intrinsic::not_intrinsic;
switch (BuiltinID) {
@@ -4070,32 +3245,32 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
SmallVector<Value*, 4> Ops;
- llvm::Value *Align = 0;
+ llvm::Value *Align = nullptr;
for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++) {
if (i == 0) {
switch (BuiltinID) {
- case ARM::BI__builtin_neon_vld1_v:
- case ARM::BI__builtin_neon_vld1q_v:
- case ARM::BI__builtin_neon_vld1q_lane_v:
- case ARM::BI__builtin_neon_vld1_lane_v:
- case ARM::BI__builtin_neon_vld1_dup_v:
- case ARM::BI__builtin_neon_vld1q_dup_v:
- case ARM::BI__builtin_neon_vst1_v:
- case ARM::BI__builtin_neon_vst1q_v:
- case ARM::BI__builtin_neon_vst1q_lane_v:
- case ARM::BI__builtin_neon_vst1_lane_v:
- case ARM::BI__builtin_neon_vst2_v:
- case ARM::BI__builtin_neon_vst2q_v:
- case ARM::BI__builtin_neon_vst2_lane_v:
- case ARM::BI__builtin_neon_vst2q_lane_v:
- case ARM::BI__builtin_neon_vst3_v:
- case ARM::BI__builtin_neon_vst3q_v:
- case ARM::BI__builtin_neon_vst3_lane_v:
- case ARM::BI__builtin_neon_vst3q_lane_v:
- case ARM::BI__builtin_neon_vst4_v:
- case ARM::BI__builtin_neon_vst4q_v:
- case ARM::BI__builtin_neon_vst4_lane_v:
- case ARM::BI__builtin_neon_vst4q_lane_v:
+ case NEON::BI__builtin_neon_vld1_v:
+ case NEON::BI__builtin_neon_vld1q_v:
+ case NEON::BI__builtin_neon_vld1q_lane_v:
+ case NEON::BI__builtin_neon_vld1_lane_v:
+ case NEON::BI__builtin_neon_vld1_dup_v:
+ case NEON::BI__builtin_neon_vld1q_dup_v:
+ case NEON::BI__builtin_neon_vst1_v:
+ case NEON::BI__builtin_neon_vst1q_v:
+ case NEON::BI__builtin_neon_vst1q_lane_v:
+ case NEON::BI__builtin_neon_vst1_lane_v:
+ case NEON::BI__builtin_neon_vst2_v:
+ case NEON::BI__builtin_neon_vst2q_v:
+ case NEON::BI__builtin_neon_vst2_lane_v:
+ case NEON::BI__builtin_neon_vst2q_lane_v:
+ case NEON::BI__builtin_neon_vst3_v:
+ case NEON::BI__builtin_neon_vst3q_v:
+ case NEON::BI__builtin_neon_vst3_lane_v:
+ case NEON::BI__builtin_neon_vst3q_lane_v:
+ case NEON::BI__builtin_neon_vst4_v:
+ case NEON::BI__builtin_neon_vst4q_v:
+ case NEON::BI__builtin_neon_vst4_lane_v:
+ case NEON::BI__builtin_neon_vst4q_lane_v:
// Get the alignment for the argument in addition to the value;
// we'll use it later.
std::pair<llvm::Value*, unsigned> Src =
@@ -4107,21 +3282,21 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
if (i == 1) {
switch (BuiltinID) {
- case ARM::BI__builtin_neon_vld2_v:
- case ARM::BI__builtin_neon_vld2q_v:
- case ARM::BI__builtin_neon_vld3_v:
- case ARM::BI__builtin_neon_vld3q_v:
- case ARM::BI__builtin_neon_vld4_v:
- case ARM::BI__builtin_neon_vld4q_v:
- case ARM::BI__builtin_neon_vld2_lane_v:
- case ARM::BI__builtin_neon_vld2q_lane_v:
- case ARM::BI__builtin_neon_vld3_lane_v:
- case ARM::BI__builtin_neon_vld3q_lane_v:
- case ARM::BI__builtin_neon_vld4_lane_v:
- case ARM::BI__builtin_neon_vld4q_lane_v:
- case ARM::BI__builtin_neon_vld2_dup_v:
- case ARM::BI__builtin_neon_vld3_dup_v:
- case ARM::BI__builtin_neon_vld4_dup_v:
+ case NEON::BI__builtin_neon_vld2_v:
+ case NEON::BI__builtin_neon_vld2q_v:
+ case NEON::BI__builtin_neon_vld3_v:
+ case NEON::BI__builtin_neon_vld3q_v:
+ case NEON::BI__builtin_neon_vld4_v:
+ case NEON::BI__builtin_neon_vld4q_v:
+ case NEON::BI__builtin_neon_vld2_lane_v:
+ case NEON::BI__builtin_neon_vld2q_lane_v:
+ case NEON::BI__builtin_neon_vld3_lane_v:
+ case NEON::BI__builtin_neon_vld3q_lane_v:
+ case NEON::BI__builtin_neon_vld4_lane_v:
+ case NEON::BI__builtin_neon_vld4q_lane_v:
+ case NEON::BI__builtin_neon_vld2_dup_v:
+ case NEON::BI__builtin_neon_vld3_dup_v:
+ case NEON::BI__builtin_neon_vld4_dup_v:
// Get the alignment for the argument in addition to the value;
// we'll use it later.
std::pair<llvm::Value*, unsigned> Src =
@@ -4134,41 +3309,59 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops.push_back(EmitScalarExpr(E->getArg(i)));
}
- // vget_lane and vset_lane are not overloaded and do not have an extra
- // argument that specifies the vector type.
switch (BuiltinID) {
default: break;
- case ARM::BI__builtin_neon_vget_lane_i8:
- case ARM::BI__builtin_neon_vget_lane_i16:
- case ARM::BI__builtin_neon_vget_lane_i32:
- case ARM::BI__builtin_neon_vget_lane_i64:
- case ARM::BI__builtin_neon_vget_lane_f32:
- case ARM::BI__builtin_neon_vgetq_lane_i8:
- case ARM::BI__builtin_neon_vgetq_lane_i16:
- case ARM::BI__builtin_neon_vgetq_lane_i32:
- case ARM::BI__builtin_neon_vgetq_lane_i64:
- case ARM::BI__builtin_neon_vgetq_lane_f32:
+ // vget_lane and vset_lane are not overloaded and do not have an extra
+ // argument that specifies the vector type.
+ case NEON::BI__builtin_neon_vget_lane_i8:
+ case NEON::BI__builtin_neon_vget_lane_i16:
+ case NEON::BI__builtin_neon_vget_lane_i32:
+ case NEON::BI__builtin_neon_vget_lane_i64:
+ case NEON::BI__builtin_neon_vget_lane_f32:
+ case NEON::BI__builtin_neon_vgetq_lane_i8:
+ case NEON::BI__builtin_neon_vgetq_lane_i16:
+ case NEON::BI__builtin_neon_vgetq_lane_i32:
+ case NEON::BI__builtin_neon_vgetq_lane_i64:
+ case NEON::BI__builtin_neon_vgetq_lane_f32:
return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
"vget_lane");
- case ARM::BI__builtin_neon_vset_lane_i8:
- case ARM::BI__builtin_neon_vset_lane_i16:
- case ARM::BI__builtin_neon_vset_lane_i32:
- case ARM::BI__builtin_neon_vset_lane_i64:
- case ARM::BI__builtin_neon_vset_lane_f32:
- case ARM::BI__builtin_neon_vsetq_lane_i8:
- case ARM::BI__builtin_neon_vsetq_lane_i16:
- case ARM::BI__builtin_neon_vsetq_lane_i32:
- case ARM::BI__builtin_neon_vsetq_lane_i64:
- case ARM::BI__builtin_neon_vsetq_lane_f32:
+ case NEON::BI__builtin_neon_vset_lane_i8:
+ case NEON::BI__builtin_neon_vset_lane_i16:
+ case NEON::BI__builtin_neon_vset_lane_i32:
+ case NEON::BI__builtin_neon_vset_lane_i64:
+ case NEON::BI__builtin_neon_vset_lane_f32:
+ case NEON::BI__builtin_neon_vsetq_lane_i8:
+ case NEON::BI__builtin_neon_vsetq_lane_i16:
+ case NEON::BI__builtin_neon_vsetq_lane_i32:
+ case NEON::BI__builtin_neon_vsetq_lane_i64:
+ case NEON::BI__builtin_neon_vsetq_lane_f32:
Ops.push_back(EmitScalarExpr(E->getArg(2)));
return Builder.CreateInsertElement(Ops[1], Ops[0], Ops[2], "vset_lane");
+
+ // Non-polymorphic crypto instructions also not overloaded
+ case NEON::BI__builtin_neon_vsha1h_u32:
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha1h), Ops,
+ "vsha1h");
+ case NEON::BI__builtin_neon_vsha1cq_u32:
+ Ops.push_back(EmitScalarExpr(E->getArg(2)));
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha1c), Ops,
+ "vsha1h");
+ case NEON::BI__builtin_neon_vsha1pq_u32:
+ Ops.push_back(EmitScalarExpr(E->getArg(2)));
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha1p), Ops,
+ "vsha1h");
+ case NEON::BI__builtin_neon_vsha1mq_u32:
+ Ops.push_back(EmitScalarExpr(E->getArg(2)));
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_sha1m), Ops,
+ "vsha1h");
}
// Get the last argument, which specifies the vector type.
llvm::APSInt Result;
const Expr *Arg = E->getArg(E->getNumArgs()-1);
if (!Arg->isIntegerConstantExpr(Result, getContext()))
- return 0;
+ return nullptr;
if (BuiltinID == ARM::BI__builtin_arm_vcvtr_f ||
BuiltinID == ARM::BI__builtin_arm_vcvtr_d) {
@@ -4191,166 +3384,27 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
// Determine the type of this overloaded NEON intrinsic.
NeonTypeFlags Type(Result.getZExtValue());
bool usgn = Type.isUnsigned();
- bool quad = Type.isQuad();
bool rightShift = false;
llvm::VectorType *VTy = GetNeonType(this, Type);
llvm::Type *Ty = VTy;
if (!Ty)
- return 0;
+ return nullptr;
+
+ // Many NEON builtins have identical semantics and uses in ARM and
+ // AArch64. Emit these in a single function.
+ ArrayRef<NeonIntrinsicInfo> IntrinsicMap(ARMSIMDIntrinsicMap);
+ const NeonIntrinsicInfo *Builtin = findNeonIntrinsicInMap(
+ IntrinsicMap, BuiltinID, NEONSIMDIntrinsicsProvenSorted);
+ if (Builtin)
+ return EmitCommonNeonBuiltinExpr(
+ Builtin->BuiltinID, Builtin->LLVMIntrinsic, Builtin->AltLLVMIntrinsic,
+ Builtin->NameHint, Builtin->TypeModifier, E, Ops, Align);
unsigned Int;
switch (BuiltinID) {
- default: return 0;
- case ARM::BI__builtin_neon_vbsl_v:
- case ARM::BI__builtin_neon_vbslq_v:
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vbsl, Ty),
- Ops, "vbsl");
- 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), 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),
- Ops, "vabs");
- case ARM::BI__builtin_neon_vaddhn_v: {
- llvm::VectorType *SrcTy =
- llvm::VectorType::getExtendedElementVectorType(VTy);
-
- // %sum = add <4 x i32> %lhs, %rhs
- Ops[0] = Builder.CreateBitCast(Ops[0], SrcTy);
- Ops[1] = Builder.CreateBitCast(Ops[1], SrcTy);
- Ops[0] = Builder.CreateAdd(Ops[0], Ops[1], "vaddhn");
-
- // %high = lshr <4 x i32> %sum, <i32 16, i32 16, i32 16, i32 16>
- Constant *ShiftAmt = ConstantInt::get(SrcTy->getElementType(),
- SrcTy->getScalarSizeInBits() / 2);
- ShiftAmt = ConstantVector::getSplat(VTy->getNumElements(), ShiftAmt);
- Ops[0] = Builder.CreateLShr(Ops[0], ShiftAmt, "vaddhn");
-
- // %res = trunc <4 x i32> %high to <4 x i16>
- return Builder.CreateTrunc(Ops[0], VTy, "vaddhn");
- }
- case ARM::BI__builtin_neon_vcale_v:
- std::swap(Ops[0], Ops[1]);
- case ARM::BI__builtin_neon_vcage_v: {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vacged);
- return EmitNeonCall(F, Ops, "vcage");
- }
- case ARM::BI__builtin_neon_vcaleq_v:
- std::swap(Ops[0], Ops[1]);
- case ARM::BI__builtin_neon_vcageq_v: {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vacgeq);
- return EmitNeonCall(F, Ops, "vcage");
- }
- case ARM::BI__builtin_neon_vcalt_v:
- std::swap(Ops[0], Ops[1]);
- case ARM::BI__builtin_neon_vcagt_v: {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vacgtd);
- return EmitNeonCall(F, Ops, "vcagt");
- }
- case ARM::BI__builtin_neon_vcaltq_v:
- std::swap(Ops[0], Ops[1]);
- case ARM::BI__builtin_neon_vcagtq_v: {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vacgtq);
- return EmitNeonCall(F, Ops, "vcagt");
- }
- case ARM::BI__builtin_neon_vcls_v:
- case ARM::BI__builtin_neon_vclsq_v: {
- 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: {
- // Generate target-independent intrinsic; also need to add second argument
- // for whether or not clz of zero is undefined; on ARM it isn't.
- Function *F = CGM.getIntrinsic(Intrinsic::ctlz, Ty);
- Ops.push_back(Builder.getInt1(getTarget().isCLZForZeroUndef()));
- return EmitNeonCall(F, Ops, "vclz");
- }
- case ARM::BI__builtin_neon_vcnt_v:
- case ARM::BI__builtin_neon_vcntq_v: {
- // generate target-independent intrinsic
- Function *F = CGM.getIntrinsic(Intrinsic::ctpop, Ty);
- return EmitNeonCall(F, Ops, "vctpop");
- }
- case ARM::BI__builtin_neon_vcvt_f16_v: {
- assert(Type.getEltType() == NeonTypeFlags::Float16 && !quad &&
- "unexpected vcvt_f16_v builtin");
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vcvtfp2hf);
- return EmitNeonCall(F, Ops, "vcvt");
- }
- case ARM::BI__builtin_neon_vcvt_f32_f16: {
- assert(Type.getEltType() == NeonTypeFlags::Float16 && !quad &&
- "unexpected vcvt_f32_f16 builtin");
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vcvthf2fp);
- return EmitNeonCall(F, Ops, "vcvt");
- }
- case ARM::BI__builtin_neon_vcvt_f32_v:
- case ARM::BI__builtin_neon_vcvtq_f32_v:
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, quad));
- return usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt")
- : Builder.CreateSIToFP(Ops[0], Ty, "vcvt");
- case ARM::BI__builtin_neon_vcvt_s32_v:
- case ARM::BI__builtin_neon_vcvt_u32_v:
- case ARM::BI__builtin_neon_vcvtq_s32_v:
- case ARM::BI__builtin_neon_vcvtq_u32_v: {
- llvm::Type *FloatTy =
- GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, quad));
- Ops[0] = Builder.CreateBitCast(Ops[0], FloatTy);
- return usgn ? Builder.CreateFPToUI(Ops[0], Ty, "vcvt")
- : Builder.CreateFPToSI(Ops[0], Ty, "vcvt");
- }
- case ARM::BI__builtin_neon_vcvt_n_f32_v:
- case ARM::BI__builtin_neon_vcvtq_n_f32_v: {
- llvm::Type *FloatTy =
- GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, quad));
- llvm::Type *Tys[2] = { FloatTy, Ty };
- Int = usgn ? Intrinsic::arm_neon_vcvtfxu2fp
- : Intrinsic::arm_neon_vcvtfxs2fp;
- 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: {
- llvm::Type *FloatTy =
- GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, quad));
- llvm::Type *Tys[2] = { Ty, FloatTy };
- Int = usgn ? Intrinsic::arm_neon_vcvtfp2fxu
- : Intrinsic::arm_neon_vcvtfp2fxs;
- Function *F = CGM.getIntrinsic(Int, Tys);
- return EmitNeonCall(F, Ops, "vcvt_n");
- }
- case ARM::BI__builtin_neon_vext_v:
- case ARM::BI__builtin_neon_vextq_v: {
- int CV = cast<ConstantInt>(Ops[2])->getSExtValue();
- SmallVector<Constant*, 16> Indices;
- for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i)
- Indices.push_back(ConstantInt::get(Int32Ty, i+CV));
-
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Value *SV = llvm::ConstantVector::get(Indices);
- return Builder.CreateShuffleVector(Ops[0], Ops[1], SV, "vext");
- }
- 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), 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), Ops, "vhsub");
- case ARM::BI__builtin_neon_vld1_v:
- case ARM::BI__builtin_neon_vld1q_v:
- Ops.push_back(Align);
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vld1, Ty),
- Ops, "vld1");
- case ARM::BI__builtin_neon_vld1q_lane_v:
+ default: return nullptr;
+ case NEON::BI__builtin_neon_vld1q_lane_v:
// Handle 64-bit integer elements as a special case. Use shuffles of
// one-element vectors to avoid poor code for i64 in the backend.
if (VTy->getElementType()->isIntegerTy(64)) {
@@ -4371,7 +3425,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return Builder.CreateShuffleVector(Ops[1], Ld, SV, "vld1q_lane");
}
// fall through
- case ARM::BI__builtin_neon_vld1_lane_v: {
+ case NEON::BI__builtin_neon_vld1_lane_v: {
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ty = llvm::PointerType::getUnqual(VTy->getElementType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
@@ -4379,90 +3433,19 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ld->setAlignment(cast<ConstantInt>(Align)->getZExtValue());
return Builder.CreateInsertElement(Ops[1], Ld, Ops[2], "vld1_lane");
}
- case ARM::BI__builtin_neon_vld1_dup_v:
- case ARM::BI__builtin_neon_vld1q_dup_v: {
- Value *V = UndefValue::get(Ty);
- Ty = llvm::PointerType::getUnqual(VTy->getElementType());
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- LoadInst *Ld = Builder.CreateLoad(Ops[0]);
- Ld->setAlignment(cast<ConstantInt>(Align)->getZExtValue());
- llvm::Constant *CI = ConstantInt::get(Int32Ty, 0);
- Ops[0] = Builder.CreateInsertElement(V, Ld, CI);
- return EmitNeonSplat(Ops[0], CI);
- }
- case ARM::BI__builtin_neon_vld2_v:
- case ARM::BI__builtin_neon_vld2q_v: {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld2, Ty);
- Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld2");
- 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_v:
- case ARM::BI__builtin_neon_vld3q_v: {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld3, Ty);
- Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld3");
- 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_v:
- case ARM::BI__builtin_neon_vld4q_v: {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld4, Ty);
- Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld4");
- 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_vld2_lane_v:
- case ARM::BI__builtin_neon_vld2q_lane_v: {
- 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(Align);
- Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "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);
- Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
- Ops[4] = Builder.CreateBitCast(Ops[4], Ty);
- Ops.push_back(Align);
- Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "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);
- 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(Align);
- Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "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_vld2_dup_v:
- case ARM::BI__builtin_neon_vld3_dup_v:
- case ARM::BI__builtin_neon_vld4_dup_v: {
+ case NEON::BI__builtin_neon_vld2_dup_v:
+ case NEON::BI__builtin_neon_vld3_dup_v:
+ case NEON::BI__builtin_neon_vld4_dup_v: {
// Handle 64-bit elements as a special-case. There is no "dup" needed.
if (VTy->getElementType()->getPrimitiveSizeInBits() == 64) {
switch (BuiltinID) {
- case ARM::BI__builtin_neon_vld2_dup_v:
+ case NEON::BI__builtin_neon_vld2_dup_v:
Int = Intrinsic::arm_neon_vld2;
break;
- case ARM::BI__builtin_neon_vld3_dup_v:
+ case NEON::BI__builtin_neon_vld3_dup_v:
Int = Intrinsic::arm_neon_vld3;
break;
- case ARM::BI__builtin_neon_vld4_dup_v:
+ case NEON::BI__builtin_neon_vld4_dup_v:
Int = Intrinsic::arm_neon_vld4;
break;
default: llvm_unreachable("unknown vld_dup intrinsic?");
@@ -4474,13 +3457,13 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return Builder.CreateStore(Ops[1], Ops[0]);
}
switch (BuiltinID) {
- case ARM::BI__builtin_neon_vld2_dup_v:
+ case NEON::BI__builtin_neon_vld2_dup_v:
Int = Intrinsic::arm_neon_vld2lane;
break;
- case ARM::BI__builtin_neon_vld3_dup_v:
+ case NEON::BI__builtin_neon_vld3_dup_v:
Int = Intrinsic::arm_neon_vld3lane;
break;
- case ARM::BI__builtin_neon_vld4_dup_v:
+ case NEON::BI__builtin_neon_vld4_dup_v:
Int = Intrinsic::arm_neon_vld4lane;
break;
default: llvm_unreachable("unknown vld_dup intrinsic?");
@@ -4509,251 +3492,58 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
return Builder.CreateStore(Ops[1], Ops[0]);
}
- 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), 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), Ops, "vmin");
- case ARM::BI__builtin_neon_vmovl_v: {
- llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy);
- Ops[0] = Builder.CreateBitCast(Ops[0], DTy);
- if (usgn)
- return Builder.CreateZExt(Ops[0], Ty, "vmovl");
- return Builder.CreateSExt(Ops[0], Ty, "vmovl");
- }
- case ARM::BI__builtin_neon_vmovn_v: {
- llvm::Type *QTy = llvm::VectorType::getExtendedElementVectorType(VTy);
- Ops[0] = Builder.CreateBitCast(Ops[0], QTy);
- return Builder.CreateTrunc(Ops[0], Ty, "vmovn");
- }
- case ARM::BI__builtin_neon_vmul_v:
- case ARM::BI__builtin_neon_vmulq_v:
- assert(Type.isPoly() && "vmul builtin only supported for polynomial types");
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vmulp, Ty),
- Ops, "vmul");
- case ARM::BI__builtin_neon_vmull_v:
- // FIXME: the integer vmull operations could be emitted in terms of pure
- // LLVM IR (2 exts followed by a mul). Unfortunately LLVM has a habit of
- // hoisting the exts outside loops. Until global ISel comes along that can
- // see through such movement this leads to bad CodeGen. So we need an
- // intrinsic for now.
- Int = usgn ? Intrinsic::arm_neon_vmullu : Intrinsic::arm_neon_vmulls;
- Int = Type.isPoly() ? (unsigned)Intrinsic::arm_neon_vmullp : Int;
- return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmull");
- case ARM::BI__builtin_neon_vfma_v:
- case ARM::BI__builtin_neon_vfmaq_v: {
- Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
- Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
- Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
- Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
-
- // NEON intrinsic puts accumulator first, unlike the LLVM fma.
- return Builder.CreateCall3(F, Ops[1], Ops[2], Ops[0]);
- }
- case ARM::BI__builtin_neon_vpadal_v:
- case ARM::BI__builtin_neon_vpadalq_v: {
- Int = usgn ? Intrinsic::arm_neon_vpadalu : Intrinsic::arm_neon_vpadals;
- // The source operand type has twice as many elements of half the size.
- unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits();
- llvm::Type *EltTy =
- llvm::IntegerType::get(getLLVMContext(), EltBits / 2);
- llvm::Type *NarrowTy =
- llvm::VectorType::get(EltTy, VTy->getNumElements() * 2);
- 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),
- Ops, "vpadd");
- case ARM::BI__builtin_neon_vpaddl_v:
- case ARM::BI__builtin_neon_vpaddlq_v: {
- Int = usgn ? Intrinsic::arm_neon_vpaddlu : Intrinsic::arm_neon_vpaddls;
- // The source operand type has twice as many elements of half the size.
- unsigned EltBits = VTy->getElementType()->getPrimitiveSizeInBits();
- llvm::Type *EltTy = llvm::IntegerType::get(getLLVMContext(), EltBits / 2);
- llvm::Type *NarrowTy =
- llvm::VectorType::get(EltTy, VTy->getNumElements() * 2);
- 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), 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), 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),
- 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), Ops, "vqadd");
- case ARM::BI__builtin_neon_vqdmlal_v: {
- SmallVector<Value *, 2> MulOps(Ops.begin() + 1, Ops.end());
- Value *Mul = EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqdmull, Ty),
- MulOps, "vqdmlal");
-
- SmallVector<Value *, 2> AddOps;
- AddOps.push_back(Ops[0]);
- AddOps.push_back(Mul);
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqadds, Ty),
- AddOps, "vqdmlal");
- }
- case ARM::BI__builtin_neon_vqdmlsl_v: {
- SmallVector<Value *, 2> MulOps(Ops.begin() + 1, Ops.end());
- Value *Mul = EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqdmull, Ty),
- MulOps, "vqdmlsl");
-
- SmallVector<Value *, 2> SubOps;
- SubOps.push_back(Ops[0]);
- SubOps.push_back(Mul);
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqsubs, Ty),
- SubOps, "vqdmlsl");
- }
- case ARM::BI__builtin_neon_vqdmulh_v:
- case ARM::BI__builtin_neon_vqdmulhq_v:
- 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),
- 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), Ops, "vqmovn");
- case ARM::BI__builtin_neon_vqmovun_v:
- 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),
- 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),
- 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), Ops, "vqrshl");
- case ARM::BI__builtin_neon_vqrshrn_n_v:
+ case NEON::BI__builtin_neon_vqrshrn_n_v:
Int =
usgn ? Intrinsic::arm_neon_vqrshiftnu : Intrinsic::arm_neon_vqrshiftns;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshrn_n",
1, true);
- case ARM::BI__builtin_neon_vqrshrun_n_v:
+ case NEON::BI__builtin_neon_vqrshrun_n_v:
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), 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), Ops, "vqshl_n",
- 1, false);
- case ARM::BI__builtin_neon_vqshlu_n_v:
- case ARM::BI__builtin_neon_vqshluq_n_v:
+ case NEON::BI__builtin_neon_vqshlu_n_v:
+ case NEON::BI__builtin_neon_vqshluq_n_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vqshiftsu, Ty),
Ops, "vqshlu", 1, false);
- case ARM::BI__builtin_neon_vqshrn_n_v:
+ case NEON::BI__builtin_neon_vqshrn_n_v:
Int = usgn ? Intrinsic::arm_neon_vqshiftnu : Intrinsic::arm_neon_vqshiftns;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshrn_n",
1, true);
- case ARM::BI__builtin_neon_vqshrun_n_v:
+ case NEON::BI__builtin_neon_vqshrun_n_v:
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), Ops, "vqsub");
- case ARM::BI__builtin_neon_vraddhn_v:
- 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:
+ case NEON::BI__builtin_neon_vrecpe_v:
+ case NEON::BI__builtin_neon_vrecpeq_v:
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),
- 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), 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), Ops, "vrshl");
- case ARM::BI__builtin_neon_vrshrn_n_v:
+ case NEON::BI__builtin_neon_vrshrn_n_v:
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:
+ case NEON::BI__builtin_neon_vrshr_n_v:
+ case NEON::BI__builtin_neon_vrshrq_n_v:
Int = usgn ? Intrinsic::arm_neon_vrshiftu : Intrinsic::arm_neon_vrshifts;
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),
- 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),
- Ops, "vrsqrts");
- case ARM::BI__builtin_neon_vrsra_n_v:
- case ARM::BI__builtin_neon_vrsraq_n_v:
+ case NEON::BI__builtin_neon_vrsra_n_v:
+ case NEON::BI__builtin_neon_vrsraq_n_v:
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
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), 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),
- Ops, "vrsubhn");
- 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), 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), 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),
- Ops, "vshrn_n", 1, true);
- case ARM::BI__builtin_neon_vshr_n_v:
- case ARM::BI__builtin_neon_vshrq_n_v:
- return EmitNeonRShiftImm(Ops[0], Ops[1], Ty, usgn, "vshr_n");
- case ARM::BI__builtin_neon_vsri_n_v:
- case ARM::BI__builtin_neon_vsriq_n_v:
+ case NEON::BI__builtin_neon_vsri_n_v:
+ case NEON::BI__builtin_neon_vsriq_n_v:
rightShift = true;
- case ARM::BI__builtin_neon_vsli_n_v:
- case ARM::BI__builtin_neon_vsliq_n_v:
+ case NEON::BI__builtin_neon_vsli_n_v:
+ case NEON::BI__builtin_neon_vsliq_n_v:
Ops[2] = EmitNeonShiftVector(Ops[2], Ty, rightShift);
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:
+ case NEON::BI__builtin_neon_vsra_n_v:
+ case NEON::BI__builtin_neon_vsraq_n_v:
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
Ops[1] = EmitNeonRShiftImm(Ops[1], Ops[2], Ty, usgn, "vsra_n");
return Builder.CreateAdd(Ops[0], Ops[1]);
- case ARM::BI__builtin_neon_vst1_v:
- case ARM::BI__builtin_neon_vst1q_v:
- Ops.push_back(Align);
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst1, Ty),
- Ops, "");
- case ARM::BI__builtin_neon_vst1q_lane_v:
+ case NEON::BI__builtin_neon_vst1q_lane_v:
// Handle 64-bit integer elements as a special case. Use a shuffle to get
// a one-element vector and avoid poor code for i64 in the backend.
if (VTy->getElementType()->isIntegerTy(64)) {
@@ -4765,7 +3555,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[1]->getType()), Ops);
}
// fall through
- case ARM::BI__builtin_neon_vst1_lane_v: {
+ case NEON::BI__builtin_neon_vst1_lane_v: {
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[1] = Builder.CreateExtractElement(Ops[1], Ops[2]);
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
@@ -4774,99 +3564,1984 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
St->setAlignment(cast<ConstantInt>(Align)->getZExtValue());
return St;
}
- case ARM::BI__builtin_neon_vst2_v:
- case ARM::BI__builtin_neon_vst2q_v:
- Ops.push_back(Align);
- 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(Align);
- 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(Align);
- 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(Align);
- 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(Align);
- 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(Align);
- return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst4lane, Ty),
- Ops, "");
- case ARM::BI__builtin_neon_vsubhn_v: {
- llvm::VectorType *SrcTy =
- llvm::VectorType::getExtendedElementVectorType(VTy);
-
- // %sum = add <4 x i32> %lhs, %rhs
- Ops[0] = Builder.CreateBitCast(Ops[0], SrcTy);
- Ops[1] = Builder.CreateBitCast(Ops[1], SrcTy);
- Ops[0] = Builder.CreateSub(Ops[0], Ops[1], "vsubhn");
-
- // %high = lshr <4 x i32> %sum, <i32 16, i32 16, i32 16, i32 16>
- Constant *ShiftAmt = ConstantInt::get(SrcTy->getElementType(),
- SrcTy->getScalarSizeInBits() / 2);
- ShiftAmt = ConstantVector::getSplat(VTy->getNumElements(), ShiftAmt);
- Ops[0] = Builder.CreateLShr(Ops[0], ShiftAmt, "vsubhn");
-
- // %res = trunc <4 x i32> %high to <4 x i16>
- return Builder.CreateTrunc(Ops[0], VTy, "vsubhn");
- }
- case ARM::BI__builtin_neon_vtbl1_v:
+ case NEON::BI__builtin_neon_vtbl1_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbl1),
Ops, "vtbl1");
- case ARM::BI__builtin_neon_vtbl2_v:
+ case NEON::BI__builtin_neon_vtbl2_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbl2),
Ops, "vtbl2");
- case ARM::BI__builtin_neon_vtbl3_v:
+ case NEON::BI__builtin_neon_vtbl3_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbl3),
Ops, "vtbl3");
- case ARM::BI__builtin_neon_vtbl4_v:
+ case NEON::BI__builtin_neon_vtbl4_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbl4),
Ops, "vtbl4");
- case ARM::BI__builtin_neon_vtbx1_v:
+ case NEON::BI__builtin_neon_vtbx1_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbx1),
Ops, "vtbx1");
- case ARM::BI__builtin_neon_vtbx2_v:
+ case NEON::BI__builtin_neon_vtbx2_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbx2),
Ops, "vtbx2");
- case ARM::BI__builtin_neon_vtbx3_v:
+ case NEON::BI__builtin_neon_vtbx3_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbx3),
Ops, "vtbx3");
- case ARM::BI__builtin_neon_vtbx4_v:
+ case NEON::BI__builtin_neon_vtbx4_v:
return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbx4),
Ops, "vtbx4");
- case ARM::BI__builtin_neon_vtst_v:
- case ARM::BI__builtin_neon_vtstq_v: {
+ }
+}
+
+static Value *EmitAArch64TblBuiltinExpr(CodeGenFunction &CGF, unsigned BuiltinID,
+ const CallExpr *E,
+ SmallVectorImpl<Value *> &Ops) {
+ unsigned int Int = 0;
+ const char *s = nullptr;
+
+ switch (BuiltinID) {
+ default:
+ return nullptr;
+ case NEON::BI__builtin_neon_vtbl1_v:
+ case NEON::BI__builtin_neon_vqtbl1_v:
+ case NEON::BI__builtin_neon_vqtbl1q_v:
+ case NEON::BI__builtin_neon_vtbl2_v:
+ case NEON::BI__builtin_neon_vqtbl2_v:
+ case NEON::BI__builtin_neon_vqtbl2q_v:
+ case NEON::BI__builtin_neon_vtbl3_v:
+ case NEON::BI__builtin_neon_vqtbl3_v:
+ case NEON::BI__builtin_neon_vqtbl3q_v:
+ case NEON::BI__builtin_neon_vtbl4_v:
+ case NEON::BI__builtin_neon_vqtbl4_v:
+ case NEON::BI__builtin_neon_vqtbl4q_v:
+ break;
+ case NEON::BI__builtin_neon_vtbx1_v:
+ case NEON::BI__builtin_neon_vqtbx1_v:
+ case NEON::BI__builtin_neon_vqtbx1q_v:
+ case NEON::BI__builtin_neon_vtbx2_v:
+ case NEON::BI__builtin_neon_vqtbx2_v:
+ case NEON::BI__builtin_neon_vqtbx2q_v:
+ case NEON::BI__builtin_neon_vtbx3_v:
+ case NEON::BI__builtin_neon_vqtbx3_v:
+ case NEON::BI__builtin_neon_vqtbx3q_v:
+ case NEON::BI__builtin_neon_vtbx4_v:
+ case NEON::BI__builtin_neon_vqtbx4_v:
+ case NEON::BI__builtin_neon_vqtbx4q_v:
+ break;
+ }
+
+ assert(E->getNumArgs() >= 3);
+
+ // Get the last argument, which specifies the vector type.
+ llvm::APSInt Result;
+ const Expr *Arg = E->getArg(E->getNumArgs() - 1);
+ if (!Arg->isIntegerConstantExpr(Result, CGF.getContext()))
+ return nullptr;
+
+ // Determine the type of this overloaded NEON intrinsic.
+ NeonTypeFlags Type(Result.getZExtValue());
+ llvm::VectorType *VTy = GetNeonType(&CGF, Type);
+ llvm::Type *Ty = VTy;
+ if (!Ty)
+ return nullptr;
+
+ unsigned nElts = VTy->getNumElements();
+
+ CodeGen::CGBuilderTy &Builder = CGF.Builder;
+
+ // AArch64 scalar builtins are not overloaded, they do not have an extra
+ // argument that specifies the vector type, need to handle each case.
+ SmallVector<Value *, 2> TblOps;
+ switch (BuiltinID) {
+ case NEON::BI__builtin_neon_vtbl1_v: {
+ TblOps.push_back(Ops[0]);
+ return packTBLDVectorList(CGF, TblOps, nullptr, Ops[1], Ty,
+ Intrinsic::aarch64_neon_tbl1, "vtbl1");
+ }
+ case NEON::BI__builtin_neon_vtbl2_v: {
+ TblOps.push_back(Ops[0]);
+ TblOps.push_back(Ops[1]);
+ return packTBLDVectorList(CGF, TblOps, nullptr, Ops[2], Ty,
+ Intrinsic::aarch64_neon_tbl1, "vtbl1");
+ }
+ case NEON::BI__builtin_neon_vtbl3_v: {
+ TblOps.push_back(Ops[0]);
+ TblOps.push_back(Ops[1]);
+ TblOps.push_back(Ops[2]);
+ return packTBLDVectorList(CGF, TblOps, nullptr, Ops[3], Ty,
+ Intrinsic::aarch64_neon_tbl2, "vtbl2");
+ }
+ case NEON::BI__builtin_neon_vtbl4_v: {
+ TblOps.push_back(Ops[0]);
+ TblOps.push_back(Ops[1]);
+ TblOps.push_back(Ops[2]);
+ TblOps.push_back(Ops[3]);
+ return packTBLDVectorList(CGF, TblOps, nullptr, Ops[4], Ty,
+ Intrinsic::aarch64_neon_tbl2, "vtbl2");
+ }
+ case NEON::BI__builtin_neon_vtbx1_v: {
+ TblOps.push_back(Ops[1]);
+ Value *TblRes = packTBLDVectorList(CGF, TblOps, nullptr, Ops[2], Ty,
+ Intrinsic::aarch64_neon_tbl1, "vtbl1");
+
+ llvm::Constant *Eight = ConstantInt::get(VTy->getElementType(), 8);
+ Value* EightV = llvm::ConstantVector::getSplat(nElts, Eight);
+ Value *CmpRes = Builder.CreateICmp(ICmpInst::ICMP_UGE, Ops[2], EightV);
+ CmpRes = Builder.CreateSExt(CmpRes, Ty);
+
+ Value *EltsFromInput = Builder.CreateAnd(CmpRes, Ops[0]);
+ Value *EltsFromTbl = Builder.CreateAnd(Builder.CreateNot(CmpRes), TblRes);
+ return Builder.CreateOr(EltsFromInput, EltsFromTbl, "vtbx");
+ }
+ case NEON::BI__builtin_neon_vtbx2_v: {
+ TblOps.push_back(Ops[1]);
+ TblOps.push_back(Ops[2]);
+ return packTBLDVectorList(CGF, TblOps, Ops[0], Ops[3], Ty,
+ Intrinsic::aarch64_neon_tbx1, "vtbx1");
+ }
+ case NEON::BI__builtin_neon_vtbx3_v: {
+ TblOps.push_back(Ops[1]);
+ TblOps.push_back(Ops[2]);
+ TblOps.push_back(Ops[3]);
+ Value *TblRes = packTBLDVectorList(CGF, TblOps, nullptr, Ops[4], Ty,
+ Intrinsic::aarch64_neon_tbl2, "vtbl2");
+
+ llvm::Constant *TwentyFour = ConstantInt::get(VTy->getElementType(), 24);
+ Value* TwentyFourV = llvm::ConstantVector::getSplat(nElts, TwentyFour);
+ Value *CmpRes = Builder.CreateICmp(ICmpInst::ICMP_UGE, Ops[4],
+ TwentyFourV);
+ CmpRes = Builder.CreateSExt(CmpRes, Ty);
+
+ Value *EltsFromInput = Builder.CreateAnd(CmpRes, Ops[0]);
+ Value *EltsFromTbl = Builder.CreateAnd(Builder.CreateNot(CmpRes), TblRes);
+ return Builder.CreateOr(EltsFromInput, EltsFromTbl, "vtbx");
+ }
+ case NEON::BI__builtin_neon_vtbx4_v: {
+ TblOps.push_back(Ops[1]);
+ TblOps.push_back(Ops[2]);
+ TblOps.push_back(Ops[3]);
+ TblOps.push_back(Ops[4]);
+ return packTBLDVectorList(CGF, TblOps, Ops[0], Ops[5], Ty,
+ Intrinsic::aarch64_neon_tbx2, "vtbx2");
+ }
+ case NEON::BI__builtin_neon_vqtbl1_v:
+ case NEON::BI__builtin_neon_vqtbl1q_v:
+ Int = Intrinsic::aarch64_neon_tbl1; s = "vtbl1"; break;
+ case NEON::BI__builtin_neon_vqtbl2_v:
+ case NEON::BI__builtin_neon_vqtbl2q_v: {
+ Int = Intrinsic::aarch64_neon_tbl2; s = "vtbl2"; break;
+ case NEON::BI__builtin_neon_vqtbl3_v:
+ case NEON::BI__builtin_neon_vqtbl3q_v:
+ Int = Intrinsic::aarch64_neon_tbl3; s = "vtbl3"; break;
+ case NEON::BI__builtin_neon_vqtbl4_v:
+ case NEON::BI__builtin_neon_vqtbl4q_v:
+ Int = Intrinsic::aarch64_neon_tbl4; s = "vtbl4"; break;
+ case NEON::BI__builtin_neon_vqtbx1_v:
+ case NEON::BI__builtin_neon_vqtbx1q_v:
+ Int = Intrinsic::aarch64_neon_tbx1; s = "vtbx1"; break;
+ case NEON::BI__builtin_neon_vqtbx2_v:
+ case NEON::BI__builtin_neon_vqtbx2q_v:
+ Int = Intrinsic::aarch64_neon_tbx2; s = "vtbx2"; break;
+ case NEON::BI__builtin_neon_vqtbx3_v:
+ case NEON::BI__builtin_neon_vqtbx3q_v:
+ Int = Intrinsic::aarch64_neon_tbx3; s = "vtbx3"; break;
+ case NEON::BI__builtin_neon_vqtbx4_v:
+ case NEON::BI__builtin_neon_vqtbx4q_v:
+ Int = Intrinsic::aarch64_neon_tbx4; s = "vtbx4"; break;
+ }
+ }
+
+ if (!Int)
+ return nullptr;
+
+ Function *F = CGF.CGM.getIntrinsic(Int, Ty);
+ return CGF.EmitNeonCall(F, Ops, s);
+}
+
+Value *CodeGenFunction::vectorWrapScalar16(Value *Op) {
+ llvm::Type *VTy = llvm::VectorType::get(Int16Ty, 4);
+ Op = Builder.CreateBitCast(Op, Int16Ty);
+ Value *V = UndefValue::get(VTy);
+ llvm::Constant *CI = ConstantInt::get(SizeTy, 0);
+ Op = Builder.CreateInsertElement(V, Op, CI);
+ return Op;
+}
+
+Value *CodeGenFunction::vectorWrapScalar8(Value *Op) {
+ llvm::Type *VTy = llvm::VectorType::get(Int8Ty, 8);
+ Op = Builder.CreateBitCast(Op, Int8Ty);
+ Value *V = UndefValue::get(VTy);
+ llvm::Constant *CI = ConstantInt::get(SizeTy, 0);
+ Op = Builder.CreateInsertElement(V, Op, CI);
+ return Op;
+}
+
+Value *CodeGenFunction::
+emitVectorWrappedScalar8Intrinsic(unsigned Int, SmallVectorImpl<Value*> &Ops,
+ const char *Name) {
+ // i8 is not a legal types for AArch64, so we can't just use
+ // a normal overloaded intrinsic call for these scalar types. Instead
+ // we'll build 64-bit vectors w/ lane zero being our input values and
+ // perform the operation on that. The back end can pattern match directly
+ // to the scalar instruction.
+ Ops[0] = vectorWrapScalar8(Ops[0]);
+ Ops[1] = vectorWrapScalar8(Ops[1]);
+ llvm::Type *VTy = llvm::VectorType::get(Int8Ty, 8);
+ Value *V = EmitNeonCall(CGM.getIntrinsic(Int, VTy), Ops, Name);
+ Constant *CI = ConstantInt::get(SizeTy, 0);
+ return Builder.CreateExtractElement(V, CI, "lane0");
+}
+
+Value *CodeGenFunction::
+emitVectorWrappedScalar16Intrinsic(unsigned Int, SmallVectorImpl<Value*> &Ops,
+ const char *Name) {
+ // i16 is not a legal types for AArch64, so we can't just use
+ // a normal overloaded intrinsic call for these scalar types. Instead
+ // we'll build 64-bit vectors w/ lane zero being our input values and
+ // perform the operation on that. The back end can pattern match directly
+ // to the scalar instruction.
+ Ops[0] = vectorWrapScalar16(Ops[0]);
+ Ops[1] = vectorWrapScalar16(Ops[1]);
+ llvm::Type *VTy = llvm::VectorType::get(Int16Ty, 4);
+ Value *V = EmitNeonCall(CGM.getIntrinsic(Int, VTy), Ops, Name);
+ Constant *CI = ConstantInt::get(SizeTy, 0);
+ return Builder.CreateExtractElement(V, CI, "lane0");
+}
+
+Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
+ const CallExpr *E) {
+ unsigned HintID = static_cast<unsigned>(-1);
+ switch (BuiltinID) {
+ default: break;
+ case AArch64::BI__builtin_arm_nop:
+ HintID = 0;
+ break;
+ case AArch64::BI__builtin_arm_yield:
+ HintID = 1;
+ break;
+ case AArch64::BI__builtin_arm_wfe:
+ HintID = 2;
+ break;
+ case AArch64::BI__builtin_arm_wfi:
+ HintID = 3;
+ break;
+ case AArch64::BI__builtin_arm_sev:
+ HintID = 4;
+ break;
+ case AArch64::BI__builtin_arm_sevl:
+ HintID = 5;
+ break;
+ }
+
+ if (HintID != static_cast<unsigned>(-1)) {
+ Function *F = CGM.getIntrinsic(Intrinsic::aarch64_hint);
+ return Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, HintID));
+ }
+
+ if (BuiltinID == AArch64::BI__builtin_arm_rbit) {
+ assert((getContext().getTypeSize(E->getType()) == 32) &&
+ "rbit of unusual size!");
+ llvm::Value *Arg = EmitScalarExpr(E->getArg(0));
+ return Builder.CreateCall(
+ CGM.getIntrinsic(Intrinsic::aarch64_rbit, Arg->getType()), Arg, "rbit");
+ }
+ if (BuiltinID == AArch64::BI__builtin_arm_rbit64) {
+ assert((getContext().getTypeSize(E->getType()) == 64) &&
+ "rbit of unusual size!");
+ llvm::Value *Arg = EmitScalarExpr(E->getArg(0));
+ return Builder.CreateCall(
+ CGM.getIntrinsic(Intrinsic::aarch64_rbit, Arg->getType()), Arg, "rbit");
+ }
+
+ if (BuiltinID == AArch64::BI__clear_cache) {
+ assert(E->getNumArgs() == 2 && "__clear_cache takes 2 arguments");
+ const FunctionDecl *FD = E->getDirectCallee();
+ SmallVector<Value*, 2> Ops;
+ for (unsigned i = 0; i < 2; i++)
+ Ops.push_back(EmitScalarExpr(E->getArg(i)));
+ llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType());
+ llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
+ StringRef Name = FD->getName();
+ return EmitNounwindRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name), Ops);
+ }
+
+ if ((BuiltinID == AArch64::BI__builtin_arm_ldrex ||
+ BuiltinID == AArch64::BI__builtin_arm_ldaex) &&
+ getContext().getTypeSize(E->getType()) == 128) {
+ Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_ldaex
+ ? Intrinsic::aarch64_ldaxp
+ : Intrinsic::aarch64_ldxp);
+
+ Value *LdPtr = EmitScalarExpr(E->getArg(0));
+ Value *Val = Builder.CreateCall(F, Builder.CreateBitCast(LdPtr, Int8PtrTy),
+ "ldxp");
+
+ Value *Val0 = Builder.CreateExtractValue(Val, 1);
+ Value *Val1 = Builder.CreateExtractValue(Val, 0);
+ llvm::Type *Int128Ty = llvm::IntegerType::get(getLLVMContext(), 128);
+ Val0 = Builder.CreateZExt(Val0, Int128Ty);
+ Val1 = Builder.CreateZExt(Val1, Int128Ty);
+
+ Value *ShiftCst = llvm::ConstantInt::get(Int128Ty, 64);
+ Val = Builder.CreateShl(Val0, ShiftCst, "shl", true /* nuw */);
+ Val = Builder.CreateOr(Val, Val1);
+ return Builder.CreateBitCast(Val, ConvertType(E->getType()));
+ } else if (BuiltinID == AArch64::BI__builtin_arm_ldrex ||
+ BuiltinID == AArch64::BI__builtin_arm_ldaex) {
+ Value *LoadAddr = EmitScalarExpr(E->getArg(0));
+
+ QualType Ty = E->getType();
+ llvm::Type *RealResTy = ConvertType(Ty);
+ llvm::Type *IntResTy = llvm::IntegerType::get(getLLVMContext(),
+ getContext().getTypeSize(Ty));
+ LoadAddr = Builder.CreateBitCast(LoadAddr, IntResTy->getPointerTo());
+
+ Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_ldaex
+ ? Intrinsic::aarch64_ldaxr
+ : Intrinsic::aarch64_ldxr,
+ LoadAddr->getType());
+ Value *Val = Builder.CreateCall(F, LoadAddr, "ldxr");
+
+ if (RealResTy->isPointerTy())
+ return Builder.CreateIntToPtr(Val, RealResTy);
+
+ Val = Builder.CreateTruncOrBitCast(Val, IntResTy);
+ return Builder.CreateBitCast(Val, RealResTy);
+ }
+
+ if ((BuiltinID == AArch64::BI__builtin_arm_strex ||
+ BuiltinID == AArch64::BI__builtin_arm_stlex) &&
+ getContext().getTypeSize(E->getArg(0)->getType()) == 128) {
+ Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_stlex
+ ? Intrinsic::aarch64_stlxp
+ : Intrinsic::aarch64_stxp);
+ llvm::Type *STy = llvm::StructType::get(Int64Ty, Int64Ty, NULL);
+
+ Value *One = llvm::ConstantInt::get(Int32Ty, 1);
+ Value *Tmp = Builder.CreateAlloca(ConvertType(E->getArg(0)->getType()),
+ One);
+ Value *Val = EmitScalarExpr(E->getArg(0));
+ Builder.CreateStore(Val, Tmp);
+
+ Value *LdPtr = Builder.CreateBitCast(Tmp,llvm::PointerType::getUnqual(STy));
+ Val = Builder.CreateLoad(LdPtr);
+
+ Value *Arg0 = Builder.CreateExtractValue(Val, 0);
+ Value *Arg1 = Builder.CreateExtractValue(Val, 1);
+ Value *StPtr = Builder.CreateBitCast(EmitScalarExpr(E->getArg(1)),
+ Int8PtrTy);
+ return Builder.CreateCall3(F, Arg0, Arg1, StPtr, "stxp");
+ } else if (BuiltinID == AArch64::BI__builtin_arm_strex ||
+ BuiltinID == AArch64::BI__builtin_arm_stlex) {
+ Value *StoreVal = EmitScalarExpr(E->getArg(0));
+ Value *StoreAddr = EmitScalarExpr(E->getArg(1));
+
+ QualType Ty = E->getArg(0)->getType();
+ llvm::Type *StoreTy = llvm::IntegerType::get(getLLVMContext(),
+ getContext().getTypeSize(Ty));
+ StoreAddr = Builder.CreateBitCast(StoreAddr, StoreTy->getPointerTo());
+
+ if (StoreVal->getType()->isPointerTy())
+ StoreVal = Builder.CreatePtrToInt(StoreVal, Int64Ty);
+ else {
+ StoreVal = Builder.CreateBitCast(StoreVal, StoreTy);
+ StoreVal = Builder.CreateZExtOrBitCast(StoreVal, Int64Ty);
+ }
+
+ Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_stlex
+ ? Intrinsic::aarch64_stlxr
+ : Intrinsic::aarch64_stxr,
+ StoreAddr->getType());
+ return Builder.CreateCall2(F, StoreVal, StoreAddr, "stxr");
+ }
+
+ if (BuiltinID == AArch64::BI__builtin_arm_clrex) {
+ Function *F = CGM.getIntrinsic(Intrinsic::aarch64_clrex);
+ return Builder.CreateCall(F);
+ }
+
+ // CRC32
+ Intrinsic::ID CRCIntrinsicID = Intrinsic::not_intrinsic;
+ switch (BuiltinID) {
+ case AArch64::BI__builtin_arm_crc32b:
+ CRCIntrinsicID = Intrinsic::aarch64_crc32b; break;
+ case AArch64::BI__builtin_arm_crc32cb:
+ CRCIntrinsicID = Intrinsic::aarch64_crc32cb; break;
+ case AArch64::BI__builtin_arm_crc32h:
+ CRCIntrinsicID = Intrinsic::aarch64_crc32h; break;
+ case AArch64::BI__builtin_arm_crc32ch:
+ CRCIntrinsicID = Intrinsic::aarch64_crc32ch; break;
+ case AArch64::BI__builtin_arm_crc32w:
+ CRCIntrinsicID = Intrinsic::aarch64_crc32w; break;
+ case AArch64::BI__builtin_arm_crc32cw:
+ CRCIntrinsicID = Intrinsic::aarch64_crc32cw; break;
+ case AArch64::BI__builtin_arm_crc32d:
+ CRCIntrinsicID = Intrinsic::aarch64_crc32x; break;
+ case AArch64::BI__builtin_arm_crc32cd:
+ CRCIntrinsicID = Intrinsic::aarch64_crc32cx; break;
+ }
+
+ if (CRCIntrinsicID != Intrinsic::not_intrinsic) {
+ Value *Arg0 = EmitScalarExpr(E->getArg(0));
+ Value *Arg1 = EmitScalarExpr(E->getArg(1));
+ Function *F = CGM.getIntrinsic(CRCIntrinsicID);
+
+ llvm::Type *DataTy = F->getFunctionType()->getParamType(1);
+ Arg1 = Builder.CreateZExtOrBitCast(Arg1, DataTy);
+
+ return Builder.CreateCall2(F, Arg0, Arg1);
+ }
+
+ llvm::SmallVector<Value*, 4> Ops;
+ for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++)
+ Ops.push_back(EmitScalarExpr(E->getArg(i)));
+
+ ArrayRef<NeonIntrinsicInfo> SISDMap(AArch64SISDIntrinsicMap);
+ const NeonIntrinsicInfo *Builtin = findNeonIntrinsicInMap(
+ SISDMap, BuiltinID, AArch64SISDIntrinsicsProvenSorted);
+
+ if (Builtin) {
+ Ops.push_back(EmitScalarExpr(E->getArg(E->getNumArgs() - 1)));
+ Value *Result = EmitCommonNeonSISDBuiltinExpr(*this, *Builtin, Ops, E);
+ assert(Result && "SISD intrinsic should have been handled");
+ return Result;
+ }
+
+ llvm::APSInt Result;
+ const Expr *Arg = E->getArg(E->getNumArgs()-1);
+ NeonTypeFlags Type(0);
+ if (Arg->isIntegerConstantExpr(Result, getContext()))
+ // Determine the type of this overloaded NEON intrinsic.
+ Type = NeonTypeFlags(Result.getZExtValue());
+
+ bool usgn = Type.isUnsigned();
+ bool quad = Type.isQuad();
+
+ // Handle non-overloaded intrinsics first.
+ switch (BuiltinID) {
+ default: break;
+ case NEON::BI__builtin_neon_vldrq_p128: {
+ llvm::Type *Int128PTy = llvm::Type::getIntNPtrTy(getLLVMContext(), 128);
+ Value *Ptr = Builder.CreateBitCast(EmitScalarExpr(E->getArg(0)), Int128PTy);
+ return Builder.CreateLoad(Ptr);
+ }
+ case NEON::BI__builtin_neon_vstrq_p128: {
+ llvm::Type *Int128PTy = llvm::Type::getIntNPtrTy(getLLVMContext(), 128);
+ Value *Ptr = Builder.CreateBitCast(Ops[0], Int128PTy);
+ return Builder.CreateStore(EmitScalarExpr(E->getArg(1)), Ptr);
+ }
+ case NEON::BI__builtin_neon_vcvts_u32_f32:
+ case NEON::BI__builtin_neon_vcvtd_u64_f64:
+ usgn = true;
+ // FALL THROUGH
+ case NEON::BI__builtin_neon_vcvts_s32_f32:
+ case NEON::BI__builtin_neon_vcvtd_s64_f64: {
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ bool Is64 = Ops[0]->getType()->getPrimitiveSizeInBits() == 64;
+ llvm::Type *InTy = Is64 ? Int64Ty : Int32Ty;
+ llvm::Type *FTy = Is64 ? DoubleTy : FloatTy;
+ Ops[0] = Builder.CreateBitCast(Ops[0], FTy);
+ if (usgn)
+ return Builder.CreateFPToUI(Ops[0], InTy);
+ return Builder.CreateFPToSI(Ops[0], InTy);
+ }
+ case NEON::BI__builtin_neon_vcvts_f32_u32:
+ case NEON::BI__builtin_neon_vcvtd_f64_u64:
+ usgn = true;
+ // FALL THROUGH
+ case NEON::BI__builtin_neon_vcvts_f32_s32:
+ case NEON::BI__builtin_neon_vcvtd_f64_s64: {
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ bool Is64 = Ops[0]->getType()->getPrimitiveSizeInBits() == 64;
+ llvm::Type *InTy = Is64 ? Int64Ty : Int32Ty;
+ llvm::Type *FTy = Is64 ? DoubleTy : FloatTy;
+ Ops[0] = Builder.CreateBitCast(Ops[0], InTy);
+ if (usgn)
+ return Builder.CreateUIToFP(Ops[0], FTy);
+ return Builder.CreateSIToFP(Ops[0], FTy);
+ }
+ case NEON::BI__builtin_neon_vpaddd_s64: {
+ llvm::Type *Ty =
+ llvm::VectorType::get(llvm::Type::getInt64Ty(getLLVMContext()), 2);
+ Value *Vec = EmitScalarExpr(E->getArg(0));
+ // The vector is v2f64, so make sure it's bitcast to that.
+ Vec = Builder.CreateBitCast(Vec, Ty, "v2i64");
+ llvm::Value *Idx0 = llvm::ConstantInt::get(SizeTy, 0);
+ llvm::Value *Idx1 = llvm::ConstantInt::get(SizeTy, 1);
+ Value *Op0 = Builder.CreateExtractElement(Vec, Idx0, "lane0");
+ Value *Op1 = Builder.CreateExtractElement(Vec, Idx1, "lane1");
+ // Pairwise addition of a v2f64 into a scalar f64.
+ return Builder.CreateAdd(Op0, Op1, "vpaddd");
+ }
+ case NEON::BI__builtin_neon_vpaddd_f64: {
+ llvm::Type *Ty =
+ llvm::VectorType::get(llvm::Type::getDoubleTy(getLLVMContext()), 2);
+ Value *Vec = EmitScalarExpr(E->getArg(0));
+ // The vector is v2f64, so make sure it's bitcast to that.
+ Vec = Builder.CreateBitCast(Vec, Ty, "v2f64");
+ llvm::Value *Idx0 = llvm::ConstantInt::get(SizeTy, 0);
+ llvm::Value *Idx1 = llvm::ConstantInt::get(SizeTy, 1);
+ Value *Op0 = Builder.CreateExtractElement(Vec, Idx0, "lane0");
+ Value *Op1 = Builder.CreateExtractElement(Vec, Idx1, "lane1");
+ // Pairwise addition of a v2f64 into a scalar f64.
+ return Builder.CreateFAdd(Op0, Op1, "vpaddd");
+ }
+ case NEON::BI__builtin_neon_vpadds_f32: {
+ llvm::Type *Ty =
+ llvm::VectorType::get(llvm::Type::getFloatTy(getLLVMContext()), 2);
+ Value *Vec = EmitScalarExpr(E->getArg(0));
+ // The vector is v2f32, so make sure it's bitcast to that.
+ Vec = Builder.CreateBitCast(Vec, Ty, "v2f32");
+ llvm::Value *Idx0 = llvm::ConstantInt::get(SizeTy, 0);
+ llvm::Value *Idx1 = llvm::ConstantInt::get(SizeTy, 1);
+ Value *Op0 = Builder.CreateExtractElement(Vec, Idx0, "lane0");
+ Value *Op1 = Builder.CreateExtractElement(Vec, Idx1, "lane1");
+ // Pairwise addition of a v2f32 into a scalar f32.
+ return Builder.CreateFAdd(Op0, Op1, "vpaddd");
+ }
+ case NEON::BI__builtin_neon_vceqzd_s64:
+ case NEON::BI__builtin_neon_vceqzd_f64:
+ case NEON::BI__builtin_neon_vceqzs_f32:
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ return EmitAArch64CompareBuiltinExpr(
+ Ops[0], ConvertType(E->getCallReturnType()), ICmpInst::FCMP_OEQ,
+ ICmpInst::ICMP_EQ, "vceqz");
+ case NEON::BI__builtin_neon_vcgezd_s64:
+ case NEON::BI__builtin_neon_vcgezd_f64:
+ case NEON::BI__builtin_neon_vcgezs_f32:
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ return EmitAArch64CompareBuiltinExpr(
+ Ops[0], ConvertType(E->getCallReturnType()), ICmpInst::FCMP_OGE,
+ ICmpInst::ICMP_SGE, "vcgez");
+ case NEON::BI__builtin_neon_vclezd_s64:
+ case NEON::BI__builtin_neon_vclezd_f64:
+ case NEON::BI__builtin_neon_vclezs_f32:
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ return EmitAArch64CompareBuiltinExpr(
+ Ops[0], ConvertType(E->getCallReturnType()), ICmpInst::FCMP_OLE,
+ ICmpInst::ICMP_SLE, "vclez");
+ case NEON::BI__builtin_neon_vcgtzd_s64:
+ case NEON::BI__builtin_neon_vcgtzd_f64:
+ case NEON::BI__builtin_neon_vcgtzs_f32:
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ return EmitAArch64CompareBuiltinExpr(
+ Ops[0], ConvertType(E->getCallReturnType()), ICmpInst::FCMP_OGT,
+ ICmpInst::ICMP_SGT, "vcgtz");
+ case NEON::BI__builtin_neon_vcltzd_s64:
+ case NEON::BI__builtin_neon_vcltzd_f64:
+ case NEON::BI__builtin_neon_vcltzs_f32:
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ return EmitAArch64CompareBuiltinExpr(
+ Ops[0], ConvertType(E->getCallReturnType()), ICmpInst::FCMP_OLT,
+ ICmpInst::ICMP_SLT, "vcltz");
+
+ case NEON::BI__builtin_neon_vceqzd_u64: {
+ llvm::Type *Ty = llvm::Type::getInt64Ty(getLLVMContext());
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ Ops[0] = Builder.CreateICmp(llvm::ICmpInst::ICMP_EQ, Ops[0],
+ llvm::Constant::getNullValue(Ty));
+ return Builder.CreateSExt(Ops[0], Ty, "vceqzd");
+ }
+ case NEON::BI__builtin_neon_vceqd_f64:
+ case NEON::BI__builtin_neon_vcled_f64:
+ case NEON::BI__builtin_neon_vcltd_f64:
+ case NEON::BI__builtin_neon_vcged_f64:
+ case NEON::BI__builtin_neon_vcgtd_f64: {
+ llvm::CmpInst::Predicate P;
+ switch (BuiltinID) {
+ default: llvm_unreachable("missing builtin ID in switch!");
+ case NEON::BI__builtin_neon_vceqd_f64: P = llvm::FCmpInst::FCMP_OEQ; break;
+ case NEON::BI__builtin_neon_vcled_f64: P = llvm::FCmpInst::FCMP_OLE; break;
+ case NEON::BI__builtin_neon_vcltd_f64: P = llvm::FCmpInst::FCMP_OLT; break;
+ case NEON::BI__builtin_neon_vcged_f64: P = llvm::FCmpInst::FCMP_OGE; break;
+ case NEON::BI__builtin_neon_vcgtd_f64: P = llvm::FCmpInst::FCMP_OGT; break;
+ }
+ Ops.push_back(EmitScalarExpr(E->getArg(1)));
+ Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy);
+ Ops[1] = Builder.CreateBitCast(Ops[1], DoubleTy);
+ Ops[0] = Builder.CreateFCmp(P, Ops[0], Ops[1]);
+ return Builder.CreateSExt(Ops[0], Int64Ty, "vcmpd");
+ }
+ case NEON::BI__builtin_neon_vceqs_f32:
+ case NEON::BI__builtin_neon_vcles_f32:
+ case NEON::BI__builtin_neon_vclts_f32:
+ case NEON::BI__builtin_neon_vcges_f32:
+ case NEON::BI__builtin_neon_vcgts_f32: {
+ llvm::CmpInst::Predicate P;
+ switch (BuiltinID) {
+ default: llvm_unreachable("missing builtin ID in switch!");
+ case NEON::BI__builtin_neon_vceqs_f32: P = llvm::FCmpInst::FCMP_OEQ; break;
+ case NEON::BI__builtin_neon_vcles_f32: P = llvm::FCmpInst::FCMP_OLE; break;
+ case NEON::BI__builtin_neon_vclts_f32: P = llvm::FCmpInst::FCMP_OLT; break;
+ case NEON::BI__builtin_neon_vcges_f32: P = llvm::FCmpInst::FCMP_OGE; break;
+ case NEON::BI__builtin_neon_vcgts_f32: P = llvm::FCmpInst::FCMP_OGT; break;
+ }
+ Ops.push_back(EmitScalarExpr(E->getArg(1)));
+ Ops[0] = Builder.CreateBitCast(Ops[0], FloatTy);
+ Ops[1] = Builder.CreateBitCast(Ops[1], FloatTy);
+ Ops[0] = Builder.CreateFCmp(P, Ops[0], Ops[1]);
+ return Builder.CreateSExt(Ops[0], Int32Ty, "vcmpd");
+ }
+ case NEON::BI__builtin_neon_vceqd_s64:
+ case NEON::BI__builtin_neon_vceqd_u64:
+ case NEON::BI__builtin_neon_vcgtd_s64:
+ case NEON::BI__builtin_neon_vcgtd_u64:
+ case NEON::BI__builtin_neon_vcltd_s64:
+ case NEON::BI__builtin_neon_vcltd_u64:
+ case NEON::BI__builtin_neon_vcged_u64:
+ case NEON::BI__builtin_neon_vcged_s64:
+ case NEON::BI__builtin_neon_vcled_u64:
+ case NEON::BI__builtin_neon_vcled_s64: {
+ llvm::CmpInst::Predicate P;
+ switch (BuiltinID) {
+ default: llvm_unreachable("missing builtin ID in switch!");
+ case NEON::BI__builtin_neon_vceqd_s64:
+ case NEON::BI__builtin_neon_vceqd_u64:P = llvm::ICmpInst::ICMP_EQ;break;
+ case NEON::BI__builtin_neon_vcgtd_s64:P = llvm::ICmpInst::ICMP_SGT;break;
+ case NEON::BI__builtin_neon_vcgtd_u64:P = llvm::ICmpInst::ICMP_UGT;break;
+ case NEON::BI__builtin_neon_vcltd_s64:P = llvm::ICmpInst::ICMP_SLT;break;
+ case NEON::BI__builtin_neon_vcltd_u64:P = llvm::ICmpInst::ICMP_ULT;break;
+ case NEON::BI__builtin_neon_vcged_u64:P = llvm::ICmpInst::ICMP_UGE;break;
+ case NEON::BI__builtin_neon_vcged_s64:P = llvm::ICmpInst::ICMP_SGE;break;
+ case NEON::BI__builtin_neon_vcled_u64:P = llvm::ICmpInst::ICMP_ULE;break;
+ case NEON::BI__builtin_neon_vcled_s64:P = llvm::ICmpInst::ICMP_SLE;break;
+ }
+ Ops.push_back(EmitScalarExpr(E->getArg(1)));
+ Ops[0] = Builder.CreateBitCast(Ops[0], Int64Ty);
+ Ops[1] = Builder.CreateBitCast(Ops[1], Int64Ty);
+ Ops[0] = Builder.CreateICmp(P, Ops[0], Ops[1]);
+ return Builder.CreateSExt(Ops[0], Int64Ty, "vceqd");
+ }
+ case NEON::BI__builtin_neon_vtstd_s64:
+ case NEON::BI__builtin_neon_vtstd_u64: {
+ llvm::Type *Ty = llvm::Type::getInt64Ty(getLLVMContext());
+ Ops.push_back(EmitScalarExpr(E->getArg(1)));
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[0] = Builder.CreateAnd(Ops[0], Ops[1]);
Ops[0] = Builder.CreateICmp(ICmpInst::ICMP_NE, Ops[0],
- ConstantAggregateZero::get(Ty));
- return Builder.CreateSExt(Ops[0], Ty, "vtst");
+ llvm::Constant::getNullValue(Ty));
+ return Builder.CreateSExt(Ops[0], Ty, "vtstd");
+ }
+ case NEON::BI__builtin_neon_vset_lane_i8:
+ case NEON::BI__builtin_neon_vset_lane_i16:
+ case NEON::BI__builtin_neon_vset_lane_i32:
+ case NEON::BI__builtin_neon_vset_lane_i64:
+ case NEON::BI__builtin_neon_vset_lane_f32:
+ case NEON::BI__builtin_neon_vsetq_lane_i8:
+ case NEON::BI__builtin_neon_vsetq_lane_i16:
+ case NEON::BI__builtin_neon_vsetq_lane_i32:
+ case NEON::BI__builtin_neon_vsetq_lane_i64:
+ case NEON::BI__builtin_neon_vsetq_lane_f32:
+ Ops.push_back(EmitScalarExpr(E->getArg(2)));
+ return Builder.CreateInsertElement(Ops[1], Ops[0], Ops[2], "vset_lane");
+ case NEON::BI__builtin_neon_vset_lane_f64:
+ // The vector type needs a cast for the v1f64 variant.
+ Ops[1] = Builder.CreateBitCast(Ops[1],
+ llvm::VectorType::get(DoubleTy, 1));
+ Ops.push_back(EmitScalarExpr(E->getArg(2)));
+ return Builder.CreateInsertElement(Ops[1], Ops[0], Ops[2], "vset_lane");
+ case NEON::BI__builtin_neon_vsetq_lane_f64:
+ // The vector type needs a cast for the v2f64 variant.
+ Ops[1] = Builder.CreateBitCast(Ops[1],
+ llvm::VectorType::get(llvm::Type::getDoubleTy(getLLVMContext()), 2));
+ Ops.push_back(EmitScalarExpr(E->getArg(2)));
+ return Builder.CreateInsertElement(Ops[1], Ops[0], Ops[2], "vset_lane");
+
+ case NEON::BI__builtin_neon_vget_lane_i8:
+ case NEON::BI__builtin_neon_vdupb_lane_i8:
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 8), 8));
+ return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
+ "vget_lane");
+ case NEON::BI__builtin_neon_vgetq_lane_i8:
+ case NEON::BI__builtin_neon_vdupb_laneq_i8:
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 8), 16));
+ return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
+ "vgetq_lane");
+ case NEON::BI__builtin_neon_vget_lane_i16:
+ case NEON::BI__builtin_neon_vduph_lane_i16:
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 16), 4));
+ return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
+ "vget_lane");
+ case NEON::BI__builtin_neon_vgetq_lane_i16:
+ case NEON::BI__builtin_neon_vduph_laneq_i16:
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 16), 8));
+ return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
+ "vgetq_lane");
+ case NEON::BI__builtin_neon_vget_lane_i32:
+ case NEON::BI__builtin_neon_vdups_lane_i32:
+ Ops[0] = Builder.CreateBitCast(
+ Ops[0],
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 32), 2));
+ return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
+ "vget_lane");
+ case NEON::BI__builtin_neon_vdups_lane_f32:
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::VectorType::get(llvm::Type::getFloatTy(getLLVMContext()), 2));
+ return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
+ "vdups_lane");
+ case NEON::BI__builtin_neon_vgetq_lane_i32:
+ case NEON::BI__builtin_neon_vdups_laneq_i32:
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 32), 4));
+ return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
+ "vgetq_lane");
+ case NEON::BI__builtin_neon_vget_lane_i64:
+ case NEON::BI__builtin_neon_vdupd_lane_i64:
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 64), 1));
+ return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
+ "vget_lane");
+ case NEON::BI__builtin_neon_vdupd_lane_f64:
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::VectorType::get(llvm::Type::getDoubleTy(getLLVMContext()), 1));
+ return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
+ "vdupd_lane");
+ case NEON::BI__builtin_neon_vgetq_lane_i64:
+ case NEON::BI__builtin_neon_vdupd_laneq_i64:
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 64), 2));
+ return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
+ "vgetq_lane");
+ case NEON::BI__builtin_neon_vget_lane_f32:
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::VectorType::get(llvm::Type::getFloatTy(getLLVMContext()), 2));
+ return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
+ "vget_lane");
+ case NEON::BI__builtin_neon_vget_lane_f64:
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::VectorType::get(llvm::Type::getDoubleTy(getLLVMContext()), 1));
+ return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
+ "vget_lane");
+ case NEON::BI__builtin_neon_vgetq_lane_f32:
+ case NEON::BI__builtin_neon_vdups_laneq_f32:
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::VectorType::get(llvm::Type::getFloatTy(getLLVMContext()), 4));
+ return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
+ "vgetq_lane");
+ case NEON::BI__builtin_neon_vgetq_lane_f64:
+ case NEON::BI__builtin_neon_vdupd_laneq_f64:
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::VectorType::get(llvm::Type::getDoubleTy(getLLVMContext()), 2));
+ return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
+ "vgetq_lane");
+ case NEON::BI__builtin_neon_vaddd_s64:
+ case NEON::BI__builtin_neon_vaddd_u64:
+ return Builder.CreateAdd(Ops[0], EmitScalarExpr(E->getArg(1)), "vaddd");
+ case NEON::BI__builtin_neon_vsubd_s64:
+ case NEON::BI__builtin_neon_vsubd_u64:
+ return Builder.CreateSub(Ops[0], EmitScalarExpr(E->getArg(1)), "vsubd");
+ case NEON::BI__builtin_neon_vqdmlalh_s16:
+ case NEON::BI__builtin_neon_vqdmlslh_s16: {
+ SmallVector<Value *, 2> ProductOps;
+ ProductOps.push_back(vectorWrapScalar16(Ops[1]));
+ ProductOps.push_back(vectorWrapScalar16(EmitScalarExpr(E->getArg(2))));
+ llvm::Type *VTy = llvm::VectorType::get(Int32Ty, 4);
+ Ops[1] = EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_sqdmull, VTy),
+ ProductOps, "vqdmlXl");
+ Constant *CI = ConstantInt::get(SizeTy, 0);
+ Ops[1] = Builder.CreateExtractElement(Ops[1], CI, "lane0");
+
+ unsigned AccumInt = BuiltinID == NEON::BI__builtin_neon_vqdmlalh_s16
+ ? Intrinsic::aarch64_neon_sqadd
+ : Intrinsic::aarch64_neon_sqsub;
+ return EmitNeonCall(CGM.getIntrinsic(AccumInt, Int32Ty), Ops, "vqdmlXl");
+ }
+ case NEON::BI__builtin_neon_vqshlud_n_s64: {
+ Ops.push_back(EmitScalarExpr(E->getArg(1)));
+ Ops[1] = Builder.CreateZExt(Ops[1], Int64Ty);
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_sqshlu, Int64Ty),
+ Ops, "vqshlu_n");
+ }
+ case NEON::BI__builtin_neon_vqshld_n_u64:
+ case NEON::BI__builtin_neon_vqshld_n_s64: {
+ unsigned Int = BuiltinID == NEON::BI__builtin_neon_vqshld_n_u64
+ ? Intrinsic::aarch64_neon_uqshl
+ : Intrinsic::aarch64_neon_sqshl;
+ Ops.push_back(EmitScalarExpr(E->getArg(1)));
+ Ops[1] = Builder.CreateZExt(Ops[1], Int64Ty);
+ return EmitNeonCall(CGM.getIntrinsic(Int, Int64Ty), Ops, "vqshl_n");
+ }
+ case NEON::BI__builtin_neon_vrshrd_n_u64:
+ case NEON::BI__builtin_neon_vrshrd_n_s64: {
+ unsigned Int = BuiltinID == NEON::BI__builtin_neon_vrshrd_n_u64
+ ? Intrinsic::aarch64_neon_urshl
+ : Intrinsic::aarch64_neon_srshl;
+ Ops.push_back(EmitScalarExpr(E->getArg(1)));
+ int SV = cast<ConstantInt>(Ops[1])->getSExtValue();
+ Ops[1] = ConstantInt::get(Int64Ty, -SV);
+ return EmitNeonCall(CGM.getIntrinsic(Int, Int64Ty), Ops, "vrshr_n");
+ }
+ case NEON::BI__builtin_neon_vrsrad_n_u64:
+ case NEON::BI__builtin_neon_vrsrad_n_s64: {
+ unsigned Int = BuiltinID == NEON::BI__builtin_neon_vrsrad_n_u64
+ ? Intrinsic::aarch64_neon_urshl
+ : Intrinsic::aarch64_neon_srshl;
+ Ops[1] = Builder.CreateBitCast(Ops[1], Int64Ty);
+ Ops.push_back(Builder.CreateNeg(EmitScalarExpr(E->getArg(2))));
+ Ops[1] = Builder.CreateCall2(CGM.getIntrinsic(Int, Int64Ty), Ops[1],
+ Builder.CreateSExt(Ops[2], Int64Ty));
+ return Builder.CreateAdd(Ops[0], Builder.CreateBitCast(Ops[1], Int64Ty));
+ }
+ case NEON::BI__builtin_neon_vshld_n_s64:
+ case NEON::BI__builtin_neon_vshld_n_u64: {
+ llvm::ConstantInt *Amt = cast<ConstantInt>(EmitScalarExpr(E->getArg(1)));
+ return Builder.CreateShl(
+ Ops[0], ConstantInt::get(Int64Ty, Amt->getZExtValue()), "shld_n");
+ }
+ case NEON::BI__builtin_neon_vshrd_n_s64: {
+ llvm::ConstantInt *Amt = cast<ConstantInt>(EmitScalarExpr(E->getArg(1)));
+ return Builder.CreateAShr(
+ Ops[0], ConstantInt::get(Int64Ty, std::min(static_cast<uint64_t>(63),
+ Amt->getZExtValue())),
+ "shrd_n");
+ }
+ case NEON::BI__builtin_neon_vshrd_n_u64: {
+ llvm::ConstantInt *Amt = cast<ConstantInt>(EmitScalarExpr(E->getArg(1)));
+ uint64_t ShiftAmt = Amt->getZExtValue();
+ // Right-shifting an unsigned value by its size yields 0.
+ if (ShiftAmt == 64)
+ return ConstantInt::get(Int64Ty, 0);
+ return Builder.CreateLShr(Ops[0], ConstantInt::get(Int64Ty, ShiftAmt),
+ "shrd_n");
+ }
+ case NEON::BI__builtin_neon_vsrad_n_s64: {
+ llvm::ConstantInt *Amt = cast<ConstantInt>(EmitScalarExpr(E->getArg(2)));
+ Ops[1] = Builder.CreateAShr(
+ Ops[1], ConstantInt::get(Int64Ty, std::min(static_cast<uint64_t>(63),
+ Amt->getZExtValue())),
+ "shrd_n");
+ return Builder.CreateAdd(Ops[0], Ops[1]);
+ }
+ case NEON::BI__builtin_neon_vsrad_n_u64: {
+ llvm::ConstantInt *Amt = cast<ConstantInt>(EmitScalarExpr(E->getArg(2)));
+ uint64_t ShiftAmt = Amt->getZExtValue();
+ // Right-shifting an unsigned value by its size yields 0.
+ // As Op + 0 = Op, return Ops[0] directly.
+ if (ShiftAmt == 64)
+ return Ops[0];
+ Ops[1] = Builder.CreateLShr(Ops[1], ConstantInt::get(Int64Ty, ShiftAmt),
+ "shrd_n");
+ return Builder.CreateAdd(Ops[0], Ops[1]);
+ }
+ case NEON::BI__builtin_neon_vqdmlalh_lane_s16:
+ case NEON::BI__builtin_neon_vqdmlalh_laneq_s16:
+ case NEON::BI__builtin_neon_vqdmlslh_lane_s16:
+ case NEON::BI__builtin_neon_vqdmlslh_laneq_s16: {
+ Ops[2] = Builder.CreateExtractElement(Ops[2], EmitScalarExpr(E->getArg(3)),
+ "lane");
+ SmallVector<Value *, 2> ProductOps;
+ ProductOps.push_back(vectorWrapScalar16(Ops[1]));
+ ProductOps.push_back(vectorWrapScalar16(Ops[2]));
+ llvm::Type *VTy = llvm::VectorType::get(Int32Ty, 4);
+ Ops[1] = EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_sqdmull, VTy),
+ ProductOps, "vqdmlXl");
+ Constant *CI = ConstantInt::get(SizeTy, 0);
+ Ops[1] = Builder.CreateExtractElement(Ops[1], CI, "lane0");
+ Ops.pop_back();
+
+ unsigned AccInt = (BuiltinID == NEON::BI__builtin_neon_vqdmlalh_lane_s16 ||
+ BuiltinID == NEON::BI__builtin_neon_vqdmlalh_laneq_s16)
+ ? Intrinsic::aarch64_neon_sqadd
+ : Intrinsic::aarch64_neon_sqsub;
+ return EmitNeonCall(CGM.getIntrinsic(AccInt, Int32Ty), Ops, "vqdmlXl");
+ }
+ case NEON::BI__builtin_neon_vqdmlals_s32:
+ case NEON::BI__builtin_neon_vqdmlsls_s32: {
+ SmallVector<Value *, 2> ProductOps;
+ ProductOps.push_back(Ops[1]);
+ ProductOps.push_back(EmitScalarExpr(E->getArg(2)));
+ Ops[1] =
+ EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_sqdmulls_scalar),
+ ProductOps, "vqdmlXl");
+
+ unsigned AccumInt = BuiltinID == NEON::BI__builtin_neon_vqdmlals_s32
+ ? Intrinsic::aarch64_neon_sqadd
+ : Intrinsic::aarch64_neon_sqsub;
+ return EmitNeonCall(CGM.getIntrinsic(AccumInt, Int64Ty), Ops, "vqdmlXl");
+ }
+ case NEON::BI__builtin_neon_vqdmlals_lane_s32:
+ case NEON::BI__builtin_neon_vqdmlals_laneq_s32:
+ case NEON::BI__builtin_neon_vqdmlsls_lane_s32:
+ case NEON::BI__builtin_neon_vqdmlsls_laneq_s32: {
+ Ops[2] = Builder.CreateExtractElement(Ops[2], EmitScalarExpr(E->getArg(3)),
+ "lane");
+ SmallVector<Value *, 2> ProductOps;
+ ProductOps.push_back(Ops[1]);
+ ProductOps.push_back(Ops[2]);
+ Ops[1] =
+ EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_sqdmulls_scalar),
+ ProductOps, "vqdmlXl");
+ Ops.pop_back();
+
+ unsigned AccInt = (BuiltinID == NEON::BI__builtin_neon_vqdmlals_lane_s32 ||
+ BuiltinID == NEON::BI__builtin_neon_vqdmlals_laneq_s32)
+ ? Intrinsic::aarch64_neon_sqadd
+ : Intrinsic::aarch64_neon_sqsub;
+ return EmitNeonCall(CGM.getIntrinsic(AccInt, Int64Ty), Ops, "vqdmlXl");
+ }
+ }
+
+ llvm::VectorType *VTy = GetNeonType(this, Type);
+ llvm::Type *Ty = VTy;
+ if (!Ty)
+ return nullptr;
+
+ // Not all intrinsics handled by the common case work for AArch64 yet, so only
+ // defer to common code if it's been added to our special map.
+ Builtin = findNeonIntrinsicInMap(AArch64SIMDIntrinsicMap, BuiltinID,
+ AArch64SIMDIntrinsicsProvenSorted);
+
+ if (Builtin)
+ return EmitCommonNeonBuiltinExpr(
+ Builtin->BuiltinID, Builtin->LLVMIntrinsic, Builtin->AltLLVMIntrinsic,
+ Builtin->NameHint, Builtin->TypeModifier, E, Ops, nullptr);
+
+ if (Value *V = EmitAArch64TblBuiltinExpr(*this, BuiltinID, E, Ops))
+ return V;
+
+ unsigned Int;
+ switch (BuiltinID) {
+ default: return nullptr;
+ case NEON::BI__builtin_neon_vbsl_v:
+ case NEON::BI__builtin_neon_vbslq_v: {
+ llvm::Type *BitTy = llvm::VectorType::getInteger(VTy);
+ Ops[0] = Builder.CreateBitCast(Ops[0], BitTy, "vbsl");
+ Ops[1] = Builder.CreateBitCast(Ops[1], BitTy, "vbsl");
+ Ops[2] = Builder.CreateBitCast(Ops[2], BitTy, "vbsl");
+
+ Ops[1] = Builder.CreateAnd(Ops[0], Ops[1], "vbsl");
+ Ops[2] = Builder.CreateAnd(Builder.CreateNot(Ops[0]), Ops[2], "vbsl");
+ Ops[0] = Builder.CreateOr(Ops[1], Ops[2], "vbsl");
+ return Builder.CreateBitCast(Ops[0], Ty);
+ }
+ case NEON::BI__builtin_neon_vfma_lane_v:
+ case NEON::BI__builtin_neon_vfmaq_lane_v: { // Only used for FP types
+ // The ARM builtins (and instructions) have the addend as the first
+ // operand, but the 'fma' intrinsics have it last. Swap it around here.
+ Value *Addend = Ops[0];
+ Value *Multiplicand = Ops[1];
+ Value *LaneSource = Ops[2];
+ Ops[0] = Multiplicand;
+ Ops[1] = LaneSource;
+ Ops[2] = Addend;
+
+ // Now adjust things to handle the lane access.
+ llvm::Type *SourceTy = BuiltinID == NEON::BI__builtin_neon_vfmaq_lane_v ?
+ llvm::VectorType::get(VTy->getElementType(), VTy->getNumElements() / 2) :
+ VTy;
+ llvm::Constant *cst = cast<Constant>(Ops[3]);
+ Value *SV = llvm::ConstantVector::getSplat(VTy->getNumElements(), cst);
+ Ops[1] = Builder.CreateBitCast(Ops[1], SourceTy);
+ Ops[1] = Builder.CreateShuffleVector(Ops[1], Ops[1], SV, "lane");
+
+ Ops.pop_back();
+ Int = Intrinsic::fma;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "fmla");
+ }
+ case NEON::BI__builtin_neon_vfma_laneq_v: {
+ llvm::VectorType *VTy = cast<llvm::VectorType>(Ty);
+ // v1f64 fma should be mapped to Neon scalar f64 fma
+ if (VTy && VTy->getElementType() == DoubleTy) {
+ Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy);
+ Ops[1] = Builder.CreateBitCast(Ops[1], DoubleTy);
+ llvm::Type *VTy = GetNeonType(this,
+ NeonTypeFlags(NeonTypeFlags::Float64, false, true));
+ Ops[2] = Builder.CreateBitCast(Ops[2], VTy);
+ Ops[2] = Builder.CreateExtractElement(Ops[2], Ops[3], "extract");
+ Value *F = CGM.getIntrinsic(Intrinsic::fma, DoubleTy);
+ Value *Result = Builder.CreateCall3(F, Ops[1], Ops[2], Ops[0]);
+ return Builder.CreateBitCast(Result, Ty);
+ }
+ Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+
+ llvm::Type *STy = llvm::VectorType::get(VTy->getElementType(),
+ VTy->getNumElements() * 2);
+ Ops[2] = Builder.CreateBitCast(Ops[2], STy);
+ Value* SV = llvm::ConstantVector::getSplat(VTy->getNumElements(),
+ cast<ConstantInt>(Ops[3]));
+ Ops[2] = Builder.CreateShuffleVector(Ops[2], Ops[2], SV, "lane");
+
+ return Builder.CreateCall3(F, Ops[2], Ops[1], Ops[0]);
+ }
+ case NEON::BI__builtin_neon_vfmaq_laneq_v: {
+ Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+
+ Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
+ Ops[2] = EmitNeonSplat(Ops[2], cast<ConstantInt>(Ops[3]));
+ return Builder.CreateCall3(F, Ops[2], Ops[1], Ops[0]);
+ }
+ case NEON::BI__builtin_neon_vfmas_lane_f32:
+ case NEON::BI__builtin_neon_vfmas_laneq_f32:
+ case NEON::BI__builtin_neon_vfmad_lane_f64:
+ case NEON::BI__builtin_neon_vfmad_laneq_f64: {
+ Ops.push_back(EmitScalarExpr(E->getArg(3)));
+ llvm::Type *Ty = ConvertType(E->getCallReturnType());
+ Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty);
+ Ops[2] = Builder.CreateExtractElement(Ops[2], Ops[3], "extract");
+ return Builder.CreateCall3(F, Ops[1], Ops[2], Ops[0]);
+ }
+ case NEON::BI__builtin_neon_vfms_v:
+ case NEON::BI__builtin_neon_vfmsq_v: { // Only used for FP types
+ // FIXME: probably remove when we no longer support aarch64_simd.h
+ // (arm_neon.h delegates to vfma).
+
+ // The ARM builtins (and instructions) have the addend as the first
+ // operand, but the 'fma' intrinsics have it last. Swap it around here.
+ Value *Subtrahend = Ops[0];
+ Value *Multiplicand = Ops[2];
+ Ops[0] = Multiplicand;
+ Ops[2] = Subtrahend;
+ Ops[1] = Builder.CreateBitCast(Ops[1], VTy);
+ Ops[1] = Builder.CreateFNeg(Ops[1]);
+ Int = Intrinsic::fma;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "fmls");
+ }
+ case NEON::BI__builtin_neon_vmull_v:
+ // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
+ Int = usgn ? Intrinsic::aarch64_neon_umull : Intrinsic::aarch64_neon_smull;
+ if (Type.isPoly()) Int = Intrinsic::aarch64_neon_pmull;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmull");
+ case NEON::BI__builtin_neon_vmax_v:
+ case NEON::BI__builtin_neon_vmaxq_v:
+ // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
+ Int = usgn ? Intrinsic::aarch64_neon_umax : Intrinsic::aarch64_neon_smax;
+ if (Ty->isFPOrFPVectorTy()) Int = Intrinsic::aarch64_neon_fmax;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmax");
+ case NEON::BI__builtin_neon_vmin_v:
+ case NEON::BI__builtin_neon_vminq_v:
+ // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
+ Int = usgn ? Intrinsic::aarch64_neon_umin : Intrinsic::aarch64_neon_smin;
+ if (Ty->isFPOrFPVectorTy()) Int = Intrinsic::aarch64_neon_fmin;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmin");
+ case NEON::BI__builtin_neon_vabd_v:
+ case NEON::BI__builtin_neon_vabdq_v:
+ // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
+ Int = usgn ? Intrinsic::aarch64_neon_uabd : Intrinsic::aarch64_neon_sabd;
+ if (Ty->isFPOrFPVectorTy()) Int = Intrinsic::aarch64_neon_fabd;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vabd");
+ case NEON::BI__builtin_neon_vpadal_v:
+ case NEON::BI__builtin_neon_vpadalq_v: {
+ unsigned ArgElts = VTy->getNumElements();
+ llvm::IntegerType *EltTy = cast<IntegerType>(VTy->getElementType());
+ unsigned BitWidth = EltTy->getBitWidth();
+ llvm::Type *ArgTy = llvm::VectorType::get(
+ llvm::IntegerType::get(getLLVMContext(), BitWidth/2), 2*ArgElts);
+ llvm::Type* Tys[2] = { VTy, ArgTy };
+ Int = usgn ? Intrinsic::aarch64_neon_uaddlp : Intrinsic::aarch64_neon_saddlp;
+ SmallVector<llvm::Value*, 1> TmpOps;
+ TmpOps.push_back(Ops[1]);
+ Function *F = CGM.getIntrinsic(Int, Tys);
+ llvm::Value *tmp = EmitNeonCall(F, TmpOps, "vpadal");
+ llvm::Value *addend = Builder.CreateBitCast(Ops[0], tmp->getType());
+ return Builder.CreateAdd(tmp, addend);
+ }
+ case NEON::BI__builtin_neon_vpmin_v:
+ case NEON::BI__builtin_neon_vpminq_v:
+ // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
+ Int = usgn ? Intrinsic::aarch64_neon_uminp : Intrinsic::aarch64_neon_sminp;
+ if (Ty->isFPOrFPVectorTy()) Int = Intrinsic::aarch64_neon_fminp;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpmin");
+ case NEON::BI__builtin_neon_vpmax_v:
+ case NEON::BI__builtin_neon_vpmaxq_v:
+ // FIXME: improve sharing scheme to cope with 3 alternative LLVM intrinsics.
+ Int = usgn ? Intrinsic::aarch64_neon_umaxp : Intrinsic::aarch64_neon_smaxp;
+ if (Ty->isFPOrFPVectorTy()) Int = Intrinsic::aarch64_neon_fmaxp;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpmax");
+ case NEON::BI__builtin_neon_vminnm_v:
+ case NEON::BI__builtin_neon_vminnmq_v:
+ Int = Intrinsic::aarch64_neon_fminnm;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vminnm");
+ case NEON::BI__builtin_neon_vmaxnm_v:
+ case NEON::BI__builtin_neon_vmaxnmq_v:
+ Int = Intrinsic::aarch64_neon_fmaxnm;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmaxnm");
+ case NEON::BI__builtin_neon_vrecpss_f32: {
+ llvm::Type *f32Type = llvm::Type::getFloatTy(getLLVMContext());
+ Ops.push_back(EmitScalarExpr(E->getArg(1)));
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_frecps, f32Type),
+ Ops, "vrecps");
+ }
+ case NEON::BI__builtin_neon_vrecpsd_f64: {
+ llvm::Type *f64Type = llvm::Type::getDoubleTy(getLLVMContext());
+ Ops.push_back(EmitScalarExpr(E->getArg(1)));
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_frecps, f64Type),
+ Ops, "vrecps");
+ }
+ case NEON::BI__builtin_neon_vrshr_n_v:
+ case NEON::BI__builtin_neon_vrshrq_n_v:
+ // FIXME: this can be shared with 32-bit ARM, but not AArch64 at the
+ // moment. After the final merge it should be added to
+ // EmitCommonNeonBuiltinExpr.
+ Int = usgn ? Intrinsic::aarch64_neon_urshl : Intrinsic::aarch64_neon_srshl;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrshr_n", 1, true);
+ case NEON::BI__builtin_neon_vqshlu_n_v:
+ case NEON::BI__builtin_neon_vqshluq_n_v:
+ // FIXME: AArch64 and ARM use different intrinsics for this, but are
+ // essentially compatible. It should be in EmitCommonNeonBuiltinExpr after
+ // the final merge.
+ Int = Intrinsic::aarch64_neon_sqshlu;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshlu_n", 1, false);
+ case NEON::BI__builtin_neon_vqshrun_n_v:
+ // FIXME: as above
+ Int = Intrinsic::aarch64_neon_sqshrun;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshrun_n");
+ case NEON::BI__builtin_neon_vqrshrun_n_v:
+ // FIXME: and again.
+ Int = Intrinsic::aarch64_neon_sqrshrun;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshrun_n");
+ case NEON::BI__builtin_neon_vqshrn_n_v:
+ // FIXME: guess
+ Int = usgn ? Intrinsic::aarch64_neon_uqshrn : Intrinsic::aarch64_neon_sqshrn;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqshrn_n");
+ case NEON::BI__builtin_neon_vrshrn_n_v:
+ // FIXME: there might be a pattern here.
+ Int = Intrinsic::aarch64_neon_rshrn;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrshrn_n");
+ case NEON::BI__builtin_neon_vqrshrn_n_v:
+ // FIXME: another one
+ Int = usgn ? Intrinsic::aarch64_neon_uqrshrn : Intrinsic::aarch64_neon_sqrshrn;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshrn_n");
+ case NEON::BI__builtin_neon_vrnda_v:
+ case NEON::BI__builtin_neon_vrndaq_v: {
+ Int = Intrinsic::round;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrnda");
+ }
+ case NEON::BI__builtin_neon_vrndi_v:
+ case NEON::BI__builtin_neon_vrndiq_v: {
+ Int = Intrinsic::nearbyint;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndi");
+ }
+ case NEON::BI__builtin_neon_vrndm_v:
+ case NEON::BI__builtin_neon_vrndmq_v: {
+ Int = Intrinsic::floor;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndm");
+ }
+ case NEON::BI__builtin_neon_vrndn_v:
+ case NEON::BI__builtin_neon_vrndnq_v: {
+ Int = Intrinsic::aarch64_neon_frintn;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndn");
+ }
+ case NEON::BI__builtin_neon_vrndp_v:
+ case NEON::BI__builtin_neon_vrndpq_v: {
+ Int = Intrinsic::ceil;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndp");
+ }
+ case NEON::BI__builtin_neon_vrndx_v:
+ case NEON::BI__builtin_neon_vrndxq_v: {
+ Int = Intrinsic::rint;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndx");
+ }
+ case NEON::BI__builtin_neon_vrnd_v:
+ case NEON::BI__builtin_neon_vrndq_v: {
+ Int = Intrinsic::trunc;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrndz");
+ }
+ case NEON::BI__builtin_neon_vceqz_v:
+ case NEON::BI__builtin_neon_vceqzq_v:
+ return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OEQ,
+ ICmpInst::ICMP_EQ, "vceqz");
+ case NEON::BI__builtin_neon_vcgez_v:
+ case NEON::BI__builtin_neon_vcgezq_v:
+ return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OGE,
+ ICmpInst::ICMP_SGE, "vcgez");
+ case NEON::BI__builtin_neon_vclez_v:
+ case NEON::BI__builtin_neon_vclezq_v:
+ return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OLE,
+ ICmpInst::ICMP_SLE, "vclez");
+ case NEON::BI__builtin_neon_vcgtz_v:
+ case NEON::BI__builtin_neon_vcgtzq_v:
+ return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OGT,
+ ICmpInst::ICMP_SGT, "vcgtz");
+ case NEON::BI__builtin_neon_vcltz_v:
+ case NEON::BI__builtin_neon_vcltzq_v:
+ return EmitAArch64CompareBuiltinExpr(Ops[0], Ty, ICmpInst::FCMP_OLT,
+ ICmpInst::ICMP_SLT, "vcltz");
+ case NEON::BI__builtin_neon_vcvt_f64_v:
+ case NEON::BI__builtin_neon_vcvtq_f64_v:
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float64, false, quad));
+ return usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt")
+ : Builder.CreateSIToFP(Ops[0], Ty, "vcvt");
+ case NEON::BI__builtin_neon_vcvt_f64_f32: {
+ assert(Type.getEltType() == NeonTypeFlags::Float64 && quad &&
+ "unexpected vcvt_f64_f32 builtin");
+ NeonTypeFlags SrcFlag = NeonTypeFlags(NeonTypeFlags::Float32, false, false);
+ Ops[0] = Builder.CreateBitCast(Ops[0], GetNeonType(this, SrcFlag));
+
+ return Builder.CreateFPExt(Ops[0], Ty, "vcvt");
+ }
+ case NEON::BI__builtin_neon_vcvt_f32_f64: {
+ assert(Type.getEltType() == NeonTypeFlags::Float32 &&
+ "unexpected vcvt_f32_f64 builtin");
+ NeonTypeFlags SrcFlag = NeonTypeFlags(NeonTypeFlags::Float64, false, true);
+ Ops[0] = Builder.CreateBitCast(Ops[0], GetNeonType(this, SrcFlag));
+
+ return Builder.CreateFPTrunc(Ops[0], Ty, "vcvt");
+ }
+ case NEON::BI__builtin_neon_vcvt_s32_v:
+ case NEON::BI__builtin_neon_vcvt_u32_v:
+ case NEON::BI__builtin_neon_vcvt_s64_v:
+ case NEON::BI__builtin_neon_vcvt_u64_v:
+ case NEON::BI__builtin_neon_vcvtq_s32_v:
+ case NEON::BI__builtin_neon_vcvtq_u32_v:
+ case NEON::BI__builtin_neon_vcvtq_s64_v:
+ case NEON::BI__builtin_neon_vcvtq_u64_v: {
+ bool Double =
+ (cast<llvm::IntegerType>(VTy->getElementType())->getBitWidth() == 64);
+ llvm::Type *InTy =
+ GetNeonType(this,
+ NeonTypeFlags(Double ? NeonTypeFlags::Float64
+ : NeonTypeFlags::Float32, false, quad));
+ Ops[0] = Builder.CreateBitCast(Ops[0], InTy);
+ if (usgn)
+ return Builder.CreateFPToUI(Ops[0], Ty);
+ return Builder.CreateFPToSI(Ops[0], Ty);
+ }
+ case NEON::BI__builtin_neon_vcvta_s32_v:
+ case NEON::BI__builtin_neon_vcvtaq_s32_v:
+ case NEON::BI__builtin_neon_vcvta_u32_v:
+ case NEON::BI__builtin_neon_vcvtaq_u32_v:
+ case NEON::BI__builtin_neon_vcvta_s64_v:
+ case NEON::BI__builtin_neon_vcvtaq_s64_v:
+ case NEON::BI__builtin_neon_vcvta_u64_v:
+ case NEON::BI__builtin_neon_vcvtaq_u64_v: {
+ Int = usgn ? Intrinsic::aarch64_neon_fcvtau : Intrinsic::aarch64_neon_fcvtas;
+ bool Double =
+ (cast<llvm::IntegerType>(VTy->getElementType())->getBitWidth() == 64);
+ llvm::Type *InTy =
+ GetNeonType(this,
+ NeonTypeFlags(Double ? NeonTypeFlags::Float64
+ : NeonTypeFlags::Float32, false, quad));
+ llvm::Type *Tys[2] = { Ty, InTy };
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvta");
+ }
+ case NEON::BI__builtin_neon_vcvtm_s32_v:
+ case NEON::BI__builtin_neon_vcvtmq_s32_v:
+ case NEON::BI__builtin_neon_vcvtm_u32_v:
+ case NEON::BI__builtin_neon_vcvtmq_u32_v:
+ case NEON::BI__builtin_neon_vcvtm_s64_v:
+ case NEON::BI__builtin_neon_vcvtmq_s64_v:
+ case NEON::BI__builtin_neon_vcvtm_u64_v:
+ case NEON::BI__builtin_neon_vcvtmq_u64_v: {
+ Int = usgn ? Intrinsic::aarch64_neon_fcvtmu : Intrinsic::aarch64_neon_fcvtms;
+ bool Double =
+ (cast<llvm::IntegerType>(VTy->getElementType())->getBitWidth() == 64);
+ llvm::Type *InTy =
+ GetNeonType(this,
+ NeonTypeFlags(Double ? NeonTypeFlags::Float64
+ : NeonTypeFlags::Float32, false, quad));
+ llvm::Type *Tys[2] = { Ty, InTy };
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtm");
+ }
+ case NEON::BI__builtin_neon_vcvtn_s32_v:
+ case NEON::BI__builtin_neon_vcvtnq_s32_v:
+ case NEON::BI__builtin_neon_vcvtn_u32_v:
+ case NEON::BI__builtin_neon_vcvtnq_u32_v:
+ case NEON::BI__builtin_neon_vcvtn_s64_v:
+ case NEON::BI__builtin_neon_vcvtnq_s64_v:
+ case NEON::BI__builtin_neon_vcvtn_u64_v:
+ case NEON::BI__builtin_neon_vcvtnq_u64_v: {
+ Int = usgn ? Intrinsic::aarch64_neon_fcvtnu : Intrinsic::aarch64_neon_fcvtns;
+ bool Double =
+ (cast<llvm::IntegerType>(VTy->getElementType())->getBitWidth() == 64);
+ llvm::Type *InTy =
+ GetNeonType(this,
+ NeonTypeFlags(Double ? NeonTypeFlags::Float64
+ : NeonTypeFlags::Float32, false, quad));
+ llvm::Type *Tys[2] = { Ty, InTy };
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtn");
+ }
+ case NEON::BI__builtin_neon_vcvtp_s32_v:
+ case NEON::BI__builtin_neon_vcvtpq_s32_v:
+ case NEON::BI__builtin_neon_vcvtp_u32_v:
+ case NEON::BI__builtin_neon_vcvtpq_u32_v:
+ case NEON::BI__builtin_neon_vcvtp_s64_v:
+ case NEON::BI__builtin_neon_vcvtpq_s64_v:
+ case NEON::BI__builtin_neon_vcvtp_u64_v:
+ case NEON::BI__builtin_neon_vcvtpq_u64_v: {
+ Int = usgn ? Intrinsic::aarch64_neon_fcvtpu : Intrinsic::aarch64_neon_fcvtps;
+ bool Double =
+ (cast<llvm::IntegerType>(VTy->getElementType())->getBitWidth() == 64);
+ llvm::Type *InTy =
+ GetNeonType(this,
+ NeonTypeFlags(Double ? NeonTypeFlags::Float64
+ : NeonTypeFlags::Float32, false, quad));
+ llvm::Type *Tys[2] = { Ty, InTy };
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtp");
+ }
+ case NEON::BI__builtin_neon_vmulx_v:
+ case NEON::BI__builtin_neon_vmulxq_v: {
+ Int = Intrinsic::aarch64_neon_fmulx;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmulx");
+ }
+ case NEON::BI__builtin_neon_vmul_lane_v:
+ case NEON::BI__builtin_neon_vmul_laneq_v: {
+ // v1f64 vmul_lane should be mapped to Neon scalar mul lane
+ bool Quad = false;
+ if (BuiltinID == NEON::BI__builtin_neon_vmul_laneq_v)
+ Quad = true;
+ Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy);
+ llvm::Type *VTy = GetNeonType(this,
+ NeonTypeFlags(NeonTypeFlags::Float64, false, Quad));
+ Ops[1] = Builder.CreateBitCast(Ops[1], VTy);
+ Ops[1] = Builder.CreateExtractElement(Ops[1], Ops[2], "extract");
+ Value *Result = Builder.CreateFMul(Ops[0], Ops[1]);
+ return Builder.CreateBitCast(Result, Ty);
+ }
+ case NEON::BI__builtin_neon_vnegd_s64:
+ return Builder.CreateNeg(EmitScalarExpr(E->getArg(0)), "vnegd");
+ case NEON::BI__builtin_neon_vpmaxnm_v:
+ case NEON::BI__builtin_neon_vpmaxnmq_v: {
+ Int = Intrinsic::aarch64_neon_fmaxnmp;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpmaxnm");
+ }
+ case NEON::BI__builtin_neon_vpminnm_v:
+ case NEON::BI__builtin_neon_vpminnmq_v: {
+ Int = Intrinsic::aarch64_neon_fminnmp;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vpminnm");
+ }
+ case NEON::BI__builtin_neon_vsqrt_v:
+ case NEON::BI__builtin_neon_vsqrtq_v: {
+ Int = Intrinsic::sqrt;
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vsqrt");
+ }
+ case NEON::BI__builtin_neon_vrbit_v:
+ case NEON::BI__builtin_neon_vrbitq_v: {
+ Int = Intrinsic::aarch64_neon_rbit;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrbit");
+ }
+ case NEON::BI__builtin_neon_vaddv_u8:
+ // FIXME: These are handled by the AArch64 scalar code.
+ usgn = true;
+ // FALLTHROUGH
+ case NEON::BI__builtin_neon_vaddv_s8: {
+ Int = usgn ? Intrinsic::aarch64_neon_uaddv : Intrinsic::aarch64_neon_saddv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 8), 8);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 8));
+ }
+ case NEON::BI__builtin_neon_vaddv_u16:
+ usgn = true;
+ // FALLTHROUGH
+ case NEON::BI__builtin_neon_vaddv_s16: {
+ Int = usgn ? Intrinsic::aarch64_neon_uaddv : Intrinsic::aarch64_neon_saddv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 16), 4);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 16));
+ }
+ case NEON::BI__builtin_neon_vaddvq_u8:
+ usgn = true;
+ // FALLTHROUGH
+ case NEON::BI__builtin_neon_vaddvq_s8: {
+ Int = usgn ? Intrinsic::aarch64_neon_uaddv : Intrinsic::aarch64_neon_saddv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 8), 16);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 8));
+ }
+ case NEON::BI__builtin_neon_vaddvq_u16:
+ usgn = true;
+ // FALLTHROUGH
+ case NEON::BI__builtin_neon_vaddvq_s16: {
+ Int = usgn ? Intrinsic::aarch64_neon_uaddv : Intrinsic::aarch64_neon_saddv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 16), 8);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 16));
+ }
+ case NEON::BI__builtin_neon_vmaxv_u8: {
+ Int = Intrinsic::aarch64_neon_umaxv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 8), 8);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 8));
+ }
+ case NEON::BI__builtin_neon_vmaxv_u16: {
+ Int = Intrinsic::aarch64_neon_umaxv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 16), 4);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 16));
+ }
+ case NEON::BI__builtin_neon_vmaxvq_u8: {
+ Int = Intrinsic::aarch64_neon_umaxv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 8), 16);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 8));
+ }
+ case NEON::BI__builtin_neon_vmaxvq_u16: {
+ Int = Intrinsic::aarch64_neon_umaxv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 16), 8);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 16));
+ }
+ case NEON::BI__builtin_neon_vmaxv_s8: {
+ Int = Intrinsic::aarch64_neon_smaxv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 8), 8);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 8));
+ }
+ case NEON::BI__builtin_neon_vmaxv_s16: {
+ Int = Intrinsic::aarch64_neon_smaxv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 16), 4);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 16));
+ }
+ case NEON::BI__builtin_neon_vmaxvq_s8: {
+ Int = Intrinsic::aarch64_neon_smaxv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 8), 16);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 8));
+ }
+ case NEON::BI__builtin_neon_vmaxvq_s16: {
+ Int = Intrinsic::aarch64_neon_smaxv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 16), 8);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 16));
+ }
+ case NEON::BI__builtin_neon_vminv_u8: {
+ Int = Intrinsic::aarch64_neon_uminv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 8), 8);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 8));
+ }
+ case NEON::BI__builtin_neon_vminv_u16: {
+ Int = Intrinsic::aarch64_neon_uminv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 16), 4);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 16));
+ }
+ case NEON::BI__builtin_neon_vminvq_u8: {
+ Int = Intrinsic::aarch64_neon_uminv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 8), 16);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 8));
+ }
+ case NEON::BI__builtin_neon_vminvq_u16: {
+ Int = Intrinsic::aarch64_neon_uminv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 16), 8);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 16));
+ }
+ case NEON::BI__builtin_neon_vminv_s8: {
+ Int = Intrinsic::aarch64_neon_sminv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 8), 8);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 8));
+ }
+ case NEON::BI__builtin_neon_vminv_s16: {
+ Int = Intrinsic::aarch64_neon_sminv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 16), 4);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 16));
+ }
+ case NEON::BI__builtin_neon_vminvq_s8: {
+ Int = Intrinsic::aarch64_neon_sminv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 8), 16);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 8));
+ }
+ case NEON::BI__builtin_neon_vminvq_s16: {
+ Int = Intrinsic::aarch64_neon_sminv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 16), 8);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 16));
+ }
+ case NEON::BI__builtin_neon_vmul_n_f64: {
+ Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy);
+ Value *RHS = Builder.CreateBitCast(EmitScalarExpr(E->getArg(1)), DoubleTy);
+ return Builder.CreateFMul(Ops[0], RHS);
+ }
+ case NEON::BI__builtin_neon_vaddlv_u8: {
+ Int = Intrinsic::aarch64_neon_uaddlv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 8), 8);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 16));
+ }
+ case NEON::BI__builtin_neon_vaddlv_u16: {
+ Int = Intrinsic::aarch64_neon_uaddlv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 16), 4);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
+ }
+ case NEON::BI__builtin_neon_vaddlvq_u8: {
+ Int = Intrinsic::aarch64_neon_uaddlv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 8), 16);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 16));
+ }
+ case NEON::BI__builtin_neon_vaddlvq_u16: {
+ Int = Intrinsic::aarch64_neon_uaddlv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 16), 8);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
+ }
+ case NEON::BI__builtin_neon_vaddlv_s8: {
+ Int = Intrinsic::aarch64_neon_saddlv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 8), 8);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 16));
+ }
+ case NEON::BI__builtin_neon_vaddlv_s16: {
+ Int = Intrinsic::aarch64_neon_saddlv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 16), 4);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
+ }
+ case NEON::BI__builtin_neon_vaddlvq_s8: {
+ Int = Intrinsic::aarch64_neon_saddlv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 8), 16);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
+ return Builder.CreateTrunc(Ops[0],
+ llvm::IntegerType::get(getLLVMContext(), 16));
+ }
+ case NEON::BI__builtin_neon_vaddlvq_s16: {
+ Int = Intrinsic::aarch64_neon_saddlv;
+ Ty = llvm::IntegerType::get(getLLVMContext(), 32);
+ VTy =
+ llvm::VectorType::get(llvm::IntegerType::get(getLLVMContext(), 16), 8);
+ llvm::Type *Tys[2] = { Ty, VTy };
+ Ops.push_back(EmitScalarExpr(E->getArg(0)));
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vaddlv");
+ }
+ case NEON::BI__builtin_neon_vsri_n_v:
+ case NEON::BI__builtin_neon_vsriq_n_v: {
+ Int = Intrinsic::aarch64_neon_vsri;
+ llvm::Function *Intrin = CGM.getIntrinsic(Int, Ty);
+ return EmitNeonCall(Intrin, Ops, "vsri_n");
+ }
+ case NEON::BI__builtin_neon_vsli_n_v:
+ case NEON::BI__builtin_neon_vsliq_n_v: {
+ Int = Intrinsic::aarch64_neon_vsli;
+ llvm::Function *Intrin = CGM.getIntrinsic(Int, Ty);
+ return EmitNeonCall(Intrin, Ops, "vsli_n");
+ }
+ case NEON::BI__builtin_neon_vsra_n_v:
+ case NEON::BI__builtin_neon_vsraq_n_v:
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ Ops[1] = EmitNeonRShiftImm(Ops[1], Ops[2], Ty, usgn, "vsra_n");
+ return Builder.CreateAdd(Ops[0], Ops[1]);
+ case NEON::BI__builtin_neon_vrsra_n_v:
+ case NEON::BI__builtin_neon_vrsraq_n_v: {
+ Int = usgn ? Intrinsic::aarch64_neon_urshl : Intrinsic::aarch64_neon_srshl;
+ SmallVector<llvm::Value*,2> TmpOps;
+ TmpOps.push_back(Ops[1]);
+ TmpOps.push_back(Ops[2]);
+ Function* F = CGM.getIntrinsic(Int, Ty);
+ llvm::Value *tmp = EmitNeonCall(F, TmpOps, "vrshr_n", 1, true);
+ Ops[0] = Builder.CreateBitCast(Ops[0], VTy);
+ return Builder.CreateAdd(Ops[0], tmp);
+ }
+ // FIXME: Sharing loads & stores with 32-bit is complicated by the absence
+ // of an Align parameter here.
+ case NEON::BI__builtin_neon_vld1_x2_v:
+ case NEON::BI__builtin_neon_vld1q_x2_v:
+ case NEON::BI__builtin_neon_vld1_x3_v:
+ case NEON::BI__builtin_neon_vld1q_x3_v:
+ case NEON::BI__builtin_neon_vld1_x4_v:
+ case NEON::BI__builtin_neon_vld1q_x4_v: {
+ llvm::Type *PTy = llvm::PointerType::getUnqual(VTy->getVectorElementType());
+ Ops[1] = Builder.CreateBitCast(Ops[1], PTy);
+ llvm::Type *Tys[2] = { VTy, PTy };
+ unsigned Int;
+ switch (BuiltinID) {
+ case NEON::BI__builtin_neon_vld1_x2_v:
+ case NEON::BI__builtin_neon_vld1q_x2_v:
+ Int = Intrinsic::aarch64_neon_ld1x2;
+ break;
+ case NEON::BI__builtin_neon_vld1_x3_v:
+ case NEON::BI__builtin_neon_vld1q_x3_v:
+ Int = Intrinsic::aarch64_neon_ld1x3;
+ break;
+ case NEON::BI__builtin_neon_vld1_x4_v:
+ case NEON::BI__builtin_neon_vld1q_x4_v:
+ Int = Intrinsic::aarch64_neon_ld1x4;
+ break;
+ }
+ Function *F = CGM.getIntrinsic(Int, Tys);
+ Ops[1] = Builder.CreateCall(F, Ops[1], "vld1xN");
+ Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ return Builder.CreateStore(Ops[1], Ops[0]);
+ }
+ case NEON::BI__builtin_neon_vst1_x2_v:
+ case NEON::BI__builtin_neon_vst1q_x2_v:
+ case NEON::BI__builtin_neon_vst1_x3_v:
+ case NEON::BI__builtin_neon_vst1q_x3_v:
+ case NEON::BI__builtin_neon_vst1_x4_v:
+ case NEON::BI__builtin_neon_vst1q_x4_v: {
+ llvm::Type *PTy = llvm::PointerType::getUnqual(VTy->getVectorElementType());
+ llvm::Type *Tys[2] = { VTy, PTy };
+ unsigned Int;
+ switch (BuiltinID) {
+ case NEON::BI__builtin_neon_vst1_x2_v:
+ case NEON::BI__builtin_neon_vst1q_x2_v:
+ Int = Intrinsic::aarch64_neon_st1x2;
+ break;
+ case NEON::BI__builtin_neon_vst1_x3_v:
+ case NEON::BI__builtin_neon_vst1q_x3_v:
+ Int = Intrinsic::aarch64_neon_st1x3;
+ break;
+ case NEON::BI__builtin_neon_vst1_x4_v:
+ case NEON::BI__builtin_neon_vst1q_x4_v:
+ Int = Intrinsic::aarch64_neon_st1x4;
+ break;
+ }
+ SmallVector<Value *, 4> IntOps(Ops.begin()+1, Ops.end());
+ IntOps.push_back(Ops[0]);
+ return EmitNeonCall(CGM.getIntrinsic(Int, Tys), IntOps, "");
+ }
+ case NEON::BI__builtin_neon_vld1_v:
+ case NEON::BI__builtin_neon_vld1q_v:
+ Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(VTy));
+ return Builder.CreateLoad(Ops[0]);
+ case NEON::BI__builtin_neon_vst1_v:
+ case NEON::BI__builtin_neon_vst1q_v:
+ Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(VTy));
+ Ops[1] = Builder.CreateBitCast(Ops[1], VTy);
+ return Builder.CreateStore(Ops[1], Ops[0]);
+ case NEON::BI__builtin_neon_vld1_lane_v:
+ case NEON::BI__builtin_neon_vld1q_lane_v:
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+ Ty = llvm::PointerType::getUnqual(VTy->getElementType());
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ Ops[0] = Builder.CreateLoad(Ops[0]);
+ return Builder.CreateInsertElement(Ops[1], Ops[0], Ops[2], "vld1_lane");
+ case NEON::BI__builtin_neon_vld1_dup_v:
+ case NEON::BI__builtin_neon_vld1q_dup_v: {
+ Value *V = UndefValue::get(Ty);
+ Ty = llvm::PointerType::getUnqual(VTy->getElementType());
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ Ops[0] = Builder.CreateLoad(Ops[0]);
+ llvm::Constant *CI = ConstantInt::get(Int32Ty, 0);
+ Ops[0] = Builder.CreateInsertElement(V, Ops[0], CI);
+ return EmitNeonSplat(Ops[0], CI);
+ }
+ case NEON::BI__builtin_neon_vst1_lane_v:
+ case NEON::BI__builtin_neon_vst1q_lane_v:
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+ Ops[1] = Builder.CreateExtractElement(Ops[1], Ops[2]);
+ Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
+ return Builder.CreateStore(Ops[1], Builder.CreateBitCast(Ops[0], Ty));
+ case NEON::BI__builtin_neon_vld2_v:
+ case NEON::BI__builtin_neon_vld2q_v: {
+ llvm::Type *PTy = llvm::PointerType::getUnqual(VTy);
+ Ops[1] = Builder.CreateBitCast(Ops[1], PTy);
+ llvm::Type *Tys[2] = { VTy, PTy };
+ Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld2, Tys);
+ Ops[1] = Builder.CreateCall(F, Ops[1], "vld2");
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::PointerType::getUnqual(Ops[1]->getType()));
+ return Builder.CreateStore(Ops[1], Ops[0]);
+ }
+ case NEON::BI__builtin_neon_vld3_v:
+ case NEON::BI__builtin_neon_vld3q_v: {
+ llvm::Type *PTy = llvm::PointerType::getUnqual(VTy);
+ Ops[1] = Builder.CreateBitCast(Ops[1], PTy);
+ llvm::Type *Tys[2] = { VTy, PTy };
+ Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld3, Tys);
+ Ops[1] = Builder.CreateCall(F, Ops[1], "vld3");
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::PointerType::getUnqual(Ops[1]->getType()));
+ return Builder.CreateStore(Ops[1], Ops[0]);
+ }
+ case NEON::BI__builtin_neon_vld4_v:
+ case NEON::BI__builtin_neon_vld4q_v: {
+ llvm::Type *PTy = llvm::PointerType::getUnqual(VTy);
+ Ops[1] = Builder.CreateBitCast(Ops[1], PTy);
+ llvm::Type *Tys[2] = { VTy, PTy };
+ Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld4, Tys);
+ Ops[1] = Builder.CreateCall(F, Ops[1], "vld4");
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::PointerType::getUnqual(Ops[1]->getType()));
+ return Builder.CreateStore(Ops[1], Ops[0]);
}
- case ARM::BI__builtin_neon_vtrn_v:
- case ARM::BI__builtin_neon_vtrnq_v: {
+ case NEON::BI__builtin_neon_vld2_dup_v:
+ case NEON::BI__builtin_neon_vld2q_dup_v: {
+ llvm::Type *PTy =
+ llvm::PointerType::getUnqual(VTy->getElementType());
+ Ops[1] = Builder.CreateBitCast(Ops[1], PTy);
+ llvm::Type *Tys[2] = { VTy, PTy };
+ Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld2r, Tys);
+ Ops[1] = Builder.CreateCall(F, Ops[1], "vld2");
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::PointerType::getUnqual(Ops[1]->getType()));
+ return Builder.CreateStore(Ops[1], Ops[0]);
+ }
+ case NEON::BI__builtin_neon_vld3_dup_v:
+ case NEON::BI__builtin_neon_vld3q_dup_v: {
+ llvm::Type *PTy =
+ llvm::PointerType::getUnqual(VTy->getElementType());
+ Ops[1] = Builder.CreateBitCast(Ops[1], PTy);
+ llvm::Type *Tys[2] = { VTy, PTy };
+ Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld3r, Tys);
+ Ops[1] = Builder.CreateCall(F, Ops[1], "vld3");
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::PointerType::getUnqual(Ops[1]->getType()));
+ return Builder.CreateStore(Ops[1], Ops[0]);
+ }
+ case NEON::BI__builtin_neon_vld4_dup_v:
+ case NEON::BI__builtin_neon_vld4q_dup_v: {
+ llvm::Type *PTy =
+ llvm::PointerType::getUnqual(VTy->getElementType());
+ Ops[1] = Builder.CreateBitCast(Ops[1], PTy);
+ llvm::Type *Tys[2] = { VTy, PTy };
+ Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld4r, Tys);
+ Ops[1] = Builder.CreateCall(F, Ops[1], "vld4");
+ Ops[0] = Builder.CreateBitCast(Ops[0],
+ llvm::PointerType::getUnqual(Ops[1]->getType()));
+ return Builder.CreateStore(Ops[1], Ops[0]);
+ }
+ case NEON::BI__builtin_neon_vld2_lane_v:
+ case NEON::BI__builtin_neon_vld2q_lane_v: {
+ llvm::Type *Tys[2] = { VTy, Ops[1]->getType() };
+ Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld2lane, Tys);
+ Ops.push_back(Ops[1]);
+ Ops.erase(Ops.begin()+1);
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+ Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
+ Ops[3] = Builder.CreateZExt(Ops[3],
+ llvm::IntegerType::get(getLLVMContext(), 64));
+ Ops[1] = Builder.CreateCall(F,
+ ArrayRef<Value*>(Ops).slice(1), "vld2_lane");
+ Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ return Builder.CreateStore(Ops[1], Ops[0]);
+ }
+ case NEON::BI__builtin_neon_vld3_lane_v:
+ case NEON::BI__builtin_neon_vld3q_lane_v: {
+ llvm::Type *Tys[2] = { VTy, Ops[1]->getType() };
+ Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld3lane, Tys);
+ Ops.push_back(Ops[1]);
+ Ops.erase(Ops.begin()+1);
+ Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
+ Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
+ Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
+ Ops[4] = Builder.CreateZExt(Ops[4],
+ llvm::IntegerType::get(getLLVMContext(), 64));
+ Ops[1] = Builder.CreateCall(F,
+ ArrayRef<Value*>(Ops).slice(1), "vld3_lane");
+ Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ return Builder.CreateStore(Ops[1], Ops[0]);
+ }
+ case NEON::BI__builtin_neon_vld4_lane_v:
+ case NEON::BI__builtin_neon_vld4q_lane_v: {
+ llvm::Type *Tys[2] = { VTy, Ops[1]->getType() };
+ Function *F = CGM.getIntrinsic(Intrinsic::aarch64_neon_ld4lane, Tys);
+ Ops.push_back(Ops[1]);
+ Ops.erase(Ops.begin()+1);
+ Ops[1] = Builder.CreateBitCast(Ops[1], 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.CreateZExt(Ops[5],
+ llvm::IntegerType::get(getLLVMContext(), 64));
+ Ops[1] = Builder.CreateCall(F,
+ ArrayRef<Value*>(Ops).slice(1), "vld4_lane");
+ Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
+ Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
+ return Builder.CreateStore(Ops[1], Ops[0]);
+ }
+ case NEON::BI__builtin_neon_vst2_v:
+ case NEON::BI__builtin_neon_vst2q_v: {
+ Ops.push_back(Ops[0]);
+ Ops.erase(Ops.begin());
+ llvm::Type *Tys[2] = { VTy, Ops[2]->getType() };
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_st2, Tys),
+ Ops, "");
+ }
+ case NEON::BI__builtin_neon_vst2_lane_v:
+ case NEON::BI__builtin_neon_vst2q_lane_v: {
+ Ops.push_back(Ops[0]);
+ Ops.erase(Ops.begin());
+ Ops[2] = Builder.CreateZExt(Ops[2],
+ llvm::IntegerType::get(getLLVMContext(), 64));
+ llvm::Type *Tys[2] = { VTy, Ops[3]->getType() };
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_st2lane, Tys),
+ Ops, "");
+ }
+ case NEON::BI__builtin_neon_vst3_v:
+ case NEON::BI__builtin_neon_vst3q_v: {
+ Ops.push_back(Ops[0]);
+ Ops.erase(Ops.begin());
+ llvm::Type *Tys[2] = { VTy, Ops[3]->getType() };
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_st3, Tys),
+ Ops, "");
+ }
+ case NEON::BI__builtin_neon_vst3_lane_v:
+ case NEON::BI__builtin_neon_vst3q_lane_v: {
+ Ops.push_back(Ops[0]);
+ Ops.erase(Ops.begin());
+ Ops[3] = Builder.CreateZExt(Ops[3],
+ llvm::IntegerType::get(getLLVMContext(), 64));
+ llvm::Type *Tys[2] = { VTy, Ops[4]->getType() };
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_st3lane, Tys),
+ Ops, "");
+ }
+ case NEON::BI__builtin_neon_vst4_v:
+ case NEON::BI__builtin_neon_vst4q_v: {
+ Ops.push_back(Ops[0]);
+ Ops.erase(Ops.begin());
+ llvm::Type *Tys[2] = { VTy, Ops[4]->getType() };
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_st4, Tys),
+ Ops, "");
+ }
+ case NEON::BI__builtin_neon_vst4_lane_v:
+ case NEON::BI__builtin_neon_vst4q_lane_v: {
+ Ops.push_back(Ops[0]);
+ Ops.erase(Ops.begin());
+ Ops[4] = Builder.CreateZExt(Ops[4],
+ llvm::IntegerType::get(getLLVMContext(), 64));
+ llvm::Type *Tys[2] = { VTy, Ops[5]->getType() };
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_st4lane, Tys),
+ Ops, "");
+ }
+ case NEON::BI__builtin_neon_vtrn_v:
+ case NEON::BI__builtin_neon_vtrnq_v: {
Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(Ty));
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- Value *SV = 0;
+ Value *SV = nullptr;
for (unsigned vi = 0; vi != 2; ++vi) {
SmallVector<Constant*, 16> Indices;
for (unsigned i = 0, e = VTy->getNumElements(); i != e; i += 2) {
- Indices.push_back(Builder.getInt32(i+vi));
- Indices.push_back(Builder.getInt32(i+e+vi));
+ Indices.push_back(ConstantInt::get(Int32Ty, i+vi));
+ Indices.push_back(ConstantInt::get(Int32Ty, i+e+vi));
}
Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ops[0], vi);
SV = llvm::ConstantVector::get(Indices);
@@ -4875,12 +5550,12 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
return SV;
}
- case ARM::BI__builtin_neon_vuzp_v:
- case ARM::BI__builtin_neon_vuzpq_v: {
+ case NEON::BI__builtin_neon_vuzp_v:
+ case NEON::BI__builtin_neon_vuzpq_v: {
Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(Ty));
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- Value *SV = 0;
+ Value *SV = nullptr;
for (unsigned vi = 0; vi != 2; ++vi) {
SmallVector<Constant*, 16> Indices;
@@ -4894,12 +5569,12 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
return SV;
}
- case ARM::BI__builtin_neon_vzip_v:
- case ARM::BI__builtin_neon_vzipq_v: {
+ case NEON::BI__builtin_neon_vzip_v:
+ case NEON::BI__builtin_neon_vzipq_v: {
Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(Ty));
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- Value *SV = 0;
+ Value *SV = nullptr;
for (unsigned vi = 0; vi != 2; ++vi) {
SmallVector<Constant*, 16> Indices;
@@ -4914,6 +5589,48 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
return SV;
}
+ case NEON::BI__builtin_neon_vqtbl1q_v: {
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_tbl1, Ty),
+ Ops, "vtbl1");
+ }
+ case NEON::BI__builtin_neon_vqtbl2q_v: {
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_tbl2, Ty),
+ Ops, "vtbl2");
+ }
+ case NEON::BI__builtin_neon_vqtbl3q_v: {
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_tbl3, Ty),
+ Ops, "vtbl3");
+ }
+ case NEON::BI__builtin_neon_vqtbl4q_v: {
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_tbl4, Ty),
+ Ops, "vtbl4");
+ }
+ case NEON::BI__builtin_neon_vqtbx1q_v: {
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_tbx1, Ty),
+ Ops, "vtbx1");
+ }
+ case NEON::BI__builtin_neon_vqtbx2q_v: {
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_tbx2, Ty),
+ Ops, "vtbx2");
+ }
+ case NEON::BI__builtin_neon_vqtbx3q_v: {
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_tbx3, Ty),
+ Ops, "vtbx3");
+ }
+ case NEON::BI__builtin_neon_vqtbx4q_v: {
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::aarch64_neon_tbx4, Ty),
+ Ops, "vtbx4");
+ }
+ case NEON::BI__builtin_neon_vsqadd_v:
+ case NEON::BI__builtin_neon_vsqaddq_v: {
+ Int = Intrinsic::aarch64_neon_usqadd;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vsqadd");
+ }
+ case NEON::BI__builtin_neon_vuqadd_v:
+ case NEON::BI__builtin_neon_vuqaddq_v: {
+ Int = Intrinsic::aarch64_neon_suqadd;
+ return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vuqadd");
+ }
}
}
@@ -4969,7 +5686,15 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
switch (BuiltinID) {
- default: return 0;
+ default: return nullptr;
+ case X86::BI_mm_prefetch: {
+ Value *Address = EmitScalarExpr(E->getArg(0));
+ Value *RW = ConstantInt::get(Int32Ty, 0);
+ Value *Locality = EmitScalarExpr(E->getArg(1));
+ Value *Data = ConstantInt::get(Int32Ty, 1);
+ Value *F = CGM.getIntrinsic(Intrinsic::prefetch);
+ return Builder.CreateCall4(F, Address, RW, Locality, Data);
+ }
case X86::BI__builtin_ia32_vec_init_v8qi:
case X86::BI__builtin_ia32_vec_init_v4hi:
case X86::BI__builtin_ia32_vec_init_v2si:
@@ -5000,7 +5725,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// extract (0, 1)
unsigned Index = BuiltinID == X86::BI__builtin_ia32_storelps ? 0 : 1;
- llvm::Value *Idx = llvm::ConstantInt::get(Int32Ty, Index);
+ llvm::Value *Idx = llvm::ConstantInt::get(SizeTy, Index);
Ops[1] = Builder.CreateExtractElement(Ops[1], Idx, "extract");
// cast pointer to i64 & store
@@ -5138,7 +5863,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// 3DNow!
case X86::BI__builtin_ia32_pswapdsf:
case X86::BI__builtin_ia32_pswapdsi: {
- const char *name = 0;
+ const char *name = nullptr;
Intrinsic::ID ID = Intrinsic::not_intrinsic;
switch(BuiltinID) {
default: llvm_unreachable("Unsupported intrinsic!");
@@ -5207,7 +5932,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
Intrinsic::ID ID = Intrinsic::not_intrinsic;
switch (BuiltinID) {
- default: return 0;
+ default: return nullptr;
// vec_ld, vec_lvsl, vec_lvsr
case PPC::BI__builtin_altivec_lvx:
@@ -5285,3 +6010,83 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
}
}
}
+
+// Emit an intrinsic that has 1 float or double.
+static Value *emitUnaryFPBuiltin(CodeGenFunction &CGF,
+ const CallExpr *E,
+ unsigned IntrinsicID) {
+ llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
+
+ Value *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType());
+ return CGF.Builder.CreateCall(F, Src0);
+}
+
+// Emit an intrinsic that has 3 float or double operands.
+static Value *emitTernaryFPBuiltin(CodeGenFunction &CGF,
+ const CallExpr *E,
+ unsigned IntrinsicID) {
+ llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
+ llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1));
+ llvm::Value *Src2 = CGF.EmitScalarExpr(E->getArg(2));
+
+ Value *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType());
+ return CGF.Builder.CreateCall3(F, Src0, Src1, Src2);
+}
+
+Value *CodeGenFunction::EmitR600BuiltinExpr(unsigned BuiltinID,
+ const CallExpr *E) {
+ switch (BuiltinID) {
+ case R600::BI__builtin_amdgpu_div_scale:
+ case R600::BI__builtin_amdgpu_div_scalef: {
+ // Translate from the intrinsics's struct return to the builtin's out
+ // argument.
+
+ std::pair<llvm::Value *, unsigned> FlagOutPtr
+ = EmitPointerWithAlignment(E->getArg(3));
+
+ llvm::Value *X = EmitScalarExpr(E->getArg(0));
+ llvm::Value *Y = EmitScalarExpr(E->getArg(1));
+ llvm::Value *Z = EmitScalarExpr(E->getArg(2));
+
+ llvm::Value *Callee = CGM.getIntrinsic(Intrinsic::AMDGPU_div_scale,
+ X->getType());
+
+ llvm::Value *Tmp = Builder.CreateCall3(Callee, X, Y, Z);
+
+ llvm::Value *Result = Builder.CreateExtractValue(Tmp, 0);
+ llvm::Value *Flag = Builder.CreateExtractValue(Tmp, 1);
+
+ llvm::Type *RealFlagType
+ = FlagOutPtr.first->getType()->getPointerElementType();
+
+ llvm::Value *FlagExt = Builder.CreateZExt(Flag, RealFlagType);
+ llvm::StoreInst *FlagStore = Builder.CreateStore(FlagExt, FlagOutPtr.first);
+ FlagStore->setAlignment(FlagOutPtr.second);
+ return Result;
+ }
+ case R600::BI__builtin_amdgpu_div_fmas:
+ case R600::BI__builtin_amdgpu_div_fmasf:
+ return emitTernaryFPBuiltin(*this, E, Intrinsic::AMDGPU_div_fmas);
+ case R600::BI__builtin_amdgpu_div_fixup:
+ case R600::BI__builtin_amdgpu_div_fixupf:
+ return emitTernaryFPBuiltin(*this, E, Intrinsic::AMDGPU_div_fixup);
+ case R600::BI__builtin_amdgpu_trig_preop:
+ case R600::BI__builtin_amdgpu_trig_preopf: {
+ Value *Src0 = EmitScalarExpr(E->getArg(0));
+ Value *Src1 = EmitScalarExpr(E->getArg(1));
+ Value *F = CGM.getIntrinsic(Intrinsic::AMDGPU_trig_preop, Src0->getType());
+ return Builder.CreateCall2(F, Src0, Src1);
+ }
+ case R600::BI__builtin_amdgpu_rcp:
+ case R600::BI__builtin_amdgpu_rcpf:
+ return emitUnaryFPBuiltin(*this, E, Intrinsic::AMDGPU_rcp);
+ case R600::BI__builtin_amdgpu_rsq:
+ case R600::BI__builtin_amdgpu_rsqf:
+ return emitUnaryFPBuiltin(*this, E, Intrinsic::AMDGPU_rsq);
+ case R600::BI__builtin_amdgpu_rsq_clamped:
+ case R600::BI__builtin_amdgpu_rsq_clampedf:
+ return emitUnaryFPBuiltin(*this, E, Intrinsic::AMDGPU_rsq_clamped);
+ default:
+ return nullptr;
+ }
+}
diff --git a/lib/CodeGen/CGCUDANV.cpp b/lib/CodeGen/CGCUDANV.cpp
index 0ebf1aaa44b8..fb11751fc91e 100644
--- a/lib/CodeGen/CGCUDANV.cpp
+++ b/lib/CodeGen/CGCUDANV.cpp
@@ -17,9 +17,9 @@
#include "CodeGenModule.h"
#include "clang/AST/Decl.h"
#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/CallSite.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
-#include "llvm/Support/CallSite.h"
#include <vector>
using namespace clang;
@@ -39,7 +39,7 @@ private:
public:
CGNVCUDARuntime(CodeGenModule &CGM);
- void EmitDeviceStubBody(CodeGenFunction &CGF, FunctionArgList &Args);
+ void EmitDeviceStubBody(CodeGenFunction &CGF, FunctionArgList &Args) override;
};
}
diff --git a/lib/CodeGen/CGCUDARuntime.cpp b/lib/CodeGen/CGCUDARuntime.cpp
index eaf31bb6f67f..29e0a91a63fe 100644
--- a/lib/CodeGen/CGCUDARuntime.cpp
+++ b/lib/CodeGen/CGCUDARuntime.cpp
@@ -31,12 +31,13 @@ RValue CGCUDARuntime::EmitCUDAKernelCallExpr(CodeGenFunction &CGF,
llvm::BasicBlock *ContBlock = CGF.createBasicBlock("kcall.end");
CodeGenFunction::ConditionalEvaluation eval(CGF);
- CGF.EmitBranchOnBoolExpr(E->getConfig(), ContBlock, ConfigOKBlock);
+ CGF.EmitBranchOnBoolExpr(E->getConfig(), ContBlock, ConfigOKBlock,
+ /*TrueCount=*/0);
eval.begin(CGF);
CGF.EmitBlock(ConfigOKBlock);
- const Decl *TargetDecl = 0;
+ const Decl *TargetDecl = nullptr;
if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E->getCallee())) {
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {
TargetDecl = DRE->getDecl();
@@ -51,5 +52,5 @@ RValue CGCUDARuntime::EmitCUDAKernelCallExpr(CodeGenFunction &CGF,
CGF.EmitBlock(ContBlock);
eval.end(CGF);
- return RValue::get(0);
+ return RValue::get(nullptr);
}
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 2f8a17afbcd1..545c5ef9f827 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -35,7 +35,7 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
return true;
// Producing an alias to a base class ctor/dtor can degrade debug quality
- // as the debugger cannot tell them appart.
+ // as the debugger cannot tell them apart.
if (getCodeGenOpts().OptimizationLevel == 0)
return true;
@@ -44,6 +44,10 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
if (!D->hasTrivialBody())
return true;
+ // For exported destructors, we need a full definition.
+ if (D->hasAttr<DLLExportAttr>())
+ return true;
+
const CXXRecordDecl *Class = D->getParent();
// If we need to manipulate a VTT parameter, give up.
@@ -56,22 +60,20 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
// If any field has a non-trivial destructor, we have to emit the
// destructor separately.
- for (CXXRecordDecl::field_iterator I = Class->field_begin(),
- E = Class->field_end(); I != E; ++I)
+ for (const auto *I : Class->fields())
if (I->getType().isDestructedType())
return true;
// Try to find a unique base class with a non-trivial destructor.
- const CXXRecordDecl *UniqueBase = 0;
- for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(),
- E = Class->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *UniqueBase = nullptr;
+ for (const auto &I : Class->bases()) {
// We're in the base destructor, so skip virtual bases.
- if (I->isVirtual()) continue;
+ if (I.isVirtual()) continue;
// Skip base classes with trivial destructors.
- const CXXRecordDecl *Base
- = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const auto *Base =
+ cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
if (Base->hasTrivialDestructor()) continue;
// If we've already found a base class with a non-trivial
@@ -113,7 +115,7 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
if (!getCodeGenOpts().CXXCtorDtorAliases)
return true;
- // The alias will use the linkage of the referrent. If we can't
+ // The alias will use the linkage of the referent. If we can't
// support aliases with that linkage, fail.
llvm::GlobalValue::LinkageTypes Linkage = getFunctionLinkage(AliasDecl);
@@ -136,20 +138,20 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
llvm::PointerType *AliasType
= getTypes().GetFunctionType(AliasDecl)->getPointerTo();
- // Find the referrent. Some aliases might require a bitcast, in
+ // Find the referent. Some aliases might require a bitcast, in
// which case the caller is responsible for ensuring the soundness
// of these semantics.
- llvm::GlobalValue *Ref = cast<llvm::GlobalValue>(GetAddrOfGlobal(TargetDecl));
+ auto *Ref = cast<llvm::GlobalValue>(GetAddrOfGlobal(TargetDecl));
llvm::Constant *Aliasee = Ref;
if (Ref->getType() != AliasType)
Aliasee = llvm::ConstantExpr::getBitCast(Ref, AliasType);
// Instead of creating as alias to a linkonce_odr, replace all of the uses
- // of the aliassee.
+ // of the aliasee.
if (llvm::GlobalValue::isDiscardableIfUnused(Linkage) &&
(TargetLinkage != llvm::GlobalValue::AvailableExternallyLinkage ||
!TargetDecl.getDecl()->hasAttr<AlwaysInlineAttr>())) {
- // FIXME: An extern template instanciation will create functions with
+ // FIXME: An extern template instantiation will create functions with
// linkage "AvailableExternally". In libc++, some classes also define
// members with attribute "AlwaysInline" and expect no reference to
// be generated. It is desirable to reenable this optimisation after
@@ -174,8 +176,8 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
return true;
// Create the alias with no name.
- llvm::GlobalAlias *Alias =
- new llvm::GlobalAlias(AliasType, Linkage, "", Aliasee, &getModule());
+ auto *Alias = llvm::GlobalAlias::create(AliasType->getElementType(), 0,
+ Linkage, "", Aliasee, &getModule());
// Switch any previous uses to the alias.
if (Entry) {
@@ -196,11 +198,13 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *ctor,
CXXCtorType ctorType) {
- // The complete constructor is equivalent to the base constructor
- // for classes with no virtual bases. Try to emit it as an alias.
- if (getTarget().getCXXABI().hasConstructorVariants() &&
- !ctor->getParent()->getNumVBases() &&
- (ctorType == Ctor_Complete || ctorType == Ctor_Base)) {
+ if (!getTarget().getCXXABI().hasConstructorVariants()) {
+ // If there are no constructor variants, always emit the complete destructor.
+ ctorType = Ctor_Complete;
+ } else if (!ctor->getParent()->getNumVBases() &&
+ (ctorType == Ctor_Complete || ctorType == Ctor_Base)) {
+ // The complete constructor is equivalent to the base constructor
+ // for classes with no virtual bases. Try to emit it as an alias.
bool ProducedAlias =
!TryEmitDefinitionAsAlias(GlobalDecl(ctor, Ctor_Complete),
GlobalDecl(ctor, Ctor_Base), true);
@@ -211,20 +215,21 @@ void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *ctor,
const CGFunctionInfo &fnInfo =
getTypes().arrangeCXXConstructorDeclaration(ctor, ctorType);
- llvm::Function *fn =
- cast<llvm::Function>(GetAddrOfCXXConstructor(ctor, ctorType, &fnInfo));
+ auto *fn = cast<llvm::Function>(
+ GetAddrOfCXXConstructor(ctor, ctorType, &fnInfo, true));
setFunctionLinkage(GlobalDecl(ctor, ctorType), fn);
CodeGenFunction(*this).GenerateCode(GlobalDecl(ctor, ctorType), fn, fnInfo);
- SetFunctionDefinitionAttributes(ctor, fn);
+ setFunctionDefinitionAttributes(ctor, fn);
SetLLVMFunctionAttributesForDefinition(ctor, fn);
}
llvm::GlobalValue *
CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor,
CXXCtorType ctorType,
- const CGFunctionInfo *fnInfo) {
+ const CGFunctionInfo *fnInfo,
+ bool DontDefer) {
GlobalDecl GD(ctor, ctorType);
StringRef name = getMangledName(GD);
@@ -236,7 +241,8 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor,
llvm::FunctionType *fnType = getTypes().GetFunctionType(*fnInfo);
return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD,
- /*ForVTable=*/false));
+ /*ForVTable=*/false,
+ DontDefer));
}
void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor,
@@ -266,13 +272,13 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor,
const CGFunctionInfo &fnInfo =
getTypes().arrangeCXXDestructor(dtor, dtorType);
- llvm::Function *fn =
- cast<llvm::Function>(GetAddrOfCXXDestructor(dtor, dtorType, &fnInfo));
+ auto *fn = cast<llvm::Function>(
+ GetAddrOfCXXDestructor(dtor, dtorType, &fnInfo, nullptr, true));
setFunctionLinkage(GlobalDecl(dtor, dtorType), fn);
CodeGenFunction(*this).GenerateCode(GlobalDecl(dtor, dtorType), fn, fnInfo);
- SetFunctionDefinitionAttributes(dtor, fn);
+ setFunctionDefinitionAttributes(dtor, fn);
SetLLVMFunctionAttributesForDefinition(dtor, fn);
}
@@ -280,7 +286,8 @@ llvm::GlobalValue *
CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor,
CXXDtorType dtorType,
const CGFunctionInfo *fnInfo,
- llvm::FunctionType *fnType) {
+ llvm::FunctionType *fnType,
+ bool DontDefer) {
GlobalDecl GD(dtor, dtorType);
StringRef name = getMangledName(GD);
@@ -292,7 +299,8 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor,
fnType = getTypes().GetFunctionType(*fnInfo);
}
return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD,
- /*ForVTable=*/false));
+ /*ForVTable=*/false,
+ DontDefer));
}
static llvm::Value *BuildAppleKextVirtualCall(CodeGenFunction &CGF,
@@ -331,9 +339,9 @@ CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD,
QualType T = QualType(QTy, 0);
const RecordType *RT = T->getAs<RecordType>();
assert(RT && "BuildAppleKextVirtualCall - Qual type must be record");
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
-
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD))
+ const auto *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD))
return BuildAppleKextVirtualDestructorCall(DD, Dtor_Complete, RD);
return ::BuildAppleKextVirtualCall(*this, MD, Ty, RD);
@@ -346,7 +354,7 @@ CodeGenFunction::BuildAppleKextVirtualDestructorCall(
const CXXDestructorDecl *DD,
CXXDtorType Type,
const CXXRecordDecl *RD) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(DD);
+ const auto *MD = cast<CXXMethodDecl>(DD);
// FIXME. Dtor_Base dtor is always direct!!
// It need be somehow inline expanded into the caller.
// -O does that. But need to support -O0 as well.
@@ -357,5 +365,5 @@ CodeGenFunction::BuildAppleKextVirtualDestructorCall(
llvm::Type *Ty = CGM.getTypes().GetFunctionType(FInfo);
return ::BuildAppleKextVirtualCall(*this, GlobalDecl(DD, Type), Ty, RD);
}
- return 0;
+ return nullptr;
}
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp
index 412b27814ac8..55ddd666c490 100644
--- a/lib/CodeGen/CGCXXABI.cpp
+++ b/lib/CodeGen/CGCXXABI.cpp
@@ -28,6 +28,41 @@ void CGCXXABI::ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S) {
<< S;
}
+bool CGCXXABI::canCopyArgument(const CXXRecordDecl *RD) const {
+ // If RD has a non-trivial move or copy constructor, we cannot copy the
+ // argument.
+ if (RD->hasNonTrivialCopyConstructor() || RD->hasNonTrivialMoveConstructor())
+ return false;
+
+ // If RD has a non-trivial destructor, we cannot copy the argument.
+ if (RD->hasNonTrivialDestructor())
+ return false;
+
+ // We can only copy the argument if there exists at least one trivial,
+ // non-deleted copy or move constructor.
+ // FIXME: This assumes that all lazily declared copy and move constructors are
+ // not deleted. This assumption might not be true in some corner cases.
+ bool CopyDeleted = false;
+ bool MoveDeleted = false;
+ for (const CXXConstructorDecl *CD : RD->ctors()) {
+ if (CD->isCopyConstructor() || CD->isMoveConstructor()) {
+ assert(CD->isTrivial());
+ // We had at least one undeleted trivial copy or move ctor. Return
+ // directly.
+ if (!CD->isDeleted())
+ return true;
+ if (CD->isCopyConstructor())
+ CopyDeleted = true;
+ else
+ MoveDeleted = true;
+ }
+ }
+
+ // If all trivial copy and move constructors are deleted, we cannot copy the
+ // argument.
+ return !(CopyDeleted && MoveDeleted);
+}
+
llvm::Constant *CGCXXABI::GetBogusMemberPointer(QualType T) {
return llvm::Constant::getNullValue(CGM.getTypes().ConvertType(T));
}
@@ -37,10 +72,9 @@ CGCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
return CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
}
-llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
- llvm::Value *&This,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT) {
+llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(
+ CodeGenFunction &CGF, const Expr *E, llvm::Value *&This,
+ llvm::Value *MemPtr, const MemberPointerType *MPT) {
ErrorUnsupportedABI(CGF, "calls through member pointers");
const FunctionProtoType *FPT =
@@ -52,10 +86,10 @@ llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
return llvm::Constant::getNullValue(FTy->getPointerTo());
}
-llvm::Value *CGCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
- llvm::Value *Base,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT) {
+llvm::Value *
+CGCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF, const Expr *E,
+ llvm::Value *Base, llvm::Value *MemPtr,
+ const MemberPointerType *MPT) {
ErrorUnsupportedABI(CGF, "loads of member pointers");
llvm::Type *Ty = CGF.ConvertType(MPT->getPointeeType())->getPointerTo();
return llvm::Constant::getNullValue(Ty);
@@ -116,13 +150,13 @@ bool CGCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
return true;
}
-void CGCXXABI::BuildThisParam(CodeGenFunction &CGF, FunctionArgList &params) {
+void CGCXXABI::buildThisParam(CodeGenFunction &CGF, FunctionArgList &params) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
// FIXME: I'm not entirely sure I like using a fake decl just for code
// generation. Maybe we can come up with a better way?
ImplicitParamDecl *ThisDecl
- = ImplicitParamDecl::Create(CGM.getContext(), 0, MD->getLocation(),
+ = ImplicitParamDecl::Create(CGM.getContext(), nullptr, MD->getLocation(),
&CGM.getContext().Idents.get("this"),
MD->getThisType(CGM.getContext()));
params.push_back(ThisDecl);
@@ -160,7 +194,7 @@ llvm::Value *CGCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
QualType ElementType) {
// Should never be called.
ErrorUnsupportedABI(CGF, "array cookie initialization");
- return 0;
+ return nullptr;
}
bool CGCXXABI::requiresArrayCookie(const CXXDeleteExpr *expr,
@@ -194,7 +228,7 @@ void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *ptr,
// If we don't need an array cookie, bail out early.
if (!requiresArrayCookie(expr, eltTy)) {
allocPtr = ptr;
- numElements = 0;
+ numElements = nullptr;
cookieSize = CharUnits::Zero();
return;
}
@@ -273,16 +307,17 @@ CGCXXABI::EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
llvm_unreachable("shouldn't be called in this ABI");
ErrorUnsupportedABI(CGF, "complete object detection in ctor");
- return 0;
+ return nullptr;
}
void CGCXXABI::EmitThreadLocalInitFuncs(
- llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
+ ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
llvm::Function *InitFunc) {
}
-LValue CGCXXABI::EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF,
- const DeclRefExpr *DRE) {
+LValue CGCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF,
+ const VarDecl *VD,
+ QualType LValType) {
ErrorUnsupportedABI(CGF, "odr-use of thread_local global");
return LValue();
}
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index 9e9a2a7aaf9b..91e49707bae6 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -19,29 +19,29 @@
#include "clang/Basic/LLVM.h"
namespace llvm {
- class Constant;
- class Type;
- class Value;
+class Constant;
+class Type;
+class Value;
}
namespace clang {
- class CastExpr;
- class CXXConstructorDecl;
- class CXXDestructorDecl;
- class CXXMethodDecl;
- class CXXRecordDecl;
- class FieldDecl;
- class MangleContext;
+class CastExpr;
+class CXXConstructorDecl;
+class CXXDestructorDecl;
+class CXXMethodDecl;
+class CXXRecordDecl;
+class FieldDecl;
+class MangleContext;
namespace CodeGen {
- class CodeGenFunction;
- class CodeGenModule;
+class CodeGenFunction;
+class CodeGenModule;
/// \brief Implements C++ ABI-specific code generation functions.
class CGCXXABI {
protected:
CodeGenModule &CGM;
- OwningPtr<MangleContext> MangleCtx;
+ std::unique_ptr<MangleContext> MangleCtx;
CGCXXABI(CodeGenModule &CGM)
: CGM(CGM), MangleCtx(CGM.getContext().createMangleContext()) {}
@@ -60,15 +60,6 @@ protected:
/// Get a null value for unsupported member pointers.
llvm::Constant *GetBogusMemberPointer(QualType T);
- // FIXME: Every place that calls getVTT{Decl,Value} is something
- // that needs to be abstracted properly.
- ImplicitParamDecl *&getVTTDecl(CodeGenFunction &CGF) {
- return CGF.CXXStructorImplicitParamDecl;
- }
- llvm::Value *&getVTTValue(CodeGenFunction &CGF) {
- return CGF.CXXStructorImplicitParamValue;
- }
-
ImplicitParamDecl *&getStructorImplicitParamDecl(CodeGenFunction &CGF) {
return CGF.CXXStructorImplicitParamDecl;
}
@@ -76,11 +67,8 @@ protected:
return CGF.CXXStructorImplicitParamValue;
}
- /// Build a parameter variable suitable for 'this'.
- void BuildThisParam(CodeGenFunction &CGF, FunctionArgList &Params);
-
/// Perform prolog initialization of the parameter variable suitable
- /// for 'this' emitted by BuildThisParam.
+ /// for 'this' emitted by buildThisParam.
void EmitThisParam(CodeGenFunction &CGF);
ASTContext &getContext() const { return CGM.getContext(); }
@@ -105,8 +93,9 @@ public:
/// when called virtually, and code generation does not support the case.
virtual bool HasThisReturn(GlobalDecl GD) const { return false; }
- /// Returns true if the given record type should be returned indirectly.
- virtual bool isReturnTypeIndirect(const CXXRecordDecl *RD) const = 0;
+ /// If the C++ ABI requires the given type be returned in a particular way,
+ /// this method sets RetAI and returns true.
+ virtual bool classifyReturnType(CGFunctionInfo &FI) const = 0;
/// Specify how one should pass an argument of a record type.
enum RecordArgABI {
@@ -123,9 +112,17 @@ public:
RAA_Indirect
};
+ /// Returns true if C++ allows us to copy the memory of an object of type RD
+ /// when it is passed as an argument.
+ bool canCopyArgument(const CXXRecordDecl *RD) const;
+
/// Returns how an argument of the given record type should be passed.
virtual RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const = 0;
+ /// Returns true if the implicit 'sret' parameter comes after the implicit
+ /// 'this' parameter of C++ instance methods.
+ virtual bool isSRetParameterAfterThis() const { return false; }
+
/// Find the LLVM type used to represent the given member pointer
/// type.
virtual llvm::Type *
@@ -134,17 +131,15 @@ public:
/// Load a member function from an object and a member function
/// pointer. Apply the this-adjustment and set 'This' to the
/// adjusted value.
- virtual llvm::Value *
- EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
- llvm::Value *&This,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT);
+ virtual llvm::Value *EmitLoadOfMemberFunctionPointer(
+ CodeGenFunction &CGF, const Expr *E, llvm::Value *&This,
+ llvm::Value *MemPtr, const MemberPointerType *MPT);
/// Calculate an l-value from an object and a data member pointer.
- virtual llvm::Value *EmitMemberDataPointerAddress(CodeGenFunction &CGF,
- llvm::Value *Base,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT);
+ virtual llvm::Value *
+ EmitMemberDataPointerAddress(CodeGenFunction &CGF, const Expr *E,
+ llvm::Value *Base, llvm::Value *MemPtr,
+ const MemberPointerType *MPT);
/// Perform a derived-to-base, base-to-derived, or bitcast member
/// pointer conversion.
@@ -212,6 +207,30 @@ public:
llvm::Value *ptr,
QualType type) = 0;
+ virtual llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) = 0;
+
+ virtual bool shouldTypeidBeNullChecked(bool IsDeref,
+ QualType SrcRecordTy) = 0;
+ virtual void EmitBadTypeidCall(CodeGenFunction &CGF) = 0;
+ virtual llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy,
+ llvm::Value *ThisPtr,
+ llvm::Type *StdTypeInfoPtrTy) = 0;
+
+ virtual bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
+ QualType SrcRecordTy) = 0;
+
+ virtual llvm::Value *
+ EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
+ QualType SrcRecordTy, QualType DestTy,
+ QualType DestRecordTy, llvm::BasicBlock *CastEnd) = 0;
+
+ virtual llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF,
+ llvm::Value *Value,
+ QualType SrcRecordTy,
+ QualType DestTy) = 0;
+
+ virtual bool EmitBadCastCall(CodeGenFunction &CGF) = 0;
+
virtual llvm::Value *GetVirtualBaseClassOffset(CodeGenFunction &CGF,
llvm::Value *This,
const CXXRecordDecl *ClassDecl,
@@ -272,23 +291,27 @@ public:
}
/// Perform ABI-specific "this" argument adjustment required prior to
- /// a virtual function call.
- virtual llvm::Value *adjustThisArgumentForVirtualCall(CodeGenFunction &CGF,
- GlobalDecl GD,
- llvm::Value *This) {
+ /// a call of a virtual function.
+ /// The "VirtualCall" argument is true iff the call itself is virtual.
+ virtual llvm::Value *
+ adjustThisArgumentForVirtualFunctionCall(CodeGenFunction &CGF, GlobalDecl GD,
+ llvm::Value *This,
+ bool VirtualCall) {
return This;
}
- /// Build the ABI-specific portion of the parameter list for a
- /// function. This generally involves a 'this' parameter and
- /// possibly some extra data for constructors and destructors.
+ /// Build a parameter variable suitable for 'this'.
+ void buildThisParam(CodeGenFunction &CGF, FunctionArgList &Params);
+
+ /// Insert any ABI-specific implicit parameters into the parameter list for a
+ /// function. This generally involves extra data for constructors and
+ /// destructors.
///
/// ABIs may also choose to override the return type, which has been
/// initialized with the type of 'this' if HasThisReturn(CGF.CurGD) is true or
/// the formal return type of the function otherwise.
- virtual void BuildInstanceFunctionParams(CodeGenFunction &CGF,
- QualType &ResTy,
- FunctionArgList &Params) = 0;
+ virtual void addImplicitStructorParams(CodeGenFunction &CGF, QualType &ResTy,
+ FunctionArgList &Params) = 0;
/// Perform ABI-specific "this" parameter adjustment in a virtual function
/// prologue.
@@ -300,14 +323,20 @@ public:
/// Emit the ABI-specific prolog for the function.
virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0;
- /// Emit the constructor call. Return the function that is called.
- virtual void EmitConstructorCall(CodeGenFunction &CGF,
- const CXXConstructorDecl *D,
- CXXCtorType Type,
- bool ForVirtualBase, bool Delegating,
- llvm::Value *This,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd) = 0;
+ /// Add any ABI-specific implicit arguments needed to call a constructor.
+ ///
+ /// \return The number of args added to the call, which is typically zero or
+ /// one.
+ virtual unsigned
+ addImplicitConstructorArgs(CodeGenFunction &CGF, const CXXConstructorDecl *D,
+ CXXCtorType Type, bool ForVirtualBase,
+ bool Delegating, CallArgList &Args) = 0;
+
+ /// Emit the destructor call.
+ virtual void EmitDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *DD, CXXDtorType Type,
+ bool ForVirtualBase, bool Delegating,
+ llvm::Value *This) = 0;
/// Emits the VTable definitions required for the given record type.
virtual void emitVTableDefinitions(CodeGenVTables &CGVT,
@@ -354,7 +383,8 @@ public:
/// base tables.
virtual void emitVirtualInheritanceTables(const CXXRecordDecl *RD) = 0;
- virtual void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) = 0;
+ virtual void setThunkLinkage(llvm::Function *Thunk, bool ForVTable,
+ GlobalDecl GD, bool ReturnAdjustment) = 0;
virtual llvm::Value *performThisAdjustment(CodeGenFunction &CGF,
llvm::Value *This,
@@ -373,10 +403,6 @@ public:
/// Gets the deleted virtual member call name.
virtual StringRef GetDeletedVirtualCallName() = 0;
- /// \brief Returns true iff static data members that are initialized in the
- /// class definition should have linkonce linkage.
- virtual bool isInlineInitializedStaticDataMemberLinkOnce() { return false; }
-
/**************************** Array cookies ******************************/
/// Returns the extra size required in order to store the array
@@ -479,14 +505,15 @@ public:
/// initialization or non-trivial destruction for thread_local
/// variables, a function to perform the initialization. Otherwise, 0.
virtual void EmitThreadLocalInitFuncs(
- llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
+ ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
llvm::Function *InitFunc);
/// Emit a reference to a non-local thread_local variable (including
/// triggering the initialization of all thread_local variables in its
/// translation unit).
- virtual LValue EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF,
- const DeclRefExpr *DRE);
+ virtual LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF,
+ const VarDecl *VD,
+ QualType LValType);
};
// Create an instance of a C++ ABI class:
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 22f2467021e1..17c3354f93e9 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -26,10 +26,10 @@
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Attributes.h"
+#include "llvm/IR/CallSite.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InlineAsm.h"
-#include "llvm/MC/SubtargetFeature.h"
-#include "llvm/Support/CallSite.h"
+#include "llvm/IR/Intrinsics.h"
#include "llvm/Transforms/Utils/Local.h"
using namespace clang;
using namespace CodeGen;
@@ -79,23 +79,26 @@ const CGFunctionInfo &
CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> FTNP) {
// When translating an unprototyped function type, always use a
// variadic type.
- return arrangeLLVMFunctionInfo(FTNP->getResultType().getUnqualifiedType(),
- None, FTNP->getExtInfo(), RequiredArgs(0));
+ return arrangeLLVMFunctionInfo(FTNP->getReturnType().getUnqualifiedType(),
+ false, None, FTNP->getExtInfo(),
+ RequiredArgs(0));
}
/// Arrange the LLVM function layout for a value of the given function
/// type, on top of any implicit parameters already stored. Use the
/// given ExtInfo instead of the ExtInfo from the function type.
static const CGFunctionInfo &arrangeLLVMFunctionInfo(CodeGenTypes &CGT,
+ bool IsInstanceMethod,
SmallVectorImpl<CanQualType> &prefix,
CanQual<FunctionProtoType> FTP,
FunctionType::ExtInfo extInfo) {
RequiredArgs required = RequiredArgs::forPrototypePlus(FTP, prefix.size());
// FIXME: Kill copy.
- for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
- prefix.push_back(FTP->getArgType(i));
- CanQualType resultType = FTP->getResultType().getUnqualifiedType();
- return CGT.arrangeLLVMFunctionInfo(resultType, prefix, extInfo, required);
+ for (unsigned i = 0, e = FTP->getNumParams(); i != e; ++i)
+ prefix.push_back(FTP->getParamType(i));
+ CanQualType resultType = FTP->getReturnType().getUnqualifiedType();
+ return CGT.arrangeLLVMFunctionInfo(resultType, IsInstanceMethod, prefix,
+ extInfo, required);
}
/// Arrange the argument and result information for a free function (i.e.
@@ -103,7 +106,7 @@ static const CGFunctionInfo &arrangeLLVMFunctionInfo(CodeGenTypes &CGT,
static const CGFunctionInfo &arrangeFreeFunctionType(CodeGenTypes &CGT,
SmallVectorImpl<CanQualType> &prefix,
CanQual<FunctionProtoType> FTP) {
- return arrangeLLVMFunctionInfo(CGT, prefix, FTP, FTP->getExtInfo());
+ return arrangeLLVMFunctionInfo(CGT, false, prefix, FTP, FTP->getExtInfo());
}
/// Arrange the argument and result information for a free function (i.e.
@@ -112,7 +115,7 @@ static const CGFunctionInfo &arrangeCXXMethodType(CodeGenTypes &CGT,
SmallVectorImpl<CanQualType> &prefix,
CanQual<FunctionProtoType> FTP) {
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
- return arrangeLLVMFunctionInfo(CGT, prefix, FTP, extInfo);
+ return arrangeLLVMFunctionInfo(CGT, true, prefix, FTP, extInfo);
}
/// Arrange the argument and result information for a value of the
@@ -123,7 +126,7 @@ CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> FTP) {
return ::arrangeFreeFunctionType(*this, argTypes, FTP);
}
-static CallingConv getCallingConventionForDecl(const Decl *D) {
+static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) {
// Set the appropriate calling convention for the Function.
if (D->hasAttr<StdCallAttr>())
return CC_X86StdCall;
@@ -146,9 +149,32 @@ static CallingConv getCallingConventionForDecl(const Decl *D) {
if (D->hasAttr<IntelOclBiccAttr>())
return CC_IntelOclBicc;
+ if (D->hasAttr<MSABIAttr>())
+ return IsWindows ? CC_C : CC_X86_64Win64;
+
+ if (D->hasAttr<SysVABIAttr>())
+ return IsWindows ? CC_X86_64SysV : CC_C;
+
return CC_C;
}
+static bool isAAPCSVFP(const CGFunctionInfo &FI, const TargetInfo &Target) {
+ switch (FI.getEffectiveCallingConvention()) {
+ case llvm::CallingConv::C:
+ switch (Target.getTriple().getEnvironment()) {
+ case llvm::Triple::EABIHF:
+ case llvm::Triple::GNUEABIHF:
+ return true;
+ default:
+ return false;
+ }
+ case llvm::CallingConv::ARM_AAPCS_VFP:
+ return true;
+ default:
+ return false;
+ }
+}
+
/// Arrange the argument and result information for a call to an
/// unknown C++ non-static member function of the given abstract type.
/// (Zero value of RD means we don't have any meaningful "this" argument type,
@@ -202,18 +228,41 @@ CodeGenTypes::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D,
CanQualType resultType =
TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy;
- TheCXXABI.BuildConstructorSignature(D, ctorKind, resultType, argTypes);
-
CanQual<FunctionProtoType> FTP = GetFormalType(D);
- RequiredArgs required = RequiredArgs::forPrototypePlus(FTP, argTypes.size());
-
// Add the formal parameters.
- for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
- argTypes.push_back(FTP->getArgType(i));
+ for (unsigned i = 0, e = FTP->getNumParams(); i != e; ++i)
+ argTypes.push_back(FTP->getParamType(i));
+
+ TheCXXABI.BuildConstructorSignature(D, ctorKind, resultType, argTypes);
+
+ RequiredArgs required =
+ (D->isVariadic() ? RequiredArgs(argTypes.size()) : RequiredArgs::All);
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
- return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo, required);
+ return arrangeLLVMFunctionInfo(resultType, true, argTypes, extInfo, required);
+}
+
+/// Arrange a call to a C++ method, passing the given arguments.
+const CGFunctionInfo &
+CodeGenTypes::arrangeCXXConstructorCall(const CallArgList &args,
+ const CXXConstructorDecl *D,
+ CXXCtorType CtorKind,
+ unsigned ExtraArgs) {
+ // FIXME: Kill copy.
+ SmallVector<CanQualType, 16> ArgTypes;
+ for (CallArgList::const_iterator i = args.begin(), e = args.end(); i != e;
+ ++i)
+ ArgTypes.push_back(Context.getCanonicalParamType(i->Ty));
+
+ CanQual<FunctionProtoType> FPT = GetFormalType(D);
+ RequiredArgs Required = RequiredArgs::forPrototypePlus(FPT, 1 + ExtraArgs);
+ GlobalDecl GD(D, CtorKind);
+ CanQualType ResultType =
+ TheCXXABI.HasThisReturn(GD) ? ArgTypes.front() : Context.VoidTy;
+
+ FunctionType::ExtInfo Info = FPT->getExtInfo();
+ return arrangeLLVMFunctionInfo(ResultType, true, ArgTypes, Info, Required);
}
/// Arrange the argument and result information for a declaration,
@@ -232,11 +281,11 @@ CodeGenTypes::arrangeCXXDestructor(const CXXDestructorDecl *D,
TheCXXABI.BuildDestructorSignature(D, dtorKind, resultType, argTypes);
CanQual<FunctionProtoType> FTP = GetFormalType(D);
- assert(FTP->getNumArgs() == 0 && "dtor with formal parameters");
+ assert(FTP->getNumParams() == 0 && "dtor with formal parameters");
assert(FTP->isVariadic() == 0 && "dtor with formal parameters");
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
- return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo,
+ return arrangeLLVMFunctionInfo(resultType, true, argTypes, extInfo,
RequiredArgs::All);
}
@@ -256,7 +305,7 @@ CodeGenTypes::arrangeFunctionDeclaration(const FunctionDecl *FD) {
// non-variadic type.
if (isa<FunctionNoProtoType>(FTy)) {
CanQual<FunctionNoProtoType> noProto = FTy.getAs<FunctionNoProtoType>();
- return arrangeLLVMFunctionInfo(noProto->getResultType(), None,
+ return arrangeLLVMFunctionInfo(noProto->getReturnType(), false, None,
noProto->getExtInfo(), RequiredArgs::All);
}
@@ -286,13 +335,13 @@ CodeGenTypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
argTys.push_back(Context.getCanonicalParamType(receiverType));
argTys.push_back(Context.getCanonicalParamType(Context.getObjCSelType()));
// FIXME: Kill copy?
- for (ObjCMethodDecl::param_const_iterator i = MD->param_begin(),
- e = MD->param_end(); i != e; ++i) {
- argTys.push_back(Context.getCanonicalParamType((*i)->getType()));
+ for (const auto *I : MD->params()) {
+ argTys.push_back(Context.getCanonicalParamType(I->getType()));
}
FunctionType::ExtInfo einfo;
- einfo = einfo.withCallingConv(getCallingConventionForDecl(MD));
+ bool IsWindows = getContext().getTargetInfo().getTriple().isOSWindows();
+ einfo = einfo.withCallingConv(getCallingConventionForDecl(MD, IsWindows));
if (getContext().getLangOpts().ObjCAutoRefCount &&
MD->hasAttr<NSReturnsRetainedAttr>())
@@ -301,8 +350,8 @@ CodeGenTypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
RequiredArgs required =
(MD->isVariadic() ? RequiredArgs(argTys.size()) : RequiredArgs::All);
- return arrangeLLVMFunctionInfo(GetReturnType(MD->getResultType()), argTys,
- einfo, required);
+ return arrangeLLVMFunctionInfo(GetReturnType(MD->getReturnType()), false,
+ argTys, einfo, required);
}
const CGFunctionInfo &
@@ -336,7 +385,7 @@ arrangeFreeFunctionLikeCall(CodeGenTypes &CGT,
// extra prefix plus the arguments in the prototype.
if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fnType)) {
if (proto->isVariadic())
- required = RequiredArgs(proto->getNumArgs() + numExtraRequiredArgs);
+ required = RequiredArgs(proto->getNumParams() + numExtraRequiredArgs);
// If we don't have a prototype at all, but we're supposed to
// explicitly use the variadic convention for unprototyped calls,
@@ -348,7 +397,7 @@ arrangeFreeFunctionLikeCall(CodeGenTypes &CGT,
required = RequiredArgs(args.size());
}
- return CGT.arrangeFreeFunctionCall(fnType->getResultType(), args,
+ return CGT.arrangeFreeFunctionCall(fnType->getReturnType(), args,
fnType->getExtInfo(), required);
}
@@ -380,8 +429,8 @@ CodeGenTypes::arrangeFreeFunctionCall(QualType resultType,
for (CallArgList::const_iterator i = args.begin(), e = args.end();
i != e; ++i)
argTypes.push_back(Context.getCanonicalParamType(i->Ty));
- return arrangeLLVMFunctionInfo(GetReturnType(resultType), argTypes, info,
- required);
+ return arrangeLLVMFunctionInfo(GetReturnType(resultType), false, argTypes,
+ info, required);
}
/// Arrange a call to a C++ method, passing the given arguments.
@@ -396,15 +445,13 @@ CodeGenTypes::arrangeCXXMethodCall(const CallArgList &args,
argTypes.push_back(Context.getCanonicalParamType(i->Ty));
FunctionType::ExtInfo info = FPT->getExtInfo();
- return arrangeLLVMFunctionInfo(GetReturnType(FPT->getResultType()),
+ return arrangeLLVMFunctionInfo(GetReturnType(FPT->getReturnType()), true,
argTypes, info, required);
}
-const CGFunctionInfo &
-CodeGenTypes::arrangeFunctionDeclaration(QualType resultType,
- const FunctionArgList &args,
- const FunctionType::ExtInfo &info,
- bool isVariadic) {
+const CGFunctionInfo &CodeGenTypes::arrangeFreeFunctionDeclaration(
+ QualType resultType, const FunctionArgList &args,
+ const FunctionType::ExtInfo &info, bool isVariadic) {
// FIXME: Kill copy.
SmallVector<CanQualType, 16> argTypes;
for (FunctionArgList::const_iterator i = args.begin(), e = args.end();
@@ -413,12 +460,12 @@ CodeGenTypes::arrangeFunctionDeclaration(QualType resultType,
RequiredArgs required =
(isVariadic ? RequiredArgs(args.size()) : RequiredArgs::All);
- return arrangeLLVMFunctionInfo(GetReturnType(resultType), argTypes, info,
+ return arrangeLLVMFunctionInfo(GetReturnType(resultType), false, argTypes, info,
required);
}
const CGFunctionInfo &CodeGenTypes::arrangeNullaryFunction() {
- return arrangeLLVMFunctionInfo(getContext().VoidTy, None,
+ return arrangeLLVMFunctionInfo(getContext().VoidTy, false, None,
FunctionType::ExtInfo(), RequiredArgs::All);
}
@@ -427,6 +474,7 @@ const CGFunctionInfo &CodeGenTypes::arrangeNullaryFunction() {
/// above functions ultimately defer to.
const CGFunctionInfo &
CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType,
+ bool IsInstanceMethod,
ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
RequiredArgs required) {
@@ -440,15 +488,17 @@ CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType,
// Lookup or create unique function info.
llvm::FoldingSetNodeID ID;
- CGFunctionInfo::Profile(ID, info, required, resultType, argTypes);
+ CGFunctionInfo::Profile(ID, IsInstanceMethod, info, required, resultType,
+ argTypes);
- void *insertPos = 0;
+ void *insertPos = nullptr;
CGFunctionInfo *FI = FunctionInfos.FindNodeOrInsertPos(ID, insertPos);
if (FI)
return *FI;
// Construct the function info. We co-allocate the ArgInfos.
- FI = CGFunctionInfo::create(CC, info, resultType, argTypes, required);
+ FI = CGFunctionInfo::create(CC, IsInstanceMethod, info, resultType, argTypes,
+ required);
FunctionInfos.InsertNode(FI, insertPos);
bool inserted = FunctionsBeingProcessed.insert(FI); (void)inserted;
@@ -461,13 +511,12 @@ CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType,
// them are direct or extend without a specified coerce type, specify the
// default now.
ABIArgInfo &retInfo = FI->getReturnInfo();
- if (retInfo.canHaveCoerceToType() && retInfo.getCoerceToType() == 0)
+ if (retInfo.canHaveCoerceToType() && retInfo.getCoerceToType() == nullptr)
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(ConvertType(I->type));
+ for (auto &I : FI->arguments())
+ if (I.info.canHaveCoerceToType() && I.info.getCoerceToType() == nullptr)
+ I.info.setCoerceToType(ConvertType(I.type));
bool erased = FunctionsBeingProcessed.erase(FI); (void)erased;
assert(erased && "Not in set?");
@@ -476,6 +525,7 @@ CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType,
}
CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC,
+ bool IsInstanceMethod,
const FunctionType::ExtInfo &info,
CanQualType resultType,
ArrayRef<CanQualType> argTypes,
@@ -486,11 +536,13 @@ CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC,
FI->CallingConvention = llvmCC;
FI->EffectiveCallingConvention = llvmCC;
FI->ASTCallingConvention = info.getCC();
+ FI->InstanceMethod = IsInstanceMethod;
FI->NoReturn = info.getNoReturn();
FI->ReturnsRetained = info.getProducesResult();
FI->Required = required;
FI->HasRegParm = info.getHasRegParm();
FI->RegParm = info.getRegParm();
+ FI->ArgStruct = nullptr;
FI->NumArgs = argTypes.size();
FI->getArgsBuffer()[0].type = resultType;
for (unsigned i = 0, e = argTypes.size(); i != e; ++i)
@@ -513,12 +565,10 @@ void CodeGenTypes::GetExpandedTypes(QualType type,
if (RD->isUnion()) {
// Unions can be here only in degenerative cases - all the fields are same
// after flattening. Thus we have to use the "largest" field.
- const FieldDecl *LargestFD = 0;
+ const FieldDecl *LargestFD = nullptr;
CharUnits UnionSize = CharUnits::Zero();
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
- const FieldDecl *FD = *i;
+ for (const auto *FD : RD->fields()) {
assert(!FD->isBitField() &&
"Cannot expand structure with bit-field members.");
CharUnits FieldSize = getContext().getTypeSizeInChars(FD->getType());
@@ -530,11 +580,10 @@ void CodeGenTypes::GetExpandedTypes(QualType type,
if (LargestFD)
GetExpandedTypes(LargestFD->getType(), expandedTypes);
} else {
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
- assert(!i->isBitField() &&
+ for (const auto *I : RD->fields()) {
+ assert(!I->isBitField() &&
"Cannot expand structure with bit-field members.");
- GetExpandedTypes(i->getType(), expandedTypes);
+ GetExpandedTypes(I->getType(), expandedTypes);
}
}
} else if (const ComplexType *CT = type->getAs<ComplexType>()) {
@@ -564,12 +613,10 @@ CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV,
if (RD->isUnion()) {
// Unions can be here only in degenerative cases - all the fields are same
// after flattening. Thus we have to use the "largest" field.
- const FieldDecl *LargestFD = 0;
+ const FieldDecl *LargestFD = nullptr;
CharUnits UnionSize = CharUnits::Zero();
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
- const FieldDecl *FD = *i;
+ for (const auto *FD : RD->fields()) {
assert(!FD->isBitField() &&
"Cannot expand structure with bit-field members.");
CharUnits FieldSize = getContext().getTypeSizeInChars(FD->getType());
@@ -584,9 +631,7 @@ CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV,
AI = ExpandTypeFromArgs(LargestFD->getType(), SubLV, AI);
}
} else {
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
- FieldDecl *FD = *i;
+ for (const auto *FD : RD->fields()) {
QualType FT = FD->getType();
// FIXME: What are the right qualifiers here?
@@ -672,8 +717,9 @@ static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val,
if (DL.isBigEndian()) {
// Preserve the high bits on big-endian targets.
// That is what memory coercion does.
- uint64_t SrcSize = DL.getTypeAllocSizeInBits(Val->getType());
- uint64_t DstSize = DL.getTypeAllocSizeInBits(DestIntTy);
+ uint64_t SrcSize = DL.getTypeSizeInBits(Val->getType());
+ uint64_t DstSize = DL.getTypeSizeInBits(DestIntTy);
+
if (SrcSize > DstSize) {
Val = CGF.Builder.CreateLShr(Val, SrcSize - DstSize, "coerce.highbits");
Val = CGF.Builder.CreateTrunc(Val, DestIntTy, "coerce.val.ii");
@@ -850,6 +896,11 @@ bool CodeGenModule::ReturnTypeUsesSRet(const CGFunctionInfo &FI) {
return FI.getReturnInfo().isIndirect();
}
+bool CodeGenModule::ReturnSlotInterferesWithArgs(const CGFunctionInfo &FI) {
+ return ReturnTypeUsesSRet(FI) &&
+ getTargetCodeGenInfo().doesReturnSlotInterfereWithArgs();
+}
+
bool CodeGenModule::ReturnTypeUsesFPRet(QualType ResultType) {
if (const BuiltinType *BT = ResultType->getAs<BuiltinType>()) {
switch (BT->getKind()) {
@@ -889,8 +940,9 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
bool Inserted = FunctionsBeingProcessed.insert(&FI); (void)Inserted;
assert(Inserted && "Recursively being processed?");
+ bool SwapThisWithSRet = false;
SmallVector<llvm::Type*, 8> argTypes;
- llvm::Type *resultType = 0;
+ llvm::Type *resultType = nullptr;
const ABIArgInfo &retAI = FI.getReturnInfo();
switch (retAI.getKind()) {
@@ -902,6 +954,18 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
resultType = retAI.getCoerceToType();
break;
+ case ABIArgInfo::InAlloca:
+ if (retAI.getInAllocaSRet()) {
+ // sret things on win32 aren't void, they return the sret pointer.
+ QualType ret = FI.getReturnType();
+ llvm::Type *ty = ConvertType(ret);
+ unsigned addressSpace = Context.getTargetAddressSpace(ret);
+ resultType = llvm::PointerType::get(ty, addressSpace);
+ } else {
+ resultType = llvm::Type::getVoidTy(getLLVMContext());
+ }
+ break;
+
case ABIArgInfo::Indirect: {
assert(!retAI.getIndirectAlign() && "Align unused on indirect return.");
resultType = llvm::Type::getVoidTy(getLLVMContext());
@@ -910,6 +974,8 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
llvm::Type *ty = ConvertType(ret);
unsigned addressSpace = Context.getTargetAddressSpace(ret);
argTypes.push_back(llvm::PointerType::get(ty, addressSpace));
+
+ SwapThisWithSRet = retAI.isSRetAfterThis();
break;
}
@@ -934,6 +1000,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
switch (argAI.getKind()) {
case ABIArgInfo::Ignore:
+ case ABIArgInfo::InAlloca:
break;
case ABIArgInfo::Indirect: {
@@ -948,8 +1015,11 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
// 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.
+ // We cannot do this for functions using the AAPCS calling convention,
+ // as structures are treated differently by that calling convention.
llvm::Type *argType = argAI.getCoerceToType();
- if (llvm::StructType *st = dyn_cast<llvm::StructType>(argType)) {
+ llvm::StructType *st = dyn_cast<llvm::StructType>(argType);
+ if (st && !isAAPCSVFP(FI, getTarget())) {
for (unsigned i = 0, e = st->getNumElements(); i != e; ++i)
argTypes.push_back(st->getElementType(i));
} else {
@@ -964,6 +1034,13 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
}
}
+ // Add the inalloca struct as the last parameter type.
+ if (llvm::StructType *ArgStruct = FI.getArgStruct())
+ argTypes.push_back(ArgStruct->getPointerTo());
+
+ if (SwapThisWithSRet)
+ std::swap(argTypes[0], argTypes[1]);
+
bool Erased = FunctionsBeingProcessed.erase(&FI); (void)Erased;
assert(Erased && "Not in set?");
@@ -1006,6 +1083,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
if (TargetDecl->hasAttr<NoReturnAttr>())
FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
+ if (TargetDecl->hasAttr<NoDuplicateAttr>())
+ FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate);
if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
const FunctionProtoType *FPT = Fn->getType()->getAs<FunctionProtoType>();
@@ -1028,6 +1107,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
}
if (TargetDecl->hasAttr<MallocAttr>())
RetAttrs.addAttribute(llvm::Attribute::NoAlias);
+ if (TargetDecl->hasAttr<ReturnsNonNullAttr>())
+ RetAttrs.addAttribute(llvm::Attribute::NonNull);
}
if (CodeGenOpts.OptimizeSize)
@@ -1038,6 +1119,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
FuncAttrs.addAttribute(llvm::Attribute::NoRedZone);
if (CodeGenOpts.NoImplicitFloat)
FuncAttrs.addAttribute(llvm::Attribute::NoImplicitFloat);
+ if (CodeGenOpts.EnableSegmentedStacks &&
+ !(TargetDecl && TargetDecl->hasAttr<NoSplitStackAttr>()))
+ FuncAttrs.addAttribute("split-stack");
if (AttrOnCallSite) {
// Attributes that should go on the call site only.
@@ -1074,6 +1158,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
QualType RetTy = FI.getReturnType();
unsigned Index = 1;
+ bool SwapThisWithSRet = false;
const ABIArgInfo &RetAI = FI.getReturnInfo();
switch (RetAI.getKind()) {
case ABIArgInfo::Extend:
@@ -1089,15 +1174,24 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
case ABIArgInfo::Ignore:
break;
+ case ABIArgInfo::InAlloca: {
+ // inalloca disables readnone and readonly
+ FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
+ .removeAttribute(llvm::Attribute::ReadNone);
+ break;
+ }
+
case ABIArgInfo::Indirect: {
llvm::AttrBuilder SRETAttrs;
SRETAttrs.addAttribute(llvm::Attribute::StructRet);
if (RetAI.getInReg())
SRETAttrs.addAttribute(llvm::Attribute::InReg);
- PAL.push_back(llvm::
- AttributeSet::get(getLLVMContext(), Index, SRETAttrs));
+ SwapThisWithSRet = RetAI.isSRetAfterThis();
+ PAL.push_back(llvm::AttributeSet::get(
+ getLLVMContext(), SwapThisWithSRet ? 2 : Index, SRETAttrs));
- ++Index;
+ if (!SwapThisWithSRet)
+ ++Index;
// sret disables readnone and readonly
FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
.removeAttribute(llvm::Attribute::ReadNone);
@@ -1108,18 +1202,31 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
llvm_unreachable("Invalid ABI kind for return argument");
}
+ if (const auto *RefTy = RetTy->getAs<ReferenceType>()) {
+ QualType PTy = RefTy->getPointeeType();
+ if (!PTy->isIncompleteType() && PTy->isConstantSizeType())
+ RetAttrs.addDereferenceableAttr(getContext().getTypeSizeInChars(PTy)
+ .getQuantity());
+ else if (getContext().getTargetAddressSpace(PTy) == 0)
+ RetAttrs.addAttribute(llvm::Attribute::NonNull);
+ }
+
if (RetAttrs.hasAttributes())
PAL.push_back(llvm::
AttributeSet::get(getLLVMContext(),
llvm::AttributeSet::ReturnIndex,
RetAttrs));
- for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
- ie = FI.arg_end(); it != ie; ++it) {
- QualType ParamType = it->type;
- const ABIArgInfo &AI = it->info;
+ for (const auto &I : FI.arguments()) {
+ QualType ParamType = I.type;
+ const ABIArgInfo &AI = I.info;
llvm::AttrBuilder Attrs;
+ // Skip over the sret parameter when it comes second. We already handled it
+ // above.
+ if (Index == 2 && SwapThisWithSRet)
+ ++Index;
+
if (AI.getPaddingType()) {
if (AI.getPaddingInReg())
PAL.push_back(llvm::AttributeSet::get(getLLVMContext(), Index,
@@ -1138,14 +1245,15 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
else if (ParamType->isUnsignedIntegerOrEnumerationType())
Attrs.addAttribute(llvm::Attribute::ZExt);
// FALL THROUGH
- case ABIArgInfo::Direct:
+ case ABIArgInfo::Direct: {
if (AI.getInReg())
Attrs.addAttribute(llvm::Attribute::InReg);
// FIXME: handle sseregparm someday...
- if (llvm::StructType *STy =
- dyn_cast<llvm::StructType>(AI.getCoerceToType())) {
+ llvm::StructType *STy =
+ dyn_cast<llvm::StructType>(AI.getCoerceToType());
+ if (!isAAPCSVFP(FI, getTarget()) && STy) {
unsigned Extra = STy->getNumElements()-1; // 1 will be added below.
if (Attrs.hasAttributes())
for (unsigned I = 0; I < Extra; ++I)
@@ -1154,7 +1262,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
Index += Extra;
}
break;
-
+ }
case ABIArgInfo::Indirect:
if (AI.getInReg())
Attrs.addAttribute(llvm::Attribute::InReg);
@@ -1173,6 +1281,13 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
// Skip increment, no matching LLVM parameter.
continue;
+ case ABIArgInfo::InAlloca:
+ // inalloca disables readnone and readonly.
+ FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
+ .removeAttribute(llvm::Attribute::ReadNone);
+ // Skip increment, no matching LLVM parameter.
+ continue;
+
case ABIArgInfo::Expand: {
SmallVector<llvm::Type*, 8> types;
// FIXME: This is rather inefficient. Do we ever actually need to do
@@ -1184,10 +1299,27 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
}
}
+ if (const auto *RefTy = ParamType->getAs<ReferenceType>()) {
+ QualType PTy = RefTy->getPointeeType();
+ if (!PTy->isIncompleteType() && PTy->isConstantSizeType())
+ Attrs.addDereferenceableAttr(getContext().getTypeSizeInChars(PTy)
+ .getQuantity());
+ else if (getContext().getTargetAddressSpace(PTy) == 0)
+ Attrs.addAttribute(llvm::Attribute::NonNull);
+ }
+
if (Attrs.hasAttributes())
PAL.push_back(llvm::AttributeSet::get(getLLVMContext(), Index, Attrs));
++Index;
}
+
+ // Add the inalloca attribute to the trailing inalloca parameter if present.
+ if (FI.usesInAlloca()) {
+ llvm::AttrBuilder Attrs;
+ Attrs.addAttribute(llvm::Attribute::InAlloca);
+ PAL.push_back(llvm::AttributeSet::get(getLLVMContext(), Index, Attrs));
+ }
+
if (FuncAttrs.hasAttributes())
PAL.push_back(llvm::
AttributeSet::get(getLLVMContext(),
@@ -1224,7 +1356,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// return statements.
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurCodeDecl)) {
if (FD->hasImplicitReturnZero()) {
- QualType RetTy = FD->getResultType().getUnqualifiedType();
+ QualType RetTy = FD->getReturnType().getUnqualifiedType();
llvm::Type* LLVMTy = CGM.getTypes().ConvertType(RetTy);
llvm::Constant* Zero = llvm::Constant::getNullValue(LLVMTy);
Builder.CreateStore(Zero, ReturnValue);
@@ -1237,15 +1369,48 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// Emit allocs for param decls. Give the LLVM Argument nodes names.
llvm::Function::arg_iterator AI = Fn->arg_begin();
- // Name the struct return argument.
- if (CGM.ReturnTypeUsesSRet(FI)) {
+ // If we're using inalloca, all the memory arguments are GEPs off of the last
+ // parameter, which is a pointer to the complete memory area.
+ llvm::Value *ArgStruct = nullptr;
+ if (FI.usesInAlloca()) {
+ llvm::Function::arg_iterator EI = Fn->arg_end();
+ --EI;
+ ArgStruct = EI;
+ assert(ArgStruct->getType() == FI.getArgStruct()->getPointerTo());
+ }
+
+ // Name the struct return parameter, which can come first or second.
+ const ABIArgInfo &RetAI = FI.getReturnInfo();
+ bool SwapThisWithSRet = false;
+ if (RetAI.isIndirect()) {
+ SwapThisWithSRet = RetAI.isSRetAfterThis();
+ if (SwapThisWithSRet)
+ ++AI;
AI->setName("agg.result");
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
- AI->getArgNo() + 1,
+ AI->addAttr(llvm::AttributeSet::get(getLLVMContext(), AI->getArgNo() + 1,
llvm::Attribute::NoAlias));
- ++AI;
+ if (SwapThisWithSRet)
+ --AI; // Go back to the beginning for 'this'.
+ else
+ ++AI; // Skip the sret parameter.
}
+ // Get the function-level nonnull attribute if it exists.
+ const NonNullAttr *NNAtt =
+ CurCodeDecl ? CurCodeDecl->getAttr<NonNullAttr>() : nullptr;
+
+ // Track if we received the parameter as a pointer (indirect, byval, or
+ // inalloca). If already have a pointer, EmitParmDecl doesn't need to copy it
+ // into a local alloca for us.
+ enum ValOrPointer { HaveValue = 0, HavePointer = 1 };
+ typedef llvm::PointerIntPair<llvm::Value *, 1> ValueAndIsPtr;
+ SmallVector<ValueAndIsPtr, 16> ArgVals;
+ ArgVals.reserve(Args.size());
+
+ // Create a pointer value for every parameter declaration. This usually
+ // entails copying one or more LLVM IR arguments into an alloca. Don't push
+ // any cleanups or do anything that might unwind. We do that separately, so
+ // we can push the cleanups in the correct order for the ABI.
assert(FI.arg_size() == Args.size() &&
"Mismatch between function signature & arguments.");
unsigned ArgNo = 1;
@@ -1264,6 +1429,13 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
++AI;
switch (ArgI.getKind()) {
+ case ABIArgInfo::InAlloca: {
+ llvm::Value *V = Builder.CreateStructGEP(
+ ArgStruct, ArgI.getInAllocaFieldIndex(), Arg->getName());
+ ArgVals.push_back(ValueAndIsPtr(V, HavePointer));
+ continue; // Don't increment AI!
+ }
+
case ABIArgInfo::Indirect: {
llvm::Value *V = AI;
@@ -1290,6 +1462,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
false);
V = AlignedTemp;
}
+ ArgVals.push_back(ValueAndIsPtr(V, HavePointer));
} else {
// Load scalar value from indirect argument.
CharUnits Alignment = getContext().getTypeAlignInChars(Ty);
@@ -1298,8 +1471,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
if (isPromoted)
V = emitArgumentDemotion(*this, Arg, V);
+ ArgVals.push_back(ValueAndIsPtr(V, HaveValue));
}
- EmitParmDecl(*Arg, V, ArgNo);
break;
}
@@ -1313,6 +1486,49 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
assert(AI != Fn->arg_end() && "Argument mismatch!");
llvm::Value *V = AI;
+ if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(Arg)) {
+ if ((NNAtt && NNAtt->isNonNull(PVD->getFunctionScopeIndex())) ||
+ PVD->hasAttr<NonNullAttr>())
+ AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
+ AI->getArgNo() + 1,
+ llvm::Attribute::NonNull));
+
+ QualType OTy = PVD->getOriginalType();
+ if (const auto *ArrTy =
+ getContext().getAsConstantArrayType(OTy)) {
+ // A C99 array parameter declaration with the static keyword also
+ // indicates dereferenceability, and if the size is constant we can
+ // use the dereferenceable attribute (which requires the size in
+ // bytes).
+ if (ArrTy->getSizeModifier() == ArrayType::Static) {
+ QualType ETy = ArrTy->getElementType();
+ uint64_t ArrSize = ArrTy->getSize().getZExtValue();
+ if (!ETy->isIncompleteType() && ETy->isConstantSizeType() &&
+ ArrSize) {
+ llvm::AttrBuilder Attrs;
+ Attrs.addDereferenceableAttr(
+ getContext().getTypeSizeInChars(ETy).getQuantity()*ArrSize);
+ AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
+ AI->getArgNo() + 1, Attrs));
+ } else if (getContext().getTargetAddressSpace(ETy) == 0) {
+ AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
+ AI->getArgNo() + 1,
+ llvm::Attribute::NonNull));
+ }
+ }
+ } else if (const auto *ArrTy =
+ getContext().getAsVariableArrayType(OTy)) {
+ // For C99 VLAs with the static keyword, we don't know the size so
+ // we can't use the dereferenceable attribute, but in addrspace(0)
+ // we know that it must be nonnull.
+ if (ArrTy->getSizeModifier() == VariableArrayType::Static &&
+ !getContext().getTargetAddressSpace(ArrTy->getElementType()))
+ AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
+ AI->getArgNo() + 1,
+ llvm::Attribute::NonNull));
+ }
+ }
+
if (Arg->getType().isRestrictQualified())
AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
AI->getArgNo() + 1,
@@ -1340,7 +1556,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
if (V->getType() != LTy)
V = Builder.CreateBitCast(V, LTy);
- EmitParmDecl(*Arg, V, ArgNo);
+ ArgVals.push_back(ValueAndIsPtr(V, HaveValue));
break;
}
@@ -1368,8 +1584,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// If the coerce-to type is a first class aggregate, we flatten it and
// pass the elements. Either way is semantically identical, but fast-isel
// and the optimizer generally likes scalar values better than FCAs.
+ // We cannot do this for functions using the AAPCS calling convention,
+ // as structures are treated differently by that calling convention.
llvm::StructType *STy = dyn_cast<llvm::StructType>(ArgI.getCoerceToType());
- if (STy && STy->getNumElements() > 1) {
+ if (!isAAPCSVFP(FI, getTarget()) && STy && STy->getNumElements() > 1) {
uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(STy);
llvm::Type *DstTy =
cast<llvm::PointerType>(Ptr->getType())->getElementType();
@@ -1412,8 +1630,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
V = EmitLoadOfScalar(V, false, AlignmentToUse, Ty, Arg->getLocStart());
if (isPromoted)
V = emitArgumentDemotion(*this, Arg, V);
+ ArgVals.push_back(ValueAndIsPtr(V, HaveValue));
+ } else {
+ ArgVals.push_back(ValueAndIsPtr(V, HavePointer));
}
- EmitParmDecl(*Arg, V, ArgNo);
continue; // Skip ++AI increment, already done.
}
@@ -1426,7 +1646,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
Alloca->setAlignment(Align.getQuantity());
LValue LV = MakeAddrLValue(Alloca, Ty, Align);
llvm::Function::arg_iterator End = ExpandTypeFromArgs(Ty, LV, AI);
- EmitParmDecl(*Arg, Alloca, ArgNo);
+ ArgVals.push_back(ValueAndIsPtr(Alloca, HavePointer));
// Name the arguments used in expansion and increment AI.
unsigned Index = 0;
@@ -1437,19 +1657,36 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
case ABIArgInfo::Ignore:
// Initialize the local variable appropriately.
- if (!hasScalarEvaluationKind(Ty))
- EmitParmDecl(*Arg, CreateMemTemp(Ty), ArgNo);
- else
- EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType())),
- ArgNo);
+ if (!hasScalarEvaluationKind(Ty)) {
+ ArgVals.push_back(ValueAndIsPtr(CreateMemTemp(Ty), HavePointer));
+ } else {
+ llvm::Value *U = llvm::UndefValue::get(ConvertType(Arg->getType()));
+ ArgVals.push_back(ValueAndIsPtr(U, HaveValue));
+ }
// Skip increment, no matching LLVM parameter.
continue;
}
++AI;
+
+ if (ArgNo == 1 && SwapThisWithSRet)
+ ++AI; // Skip the sret parameter.
}
+
+ if (FI.usesInAlloca())
+ ++AI;
assert(AI == Fn->arg_end() && "Argument mismatch!");
+
+ if (getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
+ for (int I = Args.size() - 1; I >= 0; --I)
+ EmitParmDecl(*Args[I], ArgVals[I].getPointer(), ArgVals[I].getInt(),
+ I + 1);
+ } else {
+ for (unsigned I = 0, E = Args.size(); I != E; ++I)
+ EmitParmDecl(*Args[I], ArgVals[I].getPointer(), ArgVals[I].getInt(),
+ I + 1);
+ }
}
static void eraseUnusedBitCasts(llvm::Instruction *insn) {
@@ -1468,8 +1705,8 @@ 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;
+ if (BB->empty()) return nullptr;
+ if (&BB->back() != result) return nullptr;
llvm::Type *resultType = result->getType();
@@ -1487,7 +1724,7 @@ static llvm::Value *tryEmitFusedAutoreleaseOfResult(CodeGenFunction &CGF,
// Require the generator to be immediately followed by the cast.
if (generator->getNextNode() != bitcast)
- return 0;
+ return nullptr;
insnsToKill.push_back(bitcast);
}
@@ -1497,7 +1734,7 @@ static llvm::Value *tryEmitFusedAutoreleaseOfResult(CodeGenFunction &CGF,
// or
// %generator = call i8* @objc_retainAutoreleasedReturnValue(i8* %originalResult)
llvm::CallInst *call = dyn_cast<llvm::CallInst>(generator);
- if (!call) return 0;
+ if (!call) return nullptr;
bool doRetainAutorelease;
@@ -1525,7 +1762,7 @@ static llvm::Value *tryEmitFusedAutoreleaseOfResult(CodeGenFunction &CGF,
insnsToKill.push_back(prev);
}
} else {
- return 0;
+ return nullptr;
}
result = call->getArgOperand(0);
@@ -1558,16 +1795,16 @@ static llvm::Value *tryRemoveRetainOfSelf(CodeGenFunction &CGF,
// This is only applicable to a method with an immutable 'self'.
const ObjCMethodDecl *method =
dyn_cast_or_null<ObjCMethodDecl>(CGF.CurCodeDecl);
- if (!method) return 0;
+ if (!method) return nullptr;
const VarDecl *self = method->getSelfDecl();
- if (!self->getType().isConstQualified()) return 0;
+ if (!self->getType().isConstQualified()) return nullptr;
// Look for a retain call.
llvm::CallInst *retainCall =
dyn_cast<llvm::CallInst>(result->stripPointerCasts());
if (!retainCall ||
retainCall->getCalledValue() != CGF.CGM.getARCEntrypoints().objc_retain)
- return 0;
+ return nullptr;
// Look for an ordinary load of 'self'.
llvm::Value *retainedValue = retainCall->getArgOperand(0);
@@ -1575,7 +1812,7 @@ static llvm::Value *tryRemoveRetainOfSelf(CodeGenFunction &CGF,
dyn_cast<llvm::LoadInst>(retainedValue->stripPointerCasts());
if (!load || load->isAtomic() || load->isVolatile() ||
load->getPointerOperand() != CGF.GetAddrOfLocalVar(self))
- return 0;
+ return nullptr;
// Okay! Burn it all down. This relies for correctness on the
// assumption that the retain is emitted as part of the return and
@@ -1617,17 +1854,17 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) {
// with noreturn cleanups.
if (!CGF.ReturnValue->hasOneUse()) {
llvm::BasicBlock *IP = CGF.Builder.GetInsertBlock();
- if (IP->empty()) return 0;
+ if (IP->empty()) return nullptr;
llvm::StoreInst *store = dyn_cast<llvm::StoreInst>(&IP->back());
- if (!store) return 0;
- if (store->getPointerOperand() != CGF.ReturnValue) return 0;
+ if (!store) return nullptr;
+ if (store->getPointerOperand() != CGF.ReturnValue) return nullptr;
assert(!store->isAtomic() && !store->isVolatile()); // see below
return store;
}
llvm::StoreInst *store =
- dyn_cast<llvm::StoreInst>(CGF.ReturnValue->use_back());
- if (!store) return 0;
+ dyn_cast<llvm::StoreInst>(CGF.ReturnValue->user_back());
+ if (!store) return nullptr;
// These aren't actually possible for non-coerced returns, and we
// only care about non-coerced returns on this code path.
@@ -1639,7 +1876,7 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) {
llvm::BasicBlock *IP = CGF.Builder.GetInsertBlock();
while (IP != StoreBB) {
if (!(IP = IP->getSinglePredecessor()))
- return 0;
+ return nullptr;
}
// Okay, the store's basic block dominates the insertion point; we
@@ -1651,25 +1888,41 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
bool EmitRetDbgLoc,
SourceLocation EndLoc) {
// Functions with no result always return void.
- if (ReturnValue == 0) {
+ if (!ReturnValue) {
Builder.CreateRetVoid();
return;
}
llvm::DebugLoc RetDbgLoc;
- llvm::Value *RV = 0;
+ llvm::Value *RV = nullptr;
QualType RetTy = FI.getReturnType();
const ABIArgInfo &RetAI = FI.getReturnInfo();
switch (RetAI.getKind()) {
+ case ABIArgInfo::InAlloca:
+ // Aggregrates get evaluated directly into the destination. Sometimes we
+ // need to return the sret value in a register, though.
+ assert(hasAggregateEvaluationKind(RetTy));
+ if (RetAI.getInAllocaSRet()) {
+ llvm::Function::arg_iterator EI = CurFn->arg_end();
+ --EI;
+ llvm::Value *ArgStruct = EI;
+ llvm::Value *SRet =
+ Builder.CreateStructGEP(ArgStruct, RetAI.getInAllocaFieldIndex());
+ RV = Builder.CreateLoad(SRet, "sret");
+ }
+ break;
+
case ABIArgInfo::Indirect: {
+ auto AI = CurFn->arg_begin();
+ if (RetAI.isSRetAfterThis())
+ ++AI;
switch (getEvaluationKind(RetTy)) {
case TEK_Complex: {
ComplexPairTy RT =
EmitLoadOfComplex(MakeNaturalAlignAddrLValue(ReturnValue, RetTy),
EndLoc);
- EmitStoreOfComplex(RT,
- MakeNaturalAlignAddrLValue(CurFn->arg_begin(), RetTy),
+ EmitStoreOfComplex(RT, MakeNaturalAlignAddrLValue(AI, RetTy),
/*isInit*/ true);
break;
}
@@ -1678,7 +1931,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
break;
case TEK_Scalar:
EmitStoreOfScalar(Builder.CreateLoad(ReturnValue),
- MakeNaturalAlignAddrLValue(CurFn->arg_begin(), RetTy),
+ MakeNaturalAlignAddrLValue(AI, RetTy),
/*isInit*/ true);
break;
}
@@ -1707,7 +1960,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
// If that was the only use of the return value, nuke it as well now.
if (ReturnValue->use_empty() && isa<llvm::AllocaInst>(ReturnValue)) {
cast<llvm::AllocaInst>(ReturnValue)->eraseFromParent();
- ReturnValue = 0;
+ ReturnValue = nullptr;
}
// Otherwise, we have to do a simple load.
@@ -1750,6 +2003,25 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
Ret->setDebugLoc(RetDbgLoc);
}
+static bool isInAllocaArgument(CGCXXABI &ABI, QualType type) {
+ const CXXRecordDecl *RD = type->getAsCXXRecordDecl();
+ return RD && ABI.getRecordArgABI(RD) == CGCXXABI::RAA_DirectInMemory;
+}
+
+static AggValueSlot createPlaceholderSlot(CodeGenFunction &CGF, QualType Ty) {
+ // FIXME: Generate IR in one pass, rather than going back and fixing up these
+ // placeholders.
+ llvm::Type *IRTy = CGF.ConvertTypeForMem(Ty);
+ llvm::Value *Placeholder =
+ llvm::UndefValue::get(IRTy->getPointerTo()->getPointerTo());
+ Placeholder = CGF.Builder.CreateLoad(Placeholder);
+ return AggValueSlot::forAddr(Placeholder, CharUnits::Zero(),
+ Ty.getQualifiers(),
+ AggValueSlot::IsNotDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
+}
+
void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
const VarDecl *param,
SourceLocation loc) {
@@ -1773,6 +2045,20 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
return args.add(RValue::get(Builder.CreateLoad(local)), type);
}
+ if (isInAllocaArgument(CGM.getCXXABI(), type)) {
+ AggValueSlot Slot = createPlaceholderSlot(*this, type);
+ Slot.setExternallyDestructed();
+
+ // FIXME: Either emit a copy constructor call, or figure out how to do
+ // guaranteed tail calls with perfect forwarding in LLVM.
+ CGM.ErrorUnsupported(param, "non-trivial argument copy for thunk");
+ EmitNullInitialization(Slot.getAddr(), type);
+
+ RValue RV = Slot.asRValue();
+ args.add(RV, type);
+ return;
+ }
+
args.add(convertTempToRValue(local, type, loc), type);
}
@@ -1792,7 +2078,7 @@ static void emitWriteback(CodeGenFunction &CGF,
assert(!isProvablyNull(srcAddr) &&
"shouldn't have writeback for provably null argument");
- llvm::BasicBlock *contBB = 0;
+ llvm::BasicBlock *contBB = nullptr;
// If the argument wasn't provably non-null, we need to null check
// before doing the store.
@@ -1852,14 +2138,13 @@ static void emitWriteback(CodeGenFunction &CGF,
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);
+ for (const auto &I : args.writebacks())
+ emitWriteback(CGF, I);
}
static void deactivateArgCleanupsBeforeCall(CodeGenFunction &CGF,
const CallArgList &CallArgs) {
- assert(CGF.getTarget().getCXXABI().isArgumentDestroyedByCallee());
+ assert(CGF.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee());
ArrayRef<CallArgList::CallArgCleanup> Cleanups =
CallArgs.getCleanupsToDeactivate();
// Iterate in reverse to increase the likelihood of popping the cleanup.
@@ -1874,7 +2159,7 @@ static const Expr *maybeGetUnaryAddrOfOperand(const Expr *E) {
if (const UnaryOperator *uop = dyn_cast<UnaryOperator>(E->IgnoreParens()))
if (uop->getOpcode() == UO_AddrOf)
return uop->getSubExpr();
- return 0;
+ return nullptr;
}
/// Emit an argument that's being passed call-by-writeback. That is,
@@ -1928,9 +2213,9 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
cast<llvm::PointerType>(destType->getElementType()));
CGF.Builder.CreateStore(null, temp);
}
-
- llvm::BasicBlock *contBB = 0;
- llvm::BasicBlock *originBB = 0;
+
+ llvm::BasicBlock *contBB = nullptr;
+ llvm::BasicBlock *originBB = nullptr;
// If the address is *not* known to be non-null, we need to switch.
llvm::Value *finalArgument;
@@ -1957,7 +2242,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
}
}
- llvm::Value *valueToUse = 0;
+ llvm::Value *valueToUse = nullptr;
// Perform a copy if necessary.
if (shouldCopy) {
@@ -2004,6 +2289,99 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
args.add(RValue::get(finalArgument), CRE->getType());
}
+void CallArgList::allocateArgumentMemory(CodeGenFunction &CGF) {
+ assert(!StackBase && !StackCleanup.isValid());
+
+ // Save the stack.
+ llvm::Function *F = CGF.CGM.getIntrinsic(llvm::Intrinsic::stacksave);
+ StackBase = CGF.Builder.CreateCall(F, "inalloca.save");
+
+ // Control gets really tied up in landing pads, so we have to spill the
+ // stacksave to an alloca to avoid violating SSA form.
+ // TODO: This is dead if we never emit the cleanup. We should create the
+ // alloca and store lazily on the first cleanup emission.
+ StackBaseMem = CGF.CreateTempAlloca(CGF.Int8PtrTy, "inalloca.spmem");
+ CGF.Builder.CreateStore(StackBase, StackBaseMem);
+ CGF.pushStackRestore(EHCleanup, StackBaseMem);
+ StackCleanup = CGF.EHStack.getInnermostEHScope();
+ assert(StackCleanup.isValid());
+}
+
+void CallArgList::freeArgumentMemory(CodeGenFunction &CGF) const {
+ if (StackBase) {
+ CGF.DeactivateCleanupBlock(StackCleanup, StackBase);
+ llvm::Value *F = CGF.CGM.getIntrinsic(llvm::Intrinsic::stackrestore);
+ // We could load StackBase from StackBaseMem, but in the non-exceptional
+ // case we can skip it.
+ CGF.Builder.CreateCall(F, StackBase);
+ }
+}
+
+void CodeGenFunction::EmitCallArgs(CallArgList &Args,
+ ArrayRef<QualType> ArgTypes,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd,
+ bool ForceColumnInfo) {
+ CGDebugInfo *DI = getDebugInfo();
+ SourceLocation CallLoc;
+ if (DI) CallLoc = DI->getLocation();
+
+ // We *have* to evaluate arguments from right to left in the MS C++ ABI,
+ // because arguments are destroyed left to right in the callee.
+ if (CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
+ // Insert a stack save if we're going to need any inalloca args.
+ bool HasInAllocaArgs = false;
+ for (ArrayRef<QualType>::iterator I = ArgTypes.begin(), E = ArgTypes.end();
+ I != E && !HasInAllocaArgs; ++I)
+ HasInAllocaArgs = isInAllocaArgument(CGM.getCXXABI(), *I);
+ if (HasInAllocaArgs) {
+ assert(getTarget().getTriple().getArch() == llvm::Triple::x86);
+ Args.allocateArgumentMemory(*this);
+ }
+
+ // Evaluate each argument.
+ size_t CallArgsStart = Args.size();
+ for (int I = ArgTypes.size() - 1; I >= 0; --I) {
+ CallExpr::const_arg_iterator Arg = ArgBeg + I;
+ EmitCallArg(Args, *Arg, ArgTypes[I]);
+ // Restore the debug location.
+ if (DI) DI->EmitLocation(Builder, CallLoc, ForceColumnInfo);
+ }
+
+ // Un-reverse the arguments we just evaluated so they match up with the LLVM
+ // IR function.
+ std::reverse(Args.begin() + CallArgsStart, Args.end());
+ return;
+ }
+
+ for (unsigned I = 0, E = ArgTypes.size(); I != E; ++I) {
+ CallExpr::const_arg_iterator Arg = ArgBeg + I;
+ assert(Arg != ArgEnd);
+ EmitCallArg(Args, *Arg, ArgTypes[I]);
+ // Restore the debug location.
+ if (DI) DI->EmitLocation(Builder, CallLoc, ForceColumnInfo);
+ }
+}
+
+namespace {
+
+struct DestroyUnpassedArg : EHScopeStack::Cleanup {
+ DestroyUnpassedArg(llvm::Value *Addr, QualType Ty)
+ : Addr(Addr), Ty(Ty) {}
+
+ llvm::Value *Addr;
+ QualType Ty;
+
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
+ const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor();
+ assert(!Dtor->isTrivial());
+ CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*for vbase*/ false,
+ /*Delegating=*/false, Addr);
+ }
+};
+
+}
+
void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
QualType type) {
if (const ObjCIndirectCopyRestoreExpr *CRE
@@ -2027,22 +2405,36 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
// However, we still have to push an EH-only cleanup in case we unwind before
// we make it to the call.
if (HasAggregateEvalKind &&
- CGM.getTarget().getCXXABI().isArgumentDestroyedByCallee()) {
+ CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
+ // If we're using inalloca, use the argument memory. Otherwise, use a
+ // temporary.
+ AggValueSlot Slot;
+ if (args.isUsingInAlloca())
+ Slot = createPlaceholderSlot(*this, type);
+ else
+ Slot = CreateAggTemp(type, "agg.tmp");
+
const CXXRecordDecl *RD = type->getAsCXXRecordDecl();
- if (RD && RD->hasNonTrivialDestructor()) {
- AggValueSlot Slot = CreateAggTemp(type, "agg.arg.tmp");
+ bool DestroyedInCallee =
+ RD && RD->hasNonTrivialDestructor() &&
+ CGM.getCXXABI().getRecordArgABI(RD) != CGCXXABI::RAA_Default;
+ if (DestroyedInCallee)
Slot.setExternallyDestructed();
- EmitAggExpr(E, Slot);
- RValue RV = Slot.asRValue();
- args.add(RV, type);
- pushDestroy(EHCleanup, RV.getAggregateAddr(), type, destroyCXXObject,
- /*useEHCleanupForArray*/ true);
+ EmitAggExpr(E, Slot);
+ RValue RV = Slot.asRValue();
+ args.add(RV, type);
+
+ if (DestroyedInCallee) {
+ // Create a no-op GEP between the placeholder and the cleanup so we can
+ // RAUW it successfully. It also serves as a marker of the first
+ // instruction where the cleanup is active.
+ pushFullExprCleanup<DestroyUnpassedArg>(EHCleanup, Slot.getAddr(), type);
// This unreachable is a temporary marker which will be removed later.
llvm::Instruction *IsActive = Builder.CreateUnreachable();
args.addArgCleanupDeactivation(EHStack.getInnermostEHScope(), IsActive);
- return;
}
+ return;
}
if (HasAggregateEvalKind && isa<ImplicitCastExpr>(E) &&
@@ -2128,6 +2520,7 @@ void CodeGenFunction::EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee,
call->setCallingConv(getRuntimeCC());
Builder.CreateUnreachable();
}
+ PGO.setCurrentRegionUnreachable();
}
/// Emits a call or invoke instruction to the given nullary runtime
@@ -2206,12 +2599,10 @@ void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
LValue LV = MakeAddrLValue(RV.getAggregateAddr(), Ty);
if (RD->isUnion()) {
- const FieldDecl *LargestFD = 0;
+ const FieldDecl *LargestFD = nullptr;
CharUnits UnionSize = CharUnits::Zero();
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
- const FieldDecl *FD = *i;
+ for (const auto *FD : RD->fields()) {
assert(!FD->isBitField() &&
"Cannot expand structure with bit-field members.");
CharUnits FieldSize = getContext().getTypeSizeInChars(FD->getType());
@@ -2225,10 +2616,7 @@ void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
ExpandTypeToArgs(LargestFD->getType(), FldRV, Args, IRFuncTy);
}
} else {
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
- FieldDecl *FD = *i;
-
+ for (const auto *FD : RD->fields()) {
RValue FldRV = EmitRValueForField(LV, FD, SourceLocation());
ExpandTypeToArgs(FD->getType(), FldRV, Args, IRFuncTy);
}
@@ -2251,6 +2639,20 @@ void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
}
}
+/// \brief Store a non-aggregate value to an address to initialize it. For
+/// initialization, a non-atomic store will be used.
+static void EmitInitStoreOfNonAggregate(CodeGenFunction &CGF, RValue Src,
+ LValue Dst) {
+ if (Src.isScalar())
+ CGF.EmitStoreOfScalar(Src.getScalarVal(), Dst, /*init=*/true);
+ else
+ CGF.EmitStoreOfComplex(Src.getComplexVal(), Dst, /*init=*/true);
+}
+
+void CodeGenFunction::deferPlaceholderReplacement(llvm::Instruction *Old,
+ llvm::Value *New) {
+ DeferredReplacements.push_back(std::make_pair(Old, New));
+}
RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::Value *Callee,
@@ -2272,14 +2674,44 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
cast<llvm::FunctionType>(
cast<llvm::PointerType>(Callee->getType())->getElementType());
+ // If we're using inalloca, insert the allocation after the stack save.
+ // FIXME: Do this earlier rather than hacking it in here!
+ llvm::Value *ArgMemory = nullptr;
+ if (llvm::StructType *ArgStruct = CallInfo.getArgStruct()) {
+ llvm::Instruction *IP = CallArgs.getStackBase();
+ llvm::AllocaInst *AI;
+ if (IP) {
+ IP = IP->getNextNode();
+ AI = new llvm::AllocaInst(ArgStruct, "argmem", IP);
+ } else {
+ AI = CreateTempAlloca(ArgStruct, "argmem");
+ }
+ AI->setUsedWithInAlloca(true);
+ assert(AI->isUsedWithInAlloca() && !AI->isStaticAlloca());
+ ArgMemory = AI;
+ }
+
// If the call returns a temporary with struct return, create a temporary
// alloca to hold the result, unless one is given to us.
- if (CGM.ReturnTypeUsesSRet(CallInfo)) {
- llvm::Value *Value = ReturnValue.getValue();
- if (!Value)
- Value = CreateMemTemp(RetTy);
- Args.push_back(Value);
- checkArgMatches(Value, IRArgNo, IRFuncTy);
+ llvm::Value *SRetPtr = nullptr;
+ bool SwapThisWithSRet = false;
+ if (RetAI.isIndirect() || RetAI.isInAlloca()) {
+ SRetPtr = ReturnValue.getValue();
+ if (!SRetPtr)
+ SRetPtr = CreateMemTemp(RetTy);
+ if (RetAI.isIndirect()) {
+ Args.push_back(SRetPtr);
+ SwapThisWithSRet = RetAI.isSRetAfterThis();
+ if (SwapThisWithSRet)
+ IRArgNo = 1;
+ checkArgMatches(SRetPtr, IRArgNo, IRFuncTy);
+ if (SwapThisWithSRet)
+ IRArgNo = 0;
+ } else {
+ llvm::Value *Addr =
+ Builder.CreateStructGEP(ArgMemory, RetAI.getInAllocaFieldIndex());
+ Builder.CreateStore(SRetPtr, Addr);
+ }
}
assert(CallInfo.arg_size() == CallArgs.size() &&
@@ -2290,6 +2722,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
const ABIArgInfo &ArgInfo = info_it->info;
RValue RV = I->RV;
+ // Skip 'sret' if it came second.
+ if (IRArgNo == 1 && SwapThisWithSRet)
+ ++IRArgNo;
+
CharUnits TypeAlign = getContext().getTypeAlignInChars(I->Ty);
// Insert a padding argument to ensure proper alignment.
@@ -2299,6 +2735,35 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
}
switch (ArgInfo.getKind()) {
+ case ABIArgInfo::InAlloca: {
+ assert(getTarget().getTriple().getArch() == llvm::Triple::x86);
+ if (RV.isAggregate()) {
+ // Replace the placeholder with the appropriate argument slot GEP.
+ llvm::Instruction *Placeholder =
+ cast<llvm::Instruction>(RV.getAggregateAddr());
+ CGBuilderTy::InsertPoint IP = Builder.saveIP();
+ Builder.SetInsertPoint(Placeholder);
+ llvm::Value *Addr = Builder.CreateStructGEP(
+ ArgMemory, ArgInfo.getInAllocaFieldIndex());
+ Builder.restoreIP(IP);
+ deferPlaceholderReplacement(Placeholder, Addr);
+ } else {
+ // Store the RValue into the argument struct.
+ llvm::Value *Addr =
+ Builder.CreateStructGEP(ArgMemory, ArgInfo.getInAllocaFieldIndex());
+ unsigned AS = Addr->getType()->getPointerAddressSpace();
+ llvm::Type *MemType = ConvertTypeForMem(I->Ty)->getPointerTo(AS);
+ // There are some cases where a trivial bitcast is not avoidable. The
+ // definition of a type later in a translation unit may change it's type
+ // from {}* to (%struct.foo*)*.
+ if (Addr->getType() != MemType)
+ Addr = Builder.CreateBitCast(Addr, MemType);
+ LValue argLV = MakeAddrLValue(Addr, I->Ty, TypeAlign);
+ EmitInitStoreOfNonAggregate(*this, RV, argLV);
+ }
+ break; // Don't increment IRArgNo!
+ }
+
case ABIArgInfo::Indirect: {
if (RV.isScalar() || RV.isComplex()) {
// Make a temporary alloca to pass the argument.
@@ -2307,13 +2772,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
AI->setAlignment(ArgInfo.getIndirectAlign());
Args.push_back(AI);
- LValue argLV =
- MakeAddrLValue(Args.back(), I->Ty, TypeAlign);
-
- if (RV.isScalar())
- EmitStoreOfScalar(RV.getScalarVal(), argLV, /*init*/ true);
- else
- EmitStoreOfComplex(RV.getComplexVal(), argLV, /*init*/ true);
+ LValue argLV = MakeAddrLValue(Args.back(), I->Ty, TypeAlign);
+ EmitInitStoreOfNonAggregate(*this, RV, argLV);
// Validate argument match.
checkArgMatches(AI, IRArgNo, IRFuncTy);
@@ -2386,11 +2846,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (RV.isScalar() || RV.isComplex()) {
SrcPtr = CreateMemTemp(I->Ty, "coerce");
LValue SrcLV = MakeAddrLValue(SrcPtr, I->Ty, TypeAlign);
- if (RV.isScalar()) {
- EmitStoreOfScalar(RV.getScalarVal(), SrcLV, /*init*/ true);
- } else {
- EmitStoreOfComplex(RV.getComplexVal(), SrcLV, /*init*/ true);
- }
+ EmitInitStoreOfNonAggregate(*this, RV, SrcLV);
} else
SrcPtr = RV.getAggregateAddr();
@@ -2406,8 +2862,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// If the coerce-to type is a first class aggregate, we flatten it and
// pass the elements. Either way is semantically identical, but fast-isel
// and the optimizer generally likes scalar values better than FCAs.
- if (llvm::StructType *STy =
- dyn_cast<llvm::StructType>(ArgInfo.getCoerceToType())) {
+ // We cannot do this for functions using the AAPCS calling convention,
+ // as structures are treated differently by that calling convention.
+ llvm::StructType *STy =
+ dyn_cast<llvm::StructType>(ArgInfo.getCoerceToType());
+ if (STy && !isAAPCSVFP(CallInfo, getTarget())) {
llvm::Type *SrcTy =
cast<llvm::PointerType>(SrcPtr->getType())->getElementType();
uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(SrcTy);
@@ -2456,6 +2915,42 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
}
}
+ if (SwapThisWithSRet)
+ std::swap(Args[0], Args[1]);
+
+ if (ArgMemory) {
+ llvm::Value *Arg = ArgMemory;
+ if (CallInfo.isVariadic()) {
+ // When passing non-POD arguments by value to variadic functions, we will
+ // end up with a variadic prototype and an inalloca call site. In such
+ // cases, we can't do any parameter mismatch checks. Give up and bitcast
+ // the callee.
+ unsigned CalleeAS =
+ cast<llvm::PointerType>(Callee->getType())->getAddressSpace();
+ Callee = Builder.CreateBitCast(
+ Callee, getTypes().GetFunctionType(CallInfo)->getPointerTo(CalleeAS));
+ } else {
+ llvm::Type *LastParamTy =
+ IRFuncTy->getParamType(IRFuncTy->getNumParams() - 1);
+ if (Arg->getType() != LastParamTy) {
+#ifndef NDEBUG
+ // Assert that these structs have equivalent element types.
+ llvm::StructType *FullTy = CallInfo.getArgStruct();
+ llvm::StructType *DeclaredTy = cast<llvm::StructType>(
+ cast<llvm::PointerType>(LastParamTy)->getElementType());
+ assert(DeclaredTy->getNumElements() == FullTy->getNumElements());
+ for (llvm::StructType::element_iterator DI = DeclaredTy->element_begin(),
+ DE = DeclaredTy->element_end(),
+ FI = FullTy->element_begin();
+ DI != DE; ++DI, ++FI)
+ assert(*DI == *FI);
+#endif
+ Arg = Builder.CreateBitCast(Arg, LastParamTy);
+ }
+ }
+ Args.push_back(Arg);
+ }
+
if (!CallArgs.getCleanupsToDeactivate().empty())
deactivateArgCleanupsBeforeCall(*this, CallArgs);
@@ -2496,7 +2991,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::AttributeSet Attrs = llvm::AttributeSet::get(getLLVMContext(),
AttributeList);
- llvm::BasicBlock *InvokeDest = 0;
+ llvm::BasicBlock *InvokeDest = nullptr;
if (!Attrs.hasAttribute(llvm::AttributeSet::FunctionIndex,
llvm::Attribute::NoUnwind))
InvokeDest = getInvokeDest();
@@ -2512,6 +3007,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (callOrInvoke)
*callOrInvoke = CS.getInstruction();
+ if (CurCodeDecl && CurCodeDecl->hasAttr<FlattenAttr>() &&
+ !CS.hasFnAttr(llvm::Attribute::NoInline))
+ Attrs =
+ Attrs.addAttribute(getLLVMContext(), llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::AlwaysInline);
+
CS.setAttributes(Attrs);
CS.setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
@@ -2545,9 +3046,14 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (CallArgs.hasWritebacks())
emitWritebacks(*this, CallArgs);
+ // The stack cleanup for inalloca arguments has to run out of the normal
+ // lexical order, so deactivate it and run it manually here.
+ CallArgs.freeArgumentMemory(*this);
+
switch (RetAI.getKind()) {
+ case ABIArgInfo::InAlloca:
case ABIArgInfo::Indirect:
- return convertTempToRValue(Args[0], RetTy, SourceLocation());
+ return convertTempToRValue(SRetPtr, RetTy, SourceLocation());
case ABIArgInfo::Ignore:
// If we are ignoring an argument that had a result, make sure to
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index 532cb59c62e5..9510a1cd5461 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -56,6 +56,8 @@ namespace CodeGen {
class CallArgList :
public SmallVector<CallArg, 16> {
public:
+ CallArgList() : StackBase(nullptr), StackBaseMem(nullptr) {}
+
struct Writeback {
/// The original argument. Note that the argument l-value
/// is potentially null.
@@ -97,9 +99,12 @@ namespace CodeGen {
bool hasWritebacks() const { return !Writebacks.empty(); }
- typedef SmallVectorImpl<Writeback>::const_iterator writeback_iterator;
- writeback_iterator writeback_begin() const { return Writebacks.begin(); }
- writeback_iterator writeback_end() const { return Writebacks.end(); }
+ typedef llvm::iterator_range<SmallVectorImpl<Writeback>::const_iterator>
+ writeback_const_range;
+
+ writeback_const_range writebacks() const {
+ return writeback_const_range(Writebacks.begin(), Writebacks.end());
+ }
void addArgCleanupDeactivation(EHScopeStack::stable_iterator Cleanup,
llvm::Instruction *IsActiveIP) {
@@ -113,6 +118,14 @@ namespace CodeGen {
return CleanupsToDeactivate;
}
+ void allocateArgumentMemory(CodeGenFunction &CGF);
+ llvm::Instruction *getStackBase() const { return StackBase; }
+ void freeArgumentMemory(CodeGenFunction &CGF) const;
+
+ /// \brief Returns if we're using an inalloca struct to pass arguments in
+ /// memory.
+ bool isUsingInAlloca() const { return StackBase; }
+
private:
SmallVector<Writeback, 1> Writebacks;
@@ -120,6 +133,17 @@ namespace CodeGen {
/// is used to cleanup objects that are owned by the callee once the call
/// occurs.
SmallVector<CallArgCleanup, 1> CleanupsToDeactivate;
+
+ /// The stacksave call. It dominates all of the argument evaluation.
+ llvm::CallInst *StackBase;
+
+ /// The alloca holding the stackbase. We need it to maintain SSA form.
+ llvm::AllocaInst *StackBaseMem;
+
+ /// The iterator pointing to the stack restore cleanup. We manually run and
+ /// deactivate this cleanup after the call in the unexceptional case because
+ /// it doesn't run in the normal order.
+ EHScopeStack::stable_iterator StackCleanup;
};
/// FunctionArgList - Type for representing both the decl and type
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 4848d7565d40..9427de14d704 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -12,10 +12,10 @@
//===----------------------------------------------------------------------===//
#include "CGBlocks.h"
+#include "CGCXXABI.h"
#include "CGDebugInfo.h"
#include "CGRecordLayout.h"
#include "CodeGenFunction.h"
-#include "CGCXXABI.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/EvaluatedExprVisitor.h"
@@ -66,8 +66,8 @@ CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl,
ComputeNonVirtualBaseClassOffset(getContext(), ClassDecl,
PathBegin, PathEnd);
if (Offset.isZero())
- return 0;
-
+ return nullptr;
+
llvm::Type *PtrDiffTy =
Types.ConvertType(getContext().getPointerDiffType());
@@ -114,7 +114,7 @@ ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ptr,
CharUnits nonVirtualOffset,
llvm::Value *virtualOffset) {
// Assert that we have something to do.
- assert(!nonVirtualOffset.isZero() || virtualOffset != 0);
+ assert(!nonVirtualOffset.isZero() || virtualOffset != nullptr);
// Compute the offset from the static and dynamic components.
llvm::Value *baseOffset;
@@ -143,8 +143,8 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
assert(PathBegin != PathEnd && "Base path should not be empty!");
CastExpr::path_const_iterator Start = PathBegin;
- const CXXRecordDecl *VBase = 0;
-
+ const CXXRecordDecl *VBase = nullptr;
+
// Sema has done some convenient canonicalization here: if the
// access path involved any virtual steps, the conversion path will
// *start* with a step down to the correct virtual base subobject,
@@ -169,7 +169,7 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
const ASTRecordLayout &layout = getContext().getASTRecordLayout(Derived);
CharUnits vBaseOffset = layout.getVBaseClassOffset(VBase);
NonVirtualOffset += vBaseOffset;
- VBase = 0; // we no longer have a virtual step
+ VBase = nullptr; // we no longer have a virtual step
}
// Get the base pointer type.
@@ -180,11 +180,11 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
// just do a bitcast; null checks are unnecessary.
if (NonVirtualOffset.isZero() && !VBase) {
return Builder.CreateBitCast(Value, BasePtrTy);
- }
+ }
+
+ llvm::BasicBlock *origBB = nullptr;
+ llvm::BasicBlock *endBB = nullptr;
- llvm::BasicBlock *origBB = 0;
- llvm::BasicBlock *endBB = 0;
-
// Skip over the offset (and the vtable load) if we're supposed to
// null-check the pointer.
if (NullCheckValue) {
@@ -198,7 +198,7 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
}
// Compute the virtual offset.
- llvm::Value *VirtualOffset = 0;
+ llvm::Value *VirtualOffset = nullptr;
if (VBase) {
VirtualOffset =
CGM.getCXXABI().GetVirtualBaseClassOffset(*this, Value, Derived, VBase);
@@ -246,11 +246,11 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
// No offset, we can just cast back.
return Builder.CreateBitCast(Value, DerivedPtrTy);
}
-
- llvm::BasicBlock *CastNull = 0;
- llvm::BasicBlock *CastNotNull = 0;
- llvm::BasicBlock *CastEnd = 0;
-
+
+ llvm::BasicBlock *CastNull = nullptr;
+ llvm::BasicBlock *CastNotNull = nullptr;
+ llvm::BasicBlock *CastEnd = nullptr;
+
if (NullCheckValue) {
CastNull = createBasicBlock("cast.null");
CastNotNull = createBasicBlock("cast.notnull");
@@ -290,7 +290,7 @@ llvm::Value *CodeGenFunction::GetVTTParameter(GlobalDecl GD,
bool Delegating) {
if (!CGM.getCXXABI().NeedsVTTParameter(GD)) {
// This constructor/destructor does not need a VTT parameter.
- return 0;
+ return nullptr;
}
const CXXRecordDecl *RD = cast<CXXMethodDecl>(CurCodeDecl)->getParent();
@@ -342,7 +342,7 @@ namespace {
CallBaseDtor(const CXXRecordDecl *Base, bool BaseIsVirtual)
: BaseClass(Base), BaseIsVirtual(BaseIsVirtual) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
const CXXRecordDecl *DerivedClass =
cast<CXXMethodDecl>(CGF.CurCodeDecl)->getParent();
@@ -454,7 +454,7 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
switch (CGF.getEvaluationKind(T)) {
case TEK_Scalar:
- CGF.EmitScalarInit(Init, /*decl*/ 0, LV, false);
+ CGF.EmitScalarInit(Init, /*decl*/ nullptr, LV, false);
break;
case TEK_Complex:
CGF.EmitComplexExprIntoLValue(Init, LV, /*isInit*/ true);
@@ -549,10 +549,8 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
// If we are initializing an anonymous union field, drill down to
// the field.
IndirectFieldDecl *IndirectField = MemberInit->getIndirectMember();
- IndirectFieldDecl::chain_iterator I = IndirectField->chain_begin(),
- IEnd = IndirectField->chain_end();
- for ( ; I != IEnd; ++I)
- LHS = CGF.EmitLValueForFieldInitialization(LHS, cast<FieldDecl>(*I));
+ for (const auto *I : IndirectField->chain())
+ LHS = CGF.EmitLValueForFieldInitialization(LHS, cast<FieldDecl>(I));
FieldType = MemberInit->getIndirectMember()->getAnonField()->getType();
} else {
LHS = CGF.EmitLValueForFieldInitialization(LHS, Field);
@@ -609,7 +607,7 @@ void CodeGenFunction::EmitInitializerForField(FieldDecl *Field,
EmitComplexExprIntoLValue(Init, LHS, /*isInit*/ true);
break;
case TEK_Aggregate: {
- llvm::Value *ArrayIndexVar = 0;
+ llvm::Value *ArrayIndexVar = nullptr;
if (ArrayIndexes.size()) {
llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
@@ -699,6 +697,10 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
const CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(CurGD.getDecl());
CXXCtorType CtorType = CurGD.getCtorType();
+ assert((CGM.getTarget().getCXXABI().hasConstructorVariants() ||
+ CtorType == Ctor_Complete) &&
+ "can only generate complete ctor for this ABI");
+
// Before we go any further, try the complete->base constructor
// delegation optimization.
if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor) &&
@@ -717,6 +719,9 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
if (IsTryBody)
EnterCXXTryStmt(*cast<CXXTryStmt>(Body), true);
+ RegionCounter Cnt = getPGORegionCounter(Body);
+ Cnt.beginRegion(Builder);
+
RunCleanupsScope RunCleanups(*this);
// TODO: in restricted cases, we can emit the vbase initializers of
@@ -772,8 +777,8 @@ namespace {
const VarDecl *SrcRec)
: CGF(CGF), ClassDecl(ClassDecl), SrcRec(SrcRec),
RecLayout(CGF.getContext().getASTRecordLayout(ClassDecl)),
- FirstField(0), LastField(0), FirstFieldOffset(0), LastFieldOffset(0),
- LastAddedFieldIndex(0) { }
+ FirstField(nullptr), LastField(nullptr), FirstFieldOffset(0),
+ LastFieldOffset(0), LastAddedFieldIndex(0) {}
static bool isMemcpyableField(FieldDecl *F) {
Qualifiers Qual = F->getType().getQualifiers();
@@ -783,7 +788,7 @@ namespace {
}
void addMemcpyableField(FieldDecl *F) {
- if (FirstField == 0)
+ if (!FirstField)
addInitialField(F);
else
addNextField(F);
@@ -805,7 +810,7 @@ namespace {
void emitMemcpy() {
// Give the subclass a chance to bail out if it feels the memcpy isn't
// worth it (e.g. Hasn't aggregated enough data).
- if (FirstField == 0) {
+ if (!FirstField) {
return;
}
@@ -839,7 +844,7 @@ namespace {
}
void reset() {
- FirstField = 0;
+ FirstField = nullptr;
}
protected:
@@ -912,7 +917,7 @@ namespace {
FunctionArgList &Args) {
if (CD->isCopyOrMoveConstructor() && CD->isDefaulted())
return Args[Args.size() - 1];
- return 0;
+ return nullptr;
}
// Returns true if a CXXCtorInitializer represents a member initialization
@@ -921,7 +926,7 @@ namespace {
if (!MemcpyableCtor)
return false;
FieldDecl *Field = MemberInit->getMember();
- assert(Field != 0 && "No field for member init.");
+ assert(Field && "No field for member init.");
QualType FieldType = Field->getType();
CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(MemberInit->getInit());
@@ -1009,71 +1014,71 @@ namespace {
// exists. Otherwise returns null.
FieldDecl *getMemcpyableField(Stmt *S) {
if (!AssignmentsMemcpyable)
- return 0;
+ return nullptr;
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) {
// Recognise trivial assignments.
if (BO->getOpcode() != BO_Assign)
- return 0;
+ return nullptr;
MemberExpr *ME = dyn_cast<MemberExpr>(BO->getLHS());
if (!ME)
- return 0;
+ return nullptr;
FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl());
if (!Field || !isMemcpyableField(Field))
- return 0;
+ return nullptr;
Stmt *RHS = BO->getRHS();
if (ImplicitCastExpr *EC = dyn_cast<ImplicitCastExpr>(RHS))
RHS = EC->getSubExpr();
if (!RHS)
- return 0;
+ return nullptr;
MemberExpr *ME2 = dyn_cast<MemberExpr>(RHS);
if (dyn_cast<FieldDecl>(ME2->getMemberDecl()) != Field)
- return 0;
+ return nullptr;
return Field;
} else if (CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(S)) {
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MCE->getCalleeDecl());
if (!(MD && (MD->isCopyAssignmentOperator() ||
MD->isMoveAssignmentOperator()) &&
MD->isTrivial()))
- return 0;
+ return nullptr;
MemberExpr *IOA = dyn_cast<MemberExpr>(MCE->getImplicitObjectArgument());
if (!IOA)
- return 0;
+ return nullptr;
FieldDecl *Field = dyn_cast<FieldDecl>(IOA->getMemberDecl());
if (!Field || !isMemcpyableField(Field))
- return 0;
+ return nullptr;
MemberExpr *Arg0 = dyn_cast<MemberExpr>(MCE->getArg(0));
if (!Arg0 || Field != dyn_cast<FieldDecl>(Arg0->getMemberDecl()))
- return 0;
+ return nullptr;
return Field;
} else if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
FunctionDecl *FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
if (!FD || FD->getBuiltinID() != Builtin::BI__builtin_memcpy)
- return 0;
+ return nullptr;
Expr *DstPtr = CE->getArg(0);
if (ImplicitCastExpr *DC = dyn_cast<ImplicitCastExpr>(DstPtr))
DstPtr = DC->getSubExpr();
UnaryOperator *DUO = dyn_cast<UnaryOperator>(DstPtr);
if (!DUO || DUO->getOpcode() != UO_AddrOf)
- return 0;
+ return nullptr;
MemberExpr *ME = dyn_cast<MemberExpr>(DUO->getSubExpr());
if (!ME)
- return 0;
+ return nullptr;
FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl());
if (!Field || !isMemcpyableField(Field))
- return 0;
+ return nullptr;
Expr *SrcPtr = CE->getArg(1);
if (ImplicitCastExpr *SC = dyn_cast<ImplicitCastExpr>(SrcPtr))
SrcPtr = SC->getSubExpr();
UnaryOperator *SUO = dyn_cast<UnaryOperator>(SrcPtr);
if (!SUO || SUO->getOpcode() != UO_AddrOf)
- return 0;
+ return nullptr;
MemberExpr *ME2 = dyn_cast<MemberExpr>(SUO->getSubExpr());
if (!ME2 || Field != dyn_cast<FieldDecl>(ME2->getMemberDecl()))
- return 0;
+ return nullptr;
return Field;
}
- return 0;
+ return nullptr;
}
bool AssignmentsMemcpyable;
@@ -1132,7 +1137,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
CXXConstructorDecl::init_const_iterator B = CD->init_begin(),
E = CD->init_end();
- llvm::BasicBlock *BaseCtorContinueBB = 0;
+ llvm::BasicBlock *BaseCtorContinueBB = nullptr;
if (ClassDecl->getNumVBases() &&
!CGM.getTarget().getCXXABI().hasConstructorVariants()) {
// The ABIs that don't have constructor variants need to put a branch
@@ -1190,23 +1195,17 @@ HasTrivialDestructorBody(ASTContext &Context,
return false;
// Check fields.
- for (CXXRecordDecl::field_iterator I = BaseClassDecl->field_begin(),
- E = BaseClassDecl->field_end(); I != E; ++I) {
- const FieldDecl *Field = *I;
-
+ for (const auto *Field : BaseClassDecl->fields())
if (!FieldHasTrivialDestructorBody(Context, Field))
return false;
- }
// Check non-virtual bases.
- for (CXXRecordDecl::base_class_const_iterator I =
- BaseClassDecl->bases_begin(), E = BaseClassDecl->bases_end();
- I != E; ++I) {
- if (I->isVirtual())
+ for (const auto &I : BaseClassDecl->bases()) {
+ if (I.isVirtual())
continue;
const CXXRecordDecl *NonVirtualBase =
- cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
if (!HasTrivialDestructorBody(Context, NonVirtualBase,
MostDerivedClassDecl))
return false;
@@ -1214,11 +1213,9 @@ HasTrivialDestructorBody(ASTContext &Context,
if (BaseClassDecl == MostDerivedClassDecl) {
// Check virtual bases.
- for (CXXRecordDecl::base_class_const_iterator I =
- BaseClassDecl->vbases_begin(), E = BaseClassDecl->vbases_end();
- I != E; ++I) {
+ for (const auto &I : BaseClassDecl->vbases()) {
const CXXRecordDecl *VirtualBase =
- cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
if (!HasTrivialDestructorBody(Context, VirtualBase,
MostDerivedClassDecl))
return false;
@@ -1251,13 +1248,9 @@ static bool CanSkipVTablePointerInitialization(ASTContext &Context,
// Check the fields.
const CXXRecordDecl *ClassDecl = Dtor->getParent();
- for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
- E = ClassDecl->field_end(); I != E; ++I) {
- const FieldDecl *Field = *I;
-
+ for (const auto *Field : ClassDecl->fields())
if (!FieldHasTrivialDestructorBody(Context, Field))
return false;
- }
return true;
}
@@ -1315,6 +1308,9 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
case Dtor_Base:
assert(Body);
+ RegionCounter Cnt = getPGORegionCounter(Body);
+ Cnt.beginRegion(Builder);
+
// Enter the cleanup scopes for fields and non-virtual bases.
EnterDtorCleanups(Dtor, Dtor_Base);
@@ -1355,11 +1351,8 @@ void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args)
LexicalScope Scope(*this, RootCS->getSourceRange());
AssignmentMemcpyizer AM(*this, AssignOp, Args);
- for (CompoundStmt::const_body_iterator I = RootCS->body_begin(),
- E = RootCS->body_end();
- I != E; ++I) {
- AM.emitAssignment(*I);
- }
+ for (auto *I : RootCS->body())
+ AM.emitAssignment(I);
AM.finish();
}
@@ -1368,7 +1361,7 @@ namespace {
struct CallDtorDelete : EHScopeStack::Cleanup {
CallDtorDelete() {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl);
const CXXRecordDecl *ClassDecl = Dtor->getParent();
CGF.EmitDeleteCall(Dtor->getOperatorDelete(), CGF.LoadCXXThis(),
@@ -1381,10 +1374,10 @@ namespace {
public:
CallDtorDeleteConditional(llvm::Value *ShouldDeleteCondition)
: ShouldDeleteCondition(ShouldDeleteCondition) {
- assert(ShouldDeleteCondition != NULL);
+ assert(ShouldDeleteCondition != nullptr);
}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
llvm::BasicBlock *callDeleteBB = CGF.createBasicBlock("dtor.call_delete");
llvm::BasicBlock *continueBB = CGF.createBasicBlock("dtor.continue");
llvm::Value *ShouldCallDelete
@@ -1413,7 +1406,7 @@ namespace {
: field(field), destroyer(destroyer),
useEHCleanupForArray(useEHCleanupForArray) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
// Find the address of the field.
llvm::Value *thisValue = CGF.LoadCXXThis();
QualType RecordTy = CGF.getContext().getTagDeclType(field->getParent());
@@ -1427,19 +1420,19 @@ namespace {
};
}
-/// EmitDtorEpilogue - Emit all code that comes at the end of class's
+/// \brief Emit all code that comes at the end of class's
/// destructor. This is to call destructors on members and base classes
/// in reverse order of their construction.
void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
CXXDtorType DtorType) {
- assert(!DD->isTrivial() &&
- "Should not emit dtor epilogue for trivial dtor!");
+ assert((!DD->isTrivial() || DD->hasAttr<DLLExportAttr>()) &&
+ "Should not emit dtor epilogue for non-exported trivial dtor!");
// The deleting-destructor phase just needs to call the appropriate
// operator delete that Sema picked up.
if (DtorType == Dtor_Deleting) {
assert(DD->getOperatorDelete() &&
- "operator delete missing - EmitDtorEpilogue");
+ "operator delete missing - EnterDtorCleanups");
if (CXXStructorImplicitParamValue) {
// If there is an implicit param to the deleting dtor, it's a boolean
// telling whether we should call delete at the end of the dtor.
@@ -1462,10 +1455,7 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
// We push them in the forward order so that they'll be popped in
// the reverse order.
- for (CXXRecordDecl::base_class_const_iterator I =
- ClassDecl->vbases_begin(), E = ClassDecl->vbases_end();
- I != E; ++I) {
- const CXXBaseSpecifier &Base = *I;
+ for (const auto &Base : ClassDecl->vbases()) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
@@ -1484,10 +1474,7 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
assert(DtorType == Dtor_Base);
// Destroy non-virtual bases.
- for (CXXRecordDecl::base_class_const_iterator I =
- ClassDecl->bases_begin(), E = ClassDecl->bases_end(); I != E; ++I) {
- const CXXBaseSpecifier &Base = *I;
-
+ for (const auto &Base : ClassDecl->bases()) {
// Ignore virtual bases.
if (Base.isVirtual())
continue;
@@ -1504,11 +1491,8 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
}
// Destroy direct fields.
- 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 type = field->getType();
+ for (const auto *Field : ClassDecl->fields()) {
+ QualType type = Field->getType();
QualType::DestructionKind dtorKind = type.isDestructedType();
if (!dtorKind) continue;
@@ -1517,7 +1501,7 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
if (RT && RT->getDecl()->isAnonymousStructOrUnion()) continue;
CleanupKind cleanupKind = getCleanupKind(dtorKind);
- EHStack.pushCleanup<DestroyField>(cleanupKind, field,
+ EHStack.pushCleanup<DestroyField>(cleanupKind, Field,
getDestroyer(dtorKind),
cleanupKind & EHCleanup);
}
@@ -1568,7 +1552,7 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
// 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;
+ llvm::BranchInst *zeroCheckBranch = nullptr;
// Optimize for a constant count.
llvm::ConstantInt *constantCount
@@ -1683,9 +1667,31 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
return;
}
- // Non-trivial constructors are handled in an ABI-specific manner.
- CGM.getCXXABI().EmitConstructorCall(*this, D, Type, ForVirtualBase,
- Delegating, This, ArgBeg, ArgEnd);
+ // C++11 [class.mfct.non-static]p2:
+ // If a non-static member function of a class X is called for an object that
+ // is not of type X, or of a type derived from X, the behavior is undefined.
+ // FIXME: Provide a source location here.
+ EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall, SourceLocation(), This,
+ getContext().getRecordType(D->getParent()));
+
+ CallArgList Args;
+
+ // Push the this ptr.
+ Args.add(RValue::get(This), D->getThisType(getContext()));
+
+ // Add the rest of the user-supplied arguments.
+ const FunctionProtoType *FPT = D->getType()->castAs<FunctionProtoType>();
+ EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
+
+ // Insert any ABI-specific implicit constructor arguments.
+ unsigned ExtraArgs = CGM.getCXXABI().addImplicitConstructorArgs(
+ *this, D, Type, ForVirtualBase, Delegating, Args);
+
+ // Emit the call.
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
+ const CGFunctionInfo &Info =
+ CGM.getTypes().arrangeCXXConstructorCall(Args, D, Type, ExtraArgs);
+ EmitCall(Info, Callee, ReturnValueSlot(), Args, D);
}
void
@@ -1704,38 +1710,23 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
assert(D->isInstance() &&
"Trying to emit a member call expr on a static method!");
- const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>();
+ const FunctionProtoType *FPT = D->getType()->castAs<FunctionProtoType>();
CallArgList Args;
// Push the this ptr.
Args.add(RValue::get(This), D->getThisType(getContext()));
-
// Push the src ptr.
- QualType QT = *(FPT->arg_type_begin());
+ QualType QT = *(FPT->param_type_begin());
llvm::Type *t = CGM.getTypes().ConvertType(QT);
Src = Builder.CreateBitCast(Src, t);
Args.add(RValue::get(Src), QT);
-
+
// Skip over first argument (Src).
- ++ArgBeg;
- CallExpr::const_arg_iterator Arg = ArgBeg;
- for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin()+1,
- E = FPT->arg_type_end(); I != E; ++I, ++Arg) {
- assert(Arg != ArgEnd && "Running over edge of argument list!");
- EmitCallArg(Args, *Arg, *I);
- }
- // Either we've emitted all the call args, or we have a call to a
- // variadic function.
- assert((Arg == ArgEnd || FPT->isVariadic()) &&
- "Extra arguments in non-variadic function!");
- // If we still have any arguments, emit them using the type of the argument.
- for (; Arg != ArgEnd; ++Arg) {
- QualType ArgType = Arg->getType();
- EmitCallArg(Args, *Arg, ArgType);
- }
-
+ EmitCallArgs(Args, FPT->isVariadic(), FPT->param_type_begin() + 1,
+ FPT->param_type_end(), ArgBeg + 1, ArgEnd);
+
EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, RequiredArgs::All),
Callee, ReturnValueSlot(), Args, D);
}
@@ -1790,7 +1781,7 @@ namespace {
CXXDtorType Type)
: Dtor(D), Addr(Addr), Type(Type) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
CGF.EmitCXXDestructorCall(Dtor, Type, /*ForVirtualBase=*/false,
/*Delegating=*/true, Addr);
}
@@ -1830,23 +1821,8 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
bool ForVirtualBase,
bool Delegating,
llvm::Value *This) {
- GlobalDecl GD(DD, Type);
- llvm::Value *VTT = GetVTTParameter(GD, ForVirtualBase, Delegating);
- llvm::Value *Callee = 0;
- if (getLangOpts().AppleKext)
- Callee = BuildAppleKextVirtualDestructorCall(DD, Type,
- DD->getParent());
-
- if (!Callee)
- Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
-
- if (DD->isVirtual())
- This = CGM.getCXXABI().adjustThisArgumentForVirtualCall(*this, GD, This);
-
- // FIXME: Provide a source location here.
- EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
- VTT, getContext().getPointerType(getContext().VoidPtrTy),
- 0, 0);
+ CGM.getCXXABI().EmitDestructorCall(*this, DD, Type, ForVirtualBase,
+ Delegating, This);
}
namespace {
@@ -1857,7 +1833,7 @@ namespace {
CallLocalDtor(const CXXDestructorDecl *D, llvm::Value *Addr)
: Dtor(D), Addr(Addr) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
/*ForVirtualBase=*/false,
/*Delegating=*/false, Addr);
@@ -1894,7 +1870,7 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base,
return;
// Compute where to store the address point.
- llvm::Value *VirtualOffset = 0;
+ llvm::Value *VirtualOffset = nullptr;
CharUnits NonVirtualOffset = CharUnits::Zero();
if (NeedsVirtualOffset) {
@@ -1944,10 +1920,9 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
const CXXRecordDecl *RD = Base.getBase();
// Traverse bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
+ for (const auto &I : RD->bases()) {
CXXRecordDecl *BaseDecl
- = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ = cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
// Ignore classes without a vtable.
if (!BaseDecl->isDynamicClass())
@@ -1957,7 +1932,7 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
CharUnits BaseOffsetFromNearestVBase;
bool BaseDeclIsNonVirtualPrimaryBase;
- if (I->isVirtual()) {
+ if (I.isVirtual()) {
// Check if we've visited this virtual base before.
if (!VBases.insert(BaseDecl))
continue;
@@ -1978,7 +1953,7 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base,
}
InitializeVTablePointers(BaseSubobject(BaseDecl, BaseOffset),
- I->isVirtual() ? BaseDecl : NearestVBase,
+ I.isVirtual() ? BaseDecl : NearestVBase,
BaseOffsetFromNearestVBase,
BaseDeclIsNonVirtualPrimaryBase,
VTableClass, VBases);
@@ -1993,7 +1968,7 @@ void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) {
// Initialize the vtable pointers for this class and all of its bases.
VisitedVirtualBasesSetTy VBases;
InitializeVTablePointers(BaseSubobject(RD, CharUnits::Zero()),
- /*NearestVBase=*/0,
+ /*NearestVBase=*/nullptr,
/*OffsetFromNearestVBase=*/CharUnits::Zero(),
/*BaseIsNonVirtualPrimaryBase=*/false, RD, VBases);
@@ -2127,7 +2102,7 @@ void CodeGenFunction::EmitForwardingCallToLambda(
// Prepare the return slot.
const FunctionProtoType *FPT =
callOperator->getType()->castAs<FunctionProtoType>();
- QualType resultType = FPT->getResultType();
+ QualType resultType = FPT->getReturnType();
ReturnValueSlot returnSlot;
if (!resultType->isVoidType() &&
calleeFnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect &&
@@ -2162,11 +2137,9 @@ void CodeGenFunction::EmitLambdaBlockInvokeBody() {
CallArgs.add(RValue::get(ThisPtr), ThisType);
// Add the rest of the parameters.
- for (BlockDecl::param_const_iterator I = BD->param_begin(),
- E = BD->param_end(); I != E; ++I) {
- ParmVarDecl *param = *I;
+ for (auto param : BD->params())
EmitDelegateCallArg(CallArgs, param, param->getLocStart());
- }
+
assert(!Lambda->isGenericLambda() &&
"generic lambda interconversion to block not implemented");
EmitForwardingCallToLambda(Lambda->getLambdaCallOperator(), CallArgs);
@@ -2194,11 +2167,9 @@ void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) {
CallArgs.add(RValue::get(ThisPtr), ThisType);
// Add the rest of the parameters.
- for (FunctionDecl::param_const_iterator I = MD->param_begin(),
- E = MD->param_end(); I != E; ++I) {
- ParmVarDecl *param = *I;
- EmitDelegateCallArg(CallArgs, param, param->getLocStart());
- }
+ for (auto Param : MD->params())
+ EmitDelegateCallArg(CallArgs, Param, Param->getLocStart());
+
const CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();
// For a generic lambda, find the corresponding call operator specialization
// to which the call to the static-invoker shall be forwarded.
@@ -2206,9 +2177,9 @@ void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) {
assert(MD->isFunctionTemplateSpecialization());
const TemplateArgumentList *TAL = MD->getTemplateSpecializationArgs();
FunctionTemplateDecl *CallOpTemplate = CallOp->getDescribedFunctionTemplate();
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
FunctionDecl *CorrespondingCallOpSpecialization =
- CallOpTemplate->findSpecialization(TAL->data(), TAL->size(), InsertPos);
+ CallOpTemplate->findSpecialization(TAL->asArray(), InsertPos);
assert(CorrespondingCallOpSpecialization);
CallOp = cast<CXXMethodDecl>(CorrespondingCallOpSpecialization);
}
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp
index 65de4d498d1a..ed9f96df7987 100644
--- a/lib/CodeGen/CGCleanup.cpp
+++ b/lib/CodeGen/CGCleanup.cpp
@@ -50,7 +50,7 @@ DominatingValue<RValue>::saved_type::save(CodeGenFunction &CGF, RValue rv) {
CodeGenFunction::ComplexPairTy V = rv.getComplexVal();
llvm::Type *ComplexTy =
llvm::StructType::get(V.first->getType(), V.second->getType(),
- (void*) 0);
+ (void*) nullptr);
llvm::Value *addr = CGF.CreateTempAlloca(ComplexTy, "saved-complex");
CGF.Builder.CreateStore(V.first, CGF.Builder.CreateStructGEP(addr, 0));
CGF.Builder.CreateStore(V.second, CGF.Builder.CreateStructGEP(addr, 1));
@@ -245,7 +245,7 @@ void EHScopeStack::popNullFixups() {
assert(BranchFixups.size() >= MinSize && "fixup stack out of order");
while (BranchFixups.size() > MinSize &&
- BranchFixups.back().Destination == 0)
+ BranchFixups.back().Destination == nullptr)
BranchFixups.pop_back();
}
@@ -263,7 +263,7 @@ void CodeGenFunction::initFullExprCleanup() {
// Set that as the active flag in the cleanup.
EHCleanupScope &cleanup = cast<EHCleanupScope>(*EHStack.begin());
- assert(cleanup.getActiveFlag() == 0 && "cleanup already has active flag?");
+ assert(!cleanup.getActiveFlag() && "cleanup already has active flag?");
cleanup.setActiveFlag(active);
if (cleanup.isNormalCleanup()) cleanup.setTestFlagInNormalCleanup();
@@ -283,7 +283,7 @@ static void ResolveAllBranchFixups(CodeGenFunction &CGF,
for (unsigned I = 0, E = CGF.EHStack.getNumBranchFixups(); I != E; ++I) {
// Skip this fixup if its destination isn't set.
BranchFixup &Fixup = CGF.EHStack.getBranchFixup(I);
- if (Fixup.Destination == 0) continue;
+ if (Fixup.Destination == nullptr) continue;
// If there isn't an OptimisticBranchBlock, then InitialBranch is
// still pointing directly to its destination; forward it to the
@@ -293,7 +293,7 @@ static void ResolveAllBranchFixups(CodeGenFunction &CGF,
// lbl:
// i.e. where there's an unresolved fixup inside a single cleanup
// entry which we're currently popping.
- if (Fixup.OptimisticBranchBlock == 0) {
+ if (Fixup.OptimisticBranchBlock == nullptr) {
new llvm::StoreInst(CGF.Builder.getInt32(Fixup.DestinationIndex),
CGF.getNormalCleanupDestSlot(),
Fixup.InitialBranch);
@@ -347,7 +347,7 @@ void CodeGenFunction::ResolveBranchFixups(llvm::BasicBlock *Block) {
BranchFixup &Fixup = EHStack.getBranchFixup(I);
if (Fixup.Destination != Block) continue;
- Fixup.Destination = 0;
+ Fixup.Destination = nullptr;
ResolvedAny = true;
// If it doesn't have an optimistic branch block, LatestBranch is
@@ -473,7 +473,7 @@ static void EmitCleanup(CodeGenFunction &CGF,
// If there's an active flag, load it and skip the cleanup if it's
// false.
- llvm::BasicBlock *ContBB = 0;
+ llvm::BasicBlock *ContBB = nullptr;
if (ActiveFlag) {
ContBB = CGF.createBasicBlock("cleanup.done");
llvm::BasicBlock *CleanupBB = CGF.createBasicBlock("cleanup.action");
@@ -528,7 +528,7 @@ static void destroyOptimisticNormalEntry(CodeGenFunction &CGF,
llvm::BasicBlock *unreachableBB = CGF.getUnreachableBlock();
for (llvm::BasicBlock::use_iterator
i = entry->use_begin(), e = entry->use_end(); i != e; ) {
- llvm::Use &use = i.getUse();
+ llvm::Use &use = *i;
++i;
use.set(unreachableBB);
@@ -568,15 +568,15 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
// Remember activation information.
bool IsActive = Scope.isActive();
llvm::Value *NormalActiveFlag =
- Scope.shouldTestFlagInNormalCleanup() ? Scope.getActiveFlag() : 0;
+ Scope.shouldTestFlagInNormalCleanup() ? Scope.getActiveFlag() : nullptr;
llvm::Value *EHActiveFlag =
- Scope.shouldTestFlagInEHCleanup() ? Scope.getActiveFlag() : 0;
+ Scope.shouldTestFlagInEHCleanup() ? Scope.getActiveFlag() : nullptr;
// Check whether we need an EH cleanup. This is only true if we've
// generated a lazy EH cleanup block.
llvm::BasicBlock *EHEntry = Scope.getCachedEHDispatchBlock();
- assert(Scope.hasEHBranches() == (EHEntry != 0));
- bool RequiresEHCleanup = (EHEntry != 0);
+ assert(Scope.hasEHBranches() == (EHEntry != nullptr));
+ bool RequiresEHCleanup = (EHEntry != nullptr);
EHScopeStack::stable_iterator EHParent = Scope.getEnclosingEHScope();
// Check the three conditions which might require a normal cleanup:
@@ -590,7 +590,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
// - whether there's a fallthrough
llvm::BasicBlock *FallthroughSource = Builder.GetInsertBlock();
- bool HasFallthrough = (FallthroughSource != 0 && IsActive);
+ bool HasFallthrough = (FallthroughSource != nullptr && IsActive);
// Branch-through fall-throughs leave the insertion point set to the
// end of the last cleanup, which points to the current scope. The
@@ -720,7 +720,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
// - if fall-through is a branch-through
// - if there are fixups that will be optimistically forwarded
// to the enclosing cleanup
- llvm::BasicBlock *BranchThroughDest = 0;
+ llvm::BasicBlock *BranchThroughDest = nullptr;
if (Scope.hasBranchThroughs() ||
(FallthroughSource && FallthroughIsBranchThrough) ||
(HasFixups && HasEnclosingCleanups)) {
@@ -729,7 +729,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
BranchThroughDest = CreateNormalEntry(*this, cast<EHCleanupScope>(S));
}
- llvm::BasicBlock *FallthroughDest = 0;
+ llvm::BasicBlock *FallthroughDest = nullptr;
SmallVector<llvm::Instruction*, 2> InstsToAppend;
// If there's exactly one branch-after and no other threads,
@@ -860,7 +860,9 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
// Emit the EH cleanup if required.
if (RequiresEHCleanup) {
- if (CGDebugInfo *DI = getDebugInfo())
+ CGDebugInfo *DI = getDebugInfo();
+ SaveAndRestoreLocation AutoRestoreLocation(*this, Builder);
+ if (DI)
DI->EmitLocation(Builder, CurEHLocation);
CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
@@ -941,7 +943,7 @@ void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) {
Fixup.Destination = Dest.getBlock();
Fixup.DestinationIndex = Dest.getDestIndex();
Fixup.InitialBranch = BI;
- Fixup.OptimisticBranchBlock = 0;
+ Fixup.OptimisticBranchBlock = nullptr;
Builder.ClearInsertionPoint();
return;
diff --git a/lib/CodeGen/CGCleanup.h b/lib/CodeGen/CGCleanup.h
index 1bd6bba523fb..1d4606f13669 100644
--- a/lib/CodeGen/CGCleanup.h
+++ b/lib/CodeGen/CGCleanup.h
@@ -96,7 +96,7 @@ public:
enum Kind { Cleanup, Catch, Terminate, Filter };
EHScope(Kind kind, EHScopeStack::stable_iterator enclosingEHScope)
- : CachedLandingPad(0), CachedEHDispatchBlock(0),
+ : CachedLandingPad(nullptr), CachedEHDispatchBlock(nullptr),
EnclosingEHScope(enclosingEHScope) {
CommonBits.Kind = kind;
}
@@ -145,12 +145,12 @@ public:
struct Handler {
/// A type info value, or null (C++ null, not an LLVM null pointer)
/// for a catch-all.
- llvm::Value *Type;
+ llvm::Constant *Type;
/// The catch handler for this type.
llvm::BasicBlock *Block;
- bool isCatchAll() const { return Type == 0; }
+ bool isCatchAll() const { return Type == nullptr; }
};
private:
@@ -180,10 +180,10 @@ public:
}
void setCatchAllHandler(unsigned I, llvm::BasicBlock *Block) {
- setHandler(I, /*catchall*/ 0, Block);
+ setHandler(I, /*catchall*/ nullptr, Block);
}
- void setHandler(unsigned I, llvm::Value *Type, llvm::BasicBlock *Block) {
+ void setHandler(unsigned I, llvm::Constant *Type, llvm::BasicBlock *Block) {
assert(I < getNumHandlers());
getHandlers()[I].Type = Type;
getHandlers()[I].Block = Block;
@@ -194,6 +194,15 @@ public:
return getHandlers()[I];
}
+ // Clear all handler blocks.
+ // FIXME: it's better to always call clearHandlerBlocks in DTOR and have a
+ // 'takeHandler' or some such function which removes ownership from the
+ // EHCatchScope object if the handlers should live longer than EHCatchScope.
+ void clearHandlerBlocks() {
+ for (unsigned I = 0, N = getNumHandlers(); I != N; ++I)
+ delete getHandler(I).Block;
+ }
+
typedef const Handler *iterator;
iterator begin() const { return getHandlers(); }
iterator end() const { return getHandlers() + getNumHandlers(); }
@@ -259,7 +268,7 @@ public:
EHScopeStack::stable_iterator enclosingNormal,
EHScopeStack::stable_iterator enclosingEH)
: EHScope(EHScope::Cleanup, enclosingEH), EnclosingNormal(enclosingNormal),
- NormalBlock(0), ActiveFlag(0), ExtInfo(0) {
+ NormalBlock(nullptr), ActiveFlag(nullptr), ExtInfo(nullptr) {
CleanupBits.IsNormalCleanup = isNormal;
CleanupBits.IsEHCleanup = isEH;
CleanupBits.IsActive = isActive;
@@ -446,7 +455,7 @@ class EHScopeStack::iterator {
explicit iterator(char *Ptr) : Ptr(Ptr) {}
public:
- iterator() : Ptr(0) {}
+ iterator() : Ptr(nullptr) {}
EHScope *get() const {
return reinterpret_cast<EHScope*>(Ptr);
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index fcb26f0da615..048c8f8f3674 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -37,7 +37,7 @@
#include "llvm/IR/Module.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
+#include "llvm/Support/Path.h"
using namespace clang;
using namespace clang::CodeGen;
@@ -52,30 +52,35 @@ CGDebugInfo::~CGDebugInfo() {
"Region stack mismatch, stack not empty!");
}
-
-NoLocation::NoLocation(CodeGenFunction &CGF, CGBuilderTy &B)
- : DI(CGF.getDebugInfo()), Builder(B) {
+SaveAndRestoreLocation::SaveAndRestoreLocation(CodeGenFunction &CGF,
+ CGBuilderTy &B)
+ : DI(CGF.getDebugInfo()), Builder(B) {
if (DI) {
SavedLoc = DI->getLocation();
DI->CurLoc = SourceLocation();
- Builder.SetCurrentDebugLocation(llvm::DebugLoc());
}
}
+SaveAndRestoreLocation::~SaveAndRestoreLocation() {
+ if (DI)
+ DI->EmitLocation(Builder, SavedLoc);
+}
+
+NoLocation::NoLocation(CodeGenFunction &CGF, CGBuilderTy &B)
+ : SaveAndRestoreLocation(CGF, B) {
+ if (DI)
+ Builder.SetCurrentDebugLocation(llvm::DebugLoc());
+}
+
NoLocation::~NoLocation() {
- if (DI) {
+ if (DI)
assert(Builder.getCurrentDebugLocation().isUnknown());
- DI->CurLoc = SavedLoc;
- }
}
ArtificialLocation::ArtificialLocation(CodeGenFunction &CGF, CGBuilderTy &B)
- : DI(CGF.getDebugInfo()), Builder(B) {
- if (DI) {
- SavedLoc = DI->getLocation();
- DI->CurLoc = SourceLocation();
+ : SaveAndRestoreLocation(CGF, B) {
+ if (DI)
Builder.SetCurrentDebugLocation(llvm::DebugLoc());
- }
}
void ArtificialLocation::Emit() {
@@ -91,10 +96,8 @@ void ArtificialLocation::Emit() {
}
ArtificialLocation::~ArtificialLocation() {
- if (DI) {
+ if (DI)
assert(Builder.getCurrentDebugLocation().getLine() == 0);
- DI->CurLoc = SavedLoc;
- }
}
void CGDebugInfo::setLocation(SourceLocation Loc) {
@@ -109,17 +112,14 @@ void CGDebugInfo::setLocation(SourceLocation Loc) {
if (LexicalBlockStack.empty()) return;
SourceManager &SM = CGM.getContext().getSourceManager();
+ llvm::DIScope Scope(LexicalBlockStack.back());
PresumedLoc PCLoc = SM.getPresumedLoc(CurLoc);
- PresumedLoc PPLoc = SM.getPresumedLoc(PrevLoc);
- if (PCLoc.isInvalid() || PPLoc.isInvalid() ||
- !strcmp(PPLoc.getFilename(), PCLoc.getFilename()))
+ if (PCLoc.isInvalid() || Scope.getFilename() == PCLoc.getFilename())
return;
- llvm::MDNode *LB = LexicalBlockStack.back();
- llvm::DIScope Scope = llvm::DIScope(LB);
if (Scope.isLexicalBlockFile()) {
- llvm::DILexicalBlockFile LBF = llvm::DILexicalBlockFile(LB);
+ llvm::DILexicalBlockFile LBF = llvm::DILexicalBlockFile(Scope);
llvm::DIDescriptor D
= DBuilder.createLexicalBlockFile(LBF.getScope(),
getOrCreateFile(CurLoc));
@@ -225,34 +225,20 @@ StringRef CGDebugInfo::getSelectorName(Selector S) {
/// getClassName - Get class name including template argument list.
StringRef
CGDebugInfo::getClassName(const RecordDecl *RD) {
- const ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(RD);
- if (!Spec)
+ // quick optimization to avoid having to intern strings that are already
+ // stored reliably elsewhere
+ if (!isa<ClassTemplateSpecializationDecl>(RD))
return RD->getName();
- const TemplateArgument *Args;
- unsigned NumArgs;
- if (TypeSourceInfo *TAW = Spec->getTypeAsWritten()) {
- const TemplateSpecializationType *TST =
- cast<TemplateSpecializationType>(TAW->getType());
- Args = TST->getArgs();
- NumArgs = TST->getNumArgs();
- } else {
- const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- Args = TemplateArgs.data();
- NumArgs = TemplateArgs.size();
- }
- StringRef Name = RD->getIdentifier()->getName();
- PrintingPolicy Policy(CGM.getLangOpts());
- SmallString<128> TemplateArgList;
+ SmallString<128> Name;
{
- llvm::raw_svector_ostream OS(TemplateArgList);
- TemplateSpecializationType::PrintTemplateArgumentList(OS, Args, NumArgs,
- Policy);
+ llvm::raw_svector_ostream OS(Name);
+ RD->getNameForDiagnostic(OS, CGM.getContext().getPrintingPolicy(),
+ /*Qualified*/ false);
}
// Copy this name on the side and use its reference.
- return internString(Name, TemplateArgList);
+ return internString(Name);
}
/// getOrCreateFile - Get the file debug info descriptor for the input location.
@@ -328,11 +314,18 @@ StringRef CGDebugInfo::getCurrentDirname() {
/// CreateCompileUnit - Create new compile unit.
void CGDebugInfo::CreateCompileUnit() {
+ // Should we be asking the SourceManager for the main file name, instead of
+ // accepting it as an argument? This just causes the main file name to
+ // mismatch with source locations and create extra lexical scopes or
+ // mismatched debug info (a CU with a DW_AT_file of "-", because that's what
+ // the driver passed, but functions/other things have DW_AT_file of "<stdin>"
+ // because that's what the SourceManager says)
+
// Get absolute path name.
SourceManager &SM = CGM.getContext().getSourceManager();
std::string MainFileName = CGM.getCodeGenOpts().MainFileName;
if (MainFileName.empty())
- MainFileName = "<unknown>";
+ MainFileName = "<stdin>";
// The main file name provided via the "-main-file-name" option contains just
// the file name itself with no path information. This file name may have had
@@ -342,9 +335,9 @@ void CGDebugInfo::CreateCompileUnit() {
if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
MainFileDir = MainFile->getDir()->getName();
if (MainFileDir != ".") {
- llvm::SmallString<1024> MainFileDirSS(MainFileDir);
- llvm::sys::path::append(MainFileDirSS, MainFileName);
- MainFileName = MainFileDirSS.str();
+ llvm::SmallString<1024> MainFileDirSS(MainFileDir);
+ llvm::sys::path::append(MainFileDirSS, MainFileName);
+ MainFileName = MainFileDirSS.str();
}
}
@@ -355,7 +348,7 @@ void CGDebugInfo::CreateCompileUnit() {
std::string SplitDwarfFile = CGM.getCodeGenOpts().SplitDwarfFile;
StringRef SplitDwarfFilename = internString(SplitDwarfFile);
- unsigned LangTag;
+ llvm::dwarf::SourceLanguage LangTag;
const LangOptions &LO = CGM.getLangOpts();
if (LO.CPlusPlus) {
if (LO.ObjC1)
@@ -379,16 +372,19 @@ void CGDebugInfo::CreateCompileUnit() {
// Create new compile unit.
// FIXME - Eliminate TheCU.
- TheCU = DBuilder.createCompileUnit(LangTag, Filename, getCurrentDirname(),
- Producer, LO.Optimize,
- CGM.getCodeGenOpts().DwarfDebugFlags,
- RuntimeVers, SplitDwarfFilename);
+ TheCU = DBuilder.createCompileUnit(
+ LangTag, Filename, getCurrentDirname(), Producer, LO.Optimize,
+ CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers, SplitDwarfFilename,
+ DebugKind <= CodeGenOptions::DebugLineTablesOnly
+ ? llvm::DIBuilder::LineTablesOnly
+ : llvm::DIBuilder::FullDebug,
+ DebugKind != CodeGenOptions::LocTrackingOnly);
}
/// CreateType - Get the Basic type from the cache or create a new
/// one if necessary.
llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
- unsigned Encoding = 0;
+ llvm::dwarf::TypeKind Encoding;
StringRef BTName;
switch (BT->getKind()) {
#define BUILTIN_TYPE(Id, SingletonId)
@@ -402,11 +398,10 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
case BuiltinType::Void:
return llvm::DIType();
case BuiltinType::ObjCClass:
- if (ClassTy)
- return ClassTy;
- ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- "objc_class", TheCU,
- getOrCreateMainFile(), 0);
+ if (!ClassTy)
+ ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ "objc_class", TheCU,
+ getOrCreateMainFile(), 0);
return ClassTy;
case BuiltinType::ObjCId: {
// typedef struct objc_class *Class;
@@ -435,12 +430,10 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
return ObjTy;
}
case BuiltinType::ObjCSel: {
- if (SelTy)
- return SelTy;
- SelTy =
- DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- "objc_selector", TheCU, getOrCreateMainFile(),
- 0);
+ if (!SelTy)
+ SelTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ "objc_selector", TheCU,
+ getOrCreateMainFile(), 0);
return SelTy;
}
@@ -515,7 +508,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty) {
// Bit size, align and offset of the type.
- unsigned Encoding = llvm::dwarf::DW_ATE_complex_float;
+ llvm::dwarf::TypeKind Encoding = llvm::dwarf::DW_ATE_complex_float;
if (Ty->isComplexIntegerType())
Encoding = llvm::dwarf::DW_ATE_lo_user;
@@ -540,7 +533,7 @@ llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile Unit) {
// We will create one Derived type for one qualifier and recurse to handle any
// additional ones.
- unsigned Tag;
+ llvm::dwarf::Tag Tag;
if (Qc.hasConst()) {
Tag = llvm::dwarf::DW_TAG_const_type;
Qc.removeConst();
@@ -620,7 +613,7 @@ CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty,
unsigned Line = getLineNumber(RD->getLocation());
StringRef RDName = getClassName(RD);
- unsigned Tag = 0;
+ llvm::dwarf::Tag Tag;
if (RD->isStruct() || RD->isInterface())
Tag = llvm::dwarf::DW_TAG_structure_type;
else if (RD->isUnion())
@@ -632,11 +625,13 @@ CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty,
// Create the type.
SmallString<256> FullName = getUniqueTagTypeName(Ty, CGM, TheCU);
- return DBuilder.createForwardDecl(Tag, RDName, Ctx, DefUnit, Line, 0, 0, 0,
- FullName);
+ llvm::DICompositeType RetTy = DBuilder.createReplaceableForwardDecl(
+ Tag, RDName, Ctx, DefUnit, Line, 0, 0, 0, FullName);
+ ReplaceMap.push_back(std::make_pair(Ty, static_cast<llvm::Value *>(RetTy)));
+ return RetTy;
}
-llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
+llvm::DIType CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag,
const Type *Ty,
QualType PointeeTy,
llvm::DIFile Unit) {
@@ -728,22 +723,47 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
return BlockLiteralGeneric;
}
+llvm::DIType CGDebugInfo::CreateType(const TemplateSpecializationType *Ty, llvm::DIFile Unit) {
+ assert(Ty->isTypeAlias());
+ llvm::DIType Src = getOrCreateType(Ty->getAliasedType(), Unit);
+
+ SmallString<128> NS;
+ llvm::raw_svector_ostream OS(NS);
+ Ty->getTemplateName().print(OS, CGM.getContext().getPrintingPolicy(), /*qualified*/ false);
+
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Ty->getArgs(), Ty->getNumArgs(),
+ CGM.getContext().getPrintingPolicy());
+
+ TypeAliasDecl *AliasDecl =
+ cast<TypeAliasTemplateDecl>(Ty->getTemplateName().getAsTemplateDecl())
+ ->getTemplatedDecl();
+
+ SourceLocation Loc = AliasDecl->getLocation();
+ llvm::DIFile File = getOrCreateFile(Loc);
+ unsigned Line = getLineNumber(Loc);
+
+ llvm::DIDescriptor Ctxt = getContextDescriptor(cast<Decl>(AliasDecl->getDeclContext()));
+
+ return DBuilder.createTypedef(Src, internString(OS.str()), File, Line, Ctxt);
+}
+
llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIFile Unit) {
// Typedefs are derived from some other type. If we have a typedef of a
// typedef, make sure to emit the whole chain.
llvm::DIType Src = getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit);
- if (!Src)
- return llvm::DIType();
// We don't set size information, but do specify where the typedef was
// declared.
- unsigned Line = getLineNumber(Ty->getDecl()->getLocation());
+ SourceLocation Loc = Ty->getDecl()->getLocation();
+ llvm::DIFile File = getOrCreateFile(Loc);
+ unsigned Line = getLineNumber(Loc);
const TypedefNameDecl *TyDecl = Ty->getDecl();
llvm::DIDescriptor TypedefContext =
getContextDescriptor(cast<Decl>(Ty->getDecl()->getDeclContext()));
return
- DBuilder.createTypedef(Src, TyDecl->getName(), Unit, Line, TypedefContext);
+ DBuilder.createTypedef(Src, TyDecl->getName(), File, Line, TypedefContext);
}
llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
@@ -751,15 +771,17 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
SmallVector<llvm::Value *, 16> EltTys;
// Add the result type at least.
- EltTys.push_back(getOrCreateType(Ty->getResultType(), Unit));
+ EltTys.push_back(getOrCreateType(Ty->getReturnType(), Unit));
// Set up remainder of arguments if there is a prototype.
- // FIXME: IF NOT, HOW IS THIS REPRESENTED? llvm-gcc doesn't represent '...'!
+ // otherwise emit it as a variadic function.
if (isa<FunctionNoProtoType>(Ty))
EltTys.push_back(DBuilder.createUnspecifiedParameter());
else if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Ty)) {
- for (unsigned i = 0, e = FPT->getNumArgs(); i != e; ++i)
- EltTys.push_back(getOrCreateType(FPT->getArgType(i), Unit));
+ for (unsigned i = 0, e = FPT->getNumParams(); i != e; ++i)
+ EltTys.push_back(getOrCreateType(FPT->getParamType(i), Unit));
+ if (FPT->isVariadic())
+ EltTys.push_back(DBuilder.createUnspecifiedParameter());
}
llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(EltTys);
@@ -784,7 +806,7 @@ llvm::DIType CGDebugInfo::createFieldType(StringRef name,
uint64_t sizeInBits = 0;
unsigned alignInBits = 0;
if (!type->isIncompleteArrayType()) {
- llvm::tie(sizeInBits, alignInBits) = CGM.getContext().getTypeInfo(type);
+ std::tie(sizeInBits, alignInBits) = CGM.getContext().getTypeInfo(type);
if (sizeInBitsOverride)
sizeInBits = sizeInBitsOverride;
@@ -813,7 +835,7 @@ CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl,
unsigned fieldno = 0;
for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(),
E = CXXDecl->captures_end(); I != E; ++I, ++Field, ++fieldno) {
- const LambdaExpr::Capture C = *I;
+ const LambdaCapture &C = *I;
if (C.capturesVariable()) {
VarDecl *V = C.getCapturedVar();
llvm::DIFile VUnit = getOrCreateFile(C.getLocation());
@@ -857,7 +879,7 @@ CGDebugInfo::CreateRecordStaticField(const VarDecl *Var,
unsigned LineNumber = getLineNumber(Var->getLocation());
StringRef VName = Var->getName();
- llvm::Constant *C = NULL;
+ llvm::Constant *C = nullptr;
if (Var->getInit()) {
const APValue *Value = Var->evaluateValue();
if (Value) {
@@ -926,9 +948,8 @@ void CGDebugInfo::CollectRecordFields(const RecordDecl *record,
// Static and non-static members should appear in the same order as
// the corresponding declarations in the source program.
- for (RecordDecl::decl_iterator I = record->decls_begin(),
- E = record->decls_end(); I != E; ++I)
- if (const VarDecl *V = dyn_cast<VarDecl>(*I)) {
+ for (const auto *I : record->decls())
+ if (const auto *V = dyn_cast<VarDecl>(I)) {
// Reuse the existing static member declaration if one exists
llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator MI =
StaticDataMemberCache.find(V->getCanonicalDecl());
@@ -939,7 +960,7 @@ void CGDebugInfo::CollectRecordFields(const RecordDecl *record,
llvm::DIDerivedType(cast<llvm::MDNode>(MI->second)));
} else
elements.push_back(CreateRecordStaticField(V, RecordTy));
- } else if (FieldDecl *field = dyn_cast<FieldDecl>(*I)) {
+ } else if (const auto *field = dyn_cast<FieldDecl>(I)) {
CollectRecordNormalField(field, layout.getFieldOffset(fieldNo),
tunit, elements, RecordTy);
@@ -1005,7 +1026,13 @@ llvm::DICompositeType CGDebugInfo::getOrCreateInstanceMethodType(
llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
- return DBuilder.createSubroutineType(Unit, EltTypeArray);
+ unsigned Flags = 0;
+ if (Func->getExtProtoInfo().RefQualifier == RQ_LValue)
+ Flags |= llvm::DIDescriptor::FlagLValueReference;
+ if (Func->getExtProtoInfo().RefQualifier == RQ_RValue)
+ Flags |= llvm::DIDescriptor::FlagRValueReference;
+
+ return DBuilder.createSubroutineType(Unit, EltTypeArray, Flags);
}
/// isFunctionLocalClass - Return true if CXXRecordDecl is defined
@@ -1084,6 +1111,10 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
}
if (Method->hasPrototype())
Flags |= llvm::DIDescriptor::FlagPrototyped;
+ if (Method->getRefQualifier() == RQ_LValue)
+ Flags |= llvm::DIDescriptor::FlagLValueReference;
+ if (Method->getRefQualifier() == RQ_RValue)
+ Flags |= llvm::DIDescriptor::FlagRValueReference;
llvm::DIArray TParamsArray = CollectFunctionTemplateParams(Method, Unit);
llvm::DISubprogram SP =
@@ -1092,7 +1123,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method,
MethodTy, /*isLocalToUnit=*/false,
/* isDefinition=*/ false,
Virtuality, VIndex, ContainingType,
- Flags, CGM.getLangOpts().Optimize, NULL,
+ Flags, CGM.getLangOpts().Optimize, nullptr,
TParamsArray);
SPCache[Method->getCanonicalDecl()] = llvm::WeakVH(SP);
@@ -1111,9 +1142,8 @@ CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit,
// Since we want more than just the individual member decls if we
// have templated functions iterate over every declaration to gather
// the functions.
- for(DeclContext::decl_iterator I = RD->decls_begin(),
- E = RD->decls_end(); I != E; ++I) {
- if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*I)) {
+ for(const auto *I : RD->decls()) {
+ if (const auto *Method = dyn_cast<CXXMethodDecl>(I)) {
// Reuse the existing member function declaration if it exists.
// It may be associated with the declaration of the type & should be
// reused as we're building the definition.
@@ -1130,16 +1160,13 @@ CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit,
EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy));
} else
EltTys.push_back(MI->second);
- } else if (const FunctionTemplateDecl *FTD =
- dyn_cast<FunctionTemplateDecl>(*I)) {
+ } else if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(I)) {
// Add any template specializations that have already been seen. Like
// implicit member functions, these may have been added to a declaration
// in the case of vtable-based debug info reduction.
- for (FunctionTemplateDecl::spec_iterator SI = FTD->spec_begin(),
- SE = FTD->spec_end();
- SI != SE; ++SI) {
+ for (const auto *SI : FTD->specializations()) {
llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator MI =
- SPCache.find(cast<CXXMethodDecl>(*SI)->getCanonicalDecl());
+ SPCache.find(cast<CXXMethodDecl>(SI)->getCanonicalDecl());
if (MI != SPCache.end())
EltTys.push_back(MI->second);
}
@@ -1156,15 +1183,14 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
llvm::DIType RecordTy) {
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
- for (CXXRecordDecl::base_class_const_iterator BI = RD->bases_begin(),
- BE = RD->bases_end(); BI != BE; ++BI) {
+ for (const auto &BI : RD->bases()) {
unsigned BFlags = 0;
uint64_t BaseOffset;
const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(BI->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(BI.getType()->getAs<RecordType>()->getDecl());
- if (BI->isVirtual()) {
+ if (BI.isVirtual()) {
// virtual base offset offset is -ve. The code generator emits dwarf
// expression where it expects +ve number.
BaseOffset =
@@ -1176,7 +1202,7 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
// FIXME: Inconsistent units for BaseOffset. It is in bytes when
// BI->isVirtual() and bits when not.
- AccessSpecifier Access = BI->getAccessSpecifier();
+ AccessSpecifier Access = BI.getAccessSpecifier();
if (Access == clang::AS_private)
BFlags |= llvm::DIDescriptor::FlagPrivate;
else if (Access == clang::AS_protected)
@@ -1184,7 +1210,7 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit,
llvm::DIType DTy =
DBuilder.createInheritance(RecordTy,
- getOrCreateType(BI->getType(), Unit),
+ getOrCreateType(BI.getType(), Unit),
BaseOffset, BFlags);
EltTys.push_back(DTy);
}
@@ -1225,7 +1251,7 @@ CollectTemplateParams(const TemplateParameterList *TPList,
->getTypeForDecl())
: CGM.getContext().getPointerType(D->getType());
llvm::DIType TTy = getOrCreateType(T, Unit);
- llvm::Value *V = 0;
+ llvm::Value *V = nullptr;
// Variable pointer template parameters have a value that is the address
// of the variable.
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
@@ -1239,7 +1265,7 @@ CollectTemplateParams(const TemplateParameterList *TPList,
V = CGM.GetAddrOfFunction(FD);
// Member data pointers have special handling too to compute the fixed
// offset within the object.
- if (isa<FieldDecl>(D)) {
+ if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) {
// These five lines (& possibly the above member function pointer
// handling) might be able to be refactored to use similar code in
// CodeGenModule::getMemberPointerConstant
@@ -1257,7 +1283,7 @@ CollectTemplateParams(const TemplateParameterList *TPList,
case TemplateArgument::NullPtr: {
QualType T = TA.getNullPtrType();
llvm::DIType TTy = getOrCreateType(T, Unit);
- llvm::Value *V = 0;
+ llvm::Value *V = nullptr;
// Special case member data pointer null values since they're actually -1
// instead of zero.
if (const MemberPointerType *MPT =
@@ -1287,7 +1313,7 @@ CollectTemplateParams(const TemplateParameterList *TPList,
llvm::DITemplateValueParameter TVP =
DBuilder.createTemplateParameterPack(
TheCU, Name, llvm::DIType(),
- CollectTemplateParams(NULL, TA.getPackAsArray(), Unit));
+ CollectTemplateParams(nullptr, TA.getPackAsArray(), Unit));
TemplateParams.push_back(TVP);
} break;
case TemplateArgument::Expression: {
@@ -1331,14 +1357,11 @@ CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit) {
llvm::DIArray CGDebugInfo::
CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TSpecial,
llvm::DIFile Unit) {
- llvm::PointerUnion<ClassTemplateDecl *,
- ClassTemplatePartialSpecializationDecl *>
- PU = TSpecial->getSpecializedTemplateOrPartial();
-
- TemplateParameterList *TPList = PU.is<ClassTemplateDecl *>() ?
- PU.get<ClassTemplateDecl *>()->getTemplateParameters() :
- PU.get<ClassTemplatePartialSpecializationDecl *>()->getTemplateParameters();
- const TemplateArgumentList &TAList = TSpecial->getTemplateInstantiationArgs();
+ // Always get the full list of parameters, not just the ones from
+ // the specialization.
+ TemplateParameterList *TPList =
+ TSpecial->getSpecializedTemplate()->getTemplateParameters();
+ const TemplateArgumentList &TAList = TSpecial->getTemplateArgs();
return CollectTemplateParams(TPList, TAList.asArray(), Unit);
}
@@ -1409,6 +1432,21 @@ llvm::DIType CGDebugInfo::getOrCreateInterfaceType(QualType D,
return T;
}
+void CGDebugInfo::completeType(const EnumDecl *ED) {
+ if (DebugKind <= CodeGenOptions::DebugLineTablesOnly)
+ return;
+ QualType Ty = CGM.getContext().getEnumType(ED);
+ void* TyPtr = Ty.getAsOpaquePtr();
+ auto I = TypeCache.find(TyPtr);
+ if (I == TypeCache.end() ||
+ !llvm::DIType(cast<llvm::MDNode>(static_cast<llvm::Value *>(I->second)))
+ .isForwardDecl())
+ return;
+ llvm::DIType Res = CreateTypeDefinition(Ty->castAs<EnumType>());
+ assert(!Res.isForwardDecl());
+ TypeCache[TyPtr] = Res;
+}
+
void CGDebugInfo::completeType(const RecordDecl *RD) {
if (DebugKind > CodeGenOptions::LimitedDebugInfo ||
!CGM.getLangOpts().CPlusPlus)
@@ -1416,6 +1454,9 @@ void CGDebugInfo::completeType(const RecordDecl *RD) {
}
void CGDebugInfo::completeRequiredType(const RecordDecl *RD) {
+ if (DebugKind <= CodeGenOptions::DebugLineTablesOnly)
+ return;
+
if (const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD))
if (CXXDecl->isDynamicClass())
return;
@@ -1431,40 +1472,67 @@ void CGDebugInfo::completeClassData(const RecordDecl *RD) {
return;
QualType Ty = CGM.getContext().getRecordType(RD);
void* TyPtr = Ty.getAsOpaquePtr();
- if (CompletedTypeCache.count(TyPtr))
+ auto I = TypeCache.find(TyPtr);
+ if (I != TypeCache.end() &&
+ !llvm::DIType(cast<llvm::MDNode>(static_cast<llvm::Value *>(I->second)))
+ .isForwardDecl())
return;
llvm::DIType Res = CreateTypeDefinition(Ty->castAs<RecordType>());
assert(!Res.isForwardDecl());
- CompletedTypeCache[TyPtr] = Res;
TypeCache[TyPtr] = Res;
}
+static bool hasExplicitMemberDefinition(CXXRecordDecl::method_iterator I,
+ CXXRecordDecl::method_iterator End) {
+ for (; I != End; ++I)
+ if (FunctionDecl *Tmpl = I->getInstantiatedFromMemberFunction())
+ if (!Tmpl->isImplicit() && Tmpl->isThisDeclarationADefinition() &&
+ !I->getMemberSpecializationInfo()->isExplicitSpecialization())
+ return true;
+ return false;
+}
+
+static bool shouldOmitDefinition(CodeGenOptions::DebugInfoKind DebugKind,
+ const RecordDecl *RD,
+ const LangOptions &LangOpts) {
+ if (DebugKind > CodeGenOptions::LimitedDebugInfo)
+ return false;
+
+ if (!LangOpts.CPlusPlus)
+ return false;
+
+ if (!RD->isCompleteDefinitionRequired())
+ return true;
+
+ const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
+
+ if (!CXXDecl)
+ return false;
+
+ if (CXXDecl->hasDefinition() && CXXDecl->isDynamicClass())
+ return true;
+
+ TemplateSpecializationKind Spec = TSK_Undeclared;
+ if (const ClassTemplateSpecializationDecl *SD =
+ dyn_cast<ClassTemplateSpecializationDecl>(RD))
+ Spec = SD->getSpecializationKind();
+
+ if (Spec == TSK_ExplicitInstantiationDeclaration &&
+ hasExplicitMemberDefinition(CXXDecl->method_begin(),
+ CXXDecl->method_end()))
+ return true;
+
+ return false;
+}
+
/// CreateType - get structure or union type.
llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
RecordDecl *RD = Ty->getDecl();
- const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
- // Always emit declarations for types that aren't required to be complete when
- // in limit-debug-info mode. If the type is later found to be required to be
- // complete this declaration will be upgraded to a definition by
- // `completeRequiredType`.
- // If the type is dynamic, only emit the definition in TUs that require class
- // data. This is handled by `completeClassData`.
llvm::DICompositeType T(getTypeOrNull(QualType(Ty, 0)));
- // If we've already emitted the type, just use that, even if it's only a
- // declaration. The completeType, completeRequiredType, and completeClassData
- // callbacks will handle promoting the declaration to a definition.
- if (T ||
- (DebugKind <= CodeGenOptions::LimitedDebugInfo &&
- // Under -flimit-debug-info, emit only a declaration unless the type is
- // required to be complete.
- !RD->isCompleteDefinitionRequired() && CGM.getLangOpts().CPlusPlus) ||
- // If the class is dynamic, only emit a declaration. A definition will be
- // emitted whenever the vtable is emitted.
- (CXXDecl && CXXDecl->hasDefinition() && CXXDecl->isDynamicClass()) || T) {
- llvm::DIDescriptor FDContext =
- getContextDescriptor(cast<Decl>(RD->getDeclContext()));
+ if (T || shouldOmitDefinition(DebugKind, RD, CGM.getLangOpts())) {
if (!T)
- T = getOrCreateRecordFwdDecl(Ty, FDContext);
+ T = getOrCreateRecordFwdDecl(
+ Ty, getContextDescriptor(cast<Decl>(RD->getDeclContext())));
return T;
}
@@ -1498,9 +1566,6 @@ llvm::DIType CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) {
LexicalBlockStack.push_back(&*FwdDecl);
RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
- // Add this to the completed-type cache while we're completing it recursively.
- CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
-
// Convert all the elements.
SmallVector<llvm::Value *, 16> EltTys;
// what about nested types?
@@ -1572,20 +1637,28 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// Get overall information about the record type for the debug info.
llvm::DIFile DefUnit = getOrCreateFile(ID->getLocation());
unsigned Line = getLineNumber(ID->getLocation());
- unsigned RuntimeLang = TheCU.getLanguage();
+ llvm::dwarf::SourceLanguage RuntimeLang = TheCU.getLanguage();
// If this is just a forward declaration return a special forward-declaration
// debug type since we won't be able to lay out the entire type.
ObjCInterfaceDecl *Def = ID->getDefinition();
- if (!Def) {
- llvm::DIType FwdDecl =
- DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- ID->getName(), TheCU, DefUnit, Line,
- RuntimeLang);
+ if (!Def || !Def->getImplementation()) {
+ llvm::DIType FwdDecl = DBuilder.createReplaceableForwardDecl(
+ llvm::dwarf::DW_TAG_structure_type, ID->getName(), TheCU, DefUnit, Line,
+ RuntimeLang);
+ ObjCInterfaceCache.push_back(ObjCInterfaceCacheEntry(Ty, FwdDecl, Unit));
return FwdDecl;
}
- ID = Def;
+
+ return CreateTypeDefinition(Ty, Unit);
+}
+
+llvm::DIType CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty, llvm::DIFile Unit) {
+ ObjCInterfaceDecl *ID = Ty->getDecl();
+ llvm::DIFile DefUnit = getOrCreateFile(ID->getLocation());
+ unsigned Line = getLineNumber(ID->getLocation());
+ unsigned RuntimeLang = TheCU.getLanguage();
// Bit size, align and offset of the type.
uint64_t Size = CGM.getContext().getTypeSize(Ty);
@@ -1600,10 +1673,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
Line, Size, Align, Flags,
llvm::DIType(), llvm::DIArray(), RuntimeLang);
- // Otherwise, insert it into the CompletedTypeCache so that recursive uses
- // will find it and we're emitting the complete type.
- QualType QualTy = QualType(Ty, 0);
- CompletedTypeCache[QualTy.getAsOpaquePtr()] = RealDecl;
+ QualType QTy(Ty, 0);
+ TypeCache[QTy.getAsOpaquePtr()] = RealDecl;
// Push the struct on region stack.
LexicalBlockStack.push_back(static_cast<llvm::MDNode*>(RealDecl));
@@ -1625,9 +1696,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
}
// Create entries for all of the properties.
- for (ObjCContainerDecl::prop_iterator I = ID->prop_begin(),
- E = ID->prop_end(); I != E; ++I) {
- const ObjCPropertyDecl *PD = *I;
+ for (const auto *PD : ID->properties()) {
SourceLocation Loc = PD->getLocation();
llvm::DIFile PUnit = getOrCreateFile(Loc);
unsigned PLine = getLineNumber(Loc);
@@ -1697,7 +1766,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
else if (Field->getAccessControl() == ObjCIvarDecl::Private)
Flags = llvm::DIDescriptor::FlagPrivate;
- llvm::MDNode *PropertyNode = NULL;
+ llvm::MDNode *PropertyNode = nullptr;
if (ObjCImplementationDecl *ImpD = ID->getImplementation()) {
if (ObjCPropertyImplDecl *PImpD =
ImpD->FindPropertyImplIvarDecl(Field->getIdentifier())) {
@@ -1729,12 +1798,6 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
RealDecl.setTypeArray(Elements);
- // If the implementation is not yet set, we do not want to mark it
- // as complete. An implementation may declare additional
- // private ivars that we would miss otherwise.
- if (ID->getImplementation() == 0)
- CompletedTypeCache.erase(QualTy.getAsOpaquePtr());
-
LexicalBlockStack.pop_back();
return RealDecl;
}
@@ -1829,11 +1892,13 @@ llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty,
if (!Ty->getPointeeType()->isFunctionType())
return DBuilder.createMemberPointerType(
getOrCreateType(Ty->getPointeeType(), U), ClassType);
+
+ const FunctionProtoType *FPT =
+ Ty->getPointeeType()->getAs<FunctionProtoType>();
return DBuilder.createMemberPointerType(getOrCreateInstanceMethodType(
- CGM.getContext().getPointerType(
- QualType(Ty->getClass(), Ty->getPointeeType().getCVRQualifiers())),
- Ty->getPointeeType()->getAs<FunctionProtoType>(), U),
- ClassType);
+ CGM.getContext().getPointerType(QualType(Ty->getClass(),
+ FPT->getTypeQuals())),
+ FPT, U), ClassType);
}
llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty,
@@ -1863,17 +1928,31 @@ llvm::DIType CGDebugInfo::CreateEnumType(const EnumType *Ty) {
llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation());
unsigned Line = getLineNumber(ED->getLocation());
StringRef EDName = ED->getName();
- return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_enumeration_type,
- EDName, EDContext, DefUnit, Line, 0,
- Size, Align, FullName);
+ llvm::DIType RetTy = DBuilder.createReplaceableForwardDecl(
+ llvm::dwarf::DW_TAG_enumeration_type, EDName, EDContext, DefUnit, Line,
+ 0, Size, Align, FullName);
+ ReplaceMap.push_back(std::make_pair(Ty, static_cast<llvm::Value *>(RetTy)));
+ return RetTy;
+ }
+
+ return CreateTypeDefinition(Ty);
+}
+
+llvm::DIType CGDebugInfo::CreateTypeDefinition(const EnumType *Ty) {
+ const EnumDecl *ED = Ty->getDecl();
+ uint64_t Size = 0;
+ uint64_t Align = 0;
+ if (!ED->getTypeForDecl()->isIncompleteType()) {
+ Size = CGM.getContext().getTypeSize(ED->getTypeForDecl());
+ Align = CGM.getContext().getTypeAlign(ED->getTypeForDecl());
}
+ SmallString<256> FullName = getUniqueTagTypeName(Ty, CGM, TheCU);
+
// Create DIEnumerator elements for each enumerator.
SmallVector<llvm::Value *, 16> Enumerators;
ED = ED->getDefinition();
- for (EnumDecl::enumerator_iterator
- Enum = ED->enumerator_begin(), EnumEnd = ED->enumerator_end();
- Enum != EnumEnd; ++Enum) {
+ for (const auto *Enum : ED->enumerators()) {
Enumerators.push_back(
DBuilder.createEnumerator(Enum->getName(),
Enum->getInitVal().getSExtValue()));
@@ -1907,9 +1986,12 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
switch (T->getTypeClass()) {
default:
return C.getQualifiedType(T.getTypePtr(), Quals);
- case Type::TemplateSpecialization:
- T = cast<TemplateSpecializationType>(T)->desugar();
- break;
+ case Type::TemplateSpecialization: {
+ const auto *Spec = cast<TemplateSpecializationType>(T);
+ if (Spec->isTypeAlias())
+ return C.getQualifiedType(T.getTypePtr(), Quals);
+ T = Spec->desugar();
+ break; }
case Type::TypeOfExpr:
T = cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType();
break;
@@ -1954,16 +2036,7 @@ llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) {
// Unwrap the type as needed for debug information.
Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
- // Check for existing entry.
- if (Ty->getTypeClass() == Type::ObjCInterface) {
- llvm::Value *V = getCachedInterfaceTypeOrNull(Ty);
- if (V)
- return llvm::DIType(cast<llvm::MDNode>(V));
- else return llvm::DIType();
- }
-
- llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
- TypeCache.find(Ty.getAsOpaquePtr());
+ auto it = TypeCache.find(Ty.getAsOpaquePtr());
if (it != TypeCache.end()) {
// Verify that the debug info still exists.
if (llvm::Value *V = it->second)
@@ -1973,41 +2046,15 @@ llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) {
return llvm::DIType();
}
-/// getCompletedTypeOrNull - Get the type from the cache or return null if it
-/// doesn't exist.
-llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) {
-
- // Unwrap the type as needed for debug information.
- Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
-
- // Check for existing entry.
- llvm::Value *V = 0;
- llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
- CompletedTypeCache.find(Ty.getAsOpaquePtr());
- if (it != CompletedTypeCache.end())
- V = it->second;
- else {
- V = getCachedInterfaceTypeOrNull(Ty);
- }
-
- // Verify that any cached debug info still exists.
- return llvm::DIType(cast_or_null<llvm::MDNode>(V));
-}
-
-/// getCachedInterfaceTypeOrNull - Get the type from the interface
-/// cache, unless it needs to regenerated. Otherwise return null.
-llvm::Value *CGDebugInfo::getCachedInterfaceTypeOrNull(QualType Ty) {
- // Is there a cached interface that hasn't changed?
- llvm::DenseMap<void *, std::pair<llvm::WeakVH, unsigned > >
- ::iterator it1 = ObjCInterfaceCache.find(Ty.getAsOpaquePtr());
-
- if (it1 != ObjCInterfaceCache.end())
- if (ObjCInterfaceDecl* Decl = getObjCInterfaceDecl(Ty))
- if (Checksum(Decl) == it1->second.second)
- // Return cached forward declaration.
- return it1->second.first;
+void CGDebugInfo::completeTemplateDefinition(
+ const ClassTemplateSpecializationDecl &SD) {
+ if (DebugKind <= CodeGenOptions::DebugLineTablesOnly)
+ return;
- return 0;
+ completeClassData(&SD);
+ // In case this type has no member function definitions being emitted, ensure
+ // it is retained
+ RetainedTypes.push_back(CGM.getContext().getRecordType(&SD).getAsOpaquePtr());
}
/// getOrCreateType - Get the type from the cache or create a new
@@ -2019,7 +2066,7 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
// Unwrap the type as needed for debug information.
Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
- if (llvm::DIType T = getCompletedTypeOrNull(Ty))
+ if (llvm::DIType T = getTypeOrNull(Ty))
return T;
// Otherwise create the type.
@@ -2029,39 +2076,6 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
// And update the type cache.
TypeCache[TyPtr] = Res;
- // FIXME: this getTypeOrNull call seems silly when we just inserted the type
- // into the cache - but getTypeOrNull has a special case for cached interface
- // types. We should probably just pull that out as a special case for the
- // "else" block below & skip the otherwise needless lookup.
- llvm::DIType TC = getTypeOrNull(Ty);
- if (TC && TC.isForwardDecl())
- ReplaceMap.push_back(std::make_pair(TyPtr, static_cast<llvm::Value*>(TC)));
- else if (ObjCInterfaceDecl* Decl = getObjCInterfaceDecl(Ty)) {
- // Interface types may have elements added to them by a
- // subsequent implementation or extension, so we keep them in
- // the ObjCInterfaceCache together with a checksum. Instead of
- // the (possibly) incomplete interface type, we return a forward
- // declaration that gets RAUW'd in CGDebugInfo::finalize().
- std::pair<llvm::WeakVH, unsigned> &V = ObjCInterfaceCache[TyPtr];
- if (V.first)
- return llvm::DIType(cast<llvm::MDNode>(V.first));
- TC = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- Decl->getName(), TheCU, Unit,
- getLineNumber(Decl->getLocation()),
- TheCU.getLanguage());
- // Store the forward declaration in the cache.
- V.first = TC;
- V.second = Checksum(Decl);
-
- // Register the type for replacement in finalize().
- ReplaceMap.push_back(std::make_pair(TyPtr, static_cast<llvm::Value*>(TC)));
-
- return TC;
- }
-
- if (!Res.isForwardDecl())
- CompletedTypeCache[TyPtr] = Res;
-
return Res;
}
@@ -2073,7 +2087,7 @@ unsigned CGDebugInfo::Checksum(const ObjCInterfaceDecl *ID) {
// a checksum.
unsigned Sum = 0;
for (const ObjCIvarDecl *Ivar = ID->all_declared_ivar_begin();
- Ivar != 0; Ivar = Ivar->getNextIvar())
+ Ivar != nullptr; Ivar = Ivar->getNextIvar())
++Sum;
return Sum;
@@ -2087,7 +2101,7 @@ ObjCInterfaceDecl *CGDebugInfo::getObjCInterfaceDecl(QualType Ty) {
case Type::ObjCInterface:
return cast<ObjCInterfaceType>(Ty)->getDecl();
default:
- return 0;
+ return nullptr;
}
}
@@ -2097,7 +2111,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
if (Ty.hasLocalQualifiers())
return CreateQualifiedType(Ty, Unit);
- const char *Diag = 0;
+ const char *Diag = nullptr;
// Work out details of type.
switch (Ty->getTypeClass()) {
@@ -2123,10 +2137,11 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
return CreateType(cast<ComplexType>(Ty));
case Type::Pointer:
return CreateType(cast<PointerType>(Ty), Unit);
+ case Type::Adjusted:
case Type::Decayed:
- // Decayed types are just pointers in LLVM and DWARF.
+ // Decayed and adjusted types use the adjusted type in LLVM and DWARF.
return CreateType(
- cast<PointerType>(cast<DecayedType>(Ty)->getDecayedType()), Unit);
+ cast<PointerType>(cast<AdjustedType>(Ty)->getAdjustedType()), Unit);
case Type::BlockPointer:
return CreateType(cast<BlockPointerType>(Ty), Unit);
case Type::Typedef:
@@ -2154,8 +2169,10 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
case Type::Atomic:
return CreateType(cast<AtomicType>(Ty), Unit);
- case Type::Attributed:
case Type::TemplateSpecialization:
+ return CreateType(cast<TemplateSpecializationType>(Ty), Unit);
+
+ case Type::Attributed:
case Type::Elaborated:
case Type::Paren:
case Type::SubstTemplateTypeParm:
@@ -2199,10 +2216,6 @@ llvm::DIType CGDebugInfo::getOrCreateLimitedType(const RecordType *Ty,
// correct order if the full type is needed.
Res.setTypeArray(T.getTypeArray());
- if (T && T.isForwardDecl())
- ReplaceMap.push_back(
- std::make_pair(QTy.getAsOpaquePtr(), static_cast<llvm::Value *>(T)));
-
// And update the type cache.
TypeCache[QTy.getAsOpaquePtr()] = Res;
return Res;
@@ -2222,20 +2235,14 @@ llvm::DICompositeType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
// If we ended up creating the type during the context chain construction,
// just return that.
- // FIXME: this could be dealt with better if the type was recorded as
- // completed before we started this (see the CompletedTypeCache usage in
- // CGDebugInfo::CreateTypeDefinition(const RecordType*) - that would need to
- // be pushed to before context creation, but after it was known to be
- // destined for completion (might still have an issue if this caller only
- // required a declaration but the context construction ended up creating a
- // definition)
llvm::DICompositeType T(getTypeOrNull(CGM.getContext().getRecordType(RD)));
if (T && (!T.isForwardDecl() || !RD->getDefinition()))
return T;
- // If this is just a forward declaration, construct an appropriately
- // marked node and just return it.
- if (!RD->getDefinition())
+ // If this is just a forward or incomplete declaration, construct an
+ // appropriately marked node and just return it.
+ const RecordDecl *D = RD->getDefinition();
+ if (!D || !D->isCompleteDefinition())
return getOrCreateRecordFwdDecl(Ty, RDContext);
uint64_t Size = CGM.getContext().getTypeSize(Ty);
@@ -2277,7 +2284,7 @@ void CGDebugInfo::CollectContainingType(const CXXRecordDecl *RD,
llvm::DICompositeType ContainingType;
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
- // Seek non virtual primary base root.
+ // Seek non-virtual primary base root.
while (1) {
const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
const CXXRecordDecl *PBT = BRL.getPrimaryBase();
@@ -2309,7 +2316,7 @@ llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType,
return Ty;
}
-llvm::DIDescriptor CGDebugInfo::getDeclarationOrDefinition(const Decl *D) {
+llvm::DIScope CGDebugInfo::getDeclarationOrDefinition(const Decl *D) {
// We only need a declaration (not a definition) of the type - so use whatever
// we would otherwise do to get a type for a pointee. (forward declarations in
// limited debug info, full definitions (if the type definition is available)
@@ -2327,15 +2334,15 @@ llvm::DIDescriptor CGDebugInfo::getDeclarationOrDefinition(const Decl *D) {
llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator I =
DeclCache.find(D->getCanonicalDecl());
if (I == DeclCache.end())
- return llvm::DIDescriptor();
+ return llvm::DIScope();
llvm::Value *V = I->second;
- return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(V));
+ return llvm::DIScope(dyn_cast_or_null<llvm::MDNode>(V));
}
/// getFunctionDeclaration - Return debug info descriptor to describe method
/// declaration for the given method definition.
llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
- if (!D || DebugKind == CodeGenOptions::DebugLineTablesOnly)
+ if (!D || DebugKind <= CodeGenOptions::DebugLineTablesOnly)
return llvm::DISubprogram();
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
@@ -2352,7 +2359,6 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
llvm::DICompositeType T(S);
llvm::DISubprogram SP =
CreateCXXMemberFunction(MD, getOrCreateFile(MD->getLocation()), T);
- T.addMember(SP);
return SP;
}
}
@@ -2363,9 +2369,7 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
return SP;
}
- for (FunctionDecl::redecl_iterator I = FD->redecls_begin(),
- E = FD->redecls_end(); I != E; ++I) {
- const FunctionDecl *NextFD = *I;
+ for (auto NextFD : FD->redecls()) {
llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
MI = SPCache.find(NextFD->getCanonicalDecl());
if (MI != SPCache.end()) {
@@ -2383,7 +2387,7 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
llvm::DICompositeType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
QualType FnType,
llvm::DIFile F) {
- if (!D || DebugKind == CodeGenOptions::DebugLineTablesOnly)
+ if (!D || DebugKind <= CodeGenOptions::DebugLineTablesOnly)
// Create fake but valid subroutine type. Otherwise
// llvm::DISubprogram::Verify() would return false, and
// subprogram DIE will miss DW_AT_decl_file and
@@ -2397,7 +2401,7 @@ llvm::DICompositeType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
SmallVector<llvm::Value *, 16> Elts;
// First element is always return type. For 'void' functions it is NULL.
- QualType ResultTy = OMethod->getResultType();
+ QualType ResultTy = OMethod->getReturnType();
// Replace the instancetype keyword with the actual type.
if (ResultTy == CGM.getContext().getObjCInstanceType())
@@ -2413,18 +2417,35 @@ llvm::DICompositeType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
llvm::DIType CmdTy = getOrCreateType(OMethod->getCmdDecl()->getType(), F);
Elts.push_back(DBuilder.createArtificialType(CmdTy));
// Get rest of the arguments.
- for (ObjCMethodDecl::param_const_iterator PI = OMethod->param_begin(),
- PE = OMethod->param_end(); PI != PE; ++PI)
- Elts.push_back(getOrCreateType((*PI)->getType(), F));
+ for (const auto *PI : OMethod->params())
+ Elts.push_back(getOrCreateType(PI->getType(), F));
llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
return DBuilder.createSubroutineType(F, EltTypeArray);
}
+
+ // Handle variadic function types; they need an additional
+ // unspecified parameter.
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (FD->isVariadic()) {
+ SmallVector<llvm::Value *, 16> EltTys;
+ EltTys.push_back(getOrCreateType(FD->getReturnType(), F));
+ if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FnType))
+ for (unsigned i = 0, e = FPT->getNumParams(); i != e; ++i)
+ EltTys.push_back(getOrCreateType(FPT->getParamType(i), F));
+ EltTys.push_back(DBuilder.createUnspecifiedParameter());
+ llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(EltTys);
+ return DBuilder.createSubroutineType(F, EltTypeArray);
+ }
+
return llvm::DICompositeType(getOrCreateType(FnType, F));
}
/// EmitFunctionStart - Constructs the debug code for entering a function.
-void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
+void CGDebugInfo::EmitFunctionStart(GlobalDecl GD,
+ SourceLocation Loc,
+ SourceLocation ScopeLoc,
+ QualType FnType,
llvm::Function *Fn,
CGBuilderTy &Builder) {
@@ -2434,13 +2455,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
FnBeginRegionCount.push_back(LexicalBlockStack.size());
const Decl *D = GD.getDecl();
- // Function may lack declaration in source code if it is created by Clang
- // CodeGen (examples: _GLOBAL__I_a, __cxx_global_array_dtor, thunk).
- bool HasDecl = (D != 0);
- // Use the location of the declaration.
- SourceLocation Loc;
- if (HasDecl)
- Loc = D->getLocation();
+ bool HasDecl = (D != nullptr);
unsigned Flags = 0;
llvm::DIFile Unit = getOrCreateFile(Loc);
@@ -2500,23 +2515,34 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
if (!Name.empty() && Name[0] == '\01')
Name = Name.substr(1);
- unsigned LineNo = getLineNumber(Loc);
- if (!HasDecl || D->isImplicit())
+ if (!HasDecl || D->isImplicit()) {
Flags |= llvm::DIDescriptor::FlagArtificial;
+ // Artificial functions without a location should not silently reuse CurLoc.
+ if (Loc.isInvalid())
+ CurLoc = SourceLocation();
+ }
+ unsigned LineNo = getLineNumber(Loc);
+ unsigned ScopeLine = getLineNumber(ScopeLoc);
+ // FIXME: The function declaration we're constructing here is mostly reusing
+ // declarations from CXXMethodDecl and not constructing new ones for arbitrary
+ // FunctionDecls. When/if we fix this we can have FDContext be TheCU/null for
+ // all subprograms instead of the actual context since subprogram definitions
+ // are emitted as CU level entities by the backend.
llvm::DISubprogram SP =
DBuilder.createFunction(FDContext, Name, LinkageName, Unit, LineNo,
getOrCreateFunctionType(D, FnType, Unit),
Fn->hasInternalLinkage(), true /*definition*/,
- getLineNumber(CurLoc), Flags,
+ ScopeLine, Flags,
CGM.getLangOpts().Optimize, Fn, TParamsArray,
getFunctionDeclaration(D));
if (HasDecl)
DeclCache.insert(std::make_pair(D->getCanonicalDecl(), llvm::WeakVH(SP)));
- // Push function on region stack.
+ // Push the function onto the lexical block stack.
llvm::MDNode *SPN = SP;
LexicalBlockStack.push_back(SPN);
+
if (HasDecl)
RegionMap[D] = llvm::WeakVH(SP);
}
@@ -2554,13 +2580,11 @@ void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc,
/// CreateLexicalBlock - Creates a new lexical block node and pushes it on
/// the stack.
void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) {
- llvm::DIDescriptor D =
- DBuilder.createLexicalBlock(LexicalBlockStack.empty() ?
- llvm::DIDescriptor() :
- llvm::DIDescriptor(LexicalBlockStack.back()),
- getOrCreateFile(CurLoc),
- getLineNumber(CurLoc),
- getColumnNumber(CurLoc));
+ llvm::DIDescriptor D = DBuilder.createLexicalBlock(
+ llvm::DIDescriptor(LexicalBlockStack.empty() ? nullptr
+ : LexicalBlockStack.back()),
+ getOrCreateFile(CurLoc), getLineNumber(CurLoc), getColumnNumber(CurLoc),
+ 0);
llvm::MDNode *DN = D;
LexicalBlockStack.push_back(DN);
}
@@ -2664,7 +2688,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
}
FType = Type;
- llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
+ llvm::DIType FieldTy = getOrCreateType(FType, Unit);
FieldSize = CGM.getContext().getTypeSize(FType);
FieldAlign = CGM.getContext().toBits(Align);
@@ -2684,7 +2708,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
}
/// EmitDeclare - Emit local variable declaration debug info.
-void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
+void CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::dwarf::LLVMConstants Tag,
llvm::Value *Storage,
unsigned ArgNo, CGBuilderTy &Builder) {
assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
@@ -2768,10 +2792,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
// all union fields.
const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
if (RD->isUnion() && RD->isAnonymousStructOrUnion()) {
- for (RecordDecl::field_iterator I = RD->field_begin(),
- E = RD->field_end();
- I != E; ++I) {
- FieldDecl *Field = *I;
+ for (const auto *Field : RD->fields()) {
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
StringRef FieldName = Field->getName();
@@ -2824,7 +2845,6 @@ llvm::DIType CGDebugInfo::CreateSelfType(const QualType &QualTy,
llvm::DIType Ty) {
llvm::DIType CachedTy = getTypeOrNull(QualTy);
if (CachedTy) Ty = CachedTy;
- else DEBUG(llvm::dbgs() << "No cached type for self.");
return DBuilder.createObjectPointerType(Ty);
}
@@ -2835,7 +2855,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!");
- if (Builder.GetInsertBlock() == 0)
+ if (Builder.GetInsertBlock() == nullptr)
return;
bool isByRef = VD->hasAttr<BlocksAttr>();
@@ -2965,15 +2985,12 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
BlockLayoutChunk chunk;
chunk.OffsetInBits =
blockLayout->getElementOffsetInBits(block.CXXThisIndex);
- chunk.Capture = 0;
+ chunk.Capture = nullptr;
chunks.push_back(chunk);
}
// Variable captures.
- for (BlockDecl::capture_const_iterator
- i = blockDecl->capture_begin(), e = blockDecl->capture_end();
- i != e; ++i) {
- const BlockDecl::Capture &capture = *i;
+ for (const auto &capture : blockDecl->captures()) {
const VarDecl *variable = capture.getVariable();
const CGBlockInfo::Capture &captureInfo = block.getCapture(variable);
@@ -3085,10 +3102,40 @@ CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) {
llvm::DICompositeType Ctxt(
getContextDescriptor(cast<Decl>(D->getDeclContext())));
llvm::DIDerivedType T = CreateRecordStaticField(D, Ctxt);
- Ctxt.addMember(T);
return T;
}
+/// Recursively collect all of the member fields of a global anonymous decl and
+/// create static variables for them. The first time this is called it needs
+/// to be on a union and then from there we can have additional unnamed fields.
+llvm::DIGlobalVariable
+CGDebugInfo::CollectAnonRecordDecls(const RecordDecl *RD, llvm::DIFile Unit,
+ unsigned LineNo, StringRef LinkageName,
+ llvm::GlobalVariable *Var,
+ llvm::DIDescriptor DContext) {
+ llvm::DIGlobalVariable GV;
+
+ for (const auto *Field : RD->fields()) {
+ llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
+ StringRef FieldName = Field->getName();
+
+ // Ignore unnamed fields, but recurse into anonymous records.
+ if (FieldName.empty()) {
+ const RecordType *RT = dyn_cast<RecordType>(Field->getType());
+ if (RT)
+ GV = CollectAnonRecordDecls(RT->getDecl(), Unit, LineNo, LinkageName,
+ Var, DContext);
+ continue;
+ }
+ // Use VarDecl's Tag, Scope and Line number.
+ GV = DBuilder.createStaticVariable(DContext, FieldName, LinkageName, Unit,
+ LineNo, FieldTy,
+ Var->hasInternalLinkage(), Var,
+ llvm::DIDerivedType());
+ }
+ return GV;
+}
+
/// EmitGlobalVariable - Emit information about a global variable.
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
const VarDecl *D) {
@@ -3109,46 +3156,36 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
T = CGM.getContext().getConstantArrayType(ET, ConstVal,
ArrayType::Normal, 0);
}
+
StringRef DeclName = D->getName();
StringRef LinkageName;
- if (D->getDeclContext() && !isa<FunctionDecl>(D->getDeclContext())
- && !isa<ObjCMethodDecl>(D->getDeclContext()))
+ if (D->getDeclContext() && !isa<FunctionDecl>(D->getDeclContext()) &&
+ !isa<ObjCMethodDecl>(D->getDeclContext()))
LinkageName = Var->getName();
if (LinkageName == DeclName)
LinkageName = StringRef();
+
llvm::DIDescriptor DContext =
getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()));
- llvm::DIGlobalVariable GV = DBuilder.createStaticVariable(
- DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit),
- Var->hasInternalLinkage(), Var,
- getOrCreateStaticDataMemberDeclarationOrNull(D));
- DeclCache.insert(std::make_pair(D->getCanonicalDecl(), llvm::WeakVH(GV)));
-}
-/// EmitGlobalVariable - Emit information about an objective-c interface.
-void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
- ObjCInterfaceDecl *ID) {
- assert(DebugKind >= CodeGenOptions::LimitedDebugInfo);
- // Create global variable debug descriptor.
- llvm::DIFile Unit = getOrCreateFile(ID->getLocation());
- unsigned LineNo = getLineNumber(ID->getLocation());
-
- StringRef Name = ID->getName();
-
- QualType T = CGM.getContext().getObjCInterfaceType(ID);
- if (T->isIncompleteArrayType()) {
-
- // CodeGen turns int[] into int[1] so we'll do the same here.
- llvm::APInt ConstVal(32, 1);
- QualType ET = CGM.getContext().getAsArrayType(T)->getElementType();
-
- T = CGM.getContext().getConstantArrayType(ET, ConstVal,
- ArrayType::Normal, 0);
+ // Attempt to store one global variable for the declaration - even if we
+ // emit a lot of fields.
+ llvm::DIGlobalVariable GV;
+
+ // If this is an anonymous union then we'll want to emit a global
+ // variable for each member of the anonymous union so that it's possible
+ // to find the name of any field in the union.
+ if (T->isUnionType() && DeclName.empty()) {
+ const RecordDecl *RD = cast<RecordType>(T)->getDecl();
+ assert(RD->isAnonymousStructOrUnion() && "unnamed non-anonymous struct or union?");
+ GV = CollectAnonRecordDecls(RD, Unit, LineNo, LinkageName, Var, DContext);
+ } else {
+ GV = DBuilder.createStaticVariable(
+ DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit),
+ Var->hasInternalLinkage(), Var,
+ getOrCreateStaticDataMemberDeclarationOrNull(D));
}
-
- DBuilder.createGlobalVariable(Name, Unit, LineNo,
- getOrCreateType(T, Unit),
- Var->hasInternalLinkage(), Var);
+ DeclCache.insert(std::make_pair(D->getCanonicalDecl(), llvm::WeakVH(GV)));
}
/// EmitGlobalVariable - Emit global variable's debug info.
@@ -3167,10 +3204,20 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD,
// Do not use DIGlobalVariable for enums.
if (Ty.getTag() == llvm::dwarf::DW_TAG_enumeration_type)
return;
+ // Do not emit separate definitions for function local const/statics.
+ if (isa<FunctionDecl>(VD->getDeclContext()))
+ return;
+ VD = cast<ValueDecl>(VD->getCanonicalDecl());
+ auto pair = DeclCache.insert(std::make_pair(VD, llvm::WeakVH()));
+ if (!pair.second)
+ return;
+ llvm::DIDescriptor DContext =
+ getContextDescriptor(dyn_cast<Decl>(VD->getDeclContext()));
llvm::DIGlobalVariable GV = DBuilder.createStaticVariable(
- Unit, Name, Name, Unit, getLineNumber(VD->getLocation()), Ty, true, Init,
+ DContext, Name, StringRef(), Unit, getLineNumber(VD->getLocation()), Ty,
+ true, Init,
getOrCreateStaticDataMemberDeclarationOrNull(cast<VarDecl>(VD)));
- DeclCache.insert(std::make_pair(VD->getCanonicalDecl(), llvm::WeakVH(GV)));
+ pair.first->second = llvm::WeakVH(GV);
}
llvm::DIScope CGDebugInfo::getCurrentContextDescriptor(const Decl *D) {
@@ -3196,7 +3243,7 @@ void CGDebugInfo::EmitUsingDecl(const UsingDecl &UD) {
// Emitting one decl is sufficient - debuggers can detect that this is an
// overloaded name & provide lookup for all the overloads.
const UsingShadowDecl &USD = **UD.shadow_begin();
- if (llvm::DIDescriptor Target =
+ if (llvm::DIScope Target =
getDeclarationOrDefinition(USD.getUnderlyingDecl()))
DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(USD.getDeclContext())), Target,
@@ -3206,20 +3253,20 @@ void CGDebugInfo::EmitUsingDecl(const UsingDecl &UD) {
llvm::DIImportedEntity
CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) {
if (CGM.getCodeGenOpts().getDebugInfo() < CodeGenOptions::LimitedDebugInfo)
- return llvm::DIImportedEntity(0);
+ return llvm::DIImportedEntity(nullptr);
llvm::WeakVH &VH = NamespaceAliasCache[&NA];
if (VH)
return llvm::DIImportedEntity(cast<llvm::MDNode>(VH));
- llvm::DIImportedEntity R(0);
+ llvm::DIImportedEntity R(nullptr);
if (const NamespaceAliasDecl *Underlying =
dyn_cast<NamespaceAliasDecl>(NA.getAliasedNamespace()))
// This could cache & dedup here rather than relying on metadata deduping.
- R = DBuilder.createImportedModule(
+ R = DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(NA.getDeclContext())),
EmitNamespaceAlias(*Underlying), getLineNumber(NA.getLocation()),
NA.getName());
else
- R = DBuilder.createImportedModule(
+ R = DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(NA.getDeclContext())),
getOrCreateNameSpace(cast<NamespaceDecl>(NA.getAliasedNamespace())),
getLineNumber(NA.getLocation()), NA.getName());
@@ -3248,23 +3295,27 @@ CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) {
}
void CGDebugInfo::finalize() {
- for (std::vector<std::pair<void *, llvm::WeakVH> >::const_iterator VI
- = ReplaceMap.begin(), VE = ReplaceMap.end(); VI != VE; ++VI) {
- llvm::DIType Ty, RepTy;
- // Verify that the debug info still exists.
- if (llvm::Value *V = VI->second)
- Ty = llvm::DIType(cast<llvm::MDNode>(V));
-
- llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
- TypeCache.find(VI->first);
- if (it != TypeCache.end()) {
- // Verify that the debug info still exists.
- if (llvm::Value *V = it->second)
- RepTy = llvm::DIType(cast<llvm::MDNode>(V));
- }
-
- if (Ty && Ty.isForwardDecl() && RepTy)
- Ty.replaceAllUsesWith(RepTy);
+ // Creating types might create further types - invalidating the current
+ // element and the size(), so don't cache/reference them.
+ for (size_t i = 0; i != ObjCInterfaceCache.size(); ++i) {
+ ObjCInterfaceCacheEntry E = ObjCInterfaceCache[i];
+ E.Decl.replaceAllUsesWith(CGM.getLLVMContext(),
+ E.Type->getDecl()->getDefinition()
+ ? CreateTypeDefinition(E.Type, E.Unit)
+ : E.Decl);
+ }
+
+ for (auto p : ReplaceMap) {
+ assert(p.second);
+ llvm::DIType Ty(cast<llvm::MDNode>(p.second));
+ assert(Ty.isForwardDecl());
+
+ auto it = TypeCache.find(p.first);
+ assert(it != TypeCache.end());
+ assert(it->second);
+
+ llvm::DIType RepTy(cast<llvm::MDNode>(it->second));
+ Ty.replaceAllUsesWith(CGM.getLLVMContext(), RepTy);
}
// We keep our own list of retained types, because we need to look
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 0ca274f56881..fc3f434991fa 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This is the source level debug info generator for llvm translation.
+// This is the source-level debug info generator for llvm translation.
//
//===----------------------------------------------------------------------===//
@@ -20,10 +20,10 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/DIBuilder.h"
-#include "llvm/DebugInfo.h"
+#include "llvm/IR/DIBuilder.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Allocator.h"
-#include "llvm/Support/ValueHandle.h"
namespace llvm {
class MDNode;
@@ -47,8 +47,8 @@ namespace CodeGen {
/// and is responsible for emitting to llvm globals or pass directly to
/// the backend.
class CGDebugInfo {
- friend class NoLocation;
friend class ArtificialLocation;
+ friend class SaveAndRestoreLocation;
CodeGenModule &CGM;
const CodeGenOptions::DebugInfoKind DebugKind;
llvm::DIBuilder DBuilder;
@@ -65,21 +65,27 @@ class CGDebugInfo {
llvm::DIType BlockLiteralGeneric;
/// TypeCache - Cache of previously constructed Types.
- llvm::DenseMap<void *, llvm::WeakVH> TypeCache;
+ llvm::DenseMap<const void *, llvm::WeakVH> TypeCache;
+
+ struct ObjCInterfaceCacheEntry {
+ const ObjCInterfaceType *Type;
+ llvm::DIType Decl;
+ llvm::DIFile Unit;
+ ObjCInterfaceCacheEntry(const ObjCInterfaceType *Type, llvm::DIType Decl,
+ llvm::DIFile Unit)
+ : Type(Type), Decl(Decl), Unit(Unit) {}
+ };
/// ObjCInterfaceCache - Cache of previously constructed interfaces
- /// which may change. Storing a pair of DIType and checksum.
- llvm::DenseMap<void *, std::pair<llvm::WeakVH, unsigned> > ObjCInterfaceCache;
+ /// which may change.
+ llvm::SmallVector<ObjCInterfaceCacheEntry, 32> ObjCInterfaceCache;
/// RetainedTypes - list of interfaces we want to keep even if orphaned.
std::vector<void *> RetainedTypes;
- /// CompleteTypeCache - Cache of previously constructed complete RecordTypes.
- llvm::DenseMap<void *, llvm::WeakVH> CompletedTypeCache;
-
/// ReplaceMap - Cache of forward declared types to RAUW at the end of
/// compilation.
- std::vector<std::pair<void *, llvm::WeakVH> >ReplaceMap;
+ std::vector<std::pair<const TagType *, llvm::WeakVH>> ReplaceMap;
// LexicalBlockStack - Keep track of our current nested lexical block.
std::vector<llvm::TrackingVH<llvm::MDNode> > LexicalBlockStack;
@@ -109,6 +115,7 @@ class CGDebugInfo {
llvm::DIType CreateType(const ComplexType *Ty);
llvm::DIType CreateQualifiedType(QualType Ty, llvm::DIFile Fg);
llvm::DIType CreateType(const TypedefType *Ty, llvm::DIFile Fg);
+ llvm::DIType CreateType(const TemplateSpecializationType *Ty, llvm::DIFile Fg);
llvm::DIType CreateType(const ObjCObjectPointerType *Ty,
llvm::DIFile F);
llvm::DIType CreateType(const PointerType *Ty, llvm::DIFile F);
@@ -119,6 +126,7 @@ class CGDebugInfo {
llvm::DICompositeType CreateLimitedType(const RecordType *Ty);
void CollectContainingType(const CXXRecordDecl *RD, llvm::DICompositeType CT);
llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DIFile F);
+ llvm::DIType CreateTypeDefinition(const ObjCInterfaceType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const ObjCObjectType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const VectorType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const ArrayType *Ty, llvm::DIFile F);
@@ -127,9 +135,9 @@ class CGDebugInfo {
llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const AtomicType *Ty, llvm::DIFile F);
llvm::DIType CreateEnumType(const EnumType *Ty);
+ llvm::DIType CreateTypeDefinition(const EnumType *Ty);
llvm::DIType CreateSelfType(const QualType &QualTy, llvm::DIType Ty);
llvm::DIType getTypeOrNull(const QualType);
- llvm::DIType getCompletedTypeOrNull(const QualType);
llvm::DICompositeType getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DIFile F);
llvm::DICompositeType getOrCreateInstanceMethodType(
@@ -139,7 +147,7 @@ class CGDebugInfo {
llvm::DIType getOrCreateVTablePtrType(llvm::DIFile F);
llvm::DINameSpace getOrCreateNameSpace(const NamespaceDecl *N);
llvm::DIType getOrCreateTypeDeclaration(QualType PointeeTy, llvm::DIFile F);
- llvm::DIType CreatePointerLikeType(unsigned Tag,
+ llvm::DIType CreatePointerLikeType(llvm::dwarf::Tag Tag,
const Type *Ty, QualType PointeeTy,
llvm::DIFile F);
@@ -219,8 +227,12 @@ public:
/// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate
/// start of a new function.
- void EmitFunctionStart(GlobalDecl GD, QualType FnType,
- llvm::Function *Fn, CGBuilderTy &Builder);
+ /// \param Loc The location of the function header.
+ /// \param ScopeLoc The location of the function body.
+ void EmitFunctionStart(GlobalDecl GD,
+ SourceLocation Loc, SourceLocation ScopeLoc,
+ QualType FnType, llvm::Function *Fn,
+ CGBuilderTy &Builder);
/// EmitFunctionEnd - Constructs the debug code for exiting a function.
void EmitFunctionEnd(CGBuilderTy &Builder);
@@ -261,9 +273,6 @@ public:
/// EmitGlobalVariable - Emit information about a global variable.
void EmitGlobalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl);
- /// EmitGlobalVariable - Emit information about an objective-c interface.
- void EmitGlobalVariable(llvm::GlobalVariable *GV, ObjCInterfaceDecl *Decl);
-
/// EmitGlobalVariable - Emit global variable's debug info.
void EmitGlobalVariable(const ValueDecl *VD, llvm::Constant *Init);
@@ -284,14 +293,19 @@ public:
llvm::DIType getOrCreateInterfaceType(QualType Ty,
SourceLocation Loc);
+ void completeType(const EnumDecl *ED);
void completeType(const RecordDecl *RD);
void completeRequiredType(const RecordDecl *RD);
void completeClassData(const RecordDecl *RD);
+ void completeTemplateDefinition(const ClassTemplateSpecializationDecl &SD);
+
private:
/// EmitDeclare - Emit call to llvm.dbg.declare for a variable declaration.
- void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI,
- unsigned ArgNo, CGBuilderTy &Builder);
+ /// Tag accepts custom types DW_TAG_arg_variable and DW_TAG_auto_variable,
+ /// otherwise would be of type llvm::dwarf::Tag.
+ void EmitDeclare(const VarDecl *decl, llvm::dwarf::LLVMConstants Tag,
+ llvm::Value *AI, unsigned ArgNo, CGBuilderTy &Builder);
// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
// See BuildByRefType.
@@ -342,9 +356,9 @@ private:
llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType,
StringRef Name, uint64_t *Offset);
- /// \brief Retrieve the DIDescriptor, if any, for the canonical form of this
+ /// \brief Retrieve the DIScope, if any, for the canonical form of this
/// declaration.
- llvm::DIDescriptor getDeclarationOrDefinition(const Decl *D);
+ llvm::DIScope getDeclarationOrDefinition(const Decl *D);
/// getFunctionDeclaration - Return debug info descriptor to describe method
/// declaration for the given method definition.
@@ -355,6 +369,13 @@ private:
llvm::DIDerivedType
getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D);
+ /// Return a global variable that represents one of the collection of
+ /// global variables created for an anonmyous union.
+ llvm::DIGlobalVariable
+ CollectAnonRecordDecls(const RecordDecl *RD, llvm::DIFile Unit, unsigned LineNo,
+ StringRef LinkageName, llvm::GlobalVariable *Var,
+ llvm::DIDescriptor DContext);
+
/// getFunctionName - Get function name for the given FunctionDecl. If the
/// name is constructed on demand (e.g. C++ destructor) then the name
/// is stored on the side.
@@ -394,16 +415,26 @@ private:
}
};
-/// NoLocation - An RAII object that temporarily disables debug
-/// locations. This is useful for emitting instructions that should be
-/// counted towards the function prologue.
-class NoLocation {
+/// SaveAndRestoreLocation - An RAII object saves the current location
+/// and automatically restores it to the original value.
+class SaveAndRestoreLocation {
+protected:
SourceLocation SavedLoc;
CGDebugInfo *DI;
CGBuilderTy &Builder;
public:
+ SaveAndRestoreLocation(CodeGenFunction &CGF, CGBuilderTy &B);
+ /// Autorestore everything back to normal.
+ ~SaveAndRestoreLocation();
+};
+
+/// NoLocation - An RAII object that temporarily disables debug
+/// locations. This is useful for emitting instructions that should be
+/// counted towards the function prologue.
+class NoLocation : public SaveAndRestoreLocation {
+public:
NoLocation(CodeGenFunction &CGF, CGBuilderTy &B);
- /// ~NoLocation - Autorestore everything back to normal.
+ /// Autorestore everything back to normal.
~NoLocation();
};
@@ -418,10 +449,7 @@ public:
/// This is necessary because passing an empty SourceLocation to
/// CGDebugInfo::setLocation() will result in the last valid location
/// being reused.
-class ArtificialLocation {
- SourceLocation SavedLoc;
- CGDebugInfo *DI;
- CGBuilderTy &Builder;
+class ArtificialLocation : public SaveAndRestoreLocation {
public:
ArtificialLocation(CodeGenFunction &CGF, CGBuilderTy &B);
@@ -429,7 +457,7 @@ public:
/// (= the top of the LexicalBlockStack).
void Emit();
- /// ~ArtificialLocation - Autorestore everything back to normal.
+ /// Autorestore everything back to normal.
~ArtificialLocation();
};
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 66d6b33eb6f0..91f804193049 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -126,17 +126,11 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
if (D.isStaticLocal()) {
llvm::GlobalValue::LinkageTypes Linkage =
- llvm::GlobalValue::InternalLinkage;
+ CGM.getLLVMLinkageVarDefinition(&D, /*isConstant=*/false);
- // If the variable is externally visible, it must have weak linkage so it
- // can be uniqued.
- if (D.isExternallyVisible()) {
- Linkage = llvm::GlobalValue::LinkOnceODRLinkage;
-
- // FIXME: We need to force the emission/use of a guard variable for
- // some variables even if we can constant-evaluate them because
- // we can't guarantee every translation unit will constant-evaluate them.
- }
+ // FIXME: We need to force the emission/use of a guard variable for
+ // some variables even if we can constant-evaluate them because
+ // we can't guarantee every translation unit will constant-evaluate them.
return EmitStaticVarDecl(D, Linkage);
}
@@ -155,35 +149,30 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D,
const char *Separator) {
CodeGenModule &CGM = CGF.CGM;
- if (CGF.getLangOpts().CPlusPlus) {
- StringRef Name = CGM.getMangledName(&D);
- return Name.str();
- }
- std::string ContextName;
+ if (CGF.getLangOpts().CPlusPlus)
+ return CGM.getMangledName(&D).str();
+
+ StringRef ContextName;
if (!CGF.CurFuncDecl) {
// Better be in a block declared in global scope.
const NamedDecl *ND = cast<NamedDecl>(&D);
const DeclContext *DC = ND->getDeclContext();
- if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) {
- MangleBuffer Name;
- CGM.getBlockMangledName(GlobalDecl(), Name, BD);
- ContextName = Name.getString();
- }
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC))
+ ContextName = CGM.getBlockMangledName(GlobalDecl(), BD);
else
llvm_unreachable("Unknown context for block static var decl");
- } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CGF.CurFuncDecl)) {
- StringRef Name = CGM.getMangledName(FD);
- ContextName = Name.str();
- } else if (isa<ObjCMethodDecl>(CGF.CurFuncDecl))
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CGF.CurFuncDecl))
+ ContextName = CGM.getMangledName(FD);
+ else if (isa<ObjCMethodDecl>(CGF.CurFuncDecl))
ContextName = CGF.CurFn->getName();
else
llvm_unreachable("Unknown context for static var decl");
- return ContextName + Separator + D.getNameAsString();
+ return ContextName.str() + Separator + D.getNameAsString();
}
-llvm::GlobalVariable *
+llvm::Constant *
CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
const char *Separator,
llvm::GlobalValue::LinkageTypes Linkage) {
@@ -203,7 +192,7 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), LTy,
Ty.isConstant(getContext()), Linkage,
- CGM.EmitNullConstant(D.getType()), Name, 0,
+ CGM.EmitNullConstant(D.getType()), Name, nullptr,
llvm::GlobalVariable::NotThreadLocal,
AddrSpace);
GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
@@ -212,6 +201,20 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
if (D.getTLSKind())
CGM.setTLSMode(GV, D);
+ if (D.isExternallyVisible()) {
+ if (D.hasAttr<DLLImportAttr>())
+ GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass);
+ else if (D.hasAttr<DLLExportAttr>())
+ GV->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass);
+ }
+
+ // Make sure the result is of the correct type.
+ unsigned ExpectedAddrSpace = CGM.getContext().getTargetAddressSpace(Ty);
+ if (AddrSpace != ExpectedAddrSpace) {
+ llvm::PointerType *PTy = llvm::PointerType::get(LTy, ExpectedAddrSpace);
+ return llvm::ConstantExpr::getAddrSpaceCast(GV, PTy);
+ }
+
return GV;
}
@@ -290,7 +293,7 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
llvm::GlobalValue::LinkageTypes Linkage) {
llvm::Value *&DMEntry = LocalDeclMap[&D];
- assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
+ assert(!DMEntry && "Decl already exists in localdeclmap!");
// Check to see if we already have a global variable for this
// declaration. This can happen when double-emitting function
@@ -298,12 +301,8 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
llvm::Constant *addr =
CGM.getStaticLocalDeclAddress(&D);
- llvm::GlobalVariable *var;
- if (addr) {
- var = cast<llvm::GlobalVariable>(addr->stripPointerCasts());
- } else {
- addr = var = CreateStaticVarDecl(D, ".", Linkage);
- }
+ if (!addr)
+ addr = CreateStaticVarDecl(D, ".", Linkage);
// Store into LocalDeclMap before generating initializer to handle
// circular references.
@@ -319,6 +318,8 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
// Save the type in case adding the initializer forces a type change.
llvm::Type *expectedType = addr->getType();
+ llvm::GlobalVariable *var =
+ cast<llvm::GlobalVariable>(addr->stripPointerCasts());
// If this value has an initializer, emit it.
if (D.getInit())
var = AddInitializerToStaticVarDecl(D, var);
@@ -332,17 +333,20 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
var->setSection(SA->getName());
if (D.hasAttr<UsedAttr>())
- CGM.AddUsedGlobal(var);
+ CGM.addUsedGlobal(var);
// We may have to cast the constant because of the initializer
// mismatch above.
//
// FIXME: It is really dangerous to store this in the map; if anyone
// RAUW's the GV uses of this constant will be invalid.
- llvm::Constant *castedAddr = llvm::ConstantExpr::getBitCast(var, expectedType);
+ llvm::Constant *castedAddr =
+ llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(var, expectedType);
DMEntry = castedAddr;
CGM.setStaticLocalDeclAddress(&D, castedAddr);
+ CGM.reportGlobalToASan(var, D);
+
// Emit global variable debug descriptor for static vars.
CGDebugInfo *DI = getDebugInfo();
if (DI &&
@@ -365,7 +369,7 @@ namespace {
CodeGenFunction::Destroyer *destroyer;
bool useEHCleanupForArray;
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
// Don't use an EH cleanup recursively from an EH cleanup.
bool useEHCleanupForArray =
flags.isForNormalCleanup() && this->useEHCleanupForArray;
@@ -384,11 +388,11 @@ namespace {
llvm::Value *NRVOFlag;
llvm::Value *Loc;
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
// Along the exceptions path we always execute the dtor.
bool NRVO = flags.isForNormalCleanup() && NRVOFlag;
- llvm::BasicBlock *SkipDtorBB = 0;
+ llvm::BasicBlock *SkipDtorBB = nullptr;
if (NRVO) {
// If we exited via NRVO, we skip the destructor call.
llvm::BasicBlock *RunDtorBB = CGF.createBasicBlock("nrvo.unused");
@@ -410,7 +414,7 @@ namespace {
struct CallStackRestore : EHScopeStack::Cleanup {
llvm::Value *Stack;
CallStackRestore(llvm::Value *Stack) : Stack(Stack) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
llvm::Value *V = CGF.Builder.CreateLoad(Stack);
llvm::Value *F = CGF.CGM.getIntrinsic(llvm::Intrinsic::stackrestore);
CGF.Builder.CreateCall(F, V);
@@ -421,7 +425,7 @@ namespace {
const VarDecl &Var;
ExtendGCLifetime(const VarDecl *var) : Var(*var) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
// Compute the address of the local variable, in case it's a
// byref or something.
DeclRefExpr DRE(const_cast<VarDecl*>(&Var), false,
@@ -441,7 +445,7 @@ namespace {
const VarDecl *Var)
: CleanupFn(CleanupFn), FnInfo(*Info), Var(*Var) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
DeclRefExpr DRE(const_cast<VarDecl*>(&Var), false,
Var.getType(), VK_LValue, SourceLocation());
// Compute the address of the local variable, in case it's a byref
@@ -473,7 +477,7 @@ namespace {
CallLifetimeEnd(llvm::Value *addr, llvm::Value *size)
: Addr(addr), Size(size) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
llvm::Value *castAddr = CGF.Builder.CreateBitCast(Addr, CGF.Int8PtrTy);
CGF.Builder.CreateCall2(CGF.CGM.getLLVMLifetimeEndFn(),
Size, castAddr)
@@ -530,9 +534,8 @@ static bool isAccessedBy(const VarDecl &var, const Stmt *s) {
return (ref->getDecl() == &var);
if (const BlockExpr *be = dyn_cast<BlockExpr>(e)) {
const BlockDecl *block = be->getBlockDecl();
- for (BlockDecl::capture_const_iterator i = block->capture_begin(),
- e = block->capture_end(); i != e; ++i) {
- if (i->getVariable() == &var)
+ for (const auto &I : block->captures()) {
+ if (I.getVariable() == &var)
return true;
}
}
@@ -571,7 +574,10 @@ void CodeGenFunction::EmitScalarInit(const Expr *init,
EmitStoreThroughLValue(RValue::get(value), lvalue, true);
return;
}
-
+
+ if (const CXXDefaultInitExpr *DIE = dyn_cast<CXXDefaultInitExpr>(init))
+ init = DIE->getExpr();
+
// If we're emitting a value with lifetime, we have to do the
// initialization *before* we leave the cleanup scopes.
if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(init)) {
@@ -613,7 +619,7 @@ void CodeGenFunction::EmitScalarInit(const Expr *init,
}
// Emit the initializer.
- llvm::Value *value = 0;
+ llvm::Value *value = nullptr;
switch (lifetime) {
case Qualifiers::OCL_None:
@@ -798,9 +804,6 @@ static bool shouldUseMemSetPlusStoresToInitialize(llvm::Constant *Init,
/// Should we use the LLVM lifetime intrinsics for the given local variable?
static bool shouldUseLifetimeMarkers(CodeGenFunction &CGF, const VarDecl &D,
unsigned Size) {
- // Always emit lifetime markers in -fsanitize=use-after-scope mode.
- if (CGF.getLangOpts().Sanitize.UseAfterScope)
- return true;
// For now, only in optimized builds.
if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0)
return false;
@@ -823,7 +826,7 @@ void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D) {
}
/// EmitAutoVarAlloca - Emit the alloca and debug information for a
-/// local variable. Does not emit initalization or destruction.
+/// local variable. Does not emit initialization or destruction.
CodeGenFunction::AutoVarEmission
CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
QualType Ty = D.getType();
@@ -866,7 +869,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
CGM.isTypeConstant(Ty, true)) {
EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
- emission.Address = 0; // signal this condition to later callbacks
+ emission.Address = nullptr; // signal this condition to later callbacks
assert(emission.wasEmittedAsGlobal());
return emission;
}
@@ -944,12 +947,12 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
// Push a cleanup block and restore the stack there.
// FIXME: in general circumstances, this should be an EH cleanup.
- EHStack.pushCleanup<CallStackRestore>(NormalCleanup, Stack);
+ pushStackRestore(NormalCleanup, Stack);
}
llvm::Value *elementCount;
QualType elementType;
- llvm::tie(elementCount, elementType) = getVLASize(Ty);
+ std::tie(elementCount, elementType) = getVLASize(Ty);
llvm::Type *llvmTy = ConvertTypeForMem(elementType);
@@ -961,7 +964,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
}
llvm::Value *&DMEntry = LocalDeclMap[&D];
- assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
+ assert(!DMEntry && "Decl already exists in localdeclmap!");
DMEntry = DeclPtr;
emission.Address = DeclPtr;
@@ -990,9 +993,8 @@ static bool isCapturedBy(const VarDecl &var, const Expr *e) {
if (const BlockExpr *be = dyn_cast<BlockExpr>(e)) {
const BlockDecl *block = be->getBlockDecl();
- for (BlockDecl::capture_const_iterator i = block->capture_begin(),
- e = block->capture_end(); i != e; ++i) {
- if (i->getVariable() == &var)
+ for (const auto &I : block->captures()) {
+ if (I.getVariable() == &var)
return true;
}
@@ -1002,18 +1004,16 @@ static bool isCapturedBy(const VarDecl &var, const Expr *e) {
if (const StmtExpr *SE = dyn_cast<StmtExpr>(e)) {
const CompoundStmt *CS = SE->getSubStmt();
- for (CompoundStmt::const_body_iterator BI = CS->body_begin(),
- BE = CS->body_end(); BI != BE; ++BI)
- if (Expr *E = dyn_cast<Expr>((*BI))) {
+ for (const auto *BI : CS->body())
+ if (const auto *E = dyn_cast<Expr>(BI)) {
if (isCapturedBy(var, E))
return true;
}
- else if (DeclStmt *DS = dyn_cast<DeclStmt>((*BI))) {
+ else if (const auto *DS = dyn_cast<DeclStmt>(BI)) {
// special case declarations
- for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
- I != E; ++I) {
- if (VarDecl *VD = dyn_cast<VarDecl>((*I))) {
- Expr *Init = VD->getInit();
+ for (const auto *I : DS->decls()) {
+ if (const auto *VD = dyn_cast<VarDecl>((I))) {
+ const Expr *Init = VD->getInit();
if (Init && isCapturedBy(var, Init))
return true;
}
@@ -1084,7 +1084,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
llvm::Value *Loc =
capturedByInit ? emission.Address : emission.getObjectAddress(*this);
- llvm::Constant *constant = 0;
+ llvm::Constant *constant = nullptr;
if (emission.IsConstantAggregate || D.isConstexpr()) {
assert(!capturedByInit && "constant init contains a capturing block?");
constant = CGM.EmitConstantInit(D, this);
@@ -1211,7 +1211,7 @@ void CodeGenFunction::emitAutoVarTypeCleanup(
QualType type = var->getType();
CleanupKind cleanupKind = NormalAndEHCleanup;
- CodeGenFunction::Destroyer *destroyer = 0;
+ CodeGenFunction::Destroyer *destroyer = nullptr;
switch (dtorKind) {
case QualType::DK_none:
@@ -1344,6 +1344,10 @@ void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, llvm::Value *addr,
destroyer, useEHCleanupForArray);
}
+void CodeGenFunction::pushStackRestore(CleanupKind Kind, llvm::Value *SPMem) {
+ EHStack.pushCleanup<CallStackRestore>(Kind, SPMem);
+}
+
void CodeGenFunction::pushLifetimeExtendedDestroy(
CleanupKind cleanupKind, llvm::Value *addr, QualType type,
Destroyer *destroyer, bool useEHCleanupForArray) {
@@ -1505,7 +1509,7 @@ namespace {
: ArrayBegin(arrayBegin), ArrayEnd(arrayEnd),
ElementType(elementType), Destroyer(destroyer) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
emitPartialArrayDestroy(CGF, ArrayBegin, ArrayEnd,
ElementType, Destroyer);
}
@@ -1527,7 +1531,7 @@ namespace {
: ArrayBegin(arrayBegin), ArrayEndPointer(arrayEndPointer),
ElementType(elementType), Destroyer(destroyer) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
llvm::Value *arrayEnd = CGF.Builder.CreateLoad(ArrayEndPointer);
emitPartialArrayDestroy(CGF, ArrayBegin, arrayEnd,
ElementType, Destroyer);
@@ -1594,7 +1598,7 @@ namespace {
llvm::Value *Param;
ARCPreciseLifetime_t Precise;
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
CGF.EmitARCRelease(Param, Precise);
}
};
@@ -1603,7 +1607,7 @@ namespace {
/// 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,
- unsigned ArgNo) {
+ bool ArgIsPointer, unsigned ArgNo) {
// FIXME: Why isn't ImplicitParamDecl a ParmVarDecl?
assert((isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)) &&
"Invalid argument to EmitParmDecl");
@@ -1617,7 +1621,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
// The only implicit argument a block has is its literal.
if (BlockInfo) {
LocalDeclMap[&D] = Arg;
- llvm::Value *LocalAddr = 0;
+ llvm::Value *LocalAddr = nullptr;
if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
// Allocate a stack slot to let the debug info survive the RA.
llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty),
@@ -1641,30 +1645,35 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
}
llvm::Value *DeclPtr;
- bool HasNonScalarEvalKind = !CodeGenFunction::hasScalarEvaluationKind(Ty);
- // If this is an aggregate or variable sized value, reuse the input pointer.
- if (HasNonScalarEvalKind || !Ty->isConstantSizeType()) {
- DeclPtr = Arg;
+ bool DoStore = false;
+ bool IsScalar = hasScalarEvaluationKind(Ty);
+ CharUnits Align = getContext().getDeclAlign(&D);
+ // If we already have a pointer to the argument, reuse the input pointer.
+ if (ArgIsPointer) {
+ // If we have a prettier pointer type at this point, bitcast to that.
+ unsigned AS = cast<llvm::PointerType>(Arg->getType())->getAddressSpace();
+ llvm::Type *IRTy = ConvertTypeForMem(Ty)->getPointerTo(AS);
+ DeclPtr = Arg->getType() == IRTy ? Arg : Builder.CreateBitCast(Arg, IRTy,
+ D.getName());
// Push a destructor cleanup for this parameter if the ABI requires it.
- if (HasNonScalarEvalKind &&
- getTarget().getCXXABI().isArgumentDestroyedByCallee()) {
- if (const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl()) {
- if (RD->hasNonTrivialDestructor())
- pushDestroy(QualType::DK_cxx_destructor, DeclPtr, Ty);
- }
+ if (!IsScalar &&
+ getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
+ const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ if (RD && RD->hasNonTrivialDestructor())
+ pushDestroy(QualType::DK_cxx_destructor, DeclPtr, Ty);
}
} else {
// Otherwise, create a temporary to hold the value.
llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty),
D.getName() + ".addr");
- CharUnits Align = getContext().getDeclAlign(&D);
Alloc->setAlignment(Align.getQuantity());
DeclPtr = Alloc;
+ DoStore = true;
+ }
- bool doStore = true;
-
+ LValue lv = MakeAddrLValue(DeclPtr, Ty, Align);
+ if (IsScalar) {
Qualifiers qs = Ty.getQualifiers();
- LValue lv = MakeAddrLValue(DeclPtr, Ty, Align);
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;
@@ -1693,7 +1702,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
llvm::Value *Null = CGM.EmitNullConstant(D.getType());
EmitStoreOfScalar(Null, lv, /* isInitialization */ true);
EmitARCStoreStrongCall(lv.getAddress(), Arg, true);
- doStore = false;
+ DoStore = false;
}
else
// Don't use objc_retainBlock for block pointers, because we
@@ -1712,21 +1721,21 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
if (lt == Qualifiers::OCL_Weak) {
EmitARCInitWeak(DeclPtr, Arg);
- doStore = false; // The weak init is a store, no need to do two.
+ 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.
- if (doStore)
- EmitStoreOfScalar(Arg, lv, /* isInitialization */ true);
}
+ // Store the initial value into the alloca.
+ if (DoStore)
+ EmitStoreOfScalar(Arg, lv, /* isInitialization */ true);
+
llvm::Value *&DMEntry = LocalDeclMap[&D];
- assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
+ assert(!DMEntry && "Decl already exists in localdeclmap!");
DMEntry = DeclPtr;
// Emit debug info for param declaration.
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 7bdb9eb0a4a6..94cfe211601f 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -17,6 +17,7 @@
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/Support/Path.h"
using namespace clang;
using namespace CodeGen;
@@ -89,7 +90,7 @@ static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D,
// Special-case non-array C++ destructors, where there's a function
// with the right signature that we can just call.
- const CXXRecordDecl *record = 0;
+ const CXXRecordDecl *record = nullptr;
if (dtorKind == QualType::DK_cxx_destructor &&
(record = type->getAsCXXRecordDecl())) {
assert(!record->hasTrivialDestructor());
@@ -178,8 +179,7 @@ static llvm::Constant *createAtExitStub(CodeGenModule &CGM, const VarDecl &VD,
CodeGenFunction CGF(CGM);
CGF.StartFunction(&VD, CGM.getContext().VoidTy, fn,
- CGM.getTypes().arrangeNullaryFunction(), FunctionArgList(),
- SourceLocation());
+ CGM.getTypes().arrangeNullaryFunction(), FunctionArgList());
llvm::CallInst *call = CGF.Builder.CreateCall(dtor, addr);
@@ -245,16 +245,44 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
if (!CGM.getLangOpts().Exceptions)
Fn->setDoesNotThrow();
- if (CGM.getSanOpts().Address)
- Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
- if (CGM.getSanOpts().Thread)
- Fn->addFnAttr(llvm::Attribute::SanitizeThread);
- if (CGM.getSanOpts().Memory)
- Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
+ if (!CGM.getSanitizerBlacklist().isIn(*Fn)) {
+ if (CGM.getLangOpts().Sanitize.Address)
+ Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
+ if (CGM.getLangOpts().Sanitize.Thread)
+ Fn->addFnAttr(llvm::Attribute::SanitizeThread);
+ if (CGM.getLangOpts().Sanitize.Memory)
+ Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
+ }
return Fn;
}
+/// Create a global pointer to a function that will initialize a global
+/// variable. The user has requested that this pointer be emitted in a specific
+/// section.
+void CodeGenModule::EmitPointerToInitFunc(const VarDecl *D,
+ llvm::GlobalVariable *GV,
+ llvm::Function *InitFunc,
+ InitSegAttr *ISA) {
+ llvm::GlobalVariable *PtrArray = new llvm::GlobalVariable(
+ TheModule, InitFunc->getType(), /*isConstant=*/true,
+ llvm::GlobalValue::PrivateLinkage, InitFunc, "__cxx_init_fn_ptr");
+ PtrArray->setSection(ISA->getSection());
+ addUsedGlobal(PtrArray);
+
+ // If the GV is already in a comdat group, then we have to join it.
+ llvm::Comdat *C = GV->getComdat();
+
+ // LinkOnce and Weak linkage are lowered down to a single-member comdat group.
+ // Make an explicit group so we can join it.
+ if (!C && (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage())) {
+ C = TheModule.getOrInsertComdat(GV->getName());
+ GV->setComdat(C);
+ }
+ if (C)
+ PtrArray->setComdat(C);
+}
+
void
CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
llvm::GlobalVariable *Addr,
@@ -270,9 +298,9 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
llvm::Function *Fn =
CreateGlobalInitOrDestructFunction(*this, FTy, FnName.str());
+ auto *ISA = D->getAttr<InitSegAttr>();
CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr,
PerformInit);
-
if (D->getTLSKind()) {
// FIXME: Should we support init_priority for thread_local?
// FIXME: Ideally, initialization of instantiated thread_local static data
@@ -281,9 +309,11 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
// FIXME: We only need to register one __cxa_thread_atexit function for the
// entire TU.
CXXThreadLocalInits.push_back(Fn);
- } else if (D->hasAttr<InitPriorityAttr>()) {
- unsigned int order = D->getAttr<InitPriorityAttr>()->getPriority();
- OrderGlobalInits Key(order, PrioritizedCXXGlobalInits.size());
+ } else if (PerformInit && ISA) {
+ EmitPointerToInitFunc(D, Addr, Fn, ISA);
+ DelayedCXXInitPosition.erase(D);
+ } else if (auto *IPA = D->getAttr<InitPriorityAttr>()) {
+ OrderGlobalInits Key(IPA->getPriority(), PrioritizedCXXGlobalInits.size());
PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn));
DelayedCXXInitPosition.erase(D);
} else if (D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization &&
@@ -295,10 +325,12 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
// have unordered initialization.
//
// As a consequence, we can put them into their own llvm.global_ctors entry.
- // This should allow GlobalOpt to fire more often, and allow us to implement
- // the Microsoft C++ ABI, which uses COMDAT elimination to avoid double
- // initializaiton.
- AddGlobalCtor(Fn);
+ //
+ // In addition, put the initializer into a COMDAT group with the global
+ // being initialized. On most platforms, this is a minor startup time
+ // optimization. In the MS C++ ABI, there are no guard variables, so this
+ // COMDAT key is required for correctness.
+ AddGlobalCtor(Fn, 65535, Addr);
DelayedCXXInitPosition.erase(D);
} else {
llvm::DenseMap<const Decl *, unsigned>::iterator I =
@@ -306,7 +338,7 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
if (I == DelayedCXXInitPosition.end()) {
CXXGlobalInits.push_back(Fn);
} else {
- assert(CXXGlobalInits[I->second] == 0);
+ assert(CXXGlobalInits[I->second] == nullptr);
CXXGlobalInits[I->second] = Fn;
DelayedCXXInitPosition.erase(I);
}
@@ -314,7 +346,7 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
}
void CodeGenModule::EmitCXXThreadLocalInitFunc() {
- llvm::Function *InitFn = 0;
+ llvm::Function *InitFn = nullptr;
if (!CXXThreadLocalInits.empty()) {
// Generate a guarded initialization function.
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
@@ -364,7 +396,7 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
// Compute the function suffix from priority. Prepend with zeroes to make
// sure the function names are also ordered as priorities.
std::string PrioritySuffix = llvm::utostr(Priority);
- // Priority is always <= 65535 (enforced by sema)..
+ // Priority is always <= 65535 (enforced by sema).
PrioritySuffix = std::string(6-PrioritySuffix.size(), '0')+PrioritySuffix;
llvm::Function *Fn =
CreateGlobalInitOrDestructFunction(*this, FTy,
@@ -378,8 +410,20 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
}
}
- llvm::Function *Fn =
- CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__I_a");
+ // Include the filename in the symbol name. Including "sub_" matches gcc and
+ // makes sure these symbols appear lexicographically behind the symbols with
+ // priority emitted above.
+ SourceManager &SM = Context.getSourceManager();
+ SmallString<128> FileName(llvm::sys::path::filename(
+ SM.getFileEntryForID(SM.getMainFileID())->getName()));
+ for (size_t i = 0; i < FileName.size(); ++i) {
+ // Replace everything that's not [a-zA-Z0-9._] with a _. This set happens
+ // to be the set of C preprocessing numbers.
+ if (!isPreprocessingNumberBody(FileName[i]))
+ FileName[i] = '_';
+ }
+ llvm::Function *Fn = CreateGlobalInitOrDestructFunction(
+ *this, FTy, llvm::Twine("_GLOBAL__sub_I_", FileName));
CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, CXXGlobalInits);
AddGlobalCtor(Fn);
@@ -409,17 +453,17 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
bool PerformInit) {
// Check if we need to emit debug info for variable initializer.
if (D->hasAttr<NoDebugAttr>())
- DebugInfo = NULL; // disable debug info indefinitely for this function
+ DebugInfo = nullptr; // disable debug info indefinitely for this function
StartFunction(GlobalDecl(D), getContext().VoidTy, Fn,
getTypes().arrangeNullaryFunction(),
- FunctionArgList(), D->getInit()->getExprLoc());
+ FunctionArgList(), D->getLocation(),
+ D->getInit()->getExprLoc());
// 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) {
+ if (Addr->hasWeakLinkage() || Addr->hasLinkOnceLinkage()) {
EmitCXXGuardedInit(*D, Addr, PerformInit);
} else {
EmitCXXGlobalVarDeclInit(*D, Addr, PerformInit);
@@ -432,44 +476,49 @@ void
CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
ArrayRef<llvm::Constant *> Decls,
llvm::GlobalVariable *Guard) {
- StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
- getTypes().arrangeNullaryFunction(),
- FunctionArgList(), SourceLocation());
-
- llvm::BasicBlock *ExitBlock = 0;
- if (Guard) {
- // If we have a guard variable, check whether we've already performed these
- // initializations. This happens for TLS initialization functions.
- llvm::Value *GuardVal = Builder.CreateLoad(Guard);
- llvm::Value *Uninit = Builder.CreateIsNull(GuardVal, "guard.uninitialized");
- // Mark as initialized before initializing anything else. If the
- // initializers use previously-initialized thread_local vars, that's
- // probably supposed to be OK, but the standard doesn't say.
- Builder.CreateStore(llvm::ConstantInt::get(GuardVal->getType(), 1), Guard);
- llvm::BasicBlock *InitBlock = createBasicBlock("init");
- ExitBlock = createBasicBlock("exit");
- Builder.CreateCondBr(Uninit, InitBlock, ExitBlock);
- EmitBlock(InitBlock);
- }
+ {
+ ArtificialLocation AL(*this, Builder);
+ StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
+ getTypes().arrangeNullaryFunction(), FunctionArgList());
+ // Emit an artificial location for this function.
+ AL.Emit();
+
+ llvm::BasicBlock *ExitBlock = nullptr;
+ if (Guard) {
+ // If we have a guard variable, check whether we've already performed
+ // these initializations. This happens for TLS initialization functions.
+ llvm::Value *GuardVal = Builder.CreateLoad(Guard);
+ llvm::Value *Uninit = Builder.CreateIsNull(GuardVal,
+ "guard.uninitialized");
+ // Mark as initialized before initializing anything else. If the
+ // initializers use previously-initialized thread_local vars, that's
+ // probably supposed to be OK, but the standard doesn't say.
+ Builder.CreateStore(llvm::ConstantInt::get(GuardVal->getType(),1), Guard);
+ llvm::BasicBlock *InitBlock = createBasicBlock("init");
+ ExitBlock = createBasicBlock("exit");
+ Builder.CreateCondBr(Uninit, InitBlock, ExitBlock);
+ EmitBlock(InitBlock);
+ }
- RunCleanupsScope Scope(*this);
+ RunCleanupsScope Scope(*this);
- // When building in Objective-C++ ARC mode, create an autorelease pool
- // around the global initializers.
- if (getLangOpts().ObjCAutoRefCount && getLangOpts().CPlusPlus) {
- llvm::Value *token = EmitObjCAutoreleasePoolPush();
- EmitObjCAutoreleasePoolCleanup(token);
- }
+ // When building in Objective-C++ ARC mode, create an autorelease pool
+ // around the global initializers.
+ if (getLangOpts().ObjCAutoRefCount && getLangOpts().CPlusPlus) {
+ llvm::Value *token = EmitObjCAutoreleasePoolPush();
+ EmitObjCAutoreleasePoolCleanup(token);
+ }
- for (unsigned i = 0, e = Decls.size(); i != e; ++i)
- if (Decls[i])
- EmitRuntimeCall(Decls[i]);
+ for (unsigned i = 0, e = Decls.size(); i != e; ++i)
+ if (Decls[i])
+ EmitRuntimeCall(Decls[i]);
- Scope.ForceCleanup();
+ Scope.ForceCleanup();
- if (ExitBlock) {
- Builder.CreateBr(ExitBlock);
- EmitBlock(ExitBlock);
+ if (ExitBlock) {
+ Builder.CreateBr(ExitBlock);
+ EmitBlock(ExitBlock);
+ }
}
FinishFunction();
@@ -478,18 +527,22 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
void CodeGenFunction::GenerateCXXGlobalDtorsFunc(llvm::Function *Fn,
const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> >
&DtorsAndObjects) {
- StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
- getTypes().arrangeNullaryFunction(),
- FunctionArgList(), SourceLocation());
-
- // Emit the dtors, in reverse order from construction.
- for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) {
- llvm::Value *Callee = DtorsAndObjects[e - i - 1].first;
- llvm::CallInst *CI = Builder.CreateCall(Callee,
- DtorsAndObjects[e - i - 1].second);
- // Make sure the call and the callee agree on calling convention.
- if (llvm::Function *F = dyn_cast<llvm::Function>(Callee))
- CI->setCallingConv(F->getCallingConv());
+ {
+ ArtificialLocation AL(*this, Builder);
+ StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
+ getTypes().arrangeNullaryFunction(), FunctionArgList());
+ // Emit an artificial location for this function.
+ AL.Emit();
+
+ // Emit the dtors, in reverse order from construction.
+ for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) {
+ llvm::Value *Callee = DtorsAndObjects[e - i - 1].first;
+ llvm::CallInst *CI = Builder.CreateCall(Callee,
+ DtorsAndObjects[e - i - 1].second);
+ // Make sure the call and the callee agree on calling convention.
+ if (llvm::Function *F = dyn_cast<llvm::Function>(Callee))
+ CI->setCallingConv(F->getCallingConv());
+ }
}
FinishFunction();
@@ -501,18 +554,17 @@ llvm::Function *CodeGenFunction::generateDestroyHelper(
llvm::Constant *addr, QualType type, Destroyer *destroyer,
bool useEHCleanupForArray, const VarDecl *VD) {
FunctionArgList args;
- ImplicitParamDecl dst(0, SourceLocation(), 0, getContext().VoidPtrTy);
+ ImplicitParamDecl dst(getContext(), nullptr, SourceLocation(), nullptr,
+ getContext().VoidPtrTy);
args.push_back(&dst);
-
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeFunctionDeclaration(getContext().VoidTy, args,
- FunctionType::ExtInfo(),
- /*variadic*/ false);
+
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ getContext().VoidTy, args, FunctionType::ExtInfo(), /*variadic=*/false);
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *fn =
CreateGlobalInitOrDestructFunction(CGM, FTy, "__cxx_global_array_dtor");
- StartFunction(VD, getContext().VoidTy, fn, FI, args, SourceLocation());
+ StartFunction(VD, getContext().VoidTy, fn, FI, args);
emitDestroy(addr, type, destroyer, useEHCleanupForArray);
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 39a992aab17d..1bbda5cbf09c 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -17,8 +17,8 @@
#include "TargetInfo.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
+#include "llvm/IR/CallSite.h"
#include "llvm/IR/Intrinsics.h"
-#include "llvm/Support/CallSite.h"
using namespace clang;
using namespace CodeGen;
@@ -97,24 +97,6 @@ static llvm::Constant *getUnexpectedFn(CodeGenModule &CGM) {
return CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
}
-llvm::Constant *CodeGenFunction::getUnwindResumeFn() {
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false);
-
- if (CGM.getLangOpts().SjLjExceptions)
- return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
- return CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume");
-}
-
-llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() {
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false);
-
- if (CGM.getLangOpts().SjLjExceptions)
- return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume_or_Rethrow");
- return CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
-}
-
static llvm::Constant *getTerminateFn(CodeGenModule &CGM) {
// void __terminate();
@@ -164,18 +146,21 @@ namespace {
};
}
-const EHPersonality EHPersonality::GNU_C = { "__gcc_personality_v0", 0 };
-const EHPersonality EHPersonality::GNU_C_SJLJ = { "__gcc_personality_sj0", 0 };
-const EHPersonality EHPersonality::NeXT_ObjC = { "__objc_personality_v0", 0 };
-const EHPersonality EHPersonality::GNU_CPlusPlus = { "__gxx_personality_v0", 0};
+const EHPersonality EHPersonality::GNU_C = { "__gcc_personality_v0", nullptr };
+const EHPersonality
+EHPersonality::GNU_C_SJLJ = { "__gcc_personality_sj0", nullptr };
+const EHPersonality
+EHPersonality::NeXT_ObjC = { "__objc_personality_v0", nullptr };
+const EHPersonality
+EHPersonality::GNU_CPlusPlus = { "__gxx_personality_v0", nullptr };
const EHPersonality
-EHPersonality::GNU_CPlusPlus_SJLJ = { "__gxx_personality_sj0", 0 };
+EHPersonality::GNU_CPlusPlus_SJLJ = { "__gxx_personality_sj0", nullptr };
const EHPersonality
EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0", "objc_exception_throw"};
const EHPersonality
-EHPersonality::GNU_ObjCXX = { "__gnustep_objcxx_personality_v0", 0 };
+EHPersonality::GNU_ObjCXX = { "__gnustep_objcxx_personality_v0", nullptr };
const EHPersonality
-EHPersonality::GNUstep_ObjC = { "__gnustep_objc_personality_v0", 0 };
+EHPersonality::GNUstep_ObjC = { "__gnustep_objc_personality_v0", nullptr };
static const EHPersonality &getCPersonality(const LangOptions &L) {
if (L.SjLjExceptions)
@@ -263,12 +248,9 @@ static llvm::Constant *getOpaquePersonalityFn(CodeGenModule &CGM,
/// Check whether a personality function could reasonably be swapped
/// for a C++ personality function.
static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) {
- for (llvm::Constant::use_iterator
- I = Fn->use_begin(), E = Fn->use_end(); I != E; ++I) {
- llvm::User *User = *I;
-
+ for (llvm::User *U : Fn->users()) {
// Conditionally white-list bitcasts.
- if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(User)) {
+ if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(U)) {
if (CE->getOpcode() != llvm::Instruction::BitCast) return false;
if (!PersonalityHasOnlyCXXUses(CE))
return false;
@@ -276,7 +258,7 @@ static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) {
}
// Otherwise, it has to be a landingpad instruction.
- llvm::LandingPadInst *LPI = dyn_cast<llvm::LandingPadInst>(User);
+ llvm::LandingPadInst *LPI = dyn_cast<llvm::LandingPadInst>(U);
if (!LPI) return false;
for (unsigned I = 0, E = LPI->getNumClauses(); I != E; ++I) {
@@ -363,7 +345,7 @@ namespace {
struct FreeException : EHScopeStack::Cleanup {
llvm::Value *exn;
FreeException(llvm::Value *exn) : exn(exn) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
CGF.EmitNounwindRuntimeCall(getFreeExceptionFn(CGF.CGM), exn);
}
};
@@ -421,6 +403,11 @@ llvm::Value *CodeGenFunction::getSelectorFromSlot() {
void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E,
bool KeepInsertionPoint) {
+ if (CGM.getTarget().getTriple().isWindowsMSVCEnvironment()) {
+ ErrorUnsupported(E, "throw expression");
+ return;
+ }
+
if (!E->getSubExpr()) {
EmitNoreturnRuntimeCallOrInvoke(getReThrowFn(CGM),
ArrayRef<llvm::Value*>());
@@ -465,7 +452,7 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E,
// The address of the destructor. If the exception type has a
// trivial destructor (or isn't a record), we just pass null.
- llvm::Constant *Dtor = 0;
+ llvm::Constant *Dtor = nullptr;
if (const RecordType *RecordTy = ThrowType->getAs<RecordType>()) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl());
if (!Record->hasTrivialDestructor()) {
@@ -490,10 +477,16 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
return;
const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
- if (FD == 0)
+ if (!FD) {
+ // Check if CapturedDecl is nothrow and create terminate scope for it.
+ if (const CapturedDecl* CD = dyn_cast_or_null<CapturedDecl>(D)) {
+ if (CD->isNothrow())
+ EHStack.pushTerminate();
+ }
return;
+ }
const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>();
- if (Proto == 0)
+ if (!Proto)
return;
ExceptionSpecificationType EST = Proto->getExceptionSpecType();
@@ -558,10 +551,16 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) {
return;
const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D);
- if (FD == 0)
+ if (!FD) {
+ // Check if CapturedDecl is nothrow and pop terminate scope for it.
+ if (const CapturedDecl* CD = dyn_cast_or_null<CapturedDecl>(D)) {
+ if (CD->isNothrow())
+ EHStack.popTerminate();
+ }
return;
+ }
const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>();
- if (Proto == 0)
+ if (!Proto)
return;
ExceptionSpecificationType EST = Proto->getExceptionSpecType();
@@ -577,6 +576,11 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) {
}
void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
+ if (CGM.getTarget().getTriple().isWindowsMSVCEnvironment()) {
+ ErrorUnsupported(&S, "try statement");
+ return;
+ }
+
EnterCXXTryStmt(S);
EmitStmt(S.getTryBlock());
ExitCXXTryStmt(S);
@@ -600,7 +604,7 @@ void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
QualType CaughtType = C->getCaughtType();
CaughtType = CaughtType.getNonReferenceType().getUnqualifiedType();
- llvm::Value *TypeInfo = 0;
+ llvm::Constant *TypeInfo = nullptr;
if (CaughtType->isObjCObjectPointerType())
TypeInfo = CGM.getObjCRuntime().GetEHType(CaughtType);
else
@@ -678,7 +682,7 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() {
assert(!EHStack.empty());
if (!CGM.getLangOpts().Exceptions)
- return 0;
+ return nullptr;
// Check the innermost scope for a cached landing pad. If this is
// a non-EH cleanup, we'll check enclosing scopes in EmitLandingPad.
@@ -699,56 +703,6 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() {
return LP;
}
-// This code contains a hack to work around a design flaw in
-// LLVM's EH IR which breaks semantics after inlining. This same
-// hack is implemented in llvm-gcc.
-//
-// The LLVM EH abstraction is basically a thin veneer over the
-// traditional GCC zero-cost design: for each range of instructions
-// in the function, there is (at most) one "landing pad" with an
-// associated chain of EH actions. A language-specific personality
-// function interprets this chain of actions and (1) decides whether
-// or not to resume execution at the landing pad and (2) if so,
-// provides an integer indicating why it's stopping. In LLVM IR,
-// the association of a landing pad with a range of instructions is
-// achieved via an invoke instruction, the chain of actions becomes
-// the arguments to the @llvm.eh.selector call, and the selector
-// call returns the integer indicator. Other than the required
-// presence of two intrinsic function calls in the landing pad,
-// the IR exactly describes the layout of the output code.
-//
-// A principal advantage of this design is that it is completely
-// language-agnostic; in theory, the LLVM optimizers can treat
-// landing pads neutrally, and targets need only know how to lower
-// the intrinsics to have a functioning exceptions system (assuming
-// that platform exceptions follow something approximately like the
-// GCC design). Unfortunately, landing pads cannot be combined in a
-// language-agnostic way: given selectors A and B, there is no way
-// to make a single landing pad which faithfully represents the
-// semantics of propagating an exception first through A, then
-// through B, without knowing how the personality will interpret the
-// (lowered form of the) selectors. This means that inlining has no
-// choice but to crudely chain invokes (i.e., to ignore invokes in
-// the inlined function, but to turn all unwindable calls into
-// invokes), which is only semantically valid if every unwind stops
-// at every landing pad.
-//
-// Therefore, the invoke-inline hack is to guarantee that every
-// landing pad has a catch-all.
-enum CleanupHackLevel_t {
- /// A level of hack that requires that all landing pads have
- /// catch-alls.
- CHL_MandatoryCatchall,
-
- /// A level of hack that requires that all landing pads handle
- /// cleanups.
- CHL_MandatoryCleanup,
-
- /// No hacks at all; ideal IR generation.
- CHL_Ideal
-};
-const CleanupHackLevel_t CleanupHackLevel = CHL_MandatoryCleanup;
-
llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
assert(EHStack.requiresLandingPad());
@@ -766,11 +720,9 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
// Save the current IR generation state.
CGBuilderTy::InsertPoint savedIP = Builder.saveAndClearIP();
- SourceLocation SavedLocation;
- if (CGDebugInfo *DI = getDebugInfo()) {
- SavedLocation = DI->getLocation();
+ SaveAndRestoreLocation AutoRestoreLocation(*this, Builder);
+ if (CGDebugInfo *DI = getDebugInfo())
DI->EmitLocation(Builder, CurEHLocation);
- }
const EHPersonality &personality = EHPersonality::get(getLangOpts());
@@ -877,11 +829,8 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
LPadInst->setCleanup(true);
// Otherwise, signal that we at least have cleanups.
- } else if (CleanupHackLevel == CHL_MandatoryCatchall || hasCleanup) {
- if (CleanupHackLevel == CHL_MandatoryCatchall)
- LPadInst->addClause(getCatchAllValue(*this));
- else
- LPadInst->setCleanup(true);
+ } else if (hasCleanup) {
+ LPadInst->setCleanup(true);
}
assert((LPadInst->getNumClauses() > 0 || LPadInst->isCleanup()) &&
@@ -892,8 +841,6 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
// Restore the old IR generation state.
Builder.restoreIP(savedIP);
- if (CGDebugInfo *DI = getDebugInfo())
- DI->EmitLocation(Builder, SavedLocation);
return lpad;
}
@@ -915,7 +862,7 @@ namespace {
CallEndCatch(bool MightThrow) : MightThrow(MightThrow) {}
bool MightThrow;
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
if (!MightThrow) {
CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));
return;
@@ -1244,6 +1191,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
// If the catch was not required, bail out now.
if (!CatchScope.hasEHBranches()) {
+ CatchScope.clearHandlerBlocks();
EHStack.popCatch();
return;
}
@@ -1294,6 +1242,10 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
// Initialize the catch variable and set up the cleanups.
BeginCatch(*this, C);
+ // Emit the PGO counter increment.
+ RegionCounter CatchCnt = getPGORegionCounter(C);
+ CatchCnt.beginRegion(Builder);
+
// Perform the body of the catch.
EmitStmt(C->getHandlerBlock());
@@ -1320,7 +1272,9 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
Builder.CreateBr(ContBB);
}
+ RegionCounter ContCnt = getPGORegionCounter(&S);
EmitBlock(ContBB);
+ ContCnt.beginRegion(Builder);
}
namespace {
@@ -1330,7 +1284,7 @@ namespace {
CallEndCatchForFinally(llvm::Value *ForEHVar, llvm::Value *EndCatchFn)
: ForEHVar(ForEHVar), EndCatchFn(EndCatchFn) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
llvm::BasicBlock *EndCatchBB = CGF.createBasicBlock("finally.endcatch");
llvm::BasicBlock *CleanupContBB =
CGF.createBasicBlock("finally.cleanup.cont");
@@ -1357,7 +1311,7 @@ namespace {
: Body(Body), ForEHVar(ForEHVar), EndCatchFn(EndCatchFn),
RethrowFn(RethrowFn), SavedExnVar(SavedExnVar) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
// Enter a cleanup to call the end-catch function if one was provided.
if (EndCatchFn)
CGF.EHStack.pushCleanup<CallEndCatchForFinally>(NormalAndEHCleanup,
@@ -1422,7 +1376,7 @@ void CodeGenFunction::FinallyInfo::enter(CodeGenFunction &CGF,
llvm::Constant *beginCatchFn,
llvm::Constant *endCatchFn,
llvm::Constant *rethrowFn) {
- assert((beginCatchFn != 0) == (endCatchFn != 0) &&
+ assert((beginCatchFn != nullptr) == (endCatchFn != nullptr) &&
"begin/end catch functions not paired");
assert(rethrowFn && "rethrow function is required");
@@ -1437,7 +1391,7 @@ void CodeGenFunction::FinallyInfo::enter(CodeGenFunction &CGF,
llvm::FunctionType *rethrowFnTy =
cast<llvm::FunctionType>(
cast<llvm::PointerType>(rethrowFn->getType())->getElementType());
- SavedExnVar = 0;
+ SavedExnVar = nullptr;
if (rethrowFnTy->getNumParams())
SavedExnVar = CGF.CreateTempAlloca(CGF.Int8PtrTy, "finally.exn");
@@ -1487,7 +1441,7 @@ void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) {
CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveAndClearIP();
CGF.EmitBlock(catchBB);
- llvm::Value *exn = 0;
+ llvm::Value *exn = nullptr;
// If there's a begin-catch function, call it.
if (BeginCatchFn) {
@@ -1651,54 +1605,34 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
// This can always be a call because we necessarily didn't find
// anything on the EH stack which needs our help.
const char *RethrowName = Personality.CatchallRethrowFn;
- if (RethrowName != 0 && !isCleanup) {
+ if (RethrowName != nullptr && !isCleanup) {
EmitRuntimeCall(getCatchallRethrowFn(CGM, RethrowName),
- getExceptionFromSlot())
+ getExceptionFromSlot())
->setDoesNotReturn();
- } else {
- switch (CleanupHackLevel) {
- case CHL_MandatoryCatchall:
- // In mandatory-catchall mode, we need to use
- // _Unwind_Resume_or_Rethrow, or whatever the personality's
- // equivalent is.
- EmitRuntimeCall(getUnwindResumeOrRethrowFn(),
- getExceptionFromSlot())
- ->setDoesNotReturn();
- break;
- case CHL_MandatoryCleanup: {
- // In mandatory-cleanup mode, we should use 'resume'.
-
- // Recreate the landingpad's return value for the 'resume' instruction.
- llvm::Value *Exn = getExceptionFromSlot();
- llvm::Value *Sel = getSelectorFromSlot();
-
- llvm::Type *LPadType = llvm::StructType::get(Exn->getType(),
- Sel->getType(), NULL);
- llvm::Value *LPadVal = llvm::UndefValue::get(LPadType);
- LPadVal = Builder.CreateInsertValue(LPadVal, Exn, 0, "lpad.val");
- LPadVal = Builder.CreateInsertValue(LPadVal, Sel, 1, "lpad.val");
-
- Builder.CreateResume(LPadVal);
- Builder.restoreIP(SavedIP);
- return EHResumeBlock;
- }
- case CHL_Ideal:
- // In an idealized mode where we don't have to worry about the
- // optimizer combining landing pads, we should just use
- // _Unwind_Resume (or the personality's equivalent).
- EmitRuntimeCall(getUnwindResumeFn(), getExceptionFromSlot())
- ->setDoesNotReturn();
- break;
- }
+ Builder.CreateUnreachable();
+ Builder.restoreIP(SavedIP);
+ return EHResumeBlock;
}
- Builder.CreateUnreachable();
+ // Recreate the landingpad's return value for the 'resume' instruction.
+ llvm::Value *Exn = getExceptionFromSlot();
+ llvm::Value *Sel = getSelectorFromSlot();
- Builder.restoreIP(SavedIP);
+ llvm::Type *LPadType = llvm::StructType::get(Exn->getType(),
+ Sel->getType(), NULL);
+ llvm::Value *LPadVal = llvm::UndefValue::get(LPadType);
+ LPadVal = Builder.CreateInsertValue(LPadVal, Exn, 0, "lpad.val");
+ LPadVal = Builder.CreateInsertValue(LPadVal, Sel, 1, "lpad.val");
+ Builder.CreateResume(LPadVal);
+ Builder.restoreIP(SavedIP);
return EHResumeBlock;
}
void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) {
CGM.ErrorUnsupported(&S, "SEH __try");
}
+
+void CodeGenFunction::EmitSEHLeaveStmt(const SEHLeaveStmt &S) {
+ CGM.ErrorUnsupported(&S, "SEH __leave");
+}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index cb990b243fba..512b323ba109 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -21,6 +21,7 @@
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Attr.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/IR/DataLayout.h"
@@ -53,13 +54,13 @@ llvm::Value *CodeGenFunction::EmitCastToVoidPtr(llvm::Value *value) {
llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(llvm::Type *Ty,
const Twine &Name) {
if (!Builder.isNamePreserving())
- return new llvm::AllocaInst(Ty, 0, "", AllocaInsertPt);
- return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt);
+ return new llvm::AllocaInst(Ty, nullptr, "", AllocaInsertPt);
+ return new llvm::AllocaInst(Ty, nullptr, Name, AllocaInsertPt);
}
void CodeGenFunction::InitTempAlloca(llvm::AllocaInst *Var,
llvm::Value *Init) {
- llvm::StoreInst *Store = new llvm::StoreInst(Init, Var);
+ auto *Store = new llvm::StoreInst(Init, Var);
llvm::BasicBlock *Block = AllocaInsertPt->getParent();
Block->getInstList().insertAfter(&*AllocaInsertPt, Store);
}
@@ -85,6 +86,7 @@ llvm::AllocaInst *CodeGenFunction::CreateMemTemp(QualType Ty,
/// EvaluateExprAsBool - Perform the usual unary conversions on the specified
/// expression and compare the result against zero, returning an Int1Ty value.
llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) {
+ PGO.setCurrentStmt(E);
if (const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>()) {
llvm::Value *MemPtr = EmitScalarExpr(E);
return CGM.getCXXABI().EmitMemberPointerIsNotNull(*this, MemPtr, MPT);
@@ -240,11 +242,11 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M,
}
}
- CXXDestructorDecl *ReferenceTemporaryDtor = 0;
+ CXXDestructorDecl *ReferenceTemporaryDtor = nullptr;
if (const RecordType *RT =
E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
// Get the destructor for the reference temporary.
- CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ auto *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());
if (!ClassDecl->hasTrivialDestructor())
ReferenceTemporaryDtor = ClassDecl->getDestructor();
}
@@ -322,7 +324,7 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
llvm::Value *Object = createReferenceTemporary(*this, M, E);
LValue RefTempDst = MakeAddrLValue(Object, M->getType());
- if (llvm::GlobalVariable *Var = dyn_cast<llvm::GlobalVariable>(Object)) {
+ if (auto *Var = dyn_cast<llvm::GlobalVariable>(Object)) {
// We should not have emitted the initializer for this temporary as a
// constant.
assert(!Var->hasInitializer());
@@ -342,7 +344,7 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
for (unsigned I = 0, N = CommaLHSs.size(); I != N; ++I)
EmitIgnoredExpr(CommaLHSs[I]);
- if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E)) {
+ if (const auto *opaque = dyn_cast<OpaqueValueExpr>(E)) {
if (opaque->getType()->isRecordType()) {
assert(Adjustments.empty());
return EmitOpaqueValueLValue(opaque);
@@ -351,7 +353,7 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
// Create and initialize the reference temporary.
llvm::Value *Object = createReferenceTemporary(*this, M, E);
- if (llvm::GlobalVariable *Var = dyn_cast<llvm::GlobalVariable>(Object)) {
+ if (auto *Var = dyn_cast<llvm::GlobalVariable>(Object)) {
// If the temporary is a global and has a constant initializer, we may
// have already initialized it.
if (!Var->hasInitializer()) {
@@ -389,7 +391,7 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
case SubobjectAdjustment::MemberPointerAdjustment: {
llvm::Value *Ptr = EmitScalarExpr(Adjustment.Ptr.RHS);
Object = CGM.getCXXABI().EmitMemberDataPointerAddress(
- *this, Object, Ptr, Adjustment.Ptr.MPT);
+ *this, E, Object, Ptr, Adjustment.Ptr.MPT);
break;
}
}
@@ -405,7 +407,7 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E) {
assert(LV.isSimple());
llvm::Value *Value = LV.getAddress();
- if (SanitizePerformTypeCheck && !E->getType()->isFunctionType()) {
+ if (sanitizePerformTypeCheck() && !E->getType()->isFunctionType()) {
// C++11 [dcl.ref]p5 (as amended by core issue 453):
// If a glvalue to which a reference is directly bound designates neither
// an existing object or function of an appropriate type nor a region of
@@ -439,10 +441,15 @@ static llvm::Value *emitHash16Bytes(CGBuilderTy &Builder, llvm::Value *Low,
return Builder.CreateMul(B1, KMul);
}
+bool CodeGenFunction::sanitizePerformTypeCheck() const {
+ return SanOpts->Null | SanOpts->Alignment | SanOpts->ObjectSize |
+ SanOpts->Vptr;
+}
+
void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
llvm::Value *Address,
QualType Ty, CharUnits Alignment) {
- if (!SanitizePerformTypeCheck)
+ if (!sanitizePerformTypeCheck())
return;
// Don't check pointers outside the default address space. The null check
@@ -451,10 +458,12 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
if (Address->getType()->getPointerAddressSpace())
return;
- llvm::Value *Cond = 0;
- llvm::BasicBlock *Done = 0;
+ SanitizerScope SanScope(this);
- if (SanOpts->Null) {
+ llvm::Value *Cond = nullptr;
+ llvm::BasicBlock *Done = nullptr;
+
+ if (SanOpts->Null || TCK == TCK_DowncastPointer) {
// The glvalue must not be an empty glvalue.
Cond = Builder.CreateICmpNE(
Address, llvm::Constant::getNullValue(Address->getType()));
@@ -466,7 +475,7 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
llvm::BasicBlock *Rest = createBasicBlock("not.null");
Builder.CreateCondBr(Cond, Rest, Done);
EmitBlock(Rest);
- Cond = 0;
+ Cond = nullptr;
}
}
@@ -537,44 +546,48 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
llvm::raw_svector_ostream Out(MangledName);
CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty.getUnqualifiedType(),
Out);
- llvm::hash_code TypeHash = hash_value(Out.str());
-
- // Load the vptr, and compute hash_16_bytes(TypeHash, vptr).
- llvm::Value *Low = llvm::ConstantInt::get(Int64Ty, TypeHash);
- llvm::Type *VPtrTy = llvm::PointerType::get(IntPtrTy, 0);
- llvm::Value *VPtrAddr = Builder.CreateBitCast(Address, VPtrTy);
- llvm::Value *VPtrVal = Builder.CreateLoad(VPtrAddr);
- llvm::Value *High = Builder.CreateZExt(VPtrVal, Int64Ty);
-
- llvm::Value *Hash = emitHash16Bytes(Builder, Low, High);
- Hash = Builder.CreateTrunc(Hash, IntPtrTy);
-
- // Look the hash up in our cache.
- const int CacheSize = 128;
- llvm::Type *HashTable = llvm::ArrayType::get(IntPtrTy, CacheSize);
- llvm::Value *Cache = CGM.CreateRuntimeVariable(HashTable,
- "__ubsan_vptr_type_cache");
- llvm::Value *Slot = Builder.CreateAnd(Hash,
- llvm::ConstantInt::get(IntPtrTy,
- CacheSize-1));
- llvm::Value *Indices[] = { Builder.getInt32(0), Slot };
- llvm::Value *CacheVal =
- Builder.CreateLoad(Builder.CreateInBoundsGEP(Cache, Indices));
-
- // If the hash isn't in the cache, call a runtime handler to perform the
- // hard work of checking whether the vptr is for an object of the right
- // type. This will either fill in the cache and return, or produce a
- // diagnostic.
- llvm::Constant *StaticData[] = {
- EmitCheckSourceLocation(Loc),
- EmitCheckTypeDescriptor(Ty),
- CGM.GetAddrOfRTTIDescriptor(Ty.getUnqualifiedType()),
- llvm::ConstantInt::get(Int8Ty, TCK)
- };
- llvm::Value *DynamicData[] = { Address, Hash };
- EmitCheck(Builder.CreateICmpEQ(CacheVal, Hash),
- "dynamic_type_cache_miss", StaticData, DynamicData,
- CRK_AlwaysRecoverable);
+
+ // Blacklist based on the mangled type.
+ if (!CGM.getSanitizerBlacklist().isBlacklistedType(Out.str())) {
+ llvm::hash_code TypeHash = hash_value(Out.str());
+
+ // Load the vptr, and compute hash_16_bytes(TypeHash, vptr).
+ llvm::Value *Low = llvm::ConstantInt::get(Int64Ty, TypeHash);
+ llvm::Type *VPtrTy = llvm::PointerType::get(IntPtrTy, 0);
+ llvm::Value *VPtrAddr = Builder.CreateBitCast(Address, VPtrTy);
+ llvm::Value *VPtrVal = Builder.CreateLoad(VPtrAddr);
+ llvm::Value *High = Builder.CreateZExt(VPtrVal, Int64Ty);
+
+ llvm::Value *Hash = emitHash16Bytes(Builder, Low, High);
+ Hash = Builder.CreateTrunc(Hash, IntPtrTy);
+
+ // Look the hash up in our cache.
+ const int CacheSize = 128;
+ llvm::Type *HashTable = llvm::ArrayType::get(IntPtrTy, CacheSize);
+ llvm::Value *Cache = CGM.CreateRuntimeVariable(HashTable,
+ "__ubsan_vptr_type_cache");
+ llvm::Value *Slot = Builder.CreateAnd(Hash,
+ llvm::ConstantInt::get(IntPtrTy,
+ CacheSize-1));
+ llvm::Value *Indices[] = { Builder.getInt32(0), Slot };
+ llvm::Value *CacheVal =
+ Builder.CreateLoad(Builder.CreateInBoundsGEP(Cache, Indices));
+
+ // If the hash isn't in the cache, call a runtime handler to perform the
+ // hard work of checking whether the vptr is for an object of the right
+ // type. This will either fill in the cache and return, or produce a
+ // diagnostic.
+ llvm::Constant *StaticData[] = {
+ EmitCheckSourceLocation(Loc),
+ EmitCheckTypeDescriptor(Ty),
+ CGM.GetAddrOfRTTIDescriptor(Ty.getUnqualifiedType()),
+ llvm::ConstantInt::get(Int8Ty, TCK)
+ };
+ llvm::Value *DynamicData[] = { Address, Hash };
+ EmitCheck(Builder.CreateICmpEQ(CacheVal, Hash),
+ "dynamic_type_cache_miss", StaticData, DynamicData,
+ CRK_AlwaysRecoverable);
+ }
}
if (Done) {
@@ -589,7 +602,7 @@ static bool isFlexibleArrayMemberExpr(const Expr *E) {
// For compatibility with existing code, we treat arrays of length 0 or
// 1 as flexible array members.
const ArrayType *AT = E->getType()->castAsArrayTypeUnsafe();
- if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) {
+ if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
if (CAT->getSize().ugt(1))
return false;
} else if (!isa<IncompleteArrayType>(AT))
@@ -598,10 +611,10 @@ static bool isFlexibleArrayMemberExpr(const Expr *E) {
E = E->IgnoreParens();
// A flexible array member must be the last member in the class.
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ if (const auto *ME = dyn_cast<MemberExpr>(E)) {
// FIXME: If the base type of the member expr is not FD->getParent(),
// this should not be treated as a flexible array member access.
- if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
+ if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
RecordDecl::field_iterator FI(
DeclContext::decl_iterator(const_cast<FieldDecl *>(FD)));
return ++FI == FD->getParent()->field_end();
@@ -623,19 +636,19 @@ static llvm::Value *getArrayIndexingBound(
Base = Base->IgnoreParens();
- if (const CastExpr *CE = dyn_cast<CastExpr>(Base)) {
+ if (const auto *CE = dyn_cast<CastExpr>(Base)) {
if (CE->getCastKind() == CK_ArrayToPointerDecay &&
!isFlexibleArrayMemberExpr(CE->getSubExpr())) {
IndexedType = CE->getSubExpr()->getType();
const ArrayType *AT = IndexedType->castAsArrayTypeUnsafe();
- if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
+ if (const auto *CAT = dyn_cast<ConstantArrayType>(AT))
return CGF.Builder.getInt(CAT->getSize());
- else if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(AT))
+ else if (const auto *VAT = dyn_cast<VariableArrayType>(AT))
return CGF.getVLASize(VAT).first;
}
}
- return 0;
+ return nullptr;
}
void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
@@ -643,6 +656,7 @@ void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
bool Accessed) {
assert(SanOpts->ArrayBounds &&
"should not be called unless adding bounds checks");
+ SanitizerScope SanScope(this);
QualType IndexedType;
llvm::Value *Bound = getArrayIndexingBound(*this, Base, IndexedType);
@@ -704,7 +718,7 @@ EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
RValue CodeGenFunction::GetUndefRValue(QualType Ty) {
if (Ty->isVoidType())
- return RValue::get(0);
+ return RValue::get(nullptr);
switch (getEvaluationKind(Ty)) {
case TEK_Complex: {
@@ -819,7 +833,7 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitLambdaLValue(cast<LambdaExpr>(E));
case Expr::ExprWithCleanupsClass: {
- const ExprWithCleanups *cleanups = cast<ExprWithCleanups>(E);
+ const auto *cleanups = cast<ExprWithCleanups>(E);
enterFullExpression(cleanups);
RunCleanupsScope Scope(*this);
return EmitLValue(cleanups->getSubExpr());
@@ -887,8 +901,8 @@ static bool isConstantEmittableObjectType(QualType type) {
// Otherwise, all object types satisfy this except C++ classes with
// mutable subobjects or non-trivial copy/destroy behavior.
- if (const RecordType *RT = dyn_cast<RecordType>(type))
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
+ if (const auto *RT = dyn_cast<RecordType>(type))
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
if (RD->hasMutableFields() || !RD->isTrivial())
return false;
@@ -910,7 +924,7 @@ enum ConstantEmissionKind {
};
static ConstantEmissionKind checkVarTypeForConstantEmission(QualType type) {
type = type.getCanonicalType();
- if (const ReferenceType *ref = dyn_cast<ReferenceType>(type)) {
+ if (const auto *ref = dyn_cast<ReferenceType>(type)) {
if (isConstantEmittableObjectType(ref->getPointeeType()))
return CEK_AsValueOrReference;
return CEK_AsReferenceOnly;
@@ -933,7 +947,7 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) {
ConstantEmissionKind CEK;
if (isa<ParmVarDecl>(value)) {
CEK = CEK_None;
- } else if (VarDecl *var = dyn_cast<VarDecl>(value)) {
+ } else if (auto *var = dyn_cast<VarDecl>(value)) {
CEK = checkVarTypeForConstantEmission(var->getType());
} else if (isa<EnumConstantDecl>(value)) {
CEK = CEK_AsValueOnly;
@@ -1046,7 +1060,7 @@ llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
llvm::APInt Min, End;
if (!getRangeForType(*this, Ty, Min, End,
CGM.getCodeGenOpts().StrictEnums))
- return 0;
+ return nullptr;
llvm::MDBuilder MDHelper(getLLVMContext());
return MDHelper.createRange(Min, End);
@@ -1064,7 +1078,7 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
const llvm::Type *EltTy =
cast<llvm::PointerType>(Addr->getType())->getElementType();
- const llvm::VectorType *VTy = cast<llvm::VectorType>(EltTy);
+ const auto *VTy = cast<llvm::VectorType>(EltTy);
// Handle vectors of size 3, like size 4 for better performance.
if (VTy->getNumElements() == 3) {
@@ -1118,6 +1132,7 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
if ((SanOpts->Bool && hasBooleanRepresentation(Ty)) ||
(SanOpts->Enum && Ty->getAs<EnumType>())) {
+ SanitizerScope SanScope(this);
llvm::APInt Min, End;
if (getRangeForType(*this, Ty, Min, End, true)) {
--End;
@@ -1180,7 +1195,7 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
// Handle vectors differently to get better performance.
if (Ty->isVectorType()) {
llvm::Type *SrcTy = Value->getType();
- llvm::VectorType *VecTy = cast<llvm::VectorType>(SrcTy);
+ auto *VecTy = cast<llvm::VectorType>(SrcTy);
// Handle vec3 special.
if (VecTy->getNumElements() == 3) {
llvm::LLVMContext &VMContext = getLLVMContext();
@@ -1201,7 +1216,7 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
MaskV, "extractVec");
SrcTy = llvm::VectorType::get(VecTy->getElementType(), 4);
}
- llvm::PointerType *DstPtr = cast<llvm::PointerType>(Addr->getType());
+ auto *DstPtr = cast<llvm::PointerType>(Addr->getType());
if (DstPtr->getElementType() != SrcTy) {
llvm::Type *MemTy =
llvm::PointerType::get(SrcTy, DstPtr->getAddressSpace());
@@ -1275,6 +1290,10 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
if (LV.isExtVectorElt())
return EmitLoadOfExtVectorElementLValue(LV);
+ // Global Register variables always invoke intrinsics
+ if (LV.isGlobalReg())
+ return EmitLoadOfGlobalRegLValue(LV);
+
assert(LV.isBitField() && "Unknown LValue type!");
return EmitLoadOfBitfieldLValue(LV);
}
@@ -1325,7 +1344,7 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) {
const VectorType *ExprVT = LV.getType()->getAs<VectorType>();
if (!ExprVT) {
unsigned InIdx = getAccessedFieldNo(0, Elts);
- llvm::Value *Elt = llvm::ConstantInt::get(Int32Ty, InIdx);
+ llvm::Value *Elt = llvm::ConstantInt::get(SizeTy, InIdx);
return RValue::get(Builder.CreateExtractElement(Vec, Elt));
}
@@ -1342,6 +1361,26 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) {
return RValue::get(Vec);
}
+/// @brief Load of global gamed gegisters are always calls to intrinsics.
+RValue CodeGenFunction::EmitLoadOfGlobalRegLValue(LValue LV) {
+ assert((LV.getType()->isIntegerType() || LV.getType()->isPointerType()) &&
+ "Bad type for register variable");
+ llvm::MDNode *RegName = dyn_cast<llvm::MDNode>(LV.getGlobalReg());
+ assert(RegName && "Register LValue is not metadata");
+
+ // We accept integer and pointer types only
+ llvm::Type *OrigTy = CGM.getTypes().ConvertType(LV.getType());
+ llvm::Type *Ty = OrigTy;
+ if (OrigTy->isPointerTy())
+ Ty = CGM.getTypes().getDataLayout().getIntPtrType(OrigTy);
+ llvm::Type *Types[] = { Ty };
+
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::read_register, Types);
+ llvm::Value *Call = Builder.CreateCall(F, RegName);
+ if (OrigTy->isPointerTy())
+ Call = Builder.CreateIntToPtr(Call, OrigTy);
+ return RValue::get(Call);
+}
/// EmitStoreThroughLValue - Store the specified rvalue into the specified
@@ -1369,6 +1408,9 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
if (Dst.isExtVectorElt())
return EmitStoreThroughExtVectorComponentLValue(Src, Dst);
+ if (Dst.isGlobalReg())
+ return EmitStoreThroughGlobalRegLValue(Src, Dst);
+
assert(Dst.isBitField() && "Unknown LValue type");
return EmitStoreThroughBitfieldLValue(Src, Dst);
}
@@ -1571,7 +1613,7 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
} else {
// If the Src is a scalar (not a vector) it must be updating one element.
unsigned InIdx = getAccessedFieldNo(0, Elts);
- llvm::Value *Elt = llvm::ConstantInt::get(Int32Ty, InIdx);
+ llvm::Value *Elt = llvm::ConstantInt::get(SizeTy, InIdx);
Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt);
}
@@ -1580,7 +1622,28 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src,
Store->setAlignment(Dst.getAlignment().getQuantity());
}
-// setObjCGCLValueClass - sets class of he lvalue for the purpose of
+/// @brief Store of global named registers are always calls to intrinsics.
+void CodeGenFunction::EmitStoreThroughGlobalRegLValue(RValue Src, LValue Dst) {
+ assert((Dst.getType()->isIntegerType() || Dst.getType()->isPointerType()) &&
+ "Bad type for register variable");
+ llvm::MDNode *RegName = dyn_cast<llvm::MDNode>(Dst.getGlobalReg());
+ assert(RegName && "Register LValue is not metadata");
+
+ // We accept integer and pointer types only
+ llvm::Type *OrigTy = CGM.getTypes().ConvertType(Dst.getType());
+ llvm::Type *Ty = OrigTy;
+ if (OrigTy->isPointerTy())
+ Ty = CGM.getTypes().getDataLayout().getIntPtrType(OrigTy);
+ llvm::Type *Types[] = { Ty };
+
+ llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::write_register, Types);
+ llvm::Value *Value = Src.getScalarVal();
+ if (OrigTy->isPointerTy())
+ Value = Builder.CreatePtrToInt(Value, Ty);
+ Builder.CreateCall2(F, RegName, Value);
+}
+
+// setObjCGCLValueClass - sets class of the lvalue for the purpose of
// generating write-barries API. It is currently a global, ivar,
// or neither.
static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
@@ -1602,14 +1665,14 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
}
}
LV.setObjCIvar(true);
- ObjCIvarRefExpr *Exp = cast<ObjCIvarRefExpr>(const_cast<Expr*>(E));
+ auto *Exp = cast<ObjCIvarRefExpr>(const_cast<Expr *>(E));
LV.setBaseIvarExp(Exp->getBase());
LV.setObjCArray(E->getType()->isArrayType());
return;
}
- if (const DeclRefExpr *Exp = dyn_cast<DeclRefExpr>(E)) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(Exp->getDecl())) {
+ if (const auto *Exp = dyn_cast<DeclRefExpr>(E)) {
+ if (const auto *VD = dyn_cast<VarDecl>(Exp->getDecl())) {
if (VD->hasGlobalStorage()) {
LV.setGlobalObjCRef(true);
LV.setThreadLocalRef(VD->getTLSKind() != VarDecl::TLS_None);
@@ -1619,12 +1682,12 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
return;
}
- if (const UnaryOperator *Exp = dyn_cast<UnaryOperator>(E)) {
+ if (const auto *Exp = dyn_cast<UnaryOperator>(E)) {
setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
return;
}
- if (const ParenExpr *Exp = dyn_cast<ParenExpr>(E)) {
+ if (const auto *Exp = dyn_cast<ParenExpr>(E)) {
setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
if (LV.isObjCIvar()) {
// If cast is to a structure pointer, follow gcc's behavior and make it
@@ -1638,27 +1701,27 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
return;
}
- if (const GenericSelectionExpr *Exp = dyn_cast<GenericSelectionExpr>(E)) {
+ if (const auto *Exp = dyn_cast<GenericSelectionExpr>(E)) {
setObjCGCLValueClass(Ctx, Exp->getResultExpr(), LV);
return;
}
- if (const ImplicitCastExpr *Exp = dyn_cast<ImplicitCastExpr>(E)) {
+ if (const auto *Exp = dyn_cast<ImplicitCastExpr>(E)) {
setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
return;
}
- if (const CStyleCastExpr *Exp = dyn_cast<CStyleCastExpr>(E)) {
+ if (const auto *Exp = dyn_cast<CStyleCastExpr>(E)) {
setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
return;
}
- if (const ObjCBridgedCastExpr *Exp = dyn_cast<ObjCBridgedCastExpr>(E)) {
+ if (const auto *Exp = dyn_cast<ObjCBridgedCastExpr>(E)) {
setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV, IsMemberAccess);
return;
}
- if (const ArraySubscriptExpr *Exp = dyn_cast<ArraySubscriptExpr>(E)) {
+ if (const auto *Exp = dyn_cast<ArraySubscriptExpr>(E)) {
setObjCGCLValueClass(Ctx, Exp->getBase(), LV);
if (LV.isObjCIvar() && !LV.isObjCArray())
// Using array syntax to assigning to what an ivar points to is not
@@ -1671,7 +1734,7 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
return;
}
- if (const MemberExpr *Exp = dyn_cast<MemberExpr>(E)) {
+ if (const auto *Exp = dyn_cast<MemberExpr>(E)) {
setObjCGCLValueClass(Ctx, Exp->getBase(), LV, true);
// We don't know if member is an 'ivar', but this flag is looked at
// only in the context of LV.isObjCIvar().
@@ -1690,11 +1753,16 @@ EmitBitCastOfLValueToProperType(CodeGenFunction &CGF,
static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
const Expr *E, const VarDecl *VD) {
+ QualType T = E->getType();
+
+ // If it's thread_local, emit a call to its wrapper function instead.
+ if (VD->getTLSKind() == VarDecl::TLS_Dynamic)
+ return CGF.CGM.getCXXABI().EmitThreadLocalVarDeclLValue(CGF, VD, T);
+
llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD);
llvm::Type *RealVarTy = CGF.getTypes().ConvertTypeForMem(VD->getType());
V = EmitBitCastOfLValueToProperType(CGF, V, RealVarTy);
CharUnits Alignment = CGF.getContext().getDeclAlign(VD);
- QualType T = E->getType();
LValue LV;
if (VD->getType()->isReferenceType()) {
llvm::LoadInst *LI = CGF.Builder.CreateLoad(V);
@@ -1702,7 +1770,7 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
V = LI;
LV = CGF.MakeNaturalAlignAddrLValue(V, T);
} else {
- LV = CGF.MakeAddrLValue(V, E->getType(), Alignment);
+ LV = CGF.MakeAddrLValue(V, T, Alignment);
}
setObjCGCLValueClass(CGF.getContext(), E, LV);
return LV;
@@ -1718,7 +1786,7 @@ static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF,
// isn't the same as the type of a use. Correct for this with a
// bitcast.
QualType NoProtoType =
- CGF.getContext().getFunctionNoProtoType(Proto->getResultType());
+ CGF.getContext().getFunctionNoProtoType(Proto->getReturnType());
NoProtoType = CGF.getContext().getPointerType(NoProtoType);
V = CGF.Builder.CreateBitCast(V, CGF.ConvertType(NoProtoType));
}
@@ -1734,14 +1802,44 @@ static LValue EmitCapturedFieldLValue(CodeGenFunction &CGF, const FieldDecl *FD,
return CGF.EmitLValueForField(LV, FD);
}
+/// Named Registers are named metadata pointing to the register name
+/// which will be read from/written to as an argument to the intrinsic
+/// @llvm.read/write_register.
+/// So far, only the name is being passed down, but other options such as
+/// register type, allocation type or even optimization options could be
+/// passed down via the metadata node.
+static LValue EmitGlobalNamedRegister(const VarDecl *VD,
+ CodeGenModule &CGM,
+ CharUnits Alignment) {
+ SmallString<64> Name("llvm.named.register.");
+ AsmLabelAttr *Asm = VD->getAttr<AsmLabelAttr>();
+ assert(Asm->getLabel().size() < 64-Name.size() &&
+ "Register name too big");
+ Name.append(Asm->getLabel());
+ llvm::NamedMDNode *M =
+ CGM.getModule().getOrInsertNamedMetadata(Name);
+ if (M->getNumOperands() == 0) {
+ llvm::MDString *Str = llvm::MDString::get(CGM.getLLVMContext(),
+ Asm->getLabel());
+ llvm::Value *Ops[] = { Str };
+ M->addOperand(llvm::MDNode::get(CGM.getLLVMContext(), Ops));
+ }
+ return LValue::MakeGlobalReg(M->getOperand(0), VD->getType(), Alignment);
+}
+
LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
const NamedDecl *ND = E->getDecl();
CharUnits Alignment = getContext().getDeclAlign(ND);
QualType T = E->getType();
- // A DeclRefExpr for a reference initialized by a constant expression can
- // appear without being odr-used. Directly emit the constant initializer.
- if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
+ if (const auto *VD = dyn_cast<VarDecl>(ND)) {
+ // Global Named registers access via intrinsics only
+ if (VD->getStorageClass() == SC_Register &&
+ VD->hasAttr<AsmLabelAttr>() && !VD->isLocalVarDecl())
+ return EmitGlobalNamedRegister(VD, CGM, Alignment);
+
+ // A DeclRefExpr for a reference initialized by a constant expression can
+ // appear without being odr-used. Directly emit the constant initializer.
const Expr *Init = VD->getAnyInitializer(VD);
if (Init && !isa<ParmVarDecl>(VD) && VD->getType()->isReferenceType() &&
VD->isUsableInConstantExpressions(getContext()) &&
@@ -1762,19 +1860,15 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
"Should not use decl without marking it used!");
if (ND->hasAttr<WeakRefAttr>()) {
- const ValueDecl *VD = cast<ValueDecl>(ND);
+ const auto *VD = cast<ValueDecl>(ND);
llvm::Constant *Aliasee = CGM.GetWeakRefReference(VD);
return MakeAddrLValue(Aliasee, T, Alignment);
}
- if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
+ if (const auto *VD = dyn_cast<VarDecl>(ND)) {
// Check if this is a global variable.
- if (VD->hasLinkage() || VD->isStaticDataMember()) {
- // If it's thread_local, emit a call to its wrapper function instead.
- if (VD->getTLSKind() == VarDecl::TLS_Dynamic)
- return CGM.getCXXABI().EmitThreadLocalDeclRefExpr(*this, E);
+ if (VD->hasLinkage() || VD->isStaticDataMember())
return EmitGlobalVarDeclLValue(*this, E, VD);
- }
bool isBlockVariable = VD->hasAttr<BlocksAttr>();
@@ -1830,7 +1924,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
return LV;
}
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
+ if (const auto *FD = dyn_cast<FunctionDecl>(ND))
return EmitFunctionDeclLValue(*this, E, FD);
llvm_unreachable("Unhandled DeclRefExpr");
@@ -1907,30 +2001,6 @@ LValue CodeGenFunction::EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E) {
E->getType());
}
-static llvm::Constant*
-GetAddrOfConstantWideString(StringRef Str,
- const char *GlobalName,
- ASTContext &Context,
- QualType Ty, SourceLocation Loc,
- CodeGenModule &CGM) {
-
- StringLiteral *SL = StringLiteral::Create(Context,
- Str,
- StringLiteral::Wide,
- /*Pascal = */false,
- Ty, Loc);
- llvm::Constant *C = CGM.GetConstantArrayFromStringLiteral(SL);
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(CGM.getModule(), C->getType(),
- !CGM.getLangOpts().WritableStrings,
- llvm::GlobalValue::PrivateLinkage,
- C, GlobalName);
- const unsigned WideAlignment =
- Context.getTypeAlignInChars(Ty).getQuantity();
- GV->setAlignment(WideAlignment);
- return GV;
-}
-
static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source,
SmallString<32>& Target) {
Target.resize(CharByteWidth * (Source.size() + 1));
@@ -1951,37 +2021,31 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
case PredefinedExpr::Function:
case PredefinedExpr::LFunction:
case PredefinedExpr::FuncDName:
+ case PredefinedExpr::FuncSig:
case PredefinedExpr::PrettyFunction: {
PredefinedExpr::IdentType IdentType = E->getIdentType();
- std::string GlobalVarName;
+ std::string GVName;
+ // FIXME: We should use the string literal mangling for the Microsoft C++
+ // ABI so that strings get merged.
switch (IdentType) {
default: llvm_unreachable("Invalid type");
- case PredefinedExpr::Func:
- GlobalVarName = "__func__.";
- break;
- case PredefinedExpr::Function:
- GlobalVarName = "__FUNCTION__.";
- break;
- case PredefinedExpr::FuncDName:
- GlobalVarName = "__FUNCDNAME__.";
- break;
- case PredefinedExpr::LFunction:
- GlobalVarName = "L__FUNCTION__.";
- break;
- case PredefinedExpr::PrettyFunction:
- GlobalVarName = "__PRETTY_FUNCTION__.";
- break;
+ case PredefinedExpr::Func: GVName = "__func__."; break;
+ case PredefinedExpr::Function: GVName = "__FUNCTION__."; break;
+ case PredefinedExpr::FuncDName: GVName = "__FUNCDNAME__."; break;
+ case PredefinedExpr::FuncSig: GVName = "__FUNCSIG__."; break;
+ case PredefinedExpr::LFunction: GVName = "L__FUNCTION__."; break;
+ case PredefinedExpr::PrettyFunction: GVName = "__PRETTY_FUNCTION__."; break;
}
StringRef FnName = CurFn->getName();
if (FnName.startswith("\01"))
FnName = FnName.substr(1);
- GlobalVarName += FnName;
+ GVName += FnName;
// If this is outside of a function use the top level decl.
const Decl *CurDecl = CurCodeDecl;
- if (CurDecl == 0 || isa<VarDecl>(CurDecl))
+ if (!CurDecl || isa<VarDecl>(CurDecl))
CurDecl = getContext().getTranslationUnitDecl();
const Type *ElemType = E->getType()->getArrayElementTypeNoTypeQual();
@@ -2005,18 +2069,14 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
if (ElemType->isWideCharType()) {
SmallString<32> RawChars;
ConvertUTF8ToWideString(
- getContext().getTypeSizeInChars(ElemType).getQuantity(),
- FunctionName, RawChars);
- C = GetAddrOfConstantWideString(RawChars,
- GlobalVarName.c_str(),
- getContext(),
- E->getType(),
- E->getLocation(),
- CGM);
+ getContext().getTypeSizeInChars(ElemType).getQuantity(), FunctionName,
+ RawChars);
+ StringLiteral *SL = StringLiteral::Create(
+ getContext(), RawChars, StringLiteral::Wide,
+ /*Pascal = */ false, E->getType(), E->getLocation());
+ C = CGM.GetAddrOfConstantStringFromLiteral(SL);
} else {
- C = CGM.GetAddrOfConstantCString(FunctionName,
- GlobalVarName.c_str(),
- 1);
+ C = CGM.GetAddrOfConstantCString(FunctionName, GVName.c_str(), 1);
}
return MakeAddrLValue(C, E->getType());
}
@@ -2034,7 +2094,7 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
/// integer, 1 for a floating point value, and -1 for anything else.
llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
// Only emit each type's descriptor once.
- if (llvm::Constant *C = CGM.getTypeDescriptor(T))
+ if (llvm::Constant *C = CGM.getTypeDescriptorFromMap(T))
return C;
uint16_t TypeKind = -1;
@@ -2054,7 +2114,7 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
SmallString<32> Buffer;
CGM.getDiags().ConvertArgToString(DiagnosticsEngine::ak_qualtype,
(intptr_t)T.getAsOpaquePtr(),
- 0, 0, 0, 0, 0, 0, Buffer,
+ StringRef(), StringRef(), None, Buffer,
ArrayRef<intptr_t>());
llvm::Constant *Components[] = {
@@ -2063,15 +2123,14 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
};
llvm::Constant *Descriptor = llvm::ConstantStruct::getAnon(Components);
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(CGM.getModule(), Descriptor->getType(),
- /*isConstant=*/true,
- llvm::GlobalVariable::PrivateLinkage,
- Descriptor);
+ auto *GV = new llvm::GlobalVariable(
+ CGM.getModule(), Descriptor->getType(),
+ /*isConstant=*/true, llvm::GlobalVariable::PrivateLinkage, Descriptor);
GV->setUnnamedAddr(true);
+ CGM.disableSanitizerForGlobal(GV);
// Remember the descriptor for this type.
- CGM.setTypeDescriptor(T, GV);
+ CGM.setTypeDescriptorInMap(T, GV);
return GV;
}
@@ -2112,14 +2171,23 @@ llvm::Value *CodeGenFunction::EmitCheckValue(llvm::Value *V) {
/// \endcode
/// For an invalid SourceLocation, the Filename pointer is null.
llvm::Constant *CodeGenFunction::EmitCheckSourceLocation(SourceLocation Loc) {
+ llvm::Constant *Filename;
+ int Line, Column;
+
PresumedLoc PLoc = getContext().getSourceManager().getPresumedLoc(Loc);
+ if (PLoc.isValid()) {
+ auto FilenameGV = CGM.GetAddrOfConstantCString(PLoc.getFilename(), ".src");
+ CGM.disableSanitizerForGlobal(FilenameGV);
+ Filename = FilenameGV;
+ Line = PLoc.getLine();
+ Column = PLoc.getColumn();
+ } else {
+ Filename = llvm::Constant::getNullValue(Int8PtrTy);
+ Line = Column = 0;
+ }
- llvm::Constant *Data[] = {
- PLoc.isValid() ? CGM.GetAddrOfConstantCString(PLoc.getFilename(), ".src")
- : llvm::Constant::getNullValue(Int8PtrTy),
- Builder.getInt32(PLoc.isValid() ? PLoc.getLine() : 0),
- Builder.getInt32(PLoc.isValid() ? PLoc.getColumn() : 0)
- };
+ llvm::Constant *Data[] = {Filename, Builder.getInt32(Line),
+ Builder.getInt32(Column)};
return llvm::ConstantStruct::getAnon(Data);
}
@@ -2129,6 +2197,7 @@ void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName,
ArrayRef<llvm::Value *> DynamicArgs,
CheckRecoverableKind RecoverKind) {
assert(SanOpts != &SanitizerOptions::Disabled);
+ assert(IsSanitizerScope);
if (CGM.getCodeGenOpts().SanitizeUndefinedTrapOnError) {
assert (RecoverKind != CRK_AlwaysRecoverable &&
@@ -2151,10 +2220,11 @@ void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName,
EmitBlock(Handler);
llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
- llvm::GlobalValue *InfoPtr =
+ auto *InfoPtr =
new llvm::GlobalVariable(CGM.getModule(), Info->getType(), false,
llvm::GlobalVariable::PrivateLinkage, Info);
InfoPtr->setUnnamedAddr(true);
+ CGM.disableSanitizerForGlobal(InfoPtr);
SmallVector<llvm::Value *, 4> Args;
SmallVector<llvm::Type *, 4> ArgTypes;
@@ -2171,9 +2241,9 @@ void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName,
ArgTypes.push_back(IntPtrTy);
}
- bool Recover = (RecoverKind == CRK_AlwaysRecoverable) ||
- ((RecoverKind == CRK_Recoverable) &&
- CGM.getCodeGenOpts().SanitizeRecover);
+ bool Recover = RecoverKind == CRK_AlwaysRecoverable ||
+ (RecoverKind == CRK_Recoverable &&
+ CGM.getCodeGenOpts().SanitizeRecover);
llvm::FunctionType *FnType =
llvm::FunctionType::get(CGM.VoidTy, ArgTypes, false);
@@ -2185,15 +2255,14 @@ void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName,
B.addAttribute(llvm::Attribute::UWTable);
// Checks that have two variants use a suffix to differentiate them
- bool NeedsAbortSuffix = (RecoverKind != CRK_Unrecoverable) &&
- !CGM.getCodeGenOpts().SanitizeRecover;
+ bool NeedsAbortSuffix = RecoverKind != CRK_Unrecoverable &&
+ !CGM.getCodeGenOpts().SanitizeRecover;
std::string FunctionName = ("__ubsan_handle_" + CheckName +
(NeedsAbortSuffix? "_abort" : "")).str();
- llvm::Value *Fn =
- CGM.CreateRuntimeFunction(FnType, FunctionName,
- llvm::AttributeSet::get(getLLVMContext(),
- llvm::AttributeSet::FunctionIndex,
- B));
+ llvm::Value *Fn = CGM.CreateRuntimeFunction(
+ FnType, FunctionName,
+ llvm::AttributeSet::get(getLLVMContext(),
+ llvm::AttributeSet::FunctionIndex, B));
llvm::CallInst *HandlerCall = EmitNounwindRuntimeCall(Fn, Args);
if (Recover) {
Builder.CreateBr(Cont);
@@ -2230,14 +2299,14 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked) {
/// array to pointer, return the array subexpression.
static const Expr *isSimpleArrayDecayOperand(const Expr *E) {
// If this isn't just an array->pointer decay, bail out.
- const CastExpr *CE = dyn_cast<CastExpr>(E);
- if (CE == 0 || CE->getCastKind() != CK_ArrayToPointerDecay)
- return 0;
+ const auto *CE = dyn_cast<CastExpr>(E);
+ if (!CE || CE->getCastKind() != CK_ArrayToPointerDecay)
+ return nullptr;
// If this is a decay from variable width array, bail out.
const Expr *SubExpr = CE->getSubExpr();
if (SubExpr->getType()->isVariableArrayType())
- return 0;
+ return nullptr;
return SubExpr;
}
@@ -2258,7 +2327,6 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
// Emit the vector as an lvalue to get its address.
LValue LHS = EmitLValue(E->getBase());
assert(LHS.isSimple() && "Can only subscript lvalue vectors here!");
- Idx = Builder.CreateIntCast(Idx, Int32Ty, IdxSigned, "vidx");
return LValue::MakeVectorElt(LHS.getAddress(), Idx,
E->getBase()->getType(), LHS.getAlignment());
}
@@ -2269,7 +2337,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
// We know that the pointer points to a type of the correct size, unless the
// size is a VLA or Objective-C interface.
- llvm::Value *Address = 0;
+ llvm::Value *Address = nullptr;
CharUnits ArrayAlignment;
if (const VariableArrayType *vla =
getContext().getAsVariableArrayType(E->getType())) {
@@ -2315,7 +2383,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
LValue ArrayLV;
// For simple multidimensional array indexing, set the 'accessed' flag for
// better bounds-checking of the base expression.
- if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(Array))
+ if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Array))
ArrayLV = EmitArraySubscriptExpr(ASE, /*Accessed*/ true);
else
ArrayLV = EmitLValue(Array);
@@ -2442,16 +2510,16 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
BaseLV = EmitCheckedLValue(BaseExpr, TCK_MemberAccess);
NamedDecl *ND = E->getMemberDecl();
- if (FieldDecl *Field = dyn_cast<FieldDecl>(ND)) {
+ if (auto *Field = dyn_cast<FieldDecl>(ND)) {
LValue LV = EmitLValueForField(BaseLV, Field);
setObjCGCLValueClass(getContext(), E, LV);
return LV;
}
- if (VarDecl *VD = dyn_cast<VarDecl>(ND))
+ if (auto *VD = dyn_cast<VarDecl>(ND))
return EmitGlobalVarDeclLValue(*this, E, VD);
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
+ if (const auto *FD = dyn_cast<FunctionDecl>(ND))
return EmitFunctionDeclLValue(*this, E, FD);
llvm_unreachable("Unhandled member declaration!");
@@ -2641,6 +2709,19 @@ LValue CodeGenFunction::EmitInitListLValue(const InitListExpr *E) {
return EmitLValue(E->getInit(0));
}
+/// Emit the operand of a glvalue conditional operator. This is either a glvalue
+/// or a (possibly-parenthesized) throw-expression. If this is a throw, no
+/// LValue is returned and the current block has been terminated.
+static Optional<LValue> EmitLValueOrThrowExpression(CodeGenFunction &CGF,
+ const Expr *Operand) {
+ if (auto *ThrowExpr = dyn_cast<CXXThrowExpr>(Operand->IgnoreParens())) {
+ CGF.EmitCXXThrowExpr(ThrowExpr, /*KeepInsertionPoint*/false);
+ return None;
+ }
+
+ return CGF.EmitLValue(Operand);
+}
+
LValue CodeGenFunction::
EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
if (!expr->isGLValue()) {
@@ -2651,6 +2732,7 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
}
OpaqueValueMapping binding(*this, expr);
+ RegionCounter Cnt = getPGORegionCounter(expr);
const Expr *condExpr = expr->getCond();
bool CondExprBool;
@@ -2658,8 +2740,12 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
const Expr *live = expr->getTrueExpr(), *dead = expr->getFalseExpr();
if (!CondExprBool) std::swap(live, dead);
- if (!ContainsLabel(dead))
+ if (!ContainsLabel(dead)) {
+ // If the true case is live, we need to track its region.
+ if (CondExprBool)
+ Cnt.beginRegion(Builder);
return EmitLValue(live);
+ }
}
llvm::BasicBlock *lhsBlock = createBasicBlock("cond.true");
@@ -2667,36 +2753,46 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
llvm::BasicBlock *contBlock = createBasicBlock("cond.end");
ConditionalEvaluation eval(*this);
- EmitBranchOnBoolExpr(condExpr, lhsBlock, rhsBlock);
+ EmitBranchOnBoolExpr(condExpr, lhsBlock, rhsBlock, Cnt.getCount());
// Any temporaries created here are conditional.
EmitBlock(lhsBlock);
+ Cnt.beginRegion(Builder);
eval.begin(*this);
- LValue lhs = EmitLValue(expr->getTrueExpr());
+ Optional<LValue> lhs =
+ EmitLValueOrThrowExpression(*this, expr->getTrueExpr());
eval.end(*this);
- if (!lhs.isSimple())
+ if (lhs && !lhs->isSimple())
return EmitUnsupportedLValue(expr, "conditional operator");
lhsBlock = Builder.GetInsertBlock();
- Builder.CreateBr(contBlock);
+ if (lhs)
+ Builder.CreateBr(contBlock);
// Any temporaries created here are conditional.
EmitBlock(rhsBlock);
eval.begin(*this);
- LValue rhs = EmitLValue(expr->getFalseExpr());
+ Optional<LValue> rhs =
+ EmitLValueOrThrowExpression(*this, expr->getFalseExpr());
eval.end(*this);
- if (!rhs.isSimple())
+ if (rhs && !rhs->isSimple())
return EmitUnsupportedLValue(expr, "conditional operator");
rhsBlock = Builder.GetInsertBlock();
EmitBlock(contBlock);
- llvm::PHINode *phi = Builder.CreatePHI(lhs.getAddress()->getType(), 2,
- "cond-lvalue");
- phi->addIncoming(lhs.getAddress(), lhsBlock);
- phi->addIncoming(rhs.getAddress(), rhsBlock);
- return MakeAddrLValue(phi, expr->getType());
+ if (lhs && rhs) {
+ llvm::PHINode *phi = Builder.CreatePHI(lhs->getAddress()->getType(),
+ 2, "cond-lvalue");
+ phi->addIncoming(lhs->getAddress(), lhsBlock);
+ phi->addIncoming(rhs->getAddress(), rhsBlock);
+ return MakeAddrLValue(phi, expr->getType());
+ } else {
+ assert((lhs || rhs) &&
+ "both operands of glvalue conditional are throw-expressions?");
+ return lhs ? *lhs : *rhs;
+ }
}
/// EmitCastLValue - Casts are never lvalues unless that cast is to a reference
@@ -2744,6 +2840,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
case CK_CopyAndAutoreleaseBlockObject:
+ case CK_AddressSpaceConversion:
return EmitUnsupportedLValue(E, "unexpected cast lvalue");
case CK_Dependent:
@@ -2760,7 +2857,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_Dynamic: {
LValue LV = EmitLValue(E->getSubExpr());
llvm::Value *V = LV.getAddress();
- const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(E);
+ const auto *DCE = cast<CXXDynamicCastExpr>(E);
return MakeAddrLValue(EmitDynamicCast(V, DCE), E->getType());
}
@@ -2776,8 +2873,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_DerivedToBase: {
const RecordType *DerivedClassTy =
E->getSubExpr()->getType()->getAs<RecordType>();
- CXXRecordDecl *DerivedClassDecl =
- cast<CXXRecordDecl>(DerivedClassTy->getDecl());
+ auto *DerivedClassDecl = cast<CXXRecordDecl>(DerivedClassTy->getDecl());
LValue LV = EmitLValue(E->getSubExpr());
llvm::Value *This = LV.getAddress();
@@ -2794,8 +2890,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
return EmitAggExprToLValue(E);
case CK_BaseToDerived: {
const RecordType *DerivedClassTy = E->getType()->getAs<RecordType>();
- CXXRecordDecl *DerivedClassDecl =
- cast<CXXRecordDecl>(DerivedClassTy->getDecl());
+ auto *DerivedClassDecl = cast<CXXRecordDecl>(DerivedClassTy->getDecl());
LValue LV = EmitLValue(E->getSubExpr());
@@ -2807,7 +2902,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
// C++11 [expr.static.cast]p2: Behavior is undefined if a downcast is
// performed and the object is not of the derived type.
- if (SanitizePerformTypeCheck)
+ if (sanitizePerformTypeCheck())
EmitTypeCheck(TCK_DowncastReference, E->getExprLoc(),
Derived, E->getType());
@@ -2815,7 +2910,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
}
case CK_LValueBitCast: {
// This must be a reinterpret_cast (or c-style equivalent).
- const ExplicitCastExpr *CE = cast<ExplicitCastExpr>(E);
+ const auto *CE = cast<ExplicitCastExpr>(E);
LValue LV = EmitLValue(E->getSubExpr());
llvm::Value *V = Builder.CreateBitCast(LV.getAddress(),
@@ -2867,6 +2962,10 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
SourceLocation Loc = E->getLocStart();
// Force column info to be generated so we can differentiate
// multiple call sites on the same line in the debug info.
+ // FIXME: This is insufficient. Two calls coming from the same macro
+ // expansion will still get the same line/column and break debug info. It's
+ // possible that LLVM can be fixed to not rely on this uniqueness, at which
+ // point this workaround can be removed.
const FunctionDecl* Callee = E->getDirectCallee();
bool ForceColumnInfo = Callee && Callee->isInlineSpecified();
DI->EmitLocation(Builder, Loc, ForceColumnInfo);
@@ -2876,10 +2975,10 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
if (E->getCallee()->getType()->isBlockPointerType())
return EmitBlockCallExpr(E, ReturnValue);
- if (const CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(E))
+ if (const auto *CE = dyn_cast<CXXMemberCallExpr>(E))
return EmitCXXMemberCallExpr(CE, ReturnValue);
- if (const CUDAKernelCallExpr *CE = dyn_cast<CUDAKernelCallExpr>(E))
+ if (const auto *CE = dyn_cast<CUDAKernelCallExpr>(E))
return EmitCUDAKernelCallExpr(CE, ReturnValue);
const Decl *TargetDecl = E->getCalleeDecl();
@@ -2888,12 +2987,12 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
return EmitBuiltinExpr(FD, builtinID, E);
}
- if (const CXXOperatorCallExpr *CE = dyn_cast<CXXOperatorCallExpr>(E))
+ if (const auto *CE = dyn_cast<CXXOperatorCallExpr>(E))
if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(TargetDecl))
return EmitCXXOperatorMemberCallExpr(CE, MD, ReturnValue);
- if (const CXXPseudoDestructorExpr *PseudoDtor
- = dyn_cast<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) {
+ if (const auto *PseudoDtor =
+ dyn_cast<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) {
QualType DestroyedType = PseudoDtor->getDestroyedType();
if (getLangOpts().ObjCAutoRefCount &&
DestroyedType->isObjCLifetimeType() &&
@@ -2903,7 +3002,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
// 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;
+ llvm::Value *BaseValue = nullptr;
Qualifiers BaseQuals;
// If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar.
@@ -2943,7 +3042,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
EmitScalarExpr(E->getCallee());
}
- return RValue::get(0);
+ return RValue::get(nullptr);
}
llvm::Value *Callee = EmitScalarExpr(E->getCallee());
@@ -3061,7 +3160,7 @@ LValue CodeGenFunction::EmitObjCMessageExprLValue(const ObjCMessageExpr *E) {
if (!RV.isScalar())
return MakeAddrLValue(RV.getAggregateAddr(), E->getType());
- assert(E->getMethodDecl()->getResultType()->isReferenceType() &&
+ assert(E->getMethodDecl()->getReturnType()->isReferenceType() &&
"Can't have a scalar return unless the return type is a "
"reference type!");
@@ -3089,7 +3188,7 @@ LValue CodeGenFunction::EmitLValueForIvar(QualType ObjectTy,
LValue CodeGenFunction::EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E) {
// FIXME: A lot of the code below could be shared with EmitMemberExpr.
- llvm::Value *BaseValue = 0;
+ llvm::Value *BaseValue = nullptr;
const Expr *BaseExpr = E->getBase();
Qualifiers BaseQuals;
QualType ObjectTy;
@@ -3131,11 +3230,15 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
CalleeType = getContext().getCanonicalType(CalleeType);
- const FunctionType *FnType
- = cast<FunctionType>(cast<PointerType>(CalleeType)->getPointeeType());
+ const auto *FnType =
+ cast<FunctionType>(cast<PointerType>(CalleeType)->getPointeeType());
// Force column info to differentiate multiple inlined call sites on
// the same line, analoguous to EmitCallExpr.
+ // FIXME: This is insufficient. Two calls coming from the same macro expansion
+ // will still get the same line/column and break debug info. It's possible
+ // that LLVM can be fixed to not rely on this uniqueness, at which point this
+ // workaround can be removed.
bool ForceColumnInfo = false;
if (const FunctionDecl* FD = dyn_cast_or_null<const FunctionDecl>(TargetDecl))
ForceColumnInfo = FD->isInlineSpecified();
@@ -3144,6 +3247,7 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
(!TargetDecl || !isa<FunctionDecl>(TargetDecl))) {
if (llvm::Constant *PrefixSig =
CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM)) {
+ SanitizerScope SanScope(this);
llvm::Constant *FTRTTIConst =
CGM.GetAddrOfRTTIDescriptor(QualType(FnType, 0), /*ForEH=*/true);
llvm::Type *PrefixStructTyElems[] = {
@@ -3231,8 +3335,8 @@ EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) {
const MemberPointerType *MPT
= E->getRHS()->getType()->getAs<MemberPointerType>();
- llvm::Value *AddV =
- CGM.getCXXABI().EmitMemberDataPointerAddress(*this, BaseV, OffsetV, MPT);
+ llvm::Value *AddV = CGM.getCXXABI().EmitMemberDataPointerAddress(
+ *this, E, BaseV, OffsetV, MPT);
return MakeAddrLValue(AddV, MPT->getPointeeType());
}
@@ -3288,7 +3392,7 @@ static LValueOrRValue emitPseudoObjectExpr(CodeGenFunction &CGF,
// If this semantic expression is an opaque value, bind it
// to the result of its source expression.
- if (const OpaqueValueExpr *ov = dyn_cast<OpaqueValueExpr>(semantic)) {
+ if (const auto *ov = dyn_cast<OpaqueValueExpr>(semantic)) {
// If this is the result expression, we may need to evaluate
// directly into the slot.
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 9d0f3a9661a6..4cf94c033bb4 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -370,6 +370,29 @@ AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
}
}
+/// \brief Determine if E is a trivial array filler, that is, one that is
+/// equivalent to zero-initialization.
+static bool isTrivialFiller(Expr *E) {
+ if (!E)
+ return true;
+
+ if (isa<ImplicitValueInitExpr>(E))
+ return true;
+
+ if (auto *ILE = dyn_cast<InitListExpr>(E)) {
+ if (ILE->getNumInits())
+ return false;
+ return isTrivialFiller(ILE->getArrayFiller());
+ }
+
+ if (auto *Cons = dyn_cast_or_null<CXXConstructExpr>(E))
+ return Cons->getConstructor()->isDefaultConstructor() &&
+ Cons->getConstructor()->isTrivial();
+
+ // FIXME: Are there other cases where we can avoid emitting an initializer?
+ return false;
+}
+
/// \brief Emit initialization of an array from an initializer list.
void AggExprEmitter::EmitArrayInit(llvm::Value *DestPtr, llvm::ArrayType *AType,
QualType elementType, InitListExpr *E) {
@@ -389,9 +412,9 @@ void AggExprEmitter::EmitArrayInit(llvm::Value *DestPtr, llvm::ArrayType *AType,
// already-constructed members if an initializer throws.
// For that, we'll need an EH cleanup.
QualType::DestructionKind dtorKind = elementType.isDestructedType();
- llvm::AllocaInst *endOfInit = 0;
+ llvm::AllocaInst *endOfInit = nullptr;
EHScopeStack::stable_iterator cleanup;
- llvm::Instruction *cleanupDominator = 0;
+ llvm::Instruction *cleanupDominator = nullptr;
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
@@ -435,14 +458,8 @@ void AggExprEmitter::EmitArrayInit(llvm::Value *DestPtr, llvm::ArrayType *AType,
}
// 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();
- }
+ bool hasTrivialFiller = isTrivialFiller(filler);
// Any remaining elements need to be zero-initialized, possibly
// using the filler expression. We can skip this if the we're
@@ -539,7 +556,7 @@ static Expr *findPeephole(Expr *op, CastKind kind) {
if (castE->getCastKind() == CK_NoOp)
continue;
}
- return 0;
+ return nullptr;
}
}
@@ -713,6 +730,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_CopyAndAutoreleaseBlockObject:
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLEvent:
+ case CK_AddressSpaceConversion:
llvm_unreachable("cast kind invalid for aggregate types");
}
}
@@ -891,14 +909,16 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
// Bind the common expression if necessary.
CodeGenFunction::OpaqueValueMapping binding(CGF, E);
+ RegionCounter Cnt = CGF.getPGORegionCounter(E);
CodeGenFunction::ConditionalEvaluation eval(CGF);
- CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
+ CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock, Cnt.getCount());
// Save whether the destination's lifetime is externally managed.
bool isExternallyDestructed = Dest.isExternallyDestructed();
eval.begin(CGF);
CGF.EmitBlock(LHSBlock);
+ Cnt.beginRegion(Builder);
Visit(E->getTrueExpr());
eval.end(CGF);
@@ -928,7 +948,11 @@ void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
llvm::Value *ArgPtr = CGF.EmitVAArg(ArgValue, VE->getType());
if (!ArgPtr) {
- CGF.ErrorUnsupported(VE, "aggregate va_arg expression");
+ // If EmitVAArg fails, we fall back to the LLVM instruction.
+ llvm::Value *Val =
+ Builder.CreateVAArg(ArgValue, CGF.ConvertType(VE->getType()));
+ if (!Dest.isIgnored())
+ Builder.CreateStore(Val, Dest.getAddr());
return;
}
@@ -1037,7 +1061,7 @@ AggExprEmitter::EmitInitializationToLValue(Expr *E, LValue LV) {
return;
case TEK_Scalar:
if (LV.isSimple()) {
- CGF.EmitScalarInit(E, /*D=*/0, LV, /*Captured=*/false);
+ CGF.EmitScalarInit(E, /*D=*/nullptr, LV, /*Captured=*/false);
} else {
CGF.EmitStoreThroughLValue(RValue::get(CGF.EmitScalarExpr(E)), LV);
}
@@ -1113,6 +1137,16 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
return;
}
+ if (E->getType()->isAtomicType()) {
+ // An _Atomic(T) object can be list-initialized from an expression
+ // of the same type.
+ assert(E->getNumInits() == 1 &&
+ CGF.getContext().hasSameUnqualifiedType(E->getInit(0)->getType(),
+ E->getType()) &&
+ "unexpected list initialization for atomic object");
+ return Visit(E->getInit(0));
+ }
+
assert(E->getType()->isRecordType() && "Only support structs/unions here!");
// Do struct initialization; this code just sets each individual member
@@ -1134,9 +1168,7 @@ 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 = record->field_begin(),
- FieldEnd = record->field_end();
- Field != FieldEnd; ++Field)
+ for (const auto *Field : record->fields())
assert(Field->isUnnamedBitfield() && "Only unnamed bitfields allowed");
#endif
return;
@@ -1160,14 +1192,12 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
// We'll need to enter cleanup scopes in case any of the member
// initializers throw an exception.
SmallVector<EHScopeStack::stable_iterator, 16> cleanups;
- llvm::Instruction *cleanupDominator = 0;
+ llvm::Instruction *cleanupDominator = nullptr;
// Here we iterate over the fields; this makes it simpler to both
// default-initialize fields and skip over unnamed fields.
unsigned curInitIndex = 0;
- for (RecordDecl::field_iterator field = record->field_begin(),
- fieldEnd = record->field_end();
- field != fieldEnd; ++field) {
+ for (const auto *field : record->fields()) {
// We're done once we hit the flexible array member.
if (field->getType()->isIncompleteArrayType())
break;
@@ -1184,7 +1214,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
break;
- LValue LV = CGF.EmitLValueForFieldInitialization(DestLV, *field);
+ LValue LV = CGF.EmitLValueForFieldInitialization(DestLV, field);
// We never generate write-barries for initialized fields.
LV.setNonGC(true);
@@ -1249,7 +1279,7 @@ static CharUnits GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
// If this is an initlist expr, sum up the size of sizes of the (present)
// elements. If this is something weird, assume the whole thing is non-zero.
const InitListExpr *ILE = dyn_cast<InitListExpr>(E);
- if (ILE == 0 || !CGF.getTypes().isZeroInitializable(ILE->getType()))
+ if (!ILE || !CGF.getTypes().isZeroInitializable(ILE->getType()))
return CGF.getContext().getTypeSizeInChars(E->getType());
// InitListExprs for structs have to be handled carefully. If there are
@@ -1261,8 +1291,7 @@ static CharUnits GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
CharUnits NumNonZeroBytes = CharUnits::Zero();
unsigned ILEElement = 0;
- for (RecordDecl::field_iterator Field = SD->field_begin(),
- FieldEnd = SD->field_end(); Field != FieldEnd; ++Field) {
+ for (const auto *Field : SD->fields()) {
// We're done once we hit the flexible array member or run out of
// InitListExpr elements.
if (Field->getType()->isIncompleteArrayType() ||
@@ -1299,7 +1328,8 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
CodeGenFunction &CGF) {
// If the slot is already known to be zeroed, nothing to do. Don't mess with
// volatile stores.
- if (Slot.isZeroed() || Slot.isVolatile() || Slot.getAddr() == 0) return;
+ if (Slot.isZeroed() || Slot.isVolatile() || Slot.getAddr() == nullptr)
+ return;
// C++ objects with a user-declared constructor don't need zero'ing.
if (CGF.getLangOpts().CPlusPlus)
@@ -1346,7 +1376,7 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot) {
assert(E && hasAggregateEvaluationKind(E->getType()) &&
"Invalid aggregate expression to emit");
- assert((Slot.getAddr() != 0 || Slot.isIgnored()) &&
+ assert((Slot.getAddr() != nullptr || Slot.isIgnored()) &&
"slot has bits but no address");
// Optimize the slot if possible.
@@ -1466,10 +1496,10 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
// memcpy, as well as the TBAA tags for the members of the struct, in case
// the optimizer wishes to expand it in to scalar memory operations.
llvm::MDNode *TBAAStructTag = CGM.getTBAAStructInfo(Ty);
-
+
Builder.CreateMemCpy(DestPtr, SrcPtr,
llvm::ConstantInt::get(IntPtrTy,
TypeInfo.first.getQuantity()),
alignment.getQuantity(), isVolatile,
- /*TBAATag=*/0, TBAAStructTag);
+ /*TBAATag=*/nullptr, TBAAStructTag);
}
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index cc7b24d5e83e..7aacee4d6ba1 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -18,8 +18,8 @@
#include "CGObjCRuntime.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
+#include "llvm/IR/CallSite.h"
#include "llvm/IR/Intrinsics.h"
-#include "llvm/Support/CallSite.h"
using namespace clang;
using namespace CodeGen;
@@ -95,7 +95,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
const Expr *Base = ME->getBase();
bool CanUseVirtualCall = MD->isVirtual() && !ME->hasQualifier();
- const CXXMethodDecl *DevirtualizedMethod = NULL;
+ const CXXMethodDecl *DevirtualizedMethod = nullptr;
if (CanUseVirtualCall && CanDevirtualizeMemberFunctionCall(Base, MD)) {
const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType();
DevirtualizedMethod = MD->getCorrespondingMethodInClass(BestDynamicDecl);
@@ -111,7 +111,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
// one or the one of the full expression, we would have to build
// a derived-to-base cast to compute the correct this pointer, but
// we don't have support for that yet, so do a virtual call.
- DevirtualizedMethod = NULL;
+ DevirtualizedMethod = nullptr;
}
// If the return types are not the same, this might be a case where more
// code needs to run to compensate for it. For example, the derived
@@ -119,9 +119,9 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
// type of MD and has a prefix.
// For now we just avoid devirtualizing these covariant cases.
if (DevirtualizedMethod &&
- DevirtualizedMethod->getResultType().getCanonicalType() !=
- MD->getResultType().getCanonicalType())
- DevirtualizedMethod = NULL;
+ DevirtualizedMethod->getReturnType().getCanonicalType() !=
+ MD->getReturnType().getCanonicalType())
+ DevirtualizedMethod = nullptr;
}
llvm::Value *This;
@@ -132,10 +132,10 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
if (MD->isTrivial()) {
- if (isa<CXXDestructorDecl>(MD)) return RValue::get(0);
+ if (isa<CXXDestructorDecl>(MD)) return RValue::get(nullptr);
if (isa<CXXConstructorDecl>(MD) &&
cast<CXXConstructorDecl>(MD)->isDefaultConstructor())
- return RValue::get(0);
+ return RValue::get(nullptr);
if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) {
// We don't like to generate the trivial copy/move assignment operator
@@ -158,7 +158,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
// Compute the function type we're calling.
const CXXMethodDecl *CalleeDecl = DevirtualizedMethod ? DevirtualizedMethod : MD;
- const CGFunctionInfo *FInfo = 0;
+ const CGFunctionInfo *FInfo = nullptr;
if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(CalleeDecl))
FInfo = &CGM.getTypes().arrangeCXXDestructor(Dtor,
Dtor_Complete);
@@ -199,9 +199,9 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
Callee = CGM.GetAddrOfFunction(GlobalDecl(DDtor, Dtor_Complete), Ty);
}
EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This,
- /*ImplicitParam=*/0, QualType(), 0, 0);
+ /*ImplicitParam=*/nullptr, QualType(), nullptr,nullptr);
}
- return RValue::get(0);
+ return RValue::get(nullptr);
}
if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
@@ -220,11 +220,13 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
}
}
- if (MD->isVirtual())
- This = CGM.getCXXABI().adjustThisArgumentForVirtualCall(*this, MD, This);
+ if (MD->isVirtual()) {
+ This = CGM.getCXXABI().adjustThisArgumentForVirtualFunctionCall(
+ *this, MD, This, UseVirtualCall);
+ }
return EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This,
- /*ImplicitParam=*/0, QualType(),
+ /*ImplicitParam=*/nullptr, QualType(),
CE->arg_begin(), CE->arg_end());
}
@@ -260,7 +262,7 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
// Ask the ABI to load the callee. Note that This is modified.
llvm::Value *Callee =
- CGM.getCXXABI().EmitLoadOfMemberFunctionPointer(*this, This, MemFnPtr, MPT);
+ CGM.getCXXABI().EmitLoadOfMemberFunctionPointer(*this, BO, This, MemFnPtr, MPT);
CallArgList Args;
@@ -297,7 +299,7 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
llvm::Value *Callee = EmitCXXOperatorMemberCallee(E, MD, This);
return EmitCXXMemberCall(MD, E->getExprLoc(), Callee, ReturnValue, This,
- /*ImplicitParam=*/0, QualType(),
+ /*ImplicitParam=*/nullptr, QualType(),
E->arg_begin() + 1, E->arg_end());
}
@@ -316,7 +318,7 @@ static void EmitNullBaseClassInitialization(CodeGenFunction &CGF,
const ASTRecordLayout &Layout = CGF.getContext().getASTRecordLayout(Base);
CharUnits Size = Layout.getNonVirtualSize();
- CharUnits Align = Layout.getNonVirtualAlign();
+ CharUnits Align = Layout.getNonVirtualAlignment();
llvm::Value *SizeVal = CGF.CGM.getSize(Size);
@@ -584,7 +586,7 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
// size := sizeWithoutCookie + cookieSize
// and check whether it overflows.
- llvm::Value *hasOverflow = 0;
+ llvm::Value *hasOverflow = nullptr;
// If numElementsWidth > sizeWidth, then one way or another, we're
// going to have to do a comparison for (2), and this happens to
@@ -724,8 +726,8 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
CharUnits Alignment = CGF.getContext().getTypeAlignInChars(AllocType);
switch (CGF.getEvaluationKind(AllocType)) {
case TEK_Scalar:
- CGF.EmitScalarInit(Init, 0, CGF.MakeAddrLValue(NewPtr, AllocType,
- Alignment),
+ CGF.EmitScalarInit(Init, nullptr, CGF.MakeAddrLValue(NewPtr, AllocType,
+ Alignment),
false);
return;
case TEK_Complex:
@@ -747,185 +749,249 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
}
void
-CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
- QualType elementType,
- llvm::Value *beginPtr,
- llvm::Value *numElements) {
+CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
+ QualType ElementType,
+ llvm::Value *BeginPtr,
+ llvm::Value *NumElements,
+ llvm::Value *AllocSizeWithoutCookie) {
+ // If we have a type with trivial initialization and no initializer,
+ // there's nothing to do.
if (!E->hasInitializer())
- return; // We have a POD type.
+ return;
- llvm::Value *explicitPtr = beginPtr;
- // Find the end of the array, hoisted out of the loop.
- llvm::Value *endPtr =
- Builder.CreateInBoundsGEP(beginPtr, numElements, "array.end");
+ llvm::Value *CurPtr = BeginPtr;
- unsigned initializerElements = 0;
+ unsigned InitListElements = 0;
const Expr *Init = E->getInitializer();
- llvm::AllocaInst *endOfInit = 0;
- QualType::DestructionKind dtorKind = elementType.isDestructedType();
- EHScopeStack::stable_iterator cleanup;
- llvm::Instruction *cleanupDominator = 0;
+ llvm::AllocaInst *EndOfInit = nullptr;
+ QualType::DestructionKind DtorKind = ElementType.isDestructedType();
+ EHScopeStack::stable_iterator Cleanup;
+ llvm::Instruction *CleanupDominator = nullptr;
// If the initializer is an initializer list, first do the explicit elements.
if (const InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
- initializerElements = ILE->getNumInits();
+ InitListElements = ILE->getNumInits();
// If this is a multi-dimensional array new, we will initialize multiple
// elements with each init list element.
QualType AllocType = E->getAllocatedType();
if (const ConstantArrayType *CAT = dyn_cast_or_null<ConstantArrayType>(
AllocType->getAsArrayTypeUnsafe())) {
- unsigned AS = explicitPtr->getType()->getPointerAddressSpace();
+ unsigned AS = CurPtr->getType()->getPointerAddressSpace();
llvm::Type *AllocPtrTy = ConvertTypeForMem(AllocType)->getPointerTo(AS);
- explicitPtr = Builder.CreateBitCast(explicitPtr, AllocPtrTy);
- initializerElements *= getContext().getConstantArrayElementCount(CAT);
+ CurPtr = Builder.CreateBitCast(CurPtr, AllocPtrTy);
+ InitListElements *= getContext().getConstantArrayElementCount(CAT);
}
- // Enter a partial-destruction cleanup if necessary.
- if (needsEHCleanup(dtorKind)) {
- // In principle we could tell the cleanup where we are more
+ // Enter a partial-destruction Cleanup if necessary.
+ if (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 = CreateTempAlloca(beginPtr->getType(), "array.endOfInit");
- cleanupDominator = Builder.CreateStore(beginPtr, endOfInit);
- pushIrregularPartialArrayCleanup(beginPtr, endOfInit, elementType,
- getDestroyer(dtorKind));
- cleanup = EHStack.stable_begin();
+ EndOfInit = CreateTempAlloca(BeginPtr->getType(), "array.init.end");
+ CleanupDominator = Builder.CreateStore(BeginPtr, EndOfInit);
+ pushIrregularPartialArrayCleanup(BeginPtr, EndOfInit, ElementType,
+ getDestroyer(DtorKind));
+ Cleanup = EHStack.stable_begin();
}
for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i) {
// 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(explicitPtr, endOfInit);
+ if (EndOfInit)
+ Builder.CreateStore(Builder.CreateBitCast(CurPtr, BeginPtr->getType()),
+ EndOfInit);
+ // FIXME: If the last initializer is an incomplete initializer list for
+ // an array, and we have an array filler, we can fold together the two
+ // initialization loops.
StoreAnyExprIntoOneUnit(*this, ILE->getInit(i),
- ILE->getInit(i)->getType(), explicitPtr);
- explicitPtr = Builder.CreateConstGEP1_32(explicitPtr, 1,
- "array.exp.next");
+ ILE->getInit(i)->getType(), CurPtr);
+ CurPtr = Builder.CreateConstInBoundsGEP1_32(CurPtr, 1, "array.exp.next");
}
// The remaining elements are filled with the array filler expression.
Init = ILE->getArrayFiller();
- explicitPtr = Builder.CreateBitCast(explicitPtr, beginPtr->getType());
+ // Extract the initializer for the individual array elements by pulling
+ // out the array filler from all the nested initializer lists. This avoids
+ // generating a nested loop for the initialization.
+ while (Init && Init->getType()->isConstantArrayType()) {
+ auto *SubILE = dyn_cast<InitListExpr>(Init);
+ if (!SubILE)
+ break;
+ assert(SubILE->getNumInits() == 0 && "explicit inits in array filler?");
+ Init = SubILE->getArrayFiller();
+ }
+
+ // Switch back to initializing one base element at a time.
+ CurPtr = Builder.CreateBitCast(CurPtr, BeginPtr->getType());
}
- // Create the continuation block.
- llvm::BasicBlock *contBB = createBasicBlock("new.loop.end");
+ // Attempt to perform zero-initialization using memset.
+ auto TryMemsetInitialization = [&]() -> bool {
+ // FIXME: If the type is a pointer-to-data-member under the Itanium ABI,
+ // we can initialize with a memset to -1.
+ if (!CGM.getTypes().isZeroInitializable(ElementType))
+ return false;
+
+ // Optimization: since zero initialization will just set the memory
+ // to all zeroes, generate a single memset to do it in one shot.
+
+ // Subtract out the size of any elements we've already initialized.
+ auto *RemainingSize = AllocSizeWithoutCookie;
+ if (InitListElements) {
+ // We know this can't overflow; we check this when doing the allocation.
+ auto *InitializedSize = llvm::ConstantInt::get(
+ RemainingSize->getType(),
+ getContext().getTypeSizeInChars(ElementType).getQuantity() *
+ InitListElements);
+ RemainingSize = Builder.CreateSub(RemainingSize, InitializedSize);
+ }
+
+ // Create the memset.
+ CharUnits Alignment = getContext().getTypeAlignInChars(ElementType);
+ Builder.CreateMemSet(CurPtr, Builder.getInt8(0), RemainingSize,
+ Alignment.getQuantity(), false);
+ return true;
+ };
+
+ // If all elements have already been initialized, skip any further
+ // initialization.
+ llvm::ConstantInt *ConstNum = dyn_cast<llvm::ConstantInt>(NumElements);
+ if (ConstNum && ConstNum->getZExtValue() <= InitListElements) {
+ // If there was a Cleanup, deactivate it.
+ if (CleanupDominator)
+ DeactivateCleanupBlock(Cleanup, CleanupDominator);
+ return;
+ }
+
+ assert(Init && "have trailing elements to initialize but no initializer");
+
+ // If this is a constructor call, try to optimize it out, and failing that
+ // emit a single loop to initialize all remaining elements.
+ if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) {
+ CXXConstructorDecl *Ctor = CCE->getConstructor();
+ if (Ctor->isTrivial()) {
+ // If new expression did not specify value-initialization, then there
+ // is no initialization.
+ if (!CCE->requiresZeroInitialization() || Ctor->getParent()->isEmpty())
+ return;
+
+ if (TryMemsetInitialization())
+ return;
+ }
+
+ // Store the new Cleanup position for irregular Cleanups.
+ //
+ // FIXME: Share this cleanup with the constructor call emission rather than
+ // having it create a cleanup of its own.
+ if (EndOfInit) Builder.CreateStore(CurPtr, EndOfInit);
+
+ // Emit a constructor call loop to initialize the remaining elements.
+ if (InitListElements)
+ NumElements = Builder.CreateSub(
+ NumElements,
+ llvm::ConstantInt::get(NumElements->getType(), InitListElements));
+ EmitCXXAggrConstructorCall(Ctor, NumElements, CurPtr,
+ CCE->arg_begin(), CCE->arg_end(),
+ CCE->requiresZeroInitialization());
+ return;
+ }
+
+ // If this is value-initialization, we can usually use memset.
+ ImplicitValueInitExpr IVIE(ElementType);
+ if (isa<ImplicitValueInitExpr>(Init)) {
+ if (TryMemsetInitialization())
+ return;
+
+ // Switch to an ImplicitValueInitExpr for the element type. This handles
+ // only one case: multidimensional array new of pointers to members. In
+ // all other cases, we already have an initializer for the array element.
+ Init = &IVIE;
+ }
+
+ // At this point we should have found an initializer for the individual
+ // elements of the array.
+ assert(getContext().hasSameUnqualifiedType(ElementType, Init->getType()) &&
+ "got wrong type of element to initialize");
+
+ // If we have an empty initializer list, we can usually use memset.
+ if (auto *ILE = dyn_cast<InitListExpr>(Init))
+ if (ILE->getNumInits() == 0 && TryMemsetInitialization())
+ return;
+
+ // Create the loop blocks.
+ llvm::BasicBlock *EntryBB = Builder.GetInsertBlock();
+ llvm::BasicBlock *LoopBB = createBasicBlock("new.loop");
+ llvm::BasicBlock *ContBB = createBasicBlock("new.loop.end");
+
+ // Find the end of the array, hoisted out of the loop.
+ llvm::Value *EndPtr =
+ Builder.CreateInBoundsGEP(BeginPtr, NumElements, "array.end");
// If the number of elements isn't constant, we have to now check if there is
// anything left to initialize.
- if (llvm::ConstantInt *constNum = dyn_cast<llvm::ConstantInt>(numElements)) {
- // If all elements have already been initialized, skip the whole loop.
- if (constNum->getZExtValue() <= initializerElements) {
- // If there was a cleanup, deactivate it.
- if (cleanupDominator)
- DeactivateCleanupBlock(cleanup, cleanupDominator);
- return;
- }
- } else {
- llvm::BasicBlock *nonEmptyBB = createBasicBlock("new.loop.nonempty");
- llvm::Value *isEmpty = Builder.CreateICmpEQ(explicitPtr, endPtr,
+ if (!ConstNum) {
+ llvm::Value *IsEmpty = Builder.CreateICmpEQ(CurPtr, EndPtr,
"array.isempty");
- Builder.CreateCondBr(isEmpty, contBB, nonEmptyBB);
- EmitBlock(nonEmptyBB);
+ Builder.CreateCondBr(IsEmpty, ContBB, LoopBB);
}
// Enter the loop.
- llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
- llvm::BasicBlock *loopBB = createBasicBlock("new.loop");
-
- EmitBlock(loopBB);
+ EmitBlock(LoopBB);
// Set up the current-element phi.
- llvm::PHINode *curPtr =
- Builder.CreatePHI(explicitPtr->getType(), 2, "array.cur");
- curPtr->addIncoming(explicitPtr, entryBB);
-
- // Store the new cleanup position for irregular cleanups.
- if (endOfInit) Builder.CreateStore(curPtr, endOfInit);
-
- // Enter a partial-destruction cleanup if necessary.
- if (!cleanupDominator && needsEHCleanup(dtorKind)) {
- pushRegularPartialArrayCleanup(beginPtr, curPtr, elementType,
- getDestroyer(dtorKind));
- cleanup = EHStack.stable_begin();
- cleanupDominator = Builder.CreateUnreachable();
+ llvm::PHINode *CurPtrPhi =
+ Builder.CreatePHI(CurPtr->getType(), 2, "array.cur");
+ CurPtrPhi->addIncoming(CurPtr, EntryBB);
+ CurPtr = CurPtrPhi;
+
+ // Store the new Cleanup position for irregular Cleanups.
+ if (EndOfInit) Builder.CreateStore(CurPtr, EndOfInit);
+
+ // Enter a partial-destruction Cleanup if necessary.
+ if (!CleanupDominator && needsEHCleanup(DtorKind)) {
+ pushRegularPartialArrayCleanup(BeginPtr, CurPtr, ElementType,
+ getDestroyer(DtorKind));
+ Cleanup = EHStack.stable_begin();
+ CleanupDominator = Builder.CreateUnreachable();
}
// Emit the initializer into this element.
- StoreAnyExprIntoOneUnit(*this, Init, E->getAllocatedType(), curPtr);
+ StoreAnyExprIntoOneUnit(*this, Init, Init->getType(), CurPtr);
- // Leave the cleanup if we entered one.
- if (cleanupDominator) {
- DeactivateCleanupBlock(cleanup, cleanupDominator);
- cleanupDominator->eraseFromParent();
+ // Leave the Cleanup if we entered one.
+ if (CleanupDominator) {
+ DeactivateCleanupBlock(Cleanup, CleanupDominator);
+ CleanupDominator->eraseFromParent();
}
- // Advance to the next element.
- llvm::Value *nextPtr = Builder.CreateConstGEP1_32(curPtr, 1, "array.next");
+ // Advance to the next element by adjusting the pointer type as necessary.
+ llvm::Value *NextPtr =
+ Builder.CreateConstInBoundsGEP1_32(CurPtr, 1, "array.next");
// Check whether we've gotten to the end of the array and, if so,
// exit the loop.
- llvm::Value *isEnd = Builder.CreateICmpEQ(nextPtr, endPtr, "array.atend");
- Builder.CreateCondBr(isEnd, contBB, loopBB);
- curPtr->addIncoming(nextPtr, Builder.GetInsertBlock());
+ llvm::Value *IsEnd = Builder.CreateICmpEQ(NextPtr, EndPtr, "array.atend");
+ Builder.CreateCondBr(IsEnd, ContBB, LoopBB);
+ CurPtrPhi->addIncoming(NextPtr, Builder.GetInsertBlock());
- EmitBlock(contBB);
+ EmitBlock(ContBB);
}
-static void EmitZeroMemSet(CodeGenFunction &CGF, QualType T,
- llvm::Value *NewPtr, llvm::Value *Size) {
- CGF.EmitCastToVoidPtr(NewPtr);
- CharUnits Alignment = CGF.getContext().getTypeAlignInChars(T);
- CGF.Builder.CreateMemSet(NewPtr, CGF.Builder.getInt8(0), Size,
- Alignment.getQuantity(), false);
-}
-
static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
QualType ElementType,
llvm::Value *NewPtr,
llvm::Value *NumElements,
llvm::Value *AllocSizeWithoutCookie) {
- const Expr *Init = E->getInitializer();
- if (E->isArray()) {
- if (const CXXConstructExpr *CCE = dyn_cast_or_null<CXXConstructExpr>(Init)){
- CXXConstructorDecl *Ctor = CCE->getConstructor();
- if (Ctor->isTrivial()) {
- // If new expression did not specify value-initialization, then there
- // is no initialization.
- if (!CCE->requiresZeroInitialization() || Ctor->getParent()->isEmpty())
- return;
-
- if (CGF.CGM.getTypes().isZeroInitializable(ElementType)) {
- // Optimization: since zero initialization will just set the memory
- // to all zeroes, generate a single memset to do it in one shot.
- EmitZeroMemSet(CGF, ElementType, NewPtr, AllocSizeWithoutCookie);
- return;
- }
- }
-
- CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
- CCE->arg_begin(), CCE->arg_end(),
- CCE->requiresZeroInitialization());
- return;
- } else if (Init && isa<ImplicitValueInitExpr>(Init) &&
- CGF.CGM.getTypes().isZeroInitializable(ElementType)) {
- // Optimization: since zero initialization will just set the memory
- // to all zeroes, generate a single memset to do it in one shot.
- EmitZeroMemSet(CGF, ElementType, NewPtr, AllocSizeWithoutCookie);
- return;
- }
- CGF.EmitNewArrayInitializer(E, ElementType, NewPtr, NumElements);
- return;
- }
-
- if (!Init)
- return;
-
- StoreAnyExprIntoOneUnit(CGF, Init, E->getAllocatedType(), NewPtr);
+ if (E->isArray())
+ CGF.EmitNewArrayInitializer(E, ElementType, NewPtr, NumElements,
+ AllocSizeWithoutCookie);
+ else if (const Expr *Init = E->getInitializer())
+ StoreAnyExprIntoOneUnit(CGF, Init, E->getAllocatedType(), NewPtr);
}
/// Emit a call to an operator new or operator delete function, as implicitly
@@ -963,6 +1029,24 @@ static RValue EmitNewDeleteCall(CodeGenFunction &CGF,
return RV;
}
+RValue CodeGenFunction::EmitBuiltinNewDeleteCall(const FunctionProtoType *Type,
+ const Expr *Arg,
+ bool IsDelete) {
+ CallArgList Args;
+ const Stmt *ArgS = Arg;
+ EmitCallArgs(Args, *Type->param_type_begin(),
+ ConstExprIterator(&ArgS), ConstExprIterator(&ArgS + 1));
+ // Find the allocation or deallocation function that we're calling.
+ ASTContext &Ctx = getContext();
+ DeclarationName Name = Ctx.DeclarationNames
+ .getCXXOperatorName(IsDelete ? OO_Delete : OO_New);
+ for (auto *Decl : Ctx.getTranslationUnitDecl()->lookup(Name))
+ if (auto *FD = dyn_cast<FunctionDecl>(Decl))
+ if (Ctx.hasSameType(FD->getType(), QualType(Type, 0)))
+ return EmitNewDeleteCall(*this, cast<FunctionDecl>(Decl), Type, Args);
+ llvm_unreachable("predeclared global operator new/delete is missing");
+}
+
namespace {
/// A cleanup to call the given 'operator delete' function upon
/// abnormal exit from a new expression.
@@ -991,20 +1075,20 @@ namespace {
getPlacementArgs()[I] = Arg;
}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
const FunctionProtoType *FPT
= OperatorDelete->getType()->getAs<FunctionProtoType>();
- assert(FPT->getNumArgs() == NumPlacementArgs + 1 ||
- (FPT->getNumArgs() == 2 && NumPlacementArgs == 0));
+ assert(FPT->getNumParams() == NumPlacementArgs + 1 ||
+ (FPT->getNumParams() == 2 && NumPlacementArgs == 0));
CallArgList DeleteArgs;
// The first argument is always a void*.
- FunctionProtoType::arg_type_iterator AI = FPT->arg_type_begin();
+ FunctionProtoType::param_type_iterator AI = FPT->param_type_begin();
DeleteArgs.add(RValue::get(Ptr), *AI++);
// A member 'operator delete' can take an extra 'size_t' argument.
- if (FPT->getNumArgs() == NumPlacementArgs + 2)
+ if (FPT->getNumParams() == NumPlacementArgs + 2)
DeleteArgs.add(RValue::get(AllocSize), *AI++);
// Pass the rest of the arguments, which must match exactly.
@@ -1046,20 +1130,20 @@ namespace {
getPlacementArgs()[I] = Arg;
}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
const FunctionProtoType *FPT
= OperatorDelete->getType()->getAs<FunctionProtoType>();
- assert(FPT->getNumArgs() == NumPlacementArgs + 1 ||
- (FPT->getNumArgs() == 2 && NumPlacementArgs == 0));
+ assert(FPT->getNumParams() == NumPlacementArgs + 1 ||
+ (FPT->getNumParams() == 2 && NumPlacementArgs == 0));
CallArgList DeleteArgs;
// The first argument is always a void*.
- FunctionProtoType::arg_type_iterator AI = FPT->arg_type_begin();
+ FunctionProtoType::param_type_iterator AI = FPT->param_type_begin();
DeleteArgs.add(Ptr.restore(CGF), *AI++);
// A member 'operator delete' can take an extra 'size_t' argument.
- if (FPT->getNumArgs() == NumPlacementArgs + 2) {
+ if (FPT->getNumParams() == NumPlacementArgs + 2) {
RValue RV = AllocSize.restore(CGF);
DeleteArgs.add(RV, *AI++);
}
@@ -1137,43 +1221,20 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
minElements = ILE->getNumInits();
}
- llvm::Value *numElements = 0;
- llvm::Value *allocSizeWithoutCookie = 0;
+ llvm::Value *numElements = nullptr;
+ llvm::Value *allocSizeWithoutCookie = nullptr;
llvm::Value *allocSize =
EmitCXXNewAllocSize(*this, E, minElements, numElements,
allocSizeWithoutCookie);
allocatorArgs.add(RValue::get(allocSize), sizeType);
- // Emit the rest of the arguments.
- // FIXME: Ideally, this should just use EmitCallArgs.
- CXXNewExpr::const_arg_iterator placementArg = E->placement_arg_begin();
-
- // First, use the types from the function type.
// We start at 1 here because the first argument (the allocation size)
// has already been emitted.
- for (unsigned i = 1, e = allocatorType->getNumArgs(); i != e;
- ++i, ++placementArg) {
- QualType argType = allocatorType->getArgType(i);
-
- assert(getContext().hasSameUnqualifiedType(argType.getNonReferenceType(),
- placementArg->getType()) &&
- "type mismatch in call argument!");
-
- EmitCallArg(allocatorArgs, *placementArg, argType);
- }
-
- // Either we've emitted all the call args, or we have a call to a
- // variadic function.
- assert((placementArg == E->placement_arg_end() ||
- allocatorType->isVariadic()) &&
- "Extra arguments to non-variadic function!");
-
- // If we still have any arguments, emit them using the type of the argument.
- for (CXXNewExpr::const_arg_iterator placementArgsEnd = E->placement_arg_end();
- placementArg != placementArgsEnd; ++placementArg) {
- EmitCallArg(allocatorArgs, *placementArg, placementArg->getType());
- }
+ EmitCallArgs(allocatorArgs, allocatorType->isVariadic(),
+ allocatorType->param_type_begin() + 1,
+ allocatorType->param_type_end(), E->placement_arg_begin(),
+ E->placement_arg_end());
// Emit the allocation call. If the allocator is a global placement
// operator, just "inline" it directly.
@@ -1195,8 +1256,8 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
bool nullCheck = allocatorType->isNothrow(getContext()) &&
(!allocType.isPODType(getContext()) || E->hasInitializer());
- llvm::BasicBlock *nullCheckBB = 0;
- llvm::BasicBlock *contBB = 0;
+ llvm::BasicBlock *nullCheckBB = nullptr;
+ llvm::BasicBlock *contBB = nullptr;
llvm::Value *allocation = RV.getScalarVal();
unsigned AS = allocation->getType()->getPointerAddressSpace();
@@ -1220,7 +1281,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// If there's an operator delete, enter a cleanup to call it if an
// exception is thrown.
EHScopeStack::stable_iterator operatorDeleteCleanup;
- llvm::Instruction *cleanupDominator = 0;
+ llvm::Instruction *cleanupDominator = nullptr;
if (E->getOperatorDelete() &&
!E->getOperatorDelete()->isReservedGlobalPlacementOperator()) {
EnterNewDeleteCleanup(*this, E, allocation, allocSize, allocatorArgs);
@@ -1287,16 +1348,16 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
CallArgList DeleteArgs;
// Check if we need to pass the size to the delete operator.
- llvm::Value *Size = 0;
+ llvm::Value *Size = nullptr;
QualType SizeTy;
- if (DeleteFTy->getNumArgs() == 2) {
- SizeTy = DeleteFTy->getArgType(1);
+ if (DeleteFTy->getNumParams() == 2) {
+ SizeTy = DeleteFTy->getParamType(1);
CharUnits DeleteTypeSize = getContext().getTypeSizeInChars(DeleteTy);
Size = llvm::ConstantInt::get(ConvertType(SizeTy),
DeleteTypeSize.getQuantity());
}
-
- QualType ArgTy = DeleteFTy->getArgType(0);
+
+ QualType ArgTy = DeleteFTy->getParamType(0);
llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy));
DeleteArgs.add(RValue::get(DeletePtr), ArgTy);
@@ -1319,7 +1380,7 @@ namespace {
QualType ElementType)
: Ptr(Ptr), OperatorDelete(OperatorDelete), ElementType(ElementType) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
CGF.EmitDeleteCall(OperatorDelete, Ptr, ElementType);
}
};
@@ -1333,7 +1394,7 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
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;
+ const CXXDestructorDecl *Dtor = nullptr;
if (const RecordType *RT = ElementType->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
if (RD->hasDefinition() && !RD->hasTrivialDestructor()) {
@@ -1422,22 +1483,22 @@ namespace {
: Ptr(Ptr), OperatorDelete(OperatorDelete), NumElements(NumElements),
ElementType(ElementType), CookieSize(CookieSize) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
const FunctionProtoType *DeleteFTy =
OperatorDelete->getType()->getAs<FunctionProtoType>();
- assert(DeleteFTy->getNumArgs() == 1 || DeleteFTy->getNumArgs() == 2);
+ assert(DeleteFTy->getNumParams() == 1 || DeleteFTy->getNumParams() == 2);
CallArgList Args;
// Pass the pointer as the first argument.
- QualType VoidPtrTy = DeleteFTy->getArgType(0);
+ QualType VoidPtrTy = DeleteFTy->getParamType(0);
llvm::Value *DeletePtr
= CGF.Builder.CreateBitCast(Ptr, CGF.ConvertType(VoidPtrTy));
Args.add(RValue::get(DeletePtr), VoidPtrTy);
// Pass the original requested size as the second argument.
- if (DeleteFTy->getNumArgs() == 2) {
- QualType size_t = DeleteFTy->getArgType(1);
+ if (DeleteFTy->getNumParams() == 2) {
+ QualType size_t = DeleteFTy->getParamType(1);
llvm::IntegerType *SizeTy
= cast<llvm::IntegerType>(CGF.ConvertType(size_t));
@@ -1470,8 +1531,8 @@ static void EmitArrayDelete(CodeGenFunction &CGF,
const CXXDeleteExpr *E,
llvm::Value *deletedPtr,
QualType elementType) {
- llvm::Value *numElements = 0;
- llvm::Value *allocatedPtr = 0;
+ llvm::Value *numElements = nullptr;
+ llvm::Value *allocatedPtr = nullptr;
CharUnits cookieSize;
CGF.CGM.getCXXABI().ReadArrayCookie(CGF, deletedPtr, E, elementType,
numElements, allocatedPtr, cookieSize);
@@ -1554,21 +1615,39 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
EmitBlock(DeleteEnd);
}
-static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) {
- // void __cxa_bad_typeid();
- llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);
-
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid");
-}
+static bool isGLValueFromPointerDeref(const Expr *E) {
+ E = E->IgnoreParens();
+
+ if (const auto *CE = dyn_cast<CastExpr>(E)) {
+ if (!CE->getSubExpr()->isGLValue())
+ return false;
+ return isGLValueFromPointerDeref(CE->getSubExpr());
+ }
+
+ if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E))
+ return isGLValueFromPointerDeref(OVE->getSourceExpr());
+
+ if (const auto *BO = dyn_cast<BinaryOperator>(E))
+ if (BO->getOpcode() == BO_Comma)
+ return isGLValueFromPointerDeref(BO->getRHS());
+
+ if (const auto *ACO = dyn_cast<AbstractConditionalOperator>(E))
+ return isGLValueFromPointerDeref(ACO->getTrueExpr()) ||
+ isGLValueFromPointerDeref(ACO->getFalseExpr());
+
+ // C++11 [expr.sub]p1:
+ // The expression E1[E2] is identical (by definition) to *((E1)+(E2))
+ if (isa<ArraySubscriptExpr>(E))
+ return true;
-static void EmitBadTypeidCall(CodeGenFunction &CGF) {
- llvm::Value *Fn = getBadTypeidFn(CGF);
- CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
- CGF.Builder.CreateUnreachable();
+ if (const auto *UO = dyn_cast<UnaryOperator>(E))
+ if (UO->getOpcode() == UO_Deref)
+ return true;
+
+ return false;
}
-static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF,
- const Expr *E,
+static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, const Expr *E,
llvm::Type *StdTypeInfoPtrTy) {
// Get the vtable pointer.
llvm::Value *ThisPtr = CGF.EmitLValue(E).getAddress();
@@ -1577,28 +1656,27 @@ static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF,
// If the glvalue expression is obtained by applying the unary * operator to
// a pointer and the pointer is a null pointer value, the typeid expression
// throws the std::bad_typeid exception.
- if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParens())) {
- if (UO->getOpcode() == UO_Deref) {
- llvm::BasicBlock *BadTypeidBlock =
+ //
+ // However, this paragraph's intent is not clear. We choose a very generous
+ // interpretation which implores us to consider comma operators, conditional
+ // operators, parentheses and other such constructs.
+ QualType SrcRecordTy = E->getType();
+ if (CGF.CGM.getCXXABI().shouldTypeidBeNullChecked(
+ isGLValueFromPointerDeref(E), SrcRecordTy)) {
+ llvm::BasicBlock *BadTypeidBlock =
CGF.createBasicBlock("typeid.bad_typeid");
- llvm::BasicBlock *EndBlock =
- CGF.createBasicBlock("typeid.end");
+ llvm::BasicBlock *EndBlock = CGF.createBasicBlock("typeid.end");
- llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr);
- CGF.Builder.CreateCondBr(IsNull, BadTypeidBlock, EndBlock);
+ llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr);
+ CGF.Builder.CreateCondBr(IsNull, BadTypeidBlock, EndBlock);
- CGF.EmitBlock(BadTypeidBlock);
- EmitBadTypeidCall(CGF);
- CGF.EmitBlock(EndBlock);
- }
+ CGF.EmitBlock(BadTypeidBlock);
+ CGF.CGM.getCXXABI().EmitBadTypeidCall(CGF);
+ CGF.EmitBlock(EndBlock);
}
- llvm::Value *Value = CGF.GetVTablePtr(ThisPtr,
- StdTypeInfoPtrTy->getPointerTo());
-
- // Load the type info.
- Value = CGF.Builder.CreateConstInBoundsGEP1_64(Value, -1ULL);
- return CGF.Builder.CreateLoad(Value);
+ return CGF.CGM.getCXXABI().EmitTypeid(CGF, SrcRecordTy, ThisPtr,
+ StdTypeInfoPtrTy);
}
llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
@@ -1625,173 +1703,6 @@ llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
StdTypeInfoPtrTy);
}
-static llvm::Constant *getDynamicCastFn(CodeGenFunction &CGF) {
- // void *__dynamic_cast(const void *sub,
- // const abi::__class_type_info *src,
- // const abi::__class_type_info *dst,
- // std::ptrdiff_t src2dst_offset);
-
- llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
- llvm::Type *PtrDiffTy =
- CGF.ConvertType(CGF.getContext().getPointerDiffType());
-
- llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy };
-
- llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false);
-
- // Mark the function as nounwind readonly.
- llvm::Attribute::AttrKind FuncAttrs[] = { llvm::Attribute::NoUnwind,
- llvm::Attribute::ReadOnly };
- llvm::AttributeSet Attrs = llvm::AttributeSet::get(
- CGF.getLLVMContext(), llvm::AttributeSet::FunctionIndex, FuncAttrs);
-
- return CGF.CGM.CreateRuntimeFunction(FTy, "__dynamic_cast", Attrs);
-}
-
-static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) {
- // void __cxa_bad_cast();
- llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_cast");
-}
-
-static void EmitBadCastCall(CodeGenFunction &CGF) {
- llvm::Value *Fn = getBadCastFn(CGF);
- CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
- CGF.Builder.CreateUnreachable();
-}
-
-/// \brief Compute the src2dst_offset hint as described in the
-/// Itanium C++ ABI [2.9.7]
-static CharUnits computeOffsetHint(ASTContext &Context,
- const CXXRecordDecl *Src,
- const CXXRecordDecl *Dst) {
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
- /*DetectVirtual=*/false);
-
- // If Dst is not derived from Src we can skip the whole computation below and
- // return that Src is not a public base of Dst. Record all inheritance paths.
- if (!Dst->isDerivedFrom(Src, Paths))
- return CharUnits::fromQuantity(-2ULL);
-
- unsigned NumPublicPaths = 0;
- CharUnits Offset;
-
- // Now walk all possible inheritance paths.
- for (CXXBasePaths::paths_iterator I = Paths.begin(), E = Paths.end();
- I != E; ++I) {
- if (I->Access != AS_public) // Ignore non-public inheritance.
- continue;
-
- ++NumPublicPaths;
-
- for (CXXBasePath::iterator J = I->begin(), JE = I->end(); J != JE; ++J) {
- // If the path contains a virtual base class we can't give any hint.
- // -1: no hint.
- if (J->Base->isVirtual())
- return CharUnits::fromQuantity(-1ULL);
-
- if (NumPublicPaths > 1) // Won't use offsets, skip computation.
- continue;
-
- // Accumulate the base class offsets.
- const ASTRecordLayout &L = Context.getASTRecordLayout(J->Class);
- Offset += L.getBaseClassOffset(J->Base->getType()->getAsCXXRecordDecl());
- }
- }
-
- // -2: Src is not a public base of Dst.
- if (NumPublicPaths == 0)
- return CharUnits::fromQuantity(-2ULL);
-
- // -3: Src is a multiple public base type but never a virtual base type.
- if (NumPublicPaths > 1)
- return CharUnits::fromQuantity(-3ULL);
-
- // Otherwise, the Src type is a unique public nonvirtual base type of Dst.
- // Return the offset of Src from the origin of Dst.
- return Offset;
-}
-
-static llvm::Value *
-EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
- QualType SrcTy, QualType DestTy,
- llvm::BasicBlock *CastEnd) {
- llvm::Type *PtrDiffLTy =
- CGF.ConvertType(CGF.getContext().getPointerDiffType());
- llvm::Type *DestLTy = CGF.ConvertType(DestTy);
-
- if (const PointerType *PTy = DestTy->getAs<PointerType>()) {
- if (PTy->getPointeeType()->isVoidType()) {
- // C++ [expr.dynamic.cast]p7:
- // If T is "pointer to cv void," then the result is a pointer to the
- // most derived object pointed to by v.
-
- // Get the vtable pointer.
- llvm::Value *VTable = CGF.GetVTablePtr(Value, PtrDiffLTy->getPointerTo());
-
- // Get the offset-to-top from the vtable.
- llvm::Value *OffsetToTop =
- CGF.Builder.CreateConstInBoundsGEP1_64(VTable, -2ULL);
- OffsetToTop = CGF.Builder.CreateLoad(OffsetToTop, "offset.to.top");
-
- // Finally, add the offset to the pointer.
- Value = CGF.EmitCastToVoidPtr(Value);
- Value = CGF.Builder.CreateInBoundsGEP(Value, OffsetToTop);
-
- return CGF.Builder.CreateBitCast(Value, DestLTy);
- }
- }
-
- QualType SrcRecordTy;
- QualType DestRecordTy;
-
- if (const PointerType *DestPTy = DestTy->getAs<PointerType>()) {
- SrcRecordTy = SrcTy->castAs<PointerType>()->getPointeeType();
- DestRecordTy = DestPTy->getPointeeType();
- } else {
- SrcRecordTy = SrcTy;
- DestRecordTy = DestTy->castAs<ReferenceType>()->getPointeeType();
- }
-
- assert(SrcRecordTy->isRecordType() && "source type must be a record type!");
- assert(DestRecordTy->isRecordType() && "dest type must be a record type!");
-
- llvm::Value *SrcRTTI =
- CGF.CGM.GetAddrOfRTTIDescriptor(SrcRecordTy.getUnqualifiedType());
- llvm::Value *DestRTTI =
- CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());
-
- // Compute the offset hint.
- const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
- const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl();
- llvm::Value *OffsetHint =
- llvm::ConstantInt::get(PtrDiffLTy,
- computeOffsetHint(CGF.getContext(), SrcDecl,
- DestDecl).getQuantity());
-
- // Emit the call to __dynamic_cast.
- Value = CGF.EmitCastToVoidPtr(Value);
-
- llvm::Value *args[] = { Value, SrcRTTI, DestRTTI, OffsetHint };
- Value = CGF.EmitNounwindRuntimeCall(getDynamicCastFn(CGF), args);
- Value = CGF.Builder.CreateBitCast(Value, DestLTy);
-
- /// C++ [expr.dynamic.cast]p9:
- /// A failed cast to reference type throws std::bad_cast
- if (DestTy->isReferenceType()) {
- llvm::BasicBlock *BadCastBlock =
- CGF.createBasicBlock("dynamic_cast.bad_cast");
-
- llvm::Value *IsNull = CGF.Builder.CreateIsNull(Value);
- CGF.Builder.CreateCondBr(IsNull, BadCastBlock, CastEnd);
-
- CGF.EmitBlock(BadCastBlock);
- EmitBadCastCall(CGF);
- }
-
- return Value;
-}
-
static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF,
QualType DestTy) {
llvm::Type *DestLTy = CGF.ConvertType(DestTy);
@@ -1800,7 +1711,8 @@ static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF,
/// C++ [expr.dynamic.cast]p9:
/// A failed cast to reference type throws std::bad_cast
- EmitBadCastCall(CGF);
+ if (!CGF.CGM.getCXXABI().EmitBadCastCall(CGF))
+ return nullptr;
CGF.EmitBlock(CGF.createBasicBlock("dynamic_cast.end"));
return llvm::UndefValue::get(DestLTy);
@@ -1811,17 +1723,40 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *Value,
QualType DestTy = DCE->getTypeAsWritten();
if (DCE->isAlwaysNull())
- return EmitDynamicCastToNull(*this, DestTy);
+ if (llvm::Value *T = EmitDynamicCastToNull(*this, DestTy))
+ return T;
QualType SrcTy = DCE->getSubExpr()->getType();
+ // C++ [expr.dynamic.cast]p7:
+ // If T is "pointer to cv void," then the result is a pointer to the most
+ // derived object pointed to by v.
+ const PointerType *DestPTy = DestTy->getAs<PointerType>();
+
+ bool isDynamicCastToVoid;
+ QualType SrcRecordTy;
+ QualType DestRecordTy;
+ if (DestPTy) {
+ isDynamicCastToVoid = DestPTy->getPointeeType()->isVoidType();
+ SrcRecordTy = SrcTy->castAs<PointerType>()->getPointeeType();
+ DestRecordTy = DestPTy->getPointeeType();
+ } else {
+ isDynamicCastToVoid = false;
+ SrcRecordTy = SrcTy;
+ DestRecordTy = DestTy->castAs<ReferenceType>()->getPointeeType();
+ }
+
+ assert(SrcRecordTy->isRecordType() && "source type must be a record type!");
+
// C++ [expr.dynamic.cast]p4:
// If the value of v is a null pointer value in the pointer case, the result
// is the null pointer value of type T.
- bool ShouldNullCheckSrcValue = SrcTy->isPointerType();
-
- llvm::BasicBlock *CastNull = 0;
- llvm::BasicBlock *CastNotNull = 0;
+ bool ShouldNullCheckSrcValue =
+ CGM.getCXXABI().shouldDynamicCastCallBeNullChecked(SrcTy->isPointerType(),
+ SrcRecordTy);
+
+ llvm::BasicBlock *CastNull = nullptr;
+ llvm::BasicBlock *CastNotNull = nullptr;
llvm::BasicBlock *CastEnd = createBasicBlock("dynamic_cast.end");
if (ShouldNullCheckSrcValue) {
@@ -1833,7 +1768,15 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *Value,
EmitBlock(CastNotNull);
}
- Value = EmitDynamicCastCall(*this, Value, SrcTy, DestTy, CastEnd);
+ if (isDynamicCastToVoid) {
+ Value = CGM.getCXXABI().EmitDynamicCastToVoid(*this, Value, SrcRecordTy,
+ DestTy);
+ } else {
+ assert(DestRecordTy->isRecordType() &&
+ "destination type must be a record type!");
+ Value = CGM.getCXXABI().EmitDynamicCastCall(*this, Value, SrcRecordTy,
+ DestTy, DestRecordTy, CastEnd);
+ }
if (ShouldNullCheckSrcValue) {
EmitBranch(CastEnd);
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 73d5bcb13a95..7244b9e4d1eb 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -93,7 +93,7 @@ public:
ComplexPairTy Visit(Expr *E) {
return StmtVisitor<ComplexExprEmitter, ComplexPairTy>::Visit(E);
}
-
+
ComplexPairTy VisitStmt(Stmt *S) {
S->dump(CGF.getContext().getSourceManager());
llvm_unreachable("Stmt can't have complex result type!");
@@ -306,7 +306,7 @@ ComplexPairTy ComplexExprEmitter::EmitLoadOfLValue(LValue lvalue,
unsigned ComplexAlign = C.getTypeAlignInChars(ComplexTy).getQuantity();
unsigned AlignI = std::min(AlignR, ComplexAlign);
- llvm::Value *Real=0, *Imag=0;
+ llvm::Value *Real=nullptr, *Imag=nullptr;
if (!IgnoreReal || isVolatile) {
llvm::Value *RealP = Builder.CreateStructGEP(SrcPtr, 0,
@@ -410,7 +410,7 @@ ComplexPairTy ComplexExprEmitter::EmitScalarToComplexCast(llvm::Value *Val,
return ComplexPairTy(Val, llvm::Constant::getNullValue(Val->getType()));
}
-ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
+ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
QualType DestTy) {
switch (CK) {
case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!");
@@ -427,7 +427,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
case CK_LValueBitCast: {
LValue origLV = CGF.EmitLValue(Op);
llvm::Value *V = origLV.getAddress();
- V = Builder.CreateBitCast(V,
+ V = Builder.CreateBitCast(V,
CGF.ConvertType(CGF.getContext().getPointerType(DestTy)));
return EmitLoadOfLValue(CGF.MakeAddrLValue(V, DestTy,
origLV.getAlignment()),
@@ -475,6 +475,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
case CK_CopyAndAutoreleaseBlockObject:
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLEvent:
+ case CK_AddressSpaceConversion:
llvm_unreachable("invalid cast kind for complex value");
case CK_FloatingRealToComplex:
@@ -652,7 +653,7 @@ EmitCompoundAssignLValue(const CompoundAssignOperator *E,
assert(CGF.getContext().hasSameUnqualifiedType(OpInfo.Ty,
E->getRHS()->getType()));
OpInfo.RHS = Visit(E->getRHS());
-
+
LValue LHS = CGF.EmitLValue(E->getLHS());
// Load from the l-value and convert it.
@@ -702,7 +703,7 @@ EmitCompoundAssign(const CompoundAssignOperator *E,
LValue ComplexExprEmitter::EmitBinAssignLValue(const BinaryOperator *E,
ComplexPairTy &Val) {
- assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(),
+ assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(),
E->getRHS()->getType()) &&
"Invalid assignment");
TestAndClearIgnoreReal();
@@ -751,11 +752,13 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
// Bind the common expression if necessary.
CodeGenFunction::OpaqueValueMapping binding(CGF, E);
+ RegionCounter Cnt = CGF.getPGORegionCounter(E);
CodeGenFunction::ConditionalEvaluation eval(CGF);
- CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock);
+ CGF.EmitBranchOnBoolExpr(E->getCond(), LHSBlock, RHSBlock, Cnt.getCount());
eval.begin(CGF);
CGF.EmitBlock(LHSBlock);
+ Cnt.beginRegion(Builder);
ComplexPairTy LHS = Visit(E->getTrueExpr());
LHSBlock = Builder.GetInsertBlock();
CGF.EmitBranch(ContBlock);
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index f4d6861c8b8b..b508dcb446fb 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -530,7 +530,7 @@ llvm::Constant *ConstStructBuilder::BuildStruct(CodeGenModule &CGM,
ConstStructBuilder Builder(CGM, CGF);
if (!Builder.Build(ILE))
- return 0;
+ return nullptr;
return Builder.Finalize(ILE->getType());
}
@@ -572,7 +572,7 @@ public:
//===--------------------------------------------------------------------===//
llvm::Constant *VisitStmt(Stmt *S) {
- return 0;
+ return nullptr;
}
llvm::Constant *VisitParenExpr(ParenExpr *PE) {
@@ -599,7 +599,7 @@ public:
llvm::Constant *VisitCastExpr(CastExpr* E) {
Expr *subExpr = E->getSubExpr();
llvm::Constant *C = CGM.EmitConstantExpr(subExpr, subExpr->getType(), CGF);
- if (!C) return 0;
+ if (!C) return nullptr;
llvm::Type *destType = ConvertType(E->getType());
@@ -633,6 +633,9 @@ public:
return llvm::ConstantStruct::get(STy, Elts);
}
+ case CK_AddressSpaceConversion:
+ return llvm::ConstantExpr::getAddrSpaceCast(C, destType);
+
case CK_LValueToRValue:
case CK_AtomicToNonAtomic:
case CK_NonAtomicToAtomic:
@@ -657,7 +660,7 @@ public:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
case CK_CopyAndAutoreleaseBlockObject:
- return 0;
+ return nullptr;
// These don't need to be handled here because Evaluate knows how to
// evaluate them in the cases where they can be folded.
@@ -698,7 +701,7 @@ public:
case CK_FloatingToBoolean:
case CK_FloatingCast:
case CK_ZeroToOCLEvent:
- return 0;
+ return nullptr;
}
llvm_unreachable("Invalid CastKind");
}
@@ -740,7 +743,7 @@ public:
Expr *Init = ILE->getInit(i);
llvm::Constant *C = CGM.EmitConstantExpr(Init, Init->getType(), CGF);
if (!C)
- return 0;
+ return nullptr;
RewriteType |= (C->getType() != ElemTy);
Elts.push_back(C);
}
@@ -753,7 +756,7 @@ public:
else
fillC = llvm::Constant::getNullValue(ElemTy);
if (!fillC)
- return 0;
+ return nullptr;
RewriteType |= (fillC->getType() != ElemTy);
Elts.resize(NumElements, fillC);
@@ -786,12 +789,12 @@ public:
if (ILE->getType()->isRecordType())
return EmitRecordInitialization(ILE);
- return 0;
+ return nullptr;
}
llvm::Constant *VisitCXXConstructExpr(CXXConstructExpr *E) {
if (!E->getConstructor()->isTrivial())
- return 0;
+ return nullptr;
QualType Ty = E->getType();
@@ -803,8 +806,8 @@ public:
// If the class doesn't have a trivial destructor, we can't emit it as a
// constant expr.
if (!RD->hasTrivialDestructor())
- return 0;
-
+ return nullptr;
+
// Only copy and default constructors can be trivial.
@@ -833,7 +836,10 @@ public:
// as an inline array.
std::string Str;
CGM.getContext().getObjCEncodingForType(E->getEncodedType(), Str);
- const ConstantArrayType *CAT = cast<ConstantArrayType>(E->getType());
+ QualType T = E->getType();
+ if (T->getTypeClass() == Type::TypeOfExpr)
+ T = cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType();
+ const ConstantArrayType *CAT = cast<ConstantArrayType>(T);
// Resize the string to the right size, adding zeros at the end, or
// truncating as needed.
@@ -866,7 +872,7 @@ public:
return CGM.getStaticLocalDeclAddress(VD);
}
}
- return 0;
+ return nullptr;
}
Expr *E = const_cast<Expr*>(LVBase.get<const Expr*>());
@@ -883,7 +889,7 @@ public:
C = new llvm::GlobalVariable(CGM.getModule(), C->getType(),
E->getType().isConstant(CGM.getContext()),
llvm::GlobalValue::InternalLinkage,
- C, ".compoundliteral", 0,
+ C, ".compoundliteral", nullptr,
llvm::GlobalVariable::NotThreadLocal,
CGM.getContext().getTargetAddressSpace(E->getType()));
return C;
@@ -917,7 +923,7 @@ public:
}
case Expr::CallExprClass: {
CallExpr* CE = cast<CallExpr>(E);
- unsigned builtin = CE->isBuiltinCall();
+ unsigned builtin = CE->getBuiltinCallee();
if (builtin !=
Builtin::BI__builtin___CFStringMakeConstantString &&
builtin !=
@@ -964,7 +970,7 @@ public:
}
}
- return 0;
+ return nullptr;
}
};
@@ -998,7 +1004,7 @@ llvm::Constant *CodeGenModule::EmitConstantInit(const VarDecl &D,
// interprets that as the (pointer) value of the reference, rather than the
// desired value of the referee.
if (D.getType()->isReferenceType())
- return 0;
+ return nullptr;
const Expr *E = D.getInit();
assert(E && "No initializer to emit");
@@ -1023,7 +1029,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
else
Success = E->EvaluateAsRValue(Result, Context);
- llvm::Constant *C = 0;
+ llvm::Constant *C = nullptr;
if (Success && !Result.HasSideEffects)
C = EmitConstantValue(Result.Val, DestType, CGF);
else
@@ -1039,6 +1045,25 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
QualType DestType,
CodeGenFunction *CGF) {
+ // For an _Atomic-qualified constant, we may need to add tail padding.
+ if (auto *AT = DestType->getAs<AtomicType>()) {
+ QualType InnerType = AT->getValueType();
+ auto *Inner = EmitConstantValue(Value, InnerType, CGF);
+
+ uint64_t InnerSize = Context.getTypeSize(InnerType);
+ uint64_t OuterSize = Context.getTypeSize(DestType);
+ if (InnerSize == OuterSize)
+ return Inner;
+
+ assert(InnerSize < OuterSize && "emitted over-large constant for atomic");
+ llvm::Constant *Elts[] = {
+ Inner,
+ llvm::ConstantAggregateZero::get(
+ llvm::ArrayType::get(Int8Ty, (OuterSize - InnerSize) / 8))
+ };
+ return llvm::ConstantStruct::getAnon(Elts);
+ }
+
switch (Value.getKind()) {
case APValue::Uninitialized:
llvm_unreachable("Constant expressions should be initialized.");
@@ -1060,15 +1085,17 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
// Apply offset if necessary.
if (!Offset->isNullValue()) {
- llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(C, Int8PtrTy);
+ unsigned AS = C->getType()->getPointerAddressSpace();
+ llvm::Type *CharPtrTy = Int8Ty->getPointerTo(AS);
+ llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(C, CharPtrTy);
Casted = llvm::ConstantExpr::getGetElementPtr(Casted, Offset);
- C = llvm::ConstantExpr::getBitCast(Casted, C->getType());
+ C = llvm::ConstantExpr::getPointerCast(Casted, C->getType());
}
// Convert to the appropriate type; this could be an lvalue for
// an integer.
if (isa<llvm::PointerType>(DestTy))
- return llvm::ConstantExpr::getBitCast(C, DestTy);
+ return llvm::ConstantExpr::getPointerCast(C, DestTy);
return llvm::ConstantExpr::getPtrToInt(C, DestTy);
} else {
@@ -1166,13 +1193,13 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
Elts.reserve(NumElements);
// Emit array filler, if there is one.
- llvm::Constant *Filler = 0;
+ llvm::Constant *Filler = nullptr;
if (Value.hasArrayFiller())
Filler = EmitConstantValueForMemory(Value.getArrayFiller(),
CAT->getElementType(), CGF);
// Emit initializer elements.
- llvm::Type *CommonElementType = 0;
+ llvm::Type *CommonElementType = nullptr;
for (unsigned I = 0; I < NumElements; ++I) {
llvm::Constant *C = Filler;
if (I < NumInitElts)
@@ -1183,7 +1210,7 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
if (I == 0)
CommonElementType = C->getType();
else if (C->getType() != CommonElementType)
- CommonElementType = 0;
+ CommonElementType = nullptr;
Elts.push_back(C);
}
@@ -1222,7 +1249,7 @@ CodeGenModule::EmitConstantValueForMemory(const APValue &Value,
llvm::Constant *
CodeGenModule::GetAddrOfConstantCompoundLiteral(const CompoundLiteralExpr *E) {
assert(E->isFileScope() && "not a file-scope compound literal expr");
- return ConstExprEmitter(*this, 0).EmitLValue(E);
+ return ConstExprEmitter(*this, nullptr).EmitLValue(E);
}
llvm::Constant *
@@ -1265,15 +1292,14 @@ FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T,
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
// Go through all bases and fill in any null pointer to data members.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- if (I->isVirtual()) {
+ for (const auto &I : RD->bases()) {
+ if (I.isVirtual()) {
// Ignore virtual bases.
continue;
}
const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
// Ignore empty bases.
if (BaseDecl->isEmpty())
@@ -1285,7 +1311,7 @@ FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T,
uint64_t BaseOffset =
CGM.getContext().toBits(Layout.getBaseClassOffset(BaseDecl));
- FillInNullDataMemberPointers(CGM, I->getType(),
+ FillInNullDataMemberPointers(CGM, I.getType(),
Elements, StartOffset + BaseOffset);
}
@@ -1335,16 +1361,15 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
std::vector<llvm::Constant *> elements(numElements);
// Fill in all the bases.
- for (CXXRecordDecl::base_class_const_iterator
- I = record->bases_begin(), E = record->bases_end(); I != E; ++I) {
- if (I->isVirtual()) {
+ for (const auto &I : record->bases()) {
+ if (I.isVirtual()) {
// Ignore virtual bases; if we're laying out for a complete
// object, we'll lay these out later.
continue;
}
const CXXRecordDecl *base =
- cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
// Ignore empty bases.
if (base->isEmpty())
@@ -1356,28 +1381,24 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
}
// Fill in all the fields.
- for (RecordDecl::field_iterator I = record->field_begin(),
- E = record->field_end(); I != E; ++I) {
- const FieldDecl *field = *I;
-
+ for (const auto *Field : record->fields()) {
// Fill in non-bitfields. (Bitfields always use a zero pattern, which we
// will fill in later.)
- if (!field->isBitField()) {
- unsigned fieldIndex = layout.getLLVMFieldNo(field);
- elements[fieldIndex] = CGM.EmitNullConstant(field->getType());
+ if (!Field->isBitField()) {
+ unsigned fieldIndex = layout.getLLVMFieldNo(Field);
+ elements[fieldIndex] = CGM.EmitNullConstant(Field->getType());
}
// For unions, stop after the first named field.
- if (record->isUnion() && field->getDeclName())
+ if (record->isUnion() && Field->getDeclName())
break;
}
// Fill in the virtual bases, if we're working with the complete object.
if (asCompleteObject) {
- for (CXXRecordDecl::base_class_const_iterator
- I = record->vbases_begin(), E = record->vbases_end(); I != E; ++I) {
+ for (const auto &I : record->vbases()) {
const CXXRecordDecl *base =
- cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
// Ignore empty bases.
if (base->isEmpty())
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index f3a5387c58d3..9e0fbcfd1844 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -22,13 +22,13 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
+#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
-#include "llvm/Support/CFG.h"
#include <cstdarg>
using namespace clang;
@@ -246,7 +246,7 @@ public:
}
Value *VisitObjCMessageExpr(ObjCMessageExpr *E) {
if (E->getMethodDecl() &&
- E->getMethodDecl()->getResultType()->isReferenceType())
+ E->getMethodDecl()->getReturnType()->isReferenceType())
return EmitLoadOfLValue(E);
return CGF.EmitObjCMessageExpr(E).getScalarVal();
}
@@ -365,13 +365,10 @@ public:
}
Value *VisitCXXDeleteExpr(const CXXDeleteExpr *E) {
CGF.EmitCXXDeleteExpr(E);
- return 0;
- }
- Value *VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) {
- return Builder.getInt1(E->getValue());
+ return nullptr;
}
- Value *VisitBinaryTypeTraitExpr(const BinaryTypeTraitExpr *E) {
+ Value *VisitTypeTraitExpr(const TypeTraitExpr *E) {
return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
}
@@ -390,7 +387,7 @@ public:
// effect is the evaluation of the postfix-expression before the dot or
// arrow.
CGF.EmitScalarExpr(E->getBase());
- return 0;
+ return nullptr;
}
Value *VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) {
@@ -399,7 +396,7 @@ public:
Value *VisitCXXThrowExpr(const CXXThrowExpr *E) {
CGF.EmitCXXThrowExpr(E);
- return 0;
+ return nullptr;
}
Value *VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
@@ -557,12 +554,13 @@ void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc,
Value *Src, QualType SrcType,
QualType DstType,
llvm::Type *DstTy) {
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
using llvm::APFloat;
using llvm::APSInt;
llvm::Type *SrcTy = Src->getType();
- llvm::Value *Check = 0;
+ llvm::Value *Check = nullptr;
if (llvm::IntegerType *IntTy = dyn_cast<llvm::IntegerType>(SrcTy)) {
// Integer to floating-point. This can fail for unsigned short -> __half
// or unsigned __int128 -> float.
@@ -696,7 +694,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
DstType = CGF.getContext().getCanonicalType(DstType);
if (SrcType == DstType) return Src;
- if (DstType->isVoidType()) return 0;
+ if (DstType->isVoidType()) return nullptr;
llvm::Value *OrigSrc = Src;
QualType OrigSrcType = SrcType;
@@ -704,7 +702,10 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
// If casting to/from storage-only half FP, use special intrinsics.
if (SrcType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
- Src = Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16), Src);
+ Src = Builder.CreateCall(
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16,
+ CGF.CGM.FloatTy),
+ Src);
SrcType = CGF.getContext().FloatTy;
SrcTy = CGF.FloatTy;
}
@@ -761,7 +762,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
return Builder.CreateBitCast(Src, DstTy, "conv");
// Finally, we have the arithmetic types: real int/float.
- Value *Res = NULL;
+ Value *Res = nullptr;
llvm::Type *ResTy = DstTy;
// An overflowing conversion has undefined behavior if either the source type
@@ -800,7 +801,9 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
if (DstTy != ResTy) {
assert(ResTy->isIntegerTy(16) && "Only half FP requires extra conversion");
- Res = Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16), Res);
+ Res = Builder.CreateCall(
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16, CGF.CGM.FloatTy),
+ Res);
}
return Res;
@@ -838,6 +841,7 @@ Value *ScalarExprEmitter::EmitNullValue(QualType Ty) {
/// might actually be a unary increment which has been lowered to a binary
/// operation). The check passes if \p Check, which is an \c i1, is \c true.
void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info) {
+ assert(CGF.IsSanitizerScope);
StringRef CheckName;
SmallVector<llvm::Constant *, 4> StaticData;
SmallVector<llvm::Value *, 2> DynamicData;
@@ -890,7 +894,7 @@ void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info) {
Value *ScalarExprEmitter::VisitExpr(Expr *E) {
CGF.ErrorUnsupported(E, "scalar expression");
if (E->getType()->isVoidType())
- return 0;
+ return nullptr;
return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
}
@@ -943,9 +947,8 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
MTy->getNumElements());
Value* NewV = llvm::UndefValue::get(RTy);
for (unsigned i = 0, e = MTy->getNumElements(); i != e; ++i) {
- Value *IIndx = Builder.getInt32(i);
+ Value *IIndx = llvm::ConstantInt::get(CGF.SizeTy, i);
Value *Indx = Builder.CreateExtractElement(Mask, IIndx, "shuf_idx");
- Indx = Builder.CreateZExt(Indx, CGF.Int32Ty, "idx_zext");
Value *VExt = Builder.CreateExtractElement(LHS, Indx, "shuf_elt");
NewV = Builder.CreateInsertElement(NewV, VExt, IIndx, "shuf_ins");
@@ -1016,7 +1019,7 @@ Value *ScalarExprEmitter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
}
// We have the arithmetic types: real int/float.
- Value *Res = NULL;
+ Value *Res = nullptr;
if (isa<llvm::IntegerType>(SrcEltTy)) {
bool InputSigned = SrcEltType->isSignedIntegerOrEnumerationType();
@@ -1076,8 +1079,6 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
if (CGF.SanOpts->ArrayBounds)
CGF.EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, /*Accessed*/true);
- bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType();
- Idx = Builder.CreateIntCast(Idx, CGF.Int32Ty, IdxSigned, "vecidxcast");
return Builder.CreateExtractElement(Base, Idx, "vecext");
}
@@ -1136,7 +1137,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
if (EI->getVectorOperandType()->getNumElements() == ResElts) {
llvm::ConstantInt *C = cast<llvm::ConstantInt>(EI->getIndexOperand());
- Value *LHS = 0, *RHS = 0;
+ Value *LHS = nullptr, *RHS = nullptr;
if (CurIdx == 0) {
// insert into undef -> shuffle (src, undef)
Args.push_back(C);
@@ -1299,7 +1300,18 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_AnyPointerToBlockPointerCast:
case CK_BitCast: {
Value *Src = Visit(const_cast<Expr*>(E));
- return Builder.CreateBitCast(Src, ConvertType(DestTy));
+ llvm::Type *SrcTy = Src->getType();
+ llvm::Type *DstTy = ConvertType(DestTy);
+ if (SrcTy->isPtrOrPtrVectorTy() && DstTy->isPtrOrPtrVectorTy() &&
+ SrcTy->getPointerAddressSpace() != DstTy->getPointerAddressSpace()) {
+ llvm::Type *MidTy = CGF.CGM.getDataLayout().getIntPtrType(SrcTy);
+ return Builder.CreateIntToPtr(Builder.CreatePtrToInt(Src, MidTy), DstTy);
+ }
+ return Builder.CreateBitCast(Src, DstTy);
+ }
+ case CK_AddressSpaceConversion: {
+ Value *Src = Visit(const_cast<Expr*>(E));
+ return Builder.CreateAddrSpaceCast(Src, ConvertType(DestTy));
}
case CK_AtomicToNonAtomic:
case CK_NonAtomicToAtomic:
@@ -1320,7 +1332,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
// C++11 [expr.static.cast]p11: Behavior is undefined if a downcast is
// performed and the object is not of the derived type.
- if (CGF.SanitizePerformTypeCheck)
+ if (CGF.sanitizePerformTypeCheck())
CGF.EmitTypeCheck(CodeGenFunction::TCK_DowncastPointer, CE->getExprLoc(),
Derived, DestTy->getPointeeType());
@@ -1360,7 +1372,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
// Make sure the array decay ends up being the right type. This matters if
// the array type was of an incomplete type.
- return CGF.Builder.CreateBitCast(V, ConvertType(CE->getType()));
+ return CGF.Builder.CreatePointerCast(V, ConvertType(CE->getType()));
}
case CK_FunctionToPointerDecay:
return EmitLValue(E).getAddress();
@@ -1442,7 +1454,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_ToVoid: {
CGF.EmitIgnoredExpr(E);
- return 0;
+ return nullptr;
}
case CK_VectorSplat: {
llvm::Type *DstTy = ConvertType(DestTy);
@@ -1452,7 +1464,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
// Splat the element across to all elements
unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
- return Builder.CreateVectorSplat(NumElements, Elt, "splat");;
+ return Builder.CreateVectorSplat(NumElements, Elt, "splat");
}
case CK_IntegralCast:
@@ -1485,7 +1497,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
}
case CK_ZeroToOCLEvent: {
- assert(DestTy->isEventT() && "CK_ZeroToOCLEvent cast on non event type");
+ assert(DestTy->isEventT() && "CK_ZeroToOCLEvent cast on non-event type");
return llvm::Constant::getNullValue(ConvertType(DestTy));
}
@@ -1499,7 +1511,7 @@ Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) {
llvm::Value *RetAlloca = CGF.EmitCompoundStmt(*E->getSubStmt(),
!E->getType()->isVoidType());
if (!RetAlloca)
- return 0;
+ return nullptr;
return CGF.EmitLoadOfScalar(CGF.MakeAddrLValue(RetAlloca, E->getType()),
E->getExprLoc());
}
@@ -1537,7 +1549,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre) {
QualType type = E->getSubExpr()->getType();
- llvm::PHINode *atomicPHI = 0;
+ llvm::PHINode *atomicPHI = nullptr;
llvm::Value *value;
llvm::Value *input;
@@ -1610,12 +1622,11 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
// Note that signed integer inc/dec with width less than int can't
// overflow because of promotion rules; we're just eliding a few steps here.
- if (value->getType()->getPrimitiveSizeInBits() >=
- CGF.IntTy->getBitWidth() &&
- type->isSignedIntegerOrEnumerationType()) {
+ bool CanOverflow = value->getType()->getIntegerBitWidth() >=
+ CGF.IntTy->getIntegerBitWidth();
+ if (CanOverflow && type->isSignedIntegerOrEnumerationType()) {
value = EmitAddConsiderOverflowBehavior(E, value, amt, isInc);
- } else if (value->getType()->getPrimitiveSizeInBits() >=
- CGF.IntTy->getBitWidth() && type->isUnsignedIntegerType() &&
+ } else if (CanOverflow && type->isUnsignedIntegerType() &&
CGF.SanOpts->UnsignedIntegerOverflow) {
BinOpInfo BinOp;
BinOp.LHS = value;
@@ -1682,9 +1693,10 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
// Another special case: half FP increment should be done via float
- value =
- Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16),
- input);
+ value = Builder.CreateCall(
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16,
+ CGF.CGM.FloatTy),
+ input);
}
if (value->getType()->isFloatTy())
@@ -1703,9 +1715,10 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec");
if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType)
- value =
- Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16),
- value);
+ value = Builder.CreateCall(
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16,
+ CGF.CGM.FloatTy),
+ value);
// Objective-C pointer types.
} else {
@@ -1727,10 +1740,12 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
if (atomicPHI) {
llvm::BasicBlock *opBB = Builder.GetInsertBlock();
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
- llvm::Value *old = Builder.CreateAtomicCmpXchg(LV.getAddress(), atomicPHI,
- CGF.EmitToMemory(value, type), llvm::SequentiallyConsistent);
+ llvm::Value *pair = Builder.CreateAtomicCmpXchg(
+ LV.getAddress(), atomicPHI, CGF.EmitToMemory(value, type),
+ llvm::SequentiallyConsistent, llvm::SequentiallyConsistent);
+ llvm::Value *old = Builder.CreateExtractValue(pair, 0);
+ llvm::Value *success = Builder.CreateExtractValue(pair, 1);
atomicPHI->addIncoming(old, opBB);
- llvm::Value *success = Builder.CreateICmpEQ(old, atomicPHI);
Builder.CreateCondBr(success, contBB, opBB);
Builder.SetInsertPoint(contBB);
return isPre ? value : input;
@@ -1810,7 +1825,7 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) {
QualType CurrentType = E->getTypeSourceInfo()->getType();
for (unsigned i = 0; i != n; ++i) {
OffsetOfExpr::OffsetOfNode ON = E->getComponent(i);
- llvm::Value *Offset = 0;
+ llvm::Value *Offset = nullptr;
switch (ON.getKind()) {
case OffsetOfExpr::OffsetOfNode::Array: {
// Compute the index
@@ -1906,7 +1921,7 @@ ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
QualType eltType;
llvm::Value *numElts;
- llvm::tie(numElts, eltType) = CGF.getVLASize(VAT);
+ std::tie(numElts, eltType) = CGF.getVLASize(VAT);
llvm::Value *size = numElts;
@@ -2000,7 +2015,7 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
// Load/convert the LHS.
LValue LHSLV = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
- llvm::PHINode *atomicPHI = 0;
+ llvm::PHINode *atomicPHI = nullptr;
if (const AtomicType *atomicTy = LHSTy->getAs<AtomicType>()) {
QualType type = atomicTy->getValueType();
if (!type->isBooleanType() && type->isIntegerType() &&
@@ -2069,10 +2084,12 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
if (atomicPHI) {
llvm::BasicBlock *opBB = Builder.GetInsertBlock();
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
- llvm::Value *old = Builder.CreateAtomicCmpXchg(LHSLV.getAddress(), atomicPHI,
- CGF.EmitToMemory(Result, LHSTy), llvm::SequentiallyConsistent);
+ llvm::Value *pair = Builder.CreateAtomicCmpXchg(
+ LHSLV.getAddress(), atomicPHI, CGF.EmitToMemory(Result, LHSTy),
+ llvm::SequentiallyConsistent, llvm::SequentiallyConsistent);
+ llvm::Value *old = Builder.CreateExtractValue(pair, 0);
+ llvm::Value *success = Builder.CreateExtractValue(pair, 1);
atomicPHI->addIncoming(old, opBB);
- llvm::Value *success = Builder.CreateICmpEQ(old, atomicPHI);
Builder.CreateCondBr(success, contBB, opBB);
Builder.SetInsertPoint(contBB);
return LHSLV;
@@ -2098,7 +2115,7 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
// If the result is clearly ignored, return now.
if (Ignore)
- return 0;
+ return nullptr;
// The result of an assignment in C is the assigned r-value.
if (!CGF.getLangOpts().CPlusPlus)
@@ -2114,7 +2131,7 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
const BinOpInfo &Ops, llvm::Value *Zero, bool isDiv) {
- llvm::Value *Cond = 0;
+ llvm::Value *Cond = nullptr;
if (CGF.SanOpts->IntegerDivideByZero)
Cond = Builder.CreateICmpNE(Ops.RHS, Zero);
@@ -2138,15 +2155,18 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
}
Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
- if ((CGF.SanOpts->IntegerDivideByZero ||
- CGF.SanOpts->SignedIntegerOverflow) &&
- Ops.Ty->isIntegerType()) {
- llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
- EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true);
- } else if (CGF.SanOpts->FloatDivideByZero &&
- Ops.Ty->isRealFloatingType()) {
- llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
- EmitBinOpCheck(Builder.CreateFCmpUNE(Ops.RHS, Zero), Ops);
+ {
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
+ if ((CGF.SanOpts->IntegerDivideByZero ||
+ CGF.SanOpts->SignedIntegerOverflow) &&
+ Ops.Ty->isIntegerType()) {
+ llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
+ EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true);
+ } else if (CGF.SanOpts->FloatDivideByZero &&
+ Ops.Ty->isRealFloatingType()) {
+ llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
+ EmitBinOpCheck(Builder.CreateFCmpUNE(Ops.RHS, Zero), Ops);
+ }
}
if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
@@ -2170,6 +2190,7 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) {
// Rem in C can't be a floating point type: C99 6.5.5p2.
if (CGF.SanOpts->IntegerDivideByZero) {
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
if (Ops.Ty->isIntegerType())
@@ -2227,9 +2248,10 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
if (handlerName->empty()) {
// If the signed-integer-overflow sanitizer is enabled, emit a call to its
// runtime. Otherwise, this is a -ftrapv check, so just emit a trap.
- if (!isSigned || CGF.SanOpts->SignedIntegerOverflow)
+ if (!isSigned || CGF.SanOpts->SignedIntegerOverflow) {
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
EmitBinOpCheck(Builder.CreateNot(overflow), Ops);
- else
+ } else
CGF.EmitTrapCheck(Builder.CreateNot(overflow));
return result;
}
@@ -2238,7 +2260,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
llvm::BasicBlock *initialBB = Builder.GetInsertBlock();
llvm::Function::iterator insertPt = initialBB;
llvm::BasicBlock *continueBB = CGF.createBasicBlock("nooverflow", CGF.CurFn,
- llvm::next(insertPt));
+ std::next(insertPt));
llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow", CGF.CurFn);
Builder.CreateCondBr(overflow, overflowBB, continueBB);
@@ -2418,12 +2440,12 @@ static Value* tryEmitFMulAdd(const BinOpInfo &op,
// Check whether this op is marked as fusable.
if (!op.FPContractable)
- return 0;
+ return nullptr;
// Check whether -ffp-contract=on. (If -ffp-contract=off/fast, fusing is
// either disabled, or handled entirely by the LLVM backend).
if (CGF.CGM.getCodeGenOpts().getFPContractMode() != CodeGenOptions::FPC_On)
- return 0;
+ return nullptr;
// We have a potentially fusable op. Look for a mul on one of the operands.
if (llvm::BinaryOperator* LHSBinOp = dyn_cast<llvm::BinaryOperator>(op.LHS)) {
@@ -2441,7 +2463,7 @@ static Value* tryEmitFMulAdd(const BinOpInfo &op,
}
}
- return 0;
+ return nullptr;
}
Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
@@ -2523,13 +2545,13 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
const BinaryOperator *expr = cast<BinaryOperator>(op.E);
QualType elementType = expr->getLHS()->getType()->getPointeeType();
- llvm::Value *divisor = 0;
+ llvm::Value *divisor = nullptr;
// 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);
+ std::tie(numElements, elementType) = CGF.getVLASize(vla);
divisor = numElements;
@@ -2581,6 +2603,7 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
if (CGF.SanOpts->Shift && !CGF.getLangOpts().OpenCL &&
isa<llvm::IntegerType>(Ops.LHS->getType())) {
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
llvm::Value *WidthMinusOne = GetWidthMinusOneValue(Ops.LHS, RHS);
llvm::Value *Valid = Builder.CreateICmpULE(RHS, WidthMinusOne);
@@ -2632,8 +2655,10 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
if (CGF.SanOpts->Shift && !CGF.getLangOpts().OpenCL &&
- isa<llvm::IntegerType>(Ops.LHS->getType()))
+ isa<llvm::IntegerType>(Ops.LHS->getType())) {
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
EmitBinOpCheck(Builder.CreateICmpULE(RHS, GetWidthMinusOneValue(Ops.LHS, RHS)), Ops);
+ }
// OpenCL 6.3j: shift values are effectively % word size of LHS.
if (CGF.getLangOpts().OpenCL)
@@ -2818,11 +2843,11 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
switch (E->getLHS()->getType().getObjCLifetime()) {
case Qualifiers::OCL_Strong:
- llvm::tie(LHS, RHS) = CGF.EmitARCStoreStrong(E, Ignore);
+ std::tie(LHS, RHS) = CGF.EmitARCStoreStrong(E, Ignore);
break;
case Qualifiers::OCL_Autoreleasing:
- llvm::tie(LHS,RHS) = CGF.EmitARCStoreAutoreleasing(E);
+ std::tie(LHS, RHS) = CGF.EmitARCStoreAutoreleasing(E);
break;
case Qualifiers::OCL_Weak:
@@ -2851,7 +2876,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
// If the result is clearly ignored, return now.
if (Ignore)
- return 0;
+ return nullptr;
// The result of an assignment in C is the assigned r-value.
if (!CGF.getLangOpts().CPlusPlus)
@@ -2866,8 +2891,12 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
}
Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
+ RegionCounter Cnt = CGF.getPGORegionCounter(E);
+
// Perform vector logical and on comparisons with zero vectors.
if (E->getType()->isVectorType()) {
+ Cnt.beginRegion(Builder);
+
Value *LHS = Visit(E->getLHS());
Value *RHS = Visit(E->getRHS());
Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
@@ -2889,6 +2918,8 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
bool LHSCondVal;
if (CGF.ConstantFoldsToSimpleInteger(E->getLHS(), LHSCondVal)) {
if (LHSCondVal) { // If we have 1 && X, just emit X.
+ Cnt.beginRegion(Builder);
+
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
// ZExt result to int or bool.
return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "land.ext");
@@ -2905,7 +2936,7 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
CodeGenFunction::ConditionalEvaluation eval(CGF);
// Branch on the LHS first. If it is false, go to the failure (cont) block.
- CGF.EmitBranchOnBoolExpr(E->getLHS(), RHSBlock, ContBlock);
+ CGF.EmitBranchOnBoolExpr(E->getLHS(), RHSBlock, ContBlock, Cnt.getCount());
// Any edges into the ContBlock are now from an (indeterminate number of)
// edges from this first condition. All of these values will be false. Start
@@ -2918,18 +2949,20 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
eval.begin(CGF);
CGF.EmitBlock(RHSBlock);
+ Cnt.beginRegion(Builder);
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
eval.end(CGF);
// Reaquire the RHS block, as there may be subblocks inserted.
RHSBlock = Builder.GetInsertBlock();
- // Emit an unconditional branch from this block to ContBlock. Insert an entry
- // into the phi node for the edge with the value of RHSCond.
- if (CGF.getDebugInfo())
+ // Emit an unconditional branch from this block to ContBlock.
+ {
// There is no need to emit line number for unconditional branch.
- Builder.SetCurrentDebugLocation(llvm::DebugLoc());
- CGF.EmitBlock(ContBlock);
+ SuppressDebugLocation S(Builder);
+ CGF.EmitBlock(ContBlock);
+ }
+ // Insert an entry into the phi node for the edge with the value of RHSCond.
PN->addIncoming(RHSCond, RHSBlock);
// ZExt result to int.
@@ -2937,8 +2970,12 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
}
Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
+ RegionCounter Cnt = CGF.getPGORegionCounter(E);
+
// Perform vector logical or on comparisons with zero vectors.
if (E->getType()->isVectorType()) {
+ Cnt.beginRegion(Builder);
+
Value *LHS = Visit(E->getLHS());
Value *RHS = Visit(E->getRHS());
Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
@@ -2960,6 +2997,8 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
bool LHSCondVal;
if (CGF.ConstantFoldsToSimpleInteger(E->getLHS(), LHSCondVal)) {
if (!LHSCondVal) { // If we have 0 || X, just emit X.
+ Cnt.beginRegion(Builder);
+
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
// ZExt result to int or bool.
return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "lor.ext");
@@ -2976,7 +3015,8 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
CodeGenFunction::ConditionalEvaluation eval(CGF);
// Branch on the LHS first. If it is true, go to the success (cont) block.
- CGF.EmitBranchOnBoolExpr(E->getLHS(), ContBlock, RHSBlock);
+ CGF.EmitBranchOnBoolExpr(E->getLHS(), ContBlock, RHSBlock,
+ Cnt.getParentCount() - Cnt.getCount());
// Any edges into the ContBlock are now from an (indeterminate number of)
// edges from this first condition. All of these values will be true. Start
@@ -2991,6 +3031,7 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
// Emit the RHS condition as a bool value.
CGF.EmitBlock(RHSBlock);
+ Cnt.beginRegion(Builder);
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
eval.end(CGF);
@@ -3041,6 +3082,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
// Bind the common expression if necessary.
CodeGenFunction::OpaqueValueMapping binding(CGF, E);
+ RegionCounter Cnt = CGF.getPGORegionCounter(E);
Expr *condExpr = E->getCond();
Expr *lhsExpr = E->getTrueExpr();
@@ -3055,6 +3097,8 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
// If the dead side doesn't have labels we need, just emit the Live part.
if (!CGF.ContainsLabel(dead)) {
+ if (CondExprBool)
+ Cnt.beginRegion(Builder);
Value *Result = Visit(live);
// If the live part is a throw expression, it acts like it has a void
@@ -3071,6 +3115,8 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
// the select function.
if (CGF.getLangOpts().OpenCL
&& condExpr->getType()->isVectorType()) {
+ Cnt.beginRegion(Builder);
+
llvm::Value *CondV = CGF.EmitScalarExpr(condExpr);
llvm::Value *LHS = Visit(lhsExpr);
llvm::Value *RHS = Visit(rhsExpr);
@@ -3114,13 +3160,15 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
// safe to evaluate the LHS and RHS unconditionally.
if (isCheapEnoughToEvaluateUnconditionally(lhsExpr, CGF) &&
isCheapEnoughToEvaluateUnconditionally(rhsExpr, CGF)) {
+ Cnt.beginRegion(Builder);
+
llvm::Value *CondV = CGF.EvaluateExprAsBool(condExpr);
llvm::Value *LHS = Visit(lhsExpr);
llvm::Value *RHS = Visit(rhsExpr);
if (!LHS) {
// If the conditional has void type, make sure we return a null Value*.
assert(!RHS && "LHS and RHS types must match");
- return 0;
+ return nullptr;
}
return Builder.CreateSelect(CondV, LHS, RHS, "cond");
}
@@ -3130,9 +3178,10 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end");
CodeGenFunction::ConditionalEvaluation eval(CGF);
- CGF.EmitBranchOnBoolExpr(condExpr, LHSBlock, RHSBlock);
+ CGF.EmitBranchOnBoolExpr(condExpr, LHSBlock, RHSBlock, Cnt.getCount());
CGF.EmitBlock(LHSBlock);
+ Cnt.beginRegion(Builder);
eval.begin(CGF);
Value *LHS = Visit(lhsExpr);
eval.end(CGF);
@@ -3166,6 +3215,10 @@ Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) {
}
Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
+ QualType Ty = VE->getType();
+ if (Ty->isVariablyModifiedType())
+ CGF.EmitVariablyModifiedType(Ty);
+
llvm::Value *ArgValue = CGF.EmitVAListRef(VE->getSubExpr());
llvm::Value *ArgPtr = CGF.EmitVAArg(ArgValue, VE->getType());
@@ -3312,7 +3365,7 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
LValue CodeGenFunction::EmitCompoundAssignmentLValue(
const CompoundAssignOperator *E) {
ScalarExprEmitter Scalar(*this);
- Value *Result = 0;
+ Value *Result = nullptr;
switch (E->getOpcode()) {
#define COMPOUND_OP(Op) \
case BO_##Op##Assign: \
diff --git a/lib/CodeGen/CGLoopInfo.cpp b/lib/CodeGen/CGLoopInfo.cpp
new file mode 100644
index 000000000000..a273f1d4dda8
--- /dev/null
+++ b/lib/CodeGen/CGLoopInfo.cpp
@@ -0,0 +1,112 @@
+//===---- CGLoopInfo.cpp - LLVM CodeGen for loop metadata -*- C++ -*-------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGLoopInfo.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/InstrTypes.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Metadata.h"
+using namespace clang;
+using namespace CodeGen;
+using namespace llvm;
+
+static MDNode *createMetadata(LLVMContext &Ctx, const LoopAttributes &Attrs) {
+
+ if (!Attrs.IsParallel && Attrs.VectorizerWidth == 0 &&
+ Attrs.VectorizerUnroll == 0 &&
+ Attrs.VectorizerEnable == LoopAttributes::VecUnspecified)
+ return nullptr;
+
+ SmallVector<Value *, 4> Args;
+ // Reserve operand 0 for loop id self reference.
+ MDNode *TempNode = MDNode::getTemporary(Ctx, None);
+ Args.push_back(TempNode);
+
+ // Setting vectorizer.width
+ if (Attrs.VectorizerWidth > 0) {
+ Value *Vals[] = { MDString::get(Ctx, "llvm.loop.vectorize.width"),
+ ConstantInt::get(Type::getInt32Ty(Ctx),
+ Attrs.VectorizerWidth) };
+ Args.push_back(MDNode::get(Ctx, Vals));
+ }
+
+ // Setting vectorizer.unroll
+ if (Attrs.VectorizerUnroll > 0) {
+ Value *Vals[] = { MDString::get(Ctx, "llvm.loop.interleave.count"),
+ ConstantInt::get(Type::getInt32Ty(Ctx),
+ Attrs.VectorizerUnroll) };
+ Args.push_back(MDNode::get(Ctx, Vals));
+ }
+
+ // Setting vectorizer.enable
+ if (Attrs.VectorizerEnable != LoopAttributes::VecUnspecified) {
+ Value *Vals[] = { MDString::get(Ctx, "llvm.loop.vectorize.enable"),
+ ConstantInt::get(Type::getInt1Ty(Ctx),
+ (Attrs.VectorizerEnable ==
+ LoopAttributes::VecEnable)) };
+ Args.push_back(MDNode::get(Ctx, Vals));
+ }
+
+ MDNode *LoopID = MDNode::get(Ctx, Args);
+ assert(LoopID->use_empty() && "LoopID should not be used");
+
+ // Set the first operand to itself.
+ LoopID->replaceOperandWith(0, LoopID);
+ MDNode::deleteTemporary(TempNode);
+ return LoopID;
+}
+
+LoopAttributes::LoopAttributes(bool IsParallel)
+ : IsParallel(IsParallel), VectorizerEnable(LoopAttributes::VecUnspecified),
+ VectorizerWidth(0), VectorizerUnroll(0) {}
+
+void LoopAttributes::clear() {
+ IsParallel = false;
+ VectorizerWidth = 0;
+ VectorizerUnroll = 0;
+ VectorizerEnable = LoopAttributes::VecUnspecified;
+}
+
+LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs)
+ : LoopID(nullptr), Header(Header), Attrs(Attrs) {
+ LoopID = createMetadata(Header->getContext(), Attrs);
+}
+
+void LoopInfoStack::push(BasicBlock *Header) {
+ Active.push_back(LoopInfo(Header, StagedAttrs));
+ // Clear the attributes so nested loops do not inherit them.
+ StagedAttrs.clear();
+}
+
+void LoopInfoStack::pop() {
+ assert(!Active.empty() && "No active loops to pop");
+ Active.pop_back();
+}
+
+void LoopInfoStack::InsertHelper(Instruction *I) const {
+ if (!hasInfo())
+ return;
+
+ const LoopInfo &L = getInfo();
+ if (!L.getLoopID())
+ return;
+
+ if (TerminatorInst *TI = dyn_cast<TerminatorInst>(I)) {
+ for (unsigned i = 0, ie = TI->getNumSuccessors(); i < ie; ++i)
+ if (TI->getSuccessor(i) == L.getHeader()) {
+ TI->setMetadata("llvm.loop", L.getLoopID());
+ break;
+ }
+ return;
+ }
+
+ if (L.getAttributes().IsParallel && I->mayReadOrWriteMemory())
+ I->setMetadata("llvm.mem.parallel_loop_access", L.getLoopID());
+}
diff --git a/lib/CodeGen/CGLoopInfo.h b/lib/CodeGen/CGLoopInfo.h
new file mode 100644
index 000000000000..2f6f172e047a
--- /dev/null
+++ b/lib/CodeGen/CGLoopInfo.h
@@ -0,0 +1,136 @@
+//===---- CGLoopInfo.h - LLVM CodeGen for loop metadata -*- C++ -*---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the internal state used for llvm translation for loop statement
+// metadata.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CGLOOPINFO_H
+#define CLANG_CODEGEN_CGLOOPINFO_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Support/Compiler.h"
+
+namespace llvm {
+class BasicBlock;
+class Instruction;
+class MDNode;
+} // end namespace llvm
+
+namespace clang {
+namespace CodeGen {
+
+/// \brief Attributes that may be specified on loops.
+struct LoopAttributes {
+ explicit LoopAttributes(bool IsParallel = false);
+ void clear();
+
+ /// \brief Generate llvm.loop.parallel metadata for loads and stores.
+ bool IsParallel;
+
+ /// \brief Values of llvm.loop.vectorize.enable metadata.
+ enum LVEnableState { VecUnspecified, VecEnable, VecDisable };
+
+ /// \brief llvm.loop.vectorize.enable
+ LVEnableState VectorizerEnable;
+
+ /// \brief llvm.loop.vectorize.width
+ unsigned VectorizerWidth;
+
+ /// \brief llvm.loop.interleave.count
+ unsigned VectorizerUnroll;
+};
+
+/// \brief Information used when generating a structured loop.
+class LoopInfo {
+public:
+ /// \brief Construct a new LoopInfo for the loop with entry Header.
+ LoopInfo(llvm::BasicBlock *Header, const LoopAttributes &Attrs);
+
+ /// \brief Get the loop id metadata for this loop.
+ llvm::MDNode *getLoopID() const { return LoopID; }
+
+ /// \brief Get the header block of this loop.
+ llvm::BasicBlock *getHeader() const { return Header; }
+
+ /// \brief Get the set of attributes active for this loop.
+ const LoopAttributes &getAttributes() const { return Attrs; }
+
+private:
+ /// \brief Loop ID metadata.
+ llvm::MDNode *LoopID;
+ /// \brief Header block of this loop.
+ llvm::BasicBlock *Header;
+ /// \brief The attributes for this loop.
+ LoopAttributes Attrs;
+};
+
+/// \brief A stack of loop information corresponding to loop nesting levels.
+/// This stack can be used to prepare attributes which are applied when a loop
+/// is emitted.
+class LoopInfoStack {
+ LoopInfoStack(const LoopInfoStack &) LLVM_DELETED_FUNCTION;
+ void operator=(const LoopInfoStack &) LLVM_DELETED_FUNCTION;
+
+public:
+ LoopInfoStack() {}
+
+ /// \brief Begin a new structured loop. The set of staged attributes will be
+ /// applied to the loop and then cleared.
+ void push(llvm::BasicBlock *Header);
+
+ /// \brief End the current loop.
+ void pop();
+
+ /// \brief Return the top loop id metadata.
+ llvm::MDNode *getCurLoopID() const { return getInfo().getLoopID(); }
+
+ /// \brief Return true if the top loop is parallel.
+ bool getCurLoopParallel() const {
+ return hasInfo() ? getInfo().getAttributes().IsParallel : false;
+ }
+
+ /// \brief Function called by the CodeGenFunction when an instruction is
+ /// created.
+ void InsertHelper(llvm::Instruction *I) const;
+
+ /// \brief Set the next pushed loop as parallel.
+ void setParallel(bool Enable = true) { StagedAttrs.IsParallel = Enable; }
+
+ /// \brief Set the next pushed loop 'vectorizer.enable'
+ void setVectorizerEnable(bool Enable = true) {
+ StagedAttrs.VectorizerEnable =
+ Enable ? LoopAttributes::VecEnable : LoopAttributes::VecDisable;
+ }
+
+ /// \brief Set the vectorizer width for the next loop pushed.
+ void setVectorizerWidth(unsigned W) { StagedAttrs.VectorizerWidth = W; }
+
+ /// \brief Set the vectorizer unroll for the next loop pushed.
+ void setVectorizerUnroll(unsigned U) { StagedAttrs.VectorizerUnroll = U; }
+
+private:
+ /// \brief Returns true if there is LoopInfo on the stack.
+ bool hasInfo() const { return !Active.empty(); }
+ /// \brief Return the LoopInfo for the current loop. HasInfo should be called
+ /// first to ensure LoopInfo is present.
+ const LoopInfo &getInfo() const { return Active.back(); }
+ /// \brief The set of attributes that will be applied to the next pushed loop.
+ LoopAttributes StagedAttrs;
+ /// \brief Stack of active loops.
+ llvm::SmallVector<LoopInfo, 4> Active;
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif // CLANG_CODEGEN_CGLOOPINFO_H
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 0bda053f35f7..8ca80808e007 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -22,7 +22,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/Support/CallSite.h"
+#include "llvm/IR/CallSite.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InlineAsm.h"
using namespace clang;
@@ -79,10 +79,10 @@ CodeGenFunction::EmitObjCBoxedExpr(const ObjCBoxedExpr *E) {
RValue RV = EmitAnyExpr(SubExpr);
CallArgList Args;
Args.add(RV, ArgQT);
-
- RValue result = Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
- BoxingMethod->getResultType(), Sel, Receiver, Args,
- ClassDecl, BoxingMethod);
+
+ RValue result = Runtime.GenerateMessageSend(
+ *this, ReturnValueSlot(), BoxingMethod->getReturnType(), Sel, Receiver,
+ Args, ClassDecl, BoxingMethod);
return Builder.CreateBitCast(result.getScalarVal(),
ConvertType(E->getType()));
}
@@ -90,7 +90,7 @@ CodeGenFunction::EmitObjCBoxedExpr(const ObjCBoxedExpr *E) {
llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
const ObjCMethodDecl *MethodWithObjects) {
ASTContext &Context = CGM.getContext();
- const ObjCDictionaryLiteral *DLE = 0;
+ const ObjCDictionaryLiteral *DLE = nullptr;
const ObjCArrayLiteral *ALE = dyn_cast<ObjCArrayLiteral>(E);
if (!ALE)
DLE = cast<ObjCDictionaryLiteral>(E);
@@ -106,8 +106,8 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
ArrayType::Normal, /*IndexTypeQuals=*/0);
// Allocate the temporary array(s).
- llvm::Value *Objects = CreateMemTemp(ElementArrayType, "objects");
- llvm::Value *Keys = 0;
+ llvm::Value *Objects = CreateMemTemp(ElementArrayType, "objects");
+ llvm::Value *Keys = nullptr;
if (DLE)
Keys = CreateMemTemp(ElementArrayType, "keys");
@@ -186,12 +186,9 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
llvm::Value *Receiver = Runtime.GetClass(*this, Class);
// Generate the message send.
- RValue result
- = Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
- MethodWithObjects->getResultType(),
- Sel,
- Receiver, Args, Class,
- MethodWithObjects);
+ RValue result = Runtime.GenerateMessageSend(
+ *this, ReturnValueSlot(), MethodWithObjects->getReturnType(), Sel,
+ Receiver, Args, Class, MethodWithObjects);
// The above message send needs these objects, but in ARC they are
// passed in a buffer that is essentially __unsafe_unretained.
@@ -238,7 +235,7 @@ static RValue AdjustRelatedResultType(CodeGenFunction &CGF,
return Result;
if (!Method->hasRelatedResultType() ||
- CGF.getContext().hasSameType(ExpT, Method->getResultType()) ||
+ CGF.getContext().hasSameType(ExpT, Method->getReturnType()) ||
!Result.isScalar())
return Result;
@@ -317,10 +314,10 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
bool isSuperMessage = false;
bool isClassMessage = false;
- ObjCInterfaceDecl *OID = 0;
+ ObjCInterfaceDecl *OID = nullptr;
// Find the receiver
QualType ReceiverType;
- llvm::Value *Receiver = 0;
+ llvm::Value *Receiver = nullptr;
switch (E->getReceiverKind()) {
case ObjCMessageExpr::Instance:
ReceiverType = E->getInstanceReceiver()->getType();
@@ -369,8 +366,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
shouldExtendReceiverForInnerPointerMessage(E))
Receiver = EmitARCRetainAutorelease(ReceiverType, Receiver);
- QualType ResultType =
- method ? method->getResultType() : E->getType();
+ QualType ResultType = method ? method->getReturnType() : E->getType();
CallArgList Args;
EmitCallArgs(Args, method, E->arg_begin(), E->arg_end());
@@ -435,7 +431,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
namespace {
struct FinishARCDealloc : EHScopeStack::Cleanup {
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
const ObjCMethodDecl *method = cast<ObjCMethodDecl>(CGF.CurCodeDecl);
const ObjCImplDecl *impl = cast<ObjCImplDecl>(method->getDeclContext());
@@ -470,7 +466,7 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
FunctionArgList args;
// Check if we should generate debug info for this method.
if (OMD->hasAttr<NoDebugAttr>())
- DebugInfo = NULL; // disable debug info indefinitely for this function
+ DebugInfo = nullptr; // disable debug info indefinitely for this function
llvm::Function *Fn = CGM.getObjCRuntime().GenerateMethod(OMD, CD);
@@ -480,13 +476,13 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
args.push_back(OMD->getSelfDecl());
args.push_back(OMD->getCmdDecl());
- for (ObjCMethodDecl::param_const_iterator PI = OMD->param_begin(),
- E = OMD->param_end(); PI != E; ++PI)
- args.push_back(*PI);
+ for (const auto *PI : OMD->params())
+ args.push_back(PI);
CurGD = OMD;
- StartFunction(OMD, OMD->getResultType(), Fn, FI, args, StartLoc);
+ StartFunction(OMD, OMD->getReturnType(), Fn, FI, args,
+ OMD->getLocation(), StartLoc);
// In ARC, certain methods get an extra cleanup.
if (CGM.getLangOpts().ObjCAutoRefCount &&
@@ -506,8 +502,14 @@ static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF,
/// its pointer, name, and types registered in the class struture.
void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) {
StartObjCMethod(OMD, OMD->getClassInterface(), OMD->getLocStart());
- EmitStmt(OMD->getBody());
+ PGO.assignRegionCounters(OMD, CurFn);
+ assert(isa<CompoundStmt>(OMD->getBody()));
+ RegionCounter Cnt = getPGORegionCounter(OMD->getBody());
+ Cnt.beginRegion(Builder);
+ EmitCompoundStmtWithoutScope(*cast<CompoundStmt>(OMD->getBody()));
FinishFunction(OMD->getBodyRBrace());
+ PGO.emitInstrumentationData();
+ PGO.destroyRegionCounters();
}
/// emitStructGetterCall - Call the runtime function to load a property
@@ -622,8 +624,8 @@ PropertyImplStrategy::PropertyImplStrategy(CodeGenModule &CGM,
// Evaluate the ivar's size and alignment.
ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
QualType ivarType = ivar->getType();
- llvm::tie(IvarSize, IvarAlignment)
- = CGM.getContext().getTypeInfoInChars(ivarType);
+ std::tie(IvarSize, IvarAlignment) =
+ CGM.getContext().getTypeInfoInChars(ivarType);
// If we have a copy property, we always have to use getProperty/setProperty.
// TODO: we could actually use setProperty and an expression for non-atomics.
@@ -818,7 +820,7 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
if (!hasTrivialGetExpr(propImpl)) {
if (!AtomicHelperFn) {
ReturnStmt ret(SourceLocation(), propImpl->getGetterCXXConstructor(),
- /*nrvo*/ 0);
+ /*nrvo*/ nullptr);
EmitReturnStmt(ret);
}
else {
@@ -895,16 +897,21 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
// FIXME: We shouldn't need to get the function info here, the
// runtime already should have computed it to build the function.
+ llvm::Instruction *CallInstruction;
RValue RV = EmitCall(getTypes().arrangeFreeFunctionCall(propType, args,
FunctionType::ExtInfo(),
RequiredArgs::All),
- getPropertyFn, ReturnValueSlot(), args);
+ getPropertyFn, ReturnValueSlot(), args, nullptr,
+ &CallInstruction);
+ if (llvm::CallInst *call = dyn_cast<llvm::CallInst>(CallInstruction))
+ call->setTailCall();
// We need to fix the type here. Ivars with copy & retain are
// always objects so we don't need to worry about complex or
// aggregates.
- RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(),
- getTypes().ConvertType(getterMethod->getResultType())));
+ RV = RValue::get(Builder.CreateBitCast(
+ RV.getScalarVal(),
+ getTypes().ConvertType(getterMethod->getReturnType())));
EmitReturnOfRValue(RV, propType);
@@ -955,8 +962,8 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
}
value = Builder.CreateBitCast(value, ConvertType(propType));
- value = Builder.CreateBitCast(value,
- ConvertType(GetterMethodDecl->getResultType()));
+ value = Builder.CreateBitCast(
+ value, ConvertType(GetterMethodDecl->getReturnType()));
}
EmitReturnOfRValue(RValue::get(value), propType);
@@ -1139,9 +1146,9 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
case PropertyImplStrategy::GetSetProperty:
case PropertyImplStrategy::SetPropertyAndExpressionGet: {
-
- llvm::Value *setOptimizedPropertyFn = 0;
- llvm::Value *setPropertyFn = 0;
+
+ llvm::Value *setOptimizedPropertyFn = nullptr;
+ llvm::Value *setPropertyFn = nullptr;
if (UseOptimizedSetter(CGM)) {
// 10.8 and iOS 6.0 code and GC is off
setOptimizedPropertyFn =
@@ -1292,7 +1299,7 @@ namespace {
: addr(addr), ivar(ivar), destroyer(destroyer),
useEHCleanupForArray(useEHCleanupForArray) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
LValue lvalue
= CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), addr, ivar, /*CVR*/ 0);
CGF.emitDestroy(lvalue.getAddress(), ivar->getType(), destroyer,
@@ -1324,7 +1331,7 @@ static void emitCXXDestructMethod(CodeGenFunction &CGF,
QualType::DestructionKind dtorKind = type.isDestructedType();
if (!dtorKind) continue;
- CodeGenFunction::Destroyer *destroyer = 0;
+ CodeGenFunction::Destroyer *destroyer = nullptr;
// Use a call to objc_storeStrong to destroy strong ivars, for the
// general benefit of the tools.
@@ -1356,12 +1363,9 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
// Suppress the final autorelease in ARC.
AutoreleaseResult = false;
- SmallVector<CXXCtorInitializer *, 8> IvarInitializers;
- for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(),
- E = IMP->init_end(); B != E; ++B) {
- CXXCtorInitializer *IvarInit = (*B);
+ for (const auto *IvarInit : IMP->inits()) {
FieldDecl *Field = IvarInit->getAnyMember();
- ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field);
+ ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field);
LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
LoadObjCSelf(), Ivar, 0);
EmitAggExpr(IvarInit->getInit(),
@@ -1506,9 +1510,13 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
llvm::Value *zero = llvm::Constant::getNullValue(UnsignedLongLTy);
// If the limit pointer was zero to begin with, the collection is
- // empty; skip all this.
+ // empty; skip all this. Set the branch weight assuming this has the same
+ // probability of exiting the loop as any other loop exit.
+ uint64_t EntryCount = PGO.getCurrentRegionCount();
+ RegionCounter Cnt = getPGORegionCounter(&S);
Builder.CreateCondBr(Builder.CreateICmpEQ(initialBufferLimit, zero, "iszero"),
- EmptyBB, LoopInitBB);
+ EmptyBB, LoopInitBB,
+ PGO.createBranchWeights(EntryCount, Cnt.getCount()));
// Otherwise, initialize the loop.
EmitBlock(LoopInitBB);
@@ -1537,6 +1545,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
llvm::PHINode *count = Builder.CreatePHI(UnsignedLongLTy, 3, "forcoll.count");
count->addIncoming(initialBufferLimit, LoopInitBB);
+ Cnt.beginRegion(Builder);
+
// Check whether the mutations value has changed from where it was
// at start. StateMutationsPtr should actually be invariant between
// refreshes.
@@ -1644,8 +1654,12 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
= Builder.CreateAdd(index, llvm::ConstantInt::get(UnsignedLongLTy, 1));
// If we haven't overrun the buffer yet, we can continue.
+ // Set the branch weights based on the simplifying assumption that this is
+ // like a while-loop, i.e., ignoring that the false branch fetches more
+ // elements and then returns to the loop.
Builder.CreateCondBr(Builder.CreateICmpULT(indexPlusOne, count),
- LoopBodyBB, FetchMoreBB);
+ LoopBodyBB, FetchMoreBB,
+ PGO.createBranchWeights(Cnt.getCount(), EntryCount));
index->addIncoming(indexPlusOne, AfterBody.getBlock());
count->addIncoming(count, AfterBody.getBlock());
@@ -1715,7 +1729,7 @@ namespace {
CallObjCRelease(llvm::Value *object) : object(object) {}
llvm::Value *object;
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
// Releases at the end of the full-expression are imprecise.
CGF.EmitARCRelease(object, ARCImpreciseLifetime);
}
@@ -1857,7 +1871,7 @@ static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF,
};
llvm::CallInst *result = CGF.EmitNounwindRuntimeCall(fn, args);
- if (ignored) return 0;
+ if (ignored) return nullptr;
return CGF.Builder.CreateBitCast(result, origType);
}
@@ -2055,7 +2069,7 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(llvm::Value *addr,
};
EmitNounwindRuntimeCall(fn, args);
- if (ignored) return 0;
+ if (ignored) return nullptr;
return value;
}
@@ -2324,7 +2338,7 @@ namespace {
CallObjCAutoreleasePoolObject(llvm::Value *token) : Token(token) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
CGF.EmitObjCAutoreleasePoolPop(Token);
}
};
@@ -2333,7 +2347,7 @@ namespace {
CallObjCMRRAutoreleasePoolObject(llvm::Value *token) : Token(token) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
CGF.EmitObjCMRRAutoreleasePoolPop(Token);
}
};
@@ -2550,7 +2564,7 @@ tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
// The desired result type, if it differs from the type of the
// ultimate opaque expression.
- llvm::Type *resultType = 0;
+ llvm::Type *resultType = nullptr;
while (true) {
e = e->IgnoreParens();
@@ -2824,9 +2838,8 @@ void CodeGenFunction::EmitObjCAutoreleasePoolStmt(
EHStack.pushCleanup<CallObjCMRRAutoreleasePoolObject>(NormalCleanup, token);
}
- for (CompoundStmt::const_body_iterator I = S.body_begin(),
- E = S.body_end(); I != E; ++I)
- EmitStmt(*I);
+ for (const auto *I : S.body())
+ EmitStmt(I);
if (DI)
DI->EmitLexicalBlockEnd(Builder, S.getRBracLoc());
@@ -2857,16 +2870,16 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
const ObjCPropertyImplDecl *PID) {
if (!getLangOpts().CPlusPlus ||
!getLangOpts().ObjCRuntime.hasAtomicCopyHelper())
- return 0;
+ return nullptr;
QualType Ty = PID->getPropertyIvarDecl()->getType();
if (!Ty->isRecordType())
- return 0;
+ return nullptr;
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
if ((!(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_atomic)))
- return 0;
- llvm::Constant * HelperFn = 0;
+ return nullptr;
+ llvm::Constant *HelperFn = nullptr;
if (hasTrivialSetExpr(PID))
- return 0;
+ return nullptr;
assert(PID->getSetterCXXAssignment() && "SetterCXXAssignment - null");
if ((HelperFn = CGM.getAtomicSetterHelperFnMap(Ty)))
return HelperFn;
@@ -2877,27 +2890,25 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
FunctionDecl *FD = FunctionDecl::Create(C,
C.getTranslationUnitDecl(),
SourceLocation(),
- SourceLocation(), II, C.VoidTy, 0,
- SC_Static,
+ SourceLocation(), II, C.VoidTy,
+ nullptr, SC_Static,
false,
false);
-
+
QualType DestTy = C.getPointerType(Ty);
QualType SrcTy = Ty;
SrcTy.addConst();
SrcTy = C.getPointerType(SrcTy);
FunctionArgList args;
- ImplicitParamDecl dstDecl(FD, SourceLocation(), 0, DestTy);
+ ImplicitParamDecl dstDecl(getContext(), FD, SourceLocation(), nullptr,DestTy);
args.push_back(&dstDecl);
- ImplicitParamDecl srcDecl(FD, SourceLocation(), 0, SrcTy);
+ ImplicitParamDecl srcDecl(getContext(), FD, SourceLocation(), nullptr, SrcTy);
args.push_back(&srcDecl);
-
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeFunctionDeclaration(C.VoidTy, args,
- FunctionType::ExtInfo(),
- RequiredArgs::All);
-
+
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ C.VoidTy, args, FunctionType::ExtInfo(), RequiredArgs::All);
+
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn =
@@ -2905,7 +2916,7 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
"__assign_helper_atomic_property_",
&CGM.getModule());
- StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
+ StartFunction(FD, C.VoidTy, Fn, FI, args);
DeclRefExpr DstExpr(&dstDecl, false, DestTy,
VK_RValue, SourceLocation());
@@ -2936,17 +2947,17 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
const ObjCPropertyImplDecl *PID) {
if (!getLangOpts().CPlusPlus ||
!getLangOpts().ObjCRuntime.hasAtomicCopyHelper())
- return 0;
+ return nullptr;
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
QualType Ty = PD->getType();
if (!Ty->isRecordType())
- return 0;
+ return nullptr;
if ((!(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_atomic)))
- return 0;
- llvm::Constant * HelperFn = 0;
-
+ return nullptr;
+ llvm::Constant *HelperFn = nullptr;
+
if (hasTrivialGetExpr(PID))
- return 0;
+ return nullptr;
assert(PID->getGetterCXXConstructor() && "getGetterCXXConstructor - null");
if ((HelperFn = CGM.getAtomicGetterHelperFnMap(Ty)))
return HelperFn;
@@ -2958,34 +2969,32 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
FunctionDecl *FD = FunctionDecl::Create(C,
C.getTranslationUnitDecl(),
SourceLocation(),
- SourceLocation(), II, C.VoidTy, 0,
- SC_Static,
+ SourceLocation(), II, C.VoidTy,
+ nullptr, SC_Static,
false,
false);
-
+
QualType DestTy = C.getPointerType(Ty);
QualType SrcTy = Ty;
SrcTy.addConst();
SrcTy = C.getPointerType(SrcTy);
FunctionArgList args;
- ImplicitParamDecl dstDecl(FD, SourceLocation(), 0, DestTy);
+ ImplicitParamDecl dstDecl(getContext(), FD, SourceLocation(), nullptr,DestTy);
args.push_back(&dstDecl);
- ImplicitParamDecl srcDecl(FD, SourceLocation(), 0, SrcTy);
+ ImplicitParamDecl srcDecl(getContext(), FD, SourceLocation(), nullptr, SrcTy);
args.push_back(&srcDecl);
-
- const CGFunctionInfo &FI =
- CGM.getTypes().arrangeFunctionDeclaration(C.VoidTy, args,
- FunctionType::ExtInfo(),
- RequiredArgs::All);
-
+
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ C.VoidTy, args, FunctionType::ExtInfo(), RequiredArgs::All);
+
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
"__copy_helper_atomic_property_", &CGM.getModule());
- StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
+ StartFunction(FD, C.VoidTy, Fn, FI, args);
DeclRefExpr SrcExpr(&srcDecl, false, SrcTy,
VK_RValue, SourceLocation());
@@ -3012,6 +3021,7 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
ConstructorArgs,
CXXConstExpr->hadMultipleCandidates(),
CXXConstExpr->isListInitialization(),
+ CXXConstExpr->isStdInitListInitialization(),
CXXConstExpr->requiresZeroInitialization(),
CXXConstExpr->getConstructionKind(),
SourceRange());
@@ -3050,11 +3060,11 @@ CodeGenFunction::EmitBlockCopyAndAutorelease(llvm::Value *Block, QualType Ty) {
RValue Result;
Result = Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
Ty, CopySelector,
- Val, CallArgList(), 0, 0);
+ Val, CallArgList(), nullptr, nullptr);
Val = Result.getScalarVal();
Result = Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
Ty, AutoreleaseSelector,
- Val, CallArgList(), 0, 0);
+ Val, CallArgList(), nullptr, nullptr);
Val = Result.getScalarVal();
return Val;
}
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index a7ab8507014f..619a66ab4a69 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -27,11 +27,11 @@
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/IR/CallSite.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
-#include "llvm/Support/CallSite.h"
#include "llvm/Support/Compiler.h"
#include <cstdarg>
@@ -53,7 +53,8 @@ class LazyRuntimeFunction {
/// Constructor leaves this class uninitialized, because it is intended to
/// be used as a field in another class and not all of the types that are
/// used as arguments will necessarily be available at construction time.
- LazyRuntimeFunction() : CGM(0), FunctionName(0), Function(0) {}
+ LazyRuntimeFunction()
+ : CGM(nullptr), FunctionName(nullptr), Function(nullptr) {}
/// Initialises the lazy function with the name, return type, and the types
/// of the arguments.
@@ -62,7 +63,7 @@ class LazyRuntimeFunction {
llvm::Type *RetTy, ...) {
CGM =Mod;
FunctionName = name;
- Function = 0;
+ Function = nullptr;
ArgTys.clear();
va_list Args;
va_start(Args, RetTy);
@@ -76,7 +77,7 @@ class LazyRuntimeFunction {
/// LLVM constant.
operator llvm::Constant*() {
if (!Function) {
- if (0 == FunctionName) return 0;
+ if (!FunctionName) return nullptr;
// We put the return type on the end of the vector, so pop it back off
llvm::Type *RetTy = ArgTys.back();
ArgTys.pop_back();
@@ -236,9 +237,8 @@ protected:
NameAndAttributes += TypeStr;
NameAndAttributes += '\0';
NameAndAttributes += PD->getNameAsString();
- NameAndAttributes += '\0';
return llvm::ConstantExpr::getGetElementPtr(
- CGM.GetAddrOfConstantString(NameAndAttributes), Zeros);
+ CGM.GetAddrOfConstantCString(NameAndAttributes), Zeros);
}
return MakeConstantString(PD->getNameAsString());
}
@@ -479,103 +479,92 @@ public:
CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
unsigned protocolClassVersion);
- virtual llvm::Constant *GenerateConstantString(const StringLiteral *);
+ llvm::Constant *GenerateConstantString(const StringLiteral *) override;
- virtual RValue
- GenerateMessageSend(CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel,
- llvm::Value *Receiver,
- const CallArgList &CallArgs,
+ RValue
+ GenerateMessageSend(CodeGenFunction &CGF, ReturnValueSlot Return,
+ QualType ResultType, Selector Sel,
+ llvm::Value *Receiver, const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class,
- const ObjCMethodDecl *Method);
- virtual RValue
- GenerateMessageSendSuper(CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel,
+ const ObjCMethodDecl *Method) override;
+ RValue
+ GenerateMessageSendSuper(CodeGenFunction &CGF, ReturnValueSlot Return,
+ QualType ResultType, Selector Sel,
const ObjCInterfaceDecl *Class,
- bool isCategoryImpl,
- llvm::Value *Receiver,
- bool IsClassMessage,
- const CallArgList &CallArgs,
- const ObjCMethodDecl *Method);
- virtual llvm::Value *GetClass(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *OID);
- virtual llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
- bool lval = false);
- virtual llvm::Value *GetSelector(CodeGenFunction &CGF, const ObjCMethodDecl
- *Method);
- virtual llvm::Constant *GetEHType(QualType T);
-
- virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
- const ObjCContainerDecl *CD);
- virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
- virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
- virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD);
- virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
- const ObjCProtocolDecl *PD);
- virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
- virtual llvm::Function *ModuleInitFunction();
- virtual llvm::Constant *GetPropertyGetFunction();
- virtual llvm::Constant *GetPropertySetFunction();
- virtual llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
- bool copy);
- virtual llvm::Constant *GetSetStructFunction();
- virtual llvm::Constant *GetGetStructFunction();
- virtual llvm::Constant *GetCppAtomicObjectGetFunction();
- virtual llvm::Constant *GetCppAtomicObjectSetFunction();
- virtual llvm::Constant *EnumerationMutationFunction();
-
- virtual void EmitTryStmt(CodeGenFunction &CGF,
- const ObjCAtTryStmt &S);
- virtual void EmitSynchronizedStmt(CodeGenFunction &CGF,
- const ObjCAtSynchronizedStmt &S);
- virtual void EmitThrowStmt(CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S,
- bool ClearInsertionPoint=true);
- virtual llvm::Value * EmitObjCWeakRead(CodeGenFunction &CGF,
- llvm::Value *AddrWeakObj);
- virtual void EmitObjCWeakAssign(CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst);
- virtual void EmitObjCGlobalAssign(CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dest,
- bool threadlocal=false);
- virtual void EmitObjCIvarAssign(CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dest,
- llvm::Value *ivarOffset);
- virtual void EmitObjCStrongCastAssign(CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dest);
- virtual void EmitGCMemmoveCollectable(CodeGenFunction &CGF,
- llvm::Value *DestPtr,
- llvm::Value *SrcPtr,
- llvm::Value *Size);
- virtual LValue EmitObjCValueForIvar(CodeGenFunction &CGF,
- QualType ObjectTy,
- llvm::Value *BaseValue,
- const ObjCIvarDecl *Ivar,
- unsigned CVRQualifiers);
- virtual llvm::Value *EmitIvarOffset(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *Interface,
- const ObjCIvarDecl *Ivar);
- virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF);
- virtual llvm::Constant *BuildGCBlockLayout(CodeGenModule &CGM,
- const CGBlockInfo &blockInfo) {
+ bool isCategoryImpl, llvm::Value *Receiver,
+ bool IsClassMessage, const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method) override;
+ llvm::Value *GetClass(CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *OID) override;
+ llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
+ bool lval = false) override;
+ llvm::Value *GetSelector(CodeGenFunction &CGF,
+ const ObjCMethodDecl *Method) override;
+ llvm::Constant *GetEHType(QualType T) override;
+
+ llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD) override;
+ void GenerateCategory(const ObjCCategoryImplDecl *CMD) override;
+ void GenerateClass(const ObjCImplementationDecl *ClassDecl) override;
+ void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) override;
+ llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
+ const ObjCProtocolDecl *PD) override;
+ void GenerateProtocol(const ObjCProtocolDecl *PD) override;
+ llvm::Function *ModuleInitFunction() override;
+ llvm::Constant *GetPropertyGetFunction() override;
+ llvm::Constant *GetPropertySetFunction() override;
+ llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
+ bool copy) override;
+ llvm::Constant *GetSetStructFunction() override;
+ llvm::Constant *GetGetStructFunction() override;
+ llvm::Constant *GetCppAtomicObjectGetFunction() override;
+ llvm::Constant *GetCppAtomicObjectSetFunction() override;
+ llvm::Constant *EnumerationMutationFunction() override;
+
+ void EmitTryStmt(CodeGenFunction &CGF,
+ const ObjCAtTryStmt &S) override;
+ void EmitSynchronizedStmt(CodeGenFunction &CGF,
+ const ObjCAtSynchronizedStmt &S) override;
+ void EmitThrowStmt(CodeGenFunction &CGF,
+ const ObjCAtThrowStmt &S,
+ bool ClearInsertionPoint=true) override;
+ llvm::Value * EmitObjCWeakRead(CodeGenFunction &CGF,
+ llvm::Value *AddrWeakObj) override;
+ void EmitObjCWeakAssign(CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst) override;
+ void EmitObjCGlobalAssign(CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest,
+ bool threadlocal=false) override;
+ void EmitObjCIvarAssign(CodeGenFunction &CGF, llvm::Value *src,
+ llvm::Value *dest, llvm::Value *ivarOffset) override;
+ void EmitObjCStrongCastAssign(CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest) override;
+ void EmitGCMemmoveCollectable(CodeGenFunction &CGF, llvm::Value *DestPtr,
+ llvm::Value *SrcPtr,
+ llvm::Value *Size) override;
+ LValue EmitObjCValueForIvar(CodeGenFunction &CGF, QualType ObjectTy,
+ llvm::Value *BaseValue, const ObjCIvarDecl *Ivar,
+ unsigned CVRQualifiers) override;
+ llvm::Value *EmitIvarOffset(CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *Interface,
+ const ObjCIvarDecl *Ivar) override;
+ llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) override;
+ llvm::Constant *BuildGCBlockLayout(CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo) override {
return NULLPtr;
}
- virtual llvm::Constant *BuildRCBlockLayout(CodeGenModule &CGM,
- const CGBlockInfo &blockInfo) {
+ llvm::Constant *BuildRCBlockLayout(CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo) override {
return NULLPtr;
}
-
- virtual llvm::Constant *BuildByrefLayout(CodeGenModule &CGM,
- QualType T) {
+
+ llvm::Constant *BuildByrefLayout(CodeGenModule &CGM, QualType T) override {
return NULLPtr;
}
-
- virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) {
- return 0;
+
+ llvm::GlobalVariable *GetClassGlobal(const std::string &Name,
+ bool Weak = false) override {
+ return nullptr;
}
};
/// Class representing the legacy GCC Objective-C ABI. This is the default when
@@ -595,11 +584,9 @@ class CGObjCGCC : public CGObjCGNU {
/// arguments. Returns the IMP for the corresponding method.
LazyRuntimeFunction MsgLookupSuperFn;
protected:
- virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
- llvm::Value *&Receiver,
- llvm::Value *cmd,
- llvm::MDNode *node,
- MessageSendInfo &MSI) {
+ llvm::Value *LookupIMP(CodeGenFunction &CGF, llvm::Value *&Receiver,
+ llvm::Value *cmd, llvm::MDNode *node,
+ MessageSendInfo &MSI) override {
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *args[] = {
EnforceType(Builder, Receiver, IdTy),
@@ -608,10 +595,8 @@ protected:
imp->setMetadata(msgSendMDKind, node);
return imp.getInstruction();
}
- virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
- llvm::Value *ObjCSuper,
- llvm::Value *cmd,
- MessageSendInfo &MSI) {
+ llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, llvm::Value *ObjCSuper,
+ llvm::Value *cmd, MessageSendInfo &MSI) override {
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper,
PtrToObjCSuperTy), cmd};
@@ -620,10 +605,11 @@ protected:
public:
CGObjCGCC(CodeGenModule &Mod) : CGObjCGNU(Mod, 8, 2) {
// IMP objc_msg_lookup(id, SEL);
- MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy, NULL);
+ MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy,
+ nullptr);
// IMP objc_msg_lookup_super(struct objc_super*, SEL);
MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy,
- PtrToObjCSuperTy, SelectorTy, NULL);
+ PtrToObjCSuperTy, SelectorTy, nullptr);
}
};
/// Class used when targeting the new GNUstep runtime ABI.
@@ -654,13 +640,11 @@ class CGObjCGNUstep : public CGObjCGNU {
/// lookup functions.
llvm::Type *SlotTy;
public:
- virtual llvm::Constant *GetEHType(QualType T);
+ llvm::Constant *GetEHType(QualType T) override;
protected:
- virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
- llvm::Value *&Receiver,
- llvm::Value *cmd,
- llvm::MDNode *node,
- MessageSendInfo &MSI) {
+ llvm::Value *LookupIMP(CodeGenFunction &CGF, llvm::Value *&Receiver,
+ llvm::Value *cmd, llvm::MDNode *node,
+ MessageSendInfo &MSI) override {
CGBuilderTy &Builder = CGF.Builder;
llvm::Function *LookupFn = SlotLookupFn;
@@ -696,10 +680,9 @@ class CGObjCGNUstep : public CGObjCGNU {
Receiver = Builder.CreateLoad(ReceiverPtr, true);
return imp;
}
- virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
- llvm::Value *ObjCSuper,
- llvm::Value *cmd,
- MessageSendInfo &MSI) {
+ llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, llvm::Value *ObjCSuper,
+ llvm::Value *cmd,
+ MessageSendInfo &MSI) override {
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *lookupArgs[] = {ObjCSuper, cmd};
@@ -714,68 +697,68 @@ class CGObjCGNUstep : public CGObjCGNU {
const ObjCRuntime &R = CGM.getLangOpts().ObjCRuntime;
llvm::StructType *SlotStructTy = llvm::StructType::get(PtrTy,
- PtrTy, PtrTy, IntTy, IMPTy, NULL);
+ PtrTy, PtrTy, IntTy, IMPTy, nullptr);
SlotTy = llvm::PointerType::getUnqual(SlotStructTy);
// Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender);
SlotLookupFn.init(&CGM, "objc_msg_lookup_sender", SlotTy, PtrToIdTy,
- SelectorTy, IdTy, NULL);
+ SelectorTy, IdTy, nullptr);
// Slot_t objc_msg_lookup_super(struct objc_super*, SEL);
SlotLookupSuperFn.init(&CGM, "objc_slot_lookup_super", SlotTy,
- PtrToObjCSuperTy, SelectorTy, NULL);
+ PtrToObjCSuperTy, SelectorTy, nullptr);
// If we're in ObjC++ mode, then we want to make
if (CGM.getLangOpts().CPlusPlus) {
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// void *__cxa_begin_catch(void *e)
- EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy, NULL);
+ EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy, nullptr);
// void __cxa_end_catch(void)
- ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy, NULL);
+ ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy, nullptr);
// void _Unwind_Resume_or_Rethrow(void*)
ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy,
- PtrTy, NULL);
+ PtrTy, nullptr);
} else if (R.getVersion() >= VersionTuple(1, 7)) {
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// id objc_begin_catch(void *e)
- EnterCatchFn.init(&CGM, "objc_begin_catch", IdTy, PtrTy, NULL);
+ EnterCatchFn.init(&CGM, "objc_begin_catch", IdTy, PtrTy, nullptr);
// void objc_end_catch(void)
- ExitCatchFn.init(&CGM, "objc_end_catch", VoidTy, NULL);
+ ExitCatchFn.init(&CGM, "objc_end_catch", VoidTy, nullptr);
// void _Unwind_Resume_or_Rethrow(void*)
ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy,
- PtrTy, NULL);
+ PtrTy, nullptr);
}
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
SetPropertyAtomic.init(&CGM, "objc_setProperty_atomic", VoidTy, IdTy,
- SelectorTy, IdTy, PtrDiffTy, NULL);
+ SelectorTy, IdTy, PtrDiffTy, nullptr);
SetPropertyAtomicCopy.init(&CGM, "objc_setProperty_atomic_copy", VoidTy,
- IdTy, SelectorTy, IdTy, PtrDiffTy, NULL);
+ IdTy, SelectorTy, IdTy, PtrDiffTy, nullptr);
SetPropertyNonAtomic.init(&CGM, "objc_setProperty_nonatomic", VoidTy,
- IdTy, SelectorTy, IdTy, PtrDiffTy, NULL);
+ IdTy, SelectorTy, IdTy, PtrDiffTy, nullptr);
SetPropertyNonAtomicCopy.init(&CGM, "objc_setProperty_nonatomic_copy",
- VoidTy, IdTy, SelectorTy, IdTy, PtrDiffTy, NULL);
+ VoidTy, IdTy, SelectorTy, IdTy, PtrDiffTy, nullptr);
// void objc_setCppObjectAtomic(void *dest, const void *src, void
// *helper);
CxxAtomicObjectSetFn.init(&CGM, "objc_setCppObjectAtomic", VoidTy, PtrTy,
- PtrTy, PtrTy, NULL);
+ PtrTy, PtrTy, nullptr);
// void objc_getCppObjectAtomic(void *dest, const void *src, void
// *helper);
CxxAtomicObjectGetFn.init(&CGM, "objc_getCppObjectAtomic", VoidTy, PtrTy,
- PtrTy, PtrTy, NULL);
+ PtrTy, PtrTy, nullptr);
}
- virtual llvm::Constant *GetCppAtomicObjectGetFunction() {
+ llvm::Constant *GetCppAtomicObjectGetFunction() override {
// The optimised functions were added in version 1.7 of the GNUstep
// runtime.
assert (CGM.getLangOpts().ObjCRuntime.getVersion() >=
VersionTuple(1, 7));
return CxxAtomicObjectGetFn;
}
- virtual llvm::Constant *GetCppAtomicObjectSetFunction() {
+ llvm::Constant *GetCppAtomicObjectSetFunction() override {
// The optimised functions were added in version 1.7 of the GNUstep
// runtime.
assert (CGM.getLangOpts().ObjCRuntime.getVersion() >=
VersionTuple(1, 7));
return CxxAtomicObjectSetFn;
}
- virtual llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
- bool copy) {
+ llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
+ bool copy) override {
// The optimised property functions omit the GC check, and so are not
// safe to use in GC mode. The standard functions are fast in GC mode,
// so there is less advantage in using them.
@@ -789,10 +772,8 @@ class CGObjCGNUstep : public CGObjCGNU {
if (copy) return SetPropertyAtomicCopy;
return SetPropertyAtomic;
}
- if (copy) return SetPropertyNonAtomicCopy;
- return SetPropertyNonAtomic;
- return 0;
+ return copy ? SetPropertyNonAtomicCopy : SetPropertyNonAtomic;
}
};
@@ -810,11 +791,9 @@ protected:
/// arguments. Returns the IMP for the corresponding method.
LazyRuntimeFunction MsgLookupSuperFn, MsgLookupSuperFnSRet;
- virtual llvm::Value *LookupIMP(CodeGenFunction &CGF,
- llvm::Value *&Receiver,
- llvm::Value *cmd,
- llvm::MDNode *node,
- MessageSendInfo &MSI) {
+ llvm::Value *LookupIMP(CodeGenFunction &CGF, llvm::Value *&Receiver,
+ llvm::Value *cmd, llvm::MDNode *node,
+ MessageSendInfo &MSI) override {
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *args[] = {
EnforceType(Builder, Receiver, IdTy),
@@ -830,10 +809,8 @@ protected:
return imp.getInstruction();
}
- virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
- llvm::Value *ObjCSuper,
- llvm::Value *cmd,
- MessageSendInfo &MSI) {
+ llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, llvm::Value *ObjCSuper,
+ llvm::Value *cmd, MessageSendInfo &MSI) override {
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper,
PtrToObjCSuperTy), cmd};
@@ -844,8 +821,8 @@ protected:
return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs);
}
- virtual llvm::Value *GetClassNamed(CodeGenFunction &CGF,
- const std::string &Name, bool isWeak) {
+ llvm::Value *GetClassNamed(CodeGenFunction &CGF,
+ const std::string &Name, bool isWeak) override {
if (isWeak)
return CGObjCGNU::GetClassNamed(CGF, Name, isWeak);
@@ -858,7 +835,7 @@ protected:
if (!ClassSymbol)
ClassSymbol = new llvm::GlobalVariable(TheModule, LongTy, false,
llvm::GlobalValue::ExternalLinkage,
- 0, SymbolName);
+ nullptr, SymbolName);
return ClassSymbol;
}
@@ -866,14 +843,14 @@ protected:
public:
CGObjCObjFW(CodeGenModule &Mod): CGObjCGNU(Mod, 9, 3) {
// IMP objc_msg_lookup(id, SEL);
- MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy, NULL);
+ MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy, nullptr);
MsgLookupFnSRet.init(&CGM, "objc_msg_lookup_stret", IMPTy, IdTy,
- SelectorTy, NULL);
+ SelectorTy, nullptr);
// IMP objc_msg_lookup_super(struct objc_super*, SEL);
MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy,
- PtrToObjCSuperTy, SelectorTy, NULL);
+ PtrToObjCSuperTy, SelectorTy, nullptr);
MsgLookupSuperFnSRet.init(&CGM, "objc_msg_lookup_super_stret", IMPTy,
- PtrToObjCSuperTy, SelectorTy, NULL);
+ PtrToObjCSuperTy, SelectorTy, nullptr);
}
};
} // end anonymous namespace
@@ -891,7 +868,8 @@ void CGObjCGNU::EmitClassRef(const std::string &className) {
llvm::GlobalVariable *ClassSymbol = TheModule.getGlobalVariable(symbolName);
if (!ClassSymbol) {
ClassSymbol = new llvm::GlobalVariable(TheModule, LongTy, false,
- llvm::GlobalValue::ExternalLinkage, 0, symbolName);
+ llvm::GlobalValue::ExternalLinkage,
+ nullptr, symbolName);
}
new llvm::GlobalVariable(TheModule, ClassSymbol->getType(), true,
llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef);
@@ -908,10 +886,11 @@ static std::string SymbolNameForMethod(const StringRef &ClassName,
}
CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
- unsigned protocolClassVersion)
+ unsigned protocolClassVersion)
: CGObjCRuntime(cgm), TheModule(CGM.getModule()),
- VMContext(cgm.getLLVMContext()), ClassPtrAlias(0), MetaClassPtrAlias(0),
- RuntimeVersion(runtimeABIVersion), ProtocolVersion(protocolClassVersion) {
+ VMContext(cgm.getLLVMContext()), ClassPtrAlias(nullptr),
+ MetaClassPtrAlias(nullptr), RuntimeVersion(runtimeABIVersion),
+ ProtocolVersion(protocolClassVersion) {
msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend");
@@ -948,7 +927,7 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
Int64Ty = llvm::Type::getInt64Ty(VMContext);
IntPtrTy =
- TheModule.getPointerSize() == llvm::Module::Pointer32 ? Int32Ty : Int64Ty;
+ CGM.getDataLayout().getPointerSizeInBits() == 32 ? Int32Ty : Int64Ty;
// Object type
QualType UnqualIdTy = CGM.getContext().getObjCIdType();
@@ -961,35 +940,35 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
}
PtrToIdTy = llvm::PointerType::getUnqual(IdTy);
- ObjCSuperTy = llvm::StructType::get(IdTy, IdTy, NULL);
+ ObjCSuperTy = llvm::StructType::get(IdTy, IdTy, nullptr);
PtrToObjCSuperTy = llvm::PointerType::getUnqual(ObjCSuperTy);
llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
// void objc_exception_throw(id);
- ExceptionThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy, NULL);
- ExceptionReThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy, NULL);
+ ExceptionThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy, nullptr);
+ ExceptionReThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy, nullptr);
// int objc_sync_enter(id);
- SyncEnterFn.init(&CGM, "objc_sync_enter", IntTy, IdTy, NULL);
+ SyncEnterFn.init(&CGM, "objc_sync_enter", IntTy, IdTy, nullptr);
// int objc_sync_exit(id);
- SyncExitFn.init(&CGM, "objc_sync_exit", IntTy, IdTy, NULL);
+ SyncExitFn.init(&CGM, "objc_sync_exit", IntTy, IdTy, nullptr);
// void objc_enumerationMutation (id)
EnumerationMutationFn.init(&CGM, "objc_enumerationMutation", VoidTy,
- IdTy, NULL);
+ IdTy, nullptr);
// id objc_getProperty(id, SEL, ptrdiff_t, BOOL)
GetPropertyFn.init(&CGM, "objc_getProperty", IdTy, IdTy, SelectorTy,
- PtrDiffTy, BoolTy, NULL);
+ PtrDiffTy, BoolTy, nullptr);
// void objc_setProperty(id, SEL, ptrdiff_t, id, BOOL, BOOL)
SetPropertyFn.init(&CGM, "objc_setProperty", VoidTy, IdTy, SelectorTy,
- PtrDiffTy, IdTy, BoolTy, BoolTy, NULL);
+ PtrDiffTy, IdTy, BoolTy, BoolTy, nullptr);
// void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL)
GetStructPropertyFn.init(&CGM, "objc_getPropertyStruct", VoidTy, PtrTy, PtrTy,
- PtrDiffTy, BoolTy, BoolTy, NULL);
+ PtrDiffTy, BoolTy, BoolTy, nullptr);
// void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL)
SetStructPropertyFn.init(&CGM, "objc_setPropertyStruct", VoidTy, PtrTy, PtrTy,
- PtrDiffTy, BoolTy, BoolTy, NULL);
+ PtrDiffTy, BoolTy, BoolTy, nullptr);
// IMP type
llvm::Type *IMPArgs[] = { IdTy, SelectorTy };
@@ -1014,20 +993,20 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
// id objc_assign_ivar(id, id, ptrdiff_t);
IvarAssignFn.init(&CGM, "objc_assign_ivar", IdTy, IdTy, IdTy, PtrDiffTy,
- NULL);
+ nullptr);
// id objc_assign_strongCast (id, id*)
StrongCastAssignFn.init(&CGM, "objc_assign_strongCast", IdTy, IdTy,
- PtrToIdTy, NULL);
+ PtrToIdTy, nullptr);
// id objc_assign_global(id, id*);
GlobalAssignFn.init(&CGM, "objc_assign_global", IdTy, IdTy, PtrToIdTy,
- NULL);
+ nullptr);
// id objc_assign_weak(id, id*);
- WeakAssignFn.init(&CGM, "objc_assign_weak", IdTy, IdTy, PtrToIdTy, NULL);
+ WeakAssignFn.init(&CGM, "objc_assign_weak", IdTy, IdTy, PtrToIdTy, nullptr);
// id objc_read_weak(id*);
- WeakReadFn.init(&CGM, "objc_read_weak", IdTy, PtrToIdTy, NULL);
+ WeakReadFn.init(&CGM, "objc_read_weak", IdTy, PtrToIdTy, nullptr);
// void *objc_memmove_collectable(void*, void *, size_t);
MemMoveFn.init(&CGM, "objc_memmove_collectable", PtrTy, PtrTy, PtrTy,
- SizeTy, NULL);
+ SizeTy, nullptr);
}
}
@@ -1066,8 +1045,7 @@ llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, Selector Sel,
const std::string &TypeEncoding, bool lval) {
SmallVectorImpl<TypedSelector> &Types = SelectorTable[Sel];
- llvm::GlobalAlias *SelValue = 0;
-
+ llvm::GlobalAlias *SelValue = nullptr;
for (SmallVectorImpl<TypedSelector>::iterator i = Types.begin(),
e = Types.end() ; i!=e ; i++) {
@@ -1076,11 +1054,10 @@ llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, Selector Sel,
break;
}
}
- if (0 == SelValue) {
- SelValue = new llvm::GlobalAlias(SelectorTy,
- llvm::GlobalValue::PrivateLinkage,
- ".objc_selector_"+Sel.getAsString(), NULL,
- &TheModule);
+ if (!SelValue) {
+ SelValue = llvm::GlobalAlias::create(
+ SelectorTy->getElementType(), 0, llvm::GlobalValue::PrivateLinkage,
+ ".objc_selector_" + Sel.getAsString(), &TheModule);
Types.push_back(TypedSelector(TypeEncoding, SelValue));
}
@@ -1113,7 +1090,7 @@ llvm::Constant *CGObjCGNU::GetEHType(QualType T) {
if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
return MakeConstantString("@id");
} else {
- return 0;
+ return nullptr;
}
}
@@ -1142,7 +1119,7 @@ llvm::Constant *CGObjCGNUstep::GetEHType(QualType T) {
new llvm::GlobalVariable(CGM.getModule(), PtrToInt8Ty,
false,
llvm::GlobalValue::ExternalLinkage,
- 0, "__objc_id_type_info");
+ nullptr, "__objc_id_type_info");
return llvm::ConstantExpr::getBitCast(IDEHType, PtrToInt8Ty);
}
@@ -1169,7 +1146,8 @@ llvm::Constant *CGObjCGNUstep::GetEHType(QualType T) {
llvm::Constant *Vtable = TheModule.getGlobalVariable(vtableName);
if (!Vtable) {
Vtable = new llvm::GlobalVariable(TheModule, PtrToInt8Ty, true,
- llvm::GlobalValue::ExternalLinkage, 0, vtableName);
+ llvm::GlobalValue::ExternalLinkage,
+ nullptr, vtableName);
}
llvm::Constant *Two = llvm::ConstantInt::get(IntTy, 2);
Vtable = llvm::ConstantExpr::getGetElementPtr(Vtable, Two);
@@ -1183,7 +1161,7 @@ llvm::Constant *CGObjCGNUstep::GetEHType(QualType T) {
fields.push_back(typeName);
llvm::Constant *TI =
MakeGlobal(llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty,
- NULL), fields, "__objc_eh_typeinfo_" + className,
+ nullptr), fields, "__objc_eh_typeinfo_" + className,
llvm::GlobalValue::LinkOnceODRLinkage);
return llvm::ConstantExpr::getBitCast(TI, PtrToInt8Ty);
}
@@ -1209,7 +1187,7 @@ llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) {
if (!isa)
isa = new llvm::GlobalVariable(TheModule, IdTy, /* isConstant */false,
- llvm::GlobalValue::ExternalWeakLinkage, 0, Sym);
+ llvm::GlobalValue::ExternalWeakLinkage, nullptr, Sym);
else if (isa->getType() != PtrToIdTy)
isa = llvm::ConstantExpr::getBitCast(isa, PtrToIdTy);
@@ -1218,7 +1196,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(PtrToIdTy, PtrToInt8Ty, IntTy, NULL),
+ llvm::StructType::get(PtrToIdTy, PtrToInt8Ty, IntTy, nullptr),
Ivars, ".objc_str");
ObjCStr = llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty);
ObjCStrings[Str] = ObjCStr;
@@ -1247,7 +1225,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
CGM.getTypes().ConvertType(ResultType)));
}
if (Sel == ReleaseSel) {
- return RValue::get(0);
+ return RValue::get(nullptr);
}
}
@@ -1262,9 +1240,9 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs);
- llvm::Value *ReceiverClass = 0;
+ llvm::Value *ReceiverClass = nullptr;
if (isCategoryImpl) {
- llvm::Constant *classLookupFunction = 0;
+ llvm::Constant *classLookupFunction = nullptr;
if (IsClassMessage) {
classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
IdTy, PtrTy, true), "objc_get_meta_class");
@@ -1282,16 +1260,16 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
// super_class pointer from either the class or metaclass structure.
if (IsClassMessage) {
if (!MetaClassPtrAlias) {
- MetaClassPtrAlias = new llvm::GlobalAlias(IdTy,
- llvm::GlobalValue::InternalLinkage, ".objc_metaclass_ref" +
- Class->getNameAsString(), NULL, &TheModule);
+ MetaClassPtrAlias = llvm::GlobalAlias::create(
+ IdTy->getElementType(), 0, llvm::GlobalValue::InternalLinkage,
+ ".objc_metaclass_ref" + Class->getNameAsString(), &TheModule);
}
ReceiverClass = MetaClassPtrAlias;
} else {
if (!ClassPtrAlias) {
- ClassPtrAlias = new llvm::GlobalAlias(IdTy,
- llvm::GlobalValue::InternalLinkage, ".objc_class_ref" +
- Class->getNameAsString(), NULL, &TheModule);
+ ClassPtrAlias = llvm::GlobalAlias::create(
+ IdTy->getElementType(), 0, llvm::GlobalValue::InternalLinkage,
+ ".objc_class_ref" + Class->getNameAsString(), &TheModule);
}
ReceiverClass = ClassPtrAlias;
}
@@ -1299,14 +1277,14 @@ 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(IdTy, IdTy, NULL)));
+ llvm::StructType::get(IdTy, IdTy, nullptr)));
// 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(
- Receiver->getType(), IdTy, NULL);
+ Receiver->getType(), IdTy, nullptr);
llvm::Value *ObjCSuper = Builder.CreateAlloca(ObjCSuperTy);
Builder.CreateStore(Receiver, Builder.CreateStructGEP(ObjCSuper, 0));
@@ -1326,7 +1304,8 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD);
llvm::Instruction *call;
- RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs, 0, &call);
+ RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs, nullptr,
+ &call);
call->setMetadata(msgSendMDKind, node);
return msgRet;
}
@@ -1350,7 +1329,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
CGM.getTypes().ConvertType(ResultType)));
}
if (Sel == ReleaseSel) {
- return RValue::get(0);
+ return RValue::get(nullptr);
}
}
@@ -1368,9 +1347,9 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
bool isPointerSizedReturn = (ResultType->isAnyPointerType() ||
ResultType->isIntegralOrEnumerationType() || ResultType->isVoidType());
- llvm::BasicBlock *startBB = 0;
- llvm::BasicBlock *messageBB = 0;
- llvm::BasicBlock *continueBB = 0;
+ llvm::BasicBlock *startBB = nullptr;
+ llvm::BasicBlock *messageBB = nullptr;
+ llvm::BasicBlock *continueBB = nullptr;
if (!isPointerSizedReturn) {
startBB = Builder.GetInsertBlock();
@@ -1395,7 +1374,8 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
llvm::Value *impMD[] = {
llvm::MDString::get(VMContext, Sel.getAsString()),
llvm::MDString::get(VMContext, Class ? Class->getNameAsString() :""),
- llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), Class!=0)
+ llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext),
+ Class!=nullptr)
};
llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD);
@@ -1438,7 +1418,8 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
imp = EnforceType(Builder, imp, MSI.MessengerType);
llvm::Instruction *call;
- RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs, 0, &call);
+ RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs, nullptr,
+ &call);
call->setMetadata(msgSendMDKind, node);
@@ -1494,7 +1475,7 @@ GenerateMethodList(const StringRef &ClassName,
PtrToInt8Ty, // Really a selector, but the runtime creates it us.
PtrToInt8Ty, // Method types
IMPTy, //Method pointer
- NULL);
+ nullptr);
std::vector<llvm::Constant*> Methods;
std::vector<llvm::Constant*> Elements;
for (unsigned int i = 0, e = MethodTypes.size(); i < e; ++i) {
@@ -1526,7 +1507,7 @@ GenerateMethodList(const StringRef &ClassName,
NextPtrTy,
IntTy,
ObjCMethodArrayTy,
- NULL);
+ nullptr);
Methods.clear();
Methods.push_back(llvm::ConstantPointerNull::get(
@@ -1550,7 +1531,7 @@ GenerateIvarList(ArrayRef<llvm::Constant *> IvarNames,
PtrToInt8Ty,
PtrToInt8Ty,
IntTy,
- NULL);
+ nullptr);
std::vector<llvm::Constant*> Ivars;
std::vector<llvm::Constant*> Elements;
for (unsigned int i = 0, e = IvarNames.size() ; i < e ; i++) {
@@ -1572,7 +1553,7 @@ GenerateIvarList(ArrayRef<llvm::Constant *> IvarNames,
// Structure containing array and array count
llvm::StructType *ObjCIvarListTy = llvm::StructType::get(IntTy,
ObjCIvarArrayTy,
- NULL);
+ nullptr);
// Create an instance of the structure
return MakeGlobal(ObjCIvarListTy, Elements, ".objc_ivar_list");
@@ -1622,7 +1603,7 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
Properties->getType(), // properties
IntPtrTy, // strong_pointers
IntPtrTy, // weak_pointers
- NULL);
+ nullptr);
llvm::Constant *Zero = llvm::ConstantInt::get(LongTy, 0);
// Fill in the structure
std::vector<llvm::Constant*> Elements;
@@ -1676,7 +1657,7 @@ GenerateProtocolMethodList(ArrayRef<llvm::Constant *> MethodNames,
llvm::StructType *ObjCMethodDescTy = llvm::StructType::get(
PtrToInt8Ty, // Really a selector, but the runtime does the casting for us.
PtrToInt8Ty,
- NULL);
+ nullptr);
std::vector<llvm::Constant*> Methods;
std::vector<llvm::Constant*> Elements;
for (unsigned int i = 0, e = MethodTypes.size() ; i < e ; i++) {
@@ -1690,7 +1671,7 @@ GenerateProtocolMethodList(ArrayRef<llvm::Constant *> MethodNames,
llvm::Constant *Array = llvm::ConstantArray::get(ObjCMethodArrayTy,
Methods);
llvm::StructType *ObjCMethodDescListTy = llvm::StructType::get(
- IntTy, ObjCMethodArrayTy, NULL);
+ IntTy, ObjCMethodArrayTy, nullptr);
Methods.clear();
Methods.push_back(llvm::ConstantInt::get(IntTy, MethodNames.size()));
Methods.push_back(Array);
@@ -1705,11 +1686,11 @@ llvm::Constant *CGObjCGNU::GenerateProtocolList(ArrayRef<std::string>Protocols){
PtrTy, //Should be a recurisve pointer, but it's always NULL here.
SizeTy,
ProtocolArrayTy,
- NULL);
+ nullptr);
std::vector<llvm::Constant*> Elements;
for (const std::string *iter = Protocols.begin(), *endIter = Protocols.end();
iter != endIter ; iter++) {
- llvm::Constant *protocol = 0;
+ llvm::Constant *protocol = nullptr;
llvm::StringMap<llvm::Constant*>::iterator value =
ExistingProtocols.find(*iter);
if (value == ExistingProtocols.end()) {
@@ -1755,7 +1736,7 @@ llvm::Constant *CGObjCGNU::GenerateEmptyProtocol(
MethodList->getType(),
MethodList->getType(),
MethodList->getType(),
- NULL);
+ nullptr);
std::vector<llvm::Constant*> Elements;
// The isa pointer must be set to a magic number so the runtime knows it's
// the correct layout.
@@ -1779,24 +1760,22 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
PD = Def;
SmallVector<std::string, 16> Protocols;
- for (ObjCProtocolDecl::protocol_iterator PI = PD->protocol_begin(),
- E = PD->protocol_end(); PI != E; ++PI)
- Protocols.push_back((*PI)->getNameAsString());
+ for (const auto *PI : PD->protocols())
+ Protocols.push_back(PI->getNameAsString());
SmallVector<llvm::Constant*, 16> InstanceMethodNames;
SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
SmallVector<llvm::Constant*, 16> OptionalInstanceMethodNames;
SmallVector<llvm::Constant*, 16> OptionalInstanceMethodTypes;
- for (ObjCProtocolDecl::instmeth_iterator iter = PD->instmeth_begin(),
- E = PD->instmeth_end(); iter != E; iter++) {
+ for (const auto *I : PD->instance_methods()) {
std::string TypeStr;
- Context.getObjCEncodingForMethodDecl(*iter, TypeStr);
- if ((*iter)->getImplementationControl() == ObjCMethodDecl::Optional) {
+ Context.getObjCEncodingForMethodDecl(I, TypeStr);
+ if (I->getImplementationControl() == ObjCMethodDecl::Optional) {
OptionalInstanceMethodNames.push_back(
- MakeConstantString((*iter)->getSelector().getAsString()));
+ MakeConstantString(I->getSelector().getAsString()));
OptionalInstanceMethodTypes.push_back(MakeConstantString(TypeStr));
} else {
InstanceMethodNames.push_back(
- MakeConstantString((*iter)->getSelector().getAsString()));
+ MakeConstantString(I->getSelector().getAsString()));
InstanceMethodTypes.push_back(MakeConstantString(TypeStr));
}
}
@@ -1805,18 +1784,16 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
SmallVector<llvm::Constant*, 16> ClassMethodTypes;
SmallVector<llvm::Constant*, 16> OptionalClassMethodNames;
SmallVector<llvm::Constant*, 16> OptionalClassMethodTypes;
- for (ObjCProtocolDecl::classmeth_iterator
- iter = PD->classmeth_begin(), endIter = PD->classmeth_end();
- iter != endIter ; iter++) {
+ for (const auto *I : PD->class_methods()) {
std::string TypeStr;
- Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
- if ((*iter)->getImplementationControl() == ObjCMethodDecl::Optional) {
+ Context.getObjCEncodingForMethodDecl(I,TypeStr);
+ if (I->getImplementationControl() == ObjCMethodDecl::Optional) {
OptionalClassMethodNames.push_back(
- MakeConstantString((*iter)->getSelector().getAsString()));
+ MakeConstantString(I->getSelector().getAsString()));
OptionalClassMethodTypes.push_back(MakeConstantString(TypeStr));
} else {
ClassMethodNames.push_back(
- MakeConstantString((*iter)->getSelector().getAsString()));
+ MakeConstantString(I->getSelector().getAsString()));
ClassMethodTypes.push_back(MakeConstantString(TypeStr));
}
}
@@ -1840,19 +1817,16 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
// structures for protocol metadata everywhere.
llvm::StructType *PropertyMetadataTy = llvm::StructType::get(
PtrToInt8Ty, Int8Ty, Int8Ty, Int8Ty, Int8Ty, PtrToInt8Ty,
- PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, NULL);
+ PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, nullptr);
std::vector<llvm::Constant*> Properties;
std::vector<llvm::Constant*> OptionalProperties;
// Add all of the property methods need adding to the method list and to the
// property metadata list.
- for (ObjCContainerDecl::prop_iterator
- iter = PD->prop_begin(), endIter = PD->prop_end();
- iter != endIter ; iter++) {
+ for (auto *property : PD->properties()) {
std::vector<llvm::Constant*> Fields;
- ObjCPropertyDecl *property = *iter;
- Fields.push_back(MakePropertyEncodingString(property, 0));
+ Fields.push_back(MakePropertyEncodingString(property, nullptr));
PushPropertyAttributes(Fields, property);
if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) {
@@ -1919,7 +1893,7 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
OptionalClassMethodList->getType(),
PropertyList->getType(),
OptionalPropertyList->getType(),
- NULL);
+ nullptr);
std::vector<llvm::Constant*> Elements;
// The isa pointer must be set to a magic number so the runtime knows it's
// the correct layout.
@@ -1960,7 +1934,7 @@ void CGObjCGNU::GenerateProtocolHolderCategory() {
PtrTy, //Should be a recurisve pointer, but it's always NULL here.
SizeTy,
ProtocolArrayTy,
- NULL);
+ nullptr);
std::vector<llvm::Constant*> ProtocolElements;
for (llvm::StringMapIterator<llvm::Constant*> iter =
ExistingProtocols.begin(), endIter = ExistingProtocols.end();
@@ -1980,7 +1954,7 @@ void CGObjCGNU::GenerateProtocolHolderCategory() {
ProtocolElements, ".objc_protocol_list"), PtrTy));
Categories.push_back(llvm::ConstantExpr::getBitCast(
MakeGlobal(llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty,
- PtrTy, PtrTy, PtrTy, NULL), Elements), PtrTy));
+ PtrTy, PtrTy, PtrTy, nullptr), Elements), PtrTy));
}
/// Libobjc2 uses a bitfield representation where small(ish) bitfields are
@@ -1996,8 +1970,7 @@ void CGObjCGNU::GenerateProtocolHolderCategory() {
/// bitfield / with the 63rd bit set will be 1<<64.
llvm::Constant *CGObjCGNU::MakeBitField(ArrayRef<bool> bits) {
int bitCount = bits.size();
- int ptrBits =
- (TheModule.getPointerSize() == llvm::Module::Pointer32) ? 32 : 64;
+ int ptrBits = CGM.getDataLayout().getPointerSizeInBits();
if (bitCount < ptrBits) {
uint64_t val = 1;
for (int i=0 ; i<bitCount ; ++i) {
@@ -2021,7 +1994,7 @@ llvm::Constant *CGObjCGNU::MakeBitField(ArrayRef<bool> bits) {
llvm::ConstantInt::get(Int32Ty, values.size()),
array };
llvm::Constant *GS = MakeGlobal(llvm::StructType::get(Int32Ty, arrayTy,
- NULL), fields);
+ nullptr), fields);
llvm::Constant *ptr = llvm::ConstantExpr::getPtrToInt(GS, IntPtrTy);
return ptr;
}
@@ -2032,24 +2005,20 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
// Collect information about instance methods
SmallVector<Selector, 16> InstanceMethodSels;
SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
- for (ObjCCategoryImplDecl::instmeth_iterator
- iter = OCD->instmeth_begin(), endIter = OCD->instmeth_end();
- iter != endIter ; iter++) {
- InstanceMethodSels.push_back((*iter)->getSelector());
+ for (const auto *I : OCD->instance_methods()) {
+ InstanceMethodSels.push_back(I->getSelector());
std::string TypeStr;
- CGM.getContext().getObjCEncodingForMethodDecl(*iter,TypeStr);
+ CGM.getContext().getObjCEncodingForMethodDecl(I,TypeStr);
InstanceMethodTypes.push_back(MakeConstantString(TypeStr));
}
// Collect information about class methods
SmallVector<Selector, 16> ClassMethodSels;
SmallVector<llvm::Constant*, 16> ClassMethodTypes;
- for (ObjCCategoryImplDecl::classmeth_iterator
- iter = OCD->classmeth_begin(), endIter = OCD->classmeth_end();
- iter != endIter ; iter++) {
- ClassMethodSels.push_back((*iter)->getSelector());
+ for (const auto *I : OCD->class_methods()) {
+ ClassMethodSels.push_back(I->getSelector());
std::string TypeStr;
- CGM.getContext().getObjCEncodingForMethodDecl(*iter,TypeStr);
+ CGM.getContext().getObjCEncodingForMethodDecl(I,TypeStr);
ClassMethodTypes.push_back(MakeConstantString(TypeStr));
}
@@ -2077,7 +2046,7 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
GenerateProtocolList(Protocols), PtrTy));
Categories.push_back(llvm::ConstantExpr::getBitCast(
MakeGlobal(llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty,
- PtrTy, PtrTy, PtrTy, NULL), Elements), PtrTy));
+ PtrTy, PtrTy, PtrTy, nullptr), Elements), PtrTy));
}
llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OID,
@@ -2088,17 +2057,14 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI
// setter name, setter types, getter name, getter types.
llvm::StructType *PropertyMetadataTy = llvm::StructType::get(
PtrToInt8Ty, Int8Ty, Int8Ty, Int8Ty, Int8Ty, PtrToInt8Ty,
- PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, NULL);
+ PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, nullptr);
std::vector<llvm::Constant*> Properties;
// Add all of the property methods need adding to the method list and to the
// property metadata list.
- for (ObjCImplDecl::propimpl_iterator
- iter = OID->propimpl_begin(), endIter = OID->propimpl_end();
- iter != endIter ; iter++) {
+ for (auto *propertyImpl : OID->property_impls()) {
std::vector<llvm::Constant*> Fields;
- ObjCPropertyDecl *property = iter->getPropertyDecl();
- ObjCPropertyImplDecl *propertyImpl = *iter;
+ ObjCPropertyDecl *property = propertyImpl->getPropertyDecl();
bool isSynthesized = (propertyImpl->getPropertyImplementation() ==
ObjCPropertyImplDecl::Synthesize);
bool isDynamic = (propertyImpl->getPropertyImplementation() ==
@@ -2265,12 +2231,10 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
// Collect information about instance methods
SmallVector<Selector, 16> InstanceMethodSels;
SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
- for (ObjCImplementationDecl::instmeth_iterator
- iter = OID->instmeth_begin(), endIter = OID->instmeth_end();
- iter != endIter ; iter++) {
- InstanceMethodSels.push_back((*iter)->getSelector());
+ for (const auto *I : OID->instance_methods()) {
+ InstanceMethodSels.push_back(I->getSelector());
std::string TypeStr;
- Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
+ Context.getObjCEncodingForMethodDecl(I,TypeStr);
InstanceMethodTypes.push_back(MakeConstantString(TypeStr));
}
@@ -2281,22 +2245,16 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
// Collect information about class methods
SmallVector<Selector, 16> ClassMethodSels;
SmallVector<llvm::Constant*, 16> ClassMethodTypes;
- for (ObjCImplementationDecl::classmeth_iterator
- iter = OID->classmeth_begin(), endIter = OID->classmeth_end();
- iter != endIter ; iter++) {
- ClassMethodSels.push_back((*iter)->getSelector());
+ for (const auto *I : OID->class_methods()) {
+ ClassMethodSels.push_back(I->getSelector());
std::string TypeStr;
- Context.getObjCEncodingForMethodDecl((*iter),TypeStr);
+ Context.getObjCEncodingForMethodDecl(I,TypeStr);
ClassMethodTypes.push_back(MakeConstantString(TypeStr));
}
// Collect the names of referenced protocols
SmallVector<std::string, 16> Protocols;
- for (ObjCInterfaceDecl::protocol_iterator
- I = ClassDecl->protocol_begin(),
- E = ClassDecl->protocol_end(); I != E; ++I)
- Protocols.push_back((*I)->getNameAsString());
-
-
+ for (const auto *I : ClassDecl->protocols())
+ Protocols.push_back(I->getNameAsString());
// Get the superclass pointer.
llvm::Constant *SuperClass;
@@ -2326,7 +2284,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
// the offset (third field in ivar structure)
llvm::Type *IndexTy = Int32Ty;
llvm::Constant *offsetPointerIndexes[] = {Zeros[0],
- llvm::ConstantInt::get(IndexTy, 1), 0,
+ llvm::ConstantInt::get(IndexTy, 1), nullptr,
llvm::ConstantInt::get(IndexTy, 2) };
unsigned ivarIndex = 0;
@@ -2357,14 +2315,14 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
llvm::Constant *ZeroPtr = llvm::ConstantInt::get(IntPtrTy, 0);
//Generate metaclass for class methods
llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr,
- NULLPtr, 0x12L, ClassName.c_str(), 0, Zeros[0], GenerateIvarList(
+ NULLPtr, 0x12L, ClassName.c_str(), nullptr, Zeros[0], GenerateIvarList(
empty, empty, empty), ClassMethodList, NULLPtr,
NULLPtr, NULLPtr, ZeroPtr, ZeroPtr, true);
// Generate the class structure
llvm::Constant *ClassStruct =
GenerateClassStructure(MetaClassStruct, SuperClass, 0x11L,
- ClassName.c_str(), 0,
+ ClassName.c_str(), nullptr,
llvm::ConstantInt::get(LongTy, instanceSize), IvarList,
MethodList, GenerateProtocolList(Protocols), IvarOffsetArray,
Properties, StrongIvarBitmap, WeakIvarBitmap);
@@ -2374,13 +2332,13 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
ClassPtrAlias->replaceAllUsesWith(
llvm::ConstantExpr::getBitCast(ClassStruct, IdTy));
ClassPtrAlias->eraseFromParent();
- ClassPtrAlias = 0;
+ ClassPtrAlias = nullptr;
}
if (MetaClassPtrAlias) {
MetaClassPtrAlias->replaceAllUsesWith(
llvm::ConstantExpr::getBitCast(MetaClassStruct, IdTy));
MetaClassPtrAlias->eraseFromParent();
- MetaClassPtrAlias = 0;
+ MetaClassPtrAlias = nullptr;
}
// Add class structure to list to be added to the symtab later
@@ -2393,7 +2351,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
// Only emit an ObjC load function if no Objective-C stuff has been called
if (Classes.empty() && Categories.empty() && ConstantStrings.empty() &&
ExistingProtocols.empty() && SelectorTable.empty())
- return NULL;
+ return nullptr;
// Add all referenced protocols to a category.
GenerateProtocolHolderCategory();
@@ -2401,8 +2359,8 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
llvm::StructType *SelStructTy = dyn_cast<llvm::StructType>(
SelectorTy->getElementType());
llvm::Type *SelStructPtrTy = SelectorTy;
- if (SelStructTy == 0) {
- SelStructTy = llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, NULL);
+ if (!SelStructTy) {
+ SelStructTy = llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, nullptr);
SelStructPtrTy = llvm::PointerType::getUnqual(SelStructTy);
}
@@ -2423,7 +2381,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
Elements.push_back(llvm::ConstantArray::get(StaticsArrayTy,
ConstantStrings));
llvm::StructType *StaticsListTy =
- llvm::StructType::get(PtrToInt8Ty, StaticsArrayTy, NULL);
+ llvm::StructType::get(PtrToInt8Ty, StaticsArrayTy, nullptr);
llvm::Type *StaticsListPtrTy =
llvm::PointerType::getUnqual(StaticsListTy);
Statics = MakeGlobal(StaticsListTy, Elements, ".objc_statics");
@@ -2441,7 +2399,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
llvm::StructType *SymTabTy = llvm::StructType::get(LongTy, SelStructPtrTy,
llvm::Type::getInt16Ty(VMContext),
llvm::Type::getInt16Ty(VMContext),
- ClassListTy, NULL);
+ ClassListTy, nullptr);
Elements.clear();
// Pointer to an array of selectors used in this module.
@@ -2522,7 +2480,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
// constants
llvm::StructType * ModuleTy = llvm::StructType::get(LongTy, LongTy,
PtrToInt8Ty, llvm::PointerType::getUnqual(SymTabTy),
- (RuntimeVersion >= 10) ? IntTy : NULL, NULL);
+ (RuntimeVersion >= 10) ? IntTy : nullptr, nullptr);
Elements.clear();
// Runtime version, used for ABI compatibility checking.
Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion));
@@ -2595,7 +2553,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
llvm::Constant::getNullValue(RegisterAlias->getType()));
Builder.CreateCondBr(HasRegisterAlias, AliasBB, NoAliasBB);
- // The true branch (has alias registration fucntion):
+ // The true branch (has alias registration function):
Builder.SetInsertPoint(AliasBB);
// Emit alias registration calls:
for (std::vector<ClassAliasPair>::iterator iter = ClassAliases.begin();
@@ -2603,7 +2561,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
llvm::Constant *TheClass =
TheModule.getGlobalVariable(("_OBJC_CLASS_" + iter->first).c_str(),
true);
- if (0 != TheClass) {
+ if (TheClass) {
TheClass = llvm::ConstantExpr::getBitCast(TheClass, PtrTy);
Builder.CreateCall2(RegisterAlias, TheClass,
MakeConstantString(iter->second));
@@ -2653,7 +2611,7 @@ llvm::Constant *CGObjCGNU::GetPropertySetFunction() {
llvm::Constant *CGObjCGNU::GetOptimizedPropertySetFunction(bool atomic,
bool copy) {
- return 0;
+ return nullptr;
}
llvm::Constant *CGObjCGNU::GetGetStructFunction() {
@@ -2663,10 +2621,10 @@ llvm::Constant *CGObjCGNU::GetSetStructFunction() {
return SetStructPropertyFn;
}
llvm::Constant *CGObjCGNU::GetCppAtomicObjectGetFunction() {
- return 0;
+ return nullptr;
}
llvm::Constant *CGObjCGNU::GetCppAtomicObjectSetFunction() {
- return 0;
+ return nullptr;
}
llvm::Constant *CGObjCGNU::EnumerationMutationFunction() {
@@ -2814,7 +2772,7 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(
} else {
IvarOffsetPointer = new llvm::GlobalVariable(TheModule,
llvm::Type::getInt32PtrTy(VMContext), false,
- llvm::GlobalValue::ExternalLinkage, 0, Name);
+ llvm::GlobalValue::ExternalLinkage, nullptr, Name);
}
}
return IvarOffsetPointer;
@@ -2844,7 +2802,7 @@ static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context,
if (const ObjCInterfaceDecl *Super = OID->getSuperClass())
return FindIvarInterface(Context, Super, OIVD);
- return 0;
+ return nullptr;
}
llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF,
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 2b2a5b837608..6f0979d06c53 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -29,12 +29,12 @@
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/IR/CallSite.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
-#include "llvm/Support/CallSite.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
@@ -174,6 +174,7 @@ protected:
public:
llvm::Type *ShortTy, *IntTy, *LongTy, *LongLongTy;
llvm::Type *Int8PtrTy, *Int8PtrPtrTy;
+ llvm::Type *IvarOffsetVarTy;
/// ObjectPtrTy - LLVM type for object handles (typeof(id))
llvm::Type *ObjectPtrTy;
@@ -243,8 +244,8 @@ public:
Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(IdType, Params,
- FunctionType::ExtInfo(),
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(IdType, false, Params,
+ FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_getProperty");
}
@@ -263,8 +264,9 @@ public:
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, Params,
- FunctionType::ExtInfo(),
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false,
+ Params,
+ FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
}
@@ -289,7 +291,8 @@ public:
Params.push_back(IdType);
Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, Params,
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false,
+ Params,
FunctionType::ExtInfo(),
RequiredArgs::All));
const char *name;
@@ -316,8 +319,9 @@ public:
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, Params,
- FunctionType::ExtInfo(),
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false,
+ Params,
+ FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_copyStruct");
}
@@ -335,8 +339,9 @@ public:
Params.push_back(Ctx.VoidPtrTy);
Params.push_back(Ctx.VoidPtrTy);
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, Params,
- FunctionType::ExtInfo(),
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false,
+ Params,
+ FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_copyCppObjectAtomic");
}
@@ -348,8 +353,9 @@ public:
SmallVector<CanQualType,1> Params;
Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType()));
llvm::FunctionType *FTy =
- Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, Params,
- FunctionType::ExtInfo(),
+ Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false,
+ Params,
+ FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
}
@@ -849,7 +855,7 @@ protected:
llvm::SetVector<IdentifierInfo*> DefinedSymbols;
/// ClassNames - uniqued class names.
- llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> ClassNames;
+ llvm::StringMap<llvm::GlobalVariable*> ClassNames;
/// MethodVarNames - uniqued method variable names.
llvm::DenseMap<Selector, llvm::GlobalVariable*> MethodVarNames;
@@ -885,6 +891,9 @@ protected:
/// DefinedClasses - List of defined classes.
SmallVector<llvm::GlobalValue*, 16> DefinedClasses;
+
+ /// ImplementedClasses - List of @implemented classes.
+ SmallVector<const ObjCInterfaceDecl*, 16> ImplementedClasses;
/// DefinedNonLazyClasses - List of defined "non-lazy" classes.
SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyClasses;
@@ -923,8 +932,9 @@ protected:
const Decl *Container);
/// GetClassName - Return a unique constant for the given selector's
- /// name. The return value has type char *.
- llvm::Constant *GetClassName(IdentifierInfo *Ident);
+ /// runtime name (which may change via use of objc_runtime_name attribute on
+ /// class or protocol definition. The return value has type char *.
+ llvm::Constant *GetClassName(StringRef RuntimeName);
llvm::Function *GetMethodDefinition(const ObjCMethodDecl *MD);
@@ -991,7 +1001,7 @@ protected:
llvm::SmallPtrSet<const IdentifierInfo*, 16> &PropertySet,
SmallVectorImpl<llvm::Constant*> &Properties,
const Decl *Container,
- const ObjCProtocolDecl *PROTO,
+ const ObjCProtocolDecl *Proto,
const ObjCCommonTypesHelper &ObjCTypes);
/// GetProtocolRef - Return a reference to the internal protocol
@@ -1009,14 +1019,12 @@ protected:
/// \param Name - The variable name.
/// \param Init - The variable initializer; this is also used to
/// define the type of the variable.
- /// \param Section - The section the variable should go into, or 0.
+ /// \param Section - The section the variable should go into, or empty.
/// \param Align - The alignment for the variable, or 0.
/// \param AddToUsed - Whether the variable should be added to
/// "llvm.used".
- llvm::GlobalVariable *CreateMetadataVar(Twine Name,
- llvm::Constant *Init,
- const char *Section,
- unsigned Align,
+ llvm::GlobalVariable *CreateMetadataVar(Twine Name, llvm::Constant *Init,
+ StringRef Section, unsigned Align,
bool AddToUsed);
CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
@@ -1038,12 +1046,12 @@ public:
CGObjCCommonMac(CodeGen::CodeGenModule &cgm) :
CGObjCRuntime(cgm), VMContext(cgm.getLLVMContext()) { }
- virtual llvm::Constant *GenerateConstantString(const StringLiteral *SL);
-
- virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
- const ObjCContainerDecl *CD=0);
+ llvm::Constant *GenerateConstantString(const StringLiteral *SL) override;
+
+ llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
+ const ObjCContainerDecl *CD=nullptr) override;
- virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
+ void GenerateProtocol(const ObjCProtocolDecl *PD) override;
/// GetOrEmitProtocol - Get the protocol object for the given
/// declaration, emitting it if necessary. The return value has type
@@ -1055,13 +1063,13 @@ public:
/// forward references will be filled in with empty bodies if no
/// definition is seen. The return value has type ProtocolPtrTy.
virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD)=0;
- virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
- const CGBlockInfo &blockInfo);
- virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
- const CGBlockInfo &blockInfo);
-
- virtual llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
- QualType T);
+ llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo) override;
+ llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo) override;
+
+ llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
+ QualType T) override;
};
class CGObjCMac : public CGObjCCommonMac {
@@ -1092,9 +1100,9 @@ private:
llvm::Value *EmitClassRefFromId(CodeGenFunction &CGF,
IdentifierInfo *II);
-
- llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF);
-
+
+ llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) override;
+
/// EmitSuperClassRef - Emits reference to class's main metadata class.
llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID);
@@ -1145,13 +1153,13 @@ private:
/// GetOrEmitProtocol - Get the protocol object for the given
/// declaration, emitting it if necessary. The return value has type
/// ProtocolPtrTy.
- virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD);
+ llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD) override;
/// GetOrEmitProtocolRef - Get a forward reference to the protocol
/// object for the given declaration, emitting it if needed. These
/// forward references will be filled in with empty bodies if no
/// definition is seen. The return value has type ProtocolPtrTy.
- virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD);
+ llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) override;
/// EmitProtocolExtension - Generate the protocol extension
/// structure used to store optional instance and class methods, and
@@ -1177,97 +1185,90 @@ private:
public:
CGObjCMac(CodeGen::CodeGenModule &cgm);
- virtual llvm::Function *ModuleInitFunction();
+ llvm::Function *ModuleInitFunction() override;
- virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel,
- llvm::Value *Receiver,
- const CallArgList &CallArgs,
- const ObjCInterfaceDecl *Class,
- const ObjCMethodDecl *Method);
+ CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
+ QualType ResultType,
+ Selector Sel, llvm::Value *Receiver,
+ const CallArgList &CallArgs,
+ const ObjCInterfaceDecl *Class,
+ const ObjCMethodDecl *Method) override;
- virtual CodeGen::RValue
+ CodeGen::RValue
GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel,
- const ObjCInterfaceDecl *Class,
- bool isCategoryImpl,
- llvm::Value *Receiver,
- bool IsClassMessage,
- const CallArgList &CallArgs,
- const ObjCMethodDecl *Method);
-
- virtual llvm::Value *GetClass(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID);
-
- virtual llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
- bool lval = false);
+ ReturnValueSlot Return, QualType ResultType,
+ Selector Sel, const ObjCInterfaceDecl *Class,
+ bool isCategoryImpl, llvm::Value *Receiver,
+ bool IsClassMessage, const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method) override;
+
+ llvm::Value *GetClass(CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *ID) override;
+
+ llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
+ bool lval = false) override;
/// The NeXT/Apple runtimes do not support typed selectors; just emit an
/// untyped one.
- virtual llvm::Value *GetSelector(CodeGenFunction &CGF,
- const ObjCMethodDecl *Method);
+ llvm::Value *GetSelector(CodeGenFunction &CGF,
+ const ObjCMethodDecl *Method) override;
- virtual llvm::Constant *GetEHType(QualType T);
+ llvm::Constant *GetEHType(QualType T) override;
- virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
+ void GenerateCategory(const ObjCCategoryImplDecl *CMD) override;
- virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
+ void GenerateClass(const ObjCImplementationDecl *ClassDecl) override;
- virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) {}
+ void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) override {}
- virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
- const ObjCProtocolDecl *PD);
+ llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
+ const ObjCProtocolDecl *PD) override;
- virtual llvm::Constant *GetPropertyGetFunction();
- virtual llvm::Constant *GetPropertySetFunction();
- virtual llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
- bool copy);
- virtual llvm::Constant *GetGetStructFunction();
- virtual llvm::Constant *GetSetStructFunction();
- virtual llvm::Constant *GetCppAtomicObjectGetFunction();
- virtual llvm::Constant *GetCppAtomicObjectSetFunction();
- virtual llvm::Constant *EnumerationMutationFunction();
+ llvm::Constant *GetPropertyGetFunction() override;
+ llvm::Constant *GetPropertySetFunction() override;
+ llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
+ bool copy) override;
+ llvm::Constant *GetGetStructFunction() override;
+ llvm::Constant *GetSetStructFunction() override;
+ llvm::Constant *GetCppAtomicObjectGetFunction() override;
+ llvm::Constant *GetCppAtomicObjectSetFunction() override;
+ llvm::Constant *EnumerationMutationFunction() override;
- virtual void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtTryStmt &S);
- virtual void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtSynchronizedStmt &S);
+ void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
+ const ObjCAtTryStmt &S) override;
+ void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
+ const ObjCAtSynchronizedStmt &S) override;
void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, const Stmt &S);
- virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S,
- bool ClearInsertionPoint=true);
- virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
- llvm::Value *AddrWeakObj);
- virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst);
- virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dest,
- bool threadlocal = false);
- virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dest,
- llvm::Value *ivarOffset);
- virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dest);
- virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *dest, llvm::Value *src,
- llvm::Value *size);
-
- virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
- QualType ObjectTy,
- llvm::Value *BaseValue,
- const ObjCIvarDecl *Ivar,
- unsigned CVRQualifiers);
- virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
- const ObjCInterfaceDecl *Interface,
- const ObjCIvarDecl *Ivar);
-
+ void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S,
+ bool ClearInsertionPoint=true) override;
+ llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *AddrWeakObj) override;
+ void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst) override;
+ void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest,
+ bool threadlocal = false) override;
+ void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest,
+ llvm::Value *ivarOffset) override;
+ void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest) override;
+ void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *dest, llvm::Value *src,
+ llvm::Value *size) override;
+
+ LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, QualType ObjectTy,
+ llvm::Value *BaseValue, const ObjCIvarDecl *Ivar,
+ unsigned CVRQualifiers) override;
+ llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *Interface,
+ const ObjCIvarDecl *Ivar) override;
+
/// GetClassGlobal - Return the global variable for the Objective-C
/// class of the given name.
- virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) {
+ llvm::GlobalVariable *GetClassGlobal(const std::string &Name,
+ bool Weak = false) override {
llvm_unreachable("CGObjCMac::GetClassGlobal");
}
};
@@ -1312,11 +1313,12 @@ private:
unsigned InstanceStart,
unsigned InstanceSize,
const ObjCImplementationDecl *ID);
- llvm::GlobalVariable * BuildClassMetaData(std::string &ClassName,
+ llvm::GlobalVariable * BuildClassMetaData(const std::string &ClassName,
llvm::Constant *IsAGV,
llvm::Constant *SuperClassGV,
llvm::Constant *ClassRoGV,
- bool HiddenVisibility);
+ bool HiddenVisibility,
+ bool Weak);
llvm::Constant *GetMethodConstant(const ObjCMethodDecl *MD);
@@ -1341,13 +1343,13 @@ private:
/// GetOrEmitProtocol - Get the protocol object for the given
/// declaration, emitting it if necessary. The return value has type
/// ProtocolPtrTy.
- virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD);
+ llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD) override;
/// GetOrEmitProtocolRef - Get a forward reference to the protocol
/// object for the given declaration, emitting it if needed. These
/// forward references will be filled in with empty bodies if no
/// definition is seen. The return value has type ProtocolPtrTy.
- virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD);
+ llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) override;
/// EmitProtocolList - Generate the list of referenced
/// protocols. The return value has type ProtocolListPtrTy.
@@ -1367,17 +1369,19 @@ private:
/// GetClassGlobal - Return the global variable for the Objective-C
/// class of the given name.
- llvm::GlobalVariable *GetClassGlobal(const std::string &Name);
-
+ llvm::GlobalVariable *GetClassGlobal(const std::string &Name,
+ bool Weak = false) override;
+
/// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given class reference.
llvm::Value *EmitClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
llvm::Value *EmitClassRefFromId(CodeGenFunction &CGF,
- IdentifierInfo *II);
-
- llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF);
+ IdentifierInfo *II, bool Weak,
+ const ObjCInterfaceDecl *ID);
+
+ llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) override;
/// EmitSuperClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given super class reference.
@@ -1387,7 +1391,7 @@ private:
/// EmitMetaClassRef - Return a Value * of the address of _class_t
/// meta-data
llvm::Value *EmitMetaClassRef(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID);
+ const ObjCInterfaceDecl *ID, bool Weak);
/// ObjCIvarOffsetVariable - Returns the ivar offset variable for
/// the given ivar.
@@ -1434,11 +1438,10 @@ private:
bool ImplementationIsNonLazy(const ObjCImplDecl *OD) const;
bool IsIvarOffsetKnownIdempotent(const CodeGen::CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *IV) {
- // Annotate the load as an invariant load iff the object type is the type,
- // or a derived type, of the class containing the ivar within an ObjC
- // method. This check is needed because the ivar offset is a lazily
+ // Annotate the load as an invariant load iff inside an instance method
+ // and ivar belongs to instance method's class and one of its super class.
+ // This check is needed because the ivar offset is a lazily
// initialised value that may depend on objc_msgSend to perform a fixup on
// the first message dispatch.
//
@@ -1446,128 +1449,122 @@ private:
// base of the ivar access is a parameter to an Objective C method.
// However, because the parameters are not available in the current
// interface, we cannot perform this check.
- if (CGF.CurFuncDecl && isa<ObjCMethodDecl>(CGF.CurFuncDecl))
- if (IV->getContainingInterface()->isSuperClassOf(ID))
- return true;
+ if (const ObjCMethodDecl *MD =
+ dyn_cast_or_null<ObjCMethodDecl>(CGF.CurFuncDecl))
+ if (MD->isInstanceMethod())
+ if (const ObjCInterfaceDecl *ID = MD->getClassInterface())
+ return IV->getContainingInterface()->isSuperClassOf(ID);
return false;
}
public:
CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm);
// FIXME. All stubs for now!
- virtual llvm::Function *ModuleInitFunction();
-
- virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel,
- llvm::Value *Receiver,
- const CallArgList &CallArgs,
- const ObjCInterfaceDecl *Class,
- const ObjCMethodDecl *Method);
-
- virtual CodeGen::RValue
+ llvm::Function *ModuleInitFunction() override;
+
+ CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
+ QualType ResultType, Selector Sel,
+ llvm::Value *Receiver,
+ const CallArgList &CallArgs,
+ const ObjCInterfaceDecl *Class,
+ const ObjCMethodDecl *Method) override;
+
+ CodeGen::RValue
GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel,
- const ObjCInterfaceDecl *Class,
- bool isCategoryImpl,
- llvm::Value *Receiver,
- bool IsClassMessage,
- const CallArgList &CallArgs,
- const ObjCMethodDecl *Method);
-
- virtual llvm::Value *GetClass(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID);
-
- virtual llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
- bool lvalue = false)
+ ReturnValueSlot Return, QualType ResultType,
+ Selector Sel, const ObjCInterfaceDecl *Class,
+ bool isCategoryImpl, llvm::Value *Receiver,
+ bool IsClassMessage, const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method) override;
+
+ llvm::Value *GetClass(CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *ID) override;
+
+ llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
+ bool lvalue = false) override
{ return EmitSelector(CGF, Sel, lvalue); }
/// The NeXT/Apple runtimes do not support typed selectors; just emit an
/// untyped one.
- virtual llvm::Value *GetSelector(CodeGenFunction &CGF,
- const ObjCMethodDecl *Method)
+ llvm::Value *GetSelector(CodeGenFunction &CGF,
+ const ObjCMethodDecl *Method) override
{ return EmitSelector(CGF, Method->getSelector()); }
- virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
+ void GenerateCategory(const ObjCCategoryImplDecl *CMD) override;
- virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
+ void GenerateClass(const ObjCImplementationDecl *ClassDecl) override;
- virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) {}
+ void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) override {}
- virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
- const ObjCProtocolDecl *PD);
+ llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
+ const ObjCProtocolDecl *PD) override;
- virtual llvm::Constant *GetEHType(QualType T);
+ llvm::Constant *GetEHType(QualType T) override;
- virtual llvm::Constant *GetPropertyGetFunction() {
+ llvm::Constant *GetPropertyGetFunction() override {
return ObjCTypes.getGetPropertyFn();
}
- virtual llvm::Constant *GetPropertySetFunction() {
+ llvm::Constant *GetPropertySetFunction() override {
return ObjCTypes.getSetPropertyFn();
}
-
- virtual llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
- bool copy) {
+
+ llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
+ bool copy) override {
return ObjCTypes.getOptimizedSetPropertyFn(atomic, copy);
}
-
- virtual llvm::Constant *GetSetStructFunction() {
+
+ llvm::Constant *GetSetStructFunction() override {
return ObjCTypes.getCopyStructFn();
}
- virtual llvm::Constant *GetGetStructFunction() {
+ llvm::Constant *GetGetStructFunction() override {
return ObjCTypes.getCopyStructFn();
}
- virtual llvm::Constant *GetCppAtomicObjectSetFunction() {
+ llvm::Constant *GetCppAtomicObjectSetFunction() override {
return ObjCTypes.getCppAtomicObjectFunction();
}
- virtual llvm::Constant *GetCppAtomicObjectGetFunction() {
+ llvm::Constant *GetCppAtomicObjectGetFunction() override {
return ObjCTypes.getCppAtomicObjectFunction();
}
-
- virtual llvm::Constant *EnumerationMutationFunction() {
+
+ llvm::Constant *EnumerationMutationFunction() override {
return ObjCTypes.getEnumerationMutationFn();
}
- virtual void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtTryStmt &S);
- virtual void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtSynchronizedStmt &S);
- virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S,
- bool ClearInsertionPoint=true);
- virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
- llvm::Value *AddrWeakObj);
- virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst);
- virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dest,
- bool threadlocal = false);
- virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dest,
- llvm::Value *ivarOffset);
- virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dest);
- virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *dest, llvm::Value *src,
- llvm::Value *size);
- virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
- QualType ObjectTy,
- llvm::Value *BaseValue,
- const ObjCIvarDecl *Ivar,
- unsigned CVRQualifiers);
- virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
- const ObjCInterfaceDecl *Interface,
- const ObjCIvarDecl *Ivar);
+ void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
+ const ObjCAtTryStmt &S) override;
+ void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
+ const ObjCAtSynchronizedStmt &S) override;
+ void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S,
+ bool ClearInsertionPoint=true) override;
+ llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *AddrWeakObj) override;
+ void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dst) override;
+ void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest,
+ bool threadlocal = false) override;
+ void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest,
+ llvm::Value *ivarOffset) override;
+ void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *src, llvm::Value *dest) override;
+ void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *dest, llvm::Value *src,
+ llvm::Value *size) override;
+ LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, QualType ObjectTy,
+ llvm::Value *BaseValue, const ObjCIvarDecl *Ivar,
+ unsigned CVRQualifiers) override;
+ llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *Interface,
+ const ObjCIvarDecl *Ivar) override;
};
/// A helper class for performing the null-initialization of a return
/// value.
struct NullReturnState {
llvm::BasicBlock *NullBB;
- NullReturnState() : NullBB(0) {}
+ NullReturnState() : NullBB(nullptr) {}
/// Perform a null-check of the given receiver.
void init(CodeGenFunction &CGF, llvm::Value *receiver) {
@@ -1596,8 +1593,8 @@ struct NullReturnState {
// The continuation block. This will be left null if we don't have an
// IP, which can happen if the method we're calling is marked noreturn.
- llvm::BasicBlock *contBB = 0;
-
+ llvm::BasicBlock *contBB = nullptr;
+
// Finish the call path.
llvm::BasicBlock *callBB = CGF.Builder.GetInsertBlock();
if (callBB) {
@@ -1878,14 +1875,14 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs);
if (Method)
- assert(CGM.getContext().getCanonicalType(Method->getResultType()) ==
- CGM.getContext().getCanonicalType(ResultType) &&
+ assert(CGM.getContext().getCanonicalType(Method->getReturnType()) ==
+ CGM.getContext().getCanonicalType(ResultType) &&
"Result type mismatch!");
NullReturnState nullReturn;
- llvm::Constant *Fn = NULL;
- if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) {
+ llvm::Constant *Fn = nullptr;
+ if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
if (!IsSuper) nullReturn.init(CGF, Arg0);
Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
: ObjCTypes.getSendStretFn(IsSuper);
@@ -1896,15 +1893,17 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFp2RetFn2(IsSuper)
: ObjCTypes.getSendFp2retFn(IsSuper);
} else {
+ // arm64 uses objc_msgSend for stret methods and yet null receiver check
+ // must be made for it.
+ if (!IsSuper && CGM.ReturnTypeUsesSRet(MSI.CallInfo))
+ nullReturn.init(CGF, Arg0);
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper)
: ObjCTypes.getSendFn(IsSuper);
}
bool requiresnullCheck = false;
if (CGM.getLangOpts().ObjCAutoRefCount && Method)
- for (ObjCMethodDecl::param_const_iterator i = Method->param_begin(),
- e = Method->param_end(); i != e; ++i) {
- const ParmVarDecl *ParamDecl = (*i);
+ for (const auto *ParamDecl : Method->params()) {
if (ParamDecl->hasAttr<NSConsumedAttr>()) {
if (!nullReturn.NullBB)
nullReturn.init(CGF, Arg0);
@@ -1916,7 +1915,7 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
Fn = llvm::ConstantExpr::getBitCast(Fn, MSI.MessengerType);
RValue rvalue = CGF.EmitCall(MSI.CallInfo, Fn, Return, ActualArgs);
return nullReturn.complete(CGF, rvalue, ResultType, CallArgs,
- requiresnullCheck ? Method : 0);
+ requiresnullCheck ? Method : nullptr);
}
static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) {
@@ -1967,9 +1966,8 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
// to be GC'ed.
// Walk the captured variables.
- for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(),
- ce = blockDecl->capture_end(); ci != ce; ++ci) {
- const VarDecl *variable = ci->getVariable();
+ for (const auto &CI : blockDecl->captures()) {
+ const VarDecl *variable = CI.getVariable();
QualType type = variable->getType();
const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
@@ -1980,7 +1978,7 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
uint64_t fieldOffset = layout->getElementOffset(capture.getIndex());
// __block variables are passed by their descriptor address.
- if (ci->isByRef()) {
+ if (CI.isByRef()) {
IvarsInfo.push_back(GC_IVAR(fieldOffset, /*size in words*/ 1));
continue;
}
@@ -2071,8 +2069,8 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
bool ByrefLayout) {
bool IsUnion = (RD && RD->isUnion());
CharUnits MaxUnionSize = CharUnits::Zero();
- const FieldDecl *MaxField = 0;
- const FieldDecl *LastFieldBitfieldOrUnnamed = 0;
+ const FieldDecl *MaxField = nullptr;
+ const FieldDecl *LastFieldBitfieldOrUnnamed = nullptr;
CharUnits MaxFieldOffset = CharUnits::Zero();
CharUnits LastBitfieldOrUnnamedOffset = CharUnits::Zero();
@@ -2094,8 +2092,8 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
LastBitfieldOrUnnamedOffset = FieldOffset;
continue;
}
-
- LastFieldBitfieldOrUnnamed = 0;
+
+ LastFieldBitfieldOrUnnamed = nullptr;
QualType FQT = Field->getType();
if (FQT->isRecordType() || FQT->isUnionType()) {
if (FQT->isUnionType())
@@ -2118,9 +2116,6 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
ElCount *= CArray->getSize().getZExtValue();
FQT = CArray->getElementType();
}
-
- assert(!FQT->isUnionType() &&
- "layout for array of unions not supported");
if (FQT->isRecordType() && ElCount) {
int OldIndex = RunSkipBlockVars.size() - 1;
const RecordType *RT = FQT->getAs<RecordType>();
@@ -2196,10 +2191,7 @@ void CGObjCCommonMac::BuildRCBlockVarRecordLayout(const RecordType *RT,
bool &HasUnion,
bool ByrefLayout) {
const RecordDecl *RD = RT->getDecl();
- SmallVector<const FieldDecl*, 16> Fields;
- for (RecordDecl::field_iterator i = RD->field_begin(),
- e = RD->field_end(); i != e; ++i)
- Fields.push_back(*i);
+ SmallVector<const FieldDecl*, 16> Fields(RD->fields());
llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0));
const llvm::StructLayout *RecLayout =
CGM.getDataLayout().getStructLayout(cast<llvm::StructType>(Ty));
@@ -2486,9 +2478,8 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
blockInfo.BlockHeaderForcedGapOffset,
blockInfo.BlockHeaderForcedGapSize);
// Walk the captured variables.
- for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(),
- ce = blockDecl->capture_end(); ci != ce; ++ci) {
- const VarDecl *variable = ci->getVariable();
+ for (const auto &CI : blockDecl->captures()) {
+ const VarDecl *variable = CI.getVariable();
QualType type = variable->getType();
const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
@@ -2500,17 +2491,17 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
CharUnits::fromQuantity(layout->getElementOffset(capture.getIndex()));
assert(!type->isArrayType() && "array variable should not be caught");
- if (!ci->isByRef())
+ if (!CI.isByRef())
if (const RecordType *record = type->getAs<RecordType>()) {
BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion);
continue;
}
CharUnits fieldSize;
- if (ci->isByRef())
+ if (CI.isByRef())
fieldSize = CharUnits::fromQuantity(WordSizeInBytes);
else
fieldSize = CGM.getContext().getTypeSizeInChars(type);
- UpdateRunSkipBlockVars(ci->isByRef(), getBlockCaptureLifetime(type, false),
+ UpdateRunSkipBlockVars(CI.isByRef(), getBlockCaptureLifetime(type, false),
fieldOffset, fieldSize);
}
return getBitmapBlockLayout(false);
@@ -2562,8 +2553,16 @@ llvm::Constant *CGObjCCommonMac::GetProtocolRef(const ObjCProtocolDecl *PD) {
return GetOrEmitProtocolRef(PD);
}
+static void assertPrivateName(const llvm::GlobalValue *GV) {
+ StringRef NameRef = GV->getName();
+ (void)NameRef;
+ assert(NameRef[0] == '\01' && (NameRef[1] == 'L' || NameRef[1] == 'l'));
+ assert(GV->getVisibility() == llvm::GlobalValue::DefaultVisibility);
+ assert(GV->hasPrivateLinkage());
+}
+
/*
-// APPLE LOCAL radar 4585769 - Objective-C 1.0 extensions
+// Objective-C 1.0 extensions
struct _objc_protocol {
struct _objc_protocol_extension *isa;
char *protocol_name;
@@ -2593,9 +2592,7 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
std::vector<llvm::Constant*> OptInstanceMethods, OptClassMethods;
std::vector<llvm::Constant*> MethodTypesExt, OptMethodTypesExt;
- for (ObjCProtocolDecl::instmeth_iterator
- i = PD->instmeth_begin(), e = PD->instmeth_end(); i != e; ++i) {
- ObjCMethodDecl *MD = *i;
+ for (const auto *MD : PD->instance_methods()) {
llvm::Constant *C = GetMethodDescriptionConstant(MD);
if (!C)
return GetOrEmitProtocolRef(PD);
@@ -2609,9 +2606,7 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
}
}
- for (ObjCProtocolDecl::classmeth_iterator
- i = PD->classmeth_begin(), e = PD->classmeth_end(); i != e; ++i) {
- ObjCMethodDecl *MD = *i;
+ for (const auto *MD : PD->class_methods()) {
llvm::Constant *C = GetMethodDescriptionConstant(MD);
if (!C)
return GetOrEmitProtocolRef(PD);
@@ -2631,7 +2626,7 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
llvm::Constant *Values[] = {
EmitProtocolExtension(PD, OptInstanceMethods, OptClassMethods,
MethodTypesExt),
- GetClassName(PD->getIdentifier()),
+ GetClassName(PD->getObjCRuntimeNameAsString()),
EmitProtocolList("\01L_OBJC_PROTOCOL_REFS_" + PD->getName(),
PD->protocol_begin(),
PD->protocol_end()),
@@ -2646,13 +2641,13 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
Values);
if (Entry) {
- // Already created, fix the linkage and update the initializer.
- Entry->setLinkage(llvm::GlobalValue::InternalLinkage);
+ // Already created, update the initializer.
+ assert(Entry->hasPrivateLinkage());
Entry->setInitializer(Init);
} else {
Entry =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy, false,
- llvm::GlobalValue::InternalLinkage,
+ llvm::GlobalValue::PrivateLinkage,
Init,
"\01L_OBJC_PROTOCOL_" + PD->getName());
Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
@@ -2661,7 +2656,8 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
Protocols[PD->getIdentifier()] = Entry;
}
- CGM.AddUsedGlobal(Entry);
+ assertPrivateName(Entry);
+ CGM.addCompilerUsedGlobal(Entry);
return Entry;
}
@@ -2675,13 +2671,14 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) {
// contents for protocols which were referenced but never defined.
Entry =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy, false,
- llvm::GlobalValue::ExternalLinkage,
- 0,
+ llvm::GlobalValue::PrivateLinkage,
+ nullptr,
"\01L_OBJC_PROTOCOL_" + PD->getName());
Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
// FIXME: Is this necessary? Why only for protocol?
Entry->setAlignment(4);
}
+ assertPrivateName(Entry);
return Entry;
}
@@ -2711,8 +2708,8 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD,
EmitMethodDescList("\01L_OBJC_PROTOCOL_CLASS_METHODS_OPT_" + PD->getName(),
"__OBJC,__cat_cls_meth,regular,no_dead_strip",
OptClassMethods),
- EmitPropertyList("\01L_OBJC_$_PROP_PROTO_LIST_" + PD->getName(), 0, PD,
- ObjCTypes),
+ EmitPropertyList("\01L_OBJC_$_PROP_PROTO_LIST_" + PD->getName(), nullptr,
+ PD, ObjCTypes),
EmitProtocolMethodTypes("\01L_OBJC_PROTOCOL_METHOD_TYPES_" + PD->getName(),
MethodTypesExt, ObjCTypes)
};
@@ -2726,9 +2723,8 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD,
llvm::ConstantStruct::get(ObjCTypes.ProtocolExtensionTy, Values);
// No special section, but goes in llvm.used
- return CreateMetadataVar("\01L_OBJC_PROTOCOLEXT_" + PD->getName(),
- Init,
- 0, 0, true);
+ return CreateMetadataVar("\01l_OBJC_PROTOCOLEXT_" + PD->getName(), Init,
+ StringRef(), 0, true);
}
/*
@@ -2775,14 +2771,11 @@ void CGObjCCommonMac::
PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*,16> &PropertySet,
SmallVectorImpl<llvm::Constant *> &Properties,
const Decl *Container,
- const ObjCProtocolDecl *PROTO,
+ const ObjCProtocolDecl *Proto,
const ObjCCommonTypesHelper &ObjCTypes) {
- for (ObjCProtocolDecl::protocol_iterator P = PROTO->protocol_begin(),
- E = PROTO->protocol_end(); P != E; ++P)
- PushProtocolProperties(PropertySet, Properties, Container, (*P), ObjCTypes);
- for (ObjCContainerDecl::prop_iterator I = PROTO->prop_begin(),
- E = PROTO->prop_end(); I != E; ++I) {
- const ObjCPropertyDecl *PD = *I;
+ for (const auto *P : Proto->protocols())
+ PushProtocolProperties(PropertySet, Properties, Container, P, ObjCTypes);
+ for (const auto *PD : Proto->properties()) {
if (!PropertySet.insert(PD->getIdentifier()))
continue;
llvm::Constant *Prop[] = {
@@ -2811,9 +2804,7 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
const ObjCCommonTypesHelper &ObjCTypes) {
SmallVector<llvm::Constant *, 16> Properties;
llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet;
- for (ObjCContainerDecl::prop_iterator I = OCD->prop_begin(),
- E = OCD->prop_end(); I != E; ++I) {
- const ObjCPropertyDecl *PD = *I;
+ for (const auto *PD : OCD->properties()) {
PropertySet.insert(PD->getIdentifier());
llvm::Constant *Prop[] = {
GetPropertyName(PD->getIdentifier()),
@@ -2823,17 +2814,12 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
Prop));
}
if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD)) {
- for (ObjCInterfaceDecl::all_protocol_iterator
- P = OID->all_referenced_protocol_begin(),
- E = OID->all_referenced_protocol_end(); P != E; ++P)
- PushProtocolProperties(PropertySet, Properties, Container, (*P),
- ObjCTypes);
+ for (const auto *P : OID->all_referenced_protocols())
+ PushProtocolProperties(PropertySet, Properties, Container, P, ObjCTypes);
}
else if (const ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(OCD)) {
- for (ObjCCategoryDecl::protocol_iterator P = CD->protocol_begin(),
- E = CD->protocol_end(); P != E; ++P)
- PushProtocolProperties(PropertySet, Properties, Container, (*P),
- ObjCTypes);
+ for (const auto *P : CD->protocols())
+ PushProtocolProperties(PropertySet, Properties, Container, P, ObjCTypes);
}
// Return null for empty list.
@@ -2871,11 +2857,9 @@ CGObjCCommonMac::EmitProtocolMethodTypes(Twine Name,
MethodTypes.size());
llvm::Constant *Init = llvm::ConstantArray::get(AT, MethodTypes);
- llvm::GlobalVariable *GV =
- CreateMetadataVar(Name, Init,
- (ObjCABI == 2) ? "__DATA, __objc_const" : 0,
- (ObjCABI == 2) ? 8 : 4,
- true);
+ llvm::GlobalVariable *GV = CreateMetadataVar(
+ Name, Init, (ObjCABI == 2) ? "__DATA, __objc_const" : StringRef(),
+ (ObjCABI == 2) ? 8 : 4, true);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.Int8PtrPtrTy);
}
@@ -2893,8 +2877,8 @@ CGObjCMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
GetMethodVarType(MD)
};
if (!Desc[1])
- return 0;
-
+ return nullptr;
+
return llvm::ConstantStruct::get(ObjCTypes.MethodDescriptionTy,
Desc);
}
@@ -2945,20 +2929,17 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
<< OCD->getName();
SmallVector<llvm::Constant *, 16> InstanceMethods, ClassMethods;
- for (ObjCCategoryImplDecl::instmeth_iterator
- i = OCD->instmeth_begin(), e = OCD->instmeth_end(); i != e; ++i) {
+ for (const auto *I : OCD->instance_methods())
// Instance methods should always be defined.
- InstanceMethods.push_back(GetMethodConstant(*i));
- }
- for (ObjCCategoryImplDecl::classmeth_iterator
- i = OCD->classmeth_begin(), e = OCD->classmeth_end(); i != e; ++i) {
+ InstanceMethods.push_back(GetMethodConstant(I));
+
+ for (const auto *I : OCD->class_methods())
// Class methods should always be defined.
- ClassMethods.push_back(GetMethodConstant(*i));
- }
+ ClassMethods.push_back(GetMethodConstant(I));
llvm::Constant *Values[7];
- Values[0] = GetClassName(OCD->getIdentifier());
- Values[1] = GetClassName(Interface->getIdentifier());
+ Values[0] = GetClassName(OCD->getName());
+ Values[1] = GetClassName(Interface->getObjCRuntimeNameAsString());
LazySymbols.insert(Interface->getIdentifier());
Values[2] =
EmitMethodList("\01L_OBJC_CATEGORY_INSTANCE_METHODS_" + ExtName.str(),
@@ -3073,21 +3054,15 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
Flags |= FragileABI_Class_Hidden;
SmallVector<llvm::Constant *, 16> InstanceMethods, ClassMethods;
- for (ObjCImplementationDecl::instmeth_iterator
- i = ID->instmeth_begin(), e = ID->instmeth_end(); i != e; ++i) {
+ for (const auto *I : ID->instance_methods())
// Instance methods should always be defined.
- InstanceMethods.push_back(GetMethodConstant(*i));
- }
- for (ObjCImplementationDecl::classmeth_iterator
- i = ID->classmeth_begin(), e = ID->classmeth_end(); i != e; ++i) {
- // Class methods should always be defined.
- ClassMethods.push_back(GetMethodConstant(*i));
- }
+ InstanceMethods.push_back(GetMethodConstant(I));
- for (ObjCImplementationDecl::propimpl_iterator
- i = ID->propimpl_begin(), e = ID->propimpl_end(); i != e; ++i) {
- ObjCPropertyImplDecl *PID = *i;
+ for (const auto *I : ID->class_methods())
+ // Class methods should always be defined.
+ ClassMethods.push_back(GetMethodConstant(I));
+ for (const auto *PID : ID->property_impls()) {
if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
ObjCPropertyDecl *PD = PID->getPropertyDecl();
@@ -3107,12 +3082,12 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
LazySymbols.insert(Super->getIdentifier());
Values[ 1] =
- llvm::ConstantExpr::getBitCast(GetClassName(Super->getIdentifier()),
+ llvm::ConstantExpr::getBitCast(GetClassName(Super->getObjCRuntimeNameAsString()),
ObjCTypes.ClassPtrTy);
} else {
Values[ 1] = llvm::Constant::getNullValue(ObjCTypes.ClassPtrTy);
}
- Values[ 2] = GetClassName(ID->getIdentifier());
+ Values[ 2] = GetClassName(ID->getObjCRuntimeNameAsString());
// Version is always 0.
Values[ 3] = llvm::ConstantInt::get(ObjCTypes.LongTy, 0);
Values[ 4] = llvm::ConstantInt::get(ObjCTypes.LongTy, Flags);
@@ -3133,19 +3108,19 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
Name += ClassName;
const char *Section = "__OBJC,__class,regular,no_dead_strip";
// Check for a forward reference.
- llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
+ llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
if (GV) {
assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
"Forward metaclass reference has incorrect type.");
- GV->setLinkage(llvm::GlobalValue::InternalLinkage);
GV->setInitializer(Init);
GV->setSection(Section);
GV->setAlignment(4);
- CGM.AddUsedGlobal(GV);
- }
- else
+ CGM.addCompilerUsedGlobal(GV);
+ } else
GV = CreateMetadataVar(Name, Init, Section, 4, true);
+ assertPrivateName(GV);
DefinedClasses.push_back(GV);
+ ImplementedClasses.push_back(Interface);
// method definition entries must be clear for next implementation.
MethodDefinitions.clear();
}
@@ -3165,19 +3140,19 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
while (const ObjCInterfaceDecl *Super = Root->getSuperClass())
Root = Super;
Values[ 0] =
- llvm::ConstantExpr::getBitCast(GetClassName(Root->getIdentifier()),
+ llvm::ConstantExpr::getBitCast(GetClassName(Root->getObjCRuntimeNameAsString()),
ObjCTypes.ClassPtrTy);
// The super class for the metaclass is emitted as the name of the
// super class. The runtime fixes this up to point to the
// *metaclass* for the super class.
if (ObjCInterfaceDecl *Super = ID->getClassInterface()->getSuperClass()) {
Values[ 1] =
- llvm::ConstantExpr::getBitCast(GetClassName(Super->getIdentifier()),
+ llvm::ConstantExpr::getBitCast(GetClassName(Super->getObjCRuntimeNameAsString()),
ObjCTypes.ClassPtrTy);
} else {
Values[ 1] = llvm::Constant::getNullValue(ObjCTypes.ClassPtrTy);
}
- Values[ 2] = GetClassName(ID->getIdentifier());
+ Values[ 2] = GetClassName(ID->getObjCRuntimeNameAsString());
// Version is always 0.
Values[ 3] = llvm::ConstantInt::get(ObjCTypes.LongTy, 0);
Values[ 4] = llvm::ConstantInt::get(ObjCTypes.LongTy, Flags);
@@ -3201,20 +3176,20 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
Name += ID->getName();
// Check for a forward reference.
- llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
+ llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
if (GV) {
assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
"Forward metaclass reference has incorrect type.");
- GV->setLinkage(llvm::GlobalValue::InternalLinkage);
GV->setInitializer(Init);
} else {
GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false,
- llvm::GlobalValue::InternalLinkage,
+ llvm::GlobalValue::PrivateLinkage,
Init, Name);
}
+ assertPrivateName(GV);
GV->setSection("__OBJC,__meta_class,regular,no_dead_strip");
GV->setAlignment(4);
- CGM.AddUsedGlobal(GV);
+ CGM.addCompilerUsedGlobal(GV);
return GV;
}
@@ -3230,35 +3205,31 @@ llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) {
// Check for an existing forward reference.
// Previously, metaclass with internal linkage may have been defined.
// pass 'true' as 2nd argument so it is returned.
- if (llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name,
- true)) {
- assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
- "Forward metaclass reference has incorrect type.");
- return GV;
- } else {
- // Generate as an external reference to keep a consistent
- // module. This will be patched up when we emit the metaclass.
- return new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false,
- llvm::GlobalValue::ExternalLinkage,
- 0,
- Name);
- }
+ llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
+ if (!GV)
+ GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false,
+ llvm::GlobalValue::PrivateLinkage, nullptr,
+ Name);
+
+ assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
+ "Forward metaclass reference has incorrect type.");
+ assertPrivateName(GV);
+ return GV;
}
llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) {
std::string Name = "\01L_OBJC_CLASS_" + ID->getNameAsString();
-
- if (llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name,
- true)) {
- assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
- "Forward class metadata reference has incorrect type.");
- return GV;
- } else {
- return new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false,
- llvm::GlobalValue::ExternalLinkage,
- 0,
- Name);
- }
+ llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, true);
+
+ if (!GV)
+ GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false,
+ llvm::GlobalValue::PrivateLinkage, nullptr,
+ Name);
+
+ assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
+ "Forward class metadata reference has incorrect type.");
+ assertPrivateName(GV);
+ return GV;
}
/*
@@ -3373,7 +3344,7 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
llvm::Constant *CGObjCMac::GetMethodConstant(const ObjCMethodDecl *MD) {
llvm::Function *Fn = GetMethodDefinition(MD);
if (!Fn)
- return 0;
+ return nullptr;
llvm::Constant *Method[] = {
llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
@@ -3421,29 +3392,29 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
return Method;
}
-llvm::GlobalVariable *
-CGObjCCommonMac::CreateMetadataVar(Twine Name,
- llvm::Constant *Init,
- const char *Section,
- unsigned Align,
- bool AddToUsed) {
+llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name,
+ llvm::Constant *Init,
+ StringRef Section,
+ unsigned Align,
+ bool AddToUsed) {
llvm::Type *Ty = Init->getType();
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Ty, false,
- llvm::GlobalValue::InternalLinkage, Init, Name);
- if (Section)
+ llvm::GlobalValue::PrivateLinkage, Init, Name);
+ assertPrivateName(GV);
+ if (!Section.empty())
GV->setSection(Section);
if (Align)
GV->setAlignment(Align);
if (AddToUsed)
- CGM.AddUsedGlobal(GV);
+ CGM.addCompilerUsedGlobal(GV);
return GV;
}
llvm::Function *CGObjCMac::ModuleInitFunction() {
// Abuse this interface function as a place to finalize.
FinishModule();
- return NULL;
+ return nullptr;
}
llvm::Constant *CGObjCMac::GetPropertyGetFunction() {
@@ -3501,7 +3472,7 @@ namespace {
: S(*S), SyncArgSlot(SyncArgSlot), CallTryExitVar(CallTryExitVar),
ExceptionData(ExceptionData), ObjCTypes(*ObjCTypes) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
// Check whether we need to call objc_exception_try_exit.
// In optimized code, this branch will always be folded.
llvm::BasicBlock *FinallyCallExit =
@@ -3826,7 +3797,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// @synchronized. We can't avoid a temp here because we need the
// value to be preserved. If the backend ever does liveness
// correctly after setjmp, this will be unnecessary.
- llvm::Value *SyncArgSlot = 0;
+ llvm::Value *SyncArgSlot = nullptr;
if (!isTry) {
llvm::Value *SyncArg =
CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
@@ -3861,7 +3832,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// A slot containing the exception to rethrow. Only needed when we
// have both a @catch and a @finally.
- llvm::Value *PropagatingExnVar = 0;
+ llvm::Value *PropagatingExnVar = nullptr;
// Push a normal cleanup to leave the try scope.
CGF.EHStack.pushCleanup<PerformFragileFinally>(NormalAndEHCleanup, &S,
@@ -3927,10 +3898,10 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtTryStmt* AtTryStmt = cast<ObjCAtTryStmt>(&S);
- bool HasFinally = (AtTryStmt->getFinallyStmt() != 0);
+ bool HasFinally = (AtTryStmt->getFinallyStmt() != nullptr);
- llvm::BasicBlock *CatchBlock = 0;
- llvm::BasicBlock *CatchHandler = 0;
+ llvm::BasicBlock *CatchBlock = nullptr;
+ llvm::BasicBlock *CatchHandler = nullptr;
if (HasFinally) {
// Save the currently-propagating exception before
// objc_exception_try_enter clears the exception slot.
@@ -3968,7 +3939,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtCatchStmt *CatchStmt = AtTryStmt->getCatchStmt(I);
const VarDecl *CatchParam = CatchStmt->getCatchParamDecl();
- const ObjCObjectPointerType *OPT = 0;
+ const ObjCObjectPointerType *OPT = nullptr;
// catch(...) always matches.
if (!CatchParam) {
@@ -4293,14 +4264,14 @@ llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
/// unsigned flags;
/// };
enum ImageInfoFlags {
- eImageInfo_FixAndContinue = (1 << 0),
+ eImageInfo_FixAndContinue = (1 << 0), // This flag is no longer set by clang.
eImageInfo_GarbageCollected = (1 << 1),
eImageInfo_GCOnly = (1 << 2),
- eImageInfo_OptimizedByDyld = (1 << 3), // FIXME: When is this set.
+ eImageInfo_OptimizedByDyld = (1 << 3), // This flag is set by the dyld shared cache.
// A flag indicating that the module has no instances of a @synthesize of a
// superclass variable. <rdar://problem/6803242>
- eImageInfo_CorrectedSynthesize = (1 << 4),
+ eImageInfo_CorrectedSynthesize = (1 << 4), // This flag is no longer set by clang.
eImageInfo_ImageIsSimulated = (1 << 5)
};
@@ -4373,7 +4344,7 @@ void CGObjCMac::EmitModuleInfo() {
llvm::ConstantInt::get(ObjCTypes.LongTy, ModuleVersion),
llvm::ConstantInt::get(ObjCTypes.LongTy, Size),
// This used to be the filename, now it is unused. <rdr://4327263>
- GetClassName(&CGM.getContext().Idents.get("")),
+ GetClassName(StringRef("")),
EmitModuleSymbols()
};
CreateMetadataVar("\01L_OBJC_MODULES",
@@ -4399,9 +4370,17 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() {
// The runtime expects exactly the list of defined classes followed
// by the list of defined categories, in a single array.
SmallVector<llvm::Constant*, 8> Symbols(NumClasses + NumCategories);
- for (unsigned i=0; i<NumClasses; i++)
+ for (unsigned i=0; i<NumClasses; i++) {
+ const ObjCInterfaceDecl *ID = ImplementedClasses[i];
+ assert(ID);
+ if (ObjCImplementationDecl *IMP = ID->getImplementation())
+ // We are implementing a weak imported interface. Give it external linkage
+ if (ID->isWeakImported() && !IMP->isWeakImported())
+ DefinedClasses[i]->setLinkage(llvm::GlobalVariable::ExternalLinkage);
+
Symbols[i] = llvm::ConstantExpr::getBitCast(DefinedClasses[i],
ObjCTypes.Int8PtrTy);
+ }
for (unsigned i=0; i<NumCategories; i++)
Symbols[NumClasses + i] =
llvm::ConstantExpr::getBitCast(DefinedCategories[i],
@@ -4429,7 +4408,7 @@ llvm::Value *CGObjCMac::EmitClassRefFromId(CodeGenFunction &CGF,
if (!Entry) {
llvm::Constant *Casted =
- llvm::ConstantExpr::getBitCast(GetClassName(II),
+ llvm::ConstantExpr::getBitCast(GetClassName(II->getName()),
ObjCTypes.ClassPtrTy);
Entry =
CreateMetadataVar("\01L_OBJC_CLASS_REFERENCES_", Casted,
@@ -4470,19 +4449,17 @@ llvm::Value *CGObjCMac::EmitSelector(CodeGenFunction &CGF, Selector Sel,
return CGF.Builder.CreateLoad(Entry);
}
-llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) {
- llvm::GlobalVariable *&Entry = ClassNames[Ident];
-
- if (!Entry)
- Entry = CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
- llvm::ConstantDataArray::getString(VMContext,
- Ident->getNameStart()),
- ((ObjCABI == 2) ?
- "__TEXT,__objc_classname,cstring_literals" :
- "__TEXT,__cstring,cstring_literals"),
- 1, true);
-
- return getConstantGEP(VMContext, Entry, 0, 0);
+llvm::Constant *CGObjCCommonMac::GetClassName(StringRef RuntimeName) {
+ llvm::GlobalVariable *&Entry = ClassNames[RuntimeName];
+ if (!Entry)
+ Entry = CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
+ llvm::ConstantDataArray::getString(VMContext,
+ RuntimeName),
+ ((ObjCABI == 2) ?
+ "__TEXT,__objc_classname,cstring_literals" :
+ "__TEXT,__cstring,cstring_literals"),
+ 1, true);
+ return getConstantGEP(VMContext, Entry, 0, 0);
}
llvm::Function *CGObjCCommonMac::GetMethodDefinition(const ObjCMethodDecl *MD) {
@@ -4491,7 +4468,7 @@ llvm::Function *CGObjCCommonMac::GetMethodDefinition(const ObjCMethodDecl *MD) {
if (I != MethodDefinitions.end())
return I->second;
- return NULL;
+ return nullptr;
}
/// GetIvarLayoutName - Returns a unique constant for the given
@@ -4507,16 +4484,13 @@ void CGObjCCommonMac::BuildAggrIvarRecordLayout(const RecordType *RT,
bool &HasUnion) {
const RecordDecl *RD = RT->getDecl();
// FIXME - Use iterator.
- SmallVector<const FieldDecl*, 16> Fields;
- for (RecordDecl::field_iterator i = RD->field_begin(),
- e = RD->field_end(); i != e; ++i)
- Fields.push_back(*i);
+ SmallVector<const FieldDecl*, 16> Fields(RD->fields());
llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0));
const llvm::StructLayout *RecLayout =
CGM.getDataLayout().getStructLayout(cast<llvm::StructType>(Ty));
- BuildAggrIvarLayout(0, RecLayout, RD, Fields, BytePos,
- ForStrongLayout, HasUnion);
+ BuildAggrIvarLayout(nullptr, RecLayout, RD, Fields, BytePos, ForStrongLayout,
+ HasUnion);
}
void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
@@ -4528,9 +4502,9 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
bool IsUnion = (RD && RD->isUnion());
uint64_t MaxUnionIvarSize = 0;
uint64_t MaxSkippedUnionIvarSize = 0;
- const FieldDecl *MaxField = 0;
- const FieldDecl *MaxSkippedField = 0;
- const FieldDecl *LastFieldBitfieldOrUnnamed = 0;
+ const FieldDecl *MaxField = nullptr;
+ const FieldDecl *MaxSkippedField = nullptr;
+ const FieldDecl *LastFieldBitfieldOrUnnamed = nullptr;
uint64_t MaxFieldOffset = 0;
uint64_t MaxSkippedFieldOffset = 0;
uint64_t LastBitfieldOrUnnamedOffset = 0;
@@ -4565,7 +4539,7 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
continue;
}
- LastFieldBitfieldOrUnnamed = 0;
+ LastFieldBitfieldOrUnnamed = nullptr;
QualType FQT = Field->getType();
if (FQT->isRecordType() || FQT->isUnionType()) {
if (FQT->isUnionType())
@@ -4589,9 +4563,6 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
ElCount *= CArray->getSize().getZExtValue();
FQT = CArray->getElementType();
}
-
- assert(!FQT->isUnionType() &&
- "layout for array of unions not supported");
if (FQT->isRecordType() && ElCount) {
int OldIndex = IvarsInfo.size() - 1;
int OldSkIndex = SkipIvars.size() -1;
@@ -4859,7 +4830,8 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
SkipIvars.clear();
IvarsInfo.clear();
- BuildAggrIvarLayout(OMD, 0, 0, RecFields, 0, ForStrongLayout, hasUnion);
+ BuildAggrIvarLayout(OMD, nullptr, nullptr, RecFields, 0, ForStrongLayout,
+ hasUnion);
if (IvarsInfo.empty())
return llvm::Constant::getNullValue(PtrTy);
// Sort on byte position in case we encounterred a union nested in
@@ -4875,7 +4847,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
if (CGM.getLangOpts().ObjCGCBitmapPrint) {
printf("\n%s ivar layout for class '%s': ",
ForStrongLayout ? "strong" : "weak",
- OMD->getClassInterface()->getName().data());
+ OMD->getClassInterface()->getName().str().c_str());
const unsigned char *s = (const unsigned char*)BitMap.c_str();
for (unsigned i = 0, e = BitMap.size(); i < e; i++)
if (!(s[i] & 0xf0))
@@ -4928,7 +4900,7 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D,
bool Extended) {
std::string TypeStr;
if (CGM.getContext().getObjCEncodingForMethodDecl(D, TypeStr, Extended))
- return 0;
+ return nullptr;
llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr];
@@ -4948,11 +4920,10 @@ llvm::Constant *CGObjCCommonMac::GetPropertyName(IdentifierInfo *Ident) {
llvm::GlobalVariable *&Entry = PropertyNames[Ident];
if (!Entry)
- Entry = CreateMetadataVar("\01L_OBJC_PROP_NAME_ATTR_",
- llvm::ConstantDataArray::getString(VMContext,
- Ident->getNameStart()),
- "__TEXT,__cstring,cstring_literals",
- 1, true);
+ Entry = CreateMetadataVar(
+ "\01L_OBJC_PROP_NAME_ATTR_",
+ llvm::ConstantDataArray::getString(VMContext, Ident->getName()),
+ "__TEXT,__cstring,cstring_literals", 1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
@@ -4992,14 +4963,14 @@ void CGObjCMac::FinishModule() {
llvm::Constant *Values[5];
Values[0] = llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy);
- Values[1] = GetClassName(I->first);
+ Values[1] = GetClassName(I->first->getName());
Values[2] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy);
Values[3] = Values[4] =
llvm::Constant::getNullValue(ObjCTypes.MethodDescriptionListPtrTy);
- I->second->setLinkage(llvm::GlobalValue::InternalLinkage);
+ assertPrivateName(I->second);
I->second->setInitializer(llvm::ConstantStruct::get(ObjCTypes.ProtocolTy,
Values));
- CGM.AddUsedGlobal(I->second);
+ CGM.addCompilerUsedGlobal(I->second);
}
// Add assembler directives to add lazy undefined symbol references
@@ -5035,14 +5006,14 @@ void CGObjCMac::FinishModule() {
CGObjCNonFragileABIMac::CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm)
: CGObjCCommonMac(cgm),
ObjCTypes(cgm) {
- ObjCEmptyCacheVar = ObjCEmptyVtableVar = NULL;
+ ObjCEmptyCacheVar = ObjCEmptyVtableVar = nullptr;
ObjCABI = 2;
}
/* *** */
ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
- : VMContext(cgm.getLLVMContext()), CGM(cgm), ExternalProtocolPtrTy(0)
+ : VMContext(cgm.getLLVMContext()), CGM(cgm), ExternalProtocolPtrTy(nullptr)
{
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
@@ -5054,6 +5025,14 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
Int8PtrTy = CGM.Int8PtrTy;
Int8PtrPtrTy = CGM.Int8PtrPtrTy;
+ // arm64 targets use "int" ivar offset variables. All others,
+ // including OS X x86_64 and Windows x86_64, use "long" ivar offsets.
+ if (CGM.getTarget().getTriple().getArch() == llvm::Triple::arm64 ||
+ CGM.getTarget().getTriple().getArch() == llvm::Triple::aarch64)
+ IvarOffsetVarTy = IntTy;
+ else
+ IvarOffsetVarTy = LongTy;
+
ObjectPtrTy = Types.ConvertType(Ctx.getObjCIdType());
PtrObjectPtrTy = llvm::PointerType::getUnqual(ObjectPtrTy);
SelectorPtrTy = Types.ConvertType(Ctx.getObjCSelType());
@@ -5074,11 +5053,12 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
Ctx.getTranslationUnitDecl(),
SourceLocation(), SourceLocation(),
&Ctx.Idents.get("_objc_super"));
- RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
- Ctx.getObjCIdType(), 0, 0, false, ICIS_NoInit));
- RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
- Ctx.getObjCClassType(), 0, 0, false,
- ICIS_NoInit));
+ RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(),
+ nullptr, Ctx.getObjCIdType(), nullptr, nullptr,
+ false, ICIS_NoInit));
+ RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(),
+ nullptr, Ctx.getObjCClassType(), nullptr,
+ nullptr, false, ICIS_NoInit));
RD->completeDefinition();
SuperCTy = Ctx.getTagDeclType(RD);
@@ -5357,16 +5337,15 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
ProtocolListnfABIPtrTy = llvm::PointerType::getUnqual(ProtocolListnfABITy);
// struct _ivar_t {
- // unsigned long int *offset; // pointer to ivar offset location
+ // unsigned [long] int *offset; // pointer to ivar offset location
// char *name;
// char *type;
// uint32_t alignment;
// uint32_t size;
// }
- IvarnfABITy =
- llvm::StructType::create("struct._ivar_t",
- llvm::PointerType::getUnqual(LongTy),
- Int8PtrTy, Int8PtrTy, IntTy, IntTy, NULL);
+ IvarnfABITy = llvm::StructType::create(
+ "struct._ivar_t", llvm::PointerType::getUnqual(IvarOffsetVarTy),
+ Int8PtrTy, Int8PtrTy, IntTy, IntTy, NULL);
// struct _ivar_list_t {
// uint32 entsize; // sizeof(struct _ivar_t)
@@ -5456,11 +5435,12 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
Ctx.getTranslationUnitDecl(),
SourceLocation(), SourceLocation(),
&Ctx.Idents.get("_message_ref_t"));
- RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
- Ctx.VoidPtrTy, 0, 0, false, ICIS_NoInit));
- RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
- Ctx.getObjCSelType(), 0, 0, false,
+ RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(),
+ nullptr, Ctx.VoidPtrTy, nullptr, nullptr, false,
ICIS_NoInit));
+ RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(),
+ nullptr, Ctx.getObjCSelType(), nullptr, nullptr,
+ false, ICIS_NoInit));
RD->completeDefinition();
MessageRefCTy = Ctx.getTagDeclType(RD);
@@ -5498,7 +5478,7 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
llvm::Function *CGObjCNonFragileABIMac::ModuleInitFunction() {
FinishNonFragileABIModule();
- return NULL;
+ return nullptr;
}
void CGObjCNonFragileABIMac::
@@ -5521,12 +5501,13 @@ AddModuleClassList(ArrayRef<llvm::GlobalValue*> Container,
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
- llvm::GlobalValue::InternalLinkage,
+ llvm::GlobalValue::PrivateLinkage,
Init,
SymbolName);
+ assertPrivateName(GV);
GV->setAlignment(CGM.getDataLayout().getABITypeAlignment(Init->getType()));
GV->setSection(SectionName);
- CGM.AddUsedGlobal(GV);
+ CGM.addCompilerUsedGlobal(GV);
}
void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
@@ -5534,24 +5515,22 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
// Build list of all implemented class addresses in array
// L_OBJC_LABEL_CLASS_$.
+
+ for (unsigned i=0, NumClasses=ImplementedClasses.size(); i<NumClasses; i++) {
+ const ObjCInterfaceDecl *ID = ImplementedClasses[i];
+ assert(ID);
+ if (ObjCImplementationDecl *IMP = ID->getImplementation())
+ // We are implementing a weak imported interface. Give it external linkage
+ if (ID->isWeakImported() && !IMP->isWeakImported()) {
+ DefinedClasses[i]->setLinkage(llvm::GlobalVariable::ExternalLinkage);
+ DefinedMetaClasses[i]->setLinkage(llvm::GlobalVariable::ExternalLinkage);
+ }
+ }
+
AddModuleClassList(DefinedClasses,
"\01L_OBJC_LABEL_CLASS_$",
"__DATA, __objc_classlist, regular, no_dead_strip");
-
- for (unsigned i = 0, e = DefinedClasses.size(); i < e; i++) {
- llvm::GlobalValue *IMPLGV = DefinedClasses[i];
- if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage)
- continue;
- IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage);
- }
-
- for (unsigned i = 0, e = DefinedMetaClasses.size(); i < e; i++) {
- llvm::GlobalValue *IMPLGV = DefinedMetaClasses[i];
- if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage)
- continue;
- IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage);
- }
-
+
AddModuleClassList(DefinedNonLazyClasses,
"\01L_OBJC_LABEL_NONLAZY_CLASS_$",
"__DATA, __objc_nlclslist, regular, no_dead_strip");
@@ -5650,7 +5629,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
unsigned InstanceStart,
unsigned InstanceSize,
const ObjCImplementationDecl *ID) {
- std::string ClassName = ID->getNameAsString();
+ std::string ClassName = ID->getObjCRuntimeNameAsString();
llvm::Constant *Values[10]; // 11 for 64bit targets!
if (CGM.getLangOpts().ObjCAutoRefCount)
@@ -5661,30 +5640,26 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
Values[ 2] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceSize);
// FIXME. For 64bit targets add 0 here.
Values[ 3] = (flags & NonFragileABI_Class_Meta)
- ? GetIvarLayoutName(0, ObjCTypes)
+ ? GetIvarLayoutName(nullptr, ObjCTypes)
: BuildIvarLayout(ID, true);
- Values[ 4] = GetClassName(ID->getIdentifier());
+ Values[ 4] = GetClassName(ID->getObjCRuntimeNameAsString());
// const struct _method_list_t * const baseMethods;
std::vector<llvm::Constant*> Methods;
std::string MethodListName("\01l_OBJC_$_");
if (flags & NonFragileABI_Class_Meta) {
- MethodListName += "CLASS_METHODS_" + ID->getNameAsString();
- for (ObjCImplementationDecl::classmeth_iterator
- i = ID->classmeth_begin(), e = ID->classmeth_end(); i != e; ++i) {
+ MethodListName += "CLASS_METHODS_";
+ MethodListName += ID->getObjCRuntimeNameAsString();
+ for (const auto *I : ID->class_methods())
// Class methods should always be defined.
- Methods.push_back(GetMethodConstant(*i));
- }
+ Methods.push_back(GetMethodConstant(I));
} else {
- MethodListName += "INSTANCE_METHODS_" + ID->getNameAsString();
- for (ObjCImplementationDecl::instmeth_iterator
- i = ID->instmeth_begin(), e = ID->instmeth_end(); i != e; ++i) {
+ MethodListName += "INSTANCE_METHODS_";
+ MethodListName += ID->getObjCRuntimeNameAsString();
+ for (const auto *I : ID->instance_methods())
// Instance methods should always be defined.
- Methods.push_back(GetMethodConstant(*i));
- }
- for (ObjCImplementationDecl::propimpl_iterator
- i = ID->propimpl_begin(), e = ID->propimpl_end(); i != e; ++i) {
- ObjCPropertyImplDecl *PID = *i;
+ Methods.push_back(GetMethodConstant(I));
+ for (const auto *PID : ID->property_impls()) {
if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize){
ObjCPropertyDecl *PD = PID->getPropertyDecl();
@@ -5703,29 +5678,30 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
const ObjCInterfaceDecl *OID = ID->getClassInterface();
assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer");
Values[ 6] = EmitProtocolList("\01l_OBJC_CLASS_PROTOCOLS_$_"
- + OID->getName(),
+ + OID->getObjCRuntimeNameAsString(),
OID->all_referenced_protocol_begin(),
OID->all_referenced_protocol_end());
if (flags & NonFragileABI_Class_Meta) {
Values[ 7] = llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy);
- Values[ 8] = GetIvarLayoutName(0, ObjCTypes);
+ Values[ 8] = GetIvarLayoutName(nullptr, ObjCTypes);
Values[ 9] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
} else {
Values[ 7] = EmitIvarList(ID);
Values[ 8] = BuildIvarLayout(ID, false);
- Values[ 9] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getName(),
+ Values[ 9] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getObjCRuntimeNameAsString(),
ID, ID->getClassInterface(), ObjCTypes);
}
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassRonfABITy,
Values);
llvm::GlobalVariable *CLASS_RO_GV =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassRonfABITy, false,
- llvm::GlobalValue::InternalLinkage,
+ llvm::GlobalValue::PrivateLinkage,
Init,
(flags & NonFragileABI_Class_Meta) ?
std::string("\01l_OBJC_METACLASS_RO_$_")+ClassName :
std::string("\01l_OBJC_CLASS_RO_$_")+ClassName);
+ assertPrivateName(CLASS_RO_GV);
CLASS_RO_GV->setAlignment(
CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassRonfABITy));
CLASS_RO_GV->setSection("__DATA, __objc_const");
@@ -5743,12 +5719,9 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
/// struct class_ro_t *ro;
/// }
///
-llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData(
- std::string &ClassName,
- llvm::Constant *IsAGV,
- llvm::Constant *SuperClassGV,
- llvm::Constant *ClassRoGV,
- bool HiddenVisibility) {
+llvm::GlobalVariable *CGObjCNonFragileABIMac::BuildClassMetaData(
+ const std::string &ClassName, llvm::Constant *IsAGV, llvm::Constant *SuperClassGV,
+ llvm::Constant *ClassRoGV, bool HiddenVisibility, bool Weak) {
llvm::Constant *Values[] = {
IsAGV,
SuperClassGV,
@@ -5763,7 +5736,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData(
llvm::PointerType::getUnqual(ObjCTypes.ImpnfABITy));
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassnfABITy,
Values);
- llvm::GlobalVariable *GV = GetClassGlobal(ClassName);
+ llvm::GlobalVariable *GV = GetClassGlobal(ClassName, Weak);
GV->setInitializer(Init);
GV->setSection("__DATA, __objc_data");
GV->setAlignment(
@@ -5775,7 +5748,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData(
bool
CGObjCNonFragileABIMac::ImplementationIsNonLazy(const ObjCImplDecl *OD) const {
- return OD->getClassMethod(GetNullarySelector("load")) != 0;
+ return OD->getClassMethod(GetNullarySelector("load")) != nullptr;
}
void CGObjCNonFragileABIMac::GetClassSizeInfo(const ObjCImplementationDecl *OID,
@@ -5795,29 +5768,29 @@ void CGObjCNonFragileABIMac::GetClassSizeInfo(const ObjCImplementationDecl *OID,
}
void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
- std::string ClassName = ID->getNameAsString();
+ std::string ClassName = ID->getObjCRuntimeNameAsString();
if (!ObjCEmptyCacheVar) {
ObjCEmptyCacheVar = new llvm::GlobalVariable(
CGM.getModule(),
ObjCTypes.CacheTy,
false,
llvm::GlobalValue::ExternalLinkage,
- 0,
+ nullptr,
"_objc_empty_cache");
-
+
// Make this entry NULL for any iOS device target, any iOS simulator target,
// OS X with deployment target 10.9 or later.
const llvm::Triple &Triple = CGM.getTarget().getTriple();
if (Triple.isiOS() || (Triple.isMacOSX() && !Triple.isMacOSXVersionLT(10, 9)))
// This entry will be null.
- ObjCEmptyVtableVar = 0;
+ ObjCEmptyVtableVar = nullptr;
else
ObjCEmptyVtableVar = new llvm::GlobalVariable(
CGM.getModule(),
ObjCTypes.ImpnfABITy,
false,
llvm::GlobalValue::ExternalLinkage,
- 0,
+ nullptr,
"_objc_empty_vtable");
}
assert(ID->getClassInterface() &&
@@ -5827,8 +5800,9 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassnfABITy);
uint32_t InstanceSize = InstanceStart;
uint32_t flags = NonFragileABI_Class_Meta;
- std::string ObjCMetaClassName(getMetaclassSymbolPrefix());
- std::string ObjCClassName(getClassSymbolPrefix());
+ llvm::SmallString<64> ObjCMetaClassName(getMetaclassSymbolPrefix());
+ llvm::SmallString<64> ObjCClassName(getClassSymbolPrefix());
+ llvm::SmallString<64> TClassName;
llvm::GlobalVariable *SuperClassGV, *IsAGV;
@@ -5849,31 +5823,39 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
if (!ID->getClassInterface()->getSuperClass()) {
// class is root
flags |= NonFragileABI_Class_Root;
- SuperClassGV = GetClassGlobal(ObjCClassName + ClassName);
- IsAGV = GetClassGlobal(ObjCMetaClassName + ClassName);
+ TClassName = ObjCClassName;
+ TClassName += ClassName;
+ SuperClassGV = GetClassGlobal(TClassName.str(),
+ ID->getClassInterface()->isWeakImported());
+ TClassName = ObjCMetaClassName;
+ TClassName += ClassName;
+ IsAGV = GetClassGlobal(TClassName.str(),
+ ID->getClassInterface()->isWeakImported());
} else {
// Has a root. Current class is not a root.
const ObjCInterfaceDecl *Root = ID->getClassInterface();
while (const ObjCInterfaceDecl *Super = Root->getSuperClass())
Root = Super;
- IsAGV = GetClassGlobal(ObjCMetaClassName + Root->getNameAsString());
- if (Root->isWeakImported())
- IsAGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
+ TClassName = ObjCMetaClassName ;
+ TClassName += Root->getObjCRuntimeNameAsString();
+ IsAGV = GetClassGlobal(TClassName.str(),
+ Root->isWeakImported());
+
// work on super class metadata symbol.
- std::string SuperClassName =
- ObjCMetaClassName +
- ID->getClassInterface()->getSuperClass()->getNameAsString();
- SuperClassGV = GetClassGlobal(SuperClassName);
- if (ID->getClassInterface()->getSuperClass()->isWeakImported())
- SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
+ TClassName = ObjCMetaClassName;
+ TClassName += ID->getClassInterface()->getSuperClass()->getObjCRuntimeNameAsString();
+ SuperClassGV = GetClassGlobal(
+ TClassName.str(),
+ ID->getClassInterface()->getSuperClass()->isWeakImported());
}
llvm::GlobalVariable *CLASS_RO_GV = BuildClassRoTInitializer(flags,
InstanceStart,
InstanceSize,ID);
- std::string TClassName = ObjCMetaClassName + ClassName;
- llvm::GlobalVariable *MetaTClass =
- BuildClassMetaData(TClassName, IsAGV, SuperClassGV, CLASS_RO_GV,
- classIsHidden);
+ TClassName = ObjCMetaClassName;
+ TClassName += ClassName;
+ llvm::GlobalVariable *MetaTClass = BuildClassMetaData(
+ TClassName.str(), IsAGV, SuperClassGV, CLASS_RO_GV, classIsHidden,
+ ID->getClassInterface()->isWeakImported());
DefinedMetaClasses.push_back(MetaTClass);
// Metadata for the class
@@ -5899,14 +5881,14 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
if (!ID->getClassInterface()->getSuperClass()) {
flags |= NonFragileABI_Class_Root;
- SuperClassGV = 0;
+ SuperClassGV = nullptr;
} else {
// Has a root. Current class is not a root.
- std::string RootClassName =
- ID->getClassInterface()->getSuperClass()->getNameAsString();
- SuperClassGV = GetClassGlobal(ObjCClassName + RootClassName);
- if (ID->getClassInterface()->getSuperClass()->isWeakImported())
- SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
+ TClassName = ObjCClassName;
+ TClassName += ID->getClassInterface()->getSuperClass()->getObjCRuntimeNameAsString();
+ SuperClassGV = GetClassGlobal(
+ TClassName.str(),
+ ID->getClassInterface()->getSuperClass()->isWeakImported());
}
GetClassSizeInfo(ID, InstanceStart, InstanceSize);
CLASS_RO_GV = BuildClassRoTInitializer(flags,
@@ -5914,11 +5896,14 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
InstanceSize,
ID);
- TClassName = ObjCClassName + ClassName;
+ TClassName = ObjCClassName;
+ TClassName += ClassName;
llvm::GlobalVariable *ClassMD =
- BuildClassMetaData(TClassName, MetaTClass, SuperClassGV, CLASS_RO_GV,
- classIsHidden);
+ BuildClassMetaData(TClassName.str(), MetaTClass, SuperClassGV, CLASS_RO_GV,
+ classIsHidden,
+ ID->getClassInterface()->isWeakImported());
DefinedClasses.push_back(ClassMD);
+ ImplementedClasses.push_back(ID->getClassInterface());
// Determine if this class is also "non-lazy".
if (ImplementationIsNonLazy(ID))
@@ -5950,7 +5935,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CodeGenFunction &CGF,
ObjCTypes.getExternalProtocolPtrTy());
std::string ProtocolName("\01l_OBJC_PROTOCOL_REFERENCE_$_");
- ProtocolName += PD->getName();
+ ProtocolName += PD->getObjCRuntimeNameAsString();
llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName);
if (PTGV)
@@ -5963,7 +5948,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CodeGenFunction &CGF,
ProtocolName);
PTGV->setSection("__DATA, __objc_protorefs, coalesced, no_dead_strip");
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
- CGM.AddUsedGlobal(PTGV);
+ CGM.addCompilerUsedGlobal(PTGV);
return CGF.Builder.CreateLoad(PTGV);
}
@@ -5980,58 +5965,63 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CodeGenFunction &CGF,
void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
const ObjCInterfaceDecl *Interface = OCD->getClassInterface();
const char *Prefix = "\01l_OBJC_$_CATEGORY_";
- std::string ExtCatName(Prefix + Interface->getNameAsString()+
- "_$_" + OCD->getNameAsString());
- std::string ExtClassName(getClassSymbolPrefix() +
- Interface->getNameAsString());
+
+ llvm::SmallString<64> ExtCatName(Prefix);
+ ExtCatName += Interface->getObjCRuntimeNameAsString();
+ ExtCatName += "_$_";
+ ExtCatName += OCD->getNameAsString();
+
+ llvm::SmallString<64> ExtClassName(getClassSymbolPrefix());
+ ExtClassName += Interface->getObjCRuntimeNameAsString();
llvm::Constant *Values[6];
- Values[0] = GetClassName(OCD->getIdentifier());
+ Values[0] = GetClassName(OCD->getIdentifier()->getName());
// meta-class entry symbol
- llvm::GlobalVariable *ClassGV = GetClassGlobal(ExtClassName);
- if (Interface->isWeakImported())
- ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
-
+ llvm::GlobalVariable *ClassGV =
+ GetClassGlobal(ExtClassName.str(), Interface->isWeakImported());
+
Values[1] = ClassGV;
std::vector<llvm::Constant*> Methods;
- std::string MethodListName(Prefix);
- MethodListName += "INSTANCE_METHODS_" + Interface->getNameAsString() +
- "_$_" + OCD->getNameAsString();
+ llvm::SmallString<64> MethodListName(Prefix);
+
+ MethodListName += "INSTANCE_METHODS_";
+ MethodListName += Interface->getObjCRuntimeNameAsString();
+ MethodListName += "_$_";
+ MethodListName += OCD->getName();
- for (ObjCCategoryImplDecl::instmeth_iterator
- i = OCD->instmeth_begin(), e = OCD->instmeth_end(); i != e; ++i) {
+ for (const auto *I : OCD->instance_methods())
// Instance methods should always be defined.
- Methods.push_back(GetMethodConstant(*i));
- }
+ Methods.push_back(GetMethodConstant(I));
- Values[2] = EmitMethodList(MethodListName,
+ Values[2] = EmitMethodList(MethodListName.str(),
"__DATA, __objc_const",
Methods);
MethodListName = Prefix;
- MethodListName += "CLASS_METHODS_" + Interface->getNameAsString() + "_$_" +
- OCD->getNameAsString();
+ MethodListName += "CLASS_METHODS_";
+ MethodListName += Interface->getObjCRuntimeNameAsString();
+ MethodListName += "_$_";
+ MethodListName += OCD->getNameAsString();
+
Methods.clear();
- for (ObjCCategoryImplDecl::classmeth_iterator
- i = OCD->classmeth_begin(), e = OCD->classmeth_end(); i != e; ++i) {
+ for (const auto *I : OCD->class_methods())
// Class methods should always be defined.
- Methods.push_back(GetMethodConstant(*i));
- }
+ Methods.push_back(GetMethodConstant(I));
- Values[3] = EmitMethodList(MethodListName,
+ Values[3] = EmitMethodList(MethodListName.str(),
"__DATA, __objc_const",
Methods);
const ObjCCategoryDecl *Category =
Interface->FindCategoryDeclaration(OCD->getIdentifier());
if (Category) {
SmallString<256> ExtName;
- llvm::raw_svector_ostream(ExtName) << Interface->getName() << "_$_"
+ llvm::raw_svector_ostream(ExtName) << Interface->getObjCRuntimeNameAsString() << "_$_"
<< OCD->getName();
Values[4] = EmitProtocolList("\01l_OBJC_CATEGORY_PROTOCOLS_$_"
- + Interface->getName() + "_$_"
- + Category->getName(),
- Category->protocol_begin(),
- Category->protocol_end());
+ + Interface->getObjCRuntimeNameAsString() + "_$_"
+ + Category->getName(),
+ Category->protocol_begin(),
+ Category->protocol_end());
Values[5] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ExtName.str(),
OCD, Category, ObjCTypes);
} else {
@@ -6045,13 +6035,14 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
llvm::GlobalVariable *GCATV
= new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.CategorynfABITy,
false,
- llvm::GlobalValue::InternalLinkage,
+ llvm::GlobalValue::PrivateLinkage,
Init,
- ExtCatName);
+ ExtCatName.str());
+ assertPrivateName(GCATV);
GCATV->setAlignment(
CGM.getDataLayout().getABITypeAlignment(ObjCTypes.CategorynfABITy));
GCATV->setSection("__DATA, __objc_const");
- CGM.AddUsedGlobal(GCATV);
+ CGM.addCompilerUsedGlobal(GCATV);
DefinedCategories.push_back(GCATV);
// Determine if this category is also "non-lazy".
@@ -6068,7 +6059,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetMethodConstant(
const ObjCMethodDecl *MD) {
llvm::Function *Fn = GetMethodDefinition(MD);
if (!Fn)
- return 0;
+ return nullptr;
llvm::Constant *Method[] = {
llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
@@ -6107,10 +6098,11 @@ CGObjCNonFragileABIMac::EmitMethodList(Twine Name,
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
- llvm::GlobalValue::InternalLinkage, Init, Name);
+ llvm::GlobalValue::PrivateLinkage, Init, Name);
+ assertPrivateName(GV);
GV->setAlignment(CGM.getDataLayout().getABITypeAlignment(Init->getType()));
GV->setSection(Section);
- CGM.AddUsedGlobal(GV);
+ CGM.addCompilerUsedGlobal(GV);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListnfABIPtrTy);
}
@@ -6119,18 +6111,18 @@ CGObjCNonFragileABIMac::EmitMethodList(Twine Name,
llvm::GlobalVariable *
CGObjCNonFragileABIMac::ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *Ivar) {
+
const ObjCInterfaceDecl *Container = Ivar->getContainingInterface();
- std::string Name = "OBJC_IVAR_$_" + Container->getNameAsString() +
- '.' + Ivar->getNameAsString();
+ llvm::SmallString<64> Name("OBJC_IVAR_$_");
+ Name += Container->getObjCRuntimeNameAsString();
+ Name += ".";
+ Name += Ivar->getName();
llvm::GlobalVariable *IvarOffsetGV =
CGM.getModule().getGlobalVariable(Name);
if (!IvarOffsetGV)
- IvarOffsetGV =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.LongTy,
- false,
- llvm::GlobalValue::ExternalLinkage,
- 0,
- Name);
+ IvarOffsetGV = new llvm::GlobalVariable(
+ CGM.getModule(), ObjCTypes.IvarOffsetVarTy, false,
+ llvm::GlobalValue::ExternalLinkage, nullptr, Name.str());
return IvarOffsetGV;
}
@@ -6139,10 +6131,10 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *Ivar,
unsigned long int Offset) {
llvm::GlobalVariable *IvarOffsetGV = ObjCIvarOffsetVariable(ID, Ivar);
- IvarOffsetGV->setInitializer(llvm::ConstantInt::get(ObjCTypes.LongTy,
- Offset));
+ IvarOffsetGV->setInitializer(
+ llvm::ConstantInt::get(ObjCTypes.IvarOffsetVarTy, Offset));
IvarOffsetGV->setAlignment(
- CGM.getDataLayout().getABITypeAlignment(ObjCTypes.LongTy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.IvarOffsetVarTy));
// FIXME: This matches gcc, but shouldn't the visibility be set on the use as
// well (i.e., in ObjCIvarOffsetVariable).
@@ -6160,7 +6152,7 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
/// implementation. The return value has type
/// IvarListnfABIPtrTy.
/// struct _ivar_t {
-/// unsigned long int *offset; // pointer to ivar offset location
+/// unsigned [long] int *offset; // pointer to ivar offset location
/// char *name;
/// char *type;
/// uint32_t alignment;
@@ -6223,14 +6215,15 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
const char *Prefix = "\01l_OBJC_$_INSTANCE_VARIABLES_";
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
- llvm::GlobalValue::InternalLinkage,
+ llvm::GlobalValue::PrivateLinkage,
Init,
- Prefix + OID->getName());
+ Prefix + OID->getObjCRuntimeNameAsString());
+ assertPrivateName(GV);
GV->setAlignment(
CGM.getDataLayout().getABITypeAlignment(Init->getType()));
GV->setSection("__DATA, __objc_const");
- CGM.AddUsedGlobal(GV);
+ CGM.addCompilerUsedGlobal(GV);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListnfABIPtrTy);
}
@@ -6243,10 +6236,10 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocolRef(
// reference or not. At module finalization we add the empty
// contents for protocols which were referenced but never defined.
Entry =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy, false,
- llvm::GlobalValue::ExternalLinkage,
- 0,
- "\01l_OBJC_PROTOCOL_$_" + PD->getName());
+ new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy,
+ false, llvm::GlobalValue::WeakAnyLinkage,
+ nullptr,
+ "\01l_OBJC_PROTOCOL_$_" + PD->getObjCRuntimeNameAsString());
Entry->setSection("__DATA,__datacoal_nt,coalesced");
}
@@ -6287,9 +6280,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
std::vector<llvm::Constant*> InstanceMethods, ClassMethods;
std::vector<llvm::Constant*> OptInstanceMethods, OptClassMethods;
std::vector<llvm::Constant*> MethodTypesExt, OptMethodTypesExt;
- for (ObjCProtocolDecl::instmeth_iterator
- i = PD->instmeth_begin(), e = PD->instmeth_end(); i != e; ++i) {
- ObjCMethodDecl *MD = *i;
+ for (const auto *MD : PD->instance_methods()) {
llvm::Constant *C = GetMethodDescriptionConstant(MD);
if (!C)
return GetOrEmitProtocolRef(PD);
@@ -6303,9 +6294,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
}
}
- for (ObjCProtocolDecl::classmeth_iterator
- i = PD->classmeth_begin(), e = PD->classmeth_end(); i != e; ++i) {
- ObjCMethodDecl *MD = *i;
+ for (const auto *MD : PD->class_methods()) {
llvm::Constant *C = GetMethodDescriptionConstant(MD);
if (!C)
return GetOrEmitProtocolRef(PD);
@@ -6325,48 +6314,48 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
llvm::Constant *Values[11];
// isa is NULL
Values[0] = llvm::Constant::getNullValue(ObjCTypes.ObjectPtrTy);
- Values[1] = GetClassName(PD->getIdentifier());
- Values[2] = EmitProtocolList("\01l_OBJC_$_PROTOCOL_REFS_" + PD->getName(),
+ Values[1] = GetClassName(PD->getObjCRuntimeNameAsString());
+ Values[2] = EmitProtocolList("\01l_OBJC_$_PROTOCOL_REFS_" + PD->getObjCRuntimeNameAsString(),
PD->protocol_begin(),
PD->protocol_end());
Values[3] = EmitMethodList("\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_"
- + PD->getName(),
+ + PD->getObjCRuntimeNameAsString(),
"__DATA, __objc_const",
InstanceMethods);
Values[4] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_"
- + PD->getName(),
+ + PD->getObjCRuntimeNameAsString(),
"__DATA, __objc_const",
ClassMethods);
Values[5] = EmitMethodList("\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_OPT_"
- + PD->getName(),
+ + PD->getObjCRuntimeNameAsString(),
"__DATA, __objc_const",
OptInstanceMethods);
Values[6] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_OPT_"
- + PD->getName(),
+ + PD->getObjCRuntimeNameAsString(),
"__DATA, __objc_const",
OptClassMethods);
- Values[7] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + PD->getName(),
- 0, PD, ObjCTypes);
+ Values[7] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + PD->getObjCRuntimeNameAsString(),
+ nullptr, PD, ObjCTypes);
uint32_t Size =
CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolnfABITy);
Values[8] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
Values[9] = llvm::Constant::getNullValue(ObjCTypes.IntTy);
Values[10] = EmitProtocolMethodTypes("\01l_OBJC_$_PROTOCOL_METHOD_TYPES_"
- + PD->getName(),
+ + PD->getObjCRuntimeNameAsString(),
MethodTypesExt, ObjCTypes);
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolnfABITy,
Values);
if (Entry) {
- // Already created, fix the linkage and update the initializer.
- Entry->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
+ // Already created, update the initializer.
+ assert(Entry->hasWeakAnyLinkage());
Entry->setInitializer(Init);
} else {
Entry =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy,
false, llvm::GlobalValue::WeakAnyLinkage, Init,
- "\01l_OBJC_PROTOCOL_$_" + PD->getName());
+ "\01l_OBJC_PROTOCOL_$_" + PD->getObjCRuntimeNameAsString());
Entry->setAlignment(
CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABITy));
Entry->setSection("__DATA,__datacoal_nt,coalesced");
@@ -6374,19 +6363,19 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
Protocols[PD->getIdentifier()] = Entry;
}
Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
- CGM.AddUsedGlobal(Entry);
+ CGM.addCompilerUsedGlobal(Entry);
// Use this protocol meta-data to build protocol list table in section
// __DATA, __objc_protolist
llvm::GlobalVariable *PTGV =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABIPtrTy,
false, llvm::GlobalValue::WeakAnyLinkage, Entry,
- "\01l_OBJC_LABEL_PROTOCOL_$_" + PD->getName());
+ "\01l_OBJC_LABEL_PROTOCOL_$_" + PD->getObjCRuntimeNameAsString());
PTGV->setAlignment(
CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy));
PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip");
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
- CGM.AddUsedGlobal(PTGV);
+ CGM.addCompilerUsedGlobal(PTGV);
return Entry;
}
@@ -6433,12 +6422,13 @@ CGObjCNonFragileABIMac::EmitProtocolList(Twine Name,
llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
- llvm::GlobalValue::InternalLinkage,
+ llvm::GlobalValue::PrivateLinkage,
Init, Name);
+ assertPrivateName(GV);
GV->setSection("__DATA, __objc_const");
GV->setAlignment(
CGM.getDataLayout().getABITypeAlignment(Init->getType()));
- CGM.AddUsedGlobal(GV);
+ CGM.addCompilerUsedGlobal(GV);
return llvm::ConstantExpr::getBitCast(GV,
ObjCTypes.ProtocolListnfABIPtrTy);
}
@@ -6458,8 +6448,8 @@ CGObjCNonFragileABIMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
ObjCTypes.SelectorPtrTy);
Desc[1] = GetMethodVarType(MD);
if (!Desc[1])
- return 0;
-
+ return nullptr;
+
// Protocol methods have no implementation. So, this entry is always NULL.
Desc[2] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Desc);
@@ -6479,12 +6469,6 @@ LValue CGObjCNonFragileABIMac::EmitObjCValueForIvar(
unsigned CVRQualifiers) {
ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCObjectType>()->getInterface();
llvm::Value *Offset = EmitIvarOffset(CGF, ID, Ivar);
-
- if (IsIvarOffsetKnownIdempotent(CGF, ID, Ivar))
- if (llvm::LoadInst *LI = cast<llvm::LoadInst>(Offset))
- LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
- llvm::MDNode::get(VMContext, ArrayRef<llvm::Value*>()));
-
return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
Offset);
}
@@ -6493,7 +6477,20 @@ llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset(
CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar) {
- return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar),"ivar");
+ llvm::Value *IvarOffsetValue = ObjCIvarOffsetVariable(Interface, Ivar);
+ IvarOffsetValue = CGF.Builder.CreateLoad(IvarOffsetValue, "ivar");
+ if (IsIvarOffsetKnownIdempotent(CGF, Ivar))
+ cast<llvm::LoadInst>(IvarOffsetValue)
+ ->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
+ llvm::MDNode::get(VMContext, ArrayRef<llvm::Value *>()));
+
+ // This could be 32bit int or 64bit integer depending on the architecture.
+ // Cast it to 64bit integer value, if it is a 32bit integer ivar offset value
+ // as this is what caller always expectes.
+ if (ObjCTypes.IvarOffsetVarTy == ObjCTypes.IntTy)
+ IvarOffsetValue = CGF.Builder.CreateIntCast(
+ IvarOffsetValue, ObjCTypes.LongTy, true, "ivar.conv");
+ return IvarOffsetValue;
}
static void appendSelectorForMessageRefTable(std::string &buffer,
@@ -6539,7 +6536,7 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
// Second argument: a pointer to the message ref structure. Leave
// the actual argument value blank for now.
- args.add(RValue::get(0), ObjCTypes.MessageRefCPtrTy);
+ args.add(RValue::get(nullptr), ObjCTypes.MessageRefCPtrTy);
args.insert(args.end(), formalArgs.begin(), formalArgs.end());
@@ -6554,9 +6551,9 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
// The runtime currently never uses vtable dispatch for anything
// except normal, non-super message-sends.
// FIXME: don't use this for that.
- llvm::Constant *fn = 0;
+ llvm::Constant *fn = nullptr;
std::string messageRefName("\01l_");
- if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) {
+ if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
if (isSuper) {
fn = ObjCTypes.getMessageSendSuper2StretFixupFn();
messageRefName += "objc_msgSendSuper2_stret_fixup";
@@ -6603,9 +6600,7 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
bool requiresnullCheck = false;
if (CGM.getLangOpts().ObjCAutoRefCount && method)
- for (ObjCMethodDecl::param_const_iterator i = method->param_begin(),
- e = method->param_end(); i != e; ++i) {
- const ParmVarDecl *ParamDecl = (*i);
+ for (const auto *ParamDecl : method->params()) {
if (ParamDecl->hasAttr<NSConsumedAttr>()) {
if (!nullReturn.NullBB)
nullReturn.init(CGF, arg0);
@@ -6627,8 +6622,8 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
callee = CGF.Builder.CreateBitCast(callee, MSI.MessengerType);
RValue result = CGF.EmitCall(MSI.CallInfo, callee, returnSlot, args);
- return nullReturn.complete(CGF, result, resultType, formalArgs,
- requiresnullCheck ? method : 0);
+ return nullReturn.complete(CGF, result, resultType, formalArgs,
+ requiresnullCheck ? method : nullptr);
}
/// Generate code for a message send expression in the nonfragile abi.
@@ -6652,49 +6647,56 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
}
llvm::GlobalVariable *
-CGObjCNonFragileABIMac::GetClassGlobal(const std::string &Name) {
+CGObjCNonFragileABIMac::GetClassGlobal(const std::string &Name, bool Weak) {
+ llvm::GlobalValue::LinkageTypes L =
+ Weak ? llvm::GlobalValue::ExternalWeakLinkage
+ : llvm::GlobalValue::ExternalLinkage;
+
llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
- if (!GV) {
+ if (!GV)
GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABITy,
- false, llvm::GlobalValue::ExternalLinkage,
- 0, Name);
- }
+ false, L, nullptr, Name);
+ assert(GV->getLinkage() == L);
return GV;
}
llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CodeGenFunction &CGF,
- IdentifierInfo *II) {
+ IdentifierInfo *II,
+ bool Weak,
+ const ObjCInterfaceDecl *ID) {
llvm::GlobalVariable *&Entry = ClassReferences[II];
if (!Entry) {
- std::string ClassName(getClassSymbolPrefix() + II->getName().str());
- llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName);
+ std::string ClassName(
+ getClassSymbolPrefix() +
+ (ID ? ID->getObjCRuntimeNameAsString() : II->getName()).str());
+ llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName, Weak);
Entry =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
- false, llvm::GlobalValue::InternalLinkage,
+ false, llvm::GlobalValue::PrivateLinkage,
ClassGV,
"\01L_OBJC_CLASSLIST_REFERENCES_$_");
Entry->setAlignment(
CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip");
- CGM.AddUsedGlobal(Entry);
+ CGM.addCompilerUsedGlobal(Entry);
}
-
+ assertPrivateName(Entry);
return CGF.Builder.CreateLoad(Entry);
}
llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
- return EmitClassRefFromId(CGF, ID->getIdentifier());
+ return EmitClassRefFromId(CGF, ID->getIdentifier(), ID->isWeakImported(), ID);
}
llvm::Value *CGObjCNonFragileABIMac::EmitNSAutoreleasePoolClassRef(
CodeGenFunction &CGF) {
IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
- return EmitClassRefFromId(CGF, II);
+ return EmitClassRefFromId(CGF, II, false, 0);
}
llvm::Value *
@@ -6703,20 +6705,22 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF,
llvm::GlobalVariable *&Entry = SuperClassReferences[ID->getIdentifier()];
if (!Entry) {
- std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
- llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName);
+ llvm::SmallString<64> ClassName(getClassSymbolPrefix());
+ ClassName += ID->getObjCRuntimeNameAsString();
+ llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName.str(),
+ ID->isWeakImported());
Entry =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
- false, llvm::GlobalValue::InternalLinkage,
+ false, llvm::GlobalValue::PrivateLinkage,
ClassGV,
"\01L_OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(
CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
- CGM.AddUsedGlobal(Entry);
+ CGM.addCompilerUsedGlobal(Entry);
}
-
+ assertPrivateName(Entry);
return CGF.Builder.CreateLoad(Entry);
}
@@ -6724,25 +6728,27 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF,
/// meta-data
///
llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF,
- const ObjCInterfaceDecl *ID) {
+ const ObjCInterfaceDecl *ID,
+ bool Weak) {
llvm::GlobalVariable * &Entry = MetaClassReferences[ID->getIdentifier()];
- if (Entry)
- return CGF.Builder.CreateLoad(Entry);
-
- std::string MetaClassName(getMetaclassSymbolPrefix() + ID->getNameAsString());
- llvm::GlobalVariable *MetaClassGV = GetClassGlobal(MetaClassName);
- Entry =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy, false,
- llvm::GlobalValue::InternalLinkage,
- MetaClassGV,
- "\01L_OBJC_CLASSLIST_SUP_REFS_$_");
- Entry->setAlignment(
- CGM.getDataLayout().getABITypeAlignment(
- ObjCTypes.ClassnfABIPtrTy));
-
- Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
- CGM.AddUsedGlobal(Entry);
+ if (!Entry) {
+ llvm::SmallString<64> MetaClassName(getMetaclassSymbolPrefix());
+ MetaClassName += ID->getObjCRuntimeNameAsString();
+ llvm::GlobalVariable *MetaClassGV =
+ GetClassGlobal(MetaClassName.str(), Weak);
+
+ Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
+ false, llvm::GlobalValue::PrivateLinkage,
+ MetaClassGV,
+ "\01L_OBJC_CLASSLIST_SUP_REFS_$_");
+ Entry->setAlignment(
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassnfABIPtrTy));
+
+ Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
+ CGM.addCompilerUsedGlobal(Entry);
+ }
+ assertPrivateName(Entry);
return CGF.Builder.CreateLoad(Entry);
}
@@ -6751,9 +6757,11 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF,
llvm::Value *CGObjCNonFragileABIMac::GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
if (ID->isWeakImported()) {
- std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
- llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName);
- ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
+ llvm::SmallString<64> ClassName(getClassSymbolPrefix());
+ ClassName += ID->getObjCRuntimeNameAsString();
+ llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName.str(), true);
+ (void)ClassGV;
+ assert(ClassGV->hasExternalWeakLinkage());
}
return EmitClassRef(CGF, ID);
@@ -6787,7 +6795,8 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
// If this is a class message the metaclass is passed as the target.
llvm::Value *Target;
if (IsClassMessage)
- Target = EmitMetaClassRef(CGF, Class);
+ Target = EmitMetaClassRef(CGF, Class,
+ (isCategoryImpl && Class->isWeakImported()));
else
Target = EmitSuperClassRef(CGF, Class);
@@ -6819,12 +6828,13 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF,
ObjCTypes.SelectorPtrTy);
Entry =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.SelectorPtrTy, false,
- llvm::GlobalValue::InternalLinkage,
+ llvm::GlobalValue::PrivateLinkage,
Casted, "\01L_OBJC_SELECTOR_REFERENCES_");
Entry->setExternallyInitialized(true);
Entry->setSection("__DATA, __objc_selrefs, literal_pointers, no_dead_strip");
- CGM.AddUsedGlobal(Entry);
+ CGM.addCompilerUsedGlobal(Entry);
}
+ assertPrivateName(Entry);
if (lval)
return Entry;
@@ -6969,7 +6979,7 @@ CGObjCNonFragileABIMac::GetEHType(QualType T) {
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy,
false,
llvm::GlobalValue::ExternalLinkage,
- 0, "OBJC_EHTYPE_id");
+ nullptr, "OBJC_EHTYPE_id");
return IDEHType;
}
@@ -7024,17 +7034,18 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
// attribute, emit an external reference.
if (hasObjCExceptionAttribute(CGM.getContext(), ID))
return Entry =
- new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, false,
- llvm::GlobalValue::ExternalLinkage,
- 0,
- ("OBJC_EHTYPE_$_" +
- ID->getIdentifier()->getName()));
+ new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, false,
+ llvm::GlobalValue::ExternalLinkage,
+ nullptr,
+ ("OBJC_EHTYPE_$_" +
+ ID->getObjCRuntimeNameAsString()));
}
// Otherwise we need to either make a new entry or fill in the
// initializer.
assert((!Entry || !Entry->hasInitializer()) && "Duplicate EHType definition");
- std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
+ llvm::SmallString<64> ClassName(getClassSymbolPrefix());
+ ClassName += ID->getObjCRuntimeNameAsString();
std::string VTableName = "objc_ehtype_vtable";
llvm::GlobalVariable *VTableGV =
CGM.getModule().getGlobalVariable(VTableName);
@@ -7042,39 +7053,42 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
VTableGV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.Int8PtrTy,
false,
llvm::GlobalValue::ExternalLinkage,
- 0, VTableName);
+ nullptr, VTableName);
llvm::Value *VTableIdx = llvm::ConstantInt::get(CGM.Int32Ty, 2);
llvm::Constant *Values[] = {
llvm::ConstantExpr::getGetElementPtr(VTableGV, VTableIdx),
- GetClassName(ID->getIdentifier()),
- GetClassGlobal(ClassName)
+ GetClassName(ID->getObjCRuntimeNameAsString()),
+ GetClassGlobal(ClassName.str())
};
llvm::Constant *Init =
llvm::ConstantStruct::get(ObjCTypes.EHTypeTy, Values);
+ llvm::GlobalValue::LinkageTypes L = ForDefinition
+ ? llvm::GlobalValue::ExternalLinkage
+ : llvm::GlobalValue::WeakAnyLinkage;
if (Entry) {
Entry->setInitializer(Init);
} else {
+ llvm::SmallString<64> EHTYPEName("OBJC_EHTYPE_$_");
+ EHTYPEName += ID->getObjCRuntimeNameAsString();
Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, false,
- llvm::GlobalValue::WeakAnyLinkage,
+ L,
Init,
- ("OBJC_EHTYPE_$_" +
- ID->getIdentifier()->getName()));
+ EHTYPEName.str());
}
+ assert(Entry->getLinkage() == L);
if (ID->getVisibility() == HiddenVisibility)
Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
Entry->setAlignment(CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.EHTypeTy));
- if (ForDefinition) {
+ if (ForDefinition)
Entry->setSection("__DATA,__objc_const");
- Entry->setLinkage(llvm::GlobalValue::ExternalLinkage);
- } else {
+ else
Entry->setSection("__DATA,__datacoal_nt,coalesced");
- }
return Entry;
}
diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp
index d097b6fad2c2..3d013da51e65 100644
--- a/lib/CodeGen/CGObjCRuntime.cpp
+++ b/lib/CodeGen/CGObjCRuntime.cpp
@@ -21,7 +21,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtObjC.h"
#include "clang/CodeGen/CGFunctionInfo.h"
-#include "llvm/Support/CallSite.h"
+#include "llvm/IR/CallSite.h"
using namespace clang;
using namespace CodeGen;
@@ -65,7 +65,7 @@ static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM,
uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM,
const ObjCInterfaceDecl *OID,
const ObjCIvarDecl *Ivar) {
- return LookupFieldBitOffset(CGM, OID, 0, Ivar) /
+ return LookupFieldBitOffset(CGM, OID, nullptr, Ivar) /
CGM.getContext().getCharWidth();
}
@@ -116,7 +116,7 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
// Note, there is a subtle invariant here: we can only call this routine on
// non-synthesized ivars but we may be called for synthesized ivars. However,
// a synthesized ivar can never be a bit-field, so this is safe.
- uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, 0, Ivar);
+ uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, nullptr, Ivar);
uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth();
uint64_t AlignmentBits = CGF.CGM.getTarget().getCharAlign();
uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext());
@@ -149,7 +149,7 @@ namespace {
const VarDecl *Variable;
const Stmt *Body;
llvm::BasicBlock *Block;
- llvm::Value *TypeInfo;
+ llvm::Constant *TypeInfo;
};
struct CallObjCEndCatch : EHScopeStack::Cleanup {
@@ -158,7 +158,7 @@ namespace {
bool MightThrow;
llvm::Value *Fn;
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
if (!MightThrow) {
CGF.Builder.CreateCall(Fn)->setDoesNotThrow();
return;
@@ -201,7 +201,7 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
// @catch(...) always matches.
if (!CatchDecl) {
- Handler.TypeInfo = 0; // catch-all
+ Handler.TypeInfo = nullptr; // catch-all
// Don't consider any other catches.
break;
}
@@ -242,7 +242,7 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
if (endCatchFn) {
// Add a cleanup to leave the catch.
- bool EndCatchMightThrow = (Handler.Variable == 0);
+ bool EndCatchMightThrow = (Handler.Variable == nullptr);
CGF.EHStack.pushCleanup<CallObjCEndCatch>(NormalAndEHCleanup,
EndCatchMightThrow,
@@ -303,7 +303,7 @@ namespace {
CallSyncExit(llvm::Value *SyncExitFn, llvm::Value *SyncArg)
: SyncExitFn(SyncExitFn), SyncArg(SyncArg) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
CGF.Builder.CreateCall(SyncExitFn, SyncArg)->setDoesNotThrow();
}
};
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index 7f030f2341da..fc6bee3fabed 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -156,8 +156,8 @@ public:
Selector Sel,
llvm::Value *Receiver,
const CallArgList &CallArgs,
- const ObjCInterfaceDecl *Class = 0,
- const ObjCMethodDecl *Method = 0) = 0;
+ const ObjCInterfaceDecl *Class = nullptr,
+ const ObjCMethodDecl *Method = nullptr) = 0;
/// Generate an Objective-C message send operation to the super
/// class initiated in a method for Class and with the given Self
@@ -175,7 +175,7 @@ public:
llvm::Value *Self,
bool IsClassMessage,
const CallArgList &CallArgs,
- const ObjCMethodDecl *Method = 0) = 0;
+ const ObjCMethodDecl *Method = nullptr) = 0;
/// Emit the code to return the named protocol as an object, as in a
/// \@protocol expression.
@@ -268,7 +268,8 @@ public:
const CodeGen::CGBlockInfo &blockInfo) = 0;
virtual llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
QualType T) = 0;
- virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) = 0;
+ virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name,
+ bool Weak = false) = 0;
struct MessageSendInfo {
const CGFunctionInfo &CallInfo;
diff --git a/lib/CodeGen/CGOpenCLRuntime.cpp b/lib/CodeGen/CGOpenCLRuntime.cpp
index 7c454ac7c695..079ef7234d9c 100644
--- a/lib/CodeGen/CGOpenCLRuntime.cpp
+++ b/lib/CodeGen/CGOpenCLRuntime.cpp
@@ -33,32 +33,35 @@ llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
assert(T->isOpenCLSpecificType() &&
"Not an OpenCL specific type!");
+ llvm::LLVMContext& Ctx = CGM.getLLVMContext();
+ uint32_t ImgAddrSpc =
+ CGM.getContext().getTargetAddressSpace(LangAS::opencl_global);
switch (cast<BuiltinType>(T)->getKind()) {
default:
llvm_unreachable("Unexpected opencl builtin type!");
- return 0;
+ return nullptr;
case BuiltinType::OCLImage1d:
return llvm::PointerType::get(llvm::StructType::create(
- CGM.getLLVMContext(), "opencl.image1d_t"), 0);
+ Ctx, "opencl.image1d_t"), ImgAddrSpc);
case BuiltinType::OCLImage1dArray:
return llvm::PointerType::get(llvm::StructType::create(
- CGM.getLLVMContext(), "opencl.image1d_array_t"), 0);
+ Ctx, "opencl.image1d_array_t"), ImgAddrSpc);
case BuiltinType::OCLImage1dBuffer:
return llvm::PointerType::get(llvm::StructType::create(
- CGM.getLLVMContext(), "opencl.image1d_buffer_t"), 0);
+ Ctx, "opencl.image1d_buffer_t"), ImgAddrSpc);
case BuiltinType::OCLImage2d:
return llvm::PointerType::get(llvm::StructType::create(
- CGM.getLLVMContext(), "opencl.image2d_t"), 0);
+ Ctx, "opencl.image2d_t"), ImgAddrSpc);
case BuiltinType::OCLImage2dArray:
return llvm::PointerType::get(llvm::StructType::create(
- CGM.getLLVMContext(), "opencl.image2d_array_t"), 0);
+ Ctx, "opencl.image2d_array_t"), ImgAddrSpc);
case BuiltinType::OCLImage3d:
return llvm::PointerType::get(llvm::StructType::create(
- CGM.getLLVMContext(), "opencl.image3d_t"), 0);
+ Ctx, "opencl.image3d_t"), ImgAddrSpc);
case BuiltinType::OCLSampler:
- return llvm::IntegerType::get(CGM.getLLVMContext(),32);
+ return llvm::IntegerType::get(Ctx, 32);
case BuiltinType::OCLEvent:
return llvm::PointerType::get(llvm::StructType::create(
- CGM.getLLVMContext(), "opencl.event_t"), 0);
+ Ctx, "opencl.event_t"), 0);
}
}
diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp
new file mode 100644
index 000000000000..12a3a7790eec
--- /dev/null
+++ b/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -0,0 +1,182 @@
+//===----- CGOpenMPRuntime.cpp - Interface to OpenMP Runtimes -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides a class for OpenMP runtime code generation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGOpenMPRuntime.h"
+#include "CodeGenFunction.h"
+#include "clang/AST/Decl.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+
+using namespace clang;
+using namespace CodeGen;
+
+CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
+ : CGM(CGM), DefaultOpenMPPSource(nullptr) {
+ IdentTy = llvm::StructType::create(
+ "ident_t", CGM.Int32Ty /* reserved_1 */, CGM.Int32Ty /* flags */,
+ CGM.Int32Ty /* reserved_2 */, CGM.Int32Ty /* reserved_3 */,
+ CGM.Int8PtrTy /* psource */, NULL);
+ // Build void (*kmpc_micro)(kmp_int32 *global_tid, kmp_int32 *bound_tid,...)
+ llvm::Type *MicroParams[] = {llvm::PointerType::getUnqual(CGM.Int32Ty),
+ llvm::PointerType::getUnqual(CGM.Int32Ty)};
+ Kmpc_MicroTy = llvm::FunctionType::get(CGM.VoidTy, MicroParams, true);
+}
+
+llvm::Value *
+CGOpenMPRuntime::GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags) {
+ llvm::Value *Entry = OpenMPDefaultLocMap.lookup(Flags);
+ if (!Entry) {
+ if (!DefaultOpenMPPSource) {
+ // Initialize default location for psource field of ident_t structure of
+ // all ident_t objects. Format is ";file;function;line;column;;".
+ // Taken from
+ // http://llvm.org/svn/llvm-project/openmp/trunk/runtime/src/kmp_str.c
+ DefaultOpenMPPSource =
+ CGM.GetAddrOfConstantCString(";unknown;unknown;0;0;;");
+ DefaultOpenMPPSource =
+ llvm::ConstantExpr::getBitCast(DefaultOpenMPPSource, CGM.Int8PtrTy);
+ }
+ llvm::GlobalVariable *DefaultOpenMPLocation = cast<llvm::GlobalVariable>(
+ CGM.CreateRuntimeVariable(IdentTy, ".kmpc_default_loc.addr"));
+ DefaultOpenMPLocation->setUnnamedAddr(true);
+ DefaultOpenMPLocation->setConstant(true);
+ DefaultOpenMPLocation->setLinkage(llvm::GlobalValue::PrivateLinkage);
+
+ llvm::Constant *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0, true);
+ llvm::Constant *Values[] = {Zero,
+ llvm::ConstantInt::get(CGM.Int32Ty, Flags),
+ Zero, Zero, DefaultOpenMPPSource};
+ llvm::Constant *Init = llvm::ConstantStruct::get(IdentTy, Values);
+ DefaultOpenMPLocation->setInitializer(Init);
+ return DefaultOpenMPLocation;
+ }
+ return Entry;
+}
+
+llvm::Value *CGOpenMPRuntime::EmitOpenMPUpdateLocation(
+ CodeGenFunction &CGF, SourceLocation Loc, OpenMPLocationFlags Flags) {
+ // If no debug info is generated - return global default location.
+ if (CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::NoDebugInfo ||
+ Loc.isInvalid())
+ return GetOrCreateDefaultOpenMPLocation(Flags);
+
+ assert(CGF.CurFn && "No function in current CodeGenFunction.");
+
+ llvm::Value *LocValue = nullptr;
+ OpenMPLocMapTy::iterator I = OpenMPLocMap.find(CGF.CurFn);
+ if (I != OpenMPLocMap.end()) {
+ LocValue = I->second;
+ } else {
+ // Generate "ident_t .kmpc_loc.addr;"
+ llvm::AllocaInst *AI = CGF.CreateTempAlloca(IdentTy, ".kmpc_loc.addr");
+ AI->setAlignment(CGM.getDataLayout().getPrefTypeAlignment(IdentTy));
+ OpenMPLocMap[CGF.CurFn] = AI;
+ LocValue = AI;
+
+ CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
+ CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
+ CGF.Builder.CreateMemCpy(LocValue, GetOrCreateDefaultOpenMPLocation(Flags),
+ llvm::ConstantExpr::getSizeOf(IdentTy),
+ CGM.PointerAlignInBytes);
+ }
+
+ // char **psource = &.kmpc_loc_<flags>.addr.psource;
+ llvm::Value *PSource =
+ CGF.Builder.CreateConstInBoundsGEP2_32(LocValue, 0, IdentField_PSource);
+
+ auto OMPDebugLoc = OpenMPDebugLocMap.lookup(Loc.getRawEncoding());
+ if (OMPDebugLoc == nullptr) {
+ SmallString<128> Buffer2;
+ llvm::raw_svector_ostream OS2(Buffer2);
+ // Build debug location
+ PresumedLoc PLoc = CGF.getContext().getSourceManager().getPresumedLoc(Loc);
+ OS2 << ";" << PLoc.getFilename() << ";";
+ if (const FunctionDecl *FD =
+ dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl)) {
+ OS2 << FD->getQualifiedNameAsString();
+ }
+ OS2 << ";" << PLoc.getLine() << ";" << PLoc.getColumn() << ";;";
+ OMPDebugLoc = CGF.Builder.CreateGlobalStringPtr(OS2.str());
+ OpenMPDebugLocMap[Loc.getRawEncoding()] = OMPDebugLoc;
+ }
+ // *psource = ";<File>;<Function>;<Line>;<Column>;;";
+ CGF.Builder.CreateStore(OMPDebugLoc, PSource);
+
+ return LocValue;
+}
+
+llvm::Value *CGOpenMPRuntime::GetOpenMPGlobalThreadNum(CodeGenFunction &CGF,
+ SourceLocation Loc) {
+ assert(CGF.CurFn && "No function in current CodeGenFunction.");
+
+ llvm::Value *GTid = nullptr;
+ OpenMPGtidMapTy::iterator I = OpenMPGtidMap.find(CGF.CurFn);
+ if (I != OpenMPGtidMap.end()) {
+ GTid = I->second;
+ } else {
+ // Generate "int32 .kmpc_global_thread_num.addr;"
+ CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
+ CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
+ llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc)};
+ GTid = CGF.EmitRuntimeCall(
+ CreateRuntimeFunction(OMPRTL__kmpc_global_thread_num), Args);
+ OpenMPGtidMap[CGF.CurFn] = GTid;
+ }
+ return GTid;
+}
+
+void CGOpenMPRuntime::FunctionFinished(CodeGenFunction &CGF) {
+ assert(CGF.CurFn && "No function in current CodeGenFunction.");
+ if (OpenMPGtidMap.count(CGF.CurFn))
+ OpenMPGtidMap.erase(CGF.CurFn);
+ if (OpenMPLocMap.count(CGF.CurFn))
+ OpenMPLocMap.erase(CGF.CurFn);
+}
+
+llvm::Type *CGOpenMPRuntime::getIdentTyPointerTy() {
+ return llvm::PointerType::getUnqual(IdentTy);
+}
+
+llvm::Type *CGOpenMPRuntime::getKmpc_MicroPointerTy() {
+ return llvm::PointerType::getUnqual(Kmpc_MicroTy);
+}
+
+llvm::Constant *
+CGOpenMPRuntime::CreateRuntimeFunction(OpenMPRTLFunction Function) {
+ llvm::Constant *RTLFn = nullptr;
+ switch (Function) {
+ case OMPRTL__kmpc_fork_call: {
+ // Build void __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro
+ // microtask, ...);
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty,
+ getKmpc_MicroPointerTy()};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, true);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_fork_call");
+ break;
+ }
+ case OMPRTL__kmpc_global_thread_num: {
+ // Build kmp_int32 __kmpc_global_thread_num(ident_t *loc);
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy()};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.Int32Ty, TypeParams, false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_global_thread_num");
+ break;
+ }
+ }
+ return RTLFn;
+}
diff --git a/lib/CodeGen/CGOpenMPRuntime.h b/lib/CodeGen/CGOpenMPRuntime.h
new file mode 100644
index 000000000000..862e8a148c56
--- /dev/null
+++ b/lib/CodeGen/CGOpenMPRuntime.h
@@ -0,0 +1,177 @@
+//===----- CGOpenMPRuntime.h - Interface to OpenMP Runtimes -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides a class for OpenMP runtime code generation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_OPENMPRUNTIME_H
+#define CLANG_CODEGEN_OPENMPRUNTIME_H
+
+#include "clang/AST/Type.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Value.h"
+
+namespace llvm {
+class AllocaInst;
+class CallInst;
+class GlobalVariable;
+class Constant;
+class Function;
+class Module;
+class StructLayout;
+class FunctionType;
+class StructType;
+class Type;
+class Value;
+} // namespace llvm
+
+namespace clang {
+
+namespace CodeGen {
+
+class CodeGenFunction;
+class CodeGenModule;
+
+class CGOpenMPRuntime {
+public:
+ /// \brief Values for bit flags used in the ident_t to describe the fields.
+ /// All enumeric elements are named and described in accordance with the code
+ /// from http://llvm.org/svn/llvm-project/openmp/trunk/runtime/src/kmp.h
+ enum OpenMPLocationFlags {
+ /// \brief Use trampoline for internal microtask.
+ OMP_IDENT_IMD = 0x01,
+ /// \brief Use c-style ident structure.
+ OMP_IDENT_KMPC = 0x02,
+ /// \brief Atomic reduction option for kmpc_reduce.
+ OMP_ATOMIC_REDUCE = 0x10,
+ /// \brief Explicit 'barrier' directive.
+ OMP_IDENT_BARRIER_EXPL = 0x20,
+ /// \brief Implicit barrier in code.
+ OMP_IDENT_BARRIER_IMPL = 0x40,
+ /// \brief Implicit barrier in 'for' directive.
+ OMP_IDENT_BARRIER_IMPL_FOR = 0x40,
+ /// \brief Implicit barrier in 'sections' directive.
+ OMP_IDENT_BARRIER_IMPL_SECTIONS = 0xC0,
+ /// \brief Implicit barrier in 'single' directive.
+ OMP_IDENT_BARRIER_IMPL_SINGLE = 0x140
+ };
+ enum OpenMPRTLFunction {
+ // Call to void __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro
+ // microtask, ...);
+ OMPRTL__kmpc_fork_call,
+ // Call to kmp_int32 kmpc_global_thread_num(ident_t *loc);
+ OMPRTL__kmpc_global_thread_num
+ };
+
+private:
+ CodeGenModule &CGM;
+ /// \brief Default const ident_t object used for initialization of all other
+ /// ident_t objects.
+ llvm::Constant *DefaultOpenMPPSource;
+ /// \brief Map of flags and corrsponding default locations.
+ typedef llvm::DenseMap<unsigned, llvm::Value *> OpenMPDefaultLocMapTy;
+ OpenMPDefaultLocMapTy OpenMPDefaultLocMap;
+ llvm::Value *GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags);
+ /// \brief Describes ident structure that describes a source location.
+ /// All descriptions are taken from
+ /// http://llvm.org/svn/llvm-project/openmp/trunk/runtime/src/kmp.h
+ /// Original structure:
+ /// typedef struct ident {
+ /// kmp_int32 reserved_1; /**< might be used in Fortran;
+ /// see above */
+ /// kmp_int32 flags; /**< also f.flags; KMP_IDENT_xxx flags;
+ /// KMP_IDENT_KMPC identifies this union
+ /// member */
+ /// kmp_int32 reserved_2; /**< not really used in Fortran any more;
+ /// see above */
+ ///#if USE_ITT_BUILD
+ /// /* but currently used for storing
+ /// region-specific ITT */
+ /// /* contextual information. */
+ ///#endif /* USE_ITT_BUILD */
+ /// kmp_int32 reserved_3; /**< source[4] in Fortran, do not use for
+ /// C++ */
+ /// char const *psource; /**< String describing the source location.
+ /// The string is composed of semi-colon separated
+ // fields which describe the source file,
+ /// the function and a pair of line numbers that
+ /// delimit the construct.
+ /// */
+ /// } ident_t;
+ enum IdentFieldIndex {
+ /// \brief might be used in Fortran
+ IdentField_Reserved_1,
+ /// \brief OMP_IDENT_xxx flags; OMP_IDENT_KMPC identifies this union member.
+ IdentField_Flags,
+ /// \brief Not really used in Fortran any more
+ IdentField_Reserved_2,
+ /// \brief Source[4] in Fortran, do not use for C++
+ IdentField_Reserved_3,
+ /// \brief String describing the source location. The string is composed of
+ /// semi-colon separated fields which describe the source file, the function
+ /// and a pair of line numbers that delimit the construct.
+ IdentField_PSource
+ };
+ llvm::StructType *IdentTy;
+ /// \brief Map for Sourcelocation and OpenMP runtime library debug locations.
+ typedef llvm::DenseMap<unsigned, llvm::Value *> OpenMPDebugLocMapTy;
+ OpenMPDebugLocMapTy OpenMPDebugLocMap;
+ /// \brief The type for a microtask which gets passed to __kmpc_fork_call().
+ /// Original representation is:
+ /// typedef void (kmpc_micro)(kmp_int32 global_tid, kmp_int32 bound_tid,...);
+ llvm::FunctionType *Kmpc_MicroTy;
+ /// \brief Map of local debug location and functions.
+ typedef llvm::DenseMap<llvm::Function *, llvm::Value *> OpenMPLocMapTy;
+ OpenMPLocMapTy OpenMPLocMap;
+ /// \brief Map of local gtid and functions.
+ typedef llvm::DenseMap<llvm::Function *, llvm::Value *> OpenMPGtidMapTy;
+ OpenMPGtidMapTy OpenMPGtidMap;
+
+public:
+ explicit CGOpenMPRuntime(CodeGenModule &CGM);
+ ~CGOpenMPRuntime() {}
+
+ /// \brief Cleans up references to the objects in finished function.
+ /// \param CGF Reference to finished CodeGenFunction.
+ ///
+ void FunctionFinished(CodeGenFunction &CGF);
+
+ /// \brief Emits object of ident_t type with info for source location.
+ /// \param CGF Reference to current CodeGenFunction.
+ /// \param Loc Clang source location.
+ /// \param Flags Flags for OpenMP location.
+ ///
+ llvm::Value *
+ EmitOpenMPUpdateLocation(CodeGenFunction &CGF, SourceLocation Loc,
+ OpenMPLocationFlags Flags = OMP_IDENT_KMPC);
+
+ /// \brief Generates global thread number value.
+ /// \param CGF Reference to current CodeGenFunction.
+ /// \param Loc Clang source location.
+ ///
+ llvm::Value *GetOpenMPGlobalThreadNum(CodeGenFunction &CGF,
+ SourceLocation Loc);
+
+ /// \brief Returns pointer to ident_t type;
+ llvm::Type *getIdentTyPointerTy();
+
+ /// \brief Returns pointer to kmpc_micro type;
+ llvm::Type *getKmpc_MicroPointerTy();
+
+ /// \brief Returns specified OpenMP runtime function.
+ /// \param Function OpenMP runtime function.
+ /// \return Specified function.
+ llvm::Constant *CreateRuntimeFunction(OpenMPRTLFunction Function);
+};
+} // namespace CodeGen
+} // namespace clang
+
+#endif
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
deleted file mode 100644
index aa687b956098..000000000000
--- a/lib/CodeGen/CGRTTI.cpp
+++ /dev/null
@@ -1,977 +0,0 @@
-//===--- CGCXXRTTI.cpp - Emit LLVM Code for C++ RTTI descriptors ----------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This contains code dealing with C++ code generation of RTTI descriptors.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CodeGenModule.h"
-#include "CGCXXABI.h"
-#include "CGObjCRuntime.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/AST/Type.h"
-#include "clang/Frontend/CodeGenOptions.h"
-
-using namespace clang;
-using namespace CodeGen;
-
-namespace {
-class RTTIBuilder {
- CodeGenModule &CGM; // Per-module state.
- llvm::LLVMContext &VMContext;
-
- /// Fields - The fields of the RTTI descriptor currently being built.
- SmallVector<llvm::Constant *, 16> Fields;
-
- /// GetAddrOfTypeName - Returns the mangled type name of the given type.
- llvm::GlobalVariable *
- GetAddrOfTypeName(QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage);
-
- /// GetAddrOfExternalRTTIDescriptor - Returns the constant for the RTTI
- /// descriptor of the given type.
- llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty);
-
- /// BuildVTablePointer - Build the vtable pointer for the given type.
- void BuildVTablePointer(const Type *Ty);
-
- /// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
- /// inheritance, according to the Itanium C++ ABI, 2.9.5p6b.
- void BuildSIClassTypeInfo(const CXXRecordDecl *RD);
-
- /// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for
- /// classes with bases that do not satisfy the abi::__si_class_type_info
- /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
- void BuildVMIClassTypeInfo(const CXXRecordDecl *RD);
-
- /// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, used
- /// for pointer types.
- void BuildPointerTypeInfo(QualType PointeeTy);
-
- /// BuildObjCObjectTypeInfo - Build the appropriate kind of
- /// type_info for an object type.
- void BuildObjCObjectTypeInfo(const ObjCObjectType *Ty);
-
- /// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info
- /// struct, used for member pointer types.
- void BuildPointerToMemberTypeInfo(const MemberPointerType *Ty);
-
-public:
- RTTIBuilder(CodeGenModule &CGM) : CGM(CGM),
- VMContext(CGM.getModule().getContext()) { }
-
- // Pointer type info flags.
- enum {
- /// PTI_Const - Type has const qualifier.
- PTI_Const = 0x1,
-
- /// PTI_Volatile - Type has volatile qualifier.
- PTI_Volatile = 0x2,
-
- /// PTI_Restrict - Type has restrict qualifier.
- PTI_Restrict = 0x4,
-
- /// PTI_Incomplete - Type is incomplete.
- PTI_Incomplete = 0x8,
-
- /// PTI_ContainingClassIncomplete - Containing class is incomplete.
- /// (in pointer to member).
- PTI_ContainingClassIncomplete = 0x10
- };
-
- // VMI type info flags.
- enum {
- /// VMI_NonDiamondRepeat - Class has non-diamond repeated inheritance.
- VMI_NonDiamondRepeat = 0x1,
-
- /// VMI_DiamondShaped - Class is diamond shaped.
- VMI_DiamondShaped = 0x2
- };
-
- // Base class type info flags.
- enum {
- /// BCTI_Virtual - Base class is virtual.
- BCTI_Virtual = 0x1,
-
- /// BCTI_Public - Base class is public.
- BCTI_Public = 0x2
- };
-
- /// BuildTypeInfo - Build the RTTI type info struct for the given type.
- ///
- /// \param Force - true to force the creation of this RTTI value
- llvm::Constant *BuildTypeInfo(QualType Ty, bool Force = false);
-};
-}
-
-llvm::GlobalVariable *
-RTTIBuilder::GetAddrOfTypeName(QualType Ty,
- llvm::GlobalVariable::LinkageTypes Linkage) {
- SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out);
- Out.flush();
- StringRef Name = OutName.str();
-
- // We know that the mangled name of the type starts at index 4 of the
- // mangled name of the typename, so we can just index into it in order to
- // get the mangled name of the type.
- llvm::Constant *Init = llvm::ConstantDataArray::getString(VMContext,
- Name.substr(4));
-
- llvm::GlobalVariable *GV =
- CGM.CreateOrReplaceCXXRuntimeVariable(Name, Init->getType(), Linkage);
-
- GV->setInitializer(Init);
-
- return GV;
-}
-
-llvm::Constant *RTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
- // Mangle the RTTI name.
- SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
- Out.flush();
- StringRef Name = OutName.str();
-
- // Look for an existing global.
- llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(Name);
-
- if (!GV) {
- // Create a new global variable.
- GV = new llvm::GlobalVariable(CGM.getModule(), CGM.Int8PtrTy,
- /*Constant=*/true,
- llvm::GlobalValue::ExternalLinkage, 0, Name);
- }
-
- return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
-}
-
-/// TypeInfoIsInStandardLibrary - Given a builtin type, returns whether the type
-/// info for that type is defined in the standard library.
-static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
- // Itanium C++ ABI 2.9.2:
- // Basic type information (e.g. for "int", "bool", etc.) will be kept in
- // the run-time support library. Specifically, the run-time support
- // library should contain type_info objects for the types X, X* and
- // X const*, for every X in: void, std::nullptr_t, bool, wchar_t, char,
- // unsigned char, signed char, short, unsigned short, int, unsigned int,
- // long, unsigned long, long long, unsigned long long, float, double,
- // long double, char16_t, char32_t, and the IEEE 754r decimal and
- // half-precision floating point types.
- switch (Ty->getKind()) {
- case BuiltinType::Void:
- case BuiltinType::NullPtr:
- case BuiltinType::Bool:
- case BuiltinType::WChar_S:
- case BuiltinType::WChar_U:
- case BuiltinType::Char_U:
- case BuiltinType::Char_S:
- case BuiltinType::UChar:
- case BuiltinType::SChar:
- case BuiltinType::Short:
- case BuiltinType::UShort:
- case BuiltinType::Int:
- case BuiltinType::UInt:
- case BuiltinType::Long:
- case BuiltinType::ULong:
- case BuiltinType::LongLong:
- case BuiltinType::ULongLong:
- case BuiltinType::Half:
- case BuiltinType::Float:
- case BuiltinType::Double:
- case BuiltinType::LongDouble:
- case BuiltinType::Char16:
- case BuiltinType::Char32:
- case BuiltinType::Int128:
- case BuiltinType::UInt128:
- case BuiltinType::OCLImage1d:
- case BuiltinType::OCLImage1dArray:
- case BuiltinType::OCLImage1dBuffer:
- case BuiltinType::OCLImage2d:
- case BuiltinType::OCLImage2dArray:
- case BuiltinType::OCLImage3d:
- case BuiltinType::OCLSampler:
- case BuiltinType::OCLEvent:
- return true;
-
- case BuiltinType::Dependent:
-#define BUILTIN_TYPE(Id, SingletonId)
-#define PLACEHOLDER_TYPE(Id, SingletonId) \
- case BuiltinType::Id:
-#include "clang/AST/BuiltinTypes.def"
- llvm_unreachable("asking for RRTI for a placeholder type!");
-
- case BuiltinType::ObjCId:
- case BuiltinType::ObjCClass:
- case BuiltinType::ObjCSel:
- llvm_unreachable("FIXME: Objective-C types are unsupported!");
- }
-
- llvm_unreachable("Invalid BuiltinType Kind!");
-}
-
-static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) {
- QualType PointeeTy = PointerTy->getPointeeType();
- const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(PointeeTy);
- if (!BuiltinTy)
- return false;
-
- // Check the qualifiers.
- Qualifiers Quals = PointeeTy.getQualifiers();
- Quals.removeConst();
-
- if (!Quals.empty())
- return false;
-
- return TypeInfoIsInStandardLibrary(BuiltinTy);
-}
-
-/// IsStandardLibraryRTTIDescriptor - Returns whether the type
-/// information for the given type exists in the standard library.
-static bool IsStandardLibraryRTTIDescriptor(QualType Ty) {
- // Type info for builtin types is defined in the standard library.
- if (const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(Ty))
- return TypeInfoIsInStandardLibrary(BuiltinTy);
-
- // Type info for some pointer types to builtin types is defined in the
- // standard library.
- if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
- return TypeInfoIsInStandardLibrary(PointerTy);
-
- return false;
-}
-
-/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for
-/// the given type exists somewhere else, and that we should not emit the type
-/// information in this translation unit. Assumes that it is not a
-/// standard-library type.
-static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM,
- QualType Ty) {
- ASTContext &Context = CGM.getContext();
-
- // If RTTI is disabled, assume it might be disabled in the
- // translation unit that defines any potential key function, too.
- if (!Context.getLangOpts().RTTI) return false;
-
- if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
- if (!RD->hasDefinition())
- return false;
-
- if (!RD->isDynamicClass())
- return false;
-
- // FIXME: this may need to be reconsidered if the key function
- // changes.
- return CGM.getVTables().isVTableExternal(RD);
- }
-
- return false;
-}
-
-/// IsIncompleteClassType - Returns whether the given record type is incomplete.
-static bool IsIncompleteClassType(const RecordType *RecordTy) {
- return !RecordTy->getDecl()->isCompleteDefinition();
-}
-
-/// ContainsIncompleteClassType - Returns whether the given type contains an
-/// incomplete class type. This is true if
-///
-/// * The given type is an incomplete class type.
-/// * The given type is a pointer type whose pointee type contains an
-/// incomplete class type.
-/// * The given type is a member pointer type whose class is an incomplete
-/// class type.
-/// * The given type is a member pointer type whoise pointee type contains an
-/// incomplete class type.
-/// is an indirect or direct pointer to an incomplete class type.
-static bool ContainsIncompleteClassType(QualType Ty) {
- if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
- if (IsIncompleteClassType(RecordTy))
- return true;
- }
-
- if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
- return ContainsIncompleteClassType(PointerTy->getPointeeType());
-
- if (const MemberPointerType *MemberPointerTy =
- dyn_cast<MemberPointerType>(Ty)) {
- // Check if the class type is incomplete.
- const RecordType *ClassType = cast<RecordType>(MemberPointerTy->getClass());
- if (IsIncompleteClassType(ClassType))
- return true;
-
- return ContainsIncompleteClassType(MemberPointerTy->getPointeeType());
- }
-
- return false;
-}
-
-/// getTypeInfoLinkage - Return the linkage that the type info and type info
-/// name constants should have for the given type.
-static llvm::GlobalVariable::LinkageTypes
-getTypeInfoLinkage(CodeGenModule &CGM, QualType Ty) {
- // Itanium C++ ABI 2.9.5p7:
- // In addition, it and all of the intermediate abi::__pointer_type_info
- // structs in the chain down to the abi::__class_type_info for the
- // incomplete class type must be prevented from resolving to the
- // corresponding type_info structs for the complete class type, possibly
- // by making them local static objects. Finally, a dummy class RTTI is
- // generated for the incomplete type that will not resolve to the final
- // complete class RTTI (because the latter need not exist), possibly by
- // making it a local static object.
- if (ContainsIncompleteClassType(Ty))
- return llvm::GlobalValue::InternalLinkage;
-
- switch (Ty->getLinkage()) {
- case NoLinkage:
- case VisibleNoLinkage:
- case InternalLinkage:
- case UniqueExternalLinkage:
- return llvm::GlobalValue::InternalLinkage;
-
- case ExternalLinkage:
- if (!CGM.getLangOpts().RTTI) {
- // RTTI is not enabled, which means that this type info struct is going
- // to be used for exception handling. Give it linkonce_odr linkage.
- return llvm::GlobalValue::LinkOnceODRLinkage;
- }
-
- if (const RecordType *Record = dyn_cast<RecordType>(Ty)) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
- if (RD->hasAttr<WeakAttr>())
- return llvm::GlobalValue::WeakODRLinkage;
- if (RD->isDynamicClass())
- return CGM.getVTableLinkage(RD);
- }
-
- return llvm::GlobalValue::LinkOnceODRLinkage;
- }
-
- llvm_unreachable("Invalid linkage!");
-}
-
-// CanUseSingleInheritance - Return whether the given record decl has a "single,
-// public, non-virtual base at offset zero (i.e. the derived class is dynamic
-// iff the base is)", according to Itanium C++ ABI, 2.95p6b.
-static bool CanUseSingleInheritance(const CXXRecordDecl *RD) {
- // Check the number of bases.
- if (RD->getNumBases() != 1)
- return false;
-
- // Get the base.
- CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin();
-
- // Check that the base is not virtual.
- if (Base->isVirtual())
- return false;
-
- // Check that the base is public.
- if (Base->getAccessSpecifier() != AS_public)
- return false;
-
- // Check that the class is dynamic iff the base is.
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (!BaseDecl->isEmpty() &&
- BaseDecl->isDynamicClass() != RD->isDynamicClass())
- return false;
-
- return true;
-}
-
-void RTTIBuilder::BuildVTablePointer(const Type *Ty) {
- // abi::__class_type_info.
- static const char * const ClassTypeInfo =
- "_ZTVN10__cxxabiv117__class_type_infoE";
- // abi::__si_class_type_info.
- static const char * const SIClassTypeInfo =
- "_ZTVN10__cxxabiv120__si_class_type_infoE";
- // abi::__vmi_class_type_info.
- static const char * const VMIClassTypeInfo =
- "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
-
- const char *VTableName = 0;
-
- switch (Ty->getTypeClass()) {
-#define TYPE(Class, Base)
-#define ABSTRACT_TYPE(Class, Base)
-#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
-#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
-#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
- llvm_unreachable("Non-canonical and dependent types shouldn't get here");
-
- case Type::LValueReference:
- case Type::RValueReference:
- llvm_unreachable("References shouldn't get here");
-
- case Type::Auto:
- llvm_unreachable("Undeduced auto type shouldn't get here");
-
- case Type::Builtin:
- // GCC treats vector and complex types as fundamental types.
- case Type::Vector:
- case Type::ExtVector:
- case Type::Complex:
- case Type::Atomic:
- // FIXME: GCC treats block pointers as fundamental types?!
- case Type::BlockPointer:
- // abi::__fundamental_type_info.
- VTableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE";
- break;
-
- case Type::ConstantArray:
- case Type::IncompleteArray:
- case Type::VariableArray:
- // abi::__array_type_info.
- VTableName = "_ZTVN10__cxxabiv117__array_type_infoE";
- break;
-
- case Type::FunctionNoProto:
- case Type::FunctionProto:
- // abi::__function_type_info.
- VTableName = "_ZTVN10__cxxabiv120__function_type_infoE";
- break;
-
- case Type::Enum:
- // abi::__enum_type_info.
- VTableName = "_ZTVN10__cxxabiv116__enum_type_infoE";
- break;
-
- case Type::Record: {
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
-
- if (!RD->hasDefinition() || !RD->getNumBases()) {
- VTableName = ClassTypeInfo;
- } else if (CanUseSingleInheritance(RD)) {
- VTableName = SIClassTypeInfo;
- } else {
- VTableName = VMIClassTypeInfo;
- }
-
- break;
- }
-
- case Type::ObjCObject:
- // Ignore protocol qualifiers.
- Ty = cast<ObjCObjectType>(Ty)->getBaseType().getTypePtr();
-
- // Handle id and Class.
- if (isa<BuiltinType>(Ty)) {
- VTableName = ClassTypeInfo;
- break;
- }
-
- assert(isa<ObjCInterfaceType>(Ty));
- // Fall through.
-
- case Type::ObjCInterface:
- if (cast<ObjCInterfaceType>(Ty)->getDecl()->getSuperClass()) {
- VTableName = SIClassTypeInfo;
- } else {
- VTableName = ClassTypeInfo;
- }
- break;
-
- case Type::ObjCObjectPointer:
- case Type::Pointer:
- // abi::__pointer_type_info.
- VTableName = "_ZTVN10__cxxabiv119__pointer_type_infoE";
- break;
-
- case Type::MemberPointer:
- // abi::__pointer_to_member_type_info.
- VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
- break;
- }
-
- llvm::Constant *VTable =
- CGM.getModule().getOrInsertGlobal(VTableName, CGM.Int8PtrTy);
-
- llvm::Type *PtrDiffTy =
- CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
-
- // The vtable address point is 2.
- llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2);
- VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Two);
- VTable = llvm::ConstantExpr::getBitCast(VTable, CGM.Int8PtrTy);
-
- Fields.push_back(VTable);
-}
-
-llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
- // We want to operate on the canonical type.
- Ty = CGM.getContext().getCanonicalType(Ty);
-
- // Check if we've already emitted an RTTI descriptor for this type.
- SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
- Out.flush();
- StringRef Name = OutName.str();
-
- llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name);
- if (OldGV && !OldGV->isDeclaration()) {
- assert(!OldGV->hasAvailableExternallyLinkage() &&
- "available_externally typeinfos not yet implemented");
-
- return llvm::ConstantExpr::getBitCast(OldGV, CGM.Int8PtrTy);
- }
-
- // Check if there is already an external RTTI descriptor for this type.
- bool IsStdLib = IsStandardLibraryRTTIDescriptor(Ty);
- if (!Force && (IsStdLib || ShouldUseExternalRTTIDescriptor(CGM, Ty)))
- return GetAddrOfExternalRTTIDescriptor(Ty);
-
- // Emit the standard library with external linkage.
- llvm::GlobalVariable::LinkageTypes Linkage;
- if (IsStdLib)
- Linkage = llvm::GlobalValue::ExternalLinkage;
- else
- Linkage = getTypeInfoLinkage(CGM, Ty);
-
- // Add the vtable pointer.
- BuildVTablePointer(cast<Type>(Ty));
-
- // And the name.
- llvm::GlobalVariable *TypeName = GetAddrOfTypeName(Ty, Linkage);
-
- Fields.push_back(llvm::ConstantExpr::getBitCast(TypeName, CGM.Int8PtrTy));
-
- switch (Ty->getTypeClass()) {
-#define TYPE(Class, Base)
-#define ABSTRACT_TYPE(Class, Base)
-#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
-#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
-#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
- llvm_unreachable("Non-canonical and dependent types shouldn't get here");
-
- // GCC treats vector types as fundamental types.
- case Type::Builtin:
- case Type::Vector:
- case Type::ExtVector:
- case Type::Complex:
- case Type::BlockPointer:
- // Itanium C++ ABI 2.9.5p4:
- // abi::__fundamental_type_info adds no data members to std::type_info.
- break;
-
- case Type::LValueReference:
- case Type::RValueReference:
- llvm_unreachable("References shouldn't get here");
-
- case Type::Auto:
- llvm_unreachable("Undeduced auto type shouldn't get here");
-
- case Type::ConstantArray:
- case Type::IncompleteArray:
- case Type::VariableArray:
- // Itanium C++ ABI 2.9.5p5:
- // abi::__array_type_info adds no data members to std::type_info.
- break;
-
- case Type::FunctionNoProto:
- case Type::FunctionProto:
- // Itanium C++ ABI 2.9.5p5:
- // abi::__function_type_info adds no data members to std::type_info.
- break;
-
- case Type::Enum:
- // Itanium C++ ABI 2.9.5p5:
- // abi::__enum_type_info adds no data members to std::type_info.
- break;
-
- case Type::Record: {
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
- if (!RD->hasDefinition() || !RD->getNumBases()) {
- // We don't need to emit any fields.
- break;
- }
-
- if (CanUseSingleInheritance(RD))
- BuildSIClassTypeInfo(RD);
- else
- BuildVMIClassTypeInfo(RD);
-
- break;
- }
-
- case Type::ObjCObject:
- case Type::ObjCInterface:
- BuildObjCObjectTypeInfo(cast<ObjCObjectType>(Ty));
- break;
-
- case Type::ObjCObjectPointer:
- BuildPointerTypeInfo(cast<ObjCObjectPointerType>(Ty)->getPointeeType());
- break;
-
- case Type::Pointer:
- BuildPointerTypeInfo(cast<PointerType>(Ty)->getPointeeType());
- break;
-
- case Type::MemberPointer:
- BuildPointerToMemberTypeInfo(cast<MemberPointerType>(Ty));
- break;
-
- case Type::Atomic:
- // No fields, at least for the moment.
- break;
- }
-
- llvm::Constant *Init = llvm::ConstantStruct::getAnon(Fields);
-
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(CGM.getModule(), Init->getType(),
- /*Constant=*/true, Linkage, Init, Name);
-
- // If there's already an old global variable, replace it with the new one.
- if (OldGV) {
- GV->takeName(OldGV);
- llvm::Constant *NewPtr =
- llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
- OldGV->replaceAllUsesWith(NewPtr);
- OldGV->eraseFromParent();
- }
-
- // GCC only relies on the uniqueness of the type names, not the
- // type_infos themselves, so we can emit these as hidden symbols.
- // But don't do this if we're worried about strict visibility
- // compatibility.
- if (const RecordType *RT = dyn_cast<RecordType>(Ty)) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
-
- CGM.setTypeVisibility(GV, RD, CodeGenModule::TVK_ForRTTI);
- CGM.setTypeVisibility(TypeName, RD, CodeGenModule::TVK_ForRTTIName);
- } else {
- Visibility TypeInfoVisibility = DefaultVisibility;
- if (CGM.getCodeGenOpts().HiddenWeakVTables &&
- Linkage == llvm::GlobalValue::LinkOnceODRLinkage)
- TypeInfoVisibility = HiddenVisibility;
-
- // The type name should have the same visibility as the type itself.
- Visibility ExplicitVisibility = Ty->getVisibility();
- TypeName->setVisibility(CodeGenModule::
- GetLLVMVisibility(ExplicitVisibility));
-
- TypeInfoVisibility = minVisibility(TypeInfoVisibility, Ty->getVisibility());
- GV->setVisibility(CodeGenModule::GetLLVMVisibility(TypeInfoVisibility));
- }
-
- GV->setUnnamedAddr(true);
-
- return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
-}
-
-/// ComputeQualifierFlags - Compute the pointer type info flags from the
-/// given qualifier.
-static unsigned ComputeQualifierFlags(Qualifiers Quals) {
- unsigned Flags = 0;
-
- if (Quals.hasConst())
- Flags |= RTTIBuilder::PTI_Const;
- if (Quals.hasVolatile())
- Flags |= RTTIBuilder::PTI_Volatile;
- if (Quals.hasRestrict())
- Flags |= RTTIBuilder::PTI_Restrict;
-
- return Flags;
-}
-
-/// BuildObjCObjectTypeInfo - Build the appropriate kind of type_info
-/// for the given Objective-C object type.
-void RTTIBuilder::BuildObjCObjectTypeInfo(const ObjCObjectType *OT) {
- // Drop qualifiers.
- const Type *T = OT->getBaseType().getTypePtr();
- assert(isa<BuiltinType>(T) || isa<ObjCInterfaceType>(T));
-
- // The builtin types are abi::__class_type_infos and don't require
- // extra fields.
- if (isa<BuiltinType>(T)) return;
-
- ObjCInterfaceDecl *Class = cast<ObjCInterfaceType>(T)->getDecl();
- ObjCInterfaceDecl *Super = Class->getSuperClass();
-
- // Root classes are also __class_type_info.
- if (!Super) return;
-
- QualType SuperTy = CGM.getContext().getObjCInterfaceType(Super);
-
- // Everything else is single inheritance.
- llvm::Constant *BaseTypeInfo = RTTIBuilder(CGM).BuildTypeInfo(SuperTy);
- Fields.push_back(BaseTypeInfo);
-}
-
-/// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
-/// inheritance, according to the Itanium C++ ABI, 2.95p6b.
-void RTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) {
- // Itanium C++ ABI 2.9.5p6b:
- // It adds to abi::__class_type_info a single member pointing to the
- // type_info structure for the base type,
- llvm::Constant *BaseTypeInfo =
- RTTIBuilder(CGM).BuildTypeInfo(RD->bases_begin()->getType());
- Fields.push_back(BaseTypeInfo);
-}
-
-namespace {
- /// SeenBases - Contains virtual and non-virtual bases seen when traversing
- /// a class hierarchy.
- struct SeenBases {
- llvm::SmallPtrSet<const CXXRecordDecl *, 16> NonVirtualBases;
- llvm::SmallPtrSet<const CXXRecordDecl *, 16> VirtualBases;
- };
-}
-
-/// ComputeVMIClassTypeInfoFlags - Compute the value of the flags member in
-/// abi::__vmi_class_type_info.
-///
-static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
- SeenBases &Bases) {
-
- unsigned Flags = 0;
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
-
- if (Base->isVirtual()) {
- // Mark the virtual base as seen.
- if (!Bases.VirtualBases.insert(BaseDecl)) {
- // If this virtual base has been seen before, then the class is diamond
- // shaped.
- Flags |= RTTIBuilder::VMI_DiamondShaped;
- } else {
- if (Bases.NonVirtualBases.count(BaseDecl))
- Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
- }
- } else {
- // Mark the non-virtual base as seen.
- if (!Bases.NonVirtualBases.insert(BaseDecl)) {
- // If this non-virtual base has been seen before, then the class has non-
- // diamond shaped repeated inheritance.
- Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
- } else {
- if (Bases.VirtualBases.count(BaseDecl))
- Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
- }
- }
-
- // Walk all bases.
- for (CXXRecordDecl::base_class_const_iterator I = BaseDecl->bases_begin(),
- E = BaseDecl->bases_end(); I != E; ++I)
- Flags |= ComputeVMIClassTypeInfoFlags(I, Bases);
-
- return Flags;
-}
-
-static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *RD) {
- unsigned Flags = 0;
- SeenBases Bases;
-
- // Walk all bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I)
- Flags |= ComputeVMIClassTypeInfoFlags(I, Bases);
-
- return Flags;
-}
-
-/// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for
-/// classes with bases that do not satisfy the abi::__si_class_type_info
-/// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
-void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
- llvm::Type *UnsignedIntLTy =
- CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
-
- // Itanium C++ ABI 2.9.5p6c:
- // __flags is a word with flags describing details about the class
- // structure, which may be referenced by using the __flags_masks
- // enumeration. These flags refer to both direct and indirect bases.
- unsigned Flags = ComputeVMIClassTypeInfoFlags(RD);
- Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
-
- // Itanium C++ ABI 2.9.5p6c:
- // __base_count is a word with the number of direct proper base class
- // descriptions that follow.
- Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, RD->getNumBases()));
-
- if (!RD->getNumBases())
- return;
-
- llvm::Type *LongLTy =
- CGM.getTypes().ConvertType(CGM.getContext().LongTy);
-
- // Now add the base class descriptions.
-
- // Itanium C++ ABI 2.9.5p6c:
- // __base_info[] is an array of base class descriptions -- one for every
- // direct proper base. Each description is of the type:
- //
- // struct abi::__base_class_type_info {
- // public:
- // const __class_type_info *__base_type;
- // long __offset_flags;
- //
- // enum __offset_flags_masks {
- // __virtual_mask = 0x1,
- // __public_mask = 0x2,
- // __offset_shift = 8
- // };
- // };
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXBaseSpecifier *Base = I;
-
- // The __base_type member points to the RTTI for the base type.
- Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(Base->getType()));
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
-
- int64_t OffsetFlags = 0;
-
- // All but the lower 8 bits of __offset_flags are a signed offset.
- // For a non-virtual base, this is the offset in the object of the base
- // subobject. For a virtual base, this is the offset in the virtual table of
- // the virtual base offset for the virtual base referenced (negative).
- CharUnits Offset;
- if (Base->isVirtual())
- Offset =
- CGM.getItaniumVTableContext().getVirtualBaseOffsetOffset(RD, BaseDecl);
- else {
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- Offset = Layout.getBaseClassOffset(BaseDecl);
- };
-
- OffsetFlags = uint64_t(Offset.getQuantity()) << 8;
-
- // The low-order byte of __offset_flags contains flags, as given by the
- // masks from the enumeration __offset_flags_masks.
- if (Base->isVirtual())
- OffsetFlags |= BCTI_Virtual;
- if (Base->getAccessSpecifier() == AS_public)
- OffsetFlags |= BCTI_Public;
-
- Fields.push_back(llvm::ConstantInt::get(LongLTy, OffsetFlags));
- }
-}
-
-/// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct,
-/// used for pointer types.
-void RTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) {
- Qualifiers Quals;
- QualType UnqualifiedPointeeTy =
- CGM.getContext().getUnqualifiedArrayType(PointeeTy, Quals);
-
- // Itanium C++ ABI 2.9.5p7:
- // __flags is a flag word describing the cv-qualification and other
- // attributes of the type pointed to
- unsigned Flags = ComputeQualifierFlags(Quals);
-
- // Itanium C++ ABI 2.9.5p7:
- // When the abi::__pbase_type_info is for a direct or indirect pointer to an
- // incomplete class type, the incomplete target type flag is set.
- if (ContainsIncompleteClassType(UnqualifiedPointeeTy))
- Flags |= PTI_Incomplete;
-
- llvm::Type *UnsignedIntLTy =
- CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
- Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
-
- // Itanium C++ ABI 2.9.5p7:
- // __pointee is a pointer to the std::type_info derivation for the
- // unqualified type being pointed to.
- llvm::Constant *PointeeTypeInfo =
- RTTIBuilder(CGM).BuildTypeInfo(UnqualifiedPointeeTy);
- Fields.push_back(PointeeTypeInfo);
-}
-
-/// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info
-/// struct, used for member pointer types.
-void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) {
- QualType PointeeTy = Ty->getPointeeType();
-
- Qualifiers Quals;
- QualType UnqualifiedPointeeTy =
- CGM.getContext().getUnqualifiedArrayType(PointeeTy, Quals);
-
- // Itanium C++ ABI 2.9.5p7:
- // __flags is a flag word describing the cv-qualification and other
- // attributes of the type pointed to.
- unsigned Flags = ComputeQualifierFlags(Quals);
-
- const RecordType *ClassType = cast<RecordType>(Ty->getClass());
-
- // Itanium C++ ABI 2.9.5p7:
- // When the abi::__pbase_type_info is for a direct or indirect pointer to an
- // incomplete class type, the incomplete target type flag is set.
- if (ContainsIncompleteClassType(UnqualifiedPointeeTy))
- Flags |= PTI_Incomplete;
-
- if (IsIncompleteClassType(ClassType))
- Flags |= PTI_ContainingClassIncomplete;
-
- llvm::Type *UnsignedIntLTy =
- CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
- Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
-
- // Itanium C++ ABI 2.9.5p7:
- // __pointee is a pointer to the std::type_info derivation for the
- // unqualified type being pointed to.
- llvm::Constant *PointeeTypeInfo =
- RTTIBuilder(CGM).BuildTypeInfo(UnqualifiedPointeeTy);
- Fields.push_back(PointeeTypeInfo);
-
- // Itanium C++ ABI 2.9.5p9:
- // __context is a pointer to an abi::__class_type_info corresponding to the
- // class type containing the member pointed to
- // (e.g., the "A" in "int A::*").
- Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(QualType(ClassType, 0)));
-}
-
-llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
- bool ForEH) {
- // Return a bogus pointer if RTTI is disabled, unless it's for EH.
- // FIXME: should we even be calling this method if RTTI is disabled
- // and it's not for EH?
- if (!ForEH && !getLangOpts().RTTI)
- return llvm::Constant::getNullValue(Int8PtrTy);
-
- if (ForEH && Ty->isObjCObjectPointerType() &&
- LangOpts.ObjCRuntime.isGNUFamily())
- return ObjCRuntime->GetEHType(Ty);
-
- return RTTIBuilder(*this).BuildTypeInfo(Ty);
-}
-
-void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) {
- QualType PointerType = Context.getPointerType(Type);
- QualType PointerTypeConst = Context.getPointerType(Type.withConst());
- RTTIBuilder(*this).BuildTypeInfo(Type, true);
- RTTIBuilder(*this).BuildTypeInfo(PointerType, true);
- RTTIBuilder(*this).BuildTypeInfo(PointerTypeConst, true);
-}
-
-void CodeGenModule::EmitFundamentalRTTIDescriptors() {
- QualType FundamentalTypes[] = { Context.VoidTy, Context.NullPtrTy,
- Context.BoolTy, Context.WCharTy,
- Context.CharTy, Context.UnsignedCharTy,
- Context.SignedCharTy, Context.ShortTy,
- Context.UnsignedShortTy, Context.IntTy,
- Context.UnsignedIntTy, Context.LongTy,
- Context.UnsignedLongTy, Context.LongLongTy,
- Context.UnsignedLongLongTy, Context.FloatTy,
- Context.DoubleTy, Context.LongDoubleTy,
- Context.Char16Ty, Context.Char32Ty };
- for (unsigned i = 0; i < llvm::array_lengthof(FundamentalTypes); ++i)
- EmitFundamentalRTTIDescriptor(FundamentalTypes[i]);
-}
diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h
index b29fc987a120..b45fee56ea09 100644
--- a/lib/CodeGen/CGRecordLayout.h
+++ b/lib/CodeGen/CGRecordLayout.h
@@ -130,7 +130,7 @@ private:
llvm::DenseMap<const FieldDecl *, CGBitFieldInfo> BitFields;
// FIXME: Maybe we could use a CXXBaseSpecifier as the key and use a single
- // map for both virtual and non virtual bases.
+ // map for both virtual and non-virtual bases.
llvm::DenseMap<const CXXRecordDecl *, unsigned> NonVirtualBases;
/// Map from virtual bases to their field index in the complete object.
@@ -183,6 +183,7 @@ public:
/// \brief Return llvm::StructType element number that corresponds to the
/// field FD.
unsigned getLLVMFieldNo(const FieldDecl *FD) const {
+ FD = FD->getCanonicalDecl();
assert(FieldInfo.count(FD) && "Invalid field for record!");
return FieldInfo.lookup(FD);
}
@@ -201,7 +202,8 @@ public:
/// \brief Return the BitFieldInfo that corresponds to the field FD.
const CGBitFieldInfo &getBitFieldInfo(const FieldDecl *FD) const {
- assert(FD->isBitField() && "Invalid call for non bit-field decl!");
+ FD = FD->getCanonicalDecl();
+ assert(FD->isBitField() && "Invalid call for non-bit-field decl!");
llvm::DenseMap<const FieldDecl *, CGBitFieldInfo>::const_iterator
it = BitFields.find(FD);
assert(it != BitFields.end() && "Unable to find bitfield info");
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index ab92563b21f3..a10d8e791b0f 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -25,946 +25,647 @@
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace CodeGen;
namespace {
-
-class CGRecordLayoutBuilder {
-public:
- /// FieldTypes - Holds the LLVM types that the struct is created from.
- ///
+/// The CGRecordLowering is responsible for lowering an ASTRecordLayout to an
+/// llvm::Type. Some of the lowering is straightforward, some is not. Here we
+/// detail some of the complexities and weirdnesses here.
+/// * LLVM does not have unions - Unions can, in theory be represented by any
+/// llvm::Type with correct size. We choose a field via a specific heuristic
+/// and add padding if necessary.
+/// * LLVM does not have bitfields - Bitfields are collected into contiguous
+/// runs and allocated as a single storage type for the run. ASTRecordLayout
+/// contains enough information to determine where the runs break. Microsoft
+/// and Itanium follow different rules and use different codepaths.
+/// * It is desired that, when possible, bitfields use the appropriate iN type
+/// when lowered to llvm types. For example unsigned x : 24 gets lowered to
+/// i24. This isn't always possible because i24 has storage size of 32 bit
+/// and if it is possible to use that extra byte of padding we must use
+/// [i8 x 3] instead of i24. The function clipTailPadding does this.
+/// C++ examples that require clipping:
+/// struct { int a : 24; char b; }; // a must be clipped, b goes at offset 3
+/// struct A { int a : 24; }; // a must be clipped because a struct like B
+// could exist: struct B : A { char b; }; // b goes at offset 3
+/// * Clang ignores 0 sized bitfields and 0 sized bases but *not* zero sized
+/// fields. The existing asserts suggest that LLVM assumes that *every* field
+/// has an underlying storage type. Therefore empty structures containing
+/// zero sized subobjects such as empty records or zero sized arrays still get
+/// a zero sized (empty struct) storage type.
+/// * Clang reads the complete type rather than the base type when generating
+/// code to access fields. Bitfields in tail position with tail padding may
+/// be clipped in the base class but not the complete class (we may discover
+/// that the tail padding is not used in the complete class.) However,
+/// because LLVM reads from the complete type it can generate incorrect code
+/// if we do not clip the tail padding off of the bitfield in the complete
+/// layout. This introduces a somewhat awkward extra unnecessary clip stage.
+/// The location of the clip is stored internally as a sentinal of type
+/// SCISSOR. If LLVM were updated to read base types (which it probably
+/// should because locations of things such as VBases are bogus in the llvm
+/// type anyway) then we could eliminate the SCISSOR.
+/// * Itanium allows nearly empty primary virtual bases. These bases don't get
+/// get their own storage because they're laid out as part of another base
+/// or at the beginning of the structure. Determining if a VBase actually
+/// gets storage awkwardly involves a walk of all bases.
+/// * VFPtrs and VBPtrs do *not* make a record NotZeroInitializable.
+struct CGRecordLowering {
+ // MemberInfo is a helper structure that contains information about a record
+ // member. In additional to the standard member types, there exists a
+ // sentinal member type that ensures correct rounding.
+ struct MemberInfo {
+ CharUnits Offset;
+ enum InfoKind { VFPtr, VBPtr, Field, Base, VBase, Scissor } Kind;
+ llvm::Type *Data;
+ union {
+ const FieldDecl *FD;
+ const CXXRecordDecl *RD;
+ };
+ MemberInfo(CharUnits Offset, InfoKind Kind, llvm::Type *Data,
+ const FieldDecl *FD = nullptr)
+ : Offset(Offset), Kind(Kind), Data(Data), FD(FD) {}
+ MemberInfo(CharUnits Offset, InfoKind Kind, llvm::Type *Data,
+ const CXXRecordDecl *RD)
+ : Offset(Offset), Kind(Kind), Data(Data), RD(RD) {}
+ // MemberInfos are sorted so we define a < operator.
+ bool operator <(const MemberInfo& a) const { return Offset < a.Offset; }
+ };
+ // The constructor.
+ CGRecordLowering(CodeGenTypes &Types, const RecordDecl *D);
+ // Short helper routines.
+ /// \brief Constructs a MemberInfo instance from an offset and llvm::Type *.
+ MemberInfo StorageInfo(CharUnits Offset, llvm::Type *Data) {
+ return MemberInfo(Offset, MemberInfo::Field, Data);
+ }
+ bool useMSABI() {
+ return Context.getTargetInfo().getCXXABI().isMicrosoft() ||
+ D->isMsStruct(Context);
+ }
+ /// \brief Wraps llvm::Type::getIntNTy with some implicit arguments.
+ llvm::Type *getIntNType(uint64_t NumBits) {
+ return llvm::Type::getIntNTy(Types.getLLVMContext(),
+ (unsigned)llvm::RoundUpToAlignment(NumBits, 8));
+ }
+ /// \brief Gets an llvm type of size NumBytes and alignment 1.
+ llvm::Type *getByteArrayType(CharUnits NumBytes) {
+ assert(!NumBytes.isZero() && "Empty byte arrays aren't allowed.");
+ llvm::Type *Type = llvm::Type::getInt8Ty(Types.getLLVMContext());
+ return NumBytes == CharUnits::One() ? Type :
+ (llvm::Type *)llvm::ArrayType::get(Type, NumBytes.getQuantity());
+ }
+ /// \brief Gets the storage type for a field decl and handles storage
+ /// for itanium bitfields that are smaller than their declared type.
+ llvm::Type *getStorageType(const FieldDecl *FD) {
+ llvm::Type *Type = Types.ConvertTypeForMem(FD->getType());
+ return useMSABI() || !FD->isBitField() ? Type :
+ getIntNType(std::min(FD->getBitWidthValue(Context),
+ (unsigned)Context.toBits(getSize(Type))));
+ }
+ /// \brief Gets the llvm Basesubobject type from a CXXRecordDecl.
+ llvm::Type *getStorageType(const CXXRecordDecl *RD) {
+ return Types.getCGRecordLayout(RD).getBaseSubobjectLLVMType();
+ }
+ CharUnits bitsToCharUnits(uint64_t BitOffset) {
+ return Context.toCharUnitsFromBits(BitOffset);
+ }
+ CharUnits getSize(llvm::Type *Type) {
+ return CharUnits::fromQuantity(DataLayout.getTypeAllocSize(Type));
+ }
+ CharUnits getAlignment(llvm::Type *Type) {
+ return CharUnits::fromQuantity(DataLayout.getABITypeAlignment(Type));
+ }
+ bool isZeroInitializable(const FieldDecl *FD) {
+ const Type *Type = FD->getType()->getBaseElementTypeUnsafe();
+ if (const MemberPointerType *MPT = Type->getAs<MemberPointerType>())
+ return Types.getCXXABI().isZeroInitializable(MPT);
+ if (const RecordType *RT = Type->getAs<RecordType>())
+ return isZeroInitializable(RT->getDecl());
+ return true;
+ }
+ bool isZeroInitializable(const RecordDecl *RD) {
+ return Types.getCGRecordLayout(RD).isZeroInitializable();
+ }
+ void appendPaddingBytes(CharUnits Size) {
+ if (!Size.isZero())
+ FieldTypes.push_back(getByteArrayType(Size));
+ }
+ uint64_t getFieldBitOffset(const FieldDecl *FD) {
+ return Layout.getFieldOffset(FD->getFieldIndex());
+ }
+ // Layout routines.
+ void setBitFieldInfo(const FieldDecl *FD, CharUnits StartOffset,
+ llvm::Type *StorageType);
+ /// \brief Lowers an ASTRecordLayout to a llvm type.
+ void lower(bool NonVirtualBaseType);
+ void lowerUnion();
+ void accumulateFields();
+ void accumulateBitFields(RecordDecl::field_iterator Field,
+ RecordDecl::field_iterator FieldEnd);
+ void accumulateBases();
+ void accumulateVPtrs();
+ void accumulateVBases();
+ /// \brief Recursively searches all of the bases to find out if a vbase is
+ /// not the primary vbase of some base class.
+ bool hasOwnStorage(const CXXRecordDecl *Decl, const CXXRecordDecl *Query);
+ void calculateZeroInit();
+ /// \brief Lowers bitfield storage types to I8 arrays for bitfields with tail
+ /// padding that is or can potentially be used.
+ void clipTailPadding();
+ /// \brief Determines if we need a packed llvm struct.
+ void determinePacked();
+ /// \brief Inserts padding everwhere it's needed.
+ void insertPadding();
+ /// \brief Fills out the structures that are ultimately consumed.
+ void fillOutputFields();
+ // Input memoization fields.
+ CodeGenTypes &Types;
+ const ASTContext &Context;
+ const RecordDecl *D;
+ const CXXRecordDecl *RD;
+ const ASTRecordLayout &Layout;
+ const llvm::DataLayout &DataLayout;
+ // Helpful intermediate data-structures.
+ std::vector<MemberInfo> Members;
+ // Output fields, consumed by CodeGenTypes::ComputeRecordLayout.
SmallVector<llvm::Type *, 16> FieldTypes;
-
- /// BaseSubobjectType - Holds the LLVM type for the non-virtual part
- /// of the struct. For example, consider:
- ///
- /// struct A { int i; };
- /// struct B { void *v; };
- /// struct C : virtual A, B { };
- ///
- /// The LLVM type of C will be
- /// %struct.C = type { i32 (...)**, %struct.A, i32, %struct.B }
- ///
- /// And the LLVM type of the non-virtual base struct will be
- /// %struct.C.base = type { i32 (...)**, %struct.A, i32 }
- ///
- /// This only gets initialized if the base subobject type is
- /// different from the complete-object type.
- llvm::StructType *BaseSubobjectType;
-
- /// FieldInfo - Holds a field and its corresponding LLVM field number.
llvm::DenseMap<const FieldDecl *, unsigned> Fields;
-
- /// BitFieldInfo - Holds location and size information about a bit field.
llvm::DenseMap<const FieldDecl *, CGBitFieldInfo> BitFields;
-
llvm::DenseMap<const CXXRecordDecl *, unsigned> NonVirtualBases;
llvm::DenseMap<const CXXRecordDecl *, unsigned> VirtualBases;
-
- /// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are
- /// primary base classes for some other direct or indirect base class.
- CXXIndirectPrimaryBaseSet IndirectPrimaryBases;
-
- /// LaidOutVirtualBases - A set of all laid out virtual bases, used to avoid
- /// avoid laying out virtual bases more than once.
- llvm::SmallPtrSet<const CXXRecordDecl *, 4> LaidOutVirtualBases;
-
- /// IsZeroInitializable - Whether this struct can be C++
- /// zero-initialized with an LLVM zeroinitializer.
- bool IsZeroInitializable;
- bool IsZeroInitializableAsBase;
-
- /// Packed - Whether the resulting LLVM struct will be packed or not.
- bool Packed;
-
+ bool IsZeroInitializable : 1;
+ bool IsZeroInitializableAsBase : 1;
+ bool Packed : 1;
private:
- CodeGenTypes &Types;
-
- /// LastLaidOutBaseInfo - Contains the offset and non-virtual size of the
- /// last base laid out. Used so that we can replace the last laid out base
- /// type with an i8 array if needed.
- struct LastLaidOutBaseInfo {
- CharUnits Offset;
- CharUnits NonVirtualSize;
-
- bool isValid() const { return !NonVirtualSize.isZero(); }
- void invalidate() { NonVirtualSize = CharUnits::Zero(); }
-
- } LastLaidOutBase;
-
- /// Alignment - Contains the alignment of the RecordDecl.
- CharUnits Alignment;
-
- /// NextFieldOffset - Holds the next field offset.
- CharUnits NextFieldOffset;
-
- /// LayoutUnionField - Will layout a field in an union and return the type
- /// that the field will have.
- llvm::Type *LayoutUnionField(const FieldDecl *Field,
- const ASTRecordLayout &Layout);
-
- /// LayoutUnion - Will layout a union RecordDecl.
- void LayoutUnion(const RecordDecl *D);
-
- /// Lay out a sequence of contiguous bitfields.
- bool LayoutBitfields(const ASTRecordLayout &Layout,
- unsigned &FirstFieldNo,
- RecordDecl::field_iterator &FI,
- RecordDecl::field_iterator FE);
-
- /// LayoutFields - try to layout all fields in the record decl.
- /// Returns false if the operation failed because the struct is not packed.
- bool LayoutFields(const RecordDecl *D);
-
- /// Layout a single base, virtual or non-virtual
- bool LayoutBase(const CXXRecordDecl *base,
- const CGRecordLayout &baseLayout,
- CharUnits baseOffset);
-
- /// LayoutVirtualBase - layout a single virtual base.
- bool LayoutVirtualBase(const CXXRecordDecl *base,
- CharUnits baseOffset);
-
- /// LayoutVirtualBases - layout the virtual bases of a record decl.
- bool LayoutVirtualBases(const CXXRecordDecl *RD,
- const ASTRecordLayout &Layout);
-
- /// MSLayoutVirtualBases - layout the virtual bases of a record decl,
- /// like MSVC.
- bool MSLayoutVirtualBases(const CXXRecordDecl *RD,
- const ASTRecordLayout &Layout);
-
- /// LayoutNonVirtualBase - layout a single non-virtual base.
- bool LayoutNonVirtualBase(const CXXRecordDecl *base,
- CharUnits baseOffset);
-
- /// LayoutNonVirtualBases - layout the virtual bases of a record decl.
- bool LayoutNonVirtualBases(const CXXRecordDecl *RD,
- const ASTRecordLayout &Layout);
-
- /// ComputeNonVirtualBaseType - Compute the non-virtual base field types.
- bool ComputeNonVirtualBaseType(const CXXRecordDecl *RD);
-
- /// LayoutField - layout a single field. Returns false if the operation failed
- /// because the current struct is not packed.
- bool LayoutField(const FieldDecl *D, uint64_t FieldOffset);
-
- /// LayoutBitField - layout a single bit field.
- void LayoutBitField(const FieldDecl *D, uint64_t FieldOffset);
-
- /// AppendField - Appends a field with the given offset and type.
- void AppendField(CharUnits fieldOffset, llvm::Type *FieldTy);
-
- /// AppendPadding - Appends enough padding bytes so that the total
- /// struct size is a multiple of the field alignment.
- void AppendPadding(CharUnits fieldOffset, CharUnits fieldAlignment);
-
- /// ResizeLastBaseFieldIfNecessary - Fields and bases can be laid out in the
- /// tail padding of a previous base. If this happens, the type of the previous
- /// base needs to be changed to an array of i8. Returns true if the last
- /// laid out base was resized.
- bool ResizeLastBaseFieldIfNecessary(CharUnits offset);
-
- /// getByteArrayType - Returns a byte array type with the given number of
- /// elements.
- llvm::Type *getByteArrayType(CharUnits NumBytes);
-
- /// AppendBytes - Append a given number of bytes to the record.
- void AppendBytes(CharUnits numBytes);
-
- /// AppendTailPadding - Append enough tail padding so that the type will have
- /// the passed size.
- void AppendTailPadding(CharUnits RecordSize);
-
- CharUnits getTypeAlignment(llvm::Type *Ty) const;
-
- /// getAlignmentAsLLVMStruct - Returns the maximum alignment of all the
- /// LLVM element types.
- CharUnits getAlignmentAsLLVMStruct() const;
-
- /// CheckZeroInitializable - Check if the given type contains a pointer
- /// to data member.
- void CheckZeroInitializable(QualType T);
-
-public:
- CGRecordLayoutBuilder(CodeGenTypes &Types)
- : BaseSubobjectType(0),
- IsZeroInitializable(true), IsZeroInitializableAsBase(true),
- Packed(false), Types(Types) { }
-
- /// Layout - Will layout a RecordDecl.
- void Layout(const RecordDecl *D);
+ CGRecordLowering(const CGRecordLowering &) LLVM_DELETED_FUNCTION;
+ void operator =(const CGRecordLowering &) LLVM_DELETED_FUNCTION;
};
-
-}
-
-void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
- const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D);
- Alignment = Layout.getAlignment();
- Packed = D->hasAttr<PackedAttr>() || Layout.getSize() % Alignment != 0;
-
- if (D->isUnion()) {
- LayoutUnion(D);
- return;
- }
-
- if (LayoutFields(D))
- return;
-
- // We weren't able to layout the struct. Try again with a packed struct
- Packed = true;
- LastLaidOutBase.invalidate();
- NextFieldOffset = CharUnits::Zero();
- FieldTypes.clear();
- Fields.clear();
- BitFields.clear();
- NonVirtualBases.clear();
- VirtualBases.clear();
-
- LayoutFields(D);
-}
-
-CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
- const FieldDecl *FD,
- uint64_t Offset, uint64_t Size,
- uint64_t StorageSize,
- uint64_t StorageAlignment) {
- llvm::Type *Ty = Types.ConvertTypeForMem(FD->getType());
- CharUnits TypeSizeInBytes =
- CharUnits::fromQuantity(Types.getDataLayout().getTypeAllocSize(Ty));
- uint64_t TypeSizeInBits = Types.getContext().toBits(TypeSizeInBytes);
-
- bool IsSigned = FD->getType()->isSignedIntegerOrEnumerationType();
-
- if (Size > TypeSizeInBits) {
- // We have a wide bit-field. The extra bits are only used for padding, so
- // if we have a bitfield of type T, with size N:
- //
- // T t : N;
- //
- // We can just assume that it's:
- //
- // T t : sizeof(T);
- //
- Size = TypeSizeInBits;
- }
-
+} // namespace {
+
+CGRecordLowering::CGRecordLowering(CodeGenTypes &Types, const RecordDecl *D)
+ : Types(Types), Context(Types.getContext()), D(D),
+ RD(dyn_cast<CXXRecordDecl>(D)),
+ Layout(Types.getContext().getASTRecordLayout(D)),
+ DataLayout(Types.getDataLayout()), IsZeroInitializable(true),
+ IsZeroInitializableAsBase(true), Packed(false) {}
+
+void CGRecordLowering::setBitFieldInfo(
+ const FieldDecl *FD, CharUnits StartOffset, llvm::Type *StorageType) {
+ CGBitFieldInfo &Info = BitFields[FD->getCanonicalDecl()];
+ Info.IsSigned = FD->getType()->isSignedIntegerOrEnumerationType();
+ Info.Offset = (unsigned)(getFieldBitOffset(FD) - Context.toBits(StartOffset));
+ Info.Size = FD->getBitWidthValue(Context);
+ Info.StorageSize = (unsigned)DataLayout.getTypeAllocSizeInBits(StorageType);
+ // Here we calculate the actual storage alignment of the bits. E.g if we've
+ // got an alignment >= 2 and the bitfield starts at offset 6 we've got an
+ // alignment of 2.
+ Info.StorageAlignment =
+ Layout.getAlignment().alignmentAtOffset(StartOffset).getQuantity();
+ if (Info.Size > Info.StorageSize)
+ Info.Size = Info.StorageSize;
// Reverse the bit offsets for big endian machines. Because we represent
// a bitfield as a single large integer load, we can imagine the bits
// counting from the most-significant-bit instead of the
// least-significant-bit.
- if (Types.getDataLayout().isBigEndian()) {
- Offset = StorageSize - (Offset + Size);
- }
-
- return CGBitFieldInfo(Offset, Size, IsSigned, StorageSize, StorageAlignment);
+ if (DataLayout.isBigEndian())
+ Info.Offset = Info.StorageSize - (Info.Offset + Info.Size);
}
-/// \brief Layout the range of bitfields from BFI to BFE as contiguous storage.
-bool CGRecordLayoutBuilder::LayoutBitfields(const ASTRecordLayout &Layout,
- unsigned &FirstFieldNo,
- RecordDecl::field_iterator &FI,
- RecordDecl::field_iterator FE) {
- assert(FI != FE);
- uint64_t FirstFieldOffset = Layout.getFieldOffset(FirstFieldNo);
- uint64_t NextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset);
-
- unsigned CharAlign = Types.getTarget().getCharAlign();
- assert(FirstFieldOffset % CharAlign == 0 &&
- "First field offset is misaligned");
- CharUnits FirstFieldOffsetInBytes
- = Types.getContext().toCharUnitsFromBits(FirstFieldOffset);
-
- unsigned StorageAlignment
- = llvm::MinAlign(Alignment.getQuantity(),
- FirstFieldOffsetInBytes.getQuantity());
-
- if (FirstFieldOffset < NextFieldOffsetInBits) {
- CharUnits FieldOffsetInCharUnits =
- Types.getContext().toCharUnitsFromBits(FirstFieldOffset);
-
- // Try to resize the last base field.
- if (!ResizeLastBaseFieldIfNecessary(FieldOffsetInCharUnits))
- llvm_unreachable("We must be able to resize the last base if we need to "
- "pack bits into it.");
-
- NextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset);
- assert(FirstFieldOffset >= NextFieldOffsetInBits);
- }
-
- // Append padding if necessary.
- AppendPadding(Types.getContext().toCharUnitsFromBits(FirstFieldOffset),
- CharUnits::One());
-
- // Find the last bitfield in a contiguous run of bitfields.
- RecordDecl::field_iterator BFI = FI;
- unsigned LastFieldNo = FirstFieldNo;
- uint64_t NextContiguousFieldOffset = FirstFieldOffset;
- for (RecordDecl::field_iterator FJ = FI;
- (FJ != FE && (*FJ)->isBitField() &&
- NextContiguousFieldOffset == Layout.getFieldOffset(LastFieldNo) &&
- (*FJ)->getBitWidthValue(Types.getContext()) != 0); FI = FJ++) {
- NextContiguousFieldOffset += (*FJ)->getBitWidthValue(Types.getContext());
- ++LastFieldNo;
-
- // We must use packed structs for packed fields, and also unnamed bit
- // fields since they don't affect the struct alignment.
- if (!Packed && ((*FJ)->hasAttr<PackedAttr>() || !(*FJ)->getDeclName()))
- return false;
- }
- RecordDecl::field_iterator BFE = llvm::next(FI);
- --LastFieldNo;
- assert(LastFieldNo >= FirstFieldNo && "Empty run of contiguous bitfields");
- FieldDecl *LastFD = *FI;
-
- // Find the last bitfield's offset, add its size, and round it up to the
- // character alignment to compute the storage required.
- uint64_t LastFieldOffset = Layout.getFieldOffset(LastFieldNo);
- uint64_t LastFieldSize = LastFD->getBitWidthValue(Types.getContext());
- uint64_t TotalBits = (LastFieldOffset + LastFieldSize) - FirstFieldOffset;
- CharUnits StorageBytes = Types.getContext().toCharUnitsFromBits(
- llvm::RoundUpToAlignment(TotalBits, CharAlign));
- uint64_t StorageBits = Types.getContext().toBits(StorageBytes);
-
- // Grow the storage to encompass any known padding in the layout when doing
- // so will make the storage a power-of-two. There are two cases when we can
- // do this. The first is when we have a subsequent field and can widen up to
- // its offset. The second is when the data size of the AST record layout is
- // past the end of the current storage. The latter is true when there is tail
- // padding on a struct and no members of a super class can be packed into it.
- //
- // Note that we widen the storage as much as possible here to express the
- // maximum latitude the language provides, and rely on the backend to lower
- // these in conjunction with shifts and masks to narrower operations where
- // beneficial.
- uint64_t EndOffset = Types.getContext().toBits(Layout.getDataSize());
- if (BFE != FE)
- // If there are more fields to be laid out, the offset at the end of the
- // bitfield is the offset of the next field in the record.
- EndOffset = Layout.getFieldOffset(LastFieldNo + 1);
- assert(EndOffset >= (FirstFieldOffset + TotalBits) &&
- "End offset is not past the end of the known storage bits.");
- uint64_t SpaceBits = EndOffset - FirstFieldOffset;
- uint64_t LongBits = Types.getTarget().getLongWidth();
- uint64_t WidenedBits = (StorageBits / LongBits) * LongBits +
- llvm::NextPowerOf2(StorageBits % LongBits - 1);
- assert(WidenedBits >= StorageBits && "Widening shrunk the bits!");
- if (WidenedBits <= SpaceBits) {
- StorageBits = WidenedBits;
- StorageBytes = Types.getContext().toCharUnitsFromBits(StorageBits);
- assert(StorageBits == (uint64_t)Types.getContext().toBits(StorageBytes));
- }
-
- unsigned FieldIndex = FieldTypes.size();
- AppendBytes(StorageBytes);
-
- // Now walk the bitfields associating them with this field of storage and
- // building up the bitfield specific info.
- unsigned FieldNo = FirstFieldNo;
- for (; BFI != BFE; ++BFI, ++FieldNo) {
- FieldDecl *FD = *BFI;
- uint64_t FieldOffset = Layout.getFieldOffset(FieldNo) - FirstFieldOffset;
- uint64_t FieldSize = FD->getBitWidthValue(Types.getContext());
- Fields[FD] = FieldIndex;
- BitFields[FD] = CGBitFieldInfo::MakeInfo(Types, FD, FieldOffset, FieldSize,
- StorageBits, StorageAlignment);
- }
- FirstFieldNo = LastFieldNo;
- return true;
+void CGRecordLowering::lower(bool NVBaseType) {
+ // The lowering process implemented in this function takes a variety of
+ // carefully ordered phases.
+ // 1) Store all members (fields and bases) in a list and sort them by offset.
+ // 2) Add a 1-byte capstone member at the Size of the structure.
+ // 3) Clip bitfield storages members if their tail padding is or might be
+ // used by another field or base. The clipping process uses the capstone
+ // by treating it as another object that occurs after the record.
+ // 4) Determine if the llvm-struct requires packing. It's important that this
+ // phase occur after clipping, because clipping changes the llvm type.
+ // This phase reads the offset of the capstone when determining packedness
+ // and updates the alignment of the capstone to be equal of the alignment
+ // of the record after doing so.
+ // 5) Insert padding everywhere it is needed. This phase requires 'Packed' to
+ // have been computed and needs to know the alignment of the record in
+ // order to understand if explicit tail padding is needed.
+ // 6) Remove the capstone, we don't need it anymore.
+ // 7) Determine if this record can be zero-initialized. This phase could have
+ // been placed anywhere after phase 1.
+ // 8) Format the complete list of members in a way that can be consumed by
+ // CodeGenTypes::ComputeRecordLayout.
+ CharUnits Size = NVBaseType ? Layout.getNonVirtualSize() : Layout.getSize();
+ if (D->isUnion())
+ return lowerUnion();
+ accumulateFields();
+ // RD implies C++.
+ if (RD) {
+ accumulateVPtrs();
+ accumulateBases();
+ if (Members.empty())
+ return appendPaddingBytes(Size);
+ if (!NVBaseType)
+ accumulateVBases();
+ }
+ std::stable_sort(Members.begin(), Members.end());
+ Members.push_back(StorageInfo(Size, getIntNType(8)));
+ clipTailPadding();
+ determinePacked();
+ insertPadding();
+ Members.pop_back();
+ calculateZeroInit();
+ fillOutputFields();
}
-bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
- uint64_t fieldOffset) {
- // If the field is packed, then we need a packed struct.
- if (!Packed && D->hasAttr<PackedAttr>())
- return false;
-
- assert(!D->isBitField() && "Bitfields should be laid out seperately.");
-
- CheckZeroInitializable(D->getType());
-
- assert(fieldOffset % Types.getTarget().getCharWidth() == 0
- && "field offset is not on a byte boundary!");
- CharUnits fieldOffsetInBytes
- = Types.getContext().toCharUnitsFromBits(fieldOffset);
-
- llvm::Type *Ty = Types.ConvertTypeForMem(D->getType());
- CharUnits typeAlignment = getTypeAlignment(Ty);
-
- // If the type alignment is larger then the struct alignment, we must use
- // a packed struct.
- if (typeAlignment > Alignment) {
- assert(!Packed && "Alignment is wrong even with packed struct!");
- return false;
- }
-
- if (!Packed) {
- if (const RecordType *RT = D->getType()->getAs<RecordType>()) {
- const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
- if (const MaxFieldAlignmentAttr *MFAA =
- RD->getAttr<MaxFieldAlignmentAttr>()) {
- if (MFAA->getAlignment() != Types.getContext().toBits(typeAlignment))
- return false;
- }
+void CGRecordLowering::lowerUnion() {
+ CharUnits LayoutSize = Layout.getSize();
+ llvm::Type *StorageType = nullptr;
+ // Compute zero-initializable status.
+ if (!D->field_empty() && !isZeroInitializable(*D->field_begin()))
+ IsZeroInitializable = IsZeroInitializableAsBase = false;
+ // Iterate through the fields setting bitFieldInfo and the Fields array. Also
+ // locate the "most appropriate" storage type. The heuristic for finding the
+ // storage type isn't necessary, the first (non-0-length-bitfield) field's
+ // type would work fine and be simpler but would be differen than what we've
+ // been doing and cause lit tests to change.
+ for (const auto *Field : D->fields()) {
+ if (Field->isBitField()) {
+ // Skip 0 sized bitfields.
+ if (Field->getBitWidthValue(Context) == 0)
+ continue;
+ llvm::Type *FieldType = getStorageType(Field);
+ if (LayoutSize < getSize(FieldType))
+ FieldType = getByteArrayType(LayoutSize);
+ setBitFieldInfo(Field, CharUnits::Zero(), FieldType);
}
- }
-
- // Round up the field offset to the alignment of the field type.
- CharUnits alignedNextFieldOffsetInBytes =
- NextFieldOffset.RoundUpToAlignment(typeAlignment);
+ Fields[Field->getCanonicalDecl()] = 0;
+ llvm::Type *FieldType = getStorageType(Field);
+ // Conditionally update our storage type if we've got a new "better" one.
+ if (!StorageType ||
+ getAlignment(FieldType) > getAlignment(StorageType) ||
+ (getAlignment(FieldType) == getAlignment(StorageType) &&
+ getSize(FieldType) > getSize(StorageType)))
+ StorageType = FieldType;
+ }
+ // If we have no storage type just pad to the appropriate size and return.
+ if (!StorageType)
+ return appendPaddingBytes(LayoutSize);
+ // If our storage size was bigger than our required size (can happen in the
+ // case of packed bitfields on Itanium) then just use an I8 array.
+ if (LayoutSize < getSize(StorageType))
+ StorageType = getByteArrayType(LayoutSize);
+ FieldTypes.push_back(StorageType);
+ appendPaddingBytes(LayoutSize - getSize(StorageType));
+ // Set packed if we need it.
+ if (LayoutSize % getAlignment(StorageType))
+ Packed = true;
+}
- if (fieldOffsetInBytes < alignedNextFieldOffsetInBytes) {
- // Try to resize the last base field.
- if (ResizeLastBaseFieldIfNecessary(fieldOffsetInBytes)) {
- alignedNextFieldOffsetInBytes =
- NextFieldOffset.RoundUpToAlignment(typeAlignment);
+void CGRecordLowering::accumulateFields() {
+ for (RecordDecl::field_iterator Field = D->field_begin(),
+ FieldEnd = D->field_end();
+ Field != FieldEnd;)
+ if (Field->isBitField()) {
+ RecordDecl::field_iterator Start = Field;
+ // Iterate to gather the list of bitfields.
+ for (++Field; Field != FieldEnd && Field->isBitField(); ++Field);
+ accumulateBitFields(Start, Field);
+ } else {
+ Members.push_back(MemberInfo(
+ bitsToCharUnits(getFieldBitOffset(*Field)), MemberInfo::Field,
+ getStorageType(*Field), *Field));
+ ++Field;
}
- }
-
- if (fieldOffsetInBytes < alignedNextFieldOffsetInBytes) {
- assert(!Packed && "Could not place field even with packed struct!");
- return false;
- }
-
- AppendPadding(fieldOffsetInBytes, typeAlignment);
-
- // Now append the field.
- Fields[D] = FieldTypes.size();
- AppendField(fieldOffsetInBytes, Ty);
-
- LastLaidOutBase.invalidate();
- return true;
}
-llvm::Type *
-CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field,
- const ASTRecordLayout &Layout) {
- Fields[Field] = 0;
- if (Field->isBitField()) {
- uint64_t FieldSize = Field->getBitWidthValue(Types.getContext());
-
- // Ignore zero sized bit fields.
- if (FieldSize == 0)
- return 0;
-
- unsigned StorageBits = llvm::RoundUpToAlignment(
- FieldSize, Types.getTarget().getCharAlign());
- CharUnits NumBytesToAppend
- = Types.getContext().toCharUnitsFromBits(StorageBits);
-
- llvm::Type *FieldTy = llvm::Type::getInt8Ty(Types.getLLVMContext());
- if (NumBytesToAppend > CharUnits::One())
- FieldTy = llvm::ArrayType::get(FieldTy, NumBytesToAppend.getQuantity());
-
- // Add the bit field info.
- BitFields[Field] = CGBitFieldInfo::MakeInfo(Types, Field, 0, FieldSize,
- StorageBits,
- Alignment.getQuantity());
- return FieldTy;
+void
+CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field,
+ RecordDecl::field_iterator FieldEnd) {
+ // Run stores the first element of the current run of bitfields. FieldEnd is
+ // used as a special value to note that we don't have a current run. A
+ // bitfield run is a contiguous collection of bitfields that can be stored in
+ // the same storage block. Zero-sized bitfields and bitfields that would
+ // cross an alignment boundary break a run and start a new one.
+ RecordDecl::field_iterator Run = FieldEnd;
+ // Tail is the offset of the first bit off the end of the current run. It's
+ // used to determine if the ASTRecordLayout is treating these two bitfields as
+ // contiguous. StartBitOffset is offset of the beginning of the Run.
+ uint64_t StartBitOffset, Tail = 0;
+ if (useMSABI()) {
+ for (; Field != FieldEnd; ++Field) {
+ uint64_t BitOffset = getFieldBitOffset(*Field);
+ // Zero-width bitfields end runs.
+ if (Field->getBitWidthValue(Context) == 0) {
+ Run = FieldEnd;
+ continue;
+ }
+ llvm::Type *Type = Types.ConvertTypeForMem(Field->getType());
+ // If we don't have a run yet, or don't live within the previous run's
+ // allocated storage then we allocate some storage and start a new run.
+ if (Run == FieldEnd || BitOffset >= Tail) {
+ Run = Field;
+ StartBitOffset = BitOffset;
+ Tail = StartBitOffset + DataLayout.getTypeAllocSizeInBits(Type);
+ // Add the storage member to the record. This must be added to the
+ // record before the bitfield members so that it gets laid out before
+ // the bitfields it contains get laid out.
+ Members.push_back(StorageInfo(bitsToCharUnits(StartBitOffset), Type));
+ }
+ // Bitfields get the offset of their storage but come afterward and remain
+ // there after a stable sort.
+ Members.push_back(MemberInfo(bitsToCharUnits(StartBitOffset),
+ MemberInfo::Field, nullptr, *Field));
+ }
+ return;
}
-
- // This is a regular union field.
- return Types.ConvertTypeForMem(Field->getType());
-}
-
-void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
- assert(D->isUnion() && "Can't call LayoutUnion on a non-union record!");
-
- const ASTRecordLayout &layout = Types.getContext().getASTRecordLayout(D);
-
- llvm::Type *unionType = 0;
- CharUnits unionSize = CharUnits::Zero();
- CharUnits unionAlign = CharUnits::Zero();
-
- bool hasOnlyZeroSizedBitFields = true;
- bool checkedFirstFieldZeroInit = false;
-
- unsigned fieldNo = 0;
- for (RecordDecl::field_iterator field = D->field_begin(),
- fieldEnd = D->field_end(); field != fieldEnd; ++field, ++fieldNo) {
- assert(layout.getFieldOffset(fieldNo) == 0 &&
- "Union field offset did not start at the beginning of record!");
- llvm::Type *fieldType = LayoutUnionField(*field, layout);
-
- if (!fieldType)
+ for (;;) {
+ // Check to see if we need to start a new run.
+ if (Run == FieldEnd) {
+ // If we're out of fields, return.
+ if (Field == FieldEnd)
+ break;
+ // Any non-zero-length bitfield can start a new run.
+ if (Field->getBitWidthValue(Context) != 0) {
+ Run = Field;
+ StartBitOffset = getFieldBitOffset(*Field);
+ Tail = StartBitOffset + Field->getBitWidthValue(Context);
+ }
+ ++Field;
continue;
-
- if (field->getDeclName() && !checkedFirstFieldZeroInit) {
- CheckZeroInitializable(field->getType());
- checkedFirstFieldZeroInit = true;
}
-
- hasOnlyZeroSizedBitFields = false;
-
- CharUnits fieldAlign = CharUnits::fromQuantity(
- Types.getDataLayout().getABITypeAlignment(fieldType));
- CharUnits fieldSize = CharUnits::fromQuantity(
- Types.getDataLayout().getTypeAllocSize(fieldType));
-
- if (fieldAlign < unionAlign)
+ // Add bitfields to the run as long as they qualify.
+ if (Field != FieldEnd && Field->getBitWidthValue(Context) != 0 &&
+ Tail == getFieldBitOffset(*Field)) {
+ Tail += Field->getBitWidthValue(Context);
+ ++Field;
continue;
-
- if (fieldAlign > unionAlign || fieldSize > unionSize) {
- unionType = fieldType;
- unionAlign = fieldAlign;
- unionSize = fieldSize;
- }
- }
-
- // Now add our field.
- if (unionType) {
- AppendField(CharUnits::Zero(), unionType);
-
- if (getTypeAlignment(unionType) > layout.getAlignment()) {
- // We need a packed struct.
- Packed = true;
- unionAlign = CharUnits::One();
}
+ // We've hit a break-point in the run and need to emit a storage field.
+ llvm::Type *Type = getIntNType(Tail - StartBitOffset);
+ // Add the storage member to the record and set the bitfield info for all of
+ // the bitfields in the run. Bitfields get the offset of their storage but
+ // come afterward and remain there after a stable sort.
+ Members.push_back(StorageInfo(bitsToCharUnits(StartBitOffset), Type));
+ for (; Run != Field; ++Run)
+ Members.push_back(MemberInfo(bitsToCharUnits(StartBitOffset),
+ MemberInfo::Field, nullptr, *Run));
+ Run = FieldEnd;
}
- if (unionAlign.isZero()) {
- (void)hasOnlyZeroSizedBitFields;
- assert(hasOnlyZeroSizedBitFields &&
- "0-align record did not have all zero-sized bit-fields!");
- unionAlign = CharUnits::One();
- }
-
- // Append tail padding.
- CharUnits recordSize = layout.getSize();
- if (recordSize > unionSize)
- AppendPadding(recordSize, unionAlign);
-}
-
-bool CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *base,
- const CGRecordLayout &baseLayout,
- CharUnits baseOffset) {
- ResizeLastBaseFieldIfNecessary(baseOffset);
-
- AppendPadding(baseOffset, CharUnits::One());
-
- const ASTRecordLayout &baseASTLayout
- = Types.getContext().getASTRecordLayout(base);
-
- LastLaidOutBase.Offset = NextFieldOffset;
- LastLaidOutBase.NonVirtualSize = baseASTLayout.getNonVirtualSize();
-
- llvm::StructType *subobjectType = baseLayout.getBaseSubobjectLLVMType();
- if (getTypeAlignment(subobjectType) > Alignment)
- return false;
-
- AppendField(baseOffset, subobjectType);
- return true;
}
-bool CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *base,
- CharUnits baseOffset) {
- // Ignore empty bases.
- if (base->isEmpty()) return true;
-
- const CGRecordLayout &baseLayout = Types.getCGRecordLayout(base);
- if (IsZeroInitializableAsBase) {
- assert(IsZeroInitializable &&
- "class zero-initializable as base but not as complete object");
-
- IsZeroInitializable = IsZeroInitializableAsBase =
- baseLayout.isZeroInitializableAsBase();
+void CGRecordLowering::accumulateBases() {
+ // If we've got a primary virtual base, we need to add it with the bases.
+ if (Layout.isPrimaryBaseVirtual()) {
+ const CXXRecordDecl *BaseDecl = Layout.getPrimaryBase();
+ Members.push_back(MemberInfo(CharUnits::Zero(), MemberInfo::Base,
+ getStorageType(BaseDecl), BaseDecl));
}
-
- if (!LayoutBase(base, baseLayout, baseOffset))
- return false;
- NonVirtualBases[base] = (FieldTypes.size() - 1);
- return true;
-}
-
-bool
-CGRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *base,
- CharUnits baseOffset) {
- // Ignore empty bases.
- if (base->isEmpty()) return true;
-
- const CGRecordLayout &baseLayout = Types.getCGRecordLayout(base);
- if (IsZeroInitializable)
- IsZeroInitializable = baseLayout.isZeroInitializableAsBase();
-
- if (!LayoutBase(base, baseLayout, baseOffset))
- return false;
- VirtualBases[base] = (FieldTypes.size() - 1);
- return true;
-}
-
-bool
-CGRecordLayoutBuilder::MSLayoutVirtualBases(const CXXRecordDecl *RD,
- const ASTRecordLayout &Layout) {
- if (!RD->getNumVBases())
- return true;
-
- // The vbases list is uniqued and ordered by a depth-first
- // traversal, which is what we need here.
- for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
- E = RD->vbases_end(); I != E; ++I) {
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
-
- CharUnits vbaseOffset = Layout.getVBaseClassOffset(BaseDecl);
- if (!LayoutVirtualBase(BaseDecl, vbaseOffset))
- return false;
+ // Accumulate the non-virtual bases.
+ for (const auto &Base : RD->bases()) {
+ if (Base.isVirtual())
+ continue;
+ const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
+ if (!BaseDecl->isEmpty())
+ Members.push_back(MemberInfo(Layout.getBaseClassOffset(BaseDecl),
+ MemberInfo::Base, getStorageType(BaseDecl), BaseDecl));
}
- return true;
}
-/// LayoutVirtualBases - layout the non-virtual bases of a record decl.
-bool
-CGRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
- const ASTRecordLayout &Layout) {
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+void CGRecordLowering::accumulateVPtrs() {
+ if (Layout.hasOwnVFPtr())
+ Members.push_back(MemberInfo(CharUnits::Zero(), MemberInfo::VFPtr,
+ llvm::FunctionType::get(getIntNType(32), /*isVarArg=*/true)->
+ getPointerTo()->getPointerTo()));
+ if (Layout.hasOwnVBPtr())
+ Members.push_back(MemberInfo(Layout.getVBPtrOffset(), MemberInfo::VBPtr,
+ llvm::Type::getInt32PtrTy(Types.getLLVMContext())));
+}
- // We only want to lay out virtual bases that aren't indirect primary bases
- // of some other base.
- if (I->isVirtual() && !IndirectPrimaryBases.count(BaseDecl)) {
- // Only lay out the base once.
- if (!LaidOutVirtualBases.insert(BaseDecl))
+void CGRecordLowering::accumulateVBases() {
+ CharUnits ScissorOffset = Layout.getNonVirtualSize();
+ // In the itanium ABI, it's possible to place a vbase at a dsize that is
+ // smaller than the nvsize. Here we check to see if such a base is placed
+ // before the nvsize and set the scissor offset to that, instead of the
+ // nvsize.
+ if (!useMSABI())
+ for (const auto &Base : RD->vbases()) {
+ const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
+ if (BaseDecl->isEmpty())
continue;
-
- CharUnits vbaseOffset = Layout.getVBaseClassOffset(BaseDecl);
- if (!LayoutVirtualBase(BaseDecl, vbaseOffset))
- return false;
+ // If the vbase is a primary virtual base of some base, then it doesn't
+ // get its own storage location but instead lives inside of that base.
+ if (Context.isNearlyEmpty(BaseDecl) && !hasOwnStorage(RD, BaseDecl))
+ continue;
+ ScissorOffset = std::min(ScissorOffset,
+ Layout.getVBaseClassOffset(BaseDecl));
}
-
- if (!BaseDecl->getNumVBases()) {
- // This base isn't interesting since it doesn't have any virtual bases.
+ Members.push_back(MemberInfo(ScissorOffset, MemberInfo::Scissor, nullptr,
+ RD));
+ for (const auto &Base : RD->vbases()) {
+ const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
+ if (BaseDecl->isEmpty())
+ continue;
+ CharUnits Offset = Layout.getVBaseClassOffset(BaseDecl);
+ // If the vbase is a primary virtual base of some base, then it doesn't
+ // get its own storage location but instead lives inside of that base.
+ if (!useMSABI() && Context.isNearlyEmpty(BaseDecl) &&
+ !hasOwnStorage(RD, BaseDecl)) {
+ Members.push_back(MemberInfo(Offset, MemberInfo::VBase, nullptr,
+ BaseDecl));
continue;
}
-
- if (!LayoutVirtualBases(BaseDecl, Layout))
- return false;
+ // If we've got a vtordisp, add it as a storage type.
+ if (Layout.getVBaseOffsetsMap().find(BaseDecl)->second.hasVtorDisp())
+ Members.push_back(StorageInfo(Offset - CharUnits::fromQuantity(4),
+ getIntNType(32)));
+ Members.push_back(MemberInfo(Offset, MemberInfo::VBase,
+ getStorageType(BaseDecl), BaseDecl));
}
- return true;
}
-bool
-CGRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD,
- const ASTRecordLayout &Layout) {
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
-
- // If we have a primary base, lay it out first.
- if (PrimaryBase) {
- if (!Layout.isPrimaryBaseVirtual()) {
- if (!LayoutNonVirtualBase(PrimaryBase, CharUnits::Zero()))
- return false;
- } else {
- if (!LayoutVirtualBase(PrimaryBase, CharUnits::Zero()))
- return false;
- }
-
- // Otherwise, add a vtable / vf-table if the layout says to do so.
- } else if (Layout.hasOwnVFPtr()) {
- llvm::Type *FunctionType =
- llvm::FunctionType::get(llvm::Type::getInt32Ty(Types.getLLVMContext()),
- /*isVarArg=*/true);
- llvm::Type *VTableTy = FunctionType->getPointerTo();
-
- if (getTypeAlignment(VTableTy) > Alignment) {
- // FIXME: Should we allow this to happen in Sema?
- assert(!Packed && "Alignment is wrong even with packed struct!");
- return false;
- }
-
- assert(NextFieldOffset.isZero() &&
- "VTable pointer must come first!");
- AppendField(CharUnits::Zero(), VTableTy->getPointerTo());
- }
-
- // Layout the non-virtual bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- if (I->isVirtual())
- continue;
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
-
- // We've already laid out the primary base.
- if (BaseDecl == PrimaryBase && !Layout.isPrimaryBaseVirtual())
- continue;
-
- if (!LayoutNonVirtualBase(BaseDecl, Layout.getBaseClassOffset(BaseDecl)))
+bool CGRecordLowering::hasOwnStorage(const CXXRecordDecl *Decl,
+ const CXXRecordDecl *Query) {
+ const ASTRecordLayout &DeclLayout = Context.getASTRecordLayout(Decl);
+ if (DeclLayout.isPrimaryBaseVirtual() && DeclLayout.getPrimaryBase() == Query)
+ return false;
+ for (const auto &Base : Decl->bases())
+ if (!hasOwnStorage(Base.getType()->getAsCXXRecordDecl(), Query))
return false;
- }
-
- // Add a vb-table pointer if the layout insists.
- if (Layout.hasOwnVBPtr()) {
- CharUnits VBPtrOffset = Layout.getVBPtrOffset();
- llvm::Type *Vbptr = llvm::Type::getInt32PtrTy(Types.getLLVMContext());
- AppendPadding(VBPtrOffset, getTypeAlignment(Vbptr));
- AppendField(VBPtrOffset, Vbptr);
- }
-
- return true;
-}
-
-bool
-CGRecordLayoutBuilder::ComputeNonVirtualBaseType(const CXXRecordDecl *RD) {
- const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(RD);
-
- CharUnits NonVirtualSize = Layout.getNonVirtualSize();
- CharUnits NonVirtualAlign = Layout.getNonVirtualAlign();
- CharUnits AlignedNonVirtualTypeSize =
- NonVirtualSize.RoundUpToAlignment(NonVirtualAlign);
-
- // First check if we can use the same fields as for the complete class.
- CharUnits RecordSize = Layout.getSize();
- if (AlignedNonVirtualTypeSize == RecordSize)
- return true;
-
- // Check if we need padding.
- CharUnits AlignedNextFieldOffset =
- NextFieldOffset.RoundUpToAlignment(getAlignmentAsLLVMStruct());
-
- if (AlignedNextFieldOffset > AlignedNonVirtualTypeSize) {
- assert(!Packed && "cannot layout even as packed struct");
- return false; // Needs packing.
- }
-
- bool needsPadding = (AlignedNonVirtualTypeSize != AlignedNextFieldOffset);
- if (needsPadding) {
- CharUnits NumBytes = AlignedNonVirtualTypeSize - AlignedNextFieldOffset;
- FieldTypes.push_back(getByteArrayType(NumBytes));
- }
-
- BaseSubobjectType = llvm::StructType::create(Types.getLLVMContext(),
- FieldTypes, "", Packed);
- Types.addRecordTypeName(RD, BaseSubobjectType, ".base");
-
- // Pull the padding back off.
- if (needsPadding)
- FieldTypes.pop_back();
-
return true;
}
-bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
- assert(!D->isUnion() && "Can't call LayoutFields on a union!");
- assert(!Alignment.isZero() && "Did not set alignment!");
-
- const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D);
-
- const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D);
- if (RD)
- if (!LayoutNonVirtualBases(RD, Layout))
- return false;
-
- unsigned FieldNo = 0;
-
- for (RecordDecl::field_iterator FI = D->field_begin(), FE = D->field_end();
- FI != FE; ++FI, ++FieldNo) {
- FieldDecl *FD = *FI;
-
- // If this field is a bitfield, layout all of the consecutive
- // non-zero-length bitfields and the last zero-length bitfield; these will
- // all share storage.
- if (FD->isBitField()) {
- // If all we have is a zero-width bitfield, skip it.
- if (FD->getBitWidthValue(Types.getContext()) == 0)
+void CGRecordLowering::calculateZeroInit() {
+ for (std::vector<MemberInfo>::const_iterator Member = Members.begin(),
+ MemberEnd = Members.end();
+ IsZeroInitializableAsBase && Member != MemberEnd; ++Member) {
+ if (Member->Kind == MemberInfo::Field) {
+ if (!Member->FD || isZeroInitializable(Member->FD))
continue;
-
- // Layout this range of bitfields.
- if (!LayoutBitfields(Layout, FieldNo, FI, FE)) {
- assert(!Packed &&
- "Could not layout bitfields even with a packed LLVM struct!");
- return false;
- }
- assert(FI != FE && "Advanced past the last bitfield");
- continue;
- }
-
- if (!LayoutField(FD, Layout.getFieldOffset(FieldNo))) {
- assert(!Packed &&
- "Could not layout fields even with a packed LLVM struct!");
- return false;
- }
- }
-
- if (RD) {
- // We've laid out the non-virtual bases and the fields, now compute the
- // non-virtual base field types.
- if (!ComputeNonVirtualBaseType(RD)) {
- assert(!Packed && "Could not layout even with a packed LLVM struct!");
- return false;
- }
-
- // Lay out the virtual bases. The MS ABI uses a different
- // algorithm here due to the lack of primary virtual bases.
- if (Types.getTarget().getCXXABI().hasPrimaryVBases()) {
- RD->getIndirectPrimaryBases(IndirectPrimaryBases);
- if (Layout.isPrimaryBaseVirtual())
- IndirectPrimaryBases.insert(Layout.getPrimaryBase());
-
- if (!LayoutVirtualBases(RD, Layout))
- return false;
- } else {
- if (!MSLayoutVirtualBases(RD, Layout))
- return false;
+ IsZeroInitializable = IsZeroInitializableAsBase = false;
+ } else if (Member->Kind == MemberInfo::Base ||
+ Member->Kind == MemberInfo::VBase) {
+ if (isZeroInitializable(Member->RD))
+ continue;
+ IsZeroInitializable = false;
+ if (Member->Kind == MemberInfo::Base)
+ IsZeroInitializableAsBase = false;
}
}
-
- // Append tail padding if necessary.
- AppendTailPadding(Layout.getSize());
-
- return true;
-}
-
-void CGRecordLayoutBuilder::AppendTailPadding(CharUnits RecordSize) {
- ResizeLastBaseFieldIfNecessary(RecordSize);
-
- assert(NextFieldOffset <= RecordSize && "Size mismatch!");
-
- CharUnits AlignedNextFieldOffset =
- NextFieldOffset.RoundUpToAlignment(getAlignmentAsLLVMStruct());
-
- if (AlignedNextFieldOffset == RecordSize) {
- // We don't need any padding.
- return;
- }
-
- CharUnits NumPadBytes = RecordSize - NextFieldOffset;
- AppendBytes(NumPadBytes);
-}
-
-void CGRecordLayoutBuilder::AppendField(CharUnits fieldOffset,
- llvm::Type *fieldType) {
- CharUnits fieldSize =
- CharUnits::fromQuantity(Types.getDataLayout().getTypeAllocSize(fieldType));
-
- FieldTypes.push_back(fieldType);
-
- NextFieldOffset = fieldOffset + fieldSize;
}
-void CGRecordLayoutBuilder::AppendPadding(CharUnits fieldOffset,
- CharUnits fieldAlignment) {
- assert(NextFieldOffset <= fieldOffset &&
- "Incorrect field layout!");
-
- // Do nothing if we're already at the right offset.
- if (fieldOffset == NextFieldOffset) return;
-
- // If we're not emitting a packed LLVM type, try to avoid adding
- // unnecessary padding fields.
- if (!Packed) {
- // Round up the field offset to the alignment of the field type.
- CharUnits alignedNextFieldOffset =
- NextFieldOffset.RoundUpToAlignment(fieldAlignment);
- assert(alignedNextFieldOffset <= fieldOffset);
-
- // If that's the right offset, we're done.
- if (alignedNextFieldOffset == fieldOffset) return;
+void CGRecordLowering::clipTailPadding() {
+ std::vector<MemberInfo>::iterator Prior = Members.begin();
+ CharUnits Tail = getSize(Prior->Data);
+ for (std::vector<MemberInfo>::iterator Member = Prior + 1,
+ MemberEnd = Members.end();
+ Member != MemberEnd; ++Member) {
+ // Only members with data and the scissor can cut into tail padding.
+ if (!Member->Data && Member->Kind != MemberInfo::Scissor)
+ continue;
+ if (Member->Offset < Tail) {
+ assert(Prior->Kind == MemberInfo::Field && !Prior->FD &&
+ "Only storage fields have tail padding!");
+ Prior->Data = getByteArrayType(bitsToCharUnits(llvm::RoundUpToAlignment(
+ cast<llvm::IntegerType>(Prior->Data)->getIntegerBitWidth(), 8)));
+ }
+ if (Member->Data)
+ Prior = Member;
+ Tail = Prior->Offset + getSize(Prior->Data);
}
-
- // Otherwise we need explicit padding.
- CharUnits padding = fieldOffset - NextFieldOffset;
- AppendBytes(padding);
-}
-
-bool CGRecordLayoutBuilder::ResizeLastBaseFieldIfNecessary(CharUnits offset) {
- // Check if we have a base to resize.
- if (!LastLaidOutBase.isValid())
- return false;
-
- // This offset does not overlap with the tail padding.
- if (offset >= NextFieldOffset)
- return false;
-
- // Restore the field offset and append an i8 array instead.
- FieldTypes.pop_back();
- NextFieldOffset = LastLaidOutBase.Offset;
- AppendBytes(LastLaidOutBase.NonVirtualSize);
- LastLaidOutBase.invalidate();
-
- return true;
}
-llvm::Type *CGRecordLayoutBuilder::getByteArrayType(CharUnits numBytes) {
- assert(!numBytes.isZero() && "Empty byte arrays aren't allowed.");
-
- llvm::Type *Ty = llvm::Type::getInt8Ty(Types.getLLVMContext());
- if (numBytes > CharUnits::One())
- Ty = llvm::ArrayType::get(Ty, numBytes.getQuantity());
-
- return Ty;
+void CGRecordLowering::determinePacked() {
+ CharUnits Alignment = CharUnits::One();
+ for (std::vector<MemberInfo>::const_iterator Member = Members.begin(),
+ MemberEnd = Members.end();
+ Member != MemberEnd; ++Member) {
+ if (!Member->Data)
+ continue;
+ // If any member falls at an offset that it not a multiple of its alignment,
+ // then the entire record must be packed.
+ if (Member->Offset % getAlignment(Member->Data))
+ Packed = true;
+ Alignment = std::max(Alignment, getAlignment(Member->Data));
+ }
+ // If the size of the record (the capstone's offset) is not a multiple of the
+ // record's alignment, it must be packed.
+ if (Members.back().Offset % Alignment)
+ Packed = true;
+ // Update the alignment of the sentinal.
+ if (!Packed)
+ Members.back().Data = getIntNType(Context.toBits(Alignment));
}
-void CGRecordLayoutBuilder::AppendBytes(CharUnits numBytes) {
- if (numBytes.isZero())
+void CGRecordLowering::insertPadding() {
+ std::vector<std::pair<CharUnits, CharUnits> > Padding;
+ CharUnits Size = CharUnits::Zero();
+ for (std::vector<MemberInfo>::const_iterator Member = Members.begin(),
+ MemberEnd = Members.end();
+ Member != MemberEnd; ++Member) {
+ if (!Member->Data)
+ continue;
+ CharUnits Offset = Member->Offset;
+ assert(Offset >= Size);
+ // Insert padding if we need to.
+ if (Offset != Size.RoundUpToAlignment(Packed ? CharUnits::One() :
+ getAlignment(Member->Data)))
+ Padding.push_back(std::make_pair(Size, Offset - Size));
+ Size = Offset + getSize(Member->Data);
+ }
+ if (Padding.empty())
return;
-
- // Append the padding field
- AppendField(NextFieldOffset, getByteArrayType(numBytes));
+ // Add the padding to the Members list and sort it.
+ for (std::vector<std::pair<CharUnits, CharUnits> >::const_iterator
+ Pad = Padding.begin(), PadEnd = Padding.end();
+ Pad != PadEnd; ++Pad)
+ Members.push_back(StorageInfo(Pad->first, getByteArrayType(Pad->second)));
+ std::stable_sort(Members.begin(), Members.end());
}
-CharUnits CGRecordLayoutBuilder::getTypeAlignment(llvm::Type *Ty) const {
- if (Packed)
- return CharUnits::One();
-
- return CharUnits::fromQuantity(Types.getDataLayout().getABITypeAlignment(Ty));
-}
-
-CharUnits CGRecordLayoutBuilder::getAlignmentAsLLVMStruct() const {
- if (Packed)
- return CharUnits::One();
-
- CharUnits maxAlignment = CharUnits::One();
- for (size_t i = 0; i != FieldTypes.size(); ++i)
- maxAlignment = std::max(maxAlignment, getTypeAlignment(FieldTypes[i]));
-
- return maxAlignment;
+void CGRecordLowering::fillOutputFields() {
+ for (std::vector<MemberInfo>::const_iterator Member = Members.begin(),
+ MemberEnd = Members.end();
+ Member != MemberEnd; ++Member) {
+ if (Member->Data)
+ FieldTypes.push_back(Member->Data);
+ if (Member->Kind == MemberInfo::Field) {
+ if (Member->FD)
+ Fields[Member->FD->getCanonicalDecl()] = FieldTypes.size() - 1;
+ // A field without storage must be a bitfield.
+ if (!Member->Data)
+ setBitFieldInfo(Member->FD, Member->Offset, FieldTypes.back());
+ } else if (Member->Kind == MemberInfo::Base)
+ NonVirtualBases[Member->RD] = FieldTypes.size() - 1;
+ else if (Member->Kind == MemberInfo::VBase)
+ VirtualBases[Member->RD] = FieldTypes.size() - 1;
+ }
}
-/// Merge in whether a field of the given type is zero-initializable.
-void CGRecordLayoutBuilder::CheckZeroInitializable(QualType T) {
- // This record already contains a member pointer.
- if (!IsZeroInitializableAsBase)
- return;
+CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
+ const FieldDecl *FD,
+ uint64_t Offset, uint64_t Size,
+ uint64_t StorageSize,
+ uint64_t StorageAlignment) {
+ // This function is vestigial from CGRecordLayoutBuilder days but is still
+ // used in GCObjCRuntime.cpp. That usage has a "fixme" attached to it that
+ // when addressed will allow for the removal of this function.
+ llvm::Type *Ty = Types.ConvertTypeForMem(FD->getType());
+ CharUnits TypeSizeInBytes =
+ CharUnits::fromQuantity(Types.getDataLayout().getTypeAllocSize(Ty));
+ uint64_t TypeSizeInBits = Types.getContext().toBits(TypeSizeInBytes);
- // Can only have member pointers if we're compiling C++.
- if (!Types.getContext().getLangOpts().CPlusPlus)
- return;
+ bool IsSigned = FD->getType()->isSignedIntegerOrEnumerationType();
- const Type *elementType = T->getBaseElementTypeUnsafe();
+ if (Size > TypeSizeInBits) {
+ // We have a wide bit-field. The extra bits are only used for padding, so
+ // if we have a bitfield of type T, with size N:
+ //
+ // T t : N;
+ //
+ // We can just assume that it's:
+ //
+ // T t : sizeof(T);
+ //
+ Size = TypeSizeInBits;
+ }
- if (const MemberPointerType *MPT = elementType->getAs<MemberPointerType>()) {
- if (!Types.getCXXABI().isZeroInitializable(MPT))
- IsZeroInitializable = IsZeroInitializableAsBase = false;
- } else if (const RecordType *RT = elementType->getAs<RecordType>()) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
- if (!Layout.isZeroInitializable())
- IsZeroInitializable = IsZeroInitializableAsBase = false;
+ // Reverse the bit offsets for big endian machines. Because we represent
+ // a bitfield as a single large integer load, we can imagine the bits
+ // counting from the most-significant-bit instead of the
+ // least-significant-bit.
+ if (Types.getDataLayout().isBigEndian()) {
+ Offset = StorageSize - (Offset + Size);
}
+
+ return CGBitFieldInfo(Offset, Size, IsSigned, StorageSize, StorageAlignment);
}
CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
llvm::StructType *Ty) {
- CGRecordLayoutBuilder Builder(*this);
+ CGRecordLowering Builder(*this, D);
- Builder.Layout(D);
-
- Ty->setBody(Builder.FieldTypes, Builder.Packed);
+ Builder.lower(false);
// If we're in C++, compute the base subobject type.
- llvm::StructType *BaseTy = 0;
- if (isa<CXXRecordDecl>(D) && !D->isUnion()) {
- BaseTy = Builder.BaseSubobjectType;
- if (!BaseTy) BaseTy = Ty;
+ llvm::StructType *BaseTy = nullptr;
+ if (isa<CXXRecordDecl>(D) && !D->isUnion() && !D->hasAttr<FinalAttr>()) {
+ BaseTy = Ty;
+ if (Builder.Layout.getNonVirtualSize() != Builder.Layout.getSize()) {
+ CGRecordLowering BaseBuilder(*this, D);
+ BaseBuilder.lower(true);
+ BaseTy = llvm::StructType::create(
+ getLLVMContext(), BaseBuilder.FieldTypes, "", BaseBuilder.Packed);
+ addRecordTypeName(D, BaseTy, ".base");
+ }
}
+ // Fill in the struct *after* computing the base type. Filling in the body
+ // signifies that the type is no longer opaque and record layout is complete,
+ // but we may need to recursively layout D while laying D out as a base type.
+ Ty->setBody(Builder.FieldTypes, Builder.Packed);
+
CGRecordLayout *RL =
new CGRecordLayout(Ty, BaseTy, Builder.IsZeroInitializable,
- Builder.IsZeroInitializableAsBase);
+ Builder.IsZeroInitializableAsBase);
RL->NonVirtualBases.swap(Builder.NonVirtualBases);
RL->CompleteObjectVirtualBases.swap(Builder.VirtualBases);
@@ -994,12 +695,9 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
if (BaseTy) {
CharUnits NonVirtualSize = Layout.getNonVirtualSize();
- CharUnits NonVirtualAlign = Layout.getNonVirtualAlign();
- CharUnits AlignedNonVirtualTypeSize =
- NonVirtualSize.RoundUpToAlignment(NonVirtualAlign);
uint64_t AlignedNonVirtualTypeSizeInBits =
- getContext().toBits(AlignedNonVirtualTypeSize);
+ getContext().toBits(NonVirtualSize);
assert(AlignedNonVirtualTypeSizeInBits ==
getDataLayout().getTypeAllocSizeInBits(BaseTy) &&
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 0bc51ddb5178..c2b64a7662b6 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -16,14 +16,15 @@
#include "CodeGenModule.h"
#include "TargetInfo.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Sema/LoopHint.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/IR/CallSite.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Intrinsics.h"
-#include "llvm/Support/CallSite.h"
using namespace clang;
using namespace CodeGen;
@@ -43,6 +44,7 @@ void CodeGenFunction::EmitStopPoint(const Stmt *S) {
void CodeGenFunction::EmitStmt(const Stmt *S) {
assert(S && "Null statement?");
+ PGO.setCurrentStmt(S);
// These statements have their own debug info handling.
if (EmitSimpleStmt(S))
@@ -75,7 +77,6 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::SEHExceptStmtClass:
case Stmt::SEHFinallyStmtClass:
case Stmt::MSDependentExistsStmtClass:
- case Stmt::OMPParallelDirectiveClass:
llvm_unreachable("invalid statement class to emit generically");
case Stmt::NullStmtClass:
case Stmt::CompoundStmtClass:
@@ -172,6 +173,54 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::SEHTryStmtClass:
EmitSEHTryStmt(cast<SEHTryStmt>(*S));
break;
+ case Stmt::SEHLeaveStmtClass:
+ EmitSEHLeaveStmt(cast<SEHLeaveStmt>(*S));
+ break;
+ case Stmt::OMPParallelDirectiveClass:
+ EmitOMPParallelDirective(cast<OMPParallelDirective>(*S));
+ break;
+ case Stmt::OMPSimdDirectiveClass:
+ EmitOMPSimdDirective(cast<OMPSimdDirective>(*S));
+ break;
+ case Stmt::OMPForDirectiveClass:
+ EmitOMPForDirective(cast<OMPForDirective>(*S));
+ break;
+ case Stmt::OMPSectionsDirectiveClass:
+ EmitOMPSectionsDirective(cast<OMPSectionsDirective>(*S));
+ break;
+ case Stmt::OMPSectionDirectiveClass:
+ EmitOMPSectionDirective(cast<OMPSectionDirective>(*S));
+ break;
+ case Stmt::OMPSingleDirectiveClass:
+ EmitOMPSingleDirective(cast<OMPSingleDirective>(*S));
+ break;
+ case Stmt::OMPMasterDirectiveClass:
+ EmitOMPMasterDirective(cast<OMPMasterDirective>(*S));
+ break;
+ case Stmt::OMPCriticalDirectiveClass:
+ EmitOMPCriticalDirective(cast<OMPCriticalDirective>(*S));
+ break;
+ case Stmt::OMPParallelForDirectiveClass:
+ EmitOMPParallelForDirective(cast<OMPParallelForDirective>(*S));
+ break;
+ case Stmt::OMPParallelSectionsDirectiveClass:
+ EmitOMPParallelSectionsDirective(cast<OMPParallelSectionsDirective>(*S));
+ break;
+ case Stmt::OMPTaskDirectiveClass:
+ EmitOMPTaskDirective(cast<OMPTaskDirective>(*S));
+ break;
+ case Stmt::OMPTaskyieldDirectiveClass:
+ EmitOMPTaskyieldDirective(cast<OMPTaskyieldDirective>(*S));
+ break;
+ case Stmt::OMPBarrierDirectiveClass:
+ EmitOMPBarrierDirective(cast<OMPBarrierDirective>(*S));
+ break;
+ case Stmt::OMPTaskwaitDirectiveClass:
+ EmitOMPTaskwaitDirective(cast<OMPTaskwaitDirective>(*S));
+ break;
+ case Stmt::OMPFlushDirectiveClass:
+ EmitOMPFlushDirective(cast<OMPFlushDirective>(*S));
+ break;
}
}
@@ -217,7 +266,7 @@ CodeGenFunction::EmitCompoundStmtWithoutScope(const CompoundStmt &S,
E = S.body_end()-GetLast; I != E; ++I)
EmitStmt(*I);
- llvm::Value *RetAlloca = 0;
+ llvm::Value *RetAlloca = nullptr;
if (GetLast) {
// We have to special case labels here. They are statements, but when put
// at the end of a statement expression, they yield the value of their
@@ -242,7 +291,7 @@ CodeGenFunction::EmitCompoundStmtWithoutScope(const CompoundStmt &S,
EmitAnyExprToMem(cast<Expr>(LastStmt), RetAlloca, Qualifiers(),
/*IsInit*/false);
}
-
+
}
return RetAlloca;
@@ -309,9 +358,8 @@ void CodeGenFunction::EmitBranch(llvm::BasicBlock *Target) {
void CodeGenFunction::EmitBlockAfterUses(llvm::BasicBlock *block) {
bool inserted = false;
- for (llvm::BasicBlock::use_iterator
- i = block->use_begin(), e = block->use_end(); i != e; ++i) {
- if (llvm::Instruction *insn = dyn_cast<llvm::Instruction>(*i)) {
+ for (llvm::User *u : block->users()) {
+ if (llvm::Instruction *insn = dyn_cast<llvm::Instruction>(u)) {
CurFn->getBasicBlockList().insertAfter(insn->getParent(), block);
inserted = true;
break;
@@ -358,7 +406,9 @@ void CodeGenFunction::EmitLabel(const LabelDecl *D) {
ResolveBranchFixups(Dest.getBlock());
}
+ RegionCounter Cnt = getPGORegionCounter(D->getStmt());
EmitBlock(Dest.getBlock());
+ Cnt.beginRegion(Builder);
}
/// Change the cleanup scope of the labels in this lexical scope to
@@ -391,7 +441,23 @@ void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
}
void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
- EmitStmt(S.getSubStmt());
+ const Stmt *SubStmt = S.getSubStmt();
+ switch (SubStmt->getStmtClass()) {
+ case Stmt::DoStmtClass:
+ EmitDoStmt(cast<DoStmt>(*SubStmt), S.getAttrs());
+ break;
+ case Stmt::ForStmtClass:
+ EmitForStmt(cast<ForStmt>(*SubStmt), S.getAttrs());
+ break;
+ case Stmt::WhileStmtClass:
+ EmitWhileStmt(cast<WhileStmt>(*SubStmt), S.getAttrs());
+ break;
+ case Stmt::CXXForRangeStmtClass:
+ EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*SubStmt), S.getAttrs());
+ break;
+ default:
+ EmitStmt(SubStmt);
+ }
}
void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
@@ -429,7 +495,8 @@ void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) {
void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
// C99 6.8.4.1: The first substatement is executed if the expression compares
// unequal to 0. The condition must be a scalar type.
- LexicalScope ConditionScope(*this, S.getSourceRange());
+ LexicalScope ConditionScope(*this, S.getCond()->getSourceRange());
+ RegionCounter Cnt = getPGORegionCounter(&S);
if (S.getConditionVariable())
EmitAutoVarDecl(*S.getConditionVariable());
@@ -447,6 +514,8 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
// If the skipped block has no labels in it, just emit the executed block.
// This avoids emitting dead code and simplifies the CFG substantially.
if (!ContainsLabel(Skipped)) {
+ if (CondConstant)
+ Cnt.beginRegion(Builder);
if (Executed) {
RunCleanupsScope ExecutedScope(*this);
EmitStmt(Executed);
@@ -462,10 +531,12 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
llvm::BasicBlock *ElseBlock = ContBlock;
if (S.getElse())
ElseBlock = createBasicBlock("if.else");
- EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock);
+
+ EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock, Cnt.getCount());
// Emit the 'then' code.
- EmitBlock(ThenBlock);
+ EmitBlock(ThenBlock);
+ Cnt.beginRegion(Builder);
{
RunCleanupsScope ThenScope(*this);
EmitStmt(S.getThen());
@@ -474,30 +545,121 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
// Emit the 'else' code if present.
if (const Stmt *Else = S.getElse()) {
- // There is no need to emit line number for unconditional branch.
- if (getDebugInfo())
- Builder.SetCurrentDebugLocation(llvm::DebugLoc());
- EmitBlock(ElseBlock);
+ {
+ // There is no need to emit line number for unconditional branch.
+ SuppressDebugLocation S(Builder);
+ EmitBlock(ElseBlock);
+ }
{
RunCleanupsScope ElseScope(*this);
EmitStmt(Else);
}
- // There is no need to emit line number for unconditional branch.
- if (getDebugInfo())
- Builder.SetCurrentDebugLocation(llvm::DebugLoc());
- EmitBranch(ContBlock);
+ {
+ // There is no need to emit line number for unconditional branch.
+ SuppressDebugLocation S(Builder);
+ EmitBranch(ContBlock);
+ }
}
// Emit the continuation block for code after the if.
EmitBlock(ContBlock, true);
}
-void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
+void CodeGenFunction::EmitCondBrHints(llvm::LLVMContext &Context,
+ llvm::BranchInst *CondBr,
+ const ArrayRef<const Attr *> &Attrs) {
+ // Return if there are no hints.
+ if (Attrs.empty())
+ return;
+
+ // Add vectorize and unroll hints to the metadata on the conditional branch.
+ SmallVector<llvm::Value *, 2> Metadata(1);
+ for (const auto *Attr : Attrs) {
+ const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(Attr);
+
+ // Skip non loop hint attributes
+ if (!LH)
+ continue;
+
+ LoopHintAttr::OptionType Option = LH->getOption();
+ int ValueInt = LH->getValue();
+
+ const char *MetadataName;
+ switch (Option) {
+ case LoopHintAttr::Vectorize:
+ case LoopHintAttr::VectorizeWidth:
+ MetadataName = "llvm.loop.vectorize.width";
+ break;
+ case LoopHintAttr::Interleave:
+ case LoopHintAttr::InterleaveCount:
+ MetadataName = "llvm.loop.interleave.count";
+ break;
+ case LoopHintAttr::Unroll:
+ MetadataName = "llvm.loop.unroll.enable";
+ break;
+ case LoopHintAttr::UnrollCount:
+ MetadataName = "llvm.loop.unroll.count";
+ break;
+ }
+
+ llvm::Value *Value;
+ llvm::MDString *Name;
+ switch (Option) {
+ case LoopHintAttr::Vectorize:
+ case LoopHintAttr::Interleave:
+ if (ValueInt == 1) {
+ // FIXME: In the future I will modifiy the behavior of the metadata
+ // so we can enable/disable vectorization and interleaving separately.
+ Name = llvm::MDString::get(Context, "llvm.loop.vectorize.enable");
+ Value = Builder.getTrue();
+ break;
+ }
+ // Vectorization/interleaving is disabled, set width/count to 1.
+ ValueInt = 1;
+ // Fallthrough.
+ case LoopHintAttr::VectorizeWidth:
+ case LoopHintAttr::InterleaveCount:
+ Name = llvm::MDString::get(Context, MetadataName);
+ Value = llvm::ConstantInt::get(Int32Ty, ValueInt);
+ break;
+ case LoopHintAttr::Unroll:
+ Name = llvm::MDString::get(Context, MetadataName);
+ Value = (ValueInt == 0) ? Builder.getFalse() : Builder.getTrue();
+ break;
+ case LoopHintAttr::UnrollCount:
+ Name = llvm::MDString::get(Context, MetadataName);
+ Value = llvm::ConstantInt::get(Int32Ty, ValueInt);
+ break;
+ }
+
+ SmallVector<llvm::Value *, 2> OpValues;
+ OpValues.push_back(Name);
+ OpValues.push_back(Value);
+
+ // Set or overwrite metadata indicated by Name.
+ Metadata.push_back(llvm::MDNode::get(Context, OpValues));
+ }
+
+ if (!Metadata.empty()) {
+ // Add llvm.loop MDNode to CondBr.
+ llvm::MDNode *LoopID = llvm::MDNode::get(Context, Metadata);
+ LoopID->replaceOperandWith(0, LoopID); // First op points to itself.
+
+ CondBr->setMetadata("llvm.loop", LoopID);
+ }
+}
+
+void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
+ const ArrayRef<const Attr *> &WhileAttrs) {
+ RegionCounter Cnt = getPGORegionCounter(&S);
+
// Emit the header for the loop, which will also become
// the continue target.
JumpDest LoopHeader = getJumpDestInCurrentScope("while.cond");
EmitBlock(LoopHeader.getBlock());
+ LoopStack.push(LoopHeader.getBlock());
+
// Create an exit block for when the condition fails, which will
// also become the break target.
JumpDest LoopExit = getJumpDestInCurrentScope("while.end");
@@ -535,13 +697,17 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
if (ConditionScope.requiresCleanups())
ExitBlock = createBasicBlock("while.exit");
-
- Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock);
+ llvm::BranchInst *CondBr =
+ Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock,
+ PGO.createLoopWeights(S.getCond(), Cnt));
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
EmitBranchThroughCleanup(LoopExit);
}
+
+ // Attach metadata to loop body conditional branch.
+ EmitCondBrHints(LoopBody->getContext(), CondBr, WhileAttrs);
}
// Emit the loop body. We have to emit this in a cleanup scope
@@ -549,6 +715,7 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
{
RunCleanupsScope BodyScope(*this);
EmitBlock(LoopBody);
+ Cnt.beginRegion(Builder);
EmitStmt(S.getBody());
}
@@ -560,6 +727,8 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
// Branch to the loop header again.
EmitBranch(LoopHeader.getBlock());
+ LoopStack.pop();
+
// Emit the exit block.
EmitBlock(LoopExit.getBlock(), true);
@@ -569,23 +738,27 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
SimplifyForwardingBlocks(LoopHeader.getBlock());
}
-void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
+void CodeGenFunction::EmitDoStmt(const DoStmt &S,
+ const ArrayRef<const Attr *> &DoAttrs) {
JumpDest LoopExit = getJumpDestInCurrentScope("do.end");
JumpDest LoopCond = getJumpDestInCurrentScope("do.cond");
+ RegionCounter Cnt = getPGORegionCounter(&S);
+
// Store the blocks to use for break and continue.
BreakContinueStack.push_back(BreakContinue(LoopExit, LoopCond));
// Emit the body of the loop.
llvm::BasicBlock *LoopBody = createBasicBlock("do.body");
- EmitBlock(LoopBody);
+
+ LoopStack.push(LoopBody);
+
+ EmitBlockWithFallThrough(LoopBody, Cnt);
{
RunCleanupsScope BodyScope(*this);
EmitStmt(S.getBody());
}
- BreakContinueStack.pop_back();
-
EmitBlock(LoopCond.getBlock());
// C99 6.8.5.2: "The evaluation of the controlling expression takes place
@@ -596,6 +769,8 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
// compares unequal to 0. The condition must be a scalar type.
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
+ BreakContinueStack.pop_back();
+
// "do {} while (0)" is common in macros, avoid extra blocks. Be sure
// to correctly handle break/continue though.
bool EmitBoolCondBranch = true;
@@ -604,8 +779,16 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
EmitBoolCondBranch = false;
// As long as the condition is true, iterate the loop.
- if (EmitBoolCondBranch)
- Builder.CreateCondBr(BoolCondVal, LoopBody, LoopExit.getBlock());
+ if (EmitBoolCondBranch) {
+ llvm::BranchInst *CondBr =
+ Builder.CreateCondBr(BoolCondVal, LoopBody, LoopExit.getBlock(),
+ PGO.createLoopWeights(S.getCond(), Cnt));
+
+ // Attach metadata to loop body conditional branch.
+ EmitCondBrHints(LoopBody->getContext(), CondBr, DoAttrs);
+ }
+
+ LoopStack.pop();
// Emit the exit block.
EmitBlock(LoopExit.getBlock());
@@ -616,7 +799,8 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
SimplifyForwardingBlocks(LoopCond.getBlock());
}
-void CodeGenFunction::EmitForStmt(const ForStmt &S) {
+void CodeGenFunction::EmitForStmt(const ForStmt &S,
+ const ArrayRef<const Attr *> &ForAttrs) {
JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
RunCleanupsScope ForScope(*this);
@@ -629,6 +813,8 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
if (S.getInit())
EmitStmt(S.getInit());
+ RegionCounter Cnt = getPGORegionCounter(&S);
+
// Start the loop with a block that tests the condition.
// If there's an increment, the continue scope will be overwritten
// later.
@@ -636,6 +822,18 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
llvm::BasicBlock *CondBlock = Continue.getBlock();
EmitBlock(CondBlock);
+ LoopStack.push(CondBlock);
+
+ // If the for loop doesn't have an increment we can just use the
+ // condition as the continue block. Otherwise we'll need to create
+ // a block for it (in the current scope, i.e. in the scope of the
+ // condition), and that we will become our continue block.
+ if (S.getInc())
+ Continue = getJumpDestInCurrentScope("for.inc");
+
+ // Store the blocks to use for break and continue.
+ BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
+
// Create a cleanup scope for the condition variable cleanups.
RunCleanupsScope ConditionScope(*this);
@@ -657,7 +855,13 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
// C99 6.8.5p2/p4: The first substatement is executed if the expression
// compares unequal to 0. The condition must be a scalar type.
- EmitBranchOnBoolExpr(S.getCond(), ForBody, ExitBlock);
+ llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
+ llvm::BranchInst *CondBr =
+ Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock,
+ PGO.createLoopWeights(S.getCond(), Cnt));
+
+ // Attach metadata to loop body conditional branch.
+ EmitCondBrHints(ForBody->getContext(), CondBr, ForAttrs);
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
@@ -669,16 +873,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
// Treat it as a non-zero constant. Don't even create a new block for the
// body, just fall into it.
}
-
- // If the for loop doesn't have an increment we can just use the
- // condition as the continue block. Otherwise we'll need to create
- // a block for it (in the current scope, i.e. in the scope of the
- // condition), and that we will become our continue block.
- if (S.getInc())
- Continue = getJumpDestInCurrentScope("for.inc");
-
- // Store the blocks to use for break and continue.
- BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
+ Cnt.beginRegion(Builder);
{
// Create a separate cleanup scope for the body, in case it is not
@@ -703,11 +898,15 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
if (DI)
DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd());
+ LoopStack.pop();
+
// Emit the fall-through block.
EmitBlock(LoopExit.getBlock(), true);
}
-void CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S) {
+void
+CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S,
+ const ArrayRef<const Attr *> &ForAttrs) {
JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
RunCleanupsScope ForScope(*this);
@@ -720,12 +919,16 @@ void CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S) {
EmitStmt(S.getRangeStmt());
EmitStmt(S.getBeginEndStmt());
+ RegionCounter Cnt = getPGORegionCounter(&S);
+
// Start the loop with a block that tests the condition.
// If there's an increment, the continue scope will be overwritten
// later.
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
EmitBlock(CondBlock);
+ LoopStack.push(CondBlock);
+
// If there are any cleanups between here and the loop-exit scope,
// create a block to stage a loop exit along.
llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
@@ -737,7 +940,12 @@ void CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S) {
// The body is executed if the expression, contextually converted
// to bool, is true.
- EmitBranchOnBoolExpr(S.getCond(), ForBody, ExitBlock);
+ llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
+ llvm::BranchInst *CondBr = Builder.CreateCondBr(
+ BoolCondVal, ForBody, ExitBlock, PGO.createLoopWeights(S.getCond(), Cnt));
+
+ // Attach metadata to loop body conditional branch.
+ EmitCondBrHints(ForBody->getContext(), CondBr, ForAttrs);
if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
@@ -745,6 +953,7 @@ void CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S) {
}
EmitBlock(ForBody);
+ Cnt.beginRegion(Builder);
// Create a block for the increment. In case of a 'continue', we jump there.
JumpDest Continue = getJumpDestInCurrentScope("for.inc");
@@ -772,6 +981,8 @@ void CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S) {
if (DI)
DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd());
+ LoopStack.pop();
+
// Emit the fall-through block.
EmitBlock(LoopExit.getBlock(), true);
}
@@ -809,7 +1020,8 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
// FIXME: Clean this up by using an LValue for ReturnTemp,
// EmitStoreThroughLValue, and EmitAnyExpr.
- if (S.getNRVOCandidate() && S.getNRVOCandidate()->isNRVOVariable()) {
+ if (getLangOpts().ElideConstructors &&
+ S.getNRVOCandidate() && S.getNRVOCandidate()->isNRVOVariable()) {
// Apply the named return value optimization for this return statement,
// which means doing nothing: the appropriate result has already been
// constructed into the NRVO variable.
@@ -818,12 +1030,12 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
// that the cleanup code should not destroy the variable.
if (llvm::Value *NRVOFlag = NRVOFlags[S.getNRVOCandidate()])
Builder.CreateStore(Builder.getTrue(), NRVOFlag);
- } else if (!ReturnValue) {
+ } else if (!ReturnValue || (RV && RV->getType()->isVoidType())) {
// Make sure not to return anything, but evaluate the expression
// for side effects.
if (RV)
EmitAnyExpr(RV);
- } else if (RV == 0) {
+ } else if (!RV) {
// Do nothing (return value is left uninitialized)
} else if (FnRetTy->isReferenceType()) {
// If this function returns a reference, take the address of the expression
@@ -853,7 +1065,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
}
++NumReturnExprs;
- if (RV == 0 || RV->isEvaluatable(getContext()))
+ if (!RV || RV->isEvaluatable(getContext()))
++NumSimpleReturnExprs;
cleanupScope.ForceCleanup();
@@ -866,9 +1078,8 @@ void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) {
if (HaveInsertPoint())
EmitStopPoint(&S);
- for (DeclStmt::const_decl_iterator I = S.decl_begin(), E = S.decl_end();
- I != E; ++I)
- EmitDecl(**I);
+ for (const auto *I : S.decls())
+ EmitDecl(*I);
}
void CodeGenFunction::EmitBreakStmt(const BreakStmt &S) {
@@ -880,8 +1091,7 @@ void CodeGenFunction::EmitBreakStmt(const BreakStmt &S) {
if (HaveInsertPoint())
EmitStopPoint(&S);
- JumpDest Block = BreakContinueStack.back().BreakBlock;
- EmitBranchThroughCleanup(Block);
+ EmitBranchThroughCleanup(BreakContinueStack.back().BreakBlock);
}
void CodeGenFunction::EmitContinueStmt(const ContinueStmt &S) {
@@ -893,8 +1103,7 @@ void CodeGenFunction::EmitContinueStmt(const ContinueStmt &S) {
if (HaveInsertPoint())
EmitStopPoint(&S);
- JumpDest Block = BreakContinueStack.back().ContinueBlock;
- EmitBranchThroughCleanup(Block);
+ EmitBranchThroughCleanup(BreakContinueStack.back().ContinueBlock);
}
/// EmitCaseStmtRange - If case statement range is not too big then
@@ -906,11 +1115,13 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
llvm::APSInt LHS = S.getLHS()->EvaluateKnownConstInt(getContext());
llvm::APSInt RHS = S.getRHS()->EvaluateKnownConstInt(getContext());
+ RegionCounter CaseCnt = getPGORegionCounter(&S);
+
// Emit the code for this case. We do this first to make sure it is
// properly chained from our predecessor before generating the
// switch machinery to enter this block.
- EmitBlock(createBasicBlock("sw.bb"));
- llvm::BasicBlock *CaseDest = Builder.GetInsertBlock();
+ llvm::BasicBlock *CaseDest = createBasicBlock("sw.bb");
+ EmitBlockWithFallThrough(CaseDest, CaseCnt);
EmitStmt(S.getSubStmt());
// If range is empty, do nothing.
@@ -921,7 +1132,18 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
// FIXME: parameters such as this should not be hardcoded.
if (Range.ult(llvm::APInt(Range.getBitWidth(), 64))) {
// Range is small enough to add multiple switch instruction cases.
- for (unsigned i = 0, e = Range.getZExtValue() + 1; i != e; ++i) {
+ uint64_t Total = CaseCnt.getCount();
+ unsigned NCases = Range.getZExtValue() + 1;
+ // We only have one region counter for the entire set of cases here, so we
+ // need to divide the weights evenly between the generated cases, ensuring
+ // that the total weight is preserved. E.g., a weight of 5 over three cases
+ // will be distributed as weights of 2, 2, and 1.
+ uint64_t Weight = Total / NCases, Rem = Total % NCases;
+ for (unsigned I = 0; I != NCases; ++I) {
+ if (SwitchWeights)
+ SwitchWeights->push_back(Weight + (Rem ? 1 : 0));
+ if (Rem)
+ Rem--;
SwitchInsn->addCase(Builder.getInt(LHS), CaseDest);
LHS++;
}
@@ -946,7 +1168,19 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) {
Builder.CreateSub(SwitchInsn->getCondition(), Builder.getInt(LHS));
llvm::Value *Cond =
Builder.CreateICmpULE(Diff, Builder.getInt(Range), "inbounds");
- Builder.CreateCondBr(Cond, CaseDest, FalseDest);
+
+ llvm::MDNode *Weights = nullptr;
+ if (SwitchWeights) {
+ uint64_t ThisCount = CaseCnt.getCount();
+ uint64_t DefaultCount = (*SwitchWeights)[0];
+ Weights = PGO.createBranchWeights(ThisCount, DefaultCount);
+
+ // Since we're chaining the switch default through each large case range, we
+ // need to update the weight for the default, ie, the first case, to include
+ // this case.
+ (*SwitchWeights)[0] += ThisCount;
+ }
+ Builder.CreateCondBr(Cond, CaseDest, FalseDest, Weights);
// Restore the appropriate insertion point.
if (RestoreBB)
@@ -959,7 +1193,7 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
// If there is no enclosing switch instance that we're aware of, then this
// case statement and its block can be elided. This situation only happens
// when we've constant-folded the switch, are emitting the constant case,
- // and part of the constant case includes another case statement. For
+ // and part of the constant case includes another case statement. For
// instance: switch (4) { case 4: do { case 5: } while (1); }
if (!SwitchInsn) {
EmitStmt(S.getSubStmt());
@@ -972,17 +1206,22 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
return;
}
+ RegionCounter CaseCnt = getPGORegionCounter(&S);
llvm::ConstantInt *CaseVal =
Builder.getInt(S.getLHS()->EvaluateKnownConstInt(getContext()));
- // If the body of the case is just a 'break', and if there was no fallthrough,
- // try to not emit an empty block.
- if ((CGM.getCodeGenOpts().OptimizationLevel > 0) &&
+ // If the body of the case is just a 'break', try to not emit an empty block.
+ // If we're profiling or we're not optimizing, leave the block in for better
+ // debug and coverage analysis.
+ if (!CGM.getCodeGenOpts().ProfileInstrGenerate &&
+ CGM.getCodeGenOpts().OptimizationLevel > 0 &&
isa<BreakStmt>(S.getSubStmt())) {
JumpDest Block = BreakContinueStack.back().BreakBlock;
// Only do this optimization if there are no cleanups that need emitting.
if (isObviouslyBranchWithoutCleanups(Block)) {
+ if (SwitchWeights)
+ SwitchWeights->push_back(CaseCnt.getCount());
SwitchInsn->addCase(CaseVal, Block.getBlock());
// If there was a fallthrough into this case, make sure to redirect it to
@@ -995,8 +1234,10 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
}
}
- EmitBlock(createBasicBlock("sw.bb"));
- llvm::BasicBlock *CaseDest = Builder.GetInsertBlock();
+ llvm::BasicBlock *CaseDest = createBasicBlock("sw.bb");
+ EmitBlockWithFallThrough(CaseDest, CaseCnt);
+ if (SwitchWeights)
+ SwitchWeights->push_back(CaseCnt.getCount());
SwitchInsn->addCase(CaseVal, CaseDest);
// Recursively emitting the statement is acceptable, but is not wonderful for
@@ -1012,10 +1253,19 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) {
const CaseStmt *NextCase = dyn_cast<CaseStmt>(S.getSubStmt());
// Otherwise, iteratively add consecutive cases to this switch stmt.
- while (NextCase && NextCase->getRHS() == 0) {
+ while (NextCase && NextCase->getRHS() == nullptr) {
CurCase = NextCase;
- llvm::ConstantInt *CaseVal =
+ llvm::ConstantInt *CaseVal =
Builder.getInt(CurCase->getLHS()->EvaluateKnownConstInt(getContext()));
+
+ CaseCnt = getPGORegionCounter(NextCase);
+ if (SwitchWeights)
+ SwitchWeights->push_back(CaseCnt.getCount());
+ if (CGM.getCodeGenOpts().ProfileInstrGenerate) {
+ CaseDest = createBasicBlock("sw.bb");
+ EmitBlockWithFallThrough(CaseDest, CaseCnt);
+ }
+
SwitchInsn->addCase(CaseVal, CaseDest);
NextCase = dyn_cast<CaseStmt>(CurCase->getSubStmt());
}
@@ -1028,7 +1278,10 @@ void CodeGenFunction::EmitDefaultStmt(const DefaultStmt &S) {
llvm::BasicBlock *DefaultBlock = SwitchInsn->getDefaultDest();
assert(DefaultBlock->empty() &&
"EmitDefaultStmt: Default block already defined?");
- EmitBlock(DefaultBlock);
+
+ RegionCounter Cnt = getPGORegionCounter(&S);
+ EmitBlockWithFallThrough(DefaultBlock, Cnt);
+
EmitStmt(S.getSubStmt());
}
@@ -1061,7 +1314,7 @@ static CSFC_Result CollectStatementsForCase(const Stmt *S,
bool &FoundCase,
SmallVectorImpl<const Stmt*> &ResultStmts) {
// If this is a null statement, just succeed.
- if (S == 0)
+ if (!S)
return Case ? CSFC_Success : CSFC_FallThrough;
// If this is the switchcase (case 4: or default) that we're looking for, then
@@ -1069,7 +1322,7 @@ static CSFC_Result CollectStatementsForCase(const Stmt *S,
if (const SwitchCase *SC = dyn_cast<SwitchCase>(S)) {
if (S == Case) {
FoundCase = true;
- return CollectStatementsForCase(SC->getSubStmt(), 0, FoundCase,
+ return CollectStatementsForCase(SC->getSubStmt(), nullptr, FoundCase,
ResultStmts);
}
@@ -1080,7 +1333,7 @@ static CSFC_Result CollectStatementsForCase(const Stmt *S,
// If we are in the live part of the code and we found our break statement,
// return a success!
- if (Case == 0 && isa<BreakStmt>(S))
+ if (!Case && isa<BreakStmt>(S))
return CSFC_Success;
// If this is a switch statement, then it might contain the SwitchCase, the
@@ -1125,7 +1378,7 @@ static CSFC_Result CollectStatementsForCase(const Stmt *S,
// statements in the compound statement as candidates for inclusion.
assert(FoundCase && "Didn't find case but returned fallthrough?");
// We recursively found Case, so we're not looking for it anymore.
- Case = 0;
+ Case = nullptr;
// If we found the case and skipped declarations, we can't do the
// optimization.
@@ -1139,7 +1392,7 @@ static CSFC_Result CollectStatementsForCase(const Stmt *S,
// If we have statements in our range, then we know that the statements are
// live and need to be added to the set of statements we're tracking.
for (; I != E; ++I) {
- switch (CollectStatementsForCase(*I, 0, FoundCase, ResultStmts)) {
+ switch (CollectStatementsForCase(*I, nullptr, FoundCase, ResultStmts)) {
case CSFC_Failure: return CSFC_Failure;
case CSFC_FallThrough:
// A fallthrough result means that the statement was simple and just
@@ -1185,11 +1438,12 @@ static CSFC_Result CollectStatementsForCase(const Stmt *S,
static bool FindCaseStatementsForValue(const SwitchStmt &S,
const llvm::APSInt &ConstantCondValue,
SmallVectorImpl<const Stmt*> &ResultStmts,
- ASTContext &C) {
+ ASTContext &C,
+ const SwitchCase *&ResultCase) {
// First step, find the switch case that is being branched to. We can do this
// efficiently by scanning the SwitchCase list.
const SwitchCase *Case = S.getSwitchCaseList();
- const DefaultStmt *DefaultCase = 0;
+ const DefaultStmt *DefaultCase = nullptr;
for (; Case; Case = Case->getNextSwitchCase()) {
// It's either a default or case. Just remember the default statement in
@@ -1211,10 +1465,10 @@ static bool FindCaseStatementsForValue(const SwitchStmt &S,
// If we didn't find a matching case, we use a default if it exists, or we
// elide the whole switch body!
- if (Case == 0) {
+ if (!Case) {
// It is safe to elide the body of the switch if it doesn't contain labels
// etc. If it is safe, return successfully with an empty ResultStmts list.
- if (DefaultCase == 0)
+ if (!DefaultCase)
return !CodeGenFunction::ContainsLabel(&S);
Case = DefaultCase;
}
@@ -1228,21 +1482,16 @@ static bool FindCaseStatementsForValue(const SwitchStmt &S,
// while (1) {
// case 4: ...
bool FoundCase = false;
+ ResultCase = Case;
return CollectStatementsForCase(S.getBody(), Case, FoundCase,
ResultStmts) != CSFC_Failure &&
FoundCase;
}
void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
- JumpDest SwitchExit = getJumpDestInCurrentScope("sw.epilog");
-
- RunCleanupsScope ConditionScope(*this);
-
- if (S.getConditionVariable())
- EmitAutoVarDecl(*S.getConditionVariable());
-
// Handle nested switch statements.
llvm::SwitchInst *SavedSwitchInsn = SwitchInsn;
+ SmallVector<uint64_t, 16> *SavedSwitchWeights = SwitchWeights;
llvm::BasicBlock *SavedCRBlock = CaseRangeBlock;
// See if we can constant fold the condition of the switch and therefore only
@@ -1250,19 +1499,31 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
llvm::APSInt ConstantCondValue;
if (ConstantFoldsToSimpleInteger(S.getCond(), ConstantCondValue)) {
SmallVector<const Stmt*, 4> CaseStmts;
+ const SwitchCase *Case = nullptr;
if (FindCaseStatementsForValue(S, ConstantCondValue, CaseStmts,
- getContext())) {
+ getContext(), Case)) {
+ if (Case) {
+ RegionCounter CaseCnt = getPGORegionCounter(Case);
+ CaseCnt.beginRegion(Builder);
+ }
RunCleanupsScope ExecutedScope(*this);
+ // Emit the condition variable if needed inside the entire cleanup scope
+ // used by this special case for constant folded switches.
+ if (S.getConditionVariable())
+ EmitAutoVarDecl(*S.getConditionVariable());
+
// At this point, we are no longer "within" a switch instance, so
// we can temporarily enforce this to ensure that any embedded case
// statements are not emitted.
- SwitchInsn = 0;
+ SwitchInsn = nullptr;
// Okay, we can dead code eliminate everything except this case. Emit the
// specified series of statements and we're good.
for (unsigned i = 0, e = CaseStmts.size(); i != e; ++i)
EmitStmt(CaseStmts[i]);
+ RegionCounter ExitCnt = getPGORegionCounter(&S);
+ ExitCnt.beginRegion(Builder);
// Now we want to restore the saved switch instance so that nested
// switches continue to function properly
@@ -1272,6 +1533,11 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
}
}
+ JumpDest SwitchExit = getJumpDestInCurrentScope("sw.epilog");
+
+ RunCleanupsScope ConditionScope(*this);
+ if (S.getConditionVariable())
+ EmitAutoVarDecl(*S.getConditionVariable());
llvm::Value *CondV = EmitScalarExpr(S.getCond());
// Create basic block to hold stuff that comes after switch
@@ -1280,12 +1546,29 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
// failure.
llvm::BasicBlock *DefaultBlock = createBasicBlock("sw.default");
SwitchInsn = Builder.CreateSwitch(CondV, DefaultBlock);
+ if (PGO.haveRegionCounts()) {
+ // Walk the SwitchCase list to find how many there are.
+ uint64_t DefaultCount = 0;
+ unsigned NumCases = 0;
+ for (const SwitchCase *Case = S.getSwitchCaseList();
+ Case;
+ Case = Case->getNextSwitchCase()) {
+ if (isa<DefaultStmt>(Case))
+ DefaultCount = getPGORegionCounter(Case).getCount();
+ NumCases += 1;
+ }
+ SwitchWeights = new SmallVector<uint64_t, 16>();
+ SwitchWeights->reserve(NumCases);
+ // The default needs to be first. We store the edge count, so we already
+ // know the right weight.
+ SwitchWeights->push_back(DefaultCount);
+ }
CaseRangeBlock = DefaultBlock;
// Clear the insertion point to indicate we are in unreachable code.
Builder.ClearInsertionPoint();
- // All break statements jump to NextBlock. If BreakContinueStack is non empty
+ // All break statements jump to NextBlock. If BreakContinueStack is non-empty
// then reuse last ContinueBlock.
JumpDest OuterContinue;
if (!BreakContinueStack.empty())
@@ -1320,14 +1603,26 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
// Emit continuation.
EmitBlock(SwitchExit.getBlock(), true);
-
+ RegionCounter ExitCnt = getPGORegionCounter(&S);
+ ExitCnt.beginRegion(Builder);
+
+ if (SwitchWeights) {
+ assert(SwitchWeights->size() == 1 + SwitchInsn->getNumCases() &&
+ "switch weights do not match switch cases");
+ // If there's only one jump destination there's no sense weighting it.
+ if (SwitchWeights->size() > 1)
+ SwitchInsn->setMetadata(llvm::LLVMContext::MD_prof,
+ PGO.createBranchWeights(*SwitchWeights));
+ delete SwitchWeights;
+ }
SwitchInsn = SavedSwitchInsn;
+ SwitchWeights = SavedSwitchWeights;
CaseRangeBlock = SavedCRBlock;
}
static std::string
SimplifyConstraint(const char *Constraint, const TargetInfo &Target,
- SmallVectorImpl<TargetInfo::ConstraintInfo> *OutCons=0) {
+ SmallVectorImpl<TargetInfo::ConstraintInfo> *OutCons=nullptr) {
std::string Result;
while (*Constraint) {
@@ -1493,7 +1788,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
Name = GAS->getOutputName(i);
TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i), Name);
bool IsValid = getTarget().validateOutputConstraint(Info); (void)IsValid;
- assert(IsValid && "Failed to parse output constraint");
+ assert(IsValid && "Failed to parse output constraint");
OutputConstraintInfos.push_back(Info);
}
@@ -1791,20 +2086,32 @@ static LValue InitCapturedStruct(CodeGenFunction &CGF, const CapturedStmt &S) {
return SlotLV;
}
+static void InitVLACaptures(CodeGenFunction &CGF, const CapturedStmt &S) {
+ for (auto &C : S.captures()) {
+ if (C.capturesVariable()) {
+ QualType QTy;
+ auto VD = C.getCapturedVar();
+ if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD))
+ QTy = PVD->getOriginalType();
+ else
+ QTy = VD->getType();
+ if (QTy->isVariablyModifiedType()) {
+ CGF.EmitVariablyModifiedType(QTy);
+ }
+ }
+ }
+}
+
/// Generate an outlined function for the body of a CapturedStmt, store any
/// captured variables into the captured struct, and call the outlined function.
llvm::Function *
CodeGenFunction::EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K) {
- const CapturedDecl *CD = S.getCapturedDecl();
- const RecordDecl *RD = S.getCapturedRecordDecl();
- assert(CD->hasBody() && "missing CapturedDecl body");
-
LValue CapStruct = InitCapturedStruct(*this, S);
// Emit the CapturedDecl
CodeGenFunction CGF(CGM, true);
CGF.CapturedStmtInfo = new CGCapturedStmtInfo(S, K);
- llvm::Function *F = CGF.GenerateCapturedStmtFunction(CD, RD, S.getLocStart());
+ llvm::Function *F = CGF.GenerateCapturedStmtFunction(S);
delete CGF.CapturedStmtInfo;
// Emit call to the helper function.
@@ -1813,13 +2120,21 @@ CodeGenFunction::EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K) {
return F;
}
+llvm::Value *
+CodeGenFunction::GenerateCapturedStmtArgument(const CapturedStmt &S) {
+ LValue CapStruct = InitCapturedStruct(*this, S);
+ return CapStruct.getAddress();
+}
+
/// Creates the outlined function for a CapturedStmt.
llvm::Function *
-CodeGenFunction::GenerateCapturedStmtFunction(const CapturedDecl *CD,
- const RecordDecl *RD,
- SourceLocation Loc) {
+CodeGenFunction::GenerateCapturedStmtFunction(const CapturedStmt &S) {
assert(CapturedStmtInfo &&
"CapturedStmtInfo should be set when generating the captured function");
+ const CapturedDecl *CD = S.getCapturedDecl();
+ const RecordDecl *RD = S.getCapturedRecordDecl();
+ SourceLocation Loc = S.getLocStart();
+ assert(CD->hasBody() && "missing CapturedDecl body");
// Build the argument list.
ASTContext &Ctx = CGM.getContext();
@@ -1829,8 +2144,8 @@ CodeGenFunction::GenerateCapturedStmtFunction(const CapturedDecl *CD,
// Create the function declaration.
FunctionType::ExtInfo ExtInfo;
const CGFunctionInfo &FuncInfo =
- CGM.getTypes().arrangeFunctionDeclaration(Ctx.VoidTy, Args, ExtInfo,
- /*IsVariadic=*/false);
+ CGM.getTypes().arrangeFreeFunctionDeclaration(Ctx.VoidTy, Args, ExtInfo,
+ /*IsVariadic=*/false);
llvm::FunctionType *FuncLLVMTy = CGM.getTypes().GetFunctionType(FuncInfo);
llvm::Function *F =
@@ -1839,13 +2154,17 @@ CodeGenFunction::GenerateCapturedStmtFunction(const CapturedDecl *CD,
CGM.SetInternalFunctionAttributes(CD, F, FuncInfo);
// Generate the function.
- StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args, CD->getBody()->getLocStart());
-
+ StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args,
+ CD->getLocation(),
+ CD->getBody()->getLocStart());
// Set the context parameter in CapturedStmtInfo.
llvm::Value *DeclPtr = LocalDeclMap[CD->getContextParam()];
assert(DeclPtr && "missing context parameter for CapturedStmt");
CapturedStmtInfo->setContextValue(Builder.CreateLoad(DeclPtr));
+ // Initialize variable-length arrays.
+ InitVLACaptures(*this, S);
+
// If 'this' is captured, load it into CXXThisValue.
if (CapturedStmtInfo->isCXXThisExprCaptured()) {
FieldDecl *FD = CapturedStmtInfo->getThisFieldDecl();
@@ -1855,8 +2174,11 @@ CodeGenFunction::GenerateCapturedStmtFunction(const CapturedDecl *CD,
CXXThisValue = EmitLoadOfLValue(ThisLValue, Loc).getScalarVal();
}
+ PGO.assignRegionCounters(CD, F);
CapturedStmtInfo->EmitBody(*this, CD->getBody());
FinishFunction(CD->getBodyRBrace());
+ PGO.emitInstrumentationData();
+ PGO.destroyRegionCounters();
return F;
}
diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp
new file mode 100644
index 000000000000..867f41592dd9
--- /dev/null
+++ b/lib/CodeGen/CGStmtOpenMP.cpp
@@ -0,0 +1,130 @@
+//===--- CGStmtOpenMP.cpp - Emit LLVM Code from Statements ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to emit OpenMP nodes as LLVM code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CGOpenMPRuntime.h"
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/StmtOpenMP.h"
+using namespace clang;
+using namespace CodeGen;
+
+//===----------------------------------------------------------------------===//
+// OpenMP Directive Emission
+//===----------------------------------------------------------------------===//
+
+void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
+ const CapturedStmt *CS = cast<CapturedStmt>(S.getAssociatedStmt());
+ llvm::Value *CapturedStruct = GenerateCapturedStmtArgument(*CS);
+
+ llvm::Value *OutlinedFn;
+ {
+ CodeGenFunction CGF(CGM, true);
+ CGCapturedStmtInfo CGInfo(*CS, CS->getCapturedRegionKind());
+ CGF.CapturedStmtInfo = &CGInfo;
+ OutlinedFn = CGF.GenerateCapturedStmtFunction(*CS);
+ }
+
+ // Build call __kmpc_fork_call(loc, 1, microtask, captured_struct/*context*/)
+ llvm::Value *Args[] = {
+ CGM.getOpenMPRuntime().EmitOpenMPUpdateLocation(*this, S.getLocStart()),
+ Builder.getInt32(1), // Number of arguments after 'microtask' argument
+ // (there is only one additional argument - 'context')
+ Builder.CreateBitCast(OutlinedFn,
+ CGM.getOpenMPRuntime().getKmpc_MicroPointerTy()),
+ EmitCastToVoidPtr(CapturedStruct)};
+ llvm::Constant *RTLFn = CGM.getOpenMPRuntime().CreateRuntimeFunction(
+ CGOpenMPRuntime::OMPRTL__kmpc_fork_call);
+ EmitRuntimeCall(RTLFn, Args);
+}
+
+void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
+ const CapturedStmt *CS = cast<CapturedStmt>(S.getAssociatedStmt());
+ const Stmt *Body = CS->getCapturedStmt();
+ LoopStack.setParallel();
+ LoopStack.setVectorizerEnable(true);
+ for (auto C : S.clauses()) {
+ switch (C->getClauseKind()) {
+ case OMPC_safelen: {
+ RValue Len = EmitAnyExpr(cast<OMPSafelenClause>(C)->getSafelen(),
+ AggValueSlot::ignored(), true);
+ llvm::ConstantInt *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
+ LoopStack.setVectorizerWidth(Val->getZExtValue());
+ // In presence of finite 'safelen', it may be unsafe to mark all
+ // the memory instructions parallel, because loop-carried
+ // dependences of 'safelen' iterations are possible.
+ LoopStack.setParallel(false);
+ break;
+ }
+ default:
+ // Not handled yet
+ ;
+ }
+ }
+ EmitStmt(Body);
+}
+
+void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &) {
+ llvm_unreachable("CodeGen for 'omp for' is not supported yet.");
+}
+
+void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &) {
+ llvm_unreachable("CodeGen for 'omp sections' is not supported yet.");
+}
+
+void CodeGenFunction::EmitOMPSectionDirective(const OMPSectionDirective &) {
+ llvm_unreachable("CodeGen for 'omp section' is not supported yet.");
+}
+
+void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &) {
+ llvm_unreachable("CodeGen for 'omp single' is not supported yet.");
+}
+
+void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &) {
+ llvm_unreachable("CodeGen for 'omp master' is not supported yet.");
+}
+
+void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &) {
+ llvm_unreachable("CodeGen for 'omp critical' is not supported yet.");
+}
+
+void
+CodeGenFunction::EmitOMPParallelForDirective(const OMPParallelForDirective &) {
+ llvm_unreachable("CodeGen for 'omp parallel for' is not supported yet.");
+}
+
+void CodeGenFunction::EmitOMPParallelSectionsDirective(
+ const OMPParallelSectionsDirective &) {
+ llvm_unreachable("CodeGen for 'omp parallel sections' is not supported yet.");
+}
+
+void CodeGenFunction::EmitOMPTaskDirective(const OMPTaskDirective &) {
+ llvm_unreachable("CodeGen for 'omp task' is not supported yet.");
+}
+
+void CodeGenFunction::EmitOMPTaskyieldDirective(const OMPTaskyieldDirective &) {
+ llvm_unreachable("CodeGen for 'omp taskyield' is not supported yet.");
+}
+
+void CodeGenFunction::EmitOMPBarrierDirective(const OMPBarrierDirective &) {
+ llvm_unreachable("CodeGen for 'omp barrier' is not supported yet.");
+}
+
+void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &) {
+ llvm_unreachable("CodeGen for 'omp taskwait' is not supported yet.");
+}
+
+void CodeGenFunction::EmitOMPFlushDirective(const OMPFlushDirective &) {
+ llvm_unreachable("CodeGen for 'omp flush' is not supported yet.");
+}
+
diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp
index bfff47058897..bd280ea14e8d 100644
--- a/lib/CodeGen/CGVTT.cpp
+++ b/lib/CodeGen/CGVTT.cpp
@@ -66,7 +66,8 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT,
if (VTTVT.getBase() == RD) {
// Just get the address point for the regular vtable.
AddressPoint =
- ItaniumVTContext.getVTableLayout(RD).getAddressPoint(i->VTableBase);
+ getItaniumVTableContext().getVTableLayout(RD).getAddressPoint(
+ i->VTableBase);
assert(AddressPoint != 0 && "Did not find vtable address point!");
} else {
AddressPoint = VTableAddressPoints[i->VTableIndex].lookup(i->VTableBase);
@@ -94,7 +95,7 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT,
VTT->setLinkage(Linkage);
// Set the right visibility.
- CGM.setTypeVisibility(VTT, RD, CodeGenModule::TVK_ForVTT);
+ CGM.setGlobalVisibility(VTT, RD);
}
llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) {
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index f28d9b67a8f3..0df2c43d11b5 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -30,14 +30,7 @@ using namespace clang;
using namespace CodeGen;
CodeGenVTables::CodeGenVTables(CodeGenModule &CGM)
- : CGM(CGM), ItaniumVTContext(CGM.getContext()) {
- if (CGM.getTarget().getCXXABI().isMicrosoft()) {
- // FIXME: Eventually, we should only have one of V*TContexts available.
- // Today we use both in the Microsoft ABI as MicrosoftVFTableContext
- // is not completely supported in CodeGen yet.
- MicrosoftVTContext.reset(new MicrosoftVTableContext(CGM.getContext()));
- }
-}
+ : CGM(CGM), VTContext(CGM.getContext().getVTableContext()) {}
llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
const ThunkInfo &Thunk) {
@@ -54,54 +47,13 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
Out.flush();
llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(GD);
- return GetOrCreateLLVMFunction(Name, Ty, GD, /*ForVTable=*/true);
+ return GetOrCreateLLVMFunction(Name, Ty, GD, /*ForVTable=*/true,
+ /*DontDefer*/ true);
}
static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD,
const ThunkInfo &Thunk, llvm::Function *Fn) {
CGM.setGlobalVisibility(Fn, MD);
-
- if (!CGM.getCodeGenOpts().HiddenWeakVTables)
- return;
-
- // If the thunk has weak/linkonce linkage, but the function must be
- // emitted in every translation unit that references it, then we can
- // emit its thunks with hidden visibility, since its thunks must be
- // emitted when the function is.
-
- // This follows CodeGenModule::setTypeVisibility; see the comments
- // there for explanation.
-
- if ((Fn->getLinkage() != llvm::GlobalVariable::LinkOnceODRLinkage &&
- Fn->getLinkage() != llvm::GlobalVariable::WeakODRLinkage) ||
- Fn->getVisibility() != llvm::GlobalVariable::DefaultVisibility)
- return;
-
- if (MD->getExplicitVisibility(ValueDecl::VisibilityForValue))
- return;
-
- switch (MD->getTemplateSpecializationKind()) {
- case TSK_ExplicitInstantiationDefinition:
- case TSK_ExplicitInstantiationDeclaration:
- return;
-
- case TSK_Undeclared:
- break;
-
- case TSK_ExplicitSpecialization:
- case TSK_ImplicitInstantiation:
- return;
- break;
- }
-
- // If there's an explicit definition, and that definition is
- // out-of-line, then we can't assume that all users will have a
- // definition to emit.
- const FunctionDecl *Def = 0;
- if (MD->hasBody(Def) && Def->isOutOfLine())
- return;
-
- Fn->setVisibility(llvm::GlobalValue::HiddenVisibility);
}
#ifndef NDEBUG
@@ -119,11 +71,11 @@ static RValue PerformReturnAdjustment(CodeGenFunction &CGF,
const ThunkInfo &Thunk) {
// Emit the return adjustment.
bool NullCheckValue = !ResultType->isReferenceType();
-
- llvm::BasicBlock *AdjustNull = 0;
- llvm::BasicBlock *AdjustNotNull = 0;
- llvm::BasicBlock *AdjustEnd = 0;
-
+
+ llvm::BasicBlock *AdjustNull = nullptr;
+ llvm::BasicBlock *AdjustNotNull = nullptr;
+ llvm::BasicBlock *AdjustEnd = nullptr;
+
llvm::Value *ReturnValue = RV.getScalarVal();
if (NullCheckValue) {
@@ -177,7 +129,7 @@ void CodeGenFunction::GenerateVarArgsThunk(
GlobalDecl GD, const ThunkInfo &Thunk) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- QualType ResultType = FPT->getResultType();
+ QualType ResultType = FPT->getReturnType();
// Get the original function
assert(FnInfo.isVariadic());
@@ -207,7 +159,7 @@ void CodeGenFunction::GenerateVarArgsThunk(
// with "this".
llvm::Value *ThisPtr = &*AI;
llvm::BasicBlock *EntryBB = Fn->begin();
- llvm::Instruction *ThisStore = 0;
+ llvm::Instruction *ThisStore = nullptr;
for (llvm::BasicBlock::iterator I = EntryBB->begin(), E = EntryBB->end();
I != E; I++) {
if (isa<llvm::StoreInst>(I) && I->getOperand(0) == ThisPtr) {
@@ -248,11 +200,11 @@ void CodeGenFunction::StartThunk(llvm::Function *Fn, GlobalDecl GD,
QualType ThisType = MD->getThisType(getContext());
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
QualType ResultType =
- CGM.getCXXABI().HasThisReturn(GD) ? ThisType : FPT->getResultType();
+ CGM.getCXXABI().HasThisReturn(GD) ? ThisType : FPT->getReturnType();
FunctionArgList FunctionArgs;
// Create the implicit 'this' parameter declaration.
- CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResultType, FunctionArgs);
+ CGM.getCXXABI().buildThisParam(*this, FunctionArgs);
// Add the rest of the parameters.
for (FunctionDecl::param_const_iterator I = MD->param_begin(),
@@ -260,9 +212,12 @@ void CodeGenFunction::StartThunk(llvm::Function *Fn, GlobalDecl GD,
I != E; ++I)
FunctionArgs.push_back(*I);
+ if (isa<CXXDestructorDecl>(MD))
+ CGM.getCXXABI().addImplicitStructorParams(*this, ResultType, FunctionArgs);
+
// Start defining the function.
StartFunction(GlobalDecl(), ResultType, Fn, FnInfo, FunctionArgs,
- SourceLocation());
+ MD->getLocation(), SourceLocation());
// Since we didn't pass a GlobalDecl to StartFunction, do this ourselves.
CGM.getCXXABI().EmitInstanceFunctionProlog(*this);
@@ -316,7 +271,7 @@ void CodeGenFunction::EmitCallAndReturnForThunk(GlobalDecl GD,
// Determine whether we have a return value slot to use.
QualType ResultType =
- CGM.getCXXABI().HasThisReturn(GD) ? ThisType : FPT->getResultType();
+ CGM.getCXXABI().HasThisReturn(GD) ? ThisType : FPT->getReturnType();
ReturnValueSlot Slot;
if (!ResultType->isVoidType() &&
CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect &&
@@ -366,27 +321,30 @@ void CodeGenVTables::emitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeGlobalDeclaration(GD);
// FIXME: re-use FnInfo in this computation.
- llvm::Constant *Entry = CGM.GetAddrOfThunk(GD, Thunk);
-
+ llvm::Constant *C = CGM.GetAddrOfThunk(GD, Thunk);
+ llvm::GlobalValue *Entry;
+
// Strip off a bitcast if we got one back.
- if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(Entry)) {
+ if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(C)) {
assert(CE->getOpcode() == llvm::Instruction::BitCast);
- Entry = CE->getOperand(0);
+ Entry = cast<llvm::GlobalValue>(CE->getOperand(0));
+ } else {
+ Entry = cast<llvm::GlobalValue>(C);
}
-
+
// There's already a declaration with the same name, check if it has the same
// type or if we need to replace it.
- if (cast<llvm::GlobalValue>(Entry)->getType()->getElementType() !=
+ if (Entry->getType()->getElementType() !=
CGM.getTypes().GetFunctionTypeForVTable(GD)) {
- llvm::GlobalValue *OldThunkFn = cast<llvm::GlobalValue>(Entry);
-
+ llvm::GlobalValue *OldThunkFn = Entry;
+
// If the types mismatch then we have to rewrite the definition.
assert(OldThunkFn->isDeclaration() &&
"Shouldn't replace non-declaration");
// Remove the name from the old thunk function and get a new thunk.
OldThunkFn->setName(StringRef());
- Entry = CGM.GetAddrOfThunk(GD, Thunk);
+ Entry = cast<llvm::GlobalValue>(CGM.GetAddrOfThunk(GD, Thunk));
// If needed, replace the old thunk with a bitcast.
if (!OldThunkFn->use_empty()) {
@@ -424,12 +382,14 @@ void CodeGenVTables::emitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
// FIXME: Do something better here; GenerateVarArgsThunk is extremely ugly.
if (!UseAvailableExternallyLinkage) {
CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD, Thunk);
- CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable);
+ CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable, GD,
+ !Thunk.Return.isEmpty());
}
} else {
// Normal thunk body generation.
CodeGenFunction(CGM).GenerateThunk(ThunkFn, FnInfo, GD, Thunk);
- CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable);
+ CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable, GD,
+ !Thunk.Return.isEmpty());
}
}
@@ -461,12 +421,8 @@ void CodeGenVTables::EmitThunks(GlobalDecl GD)
if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
return;
- const VTableContextBase::ThunkInfoVectorTy *ThunkInfoVector;
- if (MicrosoftVTContext.isValid()) {
- ThunkInfoVector = MicrosoftVTContext->getThunkInfo(GD);
- } else {
- ThunkInfoVector = ItaniumVTContext.getThunkInfo(GD);
- }
+ const VTableContextBase::ThunkInfoVectorTy *ThunkInfoVector =
+ VTContext->getThunkInfo(GD);
if (!ThunkInfoVector)
return;
@@ -475,12 +431,10 @@ void CodeGenVTables::EmitThunks(GlobalDecl GD)
emitThunk(GD, (*ThunkInfoVector)[I], /*ForVTable=*/false);
}
-llvm::Constant *
-CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
- const VTableComponent *Components,
- unsigned NumComponents,
- const VTableLayout::VTableThunkTy *VTableThunks,
- unsigned NumVTableThunks) {
+llvm::Constant *CodeGenVTables::CreateVTableInitializer(
+ const CXXRecordDecl *RD, const VTableComponent *Components,
+ unsigned NumComponents, const VTableLayout::VTableThunkTy *VTableThunks,
+ unsigned NumVTableThunks, llvm::Constant *RTTI) {
SmallVector<llvm::Constant *, 64> Inits;
llvm::Type *Int8PtrTy = CGM.Int8PtrTy;
@@ -488,17 +442,14 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
llvm::Type *PtrDiffTy =
CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
- QualType ClassType = CGM.getContext().getTagDeclType(RD);
- llvm::Constant *RTTI = CGM.GetAddrOfRTTIDescriptor(ClassType);
-
unsigned NextVTableThunkIndex = 0;
-
- llvm::Constant *PureVirtualFn = 0, *DeletedVirtualFn = 0;
+
+ llvm::Constant *PureVirtualFn = nullptr, *DeletedVirtualFn = nullptr;
for (unsigned I = 0; I != NumComponents; ++I) {
VTableComponent Component = Components[I];
- llvm::Constant *Init = 0;
+ llvm::Constant *Init = nullptr;
switch (Component.getKind()) {
case VTableComponent::CK_VCallOffset:
@@ -603,8 +554,8 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
DI->completeClassData(Base.getBase());
- OwningPtr<VTableLayout> VTLayout(
- ItaniumVTContext.createConstructionVTableLayout(
+ std::unique_ptr<VTableLayout> VTLayout(
+ getItaniumVTableContext().createConstructionVTableLayout(
Base.getBase(), Base.getBaseOffset(), BaseIsVirtual, RD));
// Add the address points.
@@ -633,18 +584,19 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
// Create the variable that will hold the construction vtable.
llvm::GlobalVariable *VTable =
CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType, Linkage);
- CGM.setTypeVisibility(VTable, RD, CodeGenModule::TVK_ForConstructionVTable);
+ CGM.setGlobalVisibility(VTable, RD);
// V-tables are always unnamed_addr.
VTable->setUnnamedAddr(true);
+ llvm::Constant *RTTI = CGM.GetAddrOfRTTIDescriptor(
+ CGM.getContext().getTagDeclType(Base.getBase()));
+
// Create and set the initializer.
- llvm::Constant *Init =
- CreateVTableInitializer(Base.getBase(),
- VTLayout->vtable_component_begin(),
- VTLayout->getNumVTableComponents(),
- VTLayout->vtable_thunk_begin(),
- VTLayout->getNumVTableThunks());
+ llvm::Constant *Init = CreateVTableInitializer(
+ Base.getBase(), VTLayout->vtable_component_begin(),
+ VTLayout->getNumVTableComponents(), VTLayout->vtable_thunk_begin(),
+ VTLayout->getNumVTableThunks(), RTTI);
VTable->setInitializer(Init);
return VTable;
@@ -663,7 +615,7 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
if (const CXXMethodDecl *keyFunction = Context.getCurrentKeyFunction(RD)) {
// If this class has a key function, use that to determine the
// linkage of the vtable.
- const FunctionDecl *def = 0;
+ const FunctionDecl *def = nullptr;
if (keyFunction->hasBody(def))
keyFunction = cast<CXXMethodDecl>(def);
@@ -697,18 +649,31 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
// internal linkage.
if (Context.getLangOpts().AppleKext)
return llvm::Function::InternalLinkage;
-
+
+ llvm::GlobalVariable::LinkageTypes DiscardableODRLinkage =
+ llvm::GlobalValue::LinkOnceODRLinkage;
+ llvm::GlobalVariable::LinkageTypes NonDiscardableODRLinkage =
+ llvm::GlobalValue::WeakODRLinkage;
+ if (RD->hasAttr<DLLExportAttr>()) {
+ // Cannot discard exported vtables.
+ DiscardableODRLinkage = NonDiscardableODRLinkage;
+ } else if (RD->hasAttr<DLLImportAttr>()) {
+ // Imported vtables are available externally.
+ DiscardableODRLinkage = llvm::GlobalVariable::AvailableExternallyLinkage;
+ NonDiscardableODRLinkage = llvm::GlobalVariable::AvailableExternallyLinkage;
+ }
+
switch (RD->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
case TSK_ImplicitInstantiation:
- return llvm::GlobalVariable::LinkOnceODRLinkage;
+ return DiscardableODRLinkage;
case TSK_ExplicitInstantiationDeclaration:
llvm_unreachable("Should not have been asked to emit this");
case TSK_ExplicitInstantiationDefinition:
- return llvm::GlobalVariable::WeakODRLinkage;
+ return NonDiscardableODRLinkage;
}
llvm_unreachable("Invalid TemplateSpecializationKind!");
@@ -752,7 +717,7 @@ CodeGenVTables::GenerateClassData(const CXXRecordDecl *RD) {
/// strongly elsewhere. Otherwise, we'd just like to avoid emitting
/// v-tables when unnecessary.
bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) {
- assert(RD->isDynamicClass() && "Non dynamic classes have no VTable.");
+ assert(RD->isDynamicClass() && "Non-dynamic classes have no VTable.");
// If we have an explicit instantiation declaration (and not a
// definition), the v-table is defined elsewhere.
diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h
index e8cd55eed80a..69cf079567e3 100644
--- a/lib/CodeGen/CGVTables.h
+++ b/lib/CodeGen/CGVTables.h
@@ -31,11 +31,8 @@ namespace CodeGen {
class CodeGenVTables {
CodeGenModule &CGM;
- // FIXME: Consider moving ItaniumVTContext and MicrosoftVTContext into
- // respective CXXABI classes?
- ItaniumVTableContext ItaniumVTContext;
- OwningPtr<MicrosoftVTableContext> MicrosoftVTContext;
-
+ VTableContextBase *VTContext;
+
/// VTableAddressPointsMapTy - Address points for a single vtable.
typedef llvm::DenseMap<BaseSubobject, uint64_t> VTableAddressPointsMapTy;
@@ -64,18 +61,19 @@ public:
/// decl.
/// \param Components - The vtable components; this is really an array of
/// VTableComponents.
- llvm::Constant *CreateVTableInitializer(const CXXRecordDecl *RD,
- const VTableComponent *Components,
- unsigned NumComponents,
- const VTableLayout::VTableThunkTy *VTableThunks,
- unsigned NumVTableThunks);
+ llvm::Constant *CreateVTableInitializer(
+ const CXXRecordDecl *RD, const VTableComponent *Components,
+ unsigned NumComponents, const VTableLayout::VTableThunkTy *VTableThunks,
+ unsigned NumVTableThunks, llvm::Constant *RTTI);
CodeGenVTables(CodeGenModule &CGM);
- ItaniumVTableContext &getItaniumVTableContext() { return ItaniumVTContext; }
+ ItaniumVTableContext &getItaniumVTableContext() {
+ return *cast<ItaniumVTableContext>(VTContext);
+ }
MicrosoftVTableContext &getMicrosoftVTableContext() {
- return *MicrosoftVTContext.get();
+ return *cast<MicrosoftVTableContext>(VTContext);
}
/// getSubVTTIndex - Return the index of the sub-VTT for the base class of the
@@ -100,7 +98,7 @@ public:
VTableAddressPointsMapTy& AddressPoints);
- /// GetAddrOfVTable - Get the address of the VTT for the given record decl.
+ /// GetAddrOfVTT - Get the address of the VTT for the given record decl.
llvm::GlobalVariable *GetAddrOfVTT(const CXXRecordDecl *RD);
/// EmitVTTDefinition - Emit the definition of the given vtable.
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
index da2a03437d3d..956f3247bd82 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -110,7 +110,8 @@ class LValue {
Simple, // This is a normal l-value, use getAddress().
VectorElt, // This is a vector element l-value (V[i]), use getVector*
BitField, // This is a bitfield l-value, use getBitfield*.
- ExtVectorElt // This is an extended vector subset, use getExtVectorComp
+ ExtVectorElt, // This is an extended vector subset, use getExtVectorComp
+ GlobalReg // This is a register l-value, use getGlobalReg()
} LVType;
llvm::Value *V;
@@ -168,7 +169,7 @@ class LValue {
private:
void Initialize(QualType Type, Qualifiers Quals,
CharUnits Alignment,
- llvm::MDNode *TBAAInfo = 0) {
+ llvm::MDNode *TBAAInfo = nullptr) {
this->Type = Type;
this->Quals = Quals;
this->Alignment = Alignment.getQuantity();
@@ -179,7 +180,7 @@ private:
this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false;
this->ImpreciseLifetime = false;
this->ThreadLocalRef = false;
- this->BaseIvarExp = 0;
+ this->BaseIvarExp = nullptr;
// Initialize fields for TBAA.
this->TBAABaseType = Type;
@@ -192,6 +193,7 @@ public:
bool isVectorElt() const { return LVType == VectorElt; }
bool isBitField() const { return LVType == BitField; }
bool isExtVectorElt() const { return LVType == ExtVectorElt; }
+ bool isGlobalReg() const { return LVType == GlobalReg; }
bool isVolatileQualified() const { return Quals.hasVolatile(); }
bool isRestrictQualified() const { return Quals.hasRestrict(); }
@@ -286,9 +288,12 @@ public:
return *BitFieldInfo;
}
+ // global register lvalue
+ llvm::Value *getGlobalReg() const { assert(isGlobalReg()); return V; }
+
static LValue MakeAddr(llvm::Value *address, QualType type,
CharUnits alignment, ASTContext &Context,
- llvm::MDNode *TBAAInfo = 0) {
+ llvm::MDNode *TBAAInfo = nullptr) {
Qualifiers qs = type.getQualifiers();
qs.setObjCGCAttr(Context.getObjCGCAttrKind(type));
@@ -336,6 +341,16 @@ public:
return R;
}
+ static LValue MakeGlobalReg(llvm::Value *Reg,
+ QualType type,
+ CharUnits Alignment) {
+ LValue R;
+ R.LVType = GlobalReg;
+ R.V = Reg;
+ R.Initialize(type, type.getQualifiers(), Alignment);
+ return R;
+ }
+
RValue asAggregateRValue() const {
// FIMXE: Alignment
return RValue::getAggregate(getAddress(), isVolatileQualified());
@@ -390,7 +405,7 @@ public:
/// ignored - Returns an aggregate value slot indicating that the
/// aggregate value is being ignored.
static AggValueSlot ignored() {
- return forAddr(0, CharUnits(), Qualifiers(), IsNotDestructed,
+ return forAddr(nullptr, CharUnits(), Qualifiers(), IsNotDestructed,
DoesNotNeedGCBarriers, IsNotAliased);
}
@@ -460,7 +475,7 @@ public:
}
bool isIgnored() const {
- return Addr == 0;
+ return Addr == nullptr;
}
CharUnits getAlignment() const {
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index 83dbbf0d3460..00a87d87a290 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -1,12 +1,19 @@
set(LLVM_LINK_COMPONENTS
- asmparser
- bitreader
- bitwriter
- irreader
- instrumentation
- ipo
- linker
- vectorize
+ BitReader
+ BitWriter
+ Core
+ IPO
+ IRReader
+ InstCombine
+ Instrumentation
+ Linker
+ MC
+ ObjCARCOpts
+ ProfileData
+ ScalarOpts
+ Support
+ Target
+ TransformUtils
)
add_clang_library(clangCodeGen
@@ -14,12 +21,12 @@ add_clang_library(clangCodeGen
CGAtomic.cpp
CGBlocks.cpp
CGBuiltin.cpp
- CGCall.cpp
- CGClass.cpp
CGCUDANV.cpp
CGCUDARuntime.cpp
CGCXX.cpp
CGCXXABI.cpp
+ CGCall.cpp
+ CGClass.cpp
CGCleanup.cpp
CGDebugInfo.cpp
CGDecl.cpp
@@ -27,46 +34,40 @@ add_clang_library(clangCodeGen
CGException.cpp
CGExpr.cpp
CGExprAgg.cpp
+ CGExprCXX.cpp
CGExprComplex.cpp
CGExprConstant.cpp
- CGExprCXX.cpp
CGExprScalar.cpp
+ CGLoopInfo.cpp
CGObjC.cpp
CGObjCGNU.cpp
CGObjCMac.cpp
CGObjCRuntime.cpp
CGOpenCLRuntime.cpp
+ CGOpenMPRuntime.cpp
CGRecordLayoutBuilder.cpp
- CGRTTI.cpp
CGStmt.cpp
- CGVTables.cpp
+ CGStmtOpenMP.cpp
CGVTT.cpp
+ CGVTables.cpp
CodeGenABITypes.cpp
CodeGenAction.cpp
CodeGenFunction.cpp
CodeGenModule.cpp
+ CodeGenPGO.cpp
CodeGenTBAA.cpp
CodeGenTypes.cpp
ItaniumCXXABI.cpp
MicrosoftCXXABI.cpp
- MicrosoftVBTables.cpp
ModuleBuilder.cpp
+ SanitizerBlacklist.cpp
TargetInfo.cpp
- )
-add_dependencies(clangCodeGen
- ClangARMNeon
- ClangAttrClasses
- ClangAttrList
- ClangCommentNodes
- ClangDeclNodes
- ClangDiagnosticCommon
- ClangDiagnosticFrontend
- ClangStmtNodes
- )
+ DEPENDS
+ intrinsics_gen
-target_link_libraries(clangCodeGen
- clangBasic
+ LINK_LIBS
clangAST
+ clangBasic
clangFrontend
)
diff --git a/lib/CodeGen/CodeGenABITypes.cpp b/lib/CodeGen/CodeGenABITypes.cpp
index 18c836cf2f4c..180cd51940ac 100644
--- a/lib/CodeGen/CodeGenABITypes.cpp
+++ b/lib/CodeGen/CodeGenABITypes.cpp
@@ -17,23 +17,23 @@
//===----------------------------------------------------------------------===//
#include "clang/CodeGen/CodeGenABITypes.h"
-
-#include "clang/CodeGen/CGFunctionInfo.h"
#include "CodeGenModule.h"
+#include "clang/CodeGen/CGFunctionInfo.h"
+#include "clang/Frontend/CodeGenOptions.h"
using namespace clang;
using namespace CodeGen;
CodeGenABITypes::CodeGenABITypes(ASTContext &C,
- const CodeGenOptions &CodeGenOpts,
llvm::Module &M,
- const llvm::DataLayout &TD,
- DiagnosticsEngine &Diags)
- : CGM(new CodeGen::CodeGenModule(C, CodeGenOpts, M, TD, Diags)) {
+ const llvm::DataLayout &TD)
+ : CGO(new CodeGenOptions),
+ CGM(new CodeGen::CodeGenModule(C, *CGO, M, TD, C.getDiagnostics())) {
}
CodeGenABITypes::~CodeGenABITypes()
{
+ delete CGO;
delete CGM;
}
@@ -60,10 +60,10 @@ CodeGenABITypes::arrangeCXXMethodType(const CXXRecordDecl *RD,
}
const CGFunctionInfo &
-CodeGenABITypes::arrangeLLVMFunctionInfo(CanQualType returnType,
- llvm::ArrayRef<CanQualType> argTypes,
+CodeGenABITypes::arrangeFreeFunctionCall(CanQualType returnType,
+ ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
RequiredArgs args) {
- return CGM->getTypes().arrangeLLVMFunctionInfo(returnType, argTypes,
- info, args);
+ return CGM->getTypes().arrangeLLVMFunctionInfo(
+ returnType, /*IsInstanceMethod=*/false, argTypes, info, args);
}
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index 3072204c9b66..04d2cd9d53e4 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -11,6 +11,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -18,17 +19,20 @@
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IRReader/IRReader.h"
-#include "llvm/Linker.h"
+#include "llvm/Linker/Linker.h"
#include "llvm/Pass.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/Timer.h"
+#include <memory>
using namespace clang;
using namespace llvm;
@@ -45,42 +49,33 @@ namespace clang {
Timer LLVMIRGeneration;
- OwningPtr<CodeGenerator> Gen;
+ std::unique_ptr<CodeGenerator> Gen;
- OwningPtr<llvm::Module> TheModule, LinkModule;
+ std::unique_ptr<llvm::Module> TheModule, LinkModule;
public:
BackendConsumer(BackendAction action, DiagnosticsEngine &_Diags,
const CodeGenOptions &compopts,
const TargetOptions &targetopts,
- const LangOptions &langopts,
- bool TimePasses,
- const std::string &infile,
- llvm::Module *LinkModule,
- raw_ostream *OS,
- LLVMContext &C) :
- Diags(_Diags),
- Action(action),
- CodeGenOpts(compopts),
- TargetOpts(targetopts),
- LangOpts(langopts),
- AsmOutStream(OS),
- Context(),
- LLVMIRGeneration("LLVM IR Generation Time"),
- Gen(CreateLLVMCodeGen(Diags, infile, compopts, targetopts, C)),
- LinkModule(LinkModule)
- {
+ const LangOptions &langopts, bool TimePasses,
+ const std::string &infile, llvm::Module *LinkModule,
+ raw_ostream *OS, LLVMContext &C)
+ : Diags(_Diags), Action(action), CodeGenOpts(compopts),
+ TargetOpts(targetopts), LangOpts(langopts), AsmOutStream(OS),
+ Context(), LLVMIRGeneration("LLVM IR Generation Time"),
+ Gen(CreateLLVMCodeGen(Diags, infile, compopts, targetopts, C)),
+ LinkModule(LinkModule) {
llvm::TimePassesIsEnabled = TimePasses;
}
- llvm::Module *takeModule() { return TheModule.take(); }
- llvm::Module *takeLinkModule() { return LinkModule.take(); }
+ llvm::Module *takeModule() { return TheModule.release(); }
+ llvm::Module *takeLinkModule() { return LinkModule.release(); }
- virtual void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
+ void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override {
Gen->HandleCXXStaticMemberVarInstantiation(VD);
}
- virtual void Initialize(ASTContext &Ctx) {
+ void Initialize(ASTContext &Ctx) override {
Context = &Ctx;
if (llvm::TimePassesIsEnabled)
@@ -94,7 +89,7 @@ namespace clang {
LLVMIRGeneration.stopTimer();
}
- virtual bool HandleTopLevelDecl(DeclGroupRef D) {
+ bool HandleTopLevelDecl(DeclGroupRef D) override {
PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(),
Context->getSourceManager(),
"LLVM IR generation of declaration");
@@ -110,7 +105,20 @@ namespace clang {
return true;
}
- virtual void HandleTranslationUnit(ASTContext &C) {
+ void HandleInlineMethodDefinition(CXXMethodDecl *D) override {
+ PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
+ Context->getSourceManager(),
+ "LLVM IR generation of inline method");
+ if (llvm::TimePassesIsEnabled)
+ LLVMIRGeneration.startTimer();
+
+ Gen->HandleInlineMethodDefinition(D);
+
+ if (llvm::TimePassesIsEnabled)
+ LLVMIRGeneration.stopTimer();
+ }
+
+ void HandleTranslationUnit(ASTContext &C) override {
{
PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
if (llvm::TimePassesIsEnabled)
@@ -132,7 +140,7 @@ namespace clang {
if (!M) {
// The module has been released by IR gen on failures, do not double
// free.
- TheModule.take();
+ TheModule.release();
return;
}
@@ -158,41 +166,49 @@ namespace clang {
void *OldContext = Ctx.getInlineAsmDiagnosticContext();
Ctx.setInlineAsmDiagnosticHandler(InlineAsmDiagHandler, this);
+ LLVMContext::DiagnosticHandlerTy OldDiagnosticHandler =
+ Ctx.getDiagnosticHandler();
+ void *OldDiagnosticContext = Ctx.getDiagnosticContext();
+ Ctx.setDiagnosticHandler(DiagnosticHandler, this);
+
EmitBackendOutput(Diags, CodeGenOpts, TargetOpts, LangOpts,
+ C.getTargetInfo().getTargetDescription(),
TheModule.get(), Action, AsmOutStream);
-
+
Ctx.setInlineAsmDiagnosticHandler(OldHandler, OldContext);
+
+ Ctx.setDiagnosticHandler(OldDiagnosticHandler, OldDiagnosticContext);
}
- virtual void HandleTagDeclDefinition(TagDecl *D) {
+ void HandleTagDeclDefinition(TagDecl *D) override {
PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
Context->getSourceManager(),
"LLVM IR generation of declaration");
Gen->HandleTagDeclDefinition(D);
}
- virtual void HandleTagDeclRequiredDefinition(const TagDecl *D) {
+ void HandleTagDeclRequiredDefinition(const TagDecl *D) override {
Gen->HandleTagDeclRequiredDefinition(D);
}
- virtual void CompleteTentativeDefinition(VarDecl *D) {
+ void CompleteTentativeDefinition(VarDecl *D) override {
Gen->CompleteTentativeDefinition(D);
}
- virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {
+ void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) override {
Gen->HandleVTable(RD, DefinitionRequired);
}
- virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {
+ void HandleLinkerOptionPragma(llvm::StringRef Opts) override {
Gen->HandleLinkerOptionPragma(Opts);
}
- virtual void HandleDetectMismatch(llvm::StringRef Name,
- llvm::StringRef Value) {
+ void HandleDetectMismatch(llvm::StringRef Name,
+ llvm::StringRef Value) override {
Gen->HandleDetectMismatch(Name, Value);
}
- virtual void HandleDependentLibrary(llvm::StringRef Opts) {
+ void HandleDependentLibrary(llvm::StringRef Opts) override {
Gen->HandleDependentLibrary(Opts);
}
@@ -202,8 +218,36 @@ namespace clang {
((BackendConsumer*)Context)->InlineAsmDiagHandler2(SM, Loc);
}
+ static void DiagnosticHandler(const llvm::DiagnosticInfo &DI,
+ void *Context) {
+ ((BackendConsumer *)Context)->DiagnosticHandlerImpl(DI);
+ }
+
void InlineAsmDiagHandler2(const llvm::SMDiagnostic &,
SourceLocation LocCookie);
+
+ void DiagnosticHandlerImpl(const llvm::DiagnosticInfo &DI);
+ /// \brief Specialized handler for InlineAsm diagnostic.
+ /// \return True if the diagnostic has been successfully reported, false
+ /// otherwise.
+ bool InlineAsmDiagHandler(const llvm::DiagnosticInfoInlineAsm &D);
+ /// \brief Specialized handler for StackSize diagnostic.
+ /// \return True if the diagnostic has been successfully reported, false
+ /// otherwise.
+ bool StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D);
+ /// \brief Specialized handlers for optimization remarks.
+ /// Note that these handlers only accept remarks and they always handle
+ /// them.
+ void EmitOptimizationMessage(const llvm::DiagnosticInfoOptimizationBase &D,
+ unsigned DiagID);
+ void
+ OptimizationRemarkHandler(const llvm::DiagnosticInfoOptimizationRemark &D);
+ void OptimizationRemarkHandler(
+ const llvm::DiagnosticInfoOptimizationRemarkMissed &D);
+ void OptimizationRemarkHandler(
+ const llvm::DiagnosticInfoOptimizationRemarkAnalysis &D);
+ void OptimizationFailureHandler(
+ const llvm::DiagnosticInfoOptimizationFailure &D);
};
void BackendConsumer::anchor() {}
@@ -224,13 +268,15 @@ static FullSourceLoc ConvertBackendLocation(const llvm::SMDiagnostic &D,
LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
// Create the copy and transfer ownership to clang::SourceManager.
+ // TODO: Avoid copying files into memory.
llvm::MemoryBuffer *CBuf =
llvm::MemoryBuffer::getMemBufferCopy(LBuf->getBuffer(),
LBuf->getBufferIdentifier());
- FileID FID = CSM.createFileIDForMemBuffer(CBuf);
+ // FIXME: Keep a file ID map instead of creating new IDs for each location.
+ FileID FID = CSM.createFileID(CBuf);
// Translate the offset into the file.
- unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
+ unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
SourceLocation NewLoc =
CSM.getLocForStartOfFile(FID).getLocWithOffset(Offset);
return FullSourceLoc(NewLoc, CSM);
@@ -254,13 +300,24 @@ void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D,
FullSourceLoc Loc;
if (D.getLoc() != SMLoc())
Loc = ConvertBackendLocation(D, Context->getSourceManager());
-
+ unsigned DiagID;
+ switch (D.getKind()) {
+ case llvm::SourceMgr::DK_Error:
+ DiagID = diag::err_fe_inline_asm;
+ break;
+ case llvm::SourceMgr::DK_Warning:
+ DiagID = diag::warn_fe_inline_asm;
+ break;
+ case llvm::SourceMgr::DK_Note:
+ DiagID = diag::note_fe_inline_asm;
+ break;
+ }
// If this problem has clang-level source location information, report the
- // issue as being an error in the source with a note showing the instantiated
+ // issue in the source with a note showing the instantiated
// code.
if (LocCookie.isValid()) {
- Diags.Report(LocCookie, diag::err_fe_inline_asm).AddString(Message);
+ Diags.Report(LocCookie, DiagID).AddString(Message);
if (D.getLoc().isValid()) {
DiagnosticBuilder B = Diags.Report(Loc, diag::note_fe_inline_asm_here);
@@ -276,16 +333,224 @@ void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D,
return;
}
- // Otherwise, report the backend error as occurring in the generated .s file.
- // If Loc is invalid, we still need to report the error, it just gets no
+ // Otherwise, report the backend issue as occurring in the generated .s file.
+ // If Loc is invalid, we still need to report the issue, it just gets no
// location info.
- Diags.Report(Loc, diag::err_fe_inline_asm).AddString(Message);
+ Diags.Report(Loc, DiagID).AddString(Message);
}
-//
+#define ComputeDiagID(Severity, GroupName, DiagID) \
+ do { \
+ switch (Severity) { \
+ case llvm::DS_Error: \
+ DiagID = diag::err_fe_##GroupName; \
+ break; \
+ case llvm::DS_Warning: \
+ DiagID = diag::warn_fe_##GroupName; \
+ break; \
+ case llvm::DS_Remark: \
+ llvm_unreachable("'remark' severity not expected"); \
+ break; \
+ case llvm::DS_Note: \
+ DiagID = diag::note_fe_##GroupName; \
+ break; \
+ } \
+ } while (false)
+
+#define ComputeDiagRemarkID(Severity, GroupName, DiagID) \
+ do { \
+ switch (Severity) { \
+ case llvm::DS_Error: \
+ DiagID = diag::err_fe_##GroupName; \
+ break; \
+ case llvm::DS_Warning: \
+ DiagID = diag::warn_fe_##GroupName; \
+ break; \
+ case llvm::DS_Remark: \
+ DiagID = diag::remark_fe_##GroupName; \
+ break; \
+ case llvm::DS_Note: \
+ DiagID = diag::note_fe_##GroupName; \
+ break; \
+ } \
+ } while (false)
+
+bool
+BackendConsumer::InlineAsmDiagHandler(const llvm::DiagnosticInfoInlineAsm &D) {
+ unsigned DiagID;
+ ComputeDiagID(D.getSeverity(), inline_asm, DiagID);
+ std::string Message = D.getMsgStr().str();
+
+ // If this problem has clang-level source location information, report the
+ // issue as being a problem in the source with a note showing the instantiated
+ // code.
+ SourceLocation LocCookie =
+ SourceLocation::getFromRawEncoding(D.getLocCookie());
+ if (LocCookie.isValid())
+ Diags.Report(LocCookie, DiagID).AddString(Message);
+ else {
+ // Otherwise, report the backend diagnostic as occurring in the generated
+ // .s file.
+ // If Loc is invalid, we still need to report the diagnostic, it just gets
+ // no location info.
+ FullSourceLoc Loc;
+ Diags.Report(Loc, DiagID).AddString(Message);
+ }
+ // We handled all the possible severities.
+ return true;
+}
+
+bool
+BackendConsumer::StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D) {
+ if (D.getSeverity() != llvm::DS_Warning)
+ // For now, the only support we have for StackSize diagnostic is warning.
+ // We do not know how to format other severities.
+ return false;
+
+ if (const Decl *ND = Gen->GetDeclForMangledName(D.getFunction().getName())) {
+ Diags.Report(ND->getASTContext().getFullLoc(ND->getLocation()),
+ diag::warn_fe_frame_larger_than)
+ << D.getStackSize() << Decl::castToDeclContext(ND);
+ return true;
+ }
+
+ return false;
+}
+
+void BackendConsumer::EmitOptimizationMessage(
+ const llvm::DiagnosticInfoOptimizationBase &D, unsigned DiagID) {
+ // We only support warnings and remarks.
+ assert(D.getSeverity() == llvm::DS_Remark ||
+ D.getSeverity() == llvm::DS_Warning);
+
+ SourceManager &SourceMgr = Context->getSourceManager();
+ FileManager &FileMgr = SourceMgr.getFileManager();
+ StringRef Filename;
+ unsigned Line, Column;
+ D.getLocation(&Filename, &Line, &Column);
+ SourceLocation DILoc;
+ const FileEntry *FE = FileMgr.getFile(Filename);
+ if (FE && Line > 0) {
+ // If -gcolumn-info was not used, Column will be 0. This upsets the
+ // source manager, so pass 1 if Column is not set.
+ DILoc = SourceMgr.translateFileLineCol(FE, Line, Column ? Column : 1);
+ }
+
+ // If a location isn't available, try to approximate it using the associated
+ // function definition. We use the definition's right brace to differentiate
+ // from diagnostics that genuinely relate to the function itself.
+ FullSourceLoc Loc(DILoc, SourceMgr);
+ if (Loc.isInvalid())
+ if (const Decl *FD = Gen->GetDeclForMangledName(D.getFunction().getName()))
+ Loc = FD->getASTContext().getFullLoc(FD->getBodyRBrace());
+
+ Diags.Report(Loc, DiagID)
+ << AddFlagValue(D.getPassName() ? D.getPassName() : "")
+ << D.getMsg().str();
+
+ if (DILoc.isInvalid())
+ // If we were not able to translate the file:line:col information
+ // back to a SourceLocation, at least emit a note stating that
+ // we could not translate this location. This can happen in the
+ // case of #line directives.
+ Diags.Report(Loc, diag::note_fe_backend_optimization_remark_invalid_loc)
+ << Filename << Line << Column;
+}
+
+void BackendConsumer::OptimizationRemarkHandler(
+ const llvm::DiagnosticInfoOptimizationRemark &D) {
+ // Optimization remarks are active only if the -Rpass flag has a regular
+ // expression that matches the name of the pass name in \p D.
+ if (CodeGenOpts.OptimizationRemarkPattern &&
+ CodeGenOpts.OptimizationRemarkPattern->match(D.getPassName()))
+ EmitOptimizationMessage(D, diag::remark_fe_backend_optimization_remark);
+}
+
+void BackendConsumer::OptimizationRemarkHandler(
+ const llvm::DiagnosticInfoOptimizationRemarkMissed &D) {
+ // Missed optimization remarks are active only if the -Rpass-missed
+ // flag has a regular expression that matches the name of the pass
+ // name in \p D.
+ if (CodeGenOpts.OptimizationRemarkMissedPattern &&
+ CodeGenOpts.OptimizationRemarkMissedPattern->match(D.getPassName()))
+ EmitOptimizationMessage(D,
+ diag::remark_fe_backend_optimization_remark_missed);
+}
+
+void BackendConsumer::OptimizationRemarkHandler(
+ const llvm::DiagnosticInfoOptimizationRemarkAnalysis &D) {
+ // Optimization analysis remarks are active only if the -Rpass-analysis
+ // flag has a regular expression that matches the name of the pass
+ // name in \p D.
+ if (CodeGenOpts.OptimizationRemarkAnalysisPattern &&
+ CodeGenOpts.OptimizationRemarkAnalysisPattern->match(D.getPassName()))
+ EmitOptimizationMessage(
+ D, diag::remark_fe_backend_optimization_remark_analysis);
+}
+
+void BackendConsumer::OptimizationFailureHandler(
+ const llvm::DiagnosticInfoOptimizationFailure &D) {
+ EmitOptimizationMessage(D, diag::warn_fe_backend_optimization_failure);
+}
+
+/// \brief This function is invoked when the backend needs
+/// to report something to the user.
+void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) {
+ unsigned DiagID = diag::err_fe_inline_asm;
+ llvm::DiagnosticSeverity Severity = DI.getSeverity();
+ // Get the diagnostic ID based.
+ switch (DI.getKind()) {
+ case llvm::DK_InlineAsm:
+ if (InlineAsmDiagHandler(cast<DiagnosticInfoInlineAsm>(DI)))
+ return;
+ ComputeDiagID(Severity, inline_asm, DiagID);
+ break;
+ case llvm::DK_StackSize:
+ if (StackSizeDiagHandler(cast<DiagnosticInfoStackSize>(DI)))
+ return;
+ ComputeDiagID(Severity, backend_frame_larger_than, DiagID);
+ break;
+ case llvm::DK_OptimizationRemark:
+ // Optimization remarks are always handled completely by this
+ // handler. There is no generic way of emitting them.
+ OptimizationRemarkHandler(cast<DiagnosticInfoOptimizationRemark>(DI));
+ return;
+ case llvm::DK_OptimizationRemarkMissed:
+ // Optimization remarks are always handled completely by this
+ // handler. There is no generic way of emitting them.
+ OptimizationRemarkHandler(cast<DiagnosticInfoOptimizationRemarkMissed>(DI));
+ return;
+ case llvm::DK_OptimizationRemarkAnalysis:
+ // Optimization remarks are always handled completely by this
+ // handler. There is no generic way of emitting them.
+ OptimizationRemarkHandler(
+ cast<DiagnosticInfoOptimizationRemarkAnalysis>(DI));
+ return;
+ case llvm::DK_OptimizationFailure:
+ // Optimization failures are always handled completely by this
+ // handler.
+ OptimizationFailureHandler(cast<DiagnosticInfoOptimizationFailure>(DI));
+ return;
+ default:
+ // Plugin IDs are not bound to any value as they are set dynamically.
+ ComputeDiagRemarkID(Severity, backend_plugin, DiagID);
+ break;
+ }
+ std::string MsgStorage;
+ {
+ raw_string_ostream Stream(MsgStorage);
+ DiagnosticPrinterRawOStream DP(Stream);
+ DI.print(DP);
+ }
+
+ // Report the backend message using the usual diagnostic mechanism.
+ FullSourceLoc Loc;
+ Diags.Report(Loc, DiagID).AddString(MsgStorage);
+}
+#undef ComputeDiagID
CodeGenAction::CodeGenAction(unsigned _Act, LLVMContext *_VMContext)
- : Act(_Act), LinkModule(0),
+ : Act(_Act), LinkModule(nullptr),
VMContext(_VMContext ? _VMContext : new LLVMContext),
OwnsVMContext(!_VMContext) {}
@@ -310,9 +575,7 @@ void CodeGenAction::EndSourceFileAction() {
TheModule.reset(BEConsumer->takeModule());
}
-llvm::Module *CodeGenAction::takeModule() {
- return TheModule.take();
-}
+llvm::Module *CodeGenAction::takeModule() { return TheModule.release(); }
llvm::LLVMContext *CodeGenAction::takeLLVMContext() {
OwnsVMContext = false;
@@ -330,8 +593,9 @@ static raw_ostream *GetOutputStream(CompilerInstance &CI,
case Backend_EmitBC:
return CI.createDefaultOutputFile(true, InFile, "bc");
case Backend_EmitNothing:
- return 0;
+ return nullptr;
case Backend_EmitMCNull:
+ return CI.createNullOutputFile();
case Backend_EmitObj:
return CI.createDefaultOutputFile(true, InFile, "o");
}
@@ -342,9 +606,9 @@ static raw_ostream *GetOutputStream(CompilerInstance &CI,
ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
BackendAction BA = static_cast<BackendAction>(Act);
- OwningPtr<raw_ostream> OS(GetOutputStream(CI, InFile, BA));
+ std::unique_ptr<raw_ostream> OS(GetOutputStream(CI, InFile, BA));
if (BA != Backend_EmitNothing && !OS)
- return 0;
+ return nullptr;
llvm::Module *LinkModuleToUse = LinkModule;
@@ -359,23 +623,23 @@ ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
if (!BCBuf) {
CI.getDiagnostics().Report(diag::err_cannot_open_file)
<< LinkBCFile << ErrorStr;
- return 0;
+ return nullptr;
}
- LinkModuleToUse = getLazyBitcodeModule(BCBuf, *VMContext, &ErrorStr);
- if (!LinkModuleToUse) {
+ ErrorOr<llvm::Module *> ModuleOrErr =
+ getLazyBitcodeModule(BCBuf, *VMContext);
+ if (std::error_code EC = ModuleOrErr.getError()) {
CI.getDiagnostics().Report(diag::err_cannot_open_file)
- << LinkBCFile << ErrorStr;
- return 0;
+ << LinkBCFile << EC.message();
+ return nullptr;
}
+ LinkModuleToUse = ModuleOrErr.get();
}
- BEConsumer =
- new BackendConsumer(BA, CI.getDiagnostics(),
- CI.getCodeGenOpts(), CI.getTargetOpts(),
- CI.getLangOpts(),
- CI.getFrontendOpts().ShowTimers, InFile,
- LinkModuleToUse, OS.take(), *VMContext);
+ BEConsumer = new BackendConsumer(BA, CI.getDiagnostics(), CI.getCodeGenOpts(),
+ CI.getTargetOpts(), CI.getLangOpts(),
+ CI.getFrontendOpts().ShowTimers, InFile,
+ LinkModuleToUse, OS.release(), *VMContext);
return BEConsumer;
}
@@ -390,49 +654,48 @@ void CodeGenAction::ExecuteAction() {
bool Invalid;
SourceManager &SM = CI.getSourceManager();
- const llvm::MemoryBuffer *MainFile = SM.getBuffer(SM.getMainFileID(),
- &Invalid);
+ FileID FID = SM.getMainFileID();
+ llvm::MemoryBuffer *MainFile = SM.getBuffer(FID, &Invalid);
if (Invalid)
return;
- // FIXME: This is stupid, IRReader shouldn't take ownership.
- llvm::MemoryBuffer *MainFileCopy =
- llvm::MemoryBuffer::getMemBufferCopy(MainFile->getBuffer(),
- getCurrentFile());
-
llvm::SMDiagnostic Err;
- TheModule.reset(ParseIR(MainFileCopy, Err, *VMContext));
+ TheModule.reset(ParseIR(MainFile, Err, *VMContext));
if (!TheModule) {
- // Translate from the diagnostic info to the SourceManager location.
- SourceLocation Loc = SM.translateFileLineCol(
- SM.getFileEntryForID(SM.getMainFileID()), Err.getLineNo(),
- Err.getColumnNo() + 1);
+ // Translate from the diagnostic info to the SourceManager location if
+ // available.
+ // TODO: Unify this with ConvertBackendLocation()
+ SourceLocation Loc;
+ if (Err.getLineNo() > 0) {
+ assert(Err.getColumnNo() >= 0);
+ Loc = SM.translateFileLineCol(SM.getFileEntryForID(FID),
+ Err.getLineNo(), Err.getColumnNo() + 1);
+ }
- // Get a custom diagnostic for the error. We strip off a leading
- // diagnostic code if there is one.
+ // Strip off a leading diagnostic code if there is one.
StringRef Msg = Err.getMessage();
if (Msg.startswith("error: "))
Msg = Msg.substr(7);
- // Escape '%', which is interpreted as a format character.
- SmallString<128> EscapedMessage;
- for (unsigned i = 0, e = Msg.size(); i != e; ++i) {
- if (Msg[i] == '%')
- EscapedMessage += '%';
- EscapedMessage += Msg[i];
- }
+ unsigned DiagID =
+ CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0");
+ CI.getDiagnostics().Report(Loc, DiagID) << Msg;
+ return;
+ }
+ const TargetOptions &TargetOpts = CI.getTargetOpts();
+ if (TheModule->getTargetTriple() != TargetOpts.Triple) {
unsigned DiagID = CI.getDiagnostics().getCustomDiagID(
- DiagnosticsEngine::Error, EscapedMessage);
+ DiagnosticsEngine::Warning,
+ "overriding the module target triple with %0");
- CI.getDiagnostics().Report(Loc, DiagID);
- return;
+ CI.getDiagnostics().Report(SourceLocation(), DiagID) << TargetOpts.Triple;
+ TheModule->setTargetTriple(TargetOpts.Triple);
}
- EmitBackendOutput(CI.getDiagnostics(), CI.getCodeGenOpts(),
- CI.getTargetOpts(), CI.getLangOpts(),
- TheModule.get(),
- BA, OS);
+ EmitBackendOutput(CI.getDiagnostics(), CI.getCodeGenOpts(), TargetOpts,
+ CI.getLangOpts(), CI.getTarget().getTargetDescription(),
+ TheModule.get(), BA, OS);
return;
}
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index ce1b44559dcc..5ca3a78bb4fa 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -15,13 +15,14 @@
#include "CGCUDARuntime.h"
#include "CGCXXABI.h"
#include "CGDebugInfo.h"
+#include "CGOpenMPRuntime.h"
#include "CodeGenModule.h"
+#include "CodeGenPGO.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtCXX.h"
-#include "clang/Basic/OpenCL.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
@@ -34,22 +35,23 @@ using namespace CodeGen;
CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
: CodeGenTypeCache(cgm), CGM(cgm), Target(cgm.getTarget()),
- Builder(cgm.getModule().getContext()), CapturedStmtInfo(0),
- SanitizePerformTypeCheck(CGM.getSanOpts().Null |
- CGM.getSanOpts().Alignment |
- CGM.getSanOpts().ObjectSize |
- CGM.getSanOpts().Vptr),
- SanOpts(&CGM.getSanOpts()), AutoreleaseResult(false), BlockInfo(0),
- BlockPointer(0), LambdaThisCaptureField(0), NormalCleanupDest(0),
- NextCleanupDestIndex(1), FirstBlockInfo(0), EHResumeBlock(0),
- ExceptionSlot(0), EHSelectorSlot(0), DebugInfo(CGM.getModuleDebugInfo()),
- DisableDebugInfo(false), DidCallStackSave(false), IndirectBranch(0),
- SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0), NumReturnExprs(0),
- NumSimpleReturnExprs(0), CXXABIThisDecl(0), CXXABIThisValue(0),
- CXXThisValue(0), CXXDefaultInitExprThis(0),
- CXXStructorImplicitParamDecl(0), CXXStructorImplicitParamValue(0),
- OutermostConditional(0), CurLexicalScope(0), TerminateLandingPad(0),
- TerminateHandler(0), TrapBB(0) {
+ Builder(cgm.getModule().getContext(), llvm::ConstantFolder(),
+ CGBuilderInserterTy(this)),
+ CapturedStmtInfo(nullptr), SanOpts(&CGM.getLangOpts().Sanitize),
+ IsSanitizerScope(false), AutoreleaseResult(false), BlockInfo(nullptr),
+ BlockPointer(nullptr), LambdaThisCaptureField(nullptr),
+ NormalCleanupDest(nullptr), NextCleanupDestIndex(1),
+ FirstBlockInfo(nullptr), EHResumeBlock(nullptr), ExceptionSlot(nullptr),
+ EHSelectorSlot(nullptr), DebugInfo(CGM.getModuleDebugInfo()),
+ DisableDebugInfo(false), DidCallStackSave(false), IndirectBranch(nullptr),
+ PGO(cgm), SwitchInsn(nullptr), SwitchWeights(nullptr),
+ CaseRangeBlock(nullptr), UnreachableBlock(nullptr), NumReturnExprs(0),
+ NumSimpleReturnExprs(0), CXXABIThisDecl(nullptr),
+ CXXABIThisValue(nullptr), CXXThisValue(nullptr),
+ CXXDefaultInitExprThis(nullptr), CXXStructorImplicitParamDecl(nullptr),
+ CXXStructorImplicitParamValue(nullptr), OutermostConditional(nullptr),
+ CurLexicalScope(nullptr), TerminateLandingPad(nullptr),
+ TerminateHandler(nullptr), TrapBB(nullptr) {
if (!suppressNewContext)
CGM.getCXXABI().getMangleContext().startNewFunction();
@@ -71,6 +73,10 @@ CodeGenFunction::~CodeGenFunction() {
// something.
if (FirstBlockInfo)
destroyBlockInfos(FirstBlockInfo);
+
+ if (getLangOpts().OpenMP) {
+ CGM.getOpenMPRuntime().FunctionFinished(*this);
+ }
}
@@ -157,7 +163,7 @@ void CodeGenFunction::EmitReturnBlock() {
// cleans up functions which started with a unified return block.
if (ReturnBlock.getBlock()->hasOneUse()) {
llvm::BranchInst *BI =
- dyn_cast<llvm::BranchInst>(*ReturnBlock.getBlock()->use_begin());
+ dyn_cast<llvm::BranchInst>(*ReturnBlock.getBlock()->user_begin());
if (BI && BI->isUnconditional() &&
BI->getSuccessor(0) == ReturnBlock.getBlock()) {
// Reset insertion point, including debug location, and delete the
@@ -255,7 +261,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
// Remove the AllocaInsertPt instruction, which is just a convenience for us.
llvm::Instruction *Ptr = AllocaInsertPt;
- AllocaInsertPt = 0;
+ AllocaInsertPt = nullptr;
Ptr->eraseFromParent();
// If someone took the address of a label but never did an indirect goto, we
@@ -275,6 +281,14 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
if (CGM.getCodeGenOpts().EmitDeclMetadata)
EmitDeclMetadata();
+
+ for (SmallVectorImpl<std::pair<llvm::Instruction *, llvm::Value *> >::iterator
+ I = DeferredReplacements.begin(),
+ E = DeferredReplacements.end();
+ I != E; ++I) {
+ I->first->replaceAllUsesWith(I->second);
+ I->first->eraseFromParent();
+ }
}
/// ShouldInstrumentFunction - Return true if the current function should be
@@ -330,6 +344,8 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
// Each MDNode is a list in the form of "key", N number of values which is
// the same number of values as their are kernel arguments.
+ const PrintingPolicy &Policy = ASTCtx.getPrintingPolicy();
+
// MDNode for the kernel argument address space qualifiers.
SmallVector<llvm::Value*, 8> addressQuals;
addressQuals.push_back(llvm::MDString::get(Context, "kernel_arg_addr_space"));
@@ -363,7 +379,8 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
pointeeTy.getAddressSpace())));
// Get argument type name.
- std::string typeName = pointeeTy.getUnqualifiedType().getAsString() + "*";
+ std::string typeName =
+ pointeeTy.getUnqualifiedType().getAsString(Policy) + "*";
// Turn "unsigned type" to "utype"
std::string::size_type pos = typeName.find("unsigned");
@@ -381,10 +398,15 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
if (pointeeTy.isVolatileQualified())
typeQuals += typeQuals.empty() ? "volatile" : " volatile";
} else {
- addressQuals.push_back(Builder.getInt32(0));
+ uint32_t AddrSpc = 0;
+ if (ty->isImageType())
+ AddrSpc =
+ CGM.getContext().getTargetAddressSpace(LangAS::opencl_global);
+
+ addressQuals.push_back(Builder.getInt32(AddrSpc));
// Get argument type name.
- std::string typeName = ty.getUnqualifiedType().getAsString();
+ std::string typeName = ty.getUnqualifiedType().getAsString(Policy);
// Turn "unsigned type" to "utype"
std::string::size_type pos = typeName.find("unsigned");
@@ -399,16 +421,17 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
if (ty.isVolatileQualified())
typeQuals += typeQuals.empty() ? "volatile" : " volatile";
}
-
+
argTypeQuals.push_back(llvm::MDString::get(Context, typeQuals));
// Get image access qualifier:
if (ty->isImageType()) {
- if (parm->hasAttr<OpenCLImageAccessAttr>() &&
- parm->getAttr<OpenCLImageAccessAttr>()->getAccess() == CLIA_write_only)
+ const OpenCLImageAccessAttr *A = parm->getAttr<OpenCLImageAccessAttr>();
+ if (A && A->isWriteOnly())
accessQuals.push_back(llvm::MDString::get(Context, "write_only"));
else
accessQuals.push_back(llvm::MDString::get(Context, "read_only"));
+ // FIXME: what about read_write?
} else
accessQuals.push_back(llvm::MDString::get(Context, "none"));
@@ -438,16 +461,15 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
GenOpenCLArgMetadata(FD, Fn, CGM, Context, kernelMDArgs,
Builder, getContext());
- if (FD->hasAttr<VecTypeHintAttr>()) {
- VecTypeHintAttr *attr = FD->getAttr<VecTypeHintAttr>();
- QualType hintQTy = attr->getTypeHint();
+ if (const VecTypeHintAttr *A = FD->getAttr<VecTypeHintAttr>()) {
+ QualType hintQTy = A->getTypeHint();
const ExtVectorType *hintEltQTy = hintQTy->getAs<ExtVectorType>();
bool isSignedInteger =
hintQTy->isSignedIntegerType() ||
(hintEltQTy && hintEltQTy->getElementType()->isSignedIntegerType());
llvm::Value *attrMDArgs[] = {
llvm::MDString::get(Context, "vec_type_hint"),
- llvm::UndefValue::get(CGM.getTypes().ConvertType(attr->getTypeHint())),
+ llvm::UndefValue::get(CGM.getTypes().ConvertType(A->getTypeHint())),
llvm::ConstantInt::get(
llvm::IntegerType::get(Context, 32),
llvm::APInt(32, (uint64_t)(isSignedInteger ? 1 : 0)))
@@ -455,24 +477,22 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
kernelMDArgs.push_back(llvm::MDNode::get(Context, attrMDArgs));
}
- if (FD->hasAttr<WorkGroupSizeHintAttr>()) {
- WorkGroupSizeHintAttr *attr = FD->getAttr<WorkGroupSizeHintAttr>();
+ if (const WorkGroupSizeHintAttr *A = FD->getAttr<WorkGroupSizeHintAttr>()) {
llvm::Value *attrMDArgs[] = {
llvm::MDString::get(Context, "work_group_size_hint"),
- Builder.getInt32(attr->getXDim()),
- Builder.getInt32(attr->getYDim()),
- Builder.getInt32(attr->getZDim())
+ Builder.getInt32(A->getXDim()),
+ Builder.getInt32(A->getYDim()),
+ Builder.getInt32(A->getZDim())
};
kernelMDArgs.push_back(llvm::MDNode::get(Context, attrMDArgs));
}
- if (FD->hasAttr<ReqdWorkGroupSizeAttr>()) {
- ReqdWorkGroupSizeAttr *attr = FD->getAttr<ReqdWorkGroupSizeAttr>();
+ if (const ReqdWorkGroupSizeAttr *A = FD->getAttr<ReqdWorkGroupSizeAttr>()) {
llvm::Value *attrMDArgs[] = {
llvm::MDString::get(Context, "reqd_work_group_size"),
- Builder.getInt32(attr->getXDim()),
- Builder.getInt32(attr->getYDim()),
- Builder.getInt32(attr->getZDim())
+ Builder.getInt32(A->getXDim()),
+ Builder.getInt32(A->getYDim()),
+ Builder.getInt32(A->getZDim())
};
kernelMDArgs.push_back(llvm::MDNode::get(Context, attrMDArgs));
}
@@ -483,37 +503,55 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
OpenCLKernelMetadata->addOperand(kernelMDNode);
}
+/// Determine whether the function F ends with a return stmt.
+static bool endsWithReturn(const Decl* F) {
+ const Stmt *Body = nullptr;
+ if (auto *FD = dyn_cast_or_null<FunctionDecl>(F))
+ Body = FD->getBody();
+ else if (auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(F))
+ Body = OMD->getBody();
+
+ if (auto *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
+ auto LastStmt = CS->body_rbegin();
+ if (LastStmt != CS->body_rend())
+ return isa<ReturnStmt>(*LastStmt);
+ }
+ return false;
+}
+
void CodeGenFunction::StartFunction(GlobalDecl GD,
QualType RetTy,
llvm::Function *Fn,
const CGFunctionInfo &FnInfo,
const FunctionArgList &Args,
+ SourceLocation Loc,
SourceLocation StartLoc) {
const Decl *D = GD.getDecl();
DidCallStackSave = false;
CurCodeDecl = D;
- CurFuncDecl = (D ? D->getNonClosureContext() : 0);
+ CurFuncDecl = (D ? D->getNonClosureContext() : nullptr);
FnRetTy = RetTy;
CurFn = Fn;
CurFnInfo = &FnInfo;
assert(CurFn->isDeclaration() && "Function already has body?");
- if (CGM.getSanitizerBlacklist().isIn(*Fn)) {
+ if (CGM.getSanitizerBlacklist().isIn(*Fn))
SanOpts = &SanitizerOptions::Disabled;
- SanitizePerformTypeCheck = false;
- }
// Pass inline keyword to optimizer if it appears explicitly on any
- // declaration.
- if (!CGM.getCodeGenOpts().NoInline)
- if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
- for (FunctionDecl::redecl_iterator RI = FD->redecls_begin(),
- RE = FD->redecls_end(); RI != RE; ++RI)
+ // declaration. Also, in the case of -fno-inline attach NoInline
+ // attribute to all function that are not marked AlwaysInline.
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+ if (!CGM.getCodeGenOpts().NoInline) {
+ for (auto RI : FD->redecls())
if (RI->isInlineSpecified()) {
Fn->addFnAttr(llvm::Attribute::InlineHint);
break;
}
+ } else if (!FD->hasAttr<AlwaysInlineAttr>())
+ Fn->addFnAttr(llvm::Attribute::NoInline);
+ }
if (getLangOpts().OpenCL) {
// Add metadata for a kernel function.
@@ -562,9 +600,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
QualType FnType =
getContext().getFunctionType(RetTy, ArgTypes,
FunctionProtoType::ExtProtoInfo());
-
- DI->setLocation(StartLoc);
- DI->EmitFunctionStart(GD, FnType, CurFn, Builder);
+ DI->EmitFunctionStart(GD, Loc, StartLoc, FnType, CurFn, Builder);
}
if (ShouldInstrumentFunction())
@@ -575,12 +611,27 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
if (RetTy->isVoidType()) {
// Void type; nothing to return.
- ReturnValue = 0;
+ ReturnValue = nullptr;
+
+ // Count the implicit return.
+ if (!endsWithReturn(D))
+ ++NumReturnExprs;
} else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect &&
!hasScalarEvaluationKind(CurFnInfo->getReturnType())) {
// Indirect aggregate return; emit returned value directly into sret slot.
// This reduces code size, and affects correctness in C++.
- ReturnValue = CurFn->arg_begin();
+ auto AI = CurFn->arg_begin();
+ if (CurFnInfo->getReturnInfo().isSRetAfterThis())
+ ++AI;
+ ReturnValue = AI;
+ } else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::InAlloca &&
+ !hasScalarEvaluationKind(CurFnInfo->getReturnType())) {
+ // Load the sret pointer from the argument struct and return into that.
+ unsigned Idx = CurFnInfo->getReturnInfo().getInAllocaFieldIndex();
+ llvm::Function::arg_iterator EI = CurFn->arg_end();
+ --EI;
+ llvm::Value *Addr = Builder.CreateStructGEP(EI, Idx);
+ ReturnValue = Builder.CreateLoad(Addr, "agg.result");
} else {
ReturnValue = CreateIRTemp(RetTy, "retval");
@@ -645,12 +696,34 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
void CodeGenFunction::EmitFunctionBody(FunctionArgList &Args,
const Stmt *Body) {
+ RegionCounter Cnt = getPGORegionCounter(Body);
+ Cnt.beginRegion(Builder);
if (const CompoundStmt *S = dyn_cast<CompoundStmt>(Body))
EmitCompoundStmtWithoutScope(*S);
else
EmitStmt(Body);
}
+/// When instrumenting to collect profile data, the counts for some blocks
+/// such as switch cases need to not include the fall-through counts, so
+/// emit a branch around the instrumentation code. When not instrumenting,
+/// this just calls EmitBlock().
+void CodeGenFunction::EmitBlockWithFallThrough(llvm::BasicBlock *BB,
+ RegionCounter &Cnt) {
+ llvm::BasicBlock *SkipCountBB = nullptr;
+ if (HaveInsertPoint() && CGM.getCodeGenOpts().ProfileInstrGenerate) {
+ // When instrumenting for profiling, the fallthrough to certain
+ // statements needs to skip over the instrumentation code so that we
+ // get an accurate count.
+ SkipCountBB = createBasicBlock("skipcount");
+ EmitBranch(SkipCountBB);
+ }
+ EmitBlock(BB);
+ Cnt.beginRegion(Builder, /*AddIncomingFallThrough=*/true);
+ if (SkipCountBB)
+ EmitBlock(SkipCountBB);
+}
+
/// Tries to mark the given function nounwind based on the
/// non-existence of any throwing calls within it. We believe this is
/// lightweight enough to do at -O0.
@@ -688,30 +761,47 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
// Check if we should generate debug info for this function.
if (FD->hasAttr<NoDebugAttr>())
- DebugInfo = NULL; // disable debug info indefinitely for this function
+ DebugInfo = nullptr; // disable debug info indefinitely for this function
FunctionArgList Args;
- QualType ResTy = FD->getResultType();
+ QualType ResTy = FD->getReturnType();
CurGD = GD;
- const CXXMethodDecl *MD;
- if ((MD = dyn_cast<CXXMethodDecl>(FD)) && MD->isInstance()) {
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
+ if (MD && MD->isInstance()) {
if (CGM.getCXXABI().HasThisReturn(GD))
ResTy = MD->getThisType(getContext());
- CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResTy, Args);
+ CGM.getCXXABI().buildThisParam(*this, Args);
}
for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i)
Args.push_back(FD->getParamDecl(i));
+ if (MD && (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)))
+ CGM.getCXXABI().addImplicitStructorParams(*this, ResTy, Args);
+
SourceRange BodyRange;
if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();
CurEHLocation = BodyRange.getEnd();
+ // Use the location of the start of the function to determine where
+ // the function definition is located. By default use the location
+ // of the declaration as the location for the subprogram. A function
+ // may lack a declaration in the source code if it is created by code
+ // gen. (examples: _GLOBAL__I_a, __cxx_global_array_dtor, thunk).
+ SourceLocation Loc = FD->getLocation();
+
+ // If this is a function specialization then use the pattern body
+ // as the location for the function.
+ if (const FunctionDecl *SpecDecl = FD->getTemplateInstantiationPattern())
+ if (SpecDecl->hasBody(SpecDecl))
+ Loc = SpecDecl->getLocation();
+
// Emit the standard function prologue.
- StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin());
+ StartFunction(GD, ResTy, Fn, FnInfo, Args, Loc, BodyRange.getBegin());
// Generate the body of the function.
+ PGO.assignRegionCounters(GD.getDecl(), CurFn);
if (isa<CXXDestructorDecl>(FD))
EmitDestructorBody(Args);
else if (isa<CXXConstructorDecl>(FD))
@@ -753,12 +843,13 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
// If the '}' that terminates a function is reached, and the value of the
// function call is used by the caller, the behavior is undefined.
if (getLangOpts().CPlusPlus && !FD->hasImplicitReturnZero() &&
- !FD->getResultType()->isVoidType() && Builder.GetInsertBlock()) {
- if (SanOpts->Return)
+ !FD->getReturnType()->isVoidType() && Builder.GetInsertBlock()) {
+ if (SanOpts->Return) {
+ SanitizerScope SanScope(this);
EmitCheck(Builder.getFalse(), "missing_return",
EmitCheckSourceLocation(FD->getLocation()),
ArrayRef<llvm::Value *>(), CRK_Unrecoverable);
- else if (CGM.getCodeGenOpts().OptimizationLevel == 0)
+ } else if (CGM.getCodeGenOpts().OptimizationLevel == 0)
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::trap));
Builder.CreateUnreachable();
Builder.ClearInsertionPoint();
@@ -771,6 +862,9 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
// a quick pass now to see if we can.
if (!CurFn->doesNotThrow())
TryMarkNoThrow(CurFn);
+
+ PGO.emitInstrumentationData();
+ PGO.destroyRegionCounters();
}
/// ContainsLabel - Return true if the statement contains a label in it. If
@@ -778,7 +872,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
/// that we can just remove the code.
bool CodeGenFunction::ContainsLabel(const Stmt *S, bool IgnoreCaseStmts) {
// Null statement, not a label!
- if (S == 0) return false;
+ if (!S) return false;
// If this is a label, we have to emit the code, consider something like:
// if (0) { ... foo: bar(); } goto foo;
@@ -810,7 +904,7 @@ bool CodeGenFunction::ContainsLabel(const Stmt *S, bool IgnoreCaseStmts) {
/// inside of it, this is fine.
bool CodeGenFunction::containsBreak(const Stmt *S) {
// Null statement, not a label!
- if (S == 0) return false;
+ if (!S) return false;
// If this is a switch or loop that defines its own break scope, then we can
// include it and anything inside of it.
@@ -869,19 +963,25 @@ ConstantFoldsToSimpleInteger(const Expr *Cond, llvm::APSInt &ResultInt) {
///
void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
llvm::BasicBlock *TrueBlock,
- llvm::BasicBlock *FalseBlock) {
+ llvm::BasicBlock *FalseBlock,
+ uint64_t TrueCount) {
Cond = Cond->IgnoreParens();
if (const BinaryOperator *CondBOp = dyn_cast<BinaryOperator>(Cond)) {
+
// Handle X && Y in a condition.
if (CondBOp->getOpcode() == BO_LAnd) {
+ RegionCounter Cnt = getPGORegionCounter(CondBOp);
+
// If we have "1 && X", simplify the code. "0 && X" would have constant
// folded if the case was simple enough.
bool ConstantBool = false;
if (ConstantFoldsToSimpleInteger(CondBOp->getLHS(), ConstantBool) &&
ConstantBool) {
// br(1 && X) -> br(X).
- return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock);
+ Cnt.beginRegion(Builder);
+ return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock,
+ TrueCount);
}
// If we have "X && 1", simplify the code to use an uncond branch.
@@ -889,33 +989,42 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
if (ConstantFoldsToSimpleInteger(CondBOp->getRHS(), ConstantBool) &&
ConstantBool) {
// br(X && 1) -> br(X).
- return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock);
+ return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock,
+ TrueCount);
}
// Emit the LHS as a conditional. If the LHS conditional is false, we
// want to jump to the FalseBlock.
llvm::BasicBlock *LHSTrue = createBasicBlock("land.lhs.true");
+ // The counter tells us how often we evaluate RHS, and all of TrueCount
+ // can be propagated to that branch.
+ uint64_t RHSCount = Cnt.getCount();
ConditionalEvaluation eval(*this);
- EmitBranchOnBoolExpr(CondBOp->getLHS(), LHSTrue, FalseBlock);
+ EmitBranchOnBoolExpr(CondBOp->getLHS(), LHSTrue, FalseBlock, RHSCount);
EmitBlock(LHSTrue);
// Any temporaries created here are conditional.
+ Cnt.beginRegion(Builder);
eval.begin(*this);
- EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock);
+ EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock, TrueCount);
eval.end(*this);
return;
}
if (CondBOp->getOpcode() == BO_LOr) {
+ RegionCounter Cnt = getPGORegionCounter(CondBOp);
+
// If we have "0 || X", simplify the code. "1 || X" would have constant
// folded if the case was simple enough.
bool ConstantBool = false;
if (ConstantFoldsToSimpleInteger(CondBOp->getLHS(), ConstantBool) &&
!ConstantBool) {
// br(0 || X) -> br(X).
- return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock);
+ Cnt.beginRegion(Builder);
+ return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock,
+ TrueCount);
}
// If we have "X || 0", simplify the code to use an uncond branch.
@@ -923,20 +1032,28 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
if (ConstantFoldsToSimpleInteger(CondBOp->getRHS(), ConstantBool) &&
!ConstantBool) {
// br(X || 0) -> br(X).
- return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock);
+ return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock,
+ TrueCount);
}
// Emit the LHS as a conditional. If the LHS conditional is true, we
// want to jump to the TrueBlock.
llvm::BasicBlock *LHSFalse = createBasicBlock("lor.lhs.false");
+ // We have the count for entry to the RHS and for the whole expression
+ // being true, so we can divy up True count between the short circuit and
+ // the RHS.
+ uint64_t LHSCount = Cnt.getParentCount() - Cnt.getCount();
+ uint64_t RHSCount = TrueCount - LHSCount;
ConditionalEvaluation eval(*this);
- EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, LHSFalse);
+ EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, LHSFalse, LHSCount);
EmitBlock(LHSFalse);
// Any temporaries created here are conditional.
+ Cnt.beginRegion(Builder);
eval.begin(*this);
- EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock);
+ EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock, RHSCount);
+
eval.end(*this);
return;
@@ -945,8 +1062,13 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
if (const UnaryOperator *CondUOp = dyn_cast<UnaryOperator>(Cond)) {
// br(!x, t, f) -> br(x, f, t)
- if (CondUOp->getOpcode() == UO_LNot)
- return EmitBranchOnBoolExpr(CondUOp->getSubExpr(), FalseBlock, TrueBlock);
+ if (CondUOp->getOpcode() == UO_LNot) {
+ // Negate the count.
+ uint64_t FalseCount = PGO.getCurrentRegionCount() - TrueCount;
+ // Negate the condition and swap the destination blocks.
+ return EmitBranchOnBoolExpr(CondUOp->getSubExpr(), FalseBlock, TrueBlock,
+ FalseCount);
+ }
}
if (const ConditionalOperator *CondOp = dyn_cast<ConditionalOperator>(Cond)) {
@@ -954,17 +1076,32 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
llvm::BasicBlock *LHSBlock = createBasicBlock("cond.true");
llvm::BasicBlock *RHSBlock = createBasicBlock("cond.false");
+ RegionCounter Cnt = getPGORegionCounter(CondOp);
ConditionalEvaluation cond(*this);
- EmitBranchOnBoolExpr(CondOp->getCond(), LHSBlock, RHSBlock);
+ EmitBranchOnBoolExpr(CondOp->getCond(), LHSBlock, RHSBlock, Cnt.getCount());
+
+ // When computing PGO branch weights, we only know the overall count for
+ // the true block. This code is essentially doing tail duplication of the
+ // naive code-gen, introducing new edges for which counts are not
+ // available. Divide the counts proportionally between the LHS and RHS of
+ // the conditional operator.
+ uint64_t LHSScaledTrueCount = 0;
+ if (TrueCount) {
+ double LHSRatio = Cnt.getCount() / (double) Cnt.getParentCount();
+ LHSScaledTrueCount = TrueCount * LHSRatio;
+ }
cond.begin(*this);
EmitBlock(LHSBlock);
- EmitBranchOnBoolExpr(CondOp->getLHS(), TrueBlock, FalseBlock);
+ Cnt.beginRegion(Builder);
+ EmitBranchOnBoolExpr(CondOp->getLHS(), TrueBlock, FalseBlock,
+ LHSScaledTrueCount);
cond.end(*this);
cond.begin(*this);
EmitBlock(RHSBlock);
- EmitBranchOnBoolExpr(CondOp->getRHS(), TrueBlock, FalseBlock);
+ EmitBranchOnBoolExpr(CondOp->getRHS(), TrueBlock, FalseBlock,
+ TrueCount - LHSScaledTrueCount);
cond.end(*this);
return;
@@ -980,9 +1117,15 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
return;
}
+ // Create branch weights based on the number of times we get here and the
+ // number of times the condition should be true.
+ uint64_t CurrentCount = std::max(PGO.getCurrentRegionCount(), TrueCount);
+ llvm::MDNode *Weights = PGO.createBranchWeights(TrueCount,
+ CurrentCount - TrueCount);
+
// Emit the code with the fully general case.
llvm::Value *CondV = EvaluateExprAsBool(Cond);
- Builder.CreateCondBr(CondV, TrueBlock, FalseBlock);
+ Builder.CreateCondBr(CondV, TrueBlock, FalseBlock, Weights);
}
/// ErrorUnsupported - Print out an error that codegen doesn't support the
@@ -1075,7 +1218,7 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
getContext().getAsArrayType(Ty))) {
QualType eltType;
llvm::Value *numElts;
- llvm::tie(numElts, eltType) = getVLASize(vlaType);
+ std::tie(numElts, eltType) = getVLASize(vlaType);
SizeVal = numElts;
CharUnits eltSize = getContext().getTypeSizeInChars(eltType);
@@ -1087,7 +1230,7 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
}
} else {
SizeVal = CGM.getSize(Size);
- vla = 0;
+ vla = nullptr;
}
// If the type contains a pointer to data member we can't memset it to zero.
@@ -1124,7 +1267,7 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelDecl *L) {
// Make sure that there is a block for the indirect goto.
- if (IndirectBranch == 0)
+ if (!IndirectBranch)
GetIndirectGotoBlock();
llvm::BasicBlock *BB = getJumpDestForLabel(L).getBlock();
@@ -1158,7 +1301,7 @@ llvm::Value *CodeGenFunction::emitArrayLength(const 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;
+ llvm::Value *numVLAElements = nullptr;
if (isa<VariableArrayType>(arrayType)) {
numVLAElements = getVLASize(cast<VariableArrayType>(arrayType)).first;
@@ -1251,7 +1394,7 @@ CodeGenFunction::getVLASize(QualType type) {
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 = nullptr;
QualType elementType;
do {
@@ -1264,7 +1407,7 @@ CodeGenFunction::getVLASize(const VariableArrayType *type) {
numElements = vlaSize;
} else {
// It's undefined behavior if this wraps around, so mark it that way.
- // FIXME: Teach -fcatch-undefined-behavior to trap this.
+ // FIXME: Teach -fsanitize=undefined to trap this.
numElements = Builder.CreateNUWMul(numElements, vlaSize);
}
} while ((type = getContext().getAsVariableArrayType(elementType)));
@@ -1308,6 +1451,10 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
case Type::ObjCObjectPointer:
llvm_unreachable("type class is never variably-modified!");
+ case Type::Adjusted:
+ type = cast<AdjustedType>(ty)->getAdjustedType();
+ break;
+
case Type::Decayed:
type = cast<DecayedType>(ty)->getPointeeType();
break;
@@ -1354,6 +1501,7 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
// greater than zero.
if (SanOpts->VLABound &&
size->getType()->isSignedIntegerType()) {
+ SanitizerScope SanScope(this);
llvm::Value *Zero = llvm::Constant::getNullValue(Size->getType());
llvm::Constant *StaticArgs[] = {
EmitCheckSourceLocation(size->getLocStart()),
@@ -1375,7 +1523,7 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
case Type::FunctionProto:
case Type::FunctionNoProto:
- type = cast<FunctionType>(ty)->getResultType();
+ type = cast<FunctionType>(ty)->getReturnType();
break;
case Type::Paren:
@@ -1464,12 +1612,10 @@ void CodeGenFunction::EmitVarAnnotations(const VarDecl *D, llvm::Value *V) {
assert(D->hasAttr<AnnotateAttr>() && "no annotate attribute");
// FIXME We create a new bitcast for every annotation because that's what
// llvm-gcc was doing.
- for (specific_attr_iterator<AnnotateAttr>
- ai = D->specific_attr_begin<AnnotateAttr>(),
- ae = D->specific_attr_end<AnnotateAttr>(); ai != ae; ++ai)
+ for (const auto *I : D->specific_attrs<AnnotateAttr>())
EmitAnnotationCall(CGM.getIntrinsic(llvm::Intrinsic::var_annotation),
Builder.CreateBitCast(V, CGM.Int8PtrTy, V->getName()),
- (*ai)->getAnnotation(), D->getLocation());
+ I->getAnnotation(), D->getLocation());
}
llvm::Value *CodeGenFunction::EmitFieldAnnotations(const FieldDecl *D,
@@ -1479,15 +1625,13 @@ llvm::Value *CodeGenFunction::EmitFieldAnnotations(const FieldDecl *D,
llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::ptr_annotation,
CGM.Int8PtrTy);
- for (specific_attr_iterator<AnnotateAttr>
- ai = D->specific_attr_begin<AnnotateAttr>(),
- ae = D->specific_attr_end<AnnotateAttr>(); ai != ae; ++ai) {
+ for (const auto *I : D->specific_attrs<AnnotateAttr>()) {
// FIXME Always emit the cast inst so we can differentiate between
// annotation on the first field of a struct and annotation on the struct
// itself.
if (VTy != CGM.Int8PtrTy)
V = Builder.Insert(new llvm::BitCastInst(V, CGM.Int8PtrTy));
- V = EmitAnnotationCall(F, V, (*ai)->getAnnotation(), D->getLocation());
+ V = EmitAnnotationCall(F, V, I->getAnnotation(), D->getLocation());
V = Builder.CreateBitCast(V, VTy);
}
@@ -1495,3 +1639,45 @@ llvm::Value *CodeGenFunction::EmitFieldAnnotations(const FieldDecl *D,
}
CodeGenFunction::CGCapturedStmtInfo::~CGCapturedStmtInfo() { }
+
+CodeGenFunction::SanitizerScope::SanitizerScope(CodeGenFunction *CGF)
+ : CGF(CGF) {
+ assert(!CGF->IsSanitizerScope);
+ CGF->IsSanitizerScope = true;
+}
+
+CodeGenFunction::SanitizerScope::~SanitizerScope() {
+ CGF->IsSanitizerScope = false;
+}
+
+void CodeGenFunction::InsertHelper(llvm::Instruction *I,
+ const llvm::Twine &Name,
+ llvm::BasicBlock *BB,
+ llvm::BasicBlock::iterator InsertPt) const {
+ LoopStack.InsertHelper(I);
+ if (IsSanitizerScope) {
+ I->setMetadata(
+ CGM.getModule().getMDKindID("nosanitize"),
+ llvm::MDNode::get(CGM.getLLVMContext(), ArrayRef<llvm::Value *>()));
+ }
+}
+
+template <bool PreserveNames>
+void CGBuilderInserter<PreserveNames>::InsertHelper(
+ llvm::Instruction *I, const llvm::Twine &Name, llvm::BasicBlock *BB,
+ llvm::BasicBlock::iterator InsertPt) const {
+ llvm::IRBuilderDefaultInserter<PreserveNames>::InsertHelper(I, Name, BB,
+ InsertPt);
+ if (CGF)
+ CGF->InsertHelper(I, Name, BB, InsertPt);
+}
+
+#ifdef NDEBUG
+#define PreserveNames false
+#else
+#define PreserveNames true
+#endif
+template void CGBuilderInserter<PreserveNames>::InsertHelper(
+ llvm::Instruction *I, const llvm::Twine &Name, llvm::BasicBlock *BB,
+ llvm::BasicBlock::iterator InsertPt) const;
+#undef PreserveNames
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index db291e3b1ddd..59cc30da42c5 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -16,9 +16,11 @@
#include "CGBuilder.h"
#include "CGDebugInfo.h"
+#include "CGLoopInfo.h"
#include "CGValue.h"
-#include "EHScopeStack.h"
#include "CodeGenModule.h"
+#include "CodeGenPGO.h"
+#include "EHScopeStack.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
@@ -30,55 +32,55 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Debug.h"
-#include "llvm/Support/ValueHandle.h"
namespace llvm {
- class BasicBlock;
- class LLVMContext;
- class MDNode;
- class Module;
- class SwitchInst;
- class Twine;
- class Value;
- class CallSite;
+class BasicBlock;
+class LLVMContext;
+class MDNode;
+class Module;
+class SwitchInst;
+class Twine;
+class Value;
+class CallSite;
}
namespace clang {
- class ASTContext;
- class BlockDecl;
- class CXXDestructorDecl;
- class CXXForRangeStmt;
- class CXXTryStmt;
- class Decl;
- class LabelDecl;
- class EnumConstantDecl;
- class FunctionDecl;
- class FunctionProtoType;
- class LabelStmt;
- class ObjCContainerDecl;
- class ObjCInterfaceDecl;
- class ObjCIvarDecl;
- class ObjCMethodDecl;
- class ObjCImplementationDecl;
- class ObjCPropertyImplDecl;
- class TargetInfo;
- class TargetCodeGenInfo;
- class VarDecl;
- class ObjCForCollectionStmt;
- class ObjCAtTryStmt;
- class ObjCAtThrowStmt;
- class ObjCAtSynchronizedStmt;
- class ObjCAutoreleasePoolStmt;
+class ASTContext;
+class BlockDecl;
+class CXXDestructorDecl;
+class CXXForRangeStmt;
+class CXXTryStmt;
+class Decl;
+class LabelDecl;
+class EnumConstantDecl;
+class FunctionDecl;
+class FunctionProtoType;
+class LabelStmt;
+class ObjCContainerDecl;
+class ObjCInterfaceDecl;
+class ObjCIvarDecl;
+class ObjCMethodDecl;
+class ObjCImplementationDecl;
+class ObjCPropertyImplDecl;
+class TargetInfo;
+class TargetCodeGenInfo;
+class VarDecl;
+class ObjCForCollectionStmt;
+class ObjCAtTryStmt;
+class ObjCAtThrowStmt;
+class ObjCAtSynchronizedStmt;
+class ObjCAutoreleasePoolStmt;
namespace CodeGen {
- class CodeGenTypes;
- class CGFunctionInfo;
- class CGRecordLayout;
- class CGBlockInfo;
- class CGCXXABI;
- class BlockFlags;
- class BlockFieldFlags;
+class CodeGenTypes;
+class CGFunctionInfo;
+class CGRecordLayout;
+class CGBlockInfo;
+class CGCXXABI;
+class BlockFlags;
+class BlockFieldFlags;
/// The kind of evaluation to perform on values of a particular
/// type. Basically, is the code in CGExprScalar, CGExprComplex, or
@@ -91,6 +93,19 @@ enum TypeEvaluationKind {
TEK_Aggregate
};
+class SuppressDebugLocation {
+ llvm::DebugLoc CurLoc;
+ llvm::IRBuilderBase &Builder;
+public:
+ SuppressDebugLocation(llvm::IRBuilderBase &Builder)
+ : CurLoc(Builder.getCurrentDebugLocation()), Builder(Builder) {
+ Builder.SetCurrentDebugLocation(llvm::DebugLoc());
+ }
+ ~SuppressDebugLocation() {
+ Builder.SetCurrentDebugLocation(CurLoc);
+ }
+};
+
/// CodeGenFunction - This class organizes the per-function state that is used
/// while generating LLVM code.
class CodeGenFunction : public CodeGenTypeCache {
@@ -102,13 +117,13 @@ public:
/// A jump destination is an abstract label, branching to which may
/// require a jump out through normal cleanups.
struct JumpDest {
- JumpDest() : Block(0), ScopeDepth(), Index(0) {}
+ JumpDest() : Block(nullptr), ScopeDepth(), Index(0) {}
JumpDest(llvm::BasicBlock *Block,
EHScopeStack::stable_iterator Depth,
unsigned Index)
: Block(Block), ScopeDepth(Depth), Index(Index) {}
- bool isValid() const { return Block != 0; }
+ bool isValid() const { return Block != nullptr; }
llvm::BasicBlock *getBlock() const { return Block; }
EHScopeStack::stable_iterator getScopeDepth() const { return ScopeDepth; }
unsigned getDestIndex() const { return Index; }
@@ -128,8 +143,15 @@ public:
const TargetInfo &Target;
typedef std::pair<llvm::Value *, llvm::Value *> ComplexPairTy;
+ LoopInfoStack LoopStack;
CGBuilderTy Builder;
+ /// \brief CGBuilder insert helper. This function is called after an
+ /// instruction is created using Builder.
+ void InsertHelper(llvm::Instruction *I, const llvm::Twine &Name,
+ llvm::BasicBlock *BB,
+ llvm::BasicBlock::iterator InsertPt) const;
+
/// CurFuncDecl - Holds the Decl for the current outermost
/// non-closure context.
const Decl *CurFuncDecl;
@@ -162,7 +184,7 @@ public:
public:
explicit CGCapturedStmtInfo(const CapturedStmt &S,
CapturedRegionKind K = CR_Default)
- : Kind(K), ThisValue(0), CXXThisFieldDecl(0) {
+ : Kind(K), ThisValue(nullptr), CXXThisFieldDecl(nullptr) {
RecordDecl::field_iterator Field =
S.getCapturedRecordDecl()->field_begin();
@@ -189,11 +211,13 @@ public:
return CaptureFields.lookup(VD);
}
- bool isCXXThisExprCaptured() const { return CXXThisFieldDecl != 0; }
+ bool isCXXThisExprCaptured() const { return CXXThisFieldDecl != nullptr; }
FieldDecl *getThisFieldDecl() const { return CXXThisFieldDecl; }
/// \brief Emit the captured statement body.
virtual void EmitBody(CodeGenFunction &CGF, Stmt *S) {
+ RegionCounter Cnt = CGF.getPGORegionCounter(S);
+ Cnt.beginRegion(CGF.Builder);
CGF.EmitStmt(S);
}
@@ -220,13 +244,20 @@ public:
/// potentially higher performance penalties.
unsigned char BoundsChecking;
- /// \brief Whether any type-checking sanitizers are enabled. If \c false,
- /// calls to EmitTypeCheck can be skipped.
- bool SanitizePerformTypeCheck;
-
/// \brief Sanitizer options to use for this function.
const SanitizerOptions *SanOpts;
+ /// \brief True if CodeGen currently emits code implementing sanitizer checks.
+ bool IsSanitizerScope;
+
+ /// \brief RAII object to set/unset CodeGenFunction::IsSanitizerScope.
+ class SanitizerScope {
+ CodeGenFunction *CGF;
+ public:
+ SanitizerScope(CodeGenFunction *CGF);
+ ~SanitizerScope();
+ };
+
/// In ARC, whether we should autorelease the return value.
bool AutoreleaseResult;
@@ -608,9 +639,9 @@ public:
}
void end(CodeGenFunction &CGF) {
- assert(CGF.OutermostConditional != 0);
+ assert(CGF.OutermostConditional != nullptr);
if (CGF.OutermostConditional == this)
- CGF.OutermostConditional = 0;
+ CGF.OutermostConditional = nullptr;
}
/// Returns a block which will be executed prior to each
@@ -622,7 +653,7 @@ public:
/// isInConditionalBranch - Return true if we're currently emitting
/// one branch or the other of a conditional expression.
- bool isInConditionalBranch() const { return OutermostConditional != 0; }
+ bool isInConditionalBranch() const { return OutermostConditional != nullptr; }
void setBeforeOutermostConditional(llvm::Value *value, llvm::Value *addr) {
assert(isInConditionalBranch());
@@ -643,7 +674,7 @@ public:
public:
StmtExprEvaluation(CodeGenFunction &CGF)
: CGF(CGF), SavedOutermostConditional(CGF.OutermostConditional) {
- CGF.OutermostConditional = 0;
+ CGF.OutermostConditional = nullptr;
}
~StmtExprEvaluation() {
@@ -660,7 +691,7 @@ public:
friend class CodeGenFunction;
public:
- PeepholeProtection() : Inst(0) {}
+ PeepholeProtection() : Inst(nullptr) {}
};
/// A non-RAII class containing all the information about a bound
@@ -678,7 +709,7 @@ public:
bool boundLValue)
: OpaqueValue(ov), BoundLValue(boundLValue) {}
public:
- OpaqueValueMappingData() : OpaqueValue(0) {}
+ OpaqueValueMappingData() : OpaqueValue(nullptr) {}
static bool shouldBindAsLValue(const Expr *expr) {
// gl-values should be bound as l-values for obvious reasons.
@@ -687,8 +718,8 @@ public:
// act exactly like l-values but are formally required to be
// r-values in C.
return expr->isGLValue() ||
- expr->getType()->isRecordType() ||
- expr->getType()->isFunctionType();
+ expr->getType()->isFunctionType() ||
+ hasAggregateEvaluationKind(expr->getType());
}
static OpaqueValueMappingData bind(CodeGenFunction &CGF,
@@ -723,8 +754,8 @@ public:
return data;
}
- bool isValid() const { return OpaqueValue != 0; }
- void clear() { OpaqueValue = 0; }
+ bool isValid() const { return OpaqueValue != nullptr; }
+ void clear() { OpaqueValue = nullptr; }
void unbind(CodeGenFunction &CGF) {
assert(OpaqueValue && "no data to unbind!");
@@ -827,9 +858,21 @@ private:
};
SmallVector<BreakContinue, 8> BreakContinueStack;
+ CodeGenPGO PGO;
+
+public:
+ /// Get a counter for instrumentation of the region associated with the given
+ /// statement.
+ RegionCounter getPGORegionCounter(const Stmt *S) {
+ return RegionCounter(PGO, S);
+ }
+private:
+
/// SwitchInsn - This is nearest current switch instruction. It is null if
/// current context is not in a switch.
llvm::SwitchInst *SwitchInsn;
+ /// The branch weights of SwitchInsn when doing instrumentation based PGO.
+ SmallVector<uint64_t, 16> *SwitchWeights;
/// CaseRangeBlock - This block holds if condition check for last case
/// statement range in current switch instruction.
@@ -955,7 +998,7 @@ public:
ASTContext &getContext() const { return CGM.getContext(); }
CGDebugInfo *getDebugInfo() {
if (DisableDebugInfo)
- return NULL;
+ return nullptr;
return DebugInfo;
}
void disableDebugInfo() { DisableDebugInfo = true; }
@@ -988,7 +1031,7 @@ public:
}
llvm::BasicBlock *getInvokeDest() {
- if (!EHStack.requiresLandingPad()) return 0;
+ if (!EHStack.requiresLandingPad()) return nullptr;
return getInvokeDestImpl();
}
@@ -1019,6 +1062,7 @@ public:
void pushLifetimeExtendedDestroy(CleanupKind kind, llvm::Value *addr,
QualType type, Destroyer *destroyer,
bool useEHCleanupForArray);
+ void pushStackRestore(CleanupKind kind, llvm::Value *SPMem);
void emitDestroy(llvm::Value *addr, QualType type, Destroyer *destroyer,
bool useEHCleanupForArray);
llvm::Function *generateDestroyHelper(llvm::Constant *addr, QualType type,
@@ -1126,17 +1170,22 @@ public:
void GenerateCode(GlobalDecl GD, llvm::Function *Fn,
const CGFunctionInfo &FnInfo);
+ /// \brief Emit code for the start of a function.
+ /// \param Loc The location to be associated with the function.
+ /// \param StartLoc The location of the function body.
void StartFunction(GlobalDecl GD,
QualType RetTy,
llvm::Function *Fn,
const CGFunctionInfo &FnInfo,
const FunctionArgList &Args,
- SourceLocation StartLoc);
+ SourceLocation Loc = SourceLocation(),
+ SourceLocation StartLoc = SourceLocation());
void EmitConstructorBody(FunctionArgList &Args);
void EmitDestructorBody(FunctionArgList &Args);
void emitImplicitAssignmentOperatorBody(FunctionArgList &Args);
void EmitFunctionBody(FunctionArgList &Args, const Stmt *Body);
+ void EmitBlockWithFallThrough(llvm::BasicBlock *BB, RegionCounter &Cnt);
void EmitForwardingCallToLambda(const CXXMethodDecl *LambdaCallOperator,
CallArgList &CallArgs);
@@ -1270,8 +1319,8 @@ public:
/// createBasicBlock - Create an LLVM basic block.
llvm::BasicBlock *createBasicBlock(const Twine &name = "",
- llvm::Function *parent = 0,
- llvm::BasicBlock *before = 0) {
+ llvm::Function *parent = nullptr,
+ llvm::BasicBlock *before = nullptr) {
#ifdef NDEBUG
return llvm::BasicBlock::Create(getLLVMContext(), "", parent, before);
#else
@@ -1315,7 +1364,7 @@ public:
/// HaveInsertPoint - True if an insertion point is defined. If not, this
/// indicates that the current code being emitted is unreachable.
bool HaveInsertPoint() const {
- return Builder.GetInsertBlock() != 0;
+ return Builder.GetInsertBlock() != nullptr;
}
/// EnsureInsertPoint - Ensure that an insertion point is defined so that
@@ -1380,6 +1429,10 @@ public:
AggValueSlot::IsNotAliased);
}
+ /// CreateInAllocaTmp - Create a temporary memory object for the given
+ /// aggregate type.
+ AggValueSlot CreateInAllocaTmp(QualType T, const Twine &Name = "inalloca");
+
/// Emit a cast to void* in the appropriate address space.
llvm::Value *EmitCastToVoidPtr(llvm::Value *value);
@@ -1614,7 +1667,8 @@ public:
llvm::Value *This);
void EmitNewArrayInitializer(const CXXNewExpr *E, QualType elementType,
- llvm::Value *NewPtr, llvm::Value *NumElements);
+ llvm::Value *NewPtr, llvm::Value *NumElements,
+ llvm::Value *AllocSizeWithoutCookie);
void EmitCXXTemporary(const CXXTemporary *Temporary, QualType TempType,
llvm::Value *Ptr);
@@ -1625,6 +1679,9 @@ public:
void EmitDeleteCall(const FunctionDecl *DeleteFD, llvm::Value *Ptr,
QualType DeleteTy);
+ RValue EmitBuiltinNewDeleteCall(const FunctionProtoType *Type,
+ const Expr *Arg, bool IsDelete);
+
llvm::Value* EmitCXXTypeidExpr(const CXXTypeidExpr *E);
llvm::Value *EmitDynamicCast(llvm::Value *V, const CXXDynamicCastExpr *DCE);
llvm::Value* EmitCXXUuidofExpr(const CXXUuidofExpr *E);
@@ -1656,6 +1713,10 @@ public:
TCK_DowncastReference
};
+ /// \brief Whether any type-checking sanitizers are enabled. If \c false,
+ /// calls to EmitTypeCheck can be skipped.
+ bool sanitizePerformTypeCheck() const;
+
/// \brief Emit a check that \p V is the address of storage of the
/// appropriate size and alignment for an object of type \p Type.
void EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, llvm::Value *V,
@@ -1722,19 +1783,21 @@ public:
llvm::Value *SizeForLifetimeMarkers;
struct Invalid {};
- AutoVarEmission(Invalid) : Variable(0) {}
+ AutoVarEmission(Invalid) : Variable(nullptr) {}
AutoVarEmission(const VarDecl &variable)
- : Variable(&variable), Address(0), NRVOFlag(0),
+ : Variable(&variable), Address(nullptr), NRVOFlag(nullptr),
IsByRef(false), IsConstantAggregate(false),
- SizeForLifetimeMarkers(0) {}
+ SizeForLifetimeMarkers(nullptr) {}
- bool wasEmittedAsGlobal() const { return Address == 0; }
+ bool wasEmittedAsGlobal() const { return Address == nullptr; }
public:
static AutoVarEmission invalid() { return AutoVarEmission(Invalid()); }
- bool useLifetimeMarkers() const { return SizeForLifetimeMarkers != 0; }
+ bool useLifetimeMarkers() const {
+ return SizeForLifetimeMarkers != nullptr;
+ }
llvm::Value *getSizeForLifetimeMarkers() const {
assert(useLifetimeMarkers());
return SizeForLifetimeMarkers;
@@ -1767,7 +1830,8 @@ public:
llvm::GlobalValue::LinkageTypes Linkage);
/// EmitParmDecl - Emit a ParmVarDecl or an ImplicitParamDecl.
- void EmitParmDecl(const VarDecl &D, llvm::Value *Arg, unsigned ArgNo);
+ void EmitParmDecl(const VarDecl &D, llvm::Value *Arg, bool ArgIsPointer,
+ unsigned ArgNo);
/// protectFromPeepholes - Protect a value that we're intending to
/// store to the side, but which will probably be used later, from
@@ -1820,9 +1884,14 @@ public:
void EmitGotoStmt(const GotoStmt &S);
void EmitIndirectGotoStmt(const IndirectGotoStmt &S);
void EmitIfStmt(const IfStmt &S);
- void EmitWhileStmt(const WhileStmt &S);
- void EmitDoStmt(const DoStmt &S);
- void EmitForStmt(const ForStmt &S);
+
+ void EmitCondBrHints(llvm::LLVMContext &Context, llvm::BranchInst *CondBr,
+ const ArrayRef<const Attr *> &Attrs);
+ void EmitWhileStmt(const WhileStmt &S,
+ const ArrayRef<const Attr *> &Attrs = None);
+ void EmitDoStmt(const DoStmt &S, const ArrayRef<const Attr *> &Attrs = None);
+ void EmitForStmt(const ForStmt &S,
+ const ArrayRef<const Attr *> &Attrs = None);
void EmitReturnStmt(const ReturnStmt &S);
void EmitDeclStmt(const DeclStmt &S);
void EmitBreakStmt(const BreakStmt &S);
@@ -1839,19 +1908,34 @@ public:
void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S);
void EmitObjCAutoreleasePoolStmt(const ObjCAutoreleasePoolStmt &S);
- llvm::Constant *getUnwindResumeFn();
- llvm::Constant *getUnwindResumeOrRethrowFn();
void EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
void ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
void EmitCXXTryStmt(const CXXTryStmt &S);
void EmitSEHTryStmt(const SEHTryStmt &S);
- void EmitCXXForRangeStmt(const CXXForRangeStmt &S);
+ void EmitSEHLeaveStmt(const SEHLeaveStmt &S);
+ void EmitCXXForRangeStmt(const CXXForRangeStmt &S,
+ const ArrayRef<const Attr *> &Attrs = None);
llvm::Function *EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K);
- llvm::Function *GenerateCapturedStmtFunction(const CapturedDecl *CD,
- const RecordDecl *RD,
- SourceLocation Loc);
+ llvm::Function *GenerateCapturedStmtFunction(const CapturedStmt &S);
+ llvm::Value *GenerateCapturedStmtArgument(const CapturedStmt &S);
+
+ void EmitOMPParallelDirective(const OMPParallelDirective &S);
+ void EmitOMPSimdDirective(const OMPSimdDirective &S);
+ void EmitOMPForDirective(const OMPForDirective &S);
+ void EmitOMPSectionsDirective(const OMPSectionsDirective &S);
+ void EmitOMPSectionDirective(const OMPSectionDirective &S);
+ void EmitOMPSingleDirective(const OMPSingleDirective &S);
+ void EmitOMPMasterDirective(const OMPMasterDirective &S);
+ void EmitOMPCriticalDirective(const OMPCriticalDirective &S);
+ void EmitOMPParallelForDirective(const OMPParallelForDirective &S);
+ void EmitOMPParallelSectionsDirective(const OMPParallelSectionsDirective &S);
+ void EmitOMPTaskDirective(const OMPTaskDirective &S);
+ void EmitOMPTaskyieldDirective(const OMPTaskyieldDirective &S);
+ void EmitOMPBarrierDirective(const OMPBarrierDirective &S);
+ void EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S);
+ void EmitOMPFlushDirective(const OMPFlushDirective &S);
//===--------------------------------------------------------------------===//
// LValue Expression Emission
@@ -1918,7 +2002,7 @@ public:
llvm::Value *EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
unsigned Alignment, QualType Ty,
SourceLocation Loc,
- llvm::MDNode *TBAAInfo = 0,
+ llvm::MDNode *TBAAInfo = nullptr,
QualType TBAABaseTy = QualType(),
uint64_t TBAAOffset = 0);
@@ -1933,7 +2017,7 @@ public:
/// the LLVM value representation.
void EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
bool Volatile, unsigned Alignment, QualType Ty,
- llvm::MDNode *TBAAInfo = 0, bool isInit = false,
+ llvm::MDNode *TBAAInfo = nullptr, bool isInit = false,
QualType TBAABaseTy = QualType(),
uint64_t TBAAOffset = 0);
@@ -1950,12 +2034,14 @@ public:
RValue EmitLoadOfLValue(LValue V, SourceLocation Loc);
RValue EmitLoadOfExtVectorElementLValue(LValue V);
RValue EmitLoadOfBitfieldLValue(LValue LV);
+ RValue EmitLoadOfGlobalRegLValue(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 EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit=false);
void EmitStoreThroughExtVectorComponentLValue(RValue Src, LValue Dst);
+ void EmitStoreThroughGlobalRegLValue(RValue Src, LValue Dst);
/// EmitStoreThroughBitfieldLValue - Store Src into Dst with same constraints
/// as EmitStoreThroughLValue.
@@ -1964,7 +2050,7 @@ public:
/// 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,
- llvm::Value **Result=0);
+ llvm::Value **Result=nullptr);
/// Emit an l-value for an assignment (simple or compound) of complex type.
LValue EmitComplexAssignmentLValue(const BinaryOperator *E);
@@ -1980,6 +2066,7 @@ public:
// Note: only available for agg return types
LValue EmitVAArgExprLValue(const VAArgExpr *E);
LValue EmitDeclRefLValue(const DeclRefExpr *E);
+ LValue EmitReadRegister(const VarDecl *VD);
LValue EmitStringLiteralLValue(const StringLiteral *E);
LValue EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E);
LValue EmitPredefinedLValue(const PredefinedExpr *E);
@@ -2011,7 +2098,9 @@ public:
return ConstantEmission(C, false);
}
- LLVM_EXPLICIT operator bool() const { return ValueAndIsReference.getOpaqueValue() != 0; }
+ LLVM_EXPLICIT operator bool() const {
+ return ValueAndIsReference.getOpaqueValue() != nullptr;
+ }
bool isReference() const { return ValueAndIsReference.getInt(); }
LValue getReferenceLValue(CodeGenFunction &CGF, Expr *refExpr) const {
@@ -2074,15 +2163,15 @@ public:
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
const CallArgList &Args,
- const Decl *TargetDecl = 0,
- llvm::Instruction **callOrInvoke = 0);
+ const Decl *TargetDecl = nullptr,
+ llvm::Instruction **callOrInvoke = nullptr);
RValue EmitCall(QualType FnType, llvm::Value *Callee,
SourceLocation CallLoc,
ReturnValueSlot ReturnValue,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd,
- const Decl *TargetDecl = 0);
+ const Decl *TargetDecl = nullptr);
RValue EmitCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue = ReturnValueSlot());
@@ -2156,9 +2245,19 @@ public:
const llvm::CmpInst::Predicate Fp,
const llvm::CmpInst::Predicate Ip,
const llvm::Twine &Name = "");
- llvm::Value *EmitAArch64CompareBuiltinExpr(llvm::Value *Op, llvm::Type *Ty);
- llvm::Value *EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
+
+ llvm::Value *EmitCommonNeonBuiltinExpr(unsigned BuiltinID,
+ unsigned LLVMIntrinsic,
+ unsigned AltLLVMIntrinsic,
+ const char *NameHint,
+ unsigned Modifier,
+ const CallExpr *E,
+ SmallVectorImpl<llvm::Value *> &Ops,
+ llvm::Value *Align = nullptr);
+ llvm::Function *LookupNeonLLVMIntrinsic(unsigned IntrinsicID,
+ unsigned Modifier, llvm::Type *ArgTy,
+ const CallExpr *E);
llvm::Value *EmitNeonCall(llvm::Function *F,
SmallVectorImpl<llvm::Value*> &O,
const char *name,
@@ -2168,10 +2267,22 @@ public:
bool negateForRightShift);
llvm::Value *EmitNeonRShiftImm(llvm::Value *Vec, llvm::Value *Amt,
llvm::Type *Ty, bool usgn, const char *name);
+ // Helper functions for EmitAArch64BuiltinExpr.
+ llvm::Value *vectorWrapScalar8(llvm::Value *Op);
+ llvm::Value *vectorWrapScalar16(llvm::Value *Op);
+ llvm::Value *emitVectorWrappedScalar8Intrinsic(
+ unsigned Int, SmallVectorImpl<llvm::Value *> &Ops, const char *Name);
+ llvm::Value *emitVectorWrappedScalar16Intrinsic(
+ unsigned Int, SmallVectorImpl<llvm::Value *> &Ops, const char *Name);
+ llvm::Value *EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
+ llvm::Value *EmitNeon64Call(llvm::Function *F,
+ llvm::SmallVectorImpl<llvm::Value *> &O,
+ const char *name);
llvm::Value *BuildVector(ArrayRef<llvm::Value*> Ops);
llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
+ llvm::Value *EmitR600BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitObjCProtocolExpr(const ObjCProtocolExpr *E);
llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E);
@@ -2231,7 +2342,7 @@ public:
llvm::Value *EmitARCRetainScalarExpr(const Expr *expr);
llvm::Value *EmitARCRetainAutoreleaseScalarExpr(const Expr *expr);
- void EmitARCIntrinsicUse(llvm::ArrayRef<llvm::Value*> values);
+ void EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values);
static Destroyer destroyARCStrongImprecise;
static Destroyer destroyARCStrongPrecise;
@@ -2304,9 +2415,9 @@ public:
/// CreateStaticVarDecl - Create a zero-initialized LLVM global for
/// a static local variable.
- llvm::GlobalVariable *CreateStaticVarDecl(const VarDecl &D,
- const char *Separator,
- llvm::GlobalValue::LinkageTypes Linkage);
+ llvm::Constant *CreateStaticVarDecl(const VarDecl &D,
+ const char *Separator,
+ llvm::GlobalValue::LinkageTypes Linkage);
/// AddInitializerToStaticVarDecl - Add the initializer for 'D' to the
/// global variable that has already been created for it. If the initializer
@@ -2339,7 +2450,7 @@ public:
/// variables.
void GenerateCXXGlobalInitFunc(llvm::Function *Fn,
ArrayRef<llvm::Constant *> Decls,
- llvm::GlobalVariable *Guard = 0);
+ llvm::GlobalVariable *Guard = nullptr);
/// GenerateCXXGlobalDtorsFunc - Generates code for destroying global
/// variables.
@@ -2367,7 +2478,7 @@ public:
void EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Dest);
- RValue EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest = 0);
+ RValue EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest = nullptr);
//===--------------------------------------------------------------------===//
// Annotations Emission
@@ -2413,8 +2524,10 @@ public:
/// EmitBranchOnBoolExpr - Emit a branch on a boolean condition (e.g. for an
/// if statement) to the specified blocks. Based on the condition, this might
/// try to simplify the codegen of the conditional based on the branch.
+ /// TrueCount should be the number of times we expect the condition to
+ /// evaluate to true based on PGO data.
void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock,
- llvm::BasicBlock *FalseBlock);
+ llvm::BasicBlock *FalseBlock, uint64_t TrueCount);
/// \brief Emit a description of a type in a format suitable for passing to
/// a runtime sanitizer handler.
@@ -2467,6 +2580,11 @@ private:
llvm::MDNode *getRangeForLoadFromType(QualType Ty);
void EmitReturnOfRValue(RValue RV, QualType Ty);
+ void deferPlaceholderReplacement(llvm::Instruction *Old, llvm::Value *New);
+
+ llvm::SmallVector<std::pair<llvm::Instruction *, llvm::Value *>, 4>
+ DeferredReplacements;
+
/// ExpandTypeFromArgs - Reconstruct a structure of type \arg Ty
/// from function arguments into \arg Dst. See ABIArgInfo::Expand.
///
@@ -2492,69 +2610,82 @@ private:
std::string &ConstraintStr,
SourceLocation Loc);
+public:
/// EmitCallArgs - Emit call arguments for a function.
- /// The CallArgTypeInfo parameter is used for iterating over the known
- /// argument types of the function being called.
- template<typename T>
- void EmitCallArgs(CallArgList& Args, const T* CallArgTypeInfo,
+ template <typename T>
+ void EmitCallArgs(CallArgList &Args, const T *CallArgTypeInfo,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd,
bool ForceColumnInfo = false) {
- CGDebugInfo *DI = getDebugInfo();
- SourceLocation CallLoc;
- if (DI) CallLoc = DI->getLocation();
+ if (CallArgTypeInfo) {
+ EmitCallArgs(Args, CallArgTypeInfo->isVariadic(),
+ CallArgTypeInfo->param_type_begin(),
+ CallArgTypeInfo->param_type_end(), ArgBeg, ArgEnd,
+ ForceColumnInfo);
+ } else {
+ // T::param_type_iterator might not have a default ctor.
+ const QualType *NoIter = nullptr;
+ EmitCallArgs(Args, /*AllowExtraArguments=*/true, NoIter, NoIter, ArgBeg,
+ ArgEnd, ForceColumnInfo);
+ }
+ }
+ template<typename ArgTypeIterator>
+ void EmitCallArgs(CallArgList& Args,
+ bool AllowExtraArguments,
+ ArgTypeIterator ArgTypeBeg,
+ ArgTypeIterator ArgTypeEnd,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd,
+ bool ForceColumnInfo = false) {
+ SmallVector<QualType, 16> ArgTypes;
CallExpr::const_arg_iterator Arg = ArgBeg;
// First, use the argument types that the type info knows about
- if (CallArgTypeInfo) {
- for (typename T::arg_type_iterator I = CallArgTypeInfo->arg_type_begin(),
- E = CallArgTypeInfo->arg_type_end(); I != E; ++I, ++Arg) {
- assert(Arg != ArgEnd && "Running over edge of argument list!");
- QualType ArgType = *I;
+ for (ArgTypeIterator I = ArgTypeBeg, E = ArgTypeEnd; I != E; ++I, ++Arg) {
+ assert(Arg != ArgEnd && "Running over edge of argument list!");
#ifndef NDEBUG
- QualType ActualArgType = Arg->getType();
- if (ArgType->isPointerType() && ActualArgType->isPointerType()) {
- QualType ActualBaseType =
+ QualType ArgType = *I;
+ QualType ActualArgType = Arg->getType();
+ if (ArgType->isPointerType() && ActualArgType->isPointerType()) {
+ QualType ActualBaseType =
ActualArgType->getAs<PointerType>()->getPointeeType();
- QualType ArgBaseType =
+ QualType ArgBaseType =
ArgType->getAs<PointerType>()->getPointeeType();
- if (ArgBaseType->isVariableArrayType()) {
- if (const VariableArrayType *VAT =
- getContext().getAsVariableArrayType(ActualBaseType)) {
- if (!VAT->getSizeExpr())
- ActualArgType = ArgType;
- }
+ if (ArgBaseType->isVariableArrayType()) {
+ if (const VariableArrayType *VAT =
+ getContext().getAsVariableArrayType(ActualBaseType)) {
+ if (!VAT->getSizeExpr())
+ ActualArgType = ArgType;
}
}
- assert(getContext().getCanonicalType(ArgType.getNonReferenceType()).
- getTypePtr() ==
- getContext().getCanonicalType(ActualArgType).getTypePtr() &&
- "type mismatch in call argument!");
-#endif
- EmitCallArg(Args, *Arg, ArgType);
-
- // Each argument expression could modify the debug
- // location. Restore it.
- if (DI) DI->EmitLocation(Builder, CallLoc, ForceColumnInfo);
}
-
- // Either we've emitted all the call args, or we have a call to a
- // variadic function.
- assert((Arg == ArgEnd || CallArgTypeInfo->isVariadic()) &&
- "Extra arguments in non-variadic function!");
-
+ assert(getContext().getCanonicalType(ArgType.getNonReferenceType()).
+ getTypePtr() ==
+ getContext().getCanonicalType(ActualArgType).getTypePtr() &&
+ "type mismatch in call argument!");
+#endif
+ ArgTypes.push_back(*I);
}
+ // Either we've emitted all the call args, or we have a call to variadic
+ // function or some other call that allows extra arguments.
+ assert((Arg == ArgEnd || AllowExtraArguments) &&
+ "Extra arguments in non-variadic function!");
+
// If we still have any arguments, emit them using the type of the argument.
- for (; Arg != ArgEnd; ++Arg) {
- EmitCallArg(Args, *Arg, Arg->getType());
+ for (; Arg != ArgEnd; ++Arg)
+ ArgTypes.push_back(Arg->getType());
- // Restore the debug location.
- if (DI) DI->EmitLocation(Builder, CallLoc, ForceColumnInfo);
- }
+ EmitCallArgs(Args, ArgTypes, ArgBeg, ArgEnd, ForceColumnInfo);
}
+ void EmitCallArgs(CallArgList &Args, ArrayRef<QualType> ArgTypes,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd,
+ bool ForceColumnInfo = false);
+
+private:
const TargetCodeGenInfo &getTargetHooks() const {
return CGM.getTargetCodeGenInfo();
}
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 792fbfce3349..48823befcc07 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -18,7 +18,9 @@
#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
#include "CGOpenCLRuntime.h"
+#include "CGOpenMPRuntime.h"
#include "CodeGenFunction.h"
+#include "CodeGenPGO.h"
#include "CodeGenTBAA.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
@@ -40,30 +42,31 @@
#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/IR/CallSite.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
-#include "llvm/Support/CallSite.h"
+#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Target/Mangler.h"
using namespace clang;
using namespace CodeGen;
static const char AnnotationSection[] = "llvm.metadata";
-static CGCXXABI &createCXXABI(CodeGenModule &CGM) {
+static CGCXXABI *createCXXABI(CodeGenModule &CGM) {
switch (CGM.getTarget().getCXXABI().getKind()) {
case TargetCXXABI::GenericAArch64:
case TargetCXXABI::GenericARM:
case TargetCXXABI::iOS:
+ case TargetCXXABI::iOS64:
case TargetCXXABI::GenericItanium:
- return *CreateItaniumCXXABI(CGM);
+ return CreateItaniumCXXABI(CGM);
case TargetCXXABI::Microsoft:
- return *CreateMicrosoftCXXABI(CGM);
+ return CreateMicrosoftCXXABI(CGM);
}
llvm_unreachable("invalid C++ ABI kind");
@@ -74,18 +77,18 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
DiagnosticsEngine &diags)
: Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TheModule(M),
Diags(diags), TheDataLayout(TD), Target(C.getTargetInfo()),
- ABI(createCXXABI(*this)), VMContext(M.getContext()), TBAA(0),
- TheTargetCodeGenInfo(0), Types(*this), VTables(*this), ObjCRuntime(0),
- OpenCLRuntime(0), CUDARuntime(0), DebugInfo(0), ARCData(0),
- NoObjCARCExceptionsMetadata(0), RRData(0), CFConstantStringClassRef(0),
- ConstantStringClassRef(0), NSConstantStringType(0),
- NSConcreteGlobalBlock(0), NSConcreteStackBlock(0), BlockObjectAssign(0),
- BlockObjectDispose(0), BlockDescriptorType(0), GenericBlockLiteralType(0),
- LifetimeStartFn(0), LifetimeEndFn(0),
- SanitizerBlacklist(
- llvm::SpecialCaseList::createOrDie(CGO.SanitizerBlacklistFile)),
- SanOpts(SanitizerBlacklist->isIn(M) ? SanitizerOptions::Disabled
- : LangOpts.Sanitize) {
+ ABI(createCXXABI(*this)), VMContext(M.getContext()), TBAA(nullptr),
+ TheTargetCodeGenInfo(nullptr), Types(*this), VTables(*this),
+ ObjCRuntime(nullptr), OpenCLRuntime(nullptr), OpenMPRuntime(nullptr),
+ CUDARuntime(nullptr), DebugInfo(nullptr), ARCData(nullptr),
+ NoObjCARCExceptionsMetadata(nullptr), RRData(nullptr), PGOReader(nullptr),
+ CFConstantStringClassRef(nullptr), ConstantStringClassRef(nullptr),
+ NSConstantStringType(nullptr), NSConcreteGlobalBlock(nullptr),
+ NSConcreteStackBlock(nullptr), BlockObjectAssign(nullptr),
+ BlockObjectDispose(nullptr), BlockDescriptorType(nullptr),
+ GenericBlockLiteralType(nullptr), LifetimeStartFn(nullptr),
+ LifetimeEndFn(nullptr), SanitizerBL(llvm::SpecialCaseList::createOrDie(
+ CGO.SanitizerBlacklistFile)) {
// Initialize the type cache.
llvm::LLVMContext &LLVMContext = M.getContext();
@@ -110,14 +113,16 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
createObjCRuntime();
if (LangOpts.OpenCL)
createOpenCLRuntime();
+ if (LangOpts.OpenMP)
+ createOpenMPRuntime();
if (LangOpts.CUDA)
createCUDARuntime();
// Enable TBAA unless it's suppressed. ThreadSanitizer needs TBAA even at O0.
- if (SanOpts.Thread ||
+ if (LangOpts.Sanitize.Thread ||
(!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0))
TBAA = new CodeGenTBAA(Context, VMContext, CodeGenOpts, getLangOpts(),
- ABI.getMangleContext());
+ getCXXABI().getMangleContext());
// If debug info or coverage generation is enabled, create the CGDebugInfo
// object.
@@ -131,14 +136,23 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
if (C.getLangOpts().ObjCAutoRefCount)
ARCData = new ARCEntrypoints();
RRData = new RREntrypoints();
+
+ if (!CodeGenOpts.InstrProfileInput.empty()) {
+ if (std::error_code EC = llvm::IndexedInstrProfReader::create(
+ CodeGenOpts.InstrProfileInput, PGOReader)) {
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "Could not read profile: %0");
+ getDiags().Report(DiagID) << EC.message();
+ }
+ }
}
CodeGenModule::~CodeGenModule() {
delete ObjCRuntime;
delete OpenCLRuntime;
+ delete OpenMPRuntime;
delete CUDARuntime;
delete TheTargetCodeGenInfo;
- delete &ABI;
delete TBAA;
delete DebugInfo;
delete ARCData;
@@ -168,6 +182,10 @@ void CodeGenModule::createOpenCLRuntime() {
OpenCLRuntime = new CGOpenCLRuntime(*this);
}
+void CodeGenModule::createOpenMPRuntime() {
+ OpenMPRuntime = new CGOpenMPRuntime(*this);
+}
+
void CodeGenModule::createCUDARuntime() {
CUDARuntime = CreateNVCUDARuntime(*this);
}
@@ -181,13 +199,17 @@ void CodeGenModule::applyReplacements() {
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (!Entry)
continue;
- llvm::Function *OldF = cast<llvm::Function>(Entry);
- llvm::Function *NewF = dyn_cast<llvm::Function>(Replacement);
+ auto *OldF = cast<llvm::Function>(Entry);
+ auto *NewF = dyn_cast<llvm::Function>(Replacement);
if (!NewF) {
- llvm::ConstantExpr *CE = cast<llvm::ConstantExpr>(Replacement);
- assert(CE->getOpcode() == llvm::Instruction::BitCast ||
- CE->getOpcode() == llvm::Instruction::GetElementPtr);
- NewF = dyn_cast<llvm::Function>(CE->getOperand(0));
+ if (auto *Alias = dyn_cast<llvm::GlobalAlias>(Replacement)) {
+ NewF = dyn_cast<llvm::Function>(Alias->getAliasee());
+ } else {
+ auto *CE = cast<llvm::ConstantExpr>(Replacement);
+ assert(CE->getOpcode() == llvm::Instruction::BitCast ||
+ CE->getOpcode() == llvm::Instruction::GetElementPtr);
+ NewF = dyn_cast<llvm::Function>(CE->getOperand(0));
+ }
}
// Replace old with new, but keep the old order.
@@ -200,23 +222,75 @@ void CodeGenModule::applyReplacements() {
}
}
+// This is only used in aliases that we created and we know they have a
+// linear structure.
+static const llvm::GlobalObject *getAliasedGlobal(const llvm::GlobalAlias &GA) {
+ llvm::SmallPtrSet<const llvm::GlobalAlias*, 4> Visited;
+ const llvm::Constant *C = &GA;
+ for (;;) {
+ C = C->stripPointerCasts();
+ if (auto *GO = dyn_cast<llvm::GlobalObject>(C))
+ return GO;
+ // stripPointerCasts will not walk over weak aliases.
+ auto *GA2 = dyn_cast<llvm::GlobalAlias>(C);
+ if (!GA2)
+ return nullptr;
+ if (!Visited.insert(GA2))
+ return nullptr;
+ C = GA2->getAliasee();
+ }
+}
+
void CodeGenModule::checkAliases() {
+ // Check if the constructed aliases are well formed. It is really unfortunate
+ // that we have to do this in CodeGen, but we only construct mangled names
+ // and aliases during codegen.
bool Error = false;
+ DiagnosticsEngine &Diags = getDiags();
for (std::vector<GlobalDecl>::iterator I = Aliases.begin(),
E = Aliases.end(); I != E; ++I) {
const GlobalDecl &GD = *I;
- const ValueDecl *D = cast<ValueDecl>(GD.getDecl());
+ const auto *D = cast<ValueDecl>(GD.getDecl());
const AliasAttr *AA = D->getAttr<AliasAttr>();
StringRef MangledName = getMangledName(GD);
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
- llvm::GlobalAlias *Alias = cast<llvm::GlobalAlias>(Entry);
- llvm::GlobalValue *GV = Alias->getAliasedGlobal();
- if (GV->isDeclaration()) {
+ auto *Alias = cast<llvm::GlobalAlias>(Entry);
+ const llvm::GlobalValue *GV = getAliasedGlobal(*Alias);
+ if (!GV) {
Error = true;
- getDiags().Report(AA->getLocation(), diag::err_alias_to_undefined);
- } else if (!Alias->resolveAliasedGlobal(/*stopOnWeak*/ false)) {
+ Diags.Report(AA->getLocation(), diag::err_cyclic_alias);
+ } else if (GV->isDeclaration()) {
Error = true;
- getDiags().Report(AA->getLocation(), diag::err_cyclic_alias);
+ Diags.Report(AA->getLocation(), diag::err_alias_to_undefined);
+ }
+
+ llvm::Constant *Aliasee = Alias->getAliasee();
+ llvm::GlobalValue *AliaseeGV;
+ if (auto CE = dyn_cast<llvm::ConstantExpr>(Aliasee))
+ AliaseeGV = cast<llvm::GlobalValue>(CE->getOperand(0));
+ else
+ AliaseeGV = cast<llvm::GlobalValue>(Aliasee);
+
+ if (const SectionAttr *SA = D->getAttr<SectionAttr>()) {
+ StringRef AliasSection = SA->getName();
+ if (AliasSection != AliaseeGV->getSection())
+ Diags.Report(SA->getLocation(), diag::warn_alias_with_section)
+ << AliasSection;
+ }
+
+ // We have to handle alias to weak aliases in here. LLVM itself disallows
+ // this since the object semantics would not match the IL one. For
+ // compatibility with gcc we implement it by just pointing the alias
+ // to its aliasee's aliasee. We also warn, since the user is probably
+ // expecting the link to be weak.
+ if (auto GA = dyn_cast<llvm::GlobalAlias>(AliaseeGV)) {
+ if (GA->mayBeOverridden()) {
+ Diags.Report(AA->getLocation(), diag::warn_alias_to_weak_alias)
+ << GV->getName() << GA->getName();
+ Aliasee = llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(
+ GA->getAliasee(), Alias->getType());
+ Alias->setAliasee(Aliasee);
+ }
}
}
if (!Error)
@@ -227,12 +301,29 @@ void CodeGenModule::checkAliases() {
const GlobalDecl &GD = *I;
StringRef MangledName = getMangledName(GD);
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
- llvm::GlobalAlias *Alias = cast<llvm::GlobalAlias>(Entry);
+ auto *Alias = cast<llvm::GlobalAlias>(Entry);
Alias->replaceAllUsesWith(llvm::UndefValue::get(Alias->getType()));
Alias->eraseFromParent();
}
}
+void CodeGenModule::clear() {
+ DeferredDeclsToEmit.clear();
+}
+
+void InstrProfStats::reportDiagnostics(DiagnosticsEngine &Diags,
+ StringRef MainFile) {
+ if (!hasDiagnostics())
+ return;
+ if (VisitedInMainFile > 0 && VisitedInMainFile == MissingInMainFile) {
+ if (MainFile.empty())
+ MainFile = "<stdin>";
+ Diags.Report(diag::warn_profile_data_unprofiled) << MainFile;
+ } else
+ Diags.Report(diag::warn_profile_data_out_of_date) << Visited << Missing
+ << Mismatched;
+}
+
void CodeGenModule::Release() {
EmitDeferred();
applyReplacements();
@@ -243,11 +334,16 @@ void CodeGenModule::Release() {
if (ObjCRuntime)
if (llvm::Function *ObjCInitFunction = ObjCRuntime->ModuleInitFunction())
AddGlobalCtor(ObjCInitFunction);
+ if (getCodeGenOpts().ProfileInstrGenerate)
+ if (llvm::Function *PGOInit = CodeGenPGO::emitInitialization(*this))
+ AddGlobalCtor(PGOInit, 0);
+ if (PGOReader && PGOStats.hasDiagnostics())
+ PGOStats.reportDiagnostics(getDiags(), getCodeGenOpts().MainFileName);
EmitCtorList(GlobalCtors, "llvm.global_ctors");
EmitCtorList(GlobalDtors, "llvm.global_dtors");
EmitGlobalAnnotations();
EmitStaticExternCAliases();
- EmitLLVMUsed();
+ emitLLVMUsed();
if (CodeGenOpts.Autolink &&
(Context.getLangOpts().Modules || !LinkerOptionsMetadata.empty())) {
@@ -259,14 +355,29 @@ void CodeGenModule::Release() {
getModule().addModuleFlag(llvm::Module::Warning, "Dwarf Version",
CodeGenOpts.DwarfVersion);
if (DebugInfo)
- // We support a single version in the linked module: error out when
- // modules do not have the same version. We are going to implement dropping
- // debug info when the version number is not up-to-date. Once that is
- // done, the bitcode linker is not going to see modules with different
- // version numbers.
- getModule().addModuleFlag(llvm::Module::Error, "Debug Info Version",
+ // We support a single version in the linked module. The LLVM
+ // parser will drop debug info with a different version number
+ // (and warn about it, too).
+ getModule().addModuleFlag(llvm::Module::Warning, "Debug Info Version",
llvm::DEBUG_METADATA_VERSION);
+ // We need to record the widths of enums and wchar_t, so that we can generate
+ // the correct build attributes in the ARM backend.
+ llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch();
+ if ( Arch == llvm::Triple::arm
+ || Arch == llvm::Triple::armeb
+ || Arch == llvm::Triple::thumb
+ || Arch == llvm::Triple::thumbeb) {
+ // Width of wchar_t in bytes
+ uint64_t WCharWidth =
+ Context.getTypeSizeInChars(Context.getWideCharType()).getQuantity();
+ getModule().addModuleFlag(llvm::Module::Error, "wchar_size", WCharWidth);
+
+ // The minimum width of an enum in bytes
+ uint64_t EnumWidth = Context.getLangOpts().ShortEnums ? 1 : 4;
+ getModule().addModuleFlag(llvm::Module::Error, "min_enum_size", EnumWidth);
+ }
+
SimplifyPersonality();
if (getCodeGenOpts().EmitDeclMetadata)
@@ -279,6 +390,8 @@ void CodeGenModule::Release() {
DebugInfo->finalize();
EmitVersionIdentMetadata();
+
+ EmitTargetMetadata();
}
void CodeGenModule::UpdateCompletedType(const TagDecl *TD) {
@@ -288,25 +401,25 @@ void CodeGenModule::UpdateCompletedType(const TagDecl *TD) {
llvm::MDNode *CodeGenModule::getTBAAInfo(QualType QTy) {
if (!TBAA)
- return 0;
+ return nullptr;
return TBAA->getTBAAInfo(QTy);
}
llvm::MDNode *CodeGenModule::getTBAAInfoForVTablePtr() {
if (!TBAA)
- return 0;
+ return nullptr;
return TBAA->getTBAAInfoForVTablePtr();
}
llvm::MDNode *CodeGenModule::getTBAAStructInfo(QualType QTy) {
if (!TBAA)
- return 0;
+ return nullptr;
return TBAA->getTBAAStructInfo(QTy);
}
llvm::MDNode *CodeGenModule::getTBAAStructTypeInfo(QualType QTy) {
if (!TBAA)
- return 0;
+ return nullptr;
return TBAA->getTBAAStructTypeInfo(QTy);
}
@@ -314,7 +427,7 @@ llvm::MDNode *CodeGenModule::getTBAAStructTagInfo(QualType BaseTy,
llvm::MDNode *AccessN,
uint64_t O) {
if (!TBAA)
- return 0;
+ return nullptr;
return TBAA->getTBAAStructTagInfo(BaseTy, AccessN, O);
}
@@ -332,9 +445,9 @@ void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst,
Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo);
}
-void CodeGenModule::Error(SourceLocation loc, StringRef error) {
- unsigned diagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, error);
- getDiags().Report(Context.getFullLoc(loc), diagID);
+void CodeGenModule::Error(SourceLocation loc, StringRef message) {
+ unsigned diagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, "%0");
+ getDiags().Report(Context.getFullLoc(loc), diagID) << message;
}
/// ErrorUnsupported - Print out an error that codegen doesn't support the
@@ -405,130 +518,61 @@ void CodeGenModule::setTLSMode(llvm::GlobalVariable *GV,
TLM = GetLLVMTLSModel(CodeGenOpts.getDefaultTLSModel());
// Override the TLS model if it is explicitly specified.
- if (D.hasAttr<TLSModelAttr>()) {
- const TLSModelAttr *Attr = D.getAttr<TLSModelAttr>();
+ if (const TLSModelAttr *Attr = D.getAttr<TLSModelAttr>()) {
TLM = GetLLVMTLSModel(Attr->getModel());
}
GV->setThreadLocalMode(TLM);
}
-/// Set the symbol visibility of type information (vtable and RTTI)
-/// associated with the given type.
-void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV,
- const CXXRecordDecl *RD,
- TypeVisibilityKind TVK) const {
- setGlobalVisibility(GV, RD);
-
- if (!CodeGenOpts.HiddenWeakVTables)
- return;
-
- // We never want to drop the visibility for RTTI names.
- if (TVK == TVK_ForRTTIName)
- return;
-
- // We want to drop the visibility to hidden for weak type symbols.
- // This isn't possible if there might be unresolved references
- // elsewhere that rely on this symbol being visible.
-
- // This should be kept roughly in sync with setThunkVisibility
- // in CGVTables.cpp.
-
- // Preconditions.
- if (GV->getLinkage() != llvm::GlobalVariable::LinkOnceODRLinkage ||
- GV->getVisibility() != llvm::GlobalVariable::DefaultVisibility)
- return;
-
- // Don't override an explicit visibility attribute.
- if (RD->getExplicitVisibility(NamedDecl::VisibilityForType))
- return;
-
- switch (RD->getTemplateSpecializationKind()) {
- // We have to disable the optimization if this is an EI definition
- // because there might be EI declarations in other shared objects.
- case TSK_ExplicitInstantiationDefinition:
- case TSK_ExplicitInstantiationDeclaration:
- return;
-
- // Every use of a non-template class's type information has to emit it.
- case TSK_Undeclared:
- break;
-
- // In theory, implicit instantiations can ignore the possibility of
- // an explicit instantiation declaration because there necessarily
- // must be an EI definition somewhere with default visibility. In
- // practice, it's possible to have an explicit instantiation for
- // an arbitrary template class, and linkers aren't necessarily able
- // to deal with mixed-visibility symbols.
- case TSK_ExplicitSpecialization:
- case TSK_ImplicitInstantiation:
- return;
- }
-
- // If there's a key function, there may be translation units
- // that don't have the key function's definition. But ignore
- // this if we're emitting RTTI under -fno-rtti.
- if (!(TVK != TVK_ForRTTI) || LangOpts.RTTI) {
- // FIXME: what should we do if we "lose" the key function during
- // the emission of the file?
- if (Context.getCurrentKeyFunction(RD))
- return;
- }
-
- // Otherwise, drop the visibility to hidden.
- GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
- GV->setUnnamedAddr(true);
-}
-
StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
- const NamedDecl *ND = cast<NamedDecl>(GD.getDecl());
-
- StringRef &Str = MangledDeclNames[GD.getCanonicalDecl()];
- if (!Str.empty())
- return Str;
+ StringRef &FoundStr = MangledDeclNames[GD.getCanonicalDecl()];
+ if (!FoundStr.empty())
+ return FoundStr;
- if (!getCXXABI().getMangleContext().shouldMangleDeclName(ND)) {
+ const auto *ND = cast<NamedDecl>(GD.getDecl());
+ SmallString<256> Buffer;
+ StringRef Str;
+ if (getCXXABI().getMangleContext().shouldMangleDeclName(ND)) {
+ llvm::raw_svector_ostream Out(Buffer);
+ if (const auto *D = dyn_cast<CXXConstructorDecl>(ND))
+ getCXXABI().getMangleContext().mangleCXXCtor(D, GD.getCtorType(), Out);
+ else if (const auto *D = dyn_cast<CXXDestructorDecl>(ND))
+ getCXXABI().getMangleContext().mangleCXXDtor(D, GD.getDtorType(), Out);
+ else
+ getCXXABI().getMangleContext().mangleName(ND, Out);
+ Str = Out.str();
+ } else {
IdentifierInfo *II = ND->getIdentifier();
assert(II && "Attempt to mangle unnamed decl.");
-
Str = II->getName();
- return Str;
}
-
- SmallString<256> Buffer;
- llvm::raw_svector_ostream Out(Buffer);
- if (const CXXConstructorDecl *D = dyn_cast<CXXConstructorDecl>(ND))
- getCXXABI().getMangleContext().mangleCXXCtor(D, GD.getCtorType(), Out);
- else if (const CXXDestructorDecl *D = dyn_cast<CXXDestructorDecl>(ND))
- getCXXABI().getMangleContext().mangleCXXDtor(D, GD.getDtorType(), Out);
- else
- getCXXABI().getMangleContext().mangleName(ND, Out);
- // Allocate space for the mangled name.
- Out.flush();
- size_t Length = Buffer.size();
- char *Name = MangledNamesAllocator.Allocate<char>(Length);
- std::copy(Buffer.begin(), Buffer.end(), Name);
-
- Str = StringRef(Name, Length);
-
- return Str;
+ auto &Mangled = Manglings.GetOrCreateValue(Str);
+ Mangled.second = GD;
+ return FoundStr = Mangled.first();
}
-void CodeGenModule::getBlockMangledName(GlobalDecl GD, MangleBuffer &Buffer,
- const BlockDecl *BD) {
+StringRef CodeGenModule::getBlockMangledName(GlobalDecl GD,
+ const BlockDecl *BD) {
MangleContext &MangleCtx = getCXXABI().getMangleContext();
const Decl *D = GD.getDecl();
- llvm::raw_svector_ostream Out(Buffer.getBuffer());
- if (D == 0)
+
+ SmallString<256> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ if (!D)
MangleCtx.mangleGlobalBlock(BD,
dyn_cast_or_null<VarDecl>(initializedGlobalDecl.getDecl()), Out);
- else if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
+ else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D))
MangleCtx.mangleCtorBlock(CD, GD.getCtorType(), BD, Out);
- else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D))
+ else if (const auto *DD = dyn_cast<CXXDestructorDecl>(D))
MangleCtx.mangleDtorBlock(DD, GD.getDtorType(), BD, Out);
else
MangleCtx.mangleBlock(cast<DeclContext>(D), BD, Out);
+
+ auto &Mangled = Manglings.GetOrCreateValue(Out.str());
+ Mangled.second = BD;
+ return Mangled.first();
}
llvm::GlobalValue *CodeGenModule::GetGlobalValue(StringRef Name) {
@@ -537,16 +581,17 @@ llvm::GlobalValue *CodeGenModule::GetGlobalValue(StringRef Name) {
/// AddGlobalCtor - Add a function to the list that will be called before
/// main() runs.
-void CodeGenModule::AddGlobalCtor(llvm::Function * Ctor, int Priority) {
+void CodeGenModule::AddGlobalCtor(llvm::Function *Ctor, int Priority,
+ llvm::Constant *AssociatedData) {
// FIXME: Type coercion of void()* types.
- GlobalCtors.push_back(std::make_pair(Ctor, Priority));
+ GlobalCtors.push_back(Structor(Priority, Ctor, AssociatedData));
}
/// AddGlobalDtor - Add a function to the list that will be called
/// when the module is unloaded.
-void CodeGenModule::AddGlobalDtor(llvm::Function * Dtor, int Priority) {
+void CodeGenModule::AddGlobalDtor(llvm::Function *Dtor, int Priority) {
// FIXME: Type coercion of void()* types.
- GlobalDtors.push_back(std::make_pair(Dtor, Priority));
+ GlobalDtors.push_back(Structor(Priority, Dtor, nullptr));
}
void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) {
@@ -554,16 +599,19 @@ void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) {
llvm::FunctionType* CtorFTy = llvm::FunctionType::get(VoidTy, false);
llvm::Type *CtorPFTy = llvm::PointerType::getUnqual(CtorFTy);
- // Get the type of a ctor entry, { i32, void ()* }.
- llvm::StructType *CtorStructTy =
- llvm::StructType::get(Int32Ty, llvm::PointerType::getUnqual(CtorFTy), NULL);
+ // Get the type of a ctor entry, { i32, void ()*, i8* }.
+ llvm::StructType *CtorStructTy = llvm::StructType::get(
+ Int32Ty, llvm::PointerType::getUnqual(CtorFTy), VoidPtrTy, NULL);
// Construct the constructor and destructor arrays.
SmallVector<llvm::Constant*, 8> Ctors;
for (CtorList::const_iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) {
llvm::Constant *S[] = {
- llvm::ConstantInt::get(Int32Ty, I->second, false),
- llvm::ConstantExpr::getBitCast(I->first, CtorPFTy)
+ llvm::ConstantInt::get(Int32Ty, I->Priority, false),
+ llvm::ConstantExpr::getBitCast(I->Initializer, CtorPFTy),
+ (I->AssociatedData
+ ? llvm::ConstantExpr::getBitCast(I->AssociatedData, VoidPtrTy)
+ : llvm::Constant::getNullValue(VoidPtrTy))
};
Ctors.push_back(llvm::ConstantStruct::get(CtorStructTy, S));
}
@@ -579,67 +627,25 @@ void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) {
llvm::GlobalValue::LinkageTypes
CodeGenModule::getFunctionLinkage(GlobalDecl GD) {
- const FunctionDecl *D = cast<FunctionDecl>(GD.getDecl());
-
- if (isa<CXXDestructorDecl>(D) &&
- getCXXABI().useThunkForDtorVariant(cast<CXXDestructorDecl>(D),
- GD.getDtorType()))
- return llvm::Function::LinkOnceODRLinkage;
+ const auto *D = cast<FunctionDecl>(GD.getDecl());
GVALinkage Linkage = getContext().GetGVALinkageForFunction(D);
- if (Linkage == GVA_Internal)
- return llvm::Function::InternalLinkage;
-
- if (D->hasAttr<DLLExportAttr>())
- return llvm::Function::DLLExportLinkage;
-
- if (D->hasAttr<WeakAttr>())
- return llvm::Function::WeakAnyLinkage;
-
- // In C99 mode, 'inline' functions are guaranteed to have a strong
- // definition somewhere else, so we can use available_externally linkage.
- if (Linkage == GVA_C99Inline)
- return llvm::Function::AvailableExternallyLinkage;
-
- // Note that Apple's kernel linker doesn't support symbol
- // coalescing, so we need to avoid linkonce and weak linkages there.
- // Normally, this means we just map to internal, but for explicit
- // instantiations we'll map to external.
+ if (isa<CXXDestructorDecl>(D) &&
+ getCXXABI().useThunkForDtorVariant(cast<CXXDestructorDecl>(D),
+ GD.getDtorType())) {
+ // Destructor variants in the Microsoft C++ ABI are always internal or
+ // linkonce_odr thunks emitted on an as-needed basis.
+ return Linkage == GVA_Internal ? llvm::GlobalValue::InternalLinkage
+ : llvm::GlobalValue::LinkOnceODRLinkage;
+ }
- // In C++, the compiler has to emit a definition in every translation unit
- // that references the function. We should use linkonce_odr because
- // a) if all references in this translation unit are optimized away, we
- // don't need to codegen it. b) if the function persists, it needs to be
- // merged with other definitions. c) C++ has the ODR, so we know the
- // definition is dependable.
- if (Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation)
- return !Context.getLangOpts().AppleKext
- ? llvm::Function::LinkOnceODRLinkage
- : llvm::Function::InternalLinkage;
-
- // An explicit instantiation of a template has weak linkage, since
- // explicit instantiations can occur in multiple translation units
- // and must all be equivalent. However, we are not allowed to
- // throw away these explicit instantiations.
- if (Linkage == GVA_ExplicitTemplateInstantiation)
- return !Context.getLangOpts().AppleKext
- ? llvm::Function::WeakODRLinkage
- : llvm::Function::ExternalLinkage;
-
- // Otherwise, we have strong external linkage.
- assert(Linkage == GVA_StrongExternal);
- return llvm::Function::ExternalLinkage;
+ return getLLVMLinkageForDeclarator(D, Linkage, /*isConstantVariable=*/false);
}
-
-/// SetFunctionDefinitionAttributes - Set attributes for a global.
-///
-/// FIXME: This is currently only done for aliases and functions, but not for
-/// variables (these details are set in EmitGlobalVarDefinition for variables).
-void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D,
- llvm::GlobalValue *GV) {
- SetCommonAttributes(D, GV);
+void CodeGenModule::setFunctionDefinitionAttributes(const FunctionDecl *D,
+ llvm::Function *F) {
+ setNonAliasAttributes(D, F);
}
void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D,
@@ -686,10 +692,15 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
// Naked implies noinline: we should not be inlining such functions.
B.addAttribute(llvm::Attribute::Naked);
B.addAttribute(llvm::Attribute::NoInline);
+ } else if (D->hasAttr<OptimizeNoneAttr>()) {
+ // OptimizeNone implies noinline; we should not be inlining such functions.
+ B.addAttribute(llvm::Attribute::OptimizeNone);
+ B.addAttribute(llvm::Attribute::NoInline);
+ } else if (D->hasAttr<NoDuplicateAttr>()) {
+ B.addAttribute(llvm::Attribute::NoDuplicate);
} else if (D->hasAttr<NoInlineAttr>()) {
B.addAttribute(llvm::Attribute::NoInline);
- } else if ((D->hasAttr<AlwaysInlineAttr>() ||
- D->hasAttr<ForceInlineAttr>()) &&
+ } else if (D->hasAttr<AlwaysInlineAttr>() &&
!F->getAttributes().hasAttribute(llvm::AttributeSet::FunctionIndex,
llvm::Attribute::NoInline)) {
// (noinline wins over always_inline, and we can't specify both in IR)
@@ -704,23 +715,30 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
if (D->hasAttr<MinSizeAttr>())
B.addAttribute(llvm::Attribute::MinSize);
+ if (D->hasAttr<OptimizeNoneAttr>()) {
+ // OptimizeNone wins over OptimizeForSize and MinSize.
+ B.removeAttribute(llvm::Attribute::OptimizeForSize);
+ B.removeAttribute(llvm::Attribute::MinSize);
+ }
+
if (LangOpts.getStackProtector() == LangOptions::SSPOn)
B.addAttribute(llvm::Attribute::StackProtect);
+ else if (LangOpts.getStackProtector() == LangOptions::SSPStrong)
+ B.addAttribute(llvm::Attribute::StackProtectStrong);
else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
B.addAttribute(llvm::Attribute::StackProtectReq);
// Add sanitizer attributes if function is not blacklisted.
- if (!SanitizerBlacklist->isIn(*F)) {
+ if (!SanitizerBL.isIn(*F)) {
// When AddressSanitizer is enabled, set SanitizeAddress attribute
// unless __attribute__((no_sanitize_address)) is used.
- if (SanOpts.Address && !D->hasAttr<NoSanitizeAddressAttr>())
+ if (LangOpts.Sanitize.Address && !D->hasAttr<NoSanitizeAddressAttr>())
B.addAttribute(llvm::Attribute::SanitizeAddress);
// Same for ThreadSanitizer and __attribute__((no_sanitize_thread))
- if (SanOpts.Thread && !D->hasAttr<NoSanitizeThreadAttr>()) {
+ if (LangOpts.Sanitize.Thread && !D->hasAttr<NoSanitizeThreadAttr>())
B.addAttribute(llvm::Attribute::SanitizeThread);
- }
// Same for MemorySanitizer and __attribute__((no_sanitize_memory))
- if (SanOpts.Memory && !D->hasAttr<NoSanitizeMemoryAttr>())
+ if (LangOpts.Sanitize.Memory && !D->hasAttr<NoSanitizeMemoryAttr>())
B.addAttribute(llvm::Attribute::SanitizeMemory);
}
@@ -730,7 +748,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D))
F->setUnnamedAddr(true);
- else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D))
+ else if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
if (MD->isVirtual())
F->setUnnamedAddr(true);
@@ -745,20 +763,23 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
void CodeGenModule::SetCommonAttributes(const Decl *D,
llvm::GlobalValue *GV) {
- if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ if (const auto *ND = dyn_cast<NamedDecl>(D))
setGlobalVisibility(GV, ND);
else
GV->setVisibility(llvm::GlobalValue::DefaultVisibility);
if (D->hasAttr<UsedAttr>())
- AddUsedGlobal(GV);
+ addUsedGlobal(GV);
+}
+
+void CodeGenModule::setNonAliasAttributes(const Decl *D,
+ llvm::GlobalObject *GO) {
+ SetCommonAttributes(D, GO);
if (const SectionAttr *SA = D->getAttr<SectionAttr>())
- GV->setSection(SA->getName());
+ GO->setSection(SA->getName());
- // Alias cannot have attributes. Filter them here.
- if (!isa<llvm::GlobalAlias>(GV))
- getTargetCodeGenInfo().SetTargetAttributes(D, GV, *this);
+ getTargetCodeGenInfo().SetTargetAttributes(D, GO, *this);
}
void CodeGenModule::SetInternalFunctionAttributes(const Decl *D,
@@ -769,7 +790,32 @@ void CodeGenModule::SetInternalFunctionAttributes(const Decl *D,
F->setLinkage(llvm::Function::InternalLinkage);
- SetCommonAttributes(D, F);
+ setNonAliasAttributes(D, F);
+}
+
+static void setLinkageAndVisibilityForGV(llvm::GlobalValue *GV,
+ const NamedDecl *ND) {
+ // Set linkage and visibility in case we never see a definition.
+ LinkageInfo LV = ND->getLinkageAndVisibility();
+ if (LV.getLinkage() != ExternalLinkage) {
+ // Don't set internal linkage on declarations.
+ } else {
+ if (ND->hasAttr<DLLImportAttr>()) {
+ GV->setLinkage(llvm::GlobalValue::ExternalLinkage);
+ GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+ } else if (ND->hasAttr<DLLExportAttr>()) {
+ GV->setLinkage(llvm::GlobalValue::ExternalLinkage);
+ GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
+ } else if (ND->hasAttr<WeakAttr>() || ND->isWeakImported()) {
+ // "extern_weak" is overloaded in LLVM; we probably should have
+ // separate linkage types for this.
+ GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
+ }
+
+ // Set visibility on a declaration only if it's explicit.
+ if (LV.isVisibilityExplicit())
+ GV->setVisibility(CodeGenModule::GetLLVMVisibility(LV.getVisibility()));
+ }
}
void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
@@ -783,12 +829,17 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
return;
}
- const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
+ const auto *FD = cast<FunctionDecl>(GD.getDecl());
if (!IsIncompleteFunction)
SetLLVMFunctionAttributes(FD, getTypes().arrangeGlobalDeclaration(GD), F);
- if (getCXXABI().HasThisReturn(GD)) {
+ // Add the Returned attribute for "this", except for iOS 5 and earlier
+ // where substantial code, including the libstdc++ dylib, was compiled with
+ // GCC and does not actually return "this".
+ if (getCXXABI().HasThisReturn(GD) &&
+ !(getTarget().getTriple().isiOS() &&
+ getTarget().getTriple().isOSVersionLT(6))) {
assert(!F->arg_empty() &&
F->arg_begin()->getType()
->canLosslesslyBitCastTo(F->getReturnType()) &&
@@ -799,19 +850,12 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
// Only a few attributes are set on declarations; these may later be
// overridden by a definition.
- if (FD->hasAttr<DLLImportAttr>()) {
- F->setLinkage(llvm::Function::DLLImportLinkage);
- } else if (FD->hasAttr<WeakAttr>() ||
- FD->isWeakImported()) {
- // "extern_weak" is overloaded in LLVM; we probably should have
- // separate linkage types for this.
- F->setLinkage(llvm::Function::ExternalWeakLinkage);
- } else {
- F->setLinkage(llvm::Function::ExternalLinkage);
+ setLinkageAndVisibilityForGV(F, FD);
- LinkageInfo LV = FD->getLinkageAndVisibility();
- if (LV.getLinkage() == ExternalLinkage && LV.isVisibilityExplicit()) {
- F->setVisibility(GetLLVMVisibility(LV.getVisibility()));
+ if (const auto *Dtor = dyn_cast_or_null<CXXDestructorDecl>(FD)) {
+ if (getCXXABI().useThunkForDtorVariant(Dtor, GD.getDtorType())) {
+ // Don't dllexport/import destructor thunks.
+ F->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
}
}
@@ -825,39 +869,49 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
llvm::Attribute::NoBuiltin);
}
-void CodeGenModule::AddUsedGlobal(llvm::GlobalValue *GV) {
+void CodeGenModule::addUsedGlobal(llvm::GlobalValue *GV) {
assert(!GV->isDeclaration() &&
"Only globals with definition can force usage.");
LLVMUsed.push_back(GV);
}
-void CodeGenModule::EmitLLVMUsed() {
+void CodeGenModule::addCompilerUsedGlobal(llvm::GlobalValue *GV) {
+ assert(!GV->isDeclaration() &&
+ "Only globals with definition can force usage.");
+ LLVMCompilerUsed.push_back(GV);
+}
+
+static void emitUsed(CodeGenModule &CGM, StringRef Name,
+ std::vector<llvm::WeakVH> &List) {
// Don't create llvm.used if there is no need.
- if (LLVMUsed.empty())
+ if (List.empty())
return;
- // Convert LLVMUsed to what ConstantArray needs.
+ // Convert List to what ConstantArray needs.
SmallVector<llvm::Constant*, 8> UsedArray;
- UsedArray.resize(LLVMUsed.size());
- for (unsigned i = 0, e = LLVMUsed.size(); i != e; ++i) {
+ UsedArray.resize(List.size());
+ for (unsigned i = 0, e = List.size(); i != e; ++i) {
UsedArray[i] =
- llvm::ConstantExpr::getBitCast(cast<llvm::Constant>(&*LLVMUsed[i]),
- Int8PtrTy);
+ llvm::ConstantExpr::getBitCast(cast<llvm::Constant>(&*List[i]),
+ CGM.Int8PtrTy);
}
if (UsedArray.empty())
return;
- llvm::ArrayType *ATy = llvm::ArrayType::get(Int8PtrTy, UsedArray.size());
+ llvm::ArrayType *ATy = llvm::ArrayType::get(CGM.Int8PtrTy, UsedArray.size());
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(getModule(), ATy, false,
- llvm::GlobalValue::AppendingLinkage,
- llvm::ConstantArray::get(ATy, UsedArray),
- "llvm.used");
+ auto *GV = new llvm::GlobalVariable(
+ CGM.getModule(), ATy, false, llvm::GlobalValue::AppendingLinkage,
+ llvm::ConstantArray::get(ATy, UsedArray), Name);
GV->setSection("llvm.metadata");
}
+void CodeGenModule::emitLLVMUsed() {
+ emitUsed(*this, "llvm.used", LLVMUsed);
+ emitUsed(*this, "llvm.compiler.used", LLVMCompilerUsed);
+}
+
void CodeGenModule::AppendLinkerOptions(StringRef Opts) {
llvm::Value *MDOpts = llvm::MDString::get(getLLVMContext(), Opts);
LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts));
@@ -1002,31 +1056,23 @@ void CodeGenModule::EmitDeferred() {
// Stop if we're out of both deferred v-tables and deferred declarations.
if (DeferredDeclsToEmit.empty()) break;
- GlobalDecl D = DeferredDeclsToEmit.back();
+ DeferredGlobal &G = DeferredDeclsToEmit.back();
+ GlobalDecl D = G.GD;
+ llvm::GlobalValue *GV = G.GV;
DeferredDeclsToEmit.pop_back();
+ assert(GV == GetGlobalValue(getMangledName(D)));
// Check to see if we've already emitted this. This is necessary
// for a couple of reasons: first, decls can end up in the
// deferred-decls queue multiple times, and second, decls can end
// up with definitions in unusual ways (e.g. by an extern inline
// function acquiring a strong function redefinition). Just
// ignore these cases.
- //
- // TODO: That said, looking this up multiple times is very wasteful.
- StringRef Name = getMangledName(D);
- llvm::GlobalValue *CGRef = GetGlobalValue(Name);
- assert(CGRef && "Deferred decl wasn't referenced?");
-
- if (!CGRef->isDeclaration())
- continue;
-
- // GlobalAlias::isDeclaration() defers to the aliasee, but for our
- // purposes an alias counts as a definition.
- if (isa<llvm::GlobalAlias>(CGRef))
+ if(!GV->isDeclaration())
continue;
// Otherwise, emit the definition and move on to the next one.
- EmitGlobalDefinition(D);
+ EmitGlobalDefinition(D, GV);
}
}
@@ -1037,9 +1083,9 @@ void CodeGenModule::EmitGlobalAnnotations() {
// Create a new global variable for the ConstantStruct in the Module.
llvm::Constant *Array = llvm::ConstantArray::get(llvm::ArrayType::get(
Annotations[0]->getType(), Annotations.size()), Annotations);
- llvm::GlobalValue *gv = new llvm::GlobalVariable(getModule(),
- Array->getType(), false, llvm::GlobalValue::AppendingLinkage, Array,
- "llvm.global.annotations");
+ auto *gv = new llvm::GlobalVariable(getModule(), Array->getType(), false,
+ llvm::GlobalValue::AppendingLinkage,
+ Array, "llvm.global.annotations");
gv->setSection(AnnotationSection);
}
@@ -1050,8 +1096,9 @@ llvm::Constant *CodeGenModule::EmitAnnotationString(StringRef Str) {
// Not found yet, create a new global.
llvm::Constant *s = llvm::ConstantDataArray::getString(getLLVMContext(), Str);
- llvm::GlobalValue *gv = new llvm::GlobalVariable(getModule(), s->getType(),
- true, llvm::GlobalValue::PrivateLinkage, s, ".str");
+ auto *gv =
+ new llvm::GlobalVariable(getModule(), s->getType(), true,
+ llvm::GlobalValue::PrivateLinkage, s, ".str");
gv->setSection(AnnotationSection);
gv->setUnnamedAddr(true);
AStr = gv;
@@ -1096,10 +1143,8 @@ void CodeGenModule::AddGlobalAnnotations(const ValueDecl *D,
llvm::GlobalValue *GV) {
assert(D->hasAttr<AnnotateAttr>() && "no annotate attribute");
// Get the struct elements for these annotations.
- for (specific_attr_iterator<AnnotateAttr>
- ai = D->specific_attr_begin<AnnotateAttr>(),
- ae = D->specific_attr_end<AnnotateAttr>(); ai != ae; ++ai)
- Annotations.push_back(EmitAnnotateAttr(GV, *ai, D->getLocation()));
+ for (const auto *I : D->specific_attrs<AnnotateAttr>())
+ Annotations.push_back(EmitAnnotateAttr(GV, I, D->getLocation()));
}
bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
@@ -1125,7 +1170,7 @@ llvm::Constant *CodeGenModule::GetAddrOfUuidDescriptor(
llvm::Constant *Init = EmitUuidofInitializer(Uuid, E->getType());
assert(Init && "failed to initialize as constant");
- llvm::GlobalVariable *GV = new llvm::GlobalVariable(
+ auto *GV = new llvm::GlobalVariable(
getModule(), Init->getType(),
/*isConstant=*/true, llvm::GlobalValue::LinkOnceODRLinkage, Init, Name);
return GV;
@@ -1151,9 +1196,10 @@ llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) {
/*ForVTable=*/false);
else
Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(),
- llvm::PointerType::getUnqual(DeclTy), 0);
+ llvm::PointerType::getUnqual(DeclTy),
+ nullptr);
- llvm::GlobalValue* F = cast<llvm::GlobalValue>(Aliasee);
+ auto *F = cast<llvm::GlobalValue>(Aliasee);
F->setLinkage(llvm::Function::ExternalWeakLinkage);
WeakRefReferences.insert(F);
@@ -1161,7 +1207,7 @@ llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) {
}
void CodeGenModule::EmitGlobal(GlobalDecl GD) {
- const ValueDecl *Global = cast<ValueDecl>(GD.getDecl());
+ const auto *Global = cast<ValueDecl>(GD.getDecl());
// Weak references don't produce any output by themselves.
if (Global->hasAttr<WeakRefAttr>())
@@ -1190,25 +1236,28 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
}
// Ignore declarations, they will be emitted on their first use.
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Global)) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(Global)) {
// Forward declarations are emitted lazily on first use.
if (!FD->doesThisDeclarationHaveABody()) {
if (!FD->doesDeclarationForceExternallyVisibleDefinition())
return;
- const FunctionDecl *InlineDefinition = 0;
- FD->getBody(InlineDefinition);
-
StringRef MangledName = getMangledName(GD);
- DeferredDecls.erase(MangledName);
- EmitGlobalDefinition(InlineDefinition);
+
+ // Compute the function info and LLVM type.
+ const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD);
+ llvm::Type *Ty = getTypes().GetFunctionType(FI);
+
+ GetOrCreateLLVMFunction(MangledName, Ty, GD, /*ForVTable=*/false,
+ /*DontDefer=*/false);
return;
}
} else {
- const VarDecl *VD = cast<VarDecl>(Global);
+ const auto *VD = cast<VarDecl>(Global);
assert(VD->isFileVarDecl() && "Cannot emit local var decl as global.");
- if (VD->isThisDeclarationADefinition() != VarDecl::Definition)
+ if (VD->isThisDeclarationADefinition() != VarDecl::Definition &&
+ !Context.isMSStaticDataMemberInlineDefinition(VD))
return;
}
@@ -1225,14 +1274,14 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
if (getLangOpts().CPlusPlus && isa<VarDecl>(Global) &&
cast<VarDecl>(Global)->hasInit()) {
DelayedCXXInitPosition[Global] = CXXGlobalInits.size();
- CXXGlobalInits.push_back(0);
+ CXXGlobalInits.push_back(nullptr);
}
// If the value has already been used, add it directly to the
// DeferredDeclsToEmit list.
StringRef MangledName = getMangledName(GD);
- if (GetGlobalValue(MangledName))
- DeferredDeclsToEmit.push_back(GD);
+ if (llvm::GlobalValue *GV = GetGlobalValue(MangledName))
+ addDeferredDeclToEmit(GV, GD);
else {
// Otherwise, remember that we saw a deferred decl with this name. The
// first use of the mangled name will cause it to move into
@@ -1300,9 +1349,8 @@ bool
CodeGenModule::shouldEmitFunction(GlobalDecl GD) {
if (getFunctionLinkage(GD) != llvm::Function::AvailableExternallyLinkage)
return true;
- const FunctionDecl *F = cast<FunctionDecl>(GD.getDecl());
- if (CodeGenOpts.OptimizationLevel == 0 &&
- !F->hasAttr<AlwaysInlineAttr>() && !F->hasAttr<ForceInlineAttr>())
+ const auto *F = cast<FunctionDecl>(GD.getDecl());
+ if (CodeGenOpts.OptimizationLevel == 0 && !F->hasAttr<AlwaysInlineAttr>())
return false;
// PR9614. Avoid cases where the source code is lying to us. An available
// externally function should have an equivalent function somewhere else,
@@ -1323,14 +1371,13 @@ void CodeGenModule::CompleteDIClassType(const CXXMethodDecl* D) {
if (CGDebugInfo *DI = getModuleDebugInfo())
if (getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) {
- const PointerType *ThisPtr =
- cast<PointerType>(D->getThisType(getContext()));
+ const auto *ThisPtr = cast<PointerType>(D->getThisType(getContext()));
DI->getOrCreateRecordType(ThisPtr->getPointeeType(), D->getLocation());
}
}
-void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
- const ValueDecl *D = cast<ValueDecl>(GD.getDecl());
+void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) {
+ const auto *D = cast<ValueDecl>(GD.getDecl());
PrettyStackTraceDecl CrashInfo(const_cast<ValueDecl *>(D), D->getLocation(),
Context.getSourceManager(),
@@ -1342,16 +1389,16 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
if (!shouldEmitFunction(GD))
return;
- if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
+ if (const auto *Method = dyn_cast<CXXMethodDecl>(D)) {
CompleteDIClassType(Method);
// Make sure to emit the definition(s) before we emit the thunks.
// This is necessary for the generation of certain thunks.
- if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Method))
+ if (const auto *CD = dyn_cast<CXXConstructorDecl>(Method))
EmitCXXConstructor(CD, GD.getCtorType());
- else if (const CXXDestructorDecl *DD =dyn_cast<CXXDestructorDecl>(Method))
+ else if (const auto *DD = dyn_cast<CXXDestructorDecl>(Method))
EmitCXXDestructor(DD, GD.getDtorType());
else
- EmitGlobalFunctionDefinition(GD);
+ EmitGlobalFunctionDefinition(GD, GV);
if (Method->isVirtual())
getVTables().EmitThunks(GD);
@@ -1359,10 +1406,10 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
return;
}
- return EmitGlobalFunctionDefinition(GD);
+ return EmitGlobalFunctionDefinition(GD, GV);
}
-
- if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+
+ if (const auto *VD = dyn_cast<VarDecl>(D))
return EmitGlobalVarDefinition(VD);
llvm_unreachable("Invalid argument to EmitGlobalDefinition()");
@@ -1379,6 +1426,7 @@ llvm::Constant *
CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
llvm::Type *Ty,
GlobalDecl GD, bool ForVTable,
+ bool DontDefer,
llvm::AttributeSet ExtraAttrs) {
const Decl *D = GD.getDecl();
@@ -1398,14 +1446,6 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
return llvm::ConstantExpr::getBitCast(Entry, Ty->getPointerTo());
}
- // All MSVC dtors other than the base dtor are linkonce_odr and delegate to
- // each other bottoming out with the base dtor. Therefore we emit non-base
- // dtors on usage, even if there is no dtor definition in the TU.
- if (D && isa<CXXDestructorDecl>(D) &&
- getCXXABI().useThunkForDtorVariant(cast<CXXDestructorDecl>(D),
- GD.getDtorType()))
- DeferredDeclsToEmit.push_back(GD);
-
// This function doesn't have a complete type (for example, the return
// type is an incomplete struct). Use a fake type instead, and make
// sure not to try to set attributes.
@@ -1433,50 +1473,64 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
B));
}
- // This is the first use or definition of a mangled name. If there is a
- // deferred decl with this name, remember that we need to emit it at the end
- // of the file.
- llvm::StringMap<GlobalDecl>::iterator DDI = DeferredDecls.find(MangledName);
- if (DDI != DeferredDecls.end()) {
- // Move the potentially referenced deferred decl to the DeferredDeclsToEmit
- // list, and remove it from DeferredDecls (since we don't need it anymore).
- DeferredDeclsToEmit.push_back(DDI->second);
- DeferredDecls.erase(DDI);
-
- // Otherwise, if this is a sized deallocation function, emit a weak definition
- // for it at the end of the translation unit.
- } else if (D && cast<FunctionDecl>(D)
- ->getCorrespondingUnsizedGlobalDeallocationFunction()) {
- DeferredDeclsToEmit.push_back(GD);
-
- // Otherwise, there are cases we have to worry about where we're
- // using a declaration for which we must emit a definition but where
- // we might not find a top-level definition:
- // - member functions defined inline in their classes
- // - friend functions defined inline in some class
- // - special member functions with implicit definitions
- // If we ever change our AST traversal to walk into class methods,
- // this will be unnecessary.
- //
- // We also don't emit a definition for a function if it's going to be an entry
- // in a vtable, unless it's already marked as used.
- } else if (getLangOpts().CPlusPlus && D) {
- // Look for a declaration that's lexically in a record.
- const FunctionDecl *FD = cast<FunctionDecl>(D);
- FD = FD->getMostRecentDecl();
- do {
- if (isa<CXXRecordDecl>(FD->getLexicalDeclContext())) {
- if (FD->isImplicit() && !ForVTable) {
- assert(FD->isUsed() && "Sema didn't mark implicit function as used!");
- DeferredDeclsToEmit.push_back(GD.getWithDecl(FD));
- break;
- } else if (FD->doesThisDeclarationHaveABody()) {
- DeferredDeclsToEmit.push_back(GD.getWithDecl(FD));
- break;
+ if (!DontDefer) {
+ // All MSVC dtors other than the base dtor are linkonce_odr and delegate to
+ // each other bottoming out with the base dtor. Therefore we emit non-base
+ // dtors on usage, even if there is no dtor definition in the TU.
+ if (D && isa<CXXDestructorDecl>(D) &&
+ getCXXABI().useThunkForDtorVariant(cast<CXXDestructorDecl>(D),
+ GD.getDtorType()))
+ addDeferredDeclToEmit(F, GD);
+
+ // This is the first use or definition of a mangled name. If there is a
+ // deferred decl with this name, remember that we need to emit it at the end
+ // of the file.
+ auto DDI = DeferredDecls.find(MangledName);
+ if (DDI != DeferredDecls.end()) {
+ // Move the potentially referenced deferred decl to the
+ // DeferredDeclsToEmit list, and remove it from DeferredDecls (since we
+ // don't need it anymore).
+ addDeferredDeclToEmit(F, DDI->second);
+ DeferredDecls.erase(DDI);
+
+ // Otherwise, if this is a sized deallocation function, emit a weak
+ // definition
+ // for it at the end of the translation unit.
+ } else if (D && cast<FunctionDecl>(D)
+ ->getCorrespondingUnsizedGlobalDeallocationFunction()) {
+ addDeferredDeclToEmit(F, GD);
+
+ // Otherwise, there are cases we have to worry about where we're
+ // using a declaration for which we must emit a definition but where
+ // we might not find a top-level definition:
+ // - member functions defined inline in their classes
+ // - friend functions defined inline in some class
+ // - special member functions with implicit definitions
+ // If we ever change our AST traversal to walk into class methods,
+ // this will be unnecessary.
+ //
+ // We also don't emit a definition for a function if it's going to be an
+ // entry
+ // in a vtable, unless it's already marked as used.
+ } else if (getLangOpts().CPlusPlus && D) {
+ // Look for a declaration that's lexically in a record.
+ const auto *FD = cast<FunctionDecl>(D);
+ FD = FD->getMostRecentDecl();
+ do {
+ if (isa<CXXRecordDecl>(FD->getLexicalDeclContext())) {
+ if (FD->isImplicit() && !ForVTable) {
+ assert(FD->isUsed() &&
+ "Sema didn't mark implicit function as used!");
+ addDeferredDeclToEmit(F, GD.getWithDecl(FD));
+ break;
+ } else if (FD->doesThisDeclarationHaveABody()) {
+ addDeferredDeclToEmit(F, GD.getWithDecl(FD));
+ break;
+ }
}
- }
- FD = FD->getPreviousDecl();
- } while (FD);
+ FD = FD->getPreviousDecl();
+ } while (FD);
+ }
}
// Make sure the result is of the requested type.
@@ -1494,13 +1548,14 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
/// create it (this occurs when we see a definition of the function).
llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD,
llvm::Type *Ty,
- bool ForVTable) {
+ bool ForVTable,
+ bool DontDefer) {
// If there was no specific requested type, just convert it now.
if (!Ty)
Ty = getTypes().ConvertType(cast<ValueDecl>(GD.getDecl())->getType());
StringRef MangledName = getMangledName(GD);
- return GetOrCreateLLVMFunction(MangledName, Ty, GD, ForVTable);
+ return GetOrCreateLLVMFunction(MangledName, Ty, GD, ForVTable, DontDefer);
}
/// CreateRuntimeFunction - Create a new runtime function with the specified
@@ -1509,10 +1564,10 @@ llvm::Constant *
CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy,
StringRef Name,
llvm::AttributeSet ExtraAttrs) {
- llvm::Constant *C
- = GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
- ExtraAttrs);
- if (llvm::Function *F = dyn_cast<llvm::Function>(C))
+ llvm::Constant *C =
+ GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
+ /*DontDefer=*/false, ExtraAttrs);
+ if (auto *F = dyn_cast<llvm::Function>(C))
if (F->empty())
F->setCallingConv(getRuntimeCC());
return C;
@@ -1548,8 +1603,7 @@ bool CodeGenModule::isTypeConstant(QualType Ty, bool ExcludeCtor) {
llvm::Constant *
CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
llvm::PointerType *Ty,
- const VarDecl *D,
- bool UnnamedAddr) {
+ const VarDecl *D) {
// Lookup the entry, lazily creating it if necessary.
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
@@ -1558,9 +1612,6 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
Entry->setLinkage(llvm::Function::ExternalLinkage);
}
- if (UnnamedAddr)
- Entry->setUnnamedAddr(true);
-
if (Entry->getType() == Ty)
return Entry;
@@ -1571,44 +1622,30 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
return llvm::ConstantExpr::getBitCast(Entry, Ty);
}
+ unsigned AddrSpace = GetGlobalVarAddressSpace(D, Ty->getAddressSpace());
+ auto *GV = new llvm::GlobalVariable(
+ getModule(), Ty->getElementType(), false,
+ llvm::GlobalValue::ExternalLinkage, nullptr, MangledName, nullptr,
+ llvm::GlobalVariable::NotThreadLocal, AddrSpace);
+
// This is the first use or definition of a mangled name. If there is a
// deferred decl with this name, remember that we need to emit it at the end
// of the file.
- llvm::StringMap<GlobalDecl>::iterator DDI = DeferredDecls.find(MangledName);
+ auto DDI = DeferredDecls.find(MangledName);
if (DDI != DeferredDecls.end()) {
// Move the potentially referenced deferred decl to the DeferredDeclsToEmit
// list, and remove it from DeferredDecls (since we don't need it anymore).
- DeferredDeclsToEmit.push_back(DDI->second);
+ addDeferredDeclToEmit(GV, DDI->second);
DeferredDecls.erase(DDI);
}
- unsigned AddrSpace = GetGlobalVarAddressSpace(D, Ty->getAddressSpace());
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(getModule(), Ty->getElementType(), false,
- llvm::GlobalValue::ExternalLinkage,
- 0, MangledName, 0,
- llvm::GlobalVariable::NotThreadLocal, AddrSpace);
-
// Handle things which are present even on external declarations.
if (D) {
// FIXME: This code is overly simple and should be merged with other global
// handling.
GV->setConstant(isTypeConstant(D->getType(), false));
- // Set linkage and visibility in case we never see a definition.
- LinkageInfo LV = D->getLinkageAndVisibility();
- if (LV.getLinkage() != ExternalLinkage) {
- // Don't set internal linkage on declarations.
- } else {
- if (D->hasAttr<DLLImportAttr>())
- GV->setLinkage(llvm::GlobalValue::DLLImportLinkage);
- else if (D->hasAttr<WeakAttr>() || D->isWeakImported())
- GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
-
- // Set visibility on a declaration only if it's explicit.
- if (LV.isVisibilityExplicit())
- GV->setVisibility(GetLLVMVisibility(LV.getVisibility()));
- }
+ setLinkageAndVisibilityForGV(GV, D);
if (D->getTLSKind()) {
if (D->getTLSKind() == VarDecl::TLS_Dynamic)
@@ -1618,10 +1655,16 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
// If required by the ABI, treat declarations of static data members with
// inline initializers as definitions.
- if (getCXXABI().isInlineInitializedStaticDataMemberLinkOnce() &&
- D->isStaticDataMember() && D->hasInit() &&
- !D->isThisDeclarationADefinition())
+ if (getContext().isMSStaticDataMemberInlineDefinition(D)) {
EmitGlobalVarDefinition(D);
+ }
+
+ // Handle XCore specific ABI requirements.
+ if (getTarget().getTriple().getArch() == llvm::Triple::xcore &&
+ D->getLanguageLinkage() == CLanguageLinkage &&
+ D->getType().isConstant(Context) &&
+ isExternallyVisible(D->getLinkageAndVisibility().getLinkage()))
+ GV->setSection(".cp.rodata");
}
if (AddrSpace != Ty->getAddressSpace())
@@ -1636,9 +1679,8 @@ CodeGenModule::CreateOrReplaceCXXRuntimeVariable(StringRef Name,
llvm::Type *Ty,
llvm::GlobalValue::LinkageTypes Linkage) {
llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name);
- llvm::GlobalVariable *OldGV = 0;
+ llvm::GlobalVariable *OldGV = nullptr;
-
if (GV) {
// Check if the variable has the right type.
if (GV->getType()->getElementType() == Ty)
@@ -1652,8 +1694,8 @@ CodeGenModule::CreateOrReplaceCXXRuntimeVariable(StringRef Name,
// Create a new variable.
GV = new llvm::GlobalVariable(getModule(), Ty, /*isConstant=*/true,
- Linkage, 0, Name);
-
+ Linkage, nullptr, Name);
+
if (OldGV) {
// Replace occurrences of the old variable if needed.
GV->takeName(OldGV);
@@ -1678,7 +1720,7 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D,
llvm::Type *Ty) {
assert(D->hasGlobalStorage() && "Not a global variable");
QualType ASTTy = D->getType();
- if (Ty == 0)
+ if (!Ty)
Ty = getTypes().ConvertTypeForMem(ASTTy);
llvm::PointerType *PTy =
@@ -1693,8 +1735,7 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D,
llvm::Constant *
CodeGenModule::CreateRuntimeVariable(llvm::Type *Ty,
StringRef Name) {
- return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), 0,
- true);
+ return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), nullptr);
}
void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
@@ -1764,11 +1805,11 @@ void CodeGenModule::MaybeHandleStaticInExternC(const SomeDecl *D,
// If we have multiple internal linkage entities with the same name
// in extern "C" regions, none of them gets that name.
if (!R.second)
- R.first->second = 0;
+ R.first->second = nullptr;
}
void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
- llvm::Constant *Init = 0;
+ llvm::Constant *Init = nullptr;
QualType ASTTy = D->getType();
CXXRecordDecl *RD = ASTTy->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
bool NeedsGlobalCtor = false;
@@ -1818,7 +1859,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
llvm::Constant *Entry = GetAddrOfGlobalVar(D, InitType);
// Strip off a bitcast if we got one back.
- if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(Entry)) {
+ if (auto *CE = dyn_cast<llvm::ConstantExpr>(Entry)) {
assert(CE->getOpcode() == llvm::Instruction::BitCast ||
CE->getOpcode() == llvm::Instruction::AddrSpaceCast ||
// All zero index gep.
@@ -1827,7 +1868,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
}
// Entry is now either a Function or GlobalVariable.
- llvm::GlobalVariable *GV = dyn_cast<llvm::GlobalVariable>(Entry);
+ auto *GV = dyn_cast<llvm::GlobalVariable>(Entry);
// We have a definition after a declaration with the wrong type.
// We must make a new GlobalVariable* and update everything that used OldGV
@@ -1838,7 +1879,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
// "extern int x[];") and then a definition of a different type (e.g.
// "int x[10];"). This also happens when an initializer has a different type
// from the type of the global (this happens with unions).
- if (GV == 0 ||
+ if (!GV ||
GV->getType()->getElementType() != InitType ||
GV->getType()->getAddressSpace() !=
GetGlobalVarAddressSpace(D, getContext().getTargetAddressSpace(ASTTy))) {
@@ -1872,38 +1913,35 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
GV->setAlignment(getContext().getDeclAlign(D).getQuantity());
// Set the llvm linkage type as appropriate.
- llvm::GlobalValue::LinkageTypes Linkage =
- GetLLVMLinkageVarDefinition(D, GV->isConstant());
- GV->setLinkage(Linkage);
+ llvm::GlobalValue::LinkageTypes Linkage =
+ getLLVMLinkageVarDefinition(D, GV->isConstant());
+
+ // On Darwin, the backing variable for a C++11 thread_local variable always
+ // has internal linkage; all accesses should just be calls to the
+ // Itanium-specified entry point, which has the normal linkage of the
+ // variable.
+ if (const auto *VD = dyn_cast<VarDecl>(D))
+ if (!VD->isStaticLocal() && VD->getTLSKind() == VarDecl::TLS_Dynamic &&
+ Context.getTargetInfo().getTriple().isMacOSX())
+ Linkage = llvm::GlobalValue::InternalLinkage;
- // If required by the ABI, give definitions of static data members with inline
- // initializers linkonce_odr linkage.
- if (getCXXABI().isInlineInitializedStaticDataMemberLinkOnce() &&
- D->isStaticDataMember() && InitExpr &&
- !InitDecl->isThisDeclarationADefinition())
- GV->setLinkage(llvm::GlobalVariable::LinkOnceODRLinkage);
+ GV->setLinkage(Linkage);
+ if (D->hasAttr<DLLImportAttr>())
+ GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass);
+ else if (D->hasAttr<DLLExportAttr>())
+ GV->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass);
if (Linkage == llvm::GlobalVariable::CommonLinkage)
// common vars aren't constant even if declared const.
GV->setConstant(false);
- SetCommonAttributes(D, GV);
+ setNonAliasAttributes(D, GV);
// Emit the initializer function if necessary.
if (NeedsGlobalCtor || NeedsGlobalDtor)
EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor);
- // If we are compiling with ASan, add metadata indicating dynamically
- // initialized globals.
- if (SanOpts.Address && NeedsGlobalCtor) {
- llvm::Module &M = getModule();
-
- llvm::NamedMDNode *DynamicInitializers =
- M.getOrInsertNamedMetadata("llvm.asan.dynamically_initialized_globals");
- llvm::Value *GlobalToAdd[] = { GV };
- llvm::MDNode *ThisGlobal = llvm::MDNode::get(VMContext, GlobalToAdd);
- DynamicInitializers->addOperand(ThisGlobal);
- }
+ reportGlobalToASan(GV, *D, NeedsGlobalCtor);
// Emit global variable debug information.
if (CGDebugInfo *DI = getModuleDebugInfo())
@@ -1911,47 +1949,164 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
DI->EmitGlobalVariable(GV, D);
}
-llvm::GlobalValue::LinkageTypes
-CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D, bool isConstant) {
- GVALinkage Linkage = getContext().GetGVALinkageForVariable(D);
+void CodeGenModule::reportGlobalToASan(llvm::GlobalVariable *GV,
+ SourceLocation Loc, StringRef Name,
+ bool IsDynInit, bool IsBlacklisted) {
+ if (!LangOpts.Sanitize.Address)
+ return;
+ IsDynInit &= !SanitizerBL.isIn(*GV, "init");
+ IsBlacklisted |= SanitizerBL.isIn(*GV);
+
+ llvm::GlobalVariable *LocDescr = nullptr;
+ llvm::GlobalVariable *GlobalName = nullptr;
+ if (!IsBlacklisted) {
+ // Don't generate source location and global name if it is blacklisted -
+ // it won't be instrumented anyway.
+ PresumedLoc PLoc = Context.getSourceManager().getPresumedLoc(Loc);
+ if (PLoc.isValid()) {
+ llvm::Constant *LocData[] = {
+ GetAddrOfConstantCString(PLoc.getFilename()),
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+ PLoc.getLine()),
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+ PLoc.getColumn()),
+ };
+ auto LocStruct = llvm::ConstantStruct::getAnon(LocData);
+ LocDescr = new llvm::GlobalVariable(TheModule, LocStruct->getType(), true,
+ llvm::GlobalValue::PrivateLinkage,
+ LocStruct, ".asan_loc_descr");
+ LocDescr->setUnnamedAddr(true);
+ // Add LocDescr to llvm.compiler.used, so that it won't be removed by
+ // the optimizer before the ASan instrumentation pass.
+ addCompilerUsedGlobal(LocDescr);
+ }
+ if (!Name.empty()) {
+ GlobalName = GetAddrOfConstantCString(Name);
+ // GlobalName shouldn't be removed by the optimizer.
+ addCompilerUsedGlobal(GlobalName);
+ }
+ }
+
+ llvm::Value *GlobalMetadata[] = {
+ GV, LocDescr, GlobalName,
+ llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsDynInit),
+ llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsBlacklisted)};
+
+ llvm::MDNode *ThisGlobal = llvm::MDNode::get(VMContext, GlobalMetadata);
+ llvm::NamedMDNode *AsanGlobals =
+ TheModule.getOrInsertNamedMetadata("llvm.asan.globals");
+ AsanGlobals->addOperand(ThisGlobal);
+}
+
+void CodeGenModule::reportGlobalToASan(llvm::GlobalVariable *GV,
+ const VarDecl &D, bool IsDynInit) {
+ if (!LangOpts.Sanitize.Address)
+ return;
+ std::string QualName;
+ llvm::raw_string_ostream OS(QualName);
+ D.printQualifiedName(OS);
+ reportGlobalToASan(GV, D.getLocation(), OS.str(), IsDynInit);
+}
+
+void CodeGenModule::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {
+ // For now, just make sure the global is not modified by the ASan
+ // instrumentation.
+ if (LangOpts.Sanitize.Address)
+ reportGlobalToASan(GV, SourceLocation(), "", false, true);
+}
+
+static bool isVarDeclStrongDefinition(const VarDecl *D, bool NoCommon) {
+ // Don't give variables common linkage if -fno-common was specified unless it
+ // was overridden by a NoCommon attribute.
+ if ((NoCommon || D->hasAttr<NoCommonAttr>()) && !D->hasAttr<CommonAttr>())
+ return true;
+
+ // C11 6.9.2/2:
+ // A declaration of an identifier for an object that has file scope without
+ // an initializer, and without a storage-class specifier or with the
+ // storage-class specifier static, constitutes a tentative definition.
+ if (D->getInit() || D->hasExternalStorage())
+ return true;
+
+ // A variable cannot be both common and exist in a section.
+ if (D->hasAttr<SectionAttr>())
+ return true;
+
+ // Thread local vars aren't considered common linkage.
+ if (D->getTLSKind())
+ return true;
+
+ // Tentative definitions marked with WeakImportAttr are true definitions.
+ if (D->hasAttr<WeakImportAttr>())
+ return true;
+
+ return false;
+}
+
+llvm::GlobalValue::LinkageTypes CodeGenModule::getLLVMLinkageForDeclarator(
+ const DeclaratorDecl *D, GVALinkage Linkage, bool IsConstantVariable) {
if (Linkage == GVA_Internal)
return llvm::Function::InternalLinkage;
- else if (D->hasAttr<DLLImportAttr>())
- return llvm::Function::DLLImportLinkage;
- else if (D->hasAttr<DLLExportAttr>())
- return llvm::Function::DLLExportLinkage;
- else if (D->hasAttr<SelectAnyAttr>()) {
- // selectany symbols are externally visible, so use weak instead of
- // linkonce. MSVC optimizes away references to const selectany globals, so
- // all definitions should be the same and ODR linkage should be used.
- // http://msdn.microsoft.com/en-us/library/5tkz6s71.aspx
- return llvm::GlobalVariable::WeakODRLinkage;
- } else if (D->hasAttr<WeakAttr>()) {
- if (isConstant)
+
+ if (D->hasAttr<WeakAttr>()) {
+ if (IsConstantVariable)
return llvm::GlobalVariable::WeakODRLinkage;
else
return llvm::GlobalVariable::WeakAnyLinkage;
- } else if (Linkage == GVA_TemplateInstantiation ||
- Linkage == GVA_ExplicitTemplateInstantiation)
- return llvm::GlobalVariable::WeakODRLinkage;
- else if (!getLangOpts().CPlusPlus &&
- ((!CodeGenOpts.NoCommon && !D->getAttr<NoCommonAttr>()) ||
- D->getAttr<CommonAttr>()) &&
- !D->hasExternalStorage() && !D->getInit() &&
- !D->getAttr<SectionAttr>() && !D->getTLSKind() &&
- !D->getAttr<WeakImportAttr>()) {
- // Thread local vars aren't considered common linkage.
+ }
+
+ // We are guaranteed to have a strong definition somewhere else,
+ // so we can use available_externally linkage.
+ if (Linkage == GVA_AvailableExternally)
+ return llvm::Function::AvailableExternallyLinkage;
+
+ // Note that Apple's kernel linker doesn't support symbol
+ // coalescing, so we need to avoid linkonce and weak linkages there.
+ // Normally, this means we just map to internal, but for explicit
+ // instantiations we'll map to external.
+
+ // In C++, the compiler has to emit a definition in every translation unit
+ // that references the function. We should use linkonce_odr because
+ // a) if all references in this translation unit are optimized away, we
+ // don't need to codegen it. b) if the function persists, it needs to be
+ // merged with other definitions. c) C++ has the ODR, so we know the
+ // definition is dependable.
+ if (Linkage == GVA_DiscardableODR)
+ return !Context.getLangOpts().AppleKext ? llvm::Function::LinkOnceODRLinkage
+ : llvm::Function::InternalLinkage;
+
+ // An explicit instantiation of a template has weak linkage, since
+ // explicit instantiations can occur in multiple translation units
+ // and must all be equivalent. However, we are not allowed to
+ // throw away these explicit instantiations.
+ if (Linkage == GVA_StrongODR)
+ return !Context.getLangOpts().AppleKext ? llvm::Function::WeakODRLinkage
+ : llvm::Function::ExternalLinkage;
+
+ // C++ doesn't have tentative definitions and thus cannot have common
+ // linkage.
+ if (!getLangOpts().CPlusPlus && isa<VarDecl>(D) &&
+ !isVarDeclStrongDefinition(cast<VarDecl>(D), CodeGenOpts.NoCommon))
return llvm::GlobalVariable::CommonLinkage;
- } else if (D->getTLSKind() == VarDecl::TLS_Dynamic &&
- getTarget().getTriple().isMacOSX())
- // On Darwin, the backing variable for a C++11 thread_local variable always
- // has internal linkage; all accesses should just be calls to the
- // Itanium-specified entry point, which has the normal linkage of the
- // variable.
- return llvm::GlobalValue::InternalLinkage;
+
+ // selectany symbols are externally visible, so use weak instead of
+ // linkonce. MSVC optimizes away references to const selectany globals, so
+ // all definitions should be the same and ODR linkage should be used.
+ // http://msdn.microsoft.com/en-us/library/5tkz6s71.aspx
+ if (D->hasAttr<SelectAnyAttr>())
+ return llvm::GlobalVariable::WeakODRLinkage;
+
+ // Otherwise, we have strong external linkage.
+ assert(Linkage == GVA_StrongExternal);
return llvm::GlobalVariable::ExternalLinkage;
}
+llvm::GlobalValue::LinkageTypes CodeGenModule::getLLVMLinkageVarDefinition(
+ const VarDecl *VD, bool IsConstant) {
+ GVALinkage Linkage = getContext().GetGVALinkageForVariable(VD);
+ return getLLVMLinkageForDeclarator(VD, Linkage, IsConstant);
+}
+
/// Replace the uses of a function that was declared with a non-proto type.
/// We want to silently drop extra arguments from call sites
static void replaceUsesOfNonProtoConstant(llvm::Constant *old,
@@ -1965,11 +2120,11 @@ static void replaceUsesOfNonProtoConstant(llvm::Constant *old,
for (llvm::Value::use_iterator ui = old->use_begin(), ue = old->use_end();
ui != ue; ) {
llvm::Value::use_iterator use = ui++; // Increment before the use is erased.
- llvm::User *user = *use;
+ llvm::User *user = use->getUser();
// Recognize and replace uses of bitcasts. Most calls to
// unprototyped functions will use bitcasts.
- if (llvm::ConstantExpr *bitcast = dyn_cast<llvm::ConstantExpr>(user)) {
+ if (auto *bitcast = dyn_cast<llvm::ConstantExpr>(user)) {
if (bitcast->getOpcode() == llvm::Instruction::BitCast)
replaceUsesOfNonProtoConstant(bitcast, newFn);
continue;
@@ -1978,7 +2133,7 @@ static void replaceUsesOfNonProtoConstant(llvm::Constant *old,
// Recognize calls to the function.
llvm::CallSite callSite(user);
if (!callSite) continue;
- if (!callSite.isCallee(use)) continue;
+ if (!callSite.isCallee(&*use)) continue;
// If the return types don't match exactly, then we can't
// transform this call unless it's dead.
@@ -2033,8 +2188,7 @@ static void replaceUsesOfNonProtoConstant(llvm::Constant *old,
newCall = llvm::CallInst::Create(newFn, newArgs, "",
callSite.getInstruction());
} else {
- llvm::InvokeInst *oldInvoke =
- cast<llvm::InvokeInst>(callSite.getInstruction());
+ auto *oldInvoke = cast<llvm::InvokeInst>(callSite.getInstruction());
newCall = llvm::InvokeInst::Create(newFn,
oldInvoke->getNormalDest(),
oldInvoke->getUnwindDest(),
@@ -2087,33 +2241,36 @@ void CodeGenModule::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
EmitTopLevelDecl(VD);
}
-void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
- const FunctionDecl *D = cast<FunctionDecl>(GD.getDecl());
+void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
+ llvm::GlobalValue *GV) {
+ const auto *D = cast<FunctionDecl>(GD.getDecl());
// Compute the function info and LLVM type.
const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD);
llvm::FunctionType *Ty = getTypes().GetFunctionType(FI);
// Get or create the prototype for the function.
- llvm::Constant *Entry = GetAddrOfFunction(GD, Ty);
-
- // Strip off a bitcast if we got one back.
- if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(Entry)) {
- assert(CE->getOpcode() == llvm::Instruction::BitCast);
- Entry = CE->getOperand(0);
+ if (!GV) {
+ llvm::Constant *C =
+ GetAddrOfFunction(GD, Ty, /*ForVTable=*/false, /*DontDefer*/ true);
+
+ // Strip off a bitcast if we got one back.
+ if (auto *CE = dyn_cast<llvm::ConstantExpr>(C)) {
+ assert(CE->getOpcode() == llvm::Instruction::BitCast);
+ GV = cast<llvm::GlobalValue>(CE->getOperand(0));
+ } else {
+ GV = cast<llvm::GlobalValue>(C);
+ }
}
- if (!cast<llvm::GlobalValue>(Entry)->isDeclaration()) {
+ if (!GV->isDeclaration()) {
getDiags().Report(D->getLocation(), diag::err_duplicate_mangled_name);
return;
}
- if (cast<llvm::GlobalValue>(Entry)->getType()->getElementType() != Ty) {
- llvm::GlobalValue *OldFn = cast<llvm::GlobalValue>(Entry);
-
+ if (GV->getType()->getElementType() != Ty) {
// If the types mismatch then we have to rewrite the definition.
- assert(OldFn->isDeclaration() &&
- "Shouldn't replace non-declaration");
+ assert(GV->isDeclaration() && "Shouldn't replace non-declaration");
// F is the Function* for the one with the wrong type, we must make a new
// Function* and update everything that used F (a declaration) with the new
@@ -2123,8 +2280,8 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
// (e.g. "int f()") and then a definition of a different type
// (e.g. "int f(int x)"). Move the old function aside so that it
// doesn't interfere with GetAddrOfFunction.
- OldFn->setName(StringRef());
- llvm::Function *NewFn = cast<llvm::Function>(GetAddrOfFunction(GD, Ty));
+ GV->setName(StringRef());
+ auto *NewFn = cast<llvm::Function>(GetAddrOfFunction(GD, Ty));
// This might be an implementation of a function without a
// prototype, in which case, try to do special replacement of
@@ -2133,39 +2290,39 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
// so as to make a direct call, which makes the inliner happier
// and suppresses a number of optimizer warnings (!) about
// dropping arguments.
- if (!OldFn->use_empty()) {
- ReplaceUsesOfNonProtoTypeWithRealFunction(OldFn, NewFn);
- OldFn->removeDeadConstantUsers();
+ if (!GV->use_empty()) {
+ ReplaceUsesOfNonProtoTypeWithRealFunction(GV, NewFn);
+ GV->removeDeadConstantUsers();
}
// Replace uses of F with the Function we will endow with a body.
- if (!Entry->use_empty()) {
+ if (!GV->use_empty()) {
llvm::Constant *NewPtrForOldDecl =
- llvm::ConstantExpr::getBitCast(NewFn, Entry->getType());
- Entry->replaceAllUsesWith(NewPtrForOldDecl);
+ llvm::ConstantExpr::getBitCast(NewFn, GV->getType());
+ GV->replaceAllUsesWith(NewPtrForOldDecl);
}
// Ok, delete the old function now, which is dead.
- OldFn->eraseFromParent();
+ GV->eraseFromParent();
- Entry = NewFn;
+ GV = NewFn;
}
// We need to set linkage and visibility on the function before
// generating code for it because various parts of IR generation
// want to propagate this information down (e.g. to local static
// declarations).
- llvm::Function *Fn = cast<llvm::Function>(Entry);
+ auto *Fn = cast<llvm::Function>(GV);
setFunctionLinkage(GD, Fn);
- // FIXME: this is redundant with part of SetFunctionDefinitionAttributes
+ // FIXME: this is redundant with part of setFunctionDefinitionAttributes
setGlobalVisibility(Fn, D);
MaybeHandleStaticInExternC(D, Fn);
CodeGenFunction(*this).GenerateCode(D, Fn, FI);
- SetFunctionDefinitionAttributes(D, Fn);
+ setFunctionDefinitionAttributes(D, Fn);
SetLLVMFunctionAttributesForDefinition(D, Fn);
if (const ConstructorAttr *CA = D->getAttr<ConstructorAttr>())
@@ -2177,7 +2334,7 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
}
void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
- const ValueDecl *D = cast<ValueDecl>(GD.getDecl());
+ const auto *D = cast<ValueDecl>(GD.getDecl());
const AliasAttr *AA = D->getAttr<AliasAttr>();
assert(AA && "Not an alias?");
@@ -2201,15 +2358,20 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
/*ForVTable=*/false);
else
Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(),
- llvm::PointerType::getUnqual(DeclTy), 0);
+ llvm::PointerType::getUnqual(DeclTy),
+ nullptr);
// Create the new alias itself, but don't set a name yet.
- llvm::GlobalValue *GA =
- new llvm::GlobalAlias(Aliasee->getType(),
- llvm::Function::ExternalLinkage,
- "", Aliasee, &getModule());
+ auto *GA = llvm::GlobalAlias::create(
+ cast<llvm::PointerType>(Aliasee->getType())->getElementType(), 0,
+ llvm::Function::ExternalLinkage, "", Aliasee, &getModule());
if (Entry) {
+ if (GA->getAliasee() == Entry) {
+ Diags.Report(AA->getLocation(), diag::err_cyclic_alias);
+ return;
+ }
+
assert(Entry->isDeclaration());
// If there is a declaration in the module, then we had an extern followed
@@ -2232,12 +2394,12 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
// specialization of the attributes which may be set on a global
// variable/function.
if (D->hasAttr<DLLExportAttr>()) {
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
// The dllexport attribute is ignored for undefined symbols.
if (FD->hasBody())
- GA->setLinkage(llvm::Function::DLLExportLinkage);
+ GA->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
} else {
- GA->setLinkage(llvm::Function::DLLExportLinkage);
+ GA->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
}
} else if (D->hasAttr<WeakAttr>() ||
D->hasAttr<WeakRefAttr>() ||
@@ -2330,8 +2492,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
QualType CFTy = getContext().getCFConstantStringType();
- llvm::StructType *STy =
- cast<llvm::StructType>(getTypes().ConvertType(CFTy));
+ auto *STy = cast<llvm::StructType>(getTypes().ConvertType(CFTy));
llvm::Constant *Fields[4];
@@ -2344,7 +2505,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
llvm::ConstantInt::get(Ty, 0x07C8);
// String pointer.
- llvm::Constant *C = 0;
+ llvm::Constant *C = nullptr;
if (isUTF16) {
ArrayRef<uint16_t> Arr =
llvm::makeArrayRef<uint16_t>(reinterpret_cast<uint16_t*>(
@@ -2355,30 +2516,25 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
C = llvm::ConstantDataArray::getString(VMContext, Entry.getKey());
}
- llvm::GlobalValue::LinkageTypes Linkage;
- if (isUTF16)
- // FIXME: why do utf strings get "_" labels instead of "L" labels?
- Linkage = llvm::GlobalValue::InternalLinkage;
- else
- // FIXME: With OS X ld 123.2 (xcode 4) and LTO we would get a linker error
- // when using private linkage. It is not clear if this is a bug in ld
- // or a reasonable new restriction.
- Linkage = llvm::GlobalValue::LinkerPrivateLinkage;
-
// Note: -fwritable-strings doesn't make the backing store strings of
// CFStrings writable. (See <rdar://problem/10657500>)
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(getModule(), C->getType(), /*isConstant=*/true,
- Linkage, C, ".str");
+ auto *GV =
+ new llvm::GlobalVariable(getModule(), C->getType(), /*isConstant=*/true,
+ llvm::GlobalValue::PrivateLinkage, C, ".str");
GV->setUnnamedAddr(true);
// Don't enforce the target's minimum global alignment, since the only use
// of the string is via this class initializer.
+ // FIXME: We set the section explicitly to avoid a bug in ld64 224.1. Without
+ // it LLVM can merge the string with a non unnamed_addr one during LTO. Doing
+ // that changes the section it ends in, which surprises ld64.
if (isUTF16) {
CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy);
GV->setAlignment(Align.getQuantity());
+ GV->setSection("__TEXT,__ustring");
} else {
CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy);
GV->setAlignment(Align.getQuantity());
+ GV->setSection("__TEXT,__cstring,cstring_literals");
}
// String.
@@ -2397,23 +2553,12 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
GV = new llvm::GlobalVariable(getModule(), C->getType(), true,
llvm::GlobalVariable::PrivateLinkage, C,
"_unnamed_cfstring_");
- if (const char *Sect = getTarget().getCFStringSection())
- GV->setSection(Sect);
+ GV->setSection("__DATA,__cfstring");
Entry.setValue(GV);
return GV;
}
-static RecordDecl *
-CreateRecordDecl(const ASTContext &Ctx, RecordDecl::TagKind TK,
- DeclContext *DC, IdentifierInfo *Id) {
- SourceLocation Loc;
- if (Ctx.getLangOpts().CPlusPlus)
- return CXXRecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id);
- else
- return RecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id);
-}
-
llvm::Constant *
CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
unsigned StringLength = 0;
@@ -2456,9 +2601,7 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
if (!NSConstantStringType) {
// Construct the type for a constant NSString.
- RecordDecl *D = CreateRecordDecl(Context, TTK_Struct,
- Context.getTranslationUnitDecl(),
- &Context.Idents.get("__builtin_NSString"));
+ RecordDecl *D = Context.buildImplicitRecord("__builtin_NSString");
D->startDefinition();
QualType FieldTypes[3];
@@ -2474,9 +2617,9 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
for (unsigned i = 0; i < 3; ++i) {
FieldDecl *Field = FieldDecl::Create(Context, D,
SourceLocation(),
- SourceLocation(), 0,
- FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0,
+ SourceLocation(), nullptr,
+ FieldTypes[i], /*TInfo=*/nullptr,
+ /*BitWidth=*/nullptr,
/*Mutable=*/false,
ICIS_NoInit);
Field->setAccess(AS_public);
@@ -2501,10 +2644,9 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
bool isConstant;
Linkage = llvm::GlobalValue::PrivateLinkage;
isConstant = !LangOpts.WritableStrings;
-
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C,
- ".str");
+
+ auto *GV = new llvm::GlobalVariable(getModule(), C->getType(), isConstant,
+ Linkage, C, ".str");
GV->setUnnamedAddr(true);
// Don't enforce the target's minimum global alignment, since the only use
// of the string is via this class initializer.
@@ -2521,12 +2663,13 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
GV = new llvm::GlobalVariable(getModule(), C->getType(), true,
llvm::GlobalVariable::PrivateLinkage, C,
"_unnamed_nsstring_");
+ const char *NSStringSection = "__OBJC,__cstring_object,regular,no_dead_strip";
+ const char *NSStringNonFragileABISection =
+ "__DATA,__objc_stringobj,regular,no_dead_strip";
// FIXME. Fix section.
- if (const char *Sect =
- LangOpts.ObjCRuntime.isNonFragile()
- ? getTarget().getNSStringNonFragileABISection()
- : getTarget().getNSStringSection())
- GV->setSection(Sect);
+ GV->setSection(LangOpts.ObjCRuntime.isNonFragile()
+ ? NSStringNonFragileABISection
+ : NSStringSection);
Entry.setValue(GV);
return GV;
@@ -2534,9 +2677,7 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
QualType CodeGenModule::getObjCFastEnumerationStateType() {
if (ObjCFastEnumerationStateType.isNull()) {
- RecordDecl *D = CreateRecordDecl(Context, TTK_Struct,
- Context.getTranslationUnitDecl(),
- &Context.Idents.get("__objcFastEnumerationState"));
+ RecordDecl *D = Context.buildImplicitRecord("__objcFastEnumerationState");
D->startDefinition();
QualType FieldTypes[] = {
@@ -2551,9 +2692,9 @@ QualType CodeGenModule::getObjCFastEnumerationStateType() {
FieldDecl *Field = FieldDecl::Create(Context,
D,
SourceLocation(),
- SourceLocation(), 0,
- FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0,
+ SourceLocation(), nullptr,
+ FieldTypes[i], /*TInfo=*/nullptr,
+ /*BitWidth=*/nullptr,
/*Mutable=*/false,
ICIS_NoInit);
Field->setAccess(AS_public);
@@ -2581,9 +2722,8 @@ CodeGenModule::GetConstantArrayFromStringLiteral(const StringLiteral *E) {
Str.resize(CAT->getSize().getZExtValue());
return llvm::ConstantDataArray::getString(VMContext, Str, false);
}
-
- llvm::ArrayType *AType =
- cast<llvm::ArrayType>(getTypes().ConvertType(E->getType()));
+
+ auto *AType = cast<llvm::ArrayType>(getTypes().ConvertType(E->getType()));
llvm::Type *ElemTy = AType->getElementType();
unsigned NumElements = AType->getNumElements();
@@ -2608,36 +2748,73 @@ CodeGenModule::GetConstantArrayFromStringLiteral(const StringLiteral *E) {
return llvm::ConstantDataArray::get(VMContext, Elements);
}
+static llvm::GlobalVariable *
+GenerateStringLiteral(llvm::Constant *C, llvm::GlobalValue::LinkageTypes LT,
+ CodeGenModule &CGM, StringRef GlobalName,
+ unsigned Alignment) {
+ // OpenCL v1.2 s6.5.3: a string literal is in the constant address space.
+ unsigned AddrSpace = 0;
+ if (CGM.getLangOpts().OpenCL)
+ AddrSpace = CGM.getContext().getTargetAddressSpace(LangAS::opencl_constant);
+
+ // Create a global variable for this string
+ auto *GV = new llvm::GlobalVariable(
+ CGM.getModule(), C->getType(), !CGM.getLangOpts().WritableStrings, LT, C,
+ GlobalName, nullptr, llvm::GlobalVariable::NotThreadLocal, AddrSpace);
+ GV->setAlignment(Alignment);
+ GV->setUnnamedAddr(true);
+ return GV;
+}
+
/// GetAddrOfConstantStringFromLiteral - Return a pointer to a
/// constant array for the given string literal.
-llvm::Constant *
+llvm::GlobalVariable *
CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) {
- CharUnits Align = getContext().getAlignOfGlobalVarInChars(S->getType());
- if (S->isAscii() || S->isUTF8()) {
- SmallString<64> Str(S->getString());
-
- // Resize the string to the right size, which is indicated by its type.
- const ConstantArrayType *CAT = Context.getAsConstantArrayType(S->getType());
- Str.resize(CAT->getSize().getZExtValue());
- return GetAddrOfConstantString(Str, /*GlobalName*/ 0, Align.getQuantity());
- }
+ auto Alignment =
+ getContext().getAlignOfGlobalVarInChars(S->getType()).getQuantity();
- // FIXME: the following does not memoize wide strings.
llvm::Constant *C = GetConstantArrayFromStringLiteral(S);
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(getModule(),C->getType(),
- !LangOpts.WritableStrings,
- llvm::GlobalValue::PrivateLinkage,
- C,".str");
+ llvm::GlobalVariable **Entry = nullptr;
+ if (!LangOpts.WritableStrings) {
+ Entry = &ConstantStringMap[C];
+ if (auto GV = *Entry) {
+ if (Alignment > GV->getAlignment())
+ GV->setAlignment(Alignment);
+ return GV;
+ }
+ }
- GV->setAlignment(Align.getQuantity());
- GV->setUnnamedAddr(true);
+ SmallString<256> MangledNameBuffer;
+ StringRef GlobalVariableName;
+ llvm::GlobalValue::LinkageTypes LT;
+
+ // Mangle the string literal if the ABI allows for it. However, we cannot
+ // do this if we are compiling with ASan or -fwritable-strings because they
+ // rely on strings having normal linkage.
+ if (!LangOpts.WritableStrings && !LangOpts.Sanitize.Address &&
+ getCXXABI().getMangleContext().shouldMangleStringLiteral(S)) {
+ llvm::raw_svector_ostream Out(MangledNameBuffer);
+ getCXXABI().getMangleContext().mangleStringLiteral(S, Out);
+ Out.flush();
+
+ LT = llvm::GlobalValue::LinkOnceODRLinkage;
+ GlobalVariableName = MangledNameBuffer;
+ } else {
+ LT = llvm::GlobalValue::PrivateLinkage;
+ GlobalVariableName = ".str";
+ }
+
+ auto GV = GenerateStringLiteral(C, LT, *this, GlobalVariableName, Alignment);
+ if (Entry)
+ *Entry = GV;
+
+ reportGlobalToASan(GV, S->getStrTokenLoc(0), "<string literal>");
return GV;
}
/// GetAddrOfConstantStringFromObjCEncode - Return a pointer to a constant
/// array for the given ObjCEncodeExpr node.
-llvm::Constant *
+llvm::GlobalVariable *
CodeGenModule::GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *E) {
std::string Str;
getContext().getObjCEncodingForType(E->getEncodedType(), Str);
@@ -2645,87 +2822,48 @@ CodeGenModule::GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *E) {
return GetAddrOfConstantCString(Str);
}
-
-/// GenerateWritableString -- Creates storage for a string literal.
-static llvm::GlobalVariable *GenerateStringLiteral(StringRef str,
- bool constant,
- CodeGenModule &CGM,
- const char *GlobalName,
- unsigned Alignment) {
- // Create Constant for this string literal. Don't add a '\0'.
- llvm::Constant *C =
- llvm::ConstantDataArray::getString(CGM.getLLVMContext(), str, false);
-
- // OpenCL v1.1 s6.5.3: a string literal is in the constant address space.
- unsigned AddrSpace = 0;
- if (CGM.getLangOpts().OpenCL)
- AddrSpace = CGM.getContext().getTargetAddressSpace(LangAS::opencl_constant);
-
- // Create a global variable for this string
- llvm::GlobalVariable *GV = new llvm::GlobalVariable(
- CGM.getModule(), C->getType(), constant,
- llvm::GlobalValue::PrivateLinkage, C, GlobalName, 0,
- llvm::GlobalVariable::NotThreadLocal, AddrSpace);
- GV->setAlignment(Alignment);
- GV->setUnnamedAddr(true);
- return GV;
-}
-
-/// GetAddrOfConstantString - Returns a pointer to a character array
-/// containing the literal. This contents are exactly that of the
-/// given string, i.e. it will not be null terminated automatically;
-/// see GetAddrOfConstantCString. Note that whether the result is
-/// actually a pointer to an LLVM constant depends on
-/// Feature.WriteableStrings.
-///
+/// GetAddrOfConstantCString - Returns a pointer to a character array containing
+/// the literal and a terminating '\0' character.
/// The result has pointer to array type.
-llvm::Constant *CodeGenModule::GetAddrOfConstantString(StringRef Str,
- const char *GlobalName,
- unsigned Alignment) {
- // Get the default prefix if a name wasn't specified.
- if (!GlobalName)
- GlobalName = ".str";
+llvm::GlobalVariable *CodeGenModule::GetAddrOfConstantCString(
+ const std::string &Str, const char *GlobalName, unsigned Alignment) {
+ StringRef StrWithNull(Str.c_str(), Str.size() + 1);
+ if (Alignment == 0) {
+ Alignment = getContext()
+ .getAlignOfGlobalVarInChars(getContext().CharTy)
+ .getQuantity();
+ }
- if (Alignment == 0)
- Alignment = getContext().getAlignOfGlobalVarInChars(getContext().CharTy)
- .getQuantity();
+ llvm::Constant *C =
+ llvm::ConstantDataArray::getString(getLLVMContext(), StrWithNull, false);
// Don't share any string literals if strings aren't constant.
- if (LangOpts.WritableStrings)
- return GenerateStringLiteral(Str, false, *this, GlobalName, Alignment);
-
- llvm::StringMapEntry<llvm::GlobalVariable *> &Entry =
- ConstantStringMap.GetOrCreateValue(Str);
-
- if (llvm::GlobalVariable *GV = Entry.getValue()) {
- if (Alignment > GV->getAlignment()) {
- GV->setAlignment(Alignment);
+ llvm::GlobalVariable **Entry = nullptr;
+ if (!LangOpts.WritableStrings) {
+ Entry = &ConstantStringMap[C];
+ if (auto GV = *Entry) {
+ if (Alignment > GV->getAlignment())
+ GV->setAlignment(Alignment);
+ return GV;
}
- return GV;
}
+ // Get the default prefix if a name wasn't specified.
+ if (!GlobalName)
+ GlobalName = ".str";
// Create a global variable for this.
- llvm::GlobalVariable *GV = GenerateStringLiteral(Str, true, *this, GlobalName,
- Alignment);
- Entry.setValue(GV);
+ auto GV = GenerateStringLiteral(C, llvm::GlobalValue::PrivateLinkage, *this,
+ GlobalName, Alignment);
+ if (Entry)
+ *Entry = GV;
return GV;
}
-/// GetAddrOfConstantCString - Returns a pointer to a character
-/// array containing the literal and a terminating '\0'
-/// character. The result has pointer to array type.
-llvm::Constant *CodeGenModule::GetAddrOfConstantCString(const std::string &Str,
- const char *GlobalName,
- unsigned Alignment) {
- StringRef StrWithNull(Str.c_str(), Str.size() + 1);
- return GetAddrOfConstantString(StrWithNull, GlobalName, Alignment);
-}
-
llvm::Constant *CodeGenModule::GetAddrOfGlobalTemporary(
const MaterializeTemporaryExpr *E, const Expr *Init) {
assert((E->getStorageDuration() == SD_Static ||
E->getStorageDuration() == SD_Thread) && "not a global temporary");
- const VarDecl *VD = cast<VarDecl>(E->getExtendingDecl());
+ const auto *VD = cast<VarDecl>(E->getExtendingDecl());
// If we're not materializing a subobject of the temporary, keep the
// cv-qualifiers from the type of the MaterializeTemporaryExpr.
@@ -2742,10 +2880,11 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalTemporary(
// we also need to make the temporaries externally-visible).
SmallString<256> Name;
llvm::raw_svector_ostream Out(Name);
- getCXXABI().getMangleContext().mangleReferenceTemporary(VD, Out);
+ getCXXABI().getMangleContext().mangleReferenceTemporary(
+ VD, E->getManglingNumber(), Out);
Out.flush();
- APValue *Value = 0;
+ APValue *Value = nullptr;
if (E->getStorageDuration() == SD_Static) {
// We might have a cached constant initializer for this temporary. Note
// that this might have a different value from the value computed by
@@ -2753,7 +2892,7 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalTemporary(
// modifies the temporary.
Value = getContext().getMaterializedTemporaryValue(E, false);
if (Value && Value->isUninit())
- Value = 0;
+ Value = nullptr;
}
// Try evaluating it now, it might have a constant initializer.
@@ -2762,12 +2901,12 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalTemporary(
!EvalResult.hasSideEffects())
Value = &EvalResult.Val;
- llvm::Constant *InitialValue = 0;
+ llvm::Constant *InitialValue = nullptr;
bool Constant = false;
llvm::Type *Type;
if (Value) {
// The temporary has a constant initializer, use it.
- InitialValue = EmitConstantValue(*Value, MaterializedType, 0);
+ InitialValue = EmitConstantValue(*Value, MaterializedType, nullptr);
Constant = isTypeConstant(MaterializedType, /*ExcludeCtor*/Value);
Type = InitialValue->getType();
} else {
@@ -2777,10 +2916,19 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalTemporary(
}
// Create a global variable for this lifetime-extended temporary.
- llvm::GlobalVariable *GV =
- new llvm::GlobalVariable(getModule(), Type, Constant,
- llvm::GlobalValue::PrivateLinkage,
- InitialValue, Name.c_str());
+ llvm::GlobalValue::LinkageTypes Linkage =
+ getLLVMLinkageVarDefinition(VD, Constant);
+ // There is no need for this temporary to have global linkage if the global
+ // variable has external linkage.
+ if (Linkage == llvm::GlobalVariable::ExternalLinkage)
+ Linkage = llvm::GlobalVariable::PrivateLinkage;
+ unsigned AddrSpace = GetGlobalVarAddressSpace(
+ VD, getContext().getTargetAddressSpace(MaterializedType));
+ auto *GV = new llvm::GlobalVariable(
+ getModule(), Type, Constant, Linkage, InitialValue, Name.c_str(),
+ /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal,
+ AddrSpace);
+ setGlobalVisibility(GV, VD);
GV->setAlignment(
getContext().getTypeAlignInChars(MaterializedType).getQuantity());
if (VD->getTLSKind())
@@ -2793,10 +2941,7 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalTemporary(
/// properties for an implementation.
void CodeGenModule::EmitObjCPropertyImplementations(const
ObjCImplementationDecl *D) {
- for (ObjCImplementationDecl::propimpl_iterator
- i = D->propimpl_begin(), e = D->propimpl_end(); i != e; ++i) {
- ObjCPropertyImplDecl *PID = *i;
-
+ for (const auto *PID : D->property_impls()) {
// Dynamic is just for type-checking.
if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
ObjCPropertyDecl *PD = PID->getPropertyDecl();
@@ -2836,7 +2981,7 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
Selector cxxSelector = getContext().Selectors.getSelector(0, &II);
ObjCMethodDecl *DTORMethod =
ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(),
- cxxSelector, getContext().VoidTy, 0, D,
+ cxxSelector, getContext().VoidTy, nullptr, D,
/*isInstance=*/true, /*isVariadic=*/false,
/*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true,
/*isDefined=*/false, ObjCMethodDecl::Required);
@@ -2857,8 +3002,8 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
D->getLocation(),
D->getLocation(),
cxxSelector,
- getContext().getObjCIdType(), 0,
- D, /*isInstance=*/true,
+ getContext().getObjCIdType(),
+ nullptr, D, /*isInstance=*/true,
/*isVariadic=*/false,
/*isPropertyAccessor=*/true,
/*isImplicitlyDeclared=*/true,
@@ -2871,13 +3016,12 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
/// EmitNamespace - Emit all declarations in a namespace.
void CodeGenModule::EmitNamespace(const NamespaceDecl *ND) {
- for (RecordDecl::decl_iterator I = ND->decls_begin(), E = ND->decls_end();
- I != E; ++I) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(*I))
+ for (auto *I : ND->decls()) {
+ if (const auto *VD = dyn_cast<VarDecl>(I))
if (VD->getTemplateSpecializationKind() != TSK_ExplicitSpecialization &&
VD->getTemplateSpecializationKind() != TSK_Undeclared)
continue;
- EmitTopLevelDecl(*I);
+ EmitTopLevelDecl(I);
}
}
@@ -2889,17 +3033,14 @@ void CodeGenModule::EmitLinkageSpec(const LinkageSpecDecl *LSD) {
return;
}
- for (RecordDecl::decl_iterator I = LSD->decls_begin(), E = LSD->decls_end();
- I != E; ++I) {
+ for (auto *I : LSD->decls()) {
// Meta-data for ObjC class includes references to implemented methods.
// Generate class's method definitions first.
- if (ObjCImplDecl *OID = dyn_cast<ObjCImplDecl>(*I)) {
- for (ObjCContainerDecl::method_iterator M = OID->meth_begin(),
- MEnd = OID->meth_end();
- M != MEnd; ++M)
- EmitTopLevelDecl(*M);
+ if (auto *OID = dyn_cast<ObjCImplDecl>(I)) {
+ for (auto *M : OID->methods())
+ EmitTopLevelDecl(M);
}
- EmitTopLevelDecl(*I);
+ EmitTopLevelDecl(I);
}
}
@@ -2940,7 +3081,6 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break;
// No code generation needed.
case Decl::UsingShadow:
- case Decl::Using:
case Decl::ClassTemplate:
case Decl::VarTemplate:
case Decl::VarTemplatePartialSpecialization:
@@ -2949,6 +3089,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::Block:
case Decl::Empty:
break;
+ case Decl::Using: // using X; [C++]
+ if (CGDebugInfo *DI = getModuleDebugInfo())
+ DI->EmitUsingDecl(cast<UsingDecl>(*D));
+ return;
case Decl::NamespaceAlias:
if (CGDebugInfo *DI = getModuleDebugInfo())
DI->EmitNamespaceAlias(cast<NamespaceAliasDecl>(*D));
@@ -2983,7 +3127,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break;
case Decl::ObjCProtocol: {
- ObjCProtocolDecl *Proto = cast<ObjCProtocolDecl>(D);
+ auto *Proto = cast<ObjCProtocolDecl>(D);
if (Proto->isThisDeclarationADefinition())
ObjCRuntime->GenerateProtocol(Proto);
break;
@@ -2996,7 +3140,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break;
case Decl::ObjCImplementation: {
- ObjCImplementationDecl *OMD = cast<ObjCImplementationDecl>(D);
+ auto *OMD = cast<ObjCImplementationDecl>(D);
EmitObjCPropertyImplementations(OMD);
EmitObjCIvarInitializations(OMD);
ObjCRuntime->GenerateClass(OMD);
@@ -3008,7 +3152,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break;
}
case Decl::ObjCMethod: {
- ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(D);
+ auto *OMD = cast<ObjCMethodDecl>(D);
// If this is not a prototype, emit the body.
if (OMD->getBody())
CodeGenFunction(*this).GenerateObjCMethod(OMD);
@@ -3023,7 +3167,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break;
case Decl::FileScopeAsm: {
- FileScopeAsmDecl *AD = cast<FileScopeAsmDecl>(D);
+ auto *AD = cast<FileScopeAsmDecl>(D);
StringRef AsmString = AD->getAsmString()->getString();
const std::string &S = getModule().getModuleInlineAsm();
@@ -3037,7 +3181,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
}
case Decl::Import: {
- ImportDecl *Import = cast<ImportDecl>(D);
+ auto *Import = cast<ImportDecl>(D);
// Ignore import declarations that come from imported modules.
if (clang::Module *Owner = Import->getOwningModule()) {
@@ -3048,7 +3192,14 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
ImportedModules.insert(Import->getImportedModule());
break;
- }
+ }
+
+ case Decl::ClassTemplateSpecialization: {
+ const auto *Spec = cast<ClassTemplateSpecializationDecl>(D);
+ if (DebugInfo &&
+ Spec->getSpecializationKind() == TSK_ExplicitInstantiationDefinition)
+ DebugInfo->completeTemplateDefinition(*Spec);
+ }
default:
// Make sure we handled everything we should, every other kind is a
@@ -3094,11 +3245,19 @@ void CodeGenModule::EmitStaticExternCAliases() {
IdentifierInfo *Name = I->first;
llvm::GlobalValue *Val = I->second;
if (Val && !getModule().getNamedValue(Name->getName()))
- AddUsedGlobal(new llvm::GlobalAlias(Val->getType(), Val->getLinkage(),
- Name->getName(), Val, &getModule()));
+ addUsedGlobal(llvm::GlobalAlias::create(Name->getName(), Val));
}
}
+bool CodeGenModule::lookupRepresentativeDecl(StringRef MangledName,
+ GlobalDecl &Result) const {
+ auto Res = Manglings.find(MangledName);
+ if (Res == Manglings.end())
+ return false;
+ Result = Res->getValue();
+ return true;
+}
+
/// Emits metadata nodes associating all the global values in the
/// current module with the Decls they came from. This is useful for
/// projects using IR gen as a subroutine.
@@ -3107,14 +3266,12 @@ void CodeGenModule::EmitStaticExternCAliases() {
/// with an llvm::GlobalValue, we create a global named metadata
/// with the name 'clang.global.decl.ptrs'.
void CodeGenModule::EmitDeclMetadata() {
- llvm::NamedMDNode *GlobalMetadata = 0;
+ llvm::NamedMDNode *GlobalMetadata = nullptr;
// StaticLocalDeclMap
- for (llvm::DenseMap<GlobalDecl,StringRef>::iterator
- I = MangledDeclNames.begin(), E = MangledDeclNames.end();
- I != E; ++I) {
- llvm::GlobalValue *Addr = getModule().getNamedValue(I->second);
- EmitGlobalDeclMetadata(*this, GlobalMetadata, I->first, Addr);
+ for (auto &I : MangledDeclNames) {
+ llvm::GlobalValue *Addr = getModule().getNamedValue(I.second);
+ EmitGlobalDeclMetadata(*this, GlobalMetadata, I.first, Addr);
}
}
@@ -3128,17 +3285,15 @@ void CodeGenFunction::EmitDeclMetadata() {
// Find the unique metadata ID for this name.
unsigned DeclPtrKind = Context.getMDKindID("clang.decl.ptr");
- llvm::NamedMDNode *GlobalMetadata = 0;
-
- for (llvm::DenseMap<const Decl*, llvm::Value*>::iterator
- I = LocalDeclMap.begin(), E = LocalDeclMap.end(); I != E; ++I) {
- const Decl *D = I->first;
- llvm::Value *Addr = I->second;
+ llvm::NamedMDNode *GlobalMetadata = nullptr;
- if (llvm::AllocaInst *Alloca = dyn_cast<llvm::AllocaInst>(Addr)) {
+ for (auto &I : LocalDeclMap) {
+ const Decl *D = I.first;
+ llvm::Value *Addr = I.second;
+ if (auto *Alloca = dyn_cast<llvm::AllocaInst>(Addr)) {
llvm::Value *DAddr = GetPointerConstant(getLLVMContext(), D);
Alloca->setMetadata(DeclPtrKind, llvm::MDNode::get(Context, DAddr));
- } else if (llvm::GlobalValue *GV = dyn_cast<llvm::GlobalValue>(Addr)) {
+ } else if (auto *GV = dyn_cast<llvm::GlobalValue>(Addr)) {
GlobalDecl GD = GlobalDecl(cast<VarDecl>(D));
EmitGlobalDeclMetadata(CGM, GlobalMetadata, GD, GV);
}
@@ -3157,6 +3312,14 @@ void CodeGenModule::EmitVersionIdentMetadata() {
IdentMetadata->addOperand(llvm::MDNode::get(Ctx, IdentNode));
}
+void CodeGenModule::EmitTargetMetadata() {
+ for (auto &I : MangledDeclNames) {
+ const Decl *D = I.first.getDecl()->getMostRecentDecl();
+ llvm::GlobalValue *GV = GetGlobalValue(I.second);
+ getTargetCodeGenInfo().emitTargetMD(D, GV, *this);
+ }
+}
+
void CodeGenModule::EmitCoverageFile() {
if (!getCodeGenOpts().CoverageFile.empty()) {
if (llvm::NamedMDNode *CUNode = TheModule.getNamedMetadata("llvm.dbg.cu")) {
@@ -3200,3 +3363,19 @@ llvm::Constant *CodeGenModule::EmitUuidofInitializer(StringRef Uuid,
return llvm::ConstantStruct::getAnon(Fields);
}
+
+llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
+ bool ForEH) {
+ // Return a bogus pointer if RTTI is disabled, unless it's for EH.
+ // FIXME: should we even be calling this method if RTTI is disabled
+ // and it's not for EH?
+ if (!ForEH && !getLangOpts().RTTI)
+ return llvm::Constant::getNullValue(Int8PtrTy);
+
+ if (ForEH && Ty->isObjCObjectPointerType() &&
+ LangOpts.ObjCRuntime.isGNUFamily())
+ return ObjCRuntime->GetEHType(Ty);
+
+ return getCXXABI().getAddrOfRTTIDescriptor(Ty);
+}
+
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index c16122405d43..9533a8dabb20 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -16,6 +16,7 @@
#include "CGVTables.h"
#include "CodeGenTypes.h"
+#include "SanitizerBlacklist.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -30,129 +31,124 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Module.h"
-#include "llvm/Support/ValueHandle.h"
-#include "llvm/Transforms/Utils/SpecialCaseList.h"
+#include "llvm/IR/ValueHandle.h"
namespace llvm {
- class Module;
- class Constant;
- class ConstantInt;
- class Function;
- class GlobalValue;
- class DataLayout;
- class FunctionType;
- class LLVMContext;
+class Module;
+class Constant;
+class ConstantInt;
+class Function;
+class GlobalValue;
+class DataLayout;
+class FunctionType;
+class LLVMContext;
+class IndexedInstrProfReader;
}
namespace clang {
- class TargetCodeGenInfo;
- class ASTContext;
- class AtomicType;
- class FunctionDecl;
- class IdentifierInfo;
- class ObjCMethodDecl;
- class ObjCImplementationDecl;
- class ObjCCategoryImplDecl;
- class ObjCProtocolDecl;
- class ObjCEncodeExpr;
- class BlockExpr;
- class CharUnits;
- class Decl;
- class Expr;
- class Stmt;
- class InitListExpr;
- class StringLiteral;
- class NamedDecl;
- class ValueDecl;
- class VarDecl;
- class LangOptions;
- class CodeGenOptions;
- class DiagnosticsEngine;
- class AnnotateAttr;
- class CXXDestructorDecl;
- class MangleBuffer;
- class Module;
+class TargetCodeGenInfo;
+class ASTContext;
+class AtomicType;
+class FunctionDecl;
+class IdentifierInfo;
+class ObjCMethodDecl;
+class ObjCImplementationDecl;
+class ObjCCategoryImplDecl;
+class ObjCProtocolDecl;
+class ObjCEncodeExpr;
+class BlockExpr;
+class CharUnits;
+class Decl;
+class Expr;
+class Stmt;
+class InitListExpr;
+class StringLiteral;
+class NamedDecl;
+class ValueDecl;
+class VarDecl;
+class LangOptions;
+class CodeGenOptions;
+class DiagnosticsEngine;
+class AnnotateAttr;
+class CXXDestructorDecl;
+class Module;
namespace CodeGen {
- class CallArgList;
- class CodeGenFunction;
- class CodeGenTBAA;
- class CGCXXABI;
- class CGDebugInfo;
- class CGObjCRuntime;
- class CGOpenCLRuntime;
- class CGCUDARuntime;
- class BlockFieldFlags;
- class FunctionArgList;
-
- struct OrderGlobalInits {
- unsigned int priority;
- unsigned int lex_order;
- OrderGlobalInits(unsigned int p, unsigned int l)
+class CallArgList;
+class CodeGenFunction;
+class CodeGenTBAA;
+class CGCXXABI;
+class CGDebugInfo;
+class CGObjCRuntime;
+class CGOpenCLRuntime;
+class CGOpenMPRuntime;
+class CGCUDARuntime;
+class BlockFieldFlags;
+class FunctionArgList;
+
+struct OrderGlobalInits {
+ unsigned int priority;
+ unsigned int lex_order;
+ OrderGlobalInits(unsigned int p, unsigned int l)
: priority(p), lex_order(l) {}
-
- bool operator==(const OrderGlobalInits &RHS) const {
- return priority == RHS.priority &&
- lex_order == RHS.lex_order;
- }
-
- bool operator<(const OrderGlobalInits &RHS) const {
- if (priority < RHS.priority)
- return true;
-
- return priority == RHS.priority && lex_order < RHS.lex_order;
- }
+
+ bool operator==(const OrderGlobalInits &RHS) const {
+ return priority == RHS.priority && lex_order == RHS.lex_order;
+ }
+
+ bool operator<(const OrderGlobalInits &RHS) const {
+ return std::tie(priority, lex_order) <
+ std::tie(RHS.priority, RHS.lex_order);
+ }
+};
+
+struct CodeGenTypeCache {
+ /// void
+ llvm::Type *VoidTy;
+
+ /// i8, i16, i32, and i64
+ llvm::IntegerType *Int8Ty, *Int16Ty, *Int32Ty, *Int64Ty;
+ /// float, double
+ llvm::Type *FloatTy, *DoubleTy;
+
+ /// int
+ llvm::IntegerType *IntTy;
+
+ /// intptr_t, size_t, and ptrdiff_t, which we assume are the same size.
+ union {
+ llvm::IntegerType *IntPtrTy;
+ llvm::IntegerType *SizeTy;
+ llvm::IntegerType *PtrDiffTy;
};
- struct CodeGenTypeCache {
- /// void
- llvm::Type *VoidTy;
-
- /// i8, i16, i32, and i64
- llvm::IntegerType *Int8Ty, *Int16Ty, *Int32Ty, *Int64Ty;
- /// float, double
- llvm::Type *FloatTy, *DoubleTy;
-
- /// int
- llvm::IntegerType *IntTy;
-
- /// intptr_t, size_t, and ptrdiff_t, which we assume are the same size.
- union {
- llvm::IntegerType *IntPtrTy;
- llvm::IntegerType *SizeTy;
- llvm::IntegerType *PtrDiffTy;
- };
-
- /// void* in address space 0
- union {
- llvm::PointerType *VoidPtrTy;
- llvm::PointerType *Int8PtrTy;
- };
-
- /// void** in address space 0
- union {
- llvm::PointerType *VoidPtrPtrTy;
- llvm::PointerType *Int8PtrPtrTy;
- };
-
- /// The width of a pointer into the generic address space.
- unsigned char PointerWidthInBits;
-
- /// The size and alignment of a pointer into the generic address
- /// space.
- union {
- unsigned char PointerAlignInBytes;
- unsigned char PointerSizeInBytes;
- unsigned char SizeSizeInBytes; // sizeof(size_t)
- };
-
- llvm::CallingConv::ID RuntimeCC;
- llvm::CallingConv::ID getRuntimeCC() const {
- return RuntimeCC;
- }
+ /// void* in address space 0
+ union {
+ llvm::PointerType *VoidPtrTy;
+ llvm::PointerType *Int8PtrTy;
};
+ /// void** in address space 0
+ union {
+ llvm::PointerType *VoidPtrPtrTy;
+ llvm::PointerType *Int8PtrPtrTy;
+ };
+
+ /// The width of a pointer into the generic address space.
+ unsigned char PointerWidthInBits;
+
+ /// The size and alignment of a pointer into the generic address
+ /// space.
+ union {
+ unsigned char PointerAlignInBytes;
+ unsigned char PointerSizeInBytes;
+ unsigned char SizeSizeInBytes; // sizeof(size_t)
+ };
+
+ llvm::CallingConv::ID RuntimeCC;
+ llvm::CallingConv::ID getRuntimeCC() const { return RuntimeCC; }
+};
+
struct RREntrypoints {
RREntrypoints() { memset(this, 0, sizeof(*this)); }
/// void objc_autoreleasePoolPop(void*);
@@ -221,13 +217,57 @@ struct ARCEntrypoints {
llvm::Constant *clang_arc_use;
};
-/// CodeGenModule - This class organizes the cross-function state that is used
-/// while generating LLVM code.
+/// This class records statistics on instrumentation based profiling.
+class InstrProfStats {
+ uint32_t VisitedInMainFile;
+ uint32_t MissingInMainFile;
+ uint32_t Visited;
+ uint32_t Missing;
+ uint32_t Mismatched;
+
+public:
+ InstrProfStats()
+ : VisitedInMainFile(0), MissingInMainFile(0), Visited(0), Missing(0),
+ Mismatched(0) {}
+ /// Record that we've visited a function and whether or not that function was
+ /// in the main source file.
+ void addVisited(bool MainFile) {
+ if (MainFile)
+ ++VisitedInMainFile;
+ ++Visited;
+ }
+ /// Record that a function we've visited has no profile data.
+ void addMissing(bool MainFile) {
+ if (MainFile)
+ ++MissingInMainFile;
+ ++Missing;
+ }
+ /// Record that a function we've visited has mismatched profile data.
+ void addMismatched(bool MainFile) { ++Mismatched; }
+ /// Whether or not the stats we've gathered indicate any potential problems.
+ bool hasDiagnostics() { return Missing || Mismatched; }
+ /// Report potential problems we've found to \c Diags.
+ void reportDiagnostics(DiagnosticsEngine &Diags, StringRef MainFile);
+};
+
+/// This class organizes the cross-function state that is used while generating
+/// LLVM code.
class CodeGenModule : public CodeGenTypeCache {
CodeGenModule(const CodeGenModule &) LLVM_DELETED_FUNCTION;
void operator=(const CodeGenModule &) LLVM_DELETED_FUNCTION;
- typedef std::vector<std::pair<llvm::Constant*, int> > CtorList;
+ struct Structor {
+ Structor() : Priority(0), Initializer(nullptr), AssociatedData(nullptr) {}
+ Structor(int Priority, llvm::Constant *Initializer,
+ llvm::Constant *AssociatedData)
+ : Priority(Priority), Initializer(Initializer),
+ AssociatedData(AssociatedData) {}
+ int Priority;
+ llvm::Constant *Initializer;
+ llvm::Constant *AssociatedData;
+ };
+
+ typedef std::vector<Structor> CtorList;
ASTContext &Context;
const LangOptions &LangOpts;
@@ -236,7 +276,7 @@ class CodeGenModule : public CodeGenTypeCache {
DiagnosticsEngine &Diags;
const llvm::DataLayout &TheDataLayout;
const TargetInfo &Target;
- CGCXXABI &ABI;
+ std::unique_ptr<CGCXXABI> ABI;
llvm::LLVMContext &VMContext;
CodeGenTBAA *TBAA;
@@ -248,32 +288,42 @@ class CodeGenModule : public CodeGenTypeCache {
// if TheTargetCodeGenInfo is NULL
CodeGenTypes Types;
- /// VTables - Holds information about C++ vtables.
+ /// Holds information about C++ vtables.
CodeGenVTables VTables;
CGObjCRuntime* ObjCRuntime;
CGOpenCLRuntime* OpenCLRuntime;
+ CGOpenMPRuntime* OpenMPRuntime;
CGCUDARuntime* CUDARuntime;
CGDebugInfo* DebugInfo;
ARCEntrypoints *ARCData;
llvm::MDNode *NoObjCARCExceptionsMetadata;
RREntrypoints *RRData;
+ std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader;
+ InstrProfStats PGOStats;
- // 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 see a direct reference or a definition.
+ // 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 see a direct reference
+ // or a definition.
llvm::SmallPtrSet<llvm::GlobalValue*, 10> WeakRefReferences;
- /// DeferredDecls - This contains all the decls which have definitions but
- /// which are deferred for emission and therefore should only be output if
- /// they are actually used. If a decl is in this, then it is known to have
- /// not been referenced yet.
- llvm::StringMap<GlobalDecl> DeferredDecls;
-
- /// DeferredDeclsToEmit - This is a list of deferred decls which we have seen
- /// that *are* actually referenced. These get code generated when the module
- /// is done.
- std::vector<GlobalDecl> DeferredDeclsToEmit;
+ /// This contains all the decls which have definitions but/ which are deferred
+ /// for emission and therefore should only be output if they are actually
+ /// used. If a decl is in this, then it is known to have not been referenced
+ /// yet.
+ std::map<StringRef, GlobalDecl> DeferredDecls;
+
+ /// This is a list of deferred decls which we have seen that *are* actually
+ /// referenced. These get code generated when the module is done.
+ struct DeferredGlobal {
+ DeferredGlobal(llvm::GlobalValue *GV, GlobalDecl GD) : GV(GV), GD(GD) {}
+ llvm::AssertingVH<llvm::GlobalValue> GV;
+ GlobalDecl GD;
+ };
+ std::vector<DeferredGlobal> DeferredDeclsToEmit;
+ void addDeferredDeclToEmit(llvm::GlobalValue *GV, GlobalDecl GD) {
+ DeferredDeclsToEmit.push_back(DeferredGlobal(GV, GD));
+ }
/// List of alias we have emitted. Used to make sure that what they point to
/// is defined once we get to the end of the of the translation unit.
@@ -282,27 +332,27 @@ class CodeGenModule : public CodeGenTypeCache {
typedef llvm::StringMap<llvm::TrackingVH<llvm::Constant> > ReplacementsTy;
ReplacementsTy Replacements;
- /// DeferredVTables - A queue of (optional) vtables to consider emitting.
+ /// A queue of (optional) vtables to consider emitting.
std::vector<const CXXRecordDecl*> DeferredVTables;
- /// LLVMUsed - List of global values which are required to be
- /// present in the object file; bitcast to i8*. This is used for
- /// forcing visibility of symbols which may otherwise be optimized
- /// out.
+ /// List of global values which are required to be present in the object file;
+ /// bitcast to i8*. This is used for forcing visibility of symbols which may
+ /// otherwise be optimized out.
std::vector<llvm::WeakVH> LLVMUsed;
+ std::vector<llvm::WeakVH> LLVMCompilerUsed;
- /// GlobalCtors - Store the list of global constructors and their respective
- /// priorities to be emitted when the translation unit is complete.
+ /// Store the list of global constructors and their respective priorities to
+ /// be emitted when the translation unit is complete.
CtorList GlobalCtors;
- /// GlobalDtors - Store the list of global destructors and their respective
- /// priorities to be emitted when the translation unit is complete.
+ /// Store the list of global destructors and their respective priorities to be
+ /// emitted when the translation unit is complete.
CtorList GlobalDtors;
- /// MangledDeclNames - A map of canonical GlobalDecls to their mangled names.
- llvm::DenseMap<GlobalDecl, StringRef> MangledDeclNames;
- llvm::BumpPtrAllocator MangledNamesAllocator;
-
+ /// An ordered map of canonical GlobalDecls to their mangled names.
+ llvm::MapVector<GlobalDecl, StringRef> MangledDeclNames;
+ llvm::StringMap<GlobalDecl, llvm::BumpPtrAllocator> Manglings;
+
/// Global annotations.
std::vector<llvm::Constant*> Annotations;
@@ -310,7 +360,8 @@ class CodeGenModule : public CodeGenTypeCache {
llvm::StringMap<llvm::Constant*> AnnotationStrings;
llvm::StringMap<llvm::Constant*> CFConstantStringMap;
- llvm::StringMap<llvm::GlobalVariable*> ConstantStringMap;
+
+ llvm::DenseMap<llvm::Constant *, llvm::GlobalVariable *> ConstantStringMap;
llvm::DenseMap<const Decl*, llvm::Constant *> StaticLocalDeclMap;
llvm::DenseMap<const Decl*, llvm::GlobalVariable*> StaticLocalDeclGuardMap;
llvm::DenseMap<const Expr*, llvm::Constant *> MaterializedGlobalTemporaryMap;
@@ -335,8 +386,7 @@ class CodeGenModule : public CodeGenTypeCache {
/// before any thread_local variable in this TU is odr-used.
std::vector<llvm::Constant*> CXXThreadLocalInits;
- /// CXXGlobalInits - Global variables with initializers that need to run
- /// before main.
+ /// Global variables with initializers that need to run before main.
std::vector<llvm::Constant*> CXXGlobalInits;
/// When a C++ decl with an initializer is deferred, null is
@@ -354,12 +404,11 @@ class CodeGenModule : public CodeGenTypeCache {
}
};
- /// - Global variables with initializers whose order of initialization
- /// is set by init_priority attribute.
+ /// Global variables with initializers whose order of initialization is set by
+ /// init_priority attribute.
SmallVector<GlobalInitData, 8> PrioritizedCXXGlobalInits;
- /// CXXGlobalDtors - Global destructor functions and arguments that need to
- /// run on termination.
+ /// Global destructor functions and arguments that need to run on termination.
std::vector<std::pair<llvm::WeakVH,llvm::Constant*> > CXXGlobalDtors;
/// \brief The complete set of modules that has been imported.
@@ -371,12 +420,12 @@ class CodeGenModule : public CodeGenTypeCache {
/// @name Cache for Objective-C runtime types
/// @{
- /// CFConstantStringClassRef - Cached reference to the class for constant
- /// strings. This value has type int * but is actually an Obj-C class pointer.
+ /// Cached reference to the class for constant strings. This value has type
+ /// int * but is actually an Obj-C class pointer.
llvm::WeakVH CFConstantStringClassRef;
- /// ConstantStringClassRef - Cached reference to the class for constant
- /// strings. This value has type int * but is actually an Obj-C class pointer.
+ /// Cached reference to the class for constant strings. This value has type
+ /// int * but is actually an Obj-C class pointer.
llvm::WeakVH ConstantStringClassRef;
/// \brief The LLVM type corresponding to NSConstantString.
@@ -392,6 +441,7 @@ class CodeGenModule : public CodeGenTypeCache {
void createObjCRuntime();
void createOpenCLRuntime();
+ void createOpenMPRuntime();
void createCUDARuntime();
bool isTriviallyRecursive(const FunctionDecl *F);
@@ -421,9 +471,7 @@ class CodeGenModule : public CodeGenTypeCache {
GlobalDecl initializedGlobalDecl;
- llvm::OwningPtr<llvm::SpecialCaseList> SanitizerBlacklist;
-
- const SanitizerOptions &SanOpts;
+ SanitizerBlacklist SanitizerBL;
/// @}
public:
@@ -433,42 +481,51 @@ public:
~CodeGenModule();
- /// Release - Finalize LLVM code generation.
+ void clear();
+
+ /// Finalize LLVM code generation.
void Release();
- /// getObjCRuntime() - Return a reference to the configured
- /// Objective-C runtime.
+ /// Return a reference to the configured Objective-C runtime.
CGObjCRuntime &getObjCRuntime() {
if (!ObjCRuntime) createObjCRuntime();
return *ObjCRuntime;
}
- /// hasObjCRuntime() - Return true iff an Objective-C runtime has
- /// been configured.
+ /// Return true iff an Objective-C runtime has been configured.
bool hasObjCRuntime() { return !!ObjCRuntime; }
- /// getOpenCLRuntime() - Return a reference to the configured OpenCL runtime.
+ /// Return a reference to the configured OpenCL runtime.
CGOpenCLRuntime &getOpenCLRuntime() {
- assert(OpenCLRuntime != 0);
+ assert(OpenCLRuntime != nullptr);
return *OpenCLRuntime;
}
- /// getCUDARuntime() - Return a reference to the configured CUDA runtime.
+ /// Return a reference to the configured OpenMP runtime.
+ CGOpenMPRuntime &getOpenMPRuntime() {
+ assert(OpenMPRuntime != nullptr);
+ return *OpenMPRuntime;
+ }
+
+ /// Return a reference to the configured CUDA runtime.
CGCUDARuntime &getCUDARuntime() {
- assert(CUDARuntime != 0);
+ assert(CUDARuntime != nullptr);
return *CUDARuntime;
}
ARCEntrypoints &getARCEntrypoints() const {
- assert(getLangOpts().ObjCAutoRefCount && ARCData != 0);
+ assert(getLangOpts().ObjCAutoRefCount && ARCData != nullptr);
return *ARCData;
}
RREntrypoints &getRREntrypoints() const {
- assert(RRData != 0);
+ assert(RRData != nullptr);
return *RRData;
}
+ InstrProfStats &getPGOStats() { return PGOStats; }
+ llvm::IndexedInstrProfReader *getPGOReader() const { return PGOReader.get(); }
+
llvm::Constant *getStaticLocalDeclAddress(const VarDecl *D) {
return StaticLocalDeclMap[D];
}
@@ -485,6 +542,9 @@ public:
StaticLocalDeclGuardMap[D] = C;
}
+ bool lookupRepresentativeDecl(StringRef MangledName,
+ GlobalDecl &Result) const;
+
llvm::Constant *getAtomicSetterHelperFnMap(QualType Ty) {
return AtomicSetterHelperFnMap[Ty];
}
@@ -501,10 +561,10 @@ public:
AtomicGetterHelperFnMap[Ty] = Fn;
}
- llvm::Constant *getTypeDescriptor(QualType Ty) {
+ llvm::Constant *getTypeDescriptorFromMap(QualType Ty) {
return TypeDescriptorMap[Ty];
}
- void setTypeDescriptor(QualType Ty, llvm::Constant *C) {
+ void setTypeDescriptorInMap(QualType Ty, llvm::Constant *C) {
TypeDescriptorMap[Ty] = C;
}
@@ -525,10 +585,10 @@ public:
DiagnosticsEngine &getDiags() const { return Diags; }
const llvm::DataLayout &getDataLayout() const { return TheDataLayout; }
const TargetInfo &getTarget() const { return Target; }
- CGCXXABI &getCXXABI() { return ABI; }
+ CGCXXABI &getCXXABI() const { return *ABI; }
llvm::LLVMContext &getLLVMContext() { return VMContext; }
-
- bool shouldUseTBAA() const { return TBAA != 0; }
+
+ bool shouldUseTBAA() const { return TBAA != nullptr; }
const TargetCodeGenInfo &getTargetCodeGenInfo();
@@ -566,32 +626,16 @@ public:
llvm::MDNode *TBAAInfo,
bool ConvertTypeToTag = true);
- /// getSize - Emit the given number of characters as a value of type size_t.
+ /// 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.
+ /// Set the visibility for the given LLVM GlobalValue.
void setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const;
- /// setTLSMode - Set the TLS mode for the given LLVM GlobalVariable
- /// for the thread-local variable declaration D.
+ /// Set the TLS mode for the given LLVM GlobalVariable for the thread-local
+ /// variable declaration D.
void setTLSMode(llvm::GlobalVariable *GV, const VarDecl &D) const;
- /// TypeVisibilityKind - The kind of global variable that is passed to
- /// setTypeVisibility
- enum TypeVisibilityKind {
- TVK_ForVTT,
- TVK_ForVTable,
- TVK_ForConstructionVTable,
- TVK_ForRTTI,
- TVK_ForRTTIName
- };
-
- /// setTypeVisibility - Set the visibility for the given global
- /// value which holds information about a type.
- void setTypeVisibility(llvm::GlobalValue *GV, const CXXRecordDecl *D,
- TypeVisibilityKind TVK) const;
-
static llvm::GlobalValue::VisibilityTypes GetLLVMVisibility(Visibility V) {
switch (V) {
case DefaultVisibility: return llvm::GlobalValue::DefaultVisibility;
@@ -614,50 +658,47 @@ public:
return GetAddrOfGlobalVar(cast<VarDecl>(GD.getDecl()));
}
- /// CreateOrReplaceCXXRuntimeVariable - Will return a global variable of the
- /// given type. If a variable with a different type already exists then a new
- /// variable with the right type will be created and all uses of the old
- /// variable will be replaced with a bitcast to the new variable.
+ /// Will return a global variable of the given type. If a variable with a
+ /// different type already exists then a new variable with the right type
+ /// will be created and all uses of the old variable will be replaced with a
+ /// bitcast to the new variable.
llvm::GlobalVariable *
CreateOrReplaceCXXRuntimeVariable(StringRef Name, llvm::Type *Ty,
llvm::GlobalValue::LinkageTypes Linkage);
- /// GetGlobalVarAddressSpace - Return the address space of the underlying
- /// global variable for D, as determined by its declaration. Normally this
- /// is the same as the address space of D's type, but in CUDA, address spaces
- /// are associated with declarations, not types.
+ /// Return the address space of the underlying global variable for D, as
+ /// determined by its declaration. Normally this is the same as the address
+ /// space of D's type, but in CUDA, address spaces are associated with
+ /// declarations, not types.
unsigned GetGlobalVarAddressSpace(const VarDecl *D, unsigned AddrSpace);
- /// GetAddrOfGlobalVar - Return the llvm::Constant for the address of the
- /// given global variable. If Ty is non-null and if the global doesn't exist,
- /// then it will be greated with the specified type instead of whatever the
- /// normal requested type would be.
+ /// Return the llvm::Constant for the address of the given global variable.
+ /// If Ty is non-null and if the global doesn't exist, then it will be greated
+ /// with the specified type instead of whatever the normal requested type
+ /// would be.
llvm::Constant *GetAddrOfGlobalVar(const VarDecl *D,
- llvm::Type *Ty = 0);
-
+ llvm::Type *Ty = nullptr);
- /// GetAddrOfFunction - Return the address of the given function. If Ty is
- /// non-null, then this function will use the specified type if it has to
- /// create it.
- llvm::Constant *GetAddrOfFunction(GlobalDecl GD,
- llvm::Type *Ty = 0,
- bool ForVTable = false);
+ /// Return the address of the given function. If Ty is non-null, then this
+ /// function will use the specified type if it has to create it.
+ llvm::Constant *GetAddrOfFunction(GlobalDecl GD, llvm::Type *Ty = 0,
+ bool ForVTable = false,
+ bool DontDefer = false);
- /// GetAddrOfRTTIDescriptor - Get the address of the RTTI descriptor
- /// for the given type.
+ /// Get the address of the RTTI descriptor for the given type.
llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false);
- /// GetAddrOfUuidDescriptor - Get the address of a uuid descriptor .
+ /// Get the address of a uuid descriptor .
llvm::Constant *GetAddrOfUuidDescriptor(const CXXUuidofExpr* E);
- /// GetAddrOfThunk - Get the address of the thunk for the given global decl.
+ /// Get the address of the thunk for the given global decl.
llvm::Constant *GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk);
- /// GetWeakRefReference - Get a reference to the target of VD.
+ /// Get a reference to the target of VD.
llvm::Constant *GetWeakRefReference(const ValueDecl *VD);
- /// GetNonVirtualBaseClassOffset - Returns the offset from a derived class to
- /// a class. Returns null if the offset is 0.
+ /// Returns the offset from a derived class to a class. Returns null if the
+ /// offset is 0.
llvm::Constant *
GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl,
CastExpr::path_const_iterator PathBegin,
@@ -693,67 +734,49 @@ public:
llvm::FoldingSet<ByrefHelpers> ByrefHelpersCache;
- /// getUniqueBlockCount - Fetches the global unique block count.
+ /// Fetches the global unique block count.
int getUniqueBlockCount() { return ++Block.GlobalUniqueCount; }
- /// getBlockDescriptorType - Fetches the type of a generic block
- /// descriptor.
+ /// Fetches the type of a generic block descriptor.
llvm::Type *getBlockDescriptorType();
- /// getGenericBlockLiteralType - The type of a generic block literal.
+ /// The type of a generic block literal.
llvm::Type *getGenericBlockLiteralType();
- /// GetAddrOfGlobalBlock - Gets the address of a block which
- /// requires no captures.
+ /// Gets the address of a block which requires no captures.
llvm::Constant *GetAddrOfGlobalBlock(const BlockExpr *BE, const char *);
- /// GetAddrOfConstantCFString - Return a pointer to a constant CFString object
- /// for the given string.
+ /// Return a pointer to a constant CFString object for the given string.
llvm::Constant *GetAddrOfConstantCFString(const StringLiteral *Literal);
-
- /// GetAddrOfConstantString - Return a pointer to a constant NSString object
- /// for the given string. Or a user defined String object as defined via
+
+ /// Return a pointer to a constant NSString object for the given string. Or a
+ /// user defined String object as defined via
/// -fconstant-string-class=class_name option.
llvm::Constant *GetAddrOfConstantString(const StringLiteral *Literal);
- /// GetConstantArrayFromStringLiteral - Return a constant array for the given
- /// string.
+ /// Return a constant array for the given string.
llvm::Constant *GetConstantArrayFromStringLiteral(const StringLiteral *E);
- /// GetAddrOfConstantStringFromLiteral - Return a pointer to a constant array
- /// for the given string literal.
- llvm::Constant *GetAddrOfConstantStringFromLiteral(const StringLiteral *S);
+ /// Return a pointer to a constant array for the given string literal.
+ llvm::GlobalVariable *
+ GetAddrOfConstantStringFromLiteral(const StringLiteral *S);
- /// GetAddrOfConstantStringFromObjCEncode - Return a pointer to a constant
- /// array for the given ObjCEncodeExpr node.
- llvm::Constant *GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *);
+ /// Return a pointer to a constant array for the given ObjCEncodeExpr node.
+ llvm::GlobalVariable *
+ GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *);
- /// GetAddrOfConstantString - Returns a pointer to a character array
- /// containing the literal. This contents are exactly that of the given
- /// string, i.e. it will not be null terminated automatically; see
- /// GetAddrOfConstantCString. Note that whether the result is actually a
- /// pointer to an LLVM constant depends on Feature.WriteableStrings.
- ///
- /// The result has pointer to array type.
- ///
- /// \param GlobalName If provided, the name to use for the global
- /// (if one is created).
- llvm::Constant *GetAddrOfConstantString(StringRef Str,
- const char *GlobalName=0,
- unsigned Alignment=0);
-
- /// GetAddrOfConstantCString - Returns a pointer to a character array
- /// containing the literal and a terminating '\0' character. The result has
- /// pointer to array type.
+ /// Returns a pointer to a character array containing the literal and a
+ /// terminating '\0' character. The result has pointer to array type.
///
/// \param GlobalName If provided, the name to use for the global (if one is
/// created).
- llvm::Constant *GetAddrOfConstantCString(const std::string &str,
- const char *GlobalName=0,
- unsigned Alignment=0);
+ llvm::GlobalVariable *
+ GetAddrOfConstantCString(const std::string &Str,
+ const char *GlobalName = nullptr,
+ unsigned Alignment = 0);
- /// GetAddrOfConstantCompoundLiteral - Returns a pointer to a constant global
- /// variable for the given file-scope compound literal expression.
+ /// Returns a pointer to a constant global variable for the given file-scope
+ /// compound literal expression.
llvm::Constant *GetAddrOfConstantCompoundLiteral(const CompoundLiteralExpr*E);
/// \brief Returns a pointer to a global variable representing a temporary
@@ -765,31 +788,31 @@ public:
/// Objective-C fast enumeration loop (for..in).
QualType getObjCFastEnumerationStateType();
- /// GetAddrOfCXXConstructor - Return the address of the constructor of the
- /// given type.
- llvm::GlobalValue *GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor,
- CXXCtorType ctorType,
- const CGFunctionInfo *fnInfo = 0);
-
- /// GetAddrOfCXXDestructor - Return the address of the constructor of the
- /// given type.
- llvm::GlobalValue *GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor,
- CXXDtorType dtorType,
- const CGFunctionInfo *fnInfo = 0,
- llvm::FunctionType *fnType = 0);
-
- /// getBuiltinLibFunction - Given a builtin id for a function like
- /// "__builtin_fabsf", return a Function* for "fabsf".
+ /// Return the address of the constructor of the given type.
+ llvm::GlobalValue *
+ GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor, CXXCtorType ctorType,
+ const CGFunctionInfo *fnInfo = nullptr,
+ bool DontDefer = false);
+
+ /// Return the address of the constructor of the given type.
+ llvm::GlobalValue *
+ GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor,
+ CXXDtorType dtorType,
+ const CGFunctionInfo *fnInfo = nullptr,
+ llvm::FunctionType *fnType = nullptr,
+ bool DontDefer = false);
+
+ /// Given a builtin id for a function like "__builtin_fabsf", return a
+ /// Function* for "fabsf".
llvm::Value *getBuiltinLibFunction(const FunctionDecl *FD,
unsigned BuiltinID);
llvm::Function *getIntrinsic(unsigned IID, ArrayRef<llvm::Type*> Tys = None);
- /// EmitTopLevelDecl - Emit code for a single top level declaration.
+ /// Emit code for a single top level declaration.
void EmitTopLevelDecl(Decl *D);
- /// HandleCXXStaticMemberVarInstantiation - Tell the consumer that this
- // variable has been instantiated.
+ /// Tell the consumer that this variable has been instantiated.
void HandleCXXStaticMemberVarInstantiation(VarDecl *VD);
/// \brief If the declaration has internal linkage but is inside an
@@ -798,25 +821,23 @@ public:
template<typename SomeDecl>
void MaybeHandleStaticInExternC(const SomeDecl *D, llvm::GlobalValue *GV);
- /// AddUsedGlobal - Add a global which should be forced to be
- /// present in the object file; these are emitted to the llvm.used
- /// metadata global.
- void AddUsedGlobal(llvm::GlobalValue *GV);
+ /// Add a global to a list to be added to the llvm.used metadata.
+ void addUsedGlobal(llvm::GlobalValue *GV);
+
+ /// Add a global to a list to be added to the llvm.compiler.used metadata.
+ void addCompilerUsedGlobal(llvm::GlobalValue *GV);
- /// AddCXXDtorEntry - Add a destructor and object to add to the C++ global
- /// destructor function.
+ /// Add a destructor and object to add to the C++ global destructor function.
void AddCXXDtorEntry(llvm::Constant *DtorFn, llvm::Constant *Object) {
CXXGlobalDtors.push_back(std::make_pair(DtorFn, Object));
}
- /// CreateRuntimeFunction - Create a new runtime function with the specified
- /// type and name.
+ /// Create a new runtime function with the specified type and name.
llvm::Constant *CreateRuntimeFunction(llvm::FunctionType *Ty,
StringRef Name,
llvm::AttributeSet ExtraAttrs =
llvm::AttributeSet());
- /// CreateRuntimeVariable - Create a new runtime global variable with the
- /// specified type and name.
+ /// Create a new runtime global variable with the specified type and name.
llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty,
StringRef Name);
@@ -833,85 +854,80 @@ public:
llvm::Constant *getLLVMLifetimeStartFn();
llvm::Constant *getLLVMLifetimeEndFn();
- // UpdateCompleteType - Make sure that this type is translated.
+ // Make sure that this type is translated.
void UpdateCompletedType(const TagDecl *TD);
llvm::Constant *getMemberPointerConstant(const UnaryOperator *e);
- /// EmitConstantInit - Try to emit the initializer for the given declaration
- /// as a constant; returns 0 if the expression cannot be emitted as a
- /// constant.
- llvm::Constant *EmitConstantInit(const VarDecl &D, CodeGenFunction *CGF = 0);
+ /// Try to emit the initializer for the given declaration as a constant;
+ /// returns 0 if the expression cannot be emitted as a constant.
+ llvm::Constant *EmitConstantInit(const VarDecl &D,
+ CodeGenFunction *CGF = nullptr);
- /// EmitConstantExpr - Try to emit the given expression as a
- /// constant; returns 0 if the expression cannot be emitted as a
- /// constant.
+ /// Try to emit the given expression as a constant; returns 0 if the
+ /// expression cannot be emitted as a constant.
llvm::Constant *EmitConstantExpr(const Expr *E, QualType DestType,
- CodeGenFunction *CGF = 0);
+ CodeGenFunction *CGF = nullptr);
- /// EmitConstantValue - Emit the given constant value as a constant, in the
- /// type's scalar representation.
+ /// Emit the given constant value as a constant, in the type's scalar
+ /// representation.
llvm::Constant *EmitConstantValue(const APValue &Value, QualType DestType,
- CodeGenFunction *CGF = 0);
+ CodeGenFunction *CGF = nullptr);
- /// EmitConstantValueForMemory - Emit the given constant value as a constant,
- /// in the type's memory representation.
+ /// Emit the given constant value as a constant, in the type's memory
+ /// representation.
llvm::Constant *EmitConstantValueForMemory(const APValue &Value,
QualType DestType,
- CodeGenFunction *CGF = 0);
+ CodeGenFunction *CGF = nullptr);
- /// EmitNullConstant - Return the result of value-initializing the given
- /// type, i.e. a null expression of the given type. This is usually,
- /// but not always, an LLVM null constant.
+ /// Return the result of value-initializing the given type, i.e. a null
+ /// expression of the given type. This is usually, but not always, an LLVM
+ /// null constant.
llvm::Constant *EmitNullConstant(QualType T);
- /// EmitNullConstantForBase - Return a null constant appropriate for
- /// zero-initializing a base class with the given type. This is usually,
- /// but not always, an LLVM null constant.
+ /// Return a null constant appropriate for zero-initializing a base class with
+ /// the given type. This is usually, but not always, an LLVM null constant.
llvm::Constant *EmitNullConstantForBase(const CXXRecordDecl *Record);
- /// Error - Emit a general error that something can't be done.
+ /// Emit a general error that something can't be done.
void Error(SourceLocation loc, StringRef error);
- /// ErrorUnsupported - Print out an error that codegen doesn't support the
- /// specified stmt yet.
+ /// Print out an error that codegen doesn't support the specified stmt yet.
void ErrorUnsupported(const Stmt *S, const char *Type);
- /// ErrorUnsupported - Print out an error that codegen doesn't support the
- /// specified decl yet.
+ /// Print out an error that codegen doesn't support the specified decl yet.
void ErrorUnsupported(const Decl *D, const char *Type);
- /// SetInternalFunctionAttributes - Set the attributes on the LLVM
- /// function for the given decl and function info. This applies
- /// attributes necessary for handling the ABI as well as user
- /// specified attributes like section.
+ /// Set the attributes on the LLVM function for the given decl and function
+ /// info. This applies attributes necessary for handling the ABI as well as
+ /// user specified attributes like section.
void SetInternalFunctionAttributes(const Decl *D, llvm::Function *F,
const CGFunctionInfo &FI);
- /// SetLLVMFunctionAttributes - Set the LLVM function attributes
- /// (sext, zext, etc).
+ /// Set the LLVM function attributes (sext, zext, etc).
void SetLLVMFunctionAttributes(const Decl *D,
const CGFunctionInfo &Info,
llvm::Function *F);
- /// SetLLVMFunctionAttributesForDefinition - Set the LLVM function attributes
- /// which only apply to a function definintion.
+ /// Set the LLVM function attributes which only apply to a function
+ /// definintion.
void SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F);
- /// ReturnTypeUsesSRet - Return true iff the given type uses 'sret' when used
- /// as a return type.
+ /// Return true iff the given type uses 'sret' when used as a return type.
bool ReturnTypeUsesSRet(const CGFunctionInfo &FI);
- /// ReturnTypeUsesFPRet - Return true iff the given type uses 'fpret' when
- /// used as a return type.
+ /// Return true iff the given type uses an argument slot when 'sret' is used
+ /// as a return type.
+ bool ReturnSlotInterferesWithArgs(const CGFunctionInfo &FI);
+
+ /// Return true iff the given type uses 'fpret' when used as a return type.
bool ReturnTypeUsesFPRet(QualType ResultType);
- /// ReturnTypeUsesFP2Ret - Return true iff the given type uses 'fp2ret' when
- /// used as a return type.
+ /// Return true iff the given type uses 'fp2ret' when used as a return type.
bool ReturnTypeUsesFP2Ret(QualType ResultType);
- /// ConstructAttributeList - Get the LLVM attributes and calling convention to
- /// use for a particular function type.
+ /// Get the LLVM attributes and calling convention to use for a particular
+ /// function type.
///
/// \param Info - The function type information.
/// \param TargetDecl - The decl these attributes are being constructed
@@ -926,15 +942,13 @@ public:
bool AttrOnCallSite);
StringRef getMangledName(GlobalDecl GD);
- void getBlockMangledName(GlobalDecl GD, MangleBuffer &Buffer,
- const BlockDecl *BD);
+ StringRef getBlockMangledName(GlobalDecl GD, const BlockDecl *BD);
void EmitTentativeDefinition(const VarDecl *D);
void EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired);
- /// EmitFundamentalRTTIDescriptors - Emit the RTTI descriptors for the
- /// builtin types.
+ /// Emit the RTTI descriptors for the builtin types.
void EmitFundamentalRTTIDescriptors();
/// \brief Appends Opts to the "Linker Options" metadata value.
@@ -948,23 +962,26 @@ public:
llvm::GlobalVariable::LinkageTypes getFunctionLinkage(GlobalDecl GD);
- void setFunctionLinkage(GlobalDecl GD, llvm::GlobalValue *V) {
- V->setLinkage(getFunctionLinkage(GD));
+ void setFunctionLinkage(GlobalDecl GD, llvm::Function *F) {
+ F->setLinkage(getFunctionLinkage(GD));
}
- /// getVTableLinkage - Return the appropriate linkage for the vtable, VTT,
- /// and type information of the given class.
+ /// Return the appropriate linkage for the vtable, VTT, and type information
+ /// of the given class.
llvm::GlobalVariable::LinkageTypes getVTableLinkage(const CXXRecordDecl *RD);
- /// GetTargetTypeStoreSize - Return the store size, in character units, of
- /// the given LLVM type.
+ /// Return the store size, in character units, of the given LLVM type.
CharUnits GetTargetTypeStoreSize(llvm::Type *Ty) const;
- /// GetLLVMLinkageVarDefinition - Returns LLVM linkage for a global
- /// variable.
- llvm::GlobalValue::LinkageTypes
- GetLLVMLinkageVarDefinition(const VarDecl *D, bool isConstant);
-
+ /// Returns LLVM linkage for a declarator.
+ llvm::GlobalValue::LinkageTypes
+ getLLVMLinkageForDeclarator(const DeclaratorDecl *D, GVALinkage Linkage,
+ bool IsConstantVariable);
+
+ /// Returns LLVM linkage for a declarator.
+ llvm::GlobalValue::LinkageTypes
+ getLLVMLinkageVarDefinition(const VarDecl *VD, bool IsConstant);
+
/// Emit all the global annotations.
void EmitGlobalAnnotations();
@@ -977,8 +994,8 @@ public:
/// Emit the annotation line number.
llvm::Constant *EmitAnnotationLineNo(SourceLocation L);
- /// EmitAnnotateAttr - Generate the llvm::ConstantStruct which contains the
- /// annotation information for a given GlobalValue. The annotation struct is
+ /// Generate the llvm::ConstantStruct which contains the annotation
+ /// information for a given GlobalValue. The annotation struct is
/// {i8 *, i8 *, i8 *, i32}. The first field is a constant expression, the
/// GlobalValue being annotated. The second field is the constant string
/// created from the AnnotateAttr's annotation. The third field is a constant
@@ -992,54 +1009,59 @@ public:
/// annotations are emitted during finalization of the LLVM code.
void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV);
- const llvm::SpecialCaseList &getSanitizerBlacklist() const {
- return *SanitizerBlacklist;
+ const SanitizerBlacklist &getSanitizerBlacklist() const {
+ return SanitizerBL;
}
- const SanitizerOptions &getSanOpts() const { return SanOpts; }
+ void reportGlobalToASan(llvm::GlobalVariable *GV, const VarDecl &D,
+ bool IsDynInit = false);
+ void reportGlobalToASan(llvm::GlobalVariable *GV, SourceLocation Loc,
+ StringRef Name, bool IsDynInit = false,
+ bool IsBlacklisted = false);
+
+ /// Disable sanitizer instrumentation for this global.
+ void disableSanitizerForGlobal(llvm::GlobalVariable *GV);
void addDeferredVTable(const CXXRecordDecl *RD) {
DeferredVTables.push_back(RD);
}
- /// EmitGlobal - Emit code for a singal global function or var decl. Forward
- /// declarations are emitted lazily.
+ /// Emit code for a singal global function or var decl. Forward declarations
+ /// are emitted lazily.
void EmitGlobal(GlobalDecl D);
private:
llvm::GlobalValue *GetGlobalValue(StringRef Ref);
- llvm::Constant *GetOrCreateLLVMFunction(StringRef MangledName,
- llvm::Type *Ty,
- GlobalDecl D,
- bool ForVTable,
- llvm::AttributeSet ExtraAttrs =
- llvm::AttributeSet());
+ llvm::Constant *
+ GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D,
+ bool ForVTable, bool DontDefer = false,
+ llvm::AttributeSet ExtraAttrs = llvm::AttributeSet());
+
llvm::Constant *GetOrCreateLLVMGlobal(StringRef MangledName,
llvm::PointerType *PTy,
- const VarDecl *D,
- bool UnnamedAddr = false);
+ const VarDecl *D);
- /// SetCommonAttributes - Set attributes which are common to any
- /// form of a global definition (alias, Objective-C method,
- /// function, global variable).
+ /// Set attributes which are common to any form of a global definition (alias,
+ /// Objective-C method, function, global variable).
///
/// NOTE: This should only be called for definitions.
void SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV);
- /// SetFunctionDefinitionAttributes - Set attributes for a global definition.
- void SetFunctionDefinitionAttributes(const FunctionDecl *D,
- llvm::GlobalValue *GV);
+ void setNonAliasAttributes(const Decl *D, llvm::GlobalObject *GO);
+
+ /// Set attributes for a global definition.
+ void setFunctionDefinitionAttributes(const FunctionDecl *D,
+ llvm::Function *F);
- /// SetFunctionAttributes - Set function attributes for a function
- /// declaration.
+ /// Set function attributes for a function declaration.
void SetFunctionAttributes(GlobalDecl GD,
llvm::Function *F,
bool IsIncompleteFunction);
- void EmitGlobalDefinition(GlobalDecl D);
+ void EmitGlobalDefinition(GlobalDecl D, llvm::GlobalValue *GV = nullptr);
- void EmitGlobalFunctionDefinition(GlobalDecl GD);
+ void EmitGlobalFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV);
void EmitGlobalVarDefinition(const VarDecl *D);
void EmitAliasDefinition(GlobalDecl GD);
void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);
@@ -1055,44 +1077,44 @@ private:
void EmitLinkageSpec(const LinkageSpecDecl *D);
void CompleteDIClassType(const CXXMethodDecl* D);
- /// EmitCXXConstructor - Emit a single constructor with the given type from
- /// a C++ constructor Decl.
+ /// Emit a single constructor with the given type from a C++ constructor Decl.
void EmitCXXConstructor(const CXXConstructorDecl *D, CXXCtorType Type);
- /// EmitCXXDestructor - Emit a single destructor with the given type from
- /// a C++ destructor Decl.
+ /// Emit a single destructor with the given type from a C++ destructor Decl.
void EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type);
/// \brief Emit the function that initializes C++ thread_local variables.
void EmitCXXThreadLocalInitFunc();
- /// EmitCXXGlobalInitFunc - Emit the function that initializes C++ globals.
+ /// Emit the function that initializes C++ globals.
void EmitCXXGlobalInitFunc();
- /// EmitCXXGlobalDtorFunc - Emit the function that destroys C++ globals.
+ /// Emit the function that destroys C++ globals.
void EmitCXXGlobalDtorFunc();
- /// EmitCXXGlobalVarDeclInitFunc - Emit the function that initializes the
- /// specified global (if PerformInit is true) and registers its destructor.
+ /// Emit the function that initializes the specified global (if PerformInit is
+ /// true) and registers its destructor.
void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
llvm::GlobalVariable *Addr,
bool PerformInit);
+ void EmitPointerToInitFunc(const VarDecl *VD, llvm::GlobalVariable *Addr,
+ llvm::Function *InitFunc, InitSegAttr *ISA);
+
// FIXME: Hardcoding priority here is gross.
- void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535);
- void AddGlobalDtor(llvm::Function *Dtor, int Priority=65535);
+ void AddGlobalCtor(llvm::Function *Ctor, int Priority = 65535,
+ llvm::Constant *AssociatedData = 0);
+ void AddGlobalDtor(llvm::Function *Dtor, int Priority = 65535);
- /// EmitCtorList - Generates a global array of functions and priorities using
- /// the given list and name. This array will have appending linkage and is
- /// suitable for use as a LLVM constructor or destructor array.
+ /// Generates a global array of functions and priorities using the given list
+ /// and name. This array will have appending linkage and is suitable for use
+ /// as a LLVM constructor or destructor array.
void EmitCtorList(const CtorList &Fns, const char *GlobalName);
- /// EmitFundamentalRTTIDescriptor - Emit the RTTI descriptors for the
- /// given type.
+ /// Emit the RTTI descriptors for the given type.
void EmitFundamentalRTTIDescriptor(QualType Type);
- /// EmitDeferred - Emit any needed decls for which code generation
- /// was deferred.
+ /// Emit any needed decls for which code generation was deferred.
void EmitDeferred();
/// Call replaceAllUsesWith on all pairs in Replacements.
@@ -1100,13 +1122,11 @@ private:
void checkAliases();
- /// EmitDeferredVTables - Emit any vtables which we deferred and
- /// still have a use for.
+ /// Emit any vtables which we deferred and still have a use for.
void EmitDeferredVTables();
- /// EmitLLVMUsed - Emit the llvm.used metadata used to force
- /// references to global which may otherwise be optimized out.
- void EmitLLVMUsed();
+ /// Emit the llvm.used and llvm.compiler.used metadata.
+ void emitLLVMUsed();
/// \brief Emit the link options introduced by imported modules.
void EmitModuleLinkOptions();
@@ -1120,20 +1140,22 @@ private:
/// \brief Emit the Clang version as llvm.ident metadata.
void EmitVersionIdentMetadata();
- /// EmitCoverageFile - Emit the llvm.gcov metadata used to tell LLVM where
- /// to emit the .gcno and .gcda files in a way that persists in .bc files.
+ /// Emits target specific Metadata for global declarations.
+ void EmitTargetMetadata();
+
+ /// Emit the llvm.gcov metadata used to tell LLVM where to emit the .gcno and
+ /// .gcda files in a way that persists in .bc files.
void EmitCoverageFile();
/// Emits the initializer for a uuidof string.
llvm::Constant *EmitUuidofInitializer(StringRef uuidstr, QualType IIDType);
- /// MayDeferGeneration - Determine if the given decl can be emitted
- /// lazily; this is only relevant for definitions. The given decl
- /// must be either a function or var decl.
+ /// Determine if the given decl can be emitted lazily; this is only relevant
+ /// for definitions. The given decl must be either a function or var decl.
bool MayDeferGeneration(const ValueDecl *D);
- /// SimplifyPersonality - Check whether we can use a "simpler", more
- /// core exceptions personality function.
+ /// Check whether we can use a "simpler", more core exceptions personality
+ /// function.
void SimplifyPersonality();
};
} // end namespace CodeGen
diff --git a/lib/CodeGen/CodeGenPGO.cpp b/lib/CodeGen/CodeGenPGO.cpp
new file mode 100644
index 000000000000..b233e3c7d75e
--- /dev/null
+++ b/lib/CodeGen/CodeGenPGO.cpp
@@ -0,0 +1,1011 @@
+//===--- CodeGenPGO.cpp - PGO Instrumentation for LLVM CodeGen --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Instrumentation-based profile-guided optimization
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenPGO.h"
+#include "CodeGenFunction.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/IR/MDBuilder.h"
+#include "llvm/ProfileData/InstrProfReader.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MD5.h"
+
+using namespace clang;
+using namespace CodeGen;
+
+void CodeGenPGO::setFuncName(llvm::Function *Fn) {
+ RawFuncName = Fn->getName();
+
+ // Function names may be prefixed with a binary '1' to indicate
+ // that the backend should not modify the symbols due to any platform
+ // naming convention. Do not include that '1' in the PGO profile name.
+ if (RawFuncName[0] == '\1')
+ RawFuncName = RawFuncName.substr(1);
+
+ if (!Fn->hasLocalLinkage()) {
+ PrefixedFuncName.reset(new std::string(RawFuncName));
+ return;
+ }
+
+ // For local symbols, prepend the main file name to distinguish them.
+ // Do not include the full path in the file name since there's no guarantee
+ // that it will stay the same, e.g., if the files are checked out from
+ // version control in different locations.
+ PrefixedFuncName.reset(new std::string(CGM.getCodeGenOpts().MainFileName));
+ if (PrefixedFuncName->empty())
+ PrefixedFuncName->assign("<unknown>");
+ PrefixedFuncName->append(":");
+ PrefixedFuncName->append(RawFuncName);
+}
+
+static llvm::Function *getRegisterFunc(CodeGenModule &CGM) {
+ return CGM.getModule().getFunction("__llvm_profile_register_functions");
+}
+
+static llvm::BasicBlock *getOrInsertRegisterBB(CodeGenModule &CGM) {
+ // Don't do this for Darwin. compiler-rt uses linker magic.
+ if (CGM.getTarget().getTriple().isOSDarwin())
+ return nullptr;
+
+ // Only need to insert this once per module.
+ if (llvm::Function *RegisterF = getRegisterFunc(CGM))
+ return &RegisterF->getEntryBlock();
+
+ // Construct the function.
+ auto *VoidTy = llvm::Type::getVoidTy(CGM.getLLVMContext());
+ auto *RegisterFTy = llvm::FunctionType::get(VoidTy, false);
+ auto *RegisterF = llvm::Function::Create(RegisterFTy,
+ llvm::GlobalValue::InternalLinkage,
+ "__llvm_profile_register_functions",
+ &CGM.getModule());
+ RegisterF->setUnnamedAddr(true);
+ if (CGM.getCodeGenOpts().DisableRedZone)
+ RegisterF->addFnAttr(llvm::Attribute::NoRedZone);
+
+ // Construct and return the entry block.
+ auto *BB = llvm::BasicBlock::Create(CGM.getLLVMContext(), "", RegisterF);
+ CGBuilderTy Builder(BB);
+ Builder.CreateRetVoid();
+ return BB;
+}
+
+static llvm::Constant *getOrInsertRuntimeRegister(CodeGenModule &CGM) {
+ auto *VoidTy = llvm::Type::getVoidTy(CGM.getLLVMContext());
+ auto *VoidPtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ auto *RuntimeRegisterTy = llvm::FunctionType::get(VoidTy, VoidPtrTy, false);
+ return CGM.getModule().getOrInsertFunction("__llvm_profile_register_function",
+ RuntimeRegisterTy);
+}
+
+static bool isMachO(const CodeGenModule &CGM) {
+ return CGM.getTarget().getTriple().isOSBinFormatMachO();
+}
+
+static StringRef getCountersSection(const CodeGenModule &CGM) {
+ return isMachO(CGM) ? "__DATA,__llvm_prf_cnts" : "__llvm_prf_cnts";
+}
+
+static StringRef getNameSection(const CodeGenModule &CGM) {
+ return isMachO(CGM) ? "__DATA,__llvm_prf_names" : "__llvm_prf_names";
+}
+
+static StringRef getDataSection(const CodeGenModule &CGM) {
+ return isMachO(CGM) ? "__DATA,__llvm_prf_data" : "__llvm_prf_data";
+}
+
+llvm::GlobalVariable *CodeGenPGO::buildDataVar() {
+ // Create name variable.
+ llvm::LLVMContext &Ctx = CGM.getLLVMContext();
+ auto *VarName = llvm::ConstantDataArray::getString(Ctx, getFuncName(),
+ false);
+ auto *Name = new llvm::GlobalVariable(CGM.getModule(), VarName->getType(),
+ true, VarLinkage, VarName,
+ getFuncVarName("name"));
+ Name->setSection(getNameSection(CGM));
+ Name->setAlignment(1);
+
+ // Create data variable.
+ auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
+ auto *Int64Ty = llvm::Type::getInt64Ty(Ctx);
+ auto *Int8PtrTy = llvm::Type::getInt8PtrTy(Ctx);
+ auto *Int64PtrTy = llvm::Type::getInt64PtrTy(Ctx);
+ llvm::Type *DataTypes[] = {
+ Int32Ty, Int32Ty, Int64Ty, Int8PtrTy, Int64PtrTy
+ };
+ auto *DataTy = llvm::StructType::get(Ctx, makeArrayRef(DataTypes));
+ llvm::Constant *DataVals[] = {
+ llvm::ConstantInt::get(Int32Ty, getFuncName().size()),
+ llvm::ConstantInt::get(Int32Ty, NumRegionCounters),
+ llvm::ConstantInt::get(Int64Ty, FunctionHash),
+ llvm::ConstantExpr::getBitCast(Name, Int8PtrTy),
+ llvm::ConstantExpr::getBitCast(RegionCounters, Int64PtrTy)
+ };
+ auto *Data =
+ new llvm::GlobalVariable(CGM.getModule(), DataTy, true, VarLinkage,
+ llvm::ConstantStruct::get(DataTy, DataVals),
+ getFuncVarName("data"));
+
+ // All the data should be packed into an array in its own section.
+ Data->setSection(getDataSection(CGM));
+ Data->setAlignment(8);
+
+ // Hide all these symbols so that we correctly get a copy for each
+ // executable. The profile format expects names and counters to be
+ // contiguous, so references into shared objects would be invalid.
+ if (!llvm::GlobalValue::isLocalLinkage(VarLinkage)) {
+ Name->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ Data->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ RegionCounters->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ }
+
+ // Make sure the data doesn't get deleted.
+ CGM.addUsedGlobal(Data);
+ return Data;
+}
+
+void CodeGenPGO::emitInstrumentationData() {
+ if (!RegionCounters)
+ return;
+
+ // Build the data.
+ auto *Data = buildDataVar();
+
+ // Register the data.
+ auto *RegisterBB = getOrInsertRegisterBB(CGM);
+ if (!RegisterBB)
+ return;
+ CGBuilderTy Builder(RegisterBB->getTerminator());
+ auto *VoidPtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+ Builder.CreateCall(getOrInsertRuntimeRegister(CGM),
+ Builder.CreateBitCast(Data, VoidPtrTy));
+}
+
+llvm::Function *CodeGenPGO::emitInitialization(CodeGenModule &CGM) {
+ if (!CGM.getCodeGenOpts().ProfileInstrGenerate)
+ return nullptr;
+
+ assert(CGM.getModule().getFunction("__llvm_profile_init") == nullptr &&
+ "profile initialization already emitted");
+
+ // Get the function to call at initialization.
+ llvm::Constant *RegisterF = getRegisterFunc(CGM);
+ if (!RegisterF)
+ return nullptr;
+
+ // Create the initialization function.
+ auto *VoidTy = llvm::Type::getVoidTy(CGM.getLLVMContext());
+ auto *F = llvm::Function::Create(llvm::FunctionType::get(VoidTy, false),
+ llvm::GlobalValue::InternalLinkage,
+ "__llvm_profile_init", &CGM.getModule());
+ F->setUnnamedAddr(true);
+ F->addFnAttr(llvm::Attribute::NoInline);
+ if (CGM.getCodeGenOpts().DisableRedZone)
+ F->addFnAttr(llvm::Attribute::NoRedZone);
+
+ // Add the basic block and the necessary calls.
+ CGBuilderTy Builder(llvm::BasicBlock::Create(CGM.getLLVMContext(), "", F));
+ Builder.CreateCall(RegisterF);
+ Builder.CreateRetVoid();
+
+ return F;
+}
+
+namespace {
+/// \brief Stable hasher for PGO region counters.
+///
+/// PGOHash produces a stable hash of a given function's control flow.
+///
+/// Changing the output of this hash will invalidate all previously generated
+/// profiles -- i.e., don't do it.
+///
+/// \note When this hash does eventually change (years?), we still need to
+/// support old hashes. We'll need to pull in the version number from the
+/// profile data format and use the matching hash function.
+class PGOHash {
+ uint64_t Working;
+ unsigned Count;
+ llvm::MD5 MD5;
+
+ static const int NumBitsPerType = 6;
+ static const unsigned NumTypesPerWord = sizeof(uint64_t) * 8 / NumBitsPerType;
+ static const unsigned TooBig = 1u << NumBitsPerType;
+
+public:
+ /// \brief Hash values for AST nodes.
+ ///
+ /// Distinct values for AST nodes that have region counters attached.
+ ///
+ /// These values must be stable. All new members must be added at the end,
+ /// and no members should be removed. Changing the enumeration value for an
+ /// AST node will affect the hash of every function that contains that node.
+ enum HashType : unsigned char {
+ None = 0,
+ LabelStmt = 1,
+ WhileStmt,
+ DoStmt,
+ ForStmt,
+ CXXForRangeStmt,
+ ObjCForCollectionStmt,
+ SwitchStmt,
+ CaseStmt,
+ DefaultStmt,
+ IfStmt,
+ CXXTryStmt,
+ CXXCatchStmt,
+ ConditionalOperator,
+ BinaryOperatorLAnd,
+ BinaryOperatorLOr,
+ BinaryConditionalOperator,
+
+ // Keep this last. It's for the static assert that follows.
+ LastHashType
+ };
+ static_assert(LastHashType <= TooBig, "Too many types in HashType");
+
+ // TODO: When this format changes, take in a version number here, and use the
+ // old hash calculation for file formats that used the old hash.
+ PGOHash() : Working(0), Count(0) {}
+ void combine(HashType Type);
+ uint64_t finalize();
+};
+const int PGOHash::NumBitsPerType;
+const unsigned PGOHash::NumTypesPerWord;
+const unsigned PGOHash::TooBig;
+
+ /// A RecursiveASTVisitor that fills a map of statements to PGO counters.
+ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
+ /// The next counter value to assign.
+ unsigned NextCounter;
+ /// The function hash.
+ PGOHash Hash;
+ /// The map of statements to counters.
+ llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
+
+ MapRegionCounters(llvm::DenseMap<const Stmt *, unsigned> &CounterMap)
+ : NextCounter(0), CounterMap(CounterMap) {}
+
+ // Blocks and lambdas are handled as separate functions, so we need not
+ // traverse them in the parent context.
+ bool TraverseBlockExpr(BlockExpr *BE) { return true; }
+ bool TraverseLambdaBody(LambdaExpr *LE) { return true; }
+ bool TraverseCapturedStmt(CapturedStmt *CS) { return true; }
+
+ bool VisitDecl(const Decl *D) {
+ switch (D->getKind()) {
+ default:
+ break;
+ case Decl::Function:
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ case Decl::ObjCMethod:
+ case Decl::Block:
+ case Decl::Captured:
+ CounterMap[D->getBody()] = NextCounter++;
+ break;
+ }
+ return true;
+ }
+
+ bool VisitStmt(const Stmt *S) {
+ auto Type = getHashType(S);
+ if (Type == PGOHash::None)
+ return true;
+
+ CounterMap[S] = NextCounter++;
+ Hash.combine(Type);
+ return true;
+ }
+ PGOHash::HashType getHashType(const Stmt *S) {
+ switch (S->getStmtClass()) {
+ default:
+ break;
+ case Stmt::LabelStmtClass:
+ return PGOHash::LabelStmt;
+ case Stmt::WhileStmtClass:
+ return PGOHash::WhileStmt;
+ case Stmt::DoStmtClass:
+ return PGOHash::DoStmt;
+ case Stmt::ForStmtClass:
+ return PGOHash::ForStmt;
+ case Stmt::CXXForRangeStmtClass:
+ return PGOHash::CXXForRangeStmt;
+ case Stmt::ObjCForCollectionStmtClass:
+ return PGOHash::ObjCForCollectionStmt;
+ case Stmt::SwitchStmtClass:
+ return PGOHash::SwitchStmt;
+ case Stmt::CaseStmtClass:
+ return PGOHash::CaseStmt;
+ case Stmt::DefaultStmtClass:
+ return PGOHash::DefaultStmt;
+ case Stmt::IfStmtClass:
+ return PGOHash::IfStmt;
+ case Stmt::CXXTryStmtClass:
+ return PGOHash::CXXTryStmt;
+ case Stmt::CXXCatchStmtClass:
+ return PGOHash::CXXCatchStmt;
+ case Stmt::ConditionalOperatorClass:
+ return PGOHash::ConditionalOperator;
+ case Stmt::BinaryConditionalOperatorClass:
+ return PGOHash::BinaryConditionalOperator;
+ case Stmt::BinaryOperatorClass: {
+ const BinaryOperator *BO = cast<BinaryOperator>(S);
+ if (BO->getOpcode() == BO_LAnd)
+ return PGOHash::BinaryOperatorLAnd;
+ if (BO->getOpcode() == BO_LOr)
+ return PGOHash::BinaryOperatorLOr;
+ break;
+ }
+ }
+ return PGOHash::None;
+ }
+ };
+
+ /// A StmtVisitor that propagates the raw counts through the AST and
+ /// records the count at statements where the value may change.
+ struct ComputeRegionCounts : public ConstStmtVisitor<ComputeRegionCounts> {
+ /// PGO state.
+ CodeGenPGO &PGO;
+
+ /// A flag that is set when the current count should be recorded on the
+ /// next statement, such as at the exit of a loop.
+ bool RecordNextStmtCount;
+
+ /// The map of statements to count values.
+ llvm::DenseMap<const Stmt *, uint64_t> &CountMap;
+
+ /// BreakContinueStack - Keep counts of breaks and continues inside loops.
+ struct BreakContinue {
+ uint64_t BreakCount;
+ uint64_t ContinueCount;
+ BreakContinue() : BreakCount(0), ContinueCount(0) {}
+ };
+ SmallVector<BreakContinue, 8> BreakContinueStack;
+
+ ComputeRegionCounts(llvm::DenseMap<const Stmt *, uint64_t> &CountMap,
+ CodeGenPGO &PGO)
+ : PGO(PGO), RecordNextStmtCount(false), CountMap(CountMap) {}
+
+ void RecordStmtCount(const Stmt *S) {
+ if (RecordNextStmtCount) {
+ CountMap[S] = PGO.getCurrentRegionCount();
+ RecordNextStmtCount = false;
+ }
+ }
+
+ void VisitStmt(const Stmt *S) {
+ RecordStmtCount(S);
+ for (Stmt::const_child_range I = S->children(); I; ++I) {
+ if (*I)
+ this->Visit(*I);
+ }
+ }
+
+ void VisitFunctionDecl(const FunctionDecl *D) {
+ // Counter tracks entry to the function body.
+ RegionCounter Cnt(PGO, D->getBody());
+ Cnt.beginRegion();
+ CountMap[D->getBody()] = PGO.getCurrentRegionCount();
+ Visit(D->getBody());
+ }
+
+ // Skip lambda expressions. We visit these as FunctionDecls when we're
+ // generating them and aren't interested in the body when generating a
+ // parent context.
+ void VisitLambdaExpr(const LambdaExpr *LE) {}
+
+ void VisitCapturedDecl(const CapturedDecl *D) {
+ // Counter tracks entry to the capture body.
+ RegionCounter Cnt(PGO, D->getBody());
+ Cnt.beginRegion();
+ CountMap[D->getBody()] = PGO.getCurrentRegionCount();
+ Visit(D->getBody());
+ }
+
+ void VisitObjCMethodDecl(const ObjCMethodDecl *D) {
+ // Counter tracks entry to the method body.
+ RegionCounter Cnt(PGO, D->getBody());
+ Cnt.beginRegion();
+ CountMap[D->getBody()] = PGO.getCurrentRegionCount();
+ Visit(D->getBody());
+ }
+
+ void VisitBlockDecl(const BlockDecl *D) {
+ // Counter tracks entry to the block body.
+ RegionCounter Cnt(PGO, D->getBody());
+ Cnt.beginRegion();
+ CountMap[D->getBody()] = PGO.getCurrentRegionCount();
+ Visit(D->getBody());
+ }
+
+ void VisitReturnStmt(const ReturnStmt *S) {
+ RecordStmtCount(S);
+ if (S->getRetValue())
+ Visit(S->getRetValue());
+ PGO.setCurrentRegionUnreachable();
+ RecordNextStmtCount = true;
+ }
+
+ void VisitGotoStmt(const GotoStmt *S) {
+ RecordStmtCount(S);
+ PGO.setCurrentRegionUnreachable();
+ RecordNextStmtCount = true;
+ }
+
+ void VisitLabelStmt(const LabelStmt *S) {
+ RecordNextStmtCount = false;
+ // Counter tracks the block following the label.
+ RegionCounter Cnt(PGO, S);
+ Cnt.beginRegion();
+ CountMap[S] = PGO.getCurrentRegionCount();
+ Visit(S->getSubStmt());
+ }
+
+ void VisitBreakStmt(const BreakStmt *S) {
+ RecordStmtCount(S);
+ assert(!BreakContinueStack.empty() && "break not in a loop or switch!");
+ BreakContinueStack.back().BreakCount += PGO.getCurrentRegionCount();
+ PGO.setCurrentRegionUnreachable();
+ RecordNextStmtCount = true;
+ }
+
+ void VisitContinueStmt(const ContinueStmt *S) {
+ RecordStmtCount(S);
+ assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
+ BreakContinueStack.back().ContinueCount += PGO.getCurrentRegionCount();
+ PGO.setCurrentRegionUnreachable();
+ RecordNextStmtCount = true;
+ }
+
+ void VisitWhileStmt(const WhileStmt *S) {
+ RecordStmtCount(S);
+ // Counter tracks the body of the loop.
+ RegionCounter Cnt(PGO, S);
+ BreakContinueStack.push_back(BreakContinue());
+ // Visit the body region first so the break/continue adjustments can be
+ // included when visiting the condition.
+ Cnt.beginRegion();
+ CountMap[S->getBody()] = PGO.getCurrentRegionCount();
+ Visit(S->getBody());
+ Cnt.adjustForControlFlow();
+
+ // ...then go back and propagate counts through the condition. The count
+ // at the start of the condition is the sum of the incoming edges,
+ // the backedge from the end of the loop body, and the edges from
+ // continue statements.
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+ Cnt.setCurrentRegionCount(Cnt.getParentCount() +
+ Cnt.getAdjustedCount() + BC.ContinueCount);
+ CountMap[S->getCond()] = PGO.getCurrentRegionCount();
+ Visit(S->getCond());
+ Cnt.adjustForControlFlow();
+ Cnt.applyAdjustmentsToRegion(BC.BreakCount + BC.ContinueCount);
+ RecordNextStmtCount = true;
+ }
+
+ void VisitDoStmt(const DoStmt *S) {
+ RecordStmtCount(S);
+ // Counter tracks the body of the loop.
+ RegionCounter Cnt(PGO, S);
+ BreakContinueStack.push_back(BreakContinue());
+ Cnt.beginRegion(/*AddIncomingFallThrough=*/true);
+ CountMap[S->getBody()] = PGO.getCurrentRegionCount();
+ Visit(S->getBody());
+ Cnt.adjustForControlFlow();
+
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+ // The count at the start of the condition is equal to the count at the
+ // end of the body. The adjusted count does not include either the
+ // fall-through count coming into the loop or the continue count, so add
+ // both of those separately. This is coincidentally the same equation as
+ // with while loops but for different reasons.
+ Cnt.setCurrentRegionCount(Cnt.getParentCount() +
+ Cnt.getAdjustedCount() + BC.ContinueCount);
+ CountMap[S->getCond()] = PGO.getCurrentRegionCount();
+ Visit(S->getCond());
+ Cnt.adjustForControlFlow();
+ Cnt.applyAdjustmentsToRegion(BC.BreakCount + BC.ContinueCount);
+ RecordNextStmtCount = true;
+ }
+
+ void VisitForStmt(const ForStmt *S) {
+ RecordStmtCount(S);
+ if (S->getInit())
+ Visit(S->getInit());
+ // Counter tracks the body of the loop.
+ RegionCounter Cnt(PGO, S);
+ BreakContinueStack.push_back(BreakContinue());
+ // Visit the body region first. (This is basically the same as a while
+ // loop; see further comments in VisitWhileStmt.)
+ Cnt.beginRegion();
+ CountMap[S->getBody()] = PGO.getCurrentRegionCount();
+ Visit(S->getBody());
+ Cnt.adjustForControlFlow();
+
+ // The increment is essentially part of the body but it needs to include
+ // the count for all the continue statements.
+ if (S->getInc()) {
+ Cnt.setCurrentRegionCount(PGO.getCurrentRegionCount() +
+ BreakContinueStack.back().ContinueCount);
+ CountMap[S->getInc()] = PGO.getCurrentRegionCount();
+ Visit(S->getInc());
+ Cnt.adjustForControlFlow();
+ }
+
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+
+ // ...then go back and propagate counts through the condition.
+ if (S->getCond()) {
+ Cnt.setCurrentRegionCount(Cnt.getParentCount() +
+ Cnt.getAdjustedCount() +
+ BC.ContinueCount);
+ CountMap[S->getCond()] = PGO.getCurrentRegionCount();
+ Visit(S->getCond());
+ Cnt.adjustForControlFlow();
+ }
+ Cnt.applyAdjustmentsToRegion(BC.BreakCount + BC.ContinueCount);
+ RecordNextStmtCount = true;
+ }
+
+ void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
+ RecordStmtCount(S);
+ Visit(S->getRangeStmt());
+ Visit(S->getBeginEndStmt());
+ // Counter tracks the body of the loop.
+ RegionCounter Cnt(PGO, S);
+ BreakContinueStack.push_back(BreakContinue());
+ // Visit the body region first. (This is basically the same as a while
+ // loop; see further comments in VisitWhileStmt.)
+ Cnt.beginRegion();
+ CountMap[S->getLoopVarStmt()] = PGO.getCurrentRegionCount();
+ Visit(S->getLoopVarStmt());
+ Visit(S->getBody());
+ Cnt.adjustForControlFlow();
+
+ // The increment is essentially part of the body but it needs to include
+ // the count for all the continue statements.
+ Cnt.setCurrentRegionCount(PGO.getCurrentRegionCount() +
+ BreakContinueStack.back().ContinueCount);
+ CountMap[S->getInc()] = PGO.getCurrentRegionCount();
+ Visit(S->getInc());
+ Cnt.adjustForControlFlow();
+
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+
+ // ...then go back and propagate counts through the condition.
+ Cnt.setCurrentRegionCount(Cnt.getParentCount() +
+ Cnt.getAdjustedCount() +
+ BC.ContinueCount);
+ CountMap[S->getCond()] = PGO.getCurrentRegionCount();
+ Visit(S->getCond());
+ Cnt.adjustForControlFlow();
+ Cnt.applyAdjustmentsToRegion(BC.BreakCount + BC.ContinueCount);
+ RecordNextStmtCount = true;
+ }
+
+ void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
+ RecordStmtCount(S);
+ Visit(S->getElement());
+ // Counter tracks the body of the loop.
+ RegionCounter Cnt(PGO, S);
+ BreakContinueStack.push_back(BreakContinue());
+ Cnt.beginRegion();
+ CountMap[S->getBody()] = PGO.getCurrentRegionCount();
+ Visit(S->getBody());
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+ Cnt.adjustForControlFlow();
+ Cnt.applyAdjustmentsToRegion(BC.BreakCount + BC.ContinueCount);
+ RecordNextStmtCount = true;
+ }
+
+ void VisitSwitchStmt(const SwitchStmt *S) {
+ RecordStmtCount(S);
+ Visit(S->getCond());
+ PGO.setCurrentRegionUnreachable();
+ BreakContinueStack.push_back(BreakContinue());
+ Visit(S->getBody());
+ // If the switch is inside a loop, add the continue counts.
+ BreakContinue BC = BreakContinueStack.pop_back_val();
+ if (!BreakContinueStack.empty())
+ BreakContinueStack.back().ContinueCount += BC.ContinueCount;
+ // Counter tracks the exit block of the switch.
+ RegionCounter ExitCnt(PGO, S);
+ ExitCnt.beginRegion();
+ RecordNextStmtCount = true;
+ }
+
+ void VisitCaseStmt(const CaseStmt *S) {
+ RecordNextStmtCount = false;
+ // Counter for this particular case. This counts only jumps from the
+ // switch header and does not include fallthrough from the case before
+ // this one.
+ RegionCounter Cnt(PGO, S);
+ Cnt.beginRegion(/*AddIncomingFallThrough=*/true);
+ CountMap[S] = Cnt.getCount();
+ RecordNextStmtCount = true;
+ Visit(S->getSubStmt());
+ }
+
+ void VisitDefaultStmt(const DefaultStmt *S) {
+ RecordNextStmtCount = false;
+ // Counter for this default case. This does not include fallthrough from
+ // the previous case.
+ RegionCounter Cnt(PGO, S);
+ Cnt.beginRegion(/*AddIncomingFallThrough=*/true);
+ CountMap[S] = Cnt.getCount();
+ RecordNextStmtCount = true;
+ Visit(S->getSubStmt());
+ }
+
+ void VisitIfStmt(const IfStmt *S) {
+ RecordStmtCount(S);
+ // Counter tracks the "then" part of an if statement. The count for
+ // the "else" part, if it exists, will be calculated from this counter.
+ RegionCounter Cnt(PGO, S);
+ Visit(S->getCond());
+
+ Cnt.beginRegion();
+ CountMap[S->getThen()] = PGO.getCurrentRegionCount();
+ Visit(S->getThen());
+ Cnt.adjustForControlFlow();
+
+ if (S->getElse()) {
+ Cnt.beginElseRegion();
+ CountMap[S->getElse()] = PGO.getCurrentRegionCount();
+ Visit(S->getElse());
+ Cnt.adjustForControlFlow();
+ }
+ Cnt.applyAdjustmentsToRegion(0);
+ RecordNextStmtCount = true;
+ }
+
+ void VisitCXXTryStmt(const CXXTryStmt *S) {
+ RecordStmtCount(S);
+ Visit(S->getTryBlock());
+ for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
+ Visit(S->getHandler(I));
+ // Counter tracks the continuation block of the try statement.
+ RegionCounter Cnt(PGO, S);
+ Cnt.beginRegion();
+ RecordNextStmtCount = true;
+ }
+
+ void VisitCXXCatchStmt(const CXXCatchStmt *S) {
+ RecordNextStmtCount = false;
+ // Counter tracks the catch statement's handler block.
+ RegionCounter Cnt(PGO, S);
+ Cnt.beginRegion();
+ CountMap[S] = PGO.getCurrentRegionCount();
+ Visit(S->getHandlerBlock());
+ }
+
+ void VisitAbstractConditionalOperator(
+ const AbstractConditionalOperator *E) {
+ RecordStmtCount(E);
+ // Counter tracks the "true" part of a conditional operator. The
+ // count in the "false" part will be calculated from this counter.
+ RegionCounter Cnt(PGO, E);
+ Visit(E->getCond());
+
+ Cnt.beginRegion();
+ CountMap[E->getTrueExpr()] = PGO.getCurrentRegionCount();
+ Visit(E->getTrueExpr());
+ Cnt.adjustForControlFlow();
+
+ Cnt.beginElseRegion();
+ CountMap[E->getFalseExpr()] = PGO.getCurrentRegionCount();
+ Visit(E->getFalseExpr());
+ Cnt.adjustForControlFlow();
+
+ Cnt.applyAdjustmentsToRegion(0);
+ RecordNextStmtCount = true;
+ }
+
+ void VisitBinLAnd(const BinaryOperator *E) {
+ RecordStmtCount(E);
+ // Counter tracks the right hand side of a logical and operator.
+ RegionCounter Cnt(PGO, E);
+ Visit(E->getLHS());
+ Cnt.beginRegion();
+ CountMap[E->getRHS()] = PGO.getCurrentRegionCount();
+ Visit(E->getRHS());
+ Cnt.adjustForControlFlow();
+ Cnt.applyAdjustmentsToRegion(0);
+ RecordNextStmtCount = true;
+ }
+
+ void VisitBinLOr(const BinaryOperator *E) {
+ RecordStmtCount(E);
+ // Counter tracks the right hand side of a logical or operator.
+ RegionCounter Cnt(PGO, E);
+ Visit(E->getLHS());
+ Cnt.beginRegion();
+ CountMap[E->getRHS()] = PGO.getCurrentRegionCount();
+ Visit(E->getRHS());
+ Cnt.adjustForControlFlow();
+ Cnt.applyAdjustmentsToRegion(0);
+ RecordNextStmtCount = true;
+ }
+ };
+}
+
+void PGOHash::combine(HashType Type) {
+ // Check that we never combine 0 and only have six bits.
+ assert(Type && "Hash is invalid: unexpected type 0");
+ assert(unsigned(Type) < TooBig && "Hash is invalid: too many types");
+
+ // Pass through MD5 if enough work has built up.
+ if (Count && Count % NumTypesPerWord == 0) {
+ using namespace llvm::support;
+ uint64_t Swapped = endian::byte_swap<uint64_t, little>(Working);
+ MD5.update(llvm::makeArrayRef((uint8_t *)&Swapped, sizeof(Swapped)));
+ Working = 0;
+ }
+
+ // Accumulate the current type.
+ ++Count;
+ Working = Working << NumBitsPerType | Type;
+}
+
+uint64_t PGOHash::finalize() {
+ // Use Working as the hash directly if we never used MD5.
+ if (Count <= NumTypesPerWord)
+ // No need to byte swap here, since none of the math was endian-dependent.
+ // This number will be byte-swapped as required on endianness transitions,
+ // so we will see the same value on the other side.
+ return Working;
+
+ // Check for remaining work in Working.
+ if (Working)
+ MD5.update(Working);
+
+ // Finalize the MD5 and return the hash.
+ llvm::MD5::MD5Result Result;
+ MD5.final(Result);
+ using namespace llvm::support;
+ return endian::read<uint64_t, little, unaligned>(Result);
+}
+
+static void emitRuntimeHook(CodeGenModule &CGM) {
+ const char *const RuntimeVarName = "__llvm_profile_runtime";
+ const char *const RuntimeUserName = "__llvm_profile_runtime_user";
+ if (CGM.getModule().getGlobalVariable(RuntimeVarName))
+ return;
+
+ // Declare the runtime hook.
+ llvm::LLVMContext &Ctx = CGM.getLLVMContext();
+ auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
+ auto *Var = new llvm::GlobalVariable(CGM.getModule(), Int32Ty, false,
+ llvm::GlobalValue::ExternalLinkage,
+ nullptr, RuntimeVarName);
+
+ // Make a function that uses it.
+ auto *User = llvm::Function::Create(llvm::FunctionType::get(Int32Ty, false),
+ llvm::GlobalValue::LinkOnceODRLinkage,
+ RuntimeUserName, &CGM.getModule());
+ User->addFnAttr(llvm::Attribute::NoInline);
+ if (CGM.getCodeGenOpts().DisableRedZone)
+ User->addFnAttr(llvm::Attribute::NoRedZone);
+ CGBuilderTy Builder(llvm::BasicBlock::Create(CGM.getLLVMContext(), "", User));
+ auto *Load = Builder.CreateLoad(Var);
+ Builder.CreateRet(Load);
+
+ // Create a use of the function. Now the definition of the runtime variable
+ // should get pulled in, along with any static initializears.
+ CGM.addUsedGlobal(User);
+}
+
+void CodeGenPGO::assignRegionCounters(const Decl *D, llvm::Function *Fn) {
+ bool InstrumentRegions = CGM.getCodeGenOpts().ProfileInstrGenerate;
+ llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader();
+ if (!InstrumentRegions && !PGOReader)
+ return;
+ if (D->isImplicit())
+ return;
+ setFuncName(Fn);
+
+ // Set the linkage for variables based on the function linkage. Usually, we
+ // want to match it, but available_externally and extern_weak both have the
+ // wrong semantics.
+ VarLinkage = Fn->getLinkage();
+ switch (VarLinkage) {
+ case llvm::GlobalValue::ExternalWeakLinkage:
+ VarLinkage = llvm::GlobalValue::LinkOnceAnyLinkage;
+ break;
+ case llvm::GlobalValue::AvailableExternallyLinkage:
+ VarLinkage = llvm::GlobalValue::LinkOnceODRLinkage;
+ break;
+ default:
+ break;
+ }
+
+ mapRegionCounters(D);
+ if (InstrumentRegions) {
+ emitRuntimeHook(CGM);
+ emitCounterVariables();
+ }
+ if (PGOReader) {
+ SourceManager &SM = CGM.getContext().getSourceManager();
+ loadRegionCounts(PGOReader, SM.isInMainFile(D->getLocation()));
+ computeRegionCounts(D);
+ applyFunctionAttributes(PGOReader, Fn);
+ }
+}
+
+void CodeGenPGO::mapRegionCounters(const Decl *D) {
+ RegionCounterMap.reset(new llvm::DenseMap<const Stmt *, unsigned>);
+ MapRegionCounters Walker(*RegionCounterMap);
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
+ Walker.TraverseDecl(const_cast<FunctionDecl *>(FD));
+ else if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D))
+ Walker.TraverseDecl(const_cast<ObjCMethodDecl *>(MD));
+ else if (const BlockDecl *BD = dyn_cast_or_null<BlockDecl>(D))
+ Walker.TraverseDecl(const_cast<BlockDecl *>(BD));
+ else if (const CapturedDecl *CD = dyn_cast_or_null<CapturedDecl>(D))
+ Walker.TraverseDecl(const_cast<CapturedDecl *>(CD));
+ assert(Walker.NextCounter > 0 && "no entry counter mapped for decl");
+ NumRegionCounters = Walker.NextCounter;
+ FunctionHash = Walker.Hash.finalize();
+}
+
+void CodeGenPGO::computeRegionCounts(const Decl *D) {
+ StmtCountMap.reset(new llvm::DenseMap<const Stmt *, uint64_t>);
+ ComputeRegionCounts Walker(*StmtCountMap, *this);
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
+ Walker.VisitFunctionDecl(FD);
+ else if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D))
+ Walker.VisitObjCMethodDecl(MD);
+ else if (const BlockDecl *BD = dyn_cast_or_null<BlockDecl>(D))
+ Walker.VisitBlockDecl(BD);
+ else if (const CapturedDecl *CD = dyn_cast_or_null<CapturedDecl>(D))
+ Walker.VisitCapturedDecl(const_cast<CapturedDecl *>(CD));
+}
+
+void
+CodeGenPGO::applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader,
+ llvm::Function *Fn) {
+ if (!haveRegionCounts())
+ return;
+
+ uint64_t MaxFunctionCount = PGOReader->getMaximumFunctionCount();
+ uint64_t FunctionCount = getRegionCount(0);
+ if (FunctionCount >= (uint64_t)(0.3 * (double)MaxFunctionCount))
+ // Turn on InlineHint attribute for hot functions.
+ // FIXME: 30% is from preliminary tuning on SPEC, it may not be optimal.
+ Fn->addFnAttr(llvm::Attribute::InlineHint);
+ else if (FunctionCount <= (uint64_t)(0.01 * (double)MaxFunctionCount))
+ // Turn on Cold attribute for cold functions.
+ // FIXME: 1% is from preliminary tuning on SPEC, it may not be optimal.
+ Fn->addFnAttr(llvm::Attribute::Cold);
+}
+
+void CodeGenPGO::emitCounterVariables() {
+ llvm::LLVMContext &Ctx = CGM.getLLVMContext();
+ llvm::ArrayType *CounterTy = llvm::ArrayType::get(llvm::Type::getInt64Ty(Ctx),
+ NumRegionCounters);
+ RegionCounters =
+ new llvm::GlobalVariable(CGM.getModule(), CounterTy, false, VarLinkage,
+ llvm::Constant::getNullValue(CounterTy),
+ getFuncVarName("counters"));
+ RegionCounters->setAlignment(8);
+ RegionCounters->setSection(getCountersSection(CGM));
+}
+
+void CodeGenPGO::emitCounterIncrement(CGBuilderTy &Builder, unsigned Counter) {
+ if (!RegionCounters)
+ return;
+ llvm::Value *Addr =
+ Builder.CreateConstInBoundsGEP2_64(RegionCounters, 0, Counter);
+ llvm::Value *Count = Builder.CreateLoad(Addr, "pgocount");
+ Count = Builder.CreateAdd(Count, Builder.getInt64(1));
+ Builder.CreateStore(Count, Addr);
+}
+
+void CodeGenPGO::loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader,
+ bool IsInMainFile) {
+ CGM.getPGOStats().addVisited(IsInMainFile);
+ RegionCounts.reset(new std::vector<uint64_t>);
+ uint64_t Hash;
+ if (PGOReader->getFunctionCounts(getFuncName(), Hash, *RegionCounts)) {
+ CGM.getPGOStats().addMissing(IsInMainFile);
+ RegionCounts.reset();
+ } else if (Hash != FunctionHash ||
+ RegionCounts->size() != NumRegionCounters) {
+ CGM.getPGOStats().addMismatched(IsInMainFile);
+ RegionCounts.reset();
+ }
+}
+
+void CodeGenPGO::destroyRegionCounters() {
+ RegionCounterMap.reset();
+ StmtCountMap.reset();
+ RegionCounts.reset();
+ RegionCounters = nullptr;
+}
+
+/// \brief Calculate what to divide by to scale weights.
+///
+/// Given the maximum weight, calculate a divisor that will scale all the
+/// weights to strictly less than UINT32_MAX.
+static uint64_t calculateWeightScale(uint64_t MaxWeight) {
+ return MaxWeight < UINT32_MAX ? 1 : MaxWeight / UINT32_MAX + 1;
+}
+
+/// \brief Scale an individual branch weight (and add 1).
+///
+/// Scale a 64-bit weight down to 32-bits using \c Scale.
+///
+/// According to Laplace's Rule of Succession, it is better to compute the
+/// weight based on the count plus 1, so universally add 1 to the value.
+///
+/// \pre \c Scale was calculated by \a calculateWeightScale() with a weight no
+/// greater than \c Weight.
+static uint32_t scaleBranchWeight(uint64_t Weight, uint64_t Scale) {
+ assert(Scale && "scale by 0?");
+ uint64_t Scaled = Weight / Scale + 1;
+ assert(Scaled <= UINT32_MAX && "overflow 32-bits");
+ return Scaled;
+}
+
+llvm::MDNode *CodeGenPGO::createBranchWeights(uint64_t TrueCount,
+ uint64_t FalseCount) {
+ // Check for empty weights.
+ if (!TrueCount && !FalseCount)
+ return nullptr;
+
+ // Calculate how to scale down to 32-bits.
+ uint64_t Scale = calculateWeightScale(std::max(TrueCount, FalseCount));
+
+ llvm::MDBuilder MDHelper(CGM.getLLVMContext());
+ return MDHelper.createBranchWeights(scaleBranchWeight(TrueCount, Scale),
+ scaleBranchWeight(FalseCount, Scale));
+}
+
+llvm::MDNode *CodeGenPGO::createBranchWeights(ArrayRef<uint64_t> Weights) {
+ // We need at least two elements to create meaningful weights.
+ if (Weights.size() < 2)
+ return nullptr;
+
+ // Check for empty weights.
+ uint64_t MaxWeight = *std::max_element(Weights.begin(), Weights.end());
+ if (MaxWeight == 0)
+ return nullptr;
+
+ // Calculate how to scale down to 32-bits.
+ uint64_t Scale = calculateWeightScale(MaxWeight);
+
+ SmallVector<uint32_t, 16> ScaledWeights;
+ ScaledWeights.reserve(Weights.size());
+ for (uint64_t W : Weights)
+ ScaledWeights.push_back(scaleBranchWeight(W, Scale));
+
+ llvm::MDBuilder MDHelper(CGM.getLLVMContext());
+ return MDHelper.createBranchWeights(ScaledWeights);
+}
+
+llvm::MDNode *CodeGenPGO::createLoopWeights(const Stmt *Cond,
+ RegionCounter &Cnt) {
+ if (!haveRegionCounts())
+ return nullptr;
+ uint64_t LoopCount = Cnt.getCount();
+ uint64_t CondCount = 0;
+ bool Found = getStmtCount(Cond, CondCount);
+ assert(Found && "missing expected loop condition count");
+ (void)Found;
+ if (CondCount == 0)
+ return nullptr;
+ return createBranchWeights(LoopCount,
+ std::max(CondCount, LoopCount) - LoopCount);
+}
diff --git a/lib/CodeGen/CodeGenPGO.h b/lib/CodeGen/CodeGenPGO.h
new file mode 100644
index 000000000000..2f4aa660bea3
--- /dev/null
+++ b/lib/CodeGen/CodeGenPGO.h
@@ -0,0 +1,236 @@
+//===--- CodeGenPGO.h - PGO Instrumentation for LLVM CodeGen ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Instrumentation-based profile-guided optimization
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_CODEGENPGO_H
+#define CLANG_CODEGEN_CODEGENPGO_H
+
+#include "CGBuilder.h"
+#include "CodeGenModule.h"
+#include "CodeGenTypes.h"
+#include "clang/Frontend/CodeGenOptions.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
+
+namespace clang {
+namespace CodeGen {
+class RegionCounter;
+
+/// Per-function PGO state. This class should generally not be used directly,
+/// but instead through the CodeGenFunction and RegionCounter types.
+class CodeGenPGO {
+private:
+ CodeGenModule &CGM;
+ std::unique_ptr<std::string> PrefixedFuncName;
+ StringRef RawFuncName;
+ llvm::GlobalValue::LinkageTypes VarLinkage;
+
+ unsigned NumRegionCounters;
+ uint64_t FunctionHash;
+ llvm::GlobalVariable *RegionCounters;
+ std::unique_ptr<llvm::DenseMap<const Stmt *, unsigned>> RegionCounterMap;
+ std::unique_ptr<llvm::DenseMap<const Stmt *, uint64_t>> StmtCountMap;
+ std::unique_ptr<std::vector<uint64_t>> RegionCounts;
+ uint64_t CurrentRegionCount;
+
+public:
+ CodeGenPGO(CodeGenModule &CGM)
+ : CGM(CGM), NumRegionCounters(0), FunctionHash(0),
+ RegionCounters(nullptr), CurrentRegionCount(0) {}
+
+ /// Whether or not we have PGO region data for the current function. This is
+ /// false both when we have no data at all and when our data has been
+ /// discarded.
+ bool haveRegionCounts() const { return RegionCounts != nullptr; }
+
+ /// Get the string used to identify this function in the profile data.
+ /// For functions with local linkage, this includes the main file name.
+ StringRef getFuncName() const { return StringRef(*PrefixedFuncName); }
+ std::string getFuncVarName(StringRef VarName) const {
+ return ("__llvm_profile_" + VarName + "_" + RawFuncName).str();
+ }
+
+ /// Return the counter value of the current region.
+ uint64_t getCurrentRegionCount() const { return CurrentRegionCount; }
+
+ /// Set the counter value for the current region. This is used to keep track
+ /// of changes to the most recent counter from control flow and non-local
+ /// exits.
+ void setCurrentRegionCount(uint64_t Count) { CurrentRegionCount = Count; }
+
+ /// Indicate that the current region is never reached, and thus should have a
+ /// counter value of zero. This is important so that subsequent regions can
+ /// correctly track their parent counts.
+ void setCurrentRegionUnreachable() { setCurrentRegionCount(0); }
+
+ /// Check if an execution count is known for a given statement. If so, return
+ /// true and put the value in Count; else return false.
+ bool getStmtCount(const Stmt *S, uint64_t &Count) {
+ if (!StmtCountMap)
+ return false;
+ llvm::DenseMap<const Stmt*, uint64_t>::const_iterator
+ I = StmtCountMap->find(S);
+ if (I == StmtCountMap->end())
+ return false;
+ Count = I->second;
+ return true;
+ }
+
+ /// If the execution count for the current statement is known, record that
+ /// as the current count.
+ void setCurrentStmt(const Stmt *S) {
+ uint64_t Count;
+ if (getStmtCount(S, Count))
+ setCurrentRegionCount(Count);
+ }
+
+ /// Calculate branch weights appropriate for PGO data
+ llvm::MDNode *createBranchWeights(uint64_t TrueCount, uint64_t FalseCount);
+ llvm::MDNode *createBranchWeights(ArrayRef<uint64_t> Weights);
+ llvm::MDNode *createLoopWeights(const Stmt *Cond, RegionCounter &Cnt);
+
+ /// Assign counters to regions and configure them for PGO of a given
+ /// function. Does nothing if instrumentation is not enabled and either
+ /// generates global variables or associates PGO data with each of the
+ /// counters depending on whether we are generating or using instrumentation.
+ void assignRegionCounters(const Decl *D, llvm::Function *Fn);
+ /// Emit static data structures for instrumentation data.
+ void emitInstrumentationData();
+ /// Clean up region counter state. Must be called if assignRegionCounters is
+ /// used.
+ void destroyRegionCounters();
+ /// Emit static initialization code, if any.
+ static llvm::Function *emitInitialization(CodeGenModule &CGM);
+
+private:
+ void setFuncName(llvm::Function *Fn);
+ void mapRegionCounters(const Decl *D);
+ void computeRegionCounts(const Decl *D);
+ void applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader,
+ llvm::Function *Fn);
+ void loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader,
+ bool IsInMainFile);
+ void emitCounterVariables();
+ llvm::GlobalVariable *buildDataVar();
+
+ /// Emit code to increment the counter at the given index
+ void emitCounterIncrement(CGBuilderTy &Builder, unsigned Counter);
+
+ /// Return the region counter for the given statement. This should only be
+ /// called on statements that have a dedicated counter.
+ unsigned getRegionCounter(const Stmt *S) {
+ if (!RegionCounterMap)
+ return 0;
+ return (*RegionCounterMap)[S];
+ }
+
+ /// Return the region count for the counter at the given index.
+ uint64_t getRegionCount(unsigned Counter) {
+ if (!haveRegionCounts())
+ return 0;
+ return (*RegionCounts)[Counter];
+ }
+
+ friend class RegionCounter;
+};
+
+/// A counter for a particular region. This is the primary interface through
+/// which clients manage PGO counters and their values.
+class RegionCounter {
+ CodeGenPGO *PGO;
+ unsigned Counter;
+ uint64_t Count;
+ uint64_t ParentCount;
+ uint64_t RegionCount;
+ int64_t Adjust;
+
+ RegionCounter(CodeGenPGO &PGO, unsigned CounterIndex)
+ : PGO(&PGO), Counter(CounterIndex), Count(PGO.getRegionCount(Counter)),
+ ParentCount(PGO.getCurrentRegionCount()), Adjust(0) {}
+
+public:
+ RegionCounter(CodeGenPGO &PGO, const Stmt *S)
+ : PGO(&PGO), Counter(PGO.getRegionCounter(S)),
+ Count(PGO.getRegionCount(Counter)),
+ ParentCount(PGO.getCurrentRegionCount()), Adjust(0) {}
+
+ /// Get the value of the counter. In most cases this is the number of times
+ /// the region of the counter was entered, but for switch labels it's the
+ /// number of direct jumps to that label.
+ uint64_t getCount() const { return Count; }
+
+ /// Get the value of the counter with adjustments applied. Adjustments occur
+ /// when control enters or leaves the region abnormally; i.e., if there is a
+ /// jump to a label within the region, or if the function can return from
+ /// within the region. The adjusted count, then, is the value of the counter
+ /// at the end of the region.
+ uint64_t getAdjustedCount() const {
+ return Count + Adjust;
+ }
+
+ /// Get the value of the counter in this region's parent, i.e., the region
+ /// that was active when this region began. This is useful for deriving
+ /// counts in implicitly counted regions, like the false case of a condition
+ /// or the normal exits of a loop.
+ uint64_t getParentCount() const { return ParentCount; }
+
+ /// Activate the counter by emitting an increment and starting to track
+ /// adjustments. If AddIncomingFallThrough is true, the current region count
+ /// will be added to the counter for the purposes of tracking the region.
+ void beginRegion(CGBuilderTy &Builder, bool AddIncomingFallThrough=false) {
+ beginRegion(AddIncomingFallThrough);
+ PGO->emitCounterIncrement(Builder, Counter);
+ }
+ void beginRegion(bool AddIncomingFallThrough=false) {
+ RegionCount = Count;
+ if (AddIncomingFallThrough)
+ RegionCount += PGO->getCurrentRegionCount();
+ PGO->setCurrentRegionCount(RegionCount);
+ }
+
+ /// For counters on boolean branches, begins tracking adjustments for the
+ /// uncounted path.
+ void beginElseRegion() {
+ RegionCount = ParentCount - Count;
+ PGO->setCurrentRegionCount(RegionCount);
+ }
+
+ /// Reset the current region count.
+ void setCurrentRegionCount(uint64_t CurrentCount) {
+ RegionCount = CurrentCount;
+ PGO->setCurrentRegionCount(RegionCount);
+ }
+
+ /// Adjust for non-local control flow after emitting a subexpression or
+ /// substatement. This must be called to account for constructs such as gotos,
+ /// labels, and returns, so that we can ensure that our region's count is
+ /// correct in the code that follows.
+ void adjustForControlFlow() {
+ Adjust += PGO->getCurrentRegionCount() - RegionCount;
+ // Reset the region count in case this is called again later.
+ RegionCount = PGO->getCurrentRegionCount();
+ }
+
+ /// Commit all adjustments to the current region. If the region is a loop,
+ /// the LoopAdjust value should be the count of all the breaks and continues
+ /// from the loop, to compensate for those counts being deducted from the
+ /// adjustments for the body of the loop.
+ void applyAdjustmentsToRegion(uint64_t LoopAdjust) {
+ PGO->setCurrentRegionCount(ParentCount + Adjust + LoopAdjust);
+ }
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp
index 699cc2eabe18..53ba02a81397 100644
--- a/lib/CodeGen/CodeGenTBAA.cpp
+++ b/lib/CodeGen/CodeGenTBAA.cpp
@@ -33,7 +33,7 @@ CodeGenTBAA::CodeGenTBAA(ASTContext &Ctx, llvm::LLVMContext& VMContext,
const CodeGenOptions &CGO,
const LangOptions &Features, MangleContext &MContext)
: Context(Ctx), CodeGenOpts(CGO), Features(Features), MContext(MContext),
- MDHelper(VMContext), Root(0), Char(0) {
+ MDHelper(VMContext), Root(nullptr), Char(nullptr) {
}
CodeGenTBAA::~CodeGenTBAA() {
@@ -88,7 +88,7 @@ llvm::MDNode *
CodeGenTBAA::getTBAAInfo(QualType QTy) {
// At -O0 or relaxed aliasing, TBAA is not emitted for regular types.
if (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing)
- return NULL;
+ return nullptr;
// If the type has the may_alias attribute (even on a typedef), it is
// effectively in the general char alias class.
@@ -221,7 +221,7 @@ CodeGenTBAA::getTBAAStructInfo(QualType QTy) {
return MDHelper.createTBAAStructNode(Fields);
// For now, handle any other kind of type conservatively.
- return StructMetadataCache[Ty] = NULL;
+ return StructMetadataCache[Ty] = nullptr;
}
/// Check if the given type can be handled by path-aware TBAA.
@@ -261,7 +261,7 @@ CodeGenTBAA::getTBAAStructTypeInfo(QualType QTy) {
else
FieldNode = getTBAAInfo(FieldQTy);
if (!FieldNode)
- return StructTypeMetadataCache[Ty] = NULL;
+ return StructTypeMetadataCache[Ty] = nullptr;
Fields.push_back(std::make_pair(
FieldNode, Layout.getFieldOffset(idx) / Context.getCharWidth()));
}
@@ -280,7 +280,7 @@ CodeGenTBAA::getTBAAStructTypeInfo(QualType QTy) {
MDHelper.createTBAAStructTypeNode(OutName, Fields);
}
- return StructMetadataCache[Ty] = NULL;
+ return StructMetadataCache[Ty] = nullptr;
}
/// Return a TBAA tag node for both scalar TBAA and struct-path aware TBAA.
@@ -288,7 +288,7 @@ llvm::MDNode *
CodeGenTBAA::getTBAAStructTagInfo(QualType BaseQTy, llvm::MDNode *AccessNode,
uint64_t Offset) {
if (!AccessNode)
- return NULL;
+ return nullptr;
if (!CodeGenOpts.StructPathTBAA)
return getTBAAScalarTagInfo(AccessNode);
@@ -298,7 +298,7 @@ CodeGenTBAA::getTBAAStructTagInfo(QualType BaseQTy, llvm::MDNode *AccessNode,
if (llvm::MDNode *N = StructTagMetadataCache[PathTag])
return N;
- llvm::MDNode *BNode = 0;
+ llvm::MDNode *BNode = nullptr;
if (isTBAAPathStruct(BaseQTy))
BNode = getTBAAStructTypeInfo(BaseQTy);
if (!BNode)
@@ -312,7 +312,7 @@ CodeGenTBAA::getTBAAStructTagInfo(QualType BaseQTy, llvm::MDNode *AccessNode,
llvm::MDNode *
CodeGenTBAA::getTBAAScalarTagInfo(llvm::MDNode *AccessNode) {
if (!AccessNode)
- return NULL;
+ return nullptr;
if (llvm::MDNode *N = ScalarTagMetadataCache[AccessNode])
return N;
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 5f3c59c197a6..d4e22623e029 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -38,10 +38,7 @@ CodeGenTypes::CodeGenTypes(CodeGenModule &cgm)
}
CodeGenTypes::~CodeGenTypes() {
- for (llvm::DenseMap<const Type *, CGRecordLayout *>::iterator
- I = CGRecordLayouts.begin(), E = CGRecordLayouts.end();
- I != E; ++I)
- delete I->second;
+ llvm::DeleteContainerSeconds(CGRecordLayouts);
for (llvm::FoldingSet<CGFunctionInfo>::iterator
I = FunctionInfos.begin(), E = FunctionInfos.end(); I != E; )
@@ -134,17 +131,15 @@ isSafeToConvert(const RecordDecl *RD, CodeGenTypes &CGT,
// 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(),
+ for (const auto &I : CRD->bases())
+ 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)
+ for (const auto *I : RD->fields())
if (!isSafeToConvert(I->getType(), CGT, AlreadyChecked))
return false;
@@ -186,24 +181,23 @@ static bool isSafeToConvert(const RecordDecl *RD, CodeGenTypes &CGT) {
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
+/// isFuncParamTypeConvertible - Return true if the specified type in a
+/// function parameter 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) {
+bool CodeGenTypes::isFuncParamTypeConvertible(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 (!TT) return true;
+
// Incomplete types cannot be converted.
if (TT->isIncompleteType())
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;
+ if (!RT) 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
@@ -217,17 +211,17 @@ bool CodeGenTypes::isFuncTypeArgumentConvertible(QualType Ty) {
/// 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
+/// and all of the parameter 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()))
+ if (!isFuncParamTypeConvertible(FT->getReturnType()))
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)))
+ for (unsigned i = 0, e = FPT->getNumParams(); i != e; i++)
+ if (!isFuncParamTypeConvertible(FPT->getParamType(i)))
return false;
return true;
@@ -248,6 +242,10 @@ void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) {
if (!ConvertType(ED->getIntegerType())->isIntegerTy(32))
TypeCache.clear();
}
+ // If necessary, provide the full definition of a type only used with a
+ // declaration so far.
+ if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
+ DI->completeType(ED);
return;
}
@@ -306,7 +304,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
return TCI->second;
// If we don't have it in the cache, convert it now.
- llvm::Type *ResultType = 0;
+ llvm::Type *ResultType = nullptr;
switch (Ty->getTypeClass()) {
case Type::Record: // Handled above.
#define TYPE(Class, Base)
@@ -479,11 +477,11 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
// Force conversion of all the relevant record types, to make sure
// we re-convert the FunctionType when appropriate.
- if (const RecordType *RT = FT->getResultType()->getAs<RecordType>())
+ if (const RecordType *RT = FT->getReturnType()->getAs<RecordType>())
ConvertRecordDeclType(RT->getDecl());
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT))
- for (unsigned i = 0, e = FPT->getNumArgs(); i != e; i++)
- if (const RecordType *RT = FPT->getArgType(i)->getAs<RecordType>())
+ for (unsigned i = 0, e = FPT->getNumParams(); i != e; i++)
+ if (const RecordType *RT = FPT->getParamType(i)->getAs<RecordType>())
ConvertRecordDeclType(RT->getDecl());
// Return a placeholder type.
@@ -493,7 +491,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
break;
}
- // While we're converting the argument types for a function, we don't want
+ // While we're converting the parameter 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)) {
@@ -631,7 +629,7 @@ llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) {
llvm::StructType *&Entry = RecordDeclTypes[Key];
// If we don't have a StructType at all yet, create the forward declaration.
- if (Entry == 0) {
+ if (!Entry) {
Entry = llvm::StructType::create(getLLVMContext());
addRecordTypeName(RD, Entry, "");
}
@@ -640,7 +638,7 @@ llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) {
// 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 || !RD->isCompleteDefinition() || !Ty->isOpaque())
+ if (!RD || !RD->isCompleteDefinition() || !Ty->isOpaque())
return Ty;
// If converting this type would cause us to infinitely loop, don't do it!
@@ -655,11 +653,10 @@ llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) {
// Force conversion of non-virtual base classes recursively.
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;
+ for (const auto &I : CRD->bases()) {
+ if (I.isVirtual()) continue;
- ConvertRecordDeclType(i->getType()->getAs<RecordType>()->getDecl());
+ ConvertRecordDeclType(I.getType()->getAs<RecordType>()->getDecl());
}
}
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 94ca9e21e5fe..fe155b53b3c4 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -104,7 +104,7 @@ class CodeGenTypes {
private:
/// TypeCache - This map keeps cache of llvm::Types
- /// and maps llvm::Types to corresponding clang::Type.
+ /// and maps clang::Type to corresponding llvm::Type.
llvm::DenseMap<const Type *, llvm::Type *> TypeCache;
public:
@@ -136,8 +136,8 @@ public:
/// be converted to an LLVM type (i.e. doesn't depend on an incomplete tag
/// type).
bool isFuncTypeConvertible(const FunctionType *FT);
- bool isFuncTypeArgumentConvertible(QualType Ty);
-
+ bool isFuncParamTypeConvertible(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.
@@ -175,10 +175,10 @@ public:
const CGFunctionInfo &arrangeGlobalDeclaration(GlobalDecl GD);
const CGFunctionInfo &arrangeFunctionDeclaration(const FunctionDecl *FD);
- const CGFunctionInfo &arrangeFunctionDeclaration(QualType ResTy,
- const FunctionArgList &Args,
- const FunctionType::ExtInfo &Info,
- bool isVariadic);
+ const CGFunctionInfo &
+ arrangeFreeFunctionDeclaration(QualType ResTy, const FunctionArgList &Args,
+ const FunctionType::ExtInfo &Info,
+ bool isVariadic);
const CGFunctionInfo &arrangeObjCMethodDeclaration(const ObjCMethodDecl *MD);
const CGFunctionInfo &arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
@@ -188,6 +188,10 @@ public:
const CGFunctionInfo &arrangeCXXConstructorDeclaration(
const CXXConstructorDecl *D,
CXXCtorType Type);
+ const CGFunctionInfo &arrangeCXXConstructorCall(const CallArgList &Args,
+ const CXXConstructorDecl *D,
+ CXXCtorType CtorKind,
+ unsigned ExtraArgs);
const CGFunctionInfo &arrangeCXXDestructor(const CXXDestructorDecl *D,
CXXDtorType Type);
@@ -216,6 +220,7 @@ public:
///
/// \param argTypes - must all actually be canonical as params
const CGFunctionInfo &arrangeLLVMFunctionInfo(CanQualType returnType,
+ bool IsInstanceMethod,
ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
RequiredArgs args);
diff --git a/lib/CodeGen/EHScopeStack.h b/lib/CodeGen/EHScopeStack.h
index e9d9a339ffc7..b9ccfb63d7d5 100644
--- a/lib/CodeGen/EHScopeStack.h
+++ b/lib/CodeGen/EHScopeStack.h
@@ -19,8 +19,8 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/BasicBlock.h"
-#include "llvm/IR/Value.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Value.h"
namespace clang {
namespace CodeGen {
@@ -65,9 +65,9 @@ template <class T> struct InvariantValue {
template <class T> struct DominatingValue : InvariantValue<T> {};
template <class T, bool mightBeInstruction =
- llvm::is_base_of<llvm::Value, T>::value &&
- !llvm::is_base_of<llvm::Constant, T>::value &&
- !llvm::is_base_of<llvm::BasicBlock, T>::value>
+ std::is_base_of<llvm::Value, T>::value &&
+ !std::is_base_of<llvm::Constant, T>::value &&
+ !std::is_base_of<llvm::BasicBlock, T>::value>
struct DominatingPointer;
template <class T> struct DominatingPointer<T,false> : InvariantValue<T*> {};
// template <class T> struct DominatingPointer<T,true> at end of file
@@ -182,7 +182,7 @@ public:
typedef typename DominatingValue<A0>::saved_type A0_saved;
A0_saved a0_saved;
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
T(a0).Emit(CGF, flags);
}
@@ -199,7 +199,7 @@ public:
A0_saved a0_saved;
A1_saved a1_saved;
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
T(a0, a1).Emit(CGF, flags);
@@ -219,7 +219,7 @@ public:
A1_saved a1_saved;
A2_saved a2_saved;
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved);
@@ -242,7 +242,7 @@ public:
A2_saved a2_saved;
A3_saved a3_saved;
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved);
@@ -301,8 +301,8 @@ private:
void *pushCleanup(CleanupKind K, size_t DataSize);
public:
- EHScopeStack() : StartOfBuffer(0), EndOfBuffer(0), StartOfData(0),
- InnermostNormalCleanup(stable_end()),
+ EHScopeStack() : StartOfBuffer(nullptr), EndOfBuffer(nullptr),
+ StartOfData(nullptr), InnermostNormalCleanup(stable_end()),
InnermostEHScope(stable_end()) {}
~EHScopeStack() { delete[] StartOfBuffer; }
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 0e8f31a48454..d7e61f0fe577 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -25,6 +25,7 @@
#include "CodeGenModule.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/Type.h"
+#include "llvm/IR/CallSite.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Value.h"
@@ -52,128 +53,154 @@ public:
CGCXXABI(CGM), UseARMMethodPtrABI(UseARMMethodPtrABI),
UseARMGuardVarABI(UseARMGuardVarABI) { }
- bool isReturnTypeIndirect(const CXXRecordDecl *RD) const {
- // Structures with either a non-trivial destructor or a non-trivial
- // copy constructor are always indirect.
- return !RD->hasTrivialDestructor() || RD->hasNonTrivialCopyConstructor();
- }
+ bool classifyReturnType(CGFunctionInfo &FI) const override;
- RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const {
+ RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override {
// Structures with either a non-trivial destructor or a non-trivial
// copy constructor are always indirect.
- if (!RD->hasTrivialDestructor() || RD->hasNonTrivialCopyConstructor())
+ // FIXME: Use canCopyArgument() when it is fixed to handle lazily declared
+ // special members.
+ if (RD->hasNonTrivialDestructor() || RD->hasNonTrivialCopyConstructor())
return RAA_Indirect;
return RAA_Default;
}
- bool isZeroInitializable(const MemberPointerType *MPT);
+ bool isZeroInitializable(const MemberPointerType *MPT) override;
- llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT);
+ llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT) override;
- llvm::Value *EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
- llvm::Value *&This,
- llvm::Value *MemFnPtr,
- const MemberPointerType *MPT);
+ llvm::Value *
+ EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
+ const Expr *E,
+ llvm::Value *&This,
+ llvm::Value *MemFnPtr,
+ const MemberPointerType *MPT) override;
- llvm::Value *EmitMemberDataPointerAddress(CodeGenFunction &CGF,
- llvm::Value *Base,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT);
+ llvm::Value *
+ EmitMemberDataPointerAddress(CodeGenFunction &CGF, const Expr *E,
+ llvm::Value *Base,
+ llvm::Value *MemPtr,
+ const MemberPointerType *MPT) override;
llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF,
const CastExpr *E,
- llvm::Value *Src);
+ llvm::Value *Src) override;
llvm::Constant *EmitMemberPointerConversion(const CastExpr *E,
- llvm::Constant *Src);
+ llvm::Constant *Src) override;
- llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT);
+ llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT) override;
- llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD);
+ llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD) override;
llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
- CharUnits offset);
- llvm::Constant *EmitMemberPointer(const APValue &MP, QualType MPT);
+ CharUnits offset) override;
+ llvm::Constant *EmitMemberPointer(const APValue &MP, QualType MPT) override;
llvm::Constant *BuildMemberPointer(const CXXMethodDecl *MD,
CharUnits ThisAdjustment);
llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF,
- llvm::Value *L,
- llvm::Value *R,
+ llvm::Value *L, llvm::Value *R,
const MemberPointerType *MPT,
- bool Inequality);
+ bool Inequality) override;
llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
- llvm::Value *Addr,
- const MemberPointerType *MPT);
+ llvm::Value *Addr,
+ const MemberPointerType *MPT) override;
- llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
- llvm::Value *ptr,
- QualType type);
+ llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF, llvm::Value *ptr,
+ QualType type) override;
- llvm::Value *GetVirtualBaseClassOffset(CodeGenFunction &CGF,
- llvm::Value *This,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl);
+ void EmitFundamentalRTTIDescriptor(QualType Type);
+ void EmitFundamentalRTTIDescriptors();
+ llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) override;
+
+ bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy) override;
+ void EmitBadTypeidCall(CodeGenFunction &CGF) override;
+ llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy,
+ llvm::Value *ThisPtr,
+ llvm::Type *StdTypeInfoPtrTy) override;
+
+ bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
+ QualType SrcRecordTy) override;
+
+ llvm::Value *EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
+ QualType SrcRecordTy, QualType DestTy,
+ QualType DestRecordTy,
+ llvm::BasicBlock *CastEnd) override;
+
+ llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF, llvm::Value *Value,
+ QualType SrcRecordTy,
+ QualType DestTy) override;
+
+ bool EmitBadCastCall(CodeGenFunction &CGF) override;
+
+ llvm::Value *
+ GetVirtualBaseClassOffset(CodeGenFunction &CGF, llvm::Value *This,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl) override;
void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
- CXXCtorType T,
- CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys);
+ CXXCtorType T, CanQualType &ResTy,
+ SmallVectorImpl<CanQualType> &ArgTys) override;
- void EmitCXXConstructors(const CXXConstructorDecl *D);
+ void EmitCXXConstructors(const CXXConstructorDecl *D) override;
void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
- CXXDtorType T,
- CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys);
+ CXXDtorType T, CanQualType &ResTy,
+ SmallVectorImpl<CanQualType> &ArgTys) override;
bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor,
- CXXDtorType DT) const {
+ CXXDtorType DT) const override {
// Itanium does not emit any destructor variant as an inline thunk.
// Delegating may occur as an optimization, but all variants are either
// emitted with external linkage or as linkonce if they are inline and used.
return false;
}
- void EmitCXXDestructors(const CXXDestructorDecl *D);
+ void EmitCXXDestructors(const CXXDestructorDecl *D) override;
+
+ void addImplicitStructorParams(CodeGenFunction &CGF, QualType &ResTy,
+ FunctionArgList &Params) override;
- void BuildInstanceFunctionParams(CodeGenFunction &CGF,
- QualType &ResTy,
- FunctionArgList &Params);
+ void EmitInstanceFunctionProlog(CodeGenFunction &CGF) override;
- void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
+ unsigned addImplicitConstructorArgs(CodeGenFunction &CGF,
+ const CXXConstructorDecl *D,
+ CXXCtorType Type, bool ForVirtualBase,
+ bool Delegating,
+ CallArgList &Args) override;
- void EmitConstructorCall(CodeGenFunction &CGF,
- const CXXConstructorDecl *D, CXXCtorType Type,
- bool ForVirtualBase, bool Delegating,
- llvm::Value *This,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd);
+ void EmitDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *DD,
+ CXXDtorType Type, bool ForVirtualBase,
+ bool Delegating, llvm::Value *This) override;
- void emitVTableDefinitions(CodeGenVTables &CGVT, const CXXRecordDecl *RD);
+ void emitVTableDefinitions(CodeGenVTables &CGVT,
+ const CXXRecordDecl *RD) override;
llvm::Value *getVTableAddressPointInStructor(
CodeGenFunction &CGF, const CXXRecordDecl *VTableClass,
BaseSubobject Base, const CXXRecordDecl *NearestVBase,
- bool &NeedsVirtualOffset);
+ bool &NeedsVirtualOffset) override;
llvm::Constant *
getVTableAddressPointForConstExpr(BaseSubobject Base,
- const CXXRecordDecl *VTableClass);
+ const CXXRecordDecl *VTableClass) override;
llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD,
- CharUnits VPtrOffset);
+ CharUnits VPtrOffset) override;
llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD,
- llvm::Value *This, llvm::Type *Ty);
+ llvm::Value *This,
+ llvm::Type *Ty) override;
void EmitVirtualDestructorCall(CodeGenFunction &CGF,
const CXXDestructorDecl *Dtor,
CXXDtorType DtorType, SourceLocation CallLoc,
- llvm::Value *This);
+ llvm::Value *This) override;
- void emitVirtualInheritanceTables(const CXXRecordDecl *RD);
+ void emitVirtualInheritanceTables(const CXXRecordDecl *RD) override;
- void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) {
+ void setThunkLinkage(llvm::Function *Thunk, bool ForVTable, GlobalDecl GD,
+ bool ReturnAdjustment) override {
// Allow inlining of thunks by emitting them with available_externally
// linkage together with vtables when needed.
if (ForVTable)
@@ -181,38 +208,71 @@ public:
}
llvm::Value *performThisAdjustment(CodeGenFunction &CGF, llvm::Value *This,
- const ThisAdjustment &TA);
+ const ThisAdjustment &TA) override;
llvm::Value *performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret,
- const ReturnAdjustment &RA);
+ const ReturnAdjustment &RA) override;
- StringRef GetPureVirtualCallName() { return "__cxa_pure_virtual"; }
- StringRef GetDeletedVirtualCallName() { return "__cxa_deleted_virtual"; }
+ StringRef GetPureVirtualCallName() override { return "__cxa_pure_virtual"; }
+ StringRef GetDeletedVirtualCallName() override
+ { return "__cxa_deleted_virtual"; }
- CharUnits getArrayCookieSizeImpl(QualType elementType);
+ CharUnits getArrayCookieSizeImpl(QualType elementType) override;
llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF,
llvm::Value *NewPtr,
llvm::Value *NumElements,
const CXXNewExpr *expr,
- QualType ElementType);
+ QualType ElementType) override;
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF,
llvm::Value *allocPtr,
- CharUnits cookieSize);
+ CharUnits cookieSize) override;
void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
- llvm::GlobalVariable *DeclPtr, bool PerformInit);
+ llvm::GlobalVariable *DeclPtr,
+ bool PerformInit) override;
void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
- llvm::Constant *dtor, llvm::Constant *addr);
+ llvm::Constant *dtor, llvm::Constant *addr) override;
llvm::Function *getOrCreateThreadLocalWrapper(const VarDecl *VD,
llvm::GlobalVariable *Var);
void EmitThreadLocalInitFuncs(
- llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
- llvm::Function *InitFunc);
- LValue EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF,
- const DeclRefExpr *DRE);
+ ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
+ llvm::Function *InitFunc) override;
+ LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD,
+ QualType LValType) override;
+
+ bool NeedsVTTParameter(GlobalDecl GD) override;
+
+ /**************************** RTTI Uniqueness ******************************/
+
+protected:
+ /// Returns true if the ABI requires RTTI type_info objects to be unique
+ /// across a program.
+ virtual bool shouldRTTIBeUnique() const { return true; }
+
+public:
+ /// What sort of unique-RTTI behavior should we use?
+ enum RTTIUniquenessKind {
+ /// We are guaranteeing, or need to guarantee, that the RTTI string
+ /// is unique.
+ RUK_Unique,
+
+ /// We are not guaranteeing uniqueness for the RTTI string, so we
+ /// can demote to hidden visibility but must use string comparisons.
+ RUK_NonUniqueHidden,
+
+ /// We are not guaranteeing uniqueness for the RTTI string, so we
+ /// have to use string comparisons, but we also have to emit it with
+ /// non-hidden visibility.
+ RUK_NonUniqueVisible
+ };
- bool NeedsVTTParameter(GlobalDecl GD);
+ /// Return the required visibility status for the given type and linkage in
+ /// the current ABI.
+ RTTIUniquenessKind
+ classifyRTTIUniqueness(QualType CanTy,
+ llvm::GlobalValue::LinkageTypes Linkage) const;
+ friend class ItaniumRTTIBuilder;
};
class ARMCXXABI : public ItaniumCXXABI {
@@ -221,22 +281,31 @@ public:
ItaniumCXXABI(CGM, /* UseARMMethodPtrABI = */ true,
/* UseARMGuardVarABI = */ true) {}
- bool HasThisReturn(GlobalDecl GD) const {
+ bool HasThisReturn(GlobalDecl GD) const override {
return (isa<CXXConstructorDecl>(GD.getDecl()) || (
isa<CXXDestructorDecl>(GD.getDecl()) &&
GD.getDtorType() != Dtor_Deleting));
}
- void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResTy);
+ void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV,
+ QualType ResTy) override;
- CharUnits getArrayCookieSizeImpl(QualType elementType);
+ CharUnits getArrayCookieSizeImpl(QualType elementType) override;
llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF,
llvm::Value *NewPtr,
llvm::Value *NumElements,
const CXXNewExpr *expr,
- QualType ElementType);
+ QualType ElementType) override;
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr,
- CharUnits cookieSize);
+ CharUnits cookieSize) override;
+};
+
+class iOS64CXXABI : public ARMCXXABI {
+public:
+ iOS64CXXABI(CodeGen::CodeGenModule &CGM) : ARMCXXABI(CGM) {}
+
+ // ARM64 libraries are prepared for non-unique RTTI.
+ bool shouldRTTIBeUnique() const override { return false; }
};
}
@@ -248,6 +317,9 @@ CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) {
case TargetCXXABI::iOS:
return new ARMCXXABI(CGM);
+ case TargetCXXABI::iOS64:
+ return new iOS64CXXABI(CGM);
+
// Note that AArch64 uses the generic ItaniumCXXABI class since it doesn't
// include the other 32-bit ARM oddities: constructor/destructor return values
// and array cookies.
@@ -299,11 +371,9 @@ ItaniumCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
///
/// If the member is non-virtual, memptr.ptr is the address of
/// the function to call.
-llvm::Value *
-ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
- llvm::Value *&This,
- llvm::Value *MemFnPtr,
- const MemberPointerType *MPT) {
+llvm::Value *ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
+ CodeGenFunction &CGF, const Expr *E, llvm::Value *&This,
+ llvm::Value *MemFnPtr, const MemberPointerType *MPT) {
CGBuilderTy &Builder = CGF.Builder;
const FunctionProtoType *FPT =
@@ -355,8 +425,7 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
// Cast the adjusted this to a pointer to vtable pointer and load.
llvm::Type *VTableTy = Builder.getInt8PtrTy();
- llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy->getPointerTo());
- VTable = Builder.CreateLoad(VTable, "memptr.vtable");
+ llvm::Value *VTable = CGF.GetVTablePtr(This, VTableTy);
// Apply the offset.
llvm::Value *VTableOffset = FnAsInt;
@@ -385,10 +454,9 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
/// Compute an l-value by applying the given pointer-to-member to a
/// base object.
-llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
- llvm::Value *Base,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT) {
+llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(
+ CodeGenFunction &CGF, const Expr *E, llvm::Value *Base, llvm::Value *MemPtr,
+ const MemberPointerType *MPT) {
assert(MemPtr->getType() == CGM.PtrDiffTy);
CGBuilderTy &Builder = CGF.Builder;
@@ -748,6 +816,21 @@ ItaniumCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
return Result;
}
+bool ItaniumCXXABI::classifyReturnType(CGFunctionInfo &FI) const {
+ const CXXRecordDecl *RD = FI.getReturnType()->getAsCXXRecordDecl();
+ if (!RD)
+ return false;
+
+ // Return indirectly if we have a non-trivial copy ctor or non-trivial dtor.
+ // FIXME: Use canCopyArgument() when it is fixed to handle lazily declared
+ // special members.
+ if (RD->hasNonTrivialDestructor() || RD->hasNonTrivialCopyConstructor()) {
+ FI.getReturnInfo() = ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+ return true;
+ }
+ return false;
+}
+
/// The Itanium ABI requires non-zero initialization only for data
/// member pointers, for which '0' is a valid offset.
bool ItaniumCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
@@ -773,6 +856,194 @@ llvm::Value *ItaniumCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
return CGF.Builder.CreateInBoundsGEP(ptr, offset);
}
+static llvm::Constant *getItaniumDynamicCastFn(CodeGenFunction &CGF) {
+ // void *__dynamic_cast(const void *sub,
+ // const abi::__class_type_info *src,
+ // const abi::__class_type_info *dst,
+ // std::ptrdiff_t src2dst_offset);
+
+ llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
+ llvm::Type *PtrDiffTy =
+ CGF.ConvertType(CGF.getContext().getPointerDiffType());
+
+ llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy };
+
+ llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false);
+
+ // Mark the function as nounwind readonly.
+ llvm::Attribute::AttrKind FuncAttrs[] = { llvm::Attribute::NoUnwind,
+ llvm::Attribute::ReadOnly };
+ llvm::AttributeSet Attrs = llvm::AttributeSet::get(
+ CGF.getLLVMContext(), llvm::AttributeSet::FunctionIndex, FuncAttrs);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__dynamic_cast", Attrs);
+}
+
+static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) {
+ // void __cxa_bad_cast();
+ llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_cast");
+}
+
+/// \brief Compute the src2dst_offset hint as described in the
+/// Itanium C++ ABI [2.9.7]
+static CharUnits computeOffsetHint(ASTContext &Context,
+ const CXXRecordDecl *Src,
+ const CXXRecordDecl *Dst) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+
+ // If Dst is not derived from Src we can skip the whole computation below and
+ // return that Src is not a public base of Dst. Record all inheritance paths.
+ if (!Dst->isDerivedFrom(Src, Paths))
+ return CharUnits::fromQuantity(-2ULL);
+
+ unsigned NumPublicPaths = 0;
+ CharUnits Offset;
+
+ // Now walk all possible inheritance paths.
+ for (CXXBasePaths::paths_iterator I = Paths.begin(), E = Paths.end(); I != E;
+ ++I) {
+ if (I->Access != AS_public) // Ignore non-public inheritance.
+ continue;
+
+ ++NumPublicPaths;
+
+ for (CXXBasePath::iterator J = I->begin(), JE = I->end(); J != JE; ++J) {
+ // If the path contains a virtual base class we can't give any hint.
+ // -1: no hint.
+ if (J->Base->isVirtual())
+ return CharUnits::fromQuantity(-1ULL);
+
+ if (NumPublicPaths > 1) // Won't use offsets, skip computation.
+ continue;
+
+ // Accumulate the base class offsets.
+ const ASTRecordLayout &L = Context.getASTRecordLayout(J->Class);
+ Offset += L.getBaseClassOffset(J->Base->getType()->getAsCXXRecordDecl());
+ }
+ }
+
+ // -2: Src is not a public base of Dst.
+ if (NumPublicPaths == 0)
+ return CharUnits::fromQuantity(-2ULL);
+
+ // -3: Src is a multiple public base type but never a virtual base type.
+ if (NumPublicPaths > 1)
+ return CharUnits::fromQuantity(-3ULL);
+
+ // Otherwise, the Src type is a unique public nonvirtual base type of Dst.
+ // Return the offset of Src from the origin of Dst.
+ return Offset;
+}
+
+static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) {
+ // void __cxa_bad_typeid();
+ llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid");
+}
+
+bool ItaniumCXXABI::shouldTypeidBeNullChecked(bool IsDeref,
+ QualType SrcRecordTy) {
+ return IsDeref;
+}
+
+void ItaniumCXXABI::EmitBadTypeidCall(CodeGenFunction &CGF) {
+ llvm::Value *Fn = getBadTypeidFn(CGF);
+ CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
+ CGF.Builder.CreateUnreachable();
+}
+
+llvm::Value *ItaniumCXXABI::EmitTypeid(CodeGenFunction &CGF,
+ QualType SrcRecordTy,
+ llvm::Value *ThisPtr,
+ llvm::Type *StdTypeInfoPtrTy) {
+ llvm::Value *Value =
+ CGF.GetVTablePtr(ThisPtr, StdTypeInfoPtrTy->getPointerTo());
+
+ // Load the type info.
+ Value = CGF.Builder.CreateConstInBoundsGEP1_64(Value, -1ULL);
+ return CGF.Builder.CreateLoad(Value);
+}
+
+bool ItaniumCXXABI::shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
+ QualType SrcRecordTy) {
+ return SrcIsPtr;
+}
+
+llvm::Value *ItaniumCXXABI::EmitDynamicCastCall(
+ CodeGenFunction &CGF, llvm::Value *Value, QualType SrcRecordTy,
+ QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastEnd) {
+ llvm::Type *PtrDiffLTy =
+ CGF.ConvertType(CGF.getContext().getPointerDiffType());
+ llvm::Type *DestLTy = CGF.ConvertType(DestTy);
+
+ llvm::Value *SrcRTTI =
+ CGF.CGM.GetAddrOfRTTIDescriptor(SrcRecordTy.getUnqualifiedType());
+ llvm::Value *DestRTTI =
+ CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());
+
+ // Compute the offset hint.
+ const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
+ const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl();
+ llvm::Value *OffsetHint = llvm::ConstantInt::get(
+ PtrDiffLTy,
+ computeOffsetHint(CGF.getContext(), SrcDecl, DestDecl).getQuantity());
+
+ // Emit the call to __dynamic_cast.
+ Value = CGF.EmitCastToVoidPtr(Value);
+
+ llvm::Value *args[] = {Value, SrcRTTI, DestRTTI, OffsetHint};
+ Value = CGF.EmitNounwindRuntimeCall(getItaniumDynamicCastFn(CGF), args);
+ Value = CGF.Builder.CreateBitCast(Value, DestLTy);
+
+ /// C++ [expr.dynamic.cast]p9:
+ /// A failed cast to reference type throws std::bad_cast
+ if (DestTy->isReferenceType()) {
+ llvm::BasicBlock *BadCastBlock =
+ CGF.createBasicBlock("dynamic_cast.bad_cast");
+
+ llvm::Value *IsNull = CGF.Builder.CreateIsNull(Value);
+ CGF.Builder.CreateCondBr(IsNull, BadCastBlock, CastEnd);
+
+ CGF.EmitBlock(BadCastBlock);
+ EmitBadCastCall(CGF);
+ }
+
+ return Value;
+}
+
+llvm::Value *ItaniumCXXABI::EmitDynamicCastToVoid(CodeGenFunction &CGF,
+ llvm::Value *Value,
+ QualType SrcRecordTy,
+ QualType DestTy) {
+ llvm::Type *PtrDiffLTy =
+ CGF.ConvertType(CGF.getContext().getPointerDiffType());
+ llvm::Type *DestLTy = CGF.ConvertType(DestTy);
+
+ // Get the vtable pointer.
+ llvm::Value *VTable = CGF.GetVTablePtr(Value, PtrDiffLTy->getPointerTo());
+
+ // Get the offset-to-top from the vtable.
+ llvm::Value *OffsetToTop =
+ CGF.Builder.CreateConstInBoundsGEP1_64(VTable, -2ULL);
+ OffsetToTop = CGF.Builder.CreateLoad(OffsetToTop, "offset.to.top");
+
+ // Finally, add the offset to the pointer.
+ Value = CGF.EmitCastToVoidPtr(Value);
+ Value = CGF.Builder.CreateInBoundsGEP(Value, OffsetToTop);
+
+ return CGF.Builder.CreateBitCast(Value, DestLTy);
+}
+
+bool ItaniumCXXABI::EmitBadCastCall(CodeGenFunction &CGF) {
+ llvm::Value *Fn = getBadCastFn(CGF);
+ CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
+ CGF.Builder.CreateUnreachable();
+ return true;
+}
+
llvm::Value *
ItaniumCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
llvm::Value *This,
@@ -797,34 +1068,35 @@ ItaniumCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
/// The generic ABI passes 'this', plus a VTT if it's initializing a
/// base subobject.
-void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
- CXXCtorType Type,
- CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys) {
+void
+ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
+ CXXCtorType Type, CanQualType &ResTy,
+ SmallVectorImpl<CanQualType> &ArgTys) {
ASTContext &Context = getContext();
- // 'this' parameter is already there, as well as 'this' return if
- // HasThisReturn(GlobalDecl(Ctor, Type)) is true
+ // All parameters are already in place except VTT, which goes after 'this'.
+ // These are Clang types, so we don't need to worry about sret yet.
// Check if we need to add a VTT parameter (which has type void **).
if (Type == Ctor_Base && Ctor->getParent()->getNumVBases() != 0)
- ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy));
+ ArgTys.insert(ArgTys.begin() + 1,
+ Context.getPointerType(Context.VoidPtrTy));
}
void ItaniumCXXABI::EmitCXXConstructors(const CXXConstructorDecl *D) {
// Just make sure we're in sync with TargetCXXABI.
assert(CGM.getTarget().getCXXABI().hasConstructorVariants());
+ // The constructor used for constructing this as a base class;
+ // ignores virtual bases.
+ CGM.EmitGlobal(GlobalDecl(D, Ctor_Base));
+
// The constructor used for constructing this as a complete class;
// constucts the virtual bases, then calls the base constructor.
if (!D->getParent()->isAbstract()) {
// We don't need to emit the complete ctor if the class is abstract.
CGM.EmitGlobal(GlobalDecl(D, Ctor_Complete));
}
-
- // The constructor used for constructing this as a base class;
- // ignores virtual bases.
- CGM.EmitGlobal(GlobalDecl(D, Ctor_Base));
}
/// The generic ABI passes 'this', plus a VTT if it's destroying a
@@ -844,29 +1116,26 @@ void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
}
void ItaniumCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) {
- // The destructor in a virtual table is always a 'deleting'
- // destructor, which calls the complete destructor and then uses the
- // appropriate operator delete.
- if (D->isVirtual())
- CGM.EmitGlobal(GlobalDecl(D, Dtor_Deleting));
+ // The destructor used for destructing this as a base class; ignores
+ // virtual bases.
+ CGM.EmitGlobal(GlobalDecl(D, Dtor_Base));
// The destructor used for destructing this as a most-derived class;
// call the base destructor and then destructs any virtual bases.
CGM.EmitGlobal(GlobalDecl(D, Dtor_Complete));
- // The destructor used for destructing this as a base class; ignores
- // virtual bases.
- CGM.EmitGlobal(GlobalDecl(D, Dtor_Base));
+ // The destructor in a virtual table is always a 'deleting'
+ // destructor, which calls the complete destructor and then uses the
+ // appropriate operator delete.
+ if (D->isVirtual())
+ CGM.EmitGlobal(GlobalDecl(D, Dtor_Deleting));
}
-void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
- QualType &ResTy,
- FunctionArgList &Params) {
- /// Create the 'this' variable.
- BuildThisParam(CGF, Params);
-
+void ItaniumCXXABI::addImplicitStructorParams(CodeGenFunction &CGF,
+ QualType &ResTy,
+ FunctionArgList &Params) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
- assert(MD->isInstance());
+ assert(isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD));
// Check if we need a VTT parameter as well.
if (NeedsVTTParameter(CGF.CurGD)) {
@@ -875,10 +1144,10 @@ void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
// FIXME: avoid the fake decl
QualType T = Context.getPointerType(Context.VoidPtrTy);
ImplicitParamDecl *VTTDecl
- = ImplicitParamDecl::Create(Context, 0, MD->getLocation(),
+ = ImplicitParamDecl::Create(Context, nullptr, MD->getLocation(),
&Context.Idents.get("vtt"), T);
- Params.push_back(VTTDecl);
- getVTTDecl(CGF) = VTTDecl;
+ Params.insert(Params.begin() + 1, VTTDecl);
+ getStructorImplicitParamDecl(CGF) = VTTDecl;
}
}
@@ -887,10 +1156,9 @@ void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
EmitThisParam(CGF);
/// Initialize the 'vtt' slot if needed.
- if (getVTTDecl(CGF)) {
- getVTTValue(CGF)
- = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getVTTDecl(CGF)),
- "vtt");
+ if (getStructorImplicitParamDecl(CGF)) {
+ getStructorImplicitParamValue(CGF) = CGF.Builder.CreateLoad(
+ CGF.GetAddrOfLocalVar(getStructorImplicitParamDecl(CGF)), "vtt");
}
/// If this is a function that the ABI specifies returns 'this', initialize
@@ -905,21 +1173,39 @@ void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
}
-void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
- const CXXConstructorDecl *D,
- CXXCtorType Type,
- bool ForVirtualBase, bool Delegating,
- llvm::Value *This,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd) {
- llvm::Value *VTT = CGF.GetVTTParameter(GlobalDecl(D, Type), ForVirtualBase,
- Delegating);
+unsigned ItaniumCXXABI::addImplicitConstructorArgs(
+ CodeGenFunction &CGF, const CXXConstructorDecl *D, CXXCtorType Type,
+ bool ForVirtualBase, bool Delegating, CallArgList &Args) {
+ if (!NeedsVTTParameter(GlobalDecl(D, Type)))
+ return 0;
+
+ // Insert the implicit 'vtt' argument as the second argument.
+ llvm::Value *VTT =
+ CGF.GetVTTParameter(GlobalDecl(D, Type), ForVirtualBase, Delegating);
QualType VTTTy = getContext().getPointerType(getContext().VoidPtrTy);
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
+ Args.insert(Args.begin() + 1,
+ CallArg(RValue::get(VTT), VTTTy, /*needscopy=*/false));
+ return 1; // Added one arg.
+}
+
+void ItaniumCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *DD,
+ CXXDtorType Type, bool ForVirtualBase,
+ bool Delegating, llvm::Value *This) {
+ GlobalDecl GD(DD, Type);
+ llvm::Value *VTT = CGF.GetVTTParameter(GD, ForVirtualBase, Delegating);
+ QualType VTTTy = getContext().getPointerType(getContext().VoidPtrTy);
+
+ llvm::Value *Callee = nullptr;
+ if (getContext().getLangOpts().AppleKext)
+ Callee = CGF.BuildAppleKextVirtualDestructorCall(DD, Type, DD->getParent());
+
+ if (!Callee)
+ Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
// FIXME: Provide a source location here.
- CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(),
- This, VTT, VTTTy, ArgBeg, ArgEnd);
+ CGF.EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
+ VTT, VTTTy, nullptr, nullptr);
}
void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
@@ -931,18 +1217,20 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
ItaniumVTableContext &VTContext = CGM.getItaniumVTableContext();
const VTableLayout &VTLayout = VTContext.getVTableLayout(RD);
llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
+ llvm::Constant *RTTI =
+ CGM.GetAddrOfRTTIDescriptor(CGM.getContext().getTagDeclType(RD));
// Create and set the initializer.
llvm::Constant *Init = CGVT.CreateVTableInitializer(
RD, VTLayout.vtable_component_begin(), VTLayout.getNumVTableComponents(),
- VTLayout.vtable_thunk_begin(), VTLayout.getNumVTableThunks());
+ VTLayout.vtable_thunk_begin(), VTLayout.getNumVTableThunks(), RTTI);
VTable->setInitializer(Init);
// Set the correct linkage.
VTable->setLinkage(Linkage);
// Set the right visibility.
- CGM.setTypeVisibility(VTable, RD, CodeGenModule::TVK_ForVTable);
+ CGM.setGlobalVisibility(VTable, RD);
// If this is the magic class __cxxabiv1::__fundamental_type_info,
// we will emit the typeinfo for the fundamental types. This is the
@@ -953,7 +1241,7 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
isa<NamespaceDecl>(DC) && cast<NamespaceDecl>(DC)->getIdentifier() &&
cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__cxxabiv1") &&
DC->getParent()->isTranslationUnit())
- CGM.EmitFundamentalRTTIDescriptors();
+ EmitFundamentalRTTIDescriptors();
}
llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructor(
@@ -1028,6 +1316,12 @@ llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
VTable = CGM.CreateOrReplaceCXXRuntimeVariable(
Name, ArrayType, llvm::GlobalValue::ExternalLinkage);
VTable->setUnnamedAddr(true);
+
+ if (RD->hasAttr<DLLImportAttr>())
+ VTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+ else if (RD->hasAttr<DLLExportAttr>())
+ VTable->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
+
return VTable;
}
@@ -1059,7 +1353,8 @@ void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
getVirtualFunctionPointer(CGF, GlobalDecl(Dtor, DtorType), This, Ty);
CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This,
- /*ImplicitParam=*/0, QualType(), 0, 0);
+ /*ImplicitParam=*/nullptr, QualType(), nullptr,
+ nullptr);
}
void ItaniumCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) {
@@ -1305,7 +1600,7 @@ namespace {
llvm::GlobalVariable *Guard;
CallGuardAbort(llvm::GlobalVariable *Guard) : Guard(Guard) {}
- void Emit(CodeGenFunction &CGF, Flags flags) {
+ void Emit(CodeGenFunction &CGF, Flags flags) override {
CGF.EmitNounwindRuntimeCall(getGuardAbortFn(CGF.CGM, Guard->getType()),
Guard);
}
@@ -1365,25 +1660,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
}
// Test whether the variable has completed initialization.
- llvm::Value *isInitialized;
-
- // ARM C++ ABI 3.2.3.1:
- // To support the potential use of initialization guard variables
- // as semaphores that are the target of ARM SWP and LDREX/STREX
- // synchronizing instructions we define a static initialization
- // guard variable to be a 4-byte aligned, 4- byte word with the
- // following inline access protocol.
- // #define INITIALIZED 1
- // if ((obj_guard & INITIALIZED) != INITIALIZED) {
- // if (__cxa_guard_acquire(&obj_guard))
- // ...
- // }
- if (UseARMGuardVarABI && !useInt8GuardVariable) {
- llvm::Value *V = Builder.CreateLoad(guard);
- llvm::Value *Test1 = llvm::ConstantInt::get(guardTy, 1);
- V = Builder.CreateAnd(V, Test1);
- isInitialized = Builder.CreateIsNull(V, "guard.uninitialized");
-
+ //
// Itanium C++ ABI 3.3.2:
// The following is pseudo-code showing how these functions can be used:
// if (obj_guard.first_byte == 0) {
@@ -1398,23 +1675,46 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// __cxa_guard_release (&obj_guard);
// }
// }
- } else {
- // Load the first byte of the guard variable.
- llvm::LoadInst *LI =
+
+ // Load the first byte of the guard variable.
+ llvm::LoadInst *LI =
Builder.CreateLoad(Builder.CreateBitCast(guard, CGM.Int8PtrTy));
- LI->setAlignment(1);
-
- // 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.
- //
- // In LLVM, we do this by marking the load Acquire.
- if (threadsafe)
- LI->setAtomic(llvm::Acquire);
-
- isInitialized = Builder.CreateIsNull(LI, "guard.uninitialized");
- }
+ LI->setAlignment(1);
+
+ // 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.
+ //
+ // In LLVM, we do this by marking the load Acquire.
+ if (threadsafe)
+ LI->setAtomic(llvm::Acquire);
+
+ // For ARM, we should only check the first bit, rather than the entire byte:
+ //
+ // ARM C++ ABI 3.2.3.1:
+ // To support the potential use of initialization guard variables
+ // as semaphores that are the target of ARM SWP and LDREX/STREX
+ // synchronizing instructions we define a static initialization
+ // guard variable to be a 4-byte aligned, 4-byte word with the
+ // following inline access protocol.
+ // #define INITIALIZED 1
+ // if ((obj_guard & INITIALIZED) != INITIALIZED) {
+ // if (__cxa_guard_acquire(&obj_guard))
+ // ...
+ // }
+ //
+ // and similarly for ARM64:
+ //
+ // ARM64 C++ ABI 3.2.2:
+ // This ABI instead only specifies the value bit 0 of the static guard
+ // variable; all other bits are platform defined. Bit 0 shall be 0 when the
+ // variable is not initialized and 1 when it is.
+ llvm::Value *V =
+ (UseARMGuardVarABI && !useInt8GuardVariable)
+ ? Builder.CreateAnd(LI, llvm::ConstantInt::get(CGM.Int8Ty, 1))
+ : LI;
+ llvm::Value *isInitialized = Builder.CreateIsNull(V, "guard.uninitialized");
llvm::BasicBlock *InitCheckBlock = CGF.createBasicBlock("init.check");
llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
@@ -1518,16 +1818,34 @@ void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
CGF.registerGlobalDtorWithAtExit(D, dtor, addr);
}
+static bool isThreadWrapperReplaceable(const VarDecl *VD,
+ CodeGen::CodeGenModule &CGM) {
+ assert(!VD->isStaticLocal() && "static local VarDecls don't need wrappers!");
+ // OS X prefers to have references to thread local variables to go through
+ // the thread wrapper instead of directly referencing the backing variable.
+ return VD->getTLSKind() == VarDecl::TLS_Dynamic &&
+ CGM.getTarget().getTriple().isMacOSX();
+}
+
/// Get the appropriate linkage for the wrapper function. This is essentially
-/// the weak form of the variable's linkage; every translation unit which wneeds
+/// the weak form of the variable's linkage; every translation unit which needs
/// the wrapper emits a copy, and we want the linker to merge them.
-static llvm::GlobalValue::LinkageTypes getThreadLocalWrapperLinkage(
- llvm::GlobalValue::LinkageTypes VarLinkage) {
- if (llvm::GlobalValue::isLinkerPrivateLinkage(VarLinkage))
- return llvm::GlobalValue::LinkerPrivateWeakLinkage;
+static llvm::GlobalValue::LinkageTypes
+getThreadLocalWrapperLinkage(const VarDecl *VD, CodeGen::CodeGenModule &CGM) {
+ llvm::GlobalValue::LinkageTypes VarLinkage =
+ CGM.getLLVMLinkageVarDefinition(VD, /*isConstant=*/false);
+
// For internal linkage variables, we don't need an external or weak wrapper.
if (llvm::GlobalValue::isLocalLinkage(VarLinkage))
return VarLinkage;
+
+ // If the thread wrapper is replaceable, give it appropriate linkage.
+ if (isThreadWrapperReplaceable(VD, CGM)) {
+ if (llvm::GlobalVariable::isLinkOnceLinkage(VarLinkage) ||
+ llvm::GlobalVariable::isWeakODRLinkage(VarLinkage))
+ return llvm::GlobalVariable::WeakAnyLinkage;
+ return VarLinkage;
+ }
return llvm::GlobalValue::WeakODRLinkage;
}
@@ -1550,21 +1868,28 @@ ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD,
RetTy = RetTy->getPointerElementType();
llvm::FunctionType *FnTy = llvm::FunctionType::get(RetTy, false);
- llvm::Function *Wrapper = llvm::Function::Create(
- FnTy, getThreadLocalWrapperLinkage(Var->getLinkage()), WrapperName.str(),
- &CGM.getModule());
+ llvm::Function *Wrapper =
+ llvm::Function::Create(FnTy, getThreadLocalWrapperLinkage(VD, CGM),
+ WrapperName.str(), &CGM.getModule());
// Always resolve references to the wrapper at link time.
- Wrapper->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ if (!Wrapper->hasLocalLinkage() && !isThreadWrapperReplaceable(VD, CGM))
+ Wrapper->setVisibility(llvm::GlobalValue::HiddenVisibility);
return Wrapper;
}
void ItaniumCXXABI::EmitThreadLocalInitFuncs(
- llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
+ ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
llvm::Function *InitFunc) {
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
const VarDecl *VD = Decls[I].first;
llvm::GlobalVariable *Var = Decls[I].second;
+ // Some targets require that all access to thread local variables go through
+ // the thread wrapper. This means that we cannot attempt to create a thread
+ // wrapper or a thread helper.
+ if (isThreadWrapperReplaceable(VD, CGM) && !VD->hasDefinition())
+ continue;
+
// Mangle the name for the thread_local initialization function.
SmallString<256> InitFnName;
{
@@ -1576,14 +1901,13 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
// If we have a definition for the variable, emit the initialization
// function as an alias to the global Init function (if any). Otherwise,
// produce a declaration of the initialization function.
- llvm::GlobalValue *Init = 0;
+ llvm::GlobalValue *Init = nullptr;
bool InitIsInitFunc = false;
if (VD->hasDefinition()) {
InitIsInitFunc = true;
if (InitFunc)
- Init =
- new llvm::GlobalAlias(InitFunc->getType(), Var->getLinkage(),
- InitFnName.str(), InitFunc, &CGM.getModule());
+ Init = llvm::GlobalAlias::create(Var->getLinkage(), InitFnName.str(),
+ InitFunc);
} else {
// Emit a weak global function referring to the initialization function.
// This function will not exist if the TU defining the thread_local
@@ -1632,9 +1956,9 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
}
}
-LValue ItaniumCXXABI::EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF,
- const DeclRefExpr *DRE) {
- const VarDecl *VD = cast<VarDecl>(DRE->getDecl());
+LValue ItaniumCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF,
+ const VarDecl *VD,
+ QualType LValType) {
QualType T = VD->getType();
llvm::Type *Ty = CGF.getTypes().ConvertTypeForMem(T);
llvm::Value *Val = CGF.CGM.GetAddrOfGlobalVar(VD, Ty);
@@ -1645,10 +1969,9 @@ LValue ItaniumCXXABI::EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF,
LValue LV;
if (VD->getType()->isReferenceType())
- LV = CGF.MakeNaturalAlignAddrLValue(Val, T);
+ LV = CGF.MakeNaturalAlignAddrLValue(Val, LValType);
else
- LV = CGF.MakeAddrLValue(Val, DRE->getType(),
- CGF.getContext().getDeclAlign(VD));
+ LV = CGF.MakeAddrLValue(Val, LValType, CGF.getContext().getDeclAlign(VD));
// FIXME: need setObjCGCLValueClass?
return LV;
}
@@ -1672,3 +1995,996 @@ bool ItaniumCXXABI::NeedsVTTParameter(GlobalDecl GD) {
return false;
}
+
+namespace {
+class ItaniumRTTIBuilder {
+ CodeGenModule &CGM; // Per-module state.
+ llvm::LLVMContext &VMContext;
+ const ItaniumCXXABI &CXXABI; // Per-module state.
+
+ /// Fields - The fields of the RTTI descriptor currently being built.
+ SmallVector<llvm::Constant *, 16> Fields;
+
+ /// GetAddrOfTypeName - Returns the mangled type name of the given type.
+ llvm::GlobalVariable *
+ GetAddrOfTypeName(QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage);
+
+ /// GetAddrOfExternalRTTIDescriptor - Returns the constant for the RTTI
+ /// descriptor of the given type.
+ llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty);
+
+ /// BuildVTablePointer - Build the vtable pointer for the given type.
+ void BuildVTablePointer(const Type *Ty);
+
+ /// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
+ /// inheritance, according to the Itanium C++ ABI, 2.9.5p6b.
+ void BuildSIClassTypeInfo(const CXXRecordDecl *RD);
+
+ /// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for
+ /// classes with bases that do not satisfy the abi::__si_class_type_info
+ /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
+ void BuildVMIClassTypeInfo(const CXXRecordDecl *RD);
+
+ /// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, used
+ /// for pointer types.
+ void BuildPointerTypeInfo(QualType PointeeTy);
+
+ /// BuildObjCObjectTypeInfo - Build the appropriate kind of
+ /// type_info for an object type.
+ void BuildObjCObjectTypeInfo(const ObjCObjectType *Ty);
+
+ /// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info
+ /// struct, used for member pointer types.
+ void BuildPointerToMemberTypeInfo(const MemberPointerType *Ty);
+
+public:
+ ItaniumRTTIBuilder(const ItaniumCXXABI &ABI)
+ : CGM(ABI.CGM), VMContext(CGM.getModule().getContext()), CXXABI(ABI) {}
+
+ // Pointer type info flags.
+ enum {
+ /// PTI_Const - Type has const qualifier.
+ PTI_Const = 0x1,
+
+ /// PTI_Volatile - Type has volatile qualifier.
+ PTI_Volatile = 0x2,
+
+ /// PTI_Restrict - Type has restrict qualifier.
+ PTI_Restrict = 0x4,
+
+ /// PTI_Incomplete - Type is incomplete.
+ PTI_Incomplete = 0x8,
+
+ /// PTI_ContainingClassIncomplete - Containing class is incomplete.
+ /// (in pointer to member).
+ PTI_ContainingClassIncomplete = 0x10
+ };
+
+ // VMI type info flags.
+ enum {
+ /// VMI_NonDiamondRepeat - Class has non-diamond repeated inheritance.
+ VMI_NonDiamondRepeat = 0x1,
+
+ /// VMI_DiamondShaped - Class is diamond shaped.
+ VMI_DiamondShaped = 0x2
+ };
+
+ // Base class type info flags.
+ enum {
+ /// BCTI_Virtual - Base class is virtual.
+ BCTI_Virtual = 0x1,
+
+ /// BCTI_Public - Base class is public.
+ BCTI_Public = 0x2
+ };
+
+ /// BuildTypeInfo - Build the RTTI type info struct for the given type.
+ ///
+ /// \param Force - true to force the creation of this RTTI value
+ llvm::Constant *BuildTypeInfo(QualType Ty, bool Force = false);
+};
+}
+
+llvm::GlobalVariable *ItaniumRTTIBuilder::GetAddrOfTypeName(
+ QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage) {
+ SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, Out);
+ Out.flush();
+ StringRef Name = OutName.str();
+
+ // We know that the mangled name of the type starts at index 4 of the
+ // mangled name of the typename, so we can just index into it in order to
+ // get the mangled name of the type.
+ llvm::Constant *Init = llvm::ConstantDataArray::getString(VMContext,
+ Name.substr(4));
+
+ llvm::GlobalVariable *GV =
+ CGM.CreateOrReplaceCXXRuntimeVariable(Name, Init->getType(), Linkage);
+
+ GV->setInitializer(Init);
+
+ return GV;
+}
+
+llvm::Constant *
+ItaniumRTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
+ // Mangle the RTTI name.
+ SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
+ Out.flush();
+ StringRef Name = OutName.str();
+
+ // Look for an existing global.
+ llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(Name);
+
+ if (!GV) {
+ // Create a new global variable.
+ GV = new llvm::GlobalVariable(CGM.getModule(), CGM.Int8PtrTy,
+ /*Constant=*/true,
+ llvm::GlobalValue::ExternalLinkage, nullptr,
+ Name);
+ }
+
+ return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
+}
+
+/// TypeInfoIsInStandardLibrary - Given a builtin type, returns whether the type
+/// info for that type is defined in the standard library.
+static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
+ // Itanium C++ ABI 2.9.2:
+ // Basic type information (e.g. for "int", "bool", etc.) will be kept in
+ // the run-time support library. Specifically, the run-time support
+ // library should contain type_info objects for the types X, X* and
+ // X const*, for every X in: void, std::nullptr_t, bool, wchar_t, char,
+ // unsigned char, signed char, short, unsigned short, int, unsigned int,
+ // long, unsigned long, long long, unsigned long long, float, double,
+ // long double, char16_t, char32_t, and the IEEE 754r decimal and
+ // half-precision floating point types.
+ switch (Ty->getKind()) {
+ case BuiltinType::Void:
+ case BuiltinType::NullPtr:
+ case BuiltinType::Bool:
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ case BuiltinType::Char_U:
+ case BuiltinType::Char_S:
+ case BuiltinType::UChar:
+ case BuiltinType::SChar:
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ case BuiltinType::Long:
+ case BuiltinType::ULong:
+ case BuiltinType::LongLong:
+ case BuiltinType::ULongLong:
+ case BuiltinType::Half:
+ case BuiltinType::Float:
+ case BuiltinType::Double:
+ case BuiltinType::LongDouble:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::Int128:
+ case BuiltinType::UInt128:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLSampler:
+ case BuiltinType::OCLEvent:
+ return true;
+
+ case BuiltinType::Dependent:
+#define BUILTIN_TYPE(Id, SingletonId)
+#define PLACEHOLDER_TYPE(Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
+ llvm_unreachable("asking for RRTI for a placeholder type!");
+
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ llvm_unreachable("FIXME: Objective-C types are unsupported!");
+ }
+
+ llvm_unreachable("Invalid BuiltinType Kind!");
+}
+
+static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) {
+ QualType PointeeTy = PointerTy->getPointeeType();
+ const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(PointeeTy);
+ if (!BuiltinTy)
+ return false;
+
+ // Check the qualifiers.
+ Qualifiers Quals = PointeeTy.getQualifiers();
+ Quals.removeConst();
+
+ if (!Quals.empty())
+ return false;
+
+ return TypeInfoIsInStandardLibrary(BuiltinTy);
+}
+
+/// IsStandardLibraryRTTIDescriptor - Returns whether the type
+/// information for the given type exists in the standard library.
+static bool IsStandardLibraryRTTIDescriptor(QualType Ty) {
+ // Type info for builtin types is defined in the standard library.
+ if (const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(Ty))
+ return TypeInfoIsInStandardLibrary(BuiltinTy);
+
+ // Type info for some pointer types to builtin types is defined in the
+ // standard library.
+ if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
+ return TypeInfoIsInStandardLibrary(PointerTy);
+
+ return false;
+}
+
+/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for
+/// the given type exists somewhere else, and that we should not emit the type
+/// information in this translation unit. Assumes that it is not a
+/// standard-library type.
+static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM,
+ QualType Ty) {
+ ASTContext &Context = CGM.getContext();
+
+ // If RTTI is disabled, assume it might be disabled in the
+ // translation unit that defines any potential key function, too.
+ if (!Context.getLangOpts().RTTI) return false;
+
+ if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (!RD->hasDefinition())
+ return false;
+
+ if (!RD->isDynamicClass())
+ return false;
+
+ // FIXME: this may need to be reconsidered if the key function
+ // changes.
+ return CGM.getVTables().isVTableExternal(RD);
+ }
+
+ return false;
+}
+
+/// IsIncompleteClassType - Returns whether the given record type is incomplete.
+static bool IsIncompleteClassType(const RecordType *RecordTy) {
+ return !RecordTy->getDecl()->isCompleteDefinition();
+}
+
+/// ContainsIncompleteClassType - Returns whether the given type contains an
+/// incomplete class type. This is true if
+///
+/// * The given type is an incomplete class type.
+/// * The given type is a pointer type whose pointee type contains an
+/// incomplete class type.
+/// * The given type is a member pointer type whose class is an incomplete
+/// class type.
+/// * The given type is a member pointer type whoise pointee type contains an
+/// incomplete class type.
+/// is an indirect or direct pointer to an incomplete class type.
+static bool ContainsIncompleteClassType(QualType Ty) {
+ if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
+ if (IsIncompleteClassType(RecordTy))
+ return true;
+ }
+
+ if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty))
+ return ContainsIncompleteClassType(PointerTy->getPointeeType());
+
+ if (const MemberPointerType *MemberPointerTy =
+ dyn_cast<MemberPointerType>(Ty)) {
+ // Check if the class type is incomplete.
+ const RecordType *ClassType = cast<RecordType>(MemberPointerTy->getClass());
+ if (IsIncompleteClassType(ClassType))
+ return true;
+
+ return ContainsIncompleteClassType(MemberPointerTy->getPointeeType());
+ }
+
+ return false;
+}
+
+// CanUseSingleInheritance - Return whether the given record decl has a "single,
+// public, non-virtual base at offset zero (i.e. the derived class is dynamic
+// iff the base is)", according to Itanium C++ ABI, 2.95p6b.
+static bool CanUseSingleInheritance(const CXXRecordDecl *RD) {
+ // Check the number of bases.
+ if (RD->getNumBases() != 1)
+ return false;
+
+ // Get the base.
+ CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin();
+
+ // Check that the base is not virtual.
+ if (Base->isVirtual())
+ return false;
+
+ // Check that the base is public.
+ if (Base->getAccessSpecifier() != AS_public)
+ return false;
+
+ // Check that the class is dynamic iff the base is.
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ if (!BaseDecl->isEmpty() &&
+ BaseDecl->isDynamicClass() != RD->isDynamicClass())
+ return false;
+
+ return true;
+}
+
+void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
+ // abi::__class_type_info.
+ static const char * const ClassTypeInfo =
+ "_ZTVN10__cxxabiv117__class_type_infoE";
+ // abi::__si_class_type_info.
+ static const char * const SIClassTypeInfo =
+ "_ZTVN10__cxxabiv120__si_class_type_infoE";
+ // abi::__vmi_class_type_info.
+ static const char * const VMIClassTypeInfo =
+ "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
+
+ const char *VTableName = nullptr;
+
+ switch (Ty->getTypeClass()) {
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
+#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
+#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+ llvm_unreachable("Non-canonical and dependent types shouldn't get here");
+
+ case Type::LValueReference:
+ case Type::RValueReference:
+ llvm_unreachable("References shouldn't get here");
+
+ case Type::Auto:
+ llvm_unreachable("Undeduced auto type shouldn't get here");
+
+ case Type::Builtin:
+ // GCC treats vector and complex types as fundamental types.
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::Complex:
+ case Type::Atomic:
+ // FIXME: GCC treats block pointers as fundamental types?!
+ case Type::BlockPointer:
+ // abi::__fundamental_type_info.
+ VTableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE";
+ break;
+
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ // abi::__array_type_info.
+ VTableName = "_ZTVN10__cxxabiv117__array_type_infoE";
+ break;
+
+ case Type::FunctionNoProto:
+ case Type::FunctionProto:
+ // abi::__function_type_info.
+ VTableName = "_ZTVN10__cxxabiv120__function_type_infoE";
+ break;
+
+ case Type::Enum:
+ // abi::__enum_type_info.
+ VTableName = "_ZTVN10__cxxabiv116__enum_type_infoE";
+ break;
+
+ case Type::Record: {
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
+
+ if (!RD->hasDefinition() || !RD->getNumBases()) {
+ VTableName = ClassTypeInfo;
+ } else if (CanUseSingleInheritance(RD)) {
+ VTableName = SIClassTypeInfo;
+ } else {
+ VTableName = VMIClassTypeInfo;
+ }
+
+ break;
+ }
+
+ case Type::ObjCObject:
+ // Ignore protocol qualifiers.
+ Ty = cast<ObjCObjectType>(Ty)->getBaseType().getTypePtr();
+
+ // Handle id and Class.
+ if (isa<BuiltinType>(Ty)) {
+ VTableName = ClassTypeInfo;
+ break;
+ }
+
+ assert(isa<ObjCInterfaceType>(Ty));
+ // Fall through.
+
+ case Type::ObjCInterface:
+ if (cast<ObjCInterfaceType>(Ty)->getDecl()->getSuperClass()) {
+ VTableName = SIClassTypeInfo;
+ } else {
+ VTableName = ClassTypeInfo;
+ }
+ break;
+
+ case Type::ObjCObjectPointer:
+ case Type::Pointer:
+ // abi::__pointer_type_info.
+ VTableName = "_ZTVN10__cxxabiv119__pointer_type_infoE";
+ break;
+
+ case Type::MemberPointer:
+ // abi::__pointer_to_member_type_info.
+ VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
+ break;
+ }
+
+ llvm::Constant *VTable =
+ CGM.getModule().getOrInsertGlobal(VTableName, CGM.Int8PtrTy);
+
+ llvm::Type *PtrDiffTy =
+ CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
+
+ // The vtable address point is 2.
+ llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2);
+ VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, Two);
+ VTable = llvm::ConstantExpr::getBitCast(VTable, CGM.Int8PtrTy);
+
+ Fields.push_back(VTable);
+}
+
+/// \brief Return the linkage that the type info and type info name constants
+/// should have for the given type.
+static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM,
+ QualType Ty) {
+ // Itanium C++ ABI 2.9.5p7:
+ // In addition, it and all of the intermediate abi::__pointer_type_info
+ // structs in the chain down to the abi::__class_type_info for the
+ // incomplete class type must be prevented from resolving to the
+ // corresponding type_info structs for the complete class type, possibly
+ // by making them local static objects. Finally, a dummy class RTTI is
+ // generated for the incomplete type that will not resolve to the final
+ // complete class RTTI (because the latter need not exist), possibly by
+ // making it a local static object.
+ if (ContainsIncompleteClassType(Ty))
+ return llvm::GlobalValue::InternalLinkage;
+
+ switch (Ty->getLinkage()) {
+ case NoLinkage:
+ case InternalLinkage:
+ case UniqueExternalLinkage:
+ return llvm::GlobalValue::InternalLinkage;
+
+ case VisibleNoLinkage:
+ case ExternalLinkage:
+ if (!CGM.getLangOpts().RTTI) {
+ // RTTI is not enabled, which means that this type info struct is going
+ // to be used for exception handling. Give it linkonce_odr linkage.
+ return llvm::GlobalValue::LinkOnceODRLinkage;
+ }
+
+ if (const RecordType *Record = dyn_cast<RecordType>(Ty)) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
+ if (RD->hasAttr<WeakAttr>())
+ return llvm::GlobalValue::WeakODRLinkage;
+ if (RD->isDynamicClass())
+ return CGM.getVTableLinkage(RD);
+ }
+
+ return llvm::GlobalValue::LinkOnceODRLinkage;
+ }
+
+ llvm_unreachable("Invalid linkage!");
+}
+
+llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
+ // We want to operate on the canonical type.
+ Ty = CGM.getContext().getCanonicalType(Ty);
+
+ // Check if we've already emitted an RTTI descriptor for this type.
+ SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
+ Out.flush();
+ StringRef Name = OutName.str();
+
+ llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name);
+ if (OldGV && !OldGV->isDeclaration()) {
+ assert(!OldGV->hasAvailableExternallyLinkage() &&
+ "available_externally typeinfos not yet implemented");
+
+ return llvm::ConstantExpr::getBitCast(OldGV, CGM.Int8PtrTy);
+ }
+
+ // Check if there is already an external RTTI descriptor for this type.
+ bool IsStdLib = IsStandardLibraryRTTIDescriptor(Ty);
+ if (!Force && (IsStdLib || ShouldUseExternalRTTIDescriptor(CGM, Ty)))
+ return GetAddrOfExternalRTTIDescriptor(Ty);
+
+ // Emit the standard library with external linkage.
+ llvm::GlobalVariable::LinkageTypes Linkage;
+ if (IsStdLib)
+ Linkage = llvm::GlobalValue::ExternalLinkage;
+ else
+ Linkage = getTypeInfoLinkage(CGM, Ty);
+
+ // Add the vtable pointer.
+ BuildVTablePointer(cast<Type>(Ty));
+
+ // And the name.
+ llvm::GlobalVariable *TypeName = GetAddrOfTypeName(Ty, Linkage);
+ llvm::Constant *TypeNameField;
+
+ // If we're supposed to demote the visibility, be sure to set a flag
+ // to use a string comparison for type_info comparisons.
+ ItaniumCXXABI::RTTIUniquenessKind RTTIUniqueness =
+ CXXABI.classifyRTTIUniqueness(Ty, Linkage);
+ if (RTTIUniqueness != ItaniumCXXABI::RUK_Unique) {
+ // The flag is the sign bit, which on ARM64 is defined to be clear
+ // for global pointers. This is very ARM64-specific.
+ TypeNameField = llvm::ConstantExpr::getPtrToInt(TypeName, CGM.Int64Ty);
+ llvm::Constant *flag =
+ llvm::ConstantInt::get(CGM.Int64Ty, ((uint64_t)1) << 63);
+ TypeNameField = llvm::ConstantExpr::getAdd(TypeNameField, flag);
+ TypeNameField =
+ llvm::ConstantExpr::getIntToPtr(TypeNameField, CGM.Int8PtrTy);
+ } else {
+ TypeNameField = llvm::ConstantExpr::getBitCast(TypeName, CGM.Int8PtrTy);
+ }
+ Fields.push_back(TypeNameField);
+
+ switch (Ty->getTypeClass()) {
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
+#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
+#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+ llvm_unreachable("Non-canonical and dependent types shouldn't get here");
+
+ // GCC treats vector types as fundamental types.
+ case Type::Builtin:
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::Complex:
+ case Type::BlockPointer:
+ // Itanium C++ ABI 2.9.5p4:
+ // abi::__fundamental_type_info adds no data members to std::type_info.
+ break;
+
+ case Type::LValueReference:
+ case Type::RValueReference:
+ llvm_unreachable("References shouldn't get here");
+
+ case Type::Auto:
+ llvm_unreachable("Undeduced auto type shouldn't get here");
+
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ // Itanium C++ ABI 2.9.5p5:
+ // abi::__array_type_info adds no data members to std::type_info.
+ break;
+
+ case Type::FunctionNoProto:
+ case Type::FunctionProto:
+ // Itanium C++ ABI 2.9.5p5:
+ // abi::__function_type_info adds no data members to std::type_info.
+ break;
+
+ case Type::Enum:
+ // Itanium C++ ABI 2.9.5p5:
+ // abi::__enum_type_info adds no data members to std::type_info.
+ break;
+
+ case Type::Record: {
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
+ if (!RD->hasDefinition() || !RD->getNumBases()) {
+ // We don't need to emit any fields.
+ break;
+ }
+
+ if (CanUseSingleInheritance(RD))
+ BuildSIClassTypeInfo(RD);
+ else
+ BuildVMIClassTypeInfo(RD);
+
+ break;
+ }
+
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ BuildObjCObjectTypeInfo(cast<ObjCObjectType>(Ty));
+ break;
+
+ case Type::ObjCObjectPointer:
+ BuildPointerTypeInfo(cast<ObjCObjectPointerType>(Ty)->getPointeeType());
+ break;
+
+ case Type::Pointer:
+ BuildPointerTypeInfo(cast<PointerType>(Ty)->getPointeeType());
+ break;
+
+ case Type::MemberPointer:
+ BuildPointerToMemberTypeInfo(cast<MemberPointerType>(Ty));
+ break;
+
+ case Type::Atomic:
+ // No fields, at least for the moment.
+ break;
+ }
+
+ llvm::Constant *Init = llvm::ConstantStruct::getAnon(Fields);
+
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(CGM.getModule(), Init->getType(),
+ /*Constant=*/true, Linkage, Init, Name);
+
+ // If there's already an old global variable, replace it with the new one.
+ if (OldGV) {
+ GV->takeName(OldGV);
+ llvm::Constant *NewPtr =
+ llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
+ OldGV->replaceAllUsesWith(NewPtr);
+ OldGV->eraseFromParent();
+ }
+
+ // The Itanium ABI specifies that type_info objects must be globally
+ // unique, with one exception: if the type is an incomplete class
+ // type or a (possibly indirect) pointer to one. That exception
+ // affects the general case of comparing type_info objects produced
+ // by the typeid operator, which is why the comparison operators on
+ // std::type_info generally use the type_info name pointers instead
+ // of the object addresses. However, the language's built-in uses
+ // of RTTI generally require class types to be complete, even when
+ // manipulating pointers to those class types. This allows the
+ // implementation of dynamic_cast to rely on address equality tests,
+ // which is much faster.
+
+ // All of this is to say that it's important that both the type_info
+ // object and the type_info name be uniqued when weakly emitted.
+
+ // Give the type_info object and name the formal visibility of the
+ // type itself.
+ llvm::GlobalValue::VisibilityTypes llvmVisibility;
+ if (llvm::GlobalValue::isLocalLinkage(Linkage))
+ // If the linkage is local, only default visibility makes sense.
+ llvmVisibility = llvm::GlobalValue::DefaultVisibility;
+ else if (RTTIUniqueness == ItaniumCXXABI::RUK_NonUniqueHidden)
+ llvmVisibility = llvm::GlobalValue::HiddenVisibility;
+ else
+ llvmVisibility = CodeGenModule::GetLLVMVisibility(Ty->getVisibility());
+ TypeName->setVisibility(llvmVisibility);
+ GV->setVisibility(llvmVisibility);
+
+ return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
+}
+
+/// ComputeQualifierFlags - Compute the pointer type info flags from the
+/// given qualifier.
+static unsigned ComputeQualifierFlags(Qualifiers Quals) {
+ unsigned Flags = 0;
+
+ if (Quals.hasConst())
+ Flags |= ItaniumRTTIBuilder::PTI_Const;
+ if (Quals.hasVolatile())
+ Flags |= ItaniumRTTIBuilder::PTI_Volatile;
+ if (Quals.hasRestrict())
+ Flags |= ItaniumRTTIBuilder::PTI_Restrict;
+
+ return Flags;
+}
+
+/// BuildObjCObjectTypeInfo - Build the appropriate kind of type_info
+/// for the given Objective-C object type.
+void ItaniumRTTIBuilder::BuildObjCObjectTypeInfo(const ObjCObjectType *OT) {
+ // Drop qualifiers.
+ const Type *T = OT->getBaseType().getTypePtr();
+ assert(isa<BuiltinType>(T) || isa<ObjCInterfaceType>(T));
+
+ // The builtin types are abi::__class_type_infos and don't require
+ // extra fields.
+ if (isa<BuiltinType>(T)) return;
+
+ ObjCInterfaceDecl *Class = cast<ObjCInterfaceType>(T)->getDecl();
+ ObjCInterfaceDecl *Super = Class->getSuperClass();
+
+ // Root classes are also __class_type_info.
+ if (!Super) return;
+
+ QualType SuperTy = CGM.getContext().getObjCInterfaceType(Super);
+
+ // Everything else is single inheritance.
+ llvm::Constant *BaseTypeInfo =
+ ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(SuperTy);
+ Fields.push_back(BaseTypeInfo);
+}
+
+/// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
+/// inheritance, according to the Itanium C++ ABI, 2.95p6b.
+void ItaniumRTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) {
+ // Itanium C++ ABI 2.9.5p6b:
+ // It adds to abi::__class_type_info a single member pointing to the
+ // type_info structure for the base type,
+ llvm::Constant *BaseTypeInfo =
+ ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(RD->bases_begin()->getType());
+ Fields.push_back(BaseTypeInfo);
+}
+
+namespace {
+ /// SeenBases - Contains virtual and non-virtual bases seen when traversing
+ /// a class hierarchy.
+ struct SeenBases {
+ llvm::SmallPtrSet<const CXXRecordDecl *, 16> NonVirtualBases;
+ llvm::SmallPtrSet<const CXXRecordDecl *, 16> VirtualBases;
+ };
+}
+
+/// ComputeVMIClassTypeInfoFlags - Compute the value of the flags member in
+/// abi::__vmi_class_type_info.
+///
+static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
+ SeenBases &Bases) {
+
+ unsigned Flags = 0;
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+
+ if (Base->isVirtual()) {
+ // Mark the virtual base as seen.
+ if (!Bases.VirtualBases.insert(BaseDecl)) {
+ // If this virtual base has been seen before, then the class is diamond
+ // shaped.
+ Flags |= ItaniumRTTIBuilder::VMI_DiamondShaped;
+ } else {
+ if (Bases.NonVirtualBases.count(BaseDecl))
+ Flags |= ItaniumRTTIBuilder::VMI_NonDiamondRepeat;
+ }
+ } else {
+ // Mark the non-virtual base as seen.
+ if (!Bases.NonVirtualBases.insert(BaseDecl)) {
+ // If this non-virtual base has been seen before, then the class has non-
+ // diamond shaped repeated inheritance.
+ Flags |= ItaniumRTTIBuilder::VMI_NonDiamondRepeat;
+ } else {
+ if (Bases.VirtualBases.count(BaseDecl))
+ Flags |= ItaniumRTTIBuilder::VMI_NonDiamondRepeat;
+ }
+ }
+
+ // Walk all bases.
+ for (const auto &I : BaseDecl->bases())
+ Flags |= ComputeVMIClassTypeInfoFlags(&I, Bases);
+
+ return Flags;
+}
+
+static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *RD) {
+ unsigned Flags = 0;
+ SeenBases Bases;
+
+ // Walk all bases.
+ for (const auto &I : RD->bases())
+ Flags |= ComputeVMIClassTypeInfoFlags(&I, Bases);
+
+ return Flags;
+}
+
+/// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for
+/// classes with bases that do not satisfy the abi::__si_class_type_info
+/// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
+void ItaniumRTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
+ llvm::Type *UnsignedIntLTy =
+ CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
+
+ // Itanium C++ ABI 2.9.5p6c:
+ // __flags is a word with flags describing details about the class
+ // structure, which may be referenced by using the __flags_masks
+ // enumeration. These flags refer to both direct and indirect bases.
+ unsigned Flags = ComputeVMIClassTypeInfoFlags(RD);
+ Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
+
+ // Itanium C++ ABI 2.9.5p6c:
+ // __base_count is a word with the number of direct proper base class
+ // descriptions that follow.
+ Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, RD->getNumBases()));
+
+ if (!RD->getNumBases())
+ return;
+
+ llvm::Type *LongLTy =
+ CGM.getTypes().ConvertType(CGM.getContext().LongTy);
+
+ // Now add the base class descriptions.
+
+ // Itanium C++ ABI 2.9.5p6c:
+ // __base_info[] is an array of base class descriptions -- one for every
+ // direct proper base. Each description is of the type:
+ //
+ // struct abi::__base_class_type_info {
+ // public:
+ // const __class_type_info *__base_type;
+ // long __offset_flags;
+ //
+ // enum __offset_flags_masks {
+ // __virtual_mask = 0x1,
+ // __public_mask = 0x2,
+ // __offset_shift = 8
+ // };
+ // };
+ for (const auto &Base : RD->bases()) {
+ // The __base_type member points to the RTTI for the base type.
+ Fields.push_back(ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(Base.getType()));
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+
+ int64_t OffsetFlags = 0;
+
+ // All but the lower 8 bits of __offset_flags are a signed offset.
+ // For a non-virtual base, this is the offset in the object of the base
+ // subobject. For a virtual base, this is the offset in the virtual table of
+ // the virtual base offset for the virtual base referenced (negative).
+ CharUnits Offset;
+ if (Base.isVirtual())
+ Offset =
+ CGM.getItaniumVTableContext().getVirtualBaseOffsetOffset(RD, BaseDecl);
+ else {
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ Offset = Layout.getBaseClassOffset(BaseDecl);
+ };
+
+ OffsetFlags = uint64_t(Offset.getQuantity()) << 8;
+
+ // The low-order byte of __offset_flags contains flags, as given by the
+ // masks from the enumeration __offset_flags_masks.
+ if (Base.isVirtual())
+ OffsetFlags |= BCTI_Virtual;
+ if (Base.getAccessSpecifier() == AS_public)
+ OffsetFlags |= BCTI_Public;
+
+ Fields.push_back(llvm::ConstantInt::get(LongLTy, OffsetFlags));
+ }
+}
+
+/// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct,
+/// used for pointer types.
+void ItaniumRTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) {
+ Qualifiers Quals;
+ QualType UnqualifiedPointeeTy =
+ CGM.getContext().getUnqualifiedArrayType(PointeeTy, Quals);
+
+ // Itanium C++ ABI 2.9.5p7:
+ // __flags is a flag word describing the cv-qualification and other
+ // attributes of the type pointed to
+ unsigned Flags = ComputeQualifierFlags(Quals);
+
+ // Itanium C++ ABI 2.9.5p7:
+ // When the abi::__pbase_type_info is for a direct or indirect pointer to an
+ // incomplete class type, the incomplete target type flag is set.
+ if (ContainsIncompleteClassType(UnqualifiedPointeeTy))
+ Flags |= PTI_Incomplete;
+
+ llvm::Type *UnsignedIntLTy =
+ CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
+ Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
+
+ // Itanium C++ ABI 2.9.5p7:
+ // __pointee is a pointer to the std::type_info derivation for the
+ // unqualified type being pointed to.
+ llvm::Constant *PointeeTypeInfo =
+ ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(UnqualifiedPointeeTy);
+ Fields.push_back(PointeeTypeInfo);
+}
+
+/// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info
+/// struct, used for member pointer types.
+void
+ItaniumRTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) {
+ QualType PointeeTy = Ty->getPointeeType();
+
+ Qualifiers Quals;
+ QualType UnqualifiedPointeeTy =
+ CGM.getContext().getUnqualifiedArrayType(PointeeTy, Quals);
+
+ // Itanium C++ ABI 2.9.5p7:
+ // __flags is a flag word describing the cv-qualification and other
+ // attributes of the type pointed to.
+ unsigned Flags = ComputeQualifierFlags(Quals);
+
+ const RecordType *ClassType = cast<RecordType>(Ty->getClass());
+
+ // Itanium C++ ABI 2.9.5p7:
+ // When the abi::__pbase_type_info is for a direct or indirect pointer to an
+ // incomplete class type, the incomplete target type flag is set.
+ if (ContainsIncompleteClassType(UnqualifiedPointeeTy))
+ Flags |= PTI_Incomplete;
+
+ if (IsIncompleteClassType(ClassType))
+ Flags |= PTI_ContainingClassIncomplete;
+
+ llvm::Type *UnsignedIntLTy =
+ CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);
+ Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Flags));
+
+ // Itanium C++ ABI 2.9.5p7:
+ // __pointee is a pointer to the std::type_info derivation for the
+ // unqualified type being pointed to.
+ llvm::Constant *PointeeTypeInfo =
+ ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(UnqualifiedPointeeTy);
+ Fields.push_back(PointeeTypeInfo);
+
+ // Itanium C++ ABI 2.9.5p9:
+ // __context is a pointer to an abi::__class_type_info corresponding to the
+ // class type containing the member pointed to
+ // (e.g., the "A" in "int A::*").
+ Fields.push_back(
+ ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(QualType(ClassType, 0)));
+}
+
+llvm::Constant *ItaniumCXXABI::getAddrOfRTTIDescriptor(QualType Ty) {
+ return ItaniumRTTIBuilder(*this).BuildTypeInfo(Ty);
+}
+
+void ItaniumCXXABI::EmitFundamentalRTTIDescriptor(QualType Type) {
+ QualType PointerType = getContext().getPointerType(Type);
+ QualType PointerTypeConst = getContext().getPointerType(Type.withConst());
+ ItaniumRTTIBuilder(*this).BuildTypeInfo(Type, true);
+ ItaniumRTTIBuilder(*this).BuildTypeInfo(PointerType, true);
+ ItaniumRTTIBuilder(*this).BuildTypeInfo(PointerTypeConst, true);
+}
+
+void ItaniumCXXABI::EmitFundamentalRTTIDescriptors() {
+ QualType FundamentalTypes[] = {
+ getContext().VoidTy, getContext().NullPtrTy,
+ getContext().BoolTy, getContext().WCharTy,
+ getContext().CharTy, getContext().UnsignedCharTy,
+ getContext().SignedCharTy, getContext().ShortTy,
+ getContext().UnsignedShortTy, getContext().IntTy,
+ getContext().UnsignedIntTy, getContext().LongTy,
+ getContext().UnsignedLongTy, getContext().LongLongTy,
+ getContext().UnsignedLongLongTy, getContext().HalfTy,
+ getContext().FloatTy, getContext().DoubleTy,
+ getContext().LongDoubleTy, getContext().Char16Ty,
+ getContext().Char32Ty,
+ };
+ for (const QualType &FundamentalType : FundamentalTypes)
+ EmitFundamentalRTTIDescriptor(FundamentalType);
+}
+
+/// What sort of uniqueness rules should we use for the RTTI for the
+/// given type?
+ItaniumCXXABI::RTTIUniquenessKind ItaniumCXXABI::classifyRTTIUniqueness(
+ QualType CanTy, llvm::GlobalValue::LinkageTypes Linkage) const {
+ if (shouldRTTIBeUnique())
+ return RUK_Unique;
+
+ // It's only necessary for linkonce_odr or weak_odr linkage.
+ if (Linkage != llvm::GlobalValue::LinkOnceODRLinkage &&
+ Linkage != llvm::GlobalValue::WeakODRLinkage)
+ return RUK_Unique;
+
+ // It's only necessary with default visibility.
+ if (CanTy->getVisibility() != DefaultVisibility)
+ return RUK_Unique;
+
+ // If we're not required to publish this symbol, hide it.
+ if (Linkage == llvm::GlobalValue::LinkOnceODRLinkage)
+ return RUK_NonUniqueHidden;
+
+ // If we're required to publish this symbol, as we might be under an
+ // explicit instantiation, leave it with default visibility but
+ // enable string-comparisons.
+ assert(Linkage == llvm::GlobalValue::WeakODRLinkage);
+ return RUK_NonUniqueVisible;
+}
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 7318fe72a3c3..a69d4dd3fe86 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -15,64 +15,92 @@
//===----------------------------------------------------------------------===//
#include "CGCXXABI.h"
-#include "CodeGenModule.h"
#include "CGVTables.h"
-#include "MicrosoftVBTables.h"
+#include "CodeGenModule.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/VTableBuilder.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/IR/CallSite.h"
using namespace clang;
using namespace CodeGen;
namespace {
+/// Holds all the vbtable globals for a given class.
+struct VBTableGlobals {
+ const VPtrInfoVector *VBTables;
+ SmallVector<llvm::GlobalVariable *, 2> Globals;
+};
+
class MicrosoftCXXABI : public CGCXXABI {
public:
- MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {}
+ MicrosoftCXXABI(CodeGenModule &CGM)
+ : CGCXXABI(CGM), BaseClassDescriptorType(nullptr),
+ ClassHierarchyDescriptorType(nullptr),
+ CompleteObjectLocatorType(nullptr) {}
- bool HasThisReturn(GlobalDecl GD) const;
+ bool HasThisReturn(GlobalDecl GD) const override;
- bool isReturnTypeIndirect(const CXXRecordDecl *RD) const {
- // Structures that are not C++03 PODs are always indirect.
- return !RD->isPOD();
- }
+ bool classifyReturnType(CGFunctionInfo &FI) const override;
- RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const {
- if (RD->hasNonTrivialCopyConstructor() || RD->hasNonTrivialDestructor())
- return RAA_DirectInMemory;
- return RAA_Default;
- }
+ RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override;
- StringRef GetPureVirtualCallName() { return "_purecall"; }
+ bool isSRetParameterAfterThis() const override { return true; }
+
+ StringRef GetPureVirtualCallName() override { return "_purecall"; }
// No known support for deleted functions in MSVC yet, so this choice is
// arbitrary.
- StringRef GetDeletedVirtualCallName() { return "_purecall"; }
-
- bool isInlineInitializedStaticDataMemberLinkOnce() { return true; }
+ StringRef GetDeletedVirtualCallName() override { return "_purecall"; }
llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF,
llvm::Value *ptr,
- QualType type);
+ QualType type) override;
- llvm::Value *GetVirtualBaseClassOffset(CodeGenFunction &CGF,
- llvm::Value *This,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl);
+ llvm::GlobalVariable *getMSCompleteObjectLocator(const CXXRecordDecl *RD,
+ const VPtrInfo *Info);
+
+ llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) override;
+
+ bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy) override;
+ void EmitBadTypeidCall(CodeGenFunction &CGF) override;
+ llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy,
+ llvm::Value *ThisPtr,
+ llvm::Type *StdTypeInfoPtrTy) override;
+
+ bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
+ QualType SrcRecordTy) override;
+
+ llvm::Value *EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
+ QualType SrcRecordTy, QualType DestTy,
+ QualType DestRecordTy,
+ llvm::BasicBlock *CastEnd) override;
+
+ llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF, llvm::Value *Value,
+ QualType SrcRecordTy,
+ QualType DestTy) override;
+
+ bool EmitBadCastCall(CodeGenFunction &CGF) override;
+
+ llvm::Value *
+ GetVirtualBaseClassOffset(CodeGenFunction &CGF, llvm::Value *This,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl) override;
void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
- CXXCtorType Type,
- CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys);
+ CXXCtorType Type, CanQualType &ResTy,
+ SmallVectorImpl<CanQualType> &ArgTys) override;
- llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
- const CXXRecordDecl *RD);
+ llvm::BasicBlock *
+ EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
+ const CXXRecordDecl *RD) override;
void initializeHiddenVirtualInheritanceMembers(CodeGenFunction &CGF,
- const CXXRecordDecl *RD);
+ const CXXRecordDecl *RD) override;
- void EmitCXXConstructors(const CXXConstructorDecl *D);
+ void EmitCXXConstructors(const CXXConstructorDecl *D) override;
// Background on MSVC destructors
// ==============================
@@ -109,17 +137,18 @@ public:
void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
CXXDtorType Type,
CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys);
+ SmallVectorImpl<CanQualType> &ArgTys) override;
/// Non-base dtors should be emitted as delegating thunks in this ABI.
bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor,
- CXXDtorType DT) const {
+ CXXDtorType DT) const override {
return DT != Dtor_Base;
}
- void EmitCXXDestructors(const CXXDestructorDecl *D);
+ void EmitCXXDestructors(const CXXDestructorDecl *D) override;
- const CXXRecordDecl *getThisArgumentTypeForMethod(const CXXMethodDecl *MD) {
+ const CXXRecordDecl *
+ getThisArgumentTypeForMethod(const CXXMethodDecl *MD) override {
MD = MD->getCanonicalDecl();
if (MD->isVirtual() && !isa<CXXDestructorDecl>(MD)) {
MicrosoftVTableContext::MethodVFTableLocation ML =
@@ -131,76 +160,100 @@ public:
// FIXME: might want to have a more precise type in the non-virtual
// multiple inheritance case.
if (ML.VBase || !ML.VFPtrOffset.isZero())
- return 0;
+ return nullptr;
}
return MD->getParent();
}
- llvm::Value *adjustThisArgumentForVirtualCall(CodeGenFunction &CGF,
- GlobalDecl GD,
- llvm::Value *This);
+ llvm::Value *
+ adjustThisArgumentForVirtualFunctionCall(CodeGenFunction &CGF, GlobalDecl GD,
+ llvm::Value *This,
+ bool VirtualCall) override;
- void BuildInstanceFunctionParams(CodeGenFunction &CGF,
- QualType &ResTy,
- FunctionArgList &Params);
+ void addImplicitStructorParams(CodeGenFunction &CGF, QualType &ResTy,
+ FunctionArgList &Params) override;
llvm::Value *adjustThisParameterInVirtualFunctionPrologue(
- CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This);
+ CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This) override;
- void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
+ void EmitInstanceFunctionProlog(CodeGenFunction &CGF) override;
- void EmitConstructorCall(CodeGenFunction &CGF,
- const CXXConstructorDecl *D, CXXCtorType Type,
- bool ForVirtualBase, bool Delegating,
- llvm::Value *This,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd);
+ unsigned addImplicitConstructorArgs(CodeGenFunction &CGF,
+ const CXXConstructorDecl *D,
+ CXXCtorType Type, bool ForVirtualBase,
+ bool Delegating,
+ CallArgList &Args) override;
- void emitVTableDefinitions(CodeGenVTables &CGVT, const CXXRecordDecl *RD);
+ void EmitDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *DD,
+ CXXDtorType Type, bool ForVirtualBase,
+ bool Delegating, llvm::Value *This) override;
+
+ void emitVTableDefinitions(CodeGenVTables &CGVT,
+ const CXXRecordDecl *RD) override;
llvm::Value *getVTableAddressPointInStructor(
CodeGenFunction &CGF, const CXXRecordDecl *VTableClass,
BaseSubobject Base, const CXXRecordDecl *NearestVBase,
- bool &NeedsVirtualOffset);
+ bool &NeedsVirtualOffset) override;
llvm::Constant *
getVTableAddressPointForConstExpr(BaseSubobject Base,
- const CXXRecordDecl *VTableClass);
+ const CXXRecordDecl *VTableClass) override;
llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD,
- CharUnits VPtrOffset);
+ CharUnits VPtrOffset) override;
llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD,
- llvm::Value *This, llvm::Type *Ty);
+ llvm::Value *This,
+ llvm::Type *Ty) override;
void EmitVirtualDestructorCall(CodeGenFunction &CGF,
const CXXDestructorDecl *Dtor,
CXXDtorType DtorType, SourceLocation CallLoc,
- llvm::Value *This);
+ llvm::Value *This) override;
void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF, GlobalDecl GD,
- CallArgList &CallArgs) {
+ CallArgList &CallArgs) override {
assert(GD.getDtorType() == Dtor_Deleting &&
"Only deleting destructor thunks are available in this ABI");
CallArgs.add(RValue::get(getStructorImplicitParamValue(CGF)),
CGM.getContext().IntTy);
}
- void emitVirtualInheritanceTables(const CXXRecordDecl *RD);
+ void emitVirtualInheritanceTables(const CXXRecordDecl *RD) override;
+
+ llvm::GlobalVariable *
+ getAddrOfVBTable(const VPtrInfo &VBT, const CXXRecordDecl *RD,
+ llvm::GlobalVariable::LinkageTypes Linkage);
+
+ void emitVBTableDefinition(const VPtrInfo &VBT, const CXXRecordDecl *RD,
+ llvm::GlobalVariable *GV) const;
+
+ void setThunkLinkage(llvm::Function *Thunk, bool ForVTable,
+ GlobalDecl GD, bool ReturnAdjustment) override {
+ // Never dllimport/dllexport thunks.
+ Thunk->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
- void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) {
- Thunk->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
+ GVALinkage Linkage =
+ getContext().GetGVALinkageForFunction(cast<FunctionDecl>(GD.getDecl()));
+
+ if (Linkage == GVA_Internal)
+ Thunk->setLinkage(llvm::GlobalValue::InternalLinkage);
+ else if (ReturnAdjustment)
+ Thunk->setLinkage(llvm::GlobalValue::WeakODRLinkage);
+ else
+ Thunk->setLinkage(llvm::GlobalValue::LinkOnceODRLinkage);
}
llvm::Value *performThisAdjustment(CodeGenFunction &CGF, llvm::Value *This,
- const ThisAdjustment &TA);
+ const ThisAdjustment &TA) override;
llvm::Value *performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret,
- const ReturnAdjustment &RA);
+ const ReturnAdjustment &RA) override;
void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::GlobalVariable *DeclPtr,
- bool PerformInit);
+ bool PerformInit) override;
// ==== Notes on array cookies =========
//
@@ -225,17 +278,126 @@ public:
// }
// Whereas it prints "104" and "104" if you give A a destructor.
- bool requiresArrayCookie(const CXXDeleteExpr *expr, QualType elementType);
- bool requiresArrayCookie(const CXXNewExpr *expr);
- CharUnits getArrayCookieSizeImpl(QualType type);
+ bool requiresArrayCookie(const CXXDeleteExpr *expr,
+ QualType elementType) override;
+ bool requiresArrayCookie(const CXXNewExpr *expr) override;
+ CharUnits getArrayCookieSizeImpl(QualType type) override;
llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF,
llvm::Value *NewPtr,
llvm::Value *NumElements,
const CXXNewExpr *expr,
- QualType ElementType);
+ QualType ElementType) override;
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF,
llvm::Value *allocPtr,
- CharUnits cookieSize);
+ CharUnits cookieSize) override;
+
+ friend struct MSRTTIBuilder;
+
+ bool isImageRelative() const {
+ return CGM.getTarget().getPointerWidth(/*AddressSpace=*/0) == 64;
+ }
+
+ // 5 routines for constructing the llvm types for MS RTTI structs.
+ llvm::StructType *getTypeDescriptorType(StringRef TypeInfoString) {
+ llvm::SmallString<32> TDTypeName("rtti.TypeDescriptor");
+ TDTypeName += llvm::utostr(TypeInfoString.size());
+ llvm::StructType *&TypeDescriptorType =
+ TypeDescriptorTypeMap[TypeInfoString.size()];
+ if (TypeDescriptorType)
+ return TypeDescriptorType;
+ llvm::Type *FieldTypes[] = {
+ CGM.Int8PtrPtrTy,
+ CGM.Int8PtrTy,
+ llvm::ArrayType::get(CGM.Int8Ty, TypeInfoString.size() + 1)};
+ TypeDescriptorType =
+ llvm::StructType::create(CGM.getLLVMContext(), FieldTypes, TDTypeName);
+ return TypeDescriptorType;
+ }
+
+ llvm::Type *getImageRelativeType(llvm::Type *PtrType) {
+ if (!isImageRelative())
+ return PtrType;
+ return CGM.IntTy;
+ }
+
+ llvm::StructType *getBaseClassDescriptorType() {
+ if (BaseClassDescriptorType)
+ return BaseClassDescriptorType;
+ llvm::Type *FieldTypes[] = {
+ getImageRelativeType(CGM.Int8PtrTy),
+ CGM.IntTy,
+ CGM.IntTy,
+ CGM.IntTy,
+ CGM.IntTy,
+ CGM.IntTy,
+ getImageRelativeType(getClassHierarchyDescriptorType()->getPointerTo()),
+ };
+ BaseClassDescriptorType = llvm::StructType::create(
+ CGM.getLLVMContext(), FieldTypes, "rtti.BaseClassDescriptor");
+ return BaseClassDescriptorType;
+ }
+
+ llvm::StructType *getClassHierarchyDescriptorType() {
+ if (ClassHierarchyDescriptorType)
+ return ClassHierarchyDescriptorType;
+ // Forward-declare RTTIClassHierarchyDescriptor to break a cycle.
+ ClassHierarchyDescriptorType = llvm::StructType::create(
+ CGM.getLLVMContext(), "rtti.ClassHierarchyDescriptor");
+ llvm::Type *FieldTypes[] = {
+ CGM.IntTy,
+ CGM.IntTy,
+ CGM.IntTy,
+ getImageRelativeType(
+ getBaseClassDescriptorType()->getPointerTo()->getPointerTo()),
+ };
+ ClassHierarchyDescriptorType->setBody(FieldTypes);
+ return ClassHierarchyDescriptorType;
+ }
+
+ llvm::StructType *getCompleteObjectLocatorType() {
+ if (CompleteObjectLocatorType)
+ return CompleteObjectLocatorType;
+ CompleteObjectLocatorType = llvm::StructType::create(
+ CGM.getLLVMContext(), "rtti.CompleteObjectLocator");
+ llvm::Type *FieldTypes[] = {
+ CGM.IntTy,
+ CGM.IntTy,
+ CGM.IntTy,
+ getImageRelativeType(CGM.Int8PtrTy),
+ getImageRelativeType(getClassHierarchyDescriptorType()->getPointerTo()),
+ getImageRelativeType(CompleteObjectLocatorType),
+ };
+ llvm::ArrayRef<llvm::Type *> FieldTypesRef(FieldTypes);
+ if (!isImageRelative())
+ FieldTypesRef = FieldTypesRef.drop_back();
+ CompleteObjectLocatorType->setBody(FieldTypesRef);
+ return CompleteObjectLocatorType;
+ }
+
+ llvm::GlobalVariable *getImageBase() {
+ StringRef Name = "__ImageBase";
+ if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(Name))
+ return GV;
+
+ return new llvm::GlobalVariable(CGM.getModule(), CGM.Int8Ty,
+ /*isConstant=*/true,
+ llvm::GlobalValue::ExternalLinkage,
+ /*Initializer=*/nullptr, Name);
+ }
+
+ llvm::Constant *getImageRelativeConstant(llvm::Constant *PtrVal) {
+ if (!isImageRelative())
+ return PtrVal;
+
+ llvm::Constant *ImageBaseAsInt =
+ llvm::ConstantExpr::getPtrToInt(getImageBase(), CGM.IntPtrTy);
+ llvm::Constant *PtrValAsInt =
+ llvm::ConstantExpr::getPtrToInt(PtrVal, CGM.IntPtrTy);
+ llvm::Constant *Diff =
+ llvm::ConstantExpr::getSub(PtrValAsInt, ImageBaseAsInt,
+ /*HasNUW=*/true, /*HasNSW=*/true);
+ return llvm::ConstantExpr::getTrunc(Diff, CGM.IntTy);
+ }
private:
MicrosoftMangleContext &getMangleContext() {
@@ -258,15 +420,12 @@ private:
return C ? C : getZeroInt();
}
+ CharUnits getVirtualFunctionPrologueThisAdjustment(GlobalDecl GD);
+
void
GetNullMemberPointerFields(const MemberPointerType *MPT,
llvm::SmallVectorImpl<llvm::Constant *> &fields);
- /// \brief Finds the offset from the base of RD to the vbptr it uses, even if
- /// it is reusing a vbptr from a non-virtual base. RD must have morally
- /// virtual bases.
- CharUnits GetVBPtrOffsetFromBases(const CXXRecordDecl *RD);
-
/// \brief Shared code for virtual base adjustment. Returns the offset from
/// the vbptr to the virtual base. Optionally returns the address of the
/// vbptr itself.
@@ -274,13 +433,13 @@ private:
llvm::Value *Base,
llvm::Value *VBPtrOffset,
llvm::Value *VBTableOffset,
- llvm::Value **VBPtr = 0);
+ llvm::Value **VBPtr = nullptr);
llvm::Value *GetVBaseOffsetFromVBPtr(CodeGenFunction &CGF,
llvm::Value *Base,
int32_t VBPtrOffset,
int32_t VBTableOffset,
- llvm::Value **VBPtr = 0) {
+ llvm::Value **VBPtr = nullptr) {
llvm::Value *VBPOffset = llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset),
*VBTOffset = llvm::ConstantInt::get(CGM.IntTy, VBTableOffset);
return GetVBaseOffsetFromVBPtr(CGF, Base, VBPOffset, VBTOffset, VBPtr);
@@ -288,8 +447,8 @@ private:
/// \brief Performs a full virtual base adjustment. Used to dereference
/// pointers to members of virtual bases.
- llvm::Value *AdjustVirtualBase(CodeGenFunction &CGF, const CXXRecordDecl *RD,
- llvm::Value *Base,
+ llvm::Value *AdjustVirtualBase(CodeGenFunction &CGF, const Expr *E,
+ const CXXRecordDecl *RD, llvm::Value *Base,
llvm::Value *VirtualBaseAdjustmentOffset,
llvm::Value *VBPtrOffset /* optional */);
@@ -311,69 +470,71 @@ private:
void EmitVBPtrStores(CodeGenFunction &CGF, const CXXRecordDecl *RD);
/// \brief Caching wrapper around VBTableBuilder::enumerateVBTables().
- const VBTableVector &EnumerateVBTables(const CXXRecordDecl *RD);
+ const VBTableGlobals &enumerateVBTables(const CXXRecordDecl *RD);
/// \brief Generate a thunk for calling a virtual member function MD.
- llvm::Function *EmitVirtualMemPtrThunk(const CXXMethodDecl *MD,
- StringRef ThunkName);
+ llvm::Function *EmitVirtualMemPtrThunk(
+ const CXXMethodDecl *MD,
+ const MicrosoftVTableContext::MethodVFTableLocation &ML);
public:
- virtual llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT);
+ llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT) override;
- virtual bool isZeroInitializable(const MemberPointerType *MPT);
+ bool isZeroInitializable(const MemberPointerType *MPT) override;
- virtual llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT);
+ llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT) override;
- virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
- CharUnits offset);
- virtual llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD);
- virtual llvm::Constant *EmitMemberPointer(const APValue &MP, QualType MPT);
+ llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
+ CharUnits offset) override;
+ llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD) override;
+ llvm::Constant *EmitMemberPointer(const APValue &MP, QualType MPT) override;
- virtual llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF,
- llvm::Value *L,
- llvm::Value *R,
- const MemberPointerType *MPT,
- bool Inequality);
+ llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF,
+ llvm::Value *L,
+ llvm::Value *R,
+ const MemberPointerType *MPT,
+ bool Inequality) override;
- virtual llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT);
+ llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
+ llvm::Value *MemPtr,
+ const MemberPointerType *MPT) override;
- virtual llvm::Value *EmitMemberDataPointerAddress(CodeGenFunction &CGF,
- llvm::Value *Base,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT);
+ llvm::Value *
+ EmitMemberDataPointerAddress(CodeGenFunction &CGF, const Expr *E,
+ llvm::Value *Base, llvm::Value *MemPtr,
+ const MemberPointerType *MPT) override;
- virtual llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF,
- const CastExpr *E,
- llvm::Value *Src);
+ llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF,
+ const CastExpr *E,
+ llvm::Value *Src) override;
- virtual llvm::Constant *EmitMemberPointerConversion(const CastExpr *E,
- llvm::Constant *Src);
+ llvm::Constant *EmitMemberPointerConversion(const CastExpr *E,
+ llvm::Constant *Src) override;
- virtual llvm::Value *
- EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
- llvm::Value *&This,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT);
+ llvm::Value *
+ EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, const Expr *E,
+ llvm::Value *&This, llvm::Value *MemPtr,
+ const MemberPointerType *MPT) override;
private:
typedef std::pair<const CXXRecordDecl *, CharUnits> VFTableIdTy;
- typedef llvm::DenseMap<VFTableIdTy, llvm::GlobalVariable *> VFTablesMapTy;
+ typedef llvm::DenseMap<VFTableIdTy, llvm::GlobalVariable *> VTablesMapTy;
+ typedef llvm::DenseMap<VFTableIdTy, llvm::GlobalValue *> VFTablesMapTy;
/// \brief All the vftables that have been referenced.
VFTablesMapTy VFTablesMap;
+ VTablesMapTy VTablesMap;
/// \brief This set holds the record decls we've deferred vtable emission for.
llvm::SmallPtrSet<const CXXRecordDecl *, 4> DeferredVFTables;
/// \brief All the vbtables which have been referenced.
- llvm::DenseMap<const CXXRecordDecl *, VBTableVector> VBTablesMap;
+ llvm::DenseMap<const CXXRecordDecl *, VBTableGlobals> VBTablesMap;
/// Info on the global variable used to guard initialization of static locals.
/// The BitIndex field is only used for externally invisible declarations.
struct GuardInfo {
- GuardInfo() : Guard(0), BitIndex(0) {}
+ GuardInfo() : Guard(nullptr), BitIndex(0) {}
llvm::GlobalVariable *Guard;
unsigned BitIndex;
};
@@ -381,10 +542,69 @@ private:
/// Map from DeclContext to the current guard variable. We assume that the
/// AST is visited in source code order.
llvm::DenseMap<const DeclContext *, GuardInfo> GuardVariableMap;
+
+ llvm::DenseMap<size_t, llvm::StructType *> TypeDescriptorTypeMap;
+ llvm::StructType *BaseClassDescriptorType;
+ llvm::StructType *ClassHierarchyDescriptorType;
+ llvm::StructType *CompleteObjectLocatorType;
};
}
+CGCXXABI::RecordArgABI
+MicrosoftCXXABI::getRecordArgABI(const CXXRecordDecl *RD) const {
+ switch (CGM.getTarget().getTriple().getArch()) {
+ default:
+ // FIXME: Implement for other architectures.
+ return RAA_Default;
+
+ case llvm::Triple::x86:
+ // All record arguments are passed in memory on x86. Decide whether to
+ // construct the object directly in argument memory, or to construct the
+ // argument elsewhere and copy the bytes during the call.
+
+ // If C++ prohibits us from making a copy, construct the arguments directly
+ // into argument memory.
+ if (!canCopyArgument(RD))
+ return RAA_DirectInMemory;
+
+ // Otherwise, construct the argument into a temporary and copy the bytes
+ // into the outgoing argument memory.
+ return RAA_Default;
+
+ case llvm::Triple::x86_64:
+ // Win64 passes objects with non-trivial copy ctors indirectly.
+ if (RD->hasNonTrivialCopyConstructor())
+ return RAA_Indirect;
+
+ // Win64 passes objects larger than 8 bytes indirectly.
+ if (getContext().getTypeSize(RD->getTypeForDecl()) > 64)
+ return RAA_Indirect;
+
+ // We have a trivial copy constructor or no copy constructors, but we have
+ // to make sure it isn't deleted.
+ bool CopyDeleted = false;
+ for (const CXXConstructorDecl *CD : RD->ctors()) {
+ if (CD->isCopyConstructor()) {
+ assert(CD->isTrivial());
+ // We had at least one undeleted trivial copy ctor. Return directly.
+ if (!CD->isDeleted())
+ return RAA_Default;
+ CopyDeleted = true;
+ }
+ }
+
+ // The trivial copy constructor was deleted. Return indirectly.
+ if (CopyDeleted)
+ return RAA_Indirect;
+
+ // There were no copy ctors. Return in RAX.
+ return RAA_Default;
+ }
+
+ llvm_unreachable("invalid enum");
+}
+
llvm::Value *MicrosoftCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
llvm::Value *ptr,
QualType type) {
@@ -392,33 +612,127 @@ llvm::Value *MicrosoftCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
return ptr;
}
-/// \brief Finds the first non-virtual base of RD that has virtual bases. If RD
-/// doesn't have a vbptr, it will reuse the vbptr of the returned class.
-static const CXXRecordDecl *FindFirstNVBaseWithVBases(const CXXRecordDecl *RD) {
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();
- if (!I->isVirtual() && Base->getNumVBases() > 0)
- return Base;
- }
- llvm_unreachable("RD must have an nv base with vbases");
+/// \brief Gets the offset to the virtual base that contains the vfptr for
+/// MS-ABI polymorphic types.
+static llvm::Value *getPolymorphicOffset(CodeGenFunction &CGF,
+ const CXXRecordDecl *RD,
+ llvm::Value *Value) {
+ const ASTContext &Context = RD->getASTContext();
+ for (const CXXBaseSpecifier &Base : RD->vbases())
+ if (Context.getASTRecordLayout(Base.getType()->getAsCXXRecordDecl())
+ .hasExtendableVFPtr())
+ return CGF.CGM.getCXXABI().GetVirtualBaseClassOffset(
+ CGF, Value, RD, Base.getType()->getAsCXXRecordDecl());
+ llvm_unreachable("One of our vbases should be polymorphic.");
}
-CharUnits MicrosoftCXXABI::GetVBPtrOffsetFromBases(const CXXRecordDecl *RD) {
- assert(RD->getNumVBases());
- CharUnits Total = CharUnits::Zero();
- while (RD) {
- const ASTRecordLayout &RDLayout = getContext().getASTRecordLayout(RD);
- CharUnits VBPtrOffset = RDLayout.getVBPtrOffset();
- // -1 is the sentinel for no vbptr.
- if (VBPtrOffset != CharUnits::fromQuantity(-1)) {
- Total += VBPtrOffset;
- break;
- }
- RD = FindFirstNVBaseWithVBases(RD);
- Total += RDLayout.getBaseClassOffset(RD);
- }
- return Total;
+static std::pair<llvm::Value *, llvm::Value *>
+performBaseAdjustment(CodeGenFunction &CGF, llvm::Value *Value,
+ QualType SrcRecordTy) {
+ Value = CGF.Builder.CreateBitCast(Value, CGF.Int8PtrTy);
+ const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
+
+ if (CGF.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr())
+ return std::make_pair(Value, llvm::ConstantInt::get(CGF.Int32Ty, 0));
+
+ // Perform a base adjustment.
+ llvm::Value *Offset = getPolymorphicOffset(CGF, SrcDecl, Value);
+ Value = CGF.Builder.CreateInBoundsGEP(Value, Offset);
+ Offset = CGF.Builder.CreateTrunc(Offset, CGF.Int32Ty);
+ return std::make_pair(Value, Offset);
+}
+
+bool MicrosoftCXXABI::shouldTypeidBeNullChecked(bool IsDeref,
+ QualType SrcRecordTy) {
+ const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
+ return IsDeref &&
+ !CGM.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr();
+}
+
+static llvm::CallSite emitRTtypeidCall(CodeGenFunction &CGF,
+ llvm::Value *Argument) {
+ llvm::Type *ArgTypes[] = {CGF.Int8PtrTy};
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false);
+ llvm::Value *Args[] = {Argument};
+ llvm::Constant *Fn = CGF.CGM.CreateRuntimeFunction(FTy, "__RTtypeid");
+ return CGF.EmitRuntimeCallOrInvoke(Fn, Args);
+}
+
+void MicrosoftCXXABI::EmitBadTypeidCall(CodeGenFunction &CGF) {
+ llvm::CallSite Call =
+ emitRTtypeidCall(CGF, llvm::Constant::getNullValue(CGM.VoidPtrTy));
+ Call.setDoesNotReturn();
+ CGF.Builder.CreateUnreachable();
+}
+
+llvm::Value *MicrosoftCXXABI::EmitTypeid(CodeGenFunction &CGF,
+ QualType SrcRecordTy,
+ llvm::Value *ThisPtr,
+ llvm::Type *StdTypeInfoPtrTy) {
+ llvm::Value *Offset;
+ std::tie(ThisPtr, Offset) = performBaseAdjustment(CGF, ThisPtr, SrcRecordTy);
+ return CGF.Builder.CreateBitCast(
+ emitRTtypeidCall(CGF, ThisPtr).getInstruction(), StdTypeInfoPtrTy);
+}
+
+bool MicrosoftCXXABI::shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
+ QualType SrcRecordTy) {
+ const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
+ return SrcIsPtr &&
+ !CGM.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr();
+}
+
+llvm::Value *MicrosoftCXXABI::EmitDynamicCastCall(
+ CodeGenFunction &CGF, llvm::Value *Value, QualType SrcRecordTy,
+ QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastEnd) {
+ llvm::Type *DestLTy = CGF.ConvertType(DestTy);
+
+ llvm::Value *SrcRTTI =
+ CGF.CGM.GetAddrOfRTTIDescriptor(SrcRecordTy.getUnqualifiedType());
+ llvm::Value *DestRTTI =
+ CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());
+
+ llvm::Value *Offset;
+ std::tie(Value, Offset) = performBaseAdjustment(CGF, Value, SrcRecordTy);
+
+ // PVOID __RTDynamicCast(
+ // PVOID inptr,
+ // LONG VfDelta,
+ // PVOID SrcType,
+ // PVOID TargetType,
+ // BOOL isReference)
+ llvm::Type *ArgTypes[] = {CGF.Int8PtrTy, CGF.Int32Ty, CGF.Int8PtrTy,
+ CGF.Int8PtrTy, CGF.Int32Ty};
+ llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false),
+ "__RTDynamicCast");
+ llvm::Value *Args[] = {
+ Value, Offset, SrcRTTI, DestRTTI,
+ llvm::ConstantInt::get(CGF.Int32Ty, DestTy->isReferenceType())};
+ Value = CGF.EmitRuntimeCallOrInvoke(Function, Args).getInstruction();
+ return CGF.Builder.CreateBitCast(Value, DestLTy);
+}
+
+llvm::Value *
+MicrosoftCXXABI::EmitDynamicCastToVoid(CodeGenFunction &CGF, llvm::Value *Value,
+ QualType SrcRecordTy,
+ QualType DestTy) {
+ llvm::Value *Offset;
+ std::tie(Value, Offset) = performBaseAdjustment(CGF, Value, SrcRecordTy);
+
+ // PVOID __RTCastToVoid(
+ // PVOID inptr)
+ llvm::Type *ArgTypes[] = {CGF.Int8PtrTy};
+ llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false),
+ "__RTCastToVoid");
+ llvm::Value *Args[] = {Value};
+ return CGF.EmitRuntimeCall(Function, Args);
+}
+
+bool MicrosoftCXXABI::EmitBadCastCall(CodeGenFunction &CGF) {
+ return false;
}
llvm::Value *
@@ -426,7 +740,8 @@ MicrosoftCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
llvm::Value *This,
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl) {
- int64_t VBPtrChars = GetVBPtrOffsetFromBases(ClassDecl).getQuantity();
+ int64_t VBPtrChars =
+ getContext().getASTRecordLayout(ClassDecl).getVBPtrOffset().getQuantity();
llvm::Value *VBPtrOffset = llvm::ConstantInt::get(CGM.PtrDiffTy, VBPtrChars);
CharUnits IntSize = getContext().getTypeSizeInChars(getContext().IntTy);
CharUnits VBTableChars =
@@ -446,16 +761,41 @@ bool MicrosoftCXXABI::HasThisReturn(GlobalDecl GD) const {
return isa<CXXConstructorDecl>(GD.getDecl());
}
-void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
- CXXCtorType Type,
- CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys) {
- // 'this' parameter and 'this' return are already in place
+bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const {
+ const CXXRecordDecl *RD = FI.getReturnType()->getAsCXXRecordDecl();
+ if (!RD)
+ return false;
+
+ if (FI.isInstanceMethod()) {
+ // If it's an instance method, aggregates are always returned indirectly via
+ // the second parameter.
+ FI.getReturnInfo() = ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+ FI.getReturnInfo().setSRetAfterThis(FI.isInstanceMethod());
+ return true;
+ } else if (!RD->isPOD()) {
+ // If it's a free function, non-POD types are returned indirectly.
+ FI.getReturnInfo() = ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+ return true;
+ }
+
+ // Otherwise, use the C ABI rules.
+ return false;
+}
+
+void MicrosoftCXXABI::BuildConstructorSignature(
+ const CXXConstructorDecl *Ctor, CXXCtorType Type, CanQualType &ResTy,
+ SmallVectorImpl<CanQualType> &ArgTys) {
+
+ // All parameters are already in place except is_most_derived, which goes
+ // after 'this' if it's variadic and last if it's not.
const CXXRecordDecl *Class = Ctor->getParent();
+ const FunctionProtoType *FPT = Ctor->getType()->castAs<FunctionProtoType>();
if (Class->getNumVBases()) {
- // Constructors of classes with virtual bases take an implicit parameter.
- ArgTys.push_back(CGM.getContext().IntTy);
+ if (FPT->isVariadic())
+ ArgTys.insert(ArgTys.begin() + 1, CGM.getContext().IntTy);
+ else
+ ArgTys.push_back(CGM.getContext().IntTy);
}
}
@@ -505,7 +845,7 @@ void MicrosoftCXXABI::initializeHiddenVirtualInheritanceMembers(
unsigned AS =
cast<llvm::PointerType>(getThisValue(CGF)->getType())->getAddressSpace();
- llvm::Value *Int8This = 0; // Initialize lazily.
+ llvm::Value *Int8This = nullptr; // Initialize lazily.
for (VBOffsets::const_iterator I = VBaseMap.begin(), E = VBaseMap.end();
I != E; ++I) {
@@ -547,19 +887,23 @@ void MicrosoftCXXABI::EmitVBPtrStores(CodeGenFunction &CGF,
const CXXRecordDecl *RD) {
llvm::Value *ThisInt8Ptr =
CGF.Builder.CreateBitCast(getThisValue(CGF), CGM.Int8PtrTy, "this.int8");
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- const VBTableVector &VBTables = EnumerateVBTables(RD);
- for (VBTableVector::const_iterator I = VBTables.begin(), E = VBTables.end();
- I != E; ++I) {
+ const VBTableGlobals &VBGlobals = enumerateVBTables(RD);
+ for (unsigned I = 0, E = VBGlobals.VBTables->size(); I != E; ++I) {
+ const VPtrInfo *VBT = (*VBGlobals.VBTables)[I];
+ llvm::GlobalVariable *GV = VBGlobals.Globals[I];
const ASTRecordLayout &SubobjectLayout =
- CGM.getContext().getASTRecordLayout(I->VBPtrSubobject.getBase());
- uint64_t Offs = (I->VBPtrSubobject.getBaseOffset() +
- SubobjectLayout.getVBPtrOffset()).getQuantity();
+ CGM.getContext().getASTRecordLayout(VBT->BaseWithVPtr);
+ CharUnits Offs = VBT->NonVirtualOffset;
+ Offs += SubobjectLayout.getVBPtrOffset();
+ if (VBT->getVBaseWithVPtr())
+ Offs += Layout.getVBaseClassOffset(VBT->getVBaseWithVPtr());
llvm::Value *VBPtr =
- CGF.Builder.CreateConstInBoundsGEP1_64(ThisInt8Ptr, Offs);
- VBPtr = CGF.Builder.CreateBitCast(VBPtr, I->GV->getType()->getPointerTo(0),
- "vbptr." + I->ReusingBase->getName());
- CGF.Builder.CreateStore(I->GV, VBPtr);
+ CGF.Builder.CreateConstInBoundsGEP1_64(ThisInt8Ptr, Offs.getQuantity());
+ VBPtr = CGF.Builder.CreateBitCast(VBPtr, GV->getType()->getPointerTo(0),
+ "vbptr." + VBT->ReusingBase->getName());
+ CGF.Builder.CreateStore(GV, VBPtr);
}
}
@@ -583,12 +927,61 @@ void MicrosoftCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) {
CGM.EmitGlobal(GlobalDecl(D, Dtor_Base));
}
-llvm::Value *MicrosoftCXXABI::adjustThisArgumentForVirtualCall(
- CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This) {
+CharUnits
+MicrosoftCXXABI::getVirtualFunctionPrologueThisAdjustment(GlobalDecl GD) {
+ GD = GD.getCanonicalDecl();
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+ GlobalDecl LookupGD = GD;
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ // Complete destructors take a pointer to the complete object as a
+ // parameter, thus don't need this adjustment.
+ if (GD.getDtorType() == Dtor_Complete)
+ return CharUnits();
+
+ // There's no Dtor_Base in vftable but it shares the this adjustment with
+ // the deleting one, so look it up instead.
+ LookupGD = GlobalDecl(DD, Dtor_Deleting);
+ }
+
+ MicrosoftVTableContext::MethodVFTableLocation ML =
+ CGM.getMicrosoftVTableContext().getMethodVFTableLocation(LookupGD);
+ CharUnits Adjustment = ML.VFPtrOffset;
+
+ // Normal virtual instance methods need to adjust from the vfptr that first
+ // defined the virtual method to the virtual base subobject, but destructors
+ // do not. The vector deleting destructor thunk applies this adjustment for
+ // us if necessary.
+ if (isa<CXXDestructorDecl>(MD))
+ Adjustment = CharUnits::Zero();
+
+ if (ML.VBase) {
+ const ASTRecordLayout &DerivedLayout =
+ CGM.getContext().getASTRecordLayout(MD->getParent());
+ Adjustment += DerivedLayout.getVBaseClassOffset(ML.VBase);
+ }
+
+ return Adjustment;
+}
+
+llvm::Value *MicrosoftCXXABI::adjustThisArgumentForVirtualFunctionCall(
+ CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This, bool VirtualCall) {
+ if (!VirtualCall) {
+ // If the call of a virtual function is not virtual, we just have to
+ // compensate for the adjustment the virtual function does in its prologue.
+ CharUnits Adjustment = getVirtualFunctionPrologueThisAdjustment(GD);
+ if (Adjustment.isZero())
+ return This;
+
+ unsigned AS = cast<llvm::PointerType>(This->getType())->getAddressSpace();
+ llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS);
+ This = CGF.Builder.CreateBitCast(This, charPtrTy);
+ assert(Adjustment.isPositive());
+ return CGF.Builder.CreateConstGEP1_32(This, Adjustment.getQuantity());
+ }
+
GD = GD.getCanonicalDecl();
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- // FIXME: consider splitting the vdtor vs regular method code into two
- // functions.
GlobalDecl LookupGD = GD;
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
@@ -607,51 +1000,18 @@ llvm::Value *MicrosoftCXXABI::adjustThisArgumentForVirtualCall(
unsigned AS = cast<llvm::PointerType>(This->getType())->getAddressSpace();
llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS);
CharUnits StaticOffset = ML.VFPtrOffset;
- if (ML.VBase) {
- bool AvoidVirtualOffset = false;
- if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) {
- // A base destructor can only be called from a complete destructor of the
- // same record type or another destructor of a more derived type;
- // or a constructor of the same record type if an exception is thrown.
- assert(isa<CXXDestructorDecl>(CGF.CurGD.getDecl()) ||
- isa<CXXConstructorDecl>(CGF.CurGD.getDecl()));
- const CXXRecordDecl *CurRD =
- cast<CXXMethodDecl>(CGF.CurGD.getDecl())->getParent();
-
- if (MD->getParent() == CurRD) {
- if (isa<CXXDestructorDecl>(CGF.CurGD.getDecl()))
- assert(CGF.CurGD.getDtorType() == Dtor_Complete);
- if (isa<CXXConstructorDecl>(CGF.CurGD.getDecl()))
- assert(CGF.CurGD.getCtorType() == Ctor_Complete);
- // We're calling the main base dtor from a complete structor,
- // so we know the "this" offset statically.
- AvoidVirtualOffset = true;
- } else {
- // Let's see if we try to call a destructor of a non-virtual base.
- for (CXXRecordDecl::base_class_const_iterator I = CurRD->bases_begin(),
- E = CurRD->bases_end(); I != E; ++I) {
- if (I->getType()->getAsCXXRecordDecl() != MD->getParent())
- continue;
- // If we call a base destructor for a non-virtual base, we statically
- // know where it expects the vfptr and "this" to be.
- // The total offset should reflect the adjustment done by
- // adjustThisParameterInVirtualFunctionPrologue().
- AvoidVirtualOffset = true;
- break;
- }
- }
- }
- if (AvoidVirtualOffset) {
- const ASTRecordLayout &Layout =
- CGF.getContext().getASTRecordLayout(MD->getParent());
- StaticOffset += Layout.getVBaseClassOffset(ML.VBase);
- } else {
- This = CGF.Builder.CreateBitCast(This, charPtrTy);
- llvm::Value *VBaseOffset =
- GetVirtualBaseClassOffset(CGF, This, MD->getParent(), ML.VBase);
- This = CGF.Builder.CreateInBoundsGEP(This, VBaseOffset);
- }
+ // Base destructors expect 'this' to point to the beginning of the base
+ // subobject, not the first vfptr that happens to contain the virtual dtor.
+ // However, we still need to apply the virtual base adjustment.
+ if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
+ StaticOffset = CharUnits::Zero();
+
+ if (ML.VBase) {
+ This = CGF.Builder.CreateBitCast(This, charPtrTy);
+ llvm::Value *VBaseOffset =
+ GetVirtualBaseClassOffset(CGF, This, MD->getParent(), ML.VBase);
+ This = CGF.Builder.CreateInBoundsGEP(This, VBaseOffset);
}
if (!StaticOffset.isZero()) {
assert(StaticOffset.isPositive());
@@ -678,24 +1038,29 @@ static bool IsDeletingDtor(GlobalDecl GD) {
return false;
}
-void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
- QualType &ResTy,
- FunctionArgList &Params) {
- BuildThisParam(CGF, Params);
-
+void MicrosoftCXXABI::addImplicitStructorParams(CodeGenFunction &CGF,
+ QualType &ResTy,
+ FunctionArgList &Params) {
ASTContext &Context = getContext();
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
+ assert(isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD));
if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
ImplicitParamDecl *IsMostDerived
- = ImplicitParamDecl::Create(Context, 0,
+ = ImplicitParamDecl::Create(Context, nullptr,
CGF.CurGD.getDecl()->getLocation(),
&Context.Idents.get("is_most_derived"),
Context.IntTy);
- Params.push_back(IsMostDerived);
+ // The 'most_derived' parameter goes second if the ctor is variadic and last
+ // if it's not. Dtors can't be variadic.
+ const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
+ if (FPT->isVariadic())
+ Params.insert(Params.begin() + 1, IsMostDerived);
+ else
+ Params.push_back(IsMostDerived);
getStructorImplicitParamDecl(CGF) = IsMostDerived;
} else if (IsDeletingDtor(CGF.CurGD)) {
ImplicitParamDecl *ShouldDelete
- = ImplicitParamDecl::Create(Context, 0,
+ = ImplicitParamDecl::Create(Context, nullptr,
CGF.CurGD.getDecl()->getLocation(),
&Context.Idents.get("should_call_delete"),
Context.IntTy);
@@ -706,36 +1071,12 @@ void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
llvm::Value *MicrosoftCXXABI::adjustThisParameterInVirtualFunctionPrologue(
CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This) {
- GD = GD.getCanonicalDecl();
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- GlobalDecl LookupGD = GD;
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- // Complete destructors take a pointer to the complete object as a
- // parameter, thus don't need this adjustment.
- if (GD.getDtorType() == Dtor_Complete)
- return This;
-
- // There's no Dtor_Base in vftable but it shares the this adjustment with
- // the deleting one, so look it up instead.
- LookupGD = GlobalDecl(DD, Dtor_Deleting);
- }
-
// In this ABI, every virtual function takes a pointer to one of the
// subobjects that first defines it as the 'this' parameter, rather than a
- // pointer to ther final overrider subobject. Thus, we need to adjust it back
+ // pointer to the final overrider subobject. Thus, we need to adjust it back
// to the final overrider subobject before use.
// See comments in the MicrosoftVFTableContext implementation for the details.
-
- MicrosoftVTableContext::MethodVFTableLocation ML =
- CGM.getMicrosoftVTableContext().getMethodVFTableLocation(LookupGD);
- CharUnits Adjustment = ML.VFPtrOffset;
- if (ML.VBase) {
- const ASTRecordLayout &DerivedLayout =
- CGF.getContext().getASTRecordLayout(MD->getParent());
- Adjustment += DerivedLayout.getVBaseClassOffset(ML.VBase);
- }
-
+ CharUnits Adjustment = getVirtualFunctionPrologueThisAdjustment(GD);
if (Adjustment.isZero())
return This;
@@ -784,61 +1125,81 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
}
}
-void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
- const CXXConstructorDecl *D,
- CXXCtorType Type,
- bool ForVirtualBase,
- bool Delegating,
- llvm::Value *This,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd) {
+unsigned MicrosoftCXXABI::addImplicitConstructorArgs(
+ CodeGenFunction &CGF, const CXXConstructorDecl *D, CXXCtorType Type,
+ bool ForVirtualBase, bool Delegating, CallArgList &Args) {
assert(Type == Ctor_Complete || Type == Ctor_Base);
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Ctor_Complete);
- llvm::Value *ImplicitParam = 0;
- QualType ImplicitParamTy;
- if (D->getParent()->getNumVBases()) {
- ImplicitParam = llvm::ConstantInt::get(CGM.Int32Ty, Type == Ctor_Complete);
- ImplicitParamTy = getContext().IntTy;
+ // Check if we need a 'most_derived' parameter.
+ if (!D->getParent()->getNumVBases())
+ return 0;
+
+ // Add the 'most_derived' argument second if we are variadic or last if not.
+ const FunctionProtoType *FPT = D->getType()->castAs<FunctionProtoType>();
+ llvm::Value *MostDerivedArg =
+ llvm::ConstantInt::get(CGM.Int32Ty, Type == Ctor_Complete);
+ RValue RV = RValue::get(MostDerivedArg);
+ if (MostDerivedArg) {
+ if (FPT->isVariadic())
+ Args.insert(Args.begin() + 1,
+ CallArg(RV, getContext().IntTy, /*needscopy=*/false));
+ else
+ Args.add(RV, getContext().IntTy);
+ }
+
+ return 1; // Added one arg.
+}
+
+void MicrosoftCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *DD,
+ CXXDtorType Type, bool ForVirtualBase,
+ bool Delegating, llvm::Value *This) {
+ llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
+
+ if (DD->isVirtual()) {
+ assert(Type != CXXDtorType::Dtor_Deleting &&
+ "The deleting destructor should only be called via a virtual call");
+ This = adjustThisArgumentForVirtualFunctionCall(CGF, GlobalDecl(DD, Type),
+ This, false);
}
// FIXME: Provide a source location here.
- CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
- ImplicitParam, ImplicitParamTy, ArgBeg, ArgEnd);
+ CGF.EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
+ /*ImplicitParam=*/nullptr,
+ /*ImplicitParamTy=*/QualType(), nullptr, nullptr);
}
void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
const CXXRecordDecl *RD) {
MicrosoftVTableContext &VFTContext = CGM.getMicrosoftVTableContext();
- MicrosoftVTableContext::VFPtrListTy VFPtrs = VFTContext.getVFPtrOffsets(RD);
- llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
+ VPtrInfoVector VFPtrs = VFTContext.getVFPtrOffsets(RD);
- for (MicrosoftVTableContext::VFPtrListTy::iterator I = VFPtrs.begin(),
- E = VFPtrs.end(); I != E; ++I) {
- llvm::GlobalVariable *VTable = getAddrOfVTable(RD, I->VFPtrFullOffset);
+ for (VPtrInfo *Info : VFPtrs) {
+ llvm::GlobalVariable *VTable = getAddrOfVTable(RD, Info->FullOffsetInMDC);
if (VTable->hasInitializer())
continue;
+ llvm::Constant *RTTI = getMSCompleteObjectLocator(RD, Info);
+
const VTableLayout &VTLayout =
- VFTContext.getVFTableLayout(RD, I->VFPtrFullOffset);
+ VFTContext.getVFTableLayout(RD, Info->FullOffsetInMDC);
llvm::Constant *Init = CGVT.CreateVTableInitializer(
RD, VTLayout.vtable_component_begin(),
VTLayout.getNumVTableComponents(), VTLayout.vtable_thunk_begin(),
- VTLayout.getNumVTableThunks());
- VTable->setInitializer(Init);
+ VTLayout.getNumVTableThunks(), RTTI);
- VTable->setLinkage(Linkage);
- CGM.setTypeVisibility(VTable, RD, CodeGenModule::TVK_ForVTable);
+ VTable->setInitializer(Init);
}
}
llvm::Value *MicrosoftCXXABI::getVTableAddressPointInStructor(
CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base,
const CXXRecordDecl *NearestVBase, bool &NeedsVirtualOffset) {
- NeedsVirtualOffset = (NearestVBase != 0);
+ NeedsVirtualOffset = (NearestVBase != nullptr);
- llvm::Value *VTableAddressPoint =
- getAddrOfVTable(VTableClass, Base.getBaseOffset());
+ (void)getAddrOfVTable(VTableClass, Base.getBaseOffset());
+ VFTableIdTy ID(VTableClass, Base.getBaseOffset());
+ llvm::GlobalValue *VTableAddressPoint = VFTablesMap[ID];
if (!VTableAddressPoint) {
assert(Base.getBase()->getNumVBases() &&
!CGM.getContext().getASTRecordLayout(Base.getBase()).hasOwnVFPtr());
@@ -847,17 +1208,19 @@ llvm::Value *MicrosoftCXXABI::getVTableAddressPointInStructor(
}
static void mangleVFTableName(MicrosoftMangleContext &MangleContext,
- const CXXRecordDecl *RD, const VFPtrInfo &VFPtr,
+ const CXXRecordDecl *RD, const VPtrInfo *VFPtr,
SmallString<256> &Name) {
llvm::raw_svector_ostream Out(Name);
- MangleContext.mangleCXXVFTable(RD, VFPtr.PathToMangle, Out);
+ MangleContext.mangleCXXVFTable(RD, VFPtr->MangledPath, Out);
}
llvm::Constant *MicrosoftCXXABI::getVTableAddressPointForConstExpr(
BaseSubobject Base, const CXXRecordDecl *VTableClass) {
- llvm::Constant *VTable = getAddrOfVTable(VTableClass, Base.getBaseOffset());
- assert(VTable && "Couldn't find a vftable for the given base?");
- return VTable;
+ (void)getAddrOfVTable(VTableClass, Base.getBaseOffset());
+ VFTableIdTy ID(VTableClass, Base.getBaseOffset());
+ llvm::GlobalValue *VFTable = VFTablesMap[ID];
+ assert(VFTable && "Couldn't find a vftable for the given base?");
+ return VFTable;
}
llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
@@ -866,18 +1229,16 @@ llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
// shouldn't be used in the given record type. We want to cache this result in
// VFTablesMap, thus a simple zero check is not sufficient.
VFTableIdTy ID(RD, VPtrOffset);
- VFTablesMapTy::iterator I;
+ VTablesMapTy::iterator I;
bool Inserted;
- llvm::tie(I, Inserted) = VFTablesMap.insert(
- std::make_pair(ID, static_cast<llvm::GlobalVariable *>(0)));
+ std::tie(I, Inserted) = VTablesMap.insert(std::make_pair(ID, nullptr));
if (!Inserted)
return I->second;
llvm::GlobalVariable *&VTable = I->second;
MicrosoftVTableContext &VTContext = CGM.getMicrosoftVTableContext();
- const MicrosoftVTableContext::VFPtrListTy &VFPtrs =
- VTContext.getVFPtrOffsets(RD);
+ const VPtrInfoVector &VFPtrs = VTContext.getVFPtrOffsets(RD);
if (DeferredVFTables.insert(RD)) {
// We haven't processed this record type before.
@@ -898,19 +1259,94 @@ llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
}
for (size_t J = 0, F = VFPtrs.size(); J != F; ++J) {
- if (VFPtrs[J].VFPtrFullOffset != VPtrOffset)
+ if (VFPtrs[J]->FullOffsetInMDC != VPtrOffset)
continue;
+ SmallString<256> VFTableName;
+ mangleVFTableName(getMangleContext(), RD, VFPtrs[J], VFTableName);
+ StringRef VTableName = VFTableName;
+
+ uint64_t NumVTableSlots =
+ VTContext.getVFTableLayout(RD, VFPtrs[J]->FullOffsetInMDC)
+ .getNumVTableComponents();
+ llvm::GlobalValue::LinkageTypes VTableLinkage =
+ llvm::GlobalValue::ExternalLinkage;
+ llvm::ArrayType *VTableType =
+ llvm::ArrayType::get(CGM.Int8PtrTy, NumVTableSlots);
+ if (getContext().getLangOpts().RTTIData) {
+ VTableLinkage = llvm::GlobalValue::PrivateLinkage;
+ VTableName = "";
+ }
- llvm::ArrayType *ArrayType = llvm::ArrayType::get(
- CGM.Int8PtrTy,
- VTContext.getVFTableLayout(RD, VFPtrs[J].VFPtrFullOffset)
- .getNumVTableComponents());
-
- SmallString<256> Name;
- mangleVFTableName(getMangleContext(), RD, VFPtrs[J], Name);
- VTable = CGM.CreateOrReplaceCXXRuntimeVariable(
- Name.str(), ArrayType, llvm::GlobalValue::ExternalLinkage);
- VTable->setUnnamedAddr(true);
+ VTable = CGM.getModule().getNamedGlobal(VFTableName);
+ if (!VTable) {
+ // Create a backing variable for the contents of VTable. The VTable may
+ // or may not include space for a pointer to RTTI data.
+ llvm::GlobalValue *VFTable = VTable = new llvm::GlobalVariable(
+ CGM.getModule(), VTableType, /*isConstant=*/true, VTableLinkage,
+ /*Initializer=*/nullptr, VTableName);
+ VTable->setUnnamedAddr(true);
+
+ // Only insert a pointer into the VFTable for RTTI data if we are not
+ // importing it. We never reference the RTTI data directly so there is no
+ // need to make room for it.
+ if (getContext().getLangOpts().RTTIData &&
+ !RD->hasAttr<DLLImportAttr>()) {
+ llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.IntTy, 0),
+ llvm::ConstantInt::get(CGM.IntTy, 1)};
+ // Create a GEP which points just after the first entry in the VFTable,
+ // this should be the location of the first virtual method.
+ llvm::Constant *VTableGEP =
+ llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, GEPIndices);
+ // The symbol for the VFTable is an alias to the GEP. It is
+ // transparent, to other modules, what the nature of this symbol is; all
+ // that matters is that the alias be the address of the first virtual
+ // method.
+ VFTable = llvm::GlobalAlias::create(
+ cast<llvm::SequentialType>(VTableGEP->getType())->getElementType(),
+ /*AddressSpace=*/0, llvm::GlobalValue::ExternalLinkage,
+ VFTableName.str(), VTableGEP, &CGM.getModule());
+ } else {
+ // We don't need a GlobalAlias to be a symbol for the VTable if we won't
+ // be referencing any RTTI data. The GlobalVariable will end up being
+ // an appropriate definition of the VFTable.
+ VTable->setName(VFTableName.str());
+ }
+
+ VFTable->setUnnamedAddr(true);
+ if (RD->hasAttr<DLLImportAttr>())
+ VFTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+ else if (RD->hasAttr<DLLExportAttr>())
+ VFTable->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
+
+ llvm::GlobalValue::LinkageTypes VFTableLinkage = CGM.getVTableLinkage(RD);
+ if (VFTable != VTable) {
+ if (llvm::GlobalValue::isAvailableExternallyLinkage(VFTableLinkage)) {
+ // AvailableExternally implies that we grabbed the data from another
+ // executable. No need to stick the alias in a Comdat.
+ } else if (llvm::GlobalValue::isInternalLinkage(VFTableLinkage) ||
+ llvm::GlobalValue::isWeakODRLinkage(VFTableLinkage) ||
+ llvm::GlobalValue::isLinkOnceODRLinkage(VFTableLinkage)) {
+ // The alias is going to be dropped into a Comdat, no need to make it
+ // weak.
+ if (!llvm::GlobalValue::isInternalLinkage(VFTableLinkage))
+ VFTableLinkage = llvm::GlobalValue::ExternalLinkage;
+ llvm::Comdat *C =
+ CGM.getModule().getOrInsertComdat(VFTable->getName());
+ // We must indicate which VFTable is larger to support linking between
+ // translation units which do and do not have RTTI data. The largest
+ // VFTable contains the RTTI data; translation units which reference
+ // the smaller VFTable always reference it relative to the first
+ // virtual method.
+ C->setSelectionKind(llvm::Comdat::Largest);
+ VTable->setComdat(C);
+ } else {
+ llvm_unreachable("unexpected linkage for vftable!");
+ }
+ }
+ VFTable->setLinkage(VFTableLinkage);
+ CGM.setGlobalVisibility(VFTable, RD);
+ VFTablesMap[ID] = VFTable;
+ }
break;
}
@@ -925,7 +1361,8 @@ llvm::Value *MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
CGBuilderTy &Builder = CGF.Builder;
Ty = Ty->getPointerTo()->getPointerTo();
- llvm::Value *VPtr = adjustThisArgumentForVirtualCall(CGF, GD, This);
+ llvm::Value *VPtr =
+ adjustThisArgumentForVirtualFunctionCall(CGF, GD, This, true);
llvm::Value *VTable = CGF.GetVTablePtr(VPtr, Ty);
MicrosoftVTableContext::MethodVFTableLocation ML =
@@ -955,30 +1392,47 @@ void MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(CGF.getLLVMContext()),
DtorType == Dtor_Deleting);
- This = adjustThisArgumentForVirtualCall(CGF, GD, This);
+ This = adjustThisArgumentForVirtualFunctionCall(CGF, GD, This, true);
CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This,
- ImplicitParam, Context.IntTy, 0, 0);
+ ImplicitParam, Context.IntTy, nullptr, nullptr);
}
-const VBTableVector &
-MicrosoftCXXABI::EnumerateVBTables(const CXXRecordDecl *RD) {
+const VBTableGlobals &
+MicrosoftCXXABI::enumerateVBTables(const CXXRecordDecl *RD) {
// At this layer, we can key the cache off of a single class, which is much
- // easier than caching at the GlobalVariable layer.
- llvm::DenseMap<const CXXRecordDecl*, VBTableVector>::iterator I;
- bool added;
- llvm::tie(I, added) = VBTablesMap.insert(std::make_pair(RD, VBTableVector()));
- VBTableVector &VBTables = I->second;
- if (!added)
- return VBTables;
-
- VBTableBuilder(CGM, RD).enumerateVBTables(VBTables);
+ // easier than caching each vbtable individually.
+ llvm::DenseMap<const CXXRecordDecl*, VBTableGlobals>::iterator Entry;
+ bool Added;
+ std::tie(Entry, Added) =
+ VBTablesMap.insert(std::make_pair(RD, VBTableGlobals()));
+ VBTableGlobals &VBGlobals = Entry->second;
+ if (!Added)
+ return VBGlobals;
+
+ MicrosoftVTableContext &Context = CGM.getMicrosoftVTableContext();
+ VBGlobals.VBTables = &Context.enumerateVBTables(RD);
+
+ // Cache the globals for all vbtables so we don't have to recompute the
+ // mangled names.
+ llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
+ for (VPtrInfoVector::const_iterator I = VBGlobals.VBTables->begin(),
+ E = VBGlobals.VBTables->end();
+ I != E; ++I) {
+ VBGlobals.Globals.push_back(getAddrOfVBTable(**I, RD, Linkage));
+ }
- return VBTables;
+ return VBGlobals;
}
-llvm::Function *
-MicrosoftCXXABI::EmitVirtualMemPtrThunk(const CXXMethodDecl *MD,
- StringRef ThunkName) {
+llvm::Function *MicrosoftCXXABI::EmitVirtualMemPtrThunk(
+ const CXXMethodDecl *MD,
+ const MicrosoftVTableContext::MethodVFTableLocation &ML) {
+ // Calculate the mangled name.
+ SmallString<256> ThunkName;
+ llvm::raw_svector_ostream Out(ThunkName);
+ getMangleContext().mangleVirtualMemPtrThunk(MD, Out);
+ Out.flush();
+
// If the thunk has been generated previously, just return it.
if (llvm::GlobalValue *GV = CGM.getModule().getNamedValue(ThunkName))
return cast<llvm::Function>(GV);
@@ -1002,24 +1456,127 @@ MicrosoftCXXABI::EmitVirtualMemPtrThunk(const CXXMethodDecl *MD,
CodeGenFunction CGF(CGM);
CGF.StartThunk(ThunkFn, MD, FnInfo);
- // Get to the Callee.
+ // Load the vfptr and then callee from the vftable. The callee should have
+ // adjusted 'this' so that the vfptr is at offset zero.
llvm::Value *This = CGF.LoadCXXThis();
- llvm::Value *Callee = getVirtualFunctionPointer(CGF, MD, This, ThunkTy);
+ llvm::Value *VTable =
+ CGF.GetVTablePtr(This, ThunkTy->getPointerTo()->getPointerTo());
+ llvm::Value *VFuncPtr =
+ CGF.Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn");
+ llvm::Value *Callee = CGF.Builder.CreateLoad(VFuncPtr);
+
+ unsigned CallingConv;
+ CodeGen::AttributeListType AttributeList;
+ CGM.ConstructAttributeList(FnInfo, MD, AttributeList, CallingConv, true);
+ llvm::AttributeSet Attrs =
+ llvm::AttributeSet::get(CGF.getLLVMContext(), AttributeList);
+
+ // Do a musttail call with perfect argument forwarding. Any inalloca argument
+ // will be forwarded in place without any copy.
+ SmallVector<llvm::Value *, 8> Args;
+ for (llvm::Argument &A : ThunkFn->args())
+ Args.push_back(&A);
+ llvm::CallInst *Call = CGF.Builder.CreateCall(Callee, Args);
+ Call->setTailCallKind(llvm::CallInst::TCK_MustTail);
+ Call->setAttributes(Attrs);
+ Call->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
+
+ if (Call->getType()->isVoidTy())
+ CGF.Builder.CreateRetVoid();
+ else
+ CGF.Builder.CreateRet(Call);
- // Make the call and return the result.
- CGF.EmitCallAndReturnForThunk(MD, Callee, 0);
+ // Finish the function to maintain CodeGenFunction invariants.
+ // FIXME: Don't emit unreachable code.
+ CGF.EmitBlock(CGF.createBasicBlock());
+ CGF.FinishFunction();
return ThunkFn;
}
void MicrosoftCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) {
- const VBTableVector &VBTables = EnumerateVBTables(RD);
- llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
+ const VBTableGlobals &VBGlobals = enumerateVBTables(RD);
+ for (unsigned I = 0, E = VBGlobals.VBTables->size(); I != E; ++I) {
+ const VPtrInfo *VBT = (*VBGlobals.VBTables)[I];
+ llvm::GlobalVariable *GV = VBGlobals.Globals[I];
+ emitVBTableDefinition(*VBT, RD, GV);
+ }
+}
- for (VBTableVector::const_iterator I = VBTables.begin(), E = VBTables.end();
- I != E; ++I) {
- I->EmitVBTableDefinition(CGM, RD, Linkage);
+llvm::GlobalVariable *
+MicrosoftCXXABI::getAddrOfVBTable(const VPtrInfo &VBT, const CXXRecordDecl *RD,
+ llvm::GlobalVariable::LinkageTypes Linkage) {
+ SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ getMangleContext().mangleCXXVBTable(RD, VBT.MangledPath, Out);
+ Out.flush();
+ StringRef Name = OutName.str();
+
+ llvm::ArrayType *VBTableType =
+ llvm::ArrayType::get(CGM.IntTy, 1 + VBT.ReusingBase->getNumVBases());
+
+ assert(!CGM.getModule().getNamedGlobal(Name) &&
+ "vbtable with this name already exists: mangling bug?");
+ llvm::GlobalVariable *GV =
+ CGM.CreateOrReplaceCXXRuntimeVariable(Name, VBTableType, Linkage);
+ GV->setUnnamedAddr(true);
+
+ if (RD->hasAttr<DLLImportAttr>())
+ GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+ else if (RD->hasAttr<DLLExportAttr>())
+ GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
+
+ return GV;
+}
+
+void MicrosoftCXXABI::emitVBTableDefinition(const VPtrInfo &VBT,
+ const CXXRecordDecl *RD,
+ llvm::GlobalVariable *GV) const {
+ const CXXRecordDecl *ReusingBase = VBT.ReusingBase;
+
+ assert(RD->getNumVBases() && ReusingBase->getNumVBases() &&
+ "should only emit vbtables for classes with vbtables");
+
+ const ASTRecordLayout &BaseLayout =
+ CGM.getContext().getASTRecordLayout(VBT.BaseWithVPtr);
+ const ASTRecordLayout &DerivedLayout =
+ CGM.getContext().getASTRecordLayout(RD);
+
+ SmallVector<llvm::Constant *, 4> Offsets(1 + ReusingBase->getNumVBases(),
+ nullptr);
+
+ // The offset from ReusingBase's vbptr to itself always leads.
+ CharUnits VBPtrOffset = BaseLayout.getVBPtrOffset();
+ Offsets[0] = llvm::ConstantInt::get(CGM.IntTy, -VBPtrOffset.getQuantity());
+
+ MicrosoftVTableContext &Context = CGM.getMicrosoftVTableContext();
+ for (const auto &I : ReusingBase->vbases()) {
+ const CXXRecordDecl *VBase = I.getType()->getAsCXXRecordDecl();
+ CharUnits Offset = DerivedLayout.getVBaseClassOffset(VBase);
+ assert(!Offset.isNegative());
+
+ // Make it relative to the subobject vbptr.
+ CharUnits CompleteVBPtrOffset = VBT.NonVirtualOffset + VBPtrOffset;
+ if (VBT.getVBaseWithVPtr())
+ CompleteVBPtrOffset +=
+ DerivedLayout.getVBaseClassOffset(VBT.getVBaseWithVPtr());
+ Offset -= CompleteVBPtrOffset;
+
+ unsigned VBIndex = Context.getVBTableIndex(ReusingBase, VBase);
+ assert(Offsets[VBIndex] == nullptr && "The same vbindex seen twice?");
+ Offsets[VBIndex] = llvm::ConstantInt::get(CGM.IntTy, Offset.getQuantity());
}
+
+ assert(Offsets.size() ==
+ cast<llvm::ArrayType>(cast<llvm::PointerType>(GV->getType())
+ ->getElementType())->getNumElements());
+ llvm::ArrayType *VBTableType =
+ llvm::ArrayType::get(CGM.IntTy, Offsets.size());
+ llvm::Constant *Init = llvm::ConstantArray::get(VBTableType, Offsets);
+ GV->setInitializer(Init);
+
+ // Set the right visibility.
+ CGM.setGlobalVisibility(GV, RD);
}
llvm::Value *MicrosoftCXXABI::performThisAdjustment(CodeGenFunction &CGF,
@@ -1149,6 +1706,15 @@ llvm::Value* MicrosoftCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::GlobalVariable *GV,
bool PerformInit) {
+ // MSVC only uses guards for static locals.
+ if (!D.isStaticLocal()) {
+ assert(GV->hasWeakLinkage() || GV->hasLinkOnceLinkage());
+ // GlobalOpt is allowed to discard the initializer, so use linkonce_odr.
+ CGF.CurFn->setLinkage(llvm::GlobalValue::LinkOnceODRLinkage);
+ CGF.EmitCXXGlobalVarDeclInit(D, GV, PerformInit);
+ return;
+ }
+
// MSVC always uses an i32 bitfield to guard initialization, which is *not*
// threadsafe. Since the user may be linking in inline functions compiled by
// cl.exe, there's no reason to provide a false sense of security by using
@@ -1162,29 +1728,29 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::ConstantInt *Zero = llvm::ConstantInt::get(GuardTy, 0);
// Get the guard variable for this function if we have one already.
- GuardInfo &GI = GuardVariableMap[D.getDeclContext()];
+ GuardInfo *GI = &GuardVariableMap[D.getDeclContext()];
unsigned BitIndex;
- if (D.isExternallyVisible()) {
+ if (D.isStaticLocal() && D.isExternallyVisible()) {
// Externally visible variables have to be numbered in Sema to properly
// handle unreachable VarDecls.
- BitIndex = getContext().getManglingNumber(&D);
+ BitIndex = getContext().getStaticLocalNumber(&D);
assert(BitIndex > 0);
BitIndex--;
} else {
// Non-externally visible variables are numbered here in CodeGen.
- BitIndex = GI.BitIndex++;
+ BitIndex = GI->BitIndex++;
}
if (BitIndex >= 32) {
if (D.isExternallyVisible())
ErrorUnsupportedABI(CGF, "more than 32 guarded initializations");
BitIndex %= 32;
- GI.Guard = 0;
+ GI->Guard = nullptr;
}
// Lazily create the i32 bitfield for this function.
- if (!GI.Guard) {
+ if (!GI->Guard) {
// Mangle the name for the guard.
SmallString<256> GuardName;
{
@@ -1193,13 +1759,15 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
Out.flush();
}
- // Create the guard variable with a zero-initializer. Just absorb linkage
- // and visibility from the guarded variable.
- GI.Guard = new llvm::GlobalVariable(CGM.getModule(), GuardTy, false,
- GV->getLinkage(), Zero, GuardName.str());
- GI.Guard->setVisibility(GV->getVisibility());
+ // Create the guard variable with a zero-initializer. Just absorb linkage,
+ // visibility and dll storage class from the guarded variable.
+ GI->Guard =
+ new llvm::GlobalVariable(CGM.getModule(), GuardTy, false,
+ GV->getLinkage(), Zero, GuardName.str());
+ GI->Guard->setVisibility(GV->getVisibility());
+ GI->Guard->setDLLStorageClass(GV->getDLLStorageClass());
} else {
- assert(GI.Guard->getLinkage() == GV->getLinkage() &&
+ assert(GI->Guard->getLinkage() == GV->getLinkage() &&
"static local from the same function had different linkage");
}
@@ -1211,7 +1779,7 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
// Test our bit from the guard variable.
llvm::ConstantInt *Bit = llvm::ConstantInt::get(GuardTy, 1U << BitIndex);
- llvm::LoadInst *LI = Builder.CreateLoad(GI.Guard);
+ llvm::LoadInst *LI = Builder.CreateLoad(GI->Guard);
llvm::Value *IsInitialized =
Builder.CreateICmpNE(Builder.CreateAnd(LI, Bit), Zero);
llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init");
@@ -1221,7 +1789,7 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
// Set our bit in the guard variable and emit the initializer and add a global
// destructor if appropriate.
CGF.EmitBlock(InitBlock);
- Builder.CreateStore(Builder.CreateOr(LI, Bit), GI.Guard);
+ Builder.CreateStore(Builder.CreateOr(LI, Bit), GI->Guard);
CGF.EmitCXXGlobalVarDeclInit(D, GV, PerformInit);
Builder.CreateBr(EndBlock);
@@ -1229,38 +1797,6 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
CGF.EmitBlock(EndBlock);
}
-// Member pointer helpers.
-static bool hasVBPtrOffsetField(MSInheritanceModel Inheritance) {
- return Inheritance == MSIM_Unspecified;
-}
-
-static bool hasOnlyOneField(bool IsMemberFunction,
- MSInheritanceModel Inheritance) {
- return Inheritance <= MSIM_SinglePolymorphic ||
- (!IsMemberFunction && Inheritance <= MSIM_MultiplePolymorphic);
-}
-
-// Only member pointers to functions need a this adjustment, since it can be
-// combined with the field offset for data pointers.
-static bool hasNonVirtualBaseAdjustmentField(bool IsMemberFunction,
- MSInheritanceModel Inheritance) {
- return (IsMemberFunction && Inheritance >= MSIM_Multiple);
-}
-
-static bool hasVirtualBaseAdjustmentField(MSInheritanceModel Inheritance) {
- return Inheritance >= MSIM_Virtual;
-}
-
-// Use zero for the field offset of a null data member pointer if we can
-// guarantee that zero is not a valid field offset, or if the member pointer has
-// multiple fields. Polymorphic classes have a vfptr at offset zero, so we can
-// use zero for null. If there are multiple fields, we can use zero even if it
-// is a valid field offset because null-ness testing will check the other
-// fields.
-static bool nullFieldOffsetIsZero(MSInheritanceModel Inheritance) {
- return Inheritance != MSIM_Multiple && Inheritance != MSIM_Single;
-}
-
bool MicrosoftCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
// Null-ness for function memptrs only depends on the first field, which is
// the function pointer. The rest don't matter, so we can zero initialize.
@@ -1270,28 +1806,28 @@ bool MicrosoftCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
// The virtual base adjustment field is always -1 for null, so if we have one
// we can't zero initialize. The field offset is sometimes also -1 if 0 is a
// valid field offset.
- const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
- MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
- return (!hasVirtualBaseAdjustmentField(Inheritance) &&
- nullFieldOffsetIsZero(Inheritance));
+ const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
+ MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
+ return (!MSInheritanceAttr::hasVBTableOffsetField(Inheritance) &&
+ RD->nullFieldOffsetIsZero());
}
llvm::Type *
MicrosoftCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
- const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
- MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+ const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
+ MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
llvm::SmallVector<llvm::Type *, 4> fields;
if (MPT->isMemberFunctionPointer())
fields.push_back(CGM.VoidPtrTy); // FunctionPointerOrVirtualThunk
else
fields.push_back(CGM.IntTy); // FieldOffset
- if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(),
- Inheritance))
+ if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(),
+ Inheritance))
fields.push_back(CGM.IntTy);
- if (hasVBPtrOffsetField(Inheritance))
+ if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
fields.push_back(CGM.IntTy);
- if (hasVirtualBaseAdjustmentField(Inheritance))
+ if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
fields.push_back(CGM.IntTy); // VirtualBaseAdjustmentOffset
if (fields.size() == 1)
@@ -1303,24 +1839,24 @@ void MicrosoftCXXABI::
GetNullMemberPointerFields(const MemberPointerType *MPT,
llvm::SmallVectorImpl<llvm::Constant *> &fields) {
assert(fields.empty());
- const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
- MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+ const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
+ MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
if (MPT->isMemberFunctionPointer()) {
// FunctionPointerOrVirtualThunk
fields.push_back(llvm::Constant::getNullValue(CGM.VoidPtrTy));
} else {
- if (nullFieldOffsetIsZero(Inheritance))
+ if (RD->nullFieldOffsetIsZero())
fields.push_back(getZeroInt()); // FieldOffset
else
fields.push_back(getAllOnesInt()); // FieldOffset
}
- if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(),
- Inheritance))
+ if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(),
+ Inheritance))
fields.push_back(getZeroInt());
- if (hasVBPtrOffsetField(Inheritance))
+ if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
fields.push_back(getZeroInt());
- if (hasVirtualBaseAdjustmentField(Inheritance))
+ if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
fields.push_back(getAllOnesInt());
}
@@ -1341,29 +1877,29 @@ MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField,
const CXXRecordDecl *RD,
CharUnits NonVirtualBaseAdjustment)
{
- MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+ MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
// Single inheritance class member pointer are represented as scalars instead
// of aggregates.
- if (hasOnlyOneField(IsMemberFunction, Inheritance))
+ if (MSInheritanceAttr::hasOnlyOneField(IsMemberFunction, Inheritance))
return FirstField;
llvm::SmallVector<llvm::Constant *, 4> fields;
fields.push_back(FirstField);
- if (hasNonVirtualBaseAdjustmentField(IsMemberFunction, Inheritance))
+ if (MSInheritanceAttr::hasNVOffsetField(IsMemberFunction, Inheritance))
fields.push_back(llvm::ConstantInt::get(
CGM.IntTy, NonVirtualBaseAdjustment.getQuantity()));
- if (hasVBPtrOffsetField(Inheritance)) {
+ if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance)) {
CharUnits Offs = CharUnits::Zero();
if (RD->getNumVBases())
- Offs = GetVBPtrOffsetFromBases(RD);
+ Offs = getContext().getASTRecordLayout(RD).getVBPtrOffset();
fields.push_back(llvm::ConstantInt::get(CGM.IntTy, Offs.getQuantity()));
}
// The rest of the fields are adjusted by conversions to a more derived class.
- if (hasVirtualBaseAdjustmentField(Inheritance))
+ if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
fields.push_back(getZeroInt());
return llvm::ConstantStruct::getAnon(fields);
@@ -1372,7 +1908,7 @@ MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField,
llvm::Constant *
MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
CharUnits offset) {
- const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+ const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
llvm::Constant *FirstField =
llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity());
return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/false, RD,
@@ -1395,8 +1931,8 @@ llvm::Constant *MicrosoftCXXABI::EmitMemberPointer(const APValue &MP,
// FIXME PR15713: Support virtual inheritance paths.
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD))
- return BuildMemberPointer(MPT->getClass()->getAsCXXRecordDecl(),
- MD, ThisAdjustment);
+ return BuildMemberPointer(MPT->getMostRecentCXXRecordDecl(), MD,
+ ThisAdjustment);
CharUnits FieldOffset =
getContext().toCharUnitsFromBits(getContext().getFieldOffset(MPD));
@@ -1409,6 +1945,7 @@ MicrosoftCXXABI::BuildMemberPointer(const CXXRecordDecl *RD,
CharUnits NonVirtualBaseAdjustment) {
assert(MD->isInstance() && "Member function must not be static!");
MD = MD->getCanonicalDecl();
+ RD = RD->getMostRecentDecl();
CodeGenTypes &Types = CGM.getTypes();
llvm::Constant *FirstField;
@@ -1442,16 +1979,10 @@ MicrosoftCXXABI::BuildMemberPointer(const CXXRecordDecl *RD,
"member function in virtual base class");
FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
} else {
- SmallString<256> ThunkName;
- CharUnits PointerWidth = getContext().toCharUnitsFromBits(
- getContext().getTargetInfo().getPointerWidth(0));
- uint64_t OffsetInVFTable = ML.Index * PointerWidth.getQuantity();
- llvm::raw_svector_ostream Out(ThunkName);
- getMangleContext().mangleVirtualMemPtrThunk(MD, OffsetInVFTable, Out);
- Out.flush();
-
- llvm::Function *Thunk = EmitVirtualMemPtrThunk(MD, ThunkName.str());
+ llvm::Function *Thunk = EmitVirtualMemPtrThunk(MD, ML);
FirstField = llvm::ConstantExpr::getBitCast(Thunk, CGM.VoidPtrTy);
+ // Include the vfptr adjustment if the method is in a non-primary vftable.
+ NonVirtualBaseAdjustment += ML.VFPtrOffset;
}
}
@@ -1486,9 +2017,10 @@ MicrosoftCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF,
// If this is a single field member pointer (single inheritance), this is a
// single icmp.
- const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
- MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
- if (hasOnlyOneField(MPT->isMemberFunctionPointer(), Inheritance))
+ const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
+ MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
+ if (MSInheritanceAttr::hasOnlyOneField(MPT->isMemberFunctionPointer(),
+ Inheritance))
return Builder.CreateICmp(Eq, L, R);
// Compare the first field.
@@ -1497,7 +2029,7 @@ MicrosoftCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF,
llvm::Value *Cmp0 = Builder.CreateICmp(Eq, L0, R0, "memptr.cmp.first");
// Compare everything other than the first field.
- llvm::Value *Res = 0;
+ llvm::Value *Res = nullptr;
llvm::StructType *LType = cast<llvm::StructType>(L->getType());
for (unsigned I = 1, E = LType->getNumElements(); I != E; ++I) {
llvm::Value *LF = Builder.CreateExtractValue(L, I);
@@ -1548,7 +2080,7 @@ MicrosoftCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
for (int I = 1, E = fields.size(); I < E; ++I) {
llvm::Value *Field = Builder.CreateExtractValue(MemPtr, I);
llvm::Value *Next = Builder.CreateICmpNE(Field, fields[I], "memptr.cmp");
- Res = Builder.CreateAnd(Res, Next, "memptr.tobool");
+ Res = Builder.CreateOr(Res, Next, "memptr.tobool");
}
return Res;
}
@@ -1607,16 +2139,14 @@ MicrosoftCXXABI::GetVBaseOffsetFromVBPtr(CodeGenFunction &CGF,
// Returns an adjusted base cast to i8*, since we do more address arithmetic on
// it.
-llvm::Value *
-MicrosoftCXXABI::AdjustVirtualBase(CodeGenFunction &CGF,
- const CXXRecordDecl *RD, llvm::Value *Base,
- llvm::Value *VBTableOffset,
- llvm::Value *VBPtrOffset) {
+llvm::Value *MicrosoftCXXABI::AdjustVirtualBase(
+ CodeGenFunction &CGF, const Expr *E, const CXXRecordDecl *RD,
+ llvm::Value *Base, llvm::Value *VBTableOffset, llvm::Value *VBPtrOffset) {
CGBuilderTy &Builder = CGF.Builder;
Base = Builder.CreateBitCast(Base, CGM.Int8PtrTy);
- llvm::BasicBlock *OriginalBB = 0;
- llvm::BasicBlock *SkipAdjustBB = 0;
- llvm::BasicBlock *VBaseAdjustBB = 0;
+ llvm::BasicBlock *OriginalBB = nullptr;
+ llvm::BasicBlock *SkipAdjustBB = nullptr;
+ llvm::BasicBlock *VBaseAdjustBB = nullptr;
// In the unspecified inheritance model, there might not be a vbtable at all,
// in which case we need to skip the virtual base lookup. If there is a
@@ -1637,12 +2167,18 @@ MicrosoftCXXABI::AdjustVirtualBase(CodeGenFunction &CGF,
// know the vbptr offset.
if (!VBPtrOffset) {
CharUnits offs = CharUnits::Zero();
- if (RD->getNumVBases()) {
- offs = GetVBPtrOffsetFromBases(RD);
- }
+ if (!RD->hasDefinition()) {
+ DiagnosticsEngine &Diags = CGF.CGM.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(
+ DiagnosticsEngine::Error,
+ "member pointer representation requires a "
+ "complete class type for %0 to perform this expression");
+ Diags.Report(E->getExprLoc(), DiagID) << RD << E->getSourceRange();
+ } else if (RD->getNumVBases())
+ offs = getContext().getASTRecordLayout(RD).getVBPtrOffset();
VBPtrOffset = llvm::ConstantInt::get(CGM.IntTy, offs.getQuantity());
}
- llvm::Value *VBPtr = 0;
+ llvm::Value *VBPtr = nullptr;
llvm::Value *VBaseOffs =
GetVBaseOffsetFromVBPtr(CGF, Base, VBPtrOffset, VBTableOffset, &VBPtr);
llvm::Value *AdjustedBase = Builder.CreateInBoundsGEP(VBPtr, VBaseOffs);
@@ -1659,38 +2195,41 @@ MicrosoftCXXABI::AdjustVirtualBase(CodeGenFunction &CGF,
return AdjustedBase;
}
-llvm::Value *
-MicrosoftCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
- llvm::Value *Base,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT) {
+llvm::Value *MicrosoftCXXABI::EmitMemberDataPointerAddress(
+ CodeGenFunction &CGF, const Expr *E, llvm::Value *Base, llvm::Value *MemPtr,
+ const MemberPointerType *MPT) {
assert(MPT->isMemberDataPointer());
unsigned AS = Base->getType()->getPointerAddressSpace();
llvm::Type *PType =
CGF.ConvertTypeForMem(MPT->getPointeeType())->getPointerTo(AS);
CGBuilderTy &Builder = CGF.Builder;
- const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
- MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+ const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
+ MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
// Extract the fields we need, regardless of model. We'll apply them if we
// have them.
llvm::Value *FieldOffset = MemPtr;
- llvm::Value *VirtualBaseAdjustmentOffset = 0;
- llvm::Value *VBPtrOffset = 0;
+ llvm::Value *VirtualBaseAdjustmentOffset = nullptr;
+ llvm::Value *VBPtrOffset = nullptr;
if (MemPtr->getType()->isStructTy()) {
// We need to extract values.
unsigned I = 0;
FieldOffset = Builder.CreateExtractValue(MemPtr, I++);
- if (hasVBPtrOffsetField(Inheritance))
+ if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++);
- if (hasVirtualBaseAdjustmentField(Inheritance))
+ if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++);
}
if (VirtualBaseAdjustmentOffset) {
- Base = AdjustVirtualBase(CGF, RD, Base, VirtualBaseAdjustmentOffset,
+ Base = AdjustVirtualBase(CGF, E, RD, Base, VirtualBaseAdjustmentOffset,
VBPtrOffset);
}
+
+ // Cast to char*.
+ Base = Builder.CreateBitCast(Base, Builder.getInt8Ty()->getPointerTo(AS));
+
+ // Apply the offset, which we assume is non-null.
llvm::Value *Addr =
Builder.CreateInBoundsGEP(Base, FieldOffset, "memptr.offset");
@@ -1699,9 +2238,9 @@ MicrosoftCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
return Builder.CreateBitCast(Addr, PType);
}
-static MSInheritanceModel
+static MSInheritanceAttr::Spelling
getInheritanceFromMemptr(const MemberPointerType *MPT) {
- return MPT->getClass()->getAsCXXRecordDecl()->getMSInheritanceModel();
+ return MPT->getMostRecentCXXRecordDecl()->getMSInheritanceModel();
}
llvm::Value *
@@ -1721,15 +2260,17 @@ MicrosoftCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
const MemberPointerType *SrcTy =
E->getSubExpr()->getType()->castAs<MemberPointerType>();
const MemberPointerType *DstTy = E->getType()->castAs<MemberPointerType>();
- MSInheritanceModel SrcInheritance = getInheritanceFromMemptr(SrcTy);
- MSInheritanceModel DstInheritance = getInheritanceFromMemptr(DstTy);
bool IsFunc = SrcTy->isMemberFunctionPointer();
// If the classes use the same null representation, reinterpret_cast is a nop.
bool IsReinterpret = E->getCastKind() == CK_ReinterpretMemberPointer;
- if (IsReinterpret && (IsFunc ||
- nullFieldOffsetIsZero(SrcInheritance) ==
- nullFieldOffsetIsZero(DstInheritance)))
+ if (IsReinterpret && IsFunc)
+ return Src;
+
+ CXXRecordDecl *SrcRD = SrcTy->getMostRecentCXXRecordDecl();
+ CXXRecordDecl *DstRD = DstTy->getMostRecentCXXRecordDecl();
+ if (IsReinterpret &&
+ SrcRD->nullFieldOffsetIsZero() == DstRD->nullFieldOffsetIsZero())
return Src;
CGBuilderTy &Builder = CGF.Builder;
@@ -1755,18 +2296,19 @@ MicrosoftCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
// Decompose src.
llvm::Value *FirstField = Src;
- llvm::Value *NonVirtualBaseAdjustment = 0;
- llvm::Value *VirtualBaseAdjustmentOffset = 0;
- llvm::Value *VBPtrOffset = 0;
- if (!hasOnlyOneField(IsFunc, SrcInheritance)) {
+ llvm::Value *NonVirtualBaseAdjustment = nullptr;
+ llvm::Value *VirtualBaseAdjustmentOffset = nullptr;
+ llvm::Value *VBPtrOffset = nullptr;
+ MSInheritanceAttr::Spelling SrcInheritance = SrcRD->getMSInheritanceModel();
+ if (!MSInheritanceAttr::hasOnlyOneField(IsFunc, SrcInheritance)) {
// We need to extract values.
unsigned I = 0;
FirstField = Builder.CreateExtractValue(Src, I++);
- if (hasNonVirtualBaseAdjustmentField(IsFunc, SrcInheritance))
+ if (MSInheritanceAttr::hasNVOffsetField(IsFunc, SrcInheritance))
NonVirtualBaseAdjustment = Builder.CreateExtractValue(Src, I++);
- if (hasVBPtrOffsetField(SrcInheritance))
+ if (MSInheritanceAttr::hasVBPtrOffsetField(SrcInheritance))
VBPtrOffset = Builder.CreateExtractValue(Src, I++);
- if (hasVirtualBaseAdjustmentField(SrcInheritance))
+ if (MSInheritanceAttr::hasVBTableOffsetField(SrcInheritance))
VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(Src, I++);
}
@@ -1788,20 +2330,21 @@ MicrosoftCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
// FIXME PR15713: Support conversions through virtually derived classes.
// Recompose dst from the null struct and the adjusted fields from src.
+ MSInheritanceAttr::Spelling DstInheritance = DstRD->getMSInheritanceModel();
llvm::Value *Dst;
- if (hasOnlyOneField(IsFunc, DstInheritance)) {
+ if (MSInheritanceAttr::hasOnlyOneField(IsFunc, DstInheritance)) {
Dst = FirstField;
} else {
Dst = llvm::UndefValue::get(DstNull->getType());
unsigned Idx = 0;
Dst = Builder.CreateInsertValue(Dst, FirstField, Idx++);
- if (hasNonVirtualBaseAdjustmentField(IsFunc, DstInheritance))
+ if (MSInheritanceAttr::hasNVOffsetField(IsFunc, DstInheritance))
Dst = Builder.CreateInsertValue(
Dst, getValueOrZeroInt(NonVirtualBaseAdjustment), Idx++);
- if (hasVBPtrOffsetField(DstInheritance))
+ if (MSInheritanceAttr::hasVBPtrOffsetField(DstInheritance))
Dst = Builder.CreateInsertValue(
Dst, getValueOrZeroInt(VBPtrOffset), Idx++);
- if (hasVirtualBaseAdjustmentField(DstInheritance))
+ if (MSInheritanceAttr::hasVBTableOffsetField(DstInheritance))
Dst = Builder.CreateInsertValue(
Dst, getValueOrZeroInt(VirtualBaseAdjustmentOffset), Idx++);
}
@@ -1833,24 +2376,24 @@ MicrosoftCXXABI::EmitMemberPointerConversion(const CastExpr *E,
if (E->getCastKind() == CK_ReinterpretMemberPointer)
return Src;
- MSInheritanceModel SrcInheritance = getInheritanceFromMemptr(SrcTy);
- MSInheritanceModel DstInheritance = getInheritanceFromMemptr(DstTy);
+ MSInheritanceAttr::Spelling SrcInheritance = getInheritanceFromMemptr(SrcTy);
+ MSInheritanceAttr::Spelling DstInheritance = getInheritanceFromMemptr(DstTy);
// Decompose src.
llvm::Constant *FirstField = Src;
- llvm::Constant *NonVirtualBaseAdjustment = 0;
- llvm::Constant *VirtualBaseAdjustmentOffset = 0;
- llvm::Constant *VBPtrOffset = 0;
+ llvm::Constant *NonVirtualBaseAdjustment = nullptr;
+ llvm::Constant *VirtualBaseAdjustmentOffset = nullptr;
+ llvm::Constant *VBPtrOffset = nullptr;
bool IsFunc = SrcTy->isMemberFunctionPointer();
- if (!hasOnlyOneField(IsFunc, SrcInheritance)) {
+ if (!MSInheritanceAttr::hasOnlyOneField(IsFunc, SrcInheritance)) {
// We need to extract values.
unsigned I = 0;
FirstField = Src->getAggregateElement(I++);
- if (hasNonVirtualBaseAdjustmentField(IsFunc, SrcInheritance))
+ if (MSInheritanceAttr::hasNVOffsetField(IsFunc, SrcInheritance))
NonVirtualBaseAdjustment = Src->getAggregateElement(I++);
- if (hasVBPtrOffsetField(SrcInheritance))
+ if (MSInheritanceAttr::hasVBPtrOffsetField(SrcInheritance))
VBPtrOffset = Src->getAggregateElement(I++);
- if (hasVirtualBaseAdjustmentField(SrcInheritance))
+ if (MSInheritanceAttr::hasVBTableOffsetField(SrcInheritance))
VirtualBaseAdjustmentOffset = Src->getAggregateElement(I++);
}
@@ -1873,56 +2416,54 @@ MicrosoftCXXABI::EmitMemberPointerConversion(const CastExpr *E,
// FIXME PR15713: Support conversions through virtually derived classes.
// Recompose dst from the null struct and the adjusted fields from src.
- if (hasOnlyOneField(IsFunc, DstInheritance))
+ if (MSInheritanceAttr::hasOnlyOneField(IsFunc, DstInheritance))
return FirstField;
llvm::SmallVector<llvm::Constant *, 4> Fields;
Fields.push_back(FirstField);
- if (hasNonVirtualBaseAdjustmentField(IsFunc, DstInheritance))
+ if (MSInheritanceAttr::hasNVOffsetField(IsFunc, DstInheritance))
Fields.push_back(getConstantOrZeroInt(NonVirtualBaseAdjustment));
- if (hasVBPtrOffsetField(DstInheritance))
+ if (MSInheritanceAttr::hasVBPtrOffsetField(DstInheritance))
Fields.push_back(getConstantOrZeroInt(VBPtrOffset));
- if (hasVirtualBaseAdjustmentField(DstInheritance))
+ if (MSInheritanceAttr::hasVBTableOffsetField(DstInheritance))
Fields.push_back(getConstantOrZeroInt(VirtualBaseAdjustmentOffset));
return llvm::ConstantStruct::getAnon(Fields);
}
-llvm::Value *
-MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
- llvm::Value *&This,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT) {
+llvm::Value *MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer(
+ CodeGenFunction &CGF, const Expr *E, llvm::Value *&This,
+ llvm::Value *MemPtr, const MemberPointerType *MPT) {
assert(MPT->isMemberFunctionPointer());
const FunctionProtoType *FPT =
MPT->getPointeeType()->castAs<FunctionProtoType>();
- const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+ const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
llvm::FunctionType *FTy =
CGM.getTypes().GetFunctionType(
CGM.getTypes().arrangeCXXMethodType(RD, FPT));
CGBuilderTy &Builder = CGF.Builder;
- MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+ MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel();
// Extract the fields we need, regardless of model. We'll apply them if we
// have them.
llvm::Value *FunctionPointer = MemPtr;
- llvm::Value *NonVirtualBaseAdjustment = NULL;
- llvm::Value *VirtualBaseAdjustmentOffset = NULL;
- llvm::Value *VBPtrOffset = NULL;
+ llvm::Value *NonVirtualBaseAdjustment = nullptr;
+ llvm::Value *VirtualBaseAdjustmentOffset = nullptr;
+ llvm::Value *VBPtrOffset = nullptr;
if (MemPtr->getType()->isStructTy()) {
// We need to extract values.
unsigned I = 0;
FunctionPointer = Builder.CreateExtractValue(MemPtr, I++);
- if (hasNonVirtualBaseAdjustmentField(MPT, Inheritance))
+ if (MSInheritanceAttr::hasNVOffsetField(MPT, Inheritance))
NonVirtualBaseAdjustment = Builder.CreateExtractValue(MemPtr, I++);
- if (hasVBPtrOffsetField(Inheritance))
+ if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance))
VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++);
- if (hasVirtualBaseAdjustmentField(Inheritance))
+ if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance))
VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++);
}
if (VirtualBaseAdjustmentOffset) {
- This = AdjustVirtualBase(CGF, RD, This, VirtualBaseAdjustmentOffset,
+ This = AdjustVirtualBase(CGF, E, RD, This, VirtualBaseAdjustmentOffset,
VBPtrOffset);
}
@@ -1939,3 +2480,398 @@ MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) {
return new MicrosoftCXXABI(CGM);
}
+
+// MS RTTI Overview:
+// The run time type information emitted by cl.exe contains 5 distinct types of
+// structures. Many of them reference each other.
+//
+// TypeInfo: Static classes that are returned by typeid.
+//
+// CompleteObjectLocator: Referenced by vftables. They contain information
+// required for dynamic casting, including OffsetFromTop. They also contain
+// a reference to the TypeInfo for the type and a reference to the
+// CompleteHierarchyDescriptor for the type.
+//
+// ClassHieararchyDescriptor: Contains information about a class hierarchy.
+// Used during dynamic_cast to walk a class hierarchy. References a base
+// class array and the size of said array.
+//
+// BaseClassArray: Contains a list of classes in a hierarchy. BaseClassArray is
+// somewhat of a misnomer because the most derived class is also in the list
+// as well as multiple copies of virtual bases (if they occur multiple times
+// in the hiearchy.) The BaseClassArray contains one BaseClassDescriptor for
+// every path in the hierarchy, in pre-order depth first order. Note, we do
+// not declare a specific llvm type for BaseClassArray, it's merely an array
+// of BaseClassDescriptor pointers.
+//
+// BaseClassDescriptor: Contains information about a class in a class hierarchy.
+// BaseClassDescriptor is also somewhat of a misnomer for the same reason that
+// BaseClassArray is. It contains information about a class within a
+// hierarchy such as: is this base is ambiguous and what is its offset in the
+// vbtable. The names of the BaseClassDescriptors have all of their fields
+// mangled into them so they can be aggressively deduplicated by the linker.
+
+static llvm::GlobalVariable *getTypeInfoVTable(CodeGenModule &CGM) {
+ StringRef MangledName("\01??_7type_info@@6B@");
+ if (auto VTable = CGM.getModule().getNamedGlobal(MangledName))
+ return VTable;
+ return new llvm::GlobalVariable(CGM.getModule(), CGM.Int8PtrTy,
+ /*Constant=*/true,
+ llvm::GlobalVariable::ExternalLinkage,
+ /*Initializer=*/nullptr, MangledName);
+}
+
+namespace {
+
+/// \brief A Helper struct that stores information about a class in a class
+/// hierarchy. The information stored in these structs struct is used during
+/// the generation of ClassHierarchyDescriptors and BaseClassDescriptors.
+// During RTTI creation, MSRTTIClasses are stored in a contiguous array with
+// implicit depth first pre-order tree connectivity. getFirstChild and
+// getNextSibling allow us to walk the tree efficiently.
+struct MSRTTIClass {
+ enum {
+ IsPrivateOnPath = 1 | 8,
+ IsAmbiguous = 2,
+ IsPrivate = 4,
+ IsVirtual = 16,
+ HasHierarchyDescriptor = 64
+ };
+ MSRTTIClass(const CXXRecordDecl *RD) : RD(RD) {}
+ uint32_t initialize(const MSRTTIClass *Parent,
+ const CXXBaseSpecifier *Specifier);
+
+ MSRTTIClass *getFirstChild() { return this + 1; }
+ static MSRTTIClass *getNextChild(MSRTTIClass *Child) {
+ return Child + 1 + Child->NumBases;
+ }
+
+ const CXXRecordDecl *RD, *VirtualRoot;
+ uint32_t Flags, NumBases, OffsetInVBase;
+};
+
+/// \brief Recursively initialize the base class array.
+uint32_t MSRTTIClass::initialize(const MSRTTIClass *Parent,
+ const CXXBaseSpecifier *Specifier) {
+ Flags = HasHierarchyDescriptor;
+ if (!Parent) {
+ VirtualRoot = nullptr;
+ OffsetInVBase = 0;
+ } else {
+ if (Specifier->getAccessSpecifier() != AS_public)
+ Flags |= IsPrivate | IsPrivateOnPath;
+ if (Specifier->isVirtual()) {
+ Flags |= IsVirtual;
+ VirtualRoot = RD;
+ OffsetInVBase = 0;
+ } else {
+ if (Parent->Flags & IsPrivateOnPath)
+ Flags |= IsPrivateOnPath;
+ VirtualRoot = Parent->VirtualRoot;
+ OffsetInVBase = Parent->OffsetInVBase + RD->getASTContext()
+ .getASTRecordLayout(Parent->RD).getBaseClassOffset(RD).getQuantity();
+ }
+ }
+ NumBases = 0;
+ MSRTTIClass *Child = getFirstChild();
+ for (const CXXBaseSpecifier &Base : RD->bases()) {
+ NumBases += Child->initialize(this, &Base) + 1;
+ Child = getNextChild(Child);
+ }
+ return NumBases;
+}
+
+static llvm::GlobalValue::LinkageTypes getLinkageForRTTI(QualType Ty) {
+ switch (Ty->getLinkage()) {
+ case NoLinkage:
+ case InternalLinkage:
+ case UniqueExternalLinkage:
+ return llvm::GlobalValue::InternalLinkage;
+
+ case VisibleNoLinkage:
+ case ExternalLinkage:
+ return llvm::GlobalValue::LinkOnceODRLinkage;
+ }
+ llvm_unreachable("Invalid linkage!");
+}
+
+/// \brief An ephemeral helper class for building MS RTTI types. It caches some
+/// calls to the module and information about the most derived class in a
+/// hierarchy.
+struct MSRTTIBuilder {
+ enum {
+ HasBranchingHierarchy = 1,
+ HasVirtualBranchingHierarchy = 2,
+ HasAmbiguousBases = 4
+ };
+
+ MSRTTIBuilder(MicrosoftCXXABI &ABI, const CXXRecordDecl *RD)
+ : CGM(ABI.CGM), Context(CGM.getContext()),
+ VMContext(CGM.getLLVMContext()), Module(CGM.getModule()), RD(RD),
+ Linkage(getLinkageForRTTI(CGM.getContext().getTagDeclType(RD))),
+ ABI(ABI) {}
+
+ llvm::GlobalVariable *getBaseClassDescriptor(const MSRTTIClass &Classes);
+ llvm::GlobalVariable *
+ getBaseClassArray(SmallVectorImpl<MSRTTIClass> &Classes);
+ llvm::GlobalVariable *getClassHierarchyDescriptor();
+ llvm::GlobalVariable *getCompleteObjectLocator(const VPtrInfo *Info);
+
+ CodeGenModule &CGM;
+ ASTContext &Context;
+ llvm::LLVMContext &VMContext;
+ llvm::Module &Module;
+ const CXXRecordDecl *RD;
+ llvm::GlobalVariable::LinkageTypes Linkage;
+ MicrosoftCXXABI &ABI;
+};
+
+} // namespace
+
+/// \brief Recursively serializes a class hierarchy in pre-order depth first
+/// order.
+static void serializeClassHierarchy(SmallVectorImpl<MSRTTIClass> &Classes,
+ const CXXRecordDecl *RD) {
+ Classes.push_back(MSRTTIClass(RD));
+ for (const CXXBaseSpecifier &Base : RD->bases())
+ serializeClassHierarchy(Classes, Base.getType()->getAsCXXRecordDecl());
+}
+
+/// \brief Find ambiguity among base classes.
+static void
+detectAmbiguousBases(SmallVectorImpl<MSRTTIClass> &Classes) {
+ llvm::SmallPtrSet<const CXXRecordDecl *, 8> VirtualBases;
+ llvm::SmallPtrSet<const CXXRecordDecl *, 8> UniqueBases;
+ llvm::SmallPtrSet<const CXXRecordDecl *, 8> AmbiguousBases;
+ for (MSRTTIClass *Class = &Classes.front(); Class <= &Classes.back();) {
+ if ((Class->Flags & MSRTTIClass::IsVirtual) &&
+ !VirtualBases.insert(Class->RD)) {
+ Class = MSRTTIClass::getNextChild(Class);
+ continue;
+ }
+ if (!UniqueBases.insert(Class->RD))
+ AmbiguousBases.insert(Class->RD);
+ Class++;
+ }
+ if (AmbiguousBases.empty())
+ return;
+ for (MSRTTIClass &Class : Classes)
+ if (AmbiguousBases.count(Class.RD))
+ Class.Flags |= MSRTTIClass::IsAmbiguous;
+}
+
+llvm::GlobalVariable *MSRTTIBuilder::getClassHierarchyDescriptor() {
+ SmallString<256> MangledName;
+ {
+ llvm::raw_svector_ostream Out(MangledName);
+ ABI.getMangleContext().mangleCXXRTTIClassHierarchyDescriptor(RD, Out);
+ }
+
+ // Check to see if we've already declared this ClassHierarchyDescriptor.
+ if (auto CHD = Module.getNamedGlobal(MangledName))
+ return CHD;
+
+ // Serialize the class hierarchy and initialize the CHD Fields.
+ SmallVector<MSRTTIClass, 8> Classes;
+ serializeClassHierarchy(Classes, RD);
+ Classes.front().initialize(/*Parent=*/nullptr, /*Specifier=*/nullptr);
+ detectAmbiguousBases(Classes);
+ int Flags = 0;
+ for (auto Class : Classes) {
+ if (Class.RD->getNumBases() > 1)
+ Flags |= HasBranchingHierarchy;
+ // Note: cl.exe does not calculate "HasAmbiguousBases" correctly. We
+ // believe the field isn't actually used.
+ if (Class.Flags & MSRTTIClass::IsAmbiguous)
+ Flags |= HasAmbiguousBases;
+ }
+ if ((Flags & HasBranchingHierarchy) && RD->getNumVBases() != 0)
+ Flags |= HasVirtualBranchingHierarchy;
+ // These gep indices are used to get the address of the first element of the
+ // base class array.
+ llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.IntTy, 0),
+ llvm::ConstantInt::get(CGM.IntTy, 0)};
+
+ // Forward-declare the class hierarchy descriptor
+ auto Type = ABI.getClassHierarchyDescriptorType();
+ auto CHD = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage,
+ /*Initializer=*/nullptr,
+ MangledName.c_str());
+
+ // Initialize the base class ClassHierarchyDescriptor.
+ llvm::Constant *Fields[] = {
+ llvm::ConstantInt::get(CGM.IntTy, 0), // Unknown
+ llvm::ConstantInt::get(CGM.IntTy, Flags),
+ llvm::ConstantInt::get(CGM.IntTy, Classes.size()),
+ ABI.getImageRelativeConstant(llvm::ConstantExpr::getInBoundsGetElementPtr(
+ getBaseClassArray(Classes),
+ llvm::ArrayRef<llvm::Value *>(GEPIndices))),
+ };
+ CHD->setInitializer(llvm::ConstantStruct::get(Type, Fields));
+ return CHD;
+}
+
+llvm::GlobalVariable *
+MSRTTIBuilder::getBaseClassArray(SmallVectorImpl<MSRTTIClass> &Classes) {
+ SmallString<256> MangledName;
+ {
+ llvm::raw_svector_ostream Out(MangledName);
+ ABI.getMangleContext().mangleCXXRTTIBaseClassArray(RD, Out);
+ }
+
+ // Forward-declare the base class array.
+ // cl.exe pads the base class array with 1 (in 32 bit mode) or 4 (in 64 bit
+ // mode) bytes of padding. We provide a pointer sized amount of padding by
+ // adding +1 to Classes.size(). The sections have pointer alignment and are
+ // marked pick-any so it shouldn't matter.
+ llvm::Type *PtrType = ABI.getImageRelativeType(
+ ABI.getBaseClassDescriptorType()->getPointerTo());
+ auto *ArrType = llvm::ArrayType::get(PtrType, Classes.size() + 1);
+ auto *BCA = new llvm::GlobalVariable(
+ Module, ArrType,
+ /*Constant=*/true, Linkage, /*Initializer=*/nullptr, MangledName.c_str());
+
+ // Initialize the BaseClassArray.
+ SmallVector<llvm::Constant *, 8> BaseClassArrayData;
+ for (MSRTTIClass &Class : Classes)
+ BaseClassArrayData.push_back(
+ ABI.getImageRelativeConstant(getBaseClassDescriptor(Class)));
+ BaseClassArrayData.push_back(llvm::Constant::getNullValue(PtrType));
+ BCA->setInitializer(llvm::ConstantArray::get(ArrType, BaseClassArrayData));
+ return BCA;
+}
+
+llvm::GlobalVariable *
+MSRTTIBuilder::getBaseClassDescriptor(const MSRTTIClass &Class) {
+ // Compute the fields for the BaseClassDescriptor. They are computed up front
+ // because they are mangled into the name of the object.
+ uint32_t OffsetInVBTable = 0;
+ int32_t VBPtrOffset = -1;
+ if (Class.VirtualRoot) {
+ auto &VTableContext = CGM.getMicrosoftVTableContext();
+ OffsetInVBTable = VTableContext.getVBTableIndex(RD, Class.VirtualRoot) * 4;
+ VBPtrOffset = Context.getASTRecordLayout(RD).getVBPtrOffset().getQuantity();
+ }
+
+ SmallString<256> MangledName;
+ {
+ llvm::raw_svector_ostream Out(MangledName);
+ ABI.getMangleContext().mangleCXXRTTIBaseClassDescriptor(
+ Class.RD, Class.OffsetInVBase, VBPtrOffset, OffsetInVBTable,
+ Class.Flags, Out);
+ }
+
+ // Check to see if we've already declared this object.
+ if (auto BCD = Module.getNamedGlobal(MangledName))
+ return BCD;
+
+ // Forward-declare the base class descriptor.
+ auto Type = ABI.getBaseClassDescriptorType();
+ auto BCD = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage,
+ /*Initializer=*/nullptr,
+ MangledName.c_str());
+
+ // Initialize the BaseClassDescriptor.
+ llvm::Constant *Fields[] = {
+ ABI.getImageRelativeConstant(
+ ABI.getAddrOfRTTIDescriptor(Context.getTypeDeclType(Class.RD))),
+ llvm::ConstantInt::get(CGM.IntTy, Class.NumBases),
+ llvm::ConstantInt::get(CGM.IntTy, Class.OffsetInVBase),
+ llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset),
+ llvm::ConstantInt::get(CGM.IntTy, OffsetInVBTable),
+ llvm::ConstantInt::get(CGM.IntTy, Class.Flags),
+ ABI.getImageRelativeConstant(
+ MSRTTIBuilder(ABI, Class.RD).getClassHierarchyDescriptor()),
+ };
+ BCD->setInitializer(llvm::ConstantStruct::get(Type, Fields));
+ return BCD;
+}
+
+llvm::GlobalVariable *
+MSRTTIBuilder::getCompleteObjectLocator(const VPtrInfo *Info) {
+ SmallString<256> MangledName;
+ {
+ llvm::raw_svector_ostream Out(MangledName);
+ ABI.getMangleContext().mangleCXXRTTICompleteObjectLocator(RD, Info->MangledPath, Out);
+ }
+
+ // Check to see if we've already computed this complete object locator.
+ if (auto COL = Module.getNamedGlobal(MangledName))
+ return COL;
+
+ // Compute the fields of the complete object locator.
+ int OffsetToTop = Info->FullOffsetInMDC.getQuantity();
+ int VFPtrOffset = 0;
+ // The offset includes the vtordisp if one exists.
+ if (const CXXRecordDecl *VBase = Info->getVBaseWithVPtr())
+ if (Context.getASTRecordLayout(RD)
+ .getVBaseOffsetsMap()
+ .find(VBase)
+ ->second.hasVtorDisp())
+ VFPtrOffset = Info->NonVirtualOffset.getQuantity() + 4;
+
+ // Forward-declare the complete object locator.
+ llvm::StructType *Type = ABI.getCompleteObjectLocatorType();
+ auto COL = new llvm::GlobalVariable(Module, Type, /*Constant=*/true, Linkage,
+ /*Initializer=*/nullptr, MangledName.c_str());
+
+ // Initialize the CompleteObjectLocator.
+ llvm::Constant *Fields[] = {
+ llvm::ConstantInt::get(CGM.IntTy, ABI.isImageRelative()),
+ llvm::ConstantInt::get(CGM.IntTy, OffsetToTop),
+ llvm::ConstantInt::get(CGM.IntTy, VFPtrOffset),
+ ABI.getImageRelativeConstant(
+ CGM.GetAddrOfRTTIDescriptor(Context.getTypeDeclType(RD))),
+ ABI.getImageRelativeConstant(getClassHierarchyDescriptor()),
+ ABI.getImageRelativeConstant(COL),
+ };
+ llvm::ArrayRef<llvm::Constant *> FieldsRef(Fields);
+ if (!ABI.isImageRelative())
+ FieldsRef = FieldsRef.drop_back();
+ COL->setInitializer(llvm::ConstantStruct::get(Type, FieldsRef));
+ return COL;
+}
+
+/// \brief Gets a TypeDescriptor. Returns a llvm::Constant * rather than a
+/// llvm::GlobalVariable * because different type descriptors have different
+/// types, and need to be abstracted. They are abstracting by casting the
+/// address to an Int8PtrTy.
+llvm::Constant *MicrosoftCXXABI::getAddrOfRTTIDescriptor(QualType Type) {
+ SmallString<256> MangledName, TypeInfoString;
+ {
+ llvm::raw_svector_ostream Out(MangledName);
+ getMangleContext().mangleCXXRTTI(Type, Out);
+ }
+
+ // Check to see if we've already declared this TypeDescriptor.
+ if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName))
+ return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
+
+ // Compute the fields for the TypeDescriptor.
+ {
+ llvm::raw_svector_ostream Out(TypeInfoString);
+ getMangleContext().mangleCXXRTTIName(Type, Out);
+ }
+
+ // Declare and initialize the TypeDescriptor.
+ llvm::Constant *Fields[] = {
+ getTypeInfoVTable(CGM), // VFPtr
+ llvm::ConstantPointerNull::get(CGM.Int8PtrTy), // Runtime data
+ llvm::ConstantDataArray::getString(CGM.getLLVMContext(), TypeInfoString)};
+ llvm::StructType *TypeDescriptorType =
+ getTypeDescriptorType(TypeInfoString);
+ return llvm::ConstantExpr::getBitCast(
+ new llvm::GlobalVariable(
+ CGM.getModule(), TypeDescriptorType, /*Constant=*/false,
+ getLinkageForRTTI(Type),
+ llvm::ConstantStruct::get(TypeDescriptorType, Fields),
+ MangledName.c_str()),
+ CGM.Int8PtrTy);
+}
+
+/// \brief Gets or a creates a Microsoft CompleteObjectLocator.
+llvm::GlobalVariable *
+MicrosoftCXXABI::getMSCompleteObjectLocator(const CXXRecordDecl *RD,
+ const VPtrInfo *Info) {
+ return MSRTTIBuilder(*this, RD).getCompleteObjectLocator(Info);
+}
diff --git a/lib/CodeGen/MicrosoftVBTables.cpp b/lib/CodeGen/MicrosoftVBTables.cpp
deleted file mode 100644
index dabf52c1ccc1..000000000000
--- a/lib/CodeGen/MicrosoftVBTables.cpp
+++ /dev/null
@@ -1,233 +0,0 @@
-//===--- MicrosoftVBTables.cpp - Virtual Base Table Emission --------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This class generates data about MSVC virtual base tables.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MicrosoftVBTables.h"
-#include "CodeGenModule.h"
-#include "CGCXXABI.h"
-
-namespace clang {
-namespace CodeGen {
-
-/// Holds intermediate data about a path to a vbptr inside a base subobject.
-struct VBTablePath {
- VBTablePath(const VBTableInfo &VBInfo)
- : VBInfo(VBInfo), NextBase(VBInfo.VBPtrSubobject.getBase()) { }
-
- /// All the data needed to build a vbtable, minus the GlobalVariable whose
- /// name we haven't computed yet.
- VBTableInfo VBInfo;
-
- /// Next base to use for disambiguation. Can be null if we've already
- /// disambiguated this path once.
- const CXXRecordDecl *NextBase;
-
- /// Path is not really a full path like a CXXBasePath. It holds the subset of
- /// records that need to be mangled into the vbtable symbol name in order to get
- /// a unique name.
- llvm::SmallVector<const CXXRecordDecl *, 1> Path;
-};
-
-VBTableBuilder::VBTableBuilder(CodeGenModule &CGM,
- const CXXRecordDecl *MostDerived)
- : CGM(CGM), MostDerived(MostDerived),
- DerivedLayout(CGM.getContext().getASTRecordLayout(MostDerived)) {}
-
-void VBTableBuilder::enumerateVBTables(VBTableVector &VBTables) {
- VBTablePathVector Paths;
- findUnambiguousPaths(MostDerived, BaseSubobject(MostDerived,
- CharUnits::Zero()), Paths);
- for (VBTablePathVector::iterator I = Paths.begin(), E = Paths.end();
- I != E; ++I) {
- VBTablePath *P = *I;
- P->VBInfo.GV = getAddrOfVBTable(P->VBInfo.ReusingBase, P->Path);
- VBTables.push_back(P->VBInfo);
- }
-}
-
-
-void VBTableBuilder::findUnambiguousPaths(const CXXRecordDecl *ReusingBase,
- BaseSubobject CurSubobject,
- VBTablePathVector &Paths) {
- size_t PathsStart = Paths.size();
- bool ReuseVBPtrFromBase = true;
- const CXXRecordDecl *CurBase = CurSubobject.getBase();
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(CurBase);
-
- // If this base has a vbptr, then we've found a path. These are not full
- // paths, so we don't use CXXBasePath.
- if (Layout.hasOwnVBPtr()) {
- ReuseVBPtrFromBase = false;
- VBTablePath *Info = new VBTablePath(
- VBTableInfo(ReusingBase, CurSubobject, /*GV=*/0));
- Paths.push_back(Info);
- }
-
- // Recurse onto any bases which themselves have virtual bases.
- for (CXXRecordDecl::base_class_const_iterator I = CurBase->bases_begin(),
- E = CurBase->bases_end(); I != E; ++I) {
- const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();
- if (!Base->getNumVBases())
- continue; // Bases without virtual bases have no vbptrs.
- CharUnits NextOffset;
- const CXXRecordDecl *NextReusingBase = Base;
- if (I->isVirtual()) {
- if (!VBasesSeen.insert(Base))
- continue; // Don't visit virtual bases twice.
- NextOffset = DerivedLayout.getVBaseClassOffset(Base);
- } else {
- NextOffset = (CurSubobject.getBaseOffset() +
- Layout.getBaseClassOffset(Base));
-
- // If CurBase didn't have a vbptr, then ReusingBase will reuse the vbptr
- // from the first non-virtual base with vbases for its vbptr.
- if (ReuseVBPtrFromBase) {
- NextReusingBase = ReusingBase;
- ReuseVBPtrFromBase = false;
- }
- }
-
- size_t NumPaths = Paths.size();
- findUnambiguousPaths(NextReusingBase, BaseSubobject(Base, NextOffset),
- Paths);
-
- // Tag paths through this base with the base itself. We might use it to
- // disambiguate.
- for (size_t I = NumPaths, E = Paths.size(); I != E; ++I)
- Paths[I]->NextBase = Base;
- }
-
- bool AmbiguousPaths = rebucketPaths(Paths, PathsStart);
- if (AmbiguousPaths)
- rebucketPaths(Paths, PathsStart, /*SecondPass=*/true);
-
-#ifndef NDEBUG
- // Check that the paths are in fact unique.
- for (size_t I = PathsStart + 1, E = Paths.size(); I != E; ++I) {
- assert(Paths[I]->Path != Paths[I - 1]->Path && "vbtable paths are not unique");
- }
-#endif
-}
-
-static bool pathCompare(VBTablePath *LHS, VBTablePath *RHS) {
- return LHS->Path < RHS->Path;
-}
-
-void VBTableBuilder::extendPath(VBTablePath *P, bool SecondPass) {
- assert(P->NextBase || SecondPass);
- if (P->NextBase) {
- P->Path.push_back(P->NextBase);
- P->NextBase = 0; // Prevent the path from being extended twice.
- }
-}
-
-bool VBTableBuilder::rebucketPaths(VBTablePathVector &Paths, size_t PathsStart,
- bool SecondPass) {
- // What we're essentially doing here is bucketing together ambiguous paths.
- // Any bucket with more than one path in it gets extended by NextBase, which
- // is usually the direct base of the inherited the vbptr. This code uses a
- // sorted vector to implement a multiset to form the buckets. Note that the
- // ordering is based on pointers, but it doesn't change our output order. The
- // current algorithm is designed to match MSVC 2012's names.
- // TODO: Implement MSVC 2010 or earlier names to avoid extra vbtable cruft.
- VBTablePathVector PathsSorted(&Paths[PathsStart], &Paths.back() + 1);
- std::sort(PathsSorted.begin(), PathsSorted.end(), pathCompare);
- bool AmbiguousPaths = false;
- for (size_t I = 0, E = PathsSorted.size(); I != E;) {
- // Scan forward to find the end of the bucket.
- size_t BucketStart = I;
- do {
- ++I;
- } while (I != E && PathsSorted[BucketStart]->Path == PathsSorted[I]->Path);
-
- // If this bucket has multiple paths, extend them all.
- if (I - BucketStart > 1) {
- AmbiguousPaths = true;
- for (size_t II = BucketStart; II != I; ++II)
- extendPath(PathsSorted[II], SecondPass);
- }
- }
- return AmbiguousPaths;
-}
-
-llvm::GlobalVariable *
-VBTableBuilder::getAddrOfVBTable(const CXXRecordDecl *ReusingBase,
- ArrayRef<const CXXRecordDecl *> BasePath) {
- // Caching at this layer is redundant with the caching in EnumerateVBTables().
-
- SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- MicrosoftMangleContext &Mangler =
- cast<MicrosoftMangleContext>(CGM.getCXXABI().getMangleContext());
- Mangler.mangleCXXVBTable(MostDerived, BasePath, Out);
- Out.flush();
- StringRef Name = OutName.str();
-
- llvm::ArrayType *VBTableType =
- llvm::ArrayType::get(CGM.IntTy, 1 + ReusingBase->getNumVBases());
-
- assert(!CGM.getModule().getNamedGlobal(Name) &&
- "vbtable with this name already exists: mangling bug?");
- llvm::GlobalVariable *VBTable =
- CGM.CreateOrReplaceCXXRuntimeVariable(Name, VBTableType,
- llvm::GlobalValue::ExternalLinkage);
- VBTable->setUnnamedAddr(true);
- return VBTable;
-}
-
-void VBTableInfo::EmitVBTableDefinition(
- CodeGenModule &CGM, const CXXRecordDecl *RD,
- llvm::GlobalVariable::LinkageTypes Linkage) const {
- assert(RD->getNumVBases() && ReusingBase->getNumVBases() &&
- "should only emit vbtables for classes with vbtables");
-
- const ASTRecordLayout &BaseLayout =
- CGM.getContext().getASTRecordLayout(VBPtrSubobject.getBase());
- const ASTRecordLayout &DerivedLayout =
- CGM.getContext().getASTRecordLayout(RD);
-
- SmallVector<llvm::Constant *, 4> Offsets(1 + ReusingBase->getNumVBases(), 0);
-
- // The offset from ReusingBase's vbptr to itself always leads.
- CharUnits VBPtrOffset = BaseLayout.getVBPtrOffset();
- Offsets[0] = llvm::ConstantInt::get(CGM.IntTy, -VBPtrOffset.getQuantity());
-
- MicrosoftVTableContext &Context = CGM.getMicrosoftVTableContext();
- for (CXXRecordDecl::base_class_const_iterator I = ReusingBase->vbases_begin(),
- E = ReusingBase->vbases_end(); I != E; ++I) {
- const CXXRecordDecl *VBase = I->getType()->getAsCXXRecordDecl();
- CharUnits Offset = DerivedLayout.getVBaseClassOffset(VBase);
- assert(!Offset.isNegative());
- // Make it relative to the subobject vbptr.
- Offset -= VBPtrSubobject.getBaseOffset() + VBPtrOffset;
- unsigned VBIndex = Context.getVBTableIndex(ReusingBase, VBase);
- assert(Offsets[VBIndex] == 0 && "The same vbindex seen twice?");
- Offsets[VBIndex] = llvm::ConstantInt::get(CGM.IntTy, Offset.getQuantity());
- }
-
- assert(Offsets.size() ==
- cast<llvm::ArrayType>(cast<llvm::PointerType>(GV->getType())
- ->getElementType())->getNumElements());
- llvm::ArrayType *VBTableType =
- llvm::ArrayType::get(CGM.IntTy, Offsets.size());
- llvm::Constant *Init = llvm::ConstantArray::get(VBTableType, Offsets);
- GV->setInitializer(Init);
-
- // Set the correct linkage.
- GV->setLinkage(Linkage);
-
- // Set the right visibility.
- CGM.setTypeVisibility(GV, RD, CodeGenModule::TVK_ForVTable);
-}
-
-} // namespace CodeGen
-} // namespace clang
diff --git a/lib/CodeGen/MicrosoftVBTables.h b/lib/CodeGen/MicrosoftVBTables.h
deleted file mode 100644
index 4ad8e07582ef..000000000000
--- a/lib/CodeGen/MicrosoftVBTables.h
+++ /dev/null
@@ -1,129 +0,0 @@
-//===--- MicrosoftVBTables.h - Virtual Base Table Emission ----------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This class generates data about MSVC virtual base tables.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/BaseSubobject.h"
-#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/IR/GlobalVariable.h"
-#include <vector>
-
-namespace clang {
-
-class ASTRecordLayout;
-
-namespace CodeGen {
-
-class CodeGenModule;
-
-struct VBTableInfo {
- VBTableInfo(const CXXRecordDecl *ReusingBase, BaseSubobject VBPtrSubobject,
- llvm::GlobalVariable *GV)
- : ReusingBase(ReusingBase), VBPtrSubobject(VBPtrSubobject), GV(GV) { }
-
- /// The vbtable will hold all of the virtual bases of ReusingBase. This may
- /// or may not be the same class as VBPtrSubobject.Base. A derived class will
- /// reuse the vbptr of the first non-virtual base subobject that has one.
- const CXXRecordDecl *ReusingBase;
-
- /// The vbptr is stored inside this subobject.
- BaseSubobject VBPtrSubobject;
-
- /// The GlobalVariable for this vbtable.
- llvm::GlobalVariable *GV;
-
- /// \brief Emits a definition for GV by setting it's initializer.
- void EmitVBTableDefinition(CodeGenModule &CGM, const CXXRecordDecl *RD,
- llvm::GlobalVariable::LinkageTypes Linkage) const;
-};
-
-// These are embedded in a DenseMap and the elements are large, so we don't want
-// SmallVector.
-typedef std::vector<VBTableInfo> VBTableVector;
-
-struct VBTablePath;
-
-typedef llvm::SmallVector<VBTablePath *, 6> VBTablePathVector;
-
-/// Produces MSVC-compatible vbtable data. The symbols produced by this builder
-/// match those produced by MSVC 2012, which is different from MSVC 2010.
-///
-/// Unlike Itanium, which uses only one vtable per class, MSVC uses a different
-/// symbol for every "address point" installed in base subobjects. As a result,
-/// we have to compute unique symbols for every table. Since there can be
-/// multiple non-virtual base subobjects of the same class, combining the most
-/// derived class with the base containing the vtable is insufficient. The most
-/// trivial algorithm would be to mangle in the entire path from base to most
-/// derived, but that would be too easy and would create unnecessarily large
-/// symbols. ;)
-///
-/// MSVC 2012 appears to minimize the vbtable names using the following
-/// algorithm. First, walk the class hierarchy in the usual order, depth first,
-/// left to right, to find all of the subobjects which contain a vbptr field.
-/// Visiting each class node yields a list of inheritance paths to vbptrs. Each
-/// record with a vbptr creates an initially empty path.
-///
-/// To combine paths from child nodes, the paths are compared to check for
-/// ambiguity. Paths are "ambiguous" if multiple paths have the same set of
-/// components in the same order. Each group of ambiguous paths is extended by
-/// appending the class of the base from which it came. If the current class
-/// node produced an ambiguous path, its path is extended with the current class.
-/// After extending paths, MSVC again checks for ambiguity, and extends any
-/// ambiguous path which wasn't already extended. Because each node yields an
-/// unambiguous set of paths, MSVC doesn't need to extend any path more than once
-/// to produce an unambiguous set of paths.
-///
-/// The VBTableBuilder class attempts to implement this algorithm by repeatedly
-/// bucketing paths together by sorting them.
-///
-/// TODO: Presumably vftables use the same algorithm.
-///
-/// TODO: Implement the MSVC 2010 name mangling scheme to avoid emitting
-/// duplicate vbtables with different symbols.
-class VBTableBuilder {
-public:
- VBTableBuilder(CodeGenModule &CGM, const CXXRecordDecl *MostDerived);
-
- void enumerateVBTables(VBTableVector &VBTables);
-
-private:
- bool hasVBPtr(const CXXRecordDecl *RD);
-
- llvm::GlobalVariable *getAddrOfVBTable(const CXXRecordDecl *ReusingBase,
- ArrayRef<const CXXRecordDecl *> BasePath);
-
- /// Enumerates paths to bases with vbptrs. The paths elements are compressed
- /// to contain only the classes necessary to form an unambiguous path.
- void findUnambiguousPaths(const CXXRecordDecl *ReusingBase,
- BaseSubobject CurSubobject,
- VBTablePathVector &Paths);
-
- void extendPath(VBTablePath *Info, bool SecondPass);
-
- bool rebucketPaths(VBTablePathVector &Paths, size_t PathsStart,
- bool SecondPass = false);
-
- CodeGenModule &CGM;
-
- const CXXRecordDecl *MostDerived;
-
- /// Caches the layout of the most derived class.
- const ASTRecordLayout &DerivedLayout;
-
- /// Set of vbases to avoid re-visiting the same vbases.
- llvm::SmallPtrSet<const CXXRecordDecl*, 4> VBasesSeen;
-};
-
-} // namespace CodeGen
-
-} // namespace clang
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index bc7acbc39cab..c5d18d3286a7 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -12,30 +12,31 @@
//===----------------------------------------------------------------------===//
#include "clang/CodeGen/ModuleBuilder.h"
-#include "CodeGenModule.h"
#include "CGDebugInfo.h"
+#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
+#include <memory>
using namespace clang;
namespace {
class CodeGeneratorImpl : public CodeGenerator {
DiagnosticsEngine &Diags;
- OwningPtr<const llvm::DataLayout> TD;
+ std::unique_ptr<const llvm::DataLayout> TD;
ASTContext *Ctx;
const CodeGenOptions CodeGenOpts; // Intentionally copied in.
protected:
- OwningPtr<llvm::Module> M;
- OwningPtr<CodeGen::CodeGenModule> Builder;
+ std::unique_ptr<llvm::Module> M;
+ std::unique_ptr<CodeGen::CodeGenModule> Builder;
+
public:
CodeGeneratorImpl(DiagnosticsEngine &diags, const std::string& ModuleName,
const CodeGenOptions &CGO, llvm::LLVMContext& C)
@@ -44,15 +45,28 @@ namespace {
virtual ~CodeGeneratorImpl() {}
- virtual llvm::Module* GetModule() {
+ llvm::Module* GetModule() override {
return M.get();
}
- virtual llvm::Module* ReleaseModule() {
- return M.take();
+ const Decl *GetDeclForMangledName(StringRef MangledName) override {
+ GlobalDecl Result;
+ if (!Builder->lookupRepresentativeDecl(MangledName, Result))
+ return nullptr;
+ const Decl *D = Result.getCanonicalDecl().getDecl();
+ if (auto FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->hasBody(FD))
+ return FD;
+ } else if (auto TD = dyn_cast<TagDecl>(D)) {
+ if (auto Def = TD->getDefinition())
+ return Def;
+ }
+ return D;
}
- virtual void Initialize(ASTContext &Context) {
+ llvm::Module *ReleaseModule() override { return M.release(); }
+
+ void Initialize(ASTContext &Context) override {
Ctx = &Context;
M->setTargetTriple(Ctx->getTargetInfo().getTriple().getTriple());
@@ -65,48 +79,71 @@ namespace {
HandleDependentLibrary(CodeGenOpts.DependentLibraries[i]);
}
- virtual void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
+ void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override {
if (Diags.hasErrorOccurred())
return;
Builder->HandleCXXStaticMemberVarInstantiation(VD);
}
- virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
+ bool HandleTopLevelDecl(DeclGroupRef DG) override {
if (Diags.hasErrorOccurred())
return true;
// Make sure to emit all elements of a Decl.
for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
Builder->EmitTopLevelDecl(*I);
+
+ // Emit any deferred inline method definitions.
+ for (CXXMethodDecl *MD : DeferredInlineMethodDefinitions)
+ Builder->EmitTopLevelDecl(MD);
+ DeferredInlineMethodDefinitions.clear();
+
return true;
}
+ void HandleInlineMethodDefinition(CXXMethodDecl *D) override {
+ if (Diags.hasErrorOccurred())
+ return;
+
+ assert(D->doesThisDeclarationHaveABody());
+
+ // We may want to emit this definition. However, that decision might be
+ // based on computing the linkage, and we have to defer that in case we
+ // are inside of something that will change the method's final linkage,
+ // e.g.
+ // typedef struct {
+ // void bar();
+ // void foo() { bar(); }
+ // } A;
+ DeferredInlineMethodDefinitions.push_back(D);
+ }
+
/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
/// to (e.g. struct, union, enum, class) is completed. This allows the
/// client hack on the type, which can occur at any point in the file
/// (because these can be defined in declspecs).
- virtual void HandleTagDeclDefinition(TagDecl *D) {
+ void HandleTagDeclDefinition(TagDecl *D) override {
if (Diags.hasErrorOccurred())
return;
Builder->UpdateCompletedType(D);
-
- // In C++, we may have member functions that need to be emitted at this
- // point.
- if (Ctx->getLangOpts().CPlusPlus && !D->isDependentContext()) {
- for (DeclContext::decl_iterator M = D->decls_begin(),
- MEnd = D->decls_end();
- M != MEnd; ++M)
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*M))
- if (Method->doesThisDeclarationHaveABody() &&
- (Method->hasAttr<UsedAttr>() ||
- Method->hasAttr<ConstructorAttr>()))
- Builder->EmitTopLevelDecl(Method);
+
+ // For MSVC compatibility, treat declarations of static data members with
+ // inline initializers as definitions.
+ if (Ctx->getLangOpts().MSVCCompat) {
+ for (Decl *Member : D->decls()) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(Member)) {
+ if (Ctx->isMSStaticDataMemberInlineDefinition(VD) &&
+ Ctx->DeclMustBeEmitted(VD)) {
+ Builder->EmitGlobal(VD);
+ }
+ }
+ }
}
}
- virtual void HandleTagDeclRequiredDefinition(const TagDecl *D) LLVM_OVERRIDE {
+ void HandleTagDeclRequiredDefinition(const TagDecl *D) override {
if (Diags.hasErrorOccurred())
return;
@@ -115,8 +152,10 @@ namespace {
DI->completeRequiredType(RD);
}
- virtual void HandleTranslationUnit(ASTContext &Ctx) {
+ void HandleTranslationUnit(ASTContext &Ctx) override {
if (Diags.hasErrorOccurred()) {
+ if (Builder)
+ Builder->clear();
M.reset();
return;
}
@@ -125,32 +164,35 @@ namespace {
Builder->Release();
}
- virtual void CompleteTentativeDefinition(VarDecl *D) {
+ void CompleteTentativeDefinition(VarDecl *D) override {
if (Diags.hasErrorOccurred())
return;
Builder->EmitTentativeDefinition(D);
}
- virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {
+ void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) override {
if (Diags.hasErrorOccurred())
return;
Builder->EmitVTable(RD, DefinitionRequired);
}
- virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {
+ void HandleLinkerOptionPragma(llvm::StringRef Opts) override {
Builder->AppendLinkerOptions(Opts);
}
- virtual void HandleDetectMismatch(llvm::StringRef Name,
- llvm::StringRef Value) {
+ void HandleDetectMismatch(llvm::StringRef Name,
+ llvm::StringRef Value) override {
Builder->AddDetectMismatch(Name, Value);
}
- virtual void HandleDependentLibrary(llvm::StringRef Lib) {
+ void HandleDependentLibrary(llvm::StringRef Lib) override {
Builder->AddDependentLib(Lib);
}
+
+ private:
+ std::vector<CXXMethodDecl *> DeferredInlineMethodDefinitions;
};
}
diff --git a/lib/CodeGen/SanitizerBlacklist.cpp b/lib/CodeGen/SanitizerBlacklist.cpp
new file mode 100644
index 000000000000..9f1ddc8e7d7b
--- /dev/null
+++ b/lib/CodeGen/SanitizerBlacklist.cpp
@@ -0,0 +1,52 @@
+//===--- SanitizerBlacklist.cpp - Blacklist for sanitizers ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// User-provided blacklist used to disable/alter instrumentation done in
+// sanitizers.
+//
+//===----------------------------------------------------------------------===//
+#include "SanitizerBlacklist.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/Module.h"
+
+using namespace clang;
+using namespace CodeGen;
+
+static StringRef GetGlobalTypeString(const llvm::GlobalValue &G) {
+ // Types of GlobalVariables are always pointer types.
+ llvm::Type *GType = G.getType()->getElementType();
+ // For now we support blacklisting struct types only.
+ if (llvm::StructType *SGType = dyn_cast<llvm::StructType>(GType)) {
+ if (!SGType->isLiteral())
+ return SGType->getName();
+ }
+ return "<unknown type>";
+}
+
+bool SanitizerBlacklist::isIn(const llvm::Module &M,
+ const StringRef Category) const {
+ return SCL->inSection("src", M.getModuleIdentifier(), Category);
+}
+
+bool SanitizerBlacklist::isIn(const llvm::Function &F) const {
+ return isIn(*F.getParent()) ||
+ SCL->inSection("fun", F.getName(), "");
+}
+
+bool SanitizerBlacklist::isIn(const llvm::GlobalVariable &G,
+ const StringRef Category) const {
+ return isIn(*G.getParent(), Category) ||
+ SCL->inSection("global", G.getName(), Category) ||
+ SCL->inSection("type", GetGlobalTypeString(G), Category);
+}
+
+bool SanitizerBlacklist::isBlacklistedType(StringRef MangledTypeName) const {
+ return SCL->inSection("type", MangledTypeName);
+}
diff --git a/lib/CodeGen/SanitizerBlacklist.h b/lib/CodeGen/SanitizerBlacklist.h
new file mode 100644
index 000000000000..659441dfe346
--- /dev/null
+++ b/lib/CodeGen/SanitizerBlacklist.h
@@ -0,0 +1,46 @@
+//===--- SanitizerBlacklist.h - Blacklist for sanitizers --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// User-provided blacklist used to disable/alter instrumentation done in
+// sanitizers.
+//
+//===----------------------------------------------------------------------===//
+#ifndef CLANG_CODEGEN_SANITIZERBLACKLIST_H
+#define CLANG_CODEGEN_SANITIZERBLACKLIST_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/SpecialCaseList.h"
+#include <memory>
+
+namespace llvm {
+class GlobalVariable;
+class Function;
+class Module;
+}
+
+namespace clang {
+namespace CodeGen {
+
+class SanitizerBlacklist {
+ std::unique_ptr<llvm::SpecialCaseList> SCL;
+
+public:
+ SanitizerBlacklist(llvm::SpecialCaseList *SCL) : SCL(SCL) {}
+ bool isIn(const llvm::Module &M,
+ const StringRef Category = StringRef()) const;
+ bool isIn(const llvm::Function &F) const;
+ bool isIn(const llvm::GlobalVariable &G,
+ const StringRef Category = StringRef()) const;
+ bool isBlacklistedType(StringRef MangledTypeName) const;
+};
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 76acf871da26..5da22c3e6cbb 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -23,6 +23,9 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/raw_ostream.h"
+
+#include <algorithm> // std::sort
+
using namespace clang;
using namespace CodeGen;
@@ -45,22 +48,6 @@ static bool isAggregateTypeForABI(QualType T) {
ABIInfo::~ABIInfo() {}
-static bool isRecordReturnIndirect(const RecordType *RT,
- CGCXXABI &CXXABI) {
- const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
- if (!RD)
- return false;
- return CXXABI.isReturnTypeIndirect(RD);
-}
-
-
-static bool isRecordReturnIndirect(QualType T, CGCXXABI &CXXABI) {
- const RecordType *RT = T->getAs<RecordType>();
- if (!RT)
- return false;
- return isRecordReturnIndirect(RT, CXXABI);
-}
-
static CGCXXABI::RecordArgABI getRecordArgABI(const RecordType *RT,
CGCXXABI &CXXABI) {
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
@@ -114,6 +101,9 @@ void ABIArgInfo::dump() const {
case Ignore:
OS << "Ignore";
break;
+ case InAlloca:
+ OS << "InAlloca Offset=" << getInAllocaFieldIndex();
+ break;
case Indirect:
OS << "Indirect Align=" << getIndirectAlign()
<< " ByVal=" << getIndirectByVal()
@@ -206,14 +196,12 @@ static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) {
// If this is a C++ record, check the bases first.
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
- for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(),
- e = CXXRD->bases_end(); i != e; ++i)
- if (!isEmptyRecord(Context, i->getType(), true))
+ for (const auto &I : CXXRD->bases())
+ if (!isEmptyRecord(Context, I.getType(), true))
return false;
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i)
- if (!isEmptyField(Context, *i, AllowArrays))
+ for (const auto *I : RD->fields())
+ if (!isEmptyField(Context, I, AllowArrays))
return false;
return true;
}
@@ -229,38 +217,35 @@ static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) {
static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
const RecordType *RT = T->getAsStructureType();
if (!RT)
- return 0;
+ return nullptr;
const RecordDecl *RD = RT->getDecl();
if (RD->hasFlexibleArrayMember())
- return 0;
+ return nullptr;
- const Type *Found = 0;
+ const Type *Found = nullptr;
// If this is a C++ record, check the bases first.
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
- for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(),
- e = CXXRD->bases_end(); i != e; ++i) {
+ for (const auto &I : CXXRD->bases()) {
// Ignore empty records.
- if (isEmptyRecord(Context, i->getType(), true))
+ if (isEmptyRecord(Context, I.getType(), true))
continue;
// If we already found an element then this isn't a single-element struct.
if (Found)
- return 0;
+ return nullptr;
// If this is non-empty and not a single element struct, the composite
// cannot be a single element struct.
- Found = isSingleElementStruct(i->getType(), Context);
+ Found = isSingleElementStruct(I.getType(), Context);
if (!Found)
- return 0;
+ return nullptr;
}
}
// Check for single element.
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
- const FieldDecl *FD = *i;
+ for (const auto *FD : RD->fields()) {
QualType FT = FD->getType();
// Ignore empty fields.
@@ -270,7 +255,7 @@ static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
// If we already found an element then this isn't a single-element
// struct.
if (Found)
- return 0;
+ return nullptr;
// Treat single element arrays as the element.
while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {
@@ -284,14 +269,14 @@ static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
} else {
Found = isSingleElementStruct(FT, Context);
if (!Found)
- return 0;
+ return nullptr;
}
}
// We don't consider a struct a single-element struct if it has
// padding beyond the element type.
if (Found && Context.getTypeSize(Found) != Context.getTypeSize(T))
- return 0;
+ return nullptr;
return Found;
}
@@ -336,10 +321,7 @@ static bool canExpandIndirectArgument(QualType Ty, ASTContext &Context) {
uint64_t Size = 0;
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
- const FieldDecl *FD = *i;
-
+ for (const auto *FD : RD->fields()) {
if (!is32Or64BitBasicType(FD->getType(), Context))
return false;
@@ -371,15 +353,15 @@ public:
ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType RetTy) const;
- virtual void computeInfo(CGFunctionInfo &FI) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it)
- it->info = classifyArgumentType(it->type);
+ void computeInfo(CGFunctionInfo &FI) const override {
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ for (auto &I : FI.arguments())
+ I.info = classifyArgumentType(I.type);
}
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const override;
};
class DefaultTargetCodeGenInfo : public TargetCodeGenInfo {
@@ -390,18 +372,12 @@ public:
llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
- return 0;
+ return nullptr;
}
ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const {
- if (isAggregateTypeForABI(Ty)) {
- // Records with non trivial destructors/constructors should not be passed
- // by value.
- if (isRecordReturnIndirect(Ty, getCXXABI()))
- return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
-
+ if (isAggregateTypeForABI(Ty))
return ABIArgInfo::getIndirect(0);
- }
// Treat an enum type as its underlying type.
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
@@ -440,9 +416,9 @@ class PNaClABIInfo : public ABIInfo {
ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType RetTy) const;
- virtual void computeInfo(CGFunctionInfo &FI) const;
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
+ void computeInfo(CGFunctionInfo &FI) const override;
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const override;
};
class PNaClTargetCodeGenInfo : public TargetCodeGenInfo {
@@ -452,16 +428,16 @@ class PNaClTargetCodeGenInfo : public TargetCodeGenInfo {
};
void PNaClABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ if (!getCXXABI().classifyReturnType(FI))
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it)
- it->info = classifyArgumentType(it->type);
- }
+ for (auto &I : FI.arguments())
+ I.info = classifyArgumentType(I.type);
+}
llvm::Value *PNaClABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
- return 0;
+ return nullptr;
}
/// \brief Classify argument of given type \p Ty.
@@ -512,7 +488,7 @@ static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
if ((Constraint == "y" || Constraint == "&y") && Ty->isVectorTy()) {
if (cast<llvm::VectorType>(Ty)->getBitWidth() != 64) {
// Invalid MMX constraint
- return 0;
+ return nullptr;
}
return llvm::Type::getX86_MMXTy(CGF.getLLVMContext());
@@ -526,6 +502,16 @@ static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
// X86-32 ABI Implementation
//===----------------------------------------------------------------------===//
+/// \brief Similar to llvm::CCState, but for Clang.
+struct CCState {
+ CCState(unsigned CC) : CC(CC), FreeRegs(0) {}
+
+ unsigned CC;
+ unsigned FreeRegs;
+ unsigned StackOffset;
+ bool UseInAlloca;
+};
+
/// X86_32ABIInfo - The X86-32 ABI information.
class X86_32ABIInfo : public ABIInfo {
enum Class {
@@ -544,30 +530,35 @@ class X86_32ABIInfo : public ABIInfo {
return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
}
- static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context,
- unsigned callingConvention);
+ bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context) const;
/// getIndirectResult - Give a source type \arg Ty, return a suitable result
/// such that the argument will be passed in memory.
- ABIArgInfo getIndirectResult(QualType Ty, bool ByVal,
- unsigned &FreeRegs) const;
+ ABIArgInfo getIndirectResult(QualType Ty, bool ByVal, CCState &State) const;
+
+ ABIArgInfo getIndirectReturnResult(CCState &State) const;
/// \brief Return the alignment to use for the given type on the stack.
unsigned getTypeStackAlignInBytes(QualType Ty, unsigned Align) const;
Class classify(QualType Ty) const;
- ABIArgInfo classifyReturnType(QualType RetTy,
- unsigned callingConvention) const;
- ABIArgInfo classifyArgumentType(QualType RetTy, unsigned &FreeRegs,
- bool IsFastCall) const;
- bool shouldUseInReg(QualType Ty, unsigned &FreeRegs,
- bool IsFastCall, bool &NeedsPadding) const;
+ ABIArgInfo classifyReturnType(QualType RetTy, CCState &State) const;
+ ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const;
+ bool shouldUseInReg(QualType Ty, CCState &State, bool &NeedsPadding) const;
+
+ /// \brief Rewrite the function info so that all memory arguments use
+ /// inalloca.
+ void rewriteWithInAlloca(CGFunctionInfo &FI) const;
+
+ void addFieldToArgStruct(SmallVector<llvm::Type *, 6> &FrameFields,
+ unsigned &StackOffset, ABIArgInfo &Info,
+ QualType Type) const;
public:
- virtual void computeInfo(CGFunctionInfo &FI) const;
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
+ void computeInfo(CGFunctionInfo &FI) const override;
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const override;
X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p, bool w,
unsigned r)
@@ -585,24 +576,25 @@ public:
const llvm::Triple &Triple, const CodeGenOptions &Opts);
void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const;
+ CodeGen::CodeGenModule &CGM) const override;
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const {
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override {
// Darwin uses different dwarf register numbers for EH.
if (CGM.getTarget().getTriple().isOSDarwin()) return 5;
return 4;
}
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const;
+ llvm::Value *Address) const override;
llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
StringRef Constraint,
- llvm::Type* Ty) const {
+ llvm::Type* Ty) const override {
return X86AdjustInlineAsmType(CGF, Constraint, Ty);
}
- llvm::Constant *getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const {
+ llvm::Constant *
+ getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const override {
unsigned Sig = (0xeb << 0) | // jmp rel8
(0x06 << 8) | // .+0x08
('F' << 16) |
@@ -617,8 +609,7 @@ public:
/// shouldReturnTypeInRegister - Determine if the given type should be
/// passed in a register (for the Darwin ABI).
bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
- ASTContext &Context,
- unsigned callingConvention) {
+ ASTContext &Context) const {
uint64_t Size = Context.getTypeSize(Ty);
// Type must be register sized.
@@ -643,8 +634,7 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
// Arrays are treated like records.
if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty))
- return shouldReturnTypeInRegister(AT->getElementType(), Context,
- callingConvention);
+ return shouldReturnTypeInRegister(AT->getElementType(), Context);
// Otherwise, it must be a record type.
const RecordType *RT = Ty->getAs<RecordType>();
@@ -652,33 +642,31 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
// FIXME: Traverse bases here too.
- // For thiscall conventions, structures will never be returned in
- // a register. This is for compatibility with the MSVC ABI
- if (callingConvention == llvm::CallingConv::X86_ThisCall &&
- RT->isStructureType()) {
- return false;
- }
-
// Structure types are passed in register if all fields would be
// passed in a register.
- for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(),
- e = RT->getDecl()->field_end(); i != e; ++i) {
- const FieldDecl *FD = *i;
-
+ for (const auto *FD : RT->getDecl()->fields()) {
// Empty fields are ignored.
if (isEmptyField(Context, FD, true))
continue;
// Check fields recursively.
- if (!shouldReturnTypeInRegister(FD->getType(), Context,
- callingConvention))
+ if (!shouldReturnTypeInRegister(FD->getType(), Context))
return false;
}
return true;
}
-ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
- unsigned callingConvention) const {
+ABIArgInfo X86_32ABIInfo::getIndirectReturnResult(CCState &State) const {
+ // If the return value is indirect, then the hidden argument is consuming one
+ // integer register.
+ if (State.FreeRegs) {
+ --State.FreeRegs;
+ return ABIArgInfo::getIndirectInReg(/*Align=*/0, /*ByVal=*/false);
+ }
+ return ABIArgInfo::getIndirect(/*Align=*/0, /*ByVal=*/false);
+}
+
+ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, CCState &State) const {
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
@@ -701,7 +689,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
Size));
- return ABIArgInfo::getIndirect(0);
+ return getIndirectReturnResult(State);
}
return ABIArgInfo::getDirect();
@@ -709,22 +697,18 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
if (isAggregateTypeForABI(RetTy)) {
if (const RecordType *RT = RetTy->getAs<RecordType>()) {
- if (isRecordReturnIndirect(RT, getCXXABI()))
- return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
-
// Structures with flexible arrays are always indirect.
if (RT->getDecl()->hasFlexibleArrayMember())
- return ABIArgInfo::getIndirect(0);
+ return getIndirectReturnResult(State);
}
// If specified, structs and unions are always indirect.
if (!IsSmallStructInRegABI && !RetTy->isAnyComplexType())
- return ABIArgInfo::getIndirect(0);
+ return getIndirectReturnResult(State);
// Small structures which are register sized are generally returned
// in a register.
- if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, getContext(),
- callingConvention)) {
+ if (shouldReturnTypeInRegister(RetTy, getContext())) {
uint64_t Size = getContext().getTypeSize(RetTy);
// As a special-case, if the struct is a "single-element" struct, and
@@ -742,7 +726,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),Size));
}
- return ABIArgInfo::getIndirect(0);
+ return getIndirectReturnResult(State);
}
// Treat an enum type as its underlying type.
@@ -765,13 +749,11 @@ static bool isRecordWithSSEVectorType(ASTContext &Context, QualType Ty) {
// If this is a C++ record, check the bases first.
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
- for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(),
- e = CXXRD->bases_end(); i != e; ++i)
- if (!isRecordWithSSEVectorType(Context, i->getType()))
+ for (const auto &I : CXXRD->bases())
+ if (!isRecordWithSSEVectorType(Context, I.getType()))
return false;
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
+ for (const auto *i : RD->fields()) {
QualType FT = i->getType();
if (isSSEVectorType(Context, FT))
@@ -806,10 +788,10 @@ unsigned X86_32ABIInfo::getTypeStackAlignInBytes(QualType Ty,
}
ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal,
- unsigned &FreeRegs) const {
+ CCState &State) const {
if (!ByVal) {
- if (FreeRegs) {
- --FreeRegs; // Non byval indirects just use one pointer.
+ if (State.FreeRegs) {
+ --State.FreeRegs; // Non-byval indirects just use one pointer.
return ABIArgInfo::getIndirectInReg(0, false);
}
return ABIArgInfo::getIndirect(0, false);
@@ -819,15 +801,12 @@ ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal,
unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8;
unsigned StackAlign = getTypeStackAlignInBytes(Ty, TypeAlign);
if (StackAlign == 0)
- return ABIArgInfo::getIndirect(4);
+ return ABIArgInfo::getIndirect(4, /*ByVal=*/true);
// If the stack alignment is less than the type alignment, realign the
// argument.
- if (StackAlign < TypeAlign)
- return ABIArgInfo::getIndirect(StackAlign, /*ByVal=*/true,
- /*Realign=*/true);
-
- return ABIArgInfo::getIndirect(StackAlign);
+ bool Realign = TypeAlign > StackAlign;
+ return ABIArgInfo::getIndirect(StackAlign, /*ByVal=*/true, Realign);
}
X86_32ABIInfo::Class X86_32ABIInfo::classify(QualType Ty) const {
@@ -843,8 +822,8 @@ X86_32ABIInfo::Class X86_32ABIInfo::classify(QualType Ty) const {
return Integer;
}
-bool X86_32ABIInfo::shouldUseInReg(QualType Ty, unsigned &FreeRegs,
- bool IsFastCall, bool &NeedsPadding) const {
+bool X86_32ABIInfo::shouldUseInReg(QualType Ty, CCState &State,
+ bool &NeedsPadding) const {
NeedsPadding = false;
Class C = classify(Ty);
if (C == Float)
@@ -856,14 +835,14 @@ bool X86_32ABIInfo::shouldUseInReg(QualType Ty, unsigned &FreeRegs,
if (SizeInRegs == 0)
return false;
- if (SizeInRegs > FreeRegs) {
- FreeRegs = 0;
+ if (SizeInRegs > State.FreeRegs) {
+ State.FreeRegs = 0;
return false;
}
- FreeRegs -= SizeInRegs;
+ State.FreeRegs -= SizeInRegs;
- if (IsFastCall) {
+ if (State.CC == llvm::CallingConv::X86_FastCall) {
if (Size > 32)
return false;
@@ -876,7 +855,7 @@ bool X86_32ABIInfo::shouldUseInReg(QualType Ty, unsigned &FreeRegs,
if (Ty->isReferenceType())
return true;
- if (FreeRegs)
+ if (State.FreeRegs)
NeedsPadding = true;
return false;
@@ -886,20 +865,26 @@ bool X86_32ABIInfo::shouldUseInReg(QualType Ty, unsigned &FreeRegs,
}
ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
- unsigned &FreeRegs,
- bool IsFastCall) const {
+ CCState &State) const {
// FIXME: Set alignment on indirect arguments.
if (isAggregateTypeForABI(Ty)) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
- if (IsWin32StructABI)
- return getIndirectResult(Ty, true, FreeRegs);
+ // Check with the C++ ABI first.
+ CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI());
+ if (RAA == CGCXXABI::RAA_Indirect) {
+ return getIndirectResult(Ty, false, State);
+ } else if (RAA == CGCXXABI::RAA_DirectInMemory) {
+ // The field index doesn't matter, we'll fix it up later.
+ return ABIArgInfo::getInAlloca(/*FieldIndex=*/0);
+ }
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()))
- return getIndirectResult(Ty, RAA == CGCXXABI::RAA_DirectInMemory, FreeRegs);
+ // Structs are always byval on win32, regardless of what they contain.
+ if (IsWin32StructABI)
+ return getIndirectResult(Ty, true, State);
// Structures with flexible arrays are always indirect.
if (RT->getDecl()->hasFlexibleArrayMember())
- return getIndirectResult(Ty, true, FreeRegs);
+ return getIndirectResult(Ty, true, State);
}
// Ignore empty structs/unions.
@@ -909,13 +894,13 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
llvm::LLVMContext &LLVMContext = getVMContext();
llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext);
bool NeedsPadding;
- if (shouldUseInReg(Ty, FreeRegs, IsFastCall, NeedsPadding)) {
+ if (shouldUseInReg(Ty, State, NeedsPadding)) {
unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32;
SmallVector<llvm::Type*, 3> Elements(SizeInRegs, Int32);
llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
return ABIArgInfo::getDirectInReg(Result);
}
- llvm::IntegerType *PaddingType = NeedsPadding ? Int32 : 0;
+ llvm::IntegerType *PaddingType = NeedsPadding ? Int32 : nullptr;
// Expand small (<= 128-bit) record types when we know that the stack layout
// of those arguments will match the struct. This is important because the
@@ -923,9 +908,10 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
// optimizations.
if (getContext().getTypeSize(Ty) <= 4*32 &&
canExpandIndirectArgument(Ty, getContext()))
- return ABIArgInfo::getExpandWithPadding(IsFastCall, PaddingType);
+ return ABIArgInfo::getExpandWithPadding(
+ State.CC == llvm::CallingConv::X86_FastCall, PaddingType);
- return getIndirectResult(Ty, true, FreeRegs);
+ return getIndirectResult(Ty, true, State);
}
if (const VectorType *VT = Ty->getAs<VectorType>()) {
@@ -950,7 +936,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
Ty = EnumTy->getDecl()->getIntegerType();
bool NeedsPadding;
- bool InReg = shouldUseInReg(Ty, FreeRegs, IsFastCall, NeedsPadding);
+ bool InReg = shouldUseInReg(Ty, State, NeedsPadding);
if (Ty->isPromotableIntegerType()) {
if (InReg)
@@ -963,32 +949,105 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
}
void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
- FI.getCallingConvention());
-
- unsigned CC = FI.getCallingConvention();
- bool IsFastCall = CC == llvm::CallingConv::X86_FastCall;
- unsigned FreeRegs;
- if (IsFastCall)
- FreeRegs = 2;
+ CCState State(FI.getCallingConvention());
+ if (State.CC == llvm::CallingConv::X86_FastCall)
+ State.FreeRegs = 2;
else if (FI.getHasRegParm())
- FreeRegs = FI.getRegParm();
+ State.FreeRegs = FI.getRegParm();
else
- FreeRegs = DefaultNumRegisterParameters;
+ State.FreeRegs = DefaultNumRegisterParameters;
+
+ if (!getCXXABI().classifyReturnType(FI)) {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), State);
+ } else if (FI.getReturnInfo().isIndirect()) {
+ // The C++ ABI is not aware of register usage, so we have to check if the
+ // return value was sret and put it in a register ourselves if appropriate.
+ if (State.FreeRegs) {
+ --State.FreeRegs; // The sret parameter consumes a register.
+ FI.getReturnInfo().setInReg(true);
+ }
+ }
- // If the return value is indirect, then the hidden argument is consuming one
- // integer register.
- if (FI.getReturnInfo().isIndirect() && FreeRegs) {
- --FreeRegs;
- ABIArgInfo &Old = FI.getReturnInfo();
- Old = ABIArgInfo::getIndirectInReg(Old.getIndirectAlign(),
- Old.getIndirectByVal(),
- Old.getIndirectRealign());
+ bool UsedInAlloca = false;
+ for (auto &I : FI.arguments()) {
+ I.info = classifyArgumentType(I.type, State);
+ UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca);
}
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it)
- it->info = classifyArgumentType(it->type, FreeRegs, IsFastCall);
+ // If we needed to use inalloca for any argument, do a second pass and rewrite
+ // all the memory arguments to use inalloca.
+ if (UsedInAlloca)
+ rewriteWithInAlloca(FI);
+}
+
+void
+X86_32ABIInfo::addFieldToArgStruct(SmallVector<llvm::Type *, 6> &FrameFields,
+ unsigned &StackOffset,
+ ABIArgInfo &Info, QualType Type) const {
+ assert(StackOffset % 4U == 0 && "unaligned inalloca struct");
+ Info = ABIArgInfo::getInAlloca(FrameFields.size());
+ FrameFields.push_back(CGT.ConvertTypeForMem(Type));
+ StackOffset += getContext().getTypeSizeInChars(Type).getQuantity();
+
+ // Insert padding bytes to respect alignment. For x86_32, each argument is 4
+ // byte aligned.
+ if (StackOffset % 4U) {
+ unsigned OldOffset = StackOffset;
+ StackOffset = llvm::RoundUpToAlignment(StackOffset, 4U);
+ unsigned NumBytes = StackOffset - OldOffset;
+ assert(NumBytes);
+ llvm::Type *Ty = llvm::Type::getInt8Ty(getVMContext());
+ Ty = llvm::ArrayType::get(Ty, NumBytes);
+ FrameFields.push_back(Ty);
+ }
+}
+
+void X86_32ABIInfo::rewriteWithInAlloca(CGFunctionInfo &FI) const {
+ assert(IsWin32StructABI && "inalloca only supported on win32");
+
+ // Build a packed struct type for all of the arguments in memory.
+ SmallVector<llvm::Type *, 6> FrameFields;
+
+ unsigned StackOffset = 0;
+
+ // Put the sret parameter into the inalloca struct if it's in memory.
+ ABIArgInfo &Ret = FI.getReturnInfo();
+ if (Ret.isIndirect() && !Ret.getInReg()) {
+ CanQualType PtrTy = getContext().getPointerType(FI.getReturnType());
+ addFieldToArgStruct(FrameFields, StackOffset, Ret, PtrTy);
+ // On Windows, the hidden sret parameter is always returned in eax.
+ Ret.setInAllocaSRet(IsWin32StructABI);
+ }
+
+ // Skip the 'this' parameter in ecx.
+ CGFunctionInfo::arg_iterator I = FI.arg_begin(), E = FI.arg_end();
+ if (FI.getCallingConvention() == llvm::CallingConv::X86_ThisCall)
+ ++I;
+
+ // Put arguments passed in memory into the struct.
+ for (; I != E; ++I) {
+
+ // Leave ignored and inreg arguments alone.
+ switch (I->info.getKind()) {
+ case ABIArgInfo::Indirect:
+ assert(I->info.getIndirectByVal());
+ break;
+ case ABIArgInfo::Ignore:
+ continue;
+ case ABIArgInfo::Direct:
+ case ABIArgInfo::Extend:
+ if (I->info.getInReg())
+ continue;
+ break;
+ default:
+ break;
+ }
+
+ addFieldToArgStruct(FrameFields, StackOffset, I->info, I->type);
+ }
+
+ FI.setArgStruct(llvm::StructType::get(getVMContext(), FrameFields,
+ /*isPacked=*/true));
}
llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
@@ -1031,6 +1090,44 @@ llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
return AddrTyped;
}
+bool X86_32TargetCodeGenInfo::isStructReturnInRegABI(
+ const llvm::Triple &Triple, const CodeGenOptions &Opts) {
+ assert(Triple.getArch() == llvm::Triple::x86);
+
+ switch (Opts.getStructReturnConvention()) {
+ case CodeGenOptions::SRCK_Default:
+ break;
+ case CodeGenOptions::SRCK_OnStack: // -fpcc-struct-return
+ return false;
+ case CodeGenOptions::SRCK_InRegs: // -freg-struct-return
+ return true;
+ }
+
+ if (Triple.isOSDarwin())
+ return true;
+
+ switch (Triple.getOS()) {
+ case llvm::Triple::AuroraUX:
+ case llvm::Triple::DragonFly:
+ case llvm::Triple::FreeBSD:
+ case llvm::Triple::OpenBSD:
+ case llvm::Triple::Bitrig:
+ return true;
+ case llvm::Triple::Win32:
+ switch (Triple.getEnvironment()) {
+ case llvm::Triple::UnknownEnvironment:
+ case llvm::Triple::Cygnus:
+ case llvm::Triple::GNU:
+ case llvm::Triple::MSVC:
+ return true;
+ default:
+ return false;
+ }
+ default:
+ return false;
+ }
+}
+
void X86_32TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
llvm::GlobalValue *GV,
CodeGen::CodeGenModule &CGM) const {
@@ -1219,10 +1316,10 @@ public:
return false;
}
- virtual void computeInfo(CGFunctionInfo &FI) const;
+ void computeInfo(CGFunctionInfo &FI) const override;
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const override;
};
/// WinX86_64ABIInfo - The Windows X86_64 ABI information.
@@ -1233,10 +1330,10 @@ class WinX86_64ABIInfo : public ABIInfo {
public:
WinX86_64ABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {}
- virtual void computeInfo(CGFunctionInfo &FI) const;
+ void computeInfo(CGFunctionInfo &FI) const override;
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const override;
};
class X86_64TargetCodeGenInfo : public TargetCodeGenInfo {
@@ -1248,12 +1345,12 @@ public:
return static_cast<const X86_64ABIInfo&>(TargetCodeGenInfo::getABIInfo());
}
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const {
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override {
return 7;
}
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
+ llvm::Value *Address) const override {
llvm::Value *Eight8 = llvm::ConstantInt::get(CGF.Int8Ty, 8);
// 0-15 are the 16 integer registers.
@@ -1264,12 +1361,12 @@ public:
llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
StringRef Constraint,
- llvm::Type* Ty) const {
+ llvm::Type* Ty) const override {
return X86AdjustInlineAsmType(CGF, Constraint, Ty);
}
bool isNoProtoCallVariadic(const CallArgList &args,
- const FunctionNoProtoType *fnType) const {
+ const FunctionNoProtoType *fnType) const override {
// The default CC on x86-64 sets %al to the number of SSA
// registers used, and GCC sets this when calling an unprototyped
// function, so we override the default behavior. However, don't do
@@ -1293,7 +1390,8 @@ public:
return TargetCodeGenInfo::isNoProtoCallVariadic(args, fnType);
}
- llvm::Constant *getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const {
+ llvm::Constant *
+ getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const override {
unsigned Sig = (0xeb << 0) | // jmp rel8
(0x0a << 8) | // .+0x0c
('F' << 16) |
@@ -1319,14 +1417,14 @@ public:
: X86_32TargetCodeGenInfo(CGT, d, p, w, RegParms) {}
void getDependentLibraryOption(llvm::StringRef Lib,
- llvm::SmallString<24> &Opt) const {
+ llvm::SmallString<24> &Opt) const override {
Opt = "/DEFAULTLIB:";
Opt += qualifyWindowsLibrary(Lib);
}
void getDetectMismatchOption(llvm::StringRef Name,
llvm::StringRef Value,
- llvm::SmallString<32> &Opt) const {
+ llvm::SmallString<32> &Opt) const override {
Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\"";
}
};
@@ -1336,12 +1434,12 @@ public:
WinX86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
: TargetCodeGenInfo(new WinX86_64ABIInfo(CGT)) {}
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const {
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override {
return 7;
}
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
+ llvm::Value *Address) const override {
llvm::Value *Eight8 = llvm::ConstantInt::get(CGF.Int8Ty, 8);
// 0-15 are the 16 integer registers.
@@ -1351,14 +1449,14 @@ public:
}
void getDependentLibraryOption(llvm::StringRef Lib,
- llvm::SmallString<24> &Opt) const {
+ llvm::SmallString<24> &Opt) const override {
Opt = "/DEFAULTLIB:";
Opt += qualifyWindowsLibrary(Lib);
}
void getDetectMismatchOption(llvm::StringRef Name,
llvm::StringRef Value,
- llvm::SmallString<32> &Opt) const {
+ llvm::SmallString<32> &Opt) const override {
Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\"";
}
};
@@ -1642,12 +1740,11 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
// If this is a C++ record, classify the bases first.
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
- for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(),
- e = CXXRD->bases_end(); i != e; ++i) {
- assert(!i->isVirtual() && !i->getType()->isDependentType() &&
+ for (const auto &I : CXXRD->bases()) {
+ assert(!I.isVirtual() && !I.getType()->isDependentType() &&
"Unexpected base class!");
const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
// Classify this field.
//
@@ -1657,7 +1754,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
Class FieldLo, FieldHi;
uint64_t Offset =
OffsetBase + getContext().toBits(Layout.getBaseClassOffset(Base));
- classify(i->getType(), Offset, FieldLo, FieldHi, isNamedArg);
+ classify(I.getType(), Offset, FieldLo, FieldHi, isNamedArg);
Lo = merge(Lo, FieldLo);
Hi = merge(Hi, FieldHi);
if (Lo == Memory || Hi == Memory)
@@ -1887,19 +1984,18 @@ static bool BitsContainNoUserData(QualType Ty, unsigned StartBit,
// If this is a C++ record, check the bases first.
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
- for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(),
- e = CXXRD->bases_end(); i != e; ++i) {
- assert(!i->isVirtual() && !i->getType()->isDependentType() &&
+ for (const auto &I : CXXRD->bases()) {
+ assert(!I.isVirtual() && !I.getType()->isDependentType() &&
"Unexpected base class!");
const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
// If the base is after the span we care about, ignore it.
unsigned BaseOffset = Context.toBits(Layout.getBaseClassOffset(Base));
if (BaseOffset >= EndBit) continue;
unsigned BaseStart = BaseOffset < StartBit ? StartBit-BaseOffset :0;
- if (!BitsContainNoUserData(i->getType(), BaseStart,
+ if (!BitsContainNoUserData(I.getType(), BaseStart,
EndBit-BaseOffset, Context))
return false;
}
@@ -1995,7 +2091,7 @@ GetSSETypeAtOffset(llvm::Type *IRType, unsigned IROffset,
/// the source type. IROffset is an offset in bytes into the LLVM IR type that
/// the 8-byte value references. PrefType may be null.
///
-/// SourceTy is the source level type for the entire argument. SourceOffset is
+/// 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).
///
llvm::Type *X86_64ABIInfo::
@@ -2114,7 +2210,7 @@ classifyReturnType(QualType RetTy) const {
assert((Hi != Memory || Lo == Memory) && "Invalid memory classification.");
assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification.");
- llvm::Type *ResType = 0;
+ llvm::Type *ResType = nullptr;
switch (Lo) {
case NoClass:
if (Hi == NoClass)
@@ -2175,7 +2271,7 @@ classifyReturnType(QualType RetTy) const {
break;
}
- llvm::Type *HighPart = 0;
+ llvm::Type *HighPart = nullptr;
switch (Hi) {
// Memory was handled previously and X87 should
// never occur as a hi class.
@@ -2247,7 +2343,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(
neededInt = 0;
neededSSE = 0;
- llvm::Type *ResType = 0;
+ llvm::Type *ResType = nullptr;
switch (Lo) {
case NoClass:
if (Hi == NoClass)
@@ -2308,7 +2404,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(
}
}
- llvm::Type *HighPart = 0;
+ llvm::Type *HighPart = nullptr;
switch (Hi) {
// Memory was handled previously, ComplexX87 and X87 should
// never occur as hi classes, and X87Up must be preceded by X87,
@@ -2361,7 +2457,8 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(
void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
// Keep track of the number of assigned registers.
unsigned freeIntRegs = 6, freeSSERegs = 8;
@@ -2482,9 +2579,9 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
// NOTE: 304 is a typo, there are (6 * 8 + 8 * 16) = 176 bytes of
// register save space).
- llvm::Value *InRegs = 0;
- llvm::Value *gp_offset_p = 0, *gp_offset = 0;
- llvm::Value *fp_offset_p = 0, *fp_offset = 0;
+ llvm::Value *InRegs = nullptr;
+ llvm::Value *gp_offset_p = nullptr, *gp_offset = nullptr;
+ llvm::Value *fp_offset_p = nullptr, *fp_offset = nullptr;
if (neededInt) {
gp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "gp_offset_p");
gp_offset = CGF.Builder.CreateLoad(gp_offset_p, "gp_offset");
@@ -2539,8 +2636,8 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi);
llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset);
llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset);
- llvm::Value *RegLoAddr = TyLo->isFloatingPointTy() ? FPAddr : GPAddr;
- llvm::Value *RegHiAddr = TyLo->isFloatingPointTy() ? GPAddr : FPAddr;
+ llvm::Value *RegLoAddr = TyLo->isFPOrFPVectorTy() ? FPAddr : GPAddr;
+ llvm::Value *RegHiAddr = TyLo->isFPOrFPVectorTy() ? GPAddr : FPAddr;
llvm::Value *V =
CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegLoAddr, PTyLo));
CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0));
@@ -2630,11 +2727,9 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, bool IsReturnType) const {
uint64_t Size = getContext().getTypeSize(Ty);
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- if (IsReturnType) {
- if (isRecordReturnIndirect(RT, getCXXABI()))
- return ABIArgInfo::getIndirect(0, false);
- } else {
+ const RecordType *RT = Ty->getAs<RecordType>();
+ if (RT) {
+ if (!IsReturnType) {
if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()))
return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
}
@@ -2643,18 +2738,27 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, bool IsReturnType) const {
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
// FIXME: mingw-w64-gcc emits 128-bit struct as i128
- if (Size == 128 && getTarget().getTriple().getOS() == llvm::Triple::MinGW32)
+ if (Size == 128 && getTarget().getTriple().isWindowsGNUEnvironment())
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
Size));
+ }
+ if (Ty->isMemberPointerType()) {
+ // If the member pointer is represented by an LLVM int or ptr, pass it
+ // directly.
+ llvm::Type *LLTy = CGT.ConvertType(Ty);
+ if (LLTy->isPointerTy() || LLTy->isIntegerTy())
+ return ABIArgInfo::getDirect();
+ }
+
+ if (RT || Ty->isMemberPointerType()) {
// MS x64 ABI requirement: "Any argument that doesn't fit in 8 bytes, or is
// not 1, 2, 4, or 8 bytes, must be passed by reference."
- if (Size <= 64 &&
- (Size & (Size - 1)) == 0)
- return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
- Size));
+ if (Size > 64 || !llvm::isPowerOf2_64(Size))
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
- return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+ // Otherwise, coerce it to a small integer.
+ return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size));
}
if (Ty->isPromotableIntegerType())
@@ -2664,13 +2768,11 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, bool IsReturnType) const {
}
void WinX86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classify(FI.getReturnType(), true);
- QualType RetTy = FI.getReturnType();
- FI.getReturnInfo() = classify(RetTy, true);
-
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it)
- it->info = classify(it->type, false);
+ for (auto &I : FI.arguments())
+ I.info = classify(I.type, false);
}
llvm::Value *WinX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
@@ -2701,9 +2803,9 @@ class NaClX86_64ABIInfo : public ABIInfo {
public:
NaClX86_64ABIInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX)
: ABIInfo(CGT), PInfo(CGT), NInfo(CGT, HasAVX) {}
- virtual void computeInfo(CGFunctionInfo &FI) const;
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
+ void computeInfo(CGFunctionInfo &FI) const override;
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const override;
private:
PNaClABIInfo PInfo; // Used for generating calls with pnaclcall callingconv.
X86_64ABIInfo NInfo; // Used for everything else.
@@ -2739,13 +2841,13 @@ class PPC32TargetCodeGenInfo : public DefaultTargetCodeGenInfo {
public:
PPC32TargetCodeGenInfo(CodeGenTypes &CGT) : DefaultTargetCodeGenInfo(CGT) {}
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
// This is recovered from gcc output.
return 1; // r1 is the dedicated stack pointer
}
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const;
+ llvm::Value *Address) const override;
};
}
@@ -2796,11 +2898,24 @@ PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
namespace {
/// PPC64_SVR4_ABIInfo - The 64-bit PowerPC ELF (SVR4) ABI information.
class PPC64_SVR4_ABIInfo : public DefaultABIInfo {
+public:
+ enum ABIKind {
+ ELFv1 = 0,
+ ELFv2
+ };
+
+private:
+ static const unsigned GPRBits = 64;
+ ABIKind Kind;
public:
- PPC64_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
+ PPC64_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, ABIKind Kind)
+ : DefaultABIInfo(CGT), Kind(Kind) {}
bool isPromotableTypeForABI(QualType Ty) const;
+ bool isAlignedParamType(QualType Ty) const;
+ bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
+ uint64_t &Members) const;
ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType Ty) const;
@@ -2811,56 +2926,57 @@ public:
// floating-point value) to avoid pushing them to memory on function
// entry. This would require changing the logic in PPCISelLowering
// when lowering the parameters in the caller and args in the callee.
- virtual void computeInfo(CGFunctionInfo &FI) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it) {
+ void computeInfo(CGFunctionInfo &FI) const override {
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ for (auto &I : FI.arguments()) {
// We rely on the default argument classification for the most part.
// One exception: An aggregate containing a single floating-point
// or vector item must be passed in a register if one is available.
- const Type *T = isSingleElementStruct(it->type, getContext());
+ const Type *T = isSingleElementStruct(I.type, getContext());
if (T) {
const BuiltinType *BT = T->getAs<BuiltinType>();
- if (T->isVectorType() || (BT && BT->isFloatingPoint())) {
+ if ((T->isVectorType() && getContext().getTypeSize(T) == 128) ||
+ (BT && BT->isFloatingPoint())) {
QualType QT(T, 0);
- it->info = ABIArgInfo::getDirectInReg(CGT.ConvertType(QT));
+ I.info = ABIArgInfo::getDirectInReg(CGT.ConvertType(QT));
continue;
}
}
- it->info = classifyArgumentType(it->type);
+ I.info = classifyArgumentType(I.type);
}
}
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr,
- QualType Ty,
- CodeGenFunction &CGF) const;
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const override;
};
class PPC64_SVR4_TargetCodeGenInfo : public TargetCodeGenInfo {
public:
- PPC64_SVR4_TargetCodeGenInfo(CodeGenTypes &CGT)
- : TargetCodeGenInfo(new PPC64_SVR4_ABIInfo(CGT)) {}
+ PPC64_SVR4_TargetCodeGenInfo(CodeGenTypes &CGT,
+ PPC64_SVR4_ABIInfo::ABIKind Kind)
+ : TargetCodeGenInfo(new PPC64_SVR4_ABIInfo(CGT, Kind)) {}
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
// This is recovered from gcc output.
return 1; // r1 is the dedicated stack pointer
}
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const;
+ llvm::Value *Address) const override;
};
class PPC64TargetCodeGenInfo : public DefaultTargetCodeGenInfo {
public:
PPC64TargetCodeGenInfo(CodeGenTypes &CGT) : DefaultTargetCodeGenInfo(CGT) {}
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
// This is recovered from gcc output.
return 1; // r1 is the dedicated stack pointer
}
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const;
+ llvm::Value *Address) const override;
};
}
@@ -2891,16 +3007,205 @@ PPC64_SVR4_ABIInfo::isPromotableTypeForABI(QualType Ty) const {
return false;
}
+/// isAlignedParamType - Determine whether a type requires 16-byte
+/// alignment in the parameter area.
+bool
+PPC64_SVR4_ABIInfo::isAlignedParamType(QualType Ty) const {
+ // Complex types are passed just like their elements.
+ if (const ComplexType *CTy = Ty->getAs<ComplexType>())
+ Ty = CTy->getElementType();
+
+ // Only vector types of size 16 bytes need alignment (larger types are
+ // passed via reference, smaller types are not aligned).
+ if (Ty->isVectorType())
+ return getContext().getTypeSize(Ty) == 128;
+
+ // For single-element float/vector structs, we consider the whole type
+ // to have the same alignment requirements as its single element.
+ const Type *AlignAsType = nullptr;
+ const Type *EltType = isSingleElementStruct(Ty, getContext());
+ if (EltType) {
+ const BuiltinType *BT = EltType->getAs<BuiltinType>();
+ if ((EltType->isVectorType() &&
+ getContext().getTypeSize(EltType) == 128) ||
+ (BT && BT->isFloatingPoint()))
+ AlignAsType = EltType;
+ }
+
+ // Likewise for ELFv2 homogeneous aggregates.
+ const Type *Base = nullptr;
+ uint64_t Members = 0;
+ if (!AlignAsType && Kind == ELFv2 &&
+ isAggregateTypeForABI(Ty) && isHomogeneousAggregate(Ty, Base, Members))
+ AlignAsType = Base;
+
+ // With special case aggregates, only vector base types need alignment.
+ if (AlignAsType)
+ return AlignAsType->isVectorType();
+
+ // Otherwise, we only need alignment for any aggregate type that
+ // has an alignment requirement of >= 16 bytes.
+ if (isAggregateTypeForABI(Ty) && getContext().getTypeAlign(Ty) >= 128)
+ return true;
+
+ return false;
+}
+
+/// isHomogeneousAggregate - Return true if a type is an ELFv2 homogeneous
+/// aggregate. Base is set to the base element type, and Members is set
+/// to the number of base elements.
+bool
+PPC64_SVR4_ABIInfo::isHomogeneousAggregate(QualType Ty, const Type *&Base,
+ uint64_t &Members) const {
+ if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) {
+ uint64_t NElements = AT->getSize().getZExtValue();
+ if (NElements == 0)
+ return false;
+ if (!isHomogeneousAggregate(AT->getElementType(), Base, Members))
+ return false;
+ Members *= NElements;
+ } else if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ const RecordDecl *RD = RT->getDecl();
+ if (RD->hasFlexibleArrayMember())
+ return false;
+
+ Members = 0;
+ for (const auto *FD : RD->fields()) {
+ // Ignore (non-zero arrays of) empty records.
+ QualType FT = FD->getType();
+ while (const ConstantArrayType *AT =
+ getContext().getAsConstantArrayType(FT)) {
+ if (AT->getSize().getZExtValue() == 0)
+ return false;
+ FT = AT->getElementType();
+ }
+ if (isEmptyRecord(getContext(), FT, true))
+ continue;
+
+ // For compatibility with GCC, ignore empty bitfields in C++ mode.
+ if (getContext().getLangOpts().CPlusPlus &&
+ FD->isBitField() && FD->getBitWidthValue(getContext()) == 0)
+ continue;
+
+ uint64_t FldMembers;
+ if (!isHomogeneousAggregate(FD->getType(), Base, FldMembers))
+ return false;
+
+ Members = (RD->isUnion() ?
+ std::max(Members, FldMembers) : Members + FldMembers);
+ }
+
+ if (!Base)
+ return false;
+
+ // Ensure there is no padding.
+ if (getContext().getTypeSize(Base) * Members !=
+ getContext().getTypeSize(Ty))
+ return false;
+ } else {
+ Members = 1;
+ if (const ComplexType *CT = Ty->getAs<ComplexType>()) {
+ Members = 2;
+ Ty = CT->getElementType();
+ }
+
+ // Homogeneous aggregates for ELFv2 must have base types of float,
+ // double, long double, or 128-bit vectors.
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+ if (BT->getKind() != BuiltinType::Float &&
+ BT->getKind() != BuiltinType::Double &&
+ BT->getKind() != BuiltinType::LongDouble)
+ return false;
+ } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ if (getContext().getTypeSize(VT) != 128)
+ return false;
+ } else {
+ return false;
+ }
+
+ // The base type must be the same for all members. Types that
+ // agree in both total size and mode (float vs. vector) are
+ // treated as being equivalent here.
+ const Type *TyPtr = Ty.getTypePtr();
+ if (!Base)
+ Base = TyPtr;
+
+ if (Base->isVectorType() != TyPtr->isVectorType() ||
+ getContext().getTypeSize(Base) != getContext().getTypeSize(TyPtr))
+ return false;
+ }
+
+ // Vector types require one register, floating point types require one
+ // or two registers depending on their size.
+ uint32_t NumRegs = Base->isVectorType() ? 1 :
+ (getContext().getTypeSize(Base) + 63) / 64;
+
+ // Homogeneous Aggregates may occupy at most 8 registers.
+ return (Members > 0 && Members * NumRegs <= 8);
+}
+
ABIArgInfo
PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const {
if (Ty->isAnyComplexType())
return ABIArgInfo::getDirect();
+ // Non-Altivec vector types are passed in GPRs (smaller than 16 bytes)
+ // or via reference (larger than 16 bytes).
+ if (Ty->isVectorType()) {
+ uint64_t Size = getContext().getTypeSize(Ty);
+ if (Size > 128)
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+ else if (Size < 128) {
+ llvm::Type *CoerceTy = llvm::IntegerType::get(getVMContext(), Size);
+ return ABIArgInfo::getDirect(CoerceTy);
+ }
+ }
+
if (isAggregateTypeForABI(Ty)) {
if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
- return ABIArgInfo::getIndirect(0);
+ uint64_t ABIAlign = isAlignedParamType(Ty)? 16 : 8;
+ uint64_t TyAlign = getContext().getTypeAlign(Ty) / 8;
+
+ // ELFv2 homogeneous aggregates are passed as array types.
+ const Type *Base = nullptr;
+ uint64_t Members = 0;
+ if (Kind == ELFv2 &&
+ isHomogeneousAggregate(Ty, Base, Members)) {
+ llvm::Type *BaseTy = CGT.ConvertType(QualType(Base, 0));
+ llvm::Type *CoerceTy = llvm::ArrayType::get(BaseTy, Members);
+ return ABIArgInfo::getDirect(CoerceTy);
+ }
+
+ // If an aggregate may end up fully in registers, we do not
+ // use the ByVal method, but pass the aggregate as array.
+ // This is usually beneficial since we avoid forcing the
+ // back-end to store the argument to memory.
+ uint64_t Bits = getContext().getTypeSize(Ty);
+ if (Bits > 0 && Bits <= 8 * GPRBits) {
+ llvm::Type *CoerceTy;
+
+ // Types up to 8 bytes are passed as integer type (which will be
+ // properly aligned in the argument save area doubleword).
+ if (Bits <= GPRBits)
+ CoerceTy = llvm::IntegerType::get(getVMContext(),
+ llvm::RoundUpToAlignment(Bits, 8));
+ // Larger types are passed as arrays, with the base type selected
+ // according to the required alignment in the save area.
+ else {
+ uint64_t RegBits = ABIAlign * 8;
+ uint64_t NumRegs = llvm::RoundUpToAlignment(Bits, RegBits) / RegBits;
+ llvm::Type *RegTy = llvm::IntegerType::get(getVMContext(), RegBits);
+ CoerceTy = llvm::ArrayType::get(RegTy, NumRegs);
+ }
+
+ return ABIArgInfo::getDirect(CoerceTy);
+ }
+
+ // All other aggregates are passed ByVal.
+ return ABIArgInfo::getIndirect(ABIAlign, /*ByVal=*/true,
+ /*Realign=*/TyAlign > ABIAlign);
}
return (isPromotableTypeForABI(Ty) ?
@@ -2915,8 +3220,48 @@ PPC64_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const {
if (RetTy->isAnyComplexType())
return ABIArgInfo::getDirect();
- if (isAggregateTypeForABI(RetTy))
+ // Non-Altivec vector types are returned in GPRs (smaller than 16 bytes)
+ // or via reference (larger than 16 bytes).
+ if (RetTy->isVectorType()) {
+ uint64_t Size = getContext().getTypeSize(RetTy);
+ if (Size > 128)
+ return ABIArgInfo::getIndirect(0);
+ else if (Size < 128) {
+ llvm::Type *CoerceTy = llvm::IntegerType::get(getVMContext(), Size);
+ return ABIArgInfo::getDirect(CoerceTy);
+ }
+ }
+
+ if (isAggregateTypeForABI(RetTy)) {
+ // ELFv2 homogeneous aggregates are returned as array types.
+ const Type *Base = nullptr;
+ uint64_t Members = 0;
+ if (Kind == ELFv2 &&
+ isHomogeneousAggregate(RetTy, Base, Members)) {
+ llvm::Type *BaseTy = CGT.ConvertType(QualType(Base, 0));
+ llvm::Type *CoerceTy = llvm::ArrayType::get(BaseTy, Members);
+ return ABIArgInfo::getDirect(CoerceTy);
+ }
+
+ // ELFv2 small aggregates are returned in up to two registers.
+ uint64_t Bits = getContext().getTypeSize(RetTy);
+ if (Kind == ELFv2 && Bits <= 2 * GPRBits) {
+ if (Bits == 0)
+ return ABIArgInfo::getIgnore();
+
+ llvm::Type *CoerceTy;
+ if (Bits > GPRBits) {
+ CoerceTy = llvm::IntegerType::get(getVMContext(), GPRBits);
+ CoerceTy = llvm::StructType::get(CoerceTy, CoerceTy, NULL);
+ } else
+ CoerceTy = llvm::IntegerType::get(getVMContext(),
+ llvm::RoundUpToAlignment(Bits, 8));
+ return ABIArgInfo::getDirect(CoerceTy);
+ }
+
+ // All other aggregates are returned indirectly.
return ABIArgInfo::getIndirect(0);
+ }
return (isPromotableTypeForABI(RetTy) ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
@@ -2933,6 +3278,14 @@ llvm::Value *PPC64_SVR4_ABIInfo::EmitVAArg(llvm::Value *VAListAddr,
llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap");
llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
+ // Handle types that require 16-byte alignment in the parameter save area.
+ if (isAlignedParamType(Ty)) {
+ llvm::Value *AddrAsInt = Builder.CreatePtrToInt(Addr, CGF.Int64Ty);
+ AddrAsInt = Builder.CreateAdd(AddrAsInt, Builder.getInt64(15));
+ AddrAsInt = Builder.CreateAnd(AddrAsInt, Builder.getInt64(-16));
+ Addr = Builder.CreateIntToPtr(AddrAsInt, BP, "ap.align");
+ }
+
// Update the va_list pointer. The pointer should be bumped by the
// size of the object. We can trust getTypeSize() except for a complex
// type whose base type is smaller than a doubleword. For these, the
@@ -2963,8 +3316,12 @@ llvm::Value *PPC64_SVR4_ABIInfo::EmitVAArg(llvm::Value *VAListAddr,
if (CplxBaseSize && CplxBaseSize < 8) {
llvm::Value *RealAddr = Builder.CreatePtrToInt(Addr, CGF.Int64Ty);
llvm::Value *ImagAddr = RealAddr;
- RealAddr = Builder.CreateAdd(RealAddr, Builder.getInt64(8 - CplxBaseSize));
- ImagAddr = Builder.CreateAdd(ImagAddr, Builder.getInt64(16 - CplxBaseSize));
+ if (CGF.CGM.getDataLayout().isBigEndian()) {
+ RealAddr = Builder.CreateAdd(RealAddr, Builder.getInt64(8 - CplxBaseSize));
+ ImagAddr = Builder.CreateAdd(ImagAddr, Builder.getInt64(16 - CplxBaseSize));
+ } else {
+ ImagAddr = Builder.CreateAdd(ImagAddr, Builder.getInt64(8));
+ }
llvm::Type *PBaseTy = llvm::PointerType::getUnqual(CGF.ConvertType(BaseTy));
RealAddr = Builder.CreateIntToPtr(RealAddr, PBaseTy);
ImagAddr = Builder.CreateIntToPtr(ImagAddr, PBaseTy);
@@ -2982,7 +3339,7 @@ llvm::Value *PPC64_SVR4_ABIInfo::EmitVAArg(llvm::Value *VAListAddr,
// If the argument is smaller than 8 bytes, it is right-adjusted in
// its doubleword slot. Adjust the pointer to pick it up from the
// correct offset.
- if (SizeInBytes < 8) {
+ if (SizeInBytes < 8 && CGF.CGM.getDataLayout().isBigEndian()) {
llvm::Value *AddrAsInt = Builder.CreatePtrToInt(Addr, CGF.Int64Ty);
AddrAsInt = Builder.CreateAdd(AddrAsInt, Builder.getInt64(8 - SizeInBytes));
Addr = Builder.CreateIntToPtr(AddrAsInt, BP);
@@ -3049,6 +3406,598 @@ PPC64TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
}
//===----------------------------------------------------------------------===//
+// AArch64 ABI Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class AArch64ABIInfo : public ABIInfo {
+public:
+ enum ABIKind {
+ AAPCS = 0,
+ DarwinPCS
+ };
+
+private:
+ ABIKind Kind;
+
+public:
+ AArch64ABIInfo(CodeGenTypes &CGT, ABIKind Kind) : ABIInfo(CGT), Kind(Kind) {}
+
+private:
+ ABIKind getABIKind() const { return Kind; }
+ bool isDarwinPCS() const { return Kind == DarwinPCS; }
+
+ ABIArgInfo classifyReturnType(QualType RetTy) const;
+ ABIArgInfo classifyArgumentType(QualType RetTy, unsigned &AllocatedVFP,
+ bool &IsHA, unsigned &AllocatedGPR,
+ bool &IsSmallAggr, bool IsNamedArg) const;
+ bool isIllegalVectorType(QualType Ty) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI) const {
+ // To correctly handle Homogeneous Aggregate, we need to keep track of the
+ // number of SIMD and Floating-point registers allocated so far.
+ // If the argument is an HFA or an HVA and there are sufficient unallocated
+ // SIMD and Floating-point registers, then the argument is allocated to SIMD
+ // and Floating-point Registers (with one register per member of the HFA or
+ // HVA). Otherwise, the NSRN is set to 8.
+ unsigned AllocatedVFP = 0;
+
+ // To correctly handle small aggregates, we need to keep track of the number
+ // of GPRs allocated so far. If the small aggregate can't all fit into
+ // registers, it will be on stack. We don't allow the aggregate to be
+ // partially in registers.
+ unsigned AllocatedGPR = 0;
+
+ // Find the number of named arguments. Variadic arguments get special
+ // treatment with the Darwin ABI.
+ unsigned NumRequiredArgs = (FI.isVariadic() ?
+ FI.getRequiredArgs().getNumRequiredArgs() :
+ FI.arg_size());
+
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it) {
+ unsigned PreAllocation = AllocatedVFP, PreGPR = AllocatedGPR;
+ bool IsHA = false, IsSmallAggr = false;
+ const unsigned NumVFPs = 8;
+ const unsigned NumGPRs = 8;
+ bool IsNamedArg = ((it - FI.arg_begin()) <
+ static_cast<signed>(NumRequiredArgs));
+ it->info = classifyArgumentType(it->type, AllocatedVFP, IsHA,
+ AllocatedGPR, IsSmallAggr, IsNamedArg);
+
+ // Under AAPCS the 64-bit stack slot alignment means we can't pass HAs
+ // as sequences of floats since they'll get "holes" inserted as
+ // padding by the back end.
+ if (IsHA && AllocatedVFP > NumVFPs && !isDarwinPCS() &&
+ getContext().getTypeAlign(it->type) < 64) {
+ uint32_t NumStackSlots = getContext().getTypeSize(it->type);
+ NumStackSlots = llvm::RoundUpToAlignment(NumStackSlots, 64) / 64;
+
+ llvm::Type *CoerceTy = llvm::ArrayType::get(
+ llvm::Type::getDoubleTy(getVMContext()), NumStackSlots);
+ it->info = ABIArgInfo::getDirect(CoerceTy);
+ }
+
+ // If we do not have enough VFP registers for the HA, any VFP registers
+ // that are unallocated are marked as unavailable. To achieve this, we add
+ // padding of (NumVFPs - PreAllocation) floats.
+ if (IsHA && AllocatedVFP > NumVFPs && PreAllocation < NumVFPs) {
+ llvm::Type *PaddingTy = llvm::ArrayType::get(
+ llvm::Type::getFloatTy(getVMContext()), NumVFPs - PreAllocation);
+ it->info.setPaddingType(PaddingTy);
+ }
+
+ // If we do not have enough GPRs for the small aggregate, any GPR regs
+ // that are unallocated are marked as unavailable.
+ if (IsSmallAggr && AllocatedGPR > NumGPRs && PreGPR < NumGPRs) {
+ llvm::Type *PaddingTy = llvm::ArrayType::get(
+ llvm::Type::getInt32Ty(getVMContext()), NumGPRs - PreGPR);
+ it->info =
+ ABIArgInfo::getDirect(it->info.getCoerceToType(), 0, PaddingTy);
+ }
+ }
+ }
+
+ llvm::Value *EmitDarwinVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+
+ llvm::Value *EmitAAPCSVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ return isDarwinPCS() ? EmitDarwinVAArg(VAListAddr, Ty, CGF)
+ : EmitAAPCSVAArg(VAListAddr, Ty, CGF);
+ }
+};
+
+class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ AArch64TargetCodeGenInfo(CodeGenTypes &CGT, AArch64ABIInfo::ABIKind Kind)
+ : TargetCodeGenInfo(new AArch64ABIInfo(CGT, Kind)) {}
+
+ StringRef getARCRetainAutoreleasedReturnValueMarker() const {
+ return "mov\tfp, fp\t\t; marker for objc_retainAutoreleaseReturnValue";
+ }
+
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const { return 31; }
+
+ virtual bool doesReturnSlotInterfereWithArgs() const { return false; }
+};
+}
+
+static bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
+ ASTContext &Context,
+ uint64_t *HAMembers = nullptr);
+
+ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty,
+ unsigned &AllocatedVFP,
+ bool &IsHA,
+ unsigned &AllocatedGPR,
+ bool &IsSmallAggr,
+ bool IsNamedArg) const {
+ // Handle illegal vector types here.
+ if (isIllegalVectorType(Ty)) {
+ uint64_t Size = getContext().getTypeSize(Ty);
+ if (Size <= 32) {
+ llvm::Type *ResType = llvm::Type::getInt32Ty(getVMContext());
+ AllocatedGPR++;
+ return ABIArgInfo::getDirect(ResType);
+ }
+ if (Size == 64) {
+ llvm::Type *ResType =
+ llvm::VectorType::get(llvm::Type::getInt32Ty(getVMContext()), 2);
+ AllocatedVFP++;
+ return ABIArgInfo::getDirect(ResType);
+ }
+ if (Size == 128) {
+ llvm::Type *ResType =
+ llvm::VectorType::get(llvm::Type::getInt32Ty(getVMContext()), 4);
+ AllocatedVFP++;
+ return ABIArgInfo::getDirect(ResType);
+ }
+ AllocatedGPR++;
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+ }
+ if (Ty->isVectorType())
+ // Size of a legal vector should be either 64 or 128.
+ AllocatedVFP++;
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+ if (BT->getKind() == BuiltinType::Half ||
+ BT->getKind() == BuiltinType::Float ||
+ BT->getKind() == BuiltinType::Double ||
+ BT->getKind() == BuiltinType::LongDouble)
+ AllocatedVFP++;
+ }
+
+ if (!isAggregateTypeForABI(Ty)) {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
+ if (!Ty->isFloatingType() && !Ty->isVectorType()) {
+ unsigned Alignment = getContext().getTypeAlign(Ty);
+ if (!isDarwinPCS() && Alignment > 64)
+ AllocatedGPR = llvm::RoundUpToAlignment(AllocatedGPR, Alignment / 64);
+
+ int RegsNeeded = getContext().getTypeSize(Ty) > 64 ? 2 : 1;
+ AllocatedGPR += RegsNeeded;
+ }
+ return (Ty->isPromotableIntegerType() && isDarwinPCS()
+ ? ABIArgInfo::getExtend()
+ : ABIArgInfo::getDirect());
+ }
+
+ // Structures with either a non-trivial destructor or a non-trivial
+ // copy constructor are always indirect.
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
+ AllocatedGPR++;
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/RAA ==
+ CGCXXABI::RAA_DirectInMemory);
+ }
+
+ // Empty records are always ignored on Darwin, but actually passed in C++ mode
+ // elsewhere for GNU compatibility.
+ if (isEmptyRecord(getContext(), Ty, true)) {
+ if (!getContext().getLangOpts().CPlusPlus || isDarwinPCS())
+ return ABIArgInfo::getIgnore();
+
+ ++AllocatedGPR;
+ return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext()));
+ }
+
+ // Homogeneous Floating-point Aggregates (HFAs) need to be expanded.
+ const Type *Base = nullptr;
+ uint64_t Members = 0;
+ if (isHomogeneousAggregate(Ty, Base, getContext(), &Members)) {
+ IsHA = true;
+ if (!IsNamedArg && isDarwinPCS()) {
+ // With the Darwin ABI, variadic arguments are always passed on the stack
+ // and should not be expanded. Treat variadic HFAs as arrays of doubles.
+ uint64_t Size = getContext().getTypeSize(Ty);
+ llvm::Type *BaseTy = llvm::Type::getDoubleTy(getVMContext());
+ return ABIArgInfo::getDirect(llvm::ArrayType::get(BaseTy, Size / 64));
+ }
+ AllocatedVFP += Members;
+ return ABIArgInfo::getExpand();
+ }
+
+ // Aggregates <= 16 bytes are passed directly in registers or on the stack.
+ uint64_t Size = getContext().getTypeSize(Ty);
+ if (Size <= 128) {
+ unsigned Alignment = getContext().getTypeAlign(Ty);
+ if (!isDarwinPCS() && Alignment > 64)
+ AllocatedGPR = llvm::RoundUpToAlignment(AllocatedGPR, Alignment / 64);
+
+ Size = 64 * ((Size + 63) / 64); // round up to multiple of 8 bytes
+ AllocatedGPR += Size / 64;
+ IsSmallAggr = true;
+ // We use a pair of i64 for 16-byte aggregate with 8-byte alignment.
+ // For aggregates with 16-byte alignment, we use i128.
+ if (Alignment < 128 && Size == 128) {
+ llvm::Type *BaseTy = llvm::Type::getInt64Ty(getVMContext());
+ return ABIArgInfo::getDirect(llvm::ArrayType::get(BaseTy, Size / 64));
+ }
+ return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size));
+ }
+
+ AllocatedGPR++;
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+}
+
+ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy) const {
+ if (RetTy->isVoidType())
+ return ABIArgInfo::getIgnore();
+
+ // Large vector types should be returned via memory.
+ if (RetTy->isVectorType() && getContext().getTypeSize(RetTy) > 128)
+ return ABIArgInfo::getIndirect(0);
+
+ if (!isAggregateTypeForABI(RetTy)) {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
+ RetTy = EnumTy->getDecl()->getIntegerType();
+
+ return (RetTy->isPromotableIntegerType() && isDarwinPCS()
+ ? ABIArgInfo::getExtend()
+ : ABIArgInfo::getDirect());
+ }
+
+ if (isEmptyRecord(getContext(), RetTy, true))
+ return ABIArgInfo::getIgnore();
+
+ const Type *Base = nullptr;
+ if (isHomogeneousAggregate(RetTy, Base, getContext()))
+ // Homogeneous Floating-point Aggregates (HFAs) are returned directly.
+ return ABIArgInfo::getDirect();
+
+ // Aggregates <= 16 bytes are returned directly in registers or on the stack.
+ uint64_t Size = getContext().getTypeSize(RetTy);
+ if (Size <= 128) {
+ Size = 64 * ((Size + 63) / 64); // round up to multiple of 8 bytes
+ return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size));
+ }
+
+ return ABIArgInfo::getIndirect(0);
+}
+
+/// isIllegalVectorType - check whether the vector type is legal for AArch64.
+bool AArch64ABIInfo::isIllegalVectorType(QualType Ty) const {
+ if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ // Check whether VT is legal.
+ unsigned NumElements = VT->getNumElements();
+ uint64_t Size = getContext().getTypeSize(VT);
+ // NumElements should be power of 2 between 1 and 16.
+ if ((NumElements & (NumElements - 1)) != 0 || NumElements > 16)
+ return true;
+ return Size != 64 && (Size != 128 || NumElements == 1);
+ }
+ return false;
+}
+
+static llvm::Value *EmitAArch64VAArg(llvm::Value *VAListAddr, QualType Ty,
+ int AllocatedGPR, int AllocatedVFP,
+ bool IsIndirect, CodeGenFunction &CGF) {
+ // The AArch64 va_list type and handling is specified in the Procedure Call
+ // Standard, section B.4:
+ //
+ // struct {
+ // void *__stack;
+ // void *__gr_top;
+ // void *__vr_top;
+ // int __gr_offs;
+ // int __vr_offs;
+ // };
+
+ llvm::BasicBlock *MaybeRegBlock = CGF.createBasicBlock("vaarg.maybe_reg");
+ llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg");
+ llvm::BasicBlock *OnStackBlock = CGF.createBasicBlock("vaarg.on_stack");
+ llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end");
+ auto &Ctx = CGF.getContext();
+
+ llvm::Value *reg_offs_p = nullptr, *reg_offs = nullptr;
+ int reg_top_index;
+ int RegSize;
+ if (AllocatedGPR) {
+ assert(!AllocatedVFP && "Arguments never split between int & VFP regs");
+ // 3 is the field number of __gr_offs
+ reg_offs_p = CGF.Builder.CreateStructGEP(VAListAddr, 3, "gr_offs_p");
+ reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "gr_offs");
+ reg_top_index = 1; // field number for __gr_top
+ RegSize = 8 * AllocatedGPR;
+ } else {
+ assert(!AllocatedGPR && "Argument must go in VFP or int regs");
+ // 4 is the field number of __vr_offs.
+ reg_offs_p = CGF.Builder.CreateStructGEP(VAListAddr, 4, "vr_offs_p");
+ reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "vr_offs");
+ reg_top_index = 2; // field number for __vr_top
+ RegSize = 16 * AllocatedVFP;
+ }
+
+ //=======================================
+ // Find out where argument was passed
+ //=======================================
+
+ // If reg_offs >= 0 we're already using the stack for this type of
+ // argument. We don't want to keep updating reg_offs (in case it overflows,
+ // though anyone passing 2GB of arguments, each at most 16 bytes, deserves
+ // whatever they get).
+ llvm::Value *UsingStack = nullptr;
+ UsingStack = CGF.Builder.CreateICmpSGE(
+ reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, 0));
+
+ CGF.Builder.CreateCondBr(UsingStack, OnStackBlock, MaybeRegBlock);
+
+ // Otherwise, at least some kind of argument could go in these registers, the
+ // question is whether this particular type is too big.
+ CGF.EmitBlock(MaybeRegBlock);
+
+ // Integer arguments may need to correct register alignment (for example a
+ // "struct { __int128 a; };" gets passed in x_2N, x_{2N+1}). In this case we
+ // align __gr_offs to calculate the potential address.
+ if (AllocatedGPR && !IsIndirect && Ctx.getTypeAlign(Ty) > 64) {
+ int Align = Ctx.getTypeAlign(Ty) / 8;
+
+ reg_offs = CGF.Builder.CreateAdd(
+ reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, Align - 1),
+ "align_regoffs");
+ reg_offs = CGF.Builder.CreateAnd(
+ reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, -Align),
+ "aligned_regoffs");
+ }
+
+ // Update the gr_offs/vr_offs pointer for next call to va_arg on this va_list.
+ llvm::Value *NewOffset = nullptr;
+ NewOffset = CGF.Builder.CreateAdd(
+ reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, RegSize), "new_reg_offs");
+ CGF.Builder.CreateStore(NewOffset, reg_offs_p);
+
+ // Now we're in a position to decide whether this argument really was in
+ // registers or not.
+ llvm::Value *InRegs = nullptr;
+ InRegs = CGF.Builder.CreateICmpSLE(
+ NewOffset, llvm::ConstantInt::get(CGF.Int32Ty, 0), "inreg");
+
+ CGF.Builder.CreateCondBr(InRegs, InRegBlock, OnStackBlock);
+
+ //=======================================
+ // Argument was in registers
+ //=======================================
+
+ // Now we emit the code for if the argument was originally passed in
+ // registers. First start the appropriate block:
+ CGF.EmitBlock(InRegBlock);
+
+ llvm::Value *reg_top_p = nullptr, *reg_top = nullptr;
+ reg_top_p =
+ CGF.Builder.CreateStructGEP(VAListAddr, reg_top_index, "reg_top_p");
+ reg_top = CGF.Builder.CreateLoad(reg_top_p, "reg_top");
+ llvm::Value *BaseAddr = CGF.Builder.CreateGEP(reg_top, reg_offs);
+ llvm::Value *RegAddr = nullptr;
+ llvm::Type *MemTy = llvm::PointerType::getUnqual(CGF.ConvertTypeForMem(Ty));
+
+ if (IsIndirect) {
+ // If it's been passed indirectly (actually a struct), whatever we find from
+ // stored registers or on the stack will actually be a struct **.
+ MemTy = llvm::PointerType::getUnqual(MemTy);
+ }
+
+ const Type *Base = nullptr;
+ uint64_t NumMembers;
+ bool IsHFA = isHomogeneousAggregate(Ty, Base, Ctx, &NumMembers);
+ if (IsHFA && NumMembers > 1) {
+ // Homogeneous aggregates passed in registers will have their elements split
+ // and stored 16-bytes apart regardless of size (they're notionally in qN,
+ // qN+1, ...). We reload and store into a temporary local variable
+ // contiguously.
+ assert(!IsIndirect && "Homogeneous aggregates should be passed directly");
+ llvm::Type *BaseTy = CGF.ConvertType(QualType(Base, 0));
+ llvm::Type *HFATy = llvm::ArrayType::get(BaseTy, NumMembers);
+ llvm::Value *Tmp = CGF.CreateTempAlloca(HFATy);
+ int Offset = 0;
+
+ if (CGF.CGM.getDataLayout().isBigEndian() && Ctx.getTypeSize(Base) < 128)
+ Offset = 16 - Ctx.getTypeSize(Base) / 8;
+ for (unsigned i = 0; i < NumMembers; ++i) {
+ llvm::Value *BaseOffset =
+ llvm::ConstantInt::get(CGF.Int32Ty, 16 * i + Offset);
+ llvm::Value *LoadAddr = CGF.Builder.CreateGEP(BaseAddr, BaseOffset);
+ LoadAddr = CGF.Builder.CreateBitCast(
+ LoadAddr, llvm::PointerType::getUnqual(BaseTy));
+ llvm::Value *StoreAddr = CGF.Builder.CreateStructGEP(Tmp, i);
+
+ llvm::Value *Elem = CGF.Builder.CreateLoad(LoadAddr);
+ CGF.Builder.CreateStore(Elem, StoreAddr);
+ }
+
+ RegAddr = CGF.Builder.CreateBitCast(Tmp, MemTy);
+ } else {
+ // Otherwise the object is contiguous in memory
+ unsigned BeAlign = reg_top_index == 2 ? 16 : 8;
+ if (CGF.CGM.getDataLayout().isBigEndian() &&
+ (IsHFA || !isAggregateTypeForABI(Ty)) &&
+ Ctx.getTypeSize(Ty) < (BeAlign * 8)) {
+ int Offset = BeAlign - Ctx.getTypeSize(Ty) / 8;
+ BaseAddr = CGF.Builder.CreatePtrToInt(BaseAddr, CGF.Int64Ty);
+
+ BaseAddr = CGF.Builder.CreateAdd(
+ BaseAddr, llvm::ConstantInt::get(CGF.Int64Ty, Offset), "align_be");
+
+ BaseAddr = CGF.Builder.CreateIntToPtr(BaseAddr, CGF.Int8PtrTy);
+ }
+
+ RegAddr = CGF.Builder.CreateBitCast(BaseAddr, MemTy);
+ }
+
+ CGF.EmitBranch(ContBlock);
+
+ //=======================================
+ // Argument was on the stack
+ //=======================================
+ CGF.EmitBlock(OnStackBlock);
+
+ llvm::Value *stack_p = nullptr, *OnStackAddr = nullptr;
+ stack_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "stack_p");
+ OnStackAddr = CGF.Builder.CreateLoad(stack_p, "stack");
+
+ // Again, stack arguments may need realigmnent. In this case both integer and
+ // floating-point ones might be affected.
+ if (!IsIndirect && Ctx.getTypeAlign(Ty) > 64) {
+ int Align = Ctx.getTypeAlign(Ty) / 8;
+
+ OnStackAddr = CGF.Builder.CreatePtrToInt(OnStackAddr, CGF.Int64Ty);
+
+ OnStackAddr = CGF.Builder.CreateAdd(
+ OnStackAddr, llvm::ConstantInt::get(CGF.Int64Ty, Align - 1),
+ "align_stack");
+ OnStackAddr = CGF.Builder.CreateAnd(
+ OnStackAddr, llvm::ConstantInt::get(CGF.Int64Ty, -Align),
+ "align_stack");
+
+ OnStackAddr = CGF.Builder.CreateIntToPtr(OnStackAddr, CGF.Int8PtrTy);
+ }
+
+ uint64_t StackSize;
+ if (IsIndirect)
+ StackSize = 8;
+ else
+ StackSize = Ctx.getTypeSize(Ty) / 8;
+
+ // All stack slots are 8 bytes
+ StackSize = llvm::RoundUpToAlignment(StackSize, 8);
+
+ llvm::Value *StackSizeC = llvm::ConstantInt::get(CGF.Int32Ty, StackSize);
+ llvm::Value *NewStack =
+ CGF.Builder.CreateGEP(OnStackAddr, StackSizeC, "new_stack");
+
+ // Write the new value of __stack for the next call to va_arg
+ CGF.Builder.CreateStore(NewStack, stack_p);
+
+ if (CGF.CGM.getDataLayout().isBigEndian() && !isAggregateTypeForABI(Ty) &&
+ Ctx.getTypeSize(Ty) < 64) {
+ int Offset = 8 - Ctx.getTypeSize(Ty) / 8;
+ OnStackAddr = CGF.Builder.CreatePtrToInt(OnStackAddr, CGF.Int64Ty);
+
+ OnStackAddr = CGF.Builder.CreateAdd(
+ OnStackAddr, llvm::ConstantInt::get(CGF.Int64Ty, Offset), "align_be");
+
+ OnStackAddr = CGF.Builder.CreateIntToPtr(OnStackAddr, CGF.Int8PtrTy);
+ }
+
+ OnStackAddr = CGF.Builder.CreateBitCast(OnStackAddr, MemTy);
+
+ CGF.EmitBranch(ContBlock);
+
+ //=======================================
+ // Tidy up
+ //=======================================
+ CGF.EmitBlock(ContBlock);
+
+ llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(MemTy, 2, "vaarg.addr");
+ ResAddr->addIncoming(RegAddr, InRegBlock);
+ ResAddr->addIncoming(OnStackAddr, OnStackBlock);
+
+ if (IsIndirect)
+ return CGF.Builder.CreateLoad(ResAddr, "vaarg.addr");
+
+ return ResAddr;
+}
+
+llvm::Value *AArch64ABIInfo::EmitAAPCSVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+
+ unsigned AllocatedGPR = 0, AllocatedVFP = 0;
+ bool IsHA = false, IsSmallAggr = false;
+ ABIArgInfo AI = classifyArgumentType(Ty, AllocatedVFP, IsHA, AllocatedGPR,
+ IsSmallAggr, false /*IsNamedArg*/);
+
+ return EmitAArch64VAArg(VAListAddr, Ty, AllocatedGPR, AllocatedVFP,
+ AI.isIndirect(), CGF);
+}
+
+llvm::Value *AArch64ABIInfo::EmitDarwinVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ // We do not support va_arg for aggregates or illegal vector types.
+ // Lower VAArg here for these cases and use the LLVM va_arg instruction for
+ // other cases.
+ if (!isAggregateTypeForABI(Ty) && !isIllegalVectorType(Ty))
+ return nullptr;
+
+ uint64_t Size = CGF.getContext().getTypeSize(Ty) / 8;
+ uint64_t Align = CGF.getContext().getTypeAlign(Ty) / 8;
+
+ const Type *Base = nullptr;
+ bool isHA = isHomogeneousAggregate(Ty, Base, getContext());
+
+ bool isIndirect = false;
+ // Arguments bigger than 16 bytes which aren't homogeneous aggregates should
+ // be passed indirectly.
+ if (Size > 16 && !isHA) {
+ isIndirect = true;
+ Size = 8;
+ Align = 8;
+ }
+
+ llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
+
+ CGBuilderTy &Builder = CGF.Builder;
+ llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap");
+ llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
+
+ if (isEmptyRecord(getContext(), Ty, true)) {
+ // These are ignored for parameter passing purposes.
+ llvm::Type *PTy = llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
+ return Builder.CreateBitCast(Addr, PTy);
+ }
+
+ const uint64_t MinABIAlign = 8;
+ if (Align > MinABIAlign) {
+ llvm::Value *Offset = llvm::ConstantInt::get(CGF.Int32Ty, Align - 1);
+ Addr = Builder.CreateGEP(Addr, Offset);
+ llvm::Value *AsInt = Builder.CreatePtrToInt(Addr, CGF.Int64Ty);
+ llvm::Value *Mask = llvm::ConstantInt::get(CGF.Int64Ty, ~(Align - 1));
+ llvm::Value *Aligned = Builder.CreateAnd(AsInt, Mask);
+ Addr = Builder.CreateIntToPtr(Aligned, BP, "ap.align");
+ }
+
+ uint64_t Offset = llvm::RoundUpToAlignment(Size, MinABIAlign);
+ llvm::Value *NextAddr = Builder.CreateGEP(
+ Addr, llvm::ConstantInt::get(CGF.Int32Ty, Offset), "ap.next");
+ Builder.CreateStore(NextAddr, VAListAddrAsBPP);
+
+ if (isIndirect)
+ Addr = Builder.CreateLoad(Builder.CreateBitCast(Addr, BPP));
+ llvm::Type *PTy = llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
+ llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
+
+ return AddrTyped;
+}
+
+//===----------------------------------------------------------------------===//
// ARM ABI Implementation
//===----------------------------------------------------------------------===//
@@ -3064,35 +4013,62 @@ public:
private:
ABIKind Kind;
+ mutable int VFPRegs[16];
+ const unsigned NumVFPs;
+ const unsigned NumGPRs;
+ mutable unsigned AllocatedGPRs;
+ mutable unsigned AllocatedVFPs;
public:
- ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind) : ABIInfo(CGT), Kind(_Kind) {
+ ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind) : ABIInfo(CGT), Kind(_Kind),
+ NumVFPs(16), NumGPRs(4) {
setRuntimeCC();
+ resetAllocatedRegs();
}
bool isEABI() const {
- StringRef Env = getTarget().getTriple().getEnvironmentName();
- return (Env == "gnueabi" || Env == "eabi" ||
- Env == "android" || Env == "androideabi");
+ switch (getTarget().getTriple().getEnvironment()) {
+ case llvm::Triple::Android:
+ case llvm::Triple::EABI:
+ case llvm::Triple::EABIHF:
+ case llvm::Triple::GNUEABI:
+ case llvm::Triple::GNUEABIHF:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool isEABIHF() const {
+ switch (getTarget().getTriple().getEnvironment()) {
+ case llvm::Triple::EABIHF:
+ case llvm::Triple::GNUEABIHF:
+ return true;
+ default:
+ return false;
+ }
}
ABIKind getABIKind() const { return Kind; }
private:
- ABIArgInfo classifyReturnType(QualType RetTy) const;
- ABIArgInfo classifyArgumentType(QualType RetTy, int *VFPRegs,
- unsigned &AllocatedVFP,
- bool &IsHA) const;
+ ABIArgInfo classifyReturnType(QualType RetTy, bool isVariadic) const;
+ ABIArgInfo classifyArgumentType(QualType RetTy, bool isVariadic,
+ bool &IsCPRC) const;
bool isIllegalVectorType(QualType Ty) const;
- virtual void computeInfo(CGFunctionInfo &FI) const;
+ void computeInfo(CGFunctionInfo &FI) const override;
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const override;
llvm::CallingConv::ID getLLVMDefaultCC() const;
llvm::CallingConv::ID getABIDefaultCC() const;
void setRuntimeCC();
+
+ void markAllocatedGPRs(unsigned Alignment, unsigned NumRequired) const;
+ void markAllocatedVFPs(unsigned Alignment, unsigned NumRequired) const;
+ void resetAllocatedRegs(void) const;
};
class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
@@ -3104,16 +4080,16 @@ public:
return static_cast<const ARMABIInfo&>(TargetCodeGenInfo::getABIInfo());
}
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
return 13;
}
- StringRef getARCRetainAutoreleasedReturnValueMarker() const {
+ StringRef getARCRetainAutoreleasedReturnValueMarker() const override {
return "mov\tr7, r7\t\t@ marker for objc_retainAutoreleaseReturnValue";
}
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
+ llvm::Value *Address) const override {
llvm::Value *Four8 = llvm::ConstantInt::get(CGF.Int8Ty, 4);
// 0-15 are the 16 integer registers.
@@ -3121,13 +4097,13 @@ public:
return false;
}
- unsigned getSizeOfUnwindException() const {
+ unsigned getSizeOfUnwindException() const override {
if (getABIInfo().isEABI()) return 88;
return TargetCodeGenInfo::getSizeOfUnwindException();
}
void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const {
+ CodeGen::CodeGenModule &CGM) const override {
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
if (!FD)
return;
@@ -3176,24 +4152,43 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
// allocated to the lowest-numbered sequence of such registers.
// C.2.vfp If the argument is a VFP CPRC then any VFP registers that are
// unallocated are marked as unavailable.
- unsigned AllocatedVFP = 0;
- int VFPRegs[16] = { 0 };
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it) {
- unsigned PreAllocation = AllocatedVFP;
- bool IsHA = false;
+ resetAllocatedRegs();
+
+ if (getCXXABI().classifyReturnType(FI)) {
+ if (FI.getReturnInfo().isIndirect())
+ markAllocatedGPRs(1, 1);
+ } else {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), FI.isVariadic());
+ }
+ for (auto &I : FI.arguments()) {
+ unsigned PreAllocationVFPs = AllocatedVFPs;
+ unsigned PreAllocationGPRs = AllocatedGPRs;
+ bool IsCPRC = false;
// 6.1.2.3 There is one VFP co-processor register class using registers
// s0-s15 (d0-d7) for passing arguments.
- const unsigned NumVFPs = 16;
- it->info = classifyArgumentType(it->type, VFPRegs, AllocatedVFP, IsHA);
- // If we do not have enough VFP registers for the HA, any VFP registers
- // that are unallocated are marked as unavailable. To achieve this, we add
- // padding of (NumVFPs - PreAllocation) floats.
- if (IsHA && AllocatedVFP > NumVFPs && PreAllocation < NumVFPs) {
+ I.info = classifyArgumentType(I.type, FI.isVariadic(), IsCPRC);
+
+ // If we have allocated some arguments onto the stack (due to running
+ // out of VFP registers), we cannot split an argument between GPRs and
+ // the stack. If this situation occurs, we add padding to prevent the
+ // GPRs from being used. In this situation, the current argument could
+ // only be allocated by rule C.8, so rule C.6 would mark these GPRs as
+ // unusable anyway.
+ // We do not have to do this if the argument is being passed ByVal, as the
+ // backend can handle that situation correctly.
+ const bool StackUsed = PreAllocationGPRs > NumGPRs || PreAllocationVFPs > NumVFPs;
+ const bool IsByVal = I.info.isIndirect() && I.info.getIndirectByVal();
+ if (!IsCPRC && PreAllocationGPRs < NumGPRs && AllocatedGPRs > NumGPRs &&
+ StackUsed && !IsByVal) {
llvm::Type *PaddingTy = llvm::ArrayType::get(
- llvm::Type::getFloatTy(getVMContext()), NumVFPs - PreAllocation);
- it->info = ABIArgInfo::getExpandWithPadding(false, PaddingTy);
+ llvm::Type::getInt32Ty(getVMContext()), NumGPRs - PreAllocationGPRs);
+ if (I.info.canHaveCoerceToType()) {
+ I.info = ABIArgInfo::getDirect(I.info.getCoerceToType() /* type */, 0 /* offset */,
+ PaddingTy);
+ } else {
+ I.info = ABIArgInfo::getDirect(nullptr /* type */, 0 /* offset */,
+ PaddingTy);
+ }
}
}
@@ -3209,7 +4204,7 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
/// Return the default calling convention that LLVM will use.
llvm::CallingConv::ID ARMABIInfo::getLLVMDefaultCC() const {
// The default calling convention that LLVM will infer.
- if (getTarget().getTriple().getEnvironmentName()=="gnueabihf")
+ if (isEABIHF())
return llvm::CallingConv::ARM_AAPCS_VFP;
else if (isEABI())
return llvm::CallingConv::ARM_AAPCS;
@@ -3243,8 +4238,7 @@ void ARMABIInfo::setRuntimeCC() {
/// contained in the type is returned through it; this is used for the
/// recursive calls that check aggregate component types.
static bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
- ASTContext &Context,
- uint64_t *HAMembers = 0) {
+ ASTContext &Context, uint64_t *HAMembers) {
uint64_t Members = 0;
if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) {
if (!isHomogeneousAggregate(AT->getElementType(), Base, Context, &Members))
@@ -3256,9 +4250,7 @@ static bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
return false;
Members = 0;
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
- const FieldDecl *FD = *i;
+ for (const auto *FD : RD->fields()) {
uint64_t FldMembers;
if (!isHomogeneousAggregate(FD->getType(), Base, Context, &FldMembers))
return false;
@@ -3293,10 +4285,29 @@ static bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
const Type *TyPtr = Ty.getTypePtr();
if (!Base)
Base = TyPtr;
- if (Base != TyPtr &&
- (!Base->isVectorType() || !TyPtr->isVectorType() ||
- Context.getTypeSize(Base) != Context.getTypeSize(TyPtr)))
- return false;
+
+ if (Base != TyPtr) {
+ // Homogeneous aggregates are defined as containing members with the
+ // same machine type. There are two cases in which two members have
+ // different TypePtrs but the same machine type:
+
+ // 1) Vectors of the same length, regardless of the type and number
+ // of their members.
+ const bool SameLengthVectors = Base->isVectorType() && TyPtr->isVectorType()
+ && (Context.getTypeSize(Base) == Context.getTypeSize(TyPtr));
+
+ // 2) In the 32-bit AAPCS, `double' and `long double' have the same
+ // machine type. This is not the case for the 64-bit AAPCS.
+ const bool SameSizeDoubles =
+ ( ( Base->isSpecificBuiltinType(BuiltinType::Double)
+ && TyPtr->isSpecificBuiltinType(BuiltinType::LongDouble))
+ || ( Base->isSpecificBuiltinType(BuiltinType::LongDouble)
+ && TyPtr->isSpecificBuiltinType(BuiltinType::Double)))
+ && (Context.getTypeSize(Base) == Context.getTypeSize(TyPtr));
+
+ if (!SameLengthVectors && !SameSizeDoubles)
+ return false;
+ }
}
// Homogeneous Aggregates can have at most 4 members of the base type.
@@ -3308,12 +4319,15 @@ static bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
/// markAllocatedVFPs - update VFPRegs according to the alignment and
/// number of VFP registers (unit is S register) requested.
-static void markAllocatedVFPs(int *VFPRegs, unsigned &AllocatedVFP,
- unsigned Alignment,
- unsigned NumRequired) {
+void ARMABIInfo::markAllocatedVFPs(unsigned Alignment,
+ unsigned NumRequired) const {
// Early Exit.
- if (AllocatedVFP >= 16)
+ if (AllocatedVFPs >= 16) {
+ // We use AllocatedVFP > 16 to signal that some CPRCs were allocated on
+ // the stack.
+ AllocatedVFPs = 17;
return;
+ }
// C.1.vfp If the argument is a VFP CPRC and there are sufficient consecutive
// VFP registers of the appropriate type unallocated then the argument is
// allocated to the lowest-numbered sequence of such registers.
@@ -3327,7 +4341,7 @@ static void markAllocatedVFPs(int *VFPRegs, unsigned &AllocatedVFP,
if (FoundSlot) {
for (unsigned J = I, JEnd = I + NumRequired; J < JEnd; J++)
VFPRegs[J] = 1;
- AllocatedVFP += NumRequired;
+ AllocatedVFPs += NumRequired;
return;
}
}
@@ -3335,12 +4349,31 @@ static void markAllocatedVFPs(int *VFPRegs, unsigned &AllocatedVFP,
// unallocated are marked as unavailable.
for (unsigned I = 0; I < 16; I++)
VFPRegs[I] = 1;
- AllocatedVFP = 17; // We do not have enough VFP registers.
+ AllocatedVFPs = 17; // We do not have enough VFP registers.
}
-ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, int *VFPRegs,
- unsigned &AllocatedVFP,
- bool &IsHA) const {
+/// Update AllocatedGPRs to record the number of general purpose registers
+/// which have been allocated. It is valid for AllocatedGPRs to go above 4,
+/// this represents arguments being stored on the stack.
+void ARMABIInfo::markAllocatedGPRs(unsigned Alignment,
+ unsigned NumRequired) const {
+ assert((Alignment == 1 || Alignment == 2) && "Alignment must be 4 or 8 bytes");
+
+ if (Alignment == 2 && AllocatedGPRs & 0x1)
+ AllocatedGPRs += 1;
+
+ AllocatedGPRs += NumRequired;
+}
+
+void ARMABIInfo::resetAllocatedRegs(void) const {
+ AllocatedGPRs = 0;
+ AllocatedVFPs = 0;
+ for (unsigned i = 0; i < NumVFPs; ++i)
+ VFPRegs[i] = 0;
+}
+
+ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic,
+ bool &IsCPRC) const {
// We update number of allocated VFPs according to
// 6.1.2.1 The following argument types are VFP CPRCs:
// A single-precision floating-point type (including promoted
@@ -3356,58 +4389,85 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, int *VFPRegs,
if (Size <= 32) {
llvm::Type *ResType =
llvm::Type::getInt32Ty(getVMContext());
+ markAllocatedGPRs(1, 1);
return ABIArgInfo::getDirect(ResType);
}
if (Size == 64) {
llvm::Type *ResType = llvm::VectorType::get(
llvm::Type::getInt32Ty(getVMContext()), 2);
- markAllocatedVFPs(VFPRegs, AllocatedVFP, 2, 2);
+ if (getABIKind() == ARMABIInfo::AAPCS || isVariadic){
+ markAllocatedGPRs(2, 2);
+ } else {
+ markAllocatedVFPs(2, 2);
+ IsCPRC = true;
+ }
return ABIArgInfo::getDirect(ResType);
}
if (Size == 128) {
llvm::Type *ResType = llvm::VectorType::get(
llvm::Type::getInt32Ty(getVMContext()), 4);
- markAllocatedVFPs(VFPRegs, AllocatedVFP, 4, 4);
+ if (getABIKind() == ARMABIInfo::AAPCS || isVariadic) {
+ markAllocatedGPRs(2, 4);
+ } else {
+ markAllocatedVFPs(4, 4);
+ IsCPRC = true;
+ }
return ABIArgInfo::getDirect(ResType);
}
+ markAllocatedGPRs(1, 1);
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
}
// Update VFPRegs for legal vector types.
- if (const VectorType *VT = Ty->getAs<VectorType>()) {
- uint64_t Size = getContext().getTypeSize(VT);
- // Size of a legal vector should be power of 2 and above 64.
- markAllocatedVFPs(VFPRegs, AllocatedVFP, Size >= 128 ? 4 : 2, Size / 32);
+ if (getABIKind() == ARMABIInfo::AAPCS_VFP && !isVariadic) {
+ if (const VectorType *VT = Ty->getAs<VectorType>()) {
+ uint64_t Size = getContext().getTypeSize(VT);
+ // Size of a legal vector should be power of 2 and above 64.
+ markAllocatedVFPs(Size >= 128 ? 4 : 2, Size / 32);
+ IsCPRC = true;
+ }
}
// Update VFPRegs for floating point types.
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
- if (BT->getKind() == BuiltinType::Half ||
- BT->getKind() == BuiltinType::Float)
- markAllocatedVFPs(VFPRegs, AllocatedVFP, 1, 1);
- if (BT->getKind() == BuiltinType::Double ||
- BT->getKind() == BuiltinType::LongDouble)
- markAllocatedVFPs(VFPRegs, AllocatedVFP, 2, 2);
+ if (getABIKind() == ARMABIInfo::AAPCS_VFP && !isVariadic) {
+ if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+ if (BT->getKind() == BuiltinType::Half ||
+ BT->getKind() == BuiltinType::Float) {
+ markAllocatedVFPs(1, 1);
+ IsCPRC = true;
+ }
+ if (BT->getKind() == BuiltinType::Double ||
+ BT->getKind() == BuiltinType::LongDouble) {
+ markAllocatedVFPs(2, 2);
+ IsCPRC = true;
+ }
+ }
}
if (!isAggregateTypeForABI(Ty)) {
// Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>()) {
Ty = EnumTy->getDecl()->getIntegerType();
+ }
+ unsigned Size = getContext().getTypeSize(Ty);
+ if (!IsCPRC)
+ markAllocatedGPRs(Size > 32 ? 2 : 1, (Size + 31) / 32);
return (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
+ markAllocatedGPRs(1, 1);
return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
+ }
// Ignore empty records.
if (isEmptyRecord(getContext(), Ty, true))
return ABIArgInfo::getIgnore();
- if (getABIKind() == ARMABIInfo::AAPCS_VFP) {
+ if (getABIKind() == ARMABIInfo::AAPCS_VFP && !isVariadic) {
// Homogeneous Aggregates need to be expanded when we can fit the aggregate
// into VFP registers.
- const Type *Base = 0;
+ const Type *Base = nullptr;
uint64_t Members = 0;
if (isHomogeneousAggregate(Ty, Base, getContext(), &Members)) {
assert(Base && "Base class should be set for homogeneous aggregate");
@@ -3415,17 +4475,17 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, int *VFPRegs,
if (Base->isVectorType()) {
// ElementSize is in number of floats.
unsigned ElementSize = getContext().getTypeSize(Base) == 64 ? 2 : 4;
- markAllocatedVFPs(VFPRegs, AllocatedVFP, ElementSize,
+ markAllocatedVFPs(ElementSize,
Members * ElementSize);
} else if (Base->isSpecificBuiltinType(BuiltinType::Float))
- markAllocatedVFPs(VFPRegs, AllocatedVFP, 1, Members);
+ markAllocatedVFPs(1, Members);
else {
assert(Base->isSpecificBuiltinType(BuiltinType::Double) ||
Base->isSpecificBuiltinType(BuiltinType::LongDouble));
- markAllocatedVFPs(VFPRegs, AllocatedVFP, 2, Members * 2);
+ markAllocatedVFPs(2, Members * 2);
}
- IsHA = true;
- return ABIArgInfo::getExpand();
+ IsCPRC = true;
+ return ABIArgInfo::getDirect();
}
}
@@ -3439,7 +4499,12 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, int *VFPRegs,
getABIKind() == ARMABIInfo::AAPCS)
ABIAlign = std::min(std::max(TyAlign, (uint64_t)4), (uint64_t)8);
if (getContext().getTypeSizeInChars(Ty) > CharUnits::fromQuantity(64)) {
- return ABIArgInfo::getIndirect(0, /*ByVal=*/true,
+ // Update Allocated GPRs. Since this is only used when the size of the
+ // argument is greater than 64 bytes, this will always use up any available
+ // registers (of which there are 4). We also don't care about getting the
+ // alignment right, because general-purpose registers cannot be back-filled.
+ markAllocatedGPRs(1, 4);
+ return ABIArgInfo::getIndirect(TyAlign, /*ByVal=*/true,
/*Realign=*/TyAlign > ABIAlign);
}
@@ -3451,9 +4516,11 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, int *VFPRegs,
if (getContext().getTypeAlign(Ty) <= 32) {
ElemTy = llvm::Type::getInt32Ty(getVMContext());
SizeRegs = (getContext().getTypeSize(Ty) + 31) / 32;
+ markAllocatedGPRs(1, SizeRegs);
} else {
ElemTy = llvm::Type::getInt64Ty(getVMContext());
SizeRegs = (getContext().getTypeSize(Ty) + 63) / 64;
+ markAllocatedGPRs(2, SizeRegs * 2);
}
llvm::Type *STy =
@@ -3546,13 +4613,16 @@ static bool isIntegerLikeType(QualType Ty, ASTContext &Context,
return true;
}
-ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
+ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy,
+ bool isVariadic) const {
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
// Large vector types should be returned via memory.
- if (RetTy->isVectorType() && getContext().getTypeSize(RetTy) > 128)
+ if (RetTy->isVectorType() && getContext().getTypeSize(RetTy) > 128) {
+ markAllocatedGPRs(1, 1);
return ABIArgInfo::getIndirect(0);
+ }
if (!isAggregateTypeForABI(RetTy)) {
// Treat an enum type as its underlying type.
@@ -3563,11 +4633,6 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
- // Structures with either a non-trivial destructor or a non-trivial
- // copy constructor are always indirect.
- if (isRecordReturnIndirect(RetTy, getCXXABI()))
- return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
-
// Are we following APCS?
if (getABIKind() == APCS) {
if (isEmptyRecord(getContext(), RetTy, false))
@@ -3593,6 +4658,7 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
}
// Otherwise return in memory.
+ markAllocatedGPRs(1, 1);
return ABIArgInfo::getIndirect(0);
}
@@ -3602,8 +4668,8 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
return ABIArgInfo::getIgnore();
// Check for homogeneous aggregates with AAPCS-VFP.
- if (getABIKind() == AAPCS_VFP) {
- const Type *Base = 0;
+ if (getABIKind() == AAPCS_VFP && !isVariadic) {
+ const Type *Base = nullptr;
if (isHomogeneousAggregate(RetTy, Base, getContext())) {
assert(Base && "Base class should be set for homogeneous aggregate");
// Homogeneous Aggregates are returned directly.
@@ -3615,6 +4681,10 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
// are returned indirectly.
uint64_t Size = getContext().getTypeSize(RetTy);
if (Size <= 32) {
+ if (getDataLayout().isBigEndian())
+ // Return in 32 bit integer integer type (as if loaded by LDR, AAPCS 5.4)
+ return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
+
// Return in the smallest viable integer type.
if (Size <= 8)
return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext()));
@@ -3623,6 +4693,7 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext()));
}
+ markAllocatedGPRs(1, 1);
return ABIArgInfo::getIndirect(0);
}
@@ -3723,9 +4794,9 @@ class NaClARMABIInfo : public ABIInfo {
public:
NaClARMABIInfo(CodeGen::CodeGenTypes &CGT, ARMABIInfo::ABIKind Kind)
: ABIInfo(CGT), PInfo(CGT), NInfo(CGT, Kind) {}
- virtual void computeInfo(CGFunctionInfo &FI) const;
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
+ void computeInfo(CGFunctionInfo &FI) const override;
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const override;
private:
PNaClABIInfo PInfo; // Used for generating calls with pnaclcall callingconv.
ARMABIInfo NInfo; // Used for everything else.
@@ -3754,418 +4825,6 @@ llvm::Value *NaClARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
}
//===----------------------------------------------------------------------===//
-// AArch64 ABI Implementation
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class AArch64ABIInfo : public ABIInfo {
-public:
- AArch64ABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
-
-private:
- // The AArch64 PCS is explicit about return types and argument types being
- // handled identically, so we don't need to draw a distinction between
- // Argument and Return classification.
- ABIArgInfo classifyGenericType(QualType Ty, int &FreeIntRegs,
- int &FreeVFPRegs) const;
-
- ABIArgInfo tryUseRegs(QualType Ty, int &FreeRegs, int RegsNeeded, bool IsInt,
- llvm::Type *DirectTy = 0) const;
-
- virtual void computeInfo(CGFunctionInfo &FI) const;
-
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
-};
-
-class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
-public:
- AArch64TargetCodeGenInfo(CodeGenTypes &CGT)
- :TargetCodeGenInfo(new AArch64ABIInfo(CGT)) {}
-
- const AArch64ABIInfo &getABIInfo() const {
- return static_cast<const AArch64ABIInfo&>(TargetCodeGenInfo::getABIInfo());
- }
-
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
- return 31;
- }
-
- bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
- // 0-31 are x0-x30 and sp: 8 bytes each
- llvm::Value *Eight8 = llvm::ConstantInt::get(CGF.Int8Ty, 8);
- AssignToArrayRange(CGF.Builder, Address, Eight8, 0, 31);
-
- // 64-95 are v0-v31: 16 bytes each
- llvm::Value *Sixteen8 = llvm::ConstantInt::get(CGF.Int8Ty, 16);
- AssignToArrayRange(CGF.Builder, Address, Sixteen8, 64, 95);
-
- return false;
- }
-
-};
-
-}
-
-void AArch64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
- int FreeIntRegs = 8, FreeVFPRegs = 8;
-
- FI.getReturnInfo() = classifyGenericType(FI.getReturnType(),
- FreeIntRegs, FreeVFPRegs);
-
- FreeIntRegs = FreeVFPRegs = 8;
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it) {
- it->info = classifyGenericType(it->type, FreeIntRegs, FreeVFPRegs);
-
- }
-}
-
-ABIArgInfo
-AArch64ABIInfo::tryUseRegs(QualType Ty, int &FreeRegs, int RegsNeeded,
- bool IsInt, llvm::Type *DirectTy) const {
- if (FreeRegs >= RegsNeeded) {
- FreeRegs -= RegsNeeded;
- return ABIArgInfo::getDirect(DirectTy);
- }
-
- llvm::Type *Padding = 0;
-
- // We need padding so that later arguments don't get filled in anyway. That
- // wouldn't happen if only ByVal arguments followed in the same category, but
- // a large structure will simply seem to be a pointer as far as LLVM is
- // concerned.
- if (FreeRegs > 0) {
- if (IsInt)
- Padding = llvm::Type::getInt64Ty(getVMContext());
- else
- Padding = llvm::Type::getFloatTy(getVMContext());
-
- // Either [N x i64] or [N x float].
- Padding = llvm::ArrayType::get(Padding, FreeRegs);
- FreeRegs = 0;
- }
-
- return ABIArgInfo::getIndirect(getContext().getTypeAlign(Ty) / 8,
- /*IsByVal=*/ true, /*Realign=*/ false,
- Padding);
-}
-
-
-ABIArgInfo AArch64ABIInfo::classifyGenericType(QualType Ty,
- int &FreeIntRegs,
- int &FreeVFPRegs) const {
- // Can only occurs for return, but harmless otherwise.
- if (Ty->isVoidType())
- return ABIArgInfo::getIgnore();
-
- // Large vector types should be returned via memory. There's no such concept
- // in the ABI, but they'd be over 16 bytes anyway so no matter how they're
- // classified they'd go into memory (see B.3).
- if (Ty->isVectorType() && getContext().getTypeSize(Ty) > 128) {
- if (FreeIntRegs > 0)
- --FreeIntRegs;
- return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
- }
-
- // All non-aggregate LLVM types have a concrete ABI representation so they can
- // be passed directly. After this block we're guaranteed to be in a
- // complicated case.
- if (!isAggregateTypeForABI(Ty)) {
- // Treat an enum type as its underlying type.
- if (const EnumType *EnumTy = Ty->getAs<EnumType>())
- Ty = EnumTy->getDecl()->getIntegerType();
-
- if (Ty->isFloatingType() || Ty->isVectorType())
- return tryUseRegs(Ty, FreeVFPRegs, /*RegsNeeded=*/ 1, /*IsInt=*/ false);
-
- assert(getContext().getTypeSize(Ty) <= 128 &&
- "unexpectedly large scalar type");
-
- int RegsNeeded = getContext().getTypeSize(Ty) > 64 ? 2 : 1;
-
- // If the type may need padding registers to ensure "alignment", we must be
- // careful when this is accounted for. Increasing the effective size covers
- // all cases.
- if (getContext().getTypeAlign(Ty) == 128)
- RegsNeeded += FreeIntRegs % 2 != 0;
-
- return tryUseRegs(Ty, FreeIntRegs, RegsNeeded, /*IsInt=*/ true);
- }
-
- if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
- if (FreeIntRegs > 0 && RAA == CGCXXABI::RAA_Indirect)
- --FreeIntRegs;
- return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
- }
-
- if (isEmptyRecord(getContext(), Ty, true)) {
- if (!getContext().getLangOpts().CPlusPlus) {
- // Empty structs outside C++ mode are a GNU extension, so no ABI can
- // possibly tell us what to do. It turns out (I believe) that GCC ignores
- // the object for parameter-passsing purposes.
- return ABIArgInfo::getIgnore();
- }
-
- // The combination of C++98 9p5 (sizeof(struct) != 0) and the pseudocode
- // description of va_arg in the PCS require that an empty struct does
- // actually occupy space for parameter-passing. I'm hoping for a
- // clarification giving an explicit paragraph to point to in future.
- return tryUseRegs(Ty, FreeIntRegs, /*RegsNeeded=*/ 1, /*IsInt=*/ true,
- llvm::Type::getInt8Ty(getVMContext()));
- }
-
- // Homogeneous vector aggregates get passed in registers or on the stack.
- const Type *Base = 0;
- uint64_t NumMembers = 0;
- if (isHomogeneousAggregate(Ty, Base, getContext(), &NumMembers)) {
- assert(Base && "Base class should be set for homogeneous aggregate");
- // Homogeneous aggregates are passed and returned directly.
- return tryUseRegs(Ty, FreeVFPRegs, /*RegsNeeded=*/ NumMembers,
- /*IsInt=*/ false);
- }
-
- uint64_t Size = getContext().getTypeSize(Ty);
- if (Size <= 128) {
- // Small structs can use the same direct type whether they're in registers
- // or on the stack.
- llvm::Type *BaseTy;
- unsigned NumBases;
- int SizeInRegs = (Size + 63) / 64;
-
- if (getContext().getTypeAlign(Ty) == 128) {
- BaseTy = llvm::Type::getIntNTy(getVMContext(), 128);
- NumBases = 1;
-
- // If the type may need padding registers to ensure "alignment", we must
- // be careful when this is accounted for. Increasing the effective size
- // covers all cases.
- SizeInRegs += FreeIntRegs % 2 != 0;
- } else {
- BaseTy = llvm::Type::getInt64Ty(getVMContext());
- NumBases = SizeInRegs;
- }
- llvm::Type *DirectTy = llvm::ArrayType::get(BaseTy, NumBases);
-
- return tryUseRegs(Ty, FreeIntRegs, /*RegsNeeded=*/ SizeInRegs,
- /*IsInt=*/ true, DirectTy);
- }
-
- // If the aggregate is > 16 bytes, it's passed and returned indirectly. In
- // LLVM terms the return uses an "sret" pointer, but that's handled elsewhere.
- --FreeIntRegs;
- return ABIArgInfo::getIndirect(0, /* byVal = */ false);
-}
-
-llvm::Value *AArch64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const {
- // The AArch64 va_list type and handling is specified in the Procedure Call
- // Standard, section B.4:
- //
- // struct {
- // void *__stack;
- // void *__gr_top;
- // void *__vr_top;
- // int __gr_offs;
- // int __vr_offs;
- // };
-
- assert(!CGF.CGM.getDataLayout().isBigEndian()
- && "va_arg not implemented for big-endian AArch64");
-
- int FreeIntRegs = 8, FreeVFPRegs = 8;
- Ty = CGF.getContext().getCanonicalType(Ty);
- ABIArgInfo AI = classifyGenericType(Ty, FreeIntRegs, FreeVFPRegs);
-
- llvm::BasicBlock *MaybeRegBlock = CGF.createBasicBlock("vaarg.maybe_reg");
- llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg");
- llvm::BasicBlock *OnStackBlock = CGF.createBasicBlock("vaarg.on_stack");
- llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end");
-
- llvm::Value *reg_offs_p = 0, *reg_offs = 0;
- int reg_top_index;
- int RegSize;
- if (FreeIntRegs < 8) {
- assert(FreeVFPRegs == 8 && "Arguments never split between int & VFP regs");
- // 3 is the field number of __gr_offs
- reg_offs_p = CGF.Builder.CreateStructGEP(VAListAddr, 3, "gr_offs_p");
- reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "gr_offs");
- reg_top_index = 1; // field number for __gr_top
- RegSize = 8 * (8 - FreeIntRegs);
- } else {
- assert(FreeVFPRegs < 8 && "Argument must go in VFP or int regs");
- // 4 is the field number of __vr_offs.
- reg_offs_p = CGF.Builder.CreateStructGEP(VAListAddr, 4, "vr_offs_p");
- reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "vr_offs");
- reg_top_index = 2; // field number for __vr_top
- RegSize = 16 * (8 - FreeVFPRegs);
- }
-
- //=======================================
- // Find out where argument was passed
- //=======================================
-
- // If reg_offs >= 0 we're already using the stack for this type of
- // argument. We don't want to keep updating reg_offs (in case it overflows,
- // though anyone passing 2GB of arguments, each at most 16 bytes, deserves
- // whatever they get).
- llvm::Value *UsingStack = 0;
- UsingStack = CGF.Builder.CreateICmpSGE(reg_offs,
- llvm::ConstantInt::get(CGF.Int32Ty, 0));
-
- CGF.Builder.CreateCondBr(UsingStack, OnStackBlock, MaybeRegBlock);
-
- // Otherwise, at least some kind of argument could go in these registers, the
- // quesiton is whether this particular type is too big.
- CGF.EmitBlock(MaybeRegBlock);
-
- // Integer arguments may need to correct register alignment (for example a
- // "struct { __int128 a; };" gets passed in x_2N, x_{2N+1}). In this case we
- // align __gr_offs to calculate the potential address.
- if (FreeIntRegs < 8 && AI.isDirect() && getContext().getTypeAlign(Ty) > 64) {
- int Align = getContext().getTypeAlign(Ty) / 8;
-
- reg_offs = CGF.Builder.CreateAdd(reg_offs,
- llvm::ConstantInt::get(CGF.Int32Ty, Align - 1),
- "align_regoffs");
- reg_offs = CGF.Builder.CreateAnd(reg_offs,
- llvm::ConstantInt::get(CGF.Int32Ty, -Align),
- "aligned_regoffs");
- }
-
- // Update the gr_offs/vr_offs pointer for next call to va_arg on this va_list.
- llvm::Value *NewOffset = 0;
- NewOffset = CGF.Builder.CreateAdd(reg_offs,
- llvm::ConstantInt::get(CGF.Int32Ty, RegSize),
- "new_reg_offs");
- CGF.Builder.CreateStore(NewOffset, reg_offs_p);
-
- // Now we're in a position to decide whether this argument really was in
- // registers or not.
- llvm::Value *InRegs = 0;
- InRegs = CGF.Builder.CreateICmpSLE(NewOffset,
- llvm::ConstantInt::get(CGF.Int32Ty, 0),
- "inreg");
-
- CGF.Builder.CreateCondBr(InRegs, InRegBlock, OnStackBlock);
-
- //=======================================
- // Argument was in registers
- //=======================================
-
- // Now we emit the code for if the argument was originally passed in
- // registers. First start the appropriate block:
- CGF.EmitBlock(InRegBlock);
-
- llvm::Value *reg_top_p = 0, *reg_top = 0;
- reg_top_p = CGF.Builder.CreateStructGEP(VAListAddr, reg_top_index, "reg_top_p");
- reg_top = CGF.Builder.CreateLoad(reg_top_p, "reg_top");
- llvm::Value *BaseAddr = CGF.Builder.CreateGEP(reg_top, reg_offs);
- llvm::Value *RegAddr = 0;
- llvm::Type *MemTy = llvm::PointerType::getUnqual(CGF.ConvertTypeForMem(Ty));
-
- if (!AI.isDirect()) {
- // If it's been passed indirectly (actually a struct), whatever we find from
- // stored registers or on the stack will actually be a struct **.
- MemTy = llvm::PointerType::getUnqual(MemTy);
- }
-
- const Type *Base = 0;
- uint64_t NumMembers;
- if (isHomogeneousAggregate(Ty, Base, getContext(), &NumMembers)
- && NumMembers > 1) {
- // Homogeneous aggregates passed in registers will have their elements split
- // and stored 16-bytes apart regardless of size (they're notionally in qN,
- // qN+1, ...). We reload and store into a temporary local variable
- // contiguously.
- assert(AI.isDirect() && "Homogeneous aggregates should be passed directly");
- llvm::Type *BaseTy = CGF.ConvertType(QualType(Base, 0));
- llvm::Type *HFATy = llvm::ArrayType::get(BaseTy, NumMembers);
- llvm::Value *Tmp = CGF.CreateTempAlloca(HFATy);
-
- for (unsigned i = 0; i < NumMembers; ++i) {
- llvm::Value *BaseOffset = llvm::ConstantInt::get(CGF.Int32Ty, 16 * i);
- llvm::Value *LoadAddr = CGF.Builder.CreateGEP(BaseAddr, BaseOffset);
- LoadAddr = CGF.Builder.CreateBitCast(LoadAddr,
- llvm::PointerType::getUnqual(BaseTy));
- llvm::Value *StoreAddr = CGF.Builder.CreateStructGEP(Tmp, i);
-
- llvm::Value *Elem = CGF.Builder.CreateLoad(LoadAddr);
- CGF.Builder.CreateStore(Elem, StoreAddr);
- }
-
- RegAddr = CGF.Builder.CreateBitCast(Tmp, MemTy);
- } else {
- // Otherwise the object is contiguous in memory
- RegAddr = CGF.Builder.CreateBitCast(BaseAddr, MemTy);
- }
-
- CGF.EmitBranch(ContBlock);
-
- //=======================================
- // Argument was on the stack
- //=======================================
- CGF.EmitBlock(OnStackBlock);
-
- llvm::Value *stack_p = 0, *OnStackAddr = 0;
- stack_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "stack_p");
- OnStackAddr = CGF.Builder.CreateLoad(stack_p, "stack");
-
- // Again, stack arguments may need realigmnent. In this case both integer and
- // floating-point ones might be affected.
- if (AI.isDirect() && getContext().getTypeAlign(Ty) > 64) {
- int Align = getContext().getTypeAlign(Ty) / 8;
-
- OnStackAddr = CGF.Builder.CreatePtrToInt(OnStackAddr, CGF.Int64Ty);
-
- OnStackAddr = CGF.Builder.CreateAdd(OnStackAddr,
- llvm::ConstantInt::get(CGF.Int64Ty, Align - 1),
- "align_stack");
- OnStackAddr = CGF.Builder.CreateAnd(OnStackAddr,
- llvm::ConstantInt::get(CGF.Int64Ty, -Align),
- "align_stack");
-
- OnStackAddr = CGF.Builder.CreateIntToPtr(OnStackAddr, CGF.Int8PtrTy);
- }
-
- uint64_t StackSize;
- if (AI.isDirect())
- StackSize = getContext().getTypeSize(Ty) / 8;
- else
- StackSize = 8;
-
- // All stack slots are 8 bytes
- StackSize = llvm::RoundUpToAlignment(StackSize, 8);
-
- llvm::Value *StackSizeC = llvm::ConstantInt::get(CGF.Int32Ty, StackSize);
- llvm::Value *NewStack = CGF.Builder.CreateGEP(OnStackAddr, StackSizeC,
- "new_stack");
-
- // Write the new value of __stack for the next call to va_arg
- CGF.Builder.CreateStore(NewStack, stack_p);
-
- OnStackAddr = CGF.Builder.CreateBitCast(OnStackAddr, MemTy);
-
- CGF.EmitBranch(ContBlock);
-
- //=======================================
- // Tidy up
- //=======================================
- CGF.EmitBlock(ContBlock);
-
- llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(MemTy, 2, "vaarg.addr");
- ResAddr->addIncoming(RegAddr, InRegBlock);
- ResAddr->addIncoming(OnStackAddr, OnStackBlock);
-
- if (AI.isDirect())
- return ResAddr;
-
- return CGF.Builder.CreateLoad(ResAddr, "vaarg.addr");
-}
-
-//===----------------------------------------------------------------------===//
// NVPTX ABI Implementation
//===----------------------------------------------------------------------===//
@@ -4178,20 +4837,22 @@ public:
ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType Ty) const;
- virtual void computeInfo(CGFunctionInfo &FI) const;
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CFG) const;
+ void computeInfo(CGFunctionInfo &FI) const override;
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CFG) const override;
};
class NVPTXTargetCodeGenInfo : public TargetCodeGenInfo {
public:
NVPTXTargetCodeGenInfo(CodeGenTypes &CGT)
: TargetCodeGenInfo(new NVPTXABIInfo(CGT)) {}
-
- virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const;
+
+ void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const override;
private:
- static void addKernelMetadata(llvm::Function *F);
+ // Adds a NamedMDNode with F, Name, and Operand as operands, and adds the
+ // resulting MDNode to the nvvm.annotations MDNode.
+ static void addNVVMMetadata(llvm::Function *F, StringRef Name, int Operand);
};
ABIArgInfo NVPTXABIInfo::classifyReturnType(QualType RetTy) const {
@@ -4220,10 +4881,10 @@ ABIArgInfo NVPTXABIInfo::classifyArgumentType(QualType Ty) const {
}
void NVPTXABIInfo::computeInfo(CGFunctionInfo &FI) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it)
- it->info = classifyArgumentType(it->type);
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ for (auto &I : FI.arguments())
+ I.info = classifyArgumentType(I.type);
// Always honor user-specified calling convention.
if (FI.getCallingConvention() != llvm::CallingConv::C)
@@ -4251,7 +4912,8 @@ SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
// By default, all functions are device functions
if (FD->hasAttr<OpenCLKernelAttr>()) {
// OpenCL __kernel functions get kernel metadata
- addKernelMetadata(F);
+ // Create !{<func-ref>, metadata !"kernel", i32 1} node
+ addNVVMMetadata(F, "kernel", 1);
// And kernel functions are not subject to inlining
F->addFnAttr(llvm::Attribute::NoInline);
}
@@ -4262,28 +4924,41 @@ SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
// CUDA __global__ functions get a kernel metadata entry. Since
// __global__ functions cannot be called from the device, we do not
// need to set the noinline attribute.
- if (FD->getAttr<CUDAGlobalAttr>())
- addKernelMetadata(F);
+ if (FD->hasAttr<CUDAGlobalAttr>()) {
+ // Create !{<func-ref>, metadata !"kernel", i32 1} node
+ addNVVMMetadata(F, "kernel", 1);
+ }
+ if (FD->hasAttr<CUDALaunchBoundsAttr>()) {
+ // Create !{<func-ref>, metadata !"maxntidx", i32 <val>} node
+ addNVVMMetadata(F, "maxntidx",
+ FD->getAttr<CUDALaunchBoundsAttr>()->getMaxThreads());
+ // min blocks is a default argument for CUDALaunchBoundsAttr, so getting a
+ // zero value from getMinBlocks either means it was not specified in
+ // __launch_bounds__ or the user specified a 0 value. In both cases, we
+ // don't have to add a PTX directive.
+ int MinCTASM = FD->getAttr<CUDALaunchBoundsAttr>()->getMinBlocks();
+ if (MinCTASM > 0) {
+ // Create !{<func-ref>, metadata !"minctasm", i32 <val>} node
+ addNVVMMetadata(F, "minctasm", MinCTASM);
+ }
+ }
}
}
-void NVPTXTargetCodeGenInfo::addKernelMetadata(llvm::Function *F) {
+void NVPTXTargetCodeGenInfo::addNVVMMetadata(llvm::Function *F, StringRef Name,
+ int Operand) {
llvm::Module *M = F->getParent();
llvm::LLVMContext &Ctx = M->getContext();
// Get "nvvm.annotations" metadata node
llvm::NamedMDNode *MD = M->getOrInsertNamedMetadata("nvvm.annotations");
- // Create !{<func-ref>, metadata !"kernel", i32 1} node
- llvm::SmallVector<llvm::Value *, 3> MDVals;
- MDVals.push_back(F);
- MDVals.push_back(llvm::MDString::get(Ctx, "kernel"));
- MDVals.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), 1));
-
+ llvm::Value *MDVals[] = {
+ F, llvm::MDString::get(Ctx, Name),
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), Operand)};
// Append metadata to nvvm.annotations
MD->addOperand(llvm::MDNode::get(Ctx, MDVals));
}
-
}
//===----------------------------------------------------------------------===//
@@ -4303,15 +4978,15 @@ public:
ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType ArgTy) const;
- virtual void computeInfo(CGFunctionInfo &FI) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it)
- it->info = classifyArgumentType(it->type);
+ void computeInfo(CGFunctionInfo &FI) const override {
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ for (auto &I : FI.arguments())
+ I.info = classifyArgumentType(I.type);
}
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const override;
};
class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
@@ -4363,9 +5038,8 @@ bool SystemZABIInfo::isFPArgumentType(QualType Ty) const {
// If this is a C++ record, check the bases first.
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
- for (CXXRecordDecl::base_class_const_iterator I = CXXRD->bases_begin(),
- E = CXXRD->bases_end(); I != E; ++I) {
- QualType Base = I->getType();
+ for (const auto &I : CXXRD->bases()) {
+ QualType Base = I.getType();
// Empty bases don't affect things either way.
if (isEmptyRecord(getContext(), Base, true))
@@ -4379,10 +5053,7 @@ bool SystemZABIInfo::isFPArgumentType(QualType Ty) const {
}
// Check the fields.
- for (RecordDecl::field_iterator I = RD->field_begin(),
- E = RD->field_end(); I != E; ++I) {
- const FieldDecl *FD = *I;
-
+ for (const auto *FD : RD->fields()) {
// Empty bitfields don't affect things either way.
// Unlike isSingleElementStruct(), empty structure and array fields
// do count. So do anonymous bitfields that aren't zero-sized.
@@ -4455,7 +5126,7 @@ llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
llvm::Type *IndexTy = RegCount->getType();
llvm::Value *MaxRegsV = llvm::ConstantInt::get(IndexTy, MaxRegs);
llvm::Value *InRegs = CGF.Builder.CreateICmpULT(RegCount, MaxRegsV,
- "fits_in_regs");
+ "fits_in_regs");
llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg");
llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem");
@@ -4521,37 +5192,6 @@ llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
return ResAddr;
}
-bool X86_32TargetCodeGenInfo::isStructReturnInRegABI(
- const llvm::Triple &Triple, const CodeGenOptions &Opts) {
- assert(Triple.getArch() == llvm::Triple::x86);
-
- switch (Opts.getStructReturnConvention()) {
- case CodeGenOptions::SRCK_Default:
- break;
- case CodeGenOptions::SRCK_OnStack: // -fpcc-struct-return
- return false;
- case CodeGenOptions::SRCK_InRegs: // -freg-struct-return
- return true;
- }
-
- if (Triple.isOSDarwin())
- return true;
-
- switch (Triple.getOS()) {
- case llvm::Triple::Cygwin:
- case llvm::Triple::MinGW32:
- case llvm::Triple::AuroraUX:
- case llvm::Triple::DragonFly:
- case llvm::Triple::FreeBSD:
- case llvm::Triple::OpenBSD:
- case llvm::Triple::Bitrig:
- case llvm::Triple::Win32:
- return true;
- default:
- return false;
- }
-}
-
ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const {
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
@@ -4600,7 +5240,7 @@ ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const {
if (isCompoundType(Ty))
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
- return ABIArgInfo::getDirect(0);
+ return ABIArgInfo::getDirect(nullptr);
}
//===----------------------------------------------------------------------===//
@@ -4614,7 +5254,7 @@ public:
MSP430TargetCodeGenInfo(CodeGenTypes &CGT)
: TargetCodeGenInfo(new DefaultABIInfo(CGT)) {}
void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const;
+ CodeGen::CodeGenModule &M) const override;
};
}
@@ -4635,9 +5275,8 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
// Step 3: Emit ISR vector alias.
unsigned Num = attr->getNumber() / 2;
- new llvm::GlobalAlias(GV->getType(), llvm::Function::ExternalLinkage,
- "__isr_" + Twine(Num),
- GV, &M.getModule());
+ llvm::GlobalAlias::create(llvm::Function::ExternalLinkage,
+ "__isr_" + Twine(Num), F);
}
}
}
@@ -4663,9 +5302,9 @@ public:
ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType RetTy, uint64_t &Offset) const;
- virtual void computeInfo(CGFunctionInfo &FI) const;
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
+ void computeInfo(CGFunctionInfo &FI) const override;
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const override;
};
class MIPSTargetCodeGenInfo : public TargetCodeGenInfo {
@@ -4675,12 +5314,12 @@ public:
: TargetCodeGenInfo(new MipsABIInfo(CGT, IsO32)),
SizeOfUnwindException(IsO32 ? 24 : 32) {}
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const {
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override {
return 29;
}
void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &CGM) const {
+ CodeGen::CodeGenModule &CGM) const override {
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
if (!FD) return;
llvm::Function *Fn = cast<llvm::Function>(GV);
@@ -4693,9 +5332,9 @@ public:
}
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const;
+ llvm::Value *Address) const override;
- unsigned getSizeOfUnwindException() const {
+ unsigned getSizeOfUnwindException() const override {
return SizeOfUnwindException;
}
};
@@ -4778,7 +5417,7 @@ llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty, uint64_t TySize) const {
llvm::Type *MipsABIInfo::getPaddingType(uint64_t OrigOffset,
uint64_t Offset) const {
if (OrigOffset + MinABIStackAlignInBytes > Offset)
- return 0;
+ return nullptr;
return llvm::IntegerType::get(getVMContext(), (Offset - OrigOffset) * 8);
}
@@ -4819,7 +5458,7 @@ MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
return ABIArgInfo::getExtend();
return ABIArgInfo::getDirect(
- 0, 0, IsO32 ? 0 : getPaddingType(OrigOffset, CurrOffset));
+ nullptr, 0, IsO32 ? nullptr : getPaddingType(OrigOffset, CurrOffset));
}
llvm::Type*
@@ -4871,9 +5510,6 @@ ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const {
return ABIArgInfo::getIgnore();
if (isAggregateTypeForABI(RetTy) || RetTy->isVectorType()) {
- if (isRecordReturnIndirect(RetTy, getCXXABI()))
- return ABIArgInfo::getIndirect(0);
-
if (Size <= 128) {
if (RetTy->isAnyComplexType())
return ABIArgInfo::getDirect();
@@ -4899,14 +5535,14 @@ ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const {
void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const {
ABIArgInfo &RetInfo = FI.getReturnInfo();
- RetInfo = classifyReturnType(FI.getReturnType());
+ if (!getCXXABI().classifyReturnType(FI))
+ RetInfo = classifyReturnType(FI.getReturnType());
// Check if a pointer to an aggregate is passed as a hidden argument.
uint64_t Offset = RetInfo.isIndirect() ? MinABIStackAlignInBytes : 0;
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it)
- it->info = classifyArgumentType(it->type, Offset);
+ for (auto &I : FI.arguments())
+ I.info = classifyArgumentType(I.type, Offset);
}
llvm::Value* MipsABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
@@ -4987,8 +5623,8 @@ public:
TCETargetCodeGenInfo(CodeGenTypes &CGT)
: DefaultTargetCodeGenInfo(CGT) {}
- virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const;
+ void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const override;
};
void TCETargetCodeGenInfo::SetTargetAttributes(const Decl *D,
@@ -5003,9 +5639,8 @@ void TCETargetCodeGenInfo::SetTargetAttributes(const Decl *D,
if (FD->hasAttr<OpenCLKernelAttr>()) {
// OpenCL C Kernel functions are not subject to inlining
F->addFnAttr(llvm::Attribute::NoInline);
-
- if (FD->hasAttr<ReqdWorkGroupSizeAttr>()) {
-
+ const ReqdWorkGroupSizeAttr *Attr = FD->getAttr<ReqdWorkGroupSizeAttr>();
+ if (Attr) {
// Convert the reqd_work_group_size() attributes to metadata.
llvm::LLVMContext &Context = F->getContext();
llvm::NamedMDNode *OpenCLMetadata =
@@ -5015,14 +5650,11 @@ void TCETargetCodeGenInfo::SetTargetAttributes(const Decl *D,
Operands.push_back(F);
Operands.push_back(llvm::Constant::getIntegerValue(M.Int32Ty,
- llvm::APInt(32,
- FD->getAttr<ReqdWorkGroupSizeAttr>()->getXDim())));
+ llvm::APInt(32, Attr->getXDim())));
Operands.push_back(llvm::Constant::getIntegerValue(M.Int32Ty,
- llvm::APInt(32,
- FD->getAttr<ReqdWorkGroupSizeAttr>()->getYDim())));
+ llvm::APInt(32, Attr->getYDim())));
Operands.push_back(llvm::Constant::getIntegerValue(M.Int32Ty,
- llvm::APInt(32,
- FD->getAttr<ReqdWorkGroupSizeAttr>()->getZDim())));
+ llvm::APInt(32, Attr->getZDim())));
// Add a boolean constant operand for "required" (true) or "hint" (false)
// for implementing the work_group_size_hint attr later. Currently
@@ -5053,10 +5685,10 @@ private:
ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType RetTy) const;
- virtual void computeInfo(CGFunctionInfo &FI) const;
+ void computeInfo(CGFunctionInfo &FI) const override;
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const override;
};
class HexagonTargetCodeGenInfo : public TargetCodeGenInfo {
@@ -5064,7 +5696,7 @@ public:
HexagonTargetCodeGenInfo(CodeGenTypes &CGT)
:TargetCodeGenInfo(new HexagonABIInfo(CGT)) {}
- int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
return 29;
}
};
@@ -5072,10 +5704,10 @@ public:
}
void HexagonABIInfo::computeInfo(CGFunctionInfo &FI) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it)
- it->info = classifyArgumentType(it->type);
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ for (auto &I : FI.arguments())
+ I.info = classifyArgumentType(I.type);
}
ABIArgInfo HexagonABIInfo::classifyArgumentType(QualType Ty) const {
@@ -5126,11 +5758,6 @@ ABIArgInfo HexagonABIInfo::classifyReturnType(QualType RetTy) const {
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
- // Structures with either a non-trivial destructor or a non-trivial
- // copy constructor are always indirect.
- if (isRecordReturnIndirect(RetTy, getCXXABI()))
- return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
-
if (isEmptyRecord(getContext(), RetTy, true))
return ABIArgInfo::getIgnore();
@@ -5208,9 +5835,9 @@ public:
private:
ABIArgInfo classifyType(QualType RetTy, unsigned SizeLimit) const;
- virtual void computeInfo(CGFunctionInfo &FI) const;
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
+ void computeInfo(CGFunctionInfo &FI) const override;
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const override;
// Coercion type builder for structs passed in registers. The coercion type
// serves two purposes:
@@ -5349,6 +5976,11 @@ SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const {
if (!isAggregateTypeForABI(Ty))
return ABIArgInfo::getDirect();
+ // If a C++ object has either a non-trivial copy constructor or a non-trivial
+ // destructor, it is passed with an explicit indirect pointer / sret pointer.
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
+ return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
+
// This is a small aggregate type that should be passed in registers.
// Build a coercion type from the LLVM struct type.
llvm::StructType *StrTy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty));
@@ -5385,6 +6017,7 @@ llvm::Value *SparcV9ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
switch (AI.getKind()) {
case ABIArgInfo::Expand:
+ case ABIArgInfo::InAlloca:
llvm_unreachable("Unsupported ABI kind for va_arg");
case ABIArgInfo::Extend:
@@ -5420,9 +6053,8 @@ llvm::Value *SparcV9ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
void SparcV9ABIInfo::computeInfo(CGFunctionInfo &FI) const {
FI.getReturnInfo() = classifyType(FI.getReturnType(), 32 * 8);
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it)
- it->info = classifyType(it->type, 16 * 8);
+ for (auto &I : FI.arguments())
+ I.info = classifyType(I.type, 16 * 8);
}
namespace {
@@ -5430,26 +6062,165 @@ class SparcV9TargetCodeGenInfo : public TargetCodeGenInfo {
public:
SparcV9TargetCodeGenInfo(CodeGenTypes &CGT)
: TargetCodeGenInfo(new SparcV9ABIInfo(CGT)) {}
+
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
+ return 14;
+ }
+
+ bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const override;
};
} // end anonymous namespace
+bool
+SparcV9TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const {
+ // This is calculated from the LLVM and GCC tables and verified
+ // against gcc output. AFAIK all ABIs use the same encoding.
+
+ CodeGen::CGBuilderTy &Builder = CGF.Builder;
+
+ llvm::IntegerType *i8 = CGF.Int8Ty;
+ llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
+ llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8);
+
+ // 0-31: the 8-byte general-purpose registers
+ AssignToArrayRange(Builder, Address, Eight8, 0, 31);
+
+ // 32-63: f0-31, the 4-byte floating-point registers
+ AssignToArrayRange(Builder, Address, Four8, 32, 63);
+
+ // Y = 64
+ // PSR = 65
+ // WIM = 66
+ // TBR = 67
+ // PC = 68
+ // NPC = 69
+ // FSR = 70
+ // CSR = 71
+ AssignToArrayRange(Builder, Address, Eight8, 64, 71);
+
+ // 72-87: d0-15, the 8-byte floating-point registers
+ AssignToArrayRange(Builder, Address, Eight8, 72, 87);
+
+ return false;
+}
+
//===----------------------------------------------------------------------===//
-// Xcore ABI Implementation
+// XCore ABI Implementation
//===----------------------------------------------------------------------===//
+
namespace {
+
+/// A SmallStringEnc instance is used to build up the TypeString by passing
+/// it by reference between functions that append to it.
+typedef llvm::SmallString<128> SmallStringEnc;
+
+/// TypeStringCache caches the meta encodings of Types.
+///
+/// The reason for caching TypeStrings is two fold:
+/// 1. To cache a type's encoding for later uses;
+/// 2. As a means to break recursive member type inclusion.
+///
+/// A cache Entry can have a Status of:
+/// NonRecursive: The type encoding is not recursive;
+/// Recursive: The type encoding is recursive;
+/// Incomplete: An incomplete TypeString;
+/// IncompleteUsed: An incomplete TypeString that has been used in a
+/// Recursive type encoding.
+///
+/// A NonRecursive entry will have all of its sub-members expanded as fully
+/// as possible. Whilst it may contain types which are recursive, the type
+/// itself is not recursive and thus its encoding may be safely used whenever
+/// the type is encountered.
+///
+/// A Recursive entry will have all of its sub-members expanded as fully as
+/// possible. The type itself is recursive and it may contain other types which
+/// are recursive. The Recursive encoding must not be used during the expansion
+/// of a recursive type's recursive branch. For simplicity the code uses
+/// IncompleteCount to reject all usage of Recursive encodings for member types.
+///
+/// An Incomplete entry is always a RecordType and only encodes its
+/// identifier e.g. "s(S){}". Incomplete 'StubEnc' entries are ephemeral and
+/// are placed into the cache during type expansion as a means to identify and
+/// handle recursive inclusion of types as sub-members. If there is recursion
+/// the entry becomes IncompleteUsed.
+///
+/// During the expansion of a RecordType's members:
+///
+/// If the cache contains a NonRecursive encoding for the member type, the
+/// cached encoding is used;
+///
+/// If the cache contains a Recursive encoding for the member type, the
+/// cached encoding is 'Swapped' out, as it may be incorrect, and...
+///
+/// If the member is a RecordType, an Incomplete encoding is placed into the
+/// cache to break potential recursive inclusion of itself as a sub-member;
+///
+/// Once a member RecordType has been expanded, its temporary incomplete
+/// entry is removed from the cache. If a Recursive encoding was swapped out
+/// it is swapped back in;
+///
+/// If an incomplete entry is used to expand a sub-member, the incomplete
+/// entry is marked as IncompleteUsed. The cache keeps count of how many
+/// IncompleteUsed entries it currently contains in IncompleteUsedCount;
+///
+/// If a member's encoding is found to be a NonRecursive or Recursive viz:
+/// IncompleteUsedCount==0, the member's encoding is added to the cache.
+/// Else the member is part of a recursive type and thus the recursion has
+/// been exited too soon for the encoding to be correct for the member.
+///
+class TypeStringCache {
+ enum Status {NonRecursive, Recursive, Incomplete, IncompleteUsed};
+ struct Entry {
+ std::string Str; // The encoded TypeString for the type.
+ enum Status State; // Information about the encoding in 'Str'.
+ std::string Swapped; // A temporary place holder for a Recursive encoding
+ // during the expansion of RecordType's members.
+ };
+ std::map<const IdentifierInfo *, struct Entry> Map;
+ unsigned IncompleteCount; // Number of Incomplete entries in the Map.
+ unsigned IncompleteUsedCount; // Number of IncompleteUsed entries in the Map.
+public:
+ TypeStringCache() : IncompleteCount(0), IncompleteUsedCount(0) {};
+ void addIncomplete(const IdentifierInfo *ID, std::string StubEnc);
+ bool removeIncomplete(const IdentifierInfo *ID);
+ void addIfComplete(const IdentifierInfo *ID, StringRef Str,
+ bool IsRecursive);
+ StringRef lookupStr(const IdentifierInfo *ID);
+};
+
+/// TypeString encodings for enum & union fields must be order.
+/// FieldEncoding is a helper for this ordering process.
+class FieldEncoding {
+ bool HasName;
+ std::string Enc;
+public:
+ FieldEncoding(bool b, SmallStringEnc &e) : HasName(b), Enc(e.c_str()) {};
+ StringRef str() {return Enc.c_str();};
+ bool operator<(const FieldEncoding &rhs) const {
+ if (HasName != rhs.HasName) return HasName;
+ return Enc < rhs.Enc;
+ }
+};
+
class XCoreABIInfo : public DefaultABIInfo {
public:
XCoreABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
+ llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const override;
};
-class XcoreTargetCodeGenInfo : public TargetCodeGenInfo {
+class XCoreTargetCodeGenInfo : public TargetCodeGenInfo {
+ mutable TypeStringCache TSC;
public:
- XcoreTargetCodeGenInfo(CodeGenTypes &CGT)
+ XCoreTargetCodeGenInfo(CodeGenTypes &CGT)
:TargetCodeGenInfo(new XCoreABIInfo(CGT)) {}
+ void emitTargetMD(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const override;
};
+
} // End anonymous namespace.
llvm::Value *XCoreABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
@@ -5471,6 +6242,7 @@ llvm::Value *XCoreABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
uint64_t ArgSize = 0;
switch (AI.getKind()) {
case ABIArgInfo::Expand:
+ case ABIArgInfo::InAlloca:
llvm_unreachable("Unsupported ABI kind for va_arg");
case ABIArgInfo::Ignore:
Val = llvm::UndefValue::get(ArgPtrTy);
@@ -5500,6 +6272,461 @@ llvm::Value *XCoreABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
return Val;
}
+/// During the expansion of a RecordType, an incomplete TypeString is placed
+/// into the cache as a means to identify and break recursion.
+/// If there is a Recursive encoding in the cache, it is swapped out and will
+/// be reinserted by removeIncomplete().
+/// All other types of encoding should have been used rather than arriving here.
+void TypeStringCache::addIncomplete(const IdentifierInfo *ID,
+ std::string StubEnc) {
+ if (!ID)
+ return;
+ Entry &E = Map[ID];
+ assert( (E.Str.empty() || E.State == Recursive) &&
+ "Incorrectly use of addIncomplete");
+ assert(!StubEnc.empty() && "Passing an empty string to addIncomplete()");
+ E.Swapped.swap(E.Str); // swap out the Recursive
+ E.Str.swap(StubEnc);
+ E.State = Incomplete;
+ ++IncompleteCount;
+}
+
+/// Once the RecordType has been expanded, the temporary incomplete TypeString
+/// must be removed from the cache.
+/// If a Recursive was swapped out by addIncomplete(), it will be replaced.
+/// Returns true if the RecordType was defined recursively.
+bool TypeStringCache::removeIncomplete(const IdentifierInfo *ID) {
+ if (!ID)
+ return false;
+ auto I = Map.find(ID);
+ assert(I != Map.end() && "Entry not present");
+ Entry &E = I->second;
+ assert( (E.State == Incomplete ||
+ E.State == IncompleteUsed) &&
+ "Entry must be an incomplete type");
+ bool IsRecursive = false;
+ if (E.State == IncompleteUsed) {
+ // We made use of our Incomplete encoding, thus we are recursive.
+ IsRecursive = true;
+ --IncompleteUsedCount;
+ }
+ if (E.Swapped.empty())
+ Map.erase(I);
+ else {
+ // Swap the Recursive back.
+ E.Swapped.swap(E.Str);
+ E.Swapped.clear();
+ E.State = Recursive;
+ }
+ --IncompleteCount;
+ return IsRecursive;
+}
+
+/// Add the encoded TypeString to the cache only if it is NonRecursive or
+/// Recursive (viz: all sub-members were expanded as fully as possible).
+void TypeStringCache::addIfComplete(const IdentifierInfo *ID, StringRef Str,
+ bool IsRecursive) {
+ if (!ID || IncompleteUsedCount)
+ return; // No key or it is is an incomplete sub-type so don't add.
+ Entry &E = Map[ID];
+ if (IsRecursive && !E.Str.empty()) {
+ assert(E.State==Recursive && E.Str.size() == Str.size() &&
+ "This is not the same Recursive entry");
+ // The parent container was not recursive after all, so we could have used
+ // this Recursive sub-member entry after all, but we assumed the worse when
+ // we started viz: IncompleteCount!=0.
+ return;
+ }
+ assert(E.Str.empty() && "Entry already present");
+ E.Str = Str.str();
+ E.State = IsRecursive? Recursive : NonRecursive;
+}
+
+/// Return a cached TypeString encoding for the ID. If there isn't one, or we
+/// are recursively expanding a type (IncompleteCount != 0) and the cached
+/// encoding is Recursive, return an empty StringRef.
+StringRef TypeStringCache::lookupStr(const IdentifierInfo *ID) {
+ if (!ID)
+ return StringRef(); // We have no key.
+ auto I = Map.find(ID);
+ if (I == Map.end())
+ return StringRef(); // We have no encoding.
+ Entry &E = I->second;
+ if (E.State == Recursive && IncompleteCount)
+ return StringRef(); // We don't use Recursive encodings for member types.
+
+ if (E.State == Incomplete) {
+ // The incomplete type is being used to break out of recursion.
+ E.State = IncompleteUsed;
+ ++IncompleteUsedCount;
+ }
+ return E.Str.c_str();
+}
+
+/// The XCore ABI includes a type information section that communicates symbol
+/// type information to the linker. The linker uses this information to verify
+/// safety/correctness of things such as array bound and pointers et al.
+/// The ABI only requires C (and XC) language modules to emit TypeStrings.
+/// This type information (TypeString) is emitted into meta data for all global
+/// symbols: definitions, declarations, functions & variables.
+///
+/// The TypeString carries type, qualifier, name, size & value details.
+/// Please see 'Tools Development Guide' section 2.16.2 for format details:
+/// <https://www.xmos.com/download/public/Tools-Development-Guide%28X9114A%29.pdf>
+/// The output is tested by test/CodeGen/xcore-stringtype.c.
+///
+static bool getTypeString(SmallStringEnc &Enc, const Decl *D,
+ CodeGen::CodeGenModule &CGM, TypeStringCache &TSC);
+
+/// XCore uses emitTargetMD to emit TypeString metadata for global symbols.
+void XCoreTargetCodeGenInfo::emitTargetMD(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &CGM) const {
+ SmallStringEnc Enc;
+ if (getTypeString(Enc, D, CGM, TSC)) {
+ llvm::LLVMContext &Ctx = CGM.getModule().getContext();
+ llvm::SmallVector<llvm::Value *, 2> MDVals;
+ MDVals.push_back(GV);
+ MDVals.push_back(llvm::MDString::get(Ctx, Enc.str()));
+ llvm::NamedMDNode *MD =
+ CGM.getModule().getOrInsertNamedMetadata("xcore.typestrings");
+ MD->addOperand(llvm::MDNode::get(Ctx, MDVals));
+ }
+}
+
+static bool appendType(SmallStringEnc &Enc, QualType QType,
+ const CodeGen::CodeGenModule &CGM,
+ TypeStringCache &TSC);
+
+/// Helper function for appendRecordType().
+/// Builds a SmallVector containing the encoded field types in declaration order.
+static bool extractFieldType(SmallVectorImpl<FieldEncoding> &FE,
+ const RecordDecl *RD,
+ const CodeGen::CodeGenModule &CGM,
+ TypeStringCache &TSC) {
+ for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ I != E; ++I) {
+ SmallStringEnc Enc;
+ Enc += "m(";
+ Enc += I->getName();
+ Enc += "){";
+ if (I->isBitField()) {
+ Enc += "b(";
+ llvm::raw_svector_ostream OS(Enc);
+ OS.resync();
+ OS << I->getBitWidthValue(CGM.getContext());
+ OS.flush();
+ Enc += ':';
+ }
+ if (!appendType(Enc, I->getType(), CGM, TSC))
+ return false;
+ if (I->isBitField())
+ Enc += ')';
+ Enc += '}';
+ FE.push_back(FieldEncoding(!I->getName().empty(), Enc));
+ }
+ return true;
+}
+
+/// Appends structure and union types to Enc and adds encoding to cache.
+/// Recursively calls appendType (via extractFieldType) for each field.
+/// Union types have their fields ordered according to the ABI.
+static bool appendRecordType(SmallStringEnc &Enc, const RecordType *RT,
+ const CodeGen::CodeGenModule &CGM,
+ TypeStringCache &TSC, const IdentifierInfo *ID) {
+ // Append the cached TypeString if we have one.
+ StringRef TypeString = TSC.lookupStr(ID);
+ if (!TypeString.empty()) {
+ Enc += TypeString;
+ return true;
+ }
+
+ // Start to emit an incomplete TypeString.
+ size_t Start = Enc.size();
+ Enc += (RT->isUnionType()? 'u' : 's');
+ Enc += '(';
+ if (ID)
+ Enc += ID->getName();
+ Enc += "){";
+
+ // We collect all encoded fields and order as necessary.
+ bool IsRecursive = false;
+ const RecordDecl *RD = RT->getDecl()->getDefinition();
+ if (RD && !RD->field_empty()) {
+ // An incomplete TypeString stub is placed in the cache for this RecordType
+ // so that recursive calls to this RecordType will use it whilst building a
+ // complete TypeString for this RecordType.
+ SmallVector<FieldEncoding, 16> FE;
+ std::string StubEnc(Enc.substr(Start).str());
+ StubEnc += '}'; // StubEnc now holds a valid incomplete TypeString.
+ TSC.addIncomplete(ID, std::move(StubEnc));
+ if (!extractFieldType(FE, RD, CGM, TSC)) {
+ (void) TSC.removeIncomplete(ID);
+ return false;
+ }
+ IsRecursive = TSC.removeIncomplete(ID);
+ // The ABI requires unions to be sorted but not structures.
+ // See FieldEncoding::operator< for sort algorithm.
+ if (RT->isUnionType())
+ std::sort(FE.begin(), FE.end());
+ // We can now complete the TypeString.
+ unsigned E = FE.size();
+ for (unsigned I = 0; I != E; ++I) {
+ if (I)
+ Enc += ',';
+ Enc += FE[I].str();
+ }
+ }
+ Enc += '}';
+ TSC.addIfComplete(ID, Enc.substr(Start), IsRecursive);
+ return true;
+}
+
+/// Appends enum types to Enc and adds the encoding to the cache.
+static bool appendEnumType(SmallStringEnc &Enc, const EnumType *ET,
+ TypeStringCache &TSC,
+ const IdentifierInfo *ID) {
+ // Append the cached TypeString if we have one.
+ StringRef TypeString = TSC.lookupStr(ID);
+ if (!TypeString.empty()) {
+ Enc += TypeString;
+ return true;
+ }
+
+ size_t Start = Enc.size();
+ Enc += "e(";
+ if (ID)
+ Enc += ID->getName();
+ Enc += "){";
+
+ // We collect all encoded enumerations and order them alphanumerically.
+ if (const EnumDecl *ED = ET->getDecl()->getDefinition()) {
+ SmallVector<FieldEncoding, 16> FE;
+ for (auto I = ED->enumerator_begin(), E = ED->enumerator_end(); I != E;
+ ++I) {
+ SmallStringEnc EnumEnc;
+ EnumEnc += "m(";
+ EnumEnc += I->getName();
+ EnumEnc += "){";
+ I->getInitVal().toString(EnumEnc);
+ EnumEnc += '}';
+ FE.push_back(FieldEncoding(!I->getName().empty(), EnumEnc));
+ }
+ std::sort(FE.begin(), FE.end());
+ unsigned E = FE.size();
+ for (unsigned I = 0; I != E; ++I) {
+ if (I)
+ Enc += ',';
+ Enc += FE[I].str();
+ }
+ }
+ Enc += '}';
+ TSC.addIfComplete(ID, Enc.substr(Start), false);
+ return true;
+}
+
+/// Appends type's qualifier to Enc.
+/// This is done prior to appending the type's encoding.
+static void appendQualifier(SmallStringEnc &Enc, QualType QT) {
+ // Qualifiers are emitted in alphabetical order.
+ static const char *Table[] = {"","c:","r:","cr:","v:","cv:","rv:","crv:"};
+ int Lookup = 0;
+ if (QT.isConstQualified())
+ Lookup += 1<<0;
+ if (QT.isRestrictQualified())
+ Lookup += 1<<1;
+ if (QT.isVolatileQualified())
+ Lookup += 1<<2;
+ Enc += Table[Lookup];
+}
+
+/// Appends built-in types to Enc.
+static bool appendBuiltinType(SmallStringEnc &Enc, const BuiltinType *BT) {
+ const char *EncType;
+ switch (BT->getKind()) {
+ case BuiltinType::Void:
+ EncType = "0";
+ break;
+ case BuiltinType::Bool:
+ EncType = "b";
+ break;
+ case BuiltinType::Char_U:
+ EncType = "uc";
+ break;
+ case BuiltinType::UChar:
+ EncType = "uc";
+ break;
+ case BuiltinType::SChar:
+ EncType = "sc";
+ break;
+ case BuiltinType::UShort:
+ EncType = "us";
+ break;
+ case BuiltinType::Short:
+ EncType = "ss";
+ break;
+ case BuiltinType::UInt:
+ EncType = "ui";
+ break;
+ case BuiltinType::Int:
+ EncType = "si";
+ break;
+ case BuiltinType::ULong:
+ EncType = "ul";
+ break;
+ case BuiltinType::Long:
+ EncType = "sl";
+ break;
+ case BuiltinType::ULongLong:
+ EncType = "ull";
+ break;
+ case BuiltinType::LongLong:
+ EncType = "sll";
+ break;
+ case BuiltinType::Float:
+ EncType = "ft";
+ break;
+ case BuiltinType::Double:
+ EncType = "d";
+ break;
+ case BuiltinType::LongDouble:
+ EncType = "ld";
+ break;
+ default:
+ return false;
+ }
+ Enc += EncType;
+ return true;
+}
+
+/// Appends a pointer encoding to Enc before calling appendType for the pointee.
+static bool appendPointerType(SmallStringEnc &Enc, const PointerType *PT,
+ const CodeGen::CodeGenModule &CGM,
+ TypeStringCache &TSC) {
+ Enc += "p(";
+ if (!appendType(Enc, PT->getPointeeType(), CGM, TSC))
+ return false;
+ Enc += ')';
+ return true;
+}
+
+/// Appends array encoding to Enc before calling appendType for the element.
+static bool appendArrayType(SmallStringEnc &Enc, QualType QT,
+ const ArrayType *AT,
+ const CodeGen::CodeGenModule &CGM,
+ TypeStringCache &TSC, StringRef NoSizeEnc) {
+ if (AT->getSizeModifier() != ArrayType::Normal)
+ return false;
+ Enc += "a(";
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
+ CAT->getSize().toStringUnsigned(Enc);
+ else
+ Enc += NoSizeEnc; // Global arrays use "*", otherwise it is "".
+ Enc += ':';
+ // The Qualifiers should be attached to the type rather than the array.
+ appendQualifier(Enc, QT);
+ if (!appendType(Enc, AT->getElementType(), CGM, TSC))
+ return false;
+ Enc += ')';
+ return true;
+}
+
+/// Appends a function encoding to Enc, calling appendType for the return type
+/// and the arguments.
+static bool appendFunctionType(SmallStringEnc &Enc, const FunctionType *FT,
+ const CodeGen::CodeGenModule &CGM,
+ TypeStringCache &TSC) {
+ Enc += "f{";
+ if (!appendType(Enc, FT->getReturnType(), CGM, TSC))
+ return false;
+ Enc += "}(";
+ if (const FunctionProtoType *FPT = FT->getAs<FunctionProtoType>()) {
+ // N.B. we are only interested in the adjusted param types.
+ auto I = FPT->param_type_begin();
+ auto E = FPT->param_type_end();
+ if (I != E) {
+ do {
+ if (!appendType(Enc, *I, CGM, TSC))
+ return false;
+ ++I;
+ if (I != E)
+ Enc += ',';
+ } while (I != E);
+ if (FPT->isVariadic())
+ Enc += ",va";
+ } else {
+ if (FPT->isVariadic())
+ Enc += "va";
+ else
+ Enc += '0';
+ }
+ }
+ Enc += ')';
+ return true;
+}
+
+/// Handles the type's qualifier before dispatching a call to handle specific
+/// type encodings.
+static bool appendType(SmallStringEnc &Enc, QualType QType,
+ const CodeGen::CodeGenModule &CGM,
+ TypeStringCache &TSC) {
+
+ QualType QT = QType.getCanonicalType();
+
+ if (const ArrayType *AT = QT->getAsArrayTypeUnsafe())
+ // The Qualifiers should be attached to the type rather than the array.
+ // Thus we don't call appendQualifier() here.
+ return appendArrayType(Enc, QT, AT, CGM, TSC, "");
+
+ appendQualifier(Enc, QT);
+
+ if (const BuiltinType *BT = QT->getAs<BuiltinType>())
+ return appendBuiltinType(Enc, BT);
+
+ if (const PointerType *PT = QT->getAs<PointerType>())
+ return appendPointerType(Enc, PT, CGM, TSC);
+
+ if (const EnumType *ET = QT->getAs<EnumType>())
+ return appendEnumType(Enc, ET, TSC, QT.getBaseTypeIdentifier());
+
+ if (const RecordType *RT = QT->getAsStructureType())
+ return appendRecordType(Enc, RT, CGM, TSC, QT.getBaseTypeIdentifier());
+
+ if (const RecordType *RT = QT->getAsUnionType())
+ return appendRecordType(Enc, RT, CGM, TSC, QT.getBaseTypeIdentifier());
+
+ if (const FunctionType *FT = QT->getAs<FunctionType>())
+ return appendFunctionType(Enc, FT, CGM, TSC);
+
+ return false;
+}
+
+static bool getTypeString(SmallStringEnc &Enc, const Decl *D,
+ CodeGen::CodeGenModule &CGM, TypeStringCache &TSC) {
+ if (!D)
+ return false;
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->getLanguageLinkage() != CLanguageLinkage)
+ return false;
+ return appendType(Enc, FD->getType(), CGM, TSC);
+ }
+
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (VD->getLanguageLinkage() != CLanguageLinkage)
+ return false;
+ QualType QT = VD->getType().getCanonicalType();
+ if (const ArrayType *AT = QT->getAsArrayTypeUnsafe()) {
+ // Global ArrayTypes are given a size of '*' if the size is unknown.
+ // The Qualifiers should be attached to the type rather than the array.
+ // Thus we don't call appendQualifier() here.
+ return appendArrayType(Enc, QT, AT, CGM, TSC, "*");
+ }
+ return appendType(Enc, QT, CGM, TSC);
+ }
+ return false;
+}
+
+
//===----------------------------------------------------------------------===//
// Driver code
//===----------------------------------------------------------------------===//
@@ -5524,13 +6751,23 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, false));
case llvm::Triple::aarch64:
- return *(TheTargetCodeGenInfo = new AArch64TargetCodeGenInfo(Types));
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm64:
+ case llvm::Triple::arm64_be: {
+ AArch64ABIInfo::ABIKind Kind = AArch64ABIInfo::AAPCS;
+ if (getTarget().getABI() == "darwinpcs")
+ Kind = AArch64ABIInfo::DarwinPCS;
+
+ return *(TheTargetCodeGenInfo = new AArch64TargetCodeGenInfo(Types, Kind));
+ }
case llvm::Triple::arm:
+ case llvm::Triple::armeb:
case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
{
ARMABIInfo::ABIKind Kind = ARMABIInfo::AAPCS;
- if (strcmp(getTarget().getABI(), "apcs-gnu") == 0)
+ if (getTarget().getABI() == "apcs-gnu")
Kind = ARMABIInfo::APCS;
else if (CodeGenOpts.FloatABI == "hard" ||
(CodeGenOpts.FloatABI != "soft" &&
@@ -5550,13 +6787,20 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::ppc:
return *(TheTargetCodeGenInfo = new PPC32TargetCodeGenInfo(Types));
case llvm::Triple::ppc64:
- if (Triple.isOSBinFormatELF())
- return *(TheTargetCodeGenInfo = new PPC64_SVR4_TargetCodeGenInfo(Types));
- else
+ if (Triple.isOSBinFormatELF()) {
+ // FIXME: Should be switchable via command-line option.
+ PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv1;
+ return *(TheTargetCodeGenInfo =
+ new PPC64_SVR4_TargetCodeGenInfo(Types, Kind));
+ } else
return *(TheTargetCodeGenInfo = new PPC64TargetCodeGenInfo(Types));
- case llvm::Triple::ppc64le:
+ case llvm::Triple::ppc64le: {
assert(Triple.isOSBinFormatELF() && "PPC64 LE non-ELF not supported!");
- return *(TheTargetCodeGenInfo = new PPC64_SVR4_TargetCodeGenInfo(Types));
+ // FIXME: Should be switchable via command-line option.
+ PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv2;
+ return *(TheTargetCodeGenInfo =
+ new PPC64_SVR4_TargetCodeGenInfo(Types, Kind));
+ }
case llvm::Triple::nvptx:
case llvm::Triple::nvptx64:
@@ -5575,7 +6819,7 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
bool IsDarwinVectorABI = Triple.isOSDarwin();
bool IsSmallStructInRegABI =
X86_32TargetCodeGenInfo::isStructReturnInRegABI(Triple, CodeGenOpts);
- bool IsWin32FloatStructABI = (Triple.getOS() == llvm::Triple::Win32);
+ bool IsWin32FloatStructABI = Triple.isWindowsMSVCEnvironment();
if (Triple.getOS() == llvm::Triple::Win32) {
return *(TheTargetCodeGenInfo =
@@ -5593,12 +6837,10 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
}
case llvm::Triple::x86_64: {
- bool HasAVX = strcmp(getTarget().getABI(), "avx") == 0;
+ bool HasAVX = getTarget().getABI() == "avx";
switch (Triple.getOS()) {
case llvm::Triple::Win32:
- case llvm::Triple::MinGW32:
- case llvm::Triple::Cygwin:
return *(TheTargetCodeGenInfo = new WinX86_64TargetCodeGenInfo(Types));
case llvm::Triple::NaCl:
return *(TheTargetCodeGenInfo = new NaClX86_64TargetCodeGenInfo(Types,
@@ -5613,7 +6855,6 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::sparcv9:
return *(TheTargetCodeGenInfo = new SparcV9TargetCodeGenInfo(Types));
case llvm::Triple::xcore:
- return *(TheTargetCodeGenInfo = new XcoreTargetCodeGenInfo(Types));
-
+ return *(TheTargetCodeGenInfo = new XCoreTargetCodeGenInfo(Types));
}
}
diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h
index f631f3102d0d..2616820185f5 100644
--- a/lib/CodeGen/TargetInfo.h
+++ b/lib/CodeGen/TargetInfo.h
@@ -17,189 +17,199 @@
#include "clang/AST/Type.h"
#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
namespace llvm {
- class Constant;
- class GlobalValue;
- class Type;
- class Value;
+class Constant;
+class GlobalValue;
+class Type;
+class Value;
}
namespace clang {
- class ABIInfo;
- class Decl;
-
- namespace CodeGen {
- class CallArgList;
- class CodeGenModule;
- class CodeGenFunction;
- class CGFunctionInfo;
+class ABIInfo;
+class Decl;
+
+namespace CodeGen {
+class CallArgList;
+class CodeGenModule;
+class CodeGenFunction;
+class CGFunctionInfo;
+}
+
+/// TargetCodeGenInfo - This class organizes various target-specific
+/// codegeneration issues, like target-specific attributes, builtins and so
+/// on.
+class TargetCodeGenInfo {
+ ABIInfo *Info;
+
+public:
+ // WARNING: Acquires the ownership of ABIInfo.
+ TargetCodeGenInfo(ABIInfo *info = 0) : Info(info) {}
+ virtual ~TargetCodeGenInfo();
+
+ /// getABIInfo() - Returns ABI info helper for the target.
+ const ABIInfo &getABIInfo() const { return *Info; }
+
+ /// SetTargetAttributes - Provides a convenient hook to handle extra
+ /// target-specific attributes for the given global.
+ virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const {}
+
+ /// EmitTargetMD - Provides a convenient hook to handle extra
+ /// target-specific metadata for the given global.
+ virtual void emitTargetMD(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const {}
+
+ /// Determines the size of struct _Unwind_Exception on this platform,
+ /// in 8-bit units. The Itanium ABI defines this as:
+ /// struct _Unwind_Exception {
+ /// uint64 exception_class;
+ /// _Unwind_Exception_Cleanup_Fn exception_cleanup;
+ /// uint64 private_1;
+ /// uint64 private_2;
+ /// };
+ virtual unsigned getSizeOfUnwindException() const;
+
+ /// Controls whether __builtin_extend_pointer should sign-extend
+ /// pointers to uint64_t or zero-extend them (the default). Has
+ /// no effect for targets:
+ /// - that have 64-bit pointers, or
+ /// - that cannot address through registers larger than pointers, or
+ /// - that implicitly ignore/truncate the top bits when addressing
+ /// through such registers.
+ virtual bool extendPointerWithSExt() const { return false; }
+
+ /// Determines the DWARF register number for the stack pointer, for
+ /// exception-handling purposes. Implements __builtin_dwarf_sp_column.
+ ///
+ /// Returns -1 if the operation is unsupported by this target.
+ virtual int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
+ return -1;
+ }
+
+ /// Initializes the given DWARF EH register-size table, a char*.
+ /// Implements __builtin_init_dwarf_reg_size_table.
+ ///
+ /// Returns true if the operation is unsupported by this target.
+ virtual bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const {
+ return true;
+ }
+
+ /// Performs the code-generation required to convert a return
+ /// address as stored by the system into the actual address of the
+ /// next instruction that will be executed.
+ ///
+ /// Used by __builtin_extract_return_addr().
+ virtual llvm::Value *decodeReturnAddress(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const {
+ return Address;
+ }
+
+ /// Performs the code-generation required to convert the address
+ /// of an instruction into a return address suitable for storage
+ /// by the system in a return slot.
+ ///
+ /// Used by __builtin_frob_return_addr().
+ virtual llvm::Value *encodeReturnAddress(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const {
+ return Address;
+ }
+
+ /// Corrects the low-level LLVM type for a given constraint and "usual"
+ /// type.
+ ///
+ /// \returns A pointer to a new LLVM type, possibly the same as the original
+ /// on success; 0 on failure.
+ virtual llvm::Type *adjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
+ StringRef Constraint,
+ llvm::Type *Ty) const {
+ return Ty;
+ }
+
+ /// doesReturnSlotInterfereWithArgs - Return true if the target uses an
+ /// argument slot for an 'sret' type.
+ virtual bool doesReturnSlotInterfereWithArgs() const { return true; }
+
+ /// 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 StringRef getARCRetainAutoreleasedReturnValueMarker() const {
+ return "";
+ }
+
+ /// Return a constant used by UBSan as a signature to identify functions
+ /// possessing type information, or 0 if the platform is unsupported.
+ virtual llvm::Constant *
+ getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const {
+ return nullptr;
}
- /// TargetCodeGenInfo - This class organizes various target-specific
- /// codegeneration issues, like target-specific attributes, builtins and so
- /// on.
- class TargetCodeGenInfo {
- ABIInfo *Info;
- public:
- // WARNING: Acquires the ownership of ABIInfo.
- TargetCodeGenInfo(ABIInfo *info = 0):Info(info) { }
- virtual ~TargetCodeGenInfo();
-
- /// getABIInfo() - Returns ABI info helper for the target.
- const ABIInfo& getABIInfo() const { return *Info; }
-
- /// SetTargetAttributes - Provides a convenient hook to handle extra
- /// target-specific attributes for the given global.
- virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const { }
-
- /// Determines the size of struct _Unwind_Exception on this platform,
- /// in 8-bit units. The Itanium ABI defines this as:
- /// struct _Unwind_Exception {
- /// uint64 exception_class;
- /// _Unwind_Exception_Cleanup_Fn exception_cleanup;
- /// uint64 private_1;
- /// uint64 private_2;
- /// };
- virtual unsigned getSizeOfUnwindException() const;
-
- /// Controls whether __builtin_extend_pointer should sign-extend
- /// pointers to uint64_t or zero-extend them (the default). Has
- /// no effect for targets:
- /// - that have 64-bit pointers, or
- /// - that cannot address through registers larger than pointers, or
- /// - that implicitly ignore/truncate the top bits when addressing
- /// through such registers.
- virtual bool extendPointerWithSExt() const { return false; }
-
- /// Determines the DWARF register number for the stack pointer, for
- /// exception-handling purposes. Implements __builtin_dwarf_sp_column.
- ///
- /// Returns -1 if the operation is unsupported by this target.
- virtual int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
- return -1;
- }
-
- /// Initializes the given DWARF EH register-size table, a char*.
- /// Implements __builtin_init_dwarf_reg_size_table.
- ///
- /// Returns true if the operation is unsupported by this target.
- virtual bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
- return true;
- }
-
- /// Performs the code-generation required to convert a return
- /// address as stored by the system into the actual address of the
- /// next instruction that will be executed.
- ///
- /// Used by __builtin_extract_return_addr().
- virtual llvm::Value *decodeReturnAddress(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
- return Address;
- }
-
- /// Performs the code-generation required to convert the address
- /// of an instruction into a return address suitable for storage
- /// by the system in a return slot.
- ///
- /// Used by __builtin_frob_return_addr().
- virtual llvm::Value *encodeReturnAddress(CodeGen::CodeGenFunction &CGF,
- llvm::Value *Address) const {
- return Address;
- }
-
- /// Corrects the low-level LLVM type for a given constraint and "usual"
- /// type.
- ///
- /// \returns A pointer to a new LLVM type, possibly the same as the original
- /// on success; 0 on failure.
- virtual llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
- 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 StringRef getARCRetainAutoreleasedReturnValueMarker() const {
- return "";
- }
-
- /// Return a constant used by UBSan as a signature to identify functions
- /// possessing type information, or 0 if the platform is unsupported.
- virtual llvm::Constant *getUBSanFunctionSignature(
- CodeGen::CodeGenModule &CGM) const {
- return 0;
- }
-
- /// Determine whether a call to an unprototyped functions under
- /// the given calling convention should use the variadic
- /// convention or the non-variadic convention.
- ///
- /// There's a good reason to make a platform's variadic calling
- /// convention be different from its non-variadic calling
- /// convention: the non-variadic arguments can be passed in
- /// registers (better for performance), and the variadic arguments
- /// can be passed on the stack (also better for performance). If
- /// this is done, however, unprototyped functions *must* use the
- /// non-variadic convention, because C99 states that a call
- /// through an unprototyped function type must succeed if the
- /// function was defined with a non-variadic prototype with
- /// compatible parameters. Therefore, splitting the conventions
- /// makes it impossible to call a variadic function through an
- /// unprototyped type. Since function prototypes came out in the
- /// late 1970s, this is probably an acceptable trade-off.
- /// Nonetheless, not all platforms are willing to make it, and in
- /// particularly x86-64 bends over backwards to make the
- /// conventions compatible.
- ///
- /// The default is false. This is correct whenever:
- /// - the conventions are exactly the same, because it does not
- /// matter and the resulting IR will be somewhat prettier in
- /// certain cases; or
- /// - the conventions are substantively different in how they pass
- /// arguments, because in this case using the variadic convention
- /// will lead to C99 violations.
- ///
- /// However, some platforms make the conventions identical except
- /// for passing additional out-of-band information to a variadic
- /// function: for example, x86-64 passes the number of SSE
- /// arguments in %al. On these platforms, it is desireable to
- /// call unprototyped functions using the variadic convention so
- /// that unprototyped calls to varargs functions still succeed.
- ///
- /// Relatedly, platforms which pass the fixed arguments to this:
- /// A foo(B, C, D);
- /// differently than they would pass them to this:
- /// A foo(B, C, D, ...);
- /// may need to adjust the debugger-support code in Sema to do the
- /// right thing when calling a function with no know signature.
- virtual bool isNoProtoCallVariadic(const CodeGen::CallArgList &args,
- const FunctionNoProtoType *fnType) const;
-
- /// Gets the linker options necessary to link a dependent library on this
- /// platform.
- virtual void getDependentLibraryOption(llvm::StringRef Lib,
- llvm::SmallString<24> &Opt) const;
-
- /// Gets the linker options necessary to detect object file mismatches on
- /// this platform.
- virtual void getDetectMismatchOption(llvm::StringRef Name,
- llvm::StringRef Value,
- llvm::SmallString<32> &Opt) const {}
- };
+ /// Determine whether a call to an unprototyped functions under
+ /// the given calling convention should use the variadic
+ /// convention or the non-variadic convention.
+ ///
+ /// There's a good reason to make a platform's variadic calling
+ /// convention be different from its non-variadic calling
+ /// convention: the non-variadic arguments can be passed in
+ /// registers (better for performance), and the variadic arguments
+ /// can be passed on the stack (also better for performance). If
+ /// this is done, however, unprototyped functions *must* use the
+ /// non-variadic convention, because C99 states that a call
+ /// through an unprototyped function type must succeed if the
+ /// function was defined with a non-variadic prototype with
+ /// compatible parameters. Therefore, splitting the conventions
+ /// makes it impossible to call a variadic function through an
+ /// unprototyped type. Since function prototypes came out in the
+ /// late 1970s, this is probably an acceptable trade-off.
+ /// Nonetheless, not all platforms are willing to make it, and in
+ /// particularly x86-64 bends over backwards to make the
+ /// conventions compatible.
+ ///
+ /// The default is false. This is correct whenever:
+ /// - the conventions are exactly the same, because it does not
+ /// matter and the resulting IR will be somewhat prettier in
+ /// certain cases; or
+ /// - the conventions are substantively different in how they pass
+ /// arguments, because in this case using the variadic convention
+ /// will lead to C99 violations.
+ ///
+ /// However, some platforms make the conventions identical except
+ /// for passing additional out-of-band information to a variadic
+ /// function: for example, x86-64 passes the number of SSE
+ /// arguments in %al. On these platforms, it is desirable to
+ /// call unprototyped functions using the variadic convention so
+ /// that unprototyped calls to varargs functions still succeed.
+ ///
+ /// Relatedly, platforms which pass the fixed arguments to this:
+ /// A foo(B, C, D);
+ /// differently than they would pass them to this:
+ /// A foo(B, C, D, ...);
+ /// may need to adjust the debugger-support code in Sema to do the
+ /// right thing when calling a function with no know signature.
+ virtual bool isNoProtoCallVariadic(const CodeGen::CallArgList &args,
+ const FunctionNoProtoType *fnType) const;
+
+ /// Gets the linker options necessary to link a dependent library on this
+ /// platform.
+ virtual void getDependentLibraryOption(llvm::StringRef Lib,
+ llvm::SmallString<24> &Opt) const;
+
+ /// Gets the linker options necessary to detect object file mismatches on
+ /// this platform.
+ virtual void getDetectMismatchOption(llvm::StringRef Name,
+ llvm::StringRef Value,
+ llvm::SmallString<32> &Opt) const {}
+};
}
#endif // CLANG_CODEGEN_TARGETINFO_H
diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp
index ddd2d599da06..86a48fd8b7f9 100644
--- a/lib/Driver/Action.cpp
+++ b/lib/Driver/Action.cpp
@@ -33,7 +33,8 @@ const char *Action::getClassName(ActionClass AC) {
case LinkJobClass: return "linker";
case LipoJobClass: return "lipo";
case DsymutilJobClass: return "dsymutil";
- case VerifyJobClass: return "verify";
+ case VerifyDebugInfoJobClass: return "verify-debug-info";
+ case VerifyPCHJobClass: return "verify-pch";
}
llvm_unreachable("invalid class");
@@ -117,6 +118,29 @@ DsymutilJobAction::DsymutilJobAction(ActionList &Inputs, types::ID Type)
void VerifyJobAction::anchor() {}
-VerifyJobAction::VerifyJobAction(ActionList &Inputs, types::ID Type)
- : JobAction(VerifyJobClass, Inputs, Type) {
+VerifyJobAction::VerifyJobAction(ActionClass Kind, Action *Input,
+ types::ID Type)
+ : JobAction(Kind, Input, Type) {
+ assert((Kind == VerifyDebugInfoJobClass || Kind == VerifyPCHJobClass) &&
+ "ActionClass is not a valid VerifyJobAction");
+}
+
+VerifyJobAction::VerifyJobAction(ActionClass Kind, ActionList &Inputs,
+ types::ID Type)
+ : JobAction(Kind, Inputs, Type) {
+ assert((Kind == VerifyDebugInfoJobClass || Kind == VerifyPCHJobClass) &&
+ "ActionClass is not a valid VerifyJobAction");
+}
+
+void VerifyDebugInfoJobAction::anchor() {}
+
+VerifyDebugInfoJobAction::VerifyDebugInfoJobAction(Action *Input,
+ types::ID Type)
+ : VerifyJobAction(VerifyDebugInfoJobClass, Input, Type) {
+}
+
+void VerifyPCHJobAction::anchor() {}
+
+VerifyPCHJobAction::VerifyPCHJobAction(Action *Input, types::ID Type)
+ : VerifyJobAction(VerifyPCHJobClass, Input, Type) {
}
diff --git a/lib/Driver/CC1AsOptions.cpp b/lib/Driver/CC1AsOptions.cpp
deleted file mode 100644
index 22180c92ca7f..000000000000
--- a/lib/Driver/CC1AsOptions.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-//===--- CC1AsOptions.cpp - Clang Assembler Options Table -----------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Driver/CC1AsOptions.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/Option/OptTable.h"
-#include "llvm/Option/Option.h"
-using namespace clang;
-using namespace clang::driver;
-using namespace llvm::opt;
-using namespace clang::driver::cc1asoptions;
-
-#define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE;
-#include "clang/Driver/CC1AsOptions.inc"
-#undef PREFIX
-
-static const OptTable::Info CC1AsInfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR) \
- { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
- FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
-#include "clang/Driver/CC1AsOptions.inc"
-#undef OPTION
-};
-
-namespace {
-
-class CC1AsOptTable : public OptTable {
-public:
- CC1AsOptTable()
- : OptTable(CC1AsInfoTable, llvm::array_lengthof(CC1AsInfoTable)) {}
-};
-
-}
-
-OptTable *clang::driver::createCC1AsOptTable() {
- return new CC1AsOptTable();
-}
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
index 0152b19d4c59..33db5e9a9e17 100644
--- a/lib/Driver/CMakeLists.txt
+++ b/lib/Driver/CMakeLists.txt
@@ -1,10 +1,15 @@
+set(LLVM_LINK_COMPONENTS
+ Option
+ Support
+ )
+
add_clang_library(clangDriver
Action.cpp
- CC1AsOptions.cpp
Compilation.cpp
Driver.cpp
DriverOptions.cpp
Job.cpp
+ Multilib.cpp
Phases.cpp
SanitizerArgs.cpp
Tool.cpp
@@ -13,18 +18,10 @@ add_clang_library(clangDriver
WindowsToolChain.cpp
Tools.cpp
Types.cpp
- )
-add_dependencies(clangDriver
- ClangAttrList
- ClangCC1AsOptions
- ClangDiagnosticCommon
- ClangDiagnosticDriver
+ DEPENDS
ClangDriverOptions
- )
-target_link_libraries(clangDriver
+ LINK_LIBS
clangBasic
- LLVMOption
- LLVMTransformUtils
)
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index f077fd68cc4f..49b7edd96659 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -17,8 +17,6 @@
#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
-#include <errno.h>
-#include <sys/stat.h>
using namespace clang::driver;
using namespace clang;
@@ -26,9 +24,9 @@ using namespace llvm::opt;
Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain,
InputArgList *_Args, DerivedArgList *_TranslatedArgs)
- : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),
- TranslatedArgs(_TranslatedArgs), Redirects(0) {
-}
+ : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args),
+ TranslatedArgs(_TranslatedArgs), Redirects(nullptr),
+ ForDiagnostics(false) {}
Compilation::~Compilation() {
delete TranslatedArgs;
@@ -70,8 +68,6 @@ const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC,
}
bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
- std::string P(File);
-
// FIXME: Why are we trying to remove files that we have not created? For
// example we should only try to remove a temporary assembly file if
// "clang -cc1" succeed in writing it. Was this a workaround for when
@@ -88,7 +84,7 @@ bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
if (!llvm::sys::fs::can_write(File) || !llvm::sys::fs::is_regular_file(File))
return true;
- if (llvm::error_code EC = llvm::sys::fs::remove(File)) {
+ if (std::error_code EC = llvm::sys::fs::remove(File)) {
// Failure is only failure if the file exists and is "regular". We checked
// for it being regular before, and llvm::sys::fs::remove ignores ENOENT,
// so we don't need to check again.
@@ -137,7 +133,8 @@ int Compilation::ExecuteCommand(const Command &C,
if (getDriver().CCPrintOptions && getDriver().CCPrintOptionsFilename) {
std::string Error;
OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename, Error,
- llvm::sys::fs::F_Append);
+ llvm::sys::fs::F_Append |
+ llvm::sys::fs::F_Text);
if (!Error.empty()) {
getDriver().Diag(clang::diag::err_drv_cc_print_options_failure)
<< Error;
@@ -200,7 +197,7 @@ void Compilation::ExecuteJob(const Job &J,
if (const Command *C = dyn_cast<Command>(&J)) {
if (!InputsOk(*C, FailingCommands))
return;
- const Command *FailingCommand = 0;
+ const Command *FailingCommand = nullptr;
if (int Res = ExecuteCommand(*C, FailingCommand))
FailingCommands.push_back(std::make_pair(Res, FailingCommand));
} else {
@@ -212,6 +209,8 @@ void Compilation::ExecuteJob(const Job &J,
}
void Compilation::initCompilationForDiagnostics() {
+ ForDiagnostics = true;
+
// Free actions and jobs.
DeleteContainerPointers(Actions);
Jobs.clear();
@@ -233,7 +232,7 @@ void Compilation::initCompilationForDiagnostics() {
// Redirect stdout/stderr to /dev/null.
Redirects = new const StringRef*[3]();
- Redirects[0] = 0;
+ Redirects[0] = nullptr;
Redirects[1] = new const StringRef();
Redirects[2] = new const StringRef();
}
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 588e8dfb47ac..ef26bfacdd64 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -11,6 +11,7 @@
#include "InputInfo.h"
#include "ToolChains.h"
#include "clang/Basic/Version.h"
+#include "clang/Config/config.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/DriverDiagnostic.h"
@@ -19,27 +20,25 @@
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptSpecifier.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Option/Option.h"
-#include "llvm/Option/OptSpecifier.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
-
-// FIXME: It would prevent us from including llvm-config.h
-// if config.h were included before system_error.h.
-#include "clang/Config/config.h"
+#include <memory>
using namespace clang::driver;
using namespace clang;
@@ -47,15 +46,14 @@ using namespace llvm::opt;
Driver::Driver(StringRef ClangExecutable,
StringRef DefaultTargetTriple,
- StringRef DefaultImageName,
DiagnosticsEngine &Diags)
: Opts(createDriverOptTable()), Diags(Diags), Mode(GCCMode),
ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
UseStdLib(true), DefaultTargetTriple(DefaultTargetTriple),
- DefaultImageName(DefaultImageName),
+ DefaultImageName("a.out"),
DriverTitle("clang LLVM compiler"),
- CCPrintOptionsFilename(0), CCPrintHeadersFilename(0),
- CCLogDiagnosticsFilename(0),
+ CCPrintOptionsFilename(nullptr), CCPrintHeadersFilename(nullptr),
+ CCLogDiagnosticsFilename(nullptr),
CCCPrintBindings(false),
CCPrintHeaders(false), CCLogDiagnostics(false),
CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true),
@@ -77,10 +75,7 @@ Driver::Driver(StringRef ClangExecutable,
Driver::~Driver() {
delete Opts;
- for (llvm::StringMap<ToolChain *>::iterator I = ToolChains.begin(),
- E = ToolChains.end();
- I != E; ++I)
- delete I->second;
+ llvm::DeleteContainerSeconds(ToolChains);
}
void Driver::ParseDriverMode(ArrayRef<const char *> Args) {
@@ -112,7 +107,7 @@ InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) {
unsigned IncludedFlagsBitmask;
unsigned ExcludedFlagsBitmask;
- llvm::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) =
+ std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) =
getIncludeExcludeOptionFlagMasks();
unsigned MissingArgIndex, MissingArgCount;
@@ -156,18 +151,21 @@ InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) {
// option we used to determine the final phase.
phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, Arg **FinalPhaseArg)
const {
- Arg *PhaseArg = 0;
+ Arg *PhaseArg = nullptr;
phases::ID FinalPhase;
- // -{E,M,MM} only run the preprocessor.
+ // -{E,EP,P,M,MM} only run the preprocessor.
if (CCCIsCPP() ||
(PhaseArg = DAL.getLastArg(options::OPT_E)) ||
- (PhaseArg = DAL.getLastArg(options::OPT_M, options::OPT_MM))) {
+ (PhaseArg = DAL.getLastArg(options::OPT__SLASH_EP)) ||
+ (PhaseArg = DAL.getLastArg(options::OPT_M, options::OPT_MM)) ||
+ (PhaseArg = DAL.getLastArg(options::OPT__SLASH_P))) {
FinalPhase = phases::Preprocess;
// -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler.
} else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) ||
(PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) ||
+ (PhaseArg = DAL.getLastArg(options::OPT_verify_pch)) ||
(PhaseArg = DAL.getLastArg(options::OPT_rewrite_objc)) ||
(PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) ||
(PhaseArg = DAL.getLastArg(options::OPT__migrate)) ||
@@ -191,10 +189,11 @@ const {
return FinalPhase;
}
-static Arg* MakeInputArg(const DerivedArgList &Args, OptTable *Opts,
+static Arg* MakeInputArg(DerivedArgList &Args, OptTable *Opts,
StringRef Value) {
Arg *A = new Arg(Opts->getOption(options::OPT_INPUT), Value,
Args.getBaseArgs().MakeIndex(Value), Value.data());
+ Args.AddSynthesizedArg(A);
A->claim();
return A;
}
@@ -336,9 +335,10 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// FIXME: DefaultTargetTriple is used by the target-prefixed calls to as/ld
// and getToolChain is const.
if (IsCLMode()) {
- // clang-cl targets Win32.
+ // clang-cl targets MSVC-style Win32.
llvm::Triple T(DefaultTargetTriple);
- T.setOSName(llvm::Triple::getOSTypeName(llvm::Triple::Win32));
+ T.setOS(llvm::Triple::Win32);
+ T.setEnvironment(llvm::Triple::MSVC);
DefaultTargetTriple = T.str();
}
if (const Arg *A = Args->getLastArg(options::OPT_target))
@@ -378,8 +378,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
BuildInputs(C->getDefaultToolChain(), *TranslatedArgs, Inputs);
// Construct the list of abstract actions to perform for this compilation. On
- // Darwin target OSes this uses the driver-driver and universal actions.
- if (TC.getTriple().isOSDarwin())
+ // MachO targets this uses the driver-driver and universal actions.
+ if (TC.getTriple().isOSBinFormatMachO())
BuildUniversalActions(C->getDefaultToolChain(), C->getArgs(),
Inputs, C->getActions());
else
@@ -419,7 +419,6 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
// Suppress driver output and emit preprocessor output to temp file.
Mode = CPPMode;
CCGenDiagnostics = true;
- C.getArgs().AddFlagArg(0, Opts->getOption(options::OPT_frewrite_includes));
// Save the original job command(s).
std::string Cmd;
@@ -447,13 +446,14 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
bool IgnoreInput = false;
// Ignore input from stdin or any inputs that cannot be preprocessed.
- if (!strcmp(it->second->getValue(), "-")) {
+ // Check type first as not all linker inputs have a value.
+ if (types::getPreprocessedType(it->first) == types::TY_INVALID) {
+ IgnoreInput = true;
+ } else if (!strcmp(it->second->getValue(), "-")) {
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "Error generating preprocessed source(s) - ignoring input from stdin"
".";
IgnoreInput = true;
- } else if (types::getPreprocessedType(it->first) == types::TY_INVALID) {
- IgnoreInput = true;
}
if (IgnoreInput) {
@@ -491,7 +491,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
// Construct the list of abstract actions to perform for this compilation. On
// Darwin OSes this uses the driver-driver and builds universal actions.
const ToolChain &TC = C.getDefaultToolChain();
- if (TC.getTriple().isOSDarwin())
+ if (TC.getTriple().isOSBinFormatMachO())
BuildUniversalActions(TC, C.getArgs(), Inputs, C.getActions());
else
BuildActions(TC, C.getArgs(), Inputs, C.getActions());
@@ -519,17 +519,25 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
for (ArgStringList::const_iterator it = Files.begin(), ie = Files.end();
it != ie; ++it) {
Diag(clang::diag::note_drv_command_failed_diag_msg) << *it;
+ std::string Script = StringRef(*it).rsplit('.').first;
+ // In some cases (modules) we'll dump extra data to help with reproducing
+ // the crash into a directory next to the output.
+ SmallString<128> VFS;
+ if (llvm::sys::fs::exists(Script + ".cache")) {
+ Diag(clang::diag::note_drv_command_failed_diag_msg)
+ << Script + ".cache";
+ VFS = llvm::sys::path::filename(Script + ".cache");
+ llvm::sys::path::append(VFS, "vfs", "vfs.yaml");
+ }
std::string Err;
- std::string Script = StringRef(*it).rsplit('.').first;
Script += ".sh";
- llvm::raw_fd_ostream ScriptOS(
- Script.c_str(), Err, llvm::sys::fs::F_Excl | llvm::sys::fs::F_Binary);
+ llvm::raw_fd_ostream ScriptOS(Script.c_str(), Err, llvm::sys::fs::F_Excl);
if (!Err.empty()) {
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "Error generating run script: " + Script + " " + Err;
} else {
- // Append the new filename with correct preprocessed suffix.
+ // Replace the original filename with the preprocessed one.
size_t I, E;
I = Cmd.find("-main-file-name ");
assert (I != std::string::npos && "Expected to find -main-file-name");
@@ -542,6 +550,11 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
E = I + OldFilename.size();
I = Cmd.rfind(" ", I) + 1;
Cmd.replace(I, E - I, NewFilename.data(), NewFilename.size());
+ if (!VFS.empty()) {
+ // Add the VFS overlay to the reproduction script.
+ I += NewFilename.size();
+ Cmd.insert(I, std::string(" -ivfsoverlay ") + VFS.c_str());
+ }
ScriptOS << Cmd;
Diag(clang::diag::note_drv_command_failed_diag_msg) << Script;
}
@@ -599,7 +612,7 @@ int Driver::ExecuteCompilation(const Compilation &C,
// Print extra information about abnormal failures, if possible.
//
// This is ad-hoc, but we don't want to be excessively noisy. If the result
- // status was 1, assume the command failed normally. In particular, if it
+ // status was 1, assume the command failed normally. In particular, if it
// was the compiler then assume it gave a reasonable error code. Failures
// in other tools are less common, and they generally have worse
// diagnostics, so always print the diagnostic there.
@@ -621,7 +634,7 @@ int Driver::ExecuteCompilation(const Compilation &C,
void Driver::PrintHelp(bool ShowHidden) const {
unsigned IncludedFlagsBitmask;
unsigned ExcludedFlagsBitmask;
- llvm::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) =
+ std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) =
getIncludeExcludeOptionFlagMasks();
ExcludedFlagsBitmask |= options::NoDriverOption;
@@ -746,54 +759,37 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
}
if (C.getArgs().hasArg(options::OPT_print_multi_lib)) {
- // FIXME: We need tool chain support for this.
- llvm::outs() << ".;\n";
-
- switch (C.getDefaultToolChain().getTriple().getArch()) {
- default:
- break;
-
- case llvm::Triple::x86_64:
- llvm::outs() << "x86_64;@m64" << "\n";
- break;
+ const MultilibSet &Multilibs = TC.getMultilibs();
- case llvm::Triple::ppc64:
- llvm::outs() << "ppc64;@m64" << "\n";
- break;
-
- case llvm::Triple::ppc64le:
- llvm::outs() << "ppc64le;@m64" << "\n";
- break;
+ for (MultilibSet::const_iterator I = Multilibs.begin(), E = Multilibs.end();
+ I != E; ++I) {
+ llvm::outs() << *I << "\n";
}
return false;
}
- // FIXME: What is the difference between print-multi-directory and
- // print-multi-os-directory?
- if (C.getArgs().hasArg(options::OPT_print_multi_directory) ||
- C.getArgs().hasArg(options::OPT_print_multi_os_directory)) {
- switch (C.getDefaultToolChain().getTriple().getArch()) {
- default:
- case llvm::Triple::x86:
- case llvm::Triple::ppc:
- llvm::outs() << "." << "\n";
- break;
-
- case llvm::Triple::x86_64:
- llvm::outs() << "x86_64" << "\n";
- break;
-
- case llvm::Triple::ppc64:
- llvm::outs() << "ppc64" << "\n";
- break;
-
- case llvm::Triple::ppc64le:
- llvm::outs() << "ppc64le" << "\n";
- break;
+ if (C.getArgs().hasArg(options::OPT_print_multi_directory)) {
+ const MultilibSet &Multilibs = TC.getMultilibs();
+ for (MultilibSet::const_iterator I = Multilibs.begin(), E = Multilibs.end();
+ I != E; ++I) {
+ if (I->gccSuffix().empty())
+ llvm::outs() << ".\n";
+ else {
+ StringRef Suffix(I->gccSuffix());
+ assert(Suffix.front() == '/');
+ llvm::outs() << Suffix.substr(1) << "\n";
+ }
}
return false;
}
+ if (C.getArgs().hasArg(options::OPT_print_multi_os_directory)) {
+ // FIXME: This should print out "lib/../lib", "lib/../lib64", or
+ // "lib/../lib32" as appropriate for the toolchain. For now, print
+ // nothing because it's not supported yet.
+ return false;
+ }
+
return true;
}
@@ -867,7 +863,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
// Validate the option here; we don't save the type here because its
// particular spelling may participate in other driver choices.
llvm::Triple::ArchType Arch =
- tools::darwin::getArchTypeForDarwinArchName(A->getValue());
+ tools::darwin::getArchTypeForMachOArchName(A->getValue());
if (Arch == llvm::Triple::UnknownArch) {
Diag(clang::diag::err_drv_invalid_arch_name)
<< A->getAsString(Args);
@@ -934,13 +930,12 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
Actions.push_back(new DsymutilJobAction(Inputs, types::TY_dSYM));
}
- // Verify the output (debug information only) if we passed '-verify'.
- if (Args.hasArg(options::OPT_verify)) {
- ActionList VerifyInputs;
- VerifyInputs.push_back(Actions.back());
+ // Verify the debug info output.
+ if (Args.hasArg(options::OPT_verify_debug_info)) {
+ Action *VerifyInput = Actions.back();
Actions.pop_back();
- Actions.push_back(new VerifyJobAction(VerifyInputs,
- types::TY_Nothing));
+ Actions.push_back(new VerifyDebugInfoJobAction(VerifyInput,
+ types::TY_Nothing));
}
}
}
@@ -948,7 +943,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
/// \brief Check that the file referenced by Value exists. If it doesn't,
/// issue a diagnostic and return false.
-static bool DiagnoseInputExistance(const Driver &D, const DerivedArgList &Args,
+static bool DiagnoseInputExistence(const Driver &D, const DerivedArgList &Args,
StringRef Value) {
if (!D.getCheckInputsExist())
return true;
@@ -969,18 +964,21 @@ static bool DiagnoseInputExistance(const Driver &D, const DerivedArgList &Args,
if (llvm::sys::fs::exists(Twine(Path)))
return true;
+ if (D.IsCLMode() && llvm::sys::Process::FindInEnvPath("LIB", Value))
+ return true;
+
D.Diag(clang::diag::err_drv_no_such_file) << Path.str();
return false;
}
// Construct a the list of inputs and their types.
-void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
+void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
InputList &Inputs) const {
// Track the current user specified (-x) input. We also explicitly track the
// argument used to set the type; we only want to claim the type when we
// actually use it, so we warn about unused -x arguments.
types::ID InputType = types::TY_Nothing;
- Arg *InputTypeArg = 0;
+ Arg *InputTypeArg = nullptr;
// The last /TC or /TP option sets the input type to C or C++ globally.
if (Arg *TCTP = Args.getLastArg(options::OPT__SLASH_TC,
@@ -1029,7 +1027,8 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
// Otherwise emit an error but still use a valid type to avoid
// spurious errors (e.g., no inputs).
if (!Args.hasArgNoClaim(options::OPT_E) && !CCCIsCPP())
- Diag(clang::diag::err_drv_unknown_stdin_type);
+ Diag(IsCLMode() ? clang::diag::err_drv_unknown_stdin_type_clang_cl
+ : clang::diag::err_drv_unknown_stdin_type);
Ty = types::TY_C;
} else {
// Otherwise lookup by extension.
@@ -1075,19 +1074,19 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
Ty = InputType;
}
- if (DiagnoseInputExistance(*this, Args, Value))
+ if (DiagnoseInputExistence(*this, Args, Value))
Inputs.push_back(std::make_pair(Ty, A));
} else if (A->getOption().matches(options::OPT__SLASH_Tc)) {
StringRef Value = A->getValue();
- if (DiagnoseInputExistance(*this, Args, Value)) {
+ if (DiagnoseInputExistence(*this, Args, Value)) {
Arg *InputArg = MakeInputArg(Args, Opts, A->getValue());
Inputs.push_back(std::make_pair(types::TY_C, InputArg));
}
A->claim();
} else if (A->getOption().matches(options::OPT__SLASH_Tp)) {
StringRef Value = A->getValue();
- if (DiagnoseInputExistance(*this, Args, Value)) {
+ if (DiagnoseInputExistence(*this, Args, Value)) {
Arg *InputArg = MakeInputArg(Args, Opts, A->getValue());
Inputs.push_back(std::make_pair(types::TY_CXX, InputArg));
}
@@ -1177,7 +1176,7 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args,
// Construct the actions to perform.
ActionList LinkerInputs;
- ActionList SplitInputs;
+
llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PL;
for (unsigned i = 0, e = Inputs.size(); i != e; ++i) {
types::ID InputType = Inputs[i].first;
@@ -1211,18 +1210,18 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args,
Diag(clang::diag::warn_drv_preprocessed_input_file_unused)
<< InputArg->getAsString(Args)
<< !!FinalPhaseArg
- << FinalPhaseArg ? FinalPhaseArg->getOption().getName() : "";
+ << (FinalPhaseArg ? FinalPhaseArg->getOption().getName() : "");
else
Diag(clang::diag::warn_drv_input_file_unused)
<< InputArg->getAsString(Args)
<< getPhaseName(InitialPhase)
<< !!FinalPhaseArg
- << FinalPhaseArg ? FinalPhaseArg->getOption().getName() : "";
+ << (FinalPhaseArg ? FinalPhaseArg->getOption().getName() : "");
continue;
}
// Build the pipeline for this file.
- OwningPtr<Action> Current(new InputAction(*InputArg, InputType));
+ std::unique_ptr<Action> Current(new InputAction(*InputArg, InputType));
for (SmallVectorImpl<phases::ID>::iterator
i = PL.begin(), e = PL.end(); i != e; ++i) {
phases::ID Phase = *i;
@@ -1234,7 +1233,7 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args,
// Queue linker inputs.
if (Phase == phases::Link) {
assert((i + 1) == e && "linking must be final compilation step.");
- LinkerInputs.push_back(Current.take());
+ LinkerInputs.push_back(Current.release());
break;
}
@@ -1245,14 +1244,14 @@ void Driver::BuildActions(const ToolChain &TC, DerivedArgList &Args,
continue;
// Otherwise construct the appropriate action.
- Current.reset(ConstructPhaseAction(Args, Phase, Current.take()));
+ Current.reset(ConstructPhaseAction(Args, Phase, Current.release()));
if (Current->getType() == types::TY_Nothing)
break;
}
// If we ended with something, add to the output list.
if (Current)
- Actions.push_back(Current.take());
+ Actions.push_back(Current.release());
}
// Add a link action if necessary.
@@ -1284,7 +1283,8 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
} else {
OutputTy = Input->getType();
if (!Args.hasFlag(options::OPT_frewrite_includes,
- options::OPT_fno_rewrite_includes, false))
+ options::OPT_fno_rewrite_includes, false) &&
+ !CCGenDiagnostics)
OutputTy = types::getPreprocessedType(OutputTy);
assert(OutputTy != types::TY_INVALID &&
"Cannot preprocess this input type!");
@@ -1314,6 +1314,8 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
return new CompileJobAction(Input, types::TY_AST);
} else if (Args.hasArg(options::OPT_module_file_info)) {
return new CompileJobAction(Input, types::TY_ModuleFile);
+ } else if (Args.hasArg(options::OPT_verify_pch)) {
+ return new VerifyPCHJobAction(Input, types::TY_Nothing);
} else if (IsUsingLTO(Args)) {
types::ID Output =
Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC;
@@ -1356,13 +1358,13 @@ void Driver::BuildJobs(Compilation &C) const {
if (NumOutputs > 1) {
Diag(clang::diag::err_drv_output_argument_with_multiple_files);
- FinalOutput = 0;
+ FinalOutput = nullptr;
}
}
// Collect the list of architectures.
llvm::StringSet<> ArchNames;
- if (C.getDefaultToolChain().getTriple().isOSDarwin()) {
+ if (C.getDefaultToolChain().getTriple().isOSBinFormatMachO()) {
for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end();
it != ie; ++it) {
Arg *A = *it;
@@ -1381,7 +1383,7 @@ void Driver::BuildJobs(Compilation &C) const {
//
// FIXME: This is a hack; find a cleaner way to integrate this into the
// process.
- const char *LinkingOutput = 0;
+ const char *LinkingOutput = nullptr;
if (isa<LipoJobAction>(A)) {
if (FinalOutput)
LinkingOutput = FinalOutput->getValue();
@@ -1391,7 +1393,7 @@ void Driver::BuildJobs(Compilation &C) const {
InputInfo II;
BuildJobsForAction(C, A, &C.getDefaultToolChain(),
- /*BoundArch*/0,
+ /*BoundArch*/nullptr,
/*AtTopLevel*/ true,
/*MultipleArchs*/ ArchNames.size() > 1,
/*LinkingOutput*/ LinkingOutput,
@@ -1448,7 +1450,7 @@ void Driver::BuildJobs(Compilation &C) const {
static const Tool *SelectToolForJob(Compilation &C, const ToolChain *TC,
const JobAction *JA,
const ActionList *&Inputs) {
- const Tool *ToolForJob = 0;
+ const Tool *ToolForJob = nullptr;
// See if we should look for a compiler with an integrated assembler. We match
// bottom up, so what we are actually looking for is an assembler job with a
@@ -1456,6 +1458,7 @@ static const Tool *SelectToolForJob(Compilation &C, const ToolChain *TC,
if (TC->useIntegratedAs() &&
!C.getArgs().hasArg(options::OPT_save_temps) &&
+ !C.getArgs().hasArg(options::OPT_via_file_asm) &&
!C.getArgs().hasArg(options::OPT__SLASH_FA) &&
!C.getArgs().hasArg(options::OPT__SLASH_Fa) &&
isa<AssembleJobAction>(JA) &&
@@ -1463,7 +1466,7 @@ static const Tool *SelectToolForJob(Compilation &C, const ToolChain *TC,
const Tool *Compiler =
TC->SelectTool(cast<JobAction>(**Inputs->begin()));
if (!Compiler)
- return NULL;
+ return nullptr;
if (Compiler->hasIntegratedAssembler()) {
Inputs = &(*Inputs)[0]->getInputs();
ToolForJob = Compiler;
@@ -1587,7 +1590,7 @@ void Driver::BuildJobsForAction(Compilation &C,
static const char *MakeCLOutputFilename(const ArgList &Args, StringRef ArgValue,
StringRef BaseName, types::ID FileType) {
SmallString<128> Filename = ArgValue;
-
+
if (ArgValue.empty()) {
// If the argument is empty, output to BaseName in the current dir.
Filename = BaseName;
@@ -1626,6 +1629,17 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
return C.addResultFile(FinalOutput->getValue(), &JA);
}
+ // For /P, preprocess to file named after BaseInput.
+ if (C.getArgs().hasArg(options::OPT__SLASH_P)) {
+ assert(AtTopLevel && isa<PreprocessJobAction>(JA));
+ StringRef BaseName = llvm::sys::path::filename(BaseInput);
+ StringRef NameArg;
+ if (Arg *A = C.getArgs().getLastArg(options::OPT__SLASH_Fi))
+ NameArg = A->getValue();
+ return C.addResultFile(MakeCLOutputFilename(C.getArgs(), NameArg, BaseName,
+ types::TY_PP_C), &JA);
+ }
+
// Default to writing to stdout?
if (AtTopLevel && !CCGenDiagnostics &&
(isa<PreprocessJobAction>(JA) || JA.getType() == types::TY_ModuleFile))
@@ -1831,8 +1845,7 @@ std::string Driver::GetProgramPath(const char *Name,
std::string Driver::GetTemporaryPath(StringRef Prefix, const char *Suffix)
const {
SmallString<128> Path;
- llvm::error_code EC =
- llvm::sys::fs::createTemporaryFile(Prefix, Suffix, Path);
+ std::error_code EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, Path);
if (EC) {
Diag(clang::diag::err_unable_to_make_temp) << EC.message();
return "";
@@ -1854,36 +1867,43 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple,
llvm::Triple Target(llvm::Triple::normalize(DefaultTargetTriple));
- // Handle Darwin-specific options available here.
- if (Target.isOSDarwin()) {
+ // Handle Apple-specific options available here.
+ if (Target.isOSBinFormatMachO()) {
// If an explict Darwin arch name is given, that trumps all.
if (!DarwinArchName.empty()) {
- Target.setArch(
- tools::darwin::getArchTypeForDarwinArchName(DarwinArchName));
+ tools::darwin::setTripleTypeForMachOArchName(Target, DarwinArchName);
return Target;
}
// Handle the Darwin '-arch' flag.
if (Arg *A = Args.getLastArg(options::OPT_arch)) {
- llvm::Triple::ArchType DarwinArch
- = tools::darwin::getArchTypeForDarwinArchName(A->getValue());
- if (DarwinArch != llvm::Triple::UnknownArch)
- Target.setArch(DarwinArch);
+ StringRef ArchName = A->getValue();
+ tools::darwin::setTripleTypeForMachOArchName(Target, ArchName);
}
}
- // Handle pseudo-target flags '-EL' and '-EB'.
- if (Arg *A = Args.getLastArg(options::OPT_EL, options::OPT_EB)) {
- if (A->getOption().matches(options::OPT_EL)) {
+ // Handle pseudo-target flags '-mlittle-endian'/'-EL' and
+ // '-mbig-endian'/'-EB'.
+ if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian,
+ options::OPT_mbig_endian)) {
+ if (A->getOption().matches(options::OPT_mlittle_endian)) {
if (Target.getArch() == llvm::Triple::mips)
Target.setArch(llvm::Triple::mipsel);
else if (Target.getArch() == llvm::Triple::mips64)
Target.setArch(llvm::Triple::mips64el);
+ else if (Target.getArch() == llvm::Triple::aarch64_be)
+ Target.setArch(llvm::Triple::aarch64);
+ else if (Target.getArch() == llvm::Triple::arm64_be)
+ Target.setArch(llvm::Triple::arm64);
} else {
if (Target.getArch() == llvm::Triple::mipsel)
Target.setArch(llvm::Triple::mips);
else if (Target.getArch() == llvm::Triple::mips64el)
Target.setArch(llvm::Triple::mips64);
+ else if (Target.getArch() == llvm::Triple::aarch64)
+ Target.setArch(llvm::Triple::aarch64_be);
+ else if (Target.getArch() == llvm::Triple::arm64)
+ Target.setArch(llvm::Triple::arm64_be);
}
}
@@ -1893,20 +1913,27 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple,
Target.getOS() == llvm::Triple::Minix)
return Target;
- // Handle pseudo-target flags '-m32' and '-m64'.
- // FIXME: Should this information be in llvm::Triple?
- if (Arg *A = Args.getLastArg(options::OPT_m32, options::OPT_m64)) {
- if (A->getOption().matches(options::OPT_m32)) {
- if (Target.getArch() == llvm::Triple::x86_64)
- Target.setArch(llvm::Triple::x86);
- if (Target.getArch() == llvm::Triple::ppc64)
- Target.setArch(llvm::Triple::ppc);
- } else {
- if (Target.getArch() == llvm::Triple::x86)
- Target.setArch(llvm::Triple::x86_64);
- if (Target.getArch() == llvm::Triple::ppc)
- Target.setArch(llvm::Triple::ppc64);
+ // Handle pseudo-target flags '-m64', '-mx32', '-m32' and '-m16'.
+ if (Arg *A = Args.getLastArg(options::OPT_m64, options::OPT_mx32,
+ options::OPT_m32, options::OPT_m16)) {
+ llvm::Triple::ArchType AT = llvm::Triple::UnknownArch;
+
+ if (A->getOption().matches(options::OPT_m64))
+ AT = Target.get64BitArchVariant().getArch();
+ else if (A->getOption().matches(options::OPT_mx32) &&
+ Target.get64BitArchVariant().getArch() == llvm::Triple::x86_64) {
+ AT = llvm::Triple::x86_64;
+ Target.setEnvironment(llvm::Triple::GNUX32);
+ } else if (A->getOption().matches(options::OPT_m32))
+ AT = Target.get32BitArchVariant().getArch();
+ else if (A->getOption().matches(options::OPT_m16) &&
+ Target.get32BitArchVariant().getArch() == llvm::Triple::x86) {
+ AT = llvm::Triple::x86;
+ Target.setEnvironment(llvm::Triple::CODE16);
}
+
+ if (AT != llvm::Triple::UnknownArch)
+ Target.setArch(AT);
}
return Target;
@@ -1926,13 +1953,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
case llvm::Triple::Darwin:
case llvm::Triple::MacOSX:
case llvm::Triple::IOS:
- if (Target.getArch() == llvm::Triple::x86 ||
- Target.getArch() == llvm::Triple::x86_64 ||
- Target.getArch() == llvm::Triple::arm ||
- Target.getArch() == llvm::Triple::thumb)
- TC = new toolchains::DarwinClang(*this, Target, Args);
- else
- TC = new toolchains::Darwin_Generic_GCC(*this, Target, Args);
+ TC = new toolchains::DarwinClang(*this, Target, Args);
break;
case llvm::Triple::DragonFly:
TC = new toolchains::DragonFly(*this, Target, Args);
@@ -1962,10 +1983,29 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
TC = new toolchains::Solaris(*this, Target, Args);
break;
case llvm::Triple::Win32:
- TC = new toolchains::Windows(*this, Target, Args);
+ switch (Target.getEnvironment()) {
+ default:
+ if (Target.isOSBinFormatELF())
+ TC = new toolchains::Generic_ELF(*this, Target, Args);
+ else if (Target.isOSBinFormatMachO())
+ TC = new toolchains::MachO(*this, Target, Args);
+ else
+ TC = new toolchains::Generic_GCC(*this, Target, Args);
+ break;
+ case llvm::Triple::GNU:
+ // FIXME: We need a MinGW toolchain. Use the default Generic_GCC
+ // toolchain for now as the default case would below otherwise.
+ if (Target.isOSBinFormatELF())
+ TC = new toolchains::Generic_ELF(*this, Target, Args);
+ else
+ TC = new toolchains::Generic_GCC(*this, Target, Args);
+ break;
+ case llvm::Triple::MSVC:
+ case llvm::Triple::UnknownEnvironment:
+ TC = new toolchains::Windows(*this, Target, Args);
+ break;
+ }
break;
- case llvm::Triple::MinGW32:
- // FIXME: We need a MinGW toolchain. Fallthrough for now.
default:
// TCE is an OSless target
if (Target.getArchName() == "tce") {
@@ -1981,6 +2021,14 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
TC = new toolchains::XCore(*this, Target, Args);
break;
}
+ if (Target.isOSBinFormatELF()) {
+ TC = new toolchains::Generic_ELF(*this, Target, Args);
+ break;
+ }
+ if (Target.getObjectFormat() == llvm::Triple::MachO) {
+ TC = new toolchains::MachO(*this, Target, Args);
+ break;
+ }
TC = new toolchains::Generic_GCC(*this, Target, Args);
break;
}
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index ee68e6f14d51..42cc1bc29077 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -7,7 +7,11 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Job.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
@@ -37,7 +41,7 @@ static int skipArgs(const char *Flag) {
.Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true)
.Cases("-iwithprefixbefore", "-isysroot", "-isystem", "-iquote", true)
.Cases("-resource-dir", "-serialize-diagnostic-file", true)
- .Case("-dwarf-debug-flags", true)
+ .Cases("-dwarf-debug-flags", "-ivfsoverlay", true)
.Default(false);
// Match found.
@@ -58,7 +62,8 @@ static int skipArgs(const char *Flag) {
// These flags are treated as a single argument (e.g., -F<Dir>).
StringRef FlagRef(Flag);
- if (FlagRef.startswith("-F") || FlagRef.startswith("-I"))
+ if (FlagRef.startswith("-F") || FlagRef.startswith("-I") ||
+ FlagRef.startswith("-fmodules-cache-path="))
return 1;
return 0;
@@ -119,9 +124,9 @@ int Command::Execute(const StringRef **Redirects, std::string *ErrMsg,
Argv.push_back(Executable);
for (size_t i = 0, e = Arguments.size(); i != e; ++i)
Argv.push_back(Arguments[i]);
- Argv.push_back(0);
+ Argv.push_back(nullptr);
- return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ 0,
+ return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
Redirects, /*secondsToWait*/ 0,
/*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
}
@@ -159,6 +164,9 @@ int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg,
if (ExecutionFailed)
*ExecutionFailed = false;
+ const Driver &D = getCreator().getToolChain().getDriver();
+ D.Diag(diag::warn_drv_invoking_fallback) << Fallback->getExecutable();
+
int SecondaryStatus = Fallback->Execute(Redirects, ErrMsg, ExecutionFailed);
return SecondaryStatus;
}
diff --git a/lib/Driver/Multilib.cpp b/lib/Driver/Multilib.cpp
new file mode 100644
index 000000000000..484ce1627d7b
--- /dev/null
+++ b/lib/Driver/Multilib.cpp
@@ -0,0 +1,334 @@
+//===--- Multilib.cpp - Multilib Implementation ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/Multilib.h"
+#include "Tools.h"
+#include "clang/Driver/Options.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+using namespace clang::driver;
+using namespace clang;
+using namespace llvm::opt;
+using namespace llvm::sys;
+
+/// normalize Segment to "/foo/bar" or "".
+static void normalizePathSegment(std::string &Segment) {
+ StringRef seg = Segment;
+
+ // Prune trailing "/" or "./"
+ while (1) {
+ StringRef last = *--path::end(seg);
+ if (last != ".")
+ break;
+ seg = path::parent_path(seg);
+ }
+
+ if (seg.empty() || seg == "/") {
+ Segment = "";
+ return;
+ }
+
+ // Add leading '/'
+ if (seg.front() != '/') {
+ Segment = "/" + seg.str();
+ } else {
+ Segment = seg;
+ }
+}
+
+Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix,
+ StringRef IncludeSuffix)
+ : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix) {
+ normalizePathSegment(this->GCCSuffix);
+ normalizePathSegment(this->OSSuffix);
+ normalizePathSegment(this->IncludeSuffix);
+}
+
+Multilib &Multilib::gccSuffix(StringRef S) {
+ GCCSuffix = S;
+ normalizePathSegment(GCCSuffix);
+ return *this;
+}
+
+Multilib &Multilib::osSuffix(StringRef S) {
+ OSSuffix = S;
+ normalizePathSegment(OSSuffix);
+ return *this;
+}
+
+Multilib &Multilib::includeSuffix(StringRef S) {
+ IncludeSuffix = S;
+ normalizePathSegment(IncludeSuffix);
+ return *this;
+}
+
+void Multilib::print(raw_ostream &OS) const {
+ assert(GCCSuffix.empty() || (StringRef(GCCSuffix).front() == '/'));
+ if (GCCSuffix.empty())
+ OS << ".";
+ else {
+ OS << StringRef(GCCSuffix).drop_front();
+ }
+ OS << ";";
+ for (StringRef Flag : Flags) {
+ if (Flag.front() == '+')
+ OS << "@" << Flag.substr(1);
+ }
+}
+
+bool Multilib::isValid() const {
+ llvm::StringMap<int> FlagSet;
+ for (unsigned I = 0, N = Flags.size(); I != N; ++I) {
+ StringRef Flag(Flags[I]);
+ llvm::StringMap<int>::iterator SI = FlagSet.find(Flag.substr(1));
+
+ assert(StringRef(Flag).front() == '+' || StringRef(Flag).front() == '-');
+
+ if (SI == FlagSet.end())
+ FlagSet[Flag.substr(1)] = I;
+ else if (Flags[I] != Flags[SI->getValue()])
+ return false;
+ }
+ return true;
+}
+
+bool Multilib::operator==(const Multilib &Other) const {
+ // Check whether the flags sets match
+ // allowing for the match to be order invariant
+ llvm::StringSet<> MyFlags;
+ for (const auto &Flag : Flags)
+ MyFlags.insert(Flag);
+
+ for (const auto &Flag : Other.Flags)
+ if (MyFlags.find(Flag) == MyFlags.end())
+ return false;
+
+ if (osSuffix() != Other.osSuffix())
+ return false;
+
+ if (gccSuffix() != Other.gccSuffix())
+ return false;
+
+ if (includeSuffix() != Other.includeSuffix())
+ return false;
+
+ return true;
+}
+
+raw_ostream &clang::driver::operator<<(raw_ostream &OS, const Multilib &M) {
+ M.print(OS);
+ return OS;
+}
+
+MultilibSet &MultilibSet::Maybe(const Multilib &M) {
+ Multilib Opposite;
+ // Negate any '+' flags
+ for (StringRef Flag : M.flags()) {
+ if (Flag.front() == '+')
+ Opposite.flags().push_back(("-" + Flag.substr(1)).str());
+ }
+ return Either(M, Opposite);
+}
+
+MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2) {
+ std::vector<Multilib> Ms;
+ Ms.push_back(M1);
+ Ms.push_back(M2);
+ return Either(Ms);
+}
+
+MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
+ const Multilib &M3) {
+ std::vector<Multilib> Ms;
+ Ms.push_back(M1);
+ Ms.push_back(M2);
+ Ms.push_back(M3);
+ return Either(Ms);
+}
+
+MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
+ const Multilib &M3, const Multilib &M4) {
+ std::vector<Multilib> Ms;
+ Ms.push_back(M1);
+ Ms.push_back(M2);
+ Ms.push_back(M3);
+ Ms.push_back(M4);
+ return Either(Ms);
+}
+
+MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
+ const Multilib &M3, const Multilib &M4,
+ const Multilib &M5) {
+ std::vector<Multilib> Ms;
+ Ms.push_back(M1);
+ Ms.push_back(M2);
+ Ms.push_back(M3);
+ Ms.push_back(M4);
+ Ms.push_back(M5);
+ return Either(Ms);
+}
+
+static Multilib compose(const Multilib &Base, const Multilib &New) {
+ SmallString<128> GCCSuffix;
+ llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix());
+ SmallString<128> OSSuffix;
+ llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix());
+ SmallString<128> IncludeSuffix;
+ llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(),
+ New.includeSuffix());
+
+ Multilib Composed(GCCSuffix.str(), OSSuffix.str(), IncludeSuffix.str());
+
+ Multilib::flags_list &Flags = Composed.flags();
+
+ Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end());
+ Flags.insert(Flags.end(), New.flags().begin(), New.flags().end());
+
+ return Composed;
+}
+
+MultilibSet &
+MultilibSet::Either(const std::vector<Multilib> &MultilibSegments) {
+ multilib_list Composed;
+
+ if (Multilibs.empty())
+ Multilibs.insert(Multilibs.end(), MultilibSegments.begin(),
+ MultilibSegments.end());
+ else {
+ for (const Multilib &New : MultilibSegments) {
+ for (const Multilib &Base : *this) {
+ Multilib MO = compose(Base, New);
+ if (MO.isValid())
+ Composed.push_back(MO);
+ }
+ }
+
+ Multilibs = Composed;
+ }
+
+ return *this;
+}
+
+MultilibSet &MultilibSet::FilterOut(const MultilibSet::FilterCallback &F) {
+ filterInPlace(F, Multilibs);
+ return *this;
+}
+
+MultilibSet &MultilibSet::FilterOut(std::string Regex) {
+ class REFilter : public MultilibSet::FilterCallback {
+ mutable llvm::Regex R;
+
+ public:
+ REFilter(std::string Regex) : R(Regex) {}
+ bool operator()(const Multilib &M) const override {
+ std::string Error;
+ if (!R.isValid(Error)) {
+ llvm::errs() << Error;
+ assert(false);
+ return false;
+ }
+ return R.match(M.gccSuffix());
+ }
+ };
+
+ REFilter REF(Regex);
+ filterInPlace(REF, Multilibs);
+ return *this;
+}
+
+void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); }
+
+void MultilibSet::combineWith(const MultilibSet &Other) {
+ Multilibs.insert(Multilibs.end(), Other.begin(), Other.end());
+}
+
+bool MultilibSet::select(const Multilib::flags_list &Flags, Multilib &M) const {
+ class FilterFlagsMismatch : public MultilibSet::FilterCallback {
+ llvm::StringMap<bool> FlagSet;
+
+ public:
+ FilterFlagsMismatch(const std::vector<std::string> &Flags) {
+ // Stuff all of the flags into the FlagSet such that a true mappend
+ // indicates the flag was enabled, and a false mappend indicates the
+ // flag was disabled
+ for (StringRef Flag : Flags)
+ FlagSet[Flag.substr(1)] = isFlagEnabled(Flag);
+ }
+ bool operator()(const Multilib &M) const override {
+ for (StringRef Flag : M.flags()) {
+ llvm::StringMap<bool>::const_iterator SI = FlagSet.find(Flag.substr(1));
+ if (SI != FlagSet.end())
+ if (SI->getValue() != isFlagEnabled(Flag))
+ return true;
+ }
+ return false;
+ }
+ private:
+ bool isFlagEnabled(StringRef Flag) const {
+ char Indicator = Flag.front();
+ assert(Indicator == '+' || Indicator == '-');
+ return Indicator == '+';
+ }
+ };
+
+ FilterFlagsMismatch FlagsMismatch(Flags);
+
+ multilib_list Filtered = filterCopy(FlagsMismatch, Multilibs);
+
+ if (Filtered.size() == 0) {
+ return false;
+ } else if (Filtered.size() == 1) {
+ M = Filtered[0];
+ return true;
+ }
+
+ // TODO: pick the "best" multlib when more than one is suitable
+ assert(false);
+
+ return false;
+}
+
+void MultilibSet::print(raw_ostream &OS) const {
+ for (const Multilib &M : *this)
+ OS << M << "\n";
+}
+
+MultilibSet::multilib_list
+MultilibSet::filterCopy(const MultilibSet::FilterCallback &F,
+ const multilib_list &Ms) {
+ multilib_list Copy(Ms);
+ filterInPlace(F, Copy);
+ return Copy;
+}
+
+void MultilibSet::filterInPlace(const MultilibSet::FilterCallback &F,
+ multilib_list &Ms) {
+ Ms.erase(std::remove_if(Ms.begin(), Ms.end(),
+ [&F](const Multilib &M) { return F(M); }),
+ Ms.end());
+}
+
+raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) {
+ MS.print(OS);
+ return OS;
+}
diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp
index 43209f01e247..b64f0275768c 100644
--- a/lib/Driver/SanitizerArgs.cpp
+++ b/lib/Driver/SanitizerArgs.cpp
@@ -7,16 +7,16 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Driver/SanitizerArgs.h"
-
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
-#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
-#include "llvm/Transforms/Utils/SpecialCaseList.h"
+#include "llvm/Support/SpecialCaseList.h"
+#include <memory>
using namespace clang::driver;
using namespace llvm::opt;
@@ -24,9 +24,10 @@ using namespace llvm::opt;
void SanitizerArgs::clear() {
Kind = 0;
BlacklistFile = "";
- MsanTrackOrigins = false;
+ MsanTrackOrigins = 0;
AsanZeroBaseShadow = false;
UbsanTrapOnError = false;
+ AsanSharedRuntime = false;
}
SanitizerArgs::SanitizerArgs() {
@@ -72,30 +73,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
}
UbsanTrapOnError =
- Args.hasArg(options::OPT_fcatch_undefined_behavior) ||
Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
options::OPT_fno_sanitize_undefined_trap_on_error, false);
- if (Args.hasArg(options::OPT_fcatch_undefined_behavior) &&
- !Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
- options::OPT_fno_sanitize_undefined_trap_on_error, true)) {
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << "-fcatch-undefined-behavior"
- << "-fno-sanitize-undefined-trap-on-error";
- }
-
// Warn about undefined sanitizer options that require runtime support.
if (UbsanTrapOnError && notAllowedWithTrap()) {
- if (Args.hasArg(options::OPT_fcatch_undefined_behavior))
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, NotAllowedWithTrap)
- << "-fcatch-undefined-behavior";
- else if (Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
- options::OPT_fno_sanitize_undefined_trap_on_error,
- false))
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << lastArgumentForKind(D, Args, NotAllowedWithTrap)
- << "-fsanitize-undefined-trap-on-error";
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, NotAllowedWithTrap)
+ << "-fsanitize-undefined-trap-on-error";
}
// Only one runtime library can be used at once.
@@ -123,19 +108,11 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
D.Diag(diag::err_drv_argument_not_allowed_with)
<< lastArgumentForKind(D, Args, NeedsLeakDetection)
<< lastArgumentForKind(D, Args, NeedsMsanRt);
- // FIXME: Currenly -fsanitize=leak is silently ignored in the presence of
+ // FIXME: Currently -fsanitize=leak is silently ignored in the presence of
// -fsanitize=address. Perhaps it should print an error, or perhaps
// -f(-no)sanitize=leak should change whether leak detection is enabled by
// default in ASan?
- // If -fsanitize contains extra features of ASan, it should also
- // explicitly contain -fsanitize=address (probably, turned off later in the
- // command line).
- if ((Kind & AddressFull) != 0 && (AllAdd & Address) == 0)
- D.Diag(diag::warn_drv_unused_sanitizer)
- << lastArgumentForKind(D, Args, AddressFull)
- << "-fsanitize=address";
-
// Parse -f(no-)sanitize-blacklist options.
if (Arg *BLArg = Args.getLastArg(options::OPT_fsanitize_blacklist,
options::OPT_fno_sanitize_blacklist)) {
@@ -144,7 +121,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
if (llvm::sys::fs::exists(BLPath)) {
// Validate the blacklist format.
std::string BLError;
- llvm::OwningPtr<llvm::SpecialCaseList> SCL(
+ std::unique_ptr<llvm::SpecialCaseList> SCL(
llvm::SpecialCaseList::create(BLPath, BLError));
if (!SCL.get())
D.Diag(diag::err_drv_malformed_sanitizer_blacklist) << BLError;
@@ -163,27 +140,33 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
BlacklistFile = BLPath;
}
- // Parse -f(no-)sanitize-memory-track-origins options.
- if (NeedsMsan)
- MsanTrackOrigins =
- Args.hasFlag(options::OPT_fsanitize_memory_track_origins,
- options::OPT_fno_sanitize_memory_track_origins,
- /* Default */false);
+ // Parse -f[no-]sanitize-memory-track-origins[=level] options.
+ if (NeedsMsan) {
+ if (Arg *A =
+ Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ,
+ options::OPT_fsanitize_memory_track_origins,
+ options::OPT_fno_sanitize_memory_track_origins)) {
+ if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) {
+ MsanTrackOrigins = 1;
+ } else if (A->getOption().matches(
+ options::OPT_fno_sanitize_memory_track_origins)) {
+ MsanTrackOrigins = 0;
+ } else {
+ StringRef S = A->getValue();
+ if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
+ MsanTrackOrigins > 2) {
+ D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+ }
+ }
+ }
+ }
- // Parse -f(no-)sanitize-address-zero-base-shadow options.
if (NeedsAsan) {
- bool IsAndroid = (TC.getTriple().getEnvironment() == llvm::Triple::Android);
- bool ZeroBaseShadowDefault = IsAndroid;
+ AsanSharedRuntime =
+ Args.hasArg(options::OPT_shared_libasan) ||
+ (TC.getTriple().getEnvironment() == llvm::Triple::Android);
AsanZeroBaseShadow =
- Args.hasFlag(options::OPT_fsanitize_address_zero_base_shadow,
- options::OPT_fno_sanitize_address_zero_base_shadow,
- ZeroBaseShadowDefault);
- // Zero-base shadow is a requirement on Android.
- if (IsAndroid && !AsanZeroBaseShadow) {
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << "-fno-sanitize-address-zero-base-shadow"
- << lastArgumentForKind(D, Args, Address);
- }
+ (TC.getTriple().getEnvironment() == llvm::Triple::Android);
}
}
@@ -205,11 +188,8 @@ void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args,
}
if (MsanTrackOrigins)
- CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins"));
-
- if (AsanZeroBaseShadow)
- CmdArgs.push_back(
- Args.MakeArgString("-fsanitize-address-zero-base-shadow"));
+ CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins=" +
+ llvm::utostr(MsanTrackOrigins)));
// Workaround for PR16386.
if (needsMsanRt())
@@ -222,11 +202,6 @@ unsigned SanitizerArgs::parse(const char *Value) {
#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID##Group)
#include "clang/Basic/Sanitizers.def"
.Default(SanitizeKind());
- // Assume -fsanitize=address implies -fsanitize=init-order,use-after-return.
- // FIXME: This should be either specified in Sanitizers.def, or go away when
- // we get rid of "-fsanitize=init-order,use-after-return" flags at all.
- if (ParsedKind & Address)
- ParsedKind |= InitOrder | UseAfterReturn;
return ParsedKind;
}
@@ -296,28 +271,7 @@ bool SanitizerArgs::parse(const Driver &D, const llvm::opt::ArgList &Args,
unsigned &Remove, bool DiagnoseErrors) {
Add = 0;
Remove = 0;
- const char *DeprecatedReplacement = 0;
- if (A->getOption().matches(options::OPT_faddress_sanitizer)) {
- Add = Address;
- DeprecatedReplacement = "-fsanitize=address";
- } else if (A->getOption().matches(options::OPT_fno_address_sanitizer)) {
- Remove = Address;
- DeprecatedReplacement = "-fno-sanitize=address";
- } else if (A->getOption().matches(options::OPT_fthread_sanitizer)) {
- Add = Thread;
- DeprecatedReplacement = "-fsanitize=thread";
- } else if (A->getOption().matches(options::OPT_fno_thread_sanitizer)) {
- Remove = Thread;
- DeprecatedReplacement = "-fno-sanitize=thread";
- } else if (A->getOption().matches(options::OPT_fcatch_undefined_behavior)) {
- Add = UndefinedTrap;
- DeprecatedReplacement =
- "-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error";
- } else if (A->getOption().matches(options::OPT_fbounds_checking) ||
- A->getOption().matches(options::OPT_fbounds_checking_EQ)) {
- Add = LocalBounds;
- DeprecatedReplacement = "-fsanitize=local-bounds";
- } else if (A->getOption().matches(options::OPT_fsanitize_EQ)) {
+ if (A->getOption().matches(options::OPT_fsanitize_EQ)) {
Add = parse(D, A, DiagnoseErrors);
} else if (A->getOption().matches(options::OPT_fno_sanitize_EQ)) {
Remove = parse(D, A, DiagnoseErrors);
@@ -325,11 +279,6 @@ bool SanitizerArgs::parse(const Driver &D, const llvm::opt::ArgList &Args,
// Flag is not relevant to sanitizers.
return false;
}
- // If this is a deprecated synonym, produce a warning directing users
- // towards the new spelling.
- if (DeprecatedReplacement && DiagnoseErrors)
- D.Diag(diag::warn_drv_deprecated_arg)
- << A->getAsString(Args) << DeprecatedReplacement;
return true;
}
@@ -369,7 +318,7 @@ std::string SanitizerArgs::describeSanitizeArg(const llvm::opt::ArgList &Args,
bool SanitizerArgs::getDefaultBlacklistForKind(const Driver &D, unsigned Kind,
std::string &BLPath) {
- const char *BlacklistFile = 0;
+ const char *BlacklistFile = nullptr;
if (Kind & NeedsAsanRt)
BlacklistFile = "asan_blacklist.txt";
else if (Kind & NeedsMsanRt)
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index 36aae33ec838..4f90d083c7dc 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -15,6 +15,7 @@
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
#include "clang/Driver/ToolChain.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
@@ -38,8 +39,8 @@ const Driver &ToolChain::getDriver() const {
}
bool ToolChain::useIntegratedAs() const {
- return Args.hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
+ return Args.hasFlag(options::OPT_fintegrated_as,
+ options::OPT_fno_integrated_as,
IsIntegratedAssemblerDefault());
}
@@ -114,7 +115,7 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const {
case Action::BindArchClass:
case Action::LipoJobClass:
case Action::DsymutilJobClass:
- case Action::VerifyJobClass:
+ case Action::VerifyDebugInfoJobClass:
llvm_unreachable("Invalid tool kind.");
case Action::CompileJobClass:
@@ -122,6 +123,7 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const {
case Action::PreprocessJobClass:
case Action::AnalyzeJobClass:
case Action::MigrateJobClass:
+ case Action::VerifyPCHJobClass:
return getClang();
}
@@ -146,6 +148,30 @@ std::string ToolChain::GetProgramPath(const char *Name) const {
return D.GetProgramPath(Name, *this);
}
+std::string ToolChain::GetLinkerPath() const {
+ if (Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) {
+ StringRef Suffix = A->getValue();
+
+ // If we're passed -fuse-ld= with no argument, or with the argument ld,
+ // then use whatever the default system linker is.
+ if (Suffix.empty() || Suffix == "ld")
+ return GetProgramPath("ld");
+
+ llvm::SmallString<8> LinkerName("ld.");
+ LinkerName.append(Suffix);
+
+ std::string LinkerPath(GetProgramPath(LinkerName.c_str()));
+ if (llvm::sys::fs::exists(LinkerPath))
+ return LinkerPath;
+
+ getDriver().Diag(diag::err_drv_invalid_linker_name) << A->getAsString(Args);
+ return "";
+ }
+
+ return GetProgramPath("ld");
+}
+
+
types::ID ToolChain::LookupTypeForExtension(const char *Ext) const {
return types::lookupTypeForExtension(Ext);
}
@@ -154,109 +180,27 @@ bool ToolChain::HasNativeLLVMSupport() const {
return false;
}
+bool ToolChain::isCrossCompiling() const {
+ llvm::Triple HostTriple(LLVM_HOST_TRIPLE);
+ switch (HostTriple.getArch()) {
+ // The A32/T32/T16 instruction sets are not separate architectures in this
+ // context.
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ return getArch() != llvm::Triple::arm && getArch() != llvm::Triple::thumb &&
+ getArch() != llvm::Triple::armeb && getArch() != llvm::Triple::thumbeb;
+ default:
+ return HostTriple.getArch() != getArch();
+ }
+}
+
ObjCRuntime ToolChain::getDefaultObjCRuntime(bool isNonFragile) const {
return ObjCRuntime(isNonFragile ? ObjCRuntime::GNUstep : ObjCRuntime::GCC,
VersionTuple());
}
-/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting.
-//
-// FIXME: tblgen this.
-static const char *getARMTargetCPU(const ArgList &Args,
- const llvm::Triple &Triple) {
- // For Darwin targets, the -arch option (which is translated to a
- // corresponding -march option) should determine the architecture
- // (and the Mach-O slice) regardless of any -mcpu options.
- if (!Triple.isOSDarwin()) {
- // FIXME: Warn on inconsistent use of -mcpu and -march.
- // If we have -mcpu=, use that.
- if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
- return A->getValue();
- }
-
- StringRef MArch;
- if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- // Otherwise, if we have -march= choose the base CPU for that arch.
- MArch = A->getValue();
- } else {
- // Otherwise, use the Arch from the triple.
- MArch = Triple.getArchName();
- }
-
- if (Triple.getOS() == llvm::Triple::NetBSD) {
- if (MArch == "armv6")
- return "arm1176jzf-s";
- }
-
- const char *result = llvm::StringSwitch<const char *>(MArch)
- .Cases("armv2", "armv2a","arm2")
- .Case("armv3", "arm6")
- .Case("armv3m", "arm7m")
- .Case("armv4", "strongarm")
- .Case("armv4t", "arm7tdmi")
- .Cases("armv5", "armv5t", "arm10tdmi")
- .Cases("armv5e", "armv5te", "arm1026ejs")
- .Case("armv5tej", "arm926ej-s")
- .Cases("armv6", "armv6k", "arm1136jf-s")
- .Case("armv6j", "arm1136j-s")
- .Cases("armv6z", "armv6zk", "arm1176jzf-s")
- .Case("armv6t2", "arm1156t2-s")
- .Cases("armv6m", "armv6-m", "cortex-m0")
- .Cases("armv7", "armv7a", "armv7-a", "cortex-a8")
- .Cases("armv7l", "armv7-l", "cortex-a8")
- .Cases("armv7f", "armv7-f", "cortex-a9-mp")
- .Cases("armv7s", "armv7-s", "swift")
- .Cases("armv7r", "armv7-r", "cortex-r4")
- .Cases("armv7m", "armv7-m", "cortex-m3")
- .Cases("armv7em", "armv7e-m", "cortex-m4")
- .Cases("armv8", "armv8a", "armv8-a", "cortex-a53")
- .Case("ep9312", "ep9312")
- .Case("iwmmxt", "iwmmxt")
- .Case("xscale", "xscale")
- // If all else failed, return the most base CPU with thumb interworking
- // supported by LLVM.
- .Default(0);
-
- if (result)
- return result;
-
- return
- Triple.getEnvironment() == llvm::Triple::GNUEABIHF
- ? "arm1176jzf-s"
- : "arm7tdmi";
-}
-
-/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular
-/// CPU.
-//
-// FIXME: This is redundant with -mcpu, why does LLVM use this.
-// FIXME: tblgen this, or kill it!
-static const char *getLLVMArchSuffixForARM(StringRef CPU) {
- return llvm::StringSwitch<const char *>(CPU)
- .Case("strongarm", "v4")
- .Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "v4t")
- .Cases("arm720t", "arm9", "arm9tdmi", "v4t")
- .Cases("arm920", "arm920t", "arm922t", "v4t")
- .Cases("arm940t", "ep9312","v4t")
- .Cases("arm10tdmi", "arm1020t", "v5")
- .Cases("arm9e", "arm926ej-s", "arm946e-s", "v5e")
- .Cases("arm966e-s", "arm968e-s", "arm10e", "v5e")
- .Cases("arm1020e", "arm1022e", "xscale", "iwmmxt", "v5e")
- .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6")
- .Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
- .Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
- .Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7")
- .Cases("cortex-a9", "cortex-a12", "cortex-a15", "v7")
- .Cases("cortex-r4", "cortex-r5", "v7r")
- .Case("cortex-m0", "v6m")
- .Case("cortex-m3", "v7m")
- .Case("cortex-m4", "v7em")
- .Case("cortex-a9-mp", "v7f")
- .Case("swift", "v7s")
- .Cases("cortex-a53", "cortex-a57", "v8")
- .Default("");
-}
-
std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
types::ID InputType) const {
switch (getTriple().getArch()) {
@@ -265,7 +209,7 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
case llvm::Triple::x86_64: {
llvm::Triple Triple = getTriple();
- if (!Triple.isOSDarwin())
+ if (!Triple.isOSBinFormatMachO())
return getTripleString();
if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
@@ -278,23 +222,51 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
return Triple.getTriple();
}
case llvm::Triple::arm:
- case llvm::Triple::thumb: {
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb: {
// FIXME: Factor into subclasses.
llvm::Triple Triple = getTriple();
+ bool IsBigEndian = getTriple().getArch() == llvm::Triple::armeb ||
+ getTriple().getArch() == llvm::Triple::thumbeb;
+
+ // Handle pseudo-target flags '-mlittle-endian'/'-EL' and
+ // '-mbig-endian'/'-EB'.
+ if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian,
+ options::OPT_mbig_endian)) {
+ if (A->getOption().matches(options::OPT_mlittle_endian))
+ IsBigEndian = false;
+ else
+ IsBigEndian = true;
+ }
// Thumb2 is the default for V7 on Darwin.
//
// FIXME: Thumb should just be another -target-feaure, not in the triple.
- StringRef Suffix =
- getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple));
- bool ThumbDefault = Suffix.startswith("v6m") ||
- (Suffix.startswith("v7") && getTriple().isOSDarwin());
- std::string ArchName = "arm";
+ StringRef Suffix = Triple.isOSBinFormatMachO()
+ ? tools::arm::getLLVMArchSuffixForARM(tools::arm::getARMCPUForMArch(Args, Triple))
+ : tools::arm::getLLVMArchSuffixForARM(tools::arm::getARMTargetCPU(Args, Triple));
+ bool ThumbDefault = Suffix.startswith("v6m") || Suffix.startswith("v7m") ||
+ Suffix.startswith("v7em") ||
+ (Suffix.startswith("v7") && getTriple().isOSBinFormatMachO());
+ // FIXME: this is invalid for WindowsCE
+ if (getTriple().isOSWindows())
+ ThumbDefault = true;
+ std::string ArchName;
+ if (IsBigEndian)
+ ArchName = "armeb";
+ else
+ ArchName = "arm";
// Assembly files should start in ARM mode.
if (InputType != types::TY_PP_Asm &&
Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault))
- ArchName = "thumb";
+ {
+ if (IsBigEndian)
+ ArchName = "thumbeb";
+ else
+ ArchName = "thumb";
+ }
Triple.setArchName(ArchName + Suffix.str());
return Triple.getTriple();
@@ -304,13 +276,6 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
std::string ToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
types::ID InputType) const {
- // Diagnose use of Darwin OS deployment target arguments on non-Darwin.
- if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ,
- options::OPT_miphoneos_version_min_EQ,
- options::OPT_mios_simulator_version_min_EQ))
- getDriver().Diag(diag::err_drv_clang_unsupported)
- << A->getAsString(Args);
-
return ComputeLLVMTriple(Args, InputType);
}
@@ -323,6 +288,8 @@ void ToolChain::addClangTargetOptions(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
}
+void ToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {}
+
ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType(
const ArgList &Args) const
{
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 46883357e229..b46f69de96a3 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -10,6 +10,7 @@
#include "ToolChains.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/Version.h"
+#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
@@ -27,26 +28,33 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/system_error.h"
#include "llvm/Support/Program.h"
-
-// FIXME: This needs to be listed last until we fix the broken include guards
-// in these files and the LLVM config.h files.
-#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX
-
+#include "llvm/Support/raw_ostream.h"
#include <cstdlib> // ::getenv
+#include <system_error>
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;
-/// Darwin - Darwin tool chain for i386 and x86_64.
+MachO::MachO(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : ToolChain(D, Triple, Args) {
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+ if (getDriver().getInstalledDir() != getDriver().Dir)
+ getProgramPaths().push_back(getDriver().Dir);
-Darwin::Darwin(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
- : ToolChain(D, Triple, Args), TargetInitialized(false)
-{
+ // We expect 'as', 'ld', etc. to be adjacent to our install dir.
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+ if (getDriver().getInstalledDir() != getDriver().Dir)
+ getProgramPaths().push_back(getDriver().Dir);
+}
+
+/// Darwin - Darwin tool chain for i386 and x86_64.
+Darwin::Darwin(const Driver & D, const llvm::Triple & Triple,
+ const ArgList & Args)
+ : MachO(D, Triple, Args), TargetInitialized(false) {
// Compute the initial Darwin version from the triple
unsigned Major, Minor, Micro;
if (!Triple.getMacOSXVersion(Major, Minor, Micro))
@@ -67,7 +75,7 @@ Darwin::Darwin(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
<< Major << '.' << Minor << '.' << Micro;
}
-types::ID Darwin::LookupTypeForExtension(const char *Ext) const {
+types::ID MachO::LookupTypeForExtension(const char *Ext) const {
types::ID Ty = types::lookupTypeForExtension(Ext);
// Darwin always preprocesses assembly files (unless -x is used explicitly).
@@ -77,13 +85,13 @@ types::ID Darwin::LookupTypeForExtension(const char *Ext) const {
return Ty;
}
-bool Darwin::HasNativeLLVMSupport() const {
+bool MachO::HasNativeLLVMSupport() const {
return true;
}
/// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0.
ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const {
- if (isTargetIPhoneOS())
+ if (isTargetIOSBased())
return ObjCRuntime(ObjCRuntime::iOS, TargetVersion);
if (isNonFragile)
return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion);
@@ -92,10 +100,12 @@ ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const {
/// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2.
bool Darwin::hasBlocksRuntime() const {
- if (isTargetIPhoneOS())
+ if (isTargetIOSBased())
return !isIPhoneOSVersionLT(3, 2);
- else
+ else {
+ assert(isTargetMacOS() && "unexpected darwin target");
return !isMacosxVersionLT(10, 6);
+ }
}
static const char *GetArmArchForMArch(StringRef Value) {
@@ -109,11 +119,10 @@ static const char *GetArmArchForMArch(StringRef Value) {
.Cases("armv7a", "armv7-a", "armv7")
.Cases("armv7r", "armv7-r", "armv7")
.Cases("armv7em", "armv7e-m", "armv7em")
- .Cases("armv7f", "armv7-f", "armv7f")
.Cases("armv7k", "armv7-k", "armv7k")
.Cases("armv7m", "armv7-m", "armv7m")
.Cases("armv7s", "armv7-s", "armv7s")
- .Default(0);
+ .Default(nullptr);
}
static const char *GetArmArchForMCpu(StringRef Value) {
@@ -124,17 +133,27 @@ static const char *GetArmArchForMCpu(StringRef Value) {
.Case("xscale", "xscale")
.Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "arm1176jzf-s", "armv6")
.Case("cortex-m0", "armv6m")
- .Cases("cortex-a5", "cortex-a7", "cortex-a8", "armv7")
- .Cases("cortex-a9", "cortex-a12", "cortex-a15", "armv7")
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "cortex-a9-mp", "armv7")
+ .Cases("cortex-a9", "cortex-a12", "cortex-a15", "krait", "armv7")
.Cases("cortex-r4", "cortex-r5", "armv7r")
- .Case("cortex-a9-mp", "armv7f")
.Case("cortex-m3", "armv7m")
.Case("cortex-m4", "armv7em")
.Case("swift", "armv7s")
- .Default(0);
+ .Default(nullptr);
+}
+
+static bool isSoftFloatABI(const ArgList &Args) {
+ Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
+ options::OPT_mfloat_abi_EQ);
+ if (!A)
+ return false;
+
+ return A->getOption().matches(options::OPT_msoft_float) ||
+ (A->getOption().matches(options::OPT_mfloat_abi_EQ) &&
+ A->getValue() == StringRef("soft"));
}
-StringRef Darwin::getDarwinArchName(const ArgList &Args) const {
+StringRef MachO::getMachOArchName(const ArgList &Args) const {
switch (getTriple().getArch()) {
default:
return getArchName();
@@ -157,6 +176,17 @@ StringRef Darwin::getDarwinArchName(const ArgList &Args) const {
Darwin::~Darwin() {
}
+MachO::~MachO() {
+}
+
+
+std::string MachO::ComputeEffectiveClangTriple(const ArgList &Args,
+ types::ID InputType) const {
+ llvm::Triple Triple(ComputeLLVMTriple(Args, InputType));
+
+ return Triple.getTriple();
+}
+
std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args,
types::ID InputType) const {
llvm::Triple Triple(ComputeLLVMTriple(Args, InputType));
@@ -166,25 +196,17 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args,
if (!isTargetInitialized())
return Triple.getTriple();
- if (Triple.getArchName() == "thumbv6m" ||
- Triple.getArchName() == "thumbv7m" ||
- Triple.getArchName() == "thumbv7em") {
- // OS is ios or macosx unless it's the v6m or v7m.
- Triple.setOS(llvm::Triple::Darwin);
- Triple.setEnvironment(llvm::Triple::EABI);
- } else {
- SmallString<16> Str;
- Str += isTargetIPhoneOS() ? "ios" : "macosx";
- Str += getTargetVersion().getAsString();
- Triple.setOSName(Str);
- }
+ SmallString<16> Str;
+ Str += isTargetIOSBased() ? "ios" : "macosx";
+ Str += getTargetVersion().getAsString();
+ Triple.setOSName(Str);
return Triple.getTriple();
}
void Generic_ELF::anchor() {}
-Tool *Darwin::getTool(Action::ActionClass AC) const {
+Tool *MachO::getTool(Action::ActionClass AC) const {
switch (AC) {
case Action::LipoJobClass:
if (!Lipo)
@@ -194,7 +216,7 @@ Tool *Darwin::getTool(Action::ActionClass AC) const {
if (!Dsymutil)
Dsymutil.reset(new tools::darwin::Dsymutil(*this));
return Dsymutil.get();
- case Action::VerifyJobClass:
+ case Action::VerifyDebugInfoJobClass:
if (!VerifyDebug)
VerifyDebug.reset(new tools::darwin::VerifyDebug(*this));
return VerifyDebug.get();
@@ -203,30 +225,50 @@ Tool *Darwin::getTool(Action::ActionClass AC) const {
}
}
-Tool *Darwin::buildLinker() const {
+Tool *MachO::buildLinker() const {
return new tools::darwin::Link(*this);
}
-Tool *Darwin::buildAssembler() const {
+Tool *MachO::buildAssembler() const {
return new tools::darwin::Assemble(*this);
}
DarwinClang::DarwinClang(const Driver &D, const llvm::Triple& Triple,
const ArgList &Args)
- : Darwin(D, Triple, Args)
-{
- getProgramPaths().push_back(getDriver().getInstalledDir());
- if (getDriver().getInstalledDir() != getDriver().Dir)
- getProgramPaths().push_back(getDriver().Dir);
+ : Darwin(D, Triple, Args) {
+}
- // We expect 'as', 'ld', etc. to be adjacent to our install dir.
- getProgramPaths().push_back(getDriver().getInstalledDir());
- if (getDriver().getInstalledDir() != getDriver().Dir)
- getProgramPaths().push_back(getDriver().Dir);
+void DarwinClang::addClangWarningOptions(ArgStringList &CC1Args) const {
+ // For iOS, 64-bit, promote certain warnings to errors.
+ if (!isTargetMacOS() && getTriple().isArch64Bit()) {
+ // Always enable -Wdeprecated-objc-isa-usage and promote it
+ // to an error.
+ CC1Args.push_back("-Wdeprecated-objc-isa-usage");
+ CC1Args.push_back("-Werror=deprecated-objc-isa-usage");
+
+ // Also error about implicit function declarations, as that
+ // can impact calling conventions.
+ CC1Args.push_back("-Werror=implicit-function-declaration");
+ }
+}
+
+/// \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);
}
void DarwinClang::AddLinkARCArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
+ // Avoid linking compatibility stubs on i386 mac.
+ if (isTargetMacOS() && getArch() == llvm::Triple::x86)
+ return;
+
+ ObjCRuntime runtime = getDefaultObjCRuntime(/*nonfragile*/ true);
+
+ if ((runtime.hasNativeARC() || !isObjCAutoRefCount(Args)) &&
+ runtime.hasSubscripting())
+ return;
CmdArgs.push_back("-force_load");
SmallString<128> P(getDriver().ClangExecutable);
@@ -245,12 +287,12 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString(P));
}
-void DarwinClang::AddLinkRuntimeLib(const ArgList &Args,
- ArgStringList &CmdArgs,
- const char *DarwinStaticLib,
- bool AlwaysLink) const {
+void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs,
+ StringRef DarwinStaticLib, bool AlwaysLink,
+ bool IsEmbedded) const {
SmallString<128> P(getDriver().ResourceDir);
- llvm::sys::path::append(P, "lib", "darwin", DarwinStaticLib);
+ llvm::sys::path::append(P, "lib", IsEmbedded ? "macho_embedded" : "darwin",
+ DarwinStaticLib);
// For now, allow missing resource libraries to support developers who may
// not have compiler-rt checked out or integrated into their build (unless
@@ -290,14 +332,14 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
// If we are building profile support, link that library in.
if (Args.hasArg(options::OPT_fprofile_arcs) ||
Args.hasArg(options::OPT_fprofile_generate) ||
+ Args.hasArg(options::OPT_fprofile_instr_generate) ||
Args.hasArg(options::OPT_fcreate_profile) ||
Args.hasArg(options::OPT_coverage)) {
// Select the appropriate runtime library for the target.
- if (isTargetIPhoneOS()) {
+ if (isTargetIOSBased())
AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.profile_ios.a");
- } else {
+ else
AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.profile_osx.a");
- }
}
const SanitizerArgs &Sanitize = getSanitizerArgs();
@@ -305,10 +347,11 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
// Add Ubsan runtime library, if required.
if (Sanitize.needsUbsanRt()) {
// FIXME: Move this check to SanitizerArgs::filterUnsupportedKinds.
- if (isTargetIPhoneOS()) {
+ if (isTargetIOSBased()) {
getDriver().Diag(diag::err_drv_clang_unsupported_per_platform)
<< "-fsanitize=undefined";
} else {
+ assert(isTargetMacOS() && "unexpected non OS X target");
AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ubsan_osx.a", true);
// The Ubsan runtime library requires C++.
@@ -320,7 +363,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
// should not be linked with the runtime library.
if (Sanitize.needsAsanRt()) {
// FIXME: Move this check to SanitizerArgs::filterUnsupportedKinds.
- if (isTargetIPhoneOS() && !isTargetIOSSimulator()) {
+ if (isTargetIPhoneOS()) {
getDriver().Diag(diag::err_drv_clang_unsupported_per_platform)
<< "-fsanitize=address";
} else {
@@ -348,16 +391,19 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
CmdArgs.push_back("-lSystem");
// Select the dynamic runtime library and the target specific static library.
- if (isTargetIPhoneOS()) {
+ if (isTargetIOSBased()) {
// If we are compiling as iOS / simulator, don't attempt to link libgcc_s.1,
// it never went into the SDK.
// Linking against libgcc_s.1 isn't needed for iOS 5.0+
- if (isIPhoneOSVersionLT(5, 0) && !isTargetIOSSimulator())
+ if (isIPhoneOSVersionLT(5, 0) && !isTargetIOSSimulator() &&
+ (getTriple().getArch() != llvm::Triple::arm64 &&
+ getTriple().getArch() != llvm::Triple::aarch64))
CmdArgs.push_back("-lgcc_s.1");
// We currently always need a static runtime library for iOS.
AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ios.a");
} else {
+ assert(isTargetMacOS() && "unexpected non MacOS platform");
// The dynamic runtime library was merged with libSystem for 10.6 and
// beyond; only 10.4 and 10.5 need an additional runtime library.
if (isMacosxVersionLT(10, 5))
@@ -400,7 +446,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
if (llvm::sys::path::is_absolute(env) && llvm::sys::fs::exists(env) &&
StringRef(env) != "/") {
Args.append(Args.MakeSeparateArg(
- 0, Opts.getOption(options::OPT_isysroot), env));
+ nullptr, Opts.getOption(options::OPT_isysroot), env));
}
}
}
@@ -414,12 +460,12 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
getDriver().Diag(diag::err_drv_argument_not_allowed_with)
<< OSXVersion->getAsString(Args)
<< (iOSVersion ? iOSVersion : iOSSimVersion)->getAsString(Args);
- iOSVersion = iOSSimVersion = 0;
+ iOSVersion = iOSSimVersion = nullptr;
} else if (iOSVersion && iOSSimVersion) {
getDriver().Diag(diag::err_drv_argument_not_allowed_with)
<< iOSVersion->getAsString(Args)
<< iOSSimVersion->getAsString(Args);
- iOSSimVersion = 0;
+ iOSSimVersion = nullptr;
} else if (!OSXVersion && !iOSVersion && !iOSSimVersion) {
// If no deployment target was specified on the command line, check for
// environment defines.
@@ -440,7 +486,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
StringRef first, second;
StringRef isysroot = A->getValue();
- llvm::tie(first, second) = isysroot.split(StringRef("SDKs/iPhoneOS"));
+ std::tie(first, second) = isysroot.split(StringRef("SDKs/iPhoneOS"));
if (second != "")
iOSTarget = second.substr(0,3);
}
@@ -448,9 +494,10 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
// If no OSX or iOS target has been specified and we're compiling for armv7,
// go ahead as assume we're targeting iOS.
+ StringRef MachOArchName = getMachOArchName(Args);
if (OSXTarget.empty() && iOSTarget.empty() &&
- (getDarwinArchName(Args) == "armv7" ||
- getDarwinArchName(Args) == "armv7s"))
+ (MachOArchName == "armv7" || MachOArchName == "armv7s" ||
+ MachOArchName == "arm64"))
iOSTarget = iOSVersionMin;
// Handle conflicting deployment targets
@@ -469,6 +516,8 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
// default platform.
if (!OSXTarget.empty() && !iOSTarget.empty()) {
if (getTriple().getArch() == llvm::Triple::arm ||
+ getTriple().getArch() == llvm::Triple::arm64 ||
+ getTriple().getArch() == llvm::Triple::aarch64 ||
getTriple().getArch() == llvm::Triple::thumb)
OSXTarget = "";
else
@@ -477,25 +526,36 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
if (!OSXTarget.empty()) {
const Option O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
- OSXVersion = Args.MakeJoinedArg(0, O, OSXTarget);
+ OSXVersion = Args.MakeJoinedArg(nullptr, O, OSXTarget);
Args.append(OSXVersion);
} else if (!iOSTarget.empty()) {
const Option O = Opts.getOption(options::OPT_miphoneos_version_min_EQ);
- iOSVersion = Args.MakeJoinedArg(0, O, iOSTarget);
+ iOSVersion = Args.MakeJoinedArg(nullptr, O, iOSTarget);
Args.append(iOSVersion);
} else if (!iOSSimTarget.empty()) {
const Option O = Opts.getOption(
options::OPT_mios_simulator_version_min_EQ);
- iOSSimVersion = Args.MakeJoinedArg(0, O, iOSSimTarget);
+ iOSSimVersion = Args.MakeJoinedArg(nullptr, O, iOSSimTarget);
Args.append(iOSSimVersion);
- } else {
+ } else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" &&
+ MachOArchName != "armv7em") {
// Otherwise, assume we are targeting OS X.
const Option O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
- OSXVersion = Args.MakeJoinedArg(0, O, MacosxVersionMin);
+ OSXVersion = Args.MakeJoinedArg(nullptr, O, MacosxVersionMin);
Args.append(OSXVersion);
}
}
+ DarwinPlatformKind Platform;
+ if (OSXVersion)
+ Platform = MacOS;
+ else if (iOSVersion)
+ Platform = IPhoneOS;
+ else if (iOSSimVersion)
+ Platform = IPhoneOSSimulator;
+ else
+ llvm_unreachable("Unable to infer Darwin variant");
+
// Reject invalid architecture combinations.
if (iOSSimVersion && (getTriple().getArch() != llvm::Triple::x86 &&
getTriple().getArch() != llvm::Triple::x86_64)) {
@@ -506,14 +566,14 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
// Set the tool chain target information.
unsigned Major, Minor, Micro;
bool HadExtra;
- if (OSXVersion) {
+ if (Platform == MacOS) {
assert((!iOSVersion && !iOSSimVersion) && "Unknown target platform!");
if (!Driver::GetReleaseVersion(OSXVersion->getValue(), Major, Minor,
Micro, HadExtra) || HadExtra ||
Major != 10 || Minor >= 100 || Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
<< OSXVersion->getAsString(Args);
- } else {
+ } else if (Platform == IPhoneOS || Platform == IPhoneOSSimulator) {
const Arg *Version = iOSVersion ? iOSVersion : iOSSimVersion;
assert(Version && "Unknown target platform!");
if (!Driver::GetReleaseVersion(Version->getValue(), Major, Minor,
@@ -521,9 +581,8 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
Major >= 10 || Minor >= 100 || Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
<< Version->getAsString(Args);
- }
-
- bool IsIOSSim = bool(iOSSimVersion);
+ } else
+ llvm_unreachable("unknown kind of Darwin platform");
// In GCC, the simulator historically was treated as being OS X in some
// contexts, like determining the link logic, despite generally being called
@@ -531,9 +590,9 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
// simulator as iOS + x86, and treat it differently in a few contexts.
if (iOSVersion && (getTriple().getArch() == llvm::Triple::x86 ||
getTriple().getArch() == llvm::Triple::x86_64))
- IsIOSSim = true;
+ Platform = IPhoneOSSimulator;
- setTarget(/*IsIPhoneOS=*/ !OSXVersion, Major, Minor, Micro, IsIOSSim);
+ setTarget(Platform, Major, Minor, Micro);
}
void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args,
@@ -594,6 +653,8 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args,
// Use the newer cc_kext for iOS ARM after 6.0.
if (!isTargetIPhoneOS() || isTargetIOSSimulator() ||
+ getTriple().getArch() == llvm::Triple::arm64 ||
+ getTriple().getArch() == llvm::Triple::aarch64 ||
!isIPhoneOSVersionLT(6, 0)) {
llvm::sys::path::append(P, "libclang_rt.cc_kext.a");
} else {
@@ -606,8 +667,8 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString(P.str()));
}
-DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
- const char *BoundArch) const {
+DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args,
+ const char *BoundArch) const {
DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
const OptTable &Opts = getDriver().getOpts();
@@ -618,24 +679,21 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
// have something that works, we should reevaluate each translation
// and try to push it down into tool specific logic.
- for (ArgList::const_iterator it = Args.begin(),
- ie = Args.end(); it != ie; ++it) {
- Arg *A = *it;
-
+ for (Arg *A : Args) {
if (A->getOption().matches(options::OPT_Xarch__)) {
// Skip this argument unless the architecture matches either the toolchain
// triple arch, or the arch being bound.
llvm::Triple::ArchType XarchArch =
- tools::darwin::getArchTypeForDarwinArchName(A->getValue(0));
+ tools::darwin::getArchTypeForMachOArchName(A->getValue(0));
if (!(XarchArch == getArch() ||
(BoundArch && XarchArch ==
- tools::darwin::getArchTypeForDarwinArchName(BoundArch))))
+ tools::darwin::getArchTypeForMachOArchName(BoundArch))))
continue;
Arg *OriginalArg = A;
unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1));
unsigned Prev = Index;
- Arg *XarchArg = Opts.ParseOneArg(Args, Index);
+ std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index));
// If the argument parsing failed or more than one argument was
// consumed, the -Xarch_ argument's parameter tried to consume
@@ -656,8 +714,8 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
}
XarchArg->setBaseArg(A);
- A = XarchArg;
+ A = XarchArg.release();
DAL->AddSynthesizedArg(A);
// Linker input arguments require custom handling. The problem is that we
@@ -741,7 +799,8 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
if (getTriple().getArch() == llvm::Triple::x86 ||
getTriple().getArch() == llvm::Triple::x86_64)
if (!Args.hasArgNoClaim(options::OPT_mtune_EQ))
- DAL->AddJoinedArg(0, Opts.getOption(options::OPT_mtune_EQ), "core2");
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mtune_EQ),
+ "core2");
// Add the arch options based on the particular spelling of -arch, to match
// how the driver driver works.
@@ -755,89 +814,114 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
if (Name == "ppc")
;
else if (Name == "ppc601")
- DAL->AddJoinedArg(0, MCpu, "601");
+ DAL->AddJoinedArg(nullptr, MCpu, "601");
else if (Name == "ppc603")
- DAL->AddJoinedArg(0, MCpu, "603");
+ DAL->AddJoinedArg(nullptr, MCpu, "603");
else if (Name == "ppc604")
- DAL->AddJoinedArg(0, MCpu, "604");
+ DAL->AddJoinedArg(nullptr, MCpu, "604");
else if (Name == "ppc604e")
- DAL->AddJoinedArg(0, MCpu, "604e");
+ DAL->AddJoinedArg(nullptr, MCpu, "604e");
else if (Name == "ppc750")
- DAL->AddJoinedArg(0, MCpu, "750");
+ DAL->AddJoinedArg(nullptr, MCpu, "750");
else if (Name == "ppc7400")
- DAL->AddJoinedArg(0, MCpu, "7400");
+ DAL->AddJoinedArg(nullptr, MCpu, "7400");
else if (Name == "ppc7450")
- DAL->AddJoinedArg(0, MCpu, "7450");
+ DAL->AddJoinedArg(nullptr, MCpu, "7450");
else if (Name == "ppc970")
- DAL->AddJoinedArg(0, MCpu, "970");
+ DAL->AddJoinedArg(nullptr, MCpu, "970");
else if (Name == "ppc64" || Name == "ppc64le")
- DAL->AddFlagArg(0, Opts.getOption(options::OPT_m64));
+ DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64));
else if (Name == "i386")
;
else if (Name == "i486")
- DAL->AddJoinedArg(0, MArch, "i486");
+ DAL->AddJoinedArg(nullptr, MArch, "i486");
else if (Name == "i586")
- DAL->AddJoinedArg(0, MArch, "i586");
+ DAL->AddJoinedArg(nullptr, MArch, "i586");
else if (Name == "i686")
- DAL->AddJoinedArg(0, MArch, "i686");
+ DAL->AddJoinedArg(nullptr, MArch, "i686");
else if (Name == "pentium")
- DAL->AddJoinedArg(0, MArch, "pentium");
+ DAL->AddJoinedArg(nullptr, MArch, "pentium");
else if (Name == "pentium2")
- DAL->AddJoinedArg(0, MArch, "pentium2");
+ DAL->AddJoinedArg(nullptr, MArch, "pentium2");
else if (Name == "pentpro")
- DAL->AddJoinedArg(0, MArch, "pentiumpro");
+ DAL->AddJoinedArg(nullptr, MArch, "pentiumpro");
else if (Name == "pentIIm3")
- DAL->AddJoinedArg(0, MArch, "pentium2");
+ DAL->AddJoinedArg(nullptr, MArch, "pentium2");
else if (Name == "x86_64")
- DAL->AddFlagArg(0, Opts.getOption(options::OPT_m64));
+ DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64));
else if (Name == "x86_64h") {
- DAL->AddFlagArg(0, Opts.getOption(options::OPT_m64));
- DAL->AddJoinedArg(0, MArch, "x86_64h");
+ DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64));
+ DAL->AddJoinedArg(nullptr, MArch, "x86_64h");
}
else if (Name == "arm")
- DAL->AddJoinedArg(0, MArch, "armv4t");
+ DAL->AddJoinedArg(nullptr, MArch, "armv4t");
else if (Name == "armv4t")
- DAL->AddJoinedArg(0, MArch, "armv4t");
+ DAL->AddJoinedArg(nullptr, MArch, "armv4t");
else if (Name == "armv5")
- DAL->AddJoinedArg(0, MArch, "armv5tej");
+ DAL->AddJoinedArg(nullptr, MArch, "armv5tej");
else if (Name == "xscale")
- DAL->AddJoinedArg(0, MArch, "xscale");
+ DAL->AddJoinedArg(nullptr, MArch, "xscale");
else if (Name == "armv6")
- DAL->AddJoinedArg(0, MArch, "armv6k");
+ DAL->AddJoinedArg(nullptr, MArch, "armv6k");
else if (Name == "armv6m")
- DAL->AddJoinedArg(0, MArch, "armv6m");
+ DAL->AddJoinedArg(nullptr, MArch, "armv6m");
else if (Name == "armv7")
- DAL->AddJoinedArg(0, MArch, "armv7a");
+ DAL->AddJoinedArg(nullptr, MArch, "armv7a");
else if (Name == "armv7em")
- DAL->AddJoinedArg(0, MArch, "armv7em");
- else if (Name == "armv7f")
- DAL->AddJoinedArg(0, MArch, "armv7f");
+ DAL->AddJoinedArg(nullptr, MArch, "armv7em");
else if (Name == "armv7k")
- DAL->AddJoinedArg(0, MArch, "armv7k");
+ DAL->AddJoinedArg(nullptr, MArch, "armv7k");
else if (Name == "armv7m")
- DAL->AddJoinedArg(0, MArch, "armv7m");
+ DAL->AddJoinedArg(nullptr, MArch, "armv7m");
else if (Name == "armv7s")
- DAL->AddJoinedArg(0, MArch, "armv7s");
-
- else
- llvm_unreachable("invalid Darwin arch");
+ DAL->AddJoinedArg(nullptr, MArch, "armv7s");
}
+ return DAL;
+}
+
+void MachO::AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const {
+ // Embedded targets are simple at the moment, not supporting sanitizers and
+ // with different libraries for each member of the product { static, PIC } x
+ // { hard-float, soft-float }
+ llvm::SmallString<32> CompilerRT = StringRef("libclang_rt.");
+ CompilerRT +=
+ tools::arm::getARMFloatABI(getDriver(), Args, getTriple()) == "hard"
+ ? "hard"
+ : "soft";
+ CompilerRT += Args.hasArg(options::OPT_fPIC) ? "_pic.a" : "_static.a";
+
+ AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, false, true);
+}
+
+
+DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
+ const char *BoundArch) const {
+ // First get the generic Apple args, before moving onto Darwin-specific ones.
+ DerivedArgList *DAL = MachO::TranslateArgs(Args, BoundArch);
+ const OptTable &Opts = getDriver().getOpts();
+
+ // If no architecture is bound, none of the translations here are relevant.
+ if (!BoundArch)
+ return DAL;
+
// Add an explicit version min argument for the deployment target. We do this
// after argument translation because -Xarch_ arguments may add a version min
// argument.
- if (BoundArch)
- AddDeploymentTarget(*DAL);
+ AddDeploymentTarget(*DAL);
// For iOS 6, undo the translation to add -static for -mkernel/-fapple-kext.
// FIXME: It would be far better to avoid inserting those -static arguments,
// but we can't check the deployment target in the translation code until
// it is set here.
- if (isTargetIPhoneOS() && !isIPhoneOSVersionLT(6, 0)) {
+ if (isTargetIOSBased() && !isIPhoneOSVersionLT(6, 0) &&
+ getTriple().getArch() != llvm::Triple::arm64 &&
+ getTriple().getArch() != llvm::Triple::aarch64) {
for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) {
Arg *A = *it;
++it;
@@ -854,9 +938,10 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
// Default to use libc++ on OS X 10.9+ and iOS 7+.
if (((isTargetMacOS() && !isMacosxVersionLT(10, 9)) ||
- (isTargetIPhoneOS() && !isIPhoneOSVersionLT(7, 0))) &&
+ (isTargetIOSBased() && !isIPhoneOSVersionLT(7, 0))) &&
!Args.getLastArg(options::OPT_stdlib_EQ))
- DAL->AddJoinedArg(0, Opts.getOption(options::OPT_stdlib_EQ), "libc++");
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_stdlib_EQ),
+ "libc++");
// Validate the C++ standard library choice.
CXXStdlibType Type = GetCXXStdlibType(*DAL);
@@ -864,8 +949,8 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
// Check whether the target provides libc++.
StringRef where;
- // Complain about targetting iOS < 5.0 in any way.
- if (isTargetIPhoneOS() && isIPhoneOSVersionLT(5, 0))
+ // Complain about targeting iOS < 5.0 in any way.
+ if (isTargetIOSBased() && isIPhoneOSVersionLT(5, 0))
where = "iOS 5.0";
if (where != StringRef()) {
@@ -877,11 +962,11 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
return DAL;
}
-bool Darwin::IsUnwindTablesDefault() const {
+bool MachO::IsUnwindTablesDefault() const {
return getArch() == llvm::Triple::x86_64;
}
-bool Darwin::UseDwarfDebugFlags() const {
+bool MachO::UseDwarfDebugFlags() const {
if (const char *S = ::getenv("RC_DEBUG_OPTIONS"))
return S[0] != '\0';
return false;
@@ -893,40 +978,145 @@ bool Darwin::UseSjLjExceptions() const {
getTriple().getArch() == llvm::Triple::thumb);
}
-bool Darwin::isPICDefault() const {
+bool MachO::isPICDefault() const {
return true;
}
-bool Darwin::isPIEDefault() const {
+bool MachO::isPIEDefault() const {
return false;
}
-bool Darwin::isPICDefaultForced() const {
- return getArch() == llvm::Triple::x86_64;
+bool MachO::isPICDefaultForced() const {
+ return (getArch() == llvm::Triple::x86_64 ||
+ getArch() == llvm::Triple::arm64 ||
+ getArch() == llvm::Triple::aarch64);
}
-bool Darwin::SupportsProfiling() const {
+bool MachO::SupportsProfiling() const {
// Profiling instrumentation is only supported on x86.
return getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64;
}
+void Darwin::addMinVersionArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const {
+ VersionTuple TargetVersion = getTargetVersion();
+
+ // If we had an explicit -mios-simulator-version-min argument, honor that,
+ // otherwise use the traditional deployment targets. We can't just check the
+ // is-sim attribute because existing code follows this path, and the linker
+ // may not handle the argument.
+ //
+ // FIXME: We may be able to remove this, once we can verify no one depends on
+ // it.
+ if (Args.hasArg(options::OPT_mios_simulator_version_min_EQ))
+ CmdArgs.push_back("-ios_simulator_version_min");
+ else if (isTargetIOSBased())
+ CmdArgs.push_back("-iphoneos_version_min");
+ else {
+ assert(isTargetMacOS() && "unexpected target");
+ CmdArgs.push_back("-macosx_version_min");
+ }
+
+ CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString()));
+}
+
+void Darwin::addStartObjectFileArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const {
+ // Derived from startfile spec.
+ if (Args.hasArg(options::OPT_dynamiclib)) {
+ // Derived from darwin_dylib1 spec.
+ if (isTargetIOSSimulator()) {
+ ; // iOS simulator does not need dylib1.o.
+ } else if (isTargetIPhoneOS()) {
+ if (isIPhoneOSVersionLT(3, 1))
+ CmdArgs.push_back("-ldylib1.o");
+ } else {
+ if (isMacosxVersionLT(10, 5))
+ CmdArgs.push_back("-ldylib1.o");
+ else if (isMacosxVersionLT(10, 6))
+ CmdArgs.push_back("-ldylib1.10.5.o");
+ }
+ } else {
+ if (Args.hasArg(options::OPT_bundle)) {
+ if (!Args.hasArg(options::OPT_static)) {
+ // Derived from darwin_bundle1 spec.
+ if (isTargetIOSSimulator()) {
+ ; // iOS simulator does not need bundle1.o.
+ } else if (isTargetIPhoneOS()) {
+ if (isIPhoneOSVersionLT(3, 1))
+ CmdArgs.push_back("-lbundle1.o");
+ } else {
+ if (isMacosxVersionLT(10, 6))
+ CmdArgs.push_back("-lbundle1.o");
+ }
+ }
+ } else {
+ if (Args.hasArg(options::OPT_pg) && SupportsProfiling()) {
+ if (Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_object) ||
+ Args.hasArg(options::OPT_preload)) {
+ CmdArgs.push_back("-lgcrt0.o");
+ } else {
+ CmdArgs.push_back("-lgcrt1.o");
+
+ // darwin_crt2 spec is empty.
+ }
+ // By default on OS X 10.8 and later, we don't link with a crt1.o
+ // file and the linker knows to use _main as the entry point. But,
+ // when compiling with -pg, we need to link with the gcrt1.o file,
+ // so pass the -no_new_main option to tell the linker to use the
+ // "start" symbol as the entry point.
+ if (isTargetMacOS() && !isMacosxVersionLT(10, 8))
+ CmdArgs.push_back("-no_new_main");
+ } else {
+ if (Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_object) ||
+ Args.hasArg(options::OPT_preload)) {
+ CmdArgs.push_back("-lcrt0.o");
+ } else {
+ // Derived from darwin_crt1 spec.
+ if (isTargetIOSSimulator()) {
+ ; // iOS simulator does not need crt1.o.
+ } else if (isTargetIPhoneOS()) {
+ if (getArch() == llvm::Triple::arm64 ||
+ getArch() == llvm::Triple::aarch64)
+ ; // iOS does not need any crt1 files for arm64
+ else if (isIPhoneOSVersionLT(3, 1))
+ CmdArgs.push_back("-lcrt1.o");
+ else if (isIPhoneOSVersionLT(6, 0))
+ CmdArgs.push_back("-lcrt1.3.1.o");
+ } else {
+ if (isMacosxVersionLT(10, 5))
+ CmdArgs.push_back("-lcrt1.o");
+ else if (isMacosxVersionLT(10, 6))
+ CmdArgs.push_back("-lcrt1.10.5.o");
+ else if (isMacosxVersionLT(10, 8))
+ CmdArgs.push_back("-lcrt1.10.6.o");
+
+ // darwin_crt2 spec is empty.
+ }
+ }
+ }
+ }
+ }
+
+ if (!isTargetIPhoneOS() && Args.hasArg(options::OPT_shared_libgcc) &&
+ isMacosxVersionLT(10, 5)) {
+ const char *Str = Args.MakeArgString(GetFilePath("crt3.o"));
+ CmdArgs.push_back(Str);
+ }
+}
+
bool Darwin::SupportsObjCGC() const {
- // Garbage collection is supported everywhere except on iPhone OS.
- return !isTargetIPhoneOS();
+ return isTargetMacOS();
}
void Darwin::CheckObjCARC() const {
- if (isTargetIPhoneOS() || !isMacosxVersionLT(10, 6))
+ if (isTargetIOSBased()|| (isTargetMacOS() && !isMacosxVersionLT(10, 6)))
return;
getDriver().Diag(diag::err_arc_unsupported_on_toolchain);
}
-std::string
-Darwin_Generic_GCC::ComputeEffectiveClangTriple(const ArgList &Args,
- types::ID InputType) const {
- return ComputeLLVMTriple(Args, InputType);
-}
-
/// Generic_GCC - A tool chain using the 'gcc' command to perform
/// all subcommands; this relies on gcc translating the majority of
/// command line options.
@@ -1007,14 +1197,14 @@ bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor,
return false;
}
-static StringRef getGCCToolchainDir(const ArgList &Args) {
+static llvm::StringRef getGCCToolchainDir(const ArgList &Args) {
const Arg *A = Args.getLastArg(options::OPT_gcc_toolchain);
if (A)
return A->getValue();
return GCC_INSTALL_PREFIX;
}
-/// \brief Construct a GCCInstallationDetector from the driver.
+/// \brief Initialize a GCCInstallationDetector from the driver.
///
/// This performs all of the autodetection and sets up the various paths.
/// Once constructed, a GCCInstallationDetector is essentially immutable.
@@ -1023,13 +1213,12 @@ static StringRef getGCCToolchainDir(const ArgList &Args) {
/// should instead pull the target out of the driver. This is currently
/// necessary because the driver doesn't store the final version of the target
/// triple.
-Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
- const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args)
- : IsValid(false), D(D) {
+void
+Generic_GCC::GCCInstallationDetector::init(
+ const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args) {
llvm::Triple BiarchVariantTriple =
TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant()
: TargetTriple.get32BitArchVariant();
- llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
// The library directories which may contain GCC installations.
SmallVector<StringRef, 4> CandidateLibDirs, CandidateBiarchLibDirs;
// The compatible GCC triples for this particular architecture.
@@ -1075,7 +1264,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
if (!llvm::sys::fs::exists(LibDir))
continue;
for (unsigned k = 0, ke = CandidateTripleAliases.size(); k < ke; ++k)
- ScanLibDirForGCCTriple(TargetArch, Args, LibDir,
+ ScanLibDirForGCCTriple(TargetTriple, Args, LibDir,
CandidateTripleAliases[k]);
}
for (unsigned j = 0, je = CandidateBiarchLibDirs.size(); j < je; ++j) {
@@ -1084,7 +1273,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
continue;
for (unsigned k = 0, ke = CandidateBiarchTripleAliases.size(); k < ke;
++k)
- ScanLibDirForGCCTriple(TargetArch, Args, LibDir,
+ ScanLibDirForGCCTriple(TargetTriple, Args, LibDir,
CandidateBiarchTripleAliases[k],
/*NeedsBiarchSuffix=*/ true);
}
@@ -1092,13 +1281,25 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
}
void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
- for (std::set<std::string>::const_iterator
- I = CandidateGCCInstallPaths.begin(),
- E = CandidateGCCInstallPaths.end();
- I != E; ++I)
- OS << "Found candidate GCC installation: " << *I << "\n";
+ for (const auto &InstallPath : CandidateGCCInstallPaths)
+ OS << "Found candidate GCC installation: " << InstallPath << "\n";
+
+ if (!GCCInstallPath.empty())
+ OS << "Selected GCC installation: " << GCCInstallPath << "\n";
- OS << "Selected GCC installation: " << GCCInstallPath << "\n";
+ for (const auto &Multilib : Multilibs)
+ OS << "Candidate multilib: " << Multilib << "\n";
+
+ if (Multilibs.size() != 0 || !SelectedMultilib.isDefault())
+ OS << "Selected multilib: " << SelectedMultilib << "\n";
+}
+
+bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
+ if (BiarchSibling.hasValue()) {
+ M = BiarchSibling.getValue();
+ return true;
+ }
+ return false;
}
/*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples(
@@ -1110,43 +1311,62 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
// Declare a bunch of static data sets that we'll select between below. These
// are specifically designed to always refer to string literals to avoid any
// lifetime or initialization issues.
- static const char *const AArch64LibDirs[] = { "/lib" };
+ static const char *const AArch64LibDirs[] = { "/lib64", "/lib" };
static const char *const AArch64Triples[] = { "aarch64-none-linux-gnu",
- "aarch64-linux-gnu" };
+ "aarch64-linux-gnu",
+ "aarch64-linux-android",
+ "aarch64-redhat-linux" };
+ static const char *const AArch64beLibDirs[] = { "/lib" };
+ static const char *const AArch64beTriples[] = { "aarch64_be-none-linux-gnu",
+ "aarch64_be-linux-gnu" };
static const char *const ARMLibDirs[] = { "/lib" };
static const char *const ARMTriples[] = { "arm-linux-gnueabi",
"arm-linux-androideabi" };
static const char *const ARMHFTriples[] = { "arm-linux-gnueabihf",
"armv7hl-redhat-linux-gnueabi" };
+ static const char *const ARMebLibDirs[] = { "/lib" };
+ static const char *const ARMebTriples[] = { "armeb-linux-gnueabi",
+ "armeb-linux-androideabi" };
+ static const char *const ARMebHFTriples[] = { "armeb-linux-gnueabihf",
+ "armebv7hl-redhat-linux-gnueabi" };
static const char *const X86_64LibDirs[] = { "/lib64", "/lib" };
static const char *const X86_64Triples[] = {
"x86_64-linux-gnu", "x86_64-unknown-linux-gnu", "x86_64-pc-linux-gnu",
"x86_64-redhat-linux6E", "x86_64-redhat-linux", "x86_64-suse-linux",
- "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", "x86_64-slackware-linux"
+ "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", "x86_64-slackware-linux",
+ "x86_64-linux-android", "x86_64-unknown-linux"
};
+ static const char *const X32LibDirs[] = { "/libx32" };
static const char *const X86LibDirs[] = { "/lib32", "/lib" };
static const char *const X86Triples[] = {
"i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu", "i386-linux-gnu",
"i386-redhat-linux6E", "i686-redhat-linux", "i586-redhat-linux",
"i386-redhat-linux", "i586-suse-linux", "i486-slackware-linux",
- "i686-montavista-linux"
+ "i686-montavista-linux", "i686-linux-android", "i586-linux-gnu"
};
static const char *const MIPSLibDirs[] = { "/lib" };
static const char *const MIPSTriples[] = { "mips-linux-gnu",
- "mips-mti-linux-gnu" };
+ "mips-mti-linux-gnu",
+ "mips-img-linux-gnu" };
static const char *const MIPSELLibDirs[] = { "/lib" };
static const char *const MIPSELTriples[] = { "mipsel-linux-gnu",
- "mipsel-linux-android" };
+ "mipsel-linux-android",
+ "mips-img-linux-gnu" };
static const char *const MIPS64LibDirs[] = { "/lib64", "/lib" };
static const char *const MIPS64Triples[] = { "mips64-linux-gnu",
- "mips-mti-linux-gnu" };
+ "mips-mti-linux-gnu",
+ "mips-img-linux-gnu",
+ "mips64-linux-gnuabi64" };
static const char *const MIPS64ELLibDirs[] = { "/lib64", "/lib" };
static const char *const MIPS64ELTriples[] = { "mips64el-linux-gnu",
- "mips-mti-linux-gnu" };
+ "mips-mti-linux-gnu",
+ "mips-img-linux-gnu",
+ "mips64el-linux-android",
+ "mips64el-linux-gnuabi64" };
static const char *const PPCLibDirs[] = { "/lib32", "/lib" };
static const char *const PPCTriples[] = {
@@ -1164,6 +1384,13 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
"powerpc64le-suse-linux",
"ppc64le-redhat-linux" };
+ static const char *const SPARCv8LibDirs[] = { "/lib32", "/lib" };
+ static const char *const SPARCv8Triples[] = { "sparc-linux-gnu",
+ "sparcv8-linux-gnu" };
+ static const char *const SPARCv9LibDirs[] = { "/lib64", "/lib" };
+ static const char *const SPARCv9Triples[] = { "sparc64-linux-gnu",
+ "sparcv9-linux-gnu" };
+
static const char *const SystemZLibDirs[] = { "/lib64", "/lib" };
static const char *const SystemZTriples[] = {
"s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu",
@@ -1171,6 +1398,7 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
};
switch (TargetTriple.getArch()) {
+ case llvm::Triple::arm64:
case llvm::Triple::aarch64:
LibDirs.append(AArch64LibDirs,
AArch64LibDirs + llvm::array_lengthof(AArch64LibDirs));
@@ -1181,6 +1409,17 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
BiarchTripleAliases.append(
AArch64Triples, AArch64Triples + llvm::array_lengthof(AArch64Triples));
break;
+ case llvm::Triple::arm64_be:
+ case llvm::Triple::aarch64_be:
+ LibDirs.append(AArch64beLibDirs,
+ AArch64beLibDirs + llvm::array_lengthof(AArch64beLibDirs));
+ TripleAliases.append(AArch64beTriples,
+ AArch64beTriples + llvm::array_lengthof(AArch64beTriples));
+ BiarchLibDirs.append(AArch64beLibDirs,
+ AArch64beLibDirs + llvm::array_lengthof(AArch64beLibDirs));
+ BiarchTripleAliases.append(
+ AArch64beTriples, AArch64beTriples + llvm::array_lengthof(AArch64beTriples));
+ break;
case llvm::Triple::arm:
case llvm::Triple::thumb:
LibDirs.append(ARMLibDirs, ARMLibDirs + llvm::array_lengthof(ARMLibDirs));
@@ -1192,15 +1431,35 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
ARMTriples + llvm::array_lengthof(ARMTriples));
}
break;
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumbeb:
+ LibDirs.append(ARMebLibDirs, ARMebLibDirs + llvm::array_lengthof(ARMebLibDirs));
+ if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) {
+ TripleAliases.append(ARMebHFTriples,
+ ARMebHFTriples + llvm::array_lengthof(ARMebHFTriples));
+ } else {
+ TripleAliases.append(ARMebTriples,
+ ARMebTriples + llvm::array_lengthof(ARMebTriples));
+ }
+ break;
case llvm::Triple::x86_64:
LibDirs.append(X86_64LibDirs,
X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs));
TripleAliases.append(X86_64Triples,
X86_64Triples + llvm::array_lengthof(X86_64Triples));
- BiarchLibDirs.append(X86LibDirs,
- X86LibDirs + llvm::array_lengthof(X86LibDirs));
- BiarchTripleAliases.append(X86Triples,
- X86Triples + llvm::array_lengthof(X86Triples));
+ // x32 is always available when x86_64 is available, so adding it as secondary
+ // arch with x86_64 triples
+ if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) {
+ BiarchLibDirs.append(X32LibDirs,
+ X32LibDirs + llvm::array_lengthof(X32LibDirs));
+ BiarchTripleAliases.append(X86_64Triples,
+ X86_64Triples + llvm::array_lengthof(X86_64Triples));
+ } else {
+ BiarchLibDirs.append(X86LibDirs,
+ X86LibDirs + llvm::array_lengthof(X86LibDirs));
+ BiarchTripleAliases.append(X86Triples,
+ X86Triples + llvm::array_lengthof(X86Triples));
+ }
break;
case llvm::Triple::x86:
LibDirs.append(X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs));
@@ -1283,6 +1542,26 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
TripleAliases.append(PPC64LETriples,
PPC64LETriples + llvm::array_lengthof(PPC64LETriples));
break;
+ case llvm::Triple::sparc:
+ LibDirs.append(SPARCv8LibDirs,
+ SPARCv8LibDirs + llvm::array_lengthof(SPARCv8LibDirs));
+ TripleAliases.append(SPARCv8Triples,
+ SPARCv8Triples + llvm::array_lengthof(SPARCv8Triples));
+ BiarchLibDirs.append(SPARCv9LibDirs,
+ SPARCv9LibDirs + llvm::array_lengthof(SPARCv9LibDirs));
+ BiarchTripleAliases.append(
+ SPARCv9Triples, SPARCv9Triples + llvm::array_lengthof(SPARCv9Triples));
+ break;
+ case llvm::Triple::sparcv9:
+ LibDirs.append(SPARCv9LibDirs,
+ SPARCv9LibDirs + llvm::array_lengthof(SPARCv9LibDirs));
+ TripleAliases.append(SPARCv9Triples,
+ SPARCv9Triples + llvm::array_lengthof(SPARCv9Triples));
+ BiarchLibDirs.append(SPARCv8LibDirs,
+ SPARCv8LibDirs + llvm::array_lengthof(SPARCv8LibDirs));
+ BiarchTripleAliases.append(
+ SPARCv8Triples, SPARCv8Triples + llvm::array_lengthof(SPARCv8Triples));
+ break;
case llvm::Triple::systemz:
LibDirs.append(SystemZLibDirs,
SystemZLibDirs + llvm::array_lengthof(SystemZLibDirs));
@@ -1305,42 +1584,47 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
BiarchTripleAliases.push_back(BiarchTriple.str());
}
-static bool isSoftFloatABI(const ArgList &Args) {
- Arg *A = Args.getLastArg(options::OPT_msoft_float,
- options::OPT_mhard_float,
- options::OPT_mfloat_abi_EQ);
- if (!A) return false;
+namespace {
+// Filter to remove Multilibs that don't exist as a suffix to Path
+class FilterNonExistent : public MultilibSet::FilterCallback {
+ std::string Base;
+public:
+ FilterNonExistent(std::string Base) : Base(Base) {}
+ bool operator()(const Multilib &M) const override {
+ return !llvm::sys::fs::exists(Base + M.gccSuffix() + "/crtbegin.o");
+ }
+};
+} // end anonymous namespace
- return A->getOption().matches(options::OPT_msoft_float) ||
- (A->getOption().matches(options::OPT_mfloat_abi_EQ) &&
- A->getValue() == StringRef("soft"));
+static void addMultilibFlag(bool Enabled, const char *const Flag,
+ std::vector<std::string> &Flags) {
+ if (Enabled)
+ Flags.push_back(std::string("+") + Flag);
+ else
+ Flags.push_back(std::string("-") + Flag);
}
static bool isMipsArch(llvm::Triple::ArchType Arch) {
- return Arch == llvm::Triple::mips ||
- Arch == llvm::Triple::mipsel ||
- Arch == llvm::Triple::mips64 ||
- Arch == llvm::Triple::mips64el;
+ return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel ||
+ Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el;
}
-static bool isMips16(const ArgList &Args) {
- Arg *A = Args.getLastArg(options::OPT_mips16,
- options::OPT_mno_mips16);
- return A && A->getOption().matches(options::OPT_mips16);
+static bool isMips32(llvm::Triple::ArchType Arch) {
+ return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel;
}
-static bool isMips32r2(const ArgList &Args) {
- Arg *A = Args.getLastArg(options::OPT_march_EQ,
- options::OPT_mcpu_EQ);
-
- return A && A->getValue() == StringRef("mips32r2");
+static bool isMips64(llvm::Triple::ArchType Arch) {
+ return Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el;
}
-static bool isMips64r2(const ArgList &Args) {
- Arg *A = Args.getLastArg(options::OPT_march_EQ,
- options::OPT_mcpu_EQ);
+static bool isMipsEL(llvm::Triple::ArchType Arch) {
+ return Arch == llvm::Triple::mipsel || Arch == llvm::Triple::mips64el;
+}
- return A && A->getValue() == StringRef("mips64r2");
+static bool isMips16(const ArgList &Args) {
+ Arg *A = Args.getLastArg(options::OPT_mips16,
+ options::OPT_mno_mips16);
+ return A && A->getOption().matches(options::OPT_mips16);
}
static bool isMicroMips(const ArgList &Args) {
@@ -1349,52 +1633,21 @@ static bool isMicroMips(const ArgList &Args) {
return A && A->getOption().matches(options::OPT_mmicromips);
}
-static bool isMipsFP64(const ArgList &Args) {
- Arg *A = Args.getLastArg(options::OPT_mfp64, options::OPT_mfp32);
- return A && A->getOption().matches(options::OPT_mfp64);
-}
-
-static bool isMipsNan2008(const ArgList &Args) {
- Arg *A = Args.getLastArg(options::OPT_mnan_EQ);
- return A && A->getValue() == StringRef("2008");
-}
-
-// FIXME: There is the same routine in the Tools.cpp.
-static bool hasMipsN32ABIArg(const ArgList &Args) {
- Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
- return A && (A->getValue() == StringRef("n32"));
-}
+struct DetectedMultilibs {
+ /// The set of multilibs that the detected installation supports.
+ MultilibSet Multilibs;
-static bool hasCrtBeginObj(Twine Path) {
- return llvm::sys::fs::exists(Path + "/crtbegin.o");
-}
+ /// The primary multilib appropriate for the given flags.
+ Multilib SelectedMultilib;
-static bool findTargetBiarchSuffix(std::string &Suffix, StringRef Path,
- llvm::Triple::ArchType TargetArch,
- const ArgList &Args) {
- // FIXME: This routine was only intended to model bi-arch toolchains which
- // use -m32 and -m64 to swap between variants of a target. It shouldn't be
- // doing ABI-based builtin location for MIPS.
- if (hasMipsN32ABIArg(Args))
- Suffix = "/n32";
- else if (TargetArch == llvm::Triple::x86_64 ||
- TargetArch == llvm::Triple::ppc64 ||
- TargetArch == llvm::Triple::systemz ||
- TargetArch == llvm::Triple::mips64 ||
- TargetArch == llvm::Triple::mips64el)
- Suffix = "/64";
- else
- Suffix = "/32";
-
- return hasCrtBeginObj(Path + Suffix);
-}
-
-void Generic_GCC::GCCInstallationDetector::findMIPSABIDirSuffix(
- std::string &Suffix, llvm::Triple::ArchType TargetArch, StringRef Path,
- const llvm::opt::ArgList &Args) {
- if (!isMipsArch(TargetArch))
- return;
+ /// On Biarch systems, this corresponds to the default multilib when
+ /// targeting the non-default multilib. Otherwise, it is empty.
+ llvm::Optional<Multilib> BiarchSibling;
+};
+static bool findMIPSMultilibs(const llvm::Triple &TargetTriple, StringRef Path,
+ const llvm::opt::ArgList &Args,
+ DetectedMultilibs &Result) {
// Some MIPS toolchains put libraries and object files compiled
// using different options in to the sub-directoris which names
// reflects the flags used for compilation. For example sysroot
@@ -1419,71 +1672,362 @@ void Generic_GCC::GCCInstallationDetector::findMIPSABIDirSuffix(
// /mips32
// /usr
// /lib <= crt*.o files compiled with '-mips32'
- //
- // Unfortunately different toolchains use different and partially
- // overlapped naming schemes. So we have to make a trick for detection
- // of using toolchain. We lookup a path which unique for each toolchains.
-
- bool IsMentorToolChain = hasCrtBeginObj(Path + "/mips16/soft-float");
- bool IsFSFToolChain = hasCrtBeginObj(Path + "/mips32/mips16/sof");
-
- if (IsMentorToolChain && IsFSFToolChain)
- D.Diag(diag::err_drv_unknown_toolchain);
-
- if (IsMentorToolChain) {
- if (isMips16(Args))
- Suffix += "/mips16";
- else if (isMicroMips(Args))
- Suffix += "/micromips";
-
- if (isSoftFloatABI(Args))
- Suffix += "/soft-float";
-
- if (TargetArch == llvm::Triple::mipsel ||
- TargetArch == llvm::Triple::mips64el)
- Suffix += "/el";
- } else if (IsFSFToolChain) {
- if (TargetArch == llvm::Triple::mips ||
- TargetArch == llvm::Triple::mipsel) {
- if (isMicroMips(Args))
- Suffix += "/micromips";
- else if (isMips32r2(Args))
- Suffix += "";
- else
- Suffix += "/mips32";
- if (isMips16(Args))
- Suffix += "/mips16";
- } else {
- if (isMips64r2(Args))
- Suffix += hasMipsN32ABIArg(Args) ? "/mips64r2" : "/mips64r2/64";
- else
- Suffix += hasMipsN32ABIArg(Args) ? "/mips64" : "/mips64/64";
+ FilterNonExistent NonExistent(Path);
+
+ // Check for FSF toolchain multilibs
+ MultilibSet FSFMipsMultilibs;
+ {
+ Multilib MArchMips32 = Multilib()
+ .gccSuffix("/mips32")
+ .osSuffix("/mips32")
+ .includeSuffix("/mips32")
+ .flag("+m32").flag("-m64").flag("-mmicromips").flag("+march=mips32");
+
+ Multilib MArchMicroMips = Multilib()
+ .gccSuffix("/micromips")
+ .osSuffix("/micromips")
+ .includeSuffix("/micromips")
+ .flag("+m32").flag("-m64").flag("+mmicromips");
+
+ Multilib MArchMips64r2 = Multilib()
+ .gccSuffix("/mips64r2")
+ .osSuffix("/mips64r2")
+ .includeSuffix("/mips64r2")
+ .flag("-m32").flag("+m64").flag("+march=mips64r2");
+
+ Multilib MArchMips64 = Multilib()
+ .gccSuffix("/mips64")
+ .osSuffix("/mips64")
+ .includeSuffix("/mips64")
+ .flag("-m32").flag("+m64").flag("-march=mips64r2");
+
+ Multilib MArchDefault = Multilib()
+ .flag("+m32").flag("-m64").flag("-mmicromips").flag("+march=mips32r2");
+
+ Multilib Mips16 = Multilib()
+ .gccSuffix("/mips16")
+ .osSuffix("/mips16")
+ .includeSuffix("/mips16")
+ .flag("+mips16");
+
+ Multilib MAbi64 = Multilib()
+ .gccSuffix("/64")
+ .osSuffix("/64")
+ .includeSuffix("/64")
+ .flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
+
+ Multilib BigEndian = Multilib()
+ .flag("+EB").flag("-EL");
+
+ Multilib LittleEndian = Multilib()
+ .gccSuffix("/el")
+ .osSuffix("/el")
+ .includeSuffix("/el")
+ .flag("+EL").flag("-EB");
+
+ Multilib SoftFloat = Multilib()
+ .gccSuffix("/sof")
+ .osSuffix("/sof")
+ .includeSuffix("/sof")
+ .flag("+msoft-float");
+
+ Multilib Nan2008 = Multilib()
+ .gccSuffix("/nan2008")
+ .osSuffix("/nan2008")
+ .includeSuffix("/nan2008")
+ .flag("+mnan=2008");
+
+ FSFMipsMultilibs = MultilibSet()
+ .Either(MArchMips32, MArchMicroMips,
+ MArchMips64r2, MArchMips64, MArchDefault)
+ .Maybe(Mips16)
+ .FilterOut("/mips64/mips16")
+ .FilterOut("/mips64r2/mips16")
+ .FilterOut("/micromips/mips16")
+ .Maybe(MAbi64)
+ .FilterOut("/micromips/64")
+ .FilterOut("/mips32/64")
+ .FilterOut("^/64")
+ .FilterOut("/mips16/64")
+ .Either(BigEndian, LittleEndian)
+ .Maybe(SoftFloat)
+ .Maybe(Nan2008)
+ .FilterOut(".*sof/nan2008")
+ .FilterOut(NonExistent);
+ }
+
+ // Check for Code Sourcery toolchain multilibs
+ MultilibSet CSMipsMultilibs;
+ {
+ Multilib MArchMips16 = Multilib()
+ .gccSuffix("/mips16")
+ .osSuffix("/mips16")
+ .includeSuffix("/mips16")
+ .flag("+m32").flag("+mips16");
+
+ Multilib MArchMicroMips = Multilib()
+ .gccSuffix("/micromips")
+ .osSuffix("/micromips")
+ .includeSuffix("/micromips")
+ .flag("+m32").flag("+mmicromips");
+
+ Multilib MArchDefault = Multilib()
+ .flag("-mips16").flag("-mmicromips");
+
+ Multilib SoftFloat = Multilib()
+ .gccSuffix("/soft-float")
+ .osSuffix("/soft-float")
+ .includeSuffix("/soft-float")
+ .flag("+msoft-float");
+
+ Multilib Nan2008 = Multilib()
+ .gccSuffix("/nan2008")
+ .osSuffix("/nan2008")
+ .includeSuffix("/nan2008")
+ .flag("+mnan=2008");
+
+ Multilib DefaultFloat = Multilib()
+ .flag("-msoft-float").flag("-mnan=2008");
+
+ Multilib BigEndian = Multilib()
+ .flag("+EB").flag("-EL");
+
+ Multilib LittleEndian = Multilib()
+ .gccSuffix("/el")
+ .osSuffix("/el")
+ .includeSuffix("/el")
+ .flag("+EL").flag("-EB");
+
+ // Note that this one's osSuffix is ""
+ Multilib MAbi64 = Multilib()
+ .gccSuffix("/64")
+ .includeSuffix("/64")
+ .flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
+
+ CSMipsMultilibs = MultilibSet()
+ .Either(MArchMips16, MArchMicroMips, MArchDefault)
+ .Either(SoftFloat, Nan2008, DefaultFloat)
+ .FilterOut("/micromips/nan2008")
+ .FilterOut("/mips16/nan2008")
+ .Either(BigEndian, LittleEndian)
+ .Maybe(MAbi64)
+ .FilterOut("/mips16.*/64")
+ .FilterOut("/micromips.*/64")
+ .FilterOut(NonExistent);
+ }
+
+ MultilibSet AndroidMipsMultilibs = MultilibSet()
+ .Maybe(Multilib("/mips-r2").flag("+march=mips32r2"))
+ .FilterOut(NonExistent);
+
+ MultilibSet DebianMipsMultilibs;
+ {
+ Multilib MAbiN32 = Multilib()
+ .gccSuffix("/n32")
+ .includeSuffix("/n32")
+ .flag("+mabi=n32");
+
+ Multilib M64 = Multilib()
+ .gccSuffix("/64")
+ .includeSuffix("/64")
+ .flag("+m64").flag("-m32").flag("-mabi=n32");
+
+ Multilib M32 = Multilib()
+ .flag("-m64").flag("+m32").flag("-mabi=n32");
+
+ DebianMipsMultilibs = MultilibSet()
+ .Either(M32, M64, MAbiN32)
+ .FilterOut(NonExistent);
+ }
+
+ MultilibSet ImgMultilibs;
+ {
+ Multilib Mips64r6 = Multilib()
+ .gccSuffix("/mips64r6")
+ .osSuffix("/mips64r6")
+ .includeSuffix("/mips64r6")
+ .flag("+m64").flag("-m32");
+
+ Multilib LittleEndian = Multilib()
+ .gccSuffix("/el")
+ .osSuffix("/el")
+ .includeSuffix("/el")
+ .flag("+EL").flag("-EB");
+
+ Multilib MAbi64 = Multilib()
+ .gccSuffix("/64")
+ .osSuffix("/64")
+ .includeSuffix("/64")
+ .flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
+
+ ImgMultilibs = MultilibSet()
+ .Maybe(Mips64r6)
+ .Maybe(MAbi64)
+ .Maybe(LittleEndian)
+ .FilterOut(NonExistent);
+ }
+
+ StringRef CPUName;
+ StringRef ABIName;
+ tools::mips::getMipsCPUAndABI(Args, TargetTriple, CPUName, ABIName);
+
+ llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
+
+ Multilib::flags_list Flags;
+ addMultilibFlag(isMips32(TargetArch), "m32", Flags);
+ addMultilibFlag(isMips64(TargetArch), "m64", Flags);
+ addMultilibFlag(isMips16(Args), "mips16", Flags);
+ addMultilibFlag(CPUName == "mips32", "march=mips32", Flags);
+ addMultilibFlag(CPUName == "mips32r2", "march=mips32r2", Flags);
+ addMultilibFlag(CPUName == "mips64", "march=mips64", Flags);
+ addMultilibFlag(CPUName == "mips64r2" || CPUName == "octeon",
+ "march=mips64r2", Flags);
+ addMultilibFlag(isMicroMips(Args), "mmicromips", Flags);
+ addMultilibFlag(tools::mips::isNaN2008(Args, TargetTriple), "mnan=2008",
+ Flags);
+ addMultilibFlag(ABIName == "n32", "mabi=n32", Flags);
+ addMultilibFlag(ABIName == "n64", "mabi=n64", Flags);
+ addMultilibFlag(isSoftFloatABI(Args), "msoft-float", Flags);
+ addMultilibFlag(!isSoftFloatABI(Args), "mhard-float", Flags);
+ addMultilibFlag(isMipsEL(TargetArch), "EL", Flags);
+ addMultilibFlag(!isMipsEL(TargetArch), "EB", Flags);
+
+ if (TargetTriple.getEnvironment() == llvm::Triple::Android) {
+ // Select Android toolchain. It's the only choice in that case.
+ if (AndroidMipsMultilibs.select(Flags, Result.SelectedMultilib)) {
+ Result.Multilibs = AndroidMipsMultilibs;
+ return true;
+ }
+ return false;
+ }
+
+ if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies &&
+ TargetTriple.getOS() == llvm::Triple::Linux &&
+ TargetTriple.getEnvironment() == llvm::Triple::GNU) {
+ // Select mips-img-linux-gnu toolchain.
+ if (ImgMultilibs.select(Flags, Result.SelectedMultilib)) {
+ Result.Multilibs = ImgMultilibs;
+ return true;
}
+ return false;
+ }
- if (TargetArch == llvm::Triple::mipsel ||
- TargetArch == llvm::Triple::mips64el)
- Suffix += "/el";
+ // Sort candidates. Toolchain that best meets the directories goes first.
+ // Then select the first toolchains matches command line flags.
+ MultilibSet *candidates[] = { &DebianMipsMultilibs, &FSFMipsMultilibs,
+ &CSMipsMultilibs };
+ std::sort(
+ std::begin(candidates), std::end(candidates),
+ [](MultilibSet *a, MultilibSet *b) { return a->size() > b->size(); });
+ for (const auto &candidate : candidates) {
+ if (candidate->select(Flags, Result.SelectedMultilib)) {
+ if (candidate == &DebianMipsMultilibs)
+ Result.BiarchSibling = Multilib();
+ Result.Multilibs = *candidate;
+ return true;
+ }
+ }
- if (isSoftFloatABI(Args))
- Suffix += "/sof";
- else {
- if (isMipsFP64(Args))
- Suffix += "/fp64";
+ {
+ // Fallback to the regular toolchain-tree structure.
+ Multilib Default;
+ Result.Multilibs.push_back(Default);
+ Result.Multilibs.FilterOut(NonExistent);
- if (isMipsNan2008(Args))
- Suffix += "/nan2008";
+ if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) {
+ Result.BiarchSibling = Multilib();
+ return true;
}
}
- if (!hasCrtBeginObj(Path + Suffix))
- Suffix.clear();
+ return false;
+}
+
+static bool findBiarchMultilibs(const llvm::Triple &TargetTriple,
+ StringRef Path, const ArgList &Args,
+ bool NeedsBiarchSuffix,
+ DetectedMultilibs &Result) {
+
+ // Some versions of SUSE and Fedora on ppc64 put 32-bit libs
+ // in what would normally be GCCInstallPath and put the 64-bit
+ // libs in a subdirectory named 64. The simple logic we follow is that
+ // *if* there is a subdirectory of the right name with crtbegin.o in it,
+ // we use that. If not, and if not a biarch triple alias, we look for
+ // crtbegin.o without the subdirectory.
+
+ Multilib Default;
+ Multilib Alt64 = Multilib()
+ .gccSuffix("/64")
+ .includeSuffix("/64")
+ .flag("-m32").flag("+m64").flag("-mx32");
+ Multilib Alt32 = Multilib()
+ .gccSuffix("/32")
+ .includeSuffix("/32")
+ .flag("+m32").flag("-m64").flag("-mx32");
+ Multilib Altx32 = Multilib()
+ .gccSuffix("/x32")
+ .includeSuffix("/x32")
+ .flag("-m32").flag("-m64").flag("+mx32");
+
+ FilterNonExistent NonExistent(Path);
+
+ // Determine default multilib from: 32, 64, x32
+ // Also handle cases such as 64 on 32, 32 on 64, etc.
+ enum { UNKNOWN, WANT32, WANT64, WANTX32 } Want = UNKNOWN;
+ const bool IsX32 = TargetTriple.getEnvironment() == llvm::Triple::GNUX32;
+ if (TargetTriple.isArch32Bit() && !NonExistent(Alt32))
+ Want = WANT64;
+ else if (TargetTriple.isArch64Bit() && IsX32 && !NonExistent(Altx32))
+ Want = WANT64;
+ else if (TargetTriple.isArch64Bit() && !IsX32 && !NonExistent(Alt64))
+ Want = WANT32;
+ else {
+ if (TargetTriple.isArch32Bit())
+ Want = NeedsBiarchSuffix ? WANT64 : WANT32;
+ else if (IsX32)
+ Want = NeedsBiarchSuffix ? WANT64 : WANTX32;
+ else
+ Want = NeedsBiarchSuffix ? WANT32 : WANT64;
+ }
+
+ if (Want == WANT32)
+ Default.flag("+m32").flag("-m64").flag("-mx32");
+ else if (Want == WANT64)
+ Default.flag("-m32").flag("+m64").flag("-mx32");
+ else if (Want == WANTX32)
+ Default.flag("-m32").flag("-m64").flag("+mx32");
+ else
+ return false;
+
+ Result.Multilibs.push_back(Default);
+ Result.Multilibs.push_back(Alt64);
+ Result.Multilibs.push_back(Alt32);
+ Result.Multilibs.push_back(Altx32);
+
+ Result.Multilibs.FilterOut(NonExistent);
+
+ Multilib::flags_list Flags;
+ addMultilibFlag(TargetTriple.isArch64Bit() && !IsX32, "m64", Flags);
+ addMultilibFlag(TargetTriple.isArch32Bit(), "m32", Flags);
+ addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "mx32", Flags);
+
+ if (!Result.Multilibs.select(Flags, Result.SelectedMultilib))
+ return false;
+
+ if (Result.SelectedMultilib == Alt64 ||
+ Result.SelectedMultilib == Alt32 ||
+ Result.SelectedMultilib == Altx32)
+ Result.BiarchSibling = Default;
+
+ return true;
}
void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
- llvm::Triple::ArchType TargetArch, const ArgList &Args,
+ const llvm::Triple &TargetTriple, const ArgList &Args,
const std::string &LibDir, StringRef CandidateTriple,
bool NeedsBiarchSuffix) {
+ llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
// There are various different suffixes involving the triple we
// check for. We also record what is necessary to walk from each back
// up to the lib directory.
@@ -1515,7 +2059,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
(llvm::array_lengthof(LibSuffixes) - (TargetArch != llvm::Triple::x86));
for (unsigned i = 0; i < NumLibSuffixes; ++i) {
StringRef LibSuffix = LibSuffixes[i];
- llvm::error_code EC;
+ std::error_code EC;
for (llvm::sys::fs::directory_iterator LI(LibDir + LibSuffix, EC), LE;
!EC && LI != LE; LI = LI.increment(EC)) {
StringRef VersionText = llvm::sys::path::filename(LI->path());
@@ -1528,28 +2072,21 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
if (CandidateVersion <= Version)
continue;
- std::string MIPSABIDirSuffix;
- findMIPSABIDirSuffix(MIPSABIDirSuffix, TargetArch, LI->path(), Args);
-
- // Some versions of SUSE and Fedora on ppc64 put 32-bit libs
- // in what would normally be GCCInstallPath and put the 64-bit
- // libs in a subdirectory named 64. The simple logic we follow is that
- // *if* there is a subdirectory of the right name with crtbegin.o in it,
- // we use that. If not, and if not a biarch triple alias, we look for
- // crtbegin.o without the subdirectory.
-
- std::string BiarchSuffix;
- if (findTargetBiarchSuffix(BiarchSuffix,
- LI->path() + MIPSABIDirSuffix,
- TargetArch, Args)) {
- GCCBiarchSuffix = BiarchSuffix;
- } else if (NeedsBiarchSuffix ||
- !hasCrtBeginObj(LI->path() + MIPSABIDirSuffix)) {
+ DetectedMultilibs Detected;
+
+ // Debian mips multilibs behave more like the rest of the biarch ones,
+ // so handle them there
+ if (isMipsArch(TargetArch)) {
+ if (!findMIPSMultilibs(TargetTriple, LI->path(), Args, Detected))
+ continue;
+ } else if (!findBiarchMultilibs(TargetTriple, LI->path(), Args,
+ NeedsBiarchSuffix, Detected)) {
continue;
- } else {
- GCCBiarchSuffix.clear();
}
+ Multilibs = Detected.Multilibs;
+ SelectedMultilib = Detected.SelectedMultilib;
+ BiarchSibling = Detected.BiarchSibling;
Version = CandidateVersion;
GCCTriple.setTriple(CandidateTriple);
// FIXME: We hack together the directory name here instead of
@@ -1557,7 +2094,6 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
// Linux.
GCCInstallPath = LibDir + LibSuffixes[i] + "/" + VersionText.str();
GCCParentLibPath = GCCInstallPath + InstallSuffixes[i];
- GCCMIPSABIDirSuffix = MIPSABIDirSuffix;
IsValid = true;
}
}
@@ -1565,7 +2101,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple& Triple,
const ArgList &Args)
- : ToolChain(D, Triple, Args), GCCInstallation(getDriver(), Triple, Args) {
+ : ToolChain(D, Triple, Args), GCCInstallation() {
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
@@ -1580,10 +2116,6 @@ Tool *Generic_GCC::getTool(Action::ActionClass AC) const {
if (!Preprocess)
Preprocess.reset(new tools::gcc::Preprocess(*this));
return Preprocess.get();
- case Action::PrecompileJobClass:
- if (!Precompile)
- Precompile.reset(new tools::gcc::Precompile(*this));
- return Precompile.get();
case Action::CompileJobClass:
if (!Compile)
Compile.reset(new tools::gcc::Compile(*this));
@@ -1594,7 +2126,7 @@ Tool *Generic_GCC::getTool(Action::ActionClass AC) const {
}
Tool *Generic_GCC::buildAssembler() const {
- return new tools::gcc::Assemble(*this);
+ return new tools::gnutools::Assemble(*this);
}
Tool *Generic_GCC::buildLinker() const {
@@ -1622,14 +2154,30 @@ bool Generic_GCC::isPICDefaultForced() const {
return false;
}
-void Generic_GCC::addClangTargetOptions(const ArgList &DriverArgs,
+bool Generic_GCC::IsIntegratedAssemblerDefault() const {
+ return getTriple().getArch() == llvm::Triple::x86 ||
+ getTriple().getArch() == llvm::Triple::x86_64 ||
+ getTriple().getArch() == llvm::Triple::aarch64 ||
+ getTriple().getArch() == llvm::Triple::aarch64_be ||
+ getTriple().getArch() == llvm::Triple::arm64 ||
+ getTriple().getArch() == llvm::Triple::arm64_be ||
+ getTriple().getArch() == llvm::Triple::arm ||
+ getTriple().getArch() == llvm::Triple::armeb ||
+ getTriple().getArch() == llvm::Triple::thumb ||
+ getTriple().getArch() == llvm::Triple::thumbeb;
+}
+
+void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion();
- bool UseInitArrayDefault =
+ bool UseInitArrayDefault =
getTriple().getArch() == llvm::Triple::aarch64 ||
- (getTriple().getOS() == llvm::Triple::Linux && (
- !V.isOlderThan(4, 7, 0) ||
- getTriple().getEnvironment() == llvm::Triple::Android));
+ getTriple().getArch() == llvm::Triple::aarch64_be ||
+ getTriple().getArch() == llvm::Triple::arm64 ||
+ getTriple().getArch() == llvm::Triple::arm64_be ||
+ (getTriple().getOS() == llvm::Triple::Linux &&
+ (!V.isOlderThan(4, 7, 0) ||
+ getTriple().getEnvironment() == llvm::Triple::Android));
if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
options::OPT_fno_use_init_array,
@@ -1721,7 +2269,7 @@ Hexagon_TC::Hexagon_TC(const Driver &D, const llvm::Triple &Triple,
// Determine version of GCC libraries and headers to use.
const std::string HexagonDir(GnuDir + "/lib/gcc/hexagon");
- llvm::error_code ec;
+ std::error_code ec;
GCCVersion MaxVersion= GCCVersion::Parse("0.0.0");
for (llvm::sys::fs::directory_iterator di(HexagonDir, ec), de;
!ec && di != de; di = di.increment(ec)) {
@@ -1913,6 +2461,21 @@ Tool *Bitrig::buildLinker() const {
return new tools::bitrig::Link(*this);
}
+ToolChain::CXXStdlibType
+Bitrig::GetCXXStdlibType(const ArgList &Args) const {
+ if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
+ StringRef Value = A->getValue();
+ if (Value == "libstdc++")
+ return ToolChain::CST_Libstdcxx;
+ if (Value == "libc++")
+ return ToolChain::CST_Libcxx;
+
+ getDriver().Diag(diag::err_drv_invalid_stdlib_name)
+ << A->getAsString(Args);
+ }
+ return ToolChain::CST_Libcxx;
+}
+
void Bitrig::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
@@ -1922,7 +2485,7 @@ void Bitrig::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
switch (GetCXXStdlibType(DriverArgs)) {
case ToolChain::CST_Libcxx:
addSystemInclude(DriverArgs, CC1Args,
- getDriver().SysRoot + "/usr/include/c++/");
+ getDriver().SysRoot + "/usr/include/c++/v1");
break;
case ToolChain::CST_Libstdcxx:
addSystemInclude(DriverArgs, CC1Args,
@@ -1948,9 +2511,8 @@ void Bitrig::AddCXXStdlibLibArgs(const ArgList &Args,
switch (GetCXXStdlibType(Args)) {
case ToolChain::CST_Libcxx:
CmdArgs.push_back("-lc++");
- CmdArgs.push_back("-lcxxrt");
- // Include supc++ to provide Unwind until provided by libcxx.
- CmdArgs.push_back("-lgcc");
+ CmdArgs.push_back("-lc++abi");
+ CmdArgs.push_back("-lpthread");
break;
case ToolChain::CST_Libstdcxx:
CmdArgs.push_back("-lstdc++");
@@ -2021,6 +2583,7 @@ Tool *FreeBSD::buildLinker() const {
bool FreeBSD::UseSjLjExceptions() const {
// FreeBSD uses SjLj exceptions on ARM oabi.
switch (getTriple().getEnvironment()) {
+ case llvm::Triple::GNUEABIHF:
case llvm::Triple::GNUEABI:
case llvm::Triple::EABI:
return false;
@@ -2031,6 +2594,14 @@ bool FreeBSD::UseSjLjExceptions() const {
}
}
+bool FreeBSD::HasNativeLLVMSupport() const {
+ return true;
+}
+
+bool FreeBSD::isPIEDefault() const {
+ return getSanitizerArgs().hasZeroBaseShadow();
+}
+
/// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly.
NetBSD::NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
@@ -2042,8 +2613,39 @@ NetBSD::NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
// doesn't work.
// FIXME: It'd be nicer to test if this directory exists, but I'm not sure
// what all logic is needed to emulate the '=' prefix here.
- if (Triple.getArch() == llvm::Triple::x86)
+ switch (Triple.getArch()) {
+ case llvm::Triple::x86:
getFilePaths().push_back("=/usr/lib/i386");
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ switch (Triple.getEnvironment()) {
+ case llvm::Triple::EABI:
+ case llvm::Triple::EABIHF:
+ case llvm::Triple::GNUEABI:
+ case llvm::Triple::GNUEABIHF:
+ getFilePaths().push_back("=/usr/lib/eabi");
+ break;
+ default:
+ getFilePaths().push_back("=/usr/lib/oabi");
+ break;
+ }
+ break;
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ if (tools::mips::hasMipsAbiArg(Args, "o32"))
+ getFilePaths().push_back("=/usr/lib/o32");
+ else if (tools::mips::hasMipsAbiArg(Args, "64"))
+ getFilePaths().push_back("=/usr/lib/64");
+ break;
+ case llvm::Triple::sparc:
+ getFilePaths().push_back("=/usr/lib/sparc");
+ break;
+ default:
+ break;
+ }
getFilePaths().push_back("=/usr/lib");
}
@@ -2072,9 +2674,18 @@ NetBSD::GetCXXStdlibType(const ArgList &Args) const {
unsigned Major, Minor, Micro;
getTriple().getOSVersion(Major, Minor, Micro);
- if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 23) || Major == 0) {
- if (getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64)
+ if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 40) || Major == 0) {
+ switch (getArch()) {
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
return ToolChain::CST_Libcxx;
+ default:
+ break;
+ }
}
return ToolChain::CST_Libstdcxx;
}
@@ -2210,8 +2821,9 @@ static bool IsUbuntu(enum Distro Distro) {
}
static Distro DetectDistro(llvm::Triple::ArchType Arch) {
- OwningPtr<llvm::MemoryBuffer> File;
- if (!llvm::MemoryBuffer::getFile("/etc/lsb-release", File)) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
+ llvm::MemoryBuffer::getFile("/etc/lsb-release");
+ if (File) {
StringRef Data = File.get()->getBuffer();
SmallVector<StringRef, 8> Lines;
Data.split(Lines, "\n");
@@ -2236,25 +2848,25 @@ static Distro DetectDistro(llvm::Triple::ArchType Arch) {
return Version;
}
- if (!llvm::MemoryBuffer::getFile("/etc/redhat-release", File)) {
+ File = llvm::MemoryBuffer::getFile("/etc/redhat-release");
+ if (File) {
StringRef Data = File.get()->getBuffer();
if (Data.startswith("Fedora release"))
return Fedora;
- else if (Data.startswith("Red Hat Enterprise Linux") &&
- Data.find("release 6") != StringRef::npos)
- return RHEL6;
- else if ((Data.startswith("Red Hat Enterprise Linux") ||
- Data.startswith("CentOS")) &&
- Data.find("release 5") != StringRef::npos)
- return RHEL5;
- else if ((Data.startswith("Red Hat Enterprise Linux") ||
- Data.startswith("CentOS")) &&
- Data.find("release 4") != StringRef::npos)
- return RHEL4;
+ if (Data.startswith("Red Hat Enterprise Linux") ||
+ Data.startswith("CentOS")) {
+ if (Data.find("release 6") != StringRef::npos)
+ return RHEL6;
+ else if (Data.find("release 5") != StringRef::npos)
+ return RHEL5;
+ else if (Data.find("release 4") != StringRef::npos)
+ return RHEL4;
+ }
return UnknownDistro;
}
- if (!llvm::MemoryBuffer::getFile("/etc/debian_version", File)) {
+ File = llvm::MemoryBuffer::getFile("/etc/debian_version");
+ if (File) {
StringRef Data = File.get()->getBuffer();
if (Data[0] == '5')
return DebianLenny;
@@ -2285,7 +2897,7 @@ static Distro DetectDistro(llvm::Triple::ArchType Arch) {
/// a target-triple directory in the library and header search paths.
/// Unfortunately, this triple does not align with the vanilla target triple,
/// so we provide a rough mapping here.
-static std::string getMultiarchTriple(const llvm::Triple TargetTriple,
+static std::string getMultiarchTriple(const llvm::Triple &TargetTriple,
StringRef SysRoot) {
// For most architectures, just use whatever we have rather than trying to be
// clever.
@@ -2307,18 +2919,36 @@ static std::string getMultiarchTriple(const llvm::Triple TargetTriple,
return "arm-linux-gnueabi";
}
return TargetTriple.str();
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumbeb:
+ if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) {
+ if (llvm::sys::fs::exists(SysRoot + "/lib/armeb-linux-gnueabihf"))
+ return "armeb-linux-gnueabihf";
+ } else {
+ if (llvm::sys::fs::exists(SysRoot + "/lib/armeb-linux-gnueabi"))
+ return "armeb-linux-gnueabi";
+ }
+ return TargetTriple.str();
case llvm::Triple::x86:
if (llvm::sys::fs::exists(SysRoot + "/lib/i386-linux-gnu"))
return "i386-linux-gnu";
return TargetTriple.str();
case llvm::Triple::x86_64:
- if (llvm::sys::fs::exists(SysRoot + "/lib/x86_64-linux-gnu"))
+ // We don't want this for x32, otherwise it will match x86_64 libs
+ if (TargetTriple.getEnvironment() != llvm::Triple::GNUX32 &&
+ llvm::sys::fs::exists(SysRoot + "/lib/x86_64-linux-gnu"))
return "x86_64-linux-gnu";
return TargetTriple.str();
+ case llvm::Triple::arm64:
case llvm::Triple::aarch64:
if (llvm::sys::fs::exists(SysRoot + "/lib/aarch64-linux-gnu"))
return "aarch64-linux-gnu";
return TargetTriple.str();
+ case llvm::Triple::arm64_be:
+ case llvm::Triple::aarch64_be:
+ if (llvm::sys::fs::exists(SysRoot + "/lib/aarch64_be-linux-gnu"))
+ return "aarch64_be-linux-gnu";
+ return TargetTriple.str();
case llvm::Triple::mips:
if (llvm::sys::fs::exists(SysRoot + "/lib/mips-linux-gnu"))
return "mips-linux-gnu";
@@ -2327,6 +2957,18 @@ static std::string getMultiarchTriple(const llvm::Triple TargetTriple,
if (llvm::sys::fs::exists(SysRoot + "/lib/mipsel-linux-gnu"))
return "mipsel-linux-gnu";
return TargetTriple.str();
+ case llvm::Triple::mips64:
+ if (llvm::sys::fs::exists(SysRoot + "/lib/mips64-linux-gnu"))
+ return "mips64-linux-gnu";
+ if (llvm::sys::fs::exists(SysRoot + "/lib/mips64-linux-gnuabi64"))
+ return "mips64-linux-gnuabi64";
+ return TargetTriple.str();
+ case llvm::Triple::mips64el:
+ if (llvm::sys::fs::exists(SysRoot + "/lib/mips64el-linux-gnu"))
+ return "mips64el-linux-gnu";
+ if (llvm::sys::fs::exists(SysRoot + "/lib/mips64el-linux-gnuabi64"))
+ return "mips64el-linux-gnuabi64";
+ return TargetTriple.str();
case llvm::Triple::ppc:
if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnuspe"))
return "powerpc-linux-gnuspe";
@@ -2347,35 +2989,40 @@ static void addPathIfExists(Twine Path, ToolChain::path_list &Paths) {
if (llvm::sys::fs::exists(Path)) Paths.push_back(Path.str());
}
-static StringRef getMultilibDir(const llvm::Triple &Triple,
- const ArgList &Args) {
+static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) {
if (isMipsArch(Triple.getArch())) {
// lib32 directory has a special meaning on MIPS targets.
// It contains N32 ABI binaries. Use this folder if produce
// code for N32 ABI only.
- if (hasMipsN32ABIArg(Args))
+ if (tools::mips::hasMipsAbiArg(Args, "n32"))
return "lib32";
return Triple.isArch32Bit() ? "lib" : "lib64";
}
- // It happens that only x86 and PPC use the 'lib32' variant of multilib, and
+ // It happens that only x86 and PPC use the 'lib32' variant of oslibdir, and
// using that variant while targeting other architectures causes problems
// because the libraries are laid out in shared system roots that can't cope
- // with a 'lib32' multilib search path being considered. So we only enable
+ // with a 'lib32' library search path being considered. So we only enable
// them when we know we may need it.
//
// FIXME: This is a bit of a hack. We should really unify this code for
- // reasoning about multilib spellings with the lib dir spellings in the
+ // reasoning about oslibdir spellings with the lib dir spellings in the
// GCCInstallationDetector, but that is a more significant refactoring.
if (Triple.getArch() == llvm::Triple::x86 ||
Triple.getArch() == llvm::Triple::ppc)
return "lib32";
+ if (Triple.getArch() == llvm::Triple::x86_64 &&
+ Triple.getEnvironment() == llvm::Triple::GNUX32)
+ return "libx32";
+
return Triple.isArch32Bit() ? "lib" : "lib64";
}
Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
: Generic_ELF(D, Triple, Args) {
+ GCCInstallation.init(D, Triple, Args);
+ Multilibs = GCCInstallation.getMultilibs();
llvm::Triple::ArchType Arch = Triple.getArch();
std::string SysRoot = computeSysRoot();
@@ -2391,7 +3038,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" +
GCCInstallation.getTriple().str() + "/bin").str());
- Linker = GetProgramPath("ld");
+ Linker = GetLinkerPath();
Distro Distro = DetectDistro(Arch);
@@ -2443,29 +3090,20 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// to the link paths.
path_list &Paths = getFilePaths();
- const std::string Multilib = getMultilibDir(Triple, Args);
+ const std::string OSLibDir = getOSLibDir(Triple, Args);
const std::string MultiarchTriple = getMultiarchTriple(Triple, SysRoot);
// Add the multilib suffixed paths where they are available.
if (GCCInstallation.isValid()) {
const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
const std::string &LibPath = GCCInstallation.getParentLibPath();
+ const Multilib &Multilib = GCCInstallation.getMultilib();
// Sourcery CodeBench MIPS toolchain holds some libraries under
// a biarch-like suffix of the GCC installation.
- //
- // FIXME: It would be cleaner to model this as a variant of bi-arch. IE,
- // instead of a '64' biarch suffix it would be 'el' or something.
- if (IsAndroid && IsMips && isMips32r2(Args)) {
- assert(GCCInstallation.getBiarchSuffix().empty() &&
- "Unexpected bi-arch suffix");
- addPathIfExists(GCCInstallation.getInstallPath() + "/mips-r2", Paths);
- } else {
- addPathIfExists((GCCInstallation.getInstallPath() +
- GCCInstallation.getMIPSABIDirSuffix() +
- GCCInstallation.getBiarchSuffix()),
- Paths);
- }
+ addPathIfExists((GCCInstallation.getInstallPath() +
+ Multilib.gccSuffix()),
+ Paths);
// GCC cross compiling toolchains will install target libraries which ship
// as part of the toolchain under <prefix>/<triple>/<libdir> rather than as
@@ -2473,7 +3111,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// <prefix>/<libdir>/gcc/<triple>/<version>. This decision is somewhat
// debatable, but is the reality today. We need to search this tree even
// when we have a sysroot somewhere else. It is the responsibility of
- // whomever is doing the cross build targetting a sysroot using a GCC
+ // whomever is doing the cross build targeting a sysroot using a GCC
// installation that is *not* within the system root to ensure two things:
//
// 1) Any DSOs that are linked in from this tree or from the install path
@@ -2485,8 +3123,8 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
//
// Note that this matches the GCC behavior. See the below comment for where
// Clang diverges from GCC's behavior.
- addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + Multilib +
- GCCInstallation.getMIPSABIDirSuffix(),
+ addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + OSLibDir +
+ Multilib.osSuffix(),
Paths);
// If the GCC installation we found is inside of the sysroot, we want to
@@ -2500,45 +3138,64 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// a bug.
if (StringRef(LibPath).startswith(SysRoot)) {
addPathIfExists(LibPath + "/" + MultiarchTriple, Paths);
- addPathIfExists(LibPath + "/../" + Multilib, Paths);
+ addPathIfExists(LibPath + "/../" + OSLibDir, Paths);
}
}
+
+ // Similar to the logic for GCC above, if we currently running Clang inside
+ // of the requested system root, add its parent library paths to
+ // those searched.
+ // FIXME: It's not clear whether we should use the driver's installed
+ // directory ('Dir' below) or the ResourceDir.
+ if (StringRef(D.Dir).startswith(SysRoot)) {
+ addPathIfExists(D.Dir + "/../lib/" + MultiarchTriple, Paths);
+ addPathIfExists(D.Dir + "/../" + OSLibDir, Paths);
+ }
+
addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths);
- addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths);
+ addPathIfExists(SysRoot + "/lib/../" + OSLibDir, Paths);
addPathIfExists(SysRoot + "/usr/lib/" + MultiarchTriple, Paths);
- addPathIfExists(SysRoot + "/usr/lib/../" + Multilib, Paths);
+ addPathIfExists(SysRoot + "/usr/lib/../" + OSLibDir, Paths);
// Try walking via the GCC triple path in case of biarch or multiarch GCC
// installations with strange symlinks.
if (GCCInstallation.isValid()) {
addPathIfExists(SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() +
- "/../../" + Multilib, Paths);
+ "/../../" + OSLibDir, Paths);
- // Add the non-multilib suffixed paths (if potentially different).
- const std::string &LibPath = GCCInstallation.getParentLibPath();
- const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
- if (!GCCInstallation.getBiarchSuffix().empty())
+ // Add the 'other' biarch variant path
+ Multilib BiarchSibling;
+ if (GCCInstallation.getBiarchSibling(BiarchSibling)) {
addPathIfExists(GCCInstallation.getInstallPath() +
- GCCInstallation.getMIPSABIDirSuffix(), Paths);
+ BiarchSibling.gccSuffix(), Paths);
+ }
// See comments above on the multilib variant for details of why this is
// included even from outside the sysroot.
+ const std::string &LibPath = GCCInstallation.getParentLibPath();
+ const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
+ const Multilib &Multilib = GCCInstallation.getMultilib();
addPathIfExists(LibPath + "/../" + GCCTriple.str() +
- "/lib" + GCCInstallation.getMIPSABIDirSuffix(), Paths);
+ "/lib" + Multilib.osSuffix(), Paths);
// See comments above on the multilib variant for details of why this is
// only included from within the sysroot.
if (StringRef(LibPath).startswith(SysRoot))
addPathIfExists(LibPath, Paths);
}
+
+ // Similar to the logic for GCC above, if we are currently running Clang
+ // inside of the requested system root, add its parent library path to those
+ // searched.
+ // FIXME: It's not clear whether we should use the driver's installed
+ // directory ('Dir' below) or the ResourceDir.
+ if (StringRef(D.Dir).startswith(SysRoot))
+ addPathIfExists(D.Dir + "/../lib", Paths);
+
addPathIfExists(SysRoot + "/lib", Paths);
addPathIfExists(SysRoot + "/usr/lib", Paths);
}
-bool FreeBSD::HasNativeLLVMSupport() const {
- return true;
-}
-
bool Linux::HasNativeLLVMSupport() const {
return true;
}
@@ -2564,15 +3221,15 @@ std::string Linux::computeSysRoot() const {
const StringRef InstallDir = GCCInstallation.getInstallPath();
const StringRef TripleStr = GCCInstallation.getTriple().str();
- const StringRef MIPSABIDirSuffix = GCCInstallation.getMIPSABIDirSuffix();
+ const Multilib &Multilib = GCCInstallation.getMultilib();
std::string Path = (InstallDir + "/../../../../" + TripleStr + "/libc" +
- MIPSABIDirSuffix).str();
+ Multilib.osSuffix()).str();
if (llvm::sys::fs::exists(Path))
return Path;
- Path = (InstallDir + "/../../../../sysroot" + MIPSABIDirSuffix).str();
+ Path = (InstallDir + "/../../../../sysroot" + Multilib.osSuffix()).str();
if (llvm::sys::fs::exists(Path))
return Path;
@@ -2605,10 +3262,9 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
if (CIncludeDirs != "") {
SmallVector<StringRef, 5> dirs;
CIncludeDirs.split(dirs, ":");
- for (SmallVectorImpl<StringRef>::iterator I = dirs.begin(), E = dirs.end();
- I != E; ++I) {
- StringRef Prefix = llvm::sys::path::is_absolute(*I) ? SysRoot : "";
- addExternCSystemInclude(DriverArgs, CC1Args, Prefix + *I);
+ for (StringRef dir : dirs) {
+ StringRef Prefix = llvm::sys::path::is_absolute(dir) ? SysRoot : "";
+ addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
}
return;
}
@@ -2665,18 +3321,32 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
const StringRef MIPSELMultiarchIncludeDirs[] = {
"/usr/include/mipsel-linux-gnu"
};
+ const StringRef MIPS64MultiarchIncludeDirs[] = {
+ "/usr/include/mips64-linux-gnu",
+ "/usr/include/mips64-linux-gnuabi64"
+ };
+ const StringRef MIPS64ELMultiarchIncludeDirs[] = {
+ "/usr/include/mips64el-linux-gnu",
+ "/usr/include/mips64el-linux-gnuabi64"
+ };
const StringRef PPCMultiarchIncludeDirs[] = {
"/usr/include/powerpc-linux-gnu"
};
const StringRef PPC64MultiarchIncludeDirs[] = {
"/usr/include/powerpc64-linux-gnu"
};
+ const StringRef PPC64LEMultiarchIncludeDirs[] = {
+ "/usr/include/powerpc64le-linux-gnu"
+ };
ArrayRef<StringRef> MultiarchIncludeDirs;
if (getTriple().getArch() == llvm::Triple::x86_64) {
MultiarchIncludeDirs = X86_64MultiarchIncludeDirs;
} else if (getTriple().getArch() == llvm::Triple::x86) {
MultiarchIncludeDirs = X86MultiarchIncludeDirs;
- } else if (getTriple().getArch() == llvm::Triple::aarch64) {
+ } else if (getTriple().getArch() == llvm::Triple::aarch64 ||
+ getTriple().getArch() == llvm::Triple::aarch64_be ||
+ getTriple().getArch() == llvm::Triple::arm64 ||
+ getTriple().getArch() == llvm::Triple::arm64_be) {
MultiarchIncludeDirs = AArch64MultiarchIncludeDirs;
} else if (getTriple().getArch() == llvm::Triple::arm) {
if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
@@ -2687,16 +3357,20 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
MultiarchIncludeDirs = MIPSMultiarchIncludeDirs;
} else if (getTriple().getArch() == llvm::Triple::mipsel) {
MultiarchIncludeDirs = MIPSELMultiarchIncludeDirs;
+ } else if (getTriple().getArch() == llvm::Triple::mips64) {
+ MultiarchIncludeDirs = MIPS64MultiarchIncludeDirs;
+ } else if (getTriple().getArch() == llvm::Triple::mips64el) {
+ MultiarchIncludeDirs = MIPS64ELMultiarchIncludeDirs;
} else if (getTriple().getArch() == llvm::Triple::ppc) {
MultiarchIncludeDirs = PPCMultiarchIncludeDirs;
} else if (getTriple().getArch() == llvm::Triple::ppc64) {
MultiarchIncludeDirs = PPC64MultiarchIncludeDirs;
+ } else if (getTriple().getArch() == llvm::Triple::ppc64le) {
+ MultiarchIncludeDirs = PPC64LEMultiarchIncludeDirs;
}
- for (ArrayRef<StringRef>::iterator I = MultiarchIncludeDirs.begin(),
- E = MultiarchIncludeDirs.end();
- I != E; ++I) {
- if (llvm::sys::fs::exists(SysRoot + *I)) {
- addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + *I);
+ for (StringRef Dir : MultiarchIncludeDirs) {
+ if (llvm::sys::fs::exists(SysRoot + Dir)) {
+ addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + Dir);
break;
}
}
@@ -2712,33 +3386,39 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
}
-/// \brief Helper to add the three variant paths for a libstdc++ installation.
-/*static*/ bool Linux::addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir,
- const ArgList &DriverArgs,
- ArgStringList &CC1Args) {
- if (!llvm::sys::fs::exists(Base))
- return false;
- addSystemInclude(DriverArgs, CC1Args, Base);
- addSystemInclude(DriverArgs, CC1Args, Base + "/" + TargetArchDir);
- addSystemInclude(DriverArgs, CC1Args, Base + "/backward");
- return true;
-}
-
-/// \brief Helper to add an extra variant path for an (Ubuntu) multilib
-/// libstdc++ installation.
+/// \brief Helper to add the variant paths of a libstdc++ installation.
/*static*/ bool Linux::addLibStdCXXIncludePaths(Twine Base, Twine Suffix,
- Twine TargetArchDir,
- Twine BiarchSuffix,
- Twine MIPSABIDirSuffix,
+ StringRef GCCTriple,
+ StringRef GCCMultiarchTriple,
+ StringRef TargetMultiarchTriple,
+ Twine IncludeSuffix,
const ArgList &DriverArgs,
ArgStringList &CC1Args) {
- if (!addLibStdCXXIncludePaths(Base + Suffix,
- TargetArchDir + MIPSABIDirSuffix + BiarchSuffix,
- DriverArgs, CC1Args))
+ if (!llvm::sys::fs::exists(Base + Suffix))
return false;
- addSystemInclude(DriverArgs, CC1Args, Base + "/" + TargetArchDir + Suffix
- + MIPSABIDirSuffix + BiarchSuffix);
+ addSystemInclude(DriverArgs, CC1Args, Base + Suffix);
+
+ // The vanilla GCC layout of libstdc++ headers uses a triple subdirectory. If
+ // that path exists or we have neither a GCC nor target multiarch triple, use
+ // this vanilla search path.
+ if ((GCCMultiarchTriple.empty() && TargetMultiarchTriple.empty()) ||
+ llvm::sys::fs::exists(Base + Suffix + "/" + GCCTriple + IncludeSuffix)) {
+ addSystemInclude(DriverArgs, CC1Args,
+ Base + Suffix + "/" + GCCTriple + IncludeSuffix);
+ } else {
+ // Otherwise try to use multiarch naming schemes which have normalized the
+ // triples and put the triple before the suffix.
+ //
+ // GCC surprisingly uses *both* the GCC triple with a multilib suffix and
+ // the target triple, so we support that here.
+ addSystemInclude(DriverArgs, CC1Args,
+ Base + "/" + GCCMultiarchTriple + Suffix + IncludeSuffix);
+ addSystemInclude(DriverArgs, CC1Args,
+ Base + "/" + TargetMultiarchTriple + Suffix);
+ }
+
+ addSystemInclude(DriverArgs, CC1Args, Base + Suffix + "/backward");
return true;
}
@@ -2750,9 +3430,23 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
// Check if libc++ has been enabled and provide its include paths if so.
if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) {
- // libc++ is always installed at a fixed path on Linux currently.
- addSystemInclude(DriverArgs, CC1Args,
- getDriver().SysRoot + "/usr/include/c++/v1");
+ const std::string LibCXXIncludePathCandidates[] = {
+ // The primary location is within the Clang installation.
+ // FIXME: We shouldn't hard code 'v1' here to make Clang future proof to
+ // newer ABI versions.
+ getDriver().Dir + "/../include/c++/v1",
+
+ // We also check the system as for a long time this is the only place Clang looked.
+ // FIXME: We should really remove this. It doesn't make any sense.
+ getDriver().SysRoot + "/usr/include/c++/v1"
+ };
+ for (const auto &IncludePath : LibCXXIncludePathCandidates) {
+ if (!llvm::sys::fs::exists(IncludePath))
+ continue;
+ // Add the first candidate that exists.
+ addSystemInclude(DriverArgs, CC1Args, IncludePath);
+ break;
+ }
return;
}
@@ -2767,16 +3461,23 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
StringRef LibDir = GCCInstallation.getParentLibPath();
StringRef InstallDir = GCCInstallation.getInstallPath();
StringRef TripleStr = GCCInstallation.getTriple().str();
- StringRef MIPSABIDirSuffix = GCCInstallation.getMIPSABIDirSuffix();
- StringRef BiarchSuffix = GCCInstallation.getBiarchSuffix();
+ const Multilib &Multilib = GCCInstallation.getMultilib();
+ const std::string GCCMultiarchTriple =
+ getMultiarchTriple(GCCInstallation.getTriple(), getDriver().SysRoot);
+ const std::string TargetMultiarchTriple =
+ getMultiarchTriple(getTriple(), getDriver().SysRoot);
const GCCVersion &Version = GCCInstallation.getVersion();
+ // The primary search for libstdc++ supports multiarch variants.
if (addLibStdCXXIncludePaths(LibDir.str() + "/../include",
- "/c++/" + Version.Text, TripleStr, BiarchSuffix,
- MIPSABIDirSuffix, DriverArgs, CC1Args))
+ "/c++/" + Version.Text, TripleStr, GCCMultiarchTriple,
+ TargetMultiarchTriple,
+ Multilib.includeSuffix(), DriverArgs, CC1Args))
return;
- const std::string IncludePathCandidates[] = {
+ // Otherwise, fall back on a bunch of options which don't use multiarch
+ // layouts for simplicity.
+ const std::string LibStdCXXIncludePathCandidates[] = {
// Gentoo is weird and places its headers inside the GCC install, so if the
// first attempt to find the headers fails, try these patterns.
InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." +
@@ -2789,10 +3490,11 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
LibDir.str() + "/../include/c++",
};
- for (unsigned i = 0; i < llvm::array_lengthof(IncludePathCandidates); ++i) {
- if (addLibStdCXXIncludePaths(IncludePathCandidates[i],
- TripleStr + MIPSABIDirSuffix + BiarchSuffix,
- DriverArgs, CC1Args))
+ for (const auto &IncludePath : LibStdCXXIncludePathCandidates) {
+ if (addLibStdCXXIncludePaths(IncludePath, /*Suffix*/ "", TripleStr,
+ /*GCCMultiarchTriple*/ "",
+ /*TargetMultiarchTriple*/ "",
+ Multilib.includeSuffix(), DriverArgs, CC1Args))
break;
}
}
@@ -2862,7 +3564,6 @@ bool XCore::hasBlocksRuntime() const {
return false;
}
-
void XCore::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
if (DriverArgs.hasArg(options::OPT_nostdinc) ||
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index c758fbb999fa..b5df8668d69e 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -13,11 +13,13 @@
#include "Tools.h"
#include "clang/Basic/VersionTuple.h"
#include "clang/Driver/Action.h"
+#include "clang/Driver/Multilib.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/Support/Compiler.h"
-#include <vector>
#include <set>
+#include <vector>
namespace clang {
namespace driver {
@@ -67,7 +69,6 @@ protected:
bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); }
};
-
/// \brief This is a class to find a viable GCC installation for Clang to
/// use.
///
@@ -76,14 +77,17 @@ protected:
/// Driver, and has logic for fuzzing that where appropriate.
class GCCInstallationDetector {
bool IsValid;
- const Driver &D;
llvm::Triple GCCTriple;
// FIXME: These might be better as path objects.
std::string GCCInstallPath;
- std::string GCCBiarchSuffix;
std::string GCCParentLibPath;
- std::string GCCMIPSABIDirSuffix;
+
+ /// The primary multilib appropriate for the given flags.
+ Multilib SelectedMultilib;
+ /// On Biarch systems, this corresponds to the default multilib when
+ /// targeting the non-default multilib. Otherwise, it is empty.
+ llvm::Optional<Multilib> BiarchSibling;
GCCVersion Version;
@@ -91,8 +95,12 @@ protected:
// order to print out detailed information in verbose mode.
std::set<std::string> CandidateGCCInstallPaths;
+ /// The set of multilibs that the detected installation supports.
+ MultilibSet Multilibs;
+
public:
- GCCInstallationDetector(const Driver &D, const llvm::Triple &TargetTriple,
+ GCCInstallationDetector() : IsValid(false) {}
+ void init(const Driver &D, const llvm::Triple &TargetTriple,
const llvm::opt::ArgList &Args);
/// \brief Check whether we detected a valid GCC install.
@@ -104,26 +112,18 @@ protected:
/// \brief Get the detected GCC installation path.
StringRef getInstallPath() const { return GCCInstallPath; }
- /// \brief Get the detected GCC installation path suffix for the bi-arch
- /// target variant.
- StringRef getBiarchSuffix() const { return GCCBiarchSuffix; }
-
/// \brief Get the detected GCC parent lib path.
StringRef getParentLibPath() const { return GCCParentLibPath; }
- /// \brief Get the detected GCC MIPS ABI directory suffix.
- ///
- /// This is used as a suffix both to the install directory of GCC and as
- /// a suffix to its parent lib path in order to select a MIPS ABI-specific
- /// subdirectory.
- ///
- /// This will always be empty for any non-MIPS target.
- ///
- // FIXME: This probably shouldn't exist at all, and should be factored
- // into the multiarch and/or biarch support. Please don't add more uses of
- // this interface, it is meant as a legacy crutch for the MIPS driver
- // logic.
- StringRef getMIPSABIDirSuffix() const { return GCCMIPSABIDirSuffix; }
+ /// \brief Get the detected Multilib
+ const Multilib &getMultilib() const { return SelectedMultilib; }
+
+ /// \brief Get the whole MultilibSet
+ const MultilibSet &getMultilibs() const { return Multilibs; }
+
+ /// Get the biarch sibling multilib (if it exists).
+ /// \return true iff such a sibling exists
+ bool getBiarchSibling(Multilib &M) const;
/// \brief Get the detected GCC version string.
const GCCVersion &getVersion() const { return Version; }
@@ -140,15 +140,11 @@ protected:
SmallVectorImpl<StringRef> &BiarchLibDirs,
SmallVectorImpl<StringRef> &BiarchTripleAliases);
- void ScanLibDirForGCCTriple(llvm::Triple::ArchType TargetArch,
+ void ScanLibDirForGCCTriple(const llvm::Triple &TargetArch,
const llvm::opt::ArgList &Args,
const std::string &LibDir,
StringRef CandidateTriple,
bool NeedsBiarchSuffix = false);
-
- void findMIPSABIDirSuffix(std::string &Suffix,
- llvm::Triple::ArchType TargetArch, StringRef Path,
- const llvm::opt::ArgList &Args);
};
GCCInstallationDetector GCCInstallation;
@@ -158,19 +154,18 @@ public:
const llvm::opt::ArgList &Args);
~Generic_GCC();
- virtual void printVerboseInfo(raw_ostream &OS) const;
+ void printVerboseInfo(raw_ostream &OS) const override;
- virtual bool IsUnwindTablesDefault() const;
- virtual bool isPICDefault() const;
- virtual bool isPIEDefault() const;
- virtual bool isPICDefaultForced() const;
- virtual void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
+ bool IsUnwindTablesDefault() const override;
+ bool isPICDefault() const override;
+ bool isPIEDefault() const override;
+ bool isPICDefaultForced() const override;
+ bool IsIntegratedAssemblerDefault() const override;
protected:
- virtual Tool *getTool(Action::ActionClass AC) const;
- virtual Tool *buildAssembler() const;
- virtual Tool *buildLinker() const;
+ Tool *getTool(Action::ActionClass AC) const override;
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
/// \name ToolChain Implementation Helper Functions
/// @{
@@ -184,27 +179,138 @@ protected:
/// @}
private:
- mutable OwningPtr<tools::gcc::Preprocess> Preprocess;
- mutable OwningPtr<tools::gcc::Precompile> Precompile;
- mutable OwningPtr<tools::gcc::Compile> Compile;
+ mutable std::unique_ptr<tools::gcc::Preprocess> Preprocess;
+ mutable std::unique_ptr<tools::gcc::Compile> Compile;
+};
+
+class LLVM_LIBRARY_VISIBILITY MachO : public ToolChain {
+protected:
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
+ Tool *getTool(Action::ActionClass AC) const override;
+private:
+ mutable std::unique_ptr<tools::darwin::Lipo> Lipo;
+ mutable std::unique_ptr<tools::darwin::Dsymutil> Dsymutil;
+ mutable std::unique_ptr<tools::darwin::VerifyDebug> VerifyDebug;
+
+public:
+ MachO(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
+ ~MachO();
+
+ /// @name MachO specific toolchain API
+ /// {
+
+ /// Get the "MachO" arch name for a particular compiler invocation. For
+ /// example, Apple treats different ARM variations as distinct architectures.
+ StringRef getMachOArchName(const llvm::opt::ArgList &Args) const;
+
+
+ /// Add the linker arguments to link the ARC runtime library.
+ virtual void AddLinkARCArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const {}
+
+ /// Add the linker arguments to link the compiler runtime library.
+ virtual void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
+ virtual void
+ addStartObjectFileArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const {}
+
+ virtual void addMinVersionArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const {}
+
+ /// On some iOS platforms, kernel and kernel modules were built statically. Is
+ /// this such a target?
+ virtual bool isKernelStatic() const {
+ return false;
+ }
+
+ /// Is the target either iOS or an iOS simulator?
+ bool isTargetIOSBased() const {
+ return false;
+ }
+
+ void AddLinkRuntimeLib(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs,
+ StringRef DarwinStaticLib,
+ bool AlwaysLink = false,
+ bool IsEmbedded = false) const;
+
+ /// }
+ /// @name ToolChain Implementation
+ /// {
+
+ std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
+ types::ID InputType) const override;
+
+ types::ID LookupTypeForExtension(const char *Ext) const override;
+
+ bool HasNativeLLVMSupport() const override;
+
+ llvm::opt::DerivedArgList *
+ TranslateArgs(const llvm::opt::DerivedArgList &Args,
+ const char *BoundArch) const override;
+
+ bool IsBlocksDefault() const override {
+ // Always allow blocks on Apple; users interested in versioning are
+ // expected to use /usr/include/Blocks.h.
+ return true;
+ }
+ bool IsIntegratedAssemblerDefault() const override {
+ // Default integrated assembler to on for Apple's MachO targets.
+ return true;
+ }
+
+ bool IsMathErrnoDefault() const override {
+ return false;
+ }
+
+ bool IsEncodeExtendedBlockSignatureDefault() const override {
+ return true;
+ }
+
+ bool IsObjCNonFragileABIDefault() const override {
+ // Non-fragile ABI is default for everything but i386.
+ return getTriple().getArch() != llvm::Triple::x86;
+ }
+
+ bool UseObjCMixedDispatch() const override {
+ return true;
+ }
+
+ bool IsUnwindTablesDefault() const override;
+
+ RuntimeLibType GetDefaultRuntimeLibType() const override {
+ return ToolChain::RLT_CompilerRT;
+ }
+
+ bool isPICDefault() const override;
+ bool isPIEDefault() const override;
+ bool isPICDefaultForced() const override;
+
+ bool SupportsProfiling() const override;
+
+ bool SupportsObjCGC() const override {
+ return false;
+ }
+
+ bool UseDwarfDebugFlags() const override;
+
+ bool UseSjLjExceptions() const override {
+ return false;
+ }
+
+ /// }
};
/// Darwin - The base Darwin tool chain.
-class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain {
+class LLVM_LIBRARY_VISIBILITY Darwin : public MachO {
public:
/// The host version.
unsigned DarwinVersion[3];
-protected:
- virtual Tool *buildAssembler() const;
- virtual Tool *buildLinker() const;
- virtual Tool *getTool(Action::ActionClass AC) const;
-
-private:
- mutable OwningPtr<tools::darwin::Lipo> Lipo;
- mutable OwningPtr<tools::darwin::Dsymutil> Dsymutil;
- mutable OwningPtr<tools::darwin::VerifyDebug> VerifyDebug;
-
/// Whether the information on the target has been initialized.
//
// FIXME: This should be eliminated. What we want to do is make this part of
@@ -212,11 +318,13 @@ private:
// the argument translation business.
mutable bool TargetInitialized;
- /// Whether we are targeting iPhoneOS target.
- mutable bool TargetIsIPhoneOS;
+ enum DarwinPlatformKind {
+ MacOS,
+ IPhoneOS,
+ IPhoneOSSimulator
+ };
- /// Whether we are targeting the iPhoneOS simulator target.
- mutable bool TargetIsIPhoneOSSimulator;
+ mutable DarwinPlatformKind TargetPlatform;
/// The OS version we are targeting.
mutable VersionTuple TargetVersion;
@@ -239,43 +347,62 @@ public:
~Darwin();
std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
- types::ID InputType) const;
+ types::ID InputType) const override;
- /// @name Darwin Specific Toolchain API
+ /// @name Apple Specific Toolchain Implementation
+ /// {
+
+ void
+ addMinVersionArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ void
+ addStartObjectFileArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
+ bool isKernelStatic() const override {
+ return !isTargetIPhoneOS() || isIPhoneOSVersionLT(6, 0) ||
+ getTriple().getArch() == llvm::Triple::arm64;
+ }
+
+protected:
+ /// }
+ /// @name Darwin specific Toolchain functions
/// {
// FIXME: Eliminate these ...Target functions and derive separate tool chains
// for these targets and put version in constructor.
- void setTarget(bool IsIPhoneOS, unsigned Major, unsigned Minor,
- unsigned Micro, bool IsIOSSim) const {
- assert((!IsIOSSim || IsIPhoneOS) && "Unexpected deployment target!");
-
+ void setTarget(DarwinPlatformKind Platform, unsigned Major, unsigned Minor,
+ unsigned Micro) const {
// FIXME: For now, allow reinitialization as long as values don't
// change. This will go away when we move away from argument translation.
- if (TargetInitialized && TargetIsIPhoneOS == IsIPhoneOS &&
- TargetIsIPhoneOSSimulator == IsIOSSim &&
+ if (TargetInitialized && TargetPlatform == Platform &&
TargetVersion == VersionTuple(Major, Minor, Micro))
return;
assert(!TargetInitialized && "Target already initialized!");
TargetInitialized = true;
- TargetIsIPhoneOS = IsIPhoneOS;
- TargetIsIPhoneOSSimulator = IsIOSSim;
+ TargetPlatform = Platform;
TargetVersion = VersionTuple(Major, Minor, Micro);
}
bool isTargetIPhoneOS() const {
assert(TargetInitialized && "Target not initialized!");
- return TargetIsIPhoneOS;
+ return TargetPlatform == IPhoneOS;
}
bool isTargetIOSSimulator() const {
assert(TargetInitialized && "Target not initialized!");
- return TargetIsIPhoneOSSimulator;
+ return TargetPlatform == IPhoneOSSimulator;
+ }
+
+ bool isTargetIOSBased() const {
+ assert(TargetInitialized && "Target not initialized!");
+ return isTargetIPhoneOS() || isTargetIOSSimulator();
}
bool isTargetMacOS() const {
- return !isTargetIOSSimulator() && !isTargetIPhoneOS();
+ return TargetPlatform == MacOS;
}
bool isTargetInitialized() const { return TargetInitialized; }
@@ -285,101 +412,58 @@ public:
return TargetVersion;
}
- /// getDarwinArchName - Get the "Darwin" arch name for a particular compiler
- /// invocation. For example, Darwin treats different ARM variations as
- /// distinct architectures.
- StringRef getDarwinArchName(const llvm::opt::ArgList &Args) const;
-
bool isIPhoneOSVersionLT(unsigned V0, unsigned V1=0, unsigned V2=0) const {
- assert(isTargetIPhoneOS() && "Unexpected call for OS X target!");
+ assert(isTargetIOSBased() && "Unexpected call for non iOS target!");
return TargetVersion < VersionTuple(V0, V1, V2);
}
bool isMacosxVersionLT(unsigned V0, unsigned V1=0, unsigned V2=0) const {
- assert(!isTargetIPhoneOS() && "Unexpected call for iPhoneOS target!");
+ assert(isTargetMacOS() && "Unexpected call for non OS X target!");
return TargetVersion < VersionTuple(V0, V1, V2);
}
- /// AddLinkARCArgs - Add the linker arguments to link the ARC runtime library.
- virtual void AddLinkARCArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const = 0;
-
- /// AddLinkRuntimeLibArgs - Add the linker arguments to link the compiler
- /// runtime library.
- virtual void
- AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const = 0;
-
+public:
/// }
/// @name ToolChain Implementation
/// {
- virtual types::ID LookupTypeForExtension(const char *Ext) const;
-
- virtual bool HasNativeLLVMSupport() const;
-
- virtual ObjCRuntime getDefaultObjCRuntime(bool isNonFragile) const;
- virtual bool hasBlocksRuntime() const;
+ // Darwin tools support multiple architecture (e.g., i386 and x86_64) and
+ // most development is done against SDKs, so compiling for a different
+ // architecture should not get any special treatment.
+ bool isCrossCompiling() const override { return false; }
- virtual llvm::opt::DerivedArgList *
+ llvm::opt::DerivedArgList *
TranslateArgs(const llvm::opt::DerivedArgList &Args,
- const char *BoundArch) const;
-
- virtual bool IsBlocksDefault() const {
- // Always allow blocks on Darwin; users interested in versioning are
- // expected to use /usr/include/Blocks.h.
- return true;
- }
- virtual bool IsIntegratedAssemblerDefault() const {
- // Default integrated assembler to on for Darwin.
- return true;
- }
+ const char *BoundArch) const override;
- virtual bool IsMathErrnoDefault() const {
- return false;
- }
-
- virtual bool IsEncodeExtendedBlockSignatureDefault() const {
- return true;
- }
-
- virtual bool IsObjCNonFragileABIDefault() const {
- // Non-fragile ABI is default for everything but i386.
- return getTriple().getArch() != llvm::Triple::x86;
- }
+ ObjCRuntime getDefaultObjCRuntime(bool isNonFragile) const override;
+ bool hasBlocksRuntime() const override;
- virtual bool UseObjCMixedDispatch() const {
+ bool UseObjCMixedDispatch() const override {
// This is only used with the non-fragile ABI and non-legacy dispatch.
// Mixed dispatch is used everywhere except OS X before 10.6.
- return !(!isTargetIPhoneOS() && isMacosxVersionLT(10, 6));
+ return !(isTargetMacOS() && isMacosxVersionLT(10, 6));
}
- virtual bool IsUnwindTablesDefault() const;
- virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const {
+
+ unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
// Stack protectors default to on for user code on 10.5,
// and for everything in 10.6 and beyond
- return isTargetIPhoneOS() ||
- (!isMacosxVersionLT(10, 6) ||
- (!isMacosxVersionLT(10, 5) && !KernelOrKext));
+ if (isTargetIOSBased())
+ return 1;
+ else if (isTargetMacOS() && !isMacosxVersionLT(10, 6))
+ return 1;
+ else if (isTargetMacOS() && !isMacosxVersionLT(10, 5) && !KernelOrKext)
+ return 1;
+
+ return 0;
}
- virtual RuntimeLibType GetDefaultRuntimeLibType() const {
- return ToolChain::RLT_CompilerRT;
- }
- virtual bool isPICDefault() const;
- virtual bool isPIEDefault() const;
- virtual bool isPICDefaultForced() const;
-
- virtual bool SupportsProfiling() const;
-
- virtual bool SupportsObjCGC() const;
-
- virtual void CheckObjCARC() const;
- virtual bool UseDwarfDebugFlags() const;
+ bool SupportsObjCGC() const override;
- virtual bool UseSjLjExceptions() const;
+ void CheckObjCARC() const override;
- /// }
+ bool UseSjLjExceptions() const override;
};
/// DarwinClang - The Darwin toolchain used by Clang.
@@ -388,38 +472,27 @@ public:
DarwinClang(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
- /// @name Darwin ToolChain Implementation
+ /// @name Apple ToolChain Implementation
/// {
- virtual void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
- void AddLinkRuntimeLib(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs,
- const char *DarwinStaticLib,
- bool AlwaysLink = false) const;
-
- virtual void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
-
- virtual void AddCCKextLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
+ void
+ AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
- virtual void AddLinkARCArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
- /// }
-};
+ void
+ AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
-/// Darwin_Generic_GCC - Generic Darwin tool chain using gcc.
-class LLVM_LIBRARY_VISIBILITY Darwin_Generic_GCC : public Generic_GCC {
-public:
- Darwin_Generic_GCC(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args)
- : Generic_GCC(D, Triple, Args) {}
+ void
+ AddCCKextLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
- std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
- types::ID InputType) const;
+ virtual void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const;
- virtual bool isPICDefault() const { return false; }
+ void
+ AddLinkARCArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+ /// }
};
class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC {
@@ -429,12 +502,8 @@ public:
const llvm::opt::ArgList &Args)
: Generic_GCC(D, Triple, Args) {}
- virtual bool IsIntegratedAssemblerDefault() const {
- // Default integrated assembler to on for x86.
- return (getTriple().getArch() == llvm::Triple::aarch64 ||
- getTriple().getArch() == llvm::Triple::x86 ||
- getTriple().getArch() == llvm::Triple::x86_64);
- }
+ void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
};
class LLVM_LIBRARY_VISIBILITY AuroraUX : public Generic_GCC {
@@ -443,8 +512,8 @@ public:
const llvm::opt::ArgList &Args);
protected:
- virtual Tool *buildAssembler() const;
- virtual Tool *buildLinker() const;
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
};
class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_GCC {
@@ -452,10 +521,10 @@ public:
Solaris(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
- virtual bool IsIntegratedAssemblerDefault() const { return true; }
+ bool IsIntegratedAssemblerDefault() const override { return true; }
protected:
- virtual Tool *buildAssembler() const;
- virtual Tool *buildLinker() const;
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
};
@@ -465,17 +534,25 @@ public:
OpenBSD(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
- virtual bool IsMathErrnoDefault() const { return false; }
- virtual bool IsObjCNonFragileABIDefault() const { return true; }
- virtual bool isPIEDefault() const { return true; }
+ bool IsMathErrnoDefault() const override { return false; }
+ bool IsObjCNonFragileABIDefault() const override { return true; }
+ bool isPIEDefault() const override { return true; }
+
+ unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
+ return 2;
+ }
- virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const {
- return 1;
+ virtual bool IsIntegratedAssemblerDefault() const override {
+ if (getTriple().getArch() == llvm::Triple::ppc ||
+ getTriple().getArch() == llvm::Triple::sparc ||
+ getTriple().getArch() == llvm::Triple::sparcv9)
+ return true;
+ return Generic_ELF::IsIntegratedAssemblerDefault();
}
protected:
- virtual Tool *buildAssembler() const;
- virtual Tool *buildLinker() const;
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
};
class LLVM_LIBRARY_VISIBILITY Bitrig : public Generic_ELF {
@@ -483,43 +560,49 @@ public:
Bitrig(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
- virtual bool IsMathErrnoDefault() const { return false; }
- virtual bool IsObjCNonFragileABIDefault() const { return true; }
- virtual bool IsObjCLegacyDispatchDefault() const { return false; }
+ bool IsMathErrnoDefault() const override { return false; }
+ bool IsObjCNonFragileABIDefault() const override { return true; }
- virtual void
+ CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
+ void
AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
- virtual void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
- virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const {
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+ unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
return 1;
}
protected:
- virtual Tool *buildAssembler() const;
- virtual Tool *buildLinker() const;
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
};
class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF {
public:
FreeBSD(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
- virtual bool HasNativeLLVMSupport() const;
+ bool HasNativeLLVMSupport() const override;
- virtual bool IsMathErrnoDefault() const { return false; }
- virtual bool IsObjCNonFragileABIDefault() const { return true; }
+ bool IsMathErrnoDefault() const override { return false; }
+ bool IsObjCNonFragileABIDefault() const override { return true; }
- virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const;
- virtual void
+ CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
+ void
AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
-
+ llvm::opt::ArgStringList &CC1Args) const override;
+ bool IsIntegratedAssemblerDefault() const override {
+ if (getTriple().getArch() == llvm::Triple::ppc ||
+ getTriple().getArch() == llvm::Triple::ppc64)
+ return true;
+ return Generic_ELF::IsIntegratedAssemblerDefault();
+ }
- virtual bool UseSjLjExceptions() const;
+ bool UseSjLjExceptions() const override;
+ bool isPIEDefault() const override;
protected:
- virtual Tool *buildAssembler() const;
- virtual Tool *buildLinker() const;
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
};
class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF {
@@ -527,26 +610,26 @@ public:
NetBSD(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
- virtual bool IsMathErrnoDefault() const { return false; }
- virtual bool IsObjCNonFragileABIDefault() const { return true; }
+ bool IsMathErrnoDefault() const override { return false; }
+ bool IsObjCNonFragileABIDefault() const override { return true; }
- virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const;
+ CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
- virtual void
+ void
AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
- virtual bool IsUnwindTablesDefault() const {
+ llvm::opt::ArgStringList &CC1Args) const override;
+ bool IsUnwindTablesDefault() const override {
return true;
}
- virtual bool IsIntegratedAssemblerDefault() const {
+ bool IsIntegratedAssemblerDefault() const override {
if (getTriple().getArch() == llvm::Triple::ppc)
return true;
return Generic_ELF::IsIntegratedAssemblerDefault();
}
protected:
- virtual Tool *buildAssembler() const;
- virtual Tool *buildLinker() const;
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
};
class LLVM_LIBRARY_VISIBILITY Minix : public Generic_ELF {
@@ -555,8 +638,8 @@ public:
const llvm::opt::ArgList &Args);
protected:
- virtual Tool *buildAssembler() const;
- virtual Tool *buildLinker() const;
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
};
class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_ELF {
@@ -564,11 +647,11 @@ public:
DragonFly(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
- virtual bool IsMathErrnoDefault() const { return false; }
+ bool IsMathErrnoDefault() const override { return false; }
protected:
- virtual Tool *buildAssembler() const;
- virtual Tool *buildLinker() const;
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
};
class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF {
@@ -576,31 +659,29 @@ public:
Linux(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
- virtual bool HasNativeLLVMSupport() const;
+ bool HasNativeLLVMSupport() const override;
- virtual void
+ void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
- virtual void
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void
AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
- virtual bool isPIEDefault() const;
+ llvm::opt::ArgStringList &CC1Args) const override;
+ bool isPIEDefault() const override;
std::string Linker;
std::vector<std::string> ExtraOpts;
protected:
- virtual Tool *buildAssembler() const;
- virtual Tool *buildLinker() const;
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
private:
static bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix,
- Twine TargetArchDir,
- Twine BiarchSuffix,
- Twine MIPSABIDirSuffix,
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args);
- static bool addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir,
+ StringRef GCCTriple,
+ StringRef GCCMultiarchTriple,
+ StringRef TargetMultiarchTriple,
+ Twine IncludeSuffix,
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args);
@@ -610,21 +691,21 @@ private:
class LLVM_LIBRARY_VISIBILITY Hexagon_TC : public Linux {
protected:
GCCVersion GCCLibAndIncVersion;
- virtual Tool *buildAssembler() const;
- virtual Tool *buildLinker() const;
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
public:
Hexagon_TC(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
~Hexagon_TC();
- virtual void
+ void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
- virtual void
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void
AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
- virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const;
+ llvm::opt::ArgStringList &CC1Args) const override;
+ CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; }
@@ -641,10 +722,10 @@ public:
const llvm::opt::ArgList &Args);
~TCEToolChain();
- bool IsMathErrnoDefault() const;
- bool isPICDefault() const;
- bool isPIEDefault() const;
- bool isPICDefaultForced() const;
+ bool IsMathErrnoDefault() const override;
+ bool isPICDefault() const override;
+ bool isPIEDefault() const override;
+ bool isPICDefaultForced() const override;
};
class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain {
@@ -652,22 +733,22 @@ public:
Windows(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
- virtual bool IsIntegratedAssemblerDefault() const;
- virtual bool IsUnwindTablesDefault() const;
- virtual bool isPICDefault() const;
- virtual bool isPIEDefault() const;
- virtual bool isPICDefaultForced() const;
+ bool IsIntegratedAssemblerDefault() const override;
+ bool IsUnwindTablesDefault() const override;
+ bool isPICDefault() const override;
+ bool isPIEDefault() const override;
+ bool isPICDefaultForced() const override;
- virtual void
+ void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
- virtual void
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void
AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
+ llvm::opt::ArgStringList &CC1Args) const override;
protected:
- virtual Tool *buildLinker() const;
- virtual Tool *buildAssembler() const;
+ Tool *buildLinker() const override;
+ Tool *buildAssembler() const override;
};
@@ -676,22 +757,22 @@ public:
XCore(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
protected:
- virtual Tool *buildAssembler() const;
- virtual Tool *buildLinker() const;
+ Tool *buildAssembler() const override;
+ Tool *buildLinker() const override;
public:
- virtual bool isPICDefault() const;
- virtual bool isPIEDefault() const;
- virtual bool isPICDefaultForced() const;
- virtual bool SupportsProfiling() const;
- virtual bool hasBlocksRuntime() const;
- virtual void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
- virtual void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
- virtual void AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const;
- virtual void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) const;
+ bool isPICDefault() const override;
+ bool isPIEDefault() const override;
+ bool isPICDefaultForced() const override;
+ bool SupportsProfiling() const override;
+ bool hasBlocksRuntime() const override;
+ void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
};
} // end namespace toolchains
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index b013eb510c4e..198e82e15369 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -10,6 +10,7 @@
#include "Tools.h"
#include "InputInfo.h"
#include "ToolChains.h"
+#include "clang/Basic/LangOptions.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/Action.h"
@@ -21,7 +22,6 @@
#include "clang/Driver/SanitizerArgs.h"
#include "clang/Driver/ToolChain.h"
#include "clang/Driver/Util.h"
-#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
@@ -29,28 +29,47 @@
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
+#include "llvm/Support/Compression.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/Program.h"
#include "llvm/Support/Process.h"
+#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
-#include <sys/stat.h>
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
+static void addAssemblerKPIC(const ArgList &Args, ArgStringList &CmdArgs) {
+ Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
+ options::OPT_fpic, options::OPT_fno_pic,
+ options::OPT_fPIE, options::OPT_fno_PIE,
+ options::OPT_fpie, options::OPT_fno_pie);
+ if (!LastPICArg)
+ return;
+ if (LastPICArg->getOption().matches(options::OPT_fPIC) ||
+ LastPICArg->getOption().matches(options::OPT_fpic) ||
+ LastPICArg->getOption().matches(options::OPT_fPIE) ||
+ LastPICArg->getOption().matches(options::OPT_fpie)) {
+ CmdArgs.push_back("-KPIC");
+ }
+}
+
/// CheckPreprocessingOptions - Perform some validation of preprocessing
/// arguments that is shared with gcc.
static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) {
- if (Arg *A = Args.getLastArg(options::OPT_C, options::OPT_CC))
- if (!Args.hasArg(options::OPT_E) && !D.CCCIsCPP())
+ if (Arg *A = Args.getLastArg(options::OPT_C, options::OPT_CC)) {
+ if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_P) &&
+ !Args.hasArg(options::OPT__SLASH_EP) && !D.CCCIsCPP()) {
D.Diag(diag::err_drv_argument_only_allowed_with)
- << A->getAsString(Args) << "-E";
+ << A->getBaseArg().getAsString(Args)
+ << (D.IsCLMode() ? "/E, /P or /EP" : "-E");
+ }
+ }
}
/// CheckCodeGenerationOptions - Perform some validation of code generation
@@ -157,10 +176,7 @@ static void AddLinkerInputs(const ToolChain &TC,
// (constructed via -Xarch_).
Args.AddAllArgValues(CmdArgs, options::OPT_Zlinker_input);
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
-
+ for (const auto &II : Inputs) {
if (!TC.HasNativeLLVMSupport()) {
// Don't try to pass LLVM inputs unless we have native support.
if (II.getType() == types::TY_LLVM_IR ||
@@ -181,16 +197,23 @@ static void AddLinkerInputs(const ToolChain &TC,
const Arg &A = II.getInputArg();
// Handle reserved library options.
- if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) {
+ if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx))
TC.AddCXXStdlibLibArgs(Args, CmdArgs);
- } else if (A.getOption().matches(options::OPT_Z_reserved_lib_cckext)) {
+ else if (A.getOption().matches(options::OPT_Z_reserved_lib_cckext))
TC.AddCCKextLibArgs(Args, CmdArgs);
- } else
- A.renderAsInput(Args, CmdArgs);
+ else if (A.getOption().matches(options::OPT_z)) {
+ // Pass -z prefix for gcc linker compatibility.
+ A.claim();
+ A.render(Args, CmdArgs);
+ } else {
+ A.renderAsInput(Args, CmdArgs);
+ }
}
// LIBRARY_PATH - included following the user specified library paths.
- addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH");
+ // and only supported on native toolchains.
+ if (!TC.isCrossCompiling())
+ addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH");
}
/// \brief Determine whether Objective-C automated reference counting is
@@ -208,25 +231,6 @@ static bool isObjCRuntimeLinked(const ArgList &Args) {
return Args.hasArg(options::OPT_fobjc_link_runtime);
}
-static void addProfileRT(const ToolChain &TC, const ArgList &Args,
- 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.
- std::string ProfileRT =
- std::string(TC.getDriver().Dir) + "/../lib/libprofile_rt.a";
-
- CmdArgs.push_back(Args.MakeArgString(ProfileRT));
-}
-
static bool forwardToGCC(const Option &O) {
// Don't forward inputs from the original command line. They are added from
// InputInfoList.
@@ -297,6 +301,9 @@ void Clang::AddPreprocessingOptions(Compilation &C,
if (A->getOption().matches(options::OPT_M) ||
A->getOption().matches(options::OPT_MD))
CmdArgs.push_back("-sys-header-deps");
+
+ if (isa<PrecompileJobAction>(JA))
+ CmdArgs.push_back("-module-file-deps");
}
if (Args.hasArg(options::OPT_MG)) {
@@ -442,129 +449,6 @@ void Clang::AddPreprocessingOptions(Compilation &C,
getToolChain().AddClangSystemIncludeArgs(Args, CmdArgs);
}
-/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular
-/// CPU.
-//
-// FIXME: This is redundant with -mcpu, why does LLVM use this.
-// FIXME: tblgen this, or kill it!
-static const char *getLLVMArchSuffixForARM(StringRef CPU) {
- return llvm::StringSwitch<const char *>(CPU)
- .Case("strongarm", "v4")
- .Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "v4t")
- .Cases("arm720t", "arm9", "arm9tdmi", "v4t")
- .Cases("arm920", "arm920t", "arm922t", "v4t")
- .Cases("arm940t", "ep9312","v4t")
- .Cases("arm10tdmi", "arm1020t", "v5")
- .Cases("arm9e", "arm926ej-s", "arm946e-s", "v5e")
- .Cases("arm966e-s", "arm968e-s", "arm10e", "v5e")
- .Cases("arm1020e", "arm1022e", "xscale", "iwmmxt", "v5e")
- .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6")
- .Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
- .Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
- .Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7")
- .Cases("cortex-a9", "cortex-a12", "cortex-a15", "v7")
- .Cases("cortex-r4", "cortex-r5", "v7r")
- .Case("cortex-m0", "v6m")
- .Case("cortex-m3", "v7m")
- .Case("cortex-m4", "v7em")
- .Case("cortex-a9-mp", "v7f")
- .Case("swift", "v7s")
- .Cases("cortex-a53", "cortex-a57", "v8")
- .Default("");
-}
-
-/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting.
-//
-// FIXME: tblgen this.
-static std::string getARMTargetCPU(const ArgList &Args,
- const llvm::Triple &Triple) {
- // FIXME: Warn on inconsistent use of -mcpu and -march.
-
- // If we have -mcpu=, use that.
- if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- StringRef MCPU = A->getValue();
- // Handle -mcpu=native.
- if (MCPU == "native")
- return llvm::sys::getHostCPUName();
- else
- return MCPU;
- }
-
- StringRef MArch;
- if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- // Otherwise, if we have -march= choose the base CPU for that arch.
- MArch = A->getValue();
- } else {
- // Otherwise, use the Arch from the triple.
- MArch = Triple.getArchName();
- }
-
- if (Triple.getOS() == llvm::Triple::NetBSD) {
- if (MArch == "armv6")
- return "arm1176jzf-s";
- }
-
- // Handle -march=native.
- std::string NativeMArch;
- if (MArch == "native") {
- std::string CPU = llvm::sys::getHostCPUName();
- if (CPU != "generic") {
- // Translate the native cpu into the architecture. The switch below will
- // then chose the minimum cpu for that arch.
- NativeMArch = std::string("arm") + getLLVMArchSuffixForARM(CPU);
- MArch = NativeMArch;
- }
- }
-
- return llvm::StringSwitch<const char *>(MArch)
- .Cases("armv2", "armv2a","arm2")
- .Case("armv3", "arm6")
- .Case("armv3m", "arm7m")
- .Case("armv4", "strongarm")
- .Case("armv4t", "arm7tdmi")
- .Cases("armv5", "armv5t", "arm10tdmi")
- .Cases("armv5e", "armv5te", "arm1022e")
- .Case("armv5tej", "arm926ej-s")
- .Cases("armv6", "armv6k", "arm1136jf-s")
- .Case("armv6j", "arm1136j-s")
- .Cases("armv6z", "armv6zk", "arm1176jzf-s")
- .Case("armv6t2", "arm1156t2-s")
- .Cases("armv6m", "armv6-m", "cortex-m0")
- .Cases("armv7", "armv7a", "armv7-a", "cortex-a8")
- .Cases("armv7em", "armv7e-m", "cortex-m4")
- .Cases("armv7f", "armv7-f", "cortex-a9-mp")
- .Cases("armv7s", "armv7-s", "swift")
- .Cases("armv7r", "armv7-r", "cortex-r4")
- .Cases("armv7m", "armv7-m", "cortex-m3")
- .Cases("armv8", "armv8a", "armv8-a", "cortex-a53")
- .Case("ep9312", "ep9312")
- .Case("iwmmxt", "iwmmxt")
- .Case("xscale", "xscale")
- // If all else failed, return the most base CPU with thumb interworking
- // supported by LLVM.
- .Default("arm7tdmi");
-}
-
-/// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are targeting.
-//
-// FIXME: tblgen this.
-static std::string getAArch64TargetCPU(const ArgList &Args,
- const llvm::Triple &Triple) {
- // FIXME: Warn on inconsistent use of -mcpu and -march.
-
- // If we have -mcpu=, use that.
- if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- StringRef MCPU = A->getValue();
- // Handle -mcpu=native.
- if (MCPU == "native")
- return llvm::sys::getHostCPUName();
- else
- return MCPU;
- }
-
- return "generic";
-}
-
// FIXME: Move to target hook.
static bool isSignedCharDefault(const llvm::Triple &Triple) {
switch (Triple.getArch()) {
@@ -572,7 +456,15 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) {
return true;
case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm64:
+ case llvm::Triple::arm64_be:
case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ if (Triple.isOSDarwin() || Triple.isOSWindows())
+ return true;
+ return false;
+
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
if (Triple.isOSDarwin())
@@ -596,33 +488,6 @@ static bool isNoCommonDefault(const llvm::Triple &Triple) {
}
}
-// Handle -mfpu=.
-//
-// FIXME: Centralize feature selection, defaulting shouldn't be also in the
-// frontend target.
-static void getAArch64FPUFeatures(const Driver &D, const Arg *A,
- const ArgList &Args,
- std::vector<const char *> &Features) {
- StringRef FPU = A->getValue();
- if (FPU == "fp-armv8") {
- Features.push_back("+fp-armv8");
- } else if (FPU == "neon-fp-armv8") {
- Features.push_back("+fp-armv8");
- Features.push_back("+neon");
- } else if (FPU == "crypto-neon-fp-armv8") {
- Features.push_back("+fp-armv8");
- Features.push_back("+neon");
- Features.push_back("+crypto");
- } else if (FPU == "neon") {
- Features.push_back("+neon");
- } else if (FPU == "none") {
- Features.push_back("-fp-armv8");
- Features.push_back("-crypto");
- Features.push_back("-neon");
- } else
- D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
-}
-
// Handle -mhwdiv=.
static void getARMHWDivFeatures(const Driver &D, const Arg *A,
const ArgList &Args,
@@ -659,16 +524,28 @@ static void getARMFPUFeatures(const Driver &D, const Arg *A,
Features.push_back("-vfp2");
Features.push_back("-vfp3");
Features.push_back("-neon");
+ } else if (FPU == "vfp") {
+ Features.push_back("+vfp2");
+ Features.push_back("-neon");
} else if (FPU == "vfp3-d16" || FPU == "vfpv3-d16") {
Features.push_back("+vfp3");
Features.push_back("+d16");
Features.push_back("-neon");
- } else if (FPU == "vfp") {
- Features.push_back("+vfp2");
- Features.push_back("-neon");
} else if (FPU == "vfp3" || FPU == "vfpv3") {
Features.push_back("+vfp3");
Features.push_back("-neon");
+ } else if (FPU == "vfp4-d16" || FPU == "vfpv4-d16") {
+ Features.push_back("+vfp4");
+ Features.push_back("+d16");
+ Features.push_back("-neon");
+ } else if (FPU == "vfp4" || FPU == "vfpv4") {
+ Features.push_back("+vfp4");
+ Features.push_back("-neon");
+ } else if (FPU == "fp4-sp-d16" || FPU == "fpv4-sp-d16") {
+ Features.push_back("+vfp4");
+ Features.push_back("+d16");
+ Features.push_back("+fp-only-sp");
+ Features.push_back("-neon");
} else if (FPU == "fp-armv8") {
Features.push_back("+fp-armv8");
Features.push_back("-neon");
@@ -696,9 +573,8 @@ static void getARMFPUFeatures(const Driver &D, const Arg *A,
// Select the float ABI as determined by -msoft-float, -mhard-float, and
// -mfloat-abi=.
-static StringRef getARMFloatABI(const Driver &D,
- const ArgList &Args,
- const llvm::Triple &Triple) {
+StringRef tools::arm::getARMFloatABI(const Driver &D, const ArgList &Args,
+ const llvm::Triple &Triple) {
StringRef FloatABI;
if (Arg *A = Args.getLastArg(options::OPT_msoft_float,
options::OPT_mhard_float,
@@ -727,7 +603,7 @@ static StringRef getARMFloatABI(const Driver &D,
//
// FIXME: Factor out an ARM class so we can cache the arch somewhere.
std::string ArchName =
- getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple));
+ arm::getLLVMArchSuffixForARM(arm::getARMTargetCPU(Args, Triple));
if (StringRef(ArchName).startswith("v6") ||
StringRef(ArchName).startswith("v7"))
FloatABI = "softfp";
@@ -736,9 +612,21 @@ static StringRef getARMFloatABI(const Driver &D,
break;
}
+ // FIXME: this is invalid for WindowsCE
+ case llvm::Triple::Win32:
+ FloatABI = "hard";
+ break;
+
case llvm::Triple::FreeBSD:
- // FreeBSD defaults to soft float
- FloatABI = "soft";
+ switch(Triple.getEnvironment()) {
+ case llvm::Triple::GNUEABIHF:
+ FloatABI = "hard";
+ break;
+ default:
+ // FreeBSD defaults to soft float
+ FloatABI = "soft";
+ break;
+ }
break;
default:
@@ -749,13 +637,16 @@ static StringRef getARMFloatABI(const Driver &D,
case llvm::Triple::GNUEABI:
FloatABI = "softfp";
break;
+ case llvm::Triple::EABIHF:
+ FloatABI = "hard";
+ break;
case llvm::Triple::EABI:
// EABI is always AAPCS, and if it was not marked 'hard', it's softfp
FloatABI = "softfp";
break;
case llvm::Triple::Android: {
std::string ArchName =
- getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple));
+ arm::getLLVMArchSuffixForARM(arm::getARMTargetCPU(Args, Triple));
if (StringRef(ArchName).startswith("v7"))
FloatABI = "softfp";
else
@@ -765,7 +656,9 @@ static StringRef getARMFloatABI(const Driver &D,
default:
// Assume "soft", but warn the user we are guessing.
FloatABI = "soft";
- D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft";
+ if (Triple.getOS() != llvm::Triple::UnknownOS ||
+ !Triple.isOSBinFormatMachO())
+ D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft";
break;
}
}
@@ -776,18 +669,30 @@ static StringRef getARMFloatABI(const Driver &D,
static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args,
- std::vector<const char *> &Features) {
- StringRef FloatABI = getARMFloatABI(D, Args, Triple);
- // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these
- // yet (it uses the -mfloat-abi and -msoft-float options), and it is
- // stripped out by the ARM target.
- // Use software floating point operations?
- if (FloatABI == "soft")
- Features.push_back("+soft-float");
+ std::vector<const char *> &Features,
+ bool ForAS) {
+ StringRef FloatABI = tools::arm::getARMFloatABI(D, Args, Triple);
+ if (!ForAS) {
+ // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these
+ // yet (it uses the -mfloat-abi and -msoft-float options), and it is
+ // stripped out by the ARM target. We should probably pass this a new
+ // -target-option, which is handled by the -cc1/-cc1as invocation.
+ //
+ // FIXME2: For consistency, it would be ideal if we set up the target
+ // machine state the same when using the frontend or the assembler. We don't
+ // currently do that for the assembler, we pass the options directly to the
+ // backend and never even instantiate the frontend TargetInfo. If we did,
+ // and used its handleTargetFeatures hook, then we could ensure the
+ // assembler and the frontend behave the same.
- // Use software floating point argument passing?
- if (FloatABI != "hard")
- Features.push_back("+soft-float-abi");
+ // Use software floating point operations?
+ if (FloatABI == "soft")
+ Features.push_back("+soft-float");
+
+ // Use software floating point argument passing?
+ if (FloatABI != "hard")
+ Features.push_back("+soft-float-abi");
+ }
// Honor -mfpu=.
if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ))
@@ -797,8 +702,11 @@ static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
// Setting -msoft-float effectively disables NEON because of the GCC
// implementation, although the same isn't true of VFP or VFP3.
- if (FloatABI == "soft")
+ if (FloatABI == "soft") {
Features.push_back("-neon");
+ // Also need to explicitly disable features which imply NEON.
+ Features.push_back("-crypto");
+ }
// En/disable crc
if (Arg *A = Args.getLastArg(options::OPT_mcrc,
@@ -817,23 +725,28 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
// Get the effective triple, which takes into account the deployment target.
std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args);
llvm::Triple Triple(TripleStr);
- std::string CPUName = getARMTargetCPU(Args, Triple);
+ std::string CPUName = arm::getARMTargetCPU(Args, Triple);
// Select the ABI to use.
//
// FIXME: Support -meabi.
- const char *ABIName = 0;
+ const char *ABIName = nullptr;
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
ABIName = A->getValue();
- } else if (Triple.isOSDarwin()) {
+ } else if (Triple.isOSBinFormatMachO()) {
// The backend is hardwired to assume AAPCS for M-class processors, ensure
// the frontend matches that.
if (Triple.getEnvironment() == llvm::Triple::EABI ||
+ (Triple.getOS() == llvm::Triple::UnknownOS &&
+ Triple.getObjectFormat() == llvm::Triple::MachO) ||
StringRef(CPUName).startswith("cortex-m")) {
ABIName = "aapcs";
} else {
ABIName = "apcs-gnu";
}
+ } else if (Triple.isOSWindows()) {
+ // FIXME: this is invalid for WindowsCE
+ ABIName = "aapcs";
} else {
// Select the default based on the platform.
switch(Triple.getEnvironment()) {
@@ -842,6 +755,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
case llvm::Triple::GNUEABIHF:
ABIName = "aapcs-linux";
break;
+ case llvm::Triple::EABIHF:
case llvm::Triple::EABI:
ABIName = "aapcs";
break;
@@ -853,7 +767,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
CmdArgs.push_back(ABIName);
// Determine floating point ABI from the options & target defaults.
- StringRef FloatABI = getARMFloatABI(D, Args, Triple);
+ StringRef FloatABI = tools::arm::getARMFloatABI(D, Args, Triple);
if (FloatABI == "soft") {
// Floating point operations and argument passing are soft.
//
@@ -900,23 +814,97 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
true))
CmdArgs.push_back("-no-implicit-float");
- // llvm does not support reserving registers in general. There is support
- // for reserving r9 on ARM though (defined as a platform-specific register
- // in ARM EABI).
- if (Args.hasArg(options::OPT_ffixed_r9)) {
- CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-arm-reserve-r9");
- }
+ // llvm does not support reserving registers in general. There is support
+ // for reserving r9 on ARM though (defined as a platform-specific register
+ // in ARM EABI).
+ if (Args.hasArg(options::OPT_ffixed_r9)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-reserve-r9");
+ }
+}
+
+/// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are
+/// targeting.
+static std::string getAArch64TargetCPU(const ArgList &Args) {
+ Arg *A;
+ std::string CPU;
+ // If we have -mtune or -mcpu, use that.
+ if ((A = Args.getLastArg(options::OPT_mtune_EQ))) {
+ CPU = A->getValue();
+ } else if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) {
+ StringRef Mcpu = A->getValue();
+ CPU = Mcpu.split("+").first;
+ }
+
+ // Handle CPU name is 'native'.
+ if (CPU == "native")
+ return llvm::sys::getHostCPUName();
+ else if (CPU.size())
+ return CPU;
+
+ // Make sure we pick "cyclone" if -arch is used.
+ // FIXME: Should this be picked by checking the target triple instead?
+ if (Args.getLastArg(options::OPT_arch))
+ return "cyclone";
+
+ return "generic";
+}
+
+void Clang::AddAArch64TargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args);
+ llvm::Triple Triple(TripleStr);
+
+ if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) ||
+ Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_fapple_kext))
+ CmdArgs.push_back("-disable-red-zone");
+
+ if (!Args.hasFlag(options::OPT_mimplicit_float,
+ options::OPT_mno_implicit_float, true))
+ CmdArgs.push_back("-no-implicit-float");
+
+ const char *ABIName = nullptr;
+ if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
+ ABIName = A->getValue();
+ else if (Triple.isOSDarwin())
+ ABIName = "darwinpcs";
+ else
+ ABIName = "aapcs";
+
+ CmdArgs.push_back("-target-abi");
+ CmdArgs.push_back(ABIName);
+
+ if (Args.hasArg(options::OPT_mstrict_align)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-aarch64-strict-align");
+ }
+
+ // Setting -mno-global-merge disables the codegen global merge pass. Setting
+ // -mglobal-merge has no effect as the pass is enabled by default.
+ if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge,
+ options::OPT_mno_global_merge)) {
+ if (A->getOption().matches(options::OPT_mno_global_merge))
+ CmdArgs.push_back("-mno-global-merge");
+ }
}
// Get CPU and ABI names. They are not independent
// so we have to calculate them together.
-static void getMipsCPUAndABI(const ArgList &Args,
- const llvm::Triple &Triple,
- StringRef &CPUName,
- StringRef &ABIName) {
- const char *DefMips32CPU = "mips32";
- const char *DefMips64CPU = "mips64";
+void mips::getMipsCPUAndABI(const ArgList &Args,
+ const llvm::Triple &Triple,
+ StringRef &CPUName,
+ StringRef &ABIName) {
+ const char *DefMips32CPU = "mips32r2";
+ const char *DefMips64CPU = "mips64r2";
+
+ // MIPS32r6 is the default for mips(el)?-img-linux-gnu and MIPS64r6 is the
+ // default for mips64(el)?-img-linux-gnu.
+ if (Triple.getVendor() == llvm::Triple::ImaginationTechnologies &&
+ Triple.getEnvironment() == llvm::Triple::GNU) {
+ DefMips32CPU = "mips32r6";
+ DefMips64CPU = "mips64r6";
+ }
if (Arg *A = Args.getLastArg(options::OPT_march_EQ,
options::OPT_mcpu_EQ))
@@ -948,22 +936,22 @@ static void getMipsCPUAndABI(const ArgList &Args,
}
}
- if (!ABIName.empty()) {
+ if (ABIName.empty()) {
+ // Deduce ABI name from the target triple.
+ if (Triple.getArch() == llvm::Triple::mips ||
+ Triple.getArch() == llvm::Triple::mipsel)
+ ABIName = "o32";
+ else
+ ABIName = "n64";
+ }
+
+ if (CPUName.empty()) {
// Deduce CPU name from ABI name.
CPUName = llvm::StringSwitch<const char *>(ABIName)
- .Cases("32", "o32", "eabi", DefMips32CPU)
- .Cases("n32", "n64", "64", DefMips64CPU)
+ .Cases("o32", "eabi", DefMips32CPU)
+ .Cases("n32", "n64", DefMips64CPU)
.Default("");
}
- else if (!CPUName.empty()) {
- // Deduce ABI name from CPU name.
- ABIName = llvm::StringSwitch<const char *>(CPUName)
- .Cases("mips32", "mips32r2", "o32")
- .Cases("mips64", "mips64r2", "n64")
- .Default("");
- }
-
- // FIXME: Warn on inconsistent cpu and abi usage.
}
// Convert ABI name to the GNU tools acceptable variant.
@@ -1017,11 +1005,27 @@ static void AddTargetFeature(const ArgList &Args,
}
}
-static void getMIPSTargetFeatures(const Driver &D, const ArgList &Args,
+static void getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args,
std::vector<const char *> &Features) {
+ StringRef CPUName;
+ StringRef ABIName;
+ mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
+ ABIName = getGnuCompatibleMipsABIName(ABIName);
+
+ // Always override the backend's default ABI.
+ std::string ABIFeature = llvm::StringSwitch<StringRef>(ABIName)
+ .Case("32", "+o32")
+ .Case("n32", "+n32")
+ .Case("64", "+n64")
+ .Case("eabi", "+eabi")
+ .Default(("+" + ABIName).str());
+ Features.push_back("-o32");
+ Features.push_back("-n64");
+ Features.push_back(Args.MakeArgString(ABIFeature));
+
StringRef FloatABI = getMipsFloatABI(D, Args);
- bool IsMips16 = Args.getLastArg(options::OPT_mips16) != NULL;
- if (FloatABI == "soft" || (FloatABI == "hard" && IsMips16)) {
+ if (FloatABI == "soft") {
// FIXME: Note, this is a hack. We need to pass the selected float
// mode to the MipsTargetInfoBase to define appropriate macros there.
// Now it is the only method.
@@ -1029,8 +1033,14 @@ static void getMIPSTargetFeatures(const Driver &D, const ArgList &Args,
}
if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) {
- if (StringRef(A->getValue()) == "2008")
+ StringRef Val = StringRef(A->getValue());
+ if (Val == "2008")
Features.push_back("+nan2008");
+ else if (Val == "legacy")
+ Features.push_back("-nan2008");
+ else
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Val;
}
AddTargetFeature(Args, Features, options::OPT_msingle_float,
@@ -1045,8 +1055,25 @@ static void getMIPSTargetFeatures(const Driver &D, const ArgList &Args,
"dspr2");
AddTargetFeature(Args, Features, options::OPT_mmsa, options::OPT_mno_msa,
"msa");
- AddTargetFeature(Args, Features, options::OPT_mfp64, options::OPT_mfp32,
- "fp64");
+
+ // Add the last -mfp32/-mfpxx/-mfp64 or if none are given and the ABI is O32
+ // pass -mfpxx
+ if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx,
+ options::OPT_mfp64)) {
+ if (A->getOption().matches(options::OPT_mfp32))
+ Features.push_back(Args.MakeArgString("-fp64"));
+ else if (A->getOption().matches(options::OPT_mfpxx)) {
+ Features.push_back(Args.MakeArgString("+fpxx"));
+ Features.push_back(Args.MakeArgString("+nooddspreg"));
+ } else
+ Features.push_back(Args.MakeArgString("+fp64"));
+ } else if (mips::isFPXXDefault(Triple, CPUName, ABIName)) {
+ Features.push_back(Args.MakeArgString("+fpxx"));
+ Features.push_back(Args.MakeArgString("+nooddspreg"));
+ }
+
+ AddTargetFeature(Args, Features, options::OPT_mno_odd_spreg,
+ options::OPT_modd_spreg, "nooddspreg");
}
void Clang::AddMIPSTargetArgs(const ArgList &Args,
@@ -1055,25 +1082,18 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
StringRef CPUName;
StringRef ABIName;
const llvm::Triple &Triple = getToolChain().getTriple();
- getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
+ mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName.data());
StringRef FloatABI = getMipsFloatABI(D, Args);
- bool IsMips16 = Args.getLastArg(options::OPT_mips16) != NULL;
-
- if (FloatABI == "soft" || (FloatABI == "hard" && IsMips16)) {
+ if (FloatABI == "soft") {
// Floating point operations and argument passing are soft.
CmdArgs.push_back("-msoft-float");
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("soft");
-
- if (FloatABI == "hard" && IsMips16) {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-mips16-hard-float");
- }
}
else {
// Floating point operations and argument passing are hard.
@@ -1159,6 +1179,7 @@ static std::string getPPCTargetCPU(const ArgList &Args) {
.Case("power6", "pwr6")
.Case("power6x", "pwr6x")
.Case("power7", "pwr7")
+ .Case("power8", "pwr8")
.Case("pwr3", "pwr3")
.Case("pwr4", "pwr4")
.Case("pwr5", "pwr5")
@@ -1166,6 +1187,7 @@ static std::string getPPCTargetCPU(const ArgList &Args) {
.Case("pwr6", "pwr6")
.Case("pwr6x", "pwr6x")
.Case("pwr7", "pwr7")
+ .Case("pwr8", "pwr8")
.Case("powerpc", "ppc")
.Case("powerpc64", "ppc64")
.Case("powerpc64le", "ppc64le")
@@ -1239,7 +1261,7 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
const Driver &D = getToolChain().getDriver();
- // Select the float ABI as determined by -msoft-float, -mhard-float, and
+ // Select the float ABI as determined by -msoft-float and -mhard-float.
StringRef FloatABI;
if (Arg *A = Args.getLastArg(options::OPT_msoft_float,
options::OPT_mhard_float)) {
@@ -1297,7 +1319,7 @@ static const char *getX86TargetCPU(const ArgList &Args,
if (Triple.getArch() != llvm::Triple::x86_64 &&
Triple.getArch() != llvm::Triple::x86)
- return 0; // This routine is only handling x86 targets.
+ return nullptr; // This routine is only handling x86 targets.
bool Is64Bit = Triple.getArch() == llvm::Triple::x86_64;
@@ -1308,10 +1330,9 @@ static const char *getX86TargetCPU(const ArgList &Args,
return Is64Bit ? "core2" : "yonah";
}
- // All x86 devices running Android have core2 as their common
- // denominator. This makes a better choice than pentium4.
+ // On Android use targets compatible with gcc
if (Triple.getEnvironment() == llvm::Triple::Android)
- return "core2";
+ return Is64Bit ? "x86-64" : "i686";
// Everything else goes to x86-64 in 64-bit mode.
if (Is64Bit)
@@ -1338,11 +1359,16 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T) {
return "";
case llvm::Triple::aarch64:
- return getAArch64TargetCPU(Args, T);
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm64:
+ case llvm::Triple::arm64_be:
+ return getAArch64TargetCPU(Args);
case llvm::Triple::arm:
+ case llvm::Triple::armeb:
case llvm::Triple::thumb:
- return getARMTargetCPU(Args, T);
+ case llvm::Triple::thumbeb:
+ return arm::getARMTargetCPU(Args, T);
case llvm::Triple::mips:
case llvm::Triple::mipsel:
@@ -1350,7 +1376,7 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T) {
case llvm::Triple::mips64el: {
StringRef CPUName;
StringRef ABIName;
- getMipsCPUAndABI(Args, T, CPUName, ABIName);
+ mips::getMipsCPUAndABI(Args, T, CPUName, ABIName);
return CPUName;
}
@@ -1373,7 +1399,8 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T) {
}
case llvm::Triple::sparc:
- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
+ case llvm::Triple::sparcv9:
+ if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
return A->getValue();
return "";
@@ -1392,7 +1419,26 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T) {
}
}
-static void getX86TargetFeatures(const llvm::Triple &Triple,
+static void AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ // Tell the linker to load the plugin. This has to come before AddLinkerInputs
+ // as gold requires -plugin to come before any -plugin-opt that -Wl might
+ // forward.
+ CmdArgs.push_back("-plugin");
+ std::string Plugin = ToolChain.getDriver().Dir + "/../lib/LLVMgold.so";
+ CmdArgs.push_back(Args.MakeArgString(Plugin));
+
+ // Try to pass driver level flags relevant to LTO code generation down to
+ // the plugin.
+
+ // Handle flags for selecting CPU variants.
+ std::string CPU = getCPUName(Args, ToolChain.getTriple());
+ if (!CPU.empty())
+ CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU));
+}
+
+static void getX86TargetFeatures(const Driver & D,
+ const llvm::Triple &Triple,
const ArgList &Args,
std::vector<const char *> &Features) {
if (Triple.getArchName() == "x86_64h") {
@@ -1406,6 +1452,40 @@ static void getX86TargetFeatures(const llvm::Triple &Triple,
Features.push_back("-fsgsbase");
}
+ // Add features to comply with gcc on Android
+ if (Triple.getEnvironment() == llvm::Triple::Android) {
+ if (Triple.getArch() == llvm::Triple::x86_64) {
+ Features.push_back("+sse4.2");
+ Features.push_back("+popcnt");
+ } else
+ Features.push_back("+ssse3");
+ }
+
+ // Set features according to the -arch flag on MSVC
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_arch)) {
+ StringRef Arch = A->getValue();
+ bool ArchUsed = false;
+ // First, look for flags that are shared in x86 and x86-64.
+ if (Triple.getArch() == llvm::Triple::x86_64 ||
+ Triple.getArch() == llvm::Triple::x86) {
+ if (Arch == "AVX" || Arch == "AVX2") {
+ ArchUsed = true;
+ Features.push_back(Args.MakeArgString("+" + Arch.lower()));
+ }
+ }
+ // Then, look for x86-specific flags.
+ if (Triple.getArch() == llvm::Triple::x86) {
+ if (Arch == "IA32") {
+ ArchUsed = true;
+ } else if (Arch == "SSE" || Arch == "SSE2") {
+ ArchUsed = true;
+ Features.push_back(Args.MakeArgString("+" + Arch.lower()));
+ }
+ }
+ if (!ArchUsed)
+ D.Diag(clang::diag::warn_drv_unused_argument) << A->getAsString(Args);
+ }
+
// Now add any that the user explicitly requested on the command line,
// which may override the defaults.
for (arg_iterator it = Args.filtered_begin(options::OPT_m_x86_Features_Group),
@@ -1449,6 +1529,17 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
}
if (NoImplicitFloat)
CmdArgs.push_back("-no-implicit-float");
+
+ if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) {
+ StringRef Value = A->getValue();
+ if (Value == "intel" || Value == "att") {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value));
+ } else {
+ getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << Value;
+ }
+ }
}
static inline bool HasPICArg(const ArgList &Args) {
@@ -1496,15 +1587,146 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args,
CmdArgs.push_back ("-machine-sink-split=0");
}
+// Decode AArch64 features from string like +[no]featureA+[no]featureB+...
+static bool DecodeAArch64Features(const Driver &D, const StringRef &text,
+ std::vector<const char *> &Features) {
+ SmallVector<StringRef, 8> Split;
+ text.split(Split, StringRef("+"), -1, false);
+
+ for (unsigned I = 0, E = Split.size(); I != E; ++I) {
+ const char *result = llvm::StringSwitch<const char *>(Split[I])
+ .Case("fp", "+fp-armv8")
+ .Case("simd", "+neon")
+ .Case("crc", "+crc")
+ .Case("crypto", "+crypto")
+ .Case("nofp", "-fp-armv8")
+ .Case("nosimd", "-neon")
+ .Case("nocrc", "-crc")
+ .Case("nocrypto", "-crypto")
+ .Default(nullptr);
+ if (result)
+ Features.push_back(result);
+ else if (Split[I] == "neon" || Split[I] == "noneon")
+ D.Diag(diag::err_drv_no_neon_modifier);
+ else
+ return false;
+ }
+ return true;
+}
+
+// Check if the CPU name and feature modifiers in -mcpu are legal. If yes,
+// decode CPU and feature.
+static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU,
+ std::vector<const char *> &Features) {
+ std::pair<StringRef, StringRef> Split = Mcpu.split("+");
+ CPU = Split.first;
+ if (CPU == "cyclone" || CPU == "cortex-a53" || CPU == "cortex-a57") {
+ Features.push_back("+neon");
+ Features.push_back("+crc");
+ Features.push_back("+crypto");
+ } else if (CPU == "generic") {
+ Features.push_back("+neon");
+ } else {
+ return false;
+ }
+
+ if (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features))
+ return false;
+
+ return true;
+}
+
+static bool
+getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March,
+ const ArgList &Args,
+ std::vector<const char *> &Features) {
+ std::pair<StringRef, StringRef> Split = March.split("+");
+ if (Split.first != "armv8-a")
+ return false;
+
+ if (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features))
+ return false;
+
+ return true;
+}
+
+static bool
+getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
+ const ArgList &Args,
+ std::vector<const char *> &Features) {
+ StringRef CPU;
+ if (!DecodeAArch64Mcpu(D, Mcpu, CPU, Features))
+ return false;
+
+ return true;
+}
+
+static bool
+getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune,
+ const ArgList &Args,
+ std::vector<const char *> &Features) {
+ // Handle CPU name is 'native'.
+ if (Mtune == "native")
+ Mtune = llvm::sys::getHostCPUName();
+ if (Mtune == "cyclone") {
+ Features.push_back("+zcm");
+ Features.push_back("+zcz");
+ }
+ return true;
+}
+
+static bool
+getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
+ const ArgList &Args,
+ std::vector<const char *> &Features) {
+ StringRef CPU;
+ std::vector<const char *> DecodedFeature;
+ if (!DecodeAArch64Mcpu(D, Mcpu, CPU, DecodedFeature))
+ return false;
+
+ return getAArch64MicroArchFeaturesFromMtune(D, CPU, Args, Features);
+}
+
static void getAArch64TargetFeatures(const Driver &D, const ArgList &Args,
std::vector<const char *> &Features) {
- // Honor -mfpu=.
- if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ))
- getAArch64FPUFeatures(D, A, Args, Features);
+ Arg *A;
+ bool success = true;
+ // Enable NEON by default.
+ Features.push_back("+neon");
+ if ((A = Args.getLastArg(options::OPT_march_EQ)))
+ success = getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Features);
+ else if ((A = Args.getLastArg(options::OPT_mcpu_EQ)))
+ success = getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
+
+ if (success && (A = Args.getLastArg(options::OPT_mtune_EQ)))
+ success =
+ getAArch64MicroArchFeaturesFromMtune(D, A->getValue(), Args, Features);
+ else if (success && (A = Args.getLastArg(options::OPT_mcpu_EQ)))
+ success =
+ getAArch64MicroArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
+
+ if (!success)
+ D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
+
+ if (Args.getLastArg(options::OPT_mgeneral_regs_only)) {
+ Features.push_back("-fp-armv8");
+ Features.push_back("-crypto");
+ Features.push_back("-neon");
+ }
+
+ // En/disable crc
+ if (Arg *A = Args.getLastArg(options::OPT_mcrc,
+ options::OPT_mnocrc)) {
+ if (A->getOption().matches(options::OPT_mcrc))
+ Features.push_back("+crc");
+ else
+ Features.push_back("-crc");
+ }
}
static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args, ArgStringList &CmdArgs) {
+ const ArgList &Args, ArgStringList &CmdArgs,
+ bool ForAS) {
std::vector<const char *> Features;
switch (Triple.getArch()) {
default:
@@ -1513,12 +1735,14 @@ static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple,
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
- getMIPSTargetFeatures(D, Args, Features);
+ getMIPSTargetFeatures(D, Triple, Args, Features);
break;
case llvm::Triple::arm:
+ case llvm::Triple::armeb:
case llvm::Triple::thumb:
- getARMTargetFeatures(D, Triple, Args, Features);
+ case llvm::Triple::thumbeb:
+ getARMTargetFeatures(D, Triple, Args, Features, ForAS);
break;
case llvm::Triple::ppc:
@@ -1530,11 +1754,14 @@ static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple,
getSparcTargetFeatures(Args, Features);
break;
case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm64:
+ case llvm::Triple::arm64_be:
getAArch64TargetFeatures(D, Args, Features);
break;
case llvm::Triple::x86:
case llvm::Triple::x86_64:
- getX86TargetFeatures(Triple, Args, Features);
+ getX86TargetFeatures(D, Triple, Args, Features);
break;
}
@@ -1569,7 +1796,7 @@ shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime,
if (runtime.isNonFragile())
return true;
- if (!Triple.isOSDarwin())
+ if (!Triple.isMacOSX())
return false;
return (!Triple.isMacOSXVersionLT(10,5) &&
@@ -1577,6 +1804,45 @@ shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime,
Triple.getArch() == llvm::Triple::arm));
}
+namespace {
+ struct ExceptionSettings {
+ bool ExceptionsEnabled;
+ bool ShouldUseExceptionTables;
+ ExceptionSettings() : ExceptionsEnabled(false),
+ ShouldUseExceptionTables(false) {}
+ };
+} // end anonymous namespace.
+
+// exceptionSettings() exists to share the logic between -cc1 and linker
+// invocations.
+static ExceptionSettings exceptionSettings(const ArgList &Args,
+ const llvm::Triple &Triple) {
+ ExceptionSettings ES;
+
+ // Are exceptions enabled by default?
+ ES.ExceptionsEnabled = (Triple.getArch() != llvm::Triple::xcore);
+
+ // This keeps track of whether exceptions were explicitly turned on or off.
+ bool DidHaveExplicitExceptionFlag = false;
+
+ if (Arg *A = Args.getLastArg(options::OPT_fexceptions,
+ options::OPT_fno_exceptions)) {
+ if (A->getOption().matches(options::OPT_fexceptions))
+ ES.ExceptionsEnabled = true;
+ else
+ ES.ExceptionsEnabled = false;
+
+ DidHaveExplicitExceptionFlag = true;
+ }
+
+ // Exception tables and cleanups can be enabled with -fexceptions even if the
+ // language itself doesn't support exceptions.
+ if (ES.ExceptionsEnabled && DidHaveExplicitExceptionFlag)
+ ES.ShouldUseExceptionTables = true;
+
+ return ES;
+}
+
/// addExceptionArgs - Adds exception related arguments to the driver command
/// arguments. There's a master flag, -fexceptions and also language specific
/// flags to enable/disable C++ and Objective-C exceptions.
@@ -1599,28 +1865,8 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType,
return;
}
- // Exceptions are enabled by default.
- bool ExceptionsEnabled = true;
-
- // This keeps track of whether exceptions were explicitly turned on or off.
- bool DidHaveExplicitExceptionFlag = false;
-
- if (Arg *A = Args.getLastArg(options::OPT_fexceptions,
- options::OPT_fno_exceptions)) {
- if (A->getOption().matches(options::OPT_fexceptions))
- ExceptionsEnabled = true;
- else
- ExceptionsEnabled = false;
-
- DidHaveExplicitExceptionFlag = true;
- }
-
- bool ShouldUseExceptionTables = false;
-
- // Exception tables and cleanups can be enabled with -fexceptions even if the
- // language itself doesn't support exceptions.
- if (ExceptionsEnabled && DidHaveExplicitExceptionFlag)
- ShouldUseExceptionTables = true;
+ // Gather the exception settings from the command line arguments.
+ ExceptionSettings ES = exceptionSettings(Args, Triple);
// Obj-C exceptions are enabled by default, regardless of -fexceptions. This
// is not necessarily sensible, but follows GCC.
@@ -1630,12 +1876,12 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType,
true)) {
CmdArgs.push_back("-fobjc-exceptions");
- ShouldUseExceptionTables |=
+ ES.ShouldUseExceptionTables |=
shouldUseExceptionTablesForObjCExceptions(objcRuntime, Triple);
}
if (types::isCXX(InputType)) {
- bool CXXExceptionsEnabled = ExceptionsEnabled;
+ bool CXXExceptionsEnabled = ES.ExceptionsEnabled;
if (Arg *A = Args.getLastArg(options::OPT_fcxx_exceptions,
options::OPT_fno_cxx_exceptions,
@@ -1650,11 +1896,11 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType,
if (CXXExceptionsEnabled) {
CmdArgs.push_back("-fcxx-exceptions");
- ShouldUseExceptionTables = true;
+ ES.ShouldUseExceptionTables = true;
}
}
- if (ShouldUseExceptionTables)
+ if (ES.ShouldUseExceptionTables)
CmdArgs.push_back("-fexceptions");
}
@@ -1670,19 +1916,6 @@ static bool ShouldDisableAutolink(const ArgList &Args,
Default);
}
-static bool ShouldDisableCFI(const ArgList &Args,
- const ToolChain &TC) {
- bool Default = true;
- if (TC.getTriple().isOSDarwin()) {
- // The native darwin assembler doesn't support cfi directives, so
- // we disable them if we think the .s file will be passed to it.
- Default = TC.useIntegratedAs();
- }
- return !Args.hasFlag(options::OPT_fdwarf2_cfi_asm,
- options::OPT_fno_dwarf2_cfi_asm,
- Default);
-}
-
static bool ShouldDisableDwarfDirectory(const ArgList &Args,
const ToolChain &TC) {
bool UseDwarfDirectory = Args.hasFlag(options::OPT_fdwarf_directory_asm,
@@ -1696,8 +1929,8 @@ static bool ContainsCompileAction(const Action *A) {
if (isa<CompileJobAction>(A))
return true;
- for (Action::const_iterator it = A->begin(), ie = A->end(); it != ie; ++it)
- if (ContainsCompileAction(*it))
+ for (const auto &Act : *A)
+ if (ContainsCompileAction(Act))
return true;
return false;
@@ -1713,9 +1946,8 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
if (RelaxDefault) {
RelaxDefault = false;
- for (ActionList::const_iterator it = C.getActions().begin(),
- ie = C.getActions().end(); it != ie; ++it) {
- if (ContainsCompileAction(*it)) {
+ for (const auto &Act : C.getActions()) {
+ if (ContainsCompileAction(Act)) {
RelaxDefault = true;
break;
}
@@ -1742,6 +1974,7 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
// When using an integrated assembler, translate -Wa, and -Xassembler
// options.
+ bool CompressDebugSections = false;
for (arg_iterator it = Args.filtered_begin(options::OPT_Wa_COMMA,
options::OPT_Xassembler),
ie = Args.filtered_end(); it != ie; ++it) {
@@ -1765,48 +1998,116 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
CmdArgs.push_back("-fatal-assembler-warnings");
} else if (Value == "--noexecstack") {
CmdArgs.push_back("-mnoexecstack");
+ } else if (Value == "-compress-debug-sections" ||
+ Value == "--compress-debug-sections") {
+ CompressDebugSections = true;
+ } else if (Value == "-nocompress-debug-sections" ||
+ Value == "--nocompress-debug-sections") {
+ CompressDebugSections = false;
} else if (Value.startswith("-I")) {
CmdArgs.push_back(Value.data());
// We need to consume the next argument if the current arg is a plain
// -I. The next arg will be the include directory.
if (Value == "-I")
TakeNextArg = true;
+ } else if (Value.startswith("-gdwarf-")) {
+ CmdArgs.push_back(Value.data());
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Value;
}
}
}
+ if (CompressDebugSections) {
+ if (llvm::zlib::isAvailable())
+ CmdArgs.push_back("-compress-debug-sections");
+ else
+ D.Diag(diag::warn_debug_compression_unavailable);
+ }
}
-static void addProfileRTLinux(
+// Until ARM libraries are build separately, we have them all in one library
+static StringRef getArchNameForCompilerRTLib(const ToolChain &TC) {
+ if (TC.getArch() == llvm::Triple::arm ||
+ TC.getArch() == llvm::Triple::armeb)
+ return "arm";
+ else
+ return TC.getArchName();
+}
+
+static SmallString<128> getCompilerRTLibDir(const ToolChain &TC) {
+ // The runtimes are located in the OS-specific resource directory.
+ SmallString<128> Res(TC.getDriver().ResourceDir);
+ const llvm::Triple &Triple = TC.getTriple();
+ // TC.getOS() yield "freebsd10.0" whereas "freebsd" is expected.
+ StringRef OSLibName = (Triple.getOS() == llvm::Triple::FreeBSD) ?
+ "freebsd" : TC.getOS();
+ llvm::sys::path::append(Res, "lib", OSLibName);
+ return Res;
+}
+
+// This adds the static libclang_rt.builtins-arch.a directly to the command line
+// FIXME: Make sure we can also emit shared objects if they're requested
+// and available, check for possible errors, etc.
+static void addClangRTLinux(
+ const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) {
+ SmallString<128> LibClangRT = getCompilerRTLibDir(TC);
+ llvm::sys::path::append(LibClangRT, Twine("libclang_rt.builtins-") +
+ getArchNameForCompilerRTLib(TC) +
+ ".a");
+
+ CmdArgs.push_back(Args.MakeArgString(LibClangRT));
+ CmdArgs.push_back("-lgcc_s");
+ if (TC.getDriver().CCCIsCXX())
+ CmdArgs.push_back("-lgcc_eh");
+}
+
+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_fprofile_instr_generate) ||
Args.hasArg(options::OPT_fcreate_profile) ||
Args.hasArg(options::OPT_coverage)))
return;
- // The profile runtime is located in the Linux library directory and has name
- // "libclang_rt.profile-<ArchName>.a".
- SmallString<128> LibProfile(TC.getDriver().ResourceDir);
- llvm::sys::path::append(
- LibProfile, "lib", "linux",
- Twine("libclang_rt.profile-") + TC.getArchName() + ".a");
+ // -fprofile-instr-generate requires position-independent code to build with
+ // shared objects. Link against the right archive.
+ const char *Lib = "libclang_rt.profile-";
+ if (Args.hasArg(options::OPT_fprofile_instr_generate) &&
+ Args.hasArg(options::OPT_shared))
+ Lib = "libclang_rt.profile-pic-";
+
+ SmallString<128> LibProfile = getCompilerRTLibDir(TC);
+ llvm::sys::path::append(LibProfile,
+ Twine(Lib) + getArchNameForCompilerRTLib(TC) + ".a");
CmdArgs.push_back(Args.MakeArgString(LibProfile));
}
-static void addSanitizerRTLinkFlagsLinux(
- const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs,
- const StringRef Sanitizer, bool BeforeLibStdCXX,
- bool ExportSymbols = true) {
- // Sanitizer runtime is located in the Linux library directory and
- // has name "libclang_rt.<Sanitizer>-<ArchName>.a".
- SmallString<128> LibSanitizer(TC.getDriver().ResourceDir);
- llvm::sys::path::append(
- LibSanitizer, "lib", "linux",
- (Twine("libclang_rt.") + Sanitizer + "-" + TC.getArchName() + ".a"));
+static SmallString<128> getSanitizerRTLibName(const ToolChain &TC,
+ const StringRef Sanitizer,
+ bool Shared) {
+ // Sanitizer runtime has name "libclang_rt.<Sanitizer>-<ArchName>.{a,so}"
+ // (or "libclang_rt.<Sanitizer>-<ArchName>-android.so for Android)
+ const char *EnvSuffix =
+ TC.getTriple().getEnvironment() == llvm::Triple::Android ? "-android" : "";
+ SmallString<128> LibSanitizer = getCompilerRTLibDir(TC);
+ llvm::sys::path::append(LibSanitizer,
+ Twine("libclang_rt.") + Sanitizer + "-" +
+ getArchNameForCompilerRTLib(TC) + EnvSuffix +
+ (Shared ? ".so" : ".a"));
+ return LibSanitizer;
+}
+
+static void addSanitizerRTLinkFlags(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const StringRef Sanitizer,
+ bool BeforeLibStdCXX,
+ bool ExportSymbols = true,
+ bool LinkDeps = true) {
+ SmallString<128> LibSanitizer =
+ getSanitizerRTLibName(TC, Sanitizer, /*Shared*/ false);
// Sanitizer runtime may need to come before -lstdc++ (or -lc++, libstdc++.a,
// etc.) so that the linker picks custom versions of the global 'operator
@@ -1822,10 +2123,15 @@ static void addSanitizerRTLinkFlagsLinux(
CmdArgs.insert(BeforeLibStdCXX ? CmdArgs.begin() : CmdArgs.end(),
LibSanitizerArgs.begin(), LibSanitizerArgs.end());
- CmdArgs.push_back("-lpthread");
- CmdArgs.push_back("-lrt");
- CmdArgs.push_back("-ldl");
- CmdArgs.push_back("-lm");
+ if (LinkDeps) {
+ // Link sanitizer dependencies explicitly
+ CmdArgs.push_back("-lpthread");
+ CmdArgs.push_back("-lrt");
+ CmdArgs.push_back("-lm");
+ // There's no libdl on FreeBSD.
+ if (TC.getTriple().getOS() != llvm::Triple::FreeBSD)
+ CmdArgs.push_back("-ldl");
+ }
// If possible, use a dynamic symbols file to export the symbols from the
// runtime library. If we can't do so, use -export-dynamic instead to export
@@ -1841,66 +2147,102 @@ static void addSanitizerRTLinkFlagsLinux(
/// If AddressSanitizer is enabled, add appropriate linker flags (Linux).
/// This needs to be called before we add the C run-time (malloc, etc).
-static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
- if (TC.getTriple().getEnvironment() == llvm::Triple::Android) {
- SmallString<128> LibAsan(TC.getDriver().ResourceDir);
- llvm::sys::path::append(LibAsan, "lib", "linux",
- (Twine("libclang_rt.asan-") +
- TC.getArchName() + "-android.so"));
- CmdArgs.insert(CmdArgs.begin(), Args.MakeArgString(LibAsan));
+static void addAsanRT(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs, bool Shared, bool IsCXX) {
+ if (Shared) {
+ // Link dynamic runtime if necessary.
+ SmallString<128> LibSanitizer =
+ getSanitizerRTLibName(TC, "asan", Shared);
+ CmdArgs.insert(CmdArgs.begin(), Args.MakeArgString(LibSanitizer));
+ }
+
+ // Do not link static runtime to DSOs or if compiling for Android.
+ if (Args.hasArg(options::OPT_shared) ||
+ (TC.getTriple().getEnvironment() == llvm::Triple::Android))
+ return;
+
+ if (Shared) {
+ addSanitizerRTLinkFlags(TC, Args, CmdArgs, "asan-preinit",
+ /*BeforeLibStdCXX*/ true, /*ExportSymbols*/ false,
+ /*LinkDeps*/ false);
} else {
- if (!Args.hasArg(options::OPT_shared))
- addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "asan", true);
+ addSanitizerRTLinkFlags(TC, Args, CmdArgs, "asan", true);
+ if (IsCXX)
+ addSanitizerRTLinkFlags(TC, Args, CmdArgs, "asan_cxx", true);
}
}
/// If ThreadSanitizer is enabled, add appropriate linker flags (Linux).
/// This needs to be called before we add the C run-time (malloc, etc).
-static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
+static void addTsanRT(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
if (!Args.hasArg(options::OPT_shared))
- addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "tsan", true);
+ addSanitizerRTLinkFlags(TC, Args, CmdArgs, "tsan", true);
}
/// If MemorySanitizer is enabled, add appropriate linker flags (Linux).
/// This needs to be called before we add the C run-time (malloc, etc).
-static void addMsanRTLinux(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
+static void addMsanRT(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
if (!Args.hasArg(options::OPT_shared))
- addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "msan", true);
+ addSanitizerRTLinkFlags(TC, Args, CmdArgs, "msan", true);
}
/// If LeakSanitizer is enabled, add appropriate linker flags (Linux).
/// This needs to be called before we add the C run-time (malloc, etc).
-static void addLsanRTLinux(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
+static void addLsanRT(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
if (!Args.hasArg(options::OPT_shared))
- addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "lsan", true);
+ addSanitizerRTLinkFlags(TC, Args, CmdArgs, "lsan", true);
}
/// If UndefinedBehaviorSanitizer is enabled, add appropriate linker flags
/// (Linux).
-static void addUbsanRTLinux(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs, bool IsCXX,
- bool HasOtherSanitizerRt) {
+static void addUbsanRT(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs, bool IsCXX,
+ bool HasOtherSanitizerRt) {
+ // Do not link runtime into shared libraries.
+ if (Args.hasArg(options::OPT_shared))
+ return;
+
// Need a copy of sanitizer_common. This could come from another sanitizer
// runtime; if we're not including one, include our own copy.
if (!HasOtherSanitizerRt)
- addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "san", true, false);
+ addSanitizerRTLinkFlags(TC, Args, CmdArgs, "san", true, false);
- addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "ubsan", false);
+ addSanitizerRTLinkFlags(TC, Args, CmdArgs, "ubsan", false, true);
// Only include the bits of the runtime which need a C++ ABI library if
// we're linking in C++ mode.
if (IsCXX)
- addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "ubsan_cxx", false);
+ addSanitizerRTLinkFlags(TC, Args, CmdArgs, "ubsan_cxx", false, true);
}
-static void addDfsanRTLinux(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
+static void addDfsanRT(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
if (!Args.hasArg(options::OPT_shared))
- addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "dfsan", true);
+ addSanitizerRTLinkFlags(TC, Args, CmdArgs, "dfsan", true);
+}
+
+// Should be called before we add C++ ABI library.
+static void addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ const SanitizerArgs &Sanitize = TC.getSanitizerArgs();
+ const Driver &D = TC.getDriver();
+ if (Sanitize.needsUbsanRt())
+ addUbsanRT(TC, Args, CmdArgs, D.CCCIsCXX(),
+ Sanitize.needsAsanRt() || Sanitize.needsTsanRt() ||
+ Sanitize.needsMsanRt() || Sanitize.needsLsanRt());
+ if (Sanitize.needsAsanRt())
+ addAsanRT(TC, Args, CmdArgs, Sanitize.needsSharedAsanRt(), D.CCCIsCXX());
+ if (Sanitize.needsTsanRt())
+ addTsanRT(TC, Args, CmdArgs);
+ if (Sanitize.needsMsanRt())
+ addMsanRT(TC, Args, CmdArgs);
+ if (Sanitize.needsLsanRt())
+ addLsanRT(TC, Args, CmdArgs);
+ if (Sanitize.needsDfsanRt())
+ addDfsanRT(TC, Args, CmdArgs);
}
static bool shouldUseFramePointerForTarget(const ArgList &Args,
@@ -1962,7 +2304,8 @@ static const char *SplitDebugName(const ArgList &Args,
return Args.MakeArgString(T);
} else {
// Use the compilation dir.
- SmallString<128> T(Args.getLastArgValue(options::OPT_fdebug_compilation_dir));
+ SmallString<128> T(
+ Args.getLastArgValue(options::OPT_fdebug_compilation_dir));
SmallString<128> F(llvm::sys::path::stem(Inputs[0].getBaseInput()));
llvm::sys::path::replace_extension(F, "dwo");
T += F;
@@ -1996,7 +2339,8 @@ static void SplitDebugInfo(const ToolChain &TC, Compilation &C,
}
/// \brief Vectorize at all optimization levels greater than 1 except for -Oz.
-static bool shouldEnableVectorizerAtOLevel(const ArgList &Args) {
+/// For -Oz the loop vectorizer is disable, while the slp vectorizer is enabled.
+static bool shouldEnableVectorizerAtOLevel(const ArgList &Args, bool isSlpVec) {
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
if (A->getOption().matches(options::OPT_O4) ||
A->getOption().matches(options::OPT_Ofast))
@@ -2012,9 +2356,9 @@ static bool shouldEnableVectorizerAtOLevel(const ArgList &Args) {
if (S == "s")
return true;
- // Don't vectorize -Oz.
+ // Don't vectorize -Oz, unless it's the slp vectorizer.
if (S == "z")
- return false;
+ return isSlpVec;
unsigned OptLevel = 0;
if (S.getAsInteger(10, OptLevel))
@@ -2026,6 +2370,41 @@ static bool shouldEnableVectorizerAtOLevel(const ArgList &Args) {
return false;
}
+/// Add -x lang to \p CmdArgs for \p Input.
+static void addDashXForInput(const ArgList &Args, const InputInfo &Input,
+ ArgStringList &CmdArgs) {
+ // When using -verify-pch, we don't want to provide the type
+ // 'precompiled-header' if it was inferred from the file extension
+ if (Args.hasArg(options::OPT_verify_pch) && Input.getType() == types::TY_PCH)
+ return;
+
+ CmdArgs.push_back("-x");
+ if (Args.hasArg(options::OPT_rewrite_objc))
+ CmdArgs.push_back(types::getTypeName(types::TY_PP_ObjCXX));
+ else
+ CmdArgs.push_back(types::getTypeName(Input.getType()));
+}
+
+static std::string getMSCompatibilityVersion(const char *VersionStr) {
+ unsigned Version;
+ if (StringRef(VersionStr).getAsInteger(10, Version))
+ return "0";
+
+ if (Version < 100)
+ return llvm::utostr_32(Version) + ".0";
+
+ if (Version < 10000)
+ return llvm::utostr_32(Version / 100) + "." +
+ llvm::utostr_32(Version % 100);
+
+ unsigned Build = 0, Factor = 1;
+ for ( ; Version > 10000; Version = Version / 10, Factor = Factor * 10)
+ Build = Build + (Version % 10) * Factor;
+ return llvm::utostr_32(Version / 100) + "." +
+ llvm::utostr_32(Version % 100) + "." +
+ llvm::utostr_32(Build);
+}
+
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -2036,6 +2415,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
+ bool IsWindowsGNU = getToolChain().getTriple().isWindowsGNUEnvironment();
+ bool IsWindowsCygnus =
+ getToolChain().getTriple().isWindowsCygwinEnvironment();
+ bool IsWindowsMSVC = getToolChain().getTriple().isWindowsMSVCEnvironment();
+
assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
// Invoke ourselves in -cc1 mode.
@@ -2048,6 +2432,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args);
CmdArgs.push_back(Args.MakeArgString(TripleStr));
+ const llvm::Triple TT(TripleStr);
+ if (TT.isOSWindows() && (TT.getArch() == llvm::Triple::arm ||
+ TT.getArch() == llvm::Triple::thumb)) {
+ unsigned Offset = TT.getArch() == llvm::Triple::arm ? 4 : 6;
+ unsigned Version;
+ TT.getArchName().substr(Offset).getAsInteger(10, Version);
+ if (Version < 7)
+ D.Diag(diag::err_target_unsupported_arch) << TT.getArchName()
+ << TripleStr;
+ }
+
+ // Push all default warning arguments that are specific to
+ // the given target. These come before user provided warning options
+ // are provided.
+ getToolChain().addClangWarningOptions(CmdArgs);
+
// Select the appropriate action.
RewriteKind rewriteKind = RK_None;
@@ -2082,6 +2482,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-emit-pch");
else
CmdArgs.push_back("-emit-pth");
+ } else if (isa<VerifyPCHJobAction>(JA)) {
+ CmdArgs.push_back("-verify-pch");
} else {
assert(isa<CompileJobAction>(JA) && "Invalid action for clang tool.");
@@ -2111,8 +2513,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- // The make clang go fast button.
- CmdArgs.push_back("-disable-free");
+ // We normally speed up the clang process a bit by skipping destructors at
+ // exit, but when we're generating diagnostics we can rely on some of the
+ // cleanup.
+ if (!C.isForDiagnostics())
+ CmdArgs.push_back("-disable-free");
// Disable the verification pass in -asserts builds.
#ifdef NDEBUG
@@ -2142,7 +2547,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) {
CmdArgs.push_back("-analyzer-checker=core");
- if (getToolChain().getTriple().getOS() != llvm::Triple::Win32)
+ if (!IsWindowsMSVC)
CmdArgs.push_back("-analyzer-checker=unix");
if (getToolChain().getTriple().getVendor() == llvm::Triple::Apple)
@@ -2153,8 +2558,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (types::isCXX(Inputs[0].getType()))
CmdArgs.push_back("-analyzer-checker=cplusplus");
- // Enable the following experimental checkers for testing.
- CmdArgs.push_back("-analyzer-checker=security.insecureAPI.UncheckedReturn");
+ // Enable the following experimental checkers for testing.
+ CmdArgs.push_back(
+ "-analyzer-checker=security.insecureAPI.UncheckedReturn");
CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw");
CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets");
CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp");
@@ -2185,6 +2591,54 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
bool PIC = PIE || getToolChain().isPICDefault();
bool IsPICLevelTwo = PIC;
+ // Android-specific defaults for PIC/PIE
+ if (getToolChain().getTriple().getEnvironment() == llvm::Triple::Android) {
+ switch (getToolChain().getTriple().getArch()) {
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ case llvm::Triple::aarch64:
+ case llvm::Triple::arm64:
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ PIC = true; // "-fpic"
+ break;
+
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ PIC = true; // "-fPIC"
+ IsPICLevelTwo = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // OpenBSD-specific defaults for PIE
+ if (getToolChain().getTriple().getOS() == llvm::Triple::OpenBSD) {
+ switch (getToolChain().getTriple().getArch()) {
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ case llvm::Triple::sparc:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ IsPICLevelTwo = false; // "-fpie"
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::sparcv9:
+ IsPICLevelTwo = true; // "-fPIE"
+ break;
+
+ default:
+ break;
+ }
+ }
+
// For the PIC and PIE flag options, this logic is different from the
// legacy logic in very old versions of GCC, as that logic was just
// a bug no one had ever fixed. This logic is both more rational and
@@ -2225,8 +2679,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Note that these flags are trump-cards. Regardless of the order w.r.t. the
// PIC or PIE options above, if these show up, PIC is disabled.
llvm::Triple Triple(TripleStr);
- if (KernelOrKext &&
- (!Triple.isiOS() || Triple.isOSVersionLT(6)))
+ if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6) ||
+ Triple.getArch() == llvm::Triple::arm64 ||
+ Triple.getArch() == llvm::Triple::aarch64))
PIC = PIE = false;
if (Args.hasArg(options::OPT_static))
PIC = PIE = false;
@@ -2272,6 +2727,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// LLVM Code Generator Options.
+ if (Arg *A = Args.getLastArg(options::OPT_Wframe_larger_than_EQ)) {
+ StringRef v = A->getValue();
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString("-warn-stack-size=" + v));
+ A->claim();
+ }
+
if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) {
CmdArgs.push_back("-mregparm");
CmdArgs.push_back(A->getValue());
@@ -2304,8 +2766,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// enabled. This alias option is being used to simplify the hasFlag logic.
OptSpecifier StrictAliasingAliasOption = OFastEnabled ? options::OPT_Ofast :
options::OPT_fstrict_aliasing;
+ // We turn strict aliasing off by default if we're in CL mode, since MSVC
+ // doesn't do any TBAA.
+ bool TBAAOnByDefault = !getToolChain().getDriver().IsCLMode();
if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption,
- options::OPT_fno_strict_aliasing, true))
+ options::OPT_fno_strict_aliasing, TBAAOnByDefault))
CmdArgs.push_back("-relaxed-aliasing");
if (!Args.hasFlag(options::OPT_fstruct_path_tbaa,
options::OPT_fno_struct_path_tbaa))
@@ -2452,18 +2917,24 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_fast_math))
if (!A->getOption().matches(options::OPT_fno_fast_math))
CmdArgs.push_back("-ffast-math");
- if (Arg *A = Args.getLastArg(options::OPT_ffinite_math_only, options::OPT_fno_fast_math))
+ if (Arg *A = Args.getLastArg(options::OPT_ffinite_math_only,
+ options::OPT_fno_fast_math))
if (A->getOption().matches(options::OPT_ffinite_math_only))
CmdArgs.push_back("-ffinite-math-only");
// Decide whether to use verbose asm. Verbose assembly is the default on
// toolchains which have the integrated assembler on by default.
- bool IsVerboseAsmDefault = getToolChain().IsIntegratedAssemblerDefault();
+ bool IsIntegratedAssemblerDefault =
+ getToolChain().IsIntegratedAssemblerDefault();
if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm,
- IsVerboseAsmDefault) ||
+ IsIntegratedAssemblerDefault) ||
Args.hasArg(options::OPT_dA))
CmdArgs.push_back("-masm-verbose");
+ if (!Args.hasFlag(options::OPT_fintegrated_as, options::OPT_fno_integrated_as,
+ IsIntegratedAssemblerDefault))
+ CmdArgs.push_back("-no-integrated-as");
+
if (Args.hasArg(options::OPT_fdebug_pass_structure)) {
CmdArgs.push_back("-mdebug-pass");
CmdArgs.push_back("Structure");
@@ -2491,10 +2962,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more
// complicated ways.
bool AsynchronousUnwindTables =
- Args.hasFlag(options::OPT_fasynchronous_unwind_tables,
- options::OPT_fno_asynchronous_unwind_tables,
- getToolChain().IsUnwindTablesDefault() &&
- !KernelOrKext);
+ Args.hasFlag(options::OPT_fasynchronous_unwind_tables,
+ options::OPT_fno_asynchronous_unwind_tables,
+ (getToolChain().IsUnwindTablesDefault() ||
+ getToolChain().getSanitizerArgs().needsUnwindTables()) &&
+ !KernelOrKext);
if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables,
AsynchronousUnwindTables))
CmdArgs.push_back("-munwind-tables");
@@ -2529,7 +3001,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
// Add the target features
- getTargetFeatures(D, ETriple, Args, CmdArgs);
+ getTargetFeatures(D, ETriple, Args, CmdArgs, false);
// Add target specific flags.
switch(getToolChain().getArch()) {
@@ -2537,10 +3009,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
break;
case llvm::Triple::arm:
+ case llvm::Triple::armeb:
case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
AddARMTargetArgs(Args, CmdArgs, KernelOrKext);
break;
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm64:
+ case llvm::Triple::arm64_be:
+ AddAArch64TargetArgs(Args, CmdArgs);
+ break;
+
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
@@ -2549,6 +3030,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
break;
case llvm::Triple::sparc:
+ case llvm::Triple::sparcv9:
AddSparcTargetArgs(Args, CmdArgs);
break;
@@ -2606,13 +3088,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
D.CCLogDiagnosticsFilename : "-");
}
- // Use the last option from "-g" group. "-gline-tables-only"
- // is preserved, all other debug options are substituted with "-g".
+ // Use the last option from "-g" group. "-gline-tables-only" and "-gdwarf-x"
+ // are preserved, all other debug options are substituted with "-g".
Args.ClaimAllArgs(options::OPT_g_Group);
if (Arg *A = Args.getLastArg(options::OPT_g_Group)) {
- if (A->getOption().matches(options::OPT_gline_tables_only))
+ if (A->getOption().matches(options::OPT_gline_tables_only)) {
+ // FIXME: we should support specifying dwarf version with
+ // -gline-tables-only.
CmdArgs.push_back("-gline-tables-only");
- else if (A->getOption().matches(options::OPT_gdwarf_2))
+ // Default is dwarf-2 for Darwin, OpenBSD and FreeBSD.
+ const llvm::Triple &Triple = getToolChain().getTriple();
+ if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::OpenBSD ||
+ Triple.getOS() == llvm::Triple::FreeBSD)
+ CmdArgs.push_back("-gdwarf-2");
+ } else if (A->getOption().matches(options::OPT_gdwarf_2))
CmdArgs.push_back("-gdwarf-2");
else if (A->getOption().matches(options::OPT_gdwarf_3))
CmdArgs.push_back("-gdwarf-3");
@@ -2620,8 +3109,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-gdwarf-4");
else if (!A->getOption().matches(options::OPT_g0) &&
!A->getOption().matches(options::OPT_ggdb0)) {
- // Default is dwarf-2 for darwin.
- if (getToolChain().getTriple().isOSDarwin())
+ // Default is dwarf-2 for Darwin, OpenBSD and FreeBSD.
+ const llvm::Triple &Triple = getToolChain().getTriple();
+ if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::OpenBSD ||
+ Triple.getOS() == llvm::Triple::FreeBSD)
CmdArgs.push_back("-gdwarf-2");
else
CmdArgs.push_back("-g");
@@ -2630,7 +3121,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// We ignore flags -gstrict-dwarf and -grecord-gcc-switches for now.
Args.ClaimAllArgs(options::OPT_g_flags_Group);
- if (Args.hasArg(options::OPT_gcolumn_info))
+ if (Args.hasFlag(options::OPT_gcolumn_info, options::OPT_gno_column_info,
+ /*Default*/ true))
CmdArgs.push_back("-dwarf-column-info");
// FIXME: Move backend command line options to the module.
@@ -2650,13 +3142,44 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-generate-gnu-dwarf-pub-sections");
}
- Args.AddAllArgs(CmdArgs, options::OPT_fdebug_types_section);
+ // -gdwarf-aranges turns on the emission of the aranges section in the
+ // backend.
+ if (Args.hasArg(options::OPT_gdwarf_aranges)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-generate-arange-section");
+ }
+
+ if (Args.hasFlag(options::OPT_fdebug_types_section,
+ options::OPT_fno_debug_types_section, false)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-generate-type-units");
+ }
+
+ if (Args.hasFlag(options::OPT_ffunction_sections,
+ options::OPT_fno_function_sections, false)) {
+ CmdArgs.push_back("-ffunction-sections");
+ }
- Args.AddAllArgs(CmdArgs, options::OPT_ffunction_sections);
- Args.AddAllArgs(CmdArgs, options::OPT_fdata_sections);
+ if (Args.hasFlag(options::OPT_fdata_sections,
+ options::OPT_fno_data_sections, false)) {
+ CmdArgs.push_back("-fdata-sections");
+ }
Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions);
+ if (Args.hasArg(options::OPT_fprofile_instr_generate) &&
+ (Args.hasArg(options::OPT_fprofile_instr_use) ||
+ Args.hasArg(options::OPT_fprofile_instr_use_EQ)))
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fprofile-instr-generate" << "-fprofile-instr-use";
+
+ Args.AddAllArgs(CmdArgs, options::OPT_fprofile_instr_generate);
+
+ if (Arg *A = Args.getLastArg(options::OPT_fprofile_instr_use_EQ))
+ A->render(Args, CmdArgs);
+ else if (Args.hasArg(options::OPT_fprofile_instr_use))
+ CmdArgs.push_back("-fprofile-instr-use=pgo-data");
+
if (Args.hasArg(options::OPT_ftest_coverage) ||
Args.hasArg(options::OPT_coverage))
CmdArgs.push_back("-femit-coverage-notes");
@@ -2762,7 +3285,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_objcmt_atomic_property);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_returns_innerpointer_property);
Args.AddLastArg(CmdArgs, options::OPT_objcmt_ns_nonatomic_iosonly);
- Args.AddLastArg(CmdArgs, options::OPT_objcmt_white_list_dir_path);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_designated_init);
+ Args.AddLastArg(CmdArgs, options::OPT_objcmt_whitelist_dir_path);
}
// Add preprocessing options like -I, -D, etc. if we are using the
@@ -2788,10 +3312,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ // Warn about ignored options to clang.
+ for (arg_iterator it = Args.filtered_begin(
+ options::OPT_clang_ignored_gcc_optimization_f_Group),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ D.Diag(diag::warn_ignored_gcc_optimization) << (*it)->getAsString(Args);
+ }
+
// Don't warn about unused -flto. This can happen when we're preprocessing or
// precompiling.
Args.ClaimAllArgs(options::OPT_flto);
+ Args.AddAllArgs(CmdArgs, options::OPT_R_Group);
Args.AddAllArgs(CmdArgs, options::OPT_W_Group);
if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false))
CmdArgs.push_back("-pedantic");
@@ -2826,7 +3358,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (!types::isCXX(InputType))
Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
"-std=", /*Joined=*/true);
- else if (getToolChain().getTriple().getOS() == llvm::Triple::Win32)
+ else if (IsWindowsMSVC)
CmdArgs.push_back("-std=c++11");
Args.AddLastArg(CmdArgs, options::OPT_trigraphs);
@@ -2842,9 +3374,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// behavior for now. FIXME: Directly diagnose uses of a string literal as
// a non-const char* in C, rather than using this crude hack.
if (!types::isCXX(InputType)) {
- DiagnosticsEngine::Level DiagLevel = D.getDiags().getDiagnosticLevel(
- diag::warn_deprecated_string_literal_conversion_c, SourceLocation());
- if (DiagLevel > DiagnosticsEngine::Ignored)
+ // FIXME: This should behave just like a warning flag, and thus should also
+ // respect -Weverything, -Wno-everything, -Werror=write-strings, and so on.
+ Arg *WriteStrings =
+ Args.getLastArg(options::OPT_Wwrite_strings,
+ options::OPT_Wno_write_strings, options::OPT_w);
+ if (WriteStrings &&
+ WriteStrings->getOption().matches(options::OPT_Wwrite_strings))
CmdArgs.push_back("-fconst-strings");
}
@@ -2865,9 +3401,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fno-gnu-keywords");
}
- if (ShouldDisableCFI(Args, getToolChain()))
- CmdArgs.push_back("-fno-dwarf2-cfi-asm");
-
if (ShouldDisableDwarfDirectory(Args, getToolChain()))
CmdArgs.push_back("-fno-dwarf-directory-asm");
@@ -2985,8 +3518,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Forward -f (flag) options which we can pass directly.
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
- Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info);
- Args.AddLastArg(CmdArgs, options::OPT_fno_limit_debug_info);
+ Args.AddLastArg(CmdArgs, options::OPT_fstandalone_debug);
+ Args.AddLastArg(CmdArgs, options::OPT_fno_standalone_debug);
Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names);
// AltiVec language extensions aren't relevant for assembling.
if (!isa<PreprocessJobAction>(JA) ||
@@ -3003,8 +3536,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
true))
CmdArgs.push_back("-fno-sanitize-recover");
- if (Args.hasArg(options::OPT_fcatch_undefined_behavior) ||
- Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
+ if (Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
options::OPT_fno_sanitize_undefined_trap_on_error, false))
CmdArgs.push_back("-fsanitize-undefined-trap-on-error");
@@ -3027,10 +3559,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.getLastArg(options::OPT_fapple_kext))
CmdArgs.push_back("-fapple-kext");
- if (Args.hasFlag(options::OPT_frewrite_includes,
- options::OPT_fno_rewrite_includes, false))
- CmdArgs.push_back("-frewrite-includes");
-
Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
@@ -3072,11 +3600,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
unsigned StackProtectorLevel = 0;
if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector,
options::OPT_fstack_protector_all,
+ options::OPT_fstack_protector_strong,
options::OPT_fstack_protector)) {
- if (A->getOption().matches(options::OPT_fstack_protector))
- StackProtectorLevel = 1;
+ if (A->getOption().matches(options::OPT_fstack_protector)) {
+ StackProtectorLevel = std::max<unsigned>(LangOptions::SSPOn,
+ getToolChain().GetDefaultStackProtectorLevel(KernelOrKext));
+ } else if (A->getOption().matches(options::OPT_fstack_protector_strong))
+ StackProtectorLevel = LangOptions::SSPStrong;
else if (A->getOption().matches(options::OPT_fstack_protector_all))
- StackProtectorLevel = 2;
+ StackProtectorLevel = LangOptions::SSPReq;
} else {
StackProtectorLevel =
getToolChain().GetDefaultStackProtectorLevel(KernelOrKext);
@@ -3121,10 +3653,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_munaligned_access)) {
if (A->getOption().matches(options::OPT_mno_unaligned_access)) {
CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-arm-strict-align");
+ if (getToolChain().getTriple().getArch() == llvm::Triple::aarch64 ||
+ getToolChain().getTriple().getArch() == llvm::Triple::aarch64_be ||
+ getToolChain().getTriple().getArch() == llvm::Triple::arm64 ||
+ getToolChain().getTriple().getArch() == llvm::Triple::arm64_be)
+ CmdArgs.push_back("-aarch64-strict-align");
+ else
+ CmdArgs.push_back("-arm-strict-align");
} else {
CmdArgs.push_back("-backend-option");
- CmdArgs.push_back("-arm-no-strict-align");
+ if (getToolChain().getTriple().getArch() == llvm::Triple::aarch64 ||
+ getToolChain().getTriple().getArch() == llvm::Triple::aarch64_be ||
+ getToolChain().getTriple().getArch() == llvm::Triple::arm64 ||
+ getToolChain().getTriple().getArch() == llvm::Triple::arm64_be)
+ CmdArgs.push_back("-aarch64-no-strict-align");
+ else
+ CmdArgs.push_back("-arm-no-strict-align");
}
}
}
@@ -3138,6 +3682,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-backend-option");
CmdArgs.push_back("-arm-no-restrict-it");
}
+ } else if (TT.isOSWindows() && (TT.getArch() == llvm::Triple::arm ||
+ TT.getArch() == llvm::Triple::thumb)) {
+ // Windows on ARM expects restricted IT blocks
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-restrict-it");
+ }
+
+ if (TT.getArch() == llvm::Triple::arm ||
+ TT.getArch() == llvm::Triple::thumb) {
+ if (Arg *A = Args.getLastArg(options::OPT_mlong_calls,
+ options::OPT_mno_long_calls)) {
+ if (A->getOption().matches(options::OPT_mlong_calls)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-arm-long-calls");
+ }
+ }
}
// Forward -f options with positive and negative forms; we translate
@@ -3207,44 +3767,78 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fmodules-decluse");
}
+ // -fmodules-strict-decluse is like -fmodule-decluse, but also checks that
+ // all #included headers are part of modules.
+ if (Args.hasFlag(options::OPT_fmodules_strict_decluse,
+ options::OPT_fno_modules_strict_decluse,
+ false)) {
+ CmdArgs.push_back("-fmodules-strict-decluse");
+ }
+
// -fmodule-name specifies the module that is currently being built (or
// used for header checking by -fmodule-maps).
- if (Arg *A = Args.getLastArg(options::OPT_fmodule_name)) {
- A->claim();
+ if (Arg *A = Args.getLastArg(options::OPT_fmodule_name))
A->render(Args, CmdArgs);
- }
// -fmodule-map-file can be used to specify a file containing module
// definitions.
- if (Arg *A = Args.getLastArg(options::OPT_fmodule_map_file)) {
- A->claim();
+ if (Arg *A = Args.getLastArg(options::OPT_fmodule_map_file))
A->render(Args, CmdArgs);
- }
- // If a module path was provided, pass it along. Otherwise, use a temporary
- // directory.
- if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) {
- A->claim();
- if (HaveModules) {
- A->render(Args, CmdArgs);
+ // -fmodule-cache-path specifies where our module files should be written.
+ SmallString<128> ModuleCachePath;
+ if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path))
+ ModuleCachePath = A->getValue();
+ if (HaveModules) {
+ if (C.isForDiagnostics()) {
+ // When generating crash reports, we want to emit the modules along with
+ // the reproduction sources, so we ignore any provided module path.
+ ModuleCachePath = Output.getFilename();
+ llvm::sys::path::replace_extension(ModuleCachePath, ".cache");
+ llvm::sys::path::append(ModuleCachePath, "modules");
+ } else if (ModuleCachePath.empty()) {
+ // No module path was provided: use the default.
+ llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false,
+ ModuleCachePath);
+ llvm::sys::path::append(ModuleCachePath, "org.llvm.clang");
+ llvm::sys::path::append(ModuleCachePath, "ModuleCache");
}
- } else if (HaveModules) {
- SmallString<128> DefaultModuleCache;
- llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false,
- DefaultModuleCache);
- llvm::sys::path::append(DefaultModuleCache, "org.llvm.clang");
- llvm::sys::path::append(DefaultModuleCache, "ModuleCache");
const char Arg[] = "-fmodules-cache-path=";
- DefaultModuleCache.insert(DefaultModuleCache.begin(),
- Arg, Arg + strlen(Arg));
- CmdArgs.push_back(Args.MakeArgString(DefaultModuleCache));
+ ModuleCachePath.insert(ModuleCachePath.begin(), Arg, Arg + strlen(Arg));
+ CmdArgs.push_back(Args.MakeArgString(ModuleCachePath));
}
+ // When building modules and generating crashdumps, we need to dump a module
+ // dependency VFS alongside the output.
+ if (HaveModules && C.isForDiagnostics()) {
+ SmallString<128> VFSDir(Output.getFilename());
+ llvm::sys::path::replace_extension(VFSDir, ".cache");
+ llvm::sys::path::append(VFSDir, "vfs");
+ CmdArgs.push_back("-module-dependency-dir");
+ CmdArgs.push_back(Args.MakeArgString(VFSDir));
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_fmodules_user_build_path))
+ if (HaveModules)
+ A->render(Args, CmdArgs);
+
// Pass through all -fmodules-ignore-macro arguments.
Args.AddAllArgs(CmdArgs, options::OPT_fmodules_ignore_macro);
Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval);
Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after);
+ Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp);
+
+ if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) {
+ if (!Args.getLastArg(options::OPT_fbuild_session_timestamp))
+ D.Diag(diag::err_drv_modules_validate_once_requires_timestamp);
+
+ Args.AddLastArg(CmdArgs,
+ options::OPT_fmodules_validate_once_per_build_session);
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_fmodules_validate_system_headers);
+
// -faccess-control is default.
if (Args.hasFlag(options::OPT_fno_access_control,
options::OPT_faccess_control,
@@ -3291,41 +3885,52 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fno-threadsafe-statics");
// -fuse-cxa-atexit is default.
- if (!Args.hasFlag(
- options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit,
- getToolChain().getTriple().getOS() != llvm::Triple::Cygwin &&
- getToolChain().getTriple().getOS() != llvm::Triple::MinGW32 &&
- getToolChain().getArch() != llvm::Triple::hexagon &&
- getToolChain().getArch() != llvm::Triple::xcore) ||
+ if (!Args.hasFlag(options::OPT_fuse_cxa_atexit,
+ options::OPT_fno_use_cxa_atexit,
+ !IsWindowsCygnus && !IsWindowsGNU &&
+ getToolChain().getArch() != llvm::Triple::hexagon &&
+ getToolChain().getArch() != llvm::Triple::xcore) ||
KernelOrKext)
CmdArgs.push_back("-fno-use-cxa-atexit");
// -fms-extensions=0 is default.
if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
- getToolChain().getTriple().getOS() == llvm::Triple::Win32))
+ IsWindowsMSVC))
CmdArgs.push_back("-fms-extensions");
// -fms-compatibility=0 is default.
if (Args.hasFlag(options::OPT_fms_compatibility,
options::OPT_fno_ms_compatibility,
- (getToolChain().getTriple().getOS() == llvm::Triple::Win32 &&
- Args.hasFlag(options::OPT_fms_extensions,
- options::OPT_fno_ms_extensions,
- true))))
+ (IsWindowsMSVC && Args.hasFlag(options::OPT_fms_extensions,
+ options::OPT_fno_ms_extensions,
+ true))))
CmdArgs.push_back("-fms-compatibility");
- // -fmsc-version=1700 is default.
+ // -fms-compatibility-version=17.00 is default.
if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
- getToolChain().getTriple().getOS() == llvm::Triple::Win32) ||
- Args.hasArg(options::OPT_fmsc_version)) {
- StringRef msc_ver = Args.getLastArgValue(options::OPT_fmsc_version);
- if (msc_ver.empty())
- CmdArgs.push_back("-fmsc-version=1700");
+ IsWindowsMSVC) || Args.hasArg(options::OPT_fmsc_version) ||
+ Args.hasArg(options::OPT_fms_compatibility_version)) {
+ const Arg *MSCVersion = Args.getLastArg(options::OPT_fmsc_version);
+ const Arg *MSCompatibilityVersion =
+ Args.getLastArg(options::OPT_fms_compatibility_version);
+
+ if (MSCVersion && MSCompatibilityVersion)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << MSCVersion->getAsString(Args)
+ << MSCompatibilityVersion->getAsString(Args);
+
+ std::string Ver;
+ if (MSCompatibilityVersion)
+ Ver = Args.getLastArgValue(options::OPT_fms_compatibility_version);
+ else if (MSCVersion)
+ Ver = getMSCompatibilityVersion(MSCVersion->getValue());
+
+ if (Ver.empty())
+ CmdArgs.push_back("-fms-compatibility-version=17.00");
else
- CmdArgs.push_back(Args.MakeArgString("-fmsc-version=" + msc_ver));
+ CmdArgs.push_back(Args.MakeArgString("-fms-compatibility-version=" + Ver));
}
-
// -fno-borland-extensions is default.
if (Args.hasFlag(options::OPT_fborland_extensions,
options::OPT_fno_borland_extensions, false))
@@ -3334,8 +3939,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fno-delayed-template-parsing is default, except for Windows where MSVC STL
// needs it.
if (Args.hasFlag(options::OPT_fdelayed_template_parsing,
- options::OPT_fno_delayed_template_parsing,
- getToolChain().getTriple().getOS() == llvm::Triple::Win32))
+ options::OPT_fno_delayed_template_parsing, IsWindowsMSVC))
CmdArgs.push_back("-fdelayed-template-parsing");
// -fgnu-keywords default varies depending on language; only pass if
@@ -3358,9 +3962,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
ObjCRuntime objcRuntime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind);
// -fobjc-dispatch-method is only relevant with the nonfragile-abi, and
- // legacy is the default. Next runtime is always legacy dispatch and
- // -fno-objc-legacy-dispatch gets ignored silently.
- if (objcRuntime.isNonFragile() && !objcRuntime.isNeXTFamily()) {
+ // legacy is the default. Except for deployment taget of 10.5,
+ // next runtime is always legacy dispatch and -fno-objc-legacy-dispatch
+ // gets ignored silently.
+ if (objcRuntime.isNonFragile()) {
if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch,
options::OPT_fno_objc_legacy_dispatch,
objcRuntime.isLegacyDispatchDefaultForArch(
@@ -3436,9 +4041,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- // Add exception args.
- addExceptionArgs(Args, InputType, getToolChain().getTriple(),
- KernelOrKext, objcRuntime, CmdArgs);
+ // Handle GCC-style exception args.
+ if (!C.getDriver().IsCLMode())
+ addExceptionArgs(Args, InputType, getToolChain().getTriple(), KernelOrKext,
+ objcRuntime, CmdArgs);
if (getToolChain().UseSjLjExceptions())
CmdArgs.push_back("-fsjlj-exceptions");
@@ -3458,7 +4064,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fshort-wchar default varies depending on platform; only
// pass if specified.
- if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar))
+ if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar,
+ options::OPT_fno_short_wchar))
A->render(Args, CmdArgs);
// -fno-pascal-strings is default, only pass non-default.
@@ -3501,6 +4108,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
D.Diag(diag::err_drv_clang_unsupported)
<< Args.getLastArg(options::OPT_fno_for_scope)->getAsString(Args);
+ // -finput_charset=UTF-8 is default. Reject others
+ if (Arg *inputCharset = Args.getLastArg(
+ options::OPT_finput_charset_EQ)) {
+ StringRef value = inputCharset->getValue();
+ if (value != "UTF-8")
+ D.Diag(diag::err_drv_invalid_value) << inputCharset->getAsString(Args) << value;
+ }
+
// -fcaret-diagnostics is default.
if (!Args.hasFlag(options::OPT_fcaret_diagnostics,
options::OPT_fno_caret_diagnostics, true))
@@ -3543,9 +4158,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Support both clang's -f[no-]color-diagnostics and gcc's
// -f[no-]diagnostics-colors[=never|always|auto].
enum { Colors_On, Colors_Off, Colors_Auto } ShowColors = Colors_Auto;
- for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
- it != ie; ++it) {
- const Option &O = (*it)->getOption();
+ for (const auto &Arg : Args) {
+ const Option &O = Arg->getOption();
if (!O.matches(options::OPT_fcolor_diagnostics) &&
!O.matches(options::OPT_fdiagnostics_color) &&
!O.matches(options::OPT_fno_color_diagnostics) &&
@@ -3553,7 +4167,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
!O.matches(options::OPT_fdiagnostics_color_EQ))
continue;
- (*it)->claim();
+ Arg->claim();
if (O.matches(options::OPT_fcolor_diagnostics) ||
O.matches(options::OPT_fdiagnostics_color)) {
ShowColors = Colors_On;
@@ -3562,7 +4176,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
ShowColors = Colors_Off;
} else {
assert(O.matches(options::OPT_fdiagnostics_color_EQ));
- StringRef value((*it)->getValue());
+ StringRef value(Arg->getValue());
if (value == "always")
ShowColors = Colors_On;
else if (value == "never")
@@ -3603,16 +4217,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Enable vectorization per default according to the optimization level
// selected. For optimization levels that want vectorization we use the alias
// option to simplify the hasFlag logic.
- bool EnableVec = shouldEnableVectorizerAtOLevel(Args);
+ bool EnableVec = shouldEnableVectorizerAtOLevel(Args, false);
OptSpecifier VectorizeAliasOption = EnableVec ? options::OPT_O_Group :
options::OPT_fvectorize;
if (Args.hasFlag(options::OPT_fvectorize, VectorizeAliasOption,
options::OPT_fno_vectorize, EnableVec))
CmdArgs.push_back("-vectorize-loops");
- // -fslp-vectorize is default.
- if (Args.hasFlag(options::OPT_fslp_vectorize,
- options::OPT_fno_slp_vectorize, true))
+ // -fslp-vectorize is enabled based on the optimization level selected.
+ bool EnableSLPVec = shouldEnableVectorizerAtOLevel(Args, true);
+ OptSpecifier SLPVectAliasOption = EnableSLPVec ? options::OPT_O_Group :
+ options::OPT_fslp_vectorize;
+ if (Args.hasFlag(options::OPT_fslp_vectorize, SLPVectAliasOption,
+ options::OPT_fno_slp_vectorize, EnableSLPVec))
CmdArgs.push_back("-vectorize-slp");
// -fno-slp-vectorize-aggressive is default.
@@ -3666,6 +4283,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
#endif
+ // Enable rewrite includes if the user's asked for it or if we're generating
+ // diagnostics.
+ // TODO: Once -module-dependency-dir works with -frewrite-includes it'd be
+ // nice to enable this when doing a crashdump for modules as well.
+ if (Args.hasFlag(options::OPT_frewrite_includes,
+ options::OPT_fno_rewrite_includes, false) ||
+ (C.isForDiagnostics() && !HaveModules))
+ CmdArgs.push_back("-frewrite-includes");
+
// Only allow -traditional or -traditional-cpp outside in preprocessing modes.
if (Arg *A = Args.getLastArg(options::OPT_traditional,
options::OPT_traditional_cpp)) {
@@ -3716,14 +4342,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
assert(Output.isNothing() && "Invalid output.");
}
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
- CmdArgs.push_back("-x");
- if (Args.hasArg(options::OPT_rewrite_objc))
- CmdArgs.push_back(types::getTypeName(types::TY_PP_ObjCXX));
- else
- CmdArgs.push_back(types::getTypeName(II.getType()));
+ for (const auto &II : Inputs) {
+ addDashXForInput(Args, II, CmdArgs);
+
if (II.isFilename())
CmdArgs.push_back(II.getFilename());
else
@@ -3738,9 +4359,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// analysis.
if (getToolChain().UseDwarfDebugFlags()) {
ArgStringList OriginalArgs;
- for (ArgList::const_iterator it = Args.begin(),
- ie = Args.end(); it != ie; ++it)
- (*it)->render(Args, OriginalArgs);
+ for (const auto &Arg : Args)
+ Arg->render(Args, OriginalArgs);
SmallString<256> Flags;
Flags += Exec;
@@ -3765,10 +4385,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
// Finally add the compile command to the compilation.
- if (Args.hasArg(options::OPT__SLASH_fallback)) {
- tools::visualstudio::Compile CL(getToolChain());
- Command *CLCommand = CL.GetCommand(C, JA, Output, Inputs, Args,
- LinkingOutput);
+ if (Args.hasArg(options::OPT__SLASH_fallback) &&
+ Output.getType() == types::TY_Object &&
+ (InputType == types::TY_C || InputType == types::TY_CXX)) {
+ Command *CLCommand = getCLFallback()->GetCommand(C, JA, Output, Inputs,
+ Args, LinkingOutput);
C.addCommand(new FallbackCommand(JA, *this, Exec, CmdArgs, CLCommand));
} else {
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
@@ -3927,6 +4548,45 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
return runtime;
}
+static bool maybeConsumeDash(const std::string &EH, size_t &I) {
+ bool HaveDash = (I + 1 < EH.size() && EH[I + 1] == '-');
+ I += HaveDash;
+ return !HaveDash;
+}
+
+struct EHFlags {
+ EHFlags() : Synch(false), Asynch(false), NoExceptC(false) {}
+ bool Synch;
+ bool Asynch;
+ bool NoExceptC;
+};
+
+/// /EH controls whether to run destructor cleanups when exceptions are
+/// thrown. There are three modifiers:
+/// - s: Cleanup after "synchronous" exceptions, aka C++ exceptions.
+/// - a: Cleanup after "asynchronous" exceptions, aka structured exceptions.
+/// The 'a' modifier is unimplemented and fundamentally hard in LLVM IR.
+/// - c: Assume that extern "C" functions are implicitly noexcept. This
+/// modifier is an optimization, so we ignore it for now.
+/// The default is /EHs-c-, meaning cleanups are disabled.
+static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) {
+ EHFlags EH;
+ std::vector<std::string> EHArgs = Args.getAllArgValues(options::OPT__SLASH_EH);
+ for (auto EHVal : EHArgs) {
+ for (size_t I = 0, E = EHVal.size(); I != E; ++I) {
+ switch (EHVal[I]) {
+ case 'a': EH.Asynch = maybeConsumeDash(EHVal, I); continue;
+ case 'c': EH.NoExceptC = maybeConsumeDash(EHVal, I); continue;
+ case 's': EH.Synch = maybeConsumeDash(EHVal, I); continue;
+ default: break;
+ }
+ D.Diag(clang::diag::err_drv_invalid_value) << "/EH" << EHVal;
+ break;
+ }
+ }
+ return EH;
+}
+
void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
unsigned RTOptionID = options::OPT__SLASH_MT;
@@ -3972,11 +4632,58 @@ void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
// implemented in clang.
CmdArgs.push_back("--dependent-lib=oldnames");
- // FIXME: Make this default for the win32 triple.
- CmdArgs.push_back("-cxx-abi");
- CmdArgs.push_back("microsoft");
+ // Both /showIncludes and /E (and /EP) write to stdout. Allowing both
+ // would produce interleaved output, so ignore /showIncludes in such cases.
+ if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_EP))
+ if (Arg *A = Args.getLastArg(options::OPT_show_includes))
+ A->render(Args, CmdArgs);
+
+ // This controls whether or not we emit RTTI data for polymorphic types.
+ if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR,
+ /*default=*/false))
+ CmdArgs.push_back("-fno-rtti-data");
+
+ const Driver &D = getToolChain().getDriver();
+ EHFlags EH = parseClangCLEHFlags(D, Args);
+ // FIXME: Do something with NoExceptC.
+ if (EH.Synch || EH.Asynch) {
+ CmdArgs.push_back("-fexceptions");
+ CmdArgs.push_back("-fcxx-exceptions");
+ }
+
+ // /EP should expand to -E -P.
+ if (Args.hasArg(options::OPT__SLASH_EP)) {
+ CmdArgs.push_back("-E");
+ CmdArgs.push_back("-P");
+ }
+
+ Arg *MostGeneralArg = Args.getLastArg(options::OPT__SLASH_vmg);
+ Arg *BestCaseArg = Args.getLastArg(options::OPT__SLASH_vmb);
+ if (MostGeneralArg && BestCaseArg)
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << MostGeneralArg->getAsString(Args) << BestCaseArg->getAsString(Args);
- if (Arg *A = Args.getLastArg(options::OPT_show_includes))
+ if (MostGeneralArg) {
+ Arg *SingleArg = Args.getLastArg(options::OPT__SLASH_vms);
+ Arg *MultipleArg = Args.getLastArg(options::OPT__SLASH_vmm);
+ Arg *VirtualArg = Args.getLastArg(options::OPT__SLASH_vmv);
+
+ Arg *FirstConflict = SingleArg ? SingleArg : MultipleArg;
+ Arg *SecondConflict = VirtualArg ? VirtualArg : MultipleArg;
+ if (FirstConflict && SecondConflict && FirstConflict != SecondConflict)
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << FirstConflict->getAsString(Args)
+ << SecondConflict->getAsString(Args);
+
+ if (SingleArg)
+ CmdArgs.push_back("-fms-memptr-rep=single");
+ else if (MultipleArg)
+ CmdArgs.push_back("-fms-memptr-rep=multiple");
+ else
+ CmdArgs.push_back("-fms-memptr-rep=virtual");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_vtordisp_mode_EQ))
A->render(Args, CmdArgs);
if (!Args.hasArg(options::OPT_fdiagnostics_format_EQ)) {
@@ -3988,6 +4695,12 @@ void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
}
}
+visualstudio::Compile *Clang::getCLFallback() const {
+ if (!CLFallback)
+ CLFallback.reset(new visualstudio::Compile(getToolChain()));
+ return CLFallback.get();
+}
+
void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -4034,7 +4747,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
// Add the target features
const Driver &D = getToolChain().getDriver();
- getTargetFeatures(D, Triple, Args, CmdArgs);
+ getTargetFeatures(D, Triple, Args, CmdArgs, true);
// Ignore explicit -force_cpusubtype_ALL option.
(void) Args.hasArg(options::OPT_force__cpusubtype__ALL);
@@ -4055,6 +4768,13 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
if (!A->getOption().matches(options::OPT_g0))
CmdArgs.push_back("-g");
+ if (Args.hasArg(options::OPT_gdwarf_2))
+ CmdArgs.push_back("-gdwarf-2");
+ if (Args.hasArg(options::OPT_gdwarf_3))
+ CmdArgs.push_back("-gdwarf-3");
+ if (Args.hasArg(options::OPT_gdwarf_4))
+ CmdArgs.push_back("-gdwarf-4");
+
// Add the -fdebug-compilation-dir flag if needed.
addDebugCompDirArg(Args, CmdArgs);
@@ -4068,9 +4788,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
// analysis.
if (getToolChain().UseDwarfDebugFlags()) {
ArgStringList OriginalArgs;
- for (ArgList::const_iterator it = Args.begin(),
- ie = Args.end(); it != ie; ++it)
- (*it)->render(Args, OriginalArgs);
+ for (const auto &Arg : Args)
+ Arg->render(Args, OriginalArgs);
SmallString<256> Flags;
const char *Exec = getToolChain().getDriver().getClangProgramPath();
@@ -4085,6 +4804,16 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
// FIXME: Add -static support, once we have it.
+ // Consume all the warning flags. Usually this would be handled more
+ // gracefully by -cc1 (warning about unknown warning flags, etc) but -cc1as
+ // doesn't handle that so rather than warning about unused flags that are
+ // actually used, we'll lie by omission instead.
+ // FIXME: Stop lying and consume only the appropriate driver flags
+ for (arg_iterator it = Args.filtered_begin(options::OPT_W_Group),
+ ie = Args.filtered_end();
+ it != ie; ++it)
+ (*it)->claim();
+
CollectArgsForIntegratedAssembler(C, Args, CmdArgs,
getToolChain().getDriver());
@@ -4117,9 +4846,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
- for (ArgList::const_iterator
- it = Args.begin(), ie = Args.end(); it != ie; ++it) {
- Arg *A = *it;
+ for (const auto &A : Args) {
if (forwardToGCC(A->getOption())) {
// Don't forward any -g arguments to assembly steps.
if (isa<AssembleJobAction>(JA) &&
@@ -4188,10 +4915,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
//
// FIXME: For the linker case specifically, can we safely convert
// inputs into '-Wl,' options?
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
-
+ for (const auto &II : Inputs) {
// Don't try to pass LLVM or AST inputs to a generic gcc.
if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR ||
II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC)
@@ -4244,11 +4968,6 @@ void gcc::Preprocess::RenderExtraToolArgs(const JobAction &JA,
CmdArgs.push_back("-E");
}
-void gcc::Precompile::RenderExtraToolArgs(const JobAction &JA,
- ArgStringList &CmdArgs) const {
- // The type is good enough.
-}
-
void gcc::Compile::RenderExtraToolArgs(const JobAction &JA,
ArgStringList &CmdArgs) const {
const Driver &D = getToolChain().getDriver();
@@ -4266,11 +4985,6 @@ void gcc::Compile::RenderExtraToolArgs(const JobAction &JA,
}
}
-void gcc::Assemble::RenderExtraToolArgs(const JobAction &JA,
- ArgStringList &CmdArgs) const {
- CmdArgs.push_back("-c");
-}
-
void gcc::Link::RenderExtraToolArgs(const JobAction &JA,
ArgStringList &CmdArgs) const {
// The types are (hopefully) good enough.
@@ -4320,10 +5034,7 @@ void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
//
// FIXME: For the linker case specifically, can we safely convert
// inputs into '-Wl,' options?
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
-
+ for (const auto &II : Inputs) {
// Don't try to pass LLVM or AST inputs to a generic gcc.
if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR ||
II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC)
@@ -4344,11 +5055,10 @@ void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *GCCName = "hexagon-as";
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(GCCName));
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
-
}
+
void hexagon::Link::RenderExtraToolArgs(const JobAction &JA,
ArgStringList &CmdArgs) const {
// The types are (hopefully) good enough.
@@ -4390,10 +5100,8 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA,
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
- for (std::vector<std::string>::const_iterator i = ToolChain.ExtraOpts.begin(),
- e = ToolChain.ExtraOpts.end();
- i != e; ++i)
- CmdArgs.push_back(i->c_str());
+ for (const auto &Opt : ToolChain.ExtraOpts)
+ CmdArgs.push_back(Opt.c_str());
std::string MarchString = toolchains::Hexagon_TC::GetTargetCPU(Args);
CmdArgs.push_back(Args.MakeArgString("-m" + MarchString));
@@ -4469,12 +5177,8 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA,
// Library Search Paths
//----------------------------------------------------------------------------
const ToolChain::path_list &LibPaths = ToolChain.getFilePaths();
- for (ToolChain::path_list::const_iterator
- i = LibPaths.begin(),
- e = LibPaths.end();
- i != e;
- ++i)
- CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + *i));
+ for (const auto &LibPath : LibPaths)
+ CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
//----------------------------------------------------------------------------
//
@@ -4522,7 +5226,116 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
// Hexagon tools end.
-llvm::Triple::ArchType darwin::getArchTypeForDarwinArchName(StringRef Str) {
+/// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting.
+const char *arm::getARMCPUForMArch(const ArgList &Args,
+ const llvm::Triple &Triple) {
+ StringRef MArch;
+ if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
+ // Otherwise, if we have -march= choose the base CPU for that arch.
+ MArch = A->getValue();
+ } else {
+ // Otherwise, use the Arch from the triple.
+ MArch = Triple.getArchName();
+ }
+
+ // Handle -march=native.
+ if (MArch == "native") {
+ std::string CPU = llvm::sys::getHostCPUName();
+ if (CPU != "generic") {
+ // Translate the native cpu into the architecture. The switch below will
+ // then chose the minimum cpu for that arch.
+ MArch = std::string("arm") + arm::getLLVMArchSuffixForARM(CPU);
+ }
+ }
+
+ return Triple.getARMCPUForArch(MArch);
+}
+
+/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting.
+StringRef arm::getARMTargetCPU(const ArgList &Args,
+ const llvm::Triple &Triple) {
+ // FIXME: Warn on inconsistent use of -mcpu and -march.
+ // If we have -mcpu=, use that.
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
+ StringRef MCPU = A->getValue();
+ // Handle -mcpu=native.
+ if (MCPU == "native")
+ return llvm::sys::getHostCPUName();
+ else
+ return MCPU;
+ }
+
+ return getARMCPUForMArch(Args, Triple);
+}
+
+/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular
+/// CPU.
+//
+// FIXME: This is redundant with -mcpu, why does LLVM use this.
+// FIXME: tblgen this, or kill it!
+const char *arm::getLLVMArchSuffixForARM(StringRef CPU) {
+ return llvm::StringSwitch<const char *>(CPU)
+ .Case("strongarm", "v4")
+ .Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "v4t")
+ .Cases("arm720t", "arm9", "arm9tdmi", "v4t")
+ .Cases("arm920", "arm920t", "arm922t", "v4t")
+ .Cases("arm940t", "ep9312","v4t")
+ .Cases("arm10tdmi", "arm1020t", "v5")
+ .Cases("arm9e", "arm926ej-s", "arm946e-s", "v5e")
+ .Cases("arm966e-s", "arm968e-s", "arm10e", "v5e")
+ .Cases("arm1020e", "arm1022e", "xscale", "iwmmxt", "v5e")
+ .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6")
+ .Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
+ .Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "cortex-a9-mp", "v7")
+ .Cases("cortex-a9", "cortex-a12", "cortex-a15", "krait", "v7")
+ .Cases("cortex-r4", "cortex-r5", "v7r")
+ .Case("cortex-m0", "v6m")
+ .Case("cortex-m3", "v7m")
+ .Case("cortex-m4", "v7em")
+ .Case("swift", "v7s")
+ .Case("cyclone", "v8")
+ .Cases("cortex-a53", "cortex-a57", "v8")
+ .Default("");
+}
+
+bool mips::hasMipsAbiArg(const ArgList &Args, const char *Value) {
+ Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
+ return A && (A->getValue() == StringRef(Value));
+}
+
+bool mips::isNaN2008(const ArgList &Args, const llvm::Triple &Triple) {
+ if (Arg *NaNArg = Args.getLastArg(options::OPT_mnan_EQ))
+ return llvm::StringSwitch<bool>(NaNArg->getValue())
+ .Case("2008", true)
+ .Case("legacy", false)
+ .Default(false);
+
+ // NaN2008 is the default for MIPS32r6/MIPS64r6.
+ return llvm::StringSwitch<bool>(getCPUName(Args, Triple))
+ .Cases("mips32r6", "mips64r6", true)
+ .Default(false);
+
+ return false;
+}
+
+bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName,
+ StringRef ABIName) {
+ if (Triple.getVendor() != llvm::Triple::ImaginationTechnologies &&
+ Triple.getVendor() != llvm::Triple::MipsTechnologies)
+ return false;
+
+ if (ABIName != "32")
+ return false;
+
+ return llvm::StringSwitch<bool>(CPUName)
+ .Cases("mips2", "mips3", "mips4", "mips5", true)
+ .Cases("mips32", "mips32r2", true)
+ .Cases("mips64", "mips64r2", true)
+ .Default(false);
+}
+
+llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) {
// See arch(3) and llvm-gcc's driver-driver.c. We don't implement support for
// archs which Darwin doesn't use.
@@ -4545,8 +5358,9 @@ llvm::Triple::ArchType darwin::getArchTypeForDarwinArchName(StringRef Str) {
.Cases("x86_64", "x86_64h", llvm::Triple::x86_64)
// This is derived from the driver driver.
.Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm)
- .Cases("armv7", "armv7em", "armv7f", "armv7k", "armv7m", llvm::Triple::arm)
+ .Cases("armv7", "armv7em", "armv7k", "armv7m", llvm::Triple::arm)
.Cases("armv7s", "xscale", llvm::Triple::arm)
+ .Case("arm64", llvm::Triple::arm64)
.Case("r600", llvm::Triple::r600)
.Case("nvptx", llvm::Triple::nvptx)
.Case("nvptx64", llvm::Triple::nvptx64)
@@ -4555,6 +5369,18 @@ llvm::Triple::ArchType darwin::getArchTypeForDarwinArchName(StringRef Str) {
.Default(llvm::Triple::UnknownArch);
}
+void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str) {
+ llvm::Triple::ArchType Arch = getArchTypeForMachOArchName(Str);
+ T.setArch(Arch);
+
+ if (Str == "x86_64h")
+ T.setArchName(Str);
+ else if (Str == "armv6m" || Str == "armv7m" || Str == "armv7em") {
+ T.setOS(llvm::Triple::UnknownOS);
+ T.setObjectFormat(llvm::Triple::MachO);
+ }
+}
+
const char *Clang::getBaseInputName(const ArgList &Args,
const InputInfoList &Inputs) {
return Args.MakeArgString(
@@ -4602,14 +5428,14 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
SourceAction = SourceAction->getInputs()[0];
}
- // If -no_integrated_as is used add -Q to the darwin assember driver to make
+ // If -fno_integrated_as is used add -Q to the darwin assember driver to make
// sure it runs its system assembler not clang's integrated assembler.
// Applicable to darwin11+ and Xcode 4+. darwin<10 lacked integrated-as.
// FIXME: at run-time detect assembler capabilities or rely on version
// information forwarded by -target-assembler-version (future)
- if (Args.hasArg(options::OPT_no_integrated_as)) {
- const llvm::Triple& t(getToolChain().getTriple());
- if (!(t.isMacOSX() && t.isMacOSXVersionLT(10, 7)))
+ if (Args.hasArg(options::OPT_fno_integrated_as)) {
+ const llvm::Triple &T(getToolChain().getTriple());
+ if (!(T.isMacOSX() && T.isMacOSXVersionLT(10, 7)))
CmdArgs.push_back("-Q");
}
@@ -4623,7 +5449,7 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
}
// Derived from asm spec.
- AddDarwinArch(Args, CmdArgs);
+ AddMachOArch(Args, CmdArgs);
// Use -force_cpusubtype_ALL on x86 by default.
if (getToolChain().getArch() == llvm::Triple::x86 ||
@@ -4634,8 +5460,7 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
if (getToolChain().getArch() != llvm::Triple::x86_64 &&
(((Args.hasArg(options::OPT_mkernel) ||
Args.hasArg(options::OPT_fapple_kext)) &&
- (!getDarwinToolChain().isTargetIPhoneOS() ||
- getDarwinToolChain().isIPhoneOSVersionLT(6, 0))) ||
+ getMachOToolChain().isKernelStatic()) ||
Args.hasArg(options::OPT_static)))
CmdArgs.push_back("-static");
@@ -4656,11 +5481,11 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
-void darwin::DarwinTool::anchor() {}
+void darwin::MachOTool::anchor() {}
-void darwin::DarwinTool::AddDarwinArch(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- StringRef ArchName = getDarwinToolChain().getDarwinArchName(Args);
+void darwin::MachOTool::AddMachOArch(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ StringRef ArchName = getMachOToolChain().getMachOArchName(Args);
// Derived from darwin_arch spec.
CmdArgs.push_back("-arch");
@@ -4675,9 +5500,8 @@ bool darwin::Link::NeedsTempPath(const InputInfoList &Inputs) const {
// We only need to generate a temp path for LTO if we aren't compiling object
// files. When compiling source files, we run 'dsymutil' after linking. We
// don't run 'dsymutil' when compiling object files.
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it)
- if (it->getType() != types::TY_Object)
+ for (const auto &Input : Inputs)
+ if (Input.getType() != types::TY_Object)
return true;
return false;
@@ -4688,7 +5512,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
ArgStringList &CmdArgs,
const InputInfoList &Inputs) const {
const Driver &D = getToolChain().getDriver();
- const toolchains::Darwin &DarwinTC = getDarwinToolChain();
+ const toolchains::MachO &MachOTC = getMachOToolChain();
unsigned Version[3] = { 0, 0, 0 };
if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) {
@@ -4700,27 +5524,10 @@ void darwin::Link::AddLinkArgs(Compilation &C,
<< A->getAsString(Args);
}
- // Newer linkers support -demangle, pass it if supported and not disabled by
+ // Newer linkers support -demangle. Pass it if supported and not disabled by
// the user.
- if (Version[0] >= 100 && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) {
- // Don't pass -demangle to ld_classic.
- //
- // FIXME: This is a temporary workaround, ld should be handling this.
- bool UsesLdClassic = (getToolChain().getArch() == llvm::Triple::x86 &&
- Args.hasArg(options::OPT_static));
- if (getToolChain().getArch() == llvm::Triple::x86) {
- for (arg_iterator it = Args.filtered_begin(options::OPT_Xlinker,
- options::OPT_Wl_COMMA),
- ie = Args.filtered_end(); it != ie; ++it) {
- const Arg *A = *it;
- for (unsigned i = 0, e = A->getNumValues(); i != e; ++i)
- if (StringRef(A->getValue(i)) == "-kext")
- UsesLdClassic = true;
- }
- }
- if (!UsesLdClassic)
- CmdArgs.push_back("-demangle");
- }
+ if (Version[0] >= 100 && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
+ CmdArgs.push_back("-demangle");
if (Args.hasArg(options::OPT_rdynamic) && Version[0] >= 137)
CmdArgs.push_back("-export_dynamic");
@@ -4746,7 +5553,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
}
if (!Args.hasArg(options::OPT_dynamiclib)) {
- AddDarwinArch(Args, CmdArgs);
+ AddMachOArch(Args, CmdArgs);
// FIXME: Why do this only on this path?
Args.AddLastArg(CmdArgs, options::OPT_force__cpusubtype__ALL);
@@ -4782,7 +5589,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
Args.AddAllArgsTranslated(CmdArgs, options::OPT_current__version,
"-dylib_current_version");
- AddDarwinArch(Args, CmdArgs);
+ AddMachOArch(Args, CmdArgs);
Args.AddAllArgsTranslated(CmdArgs, options::OPT_install__name,
"-dylib_install_name");
@@ -4791,7 +5598,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
Args.AddLastArg(CmdArgs, options::OPT_all__load);
Args.AddAllArgs(CmdArgs, options::OPT_allowable__client);
Args.AddLastArg(CmdArgs, options::OPT_bind__at__load);
- if (DarwinTC.isTargetIPhoneOS())
+ if (MachOTC.isTargetIOSBased())
Args.AddLastArg(CmdArgs, options::OPT_arch__errors__fatal);
Args.AddLastArg(CmdArgs, options::OPT_dead__strip);
Args.AddLastArg(CmdArgs, options::OPT_no__dead__strip__inits__and__terms);
@@ -4805,22 +5612,7 @@ void darwin::Link::AddLinkArgs(Compilation &C,
Args.AddAllArgs(CmdArgs, options::OPT_init);
// Add the deployment target.
- VersionTuple TargetVersion = DarwinTC.getTargetVersion();
-
- // If we had an explicit -mios-simulator-version-min argument, honor that,
- // otherwise use the traditional deployment targets. We can't just check the
- // is-sim attribute because existing code follows this path, and the linker
- // may not handle the argument.
- //
- // FIXME: We may be able to remove this, once we can verify no one depends on
- // it.
- if (Args.hasArg(options::OPT_mios_simulator_version_min_EQ))
- CmdArgs.push_back("-ios_simulator_version_min");
- else if (DarwinTC.isTargetIPhoneOS())
- CmdArgs.push_back("-iphoneos_version_min");
- else
- CmdArgs.push_back("-macosx_version_min");
- CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString()));
+ MachOTC.addMinVersionArgs(Args, CmdArgs);
Args.AddLastArg(CmdArgs, options::OPT_nomultidefs);
Args.AddLastArg(CmdArgs, options::OPT_multi__module);
@@ -4889,6 +5681,12 @@ void darwin::Link::AddLinkArgs(Compilation &C,
Args.AddLastArg(CmdArgs, options::OPT_Mach);
}
+enum LibOpenMP {
+ LibUnknown,
+ LibGOMP,
+ LibIOMP5
+};
+
void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -4904,8 +5702,8 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
/// Hack(tm) to ignore linking errors when we are doing ARC migration.
if (Args.hasArg(options::OPT_ccc_arcmt_check,
options::OPT_ccc_arcmt_migrate)) {
- for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I)
- (*I)->claim();
+ for (const auto &Arg : Args)
+ Arg->claim();
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("touch"));
CmdArgs.push_back(Output.getFilename());
@@ -4935,120 +5733,42 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Output.getFilename());
if (!Args.hasArg(options::OPT_nostdlib) &&
- !Args.hasArg(options::OPT_nostartfiles)) {
- // Derived from startfile spec.
- if (Args.hasArg(options::OPT_dynamiclib)) {
- // Derived from darwin_dylib1 spec.
- if (getDarwinToolChain().isTargetIOSSimulator()) {
- // The simulator doesn't have a versioned crt1 file.
- CmdArgs.push_back("-ldylib1.o");
- } else if (getDarwinToolChain().isTargetIPhoneOS()) {
- if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1))
- CmdArgs.push_back("-ldylib1.o");
- } else {
- if (getDarwinToolChain().isMacosxVersionLT(10, 5))
- CmdArgs.push_back("-ldylib1.o");
- else if (getDarwinToolChain().isMacosxVersionLT(10, 6))
- CmdArgs.push_back("-ldylib1.10.5.o");
- }
- } else {
- if (Args.hasArg(options::OPT_bundle)) {
- if (!Args.hasArg(options::OPT_static)) {
- // Derived from darwin_bundle1 spec.
- if (getDarwinToolChain().isTargetIOSSimulator()) {
- // The simulator doesn't have a versioned crt1 file.
- CmdArgs.push_back("-lbundle1.o");
- } else if (getDarwinToolChain().isTargetIPhoneOS()) {
- if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1))
- CmdArgs.push_back("-lbundle1.o");
- } else {
- if (getDarwinToolChain().isMacosxVersionLT(10, 6))
- CmdArgs.push_back("-lbundle1.o");
- }
- }
- } else {
- if (Args.hasArg(options::OPT_pg) &&
- getToolChain().SupportsProfiling()) {
- if (Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_object) ||
- Args.hasArg(options::OPT_preload)) {
- CmdArgs.push_back("-lgcrt0.o");
- } else {
- CmdArgs.push_back("-lgcrt1.o");
-
- // darwin_crt2 spec is empty.
- }
- // By default on OS X 10.8 and later, we don't link with a crt1.o
- // file and the linker knows to use _main as the entry point. But,
- // when compiling with -pg, we need to link with the gcrt1.o file,
- // so pass the -no_new_main option to tell the linker to use the
- // "start" symbol as the entry point.
- if (getDarwinToolChain().isTargetMacOS() &&
- !getDarwinToolChain().isMacosxVersionLT(10, 8))
- CmdArgs.push_back("-no_new_main");
- } else {
- if (Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_object) ||
- Args.hasArg(options::OPT_preload)) {
- CmdArgs.push_back("-lcrt0.o");
- } else {
- // Derived from darwin_crt1 spec.
- if (getDarwinToolChain().isTargetIOSSimulator()) {
- // The simulator doesn't have a versioned crt1 file.
- CmdArgs.push_back("-lcrt1.o");
- } else if (getDarwinToolChain().isTargetIPhoneOS()) {
- if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1))
- CmdArgs.push_back("-lcrt1.o");
- else if (getDarwinToolChain().isIPhoneOSVersionLT(6, 0))
- CmdArgs.push_back("-lcrt1.3.1.o");
- } else {
- if (getDarwinToolChain().isMacosxVersionLT(10, 5))
- CmdArgs.push_back("-lcrt1.o");
- else if (getDarwinToolChain().isMacosxVersionLT(10, 6))
- CmdArgs.push_back("-lcrt1.10.5.o");
- else if (getDarwinToolChain().isMacosxVersionLT(10, 8))
- CmdArgs.push_back("-lcrt1.10.6.o");
-
- // darwin_crt2 spec is empty.
- }
- }
- }
- }
- }
-
- if (!getDarwinToolChain().isTargetIPhoneOS() &&
- Args.hasArg(options::OPT_shared_libgcc) &&
- getDarwinToolChain().isMacosxVersionLT(10, 5)) {
- const char *Str =
- Args.MakeArgString(getToolChain().GetFilePath("crt3.o"));
- CmdArgs.push_back(Str);
- }
- }
+ !Args.hasArg(options::OPT_nostartfiles))
+ getMachOToolChain().addStartObjectFileArgs(Args, CmdArgs);
Args.AddAllArgs(CmdArgs, options::OPT_L);
- if (Args.hasArg(options::OPT_fopenmp))
- // This is more complicated in gcc...
+ LibOpenMP UsedOpenMPLib = LibUnknown;
+ if (Args.hasArg(options::OPT_fopenmp)) {
+ UsedOpenMPLib = LibGOMP;
+ } else if (const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ)) {
+ UsedOpenMPLib = llvm::StringSwitch<LibOpenMP>(A->getValue())
+ .Case("libgomp", LibGOMP)
+ .Case("libiomp5", LibIOMP5)
+ .Default(LibUnknown);
+ if (UsedOpenMPLib == LibUnknown)
+ getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << A->getValue();
+ }
+ switch (UsedOpenMPLib) {
+ case LibGOMP:
CmdArgs.push_back("-lgomp");
+ break;
+ case LibIOMP5:
+ CmdArgs.push_back("-liomp5");
+ break;
+ case LibUnknown:
+ break;
+ }
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
if (isObjCRuntimeLinked(Args) &&
!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
- // Avoid linking compatibility stubs on i386 mac.
- if (!getDarwinToolChain().isTargetMacOS() ||
- getDarwinToolChain().getArch() != llvm::Triple::x86) {
- // If we don't have ARC or subscripting 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.
- ObjCRuntime runtime =
- getDarwinToolChain().getDefaultObjCRuntime(/*nonfragile*/ true);
- // We use arclite library for both ARC and subscripting support.
- if ((!runtime.hasNativeARC() && isObjCAutoRefCount(Args)) ||
- !runtime.hasSubscripting())
- getDarwinToolChain().AddLinkARCArgs(Args, CmdArgs);
- }
+ // We use arclite library for both ARC and subscripting support.
+ getMachOToolChain().AddLinkARCArgs(Args, CmdArgs);
+
CmdArgs.push_back("-framework");
CmdArgs.push_back("Foundation");
// Link libobj.
@@ -5072,7 +5792,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
// link_ssp spec is empty.
// Let the tool chain choose which runtime library to link.
- getDarwinToolChain().AddLinkRuntimeLibArgs(Args, CmdArgs);
+ getMachOToolChain().AddLinkRuntimeLibArgs(Args, CmdArgs);
}
if (!Args.hasArg(options::OPT_nostdlib) &&
@@ -5084,7 +5804,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_F);
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("ld"));
+ Args.MakeArgString(getToolChain().GetLinkerPath());
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -5101,14 +5821,12 @@ void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-output");
CmdArgs.push_back(Output.getFilename());
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
+ for (const auto &II : Inputs) {
assert(II.isFilename() && "Unexpected lipo input.");
CmdArgs.push_back(II.getFilename());
}
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("lipo"));
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("lipo"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -5168,18 +5886,13 @@ void solaris::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
+ for (const auto &II : Inputs)
CmdArgs.push_back(II.getFilename());
- }
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
-
void solaris::Link::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -5278,10 +5991,10 @@ void solaris::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
CmdArgs.push_back(Args.MakeArgString(LibPath + "crtn.o"));
- addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
+ addProfileRT(getToolChain(), Args, CmdArgs);
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("ld"));
+ Args.MakeArgString(getToolChain().GetLinkerPath());
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -5298,14 +6011,10 @@ void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
+ for (const auto &II : Inputs)
CmdArgs.push_back(II.getFilename());
- }
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("gas"));
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("gas"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -5390,10 +6099,10 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().GetFilePath("crtend.o")));
}
- addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
+ addProfileRT(getToolChain(), Args, CmdArgs);
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("ld"));
+ Args.MakeArgString(getToolChain().GetLinkerPath());
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -5403,19 +6112,36 @@ void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const ArgList &Args,
const char *LinkingOutput) const {
ArgStringList CmdArgs;
+ bool NeedsKPIC = false;
- // When building 32-bit code on OpenBSD/amd64, we have to explicitly
- // instruct as in the base system to assemble 32-bit code.
- if (getToolChain().getArch() == llvm::Triple::x86)
+ switch (getToolChain().getArch()) {
+ case llvm::Triple::x86:
+ // When building 32-bit code on OpenBSD/amd64, we have to explicitly
+ // instruct as in the base system to assemble 32-bit code.
CmdArgs.push_back("--32");
- else if (getToolChain().getArch() == llvm::Triple::ppc) {
+ break;
+
+ case llvm::Triple::ppc:
CmdArgs.push_back("-mppc");
CmdArgs.push_back("-many");
- } else if (getToolChain().getArch() == llvm::Triple::mips64 ||
- getToolChain().getArch() == llvm::Triple::mips64el) {
+ break;
+
+ case llvm::Triple::sparc:
+ CmdArgs.push_back("-32");
+ NeedsKPIC = true;
+ break;
+
+ case llvm::Triple::sparcv9:
+ CmdArgs.push_back("-64");
+ CmdArgs.push_back("-Av9a");
+ NeedsKPIC = true;
+ break;
+
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el: {
StringRef CPUName;
StringRef ABIName;
- getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
+ mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
CmdArgs.push_back("-mabi");
CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data());
@@ -5425,30 +6151,25 @@ void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
else
CmdArgs.push_back("-EL");
- Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
- options::OPT_fpic, options::OPT_fno_pic,
- options::OPT_fPIE, options::OPT_fno_PIE,
- options::OPT_fpie, options::OPT_fno_pie);
- if (LastPICArg &&
- (LastPICArg->getOption().matches(options::OPT_fPIC) ||
- LastPICArg->getOption().matches(options::OPT_fpic) ||
- LastPICArg->getOption().matches(options::OPT_fPIE) ||
- LastPICArg->getOption().matches(options::OPT_fpie))) {
- CmdArgs.push_back("-KPIC");
- }
+ NeedsKPIC = true;
+ break;
}
+ default:
+ break;
+ }
+
+ if (NeedsKPIC)
+ addAssemblerKPIC(Args, CmdArgs);
+
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
options::OPT_Xassembler);
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
+ for (const auto &II : Inputs)
CmdArgs.push_back(II.getFilename());
- }
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("as"));
@@ -5583,7 +6304,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("ld"));
+ Args.MakeArgString(getToolChain().GetLinkerPath());
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -5600,14 +6321,10 @@ void bitrig::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
+ for (const auto &II : Inputs)
CmdArgs.push_back(II.getFilename());
- }
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -5723,7 +6440,7 @@ void bitrig::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("ld"));
+ Args.MakeArgString(getToolChain().GetLinkerPath());
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -5746,7 +6463,7 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().getArch() == llvm::Triple::mips64el) {
StringRef CPUName;
StringRef ABIName;
- getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
+ mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
CmdArgs.push_back("-march");
CmdArgs.push_back(CPUName.data());
@@ -5760,21 +6477,23 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
else
CmdArgs.push_back("-EL");
- Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
- options::OPT_fpic, options::OPT_fno_pic,
- options::OPT_fPIE, options::OPT_fno_PIE,
- options::OPT_fpie, options::OPT_fno_pie);
- if (LastPICArg &&
- (LastPICArg->getOption().matches(options::OPT_fPIC) ||
- LastPICArg->getOption().matches(options::OPT_fpic) ||
- LastPICArg->getOption().matches(options::OPT_fPIE) ||
- LastPICArg->getOption().matches(options::OPT_fpie))) {
- CmdArgs.push_back("-KPIC");
- }
+ addAssemblerKPIC(Args, CmdArgs);
} else if (getToolChain().getArch() == llvm::Triple::arm ||
- getToolChain().getArch() == llvm::Triple::thumb) {
- CmdArgs.push_back("-mfpu=softvfp");
+ getToolChain().getArch() == llvm::Triple::armeb ||
+ getToolChain().getArch() == llvm::Triple::thumb ||
+ getToolChain().getArch() == llvm::Triple::thumbeb) {
+ const Driver &D = getToolChain().getDriver();
+ const llvm::Triple &Triple = getToolChain().getTriple();
+ StringRef FloatABI = arm::getARMFloatABI(D, Args, Triple);
+
+ if (FloatABI == "hard") {
+ CmdArgs.push_back("-mfpu=vfp");
+ } else {
+ CmdArgs.push_back("-mfpu=softvfp");
+ }
+
switch(getToolChain().getTriple().getEnvironment()) {
+ case llvm::Triple::GNUEABIHF:
case llvm::Triple::GNUEABI:
case llvm::Triple::EABI:
CmdArgs.push_back("-meabi=5");
@@ -5783,6 +6502,14 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
default:
CmdArgs.push_back("-matpcs");
}
+ } else if (getToolChain().getArch() == llvm::Triple::sparc ||
+ getToolChain().getArch() == llvm::Triple::sparcv9) {
+ if (getToolChain().getArch() == llvm::Triple::sparc)
+ CmdArgs.push_back("-Av8plusa");
+ else
+ CmdArgs.push_back("-Av9a");
+
+ addAssemblerKPIC(Args, CmdArgs);
}
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
@@ -5791,14 +6518,10 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
+ for (const auto &II : Inputs)
CmdArgs.push_back(II.getFilename());
- }
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -5810,6 +6533,9 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
const toolchains::FreeBSD& ToolChain =
static_cast<const toolchains::FreeBSD&>(getToolChain());
const Driver &D = ToolChain.getDriver();
+ const bool IsPIE =
+ !Args.hasArg(options::OPT_shared) &&
+ (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault());
ArgStringList CmdArgs;
// Silence warning for "clang -g foo.o -o foo"
@@ -5823,7 +6549,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!D.SysRoot.empty())
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
- if (Args.hasArg(options::OPT_pie))
+ if (IsPIE)
CmdArgs.push_back("-pie");
if (Args.hasArg(options::OPT_static)) {
@@ -5869,11 +6595,11 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nostartfiles)) {
- const char *crt1 = NULL;
+ const char *crt1 = nullptr;
if (!Args.hasArg(options::OPT_shared)) {
if (Args.hasArg(options::OPT_pg))
crt1 = "gcrt1.o";
- else if (Args.hasArg(options::OPT_pie))
+ else if (IsPIE)
crt1 = "Scrt1.o";
else
crt1 = "crt1.o";
@@ -5883,10 +6609,10 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
- const char *crtbegin = NULL;
+ const char *crtbegin = nullptr;
if (Args.hasArg(options::OPT_static))
crtbegin = "crtbeginT.o";
- else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
+ else if (Args.hasArg(options::OPT_shared) || IsPIE)
crtbegin = "crtbeginS.o";
else
crtbegin = "crtbegin.o";
@@ -5896,9 +6622,8 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_L);
const ToolChain::path_list Paths = ToolChain.getFilePaths();
- for (ToolChain::path_list::const_iterator i = Paths.begin(), e = Paths.end();
- i != e; ++i)
- CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + *i));
+ for (const auto &Path : Paths)
+ CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_e);
Args.AddAllArgs(CmdArgs, options::OPT_s);
@@ -5906,25 +6631,8 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
Args.AddAllArgs(CmdArgs, options::OPT_r);
- // Tell the linker to load the plugin. This has to come before AddLinkerInputs
- // as gold requires -plugin to come before any -plugin-opt that -Wl might
- // forward.
- if (D.IsUsingLTO(Args)) {
- CmdArgs.push_back("-plugin");
- std::string Plugin = ToolChain.getDriver().Dir + "/../lib/LLVMgold.so";
- CmdArgs.push_back(Args.MakeArgString(Plugin));
-
- // Try to pass driver level flags relevant to LTO code generation down to
- // the plugin.
-
- // Handle flags for selecting CPU variants.
- std::string CPU = getCPUName(Args, ToolChain.getTriple());
- if (!CPU.empty()) {
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-plugin-opt=mcpu=") +
- CPU));
- }
- }
+ if (D.IsUsingLTO(Args))
+ AddGoldPlugin(ToolChain, Args, CmdArgs);
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
@@ -5984,17 +6692,19 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nostartfiles)) {
- if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
+ if (Args.hasArg(options::OPT_shared) || IsPIE)
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
else
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
}
- addProfileRT(ToolChain, Args, CmdArgs, ToolChain.getTriple());
+ addSanitizerRuntimes(getToolChain(), Args, CmdArgs);
+
+ addProfileRT(ToolChain, Args, CmdArgs);
const char *Exec =
- Args.MakeArgString(ToolChain.GetProgramPath("ld"));
+ Args.MakeArgString(getToolChain().GetLinkerPath());
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -6005,25 +6715,28 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
ArgStringList CmdArgs;
- // When building 32-bit code on NetBSD/amd64, we have to explicitly
- // instruct as in the base system to assemble 32-bit code.
- if (getToolChain().getArch() == llvm::Triple::x86)
+ // GNU as needs different flags for creating the correct output format
+ // on architectures with different ABIs or optional feature sets.
+ switch (getToolChain().getArch()) {
+ case llvm::Triple::x86:
CmdArgs.push_back("--32");
-
- // Pass the target CPU to GNU as for ARM, since the source code might
- // not have the correct .cpu annotation.
- if (getToolChain().getArch() == llvm::Triple::arm) {
- std::string MArch(getARMTargetCPU(Args, getToolChain().getTriple()));
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb: {
+ std::string MArch(arm::getARMTargetCPU(Args, getToolChain().getTriple()));
CmdArgs.push_back(Args.MakeArgString("-mcpu=" + MArch));
+ break;
}
- if (getToolChain().getArch() == llvm::Triple::mips ||
- getToolChain().getArch() == llvm::Triple::mipsel ||
- getToolChain().getArch() == llvm::Triple::mips64 ||
- getToolChain().getArch() == llvm::Triple::mips64el) {
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el: {
StringRef CPUName;
StringRef ABIName;
- getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
+ mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
CmdArgs.push_back("-march");
CmdArgs.push_back(CPUName.data());
@@ -6037,17 +6750,23 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
else
CmdArgs.push_back("-EL");
- Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
- options::OPT_fpic, options::OPT_fno_pic,
- options::OPT_fPIE, options::OPT_fno_PIE,
- options::OPT_fpie, options::OPT_fno_pie);
- if (LastPICArg &&
- (LastPICArg->getOption().matches(options::OPT_fPIC) ||
- LastPICArg->getOption().matches(options::OPT_fpic) ||
- LastPICArg->getOption().matches(options::OPT_fPIE) ||
- LastPICArg->getOption().matches(options::OPT_fpie))) {
- CmdArgs.push_back("-KPIC");
- }
+ addAssemblerKPIC(Args, CmdArgs);
+ break;
+ }
+
+ case llvm::Triple::sparc:
+ CmdArgs.push_back("-32");
+ addAssemblerKPIC(Args, CmdArgs);
+ break;
+
+ case llvm::Triple::sparcv9:
+ CmdArgs.push_back("-64");
+ CmdArgs.push_back("-Av9");
+ addAssemblerKPIC(Args, CmdArgs);
+ break;
+
+ default:
+ break;
}
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
@@ -6056,11 +6775,8 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
+ for (const auto &II : Inputs)
CmdArgs.push_back(II.getFilename());
- }
const char *Exec = Args.MakeArgString((getToolChain().GetProgramPath("as")));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
@@ -6077,12 +6793,12 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!D.SysRoot.empty())
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+ CmdArgs.push_back("--eh-frame-hdr");
if (Args.hasArg(options::OPT_static)) {
CmdArgs.push_back("-Bstatic");
} else {
if (Args.hasArg(options::OPT_rdynamic))
CmdArgs.push_back("-export-dynamic");
- CmdArgs.push_back("--eh-frame-hdr");
if (Args.hasArg(options::OPT_shared)) {
CmdArgs.push_back("-Bshareable");
} else {
@@ -6091,11 +6807,61 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- // When building 32-bit code on NetBSD/amd64, we have to explicitly
- // instruct ld in the base system to link 32-bit code.
- if (getToolChain().getArch() == llvm::Triple::x86) {
+ // Many NetBSD architectures support more than one ABI.
+ // Determine the correct emulation for ld.
+ switch (getToolChain().getArch()) {
+ case llvm::Triple::x86:
CmdArgs.push_back("-m");
CmdArgs.push_back("elf_i386");
+ break;
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ CmdArgs.push_back("-m");
+ switch (getToolChain().getTriple().getEnvironment()) {
+ case llvm::Triple::EABI:
+ case llvm::Triple::GNUEABI:
+ CmdArgs.push_back("armelf_nbsd_eabi");
+ break;
+ case llvm::Triple::EABIHF:
+ case llvm::Triple::GNUEABIHF:
+ CmdArgs.push_back("armelf_nbsd_eabihf");
+ break;
+ default:
+ CmdArgs.push_back("armelf_nbsd");
+ break;
+ }
+ break;
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ if (mips::hasMipsAbiArg(Args, "32")) {
+ CmdArgs.push_back("-m");
+ if (getToolChain().getArch() == llvm::Triple::mips64)
+ CmdArgs.push_back("elf32btsmip");
+ else
+ CmdArgs.push_back("elf32ltsmip");
+ } else if (mips::hasMipsAbiArg(Args, "64")) {
+ CmdArgs.push_back("-m");
+ if (getToolChain().getArch() == llvm::Triple::mips64)
+ CmdArgs.push_back("elf64btsmip");
+ else
+ CmdArgs.push_back("elf64ltsmip");
+ }
+ break;
+
+ case llvm::Triple::sparc:
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf32_sparc");
+ break;
+
+ case llvm::Triple::sparcv9:
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf64_sparc");
+ break;
+
+ default:
+ break;
}
if (Output.isFilename()) {
@@ -6135,10 +6901,19 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
unsigned Major, Minor, Micro;
getToolChain().getTriple().getOSVersion(Major, Minor, Micro);
bool useLibgcc = true;
- if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 23) || Major == 0) {
- if (getToolChain().getArch() == llvm::Triple::x86 ||
- getToolChain().getArch() == llvm::Triple::x86_64)
+ if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 40) || Major == 0) {
+ switch(getToolChain().getArch()) {
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
useLibgcc = false;
+ break;
+ default:
+ break;
+ }
}
if (!Args.hasArg(options::OPT_nostdlib) &&
@@ -6180,9 +6955,9 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
"crtn.o")));
}
- addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
+ addProfileRT(getToolChain(), Args, CmdArgs);
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld"));
+ const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -6192,13 +6967,17 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const ArgList &Args,
const char *LinkingOutput) const {
ArgStringList CmdArgs;
+ bool NeedsKPIC = false;
// Add --32/--64 to make sure we get the format we want.
// This is incomplete
if (getToolChain().getArch() == llvm::Triple::x86) {
CmdArgs.push_back("--32");
} else if (getToolChain().getArch() == llvm::Triple::x86_64) {
- CmdArgs.push_back("--64");
+ if (getToolChain().getTriple().getEnvironment() == llvm::Triple::GNUX32)
+ CmdArgs.push_back("--x32");
+ else
+ CmdArgs.push_back("--64");
} else if (getToolChain().getArch() == llvm::Triple::ppc) {
CmdArgs.push_back("-a32");
CmdArgs.push_back("-mppc");
@@ -6209,21 +6988,41 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-many");
} else if (getToolChain().getArch() == llvm::Triple::ppc64le) {
CmdArgs.push_back("-a64");
- CmdArgs.push_back("-mppc64le");
+ CmdArgs.push_back("-mppc64");
CmdArgs.push_back("-many");
- } else if (getToolChain().getArch() == llvm::Triple::arm) {
+ CmdArgs.push_back("-mlittle-endian");
+ } else if (getToolChain().getArch() == llvm::Triple::sparc) {
+ CmdArgs.push_back("-32");
+ CmdArgs.push_back("-Av8plusa");
+ NeedsKPIC = true;
+ } else if (getToolChain().getArch() == llvm::Triple::sparcv9) {
+ CmdArgs.push_back("-64");
+ CmdArgs.push_back("-Av9a");
+ NeedsKPIC = true;
+ } else if (getToolChain().getArch() == llvm::Triple::arm ||
+ getToolChain().getArch() == llvm::Triple::armeb) {
StringRef MArch = getToolChain().getArchName();
if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a")
CmdArgs.push_back("-mfpu=neon");
- if (MArch == "armv8" || MArch == "armv8a" || MArch == "armv8-a")
+ if (MArch == "armv8" || MArch == "armv8a" || MArch == "armv8-a" ||
+ MArch == "armebv8" || MArch == "armebv8a" || MArch == "armebv8-a")
CmdArgs.push_back("-mfpu=crypto-neon-fp-armv8");
- StringRef ARMFloatABI = getARMFloatABI(getToolChain().getDriver(), Args,
- getToolChain().getTriple());
+ StringRef ARMFloatABI = tools::arm::getARMFloatABI(
+ getToolChain().getDriver(), Args, getToolChain().getTriple());
CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=" + ARMFloatABI));
Args.AddLastArg(CmdArgs, options::OPT_march_EQ);
- Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ);
+
+ // FIXME: remove krait check when GNU tools support krait cpu
+ // for now replace it with -march=armv7-a to avoid a lower
+ // march from being picked in the absence of a cpu flag.
+ Arg *A;
+ if ((A = Args.getLastArg(options::OPT_mcpu_EQ)) &&
+ StringRef(A->getValue()) == "krait")
+ CmdArgs.push_back("-march=armv7-a");
+ else
+ Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ);
Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ);
} else if (getToolChain().getArch() == llvm::Triple::mips ||
getToolChain().getArch() == llvm::Triple::mipsel ||
@@ -6231,13 +7030,34 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().getArch() == llvm::Triple::mips64el) {
StringRef CPUName;
StringRef ABIName;
- getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
+ mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
+ ABIName = getGnuCompatibleMipsABIName(ABIName);
CmdArgs.push_back("-march");
CmdArgs.push_back(CPUName.data());
CmdArgs.push_back("-mabi");
- CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data());
+ CmdArgs.push_back(ABIName.data());
+
+ // -mno-shared should be emitted unless -fpic, -fpie, -fPIC, -fPIE,
+ // or -mshared (not implemented) is in effect.
+ bool IsPicOrPie = false;
+ if (Arg *A = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
+ options::OPT_fpic, options::OPT_fno_pic,
+ options::OPT_fPIE, options::OPT_fno_PIE,
+ options::OPT_fpie, options::OPT_fno_pie)) {
+ if (A->getOption().matches(options::OPT_fPIC) ||
+ A->getOption().matches(options::OPT_fpic) ||
+ A->getOption().matches(options::OPT_fPIE) ||
+ A->getOption().matches(options::OPT_fpie))
+ IsPicOrPie = true;
+ }
+ if (!IsPicOrPie)
+ CmdArgs.push_back("-mno-shared");
+
+ // LLVM doesn't support -mplt yet and acts as if it is always given.
+ // However, -mplt has no effect with the N64 ABI.
+ CmdArgs.push_back(ABIName == "64" ? "-KPIC" : "-call_nonpic");
if (getToolChain().getArch() == llvm::Triple::mips ||
getToolChain().getArch() == llvm::Triple::mips64)
@@ -6250,14 +7070,28 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString("-mnan=2008"));
}
- if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfp64)) {
- if (A->getOption().matches(options::OPT_mfp32))
- CmdArgs.push_back(Args.MakeArgString("-mfp32"));
- else
- CmdArgs.push_back(Args.MakeArgString("-mfp64"));
+ // Add the last -mfp32/-mfpxx/-mfp64 or -mfpxx if it is enabled by default.
+ if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx,
+ options::OPT_mfp64)) {
+ A->claim();
+ A->render(Args, CmdArgs);
+ } else if (mips::isFPXXDefault(getToolChain().getTriple(), CPUName,
+ ABIName))
+ CmdArgs.push_back("-mfpxx");
+
+ // Pass on -mmips16 or -mno-mips16. However, the assembler equivalent of
+ // -mno-mips16 is actually -no-mips16.
+ if (Arg *A = Args.getLastArg(options::OPT_mips16,
+ options::OPT_mno_mips16)) {
+ if (A->getOption().matches(options::OPT_mips16)) {
+ A->claim();
+ A->render(Args, CmdArgs);
+ } else {
+ A->claim();
+ CmdArgs.push_back("-no-mips16");
+ }
}
- Args.AddLastArg(CmdArgs, options::OPT_mips16, options::OPT_mno_mips16);
Args.AddLastArg(CmdArgs, options::OPT_mmicromips,
options::OPT_mno_micromips);
Args.AddLastArg(CmdArgs, options::OPT_mdsp, options::OPT_mno_dsp);
@@ -6270,17 +7104,13 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString("-mmsa"));
}
- Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
- options::OPT_fpic, options::OPT_fno_pic,
- options::OPT_fPIE, options::OPT_fno_PIE,
- options::OPT_fpie, options::OPT_fno_pie);
- if (LastPICArg &&
- (LastPICArg->getOption().matches(options::OPT_fPIC) ||
- LastPICArg->getOption().matches(options::OPT_fpic) ||
- LastPICArg->getOption().matches(options::OPT_fPIE) ||
- LastPICArg->getOption().matches(options::OPT_fpie))) {
- CmdArgs.push_back("-KPIC");
- }
+ Args.AddLastArg(CmdArgs, options::OPT_mhard_float,
+ options::OPT_msoft_float);
+
+ Args.AddLastArg(CmdArgs, options::OPT_modd_spreg,
+ options::OPT_mno_odd_spreg);
+
+ NeedsKPIC = true;
} else if (getToolChain().getArch() == llvm::Triple::systemz) {
// Always pass an -march option, since our default of z10 is later
// than the GNU assembler's default.
@@ -6288,20 +7118,19 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName));
}
+ if (NeedsKPIC)
+ addAssemblerKPIC(Args, CmdArgs);
+
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
options::OPT_Xassembler);
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
+ for (const auto &II : Inputs)
CmdArgs.push_back(II.getFilename());
- }
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
// Handle the debug info splitting at object creation time if we're
@@ -6313,7 +7142,7 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
SplitDebugName(Args, Inputs));
}
-static void AddLibgcc(llvm::Triple Triple, const Driver &D,
+static void AddLibgcc(const llvm::Triple &Triple, const Driver &D,
ArgStringList &CmdArgs, const ArgList &Args) {
bool isAndroid = Triple.getEnvironment() == llvm::Triple::Android;
bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) ||
@@ -6346,44 +7175,77 @@ static void AddLibgcc(llvm::Triple Triple, const Driver &D,
CmdArgs.push_back("-ldl");
}
-static bool hasMipsN32ABIArg(const ArgList &Args) {
- Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
- return A && (A->getValue() == StringRef("n32"));
-}
-
static StringRef getLinuxDynamicLinker(const ArgList &Args,
const toolchains::Linux &ToolChain) {
- if (ToolChain.getTriple().getEnvironment() == llvm::Triple::Android)
- return "/system/bin/linker";
- else if (ToolChain.getArch() == llvm::Triple::x86)
+ if (ToolChain.getTriple().getEnvironment() == llvm::Triple::Android) {
+ if (ToolChain.getTriple().isArch64Bit())
+ return "/system/bin/linker64";
+ else
+ return "/system/bin/linker";
+ } else if (ToolChain.getArch() == llvm::Triple::x86 ||
+ ToolChain.getArch() == llvm::Triple::sparc)
return "/lib/ld-linux.so.2";
- else if (ToolChain.getArch() == llvm::Triple::aarch64)
+ else if (ToolChain.getArch() == llvm::Triple::aarch64 ||
+ ToolChain.getArch() == llvm::Triple::arm64)
return "/lib/ld-linux-aarch64.so.1";
+ else if (ToolChain.getArch() == llvm::Triple::aarch64_be ||
+ ToolChain.getArch() == llvm::Triple::arm64_be)
+ return "/lib/ld-linux-aarch64_be.so.1";
else if (ToolChain.getArch() == llvm::Triple::arm ||
ToolChain.getArch() == llvm::Triple::thumb) {
if (ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
return "/lib/ld-linux-armhf.so.3";
else
return "/lib/ld-linux.so.3";
+ } else if (ToolChain.getArch() == llvm::Triple::armeb ||
+ ToolChain.getArch() == llvm::Triple::thumbeb) {
+ if (ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
+ return "/lib/ld-linux-armhf.so.3"; /* TODO: check which dynamic linker name. */
+ else
+ return "/lib/ld-linux.so.3"; /* TODO: check which dynamic linker name. */
} else if (ToolChain.getArch() == llvm::Triple::mips ||
- ToolChain.getArch() == llvm::Triple::mipsel)
+ ToolChain.getArch() == llvm::Triple::mipsel) {
+ if (mips::isNaN2008(Args, ToolChain.getTriple()))
+ return "/lib/ld-linux-mipsn8.so.1";
return "/lib/ld.so.1";
- else if (ToolChain.getArch() == llvm::Triple::mips64 ||
- ToolChain.getArch() == llvm::Triple::mips64el) {
- if (hasMipsN32ABIArg(Args))
- return "/lib32/ld.so.1";
- else
- return "/lib64/ld.so.1";
+ } else if (ToolChain.getArch() == llvm::Triple::mips64 ||
+ ToolChain.getArch() == llvm::Triple::mips64el) {
+ if (mips::hasMipsAbiArg(Args, "n32"))
+ return mips::isNaN2008(Args, ToolChain.getTriple())
+ ? "/lib32/ld-linux-mipsn8.so.1" : "/lib32/ld.so.1";
+ return mips::isNaN2008(Args, ToolChain.getTriple())
+ ? "/lib64/ld-linux-mipsn8.so.1" : "/lib64/ld.so.1";
} else if (ToolChain.getArch() == llvm::Triple::ppc)
return "/lib/ld.so.1";
else if (ToolChain.getArch() == llvm::Triple::ppc64 ||
- ToolChain.getArch() == llvm::Triple::ppc64le ||
ToolChain.getArch() == llvm::Triple::systemz)
return "/lib64/ld64.so.1";
+ else if (ToolChain.getArch() == llvm::Triple::ppc64le)
+ return "/lib64/ld64.so.2";
+ else if (ToolChain.getArch() == llvm::Triple::sparcv9)
+ return "/lib64/ld-linux.so.2";
+ else if (ToolChain.getArch() == llvm::Triple::x86_64 &&
+ ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUX32)
+ return "/libx32/ld-linux-x32.so.2";
else
return "/lib64/ld-linux-x86-64.so.2";
}
+static void AddRunTimeLibs(const ToolChain &TC, const Driver &D,
+ ArgStringList &CmdArgs, const ArgList &Args) {
+ // Make use of compiler-rt if --rtlib option is used
+ ToolChain::RuntimeLibType RLT = TC.GetRuntimeLibType(Args);
+
+ switch(RLT) {
+ case ToolChain::RLT_CompilerRT:
+ addClangRTLinux(TC, Args, CmdArgs);
+ break;
+ case ToolChain::RLT_Libgcc:
+ AddLibgcc(TC.getTriple(), D, CmdArgs, Args);
+ break;
+ }
+}
+
void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -6394,10 +7256,14 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
const Driver &D = ToolChain.getDriver();
const bool isAndroid =
ToolChain.getTriple().getEnvironment() == llvm::Triple::Android;
- const SanitizerArgs &Sanitize = ToolChain.getSanitizerArgs();
const bool IsPIE =
!Args.hasArg(options::OPT_shared) &&
- (Args.hasArg(options::OPT_pie) || Sanitize.hasZeroBaseShadow());
+ !Args.hasArg(options::OPT_static) &&
+ (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault() ||
+ // On Android every code is PIC so every executable is PIE
+ // Cannot use isPIEDefault here since otherwise
+ // PIE only logic will be enabled during compilation
+ isAndroid);
ArgStringList CmdArgs;
@@ -6421,10 +7287,8 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_s))
CmdArgs.push_back("-s");
- for (std::vector<std::string>::const_iterator i = ToolChain.ExtraOpts.begin(),
- e = ToolChain.ExtraOpts.end();
- i != e; ++i)
- CmdArgs.push_back(i->c_str());
+ for (const auto &Opt : ToolChain.ExtraOpts)
+ CmdArgs.push_back(Opt.c_str());
if (!Args.hasArg(options::OPT_static)) {
CmdArgs.push_back("--eh-frame-hdr");
@@ -6433,51 +7297,68 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-m");
if (ToolChain.getArch() == llvm::Triple::x86)
CmdArgs.push_back("elf_i386");
- else if (ToolChain.getArch() == llvm::Triple::aarch64)
+ else if (ToolChain.getArch() == llvm::Triple::aarch64 ||
+ ToolChain.getArch() == llvm::Triple::arm64)
CmdArgs.push_back("aarch64linux");
+ else if (ToolChain.getArch() == llvm::Triple::aarch64_be ||
+ ToolChain.getArch() == llvm::Triple::arm64_be)
+ CmdArgs.push_back("aarch64_be_linux");
else if (ToolChain.getArch() == llvm::Triple::arm
|| ToolChain.getArch() == llvm::Triple::thumb)
CmdArgs.push_back("armelf_linux_eabi");
+ else if (ToolChain.getArch() == llvm::Triple::armeb
+ || ToolChain.getArch() == llvm::Triple::thumbeb)
+ CmdArgs.push_back("armebelf_linux_eabi"); /* TODO: check which NAME. */
else if (ToolChain.getArch() == llvm::Triple::ppc)
CmdArgs.push_back("elf32ppclinux");
else if (ToolChain.getArch() == llvm::Triple::ppc64)
CmdArgs.push_back("elf64ppc");
+ else if (ToolChain.getArch() == llvm::Triple::ppc64le)
+ CmdArgs.push_back("elf64lppc");
+ else if (ToolChain.getArch() == llvm::Triple::sparc)
+ CmdArgs.push_back("elf32_sparc");
+ else if (ToolChain.getArch() == llvm::Triple::sparcv9)
+ CmdArgs.push_back("elf64_sparc");
else if (ToolChain.getArch() == llvm::Triple::mips)
CmdArgs.push_back("elf32btsmip");
else if (ToolChain.getArch() == llvm::Triple::mipsel)
CmdArgs.push_back("elf32ltsmip");
else if (ToolChain.getArch() == llvm::Triple::mips64) {
- if (hasMipsN32ABIArg(Args))
+ if (mips::hasMipsAbiArg(Args, "n32"))
CmdArgs.push_back("elf32btsmipn32");
else
CmdArgs.push_back("elf64btsmip");
}
else if (ToolChain.getArch() == llvm::Triple::mips64el) {
- if (hasMipsN32ABIArg(Args))
+ if (mips::hasMipsAbiArg(Args, "n32"))
CmdArgs.push_back("elf32ltsmipn32");
else
CmdArgs.push_back("elf64ltsmip");
}
else if (ToolChain.getArch() == llvm::Triple::systemz)
CmdArgs.push_back("elf64_s390");
+ else if (ToolChain.getArch() == llvm::Triple::x86_64 &&
+ ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUX32)
+ CmdArgs.push_back("elf32_x86_64");
else
CmdArgs.push_back("elf_x86_64");
if (Args.hasArg(options::OPT_static)) {
- if (ToolChain.getArch() == llvm::Triple::arm
- || ToolChain.getArch() == llvm::Triple::thumb)
+ if (ToolChain.getArch() == llvm::Triple::arm ||
+ ToolChain.getArch() == llvm::Triple::armeb ||
+ ToolChain.getArch() == llvm::Triple::thumb ||
+ ToolChain.getArch() == llvm::Triple::thumbeb)
CmdArgs.push_back("-Bstatic");
else
CmdArgs.push_back("-static");
} else if (Args.hasArg(options::OPT_shared)) {
CmdArgs.push_back("-shared");
- if (isAndroid) {
- CmdArgs.push_back("-Bsymbolic");
- }
}
if (ToolChain.getArch() == llvm::Triple::arm ||
+ ToolChain.getArch() == llvm::Triple::armeb ||
ToolChain.getArch() == llvm::Triple::thumb ||
+ ToolChain.getArch() == llvm::Triple::thumbeb ||
(!Args.hasArg(options::OPT_static) &&
!Args.hasArg(options::OPT_shared))) {
CmdArgs.push_back("-dynamic-linker");
@@ -6491,7 +7372,7 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nostartfiles)) {
if (!isAndroid) {
- const char *crt1 = NULL;
+ const char *crt1 = nullptr;
if (!Args.hasArg(options::OPT_shared)){
if (Args.hasArg(options::OPT_pg))
crt1 = "gcrt1.o";
@@ -6522,57 +7403,24 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
+ Args.AddAllArgs(CmdArgs, options::OPT_u);
const ToolChain::path_list Paths = ToolChain.getFilePaths();
- for (ToolChain::path_list::const_iterator i = Paths.begin(), e = Paths.end();
- i != e; ++i)
- CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + *i));
-
- // Tell the linker to load the plugin. This has to come before AddLinkerInputs
- // as gold requires -plugin to come before any -plugin-opt that -Wl might
- // forward.
- if (D.IsUsingLTO(Args)) {
- CmdArgs.push_back("-plugin");
- std::string Plugin = ToolChain.getDriver().Dir + "/../lib/LLVMgold.so";
- CmdArgs.push_back(Args.MakeArgString(Plugin));
-
- // Try to pass driver level flags relevant to LTO code generation down to
- // the plugin.
-
- // Handle flags for selecting CPU variants.
- std::string CPU = getCPUName(Args, ToolChain.getTriple());
- if (!CPU.empty()) {
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-plugin-opt=mcpu=") +
- CPU));
- }
- }
+ for (const auto &Path : Paths)
+ CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path));
+ if (D.IsUsingLTO(Args))
+ AddGoldPlugin(ToolChain, Args, CmdArgs);
if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
CmdArgs.push_back("--no-demangle");
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
- // Call these before we add the C++ ABI library.
- if (Sanitize.needsUbsanRt())
- addUbsanRTLinux(getToolChain(), Args, CmdArgs, D.CCCIsCXX(),
- Sanitize.needsAsanRt() || Sanitize.needsTsanRt() ||
- Sanitize.needsMsanRt() || Sanitize.needsLsanRt());
- if (Sanitize.needsAsanRt())
- addAsanRTLinux(getToolChain(), Args, CmdArgs);
- if (Sanitize.needsTsanRt())
- addTsanRTLinux(getToolChain(), Args, CmdArgs);
- if (Sanitize.needsMsanRt())
- addMsanRTLinux(getToolChain(), Args, CmdArgs);
- if (Sanitize.needsLsanRt())
- addLsanRTLinux(getToolChain(), Args, CmdArgs);
- if (Sanitize.needsDfsanRt())
- addDfsanRTLinux(getToolChain(), Args, CmdArgs);
-
+ addSanitizerRuntimes(getToolChain(), Args, CmdArgs);
// The profile runtime also needs access to system libraries.
- addProfileRTLinux(getToolChain(), Args, CmdArgs);
+ addProfileRT(getToolChain(), Args, CmdArgs);
if (D.CCCIsCXX() &&
!Args.hasArg(options::OPT_nostdlib) &&
@@ -6592,19 +7440,37 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_static))
CmdArgs.push_back("--start-group");
- bool OpenMP = Args.hasArg(options::OPT_fopenmp);
- if (OpenMP) {
+ LibOpenMP UsedOpenMPLib = LibUnknown;
+ if (Args.hasArg(options::OPT_fopenmp)) {
+ UsedOpenMPLib = LibGOMP;
+ } else if (const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ)) {
+ UsedOpenMPLib = llvm::StringSwitch<LibOpenMP>(A->getValue())
+ .Case("libgomp", LibGOMP)
+ .Case("libiomp5", LibIOMP5)
+ .Default(LibUnknown);
+ if (UsedOpenMPLib == LibUnknown)
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << A->getValue();
+ }
+ switch (UsedOpenMPLib) {
+ case LibGOMP:
CmdArgs.push_back("-lgomp");
- // FIXME: Exclude this for platforms whith libgomp that doesn't require
- // librt. Most modern Linux platfroms require it, but some may not.
+ // FIXME: Exclude this for platforms with libgomp that don't require
+ // librt. Most modern Linux platforms require it, but some may not.
CmdArgs.push_back("-lrt");
+ break;
+ case LibIOMP5:
+ CmdArgs.push_back("-liomp5");
+ break;
+ case LibUnknown:
+ break;
}
+ AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
- AddLibgcc(ToolChain.getTriple(), D, CmdArgs, Args);
-
- if (Args.hasArg(options::OPT_pthread) ||
- Args.hasArg(options::OPT_pthreads) || OpenMP)
+ if ((Args.hasArg(options::OPT_pthread) ||
+ Args.hasArg(options::OPT_pthreads) || UsedOpenMPLib != LibUnknown) &&
+ !isAndroid)
CmdArgs.push_back("-lpthread");
CmdArgs.push_back("-lc");
@@ -6612,7 +7478,7 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_static))
CmdArgs.push_back("--end-group");
else
- AddLibgcc(ToolChain.getTriple(), D, CmdArgs, Args);
+ AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
}
if (!Args.hasArg(options::OPT_nostartfiles)) {
@@ -6640,20 +7506,15 @@ void minix::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
ArgStringList CmdArgs;
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
- options::OPT_Xassembler);
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
+ for (const auto &II : Inputs)
CmdArgs.push_back(II.getFilename());
- }
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -6686,7 +7547,7 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
- addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
+ addProfileRT(getToolChain(), Args, CmdArgs);
if (!Args.hasArg(options::OPT_nostdlib) &&
!Args.hasArg(options::OPT_nodefaultlibs)) {
@@ -6707,7 +7568,7 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
}
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld"));
+ const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -6727,20 +7588,15 @@ void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
if (getToolChain().getArch() == llvm::Triple::x86)
CmdArgs.push_back("--32");
- Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
- options::OPT_Xassembler);
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
+ for (const auto &II : Inputs)
CmdArgs.push_back(II.getFilename());
- }
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("as"));
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -6888,13 +7744,21 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().GetFilePath("crtn.o")));
}
- addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
+ addProfileRT(getToolChain(), Args, CmdArgs);
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("ld"));
+ const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
+static void addSanitizerRTWindows(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs,
+ const StringRef RTName) {
+ SmallString<128> LibSanitizer(getCompilerRTLibDir(TC));
+ llvm::sys::path::append(LibSanitizer,
+ Twine("clang_rt.") + RTName + ".lib");
+ CmdArgs.push_back(Args.MakeArgString(LibSanitizer));
+}
+
void visualstudio::Link::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -6917,6 +7781,10 @@ void visualstudio::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-nologo");
+ if (Args.hasArg(options::OPT_g_Group)) {
+ CmdArgs.push_back("-debug");
+ }
+
bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd);
if (DLL) {
@@ -6931,28 +7799,25 @@ void visualstudio::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (getToolChain().getSanitizerArgs().needsAsanRt()) {
CmdArgs.push_back(Args.MakeArgString("-debug"));
CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
- SmallString<128> LibSanitizer(getToolChain().getDriver().ResourceDir);
- llvm::sys::path::append(LibSanitizer, "lib", "windows");
+ // FIXME: Handle 64-bit.
if (DLL) {
- llvm::sys::path::append(LibSanitizer, "clang_rt.asan_dll_thunk-i386.lib");
+ addSanitizerRTWindows(getToolChain(), Args, CmdArgs,
+ "asan_dll_thunk-i386");
} else {
- llvm::sys::path::append(LibSanitizer, "clang_rt.asan-i386.lib");
+ addSanitizerRTWindows(getToolChain(), Args, CmdArgs, "asan-i386");
+ addSanitizerRTWindows(getToolChain(), Args, CmdArgs, "asan_cxx-i386");
}
- // FIXME: Handle 64-bit.
- CmdArgs.push_back(Args.MakeArgString(LibSanitizer));
}
Args.AddAllArgValues(CmdArgs, options::OPT_l);
Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);
// Add filenames immediately.
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- if (it->isFilename())
- CmdArgs.push_back(it->getFilename());
+ for (const auto &Input : Inputs)
+ if (Input.isFilename())
+ CmdArgs.push_back(Input.getFilename());
else
- it->getInputArg().renderAsInput(Args, CmdArgs);
- }
+ Input.getInputArg().renderAsInput(Args, CmdArgs);
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("link.exe"));
@@ -6977,14 +7842,9 @@ static std::string FindFallback(const char *FallbackName,
if (!OptPath.hasValue())
return FallbackName;
-#ifdef LLVM_ON_WIN32
- const StringRef PathSeparators = ";";
-#else
- const StringRef PathSeparators = ":";
-#endif
-
+ const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'};
SmallVector<StringRef, 8> PathSegments;
- llvm::SplitString(OptPath.getValue(), PathSegments, PathSeparators);
+ llvm::SplitString(OptPath.getValue(), PathSegments, EnvPathSeparatorStr);
for (size_t i = 0, e = PathSegments.size(); i != e; ++i) {
const StringRef &PathSegment = PathSegments[i];
@@ -7034,19 +7894,31 @@ Command *visualstudio::Compile::GetCommand(Compilation &C, const JobAction &JA,
// Flags for which clang-cl have an alias.
// FIXME: How can we ensure this stays in sync with relevant clang-cl options?
- if (Arg *A = Args.getLastArg(options::OPT_frtti, options::OPT_fno_rtti))
- CmdArgs.push_back(A->getOption().getID() == options::OPT_frtti ? "/GR"
- : "/GR-");
+ if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR,
+ /*default=*/false))
+ CmdArgs.push_back("/GR-");
+ if (Arg *A = Args.getLastArg(options::OPT_ffunction_sections,
+ options::OPT_fno_function_sections))
+ CmdArgs.push_back(A->getOption().getID() == options::OPT_ffunction_sections
+ ? "/Gy"
+ : "/Gy-");
+ if (Arg *A = Args.getLastArg(options::OPT_fdata_sections,
+ options::OPT_fno_data_sections))
+ CmdArgs.push_back(
+ A->getOption().getID() == options::OPT_fdata_sections ? "/Gw" : "/Gw-");
if (Args.hasArg(options::OPT_fsyntax_only))
CmdArgs.push_back("/Zs");
+ if (Args.hasArg(options::OPT_g_Flag, options::OPT_gline_tables_only))
+ CmdArgs.push_back("/Z7");
std::vector<std::string> Includes = Args.getAllArgValues(options::OPT_include);
- for (size_t I = 0, E = Includes.size(); I != E; ++I)
- CmdArgs.push_back(Args.MakeArgString(std::string("/FI") + Includes[I]));
+ for (const auto &Include : Includes)
+ CmdArgs.push_back(Args.MakeArgString(std::string("/FI") + Include));
// Flags that can simply be passed through.
Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LD);
Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LDd);
+ Args.AddAllArgs(CmdArgs, options::OPT__SLASH_EH);
// The order of these flags is relevant, so pick the last one.
if (Arg *A = Args.getLastArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd,
@@ -7072,7 +7944,6 @@ Command *visualstudio::Compile::GetCommand(Compilation &C, const JobAction &JA,
const Driver &D = getToolChain().getDriver();
std::string Exec = FindFallback("cl.exe", D.getClangProgramPath());
-
return new Command(JA, *this, Args.MakeArgString(Exec), CmdArgs);
}
@@ -7092,21 +7963,24 @@ void XCore::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-c");
- if (Args.hasArg(options::OPT_g_Group)) {
- CmdArgs.push_back("-g");
- }
+ if (Args.hasArg(options::OPT_v))
+ CmdArgs.push_back("-v");
+
+ if (Arg *A = Args.getLastArg(options::OPT_g_Group))
+ if (!A->getOption().matches(options::OPT_g0))
+ CmdArgs.push_back("-g");
+
+ if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm,
+ false))
+ CmdArgs.push_back("-fverbose-asm");
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
options::OPT_Xassembler);
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
+ for (const auto &II : Inputs)
CmdArgs.push_back(II.getFilename());
- }
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("xcc"));
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -7124,9 +7998,15 @@ void XCore::Link::ConstructJob(Compilation &C, const JobAction &JA,
assert(Output.isNothing() && "Invalid output.");
}
+ if (Args.hasArg(options::OPT_v))
+ CmdArgs.push_back("-v");
+
+ ExceptionSettings EH = exceptionSettings(Args, getToolChain().getTriple());
+ if (EH.ShouldUseExceptionTables)
+ CmdArgs.push_back("-fexceptions");
+
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("xcc"));
+ const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index d5b2848c9b01..4c89676e0e19 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -25,10 +25,15 @@ namespace driver {
class Driver;
namespace toolchains {
- class Darwin;
+ class MachO;
}
namespace tools {
+
+namespace visualstudio {
+ class Compile;
+}
+
using llvm::opt::ArgStringList;
/// \brief Clang compiler tool.
@@ -54,6 +59,8 @@ using llvm::opt::ArgStringList;
void AddARMTargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
bool KernelOrKext) const;
+ void AddARM64TargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
void AddMIPSTargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
void AddR600TargetArgs(const llvm::opt::ArgList &Args,
@@ -76,18 +83,21 @@ using llvm::opt::ArgStringList;
void AddClangCLArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
+ visualstudio::Compile *getCLFallback() const;
+
+ mutable std::unique_ptr<visualstudio::Compile> CLFallback;
+
public:
Clang(const ToolChain &TC) : Tool("clang", "clang frontend", TC) {}
- virtual bool hasGoodDiagnostics() const { return true; }
- virtual bool hasIntegratedAssembler() const { return true; }
- virtual bool hasIntegratedCPP() const { return true; }
+ bool hasGoodDiagnostics() const override { return true; }
+ bool hasIntegratedAssembler() const override { return true; }
+ bool hasIntegratedCPP() const override { return true; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
/// \brief Clang integrated assembler tool.
@@ -96,15 +106,14 @@ using llvm::opt::ArgStringList;
ClangAs(const ToolChain &TC) : Tool("clang::as",
"clang integrated assembler", TC) {}
- virtual bool hasGoodDiagnostics() const { return true; }
- virtual bool hasIntegratedAssembler() const { return false; }
- virtual bool hasIntegratedCPP() const { return false; }
+ bool hasGoodDiagnostics() const override { return true; }
+ bool hasIntegratedAssembler() const override { return false; }
+ bool hasIntegratedCPP() const override { return false; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
/// gcc - Generic GCC tool implementations.
@@ -114,11 +123,11 @@ namespace gcc {
Common(const char *Name, const char *ShortName,
const ToolChain &TC) : Tool(Name, ShortName, TC) {}
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
/// RenderExtraToolArgs - Render any arguments necessary to force
/// the particular tool mode.
@@ -132,23 +141,11 @@ namespace gcc {
Preprocess(const ToolChain &TC) : Common("gcc::Preprocess",
"gcc preprocessor", TC) {}
- virtual bool hasGoodDiagnostics() const { return true; }
- virtual bool hasIntegratedCPP() const { return false; }
+ bool hasGoodDiagnostics() const override { return true; }
+ bool hasIntegratedCPP() const override { return false; }
- virtual void RenderExtraToolArgs(const JobAction &JA,
- llvm::opt::ArgStringList &CmdArgs) const;
- };
-
- class LLVM_LIBRARY_VISIBILITY Precompile : public Common {
- public:
- Precompile(const ToolChain &TC) : Common("gcc::Precompile",
- "gcc precompile", TC) {}
-
- virtual bool hasGoodDiagnostics() const { return true; }
- virtual bool hasIntegratedCPP() const { return true; }
-
- virtual void RenderExtraToolArgs(const JobAction &JA,
- llvm::opt::ArgStringList &CmdArgs) const;
+ void RenderExtraToolArgs(const JobAction &JA,
+ llvm::opt::ArgStringList &CmdArgs) const override;
};
class LLVM_LIBRARY_VISIBILITY Compile : public Common {
@@ -156,22 +153,11 @@ namespace gcc {
Compile(const ToolChain &TC) : Common("gcc::Compile",
"gcc frontend", TC) {}
- virtual bool hasGoodDiagnostics() const { return true; }
- virtual bool hasIntegratedCPP() const { return true; }
+ bool hasGoodDiagnostics() const override { return true; }
+ bool hasIntegratedCPP() const override { return true; }
- virtual void RenderExtraToolArgs(const JobAction &JA,
- llvm::opt::ArgStringList &CmdArgs) const;
- };
-
- class LLVM_LIBRARY_VISIBILITY Assemble : public Common {
- public:
- Assemble(const ToolChain &TC) : Common("gcc::Assemble",
- "assembler (via gcc)", TC) {}
-
- virtual bool hasIntegratedCPP() const { return false; }
-
- virtual void RenderExtraToolArgs(const JobAction &JA,
- llvm::opt::ArgStringList &CmdArgs) const;
+ void RenderExtraToolArgs(const JobAction &JA,
+ llvm::opt::ArgStringList &CmdArgs) const override;
};
class LLVM_LIBRARY_VISIBILITY Link : public Common {
@@ -179,11 +165,11 @@ namespace gcc {
Link(const ToolChain &TC) : Common("gcc::Link",
"linker (via gcc)", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
- virtual bool isLinkJob() const { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
- virtual void RenderExtraToolArgs(const JobAction &JA,
- llvm::opt::ArgStringList &CmdArgs) const;
+ void RenderExtraToolArgs(const JobAction &JA,
+ llvm::opt::ArgStringList &CmdArgs) const override;
};
} // end namespace gcc
@@ -195,15 +181,14 @@ namespace hexagon {
Assemble(const ToolChain &TC) : Tool("hexagon::Assemble",
"hexagon-as", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
+ bool hasIntegratedCPP() const override { return false; }
- virtual void RenderExtraToolArgs(const JobAction &JA,
- llvm::opt::ArgStringList &CmdArgs) const;
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void RenderExtraToolArgs(const JobAction &JA,
+ llvm::opt::ArgStringList &CmdArgs) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
@@ -211,111 +196,124 @@ namespace hexagon {
Link(const ToolChain &TC) : Tool("hexagon::Link",
"hexagon-ld", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
- virtual bool isLinkJob() const { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
virtual void RenderExtraToolArgs(const JobAction &JA,
llvm::opt::ArgStringList &CmdArgs) const;
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
} // end namespace hexagon.
+namespace arm {
+ StringRef getARMTargetCPU(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple);
+ const char* getARMCPUForMArch(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple);
+ const char* getLLVMArchSuffixForARM(StringRef CPU);
+}
+
+namespace mips {
+ void getMipsCPUAndABI(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple, StringRef &CPUName,
+ StringRef &ABIName);
+ bool hasMipsAbiArg(const llvm::opt::ArgList &Args, const char *Value);
+ bool isNaN2008(const llvm::opt::ArgList &Args, const llvm::Triple &Triple);
+ bool isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName,
+ StringRef ABIName);
+}
namespace darwin {
- llvm::Triple::ArchType getArchTypeForDarwinArchName(StringRef Str);
+ llvm::Triple::ArchType getArchTypeForMachOArchName(StringRef Str);
+ void setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str);
- class LLVM_LIBRARY_VISIBILITY DarwinTool : public Tool {
+ class LLVM_LIBRARY_VISIBILITY MachOTool : public Tool {
virtual void anchor();
protected:
- void AddDarwinArch(const llvm::opt::ArgList &Args,
+ void AddMachOArch(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
- const toolchains::Darwin &getDarwinToolChain() const {
- return reinterpret_cast<const toolchains::Darwin&>(getToolChain());
+ const toolchains::MachO &getMachOToolChain() const {
+ return reinterpret_cast<const toolchains::MachO&>(getToolChain());
}
public:
- DarwinTool(const char *Name, const char *ShortName,
+ MachOTool(const char *Name, const char *ShortName,
const ToolChain &TC) : Tool(Name, ShortName, TC) {}
};
- class LLVM_LIBRARY_VISIBILITY Assemble : public DarwinTool {
+ class LLVM_LIBRARY_VISIBILITY Assemble : public MachOTool {
public:
- Assemble(const ToolChain &TC) : DarwinTool("darwin::Assemble",
- "assembler", TC) {}
+ Assemble(const ToolChain &TC) : MachOTool("darwin::Assemble",
+ "assembler", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
+ bool hasIntegratedCPP() const override { return false; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
- class LLVM_LIBRARY_VISIBILITY Link : public DarwinTool {
+ class LLVM_LIBRARY_VISIBILITY Link : public MachOTool {
bool NeedsTempPath(const InputInfoList &Inputs) const;
void AddLinkArgs(Compilation &C, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
const InputInfoList &Inputs) const;
public:
- Link(const ToolChain &TC) : DarwinTool("darwin::Link", "linker", TC) {}
+ Link(const ToolChain &TC) : MachOTool("darwin::Link", "linker", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
- virtual bool isLinkJob() const { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
- class LLVM_LIBRARY_VISIBILITY Lipo : public DarwinTool {
+ class LLVM_LIBRARY_VISIBILITY Lipo : public MachOTool {
public:
- Lipo(const ToolChain &TC) : DarwinTool("darwin::Lipo", "lipo", TC) {}
+ Lipo(const ToolChain &TC) : MachOTool("darwin::Lipo", "lipo", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
+ bool hasIntegratedCPP() const override { return false; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
- class LLVM_LIBRARY_VISIBILITY Dsymutil : public DarwinTool {
+ class LLVM_LIBRARY_VISIBILITY Dsymutil : public MachOTool {
public:
- Dsymutil(const ToolChain &TC) : DarwinTool("darwin::Dsymutil",
- "dsymutil", TC) {}
+ Dsymutil(const ToolChain &TC) : MachOTool("darwin::Dsymutil",
+ "dsymutil", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
- virtual bool isDsymutilJob() const { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+ bool isDsymutilJob() const override { return true; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
- class LLVM_LIBRARY_VISIBILITY VerifyDebug : public DarwinTool {
+ class LLVM_LIBRARY_VISIBILITY VerifyDebug : public MachOTool {
public:
- VerifyDebug(const ToolChain &TC) : DarwinTool("darwin::VerifyDebug",
- "dwarfdump", TC) {}
+ VerifyDebug(const ToolChain &TC) : MachOTool("darwin::VerifyDebug",
+ "dwarfdump", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
+ bool hasIntegratedCPP() const override { return false; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
}
@@ -327,26 +325,25 @@ namespace openbsd {
Assemble(const ToolChain &TC) : Tool("openbsd::Assemble", "assembler",
TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
+ bool hasIntegratedCPP() const override { return false; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
Link(const ToolChain &TC) : Tool("openbsd::Link", "linker", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
- virtual bool isLinkJob() const { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
} // end namespace openbsd
@@ -357,26 +354,24 @@ namespace bitrig {
Assemble(const ToolChain &TC) : Tool("bitrig::Assemble", "assembler",
TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
+ bool hasIntegratedCPP() const override { return false; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
Link(const ToolChain &TC) : Tool("bitrig::Link", "linker", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
- virtual bool isLinkJob() const { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
} // end namespace bitrig
@@ -387,26 +382,24 @@ namespace freebsd {
Assemble(const ToolChain &TC) : Tool("freebsd::Assemble", "assembler",
TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
+ bool hasIntegratedCPP() const override { return false; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
Link(const ToolChain &TC) : Tool("freebsd::Link", "linker", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
- virtual bool isLinkJob() const { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
} // end namespace freebsd
@@ -418,13 +411,12 @@ namespace netbsd {
Assemble(const ToolChain &TC)
: Tool("netbsd::Assemble", "assembler", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
+ bool hasIntegratedCPP() const override { return false; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
@@ -432,14 +424,13 @@ namespace netbsd {
Link(const ToolChain &TC)
: Tool("netbsd::Link", "linker", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
- virtual bool isLinkJob() const { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
} // end namespace netbsd
@@ -449,26 +440,26 @@ namespace gnutools {
public:
Assemble(const ToolChain &TC) : Tool("GNU::Assemble", "assembler", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
+ bool hasIntegratedCPP() const override { return false; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
Link(const ToolChain &TC) : Tool("GNU::Link", "linker", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
- virtual bool isLinkJob() const { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
}
/// minix -- Directly call GNU Binutils assembler and linker
@@ -478,26 +469,26 @@ namespace minix {
Assemble(const ToolChain &TC) : Tool("minix::Assemble", "assembler",
TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
+ bool hasIntegratedCPP() const override { return false; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
Link(const ToolChain &TC) : Tool("minix::Link", "linker", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
- virtual bool isLinkJob() const { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
} // end namespace minix
@@ -508,26 +499,24 @@ namespace solaris {
Assemble(const ToolChain &TC) : Tool("solaris::Assemble", "assembler",
TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
+ bool hasIntegratedCPP() const override { return false; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
Link(const ToolChain &TC) : Tool("solaris::Link", "linker", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
- virtual bool isLinkJob() const { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
} // end namespace solaris
@@ -538,26 +527,24 @@ namespace auroraux {
Assemble(const ToolChain &TC) : Tool("auroraux::Assemble", "assembler",
TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
+ bool hasIntegratedCPP() const override { return false; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
Link(const ToolChain &TC) : Tool("auroraux::Link", "linker", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
- virtual bool isLinkJob() const { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
} // end namespace auroraux
@@ -568,58 +555,55 @@ namespace dragonfly {
Assemble(const ToolChain &TC) : Tool("dragonfly::Assemble", "assembler",
TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
+ bool hasIntegratedCPP() const override { return false; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
Link(const ToolChain &TC) : Tool("dragonfly::Link", "linker", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
- virtual bool isLinkJob() const { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
} // end namespace dragonfly
- /// Visual studio tools.
+/// Visual studio tools.
namespace visualstudio {
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
Link(const ToolChain &TC) : Tool("visualstudio::Link", "linker", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
- virtual bool isLinkJob() const { return true; }
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
class LLVM_LIBRARY_VISIBILITY Compile : public Tool {
public:
Compile(const ToolChain &TC) : Tool("visualstudio::Compile", "compiler", TC) {}
- virtual bool hasIntegratedAssembler() const { return true; }
- virtual bool hasIntegratedCPP() const { return true; }
- virtual bool isLinkJob() const { return false; }
+ bool hasIntegratedAssembler() const override { return true; }
+ bool hasIntegratedCPP() const override { return true; }
+ bool isLinkJob() const override { return false; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
Command *GetCommand(Compilation &C, const JobAction &JA,
const InputInfo &Output,
@@ -629,6 +613,10 @@ namespace visualstudio {
};
} // end namespace visualstudio
+namespace arm {
+ StringRef getARMFloatABI(const Driver &D, const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple);
+}
namespace XCore {
// For XCore, we do not need to instantiate tools for PreProcess, PreCompile and Compile.
// We simply use "clang -cc1" for those actions.
@@ -637,12 +625,11 @@ namespace XCore {
Assemble(const ToolChain &TC) : Tool("XCore::Assemble",
"XCore-as", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ bool hasIntegratedCPP() const override { return false; }
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
@@ -650,13 +637,12 @@ namespace XCore {
Link(const ToolChain &TC) : Tool("XCore::Link",
"XCore-ld", TC) {}
- virtual bool hasIntegratedCPP() const { return false; }
- virtual bool isLinkJob() const { return true; }
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &TCArgs,
- const char *LinkingOutput) const;
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return true; }
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
} // end namespace XCore.
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index d947ae7c03d6..3538dbc2c0e9 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -174,6 +174,8 @@ types::ID types::lookupTypeForExtension(const char *Ext) {
.Case("F95", TY_Fortran)
.Case("mii", TY_PP_ObjCXX)
.Case("pcm", TY_ModuleFile)
+ .Case("pch", TY_PCH)
+ .Case("gch", TY_PCH)
.Default(TY_INVALID);
}
diff --git a/lib/Driver/WindowsToolChain.cpp b/lib/Driver/WindowsToolChain.cpp
index 2b6320ac12e3..913425a19f00 100644
--- a/lib/Driver/WindowsToolChain.cpp
+++ b/lib/Driver/WindowsToolChain.cpp
@@ -14,6 +14,7 @@
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/ErrorHandling.h"
@@ -21,11 +22,15 @@
// Include the necessary headers to interface with the Windows registry and
// environment.
-#ifdef _MSC_VER
+#if defined(LLVM_ON_WIN32)
+#define USE_WIN32
+#endif
+
+#ifdef USE_WIN32
#define WIN32_LEAN_AND_MEAN
#define NOGDI
#define NOMINMAX
- #include <Windows.h>
+ #include <windows.h>
#endif
using namespace clang::driver;
@@ -43,10 +48,10 @@ Tool *Windows::buildLinker() const {
}
Tool *Windows::buildAssembler() const {
- if (getTriple().getEnvironment() == llvm::Triple::MachO)
+ if (getTriple().isOSBinFormatMachO())
return new tools::darwin::Assemble(*this);
getDriver().Diag(clang::diag::err_no_external_assembler);
- return NULL;
+ return nullptr;
}
bool Windows::IsIntegratedAssemblerDefault() const {
@@ -54,7 +59,11 @@ bool Windows::IsIntegratedAssemblerDefault() const {
}
bool Windows::IsUnwindTablesDefault() const {
- return getArch() == llvm::Triple::x86_64;
+ // FIXME: LLVM's lowering of Win64 data is broken right now. MSVC's linker
+ // says that our object files provide invalid .pdata contributions. Until
+ // that is fixed, don't ask for unwind tables.
+ return false;
+ //return getArch() == llvm::Triple::x86_64;
}
bool Windows::isPICDefault() const {
@@ -69,9 +78,6 @@ bool Windows::isPICDefaultForced() const {
return getArch() == llvm::Triple::x86_64;
}
-// FIXME: This probably should goto to some platform utils place.
-#ifdef _MSC_VER
-
/// \brief Read registry string.
/// This also supports a means to look for high-versioned keys by use
/// of a $VERSION placeholder in the key path.
@@ -82,6 +88,9 @@ bool Windows::isPICDefaultForced() const {
/// characters are compared.
static bool getSystemRegistryString(const char *keyPath, const char *valueName,
char *value, size_t maxLength) {
+#ifndef USE_WIN32
+ return false;
+#else
HKEY hRootKey = NULL;
HKEY hKey = NULL;
const char* subKey = NULL;
@@ -183,6 +192,7 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName,
}
}
return returnValue;
+#endif // USE_WIN32
}
/// \brief Get Windows SDK installation directory.
@@ -202,7 +212,7 @@ static bool getWindowsSDKDir(std::string &path) {
return false;
}
- // Get Visual Studio installation directory.
+// Get Visual Studio installation directory.
static bool getVisualStudioDir(std::string &path) {
// First check the environment variables that vsvars32.bat sets.
const char* vcinstalldir = getenv("VCINSTALLDIR");
@@ -244,25 +254,11 @@ static bool getVisualStudioDir(std::string &path) {
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)
+ const char *vscomntools = nullptr;
+
+ // Find any version we can
+ if (vs100comntools)
vscomntools = vs100comntools;
else if (vs90comntools)
vscomntools = vs90comntools;
@@ -277,8 +273,6 @@ static bool getVisualStudioDir(std::string &path) {
return false;
}
-#endif // _MSC_VER
-
void Windows::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
if (DriverArgs.hasArg(options::OPT_nostdinc))
@@ -293,21 +287,15 @@ void Windows::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
if (DriverArgs.hasArg(options::OPT_nostdlibinc))
return;
-#ifdef _MSC_VER
// Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat.
if (const char *cl_include_dir = getenv("INCLUDE")) {
SmallVector<StringRef, 8> Dirs;
- StringRef(cl_include_dir).split(Dirs, ";");
- int n = 0;
- for (SmallVectorImpl<StringRef>::iterator I = Dirs.begin(), E = Dirs.end();
- I != E; ++I) {
- StringRef d = *I;
- if (d.size() == 0)
- continue;
- ++n;
- addSystemInclude(DriverArgs, CC1Args, d);
- }
- if (n) return;
+ StringRef(cl_include_dir)
+ .split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ for (StringRef Dir : Dirs)
+ addSystemInclude(DriverArgs, CC1Args, Dir);
+ if (!Dirs.empty())
+ return;
}
std::string VSDir;
@@ -316,17 +304,24 @@ void Windows::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
// When built with access to the proper Windows APIs, try to actually find
// the correct include paths first.
if (getVisualStudioDir(VSDir)) {
- addSystemInclude(DriverArgs, CC1Args, VSDir + "\\VC\\include");
- if (getWindowsSDKDir(WindowsSDKDir))
- addSystemInclude(DriverArgs, CC1Args, WindowsSDKDir + "\\include");
- else
- addSystemInclude(DriverArgs, CC1Args,
- VSDir + "\\VC\\PlatformSDK\\Include");
+ SmallString<128> P;
+ P = VSDir;
+ llvm::sys::path::append(P, "VC\\include");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ if (getWindowsSDKDir(WindowsSDKDir)) {
+ P = WindowsSDKDir;
+ llvm::sys::path::append(P, "include");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ } else {
+ P = VSDir;
+ llvm::sys::path::append(P, "VC\\PlatformSDK\\Include");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ }
return;
}
-#endif // _MSC_VER
// As a fallback, select default install paths.
+ // FIXME: Don't guess drives and paths like this on Windows.
const StringRef Paths[] = {
"C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
"C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
diff --git a/lib/Edit/CMakeLists.txt b/lib/Edit/CMakeLists.txt
index cce1c197ae50..a7fa9c28e1f6 100644
--- a/lib/Edit/CMakeLists.txt
+++ b/lib/Edit/CMakeLists.txt
@@ -1,20 +1,14 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
add_clang_library(clangEdit
Commit.cpp
EditedSource.cpp
RewriteObjCFoundationAPI.cpp
- )
-add_dependencies(clangEdit
- ClangAttrClasses
- ClangAttrList
- ClangCommentNodes
- ClangDeclNodes
- ClangDiagnosticCommon
- ClangStmtNodes
- )
-
-target_link_libraries(clangEdit
- clangBasic
+ LINK_LIBS
clangAST
+ clangBasic
clangLex
)
diff --git a/lib/Edit/Commit.cpp b/lib/Edit/Commit.cpp
index 706c732dba45..9c08cc28ac9b 100644
--- a/lib/Edit/Commit.cpp
+++ b/lib/Edit/Commit.cpp
@@ -38,9 +38,7 @@ CharSourceRange Commit::Edit::getInsertFromRange(SourceManager &SM) const {
Commit::Commit(EditedSource &Editor)
: SourceMgr(Editor.getSourceManager()), LangOpts(Editor.getLangOpts()),
PPRec(Editor.getPPCondDirectiveRecord()),
- Editor(&Editor),
- ForceCommitInSystemHeader(Editor.getForceCommitInSystemHeader()),
- IsCommitable(true) { }
+ Editor(&Editor), IsCommitable(true) { }
bool Commit::insert(SourceLocation loc, StringRef text,
bool afterToken, bool beforePreviousInsertions) {
@@ -234,7 +232,7 @@ bool Commit::canInsert(SourceLocation loc, FileOffset &offs) {
if (!isAtStartOfMacroExpansion(loc, &loc))
return false;
- if (SM.isInSystemHeader(loc) && ForceCommitInSystemHeader)
+ if (SM.isInSystemHeader(loc))
return false;
std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
@@ -265,7 +263,7 @@ bool Commit::canInsertAfterToken(SourceLocation loc, FileOffset &offs,
if (!isAtEndOfMacroExpansion(loc, &loc))
return false;
- if (SM.isInSystemHeader(loc) && ForceCommitInSystemHeader)
+ if (SM.isInSystemHeader(loc))
return false;
loc = Lexer::getLocForEndOfToken(loc, 0, SourceMgr, LangOpts);
@@ -303,8 +301,8 @@ bool Commit::canRemoveRange(CharSourceRange range,
if (range.getBegin().isMacroID() || range.getEnd().isMacroID())
return false;
- if ((SM.isInSystemHeader(range.getBegin()) ||
- SM.isInSystemHeader(range.getEnd())) && ForceCommitInSystemHeader)
+ if (SM.isInSystemHeader(range.getBegin()) ||
+ SM.isInSystemHeader(range.getEnd()))
return false;
if (PPRec && PPRec->rangeIntersectsConditionalDirective(range.getAsRange()))
diff --git a/lib/Edit/EditedSource.cpp b/lib/Edit/EditedSource.cpp
index 34b5e62333ad..6cf6335da181 100644
--- a/lib/Edit/EditedSource.cpp
+++ b/lib/Edit/EditedSource.cpp
@@ -72,13 +72,11 @@ bool EditedSource::commitInsert(SourceLocation OrigLoc,
return true;
}
- Twine concat;
if (beforePreviousInsertions)
- concat = Twine(text) + FA.Text;
+ FA.Text = copyString(Twine(text) + FA.Text);
else
- concat = Twine(FA.Text) + text;
+ FA.Text = copyString(Twine(FA.Text) + text);
- FA.Text = copyString(concat);
return true;
}
@@ -160,7 +158,7 @@ void EditedSource::commitRemove(SourceLocation OrigLoc,
}
FileOffset TopBegin, TopEnd;
- FileEdit *TopFA = 0;
+ FileEdit *TopFA = nullptr;
if (I == FileEdits.end()) {
FileEditsTy::iterator
diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp
index f4206fbd8f4f..666844c65ffc 100644
--- a/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -58,7 +58,7 @@ static bool checkForLiteralCreation(const ObjCMessageExpr *Msg,
bool edit::rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit) {
- IdentifierInfo *II = 0;
+ IdentifierInfo *II = nullptr;
if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
return false;
if (Msg->getNumArgs() != 1)
@@ -339,7 +339,7 @@ static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit,
const ParentMap *PMap) {
- IdentifierInfo *II = 0;
+ IdentifierInfo *II = nullptr;
if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
return false;
@@ -447,7 +447,7 @@ static bool getNSArrayObjects(const Expr *E, const NSAPI &NS,
return false;
if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {
- IdentifierInfo *Cls = 0;
+ IdentifierInfo *Cls = nullptr;
if (!checkForLiteralCreation(Msg, Cls, NS.getASTContext().getLangOpts()))
return false;
@@ -606,7 +606,7 @@ static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
if (!Msg)
return false;
- IdentifierInfo *II = 0;
+ IdentifierInfo *II = nullptr;
if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
return false;
@@ -1033,6 +1033,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
case CK_IntegralComplexToReal:
case CK_IntegralComplexToBoolean:
case CK_AtomicToNonAtomic:
+ case CK_AddressSpaceConversion:
needsCast = true;
break;
diff --git a/lib/Format/BreakableToken.cpp b/lib/Format/BreakableToken.cpp
index d720ce990b52..1bea0e565131 100644
--- a/lib/Format/BreakableToken.cpp
+++ b/lib/Format/BreakableToken.cpp
@@ -13,8 +13,6 @@
///
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "format-token-breaker"
-
#include "BreakableToken.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Format/Format.h"
@@ -22,6 +20,8 @@
#include "llvm/Support/Debug.h"
#include <algorithm>
+#define DEBUG_TYPE "format-token-breaker"
+
namespace clang {
namespace format {
@@ -82,19 +82,15 @@ static BreakableToken::Split getCommentSplit(StringRef Text,
return BreakableToken::Split(StringRef::npos, 0);
}
-static BreakableToken::Split getStringSplit(StringRef Text,
- unsigned UsedColumns,
- unsigned ColumnLimit,
- unsigned TabWidth,
- encoding::Encoding Encoding) {
+static BreakableToken::Split
+getStringSplit(StringRef Text, unsigned UsedColumns, unsigned ColumnLimit,
+ unsigned TabWidth, encoding::Encoding Encoding) {
// FIXME: Reduce unit test case.
if (Text.empty())
return BreakableToken::Split(StringRef::npos, 0);
if (ColumnLimit <= UsedColumns)
return BreakableToken::Split(StringRef::npos, 0);
- unsigned MaxSplit = std::min<unsigned>(
- ColumnLimit - UsedColumns,
- encoding::columnWidthWithTabs(Text, UsedColumns, TabWidth, Encoding) - 1);
+ unsigned MaxSplit = ColumnLimit - UsedColumns;
StringRef::size_type SpaceOffset = 0;
StringRef::size_type SlashOffset = 0;
StringRef::size_type WordStartOffset = 0;
@@ -110,7 +106,7 @@ static BreakableToken::Split getStringSplit(StringRef Text,
Text.substr(0, Advance), UsedColumns + Chars, TabWidth, Encoding);
}
- if (Chars > MaxSplit)
+ if (Chars > MaxSplit || Text.size() == Advance)
break;
if (IsBlank(Text[0]))
@@ -151,7 +147,7 @@ BreakableSingleLineToken::BreakableSingleLineToken(
encoding::Encoding Encoding, const FormatStyle &Style)
: BreakableToken(Tok, IndentLevel, InPPDirective, Encoding, Style),
StartColumn(StartColumn), Prefix(Prefix), Postfix(Postfix) {
- assert(Tok.TokenText.startswith(Prefix) && Tok.TokenText.endswith(Postfix));
+ assert(Tok.TokenText.endswith(Postfix));
Line = Tok.TokenText.substr(
Prefix.size(), Tok.TokenText.size() - Prefix.size() - Postfix.size());
}
@@ -174,24 +170,38 @@ BreakableStringLiteral::getSplit(unsigned LineIndex, unsigned TailOffset,
void BreakableStringLiteral::insertBreak(unsigned LineIndex,
unsigned TailOffset, Split Split,
WhitespaceManager &Whitespaces) {
+ unsigned LeadingSpaces = StartColumn;
+ // The '@' of an ObjC string literal (@"Test") does not become part of the
+ // string token.
+ // FIXME: It might be a cleaner solution to merge the tokens as a
+ // precomputation step.
+ if (Prefix.startswith("@"))
+ --LeadingSpaces;
Whitespaces.replaceWhitespaceInToken(
Tok, Prefix.size() + TailOffset + Split.first, Split.second, Postfix,
- Prefix, InPPDirective, 1, IndentLevel, StartColumn);
+ Prefix, InPPDirective, 1, IndentLevel, LeadingSpaces);
}
-static StringRef getLineCommentPrefix(StringRef Comment) {
- static const char *const KnownPrefixes[] = { "/// ", "///", "// ", "//" };
- for (size_t i = 0, e = llvm::array_lengthof(KnownPrefixes); i != e; ++i)
- if (Comment.startswith(KnownPrefixes[i]))
- return KnownPrefixes[i];
- return "";
+static StringRef getLineCommentIndentPrefix(StringRef Comment) {
+ static const char *const KnownPrefixes[] = { "///", "//" };
+ StringRef LongestPrefix;
+ for (StringRef KnownPrefix : KnownPrefixes) {
+ if (Comment.startswith(KnownPrefix)) {
+ size_t PrefixLength = KnownPrefix.size();
+ while (PrefixLength < Comment.size() && Comment[PrefixLength] == ' ')
+ ++PrefixLength;
+ if (PrefixLength > LongestPrefix.size())
+ LongestPrefix = Comment.substr(0, PrefixLength);
+ }
+ }
+ return LongestPrefix;
}
BreakableLineComment::BreakableLineComment(
const FormatToken &Token, unsigned IndentLevel, unsigned StartColumn,
bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style)
: BreakableSingleLineToken(Token, IndentLevel, StartColumn,
- getLineCommentPrefix(Token.TokenText), "",
+ getLineCommentIndentPrefix(Token.TokenText), "",
InPPDirective, Encoding, Style) {
OriginalPrefix = Prefix;
if (Token.TokenText.size() > Prefix.size() &&
@@ -337,11 +347,10 @@ void BreakableBlockComment::adjustWhitespace(unsigned LineIndex,
LeadingWhitespace[LineIndex] =
Lines[LineIndex].begin() - Lines[LineIndex - 1].end();
- // Adjust the start column uniformly accross all lines.
- StartOfLineColumn[LineIndex] = std::max<int>(
- 0,
+ // Adjust the start column uniformly across all lines.
+ StartOfLineColumn[LineIndex] =
encoding::columnWidthWithTabs(Whitespace, 0, Style.TabWidth, Encoding) +
- IndentDelta);
+ IndentDelta;
}
unsigned BreakableBlockComment::getLineCount() const { return Lines.size(); }
@@ -425,7 +434,6 @@ BreakableBlockComment::replaceWhitespaceBefore(unsigned LineIndex,
unsigned WhitespaceOffsetInToken = Lines[LineIndex].data() -
Tok.TokenText.data() -
LeadingWhitespace[LineIndex];
- assert(StartOfLineColumn[LineIndex] >= Prefix.size());
Whitespaces.replaceWhitespaceInToken(
Tok, WhitespaceOffsetInToken, LeadingWhitespace[LineIndex], "", Prefix,
InPPDirective, 1, IndentLevel,
@@ -438,7 +446,7 @@ BreakableBlockComment::getContentStartColumn(unsigned LineIndex,
// If we break, we always break at the predefined indent.
if (TailOffset != 0)
return IndentAtLineBreak;
- return StartOfLineColumn[LineIndex];
+ return std::max(0, StartOfLineColumn[LineIndex]);
}
} // namespace format
diff --git a/lib/Format/BreakableToken.h b/lib/Format/BreakableToken.h
index b965190d54de..72bb1e4404ff 100644
--- a/lib/Format/BreakableToken.h
+++ b/lib/Format/BreakableToken.h
@@ -90,10 +90,9 @@ protected:
/// \c getSplit() needs to be implemented by child classes.
class BreakableSingleLineToken : public BreakableToken {
public:
- virtual unsigned getLineCount() const;
- virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
- unsigned TailOffset,
- StringRef::size_type Length) const;
+ unsigned getLineCount() const override;
+ unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset,
+ StringRef::size_type Length) const override;
protected:
BreakableSingleLineToken(const FormatToken &Tok, unsigned IndentLevel,
@@ -123,13 +122,12 @@ public:
StringRef Postfix, bool InPPDirective,
encoding::Encoding Encoding, const FormatStyle &Style);
- virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
- unsigned ColumnLimit) const;
- virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
- WhitespaceManager &Whitespaces);
- virtual void replaceWhitespace(unsigned LineIndex, unsigned TailOffset,
- Split Split,
- WhitespaceManager &Whitespaces) {}
+ Split getSplit(unsigned LineIndex, unsigned TailOffset,
+ unsigned ColumnLimit) const override;
+ void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) override;
+ void replaceWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) override {}
};
class BreakableLineComment : public BreakableSingleLineToken {
@@ -142,15 +140,14 @@ public:
unsigned StartColumn, bool InPPDirective,
encoding::Encoding Encoding, const FormatStyle &Style);
- virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
- unsigned ColumnLimit) const;
- virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
- WhitespaceManager &Whitespaces);
- virtual void replaceWhitespace(unsigned LineIndex, unsigned TailOffset,
- Split Split,
- WhitespaceManager &Whitespaces);
- virtual void replaceWhitespaceBefore(unsigned LineIndex,
- WhitespaceManager &Whitespaces);
+ Split getSplit(unsigned LineIndex, unsigned TailOffset,
+ unsigned ColumnLimit) const override;
+ void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) override;
+ void replaceWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) override;
+ void replaceWhitespaceBefore(unsigned LineIndex,
+ WhitespaceManager &Whitespaces) override;
private:
// The prefix without an additional space if one was added.
@@ -170,19 +167,17 @@ public:
bool FirstInLine, bool InPPDirective,
encoding::Encoding Encoding, const FormatStyle &Style);
- virtual unsigned getLineCount() const;
- virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
- unsigned TailOffset,
- StringRef::size_type Length) const;
- virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
- unsigned ColumnLimit) const;
- virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
- WhitespaceManager &Whitespaces);
- virtual void replaceWhitespace(unsigned LineIndex, unsigned TailOffset,
- Split Split,
- WhitespaceManager &Whitespaces);
- virtual void replaceWhitespaceBefore(unsigned LineIndex,
- WhitespaceManager &Whitespaces);
+ unsigned getLineCount() const override;
+ unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset,
+ StringRef::size_type Length) const override;
+ Split getSplit(unsigned LineIndex, unsigned TailOffset,
+ unsigned ColumnLimit) const override;
+ void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) override;
+ void replaceWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) override;
+ void replaceWhitespaceBefore(unsigned LineIndex,
+ WhitespaceManager &Whitespaces) override;
private:
// Rearranges the whitespace between Lines[LineIndex-1] and Lines[LineIndex],
@@ -217,7 +212,7 @@ private:
// StartOfLineColumn[i] is the target column at which Line[i] should be.
// Note that this excludes a leading "* " or "*" in case all lines have
// a "*" prefix.
- SmallVector<unsigned, 16> StartOfLineColumn;
+ SmallVector<int, 16> StartOfLineColumn;
// The column at which the text of a broken line should start.
// Note that an optional decoration would go before that column.
diff --git a/lib/Format/CMakeLists.txt b/lib/Format/CMakeLists.txt
index e3ef5bd21ee9..47e15bd08a3f 100644
--- a/lib/Format/CMakeLists.txt
+++ b/lib/Format/CMakeLists.txt
@@ -8,23 +8,9 @@ add_clang_library(clangFormat
TokenAnnotator.cpp
UnwrappedLineParser.cpp
WhitespaceManager.cpp
- )
-
-add_dependencies(clangFormat
- ClangAttrClasses
- ClangAttrList
- ClangDeclNodes
- ClangDiagnosticCommon
- ClangDiagnosticFrontend
- ClangStmtNodes
- )
-target_link_libraries(clangFormat
+ LINK_LIBS
clangBasic
- clangFrontend
- clangAST
- clangASTMatchers
- clangRewriteCore
- clangRewriteFrontend
+ clangLex
clangTooling
)
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
index 971acc2b7a3c..014c30e346ad 100644
--- a/lib/Format/ContinuationIndenter.cpp
+++ b/lib/Format/ContinuationIndenter.cpp
@@ -12,8 +12,6 @@
///
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "format-formatter"
-
#include "BreakableToken.h"
#include "ContinuationIndenter.h"
#include "WhitespaceManager.h"
@@ -23,13 +21,15 @@
#include "llvm/Support/Debug.h"
#include <string>
+#define DEBUG_TYPE "format-formatter"
+
namespace clang {
namespace format {
// Returns the length of everything up to the first possible line break after
// the ), ], } or > matching \c Tok.
static unsigned getLengthToMatchingParen(const FormatToken &Tok) {
- if (Tok.MatchingParen == NULL)
+ if (!Tok.MatchingParen)
return 0;
FormatToken *End = Tok.MatchingParen;
while (End->Next && !End->Next->CanBreakBefore) {
@@ -63,7 +63,8 @@ ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style,
bool BinPackInconclusiveFunctions)
: Style(Style), SourceMgr(SourceMgr), Whitespaces(Whitespaces),
Encoding(Encoding),
- BinPackInconclusiveFunctions(BinPackInconclusiveFunctions) {}
+ BinPackInconclusiveFunctions(BinPackInconclusiveFunctions),
+ CommentPragmasRegex(Style.CommentPragmas) {}
LineState ContinuationIndenter::getInitialState(unsigned FirstIndent,
const AnnotatedLine *Line,
@@ -77,10 +78,9 @@ LineState ContinuationIndenter::getInitialState(unsigned FirstIndent,
/*AvoidBinPacking=*/false,
/*NoLineBreak=*/false));
State.LineContainsContinuedForLoopSection = false;
- State.ParenLevel = 0;
State.StartOfStringLiteral = 0;
- State.StartOfLineLevel = State.ParenLevel;
- State.LowestLevelOnLine = State.ParenLevel;
+ State.StartOfLineLevel = 0;
+ State.LowestLevelOnLine = 0;
State.IgnoreStackForComparison = false;
// The first token has already been indented and thus consumed.
@@ -98,8 +98,8 @@ bool ContinuationIndenter::canBreak(const LineState &State) {
// The opening "{" of a braced list has to be on the same line as the first
// element if it is nested in another braced init list or function call.
if (!Current.MustBreakBefore && Previous.is(tok::l_brace) &&
- Previous.Type != TT_DictLiteral &&
- Previous.BlockKind == BK_BracedInit && Previous.Previous &&
+ Previous.Type != TT_DictLiteral && Previous.BlockKind == BK_BracedInit &&
+ Previous.Previous &&
Previous.Previous->isOneOf(tok::l_brace, tok::l_paren, tok::comma))
return false;
// This prevents breaks like:
@@ -107,10 +107,21 @@ bool ContinuationIndenter::canBreak(const LineState &State) {
// SomeParameter, OtherParameter).DoSomething(
// ...
// As they hide "DoSomething" and are generally bad for readability.
- if (Previous.opensScope() && State.LowestLevelOnLine < State.StartOfLineLevel)
+ if (Previous.opensScope() && Previous.isNot(tok::l_brace) &&
+ State.LowestLevelOnLine < State.StartOfLineLevel &&
+ State.LowestLevelOnLine < Current.NestingLevel)
return false;
if (Current.isMemberAccess() && State.Stack.back().ContainsUnwrappedBuilder)
return false;
+
+ // Don't create a 'hanging' indent if there are multiple blocks in a single
+ // statement.
+ if (Style.Language == FormatStyle::LK_JavaScript &&
+ Previous.is(tok::l_brace) && State.Stack.size() > 1 &&
+ State.Stack[State.Stack.size() - 2].JSFunctionInlined &&
+ State.Stack[State.Stack.size() - 2].HasMultipleNestedBlocks)
+ return false;
+
return !State.Stack.back().NoLineBreak;
}
@@ -136,13 +147,21 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
if (Style.AlwaysBreakBeforeMultilineStrings &&
State.Column > State.Stack.back().Indent && // Breaking saves columns.
!Previous.isOneOf(tok::kw_return, tok::lessless, tok::at) &&
- Previous.Type != TT_InlineASMColon && NextIsMultilineString(State))
+ Previous.Type != TT_InlineASMColon &&
+ Previous.Type != TT_ConditionalExpr && nextIsMultilineString(State))
return true;
if (((Previous.Type == TT_DictLiteral && Previous.is(tok::l_brace)) ||
Previous.Type == TT_ArrayInitializerLSquare) &&
+ Style.ColumnLimit > 0 &&
getLengthToMatchingParen(Previous) + State.Column > getColumnLimit(State))
return true;
+ if (Current.Type == TT_CtorInitializerColon &&
+ ((Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All) ||
+ Style.BreakConstructorInitializersBeforeComma || Style.ColumnLimit != 0))
+ return true;
+ if (State.Column < getNewLineColumn(State))
+ return false;
if (!Style.BreakBeforeBinaryOperators) {
// If we need to break somewhere inside the LHS of a binary expression, we
// should also break after the operator. Otherwise, the formatting would
@@ -165,38 +184,45 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
if (Previous.Type == TT_BinaryOperator &&
(!IsComparison || LHSIsBinaryExpr) &&
Current.Type != TT_BinaryOperator && // For >>.
- !Current.isTrailingComment() &&
- !Previous.isOneOf(tok::lessless, tok::question) &&
+ !Current.isTrailingComment() && !Previous.is(tok::lessless) &&
Previous.getPrecedence() != prec::Assignment &&
State.Stack.back().BreakBeforeParameter)
return true;
}
// Same as above, but for the first "<<" operator.
- if (Current.is(tok::lessless) && State.Stack.back().BreakBeforeParameter &&
+ if (Current.is(tok::lessless) && Current.Type != TT_OverloadedOperator &&
+ State.Stack.back().BreakBeforeParameter &&
State.Stack.back().FirstLessLess == 0)
return true;
- // FIXME: Comparing LongestObjCSelectorName to 0 is a hacky way of finding
- // out whether it is the first parameter. Clean this up.
- if (Current.Type == TT_ObjCSelectorName &&
- Current.LongestObjCSelectorName == 0 &&
+ if (Current.Type == TT_SelectorName &&
+ State.Stack.back().ObjCSelectorNameFound &&
State.Stack.back().BreakBeforeParameter)
return true;
- if ((Current.Type == TT_CtorInitializerColon ||
- (Previous.ClosesTemplateDeclaration && State.ParenLevel == 0 &&
- !Current.isTrailingComment())))
+ if (Previous.ClosesTemplateDeclaration && Current.NestingLevel == 0 &&
+ !Current.isTrailingComment())
return true;
- if ((Current.Type == TT_StartOfName || Current.is(tok::kw_operator)) &&
- State.Line->MightBeFunctionDecl &&
- State.Stack.back().BreakBeforeParameter && State.ParenLevel == 0)
+ // If the return type spans multiple lines, wrap before the function name.
+ if ((Current.Type == TT_FunctionDeclarationName ||
+ Current.is(tok::kw_operator)) &&
+ State.Stack.back().BreakBeforeParameter)
return true;
+
if (startsSegmentOfBuilderTypeCall(Current) &&
(State.Stack.back().CallContinuation != 0 ||
(State.Stack.back().BreakBeforeParameter &&
State.Stack.back().ContainsUnwrappedBuilder)))
return true;
+
+ // The following could be precomputed as they do not depend on the state.
+ // However, as they should take effect only if the UnwrappedLine does not fit
+ // into the ColumnLimit, they are checked here in the ContinuationIndenter.
+ if (Style.ColumnLimit != 0 && Previous.BlockKind == BK_Block &&
+ Previous.is(tok::l_brace) && !Current.isOneOf(tok::r_brace, tok::comment))
+ return true;
+
return false;
}
@@ -205,9 +231,9 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline,
unsigned ExtraSpaces) {
const FormatToken &Current = *State.NextToken;
- if (State.Stack.size() == 0 ||
- (Current.Type == TT_ImplicitStringLiteral &&
- (Current.Previous->Tok.getIdentifierInfo() == NULL ||
+ assert(!State.Stack.empty());
+ if ((Current.Type == TT_ImplicitStringLiteral &&
+ (Current.Previous->Tok.getIdentifierInfo() == nullptr ||
Current.Previous->Tok.getIdentifierInfo()->getPPKeywordID() ==
tok::pp_not_keyword))) {
// FIXME: Is this correct?
@@ -215,8 +241,8 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline,
State.NextToken->WhitespaceRange.getEnd()) -
SourceMgr.getSpellingColumnNumber(
State.NextToken->WhitespaceRange.getBegin());
- State.Column += WhitespaceLength + State.NextToken->ColumnWidth;
- State.NextToken = State.NextToken->Next;
+ State.Column += WhitespaceLength;
+ moveStateToNextToken(State, DryRun, /*Newline=*/false);
return 0;
}
@@ -234,7 +260,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *State.NextToken->Previous;
if (Current.is(tok::equal) &&
- (State.Line->First->is(tok::kw_for) || State.ParenLevel == 0) &&
+ (State.Line->First->is(tok::kw_for) || Current.NestingLevel == 0) &&
State.Stack.back().VariablePos == 0) {
State.Stack.back().VariablePos = State.Column;
// Move over * and & if they are bound to the variable name.
@@ -255,9 +281,12 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, /*IndentLevel=*/0,
Spaces, State.Column + Spaces);
- if (Current.Type == TT_ObjCSelectorName && State.Stack.back().ColonPos == 0) {
- if (State.Stack.back().Indent + Current.LongestObjCSelectorName >
- State.Column + Spaces + Current.ColumnWidth)
+ if (Current.Type == TT_SelectorName &&
+ !State.Stack.back().ObjCSelectorNameFound) {
+ if (Current.LongestObjCSelectorName == 0)
+ State.Stack.back().AlignColons = false;
+ else if (State.Stack.back().Indent + Current.LongestObjCSelectorName >
+ State.Column + Spaces + Current.ColumnWidth)
State.Stack.back().ColonPos =
State.Stack.back().Indent + Current.LongestObjCSelectorName;
else
@@ -265,7 +294,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
}
if (Previous.opensScope() && Previous.Type != TT_ObjCMethodExpr &&
- Current.Type != TT_LineComment)
+ (Current.Type != TT_LineComment || Previous.BlockKind == BK_BracedInit))
State.Stack.back().Indent = State.Column + Spaces;
if (State.Stack.back().AvoidBinPacking && startsNextParameter(Current, Style))
State.Stack.back().NoLineBreak = true;
@@ -273,17 +302,21 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
State.Stack.back().ContainsUnwrappedBuilder = true;
State.Column += Spaces;
- if (Current.is(tok::l_paren) && Previous.isOneOf(tok::kw_if, tok::kw_for))
+ if (Current.isNot(tok::comment) && Previous.is(tok::l_paren) &&
+ Previous.Previous && Previous.Previous->isOneOf(tok::kw_if, tok::kw_for))
// Treat the condition inside an if as if it was a second function
// parameter, i.e. let nested calls have a continuation indent.
- State.Stack.back().LastSpace = State.Column + 1; // 1 is length of "(".
- else if (Previous.is(tok::comma) || Previous.Type == TT_ObjCMethodExpr)
+ State.Stack.back().LastSpace = State.Column;
+ else if (!Current.isOneOf(tok::comment, tok::caret) &&
+ (Previous.is(tok::comma) ||
+ (Previous.is(tok::colon) && Previous.Type == TT_ObjCMethodExpr)))
State.Stack.back().LastSpace = State.Column;
else if ((Previous.Type == TT_BinaryOperator ||
Previous.Type == TT_ConditionalExpr ||
- Previous.Type == TT_UnaryOperator ||
Previous.Type == TT_CtorInitializerColon) &&
- (Previous.getPrecedence() != prec::Assignment ||
+ ((Previous.getPrecedence() != prec::Assignment &&
+ (Previous.isNot(tok::lessless) || Previous.OperatorIndex != 0 ||
+ !Previous.LastOperator)) ||
Current.StartsBinaryExpression))
// Always indent relative to the RHS of the expression unless this is a
// simple assignment without binary expression on the RHS. Also indent
@@ -313,17 +346,16 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
bool DryRun) {
FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *State.NextToken->Previous;
- // If we are continuing an expression, we want to use the continuation indent.
- unsigned ContinuationIndent =
- std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) +
- Style.ContinuationIndentWidth;
+
// Extra penalty that needs to be added because of the way certain line
// breaks are chosen.
unsigned Penalty = 0;
- const FormatToken *PreviousNonComment =
- State.NextToken->getPreviousNonComment();
- // The first line break on any ParenLevel causes an extra penalty in order
+ const FormatToken *PreviousNonComment = Current.getPreviousNonComment();
+ const FormatToken *NextNonComment = Previous.getNextNonComment();
+ if (!NextNonComment)
+ NextNonComment = &Current;
+ // The first line break on any NestingLevel causes an extra penalty in order
// prefer similar line breaks.
if (!State.Stack.back().ContainsLineBreak)
Penalty += 15;
@@ -332,96 +364,61 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
Penalty += State.NextToken->SplitPenalty;
// Breaking before the first "<<" is generally not desirable if the LHS is
- // short.
- if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess == 0 &&
- State.Column <= Style.ColumnLimit / 2)
+ // short. Also always add the penalty if the LHS is split over mutliple lines
+ // to avoid unnecessary line breaks that just work around this penalty.
+ if (NextNonComment->is(tok::lessless) &&
+ State.Stack.back().FirstLessLess == 0 &&
+ (State.Column <= Style.ColumnLimit / 3 ||
+ State.Stack.back().BreakBeforeParameter))
Penalty += Style.PenaltyBreakFirstLessLess;
- if (Current.is(tok::l_brace) && Current.BlockKind == BK_Block) {
- State.Column = State.FirstIndent;
- } else if (Current.isOneOf(tok::r_brace, tok::r_square)) {
- if (Current.closesBlockTypeList(Style) ||
- (Current.MatchingParen &&
- Current.MatchingParen->BlockKind == BK_BracedInit))
- State.Column = State.Stack[State.Stack.size() - 2].LastSpace;
- else
- State.Column = State.FirstIndent;
- } else if (Current.is(tok::string_literal) &&
- State.StartOfStringLiteral != 0) {
- State.Column = State.StartOfStringLiteral;
- State.Stack.back().BreakBeforeParameter = true;
- } else if (Current.is(tok::lessless) &&
- State.Stack.back().FirstLessLess != 0) {
- State.Column = State.Stack.back().FirstLessLess;
- } else if (Current.isMemberAccess()) {
- if (State.Stack.back().CallContinuation == 0) {
- State.Column = ContinuationIndent;
+ State.Column = getNewLineColumn(State);
+ if (NextNonComment->isMemberAccess()) {
+ if (State.Stack.back().CallContinuation == 0)
State.Stack.back().CallContinuation = State.Column;
- } else {
- State.Column = State.Stack.back().CallContinuation;
- }
- } else if (State.Stack.back().QuestionColumn != 0 &&
- (Current.Type == TT_ConditionalExpr ||
- Previous.Type == TT_ConditionalExpr)) {
- State.Column = State.Stack.back().QuestionColumn;
- } else if (Previous.is(tok::comma) && State.Stack.back().VariablePos != 0) {
- State.Column = State.Stack.back().VariablePos;
- } else if ((PreviousNonComment &&
- PreviousNonComment->ClosesTemplateDeclaration) ||
- ((Current.Type == TT_StartOfName ||
- Current.is(tok::kw_operator)) &&
- State.ParenLevel == 0 &&
- (!Style.IndentFunctionDeclarationAfterType ||
- State.Line->StartsDefinition))) {
- State.Column = State.Stack.back().Indent;
- } else if (Current.Type == TT_ObjCSelectorName) {
- if (State.Stack.back().ColonPos == 0) {
- State.Stack.back().ColonPos =
- State.Stack.back().Indent + Current.LongestObjCSelectorName;
- State.Column = State.Stack.back().ColonPos - Current.ColumnWidth;
- } else if (State.Stack.back().ColonPos > Current.ColumnWidth) {
- State.Column = State.Stack.back().ColonPos - Current.ColumnWidth;
- } else {
- State.Column = State.Stack.back().Indent;
- State.Stack.back().ColonPos = State.Column + Current.ColumnWidth;
+ } else if (NextNonComment->Type == TT_SelectorName) {
+ if (!State.Stack.back().ObjCSelectorNameFound) {
+ if (NextNonComment->LongestObjCSelectorName == 0) {
+ State.Stack.back().AlignColons = false;
+ } else {
+ State.Stack.back().ColonPos =
+ State.Stack.back().Indent + NextNonComment->LongestObjCSelectorName;
+ }
+ } else if (State.Stack.back().AlignColons &&
+ State.Stack.back().ColonPos <= NextNonComment->ColumnWidth) {
+ State.Stack.back().ColonPos = State.Column + NextNonComment->ColumnWidth;
}
- } else if (Current.Type == TT_ArraySubscriptLSquare) {
- if (State.Stack.back().StartOfArraySubscripts != 0)
- State.Column = State.Stack.back().StartOfArraySubscripts;
- else
- State.Column = ContinuationIndent;
- } else if (Current.Type == TT_StartOfName ||
- Previous.isOneOf(tok::coloncolon, tok::equal) ||
- Previous.Type == TT_ObjCMethodExpr) {
- State.Column = ContinuationIndent;
- } else if (Current.Type == TT_CtorInitializerColon) {
- State.Column = State.FirstIndent + Style.ConstructorInitializerIndentWidth;
- } else if (Current.Type == TT_CtorInitializerComma) {
- State.Column = State.Stack.back().Indent;
- } else {
- State.Column = State.Stack.back().Indent;
- // Ensure that we fall back to the continuation indent width instead of just
- // flushing continuations left.
- if (State.Column == State.FirstIndent &&
- PreviousNonComment->isNot(tok::r_brace))
- State.Column += Style.ContinuationIndentWidth;
+ } else if (PreviousNonComment && PreviousNonComment->is(tok::colon) &&
+ (PreviousNonComment->Type == TT_ObjCMethodExpr ||
+ PreviousNonComment->Type == TT_DictLiteral)) {
+ // FIXME: This is hacky, find a better way. The problem is that in an ObjC
+ // method expression, the block should be aligned to the line starting it,
+ // e.g.:
+ // [aaaaaaaaaaaaaaa aaaaaaaaa: \\ break for some reason
+ // ^(int *i) {
+ // // ...
+ // }];
+ // Thus, we set LastSpace of the next higher NestingLevel, to which we move
+ // when we consume all of the "}"'s FakeRParens at the "{".
+ if (State.Stack.size() > 1)
+ State.Stack[State.Stack.size() - 2].LastSpace =
+ std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) +
+ Style.ContinuationIndentWidth;
}
if ((Previous.isOneOf(tok::comma, tok::semi) &&
!State.Stack.back().AvoidBinPacking) ||
Previous.Type == TT_BinaryOperator)
State.Stack.back().BreakBeforeParameter = false;
- if (Previous.Type == TT_TemplateCloser && State.ParenLevel == 0)
+ if (Previous.Type == TT_TemplateCloser && Current.NestingLevel == 0)
State.Stack.back().BreakBeforeParameter = false;
- if (Current.is(tok::question) ||
+ if (NextNonComment->is(tok::question) ||
(PreviousNonComment && PreviousNonComment->is(tok::question)))
State.Stack.back().BreakBeforeParameter = true;
if (!DryRun) {
- unsigned Newlines = 1;
- if (Current.is(tok::comment))
- Newlines = std::max(Newlines, std::min(Current.NewlinesBefore,
- Style.MaxEmptyLinesToKeep + 1));
+ unsigned Newlines = std::max(
+ 1u, std::min(Current.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1));
Whitespaces.replaceWhitespace(Current, Newlines,
State.Stack.back().IndentLevel, State.Column,
State.Column, State.Line->InPPDirective);
@@ -429,51 +426,164 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
if (!Current.isTrailingComment())
State.Stack.back().LastSpace = State.Column;
- if (Current.isMemberAccess())
- State.Stack.back().LastSpace += Current.ColumnWidth;
- State.StartOfLineLevel = State.ParenLevel;
- State.LowestLevelOnLine = State.ParenLevel;
+ State.StartOfLineLevel = Current.NestingLevel;
+ State.LowestLevelOnLine = Current.NestingLevel;
// Any break on this level means that the parent level has been broken
// and we need to avoid bin packing there.
- for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) {
- State.Stack[i].BreakBeforeParameter = true;
+ bool JavaScriptFormat = Style.Language == FormatStyle::LK_JavaScript &&
+ Current.is(tok::r_brace) &&
+ State.Stack.size() > 1 &&
+ State.Stack[State.Stack.size() - 2].JSFunctionInlined;
+ if (!JavaScriptFormat) {
+ for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) {
+ State.Stack[i].BreakBeforeParameter = true;
+ }
}
+
if (PreviousNonComment &&
!PreviousNonComment->isOneOf(tok::comma, tok::semi) &&
PreviousNonComment->Type != TT_TemplateCloser &&
PreviousNonComment->Type != TT_BinaryOperator &&
- Current.Type != TT_BinaryOperator &&
- !PreviousNonComment->opensScope())
+ Current.Type != TT_BinaryOperator && !PreviousNonComment->opensScope())
State.Stack.back().BreakBeforeParameter = true;
// If we break after { or the [ of an array initializer, we should also break
// before the corresponding } or ].
- if (Previous.is(tok::l_brace) || Previous.Type == TT_ArrayInitializerLSquare)
+ if (PreviousNonComment &&
+ (PreviousNonComment->is(tok::l_brace) ||
+ PreviousNonComment->Type == TT_ArrayInitializerLSquare))
State.Stack.back().BreakBeforeClosingBrace = true;
if (State.Stack.back().AvoidBinPacking) {
// If we are breaking after '(', '{', '<', this is not bin packing
- // unless AllowAllParametersOfDeclarationOnNextLine is false.
+ // unless AllowAllParametersOfDeclarationOnNextLine is false or this is a
+ // dict/object literal.
if (!(Previous.isOneOf(tok::l_paren, tok::l_brace) ||
Previous.Type == TT_BinaryOperator) ||
(!Style.AllowAllParametersOfDeclarationOnNextLine &&
- State.Line->MustBeDeclaration))
+ State.Line->MustBeDeclaration) ||
+ Previous.Type == TT_DictLiteral)
State.Stack.back().BreakBeforeParameter = true;
}
return Penalty;
}
+unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
+ if (!State.NextToken || !State.NextToken->Previous)
+ return 0;
+ FormatToken &Current = *State.NextToken;
+ const FormatToken &Previous = *State.NextToken->Previous;
+ // If we are continuing an expression, we want to use the continuation indent.
+ unsigned ContinuationIndent =
+ std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) +
+ Style.ContinuationIndentWidth;
+ const FormatToken *PreviousNonComment = Current.getPreviousNonComment();
+ const FormatToken *NextNonComment = Previous.getNextNonComment();
+ if (!NextNonComment)
+ NextNonComment = &Current;
+ if (NextNonComment->is(tok::l_brace) && NextNonComment->BlockKind == BK_Block)
+ return Current.NestingLevel == 0 ? State.FirstIndent
+ : State.Stack.back().Indent;
+ if (Current.isOneOf(tok::r_brace, tok::r_square)) {
+ if (State.Stack.size() > 1 &&
+ State.Stack[State.Stack.size() - 2].JSFunctionInlined)
+ return State.FirstIndent;
+ if (Current.closesBlockTypeList(Style) ||
+ (Current.MatchingParen &&
+ Current.MatchingParen->BlockKind == BK_BracedInit))
+ return State.Stack[State.Stack.size() - 2].LastSpace;
+ else
+ return State.FirstIndent;
+ }
+ if (Current.is(tok::identifier) && Current.Next &&
+ Current.Next->Type == TT_DictLiteral)
+ return State.Stack.back().Indent;
+ if (NextNonComment->isStringLiteral() && State.StartOfStringLiteral != 0)
+ return State.StartOfStringLiteral;
+ if (NextNonComment->is(tok::lessless) &&
+ State.Stack.back().FirstLessLess != 0)
+ return State.Stack.back().FirstLessLess;
+ if (NextNonComment->isMemberAccess()) {
+ if (State.Stack.back().CallContinuation == 0) {
+ return ContinuationIndent;
+ } else {
+ return State.Stack.back().CallContinuation;
+ }
+ }
+ if (State.Stack.back().QuestionColumn != 0 &&
+ ((NextNonComment->is(tok::colon) &&
+ NextNonComment->Type == TT_ConditionalExpr) ||
+ Previous.Type == TT_ConditionalExpr))
+ return State.Stack.back().QuestionColumn;
+ if (Previous.is(tok::comma) && State.Stack.back().VariablePos != 0)
+ return State.Stack.back().VariablePos;
+ if ((PreviousNonComment && (PreviousNonComment->ClosesTemplateDeclaration ||
+ PreviousNonComment->Type == TT_AttributeParen)) ||
+ (!Style.IndentWrappedFunctionNames &&
+ (NextNonComment->is(tok::kw_operator) ||
+ NextNonComment->Type == TT_FunctionDeclarationName)))
+ return std::max(State.Stack.back().LastSpace, State.Stack.back().Indent);
+ if (NextNonComment->Type == TT_SelectorName) {
+ if (!State.Stack.back().ObjCSelectorNameFound) {
+ if (NextNonComment->LongestObjCSelectorName == 0) {
+ return State.Stack.back().Indent;
+ } else {
+ return State.Stack.back().Indent +
+ NextNonComment->LongestObjCSelectorName -
+ NextNonComment->ColumnWidth;
+ }
+ } else if (!State.Stack.back().AlignColons) {
+ return State.Stack.back().Indent;
+ } else if (State.Stack.back().ColonPos > NextNonComment->ColumnWidth) {
+ return State.Stack.back().ColonPos - NextNonComment->ColumnWidth;
+ } else {
+ return State.Stack.back().Indent;
+ }
+ }
+ if (NextNonComment->Type == TT_ArraySubscriptLSquare) {
+ if (State.Stack.back().StartOfArraySubscripts != 0)
+ return State.Stack.back().StartOfArraySubscripts;
+ else
+ return ContinuationIndent;
+ }
+ if (NextNonComment->Type == TT_StartOfName ||
+ Previous.isOneOf(tok::coloncolon, tok::equal)) {
+ return ContinuationIndent;
+ }
+ if (PreviousNonComment && PreviousNonComment->is(tok::colon) &&
+ (PreviousNonComment->Type == TT_ObjCMethodExpr ||
+ PreviousNonComment->Type == TT_DictLiteral))
+ return ContinuationIndent;
+ if (NextNonComment->Type == TT_CtorInitializerColon)
+ return State.FirstIndent + Style.ConstructorInitializerIndentWidth;
+ if (NextNonComment->Type == TT_CtorInitializerComma)
+ return State.Stack.back().Indent;
+ if (State.Stack.back().Indent == State.FirstIndent && PreviousNonComment &&
+ PreviousNonComment->isNot(tok::r_brace))
+ // Ensure that we fall back to the continuation indent width instead of
+ // just flushing continuations left.
+ return State.Stack.back().Indent + Style.ContinuationIndentWidth;
+ return State.Stack.back().Indent;
+}
+
unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
bool DryRun, bool Newline) {
- const FormatToken &Current = *State.NextToken;
assert(State.Stack.size());
+ const FormatToken &Current = *State.NextToken;
if (Current.Type == TT_InheritanceColon)
State.Stack.back().AvoidBinPacking = true;
- if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess == 0)
- State.Stack.back().FirstLessLess = State.Column;
+ if (Current.is(tok::lessless) && Current.Type != TT_OverloadedOperator) {
+ if (State.Stack.back().FirstLessLess == 0)
+ State.Stack.back().FirstLessLess = State.Column;
+ else
+ State.Stack.back().LastOperatorWrapped = Newline;
+ }
+ if ((Current.Type == TT_BinaryOperator && Current.isNot(tok::lessless)) ||
+ Current.Type == TT_ConditionalExpr)
+ State.Stack.back().LastOperatorWrapped = Newline;
if (Current.Type == TT_ArraySubscriptLSquare &&
State.Stack.back().StartOfArraySubscripts == 0)
State.Stack.back().StartOfArraySubscripts = State.Column;
@@ -484,10 +594,12 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
State.Stack.back().QuestionColumn = State.Column;
if (!Current.opensScope() && !Current.closesScope())
State.LowestLevelOnLine =
- std::min(State.LowestLevelOnLine, State.ParenLevel);
+ std::min(State.LowestLevelOnLine, Current.NestingLevel);
if (Current.isMemberAccess())
State.Stack.back().StartOfFunctionCall =
- Current.LastInChainOfCalls ? 0 : State.Column + Current.ColumnWidth;
+ Current.LastOperator ? 0 : State.Column + Current.ColumnWidth;
+ if (Current.Type == TT_SelectorName)
+ State.Stack.back().ObjCSelectorNameFound = true;
if (Current.Type == TT_CtorInitializerColon) {
// Indent 2 from the column, so:
// SomeClass::SomeClass()
@@ -509,8 +621,67 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
// Insert scopes created by fake parenthesis.
const FormatToken *Previous = Current.getPreviousNonComment();
+
+ // Add special behavior to support a format commonly used for JavaScript
+ // closures:
+ // SomeFunction(function() {
+ // foo();
+ // bar();
+ // }, a, b, c);
+ if (Style.Language == FormatStyle::LK_JavaScript) {
+ if (Current.isNot(tok::comment) && Previous && Previous->is(tok::l_brace) &&
+ State.Stack.size() > 1) {
+ if (State.Stack[State.Stack.size() - 2].JSFunctionInlined && Newline) {
+ for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) {
+ State.Stack[i].NoLineBreak = true;
+ }
+ }
+ State.Stack[State.Stack.size() - 2].JSFunctionInlined = false;
+ }
+ if (Current.TokenText == "function")
+ State.Stack.back().JSFunctionInlined = !Newline;
+ }
+
+ moveStatePastFakeLParens(State, Newline);
+ moveStatePastScopeOpener(State, Newline);
+ moveStatePastScopeCloser(State);
+ moveStatePastFakeRParens(State);
+
+ if (Current.isStringLiteral() && State.StartOfStringLiteral == 0) {
+ State.StartOfStringLiteral = State.Column;
+ } else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash) &&
+ !Current.isStringLiteral()) {
+ State.StartOfStringLiteral = 0;
+ }
+
+ State.Column += Current.ColumnWidth;
+ State.NextToken = State.NextToken->Next;
+ unsigned Penalty = breakProtrudingToken(Current, State, DryRun);
+ if (State.Column > getColumnLimit(State)) {
+ unsigned ExcessCharacters = State.Column - getColumnLimit(State);
+ Penalty += Style.PenaltyExcessCharacter * ExcessCharacters;
+ }
+
+ if (Current.Role)
+ Current.Role->formatFromToken(State, this, DryRun);
+ // If the previous has a special role, let it consume tokens as appropriate.
+ // It is necessary to start at the previous token for the only implemented
+ // role (comma separated list). That way, the decision whether or not to break
+ // after the "{" is already done and both options are tried and evaluated.
+ // FIXME: This is ugly, find a better way.
+ if (Previous && Previous->Role)
+ Penalty += Previous->Role->formatAfterToken(State, this, DryRun);
+
+ return Penalty;
+}
+
+void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,
+ bool Newline) {
+ const FormatToken &Current = *State.NextToken;
+ const FormatToken *Previous = Current.getPreviousNonComment();
+
// Don't add extra indentation for the first fake parenthesis after
- // 'return', assignements or opening <({[. The indentation for these cases
+ // 'return', assignments or opening <({[. The indentation for these cases
// is special cased.
bool SkipFirstExtraIndent =
(Previous && (Previous->opensScope() || Previous->is(tok::kw_return) ||
@@ -531,6 +702,24 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
std::max(std::max(State.Column, NewParenState.Indent),
State.Stack.back().LastSpace);
+ // Don't allow the RHS of an operator to be split over multiple lines unless
+ // there is a line-break right after the operator.
+ // Exclude relational operators, as there, it is always more desirable to
+ // have the LHS 'left' of the RHS.
+ if (Previous && Previous->getPrecedence() > prec::Assignment &&
+ (Previous->Type == TT_BinaryOperator ||
+ Previous->Type == TT_ConditionalExpr) &&
+ Previous->getPrecedence() != prec::Relational) {
+ bool BreakBeforeOperator = Previous->is(tok::lessless) ||
+ (Previous->Type == TT_BinaryOperator &&
+ Style.BreakBeforeBinaryOperators) ||
+ (Previous->Type == TT_ConditionalExpr &&
+ Style.BreakBeforeTernaryOperators);
+ if ((!Newline && !BreakBeforeOperator) ||
+ (!State.Stack.back().LastOperatorWrapped && BreakBeforeOperator))
+ NewParenState.NoLineBreak = true;
+ }
+
// Do not indent relative to the fake parentheses inserted for "." or "->".
// This is a special case to make the following to statements consistent:
// OuterFunction(InnerFunctionCall( // break
@@ -539,6 +728,7 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
// ParameterToInnerFunction));
if (*I > prec::Unknown)
NewParenState.LastSpace = std::max(NewParenState.LastSpace, State.Column);
+ NewParenState.StartOfFunctionCall = State.Column;
// Always indent conditional expressions. Never indent expression where
// the 'operator' is ',', ';' or an assignment (i.e. *I <=
@@ -553,131 +743,160 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
State.Stack.push_back(NewParenState);
SkipFirstExtraIndent = false;
}
+}
- // If we encounter an opening (, [, { or <, we add a level to our stacks to
- // prepare for the following tokens.
- if (Current.opensScope()) {
- unsigned NewIndent;
- unsigned NewIndentLevel = State.Stack.back().IndentLevel;
- bool AvoidBinPacking;
- bool BreakBeforeParameter = false;
- if (Current.is(tok::l_brace) ||
- Current.Type == TT_ArrayInitializerLSquare) {
- if (Current.MatchingParen && Current.BlockKind == BK_Block) {
- // If this is an l_brace starting a nested block, we pretend (wrt. to
- // indentation) that we already consumed the corresponding r_brace.
- // Thus, we remove all ParenStates caused bake fake parentheses that end
- // at the r_brace. The net effect of this is that we don't indent
- // relative to the l_brace, if the nested block is the last parameter of
- // a function. For example, this formats:
- //
- // SomeFunction(a, [] {
- // f(); // break
- // });
- //
- // instead of:
- // SomeFunction(a, [] {
- // f(); // break
- // });
- for (unsigned i = 0; i != Current.MatchingParen->FakeRParens; ++i)
- State.Stack.pop_back();
- NewIndent = State.Stack.back().LastSpace + Style.IndentWidth;
- ++NewIndentLevel;
- BreakBeforeParameter = true;
- } else {
- NewIndent = State.Stack.back().LastSpace;
- if (Current.opensBlockTypeList(Style)) {
- NewIndent += Style.IndentWidth;
- ++NewIndentLevel;
- } else {
- NewIndent += Style.ContinuationIndentWidth;
- }
- }
- const FormatToken *NextNoComment = Current.getNextNonComment();
- AvoidBinPacking = Current.BlockKind == BK_Block ||
- Current.Type == TT_ArrayInitializerLSquare ||
- Current.Type == TT_DictLiteral ||
- (NextNoComment &&
- NextNoComment->Type == TT_DesignatedInitializerPeriod);
- } else {
- NewIndent = Style.ContinuationIndentWidth +
- std::max(State.Stack.back().LastSpace,
- State.Stack.back().StartOfFunctionCall);
- AvoidBinPacking = !Style.BinPackParameters ||
- (Style.ExperimentalAutoDetectBinPacking &&
- (Current.PackingKind == PPK_OnePerLine ||
- (!BinPackInconclusiveFunctions &&
- Current.PackingKind == PPK_Inconclusive)));
- // If this '[' opens an ObjC call, determine whether all parameters fit
- // into one line and put one per line if they don't.
- if (Current.Type == TT_ObjCMethodExpr &&
- getLengthToMatchingParen(Current) + State.Column >
- getColumnLimit(State))
- BreakBeforeParameter = true;
+// Remove the fake r_parens after 'Tok'.
+static void consumeRParens(LineState& State, const FormatToken &Tok) {
+ for (unsigned i = 0, e = Tok.FakeRParens; i != e; ++i) {
+ unsigned VariablePos = State.Stack.back().VariablePos;
+ assert(State.Stack.size() > 1);
+ if (State.Stack.size() == 1) {
+ // Do not pop the last element.
+ break;
}
+ State.Stack.pop_back();
+ State.Stack.back().VariablePos = VariablePos;
+ }
+}
+
+// Returns whether 'Tok' opens or closes a scope requiring special handling
+// of the subsequent fake r_parens.
+//
+// For example, if this is an l_brace starting a nested block, we pretend (wrt.
+// to indentation) that we already consumed the corresponding r_brace. Thus, we
+// remove all ParenStates caused by fake parentheses that end at the r_brace.
+// The net effect of this is that we don't indent relative to the l_brace, if
+// the nested block is the last parameter of a function. This formats:
+//
+// SomeFunction(a, [] {
+// f(); // break
+// });
+//
+// instead of:
+// SomeFunction(a, [] {
+// f(); // break
+// });
+static bool fakeRParenSpecialCase(const LineState &State) {
+ const FormatToken &Tok = *State.NextToken;
+ if (!Tok.MatchingParen)
+ return false;
+ const FormatToken *Left = &Tok;
+ if (Tok.isOneOf(tok::r_brace, tok::r_square))
+ Left = Tok.MatchingParen;
+ return !State.Stack.back().HasMultipleNestedBlocks &&
+ Left->isOneOf(tok::l_brace, tok::l_square) &&
+ (Left->BlockKind == BK_Block ||
+ Left->Type == TT_ArrayInitializerLSquare ||
+ Left->Type == TT_DictLiteral);
+}
+
+void ContinuationIndenter::moveStatePastFakeRParens(LineState &State) {
+ // Don't remove FakeRParens attached to r_braces that surround nested blocks
+ // as they will have been removed early (see above).
+ if (fakeRParenSpecialCase(State))
+ return;
+
+ consumeRParens(State, *State.NextToken);
+}
- bool NoLineBreak = State.Stack.back().NoLineBreak ||
- (Current.Type == TT_TemplateOpener &&
- State.Stack.back().ContainsUnwrappedBuilder);
- State.Stack.push_back(ParenState(NewIndent, NewIndentLevel,
- State.Stack.back().LastSpace,
- AvoidBinPacking, NoLineBreak));
- State.Stack.back().BreakBeforeParameter = BreakBeforeParameter;
- ++State.ParenLevel;
+void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
+ bool Newline) {
+ const FormatToken &Current = *State.NextToken;
+ if (!Current.opensScope())
+ return;
+
+ if (Current.MatchingParen && Current.BlockKind == BK_Block) {
+ moveStateToNewBlock(State);
+ return;
}
+ unsigned NewIndent;
+ unsigned NewIndentLevel = State.Stack.back().IndentLevel;
+ bool AvoidBinPacking;
+ bool BreakBeforeParameter = false;
+ if (Current.is(tok::l_brace) || Current.Type == TT_ArrayInitializerLSquare) {
+ if (fakeRParenSpecialCase(State))
+ consumeRParens(State, *Current.MatchingParen);
+
+ NewIndent = State.Stack.back().LastSpace;
+ if (Current.opensBlockTypeList(Style)) {
+ NewIndent += Style.IndentWidth;
+ NewIndent = std::min(State.Column + 2, NewIndent);
+ ++NewIndentLevel;
+ } else {
+ NewIndent += Style.ContinuationIndentWidth;
+ NewIndent = std::min(State.Column + 1, NewIndent);
+ }
+ const FormatToken *NextNoComment = Current.getNextNonComment();
+ AvoidBinPacking = Current.Type == TT_ArrayInitializerLSquare ||
+ Current.Type == TT_DictLiteral ||
+ Style.Language == FormatStyle::LK_Proto ||
+ !Style.BinPackParameters ||
+ (NextNoComment &&
+ NextNoComment->Type == TT_DesignatedInitializerPeriod);
+ } else {
+ NewIndent = Style.ContinuationIndentWidth +
+ std::max(State.Stack.back().LastSpace,
+ State.Stack.back().StartOfFunctionCall);
+ AvoidBinPacking = !Style.BinPackParameters ||
+ (Style.ExperimentalAutoDetectBinPacking &&
+ (Current.PackingKind == PPK_OnePerLine ||
+ (!BinPackInconclusiveFunctions &&
+ Current.PackingKind == PPK_Inconclusive)));
+ // If this '[' opens an ObjC call, determine whether all parameters fit
+ // into one line and put one per line if they don't.
+ if (Current.Type == TT_ObjCMethodExpr && Style.ColumnLimit != 0 &&
+ getLengthToMatchingParen(Current) + State.Column >
+ getColumnLimit(State))
+ BreakBeforeParameter = true;
+ }
+ bool NoLineBreak = State.Stack.back().NoLineBreak ||
+ (Current.Type == TT_TemplateOpener &&
+ State.Stack.back().ContainsUnwrappedBuilder);
+ State.Stack.push_back(ParenState(NewIndent, NewIndentLevel,
+ State.Stack.back().LastSpace,
+ AvoidBinPacking, NoLineBreak));
+ State.Stack.back().BreakBeforeParameter = BreakBeforeParameter;
+ State.Stack.back().HasMultipleNestedBlocks = Current.BlockParameterCount > 1;
+}
+
+void ContinuationIndenter::moveStatePastScopeCloser(LineState &State) {
+ const FormatToken &Current = *State.NextToken;
+ if (!Current.closesScope())
+ return;
+
// If we encounter a closing ), ], } or >, we can remove a level from our
// stacks.
if (State.Stack.size() > 1 &&
(Current.isOneOf(tok::r_paren, tok::r_square) ||
(Current.is(tok::r_brace) && State.NextToken != State.Line->First) ||
- State.NextToken->Type == TT_TemplateCloser)) {
+ State.NextToken->Type == TT_TemplateCloser))
State.Stack.pop_back();
- --State.ParenLevel;
- }
+
if (Current.is(tok::r_square)) {
// If this ends the array subscript expr, reset the corresponding value.
const FormatToken *NextNonComment = Current.getNextNonComment();
if (NextNonComment && NextNonComment->isNot(tok::l_square))
State.Stack.back().StartOfArraySubscripts = 0;
}
+}
- // Remove scopes created by fake parenthesis.
- if (Current.isNot(tok::r_brace) ||
- (Current.MatchingParen && Current.MatchingParen->BlockKind != BK_Block)) {
- // Don't remove FakeRParens attached to r_braces that surround nested blocks
- // as they will have been removed early (see above).
- for (unsigned i = 0, e = Current.FakeRParens; i != e; ++i) {
- unsigned VariablePos = State.Stack.back().VariablePos;
- State.Stack.pop_back();
- State.Stack.back().VariablePos = VariablePos;
- }
- }
-
- if (Current.is(tok::string_literal) && State.StartOfStringLiteral == 0) {
- State.StartOfStringLiteral = State.Column;
- } else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash,
- tok::string_literal)) {
- State.StartOfStringLiteral = 0;
- }
-
- State.Column += Current.ColumnWidth;
- State.NextToken = State.NextToken->Next;
- unsigned Penalty = breakProtrudingToken(Current, State, DryRun);
- if (State.Column > getColumnLimit(State)) {
- unsigned ExcessCharacters = State.Column - getColumnLimit(State);
- Penalty += Style.PenaltyExcessCharacter * ExcessCharacters;
- }
-
- // If the previous has a special role, let it consume tokens as appropriate.
- // It is necessary to start at the previous token for the only implemented
- // role (comma separated list). That way, the decision whether or not to break
- // after the "{" is already done and both options are tried and evaluated.
- // FIXME: This is ugly, find a better way.
- if (Previous && Previous->Role)
- Penalty += Previous->Role->format(State, this, DryRun);
-
- return Penalty;
+void ContinuationIndenter::moveStateToNewBlock(LineState &State) {
+ // If we have already found more than one lambda introducers on this level, we
+ // opt out of this because similarity between the lambdas is more important.
+ if (fakeRParenSpecialCase(State))
+ consumeRParens(State, *State.NextToken->MatchingParen);
+
+ // For some reason, ObjC blocks are indented like continuations.
+ unsigned NewIndent = State.Stack.back().LastSpace +
+ (State.NextToken->Type == TT_ObjCBlockLBrace
+ ? Style.ContinuationIndentWidth
+ : Style.IndentWidth);
+ State.Stack.push_back(ParenState(
+ NewIndent, /*NewIndentLevel=*/State.Stack.back().IndentLevel + 1,
+ State.Stack.back().LastSpace, /*AvoidBinPacking=*/true,
+ State.Stack.back().NoLineBreak));
+ State.Stack.back().BreakBeforeParameter = true;
}
unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current,
@@ -696,8 +915,7 @@ unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current,
return 0;
}
-static bool getRawStringLiteralPrefixPostfix(StringRef Text,
- StringRef &Prefix,
+static bool getRawStringLiteralPrefixPostfix(StringRef Text, StringRef &Prefix,
StringRef &Postfix) {
if (Text.startswith(Prefix = "R\"") || Text.startswith(Prefix = "uR\"") ||
Text.startswith(Prefix = "UR\"") || Text.startswith(Prefix = "u8R\"") ||
@@ -727,19 +945,14 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
if (Current.Type == TT_ImplicitStringLiteral)
return 0;
- if (!Current.isOneOf(tok::string_literal, tok::wide_string_literal,
- tok::utf8_string_literal, tok::utf16_string_literal,
- tok::utf32_string_literal, tok::comment))
+ if (!Current.isStringLiteral() && !Current.is(tok::comment))
return 0;
- llvm::OwningPtr<BreakableToken> Token;
+ std::unique_ptr<BreakableToken> Token;
unsigned StartColumn = State.Column - Current.ColumnWidth;
unsigned ColumnLimit = getColumnLimit(State);
- if (Current.isOneOf(tok::string_literal, tok::wide_string_literal,
- tok::utf8_string_literal, tok::utf16_string_literal,
- tok::utf32_string_literal) &&
- Current.Type != TT_ImplicitStringLiteral) {
+ if (Current.isStringLiteral()) {
// Don't break string literals inside preprocessor directives (except for
// #define directives, as their contents are stored in separate lines and
// are not affected by this check).
@@ -755,13 +968,20 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
StringRef Text = Current.TokenText;
StringRef Prefix;
StringRef Postfix;
+ bool IsNSStringLiteral = false;
// FIXME: Handle whitespace between '_T', '(', '"..."', and ')'.
// FIXME: Store Prefix and Suffix (or PrefixLength and SuffixLength to
// reduce the overhead) for each FormatToken, which is a string, so that we
// don't run multiple checks here on the hot path.
+ if (Text.startswith("\"") && Current.Previous &&
+ Current.Previous->is(tok::at)) {
+ IsNSStringLiteral = true;
+ Prefix = "@\"";
+ }
if ((Text.endswith(Postfix = "\"") &&
- (Text.startswith(Prefix = "\"") || Text.startswith(Prefix = "u\"") ||
- Text.startswith(Prefix = "U\"") || Text.startswith(Prefix = "u8\"") ||
+ (IsNSStringLiteral || Text.startswith(Prefix = "\"") ||
+ Text.startswith(Prefix = "u\"") || Text.startswith(Prefix = "U\"") ||
+ Text.startswith(Prefix = "u8\"") ||
Text.startswith(Prefix = "L\""))) ||
(Text.startswith(Prefix = "_T(\"") && Text.endswith(Postfix = "\")")) ||
getRawStringLiteralPrefixPostfix(Text, Prefix, Postfix)) {
@@ -772,12 +992,16 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
return 0;
}
} else if (Current.Type == TT_BlockComment && Current.isTrailingComment()) {
+ if (CommentPragmasRegex.match(Current.TokenText.substr(2)))
+ return 0;
Token.reset(new BreakableBlockComment(
Current, State.Line->Level, StartColumn, Current.OriginalColumn,
!Current.Previous, State.Line->InPPDirective, Encoding, Style));
} else if (Current.Type == TT_LineComment &&
- (Current.Previous == NULL ||
+ (Current.Previous == nullptr ||
Current.Previous->Type != TT_ImplicitStringLiteral)) {
+ if (CommentPragmasRegex.match(Current.TokenText.substr(2)))
+ return 0;
Token.reset(new BreakableLineComment(Current, State.Line->Level,
StartColumn, /*InPPDirective=*/false,
Encoding, Style));
@@ -822,6 +1046,12 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
break;
}
+ // When breaking before a tab character, it may be moved by a few columns,
+ // but will still be expanded to the next tab stop, so we don't save any
+ // columns.
+ if (NewRemainingTokenColumns == RemainingTokenColumns)
+ break;
+
assert(NewRemainingTokenColumns < RemainingTokenColumns);
if (!DryRun)
Token->insertBreak(LineIndex, TailOffset, Split, Whitespaces);
@@ -848,8 +1078,8 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
State.Stack[i].BreakBeforeParameter = true;
}
- Penalty += Current.is(tok::string_literal) ? Style.PenaltyBreakString
- : Style.PenaltyBreakComment;
+ Penalty += Current.isStringLiteral() ? Style.PenaltyBreakString
+ : Style.PenaltyBreakComment;
State.Stack.back().LastSpace = StartColumn;
}
@@ -861,18 +1091,19 @@ unsigned ContinuationIndenter::getColumnLimit(const LineState &State) const {
return Style.ColumnLimit - (State.Line->InPPDirective ? 2 : 0);
}
-bool ContinuationIndenter::NextIsMultilineString(const LineState &State) {
+bool ContinuationIndenter::nextIsMultilineString(const LineState &State) {
const FormatToken &Current = *State.NextToken;
- if (!Current.is(tok::string_literal))
+ if (!Current.isStringLiteral() || Current.Type == TT_ImplicitStringLiteral)
return false;
// We never consider raw string literals "multiline" for the purpose of
- // AlwaysBreakBeforeMultilineStrings implementation.
+ // AlwaysBreakBeforeMultilineStrings implementation as they are special-cased
+ // (see TokenAnnotator::mustBreakBefore().
if (Current.TokenText.startswith("R\""))
return false;
if (Current.IsMultiline)
return true;
if (Current.getNextNonComment() &&
- Current.getNextNonComment()->is(tok::string_literal))
+ Current.getNextNonComment()->isStringLiteral())
return true; // Implicit concatenation.
if (State.Column + Current.ColumnWidth + Current.UnbreakableTailLength >
Style.ColumnLimit)
diff --git a/lib/Format/ContinuationIndenter.h b/lib/Format/ContinuationIndenter.h
index b31756583389..0969a8cec983 100644
--- a/lib/Format/ContinuationIndenter.h
+++ b/lib/Format/ContinuationIndenter.h
@@ -18,6 +18,7 @@
#include "Encoding.h"
#include "clang/Format/Format.h"
+#include "llvm/Support/Regex.h"
namespace clang {
class SourceManager;
@@ -72,6 +73,18 @@ private:
/// accordingly.
unsigned moveStateToNextToken(LineState &State, bool DryRun, bool Newline);
+ /// \brief Update 'State' according to the next token's fake left parentheses.
+ void moveStatePastFakeLParens(LineState &State, bool Newline);
+ /// \brief Update 'State' according to the next token's fake r_parens.
+ void moveStatePastFakeRParens(LineState &State);
+
+ /// \brief Update 'State' according to the next token being one of "(<{[".
+ void moveStatePastScopeOpener(LineState &State, bool Newline);
+ /// \brief Update 'State' according to the next token being one of ")>}]".
+ void moveStatePastScopeCloser(LineState &State);
+ /// \brief Update 'State' with the next token opening a nested block.
+ void moveStateToNewBlock(LineState &State);
+
/// \brief If the current token sticks out over the end of the line, break
/// it if possible.
///
@@ -103,6 +116,9 @@ private:
/// \c Replacement.
unsigned addTokenOnNewLine(LineState &State, bool DryRun);
+ /// \brief Calculate the new column for a line wrap before the next token.
+ unsigned getNewLineColumn(const LineState &State);
+
/// \brief Adds a multiline token to the \p State.
///
/// \returns Extra penalty for the first line of the literal: last line is
@@ -115,13 +131,14 @@ private:
///
/// This includes implicitly concatenated strings, strings that will be broken
/// by clang-format and string literals with escaped newlines.
- bool NextIsMultilineString(const LineState &State);
+ bool nextIsMultilineString(const LineState &State);
FormatStyle Style;
SourceManager &SourceMgr;
WhitespaceManager &Whitespaces;
encoding::Encoding Encoding;
bool BinPackInconclusiveFunctions;
+ llvm::Regex CommentPragmasRegex;
};
struct ParenState {
@@ -130,10 +147,12 @@ struct ParenState {
: Indent(Indent), IndentLevel(IndentLevel), LastSpace(LastSpace),
FirstLessLess(0), BreakBeforeClosingBrace(false), QuestionColumn(0),
AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
- NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0),
- StartOfArraySubscripts(0), NestedNameSpecifierContinuation(0),
- CallContinuation(0), VariablePos(0), ContainsLineBreak(false),
- ContainsUnwrappedBuilder(0) {}
+ NoLineBreak(NoLineBreak), LastOperatorWrapped(true), ColonPos(0),
+ StartOfFunctionCall(0), StartOfArraySubscripts(0),
+ NestedNameSpecifierContinuation(0), CallContinuation(0), VariablePos(0),
+ ContainsLineBreak(false), ContainsUnwrappedBuilder(0),
+ AlignColons(true), ObjCSelectorNameFound(false),
+ HasMultipleNestedBlocks(false), JSFunctionInlined(false) {}
/// \brief The position to which a specific parenthesis level needs to be
/// indented.
@@ -176,6 +195,10 @@ struct ParenState {
/// \brief Line breaking in this context would break a formatting rule.
bool NoLineBreak;
+ /// \brief True if the last binary operator on this level was wrapped to the
+ /// next line.
+ bool LastOperatorWrapped;
+
/// \brief The position of the colon in an ObjC method declaration/call.
unsigned ColonPos;
@@ -210,6 +233,30 @@ struct ParenState {
/// builder-type call on one line.
bool ContainsUnwrappedBuilder;
+ /// \brief \c true if the colons of the curren ObjC method expression should
+ /// be aligned.
+ ///
+ /// Not considered for memoization as it will always have the same value at
+ /// the same token.
+ bool AlignColons;
+
+ /// \brief \c true if at least one selector name was found in the current
+ /// ObjC method expression.
+ ///
+ /// Not considered for memoization as it will always have the same value at
+ /// the same token.
+ bool ObjCSelectorNameFound;
+
+ /// \brief \c true if there are multiple nested blocks inside these parens.
+ ///
+ /// Not considered for memoization as it will always have the same value at
+ /// the same token.
+ bool HasMultipleNestedBlocks;
+
+ // \brief The previous JavaScript 'function' keyword is not wrapped to a new
+ // line.
+ bool JSFunctionInlined;
+
bool operator<(const ParenState &Other) const {
if (Indent != Other.Indent)
return Indent < Other.Indent;
@@ -227,6 +274,8 @@ struct ParenState {
return BreakBeforeParameter;
if (NoLineBreak != Other.NoLineBreak)
return NoLineBreak;
+ if (LastOperatorWrapped != Other.LastOperatorWrapped)
+ return LastOperatorWrapped;
if (ColonPos != Other.ColonPos)
return ColonPos < Other.ColonPos;
if (StartOfFunctionCall != Other.StartOfFunctionCall)
@@ -241,6 +290,8 @@ struct ParenState {
return ContainsLineBreak < Other.ContainsLineBreak;
if (ContainsUnwrappedBuilder != Other.ContainsUnwrappedBuilder)
return ContainsUnwrappedBuilder < Other.ContainsUnwrappedBuilder;
+ if (JSFunctionInlined != Other.JSFunctionInlined)
+ return JSFunctionInlined < Other.JSFunctionInlined;
return false;
}
};
@@ -258,13 +309,10 @@ struct LineState {
/// \brief \c true if this line contains a continued for-loop section.
bool LineContainsContinuedForLoopSection;
- /// \brief The level of nesting inside (), [], <> and {}.
- unsigned ParenLevel;
-
- /// \brief The \c ParenLevel at the start of this line.
+ /// \brief The \c NestingLevel at the start of this line.
unsigned StartOfLineLevel;
- /// \brief The lowest \c ParenLevel on the current line.
+ /// \brief The lowest \c NestingLevel on the current line.
unsigned LowestLevelOnLine;
/// \brief The start column of the string literal, if we're in a string
@@ -307,8 +355,6 @@ struct LineState {
if (LineContainsContinuedForLoopSection !=
Other.LineContainsContinuedForLoopSection)
return LineContainsContinuedForLoopSection;
- if (ParenLevel != Other.ParenLevel)
- return ParenLevel < Other.ParenLevel;
if (StartOfLineLevel != Other.StartOfLineLevel)
return StartOfLineLevel < Other.StartOfLineLevel;
if (LowestLevelOnLine != Other.LowestLevelOnLine)
diff --git a/lib/Format/Encoding.h b/lib/Format/Encoding.h
index 356334d5376f..dba5174b97b4 100644
--- a/lib/Format/Encoding.h
+++ b/lib/Format/Encoding.h
@@ -64,6 +64,10 @@ inline unsigned getCodePointCount(StringRef Text, Encoding Encoding) {
inline unsigned columnWidth(StringRef Text, Encoding Encoding) {
if (Encoding == Encoding_UTF8) {
int ContentWidth = llvm::sys::unicode::columnWidthUTF8(Text);
+ // FIXME: Figure out the correct way to handle this in the presence of both
+ // printable and unprintable multi-byte UTF-8 characters. Falling back to
+ // returning the number of bytes may cause problems, as columnWidth suddenly
+ // becomes non-additive.
if (ContentWidth >= 0)
return ContentWidth;
}
@@ -81,9 +85,7 @@ inline unsigned columnWidthWithTabs(StringRef Text, unsigned StartColumn,
StringRef::size_type TabPos = Tail.find('\t');
if (TabPos == StringRef::npos)
return TotalWidth + columnWidth(Tail, Encoding);
- int Width = columnWidth(Tail.substr(0, TabPos), Encoding);
- assert(Width >= 0);
- TotalWidth += Width;
+ TotalWidth += columnWidth(Tail.substr(0, TabPos), Encoding);
TotalWidth += TabWidth - (TotalWidth + StartColumn) % TabWidth;
Tail = Tail.substr(TabPos + 1);
}
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 01c122ecc7bf..58dd5604e427 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -13,84 +13,131 @@
///
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "format-formatter"
-
#include "ContinuationIndenter.h"
#include "TokenAnnotator.h"
#include "UnwrappedLineParser.h"
#include "WhitespaceManager.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Format/Format.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Debug.h"
-#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/YAMLTraits.h"
#include <queue>
#include <string>
+#define DEBUG_TYPE "format-formatter"
+
+using clang::format::FormatStyle;
+
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
+
namespace llvm {
namespace yaml {
-template <>
-struct ScalarEnumerationTraits<clang::format::FormatStyle::LanguageStandard> {
- static void enumeration(IO &IO,
- clang::format::FormatStyle::LanguageStandard &Value) {
- IO.enumCase(Value, "Cpp03", clang::format::FormatStyle::LS_Cpp03);
- IO.enumCase(Value, "C++03", clang::format::FormatStyle::LS_Cpp03);
- IO.enumCase(Value, "Cpp11", clang::format::FormatStyle::LS_Cpp11);
- IO.enumCase(Value, "C++11", clang::format::FormatStyle::LS_Cpp11);
- IO.enumCase(Value, "Auto", clang::format::FormatStyle::LS_Auto);
+template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
+ static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) {
+ IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp);
+ IO.enumCase(Value, "JavaScript", FormatStyle::LK_JavaScript);
+ IO.enumCase(Value, "Proto", FormatStyle::LK_Proto);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<FormatStyle::LanguageStandard> {
+ static void enumeration(IO &IO, FormatStyle::LanguageStandard &Value) {
+ IO.enumCase(Value, "Cpp03", FormatStyle::LS_Cpp03);
+ IO.enumCase(Value, "C++03", FormatStyle::LS_Cpp03);
+ IO.enumCase(Value, "Cpp11", FormatStyle::LS_Cpp11);
+ IO.enumCase(Value, "C++11", FormatStyle::LS_Cpp11);
+ IO.enumCase(Value, "Auto", FormatStyle::LS_Auto);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<FormatStyle::UseTabStyle> {
+ static void enumeration(IO &IO, FormatStyle::UseTabStyle &Value) {
+ IO.enumCase(Value, "Never", FormatStyle::UT_Never);
+ IO.enumCase(Value, "false", FormatStyle::UT_Never);
+ IO.enumCase(Value, "Always", FormatStyle::UT_Always);
+ IO.enumCase(Value, "true", FormatStyle::UT_Always);
+ IO.enumCase(Value, "ForIndentation", FormatStyle::UT_ForIndentation);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> {
+ static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) {
+ IO.enumCase(Value, "None", FormatStyle::SFS_None);
+ IO.enumCase(Value, "false", FormatStyle::SFS_None);
+ IO.enumCase(Value, "All", FormatStyle::SFS_All);
+ IO.enumCase(Value, "true", FormatStyle::SFS_All);
+ IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
+ static void enumeration(IO &IO, FormatStyle::BraceBreakingStyle &Value) {
+ IO.enumCase(Value, "Attach", FormatStyle::BS_Attach);
+ IO.enumCase(Value, "Linux", FormatStyle::BS_Linux);
+ IO.enumCase(Value, "Stroustrup", FormatStyle::BS_Stroustrup);
+ IO.enumCase(Value, "Allman", FormatStyle::BS_Allman);
+ IO.enumCase(Value, "GNU", FormatStyle::BS_GNU);
}
};
template <>
-struct ScalarEnumerationTraits<clang::format::FormatStyle::UseTabStyle> {
+struct ScalarEnumerationTraits<FormatStyle::NamespaceIndentationKind> {
static void enumeration(IO &IO,
- clang::format::FormatStyle::UseTabStyle &Value) {
- IO.enumCase(Value, "Never", clang::format::FormatStyle::UT_Never);
- IO.enumCase(Value, "false", clang::format::FormatStyle::UT_Never);
- IO.enumCase(Value, "Always", clang::format::FormatStyle::UT_Always);
- IO.enumCase(Value, "true", clang::format::FormatStyle::UT_Always);
- IO.enumCase(Value, "ForIndentation",
- clang::format::FormatStyle::UT_ForIndentation);
+ FormatStyle::NamespaceIndentationKind &Value) {
+ IO.enumCase(Value, "None", FormatStyle::NI_None);
+ IO.enumCase(Value, "Inner", FormatStyle::NI_Inner);
+ IO.enumCase(Value, "All", FormatStyle::NI_All);
}
};
template <>
-struct ScalarEnumerationTraits<clang::format::FormatStyle::BraceBreakingStyle> {
- static void
- enumeration(IO &IO, clang::format::FormatStyle::BraceBreakingStyle &Value) {
- IO.enumCase(Value, "Attach", clang::format::FormatStyle::BS_Attach);
- IO.enumCase(Value, "Linux", clang::format::FormatStyle::BS_Linux);
- IO.enumCase(Value, "Stroustrup", clang::format::FormatStyle::BS_Stroustrup);
- IO.enumCase(Value, "Allman", clang::format::FormatStyle::BS_Allman);
+struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> {
+ static void enumeration(IO &IO,
+ FormatStyle::PointerAlignmentStyle &Value) {
+ IO.enumCase(Value, "Middle", FormatStyle::PAS_Middle);
+ IO.enumCase(Value, "Left", FormatStyle::PAS_Left);
+ IO.enumCase(Value, "Right", FormatStyle::PAS_Right);
+
+ // For backward compatibility.
+ IO.enumCase(Value, "true", FormatStyle::PAS_Left);
+ IO.enumCase(Value, "false", FormatStyle::PAS_Right);
}
};
template <>
-struct ScalarEnumerationTraits<
- clang::format::FormatStyle::NamespaceIndentationKind> {
- static void
- enumeration(IO &IO,
- clang::format::FormatStyle::NamespaceIndentationKind &Value) {
- IO.enumCase(Value, "None", clang::format::FormatStyle::NI_None);
- IO.enumCase(Value, "Inner", clang::format::FormatStyle::NI_Inner);
- IO.enumCase(Value, "All", clang::format::FormatStyle::NI_All);
+struct ScalarEnumerationTraits<FormatStyle::SpaceBeforeParensOptions> {
+ static void enumeration(IO &IO,
+ FormatStyle::SpaceBeforeParensOptions &Value) {
+ IO.enumCase(Value, "Never", FormatStyle::SBPO_Never);
+ IO.enumCase(Value, "ControlStatements",
+ FormatStyle::SBPO_ControlStatements);
+ IO.enumCase(Value, "Always", FormatStyle::SBPO_Always);
+
+ // For backward compatibility.
+ IO.enumCase(Value, "false", FormatStyle::SBPO_Never);
+ IO.enumCase(Value, "true", FormatStyle::SBPO_ControlStatements);
}
};
-template <> struct MappingTraits<clang::format::FormatStyle> {
- static void mapping(llvm::yaml::IO &IO, clang::format::FormatStyle &Style) {
+template <> struct MappingTraits<FormatStyle> {
+ static void mapping(IO &IO, FormatStyle &Style) {
+ // When reading, read the language first, we need it for getPredefinedStyle.
+ IO.mapOptional("Language", Style.Language);
+
if (IO.outputting()) {
StringRef StylesArray[] = { "LLVM", "Google", "Chromium",
- "Mozilla", "WebKit" };
+ "Mozilla", "WebKit", "GNU" };
ArrayRef<StringRef> Styles(StylesArray);
for (size_t i = 0, e = Styles.size(); i < e; ++i) {
StringRef StyleName(Styles[i]);
- clang::format::FormatStyle PredefinedStyle;
- if (clang::format::getPredefinedStyle(StyleName, &PredefinedStyle) &&
+ FormatStyle PredefinedStyle;
+ if (getPredefinedStyle(StyleName, Style.Language, &PredefinedStyle) &&
Style == PredefinedStyle) {
IO.mapOptional("# BasedOnStyle", StyleName);
break;
@@ -99,11 +146,16 @@ template <> struct MappingTraits<clang::format::FormatStyle> {
} else {
StringRef BasedOnStyle;
IO.mapOptional("BasedOnStyle", BasedOnStyle);
- if (!BasedOnStyle.empty())
- if (!clang::format::getPredefinedStyle(BasedOnStyle, &Style)) {
+ if (!BasedOnStyle.empty()) {
+ FormatStyle::LanguageKind OldLanguage = Style.Language;
+ FormatStyle::LanguageKind Language =
+ ((FormatStyle *)IO.getContext())->Language;
+ if (!getPredefinedStyle(BasedOnStyle, Language, &Style)) {
IO.setError(Twine("Unknown value for BasedOnStyle: ", BasedOnStyle));
return;
}
+ Style.Language = OldLanguage;
+ }
}
IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
@@ -113,10 +165,14 @@ template <> struct MappingTraits<clang::format::FormatStyle> {
IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",
Style.AllowAllParametersOfDeclarationOnNextLine);
+ IO.mapOptional("AllowShortBlocksOnASingleLine",
+ Style.AllowShortBlocksOnASingleLine);
IO.mapOptional("AllowShortIfStatementsOnASingleLine",
Style.AllowShortIfStatementsOnASingleLine);
IO.mapOptional("AllowShortLoopsOnASingleLine",
Style.AllowShortLoopsOnASingleLine);
+ IO.mapOptional("AllowShortFunctionsOnASingleLine",
+ Style.AllowShortFunctionsOnASingleLine);
IO.mapOptional("AlwaysBreakTemplateDeclarations",
Style.AlwaysBreakTemplateDeclarations);
IO.mapOptional("AlwaysBreakBeforeMultilineStrings",
@@ -131,12 +187,19 @@ template <> struct MappingTraits<clang::format::FormatStyle> {
IO.mapOptional("ColumnLimit", Style.ColumnLimit);
IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine",
Style.ConstructorInitializerAllOnOneLineOrOnePerLine);
- IO.mapOptional("DerivePointerBinding", Style.DerivePointerBinding);
+ IO.mapOptional("DerivePointerAlignment", Style.DerivePointerAlignment);
IO.mapOptional("ExperimentalAutoDetectBinPacking",
Style.ExperimentalAutoDetectBinPacking);
IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels);
+ IO.mapOptional("IndentWrappedFunctionNames",
+ Style.IndentWrappedFunctionNames);
+ IO.mapOptional("IndentFunctionDeclarationAfterType",
+ Style.IndentWrappedFunctionNames);
IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep);
+ IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks",
+ Style.KeepEmptyLinesAtTheStartOfBlocks);
IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
+ IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty);
IO.mapOptional("ObjCSpaceBeforeProtocolList",
Style.ObjCSpaceBeforeProtocolList);
IO.mapOptional("PenaltyBreakBeforeFirstCallParameter",
@@ -148,7 +211,7 @@ template <> struct MappingTraits<clang::format::FormatStyle> {
IO.mapOptional("PenaltyExcessCharacter", Style.PenaltyExcessCharacter);
IO.mapOptional("PenaltyReturnTypeOnItsOwnLine",
Style.PenaltyReturnTypeOnItsOwnLine);
- IO.mapOptional("PointerBindsToType", Style.PointerBindsToType);
+ IO.mapOptional("PointerAlignment", Style.PointerAlignment);
IO.mapOptional("SpacesBeforeTrailingComments",
Style.SpacesBeforeTrailingComments);
IO.mapOptional("Cpp11BracedListStyle", Style.Cpp11BracedListStyle);
@@ -157,18 +220,54 @@ template <> struct MappingTraits<clang::format::FormatStyle> {
IO.mapOptional("TabWidth", Style.TabWidth);
IO.mapOptional("UseTab", Style.UseTab);
IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
- IO.mapOptional("IndentFunctionDeclarationAfterType",
- Style.IndentFunctionDeclarationAfterType);
IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses);
IO.mapOptional("SpacesInAngles", Style.SpacesInAngles);
IO.mapOptional("SpaceInEmptyParentheses", Style.SpaceInEmptyParentheses);
IO.mapOptional("SpacesInCStyleCastParentheses",
Style.SpacesInCStyleCastParentheses);
- IO.mapOptional("SpaceAfterControlStatementKeyword",
- Style.SpaceAfterControlStatementKeyword);
+ IO.mapOptional("SpacesInContainerLiterals",
+ Style.SpacesInContainerLiterals);
IO.mapOptional("SpaceBeforeAssignmentOperators",
Style.SpaceBeforeAssignmentOperators);
IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth);
+ IO.mapOptional("CommentPragmas", Style.CommentPragmas);
+ IO.mapOptional("ForEachMacros", Style.ForEachMacros);
+
+ // For backward compatibility.
+ if (!IO.outputting()) {
+ IO.mapOptional("SpaceAfterControlStatementKeyword",
+ Style.SpaceBeforeParens);
+ IO.mapOptional("PointerBindsToType", Style.PointerAlignment);
+ IO.mapOptional("DerivePointerBinding", Style.DerivePointerAlignment);
+ }
+ IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens);
+ IO.mapOptional("DisableFormat", Style.DisableFormat);
+ }
+};
+
+// Allows to read vector<FormatStyle> while keeping default values.
+// IO.getContext() should contain a pointer to the FormatStyle structure, that
+// will be used to get default values for missing keys.
+// If the first element has no Language specified, it will be treated as the
+// default one for the following elements.
+template <> struct DocumentListTraits<std::vector<FormatStyle> > {
+ static size_t size(IO &IO, std::vector<FormatStyle> &Seq) {
+ return Seq.size();
+ }
+ static FormatStyle &element(IO &IO, std::vector<FormatStyle> &Seq,
+ size_t Index) {
+ if (Index >= Seq.size()) {
+ assert(Index == Seq.size());
+ FormatStyle Template;
+ if (Seq.size() > 0 && Seq[0].Language == FormatStyle::LK_None) {
+ Template = Seq[0];
+ } else {
+ Template = *((const FormatStyle *)IO.getContext());
+ Template.Language = FormatStyle::LK_None;
+ }
+ Seq.resize(Index + 1, Template);
+ }
+ return Seq[Index];
}
};
}
@@ -177,19 +276,39 @@ template <> struct MappingTraits<clang::format::FormatStyle> {
namespace clang {
namespace format {
-void setDefaultPenalties(FormatStyle &Style) {
- Style.PenaltyBreakComment = 60;
- Style.PenaltyBreakFirstLessLess = 120;
- Style.PenaltyBreakString = 1000;
- Style.PenaltyExcessCharacter = 1000000;
+const std::error_category &getParseCategory() {
+ static ParseErrorCategory C;
+ return C;
+}
+std::error_code make_error_code(ParseError e) {
+ return std::error_code(static_cast<int>(e), getParseCategory());
+}
+
+const char *ParseErrorCategory::name() const LLVM_NOEXCEPT {
+ return "clang-format.parse_error";
+}
+
+std::string ParseErrorCategory::message(int EV) const {
+ switch (static_cast<ParseError>(EV)) {
+ case ParseError::Success:
+ return "Success";
+ case ParseError::Error:
+ return "Invalid argument";
+ case ParseError::Unsuitable:
+ return "Unsuitable";
+ }
+ llvm_unreachable("unexpected parse error");
}
FormatStyle getLLVMStyle() {
FormatStyle LLVMStyle;
+ LLVMStyle.Language = FormatStyle::LK_Cpp;
LLVMStyle.AccessModifierOffset = -2;
LLVMStyle.AlignEscapedNewlinesLeft = false;
LLVMStyle.AlignTrailingComments = true;
LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
+ LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
+ LLVMStyle.AllowShortBlocksOnASingleLine = false;
LLVMStyle.AllowShortIfStatementsOnASingleLine = false;
LLVMStyle.AllowShortLoopsOnASingleLine = false;
LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
@@ -200,91 +319,92 @@ FormatStyle getLLVMStyle() {
LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
LLVMStyle.BreakConstructorInitializersBeforeComma = false;
LLVMStyle.ColumnLimit = 80;
+ LLVMStyle.CommentPragmas = "^ IWYU pragma:";
LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
LLVMStyle.ConstructorInitializerIndentWidth = 4;
- LLVMStyle.Cpp11BracedListStyle = false;
- LLVMStyle.DerivePointerBinding = false;
+ LLVMStyle.ContinuationIndentWidth = 4;
+ LLVMStyle.Cpp11BracedListStyle = true;
+ LLVMStyle.DerivePointerAlignment = false;
LLVMStyle.ExperimentalAutoDetectBinPacking = false;
+ LLVMStyle.ForEachMacros.push_back("foreach");
+ LLVMStyle.ForEachMacros.push_back("Q_FOREACH");
+ LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH");
LLVMStyle.IndentCaseLabels = false;
- LLVMStyle.IndentFunctionDeclarationAfterType = false;
+ LLVMStyle.IndentWrappedFunctionNames = false;
LLVMStyle.IndentWidth = 2;
LLVMStyle.TabWidth = 8;
LLVMStyle.MaxEmptyLinesToKeep = 1;
+ LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;
LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
+ LLVMStyle.ObjCSpaceAfterProperty = false;
LLVMStyle.ObjCSpaceBeforeProtocolList = true;
- LLVMStyle.PointerBindsToType = false;
+ LLVMStyle.PointerAlignment = FormatStyle::PAS_Right;
LLVMStyle.SpacesBeforeTrailingComments = 1;
- LLVMStyle.Standard = FormatStyle::LS_Cpp03;
+ LLVMStyle.Standard = FormatStyle::LS_Cpp11;
LLVMStyle.UseTab = FormatStyle::UT_Never;
LLVMStyle.SpacesInParentheses = false;
LLVMStyle.SpaceInEmptyParentheses = false;
+ LLVMStyle.SpacesInContainerLiterals = true;
LLVMStyle.SpacesInCStyleCastParentheses = false;
- LLVMStyle.SpaceAfterControlStatementKeyword = true;
+ LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
LLVMStyle.SpaceBeforeAssignmentOperators = true;
- LLVMStyle.ContinuationIndentWidth = 4;
LLVMStyle.SpacesInAngles = false;
- setDefaultPenalties(LLVMStyle);
+ LLVMStyle.PenaltyBreakComment = 300;
+ LLVMStyle.PenaltyBreakFirstLessLess = 120;
+ LLVMStyle.PenaltyBreakString = 1000;
+ LLVMStyle.PenaltyExcessCharacter = 1000000;
LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60;
LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;
+ LLVMStyle.DisableFormat = false;
+
return LLVMStyle;
}
-FormatStyle getGoogleStyle() {
- FormatStyle GoogleStyle;
+FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
+ FormatStyle GoogleStyle = getLLVMStyle();
+ GoogleStyle.Language = Language;
+
GoogleStyle.AccessModifierOffset = -1;
GoogleStyle.AlignEscapedNewlinesLeft = true;
- GoogleStyle.AlignTrailingComments = true;
- GoogleStyle.AllowAllParametersOfDeclarationOnNextLine = true;
GoogleStyle.AllowShortIfStatementsOnASingleLine = true;
GoogleStyle.AllowShortLoopsOnASingleLine = true;
GoogleStyle.AlwaysBreakBeforeMultilineStrings = true;
GoogleStyle.AlwaysBreakTemplateDeclarations = true;
- GoogleStyle.BinPackParameters = true;
- GoogleStyle.BreakBeforeBinaryOperators = false;
- GoogleStyle.BreakBeforeTernaryOperators = true;
- GoogleStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
- GoogleStyle.BreakConstructorInitializersBeforeComma = false;
- GoogleStyle.ColumnLimit = 80;
GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
- GoogleStyle.ConstructorInitializerIndentWidth = 4;
- GoogleStyle.Cpp11BracedListStyle = true;
- GoogleStyle.DerivePointerBinding = true;
- GoogleStyle.ExperimentalAutoDetectBinPacking = false;
+ GoogleStyle.DerivePointerAlignment = true;
GoogleStyle.IndentCaseLabels = true;
- GoogleStyle.IndentFunctionDeclarationAfterType = true;
- GoogleStyle.IndentWidth = 2;
- GoogleStyle.TabWidth = 8;
- GoogleStyle.MaxEmptyLinesToKeep = 1;
- GoogleStyle.NamespaceIndentation = FormatStyle::NI_None;
+ GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false;
+ GoogleStyle.ObjCSpaceAfterProperty = false;
GoogleStyle.ObjCSpaceBeforeProtocolList = false;
- GoogleStyle.PointerBindsToType = true;
+ GoogleStyle.PointerAlignment = FormatStyle::PAS_Left;
GoogleStyle.SpacesBeforeTrailingComments = 2;
GoogleStyle.Standard = FormatStyle::LS_Auto;
- GoogleStyle.UseTab = FormatStyle::UT_Never;
- GoogleStyle.SpacesInParentheses = false;
- GoogleStyle.SpaceInEmptyParentheses = false;
- GoogleStyle.SpacesInCStyleCastParentheses = false;
- GoogleStyle.SpaceAfterControlStatementKeyword = true;
- GoogleStyle.SpaceBeforeAssignmentOperators = true;
- GoogleStyle.ContinuationIndentWidth = 4;
- GoogleStyle.SpacesInAngles = false;
-
- setDefaultPenalties(GoogleStyle);
+
GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200;
GoogleStyle.PenaltyBreakBeforeFirstCallParameter = 1;
+ if (Language == FormatStyle::LK_JavaScript) {
+ GoogleStyle.BreakBeforeTernaryOperators = false;
+ GoogleStyle.MaxEmptyLinesToKeep = 3;
+ GoogleStyle.SpacesInContainerLiterals = false;
+ } else if (Language == FormatStyle::LK_Proto) {
+ GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
+ GoogleStyle.SpacesInContainerLiterals = false;
+ }
+
return GoogleStyle;
}
-FormatStyle getChromiumStyle() {
- FormatStyle ChromiumStyle = getGoogleStyle();
+FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {
+ FormatStyle ChromiumStyle = getGoogleStyle(Language);
ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
+ ChromiumStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
ChromiumStyle.AllowShortLoopsOnASingleLine = false;
ChromiumStyle.BinPackParameters = false;
- ChromiumStyle.DerivePointerBinding = false;
+ ChromiumStyle.DerivePointerAlignment = false;
ChromiumStyle.Standard = FormatStyle::LS_Cpp03;
return ChromiumStyle;
}
@@ -292,12 +412,15 @@ FormatStyle getChromiumStyle() {
FormatStyle getMozillaStyle() {
FormatStyle MozillaStyle = getLLVMStyle();
MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false;
+ MozillaStyle.Cpp11BracedListStyle = false;
MozillaStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
- MozillaStyle.DerivePointerBinding = true;
+ MozillaStyle.DerivePointerAlignment = true;
MozillaStyle.IndentCaseLabels = true;
+ MozillaStyle.ObjCSpaceAfterProperty = true;
MozillaStyle.ObjCSpaceBeforeProtocolList = false;
MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200;
- MozillaStyle.PointerBindsToType = true;
+ MozillaStyle.PointerAlignment = FormatStyle::PAS_Left;
+ MozillaStyle.Standard = FormatStyle::LS_Cpp03;
return MozillaStyle;
}
@@ -308,36 +431,102 @@ FormatStyle getWebKitStyle() {
Style.BreakBeforeBinaryOperators = true;
Style.BreakBeforeBraces = FormatStyle::BS_Stroustrup;
Style.BreakConstructorInitializersBeforeComma = true;
+ Style.Cpp11BracedListStyle = false;
Style.ColumnLimit = 0;
Style.IndentWidth = 4;
Style.NamespaceIndentation = FormatStyle::NI_Inner;
- Style.PointerBindsToType = true;
+ Style.ObjCSpaceAfterProperty = true;
+ Style.PointerAlignment = FormatStyle::PAS_Left;
+ Style.Standard = FormatStyle::LS_Cpp03;
+ return Style;
+}
+
+FormatStyle getGNUStyle() {
+ FormatStyle Style = getLLVMStyle();
+ Style.BreakBeforeBinaryOperators = true;
+ Style.BreakBeforeBraces = FormatStyle::BS_GNU;
+ Style.BreakBeforeTernaryOperators = true;
+ Style.Cpp11BracedListStyle = false;
+ Style.ColumnLimit = 79;
+ Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
+ Style.Standard = FormatStyle::LS_Cpp03;
return Style;
}
-bool getPredefinedStyle(StringRef Name, FormatStyle *Style) {
- if (Name.equals_lower("llvm"))
+FormatStyle getNoStyle() {
+ FormatStyle NoStyle = getLLVMStyle();
+ NoStyle.DisableFormat = true;
+ return NoStyle;
+}
+
+bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language,
+ FormatStyle *Style) {
+ if (Name.equals_lower("llvm")) {
*Style = getLLVMStyle();
- else if (Name.equals_lower("chromium"))
- *Style = getChromiumStyle();
- else if (Name.equals_lower("mozilla"))
+ } else if (Name.equals_lower("chromium")) {
+ *Style = getChromiumStyle(Language);
+ } else if (Name.equals_lower("mozilla")) {
*Style = getMozillaStyle();
- else if (Name.equals_lower("google"))
- *Style = getGoogleStyle();
- else if (Name.equals_lower("webkit"))
+ } else if (Name.equals_lower("google")) {
+ *Style = getGoogleStyle(Language);
+ } else if (Name.equals_lower("webkit")) {
*Style = getWebKitStyle();
- else
+ } else if (Name.equals_lower("gnu")) {
+ *Style = getGNUStyle();
+ } else if (Name.equals_lower("none")) {
+ *Style = getNoStyle();
+ } else {
return false;
+ }
+ Style->Language = Language;
return true;
}
-llvm::error_code parseConfiguration(StringRef Text, FormatStyle *Style) {
+std::error_code parseConfiguration(StringRef Text, FormatStyle *Style) {
+ assert(Style);
+ FormatStyle::LanguageKind Language = Style->Language;
+ assert(Language != FormatStyle::LK_None);
if (Text.trim().empty())
- return llvm::make_error_code(llvm::errc::invalid_argument);
+ return make_error_code(ParseError::Error);
+
+ std::vector<FormatStyle> Styles;
llvm::yaml::Input Input(Text);
- Input >> *Style;
- return Input.error();
+ // DocumentListTraits<vector<FormatStyle>> uses the context to get default
+ // values for the fields, keys for which are missing from the configuration.
+ // Mapping also uses the context to get the language to find the correct
+ // base style.
+ Input.setContext(Style);
+ Input >> Styles;
+ if (Input.error())
+ return Input.error();
+
+ for (unsigned i = 0; i < Styles.size(); ++i) {
+ // Ensures that only the first configuration can skip the Language option.
+ if (Styles[i].Language == FormatStyle::LK_None && i != 0)
+ return make_error_code(ParseError::Error);
+ // Ensure that each language is configured at most once.
+ for (unsigned j = 0; j < i; ++j) {
+ if (Styles[i].Language == Styles[j].Language) {
+ DEBUG(llvm::dbgs()
+ << "Duplicate languages in the config file on positions " << j
+ << " and " << i << "\n");
+ return make_error_code(ParseError::Error);
+ }
+ }
+ }
+ // Look for a suitable configuration starting from the end, so we can
+ // find the configuration for the specific language first, and the default
+ // configuration (which can only be at slot 0) after it.
+ for (int i = Styles.size() - 1; i >= 0; --i) {
+ if (Styles[i].Language == Language ||
+ Styles[i].Language == FormatStyle::LK_None) {
+ *Style = Styles[i];
+ Style->Language = Language;
+ return make_error_code(ParseError::Success);
+ }
+ }
+ return make_error_code(ParseError::Unsuitable);
}
std::string configurationAsText(const FormatStyle &Style) {
@@ -362,7 +551,7 @@ public:
void format(unsigned FirstIndent, const AnnotatedLine *Line) {
LineState State =
Indenter->getInitialState(FirstIndent, Line, /*DryRun=*/false);
- while (State.NextToken != NULL) {
+ while (State.NextToken) {
bool Newline =
Indenter->mustBreak(State) ||
(Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0);
@@ -381,14 +570,14 @@ public:
/// \brief Calculates how many lines can be merged into 1 starting at \p I.
unsigned
tryFitMultipleLinesInOne(unsigned Indent,
- SmallVectorImpl<AnnotatedLine *>::const_iterator &I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator I,
SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
// We can never merge stuff if there are trailing line comments.
- AnnotatedLine *TheLine = *I;
+ const AnnotatedLine *TheLine = *I;
if (TheLine->Last->Type == TT_LineComment)
return 0;
- if (Indent > Style.ColumnLimit)
+ if (Style.ColumnLimit > 0 && Indent > Style.ColumnLimit)
return 0;
unsigned Limit =
@@ -399,19 +588,54 @@ public:
? 0
: Limit - TheLine->Last->TotalLength;
- if (I + 1 == E || I[1]->Type == LT_Invalid)
+ if (I + 1 == E || I[1]->Type == LT_Invalid || I[1]->First->MustBreakBefore)
return 0;
+ // FIXME: TheLine->Level != 0 might or might not be the right check to do.
+ // If necessary, change to something smarter.
+ bool MergeShortFunctions =
+ Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All ||
+ (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline &&
+ TheLine->Level != 0);
+
+ if (TheLine->Last->Type == TT_FunctionLBrace &&
+ TheLine->First != TheLine->Last) {
+ return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
+ }
if (TheLine->Last->is(tok::l_brace)) {
- return tryMergeSimpleBlock(I, E, Limit);
- } else if (Style.AllowShortIfStatementsOnASingleLine &&
- TheLine->First->is(tok::kw_if)) {
- return tryMergeSimpleControlStatement(I, E, Limit);
- } else if (Style.AllowShortLoopsOnASingleLine &&
- TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) {
- return tryMergeSimpleControlStatement(I, E, Limit);
- } else if (TheLine->InPPDirective && (TheLine->First->HasUnescapedNewline ||
- TheLine->First->IsFirst)) {
+ return Style.BreakBeforeBraces == FormatStyle::BS_Attach
+ ? tryMergeSimpleBlock(I, E, Limit)
+ : 0;
+ }
+ if (I[1]->First->Type == TT_FunctionLBrace &&
+ Style.BreakBeforeBraces != FormatStyle::BS_Attach) {
+ // Check for Limit <= 2 to account for the " {".
+ if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(TheLine)))
+ return 0;
+ Limit -= 2;
+
+ unsigned MergedLines = 0;
+ if (MergeShortFunctions) {
+ MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
+ // If we managed to merge the block, count the function header, which is
+ // on a separate line.
+ if (MergedLines > 0)
+ ++MergedLines;
+ }
+ return MergedLines;
+ }
+ if (TheLine->First->is(tok::kw_if)) {
+ return Style.AllowShortIfStatementsOnASingleLine
+ ? tryMergeSimpleControlStatement(I, E, Limit)
+ : 0;
+ }
+ if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) {
+ return Style.AllowShortLoopsOnASingleLine
+ ? tryMergeSimpleControlStatement(I, E, Limit)
+ : 0;
+ }
+ if (TheLine->InPPDirective &&
+ (TheLine->First->HasUnescapedNewline || TheLine->First->IsFirst)) {
return tryMergeSimplePPDirective(I, E, Limit);
}
return 0;
@@ -419,7 +643,7 @@ public:
private:
unsigned
- tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator &I,
+ tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
SmallVectorImpl<AnnotatedLine *>::const_iterator E,
unsigned Limit) {
if (Limit == 0)
@@ -434,23 +658,25 @@ private:
}
unsigned tryMergeSimpleControlStatement(
- SmallVectorImpl<AnnotatedLine *>::const_iterator &I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator I,
SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {
if (Limit == 0)
return 0;
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman &&
- I[1]->First->is(tok::l_brace))
+ if ((Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU) &&
+ (I[1]->First->is(tok::l_brace) && !Style.AllowShortBlocksOnASingleLine))
return 0;
if (I[1]->InPPDirective != (*I)->InPPDirective ||
(I[1]->InPPDirective && I[1]->First->HasUnescapedNewline))
return 0;
+ Limit = limitConsideringMacros(I + 1, E, Limit);
AnnotatedLine &Line = **I;
if (Line.Last->isNot(tok::r_paren))
return 0;
if (1 + I[1]->Last->TotalLength > Limit)
return 0;
if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for,
- tok::kw_while) ||
+ tok::kw_while) ||
I[1]->First->Type == TT_LineComment)
return 0;
// Only inline simple if's (no nested if or else).
@@ -461,54 +687,69 @@ private:
}
unsigned
- tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator &I,
+ tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
SmallVectorImpl<AnnotatedLine *>::const_iterator E,
unsigned Limit) {
- // No merging if the brace already is on the next line.
- if (Style.BreakBeforeBraces != FormatStyle::BS_Attach)
+ AnnotatedLine &Line = **I;
+
+ // Don't merge ObjC @ keywords and methods.
+ if (Line.First->isOneOf(tok::at, tok::minus, tok::plus))
return 0;
- // First, check that the current line allows merging. This is the case if
- // we're not in a control flow statement and the last token is an opening
- // brace.
- AnnotatedLine &Line = **I;
- if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::r_brace,
- tok::kw_else, tok::kw_try, tok::kw_catch,
- tok::kw_for,
- // This gets rid of all ObjC @ keywords and methods.
- tok::at, tok::minus, tok::plus))
+ // Check that the current line allows merging. This depends on whether we
+ // are in a control flow statements as well as several style flags.
+ if (Line.First->isOneOf(tok::kw_else, tok::kw_case))
return 0;
+ if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::kw_try,
+ tok::kw_catch, tok::kw_for, tok::r_brace)) {
+ if (!Style.AllowShortBlocksOnASingleLine)
+ return 0;
+ if (!Style.AllowShortIfStatementsOnASingleLine &&
+ Line.First->is(tok::kw_if))
+ return 0;
+ if (!Style.AllowShortLoopsOnASingleLine &&
+ Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for))
+ return 0;
+ // FIXME: Consider an option to allow short exception handling clauses on
+ // a single line.
+ if (Line.First->isOneOf(tok::kw_try, tok::kw_catch))
+ return 0;
+ }
FormatToken *Tok = I[1]->First;
if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore &&
- (Tok->getNextNonComment() == NULL ||
+ (Tok->getNextNonComment() == nullptr ||
Tok->getNextNonComment()->is(tok::semi))) {
// We merge empty blocks even if the line exceeds the column limit.
Tok->SpacesRequiredBefore = 0;
Tok->CanBreakBefore = true;
return 1;
} else if (Limit != 0 && Line.First->isNot(tok::kw_namespace)) {
+ // We don't merge short records.
+ if (Line.First->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct))
+ return 0;
+
// Check that we still have three lines and they fit into the limit.
if (I + 2 == E || I[2]->Type == LT_Invalid)
return 0;
+ Limit = limitConsideringMacros(I + 2, E, Limit);
if (!nextTwoLinesFitInto(I, Limit))
return 0;
// Second, check that the next line does not contain any braces - if it
// does, readability declines when putting it into a single line.
- if (I[1]->Last->Type == TT_LineComment || Tok->MustBreakBefore)
+ if (I[1]->Last->Type == TT_LineComment)
return 0;
do {
- if (Tok->isOneOf(tok::l_brace, tok::r_brace))
+ if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit)
return 0;
Tok = Tok->Next;
- } while (Tok != NULL);
+ } while (Tok);
- // Last, check that the third line contains a single closing brace.
+ // Last, check that the third line starts with a closing brace.
Tok = I[2]->First;
- if (Tok->getNextNonComment() != NULL || Tok->isNot(tok::r_brace) ||
- Tok->MustBreakBefore)
+ if (Tok->isNot(tok::r_brace))
return 0;
return 2;
@@ -516,34 +757,60 @@ private:
return 0;
}
+ /// Returns the modified column limit for \p I if it is inside a macro and
+ /// needs a trailing '\'.
+ unsigned
+ limitConsideringMacros(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E,
+ unsigned Limit) {
+ if (I[0]->InPPDirective && I + 1 != E &&
+ !I[1]->First->HasUnescapedNewline && !I[1]->First->is(tok::eof)) {
+ return Limit < 2 ? 0 : Limit - 2;
+ }
+ return Limit;
+ }
+
bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
unsigned Limit) {
+ if (I[1]->First->MustBreakBefore || I[2]->First->MustBreakBefore)
+ return false;
return 1 + I[1]->Last->TotalLength + 1 + I[2]->Last->TotalLength <= Limit;
}
+ bool containsMustBreak(const AnnotatedLine *Line) {
+ for (const FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
+ if (Tok->MustBreakBefore)
+ return true;
+ }
+ return false;
+ }
+
const FormatStyle &Style;
};
class UnwrappedLineFormatter {
public:
- UnwrappedLineFormatter(SourceManager &SourceMgr,
- SmallVectorImpl<CharSourceRange> &Ranges,
- ContinuationIndenter *Indenter,
+ UnwrappedLineFormatter(ContinuationIndenter *Indenter,
WhitespaceManager *Whitespaces,
const FormatStyle &Style)
- : SourceMgr(SourceMgr), Ranges(Ranges), Indenter(Indenter),
- Whitespaces(Whitespaces), Style(Style), Joiner(Style) {}
+ : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style),
+ Joiner(Style) {}
unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun,
- int AdditionalIndent = 0) {
+ int AdditionalIndent = 0, bool FixBadIndentation = false) {
+ // Try to look up already computed penalty in DryRun-mode.
+ std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned> CacheKey(
+ &Lines, AdditionalIndent);
+ auto CacheIt = PenaltyCache.find(CacheKey);
+ if (DryRun && CacheIt != PenaltyCache.end())
+ return CacheIt->second;
+
assert(!Lines.empty());
unsigned Penalty = 0;
std::vector<int> IndentForLevel;
for (unsigned i = 0, e = Lines[0]->Level; i != e; ++i)
IndentForLevel.push_back(Style.IndentWidth * i + AdditionalIndent);
- bool PreviousLineWasTouched = false;
- const AnnotatedLine *PreviousLine = NULL;
- bool FormatPPDirective = false;
+ const AnnotatedLine *PreviousLine = nullptr;
for (SmallVectorImpl<AnnotatedLine *>::const_iterator I = Lines.begin(),
E = Lines.end();
I != E; ++I) {
@@ -551,21 +818,30 @@ public:
const FormatToken *FirstTok = TheLine.First;
int Offset = getIndentOffset(*FirstTok);
- // Check whether this line is part of a formatted preprocessor directive.
- if (FirstTok->HasUnescapedNewline)
- FormatPPDirective = false;
- if (!FormatPPDirective && TheLine.InPPDirective &&
- (touchesLine(TheLine) || touchesPPDirective(I + 1, E)))
- FormatPPDirective = true;
-
// Determine indent and try to merge multiple unwrapped lines.
- while (IndentForLevel.size() <= TheLine.Level)
- IndentForLevel.push_back(-1);
- IndentForLevel.resize(TheLine.Level + 1);
- unsigned Indent = getIndent(IndentForLevel, TheLine.Level);
+ unsigned Indent;
+ if (TheLine.InPPDirective) {
+ Indent = TheLine.Level * Style.IndentWidth;
+ } else {
+ while (IndentForLevel.size() <= TheLine.Level)
+ IndentForLevel.push_back(-1);
+ IndentForLevel.resize(TheLine.Level + 1);
+ Indent = getIndent(IndentForLevel, TheLine.Level);
+ }
+ unsigned LevelIndent = Indent;
if (static_cast<int>(Indent) + Offset >= 0)
Indent += Offset;
+
+ // Merge multiple lines if possible.
unsigned MergedLines = Joiner.tryFitMultipleLinesInOne(Indent, I, E);
+ if (MergedLines > 0 && Style.ColumnLimit == 0) {
+ // Disallow line merging if there is a break at the start of one of the
+ // input lines.
+ for (unsigned i = 0; i < MergedLines; ++i) {
+ if (I[i + 1]->First->NewlinesBefore > 0)
+ MergedLines = 0;
+ }
+ }
if (!DryRun) {
for (unsigned i = 0; i < MergedLines; ++i) {
join(*I[i], *I[i + 1]);
@@ -573,18 +849,18 @@ public:
}
I += MergedLines;
- bool WasMoved = PreviousLineWasTouched && FirstTok->NewlinesBefore == 0;
+ bool FixIndentation =
+ FixBadIndentation && (LevelIndent != FirstTok->OriginalColumn);
if (TheLine.First->is(tok::eof)) {
- if (PreviousLineWasTouched && !DryRun) {
+ if (PreviousLine && PreviousLine->Affected && !DryRun) {
+ // Remove the file's trailing whitespace.
unsigned Newlines = std::min(FirstTok->NewlinesBefore, 1u);
Whitespaces->replaceWhitespace(*TheLine.First, Newlines,
/*IndentLevel=*/0, /*Spaces=*/0,
/*TargetColumn=*/0);
}
} else if (TheLine.Type != LT_Invalid &&
- (WasMoved || FormatPPDirective || touchesLine(TheLine))) {
- unsigned LevelIndent =
- getIndent(IndentForLevel, TheLine.Level);
+ (TheLine.Affected || FixIndentation)) {
if (FirstTok->WhitespaceRange.isValid()) {
if (!DryRun)
formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level,
@@ -603,9 +879,12 @@ public:
if (TheLine.Last->TotalLength + Indent <= ColumnLimit) {
LineState State = Indenter->getInitialState(Indent, &TheLine, DryRun);
- while (State.NextToken != NULL)
+ while (State.NextToken) {
+ formatChildren(State, /*Newline=*/false, /*DryRun=*/false, Penalty);
Indenter->addTokenToState(State, /*Newline=*/false, DryRun);
+ }
} else if (Style.ColumnLimit == 0) {
+ // FIXME: Implement nested blocks for ColumnLimit = 0.
NoColumnLimitFormatter Formatter(Indenter);
if (!DryRun)
Formatter.format(Indent, &TheLine);
@@ -613,19 +892,21 @@ public:
Penalty += format(TheLine, Indent, DryRun);
}
- IndentForLevel[TheLine.Level] = LevelIndent;
- PreviousLineWasTouched = true;
+ if (!TheLine.InPPDirective)
+ IndentForLevel[TheLine.Level] = LevelIndent;
+ } else if (TheLine.ChildrenAffected) {
+ format(TheLine.Children, DryRun);
} else {
// Format the first token if necessary, and notify the WhitespaceManager
// about the unchanged whitespace.
- for (FormatToken *Tok = TheLine.First; Tok != NULL; Tok = Tok->Next) {
+ for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {
if (Tok == TheLine.First &&
(Tok->NewlinesBefore > 0 || Tok->IsFirst)) {
unsigned LevelIndent = Tok->OriginalColumn;
if (!DryRun) {
- // Remove trailing whitespace of the previous line if it was
- // touched.
- if (PreviousLineWasTouched || touchesEmptyLineBefore(TheLine)) {
+ // Remove trailing whitespace of the previous line.
+ if ((PreviousLine && PreviousLine->Affected) ||
+ TheLine.LeadingEmptyLinesAffected) {
formatFirstToken(*Tok, PreviousLine, TheLine.Level, LevelIndent,
TheLine.InPPDirective);
} else {
@@ -635,24 +916,21 @@ public:
if (static_cast<int>(LevelIndent) - Offset >= 0)
LevelIndent -= Offset;
- if (Tok->isNot(tok::comment))
+ if (Tok->isNot(tok::comment) && !TheLine.InPPDirective)
IndentForLevel[TheLine.Level] = LevelIndent;
} else if (!DryRun) {
Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);
}
}
- // If we did not reformat this unwrapped line, the column at the end of
- // the last token is unchanged - thus, we can calculate the end of the
- // last token.
- PreviousLineWasTouched = false;
}
if (!DryRun) {
- for (FormatToken *Tok = TheLine.First; Tok != NULL; Tok = Tok->Next) {
+ for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {
Tok->Finalized = true;
}
}
PreviousLine = *I;
}
+ PenaltyCache[CacheKey] = Penalty;
return Penalty;
}
@@ -722,6 +1000,14 @@ private:
Newlines = std::min(Newlines, 1u);
if (Newlines == 0 && !RootToken.IsFirst)
Newlines = 1;
+ if (RootToken.IsFirst && !RootToken.HasUnescapedNewline)
+ Newlines = 0;
+
+ // Remove empty lines after "{".
+ if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
+ PreviousLine->Last->is(tok::l_brace) &&
+ PreviousLine->First->isNot(tok::kw_namespace))
+ Newlines = 1;
// Insert extra new line before access specifiers.
if (PreviousLine && PreviousLine->Last->isOneOf(tok::semi, tok::r_brace) &&
@@ -732,9 +1018,9 @@ private:
if (PreviousLine && PreviousLine->First->isAccessSpecifier())
Newlines = std::min(1u, Newlines);
- Whitespaces->replaceWhitespace(
- RootToken, Newlines, IndentLevel, Indent, Indent,
- InPPDirective && !RootToken.HasUnescapedNewline);
+ Whitespaces->replaceWhitespace(RootToken, Newlines, IndentLevel, Indent,
+ Indent, InPPDirective &&
+ !RootToken.HasUnescapedNewline);
}
/// \brief Get the indent of \p Level from \p IndentForLevel.
@@ -753,6 +1039,8 @@ private:
void join(AnnotatedLine &A, const AnnotatedLine &B) {
assert(!A.Last->Next);
assert(!B.First->Previous);
+ if (B.Affected)
+ A.Affected = true;
A.Last->Next = B.First;
B.First->Previous = A.Last;
B.First->CanBreakBefore = true;
@@ -768,47 +1056,11 @@ private:
return Style.ColumnLimit - (InPPDirective ? 2 : 0);
}
- bool touchesRanges(const CharSourceRange &Range) {
- for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(),
- E = Ranges.end();
- I != E; ++I) {
- if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), I->getBegin()) &&
- !SourceMgr.isBeforeInTranslationUnit(I->getEnd(), Range.getBegin()))
- return true;
- }
- return false;
- }
-
- bool touchesLine(const AnnotatedLine &TheLine) {
- const FormatToken *First = TheLine.First;
- const FormatToken *Last = TheLine.Last;
- CharSourceRange LineRange = CharSourceRange::getCharRange(
- First->WhitespaceRange.getBegin().getLocWithOffset(
- First->LastNewlineOffset),
- Last->getStartOfNonWhitespace().getLocWithOffset(
- Last->TokenText.size() - 1));
- return touchesRanges(LineRange);
- }
-
- bool touchesPPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
- for (; I != E; ++I) {
- if ((*I)->First->HasUnescapedNewline)
- return false;
- if (touchesLine(**I))
- return true;
+ struct CompareLineStatePointers {
+ bool operator()(LineState *obj1, LineState *obj2) const {
+ return *obj1 < *obj2;
}
- return false;
- }
-
- bool touchesEmptyLineBefore(const AnnotatedLine &TheLine) {
- const FormatToken *First = TheLine.First;
- CharSourceRange LineRange = CharSourceRange::getCharRange(
- First->WhitespaceRange.getBegin(),
- First->WhitespaceRange.getBegin().getLocWithOffset(
- First->LastNewlineOffset));
- return touchesRanges(LineRange);
- }
+ };
/// \brief Analyze the entire solution space starting from \p InitialState.
///
@@ -819,7 +1071,7 @@ private:
///
/// If \p DryRun is \c false, directly applies the changes.
unsigned analyzeSolutionSpace(LineState &InitialState, bool DryRun = false) {
- std::set<LineState> Seen;
+ std::set<LineState *, CompareLineStatePointers> Seen;
// Increasing count of \c StateNode items we have created. This is used to
// create a deterministic order independent of the container.
@@ -828,7 +1080,7 @@ private:
// Insert start element into queue.
StateNode *Node =
- new (Allocator.Allocate()) StateNode(InitialState, false, NULL);
+ new (Allocator.Allocate()) StateNode(InitialState, false, nullptr);
Queue.push(QueueItem(OrderedPenalty(0, Count), Node));
++Count;
@@ -838,7 +1090,7 @@ private:
while (!Queue.empty()) {
Penalty = Queue.top().first.first;
StateNode *Node = Queue.top().second;
- if (Node->State.NextToken == NULL) {
+ if (!Node->State.NextToken) {
DEBUG(llvm::dbgs() << "\n---\nPenalty for line: " << Penalty << "\n");
break;
}
@@ -849,7 +1101,7 @@ private:
if (Count > 10000)
Node->State.IgnoreStackForComparison = true;
- if (!Seen.insert(Node->State).second)
+ if (!Seen.insert(&Node->State).second)
// State already examined with lower penalty.
continue;
@@ -953,20 +1205,38 @@ private:
return true;
if (NewLine) {
- int AdditionalIndent = State.Stack.back().Indent -
- Previous.Children[0]->Level * Style.IndentWidth;
- Penalty += format(Previous.Children, DryRun, AdditionalIndent);
+ int AdditionalIndent =
+ State.FirstIndent - State.Line->Level * Style.IndentWidth;
+ if (State.Stack.size() < 2 ||
+ !State.Stack[State.Stack.size() - 2].JSFunctionInlined) {
+ AdditionalIndent = State.Stack.back().Indent -
+ Previous.Children[0]->Level * Style.IndentWidth;
+ }
+
+ Penalty += format(Previous.Children, DryRun, AdditionalIndent,
+ /*FixBadIndentation=*/true);
return true;
}
// Cannot merge multiple statements into a single line.
if (Previous.Children.size() > 1)
- return false;
+ return false;
+
+ // Cannot merge into one line if this line ends on a comment.
+ if (Previous.is(tok::comment))
+ return false;
// We can't put the closing "}" on a line with a trailing comment.
if (Previous.Children[0]->Last->isTrailingComment())
return false;
+ // If the child line exceeds the column limit, we wouldn't want to merge it.
+ // We add +2 for the trailing " }".
+ if (Style.ColumnLimit > 0 &&
+ Previous.Children[0]->Last->TotalLength + State.Column + 2 >
+ Style.ColumnLimit)
+ return false;
+
if (!DryRun) {
Whitespaces->replaceWhitespace(
*Previous.Children[0]->First,
@@ -979,31 +1249,43 @@ private:
return true;
}
- SourceManager &SourceMgr;
- SmallVectorImpl<CharSourceRange> &Ranges;
ContinuationIndenter *Indenter;
WhitespaceManager *Whitespaces;
FormatStyle Style;
LineJoiner Joiner;
llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
+
+ // Cache to store the penalty of formatting a vector of AnnotatedLines
+ // starting from a specific additional offset. Improves performance if there
+ // are many nested blocks.
+ std::map<std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned>,
+ unsigned> PenaltyCache;
};
class FormatTokenLexer {
public:
FormatTokenLexer(Lexer &Lex, SourceManager &SourceMgr, FormatStyle &Style,
encoding::Encoding Encoding)
- : FormatTok(NULL), IsFirstToken(true), GreaterStashed(false), Column(0),
- TrailingWhitespace(0), Lex(Lex), SourceMgr(SourceMgr), Style(Style),
- IdentTable(getFormattingLangOpts()), Encoding(Encoding) {
+ : FormatTok(nullptr), IsFirstToken(true), GreaterStashed(false),
+ Column(0), TrailingWhitespace(0), Lex(Lex), SourceMgr(SourceMgr),
+ Style(Style), IdentTable(getFormattingLangOpts()), Encoding(Encoding),
+ FirstInLineIndex(0) {
Lex.SetKeepWhitespaceMode(true);
+
+ for (const std::string &ForEachMacro : Style.ForEachMacros)
+ ForEachMacros.push_back(&IdentTable.get(ForEachMacro));
+ std::sort(ForEachMacros.begin(), ForEachMacros.end());
}
ArrayRef<FormatToken *> lex() {
assert(Tokens.empty());
+ assert(FirstInLineIndex == 0);
do {
Tokens.push_back(getNextToken());
- maybeJoinPreviousTokens();
+ tryMergePreviousTokens();
+ if (Tokens.back()->NewlinesBefore > 0)
+ FirstInLineIndex = Tokens.size() - 1;
} while (Tokens.back()->Tok.isNot(tok::eof));
return Tokens;
}
@@ -1011,23 +1293,125 @@ public:
IdentifierTable &getIdentTable() { return IdentTable; }
private:
- void maybeJoinPreviousTokens() {
- if (Tokens.size() < 4)
+ void tryMergePreviousTokens() {
+ if (tryMerge_TMacro())
return;
+ if (tryMergeConflictMarkers())
+ return;
+
+ if (Style.Language == FormatStyle::LK_JavaScript) {
+ if (tryMergeEscapeSequence())
+ return;
+ if (tryMergeJSRegexLiteral())
+ return;
+
+ static tok::TokenKind JSIdentity[] = { tok::equalequal, tok::equal };
+ static tok::TokenKind JSNotIdentity[] = { tok::exclaimequal, tok::equal };
+ static tok::TokenKind JSShiftEqual[] = { tok::greater, tok::greater,
+ tok::greaterequal };
+ static tok::TokenKind JSRightArrow[] = { tok::equal, tok::greater };
+ // FIXME: We probably need to change token type to mimic operator with the
+ // correct priority.
+ if (tryMergeTokens(JSIdentity))
+ return;
+ if (tryMergeTokens(JSNotIdentity))
+ return;
+ if (tryMergeTokens(JSShiftEqual))
+ return;
+ if (tryMergeTokens(JSRightArrow))
+ return;
+ }
+ }
+
+ bool tryMergeTokens(ArrayRef<tok::TokenKind> Kinds) {
+ if (Tokens.size() < Kinds.size())
+ return false;
+
+ SmallVectorImpl<FormatToken *>::const_iterator First =
+ Tokens.end() - Kinds.size();
+ if (!First[0]->is(Kinds[0]))
+ return false;
+ unsigned AddLength = 0;
+ for (unsigned i = 1; i < Kinds.size(); ++i) {
+ if (!First[i]->is(Kinds[i]) || First[i]->WhitespaceRange.getBegin() !=
+ First[i]->WhitespaceRange.getEnd())
+ return false;
+ AddLength += First[i]->TokenText.size();
+ }
+ Tokens.resize(Tokens.size() - Kinds.size() + 1);
+ First[0]->TokenText = StringRef(First[0]->TokenText.data(),
+ First[0]->TokenText.size() + AddLength);
+ First[0]->ColumnWidth += AddLength;
+ return true;
+ }
+
+ // Tries to merge an escape sequence, i.e. a "\\" and the following
+ // character. Use e.g. inside JavaScript regex literals.
+ bool tryMergeEscapeSequence() {
+ if (Tokens.size() < 2)
+ return false;
+ FormatToken *Previous = Tokens[Tokens.size() - 2];
+ if (Previous->isNot(tok::unknown) || Previous->TokenText != "\\" ||
+ Tokens.back()->NewlinesBefore != 0)
+ return false;
+ Previous->ColumnWidth += Tokens.back()->ColumnWidth;
+ StringRef Text = Previous->TokenText;
+ Previous->TokenText =
+ StringRef(Text.data(), Text.size() + Tokens.back()->TokenText.size());
+ Tokens.resize(Tokens.size() - 1);
+ return true;
+ }
+
+ // Try to determine whether the current token ends a JavaScript regex literal.
+ // We heuristically assume that this is a regex literal if we find two
+ // unescaped slashes on a line and the token before the first slash is one of
+ // "(;,{}![:?", a binary operator or 'return', as those cannot be followed by
+ // a division.
+ bool tryMergeJSRegexLiteral() {
+ if (Tokens.size() < 2 || Tokens.back()->isNot(tok::slash) ||
+ (Tokens[Tokens.size() - 2]->is(tok::unknown) &&
+ Tokens[Tokens.size() - 2]->TokenText == "\\"))
+ return false;
+ unsigned TokenCount = 0;
+ unsigned LastColumn = Tokens.back()->OriginalColumn;
+ for (auto I = Tokens.rbegin() + 1, E = Tokens.rend(); I != E; ++I) {
+ ++TokenCount;
+ if (I[0]->is(tok::slash) && I + 1 != E &&
+ (I[1]->isOneOf(tok::l_paren, tok::semi, tok::l_brace, tok::r_brace,
+ tok::exclaim, tok::l_square, tok::colon, tok::comma,
+ tok::question, tok::kw_return) ||
+ I[1]->isBinaryOperator())) {
+ Tokens.resize(Tokens.size() - TokenCount);
+ Tokens.back()->Tok.setKind(tok::unknown);
+ Tokens.back()->Type = TT_RegexLiteral;
+ Tokens.back()->ColumnWidth += LastColumn - I[0]->OriginalColumn;
+ return true;
+ }
+
+ // There can't be a newline inside a regex literal.
+ if (I[0]->NewlinesBefore > 0)
+ return false;
+ }
+ return false;
+ }
+
+ bool tryMerge_TMacro() {
+ if (Tokens.size() < 4)
+ return false;
FormatToken *Last = Tokens.back();
if (!Last->is(tok::r_paren))
- return;
+ return false;
FormatToken *String = Tokens[Tokens.size() - 2];
if (!String->is(tok::string_literal) || String->IsMultiline)
- return;
+ return false;
if (!Tokens[Tokens.size() - 3]->is(tok::l_paren))
- return;
+ return false;
FormatToken *Macro = Tokens[Tokens.size() - 4];
if (Macro->TokenText != "_T")
- return;
+ return false;
const char *Start = Macro->TokenText.data();
const char *End = Last->TokenText.data() + Last->TokenText.size();
@@ -1043,6 +1427,69 @@ private:
Tokens.pop_back();
Tokens.pop_back();
Tokens.back() = String;
+ return true;
+ }
+
+ bool tryMergeConflictMarkers() {
+ if (Tokens.back()->NewlinesBefore == 0 && Tokens.back()->isNot(tok::eof))
+ return false;
+
+ // Conflict lines look like:
+ // <marker> <text from the vcs>
+ // For example:
+ // >>>>>>> /file/in/file/system at revision 1234
+ //
+ // We merge all tokens in a line that starts with a conflict marker
+ // into a single token with a special token type that the unwrapped line
+ // parser will use to correctly rebuild the underlying code.
+
+ FileID ID;
+ // Get the position of the first token in the line.
+ unsigned FirstInLineOffset;
+ std::tie(ID, FirstInLineOffset) = SourceMgr.getDecomposedLoc(
+ Tokens[FirstInLineIndex]->getStartOfNonWhitespace());
+ StringRef Buffer = SourceMgr.getBuffer(ID)->getBuffer();
+ // Calculate the offset of the start of the current line.
+ auto LineOffset = Buffer.rfind('\n', FirstInLineOffset);
+ if (LineOffset == StringRef::npos) {
+ LineOffset = 0;
+ } else {
+ ++LineOffset;
+ }
+
+ auto FirstSpace = Buffer.find_first_of(" \n", LineOffset);
+ StringRef LineStart;
+ if (FirstSpace == StringRef::npos) {
+ LineStart = Buffer.substr(LineOffset);
+ } else {
+ LineStart = Buffer.substr(LineOffset, FirstSpace - LineOffset);
+ }
+
+ TokenType Type = TT_Unknown;
+ if (LineStart == "<<<<<<<" || LineStart == ">>>>") {
+ Type = TT_ConflictStart;
+ } else if (LineStart == "|||||||" || LineStart == "=======" ||
+ LineStart == "====") {
+ Type = TT_ConflictAlternative;
+ } else if (LineStart == ">>>>>>>" || LineStart == "<<<<") {
+ Type = TT_ConflictEnd;
+ }
+
+ if (Type != TT_Unknown) {
+ FormatToken *Next = Tokens.back();
+
+ Tokens.resize(FirstInLineIndex + 1);
+ // We do not need to build a complete token here, as we will skip it
+ // during parsing anyway (as we must not touch whitespace around conflict
+ // markers).
+ Tokens.back()->Type = Type;
+ Tokens.back()->Tok.setKind(tok::kw___unknown_anytype);
+
+ Tokens.push_back(Next);
+ return true;
+ }
+
+ return false;
}
FormatToken *getNextToken() {
@@ -1122,7 +1569,7 @@ private:
// FIXME: Add a more explicit test.
while (FormatTok->TokenText.size() > 1 && FormatTok->TokenText[0] == '\\' &&
FormatTok->TokenText[1] == '\n') {
- // FIXME: ++FormatTok->NewlinesBefore is missing...
+ ++FormatTok->NewlinesBefore;
WhitespaceLength += 2;
Column = 0;
FormatTok->TokenText = FormatTok->TokenText.substr(2);
@@ -1174,6 +1621,10 @@ private:
Column = FormatTok->LastLineColumnWidth;
}
+ FormatTok->IsForEachMacro =
+ std::binary_search(ForEachMacros.begin(), ForEachMacros.end(),
+ FormatTok->Tok.getIdentifierInfo());
+
return FormatTok;
}
@@ -1188,7 +1639,10 @@ private:
IdentifierTable IdentTable;
encoding::Encoding Encoding;
llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
+ // Index (in 'Tokens') of the last token that starts a new line.
+ unsigned FirstInLineIndex;
SmallVector<FormatToken *, 16> Tokens;
+ SmallVector<IdentifierInfo *, 8> ForEachMacros;
void readRawToken(FormatToken &Tok) {
Lex.LexFromRawLexer(Tok.Tok);
@@ -1196,14 +1650,31 @@ private:
Tok.Tok.getLength());
// For formatting, treat unterminated string literals like normal string
// literals.
- if (Tok.is(tok::unknown) && !Tok.TokenText.empty() &&
- Tok.TokenText[0] == '"') {
- Tok.Tok.setKind(tok::string_literal);
- Tok.IsUnterminatedLiteral = true;
+ if (Tok.is(tok::unknown)) {
+ if (!Tok.TokenText.empty() && Tok.TokenText[0] == '"') {
+ Tok.Tok.setKind(tok::string_literal);
+ Tok.IsUnterminatedLiteral = true;
+ } else if (Style.Language == FormatStyle::LK_JavaScript &&
+ Tok.TokenText == "''") {
+ Tok.Tok.setKind(tok::char_constant);
+ }
}
}
};
+static StringRef getLanguageName(FormatStyle::LanguageKind Language) {
+ switch (Language) {
+ case FormatStyle::LK_Cpp:
+ return "C++";
+ case FormatStyle::LK_JavaScript:
+ return "JavaScript";
+ case FormatStyle::LK_Proto:
+ return "Proto";
+ default:
+ return "Unknown";
+ }
+}
+
class Formatter : public UnwrappedLineConsumer {
public:
Formatter(const FormatStyle &Style, Lexer &Lex, SourceManager &SourceMgr,
@@ -1216,6 +1687,8 @@ public:
<< (Encoding == encoding::Encoding_UTF8 ? "UTF8"
: "unknown")
<< "\n");
+ DEBUG(llvm::dbgs() << "Language: " << getLanguageName(Style.Language)
+ << "\n");
}
tooling::Replacements format() {
@@ -1261,17 +1734,151 @@ public:
for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
Annotator.calculateFormattingInformation(*AnnotatedLines[i]);
}
+ computeAffectedLines(AnnotatedLines.begin(), AnnotatedLines.end());
Annotator.setCommentLineLevels(AnnotatedLines);
ContinuationIndenter Indenter(Style, SourceMgr, Whitespaces, Encoding,
BinPackInconclusiveFunctions);
- UnwrappedLineFormatter Formatter(SourceMgr, Ranges, &Indenter, &Whitespaces,
- Style);
+ UnwrappedLineFormatter Formatter(&Indenter, &Whitespaces, Style);
Formatter.format(AnnotatedLines, /*DryRun=*/false);
return Whitespaces.generateReplacements();
}
private:
+ // Determines which lines are affected by the SourceRanges given as input.
+ // Returns \c true if at least one line between I and E or one of their
+ // children is affected.
+ bool computeAffectedLines(SmallVectorImpl<AnnotatedLine *>::iterator I,
+ SmallVectorImpl<AnnotatedLine *>::iterator E) {
+ bool SomeLineAffected = false;
+ const AnnotatedLine *PreviousLine = nullptr;
+ while (I != E) {
+ AnnotatedLine *Line = *I;
+ Line->LeadingEmptyLinesAffected = affectsLeadingEmptyLines(*Line->First);
+
+ // If a line is part of a preprocessor directive, it needs to be formatted
+ // if any token within the directive is affected.
+ if (Line->InPPDirective) {
+ FormatToken *Last = Line->Last;
+ SmallVectorImpl<AnnotatedLine *>::iterator PPEnd = I + 1;
+ while (PPEnd != E && !(*PPEnd)->First->HasUnescapedNewline) {
+ Last = (*PPEnd)->Last;
+ ++PPEnd;
+ }
+
+ if (affectsTokenRange(*Line->First, *Last,
+ /*IncludeLeadingNewlines=*/false)) {
+ SomeLineAffected = true;
+ markAllAsAffected(I, PPEnd);
+ }
+ I = PPEnd;
+ continue;
+ }
+
+ if (nonPPLineAffected(Line, PreviousLine))
+ SomeLineAffected = true;
+
+ PreviousLine = Line;
+ ++I;
+ }
+ return SomeLineAffected;
+ }
+
+ // Determines whether 'Line' is affected by the SourceRanges given as input.
+ // Returns \c true if line or one if its children is affected.
+ bool nonPPLineAffected(AnnotatedLine *Line,
+ const AnnotatedLine *PreviousLine) {
+ bool SomeLineAffected = false;
+ Line->ChildrenAffected =
+ computeAffectedLines(Line->Children.begin(), Line->Children.end());
+ if (Line->ChildrenAffected)
+ SomeLineAffected = true;
+
+ // Stores whether one of the line's tokens is directly affected.
+ bool SomeTokenAffected = false;
+ // Stores whether we need to look at the leading newlines of the next token
+ // in order to determine whether it was affected.
+ bool IncludeLeadingNewlines = false;
+
+ // Stores whether the first child line of any of this line's tokens is
+ // affected.
+ bool SomeFirstChildAffected = false;
+
+ for (FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
+ // Determine whether 'Tok' was affected.
+ if (affectsTokenRange(*Tok, *Tok, IncludeLeadingNewlines))
+ SomeTokenAffected = true;
+
+ // Determine whether the first child of 'Tok' was affected.
+ if (!Tok->Children.empty() && Tok->Children.front()->Affected)
+ SomeFirstChildAffected = true;
+
+ IncludeLeadingNewlines = Tok->Children.empty();
+ }
+
+ // Was this line moved, i.e. has it previously been on the same line as an
+ // affected line?
+ bool LineMoved = PreviousLine && PreviousLine->Affected &&
+ Line->First->NewlinesBefore == 0;
+
+ bool IsContinuedComment =
+ Line->First->is(tok::comment) && Line->First->Next == nullptr &&
+ Line->First->NewlinesBefore < 2 && PreviousLine &&
+ PreviousLine->Affected && PreviousLine->Last->is(tok::comment);
+
+ if (SomeTokenAffected || SomeFirstChildAffected || LineMoved ||
+ IsContinuedComment) {
+ Line->Affected = true;
+ SomeLineAffected = true;
+ }
+ return SomeLineAffected;
+ }
+
+ // Marks all lines between I and E as well as all their children as affected.
+ void markAllAsAffected(SmallVectorImpl<AnnotatedLine *>::iterator I,
+ SmallVectorImpl<AnnotatedLine *>::iterator E) {
+ while (I != E) {
+ (*I)->Affected = true;
+ markAllAsAffected((*I)->Children.begin(), (*I)->Children.end());
+ ++I;
+ }
+ }
+
+ // Returns true if the range from 'First' to 'Last' intersects with one of the
+ // input ranges.
+ bool affectsTokenRange(const FormatToken &First, const FormatToken &Last,
+ bool IncludeLeadingNewlines) {
+ SourceLocation Start = First.WhitespaceRange.getBegin();
+ if (!IncludeLeadingNewlines)
+ Start = Start.getLocWithOffset(First.LastNewlineOffset);
+ SourceLocation End = Last.getStartOfNonWhitespace();
+ if (Last.TokenText.size() > 0)
+ End = End.getLocWithOffset(Last.TokenText.size() - 1);
+ CharSourceRange Range = CharSourceRange::getCharRange(Start, End);
+ return affectsCharSourceRange(Range);
+ }
+
+ // Returns true if one of the input ranges intersect the leading empty lines
+ // before 'Tok'.
+ bool affectsLeadingEmptyLines(const FormatToken &Tok) {
+ CharSourceRange EmptyLineRange = CharSourceRange::getCharRange(
+ Tok.WhitespaceRange.getBegin(),
+ Tok.WhitespaceRange.getBegin().getLocWithOffset(Tok.LastNewlineOffset));
+ return affectsCharSourceRange(EmptyLineRange);
+ }
+
+ // Returns true if 'Range' intersects with one of the input ranges.
+ bool affectsCharSourceRange(const CharSourceRange &Range) {
+ for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(),
+ E = Ranges.end();
+ I != E; ++I) {
+ if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), I->getBegin()) &&
+ !SourceMgr.isBeforeInTranslationUnit(I->getEnd(), Range.getBegin()))
+ return true;
+ }
+ return false;
+ }
+
static bool inputUsesCRLF(StringRef Text) {
return Text.count('\r') * 2 > Text.count('\n');
}
@@ -1316,11 +1923,11 @@ private:
Tok = Tok->Next;
}
}
- if (Style.DerivePointerBinding) {
+ if (Style.DerivePointerAlignment) {
if (CountBoundToType > CountBoundToVariable)
- Style.PointerBindsToType = true;
+ Style.PointerAlignment = FormatStyle::PAS_Left;
else if (CountBoundToType < CountBoundToVariable)
- Style.PointerBindsToType = false;
+ Style.PointerAlignment = FormatStyle::PAS_Right;
}
if (Style.Standard == FormatStyle::LS_Auto) {
Style.Standard = HasCpp03IncompatibleFormat ? FormatStyle::LS_Cpp11
@@ -1330,12 +1937,12 @@ private:
HasBinPackedFunction || !HasOnePerLineFunction;
}
- virtual void consumeUnwrappedLine(const UnwrappedLine &TheLine) {
+ void consumeUnwrappedLine(const UnwrappedLine &TheLine) override {
assert(!UnwrappedLines.empty());
UnwrappedLines.back().push_back(TheLine);
}
- virtual void finishRun() {
+ void finishRun() override {
UnwrappedLines.push_back(SmallVector<UnwrappedLine, 16>());
}
@@ -1355,6 +1962,11 @@ private:
tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex,
SourceManager &SourceMgr,
std::vector<CharSourceRange> Ranges) {
+ if (Style.DisableFormat) {
+ tooling::Replacements EmptyResult;
+ return EmptyResult;
+ }
+
Formatter formatter(Style, Lex, SourceMgr, Ranges);
return formatter.format();
}
@@ -1389,7 +2001,9 @@ LangOptions getFormattingLangOpts(FormatStyle::LanguageStandard Standard) {
LangOptions LangOpts;
LangOpts.CPlusPlus = 1;
LangOpts.CPlusPlus11 = Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
+ LangOpts.CPlusPlus1y = Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
LangOpts.LineComment = 1;
+ LangOpts.CXXOperatorNames = 1;
LangOpts.Bool = 1;
LangOpts.ObjC1 = 1;
LangOpts.ObjC2 = 1;
@@ -1407,15 +2021,29 @@ const char *StyleOptionHelpDescription =
"parameters, e.g.:\n"
" -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
-FormatStyle getStyle(StringRef StyleName, StringRef FileName) {
- // Fallback style in case the rest of this function can't determine a style.
- StringRef FallbackStyle = "LLVM";
- FormatStyle Style;
- getPredefinedStyle(FallbackStyle, &Style);
+static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
+ if (FileName.endswith_lower(".js")) {
+ return FormatStyle::LK_JavaScript;
+ } else if (FileName.endswith_lower(".proto") ||
+ FileName.endswith_lower(".protodevel")) {
+ return FormatStyle::LK_Proto;
+ }
+ return FormatStyle::LK_Cpp;
+}
+
+FormatStyle getStyle(StringRef StyleName, StringRef FileName,
+ StringRef FallbackStyle) {
+ FormatStyle Style = getLLVMStyle();
+ Style.Language = getLanguageByFileName(FileName);
+ if (!getPredefinedStyle(FallbackStyle, Style.Language, &Style)) {
+ llvm::errs() << "Invalid fallback style \"" << FallbackStyle
+ << "\" using LLVM style\n";
+ return Style;
+ }
if (StyleName.startswith("{")) {
// Parse YAML/JSON style from the command line.
- if (llvm::error_code ec = parseConfiguration(StyleName, &Style)) {
+ if (std::error_code ec = parseConfiguration(StyleName, &Style)) {
llvm::errs() << "Error parsing -style: " << ec.message() << ", using "
<< FallbackStyle << " style\n";
}
@@ -1423,12 +2051,14 @@ FormatStyle getStyle(StringRef StyleName, StringRef FileName) {
}
if (!StyleName.equals_lower("file")) {
- if (!getPredefinedStyle(StyleName, &Style))
+ if (!getPredefinedStyle(StyleName, Style.Language, &Style))
llvm::errs() << "Invalid value for -style, using " << FallbackStyle
<< " style\n";
return Style;
}
+ // Look for .clang-format/_clang-format file in the file's parent directories.
+ SmallString<128> UnsuitableConfigFiles;
SmallString<128> Path(FileName);
llvm::sys::fs::make_absolute(Path);
for (StringRef Directory = Path; !Directory.empty();
@@ -1453,16 +2083,23 @@ FormatStyle getStyle(StringRef StyleName, StringRef FileName) {
}
if (IsFile) {
- OwningPtr<llvm::MemoryBuffer> Text;
- if (llvm::error_code ec =
- llvm::MemoryBuffer::getFile(ConfigFile.c_str(), Text)) {
- llvm::errs() << ec.message() << "\n";
- continue;
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
+ llvm::MemoryBuffer::getFile(ConfigFile.c_str());
+ if (std::error_code EC = Text.getError()) {
+ llvm::errs() << EC.message() << "\n";
+ break;
}
- if (llvm::error_code ec = parseConfiguration(Text->getBuffer(), &Style)) {
+ if (std::error_code ec =
+ parseConfiguration(Text.get()->getBuffer(), &Style)) {
+ if (ec == ParseError::Unsuitable) {
+ if (!UnsuitableConfigFiles.empty())
+ UnsuitableConfigFiles.append(", ");
+ UnsuitableConfigFiles.append(ConfigFile);
+ continue;
+ }
llvm::errs() << "Error reading " << ConfigFile << ": " << ec.message()
<< "\n";
- continue;
+ break;
}
DEBUG(llvm::dbgs() << "Using configuration file " << ConfigFile << "\n");
return Style;
@@ -1470,6 +2107,11 @@ FormatStyle getStyle(StringRef StyleName, StringRef FileName) {
}
llvm::errs() << "Can't find usable .clang-format, using " << FallbackStyle
<< " style\n";
+ if (!UnsuitableConfigFiles.empty()) {
+ llvm::errs() << "Configuration file(s) do(es) not support "
+ << getLanguageName(Style.Language) << ": "
+ << UnsuitableConfigFiles << "\n";
+ }
return Style;
}
diff --git a/lib/Format/FormatToken.cpp b/lib/Format/FormatToken.cpp
index 8ac704a3bb6d..c91d25f46de1 100644
--- a/lib/Format/FormatToken.cpp
+++ b/lib/Format/FormatToken.cpp
@@ -22,34 +22,65 @@
namespace clang {
namespace format {
+// FIXME: This is copy&pasted from Sema. Put it in a common place and remove
+// duplication.
+bool FormatToken::isSimpleTypeSpecifier() const {
+ switch (Tok.getKind()) {
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw___int64:
+ case tok::kw___int128:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_int:
+ case tok::kw_half:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_wchar_t:
+ case tok::kw_bool:
+ case tok::kw___underlying_type:
+ case tok::annot_typename:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+ case tok::kw_typeof:
+ case tok::kw_decltype:
+ return true;
+ default:
+ return false;
+ }
+}
+
TokenRole::~TokenRole() {}
void TokenRole::precomputeFormattingInfos(const FormatToken *Token) {}
-unsigned CommaSeparatedList::format(LineState &State,
- ContinuationIndenter *Indenter,
- bool DryRun) {
- if (!State.NextToken->Previous || !State.NextToken->Previous->Previous ||
- Commas.size() <= 2)
+unsigned CommaSeparatedList::formatAfterToken(LineState &State,
+ ContinuationIndenter *Indenter,
+ bool DryRun) {
+ if (!State.NextToken->Previous || !State.NextToken->Previous->Previous)
return 0;
// Ensure that we start on the opening brace.
const FormatToken *LBrace = State.NextToken->Previous->Previous;
- if (LBrace->isNot(tok::l_brace) ||
- LBrace->BlockKind == BK_Block ||
+ if (LBrace->isNot(tok::l_brace) || LBrace->BlockKind == BK_Block ||
LBrace->Type == TT_DictLiteral ||
LBrace->Next->Type == TT_DesignatedInitializerPeriod)
return 0;
// Calculate the number of code points we have to format this list. As the
// first token is already placed, we have to subtract it.
- unsigned RemainingCodePoints = Style.ColumnLimit - State.Column +
- State.NextToken->Previous->ColumnWidth;
+ unsigned RemainingCodePoints =
+ Style.ColumnLimit - State.Column + State.NextToken->Previous->ColumnWidth;
// Find the best ColumnFormat, i.e. the best number of columns to use.
const ColumnFormat *Format = getColumnFormat(RemainingCodePoints);
+ // If no ColumnFormat can be used, the braced list would generally be
+ // bin-packed. Add a severe penalty to this so that column layouts are
+ // preferred if possible.
if (!Format)
- return 0;
+ return 10000;
// Format the entire list.
unsigned Penalty = 0;
@@ -79,6 +110,14 @@ unsigned CommaSeparatedList::format(LineState &State,
return Penalty;
}
+unsigned CommaSeparatedList::formatFromToken(LineState &State,
+ ContinuationIndenter *Indenter,
+ bool DryRun) {
+ if (HasNestedBracedList)
+ State.Stack.back().AvoidBinPacking = true;
+ return 0;
+}
+
// Returns the lengths in code points between Begin and End (both included),
// assuming that the entire sequence is put on a single line.
static unsigned CodePointsBetween(const FormatToken *Begin,
@@ -92,6 +131,11 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
if (!Token->MatchingParen || Token->isNot(tok::l_brace))
return;
+ // In C++11 braced list style, we should not format in columns unless we allow
+ // bin-packing of function parameters.
+ if (Style.Cpp11BracedListStyle && !Style.BinPackParameters)
+ return;
+
FormatToken *ItemBegin = Token->Next;
SmallVector<bool, 8> MustBreakBeforeItem;
@@ -99,7 +143,6 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
// trailing comments which are otherwise ignored for column alignment.
SmallVector<unsigned, 8> EndOfLineItemLength;
- bool HasNestedBracedList = false;
for (unsigned i = 0, e = Commas.size() + 1; i != e; ++i) {
// Skip comments on their own line.
while (ItemBegin->HasUnescapedNewline && ItemBegin->isTrailingComment())
@@ -108,7 +151,7 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
MustBreakBeforeItem.push_back(ItemBegin->MustBreakBefore);
if (ItemBegin->is(tok::l_brace))
HasNestedBracedList = true;
- const FormatToken *ItemEnd = NULL;
+ const FormatToken *ItemEnd = nullptr;
if (i == Commas.size()) {
ItemEnd = Token->MatchingParen;
const FormatToken *NonCommentEnd = ItemEnd->getPreviousNonComment();
@@ -139,6 +182,12 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
ItemBegin = ItemEnd->Next;
}
+ // If this doesn't have a nested list, we require at least 6 elements in order
+ // create a column layout. If it has a nested list, column layout ensures one
+ // list element per line.
+ if (HasNestedBracedList || Commas.size() < 5 || Token->NestingLevel != 0)
+ return;
+
// We can never place more than ColumnLimit / 3 items in a row (because of the
// spaces and the comma).
for (unsigned Columns = 1; Columns <= Style.ColumnLimit / 3; ++Columns) {
@@ -158,8 +207,7 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
HasRowWithSufficientColumns = true;
unsigned length =
(Column == Columns - 1) ? EndOfLineItemLength[i] : ItemLengths[i];
- Format.ColumnSizes[Column] =
- std::max(Format.ColumnSizes[Column], length);
+ Format.ColumnSizes[Column] = std::max(Format.ColumnSizes[Column], length);
++Column;
}
// If all rows are terminated early (e.g. by trailing comments), we don't
@@ -175,18 +223,13 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
if (Format.TotalWidth > Style.ColumnLimit)
continue;
- // If this braced list has nested braced list, we format it either with one
- // element per line or with all elements on one line.
- if (HasNestedBracedList && Columns > 1 && Format.LineCount > 1)
- continue;
-
Formats.push_back(Format);
}
}
const CommaSeparatedList::ColumnFormat *
CommaSeparatedList::getColumnFormat(unsigned RemainingCharacters) const {
- const ColumnFormat *BestFormat = NULL;
+ const ColumnFormat *BestFormat = nullptr;
for (SmallVector<ColumnFormat, 4>::const_reverse_iterator
I = Formats.rbegin(),
E = Formats.rend();
diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h
index 2145ee28dcc0..c376c5009559 100644
--- a/lib/Format/FormatToken.h
+++ b/lib/Format/FormatToken.h
@@ -19,7 +19,7 @@
#include "clang/Basic/OperatorPrecedence.h"
#include "clang/Format/Format.h"
#include "clang/Lex/Lexer.h"
-#include "llvm/ADT/OwningPtr.h"
+#include <memory>
namespace clang {
namespace format {
@@ -27,36 +27,45 @@ namespace format {
enum TokenType {
TT_ArrayInitializerLSquare,
TT_ArraySubscriptLSquare,
+ TT_AttributeParen,
TT_BinaryOperator,
TT_BitFieldColon,
TT_BlockComment,
TT_CastRParen,
TT_ConditionalExpr,
+ TT_ConflictAlternative,
+ TT_ConflictEnd,
+ TT_ConflictStart,
TT_CtorInitializerColon,
TT_CtorInitializerComma,
TT_DesignatedInitializerPeriod,
TT_DictLiteral,
+ TT_FunctionDeclarationName,
+ TT_FunctionLBrace,
+ TT_FunctionTypeLParen,
TT_ImplicitStringLiteral,
- TT_InlineASMColon,
TT_InheritanceColon,
- TT_FunctionTypeLParen,
+ TT_InlineASMColon,
TT_LambdaLSquare,
TT_LineComment,
+ TT_ObjCBlockLBrace,
TT_ObjCBlockLParen,
TT_ObjCDecl,
TT_ObjCForIn,
TT_ObjCMethodExpr,
TT_ObjCMethodSpecifier,
TT_ObjCProperty,
- TT_ObjCSelectorName,
TT_OverloadedOperator,
TT_OverloadedOperatorLParen,
TT_PointerOrReference,
TT_PureVirtualSpecifier,
TT_RangeBasedForLoopColon,
+ TT_RegexLiteral,
+ TT_SelectorName,
TT_StartOfName,
TT_TemplateCloser,
TT_TemplateOpener,
+ TT_TrailingAnnotation,
TT_TrailingReturnArrow,
TT_TrailingUnaryOperator,
TT_UnaryOperator,
@@ -87,7 +96,7 @@ class TokenRole;
class AnnotatedLine;
/// \brief A wrapper around a \c Token storing information about the
-/// whitespace characters preceeding it.
+/// whitespace characters preceding it.
struct FormatToken {
FormatToken()
: NewlinesBefore(0), HasUnescapedNewline(false), LastNewlineOffset(0),
@@ -95,12 +104,14 @@ struct FormatToken {
IsFirst(false), MustBreakBefore(false), IsUnterminatedLiteral(false),
BlockKind(BK_Unknown), Type(TT_Unknown), SpacesRequiredBefore(0),
CanBreakBefore(false), ClosesTemplateDeclaration(false),
- ParameterCount(0), PackingKind(PPK_Inconclusive), TotalLength(0),
- UnbreakableTailLength(0), BindingStrength(0), SplitPenalty(0),
+ ParameterCount(0), BlockParameterCount(0),
+ PackingKind(PPK_Inconclusive), TotalLength(0), UnbreakableTailLength(0),
+ BindingStrength(0), NestingLevel(0), SplitPenalty(0),
LongestObjCSelectorName(0), FakeRParens(0),
StartsBinaryExpression(false), EndsBinaryExpression(false),
- LastInChainOfCalls(false), PartOfMultiVariableDeclStmt(false),
- MatchingParen(NULL), Previous(NULL), Next(NULL),
+ OperatorIndex(0), LastOperator(false),
+ PartOfMultiVariableDeclStmt(false), IsForEachMacro(false),
+ MatchingParen(nullptr), Previous(nullptr), Next(nullptr),
Decision(FD_Unformatted), Finalized(false) {}
/// \brief The \c Token.
@@ -116,7 +127,7 @@ struct FormatToken {
/// Token.
bool HasUnescapedNewline;
- /// \brief The range of the whitespace immediately preceeding the \c Token.
+ /// \brief The range of the whitespace immediately preceding the \c Token.
SourceRange WhitespaceRange;
/// \brief The offset just past the last '\n' in this token's leading
@@ -182,9 +193,13 @@ struct FormatToken {
/// the number of commas.
unsigned ParameterCount;
+ /// \brief Number of parameters that are nested blocks,
+ /// if this is "(", "[" or "<".
+ unsigned BlockParameterCount;
+
/// \brief A token can have a special role that can carry extra information
/// about the token's formatting.
- llvm::OwningPtr<TokenRole> Role;
+ std::unique_ptr<TokenRole> Role;
/// \brief If this is an opening parenthesis, how are the parameters packed?
ParameterPackingKind PackingKind;
@@ -206,11 +221,18 @@ struct FormatToken {
/// operator precedence, parenthesis nesting, etc.
unsigned BindingStrength;
+ /// \brief The nesting level of this token, i.e. the number of surrounding (),
+ /// [], {} or <>.
+ unsigned NestingLevel;
+
/// \brief Penalty for inserting a line break before this token.
unsigned SplitPenalty;
/// \brief If this is the first ObjC selector name in an ObjC method
/// definition or call, this contains the length of the longest name.
+ ///
+ /// This being set to 0 means that the selectors should not be colon-aligned,
+ /// e.g. because several of them are block-type.
unsigned LongestObjCSelectorName;
/// \brief Stores the number of required fake parentheses and the
@@ -228,14 +250,22 @@ struct FormatToken {
/// \brief \c true if this token ends a binary expression.
bool EndsBinaryExpression;
- /// \brief Is this the last "." or "->" in a builder-type call?
- bool LastInChainOfCalls;
+ /// \brief Is this is an operator (or "."/"->") in a sequence of operators
+ /// with the same precedence, contains the 0-based operator index.
+ unsigned OperatorIndex;
+
+ /// \brief Is this the last operator (or "."/"->") in a sequence of operators
+ /// with the same precedence?
+ bool LastOperator;
/// \brief Is this token part of a \c DeclStmt defining multiple variables?
///
/// Only set if \c Type == \c TT_StartOfName.
bool PartOfMultiVariableDeclStmt;
+ /// \brief Is this a foreach macro?
+ bool IsForEachMacro;
+
bool is(tok::TokenKind Kind) const { return Tok.is(Kind); }
bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const {
@@ -260,6 +290,7 @@ struct FormatToken {
}
bool isNot(tok::TokenKind Kind) const { return Tok.isNot(Kind); }
+ bool isStringLiteral() const { return tok::isStringLiteral(Tok.getKind()); }
bool isObjCAtKeyword(tok::ObjCKeywordKind Kind) const {
return Tok.isObjCAtKeyword(Kind);
@@ -270,6 +301,9 @@ struct FormatToken {
(!ColonRequired || (Next && Next->is(tok::colon)));
}
+ /// \brief Determine whether the token is a simple-type-specifier.
+ bool isSimpleTypeSpecifier() const;
+
bool isObjCAccessSpecifier() const {
return is(tok::at) && Next && (Next->isObjCAtKeyword(tok::objc_public) ||
Next->isObjCAtKeyword(tok::objc_protected) ||
@@ -290,7 +324,7 @@ struct FormatToken {
/// \brief Returns \c true if this is a "." or "->" accessing a member.
bool isMemberAccess() const {
- return isOneOf(tok::arrow, tok::period) &&
+ return isOneOf(tok::arrow, tok::period, tok::arrowstar) &&
Type != TT_DesignatedInitializerPeriod;
}
@@ -326,7 +360,7 @@ struct FormatToken {
/// \brief Returns the previous token ignoring comments.
FormatToken *getPreviousNonComment() const {
FormatToken *Tok = Previous;
- while (Tok != NULL && Tok->is(tok::comment))
+ while (Tok && Tok->is(tok::comment))
Tok = Tok->Previous;
return Tok;
}
@@ -334,7 +368,7 @@ struct FormatToken {
/// \brief Returns the next token ignoring comments.
const FormatToken *getNextNonComment() const {
const FormatToken *Tok = Next;
- while (Tok != NULL && Tok->is(tok::comment))
+ while (Tok && Tok->is(tok::comment))
Tok = Tok->Next;
return Tok;
}
@@ -388,10 +422,21 @@ public:
/// \brief Apply the special formatting that the given role demands.
///
+ /// Assumes that the token having this role is already formatted.
+ ///
/// Continues formatting from \p State leaving indentation to \p Indenter and
/// returns the total penalty that this formatting incurs.
- virtual unsigned format(LineState &State, ContinuationIndenter *Indenter,
- bool DryRun) {
+ virtual unsigned formatFromToken(LineState &State,
+ ContinuationIndenter *Indenter,
+ bool DryRun) {
+ return 0;
+ }
+
+ /// \brief Same as \c formatFromToken, but assumes that the first token has
+ /// already been set thereby deciding on the first line break.
+ virtual unsigned formatAfterToken(LineState &State,
+ ContinuationIndenter *Indenter,
+ bool DryRun) {
return 0;
}
@@ -404,15 +449,21 @@ protected:
class CommaSeparatedList : public TokenRole {
public:
- CommaSeparatedList(const FormatStyle &Style) : TokenRole(Style) {}
+ CommaSeparatedList(const FormatStyle &Style)
+ : TokenRole(Style), HasNestedBracedList(false) {}
- virtual void precomputeFormattingInfos(const FormatToken *Token);
+ void precomputeFormattingInfos(const FormatToken *Token) override;
+
+ unsigned formatAfterToken(LineState &State, ContinuationIndenter *Indenter,
+ bool DryRun) override;
- virtual unsigned format(LineState &State, ContinuationIndenter *Indenter,
- bool DryRun);
+ unsigned formatFromToken(LineState &State, ContinuationIndenter *Indenter,
+ bool DryRun) override;
/// \brief Adds \p Token as the next comma to the \c CommaSeparated list.
- virtual void CommaFound(const FormatToken *Token) { Commas.push_back(Token); }
+ void CommaFound(const FormatToken *Token) override {
+ Commas.push_back(Token);
+ }
private:
/// \brief A struct that holds information on how to format a given list with
@@ -444,6 +495,8 @@ private:
/// \brief Precomputed formats that can be used for this list.
SmallVector<ColumnFormat, 4> Formats;
+
+ bool HasNestedBracedList;
};
} // namespace format
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index 074e1d78454b..017afe1a370b 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -17,6 +17,8 @@
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/Debug.h"
+#define DEBUG_TYPE "format-token-annotator"
+
namespace clang {
namespace format {
@@ -34,16 +36,22 @@ public:
: Style(Style), Line(Line), CurrentToken(Line.First),
KeywordVirtualFound(false), AutoFound(false), Ident_in(Ident_in) {
Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false));
+ resetTokenMetadata(CurrentToken);
}
private:
bool parseAngle() {
- if (CurrentToken == NULL)
+ if (!CurrentToken)
return false;
ScopedContextCreator ContextCreator(*this, tok::less, 10);
FormatToken *Left = CurrentToken->Previous;
Contexts.back().IsExpression = false;
- while (CurrentToken != NULL) {
+ // If there's a template keyword before the opening angle bracket, this is a
+ // template parameter, not an argument.
+ Contexts.back().InTemplateArgument =
+ Left->Previous && Left->Previous->Tok.isNot(tok::kw_template);
+
+ while (CurrentToken) {
if (CurrentToken->is(tok::greater)) {
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
@@ -61,7 +69,11 @@ private:
// parameters.
// FIXME: This is getting out of hand, write a decent parser.
if (CurrentToken->Previous->isOneOf(tok::pipepipe, tok::ampamp) &&
- (CurrentToken->Previous->Type == TT_BinaryOperator ||
+ ((CurrentToken->Previous->Type == TT_BinaryOperator &&
+ // Toplevel bool expressions do not make lots of sense;
+ // If we're on the top level, it contains only the base context and
+ // the context for the current opening angle bracket.
+ Contexts.size() > 2) ||
Contexts[Contexts.size() - 2].IsExpression) &&
Line.First->isNot(tok::kw_template))
return false;
@@ -73,7 +85,7 @@ private:
}
bool parseParens(bool LookForDecls = false) {
- if (CurrentToken == NULL)
+ if (!CurrentToken)
return false;
ScopedContextCreator ContextCreator(*this, tok::l_paren, 1);
@@ -84,7 +96,7 @@ private:
bool StartsObjCMethodExpr = false;
FormatToken *Left = CurrentToken->Previous;
if (CurrentToken->is(tok::caret)) {
- // ^( starts a block.
+ // (^ can start a block type.
Left->Type = TT_ObjCBlockLParen;
} else if (FormatToken *MaybeSel = Left->Previous) {
// @selector( starts a selector.
@@ -94,15 +106,31 @@ private:
}
}
- if (Left->Previous && Left->Previous->isOneOf(tok::kw_static_assert,
- tok::kw_if, tok::kw_while)) {
+ if (Left->Previous &&
+ (Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_if,
+ tok::kw_while, tok::l_paren, tok::comma) ||
+ Left->Previous->Type == TT_BinaryOperator)) {
// static_assert, if and while usually contain expressions.
Contexts.back().IsExpression = true;
+ } else if (Line.InPPDirective &&
+ (!Left->Previous ||
+ (Left->Previous->isNot(tok::identifier) &&
+ Left->Previous->Type != TT_OverloadedOperator))) {
+ Contexts.back().IsExpression = true;
} else if (Left->Previous && Left->Previous->is(tok::r_square) &&
Left->Previous->MatchingParen &&
Left->Previous->MatchingParen->Type == TT_LambdaLSquare) {
// This is a parameter list of a lambda expression.
Contexts.back().IsExpression = false;
+ } else if (Contexts[Contexts.size() - 2].CaretFound) {
+ // This is the parameter list of an ObjC block.
+ Contexts.back().IsExpression = false;
+ } else if (Left->Previous && Left->Previous->is(tok::kw___attribute)) {
+ Left->Type = TT_AttributeParen;
+ } else if (Left->Previous && Left->Previous->IsForEachMacro) {
+ // The first argument to a foreach macro is a declaration.
+ Contexts.back().IsForEachMacro = true;
+ Contexts.back().IsExpression = false;
}
if (StartsObjCMethodExpr) {
@@ -113,7 +141,7 @@ private:
bool MightBeFunctionType = CurrentToken->is(tok::star);
bool HasMultipleLines = false;
bool HasMultipleParametersOnALine = false;
- while (CurrentToken != NULL) {
+ while (CurrentToken) {
// LookForDecls is set when "if (" has been seen. Check for
// 'identifier' '*' 'identifier' followed by not '=' -- this
// '*' has to be a binary operator but determineStarAmpUsage() will
@@ -136,6 +164,8 @@ private:
CurrentToken->Previous->Previous->isOneOf(tok::l_paren,
tok::coloncolon))
MightBeFunctionType = true;
+ if (CurrentToken->Previous->Type == TT_BinaryOperator)
+ Contexts.back().IsExpression = true;
if (CurrentToken->is(tok::r_paren)) {
if (MightBeFunctionType && CurrentToken->Next &&
(CurrentToken->Next->is(tok::l_paren) ||
@@ -147,12 +177,15 @@ private:
if (StartsObjCMethodExpr) {
CurrentToken->Type = TT_ObjCMethodExpr;
- if (Contexts.back().FirstObjCSelectorName != NULL) {
+ if (Contexts.back().FirstObjCSelectorName) {
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
Contexts.back().LongestObjCSelectorName;
}
}
+ if (Left->Type == TT_AttributeParen)
+ CurrentToken->Type = TT_AttributeParen;
+
if (!HasMultipleLines)
Left->PackingKind = PPK_Inconclusive;
else if (HasMultipleParametersOnALine)
@@ -165,13 +198,19 @@ private:
}
if (CurrentToken->isOneOf(tok::r_square, tok::r_brace))
return false;
- updateParameterCount(Left, CurrentToken);
+ else if (CurrentToken->is(tok::l_brace))
+ Left->Type = TT_Unknown; // Not TT_ObjCBlockLParen
if (CurrentToken->is(tok::comma) && CurrentToken->Next &&
!CurrentToken->Next->HasUnescapedNewline &&
!CurrentToken->Next->isTrailingComment())
HasMultipleParametersOnALine = true;
+ if (CurrentToken->isOneOf(tok::kw_const, tok::kw_auto) ||
+ CurrentToken->isSimpleTypeSpecifier())
+ Contexts.back().IsExpression = false;
+ FormatToken *Tok = CurrentToken;
if (!consumeToken())
return false;
+ updateParameterCount(Left, Tok);
if (CurrentToken && CurrentToken->HasUnescapedNewline)
HasMultipleLines = true;
}
@@ -189,6 +228,7 @@ private:
FormatToken *Parent = Left->getPreviousNonComment();
bool StartsObjCMethodExpr =
Contexts.back().CanBeExpression && Left->Type != TT_LambdaLSquare &&
+ CurrentToken->isNot(tok::l_brace) &&
(!Parent || Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren,
tok::kw_return, tok::kw_throw) ||
Parent->isUnaryOperator() || Parent->Type == TT_ObjCForIn ||
@@ -207,7 +247,7 @@ private:
Left->Type = TT_ArraySubscriptLSquare;
}
- while (CurrentToken != NULL) {
+ while (CurrentToken) {
if (CurrentToken->is(tok::r_square)) {
if (CurrentToken->Next && CurrentToken->Next->is(tok::l_paren) &&
Left->Type == TT_ObjCMethodExpr) {
@@ -216,19 +256,22 @@ private:
StartsObjCMethodExpr = false;
Left->Type = TT_Unknown;
}
- if (StartsObjCMethodExpr) {
+ if (StartsObjCMethodExpr && CurrentToken->Previous != Left) {
CurrentToken->Type = TT_ObjCMethodExpr;
// determineStarAmpUsage() thinks that '*' '[' is allocating an
// array of pointers, but if '[' starts a selector then '*' is a
// binary operator.
- if (Parent != NULL && Parent->Type == TT_PointerOrReference)
+ if (Parent && Parent->Type == TT_PointerOrReference)
Parent->Type = TT_BinaryOperator;
}
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
- if (Contexts.back().FirstObjCSelectorName != NULL)
+ if (Contexts.back().FirstObjCSelectorName) {
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
Contexts.back().LongestObjCSelectorName;
+ if (Left->BlockParameterCount > 1)
+ Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = 0;
+ }
next();
return true;
}
@@ -237,23 +280,32 @@ private:
if (CurrentToken->is(tok::colon))
ColonFound = true;
if (CurrentToken->is(tok::comma) &&
+ Style.Language != FormatStyle::LK_Proto &&
(Left->Type == TT_ArraySubscriptLSquare ||
(Left->Type == TT_ObjCMethodExpr && !ColonFound)))
Left->Type = TT_ArrayInitializerLSquare;
- updateParameterCount(Left, CurrentToken);
+ FormatToken* Tok = CurrentToken;
if (!consumeToken())
return false;
+ updateParameterCount(Left, Tok);
}
return false;
}
bool parseBrace() {
- if (CurrentToken != NULL) {
+ if (CurrentToken) {
FormatToken *Left = CurrentToken->Previous;
+
+ if (Contexts.back().CaretFound)
+ Left->Type = TT_ObjCBlockLBrace;
+ Contexts.back().CaretFound = false;
+
ScopedContextCreator ContextCreator(*this, tok::l_brace, 1);
Contexts.back().ColonIsDictLiteral = true;
+ if (Left->BlockKind == BK_BracedInit)
+ Contexts.back().IsExpression = true;
- while (CurrentToken != NULL) {
+ while (CurrentToken) {
if (CurrentToken->is(tok::r_brace)) {
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
@@ -263,18 +315,26 @@ private:
if (CurrentToken->isOneOf(tok::r_paren, tok::r_square))
return false;
updateParameterCount(Left, CurrentToken);
- if (CurrentToken->is(tok::colon))
+ if (CurrentToken->is(tok::colon) &&
+ Style.Language != FormatStyle::LK_Proto) {
+ if (CurrentToken->getPreviousNonComment()->is(tok::identifier))
+ CurrentToken->getPreviousNonComment()->Type = TT_SelectorName;
Left->Type = TT_DictLiteral;
+ }
if (!consumeToken())
return false;
}
}
- // No closing "}" found, this probably starts a definition.
- Line.StartsDefinition = true;
return true;
}
void updateParameterCount(FormatToken *Left, FormatToken *Current) {
+ if (Current->Type == TT_LambdaLSquare ||
+ (Current->is(tok::caret) && Current->Type == TT_UnaryOperator) ||
+ (Style.Language == FormatStyle::LK_JavaScript &&
+ Current->TokenText == "function")) {
+ ++Left->BlockParameterCount;
+ }
if (Current->is(tok::comma)) {
++Left->ParameterCount;
if (!Left->Role)
@@ -286,7 +346,7 @@ private:
}
bool parseConditional() {
- while (CurrentToken != NULL) {
+ while (CurrentToken) {
if (CurrentToken->is(tok::colon)) {
CurrentToken->Type = TT_ConditionalExpr;
next();
@@ -299,12 +359,12 @@ private:
}
bool parseTemplateDeclaration() {
- if (CurrentToken != NULL && CurrentToken->is(tok::less)) {
+ if (CurrentToken && CurrentToken->is(tok::less)) {
CurrentToken->Type = TT_TemplateOpener;
next();
if (!parseAngle())
return false;
- if (CurrentToken != NULL)
+ if (CurrentToken)
CurrentToken->Previous->ClosesTemplateDeclaration = true;
return true;
}
@@ -317,33 +377,34 @@ private:
switch (Tok->Tok.getKind()) {
case tok::plus:
case tok::minus:
- if (Tok->Previous == NULL && Line.MustBeDeclaration)
+ if (!Tok->Previous && Line.MustBeDeclaration)
Tok->Type = TT_ObjCMethodSpecifier;
break;
case tok::colon:
- if (Tok->Previous == NULL)
+ if (!Tok->Previous)
return false;
// Colons from ?: are handled in parseConditional().
- if (Tok->Previous->is(tok::r_paren) && Contexts.size() == 1) {
+ if (Tok->Previous->is(tok::r_paren) && Contexts.size() == 1 &&
+ Line.First->isNot(tok::kw_case)) {
Tok->Type = TT_CtorInitializerColon;
} else if (Contexts.back().ColonIsDictLiteral) {
Tok->Type = TT_DictLiteral;
} else if (Contexts.back().ColonIsObjCMethodExpr ||
Line.First->Type == TT_ObjCMethodSpecifier) {
Tok->Type = TT_ObjCMethodExpr;
- Tok->Previous->Type = TT_ObjCSelectorName;
+ Tok->Previous->Type = TT_SelectorName;
if (Tok->Previous->ColumnWidth >
Contexts.back().LongestObjCSelectorName) {
Contexts.back().LongestObjCSelectorName = Tok->Previous->ColumnWidth;
}
- if (Contexts.back().FirstObjCSelectorName == NULL)
+ if (!Contexts.back().FirstObjCSelectorName)
Contexts.back().FirstObjCSelectorName = Tok->Previous;
} else if (Contexts.back().ColonIsForRangeExpr) {
Tok->Type = TT_RangeBasedForLoopColon;
- } else if (CurrentToken != NULL &&
- CurrentToken->is(tok::numeric_constant)) {
+ } else if (CurrentToken && CurrentToken->is(tok::numeric_constant)) {
Tok->Type = TT_BitFieldColon;
- } else if (Contexts.size() == 1 && Line.First->isNot(tok::kw_enum)) {
+ } else if (Contexts.size() == 1 &&
+ !Line.First->isOneOf(tok::kw_enum, tok::kw_case)) {
Tok->Type = TT_InheritanceColon;
} else if (Contexts.back().ContextKind == tok::l_paren) {
Tok->Type = TT_InlineASMColon;
@@ -351,7 +412,7 @@ private:
break;
case tok::kw_if:
case tok::kw_while:
- if (CurrentToken != NULL && CurrentToken->is(tok::l_paren)) {
+ if (CurrentToken && CurrentToken->is(tok::l_paren)) {
next();
if (!parseParens(/*LookForDecls=*/true))
return false;
@@ -367,7 +428,9 @@ private:
if (!parseParens())
return false;
if (Line.MustBeDeclaration && Contexts.size() == 1 &&
- !Contexts.back().IsExpression)
+ !Contexts.back().IsExpression &&
+ Line.First->Type != TT_ObjCProperty &&
+ (!Tok->Previous || Tok->Previous->isNot(tok::kw_decltype)))
Line.MightBeFunctionDecl = true;
break;
case tok::l_square:
@@ -392,7 +455,7 @@ private:
return false;
case tok::r_brace:
// Lines can start with '}'.
- if (Tok->Previous != NULL)
+ if (Tok->Previous)
return false;
break;
case tok::greater:
@@ -429,6 +492,8 @@ private:
Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true;
if (Contexts.back().InCtorInitializer)
Tok->Type = TT_CtorInitializerComma;
+ if (Contexts.back().IsForEachMacro)
+ Contexts.back().IsExpression = true;
break;
default:
break;
@@ -438,15 +503,15 @@ private:
void parseIncludeDirective() {
next();
- if (CurrentToken != NULL && CurrentToken->is(tok::less)) {
+ if (CurrentToken && CurrentToken->is(tok::less)) {
next();
- while (CurrentToken != NULL) {
+ while (CurrentToken) {
if (CurrentToken->isNot(tok::comment) || CurrentToken->Next)
CurrentToken->Type = TT_ImplicitStringLiteral;
next();
}
} else {
- while (CurrentToken != NULL) {
+ while (CurrentToken) {
if (CurrentToken->is(tok::string_literal))
// Mark these string literals as "implicit" literals, too, so that
// they are not split or line-wrapped.
@@ -461,15 +526,27 @@ private:
// We still want to format the whitespace left of the first token of the
// warning or error.
next();
- while (CurrentToken != NULL) {
+ while (CurrentToken) {
CurrentToken->Type = TT_ImplicitStringLiteral;
next();
}
}
+ void parsePragma() {
+ next(); // Consume "pragma".
+ if (CurrentToken && CurrentToken->TokenText == "mark") {
+ next(); // Consume "mark".
+ next(); // Consume first token (so we fix leading whitespace).
+ while (CurrentToken) {
+ CurrentToken->Type = TT_ImplicitStringLiteral;
+ next();
+ }
+ }
+ }
+
void parsePreprocessorDirective() {
next();
- if (CurrentToken == NULL)
+ if (!CurrentToken)
return;
if (CurrentToken->Tok.is(tok::numeric_constant)) {
CurrentToken->SpacesRequiredBefore = 1;
@@ -477,7 +554,7 @@ private:
}
// Hashes in the middle of a line can lead to any strange token
// sequence.
- if (CurrentToken->Tok.getIdentifierInfo() == NULL)
+ if (!CurrentToken->Tok.getIdentifierInfo())
return;
switch (CurrentToken->Tok.getIdentifierInfo()->getPPKeywordID()) {
case tok::pp_include:
@@ -488,14 +565,18 @@ private:
case tok::pp_warning:
parseWarningOrError();
break;
+ case tok::pp_pragma:
+ parsePragma();
+ break;
case tok::pp_if:
case tok::pp_elif:
+ Contexts.back().IsExpression = true;
parseLine();
break;
default:
break;
}
- while (CurrentToken != NULL)
+ while (CurrentToken)
next();
}
@@ -505,7 +586,16 @@ public:
parsePreprocessorDirective();
return LT_PreprocessorDirective;
}
- while (CurrentToken != NULL) {
+
+ // Directly allow to 'import <string-literal>' to support protocol buffer
+ // definitions (code.google.com/p/protobuf) or missing "#" (either way we
+ // should not break the line).
+ IdentifierInfo *Info = CurrentToken->Tok.getIdentifierInfo();
+ if (Info && Info->getPPKeywordID() == tok::pp_import &&
+ CurrentToken->Next && CurrentToken->Next->is(tok::string_literal))
+ parseIncludeDirective();
+
+ while (CurrentToken) {
if (CurrentToken->is(tok::kw_virtual))
KeywordVirtualFound = true;
if (!consumeToken())
@@ -515,7 +605,7 @@ public:
return LT_VirtualFunctionDecl;
if (Line.First->Type == TT_ObjCMethodSpecifier) {
- if (Contexts.back().FirstObjCSelectorName != NULL)
+ if (Contexts.back().FirstObjCSelectorName)
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
Contexts.back().LongestObjCSelectorName;
return LT_ObjCMethodDecl;
@@ -525,26 +615,32 @@ public:
}
private:
+ void resetTokenMetadata(FormatToken *Token) {
+ if (!Token)
+ return;
+
+ // Reset token type in case we have already looked at it and then
+ // recovered from an error (e.g. failure to find the matching >).
+ if (CurrentToken->Type != TT_LambdaLSquare &&
+ CurrentToken->Type != TT_FunctionLBrace &&
+ CurrentToken->Type != TT_ImplicitStringLiteral &&
+ CurrentToken->Type != TT_RegexLiteral &&
+ CurrentToken->Type != TT_TrailingReturnArrow)
+ CurrentToken->Type = TT_Unknown;
+ CurrentToken->Role.reset();
+ CurrentToken->FakeLParens.clear();
+ CurrentToken->FakeRParens = 0;
+ }
+
void next() {
- if (CurrentToken != NULL) {
+ if (CurrentToken) {
determineTokenType(*CurrentToken);
CurrentToken->BindingStrength = Contexts.back().BindingStrength;
- }
-
- if (CurrentToken != NULL)
+ CurrentToken->NestingLevel = Contexts.size() - 1;
CurrentToken = CurrentToken->Next;
-
- if (CurrentToken != NULL) {
- // Reset token type in case we have already looked at it and then
- // recovered from an error (e.g. failure to find the matching >).
- if (CurrentToken->Type != TT_LambdaLSquare &&
- CurrentToken->Type != TT_ImplicitStringLiteral)
- CurrentToken->Type = TT_Unknown;
- if (CurrentToken->Role)
- CurrentToken->Role.reset(NULL);
- CurrentToken->FakeLParens.clear();
- CurrentToken->FakeRParens = 0;
}
+
+ resetTokenMetadata(CurrentToken);
}
/// \brief A struct to hold information valid in a specific context, e.g.
@@ -555,9 +651,10 @@ private:
: ContextKind(ContextKind), BindingStrength(BindingStrength),
LongestObjCSelectorName(0), ColonIsForRangeExpr(false),
ColonIsDictLiteral(false), ColonIsObjCMethodExpr(false),
- FirstObjCSelectorName(NULL), FirstStartOfName(NULL),
+ FirstObjCSelectorName(nullptr), FirstStartOfName(nullptr),
IsExpression(IsExpression), CanBeExpression(true),
- InCtorInitializer(false) {}
+ InTemplateArgument(false), InCtorInitializer(false),
+ CaretFound(false), IsForEachMacro(false) {}
tok::TokenKind ContextKind;
unsigned BindingStrength;
@@ -569,7 +666,10 @@ private:
FormatToken *FirstStartOfName;
bool IsExpression;
bool CanBeExpression;
+ bool InTemplateArgument;
bool InCtorInitializer;
+ bool CaretFound;
+ bool IsForEachMacro;
};
/// \brief Puts a new \c Context onto the stack \c Contexts for the lifetime
@@ -596,19 +696,26 @@ private:
for (FormatToken *Previous = Current.Previous;
Previous && !Previous->isOneOf(tok::comma, tok::semi);
Previous = Previous->Previous) {
- if (Previous->is(tok::r_square))
+ if (Previous->isOneOf(tok::r_square, tok::r_paren))
Previous = Previous->MatchingParen;
if (Previous->Type == TT_BinaryOperator &&
Previous->isOneOf(tok::star, tok::amp)) {
Previous->Type = TT_PointerOrReference;
}
}
- } else if (Current.isOneOf(tok::kw_return, tok::kw_throw) ||
- (Current.is(tok::l_paren) && !Line.MustBeDeclaration &&
- !Line.InPPDirective &&
- (!Current.Previous ||
- !Current.Previous->isOneOf(tok::kw_for, tok::kw_catch)))) {
+ } else if (Current.isOneOf(tok::kw_return, tok::kw_throw)) {
Contexts.back().IsExpression = true;
+ } else if (Current.is(tok::l_paren) && !Line.MustBeDeclaration &&
+ !Line.InPPDirective &&
+ (!Current.Previous ||
+ Current.Previous->isNot(tok::kw_decltype))) {
+ bool ParametersOfFunctionType =
+ Current.Previous && Current.Previous->is(tok::r_paren) &&
+ Current.Previous->MatchingParen &&
+ Current.Previous->MatchingParen->Type == TT_FunctionTypeLParen;
+ bool IsForOrCatch = Current.Previous &&
+ Current.Previous->isOneOf(tok::kw_for, tok::kw_catch);
+ Contexts.back().IsExpression = !ParametersOfFunctionType && !IsForOrCatch;
} else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) {
for (FormatToken *Previous = Current.Previous;
Previous && Previous->isOneOf(tok::star, tok::amp);
@@ -640,13 +747,18 @@ private:
} else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) {
Current.Type =
determineStarAmpUsage(Current, Contexts.back().CanBeExpression &&
- Contexts.back().IsExpression);
+ Contexts.back().IsExpression,
+ Contexts.back().InTemplateArgument);
} else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) {
Current.Type = determinePlusMinusCaretUsage(Current);
+ if (Current.Type == TT_UnaryOperator && Current.is(tok::caret))
+ Contexts.back().CaretFound = true;
} else if (Current.isOneOf(tok::minusminus, tok::plusplus)) {
Current.Type = determineIncrementUsage(Current);
} else if (Current.is(tok::exclaim)) {
Current.Type = TT_UnaryOperator;
+ } else if (Current.is(tok::question)) {
+ Current.Type = TT_ConditionalExpr;
} else if (Current.isBinaryOperator() &&
(!Current.Previous ||
Current.Previous->isNot(tok::l_square))) {
@@ -657,38 +769,7 @@ private:
else
Current.Type = TT_BlockComment;
} else if (Current.is(tok::r_paren)) {
- FormatToken *LeftOfParens = NULL;
- if (Current.MatchingParen)
- LeftOfParens = Current.MatchingParen->getPreviousNonComment();
- bool IsCast = false;
- bool ParensAreEmpty = Current.Previous == Current.MatchingParen;
- bool ParensAreType = !Current.Previous ||
- Current.Previous->Type == TT_PointerOrReference ||
- Current.Previous->Type == TT_TemplateCloser ||
- isSimpleTypeSpecifier(*Current.Previous);
- bool ParensCouldEndDecl =
- Current.Next &&
- Current.Next->isOneOf(tok::equal, tok::semi, tok::l_brace);
- bool IsSizeOfOrAlignOf =
- LeftOfParens &&
- LeftOfParens->isOneOf(tok::kw_sizeof, tok::kw_alignof);
- if (ParensAreType && !ParensCouldEndDecl && !IsSizeOfOrAlignOf &&
- (Contexts.back().IsExpression ||
- (Current.Next && Current.Next->isBinaryOperator())))
- IsCast = true;
- if (Current.Next && Current.Next->isNot(tok::string_literal) &&
- (Current.Next->Tok.isLiteral() ||
- Current.Next->isOneOf(tok::kw_sizeof, tok::kw_alignof)))
- IsCast = true;
- // If there is an identifier after the (), it is likely a cast, unless
- // there is also an identifier before the ().
- if (LeftOfParens && (LeftOfParens->Tok.getIdentifierInfo() == NULL ||
- LeftOfParens->is(tok::kw_return)) &&
- LeftOfParens->Type != TT_OverloadedOperator &&
- LeftOfParens->Type != TT_TemplateCloser && Current.Next &&
- Current.Next->is(tok::identifier))
- IsCast = true;
- if (IsCast && !ParensAreEmpty)
+ if (rParenEndsCast(Current))
Current.Type = TT_CastRParen;
} else if (Current.is(tok::at) && Current.Next) {
switch (Current.Next->Tok.getObjCKeywordID()) {
@@ -708,6 +789,12 @@ private:
if (PreviousNoComment &&
PreviousNoComment->isOneOf(tok::comma, tok::l_brace))
Current.Type = TT_DesignatedInitializerPeriod;
+ } else if (Current.isOneOf(tok::identifier, tok::kw_const) &&
+ Current.Previous && Current.Previous->isNot(tok::equal) &&
+ Line.MightBeFunctionDecl && Contexts.size() == 1) {
+ // Line.MightBeFunctionDecl can only be true after the parentheses of a
+ // function declaration have been found.
+ Current.Type = TT_TrailingAnnotation;
}
}
}
@@ -718,15 +805,15 @@ private:
/// This is a heuristic based on whether \p Tok is an identifier following
/// something that is likely a type.
bool isStartOfName(const FormatToken &Tok) {
- if (Tok.isNot(tok::identifier) || Tok.Previous == NULL)
+ if (Tok.isNot(tok::identifier) || !Tok.Previous)
return false;
// Skip "const" as it does not have an influence on whether this is a name.
FormatToken *PreviousNotConst = Tok.Previous;
- while (PreviousNotConst != NULL && PreviousNotConst->is(tok::kw_const))
+ while (PreviousNotConst && PreviousNotConst->is(tok::kw_const))
PreviousNotConst = PreviousNotConst->Previous;
- if (PreviousNotConst == NULL)
+ if (!PreviousNotConst)
return false;
bool IsPPKeyword = PreviousNotConst->is(tok::identifier) &&
@@ -738,19 +825,84 @@ private:
PreviousNotConst->MatchingParen->Previous &&
PreviousNotConst->MatchingParen->Previous->isNot(tok::kw_template);
+ if (PreviousNotConst->is(tok::r_paren) && PreviousNotConst->MatchingParen &&
+ PreviousNotConst->MatchingParen->Previous &&
+ PreviousNotConst->MatchingParen->Previous->is(tok::kw_decltype))
+ return true;
+
return (!IsPPKeyword && PreviousNotConst->is(tok::identifier)) ||
PreviousNotConst->Type == TT_PointerOrReference ||
- isSimpleTypeSpecifier(*PreviousNotConst);
+ PreviousNotConst->isSimpleTypeSpecifier();
+ }
+
+ /// \brief Determine whether ')' is ending a cast.
+ bool rParenEndsCast(const FormatToken &Tok) {
+ FormatToken *LeftOfParens = nullptr;
+ if (Tok.MatchingParen)
+ LeftOfParens = Tok.MatchingParen->getPreviousNonComment();
+ if (LeftOfParens && LeftOfParens->is(tok::r_paren))
+ return false;
+ bool IsCast = false;
+ bool ParensAreEmpty = Tok.Previous == Tok.MatchingParen;
+ bool ParensAreType = !Tok.Previous ||
+ Tok.Previous->Type == TT_PointerOrReference ||
+ Tok.Previous->Type == TT_TemplateCloser ||
+ Tok.Previous->isSimpleTypeSpecifier();
+ bool ParensCouldEndDecl =
+ Tok.Next && Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace);
+ bool IsSizeOfOrAlignOf =
+ LeftOfParens && LeftOfParens->isOneOf(tok::kw_sizeof, tok::kw_alignof);
+ if (ParensAreType && !ParensCouldEndDecl && !IsSizeOfOrAlignOf &&
+ ((Contexts.size() > 1 && Contexts[Contexts.size() - 2].IsExpression) ||
+ (Tok.Next && Tok.Next->isBinaryOperator())))
+ IsCast = true;
+ else if (Tok.Next && Tok.Next->isNot(tok::string_literal) &&
+ (Tok.Next->Tok.isLiteral() ||
+ Tok.Next->isOneOf(tok::kw_sizeof, tok::kw_alignof)))
+ IsCast = true;
+ // If there is an identifier after the (), it is likely a cast, unless
+ // there is also an identifier before the ().
+ else if (LeftOfParens &&
+ (LeftOfParens->Tok.getIdentifierInfo() == nullptr ||
+ LeftOfParens->is(tok::kw_return)) &&
+ LeftOfParens->Type != TT_OverloadedOperator &&
+ LeftOfParens->isNot(tok::at) &&
+ LeftOfParens->Type != TT_TemplateCloser && Tok.Next) {
+ if (Tok.Next->isOneOf(tok::identifier, tok::numeric_constant)) {
+ IsCast = true;
+ } else {
+ // Use heuristics to recognize c style casting.
+ FormatToken *Prev = Tok.Previous;
+ if (Prev && Prev->isOneOf(tok::amp, tok::star))
+ Prev = Prev->Previous;
+
+ if (Prev && Tok.Next && Tok.Next->Next) {
+ bool NextIsUnary = Tok.Next->isUnaryOperator() ||
+ Tok.Next->isOneOf(tok::amp, tok::star);
+ IsCast = NextIsUnary && Tok.Next->Next->isOneOf(
+ tok::identifier, tok::numeric_constant);
+ }
+
+ for (; Prev != Tok.MatchingParen; Prev = Prev->Previous) {
+ if (!Prev || !Prev->isOneOf(tok::kw_const, tok::identifier)) {
+ IsCast = false;
+ break;
+ }
+ }
+ }
+ }
+ return IsCast && !ParensAreEmpty;
}
/// \brief Return the type of the given token assuming it is * or &.
- TokenType determineStarAmpUsage(const FormatToken &Tok, bool IsExpression) {
+ TokenType determineStarAmpUsage(const FormatToken &Tok, bool IsExpression,
+ bool InTemplateArgument) {
const FormatToken *PrevToken = Tok.getPreviousNonComment();
- if (PrevToken == NULL)
+ if (!PrevToken)
return TT_UnaryOperator;
const FormatToken *NextToken = Tok.getNextNonComment();
- if (NextToken == NULL)
+ if (!NextToken || NextToken->is(tok::l_brace))
return TT_Unknown;
if (PrevToken->is(tok::coloncolon) ||
@@ -761,20 +913,37 @@ private:
tok::comma, tok::semi, tok::kw_return, tok::colon,
tok::equal, tok::kw_delete, tok::kw_sizeof) ||
PrevToken->Type == TT_BinaryOperator ||
+ PrevToken->Type == TT_ConditionalExpr ||
PrevToken->Type == TT_UnaryOperator || PrevToken->Type == TT_CastRParen)
return TT_UnaryOperator;
- if (NextToken->is(tok::l_square))
+ if (NextToken->is(tok::l_square) && NextToken->Type != TT_LambdaLSquare)
+ return TT_PointerOrReference;
+ if (NextToken->is(tok::kw_operator))
return TT_PointerOrReference;
if (PrevToken->is(tok::r_paren) && PrevToken->MatchingParen &&
PrevToken->MatchingParen->Previous &&
- PrevToken->MatchingParen->Previous->is(tok::kw_typeof))
+ PrevToken->MatchingParen->Previous->isOneOf(tok::kw_typeof,
+ tok::kw_decltype))
return TT_PointerOrReference;
if (PrevToken->Tok.isLiteral() ||
- PrevToken->isOneOf(tok::r_paren, tok::r_square) ||
- NextToken->Tok.isLiteral() || NextToken->isUnaryOperator())
+ PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::kw_true,
+ tok::kw_false) ||
+ NextToken->Tok.isLiteral() ||
+ NextToken->isOneOf(tok::kw_true, tok::kw_false) ||
+ NextToken->isUnaryOperator() ||
+ // If we know we're in a template argument, there are no named
+ // declarations. Thus, having an identifier on the right-hand side
+ // indicates a binary operator.
+ (InTemplateArgument && NextToken->Tok.isAnyIdentifier()))
+ return TT_BinaryOperator;
+
+ // This catches some cases where evaluation order is used as control flow:
+ // aaa && aaa->f();
+ const FormatToken *NextNextToken = NextToken->getNextNonComment();
+ if (NextNextToken && NextNextToken->is(tok::arrow))
return TT_BinaryOperator;
// It is very unlikely that we are going to find a pointer or reference type
@@ -787,7 +956,7 @@ private:
TokenType determinePlusMinusCaretUsage(const FormatToken &Tok) {
const FormatToken *PrevToken = Tok.getPreviousNonComment();
- if (PrevToken == NULL || PrevToken->Type == TT_CastRParen)
+ if (!PrevToken || PrevToken->Type == TT_CastRParen)
return TT_UnaryOperator;
// Use heuristics to recognize unary operators.
@@ -807,7 +976,7 @@ private:
/// \brief Determine whether ++/-- are pre- or post-increments/-decrements.
TokenType determineIncrementUsage(const FormatToken &Tok) {
const FormatToken *PrevToken = Tok.getPreviousNonComment();
- if (PrevToken == NULL || PrevToken->Type == TT_CastRParen)
+ if (!PrevToken || PrevToken->Type == TT_CastRParen)
return TT_UnaryOperator;
if (PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::identifier))
return TT_TrailingUnaryOperator;
@@ -815,37 +984,6 @@ private:
return TT_UnaryOperator;
}
- // FIXME: This is copy&pasted from Sema. Put it in a common place and remove
- // duplication.
- /// \brief Determine whether the token kind starts a simple-type-specifier.
- bool isSimpleTypeSpecifier(const FormatToken &Tok) const {
- switch (Tok.Tok.getKind()) {
- case tok::kw_short:
- case tok::kw_long:
- case tok::kw___int64:
- case tok::kw___int128:
- case tok::kw_signed:
- case tok::kw_unsigned:
- case tok::kw_void:
- case tok::kw_char:
- case tok::kw_int:
- case tok::kw_half:
- case tok::kw_float:
- case tok::kw_double:
- case tok::kw_wchar_t:
- case tok::kw_bool:
- case tok::kw___underlying_type:
- case tok::annot_typename:
- case tok::kw_char16_t:
- case tok::kw_char32_t:
- case tok::kw_typeof:
- case tok::kw_decltype:
- return true;
- default:
- return false;
- }
- }
-
SmallVector<Context, 8> Contexts;
const FormatStyle &Style;
@@ -875,10 +1013,11 @@ public:
// expression.
while (Current &&
(Current->is(tok::kw_return) ||
- (Current->is(tok::colon) && Current->Type == TT_ObjCMethodExpr)))
+ (Current->is(tok::colon) && (Current->Type == TT_ObjCMethodExpr ||
+ Current->Type == TT_DictLiteral))))
next();
- if (Current == NULL || Precedence > PrecedenceArrowAndPeriod)
+ if (!Current || Precedence > PrecedenceArrowAndPeriod)
return;
// Conditional expressions need to be parsed separately for proper nesting.
@@ -895,7 +1034,8 @@ public:
}
FormatToken *Start = Current;
- FormatToken *LatestOperator = NULL;
+ FormatToken *LatestOperator = nullptr;
+ unsigned OperatorIndex = 0;
while (Current) {
// Consume operators with higher precedence.
@@ -903,17 +1043,20 @@ public:
int CurrentPrecedence = getCurrentPrecedence();
- if (Current && Current->Type == TT_ObjCSelectorName &&
- Precedence == CurrentPrecedence)
+ if (Current && Current->Type == TT_SelectorName &&
+ Precedence == CurrentPrecedence) {
+ if (LatestOperator)
+ addFakeParenthesis(Start, prec::Level(Precedence));
Start = Current;
+ }
// At the end of the line or when an operator with higher precedence is
// found, insert fake parenthesis and return.
- if (Current == NULL || Current->closesScope() ||
+ if (!Current || Current->closesScope() ||
(CurrentPrecedence != -1 && CurrentPrecedence < Precedence)) {
if (LatestOperator) {
+ LatestOperator->LastOperator = true;
if (Precedence == PrecedenceArrowAndPeriod) {
- LatestOperator->LastInChainOfCalls = true;
// Call expressions don't have a binary operator precedence.
addFakeParenthesis(Start, prec::Unknown);
} else {
@@ -932,8 +1075,11 @@ public:
next();
} else {
// Operator found.
- if (CurrentPrecedence == Precedence)
+ if (CurrentPrecedence == Precedence) {
LatestOperator = Current;
+ Current->OperatorIndex = OperatorIndex;
+ ++OperatorIndex;
+ }
next();
}
@@ -948,8 +1094,10 @@ private:
if (Current->Type == TT_ConditionalExpr)
return prec::Conditional;
else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon ||
- Current->Type == TT_ObjCSelectorName)
+ Current->Type == TT_SelectorName)
return 0;
+ else if (Current->Type == TT_RangeBasedForLoopColon)
+ return prec::Comma;
else if (Current->Type == TT_BinaryOperator || Current->is(tok::comma))
return Current->getPrecedence();
else if (Current->isOneOf(tok::period, tok::arrow))
@@ -972,7 +1120,7 @@ private:
/// \brief Parse unary operator expressions and surround them with fake
/// parentheses if appropriate.
void parseUnaryOperator() {
- if (Current == NULL || Current->Type != TT_UnaryOperator) {
+ if (!Current || Current->Type != TT_UnaryOperator) {
parse(PrecedenceArrowAndPeriod);
return;
}
@@ -991,7 +1139,7 @@ private:
if (!Current || !Current->is(tok::question))
return;
next();
- parse(prec::LogicalOr);
+ parseConditionalExpr();
if (!Current || Current->Type != TT_ConditionalExpr)
return;
next();
@@ -1013,15 +1161,15 @@ private:
void
TokenAnnotator::setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines) {
- const AnnotatedLine *NextNonCommentLine = NULL;
+ const AnnotatedLine *NextNonCommentLine = nullptr;
for (SmallVectorImpl<AnnotatedLine *>::reverse_iterator I = Lines.rbegin(),
E = Lines.rend();
I != E; ++I) {
if (NextNonCommentLine && (*I)->First->is(tok::comment) &&
- (*I)->First->Next == NULL)
+ (*I)->First->Next == nullptr)
(*I)->Level = NextNonCommentLine->Level;
else
- NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : NULL;
+ NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : nullptr;
setCommentLineLevels((*I)->Children);
}
@@ -1052,31 +1200,108 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {
Line.First->CanBreakBefore = Line.First->MustBreakBefore;
}
+// This function heuristically determines whether 'Current' starts the name of a
+// function declaration.
+static bool isFunctionDeclarationName(const FormatToken &Current) {
+ if (Current.Type != TT_StartOfName ||
+ Current.NestingLevel != 0 ||
+ Current.Previous->Type == TT_StartOfName)
+ return false;
+ const FormatToken *Next = Current.Next;
+ for (; Next; Next = Next->Next) {
+ if (Next->Type == TT_TemplateOpener) {
+ Next = Next->MatchingParen;
+ } else if (Next->is(tok::coloncolon)) {
+ Next = Next->Next;
+ if (!Next || !Next->is(tok::identifier))
+ return false;
+ } else if (Next->is(tok::l_paren)) {
+ break;
+ } else {
+ return false;
+ }
+ }
+ if (!Next)
+ return false;
+ assert(Next->is(tok::l_paren));
+ if (Next->Next == Next->MatchingParen)
+ return true;
+ for (const FormatToken *Tok = Next->Next; Tok != Next->MatchingParen;
+ Tok = Tok->Next) {
+ if (Tok->is(tok::kw_const) || Tok->isSimpleTypeSpecifier() ||
+ Tok->Type == TT_PointerOrReference || Tok->Type == TT_StartOfName)
+ return true;
+ if (Tok->isOneOf(tok::l_brace, tok::string_literal) || Tok->Tok.isLiteral())
+ return false;
+ }
+ return false;
+}
+
void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
+ for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(),
+ E = Line.Children.end();
+ I != E; ++I) {
+ calculateFormattingInformation(**I);
+ }
+
Line.First->TotalLength =
Line.First->IsMultiline ? Style.ColumnLimit : Line.First->ColumnWidth;
if (!Line.First->Next)
return;
FormatToken *Current = Line.First->Next;
bool InFunctionDecl = Line.MightBeFunctionDecl;
- while (Current != NULL) {
- if (Current->Type == TT_LineComment)
- Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments;
- else if (Current->SpacesRequiredBefore == 0 &&
- spaceRequiredBefore(Line, *Current))
+ while (Current) {
+ if (isFunctionDeclarationName(*Current))
+ Current->Type = TT_FunctionDeclarationName;
+ if (Current->Type == TT_LineComment) {
+ if (Current->Previous->BlockKind == BK_BracedInit &&
+ Current->Previous->opensScope())
+ Current->SpacesRequiredBefore = Style.Cpp11BracedListStyle ? 0 : 1;
+ else
+ Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments;
+
+ // If we find a trailing comment, iterate backwards to determine whether
+ // it seems to relate to a specific parameter. If so, break before that
+ // parameter to avoid changing the comment's meaning. E.g. don't move 'b'
+ // to the previous line in:
+ // SomeFunction(a,
+ // b, // comment
+ // c);
+ if (!Current->HasUnescapedNewline) {
+ for (FormatToken *Parameter = Current->Previous; Parameter;
+ Parameter = Parameter->Previous) {
+ if (Parameter->isOneOf(tok::comment, tok::r_brace))
+ break;
+ if (Parameter->Previous && Parameter->Previous->is(tok::comma)) {
+ if (Parameter->Previous->Type != TT_CtorInitializerComma &&
+ Parameter->HasUnescapedNewline)
+ Parameter->MustBreakBefore = true;
+ break;
+ }
+ }
+ }
+ } else if (Current->SpacesRequiredBefore == 0 &&
+ spaceRequiredBefore(Line, *Current)) {
Current->SpacesRequiredBefore = 1;
+ }
Current->MustBreakBefore =
Current->MustBreakBefore || mustBreakBefore(Line, *Current);
Current->CanBreakBefore =
Current->MustBreakBefore || canBreakBefore(Line, *Current);
- if (Current->MustBreakBefore || !Current->Children.empty() ||
+ unsigned ChildSize = 0;
+ if (Current->Previous->Children.size() == 1) {
+ FormatToken &LastOfChild = *Current->Previous->Children[0]->Last;
+ ChildSize = LastOfChild.isTrailingComment() ? Style.ColumnLimit
+ : LastOfChild.TotalLength + 1;
+ }
+ if (Current->MustBreakBefore || Current->Previous->Children.size() > 1 ||
Current->IsMultiline)
Current->TotalLength = Current->Previous->TotalLength + Style.ColumnLimit;
else
Current->TotalLength = Current->Previous->TotalLength +
- Current->ColumnWidth +
+ Current->ColumnWidth + ChildSize +
Current->SpacesRequiredBefore;
if (Current->Type == TT_CtorInitializerColon)
@@ -1092,24 +1317,18 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
}
calculateUnbreakableTailLengths(Line);
- for (Current = Line.First; Current != NULL; Current = Current->Next) {
+ for (Current = Line.First; Current != nullptr; Current = Current->Next) {
if (Current->Role)
Current->Role->precomputeFormattingInfos(Current);
}
DEBUG({ printDebugInfo(Line); });
-
- for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(),
- E = Line.Children.end();
- I != E; ++I) {
- calculateFormattingInformation(**I);
- }
}
void TokenAnnotator::calculateUnbreakableTailLengths(AnnotatedLine &Line) {
unsigned UnbreakableTailLength = 0;
FormatToken *Current = Line.Last;
- while (Current != NULL) {
+ while (Current) {
Current->UnbreakableTailLength = UnbreakableTailLength;
if (Current->CanBreakBefore ||
Current->isOneOf(tok::comment, tok::string_literal)) {
@@ -1130,18 +1349,22 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if (Left.is(tok::semi))
return 0;
- if (Left.is(tok::comma))
+ if (Left.is(tok::comma) || (Right.is(tok::identifier) && Right.Next &&
+ Right.Next->Type == TT_DictLiteral))
return 1;
- if (Right.is(tok::l_square))
- return 150;
-
- if (Right.Type == TT_StartOfName || Right.is(tok::kw_operator)) {
+ if (Right.is(tok::l_square)) {
+ if (Style.Language == FormatStyle::LK_Proto)
+ return 1;
+ if (Right.Type != TT_ObjCMethodExpr && Right.Type != TT_LambdaLSquare)
+ return 500;
+ }
+ if (Right.Type == TT_StartOfName ||
+ Right.Type == TT_FunctionDeclarationName || Right.is(tok::kw_operator)) {
if (Line.First->is(tok::kw_for) && Right.PartOfMultiVariableDeclStmt)
return 3;
if (Left.Type == TT_StartOfName)
return 20;
- if (InFunctionDecl && Right.BindingStrength == 1)
- // FIXME: Clean up hack of using BindingStrength to find top-level names.
+ if (InFunctionDecl && Right.NestingLevel == 0)
return Style.PenaltyReturnTypeOnItsOwnLine;
return 200;
}
@@ -1149,7 +1372,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
return 150;
if (Left.Type == TT_CastRParen)
return 100;
- if (Left.is(tok::coloncolon))
+ if (Left.is(tok::coloncolon) ||
+ (Right.is(tok::period) && Style.Language == FormatStyle::LK_Proto))
return 500;
if (Left.isOneOf(tok::kw_class, tok::kw_struct))
return 5000;
@@ -1159,17 +1383,22 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
return 2;
if (Right.isMemberAccess()) {
- if (Left.isOneOf(tok::r_paren, tok::r_square) && Left.MatchingParen &&
+ if (Left.is(tok::r_paren) && Left.MatchingParen &&
Left.MatchingParen->ParameterCount > 0)
return 20; // Should be smaller than breaking at a nested comma.
return 150;
}
- // Breaking before a trailing 'const' or not-function-like annotation is bad.
- if (Left.is(tok::r_paren) && Line.Type != LT_ObjCProperty &&
- (Right.is(tok::kw_const) || (Right.is(tok::identifier) && Right.Next &&
- Right.Next->isNot(tok::l_paren))))
- return 100;
+ if (Right.Type == TT_TrailingAnnotation &&
+ (!Right.Next || Right.Next->isNot(tok::l_paren))) {
+ // Generally, breaking before a trailing annotation is bad unless it is
+ // function-like. It seems to be especially preferable to keep standard
+ // annotations (i.e. "const", "final" and "override") on the same line.
+ // Use a slightly higher penalty after ")" so that annotations like
+ // "const override" are kept together.
+ bool is_short_annotation = Right.TokenText.size() < 10;
+ return (Left.is(tok::r_paren) ? 100 : 120) + (is_short_annotation ? 50 : 0);
+ }
// In for-loops, prefer breaking at ',' and ';'.
if (Line.First->is(tok::kw_for) && Left.is(tok::equal))
@@ -1177,13 +1406,15 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
// In Objective-C method expressions, prefer breaking before "param:" over
// breaking after it.
- if (Right.Type == TT_ObjCSelectorName)
+ if (Right.Type == TT_SelectorName)
return 0;
if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
- return 50;
+ return Line.MightBeFunctionDecl ? 50 : 500;
if (Left.is(tok::l_paren) && InFunctionDecl)
return 100;
+ if (Left.is(tok::equal) && InFunctionDecl)
+ return 110;
if (Left.opensScope())
return Left.ParameterCount > 1 ? Style.PenaltyBreakBeforeFirstCallParameter
: 19;
@@ -1215,6 +1446,23 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
const FormatToken &Left,
const FormatToken &Right) {
+ if (Style.Language == FormatStyle::LK_Proto) {
+ if (Right.is(tok::period) &&
+ (Left.TokenText == "optional" || Left.TokenText == "required" ||
+ Left.TokenText == "repeated"))
+ return true;
+ if (Right.is(tok::l_paren) &&
+ (Left.TokenText == "returns" || Left.TokenText == "option"))
+ return true;
+ } else if (Style.Language == FormatStyle::LK_JavaScript) {
+ if (Left.TokenText == "var")
+ return true;
+ }
+ if (Left.is(tok::kw_return) && Right.isNot(tok::semi))
+ return true;
+ if (Style.ObjCSpaceAfterProperty && Line.Type == LT_ObjCProperty &&
+ Left.Tok.getObjCKeywordID() == tok::objc_property)
+ return true;
if (Right.is(tok::hashhash))
return Left.is(tok::hash);
if (Left.isOneOf(tok::hashhash, tok::hash))
@@ -1246,7 +1494,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
return false;
if (Left.is(tok::coloncolon))
return false;
- if (Right.is(tok::coloncolon))
+ if (Right.is(tok::coloncolon) && Left.isNot(tok::l_brace))
return (Left.is(tok::less) && Style.Standard == FormatStyle::LS_Cpp03) ||
!Left.isOneOf(tok::identifier, tok::greater, tok::l_paren,
tok::r_paren, tok::less);
@@ -1259,60 +1507,64 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Right.Type == TT_PointerOrReference)
return Left.Tok.isLiteral() ||
((Left.Type != TT_PointerOrReference) && Left.isNot(tok::l_paren) &&
- !Style.PointerBindsToType);
+ Style.PointerAlignment != FormatStyle::PAS_Left);
if (Right.Type == TT_FunctionTypeLParen && Left.isNot(tok::l_paren) &&
- (Left.Type != TT_PointerOrReference || Style.PointerBindsToType))
+ (Left.Type != TT_PointerOrReference || Style.PointerAlignment != FormatStyle::PAS_Right))
return true;
if (Left.Type == TT_PointerOrReference)
return Right.Tok.isLiteral() || Right.Type == TT_BlockComment ||
((Right.Type != TT_PointerOrReference) &&
- Right.isNot(tok::l_paren) && Style.PointerBindsToType &&
+ Right.isNot(tok::l_paren) && Style.PointerAlignment != FormatStyle::PAS_Right &&
Left.Previous &&
!Left.Previous->isOneOf(tok::l_paren, tok::coloncolon));
if (Right.is(tok::star) && Left.is(tok::l_paren))
return false;
if (Left.is(tok::l_square))
return Left.Type == TT_ArrayInitializerLSquare &&
- Right.isNot(tok::r_square);
+ Style.SpacesInContainerLiterals && Right.isNot(tok::r_square);
if (Right.is(tok::r_square))
- return Right.MatchingParen &&
+ return Right.MatchingParen && Style.SpacesInContainerLiterals &&
Right.MatchingParen->Type == TT_ArrayInitializerLSquare;
if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr &&
- Right.Type != TT_LambdaLSquare && Left.isNot(tok::numeric_constant))
+ Right.Type != TT_LambdaLSquare && Left.isNot(tok::numeric_constant) &&
+ Left.Type != TT_DictLiteral)
return false;
if (Left.is(tok::colon))
return Left.Type != TT_ObjCMethodExpr;
- if (Right.is(tok::colon))
- return Right.Type != TT_ObjCMethodExpr && !Left.is(tok::question);
+ if (Left.Type == TT_BlockComment)
+ return !Left.TokenText.endswith("=*/");
if (Right.is(tok::l_paren)) {
- if (Left.is(tok::r_paren) && Left.MatchingParen &&
- Left.MatchingParen->Previous &&
- Left.MatchingParen->Previous->is(tok::kw___attribute))
+ if (Left.is(tok::r_paren) && Left.Type == TT_AttributeParen)
return true;
return Line.Type == LT_ObjCDecl ||
- Left.isOneOf(tok::kw_return, tok::kw_new, tok::kw_delete,
- tok::semi) ||
- (Style.SpaceAfterControlStatementKeyword &&
- Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch,
- tok::kw_catch));
+ Left.isOneOf(tok::kw_new, tok::kw_delete, tok::semi) ||
+ (Style.SpaceBeforeParens != FormatStyle::SBPO_Never &&
+ (Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while,
+ tok::kw_switch, tok::kw_catch, tok::kw_case) ||
+ Left.IsForEachMacro)) ||
+ (Style.SpaceBeforeParens == FormatStyle::SBPO_Always &&
+ Left.isOneOf(tok::identifier, tok::kw___attribute) &&
+ Line.Type != LT_PreprocessorDirective);
}
if (Left.is(tok::at) && Right.Tok.getObjCKeywordID() != tok::objc_not_keyword)
return false;
if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
return !Left.Children.empty(); // No spaces in "{}".
- if (Left.is(tok::l_brace) || Right.is(tok::r_brace))
+ if ((Left.is(tok::l_brace) && Left.BlockKind != BK_Block) ||
+ (Right.is(tok::r_brace) && Right.MatchingParen &&
+ Right.MatchingParen->BlockKind != BK_Block))
return !Style.Cpp11BracedListStyle;
if (Right.Type == TT_UnaryOperator)
return !Left.isOneOf(tok::l_paren, tok::l_square, tok::at) &&
(Left.isNot(tok::colon) || Left.Type != TT_ObjCMethodExpr);
- if (Left.isOneOf(tok::identifier, tok::greater, tok::r_square) &&
+ if ((Left.isOneOf(tok::identifier, tok::greater, tok::r_square,
+ tok::r_paren) ||
+ Left.isSimpleTypeSpecifier()) &&
Right.is(tok::l_brace) && Right.getNextNonComment() &&
Right.BlockKind != BK_Block)
return false;
if (Left.is(tok::period) || Right.is(tok::period))
return false;
- if (Left.Type == TT_BlockComment && Left.TokenText.endswith("=*/"))
- return false;
if (Right.is(tok::hash) && Left.is(tok::identifier) && Left.TokenText == "L")
return false;
return true;
@@ -1350,11 +1602,12 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return false;
if (Tok.is(tok::colon))
return !Line.First->isOneOf(tok::kw_case, tok::kw_default) &&
- Tok.getNextNonComment() != NULL && Tok.Type != TT_ObjCMethodExpr &&
- !Tok.Previous->is(tok::question);
+ Tok.getNextNonComment() && Tok.Type != TT_ObjCMethodExpr &&
+ !Tok.Previous->is(tok::question) &&
+ (Tok.Type != TT_DictLiteral || Style.SpacesInContainerLiterals);
if (Tok.Previous->Type == TT_UnaryOperator ||
Tok.Previous->Type == TT_CastRParen)
- return false;
+ return Tok.Type == TT_BinaryOperator;
if (Tok.Previous->is(tok::greater) && Tok.is(tok::greater)) {
return Tok.Type == TT_TemplateCloser &&
Tok.Previous->Type == TT_TemplateCloser &&
@@ -1367,7 +1620,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
Tok.getPrecedence() == prec::Assignment)
return false;
if ((Tok.Type == TT_BinaryOperator && !Tok.Previous->is(tok::l_paren)) ||
- Tok.Previous->Type == TT_BinaryOperator)
+ Tok.Previous->Type == TT_BinaryOperator ||
+ Tok.Previous->Type == TT_ConditionalExpr)
return true;
if (Tok.Previous->Type == TT_TemplateCloser && Tok.is(tok::l_paren))
return false;
@@ -1376,16 +1630,28 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return true;
if (Tok.Type == TT_TrailingUnaryOperator)
return false;
+ if (Tok.Previous->Type == TT_RegexLiteral)
+ return false;
return spaceRequiredBetween(Line, *Tok.Previous, Tok);
}
+// Returns 'true' if 'Tok' is a brace we'd want to break before in Allman style.
+static bool isAllmanBrace(const FormatToken &Tok) {
+ return Tok.is(tok::l_brace) && Tok.BlockKind == BK_Block &&
+ Tok.Type != TT_ObjCBlockLBrace && Tok.Type != TT_DictLiteral;
+}
+
bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
const FormatToken &Right) {
+ const FormatToken &Left = *Right.Previous;
+ if (Right.NewlinesBefore > 1)
+ return true;
if (Right.is(tok::comment)) {
- return Right.NewlinesBefore > 0;
+ return Right.Previous->BlockKind != BK_BracedInit &&
+ Right.Previous->Type != TT_CtorInitializerColon &&
+ (Right.NewlinesBefore > 0 && Right.HasUnescapedNewline);
} else if (Right.Previous->isTrailingComment() ||
- (Right.is(tok::string_literal) &&
- Right.Previous->is(tok::string_literal))) {
+ (Right.isStringLiteral() && Right.Previous->isStringLiteral())) {
return true;
} else if (Right.Previous->IsUnterminatedLiteral) {
return true;
@@ -1395,45 +1661,83 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
return true;
} else if (Right.Previous->ClosesTemplateDeclaration &&
Right.Previous->MatchingParen &&
- Right.Previous->MatchingParen->BindingStrength == 1 &&
+ Right.Previous->MatchingParen->NestingLevel == 0 &&
Style.AlwaysBreakTemplateDeclarations) {
- // FIXME: Fix horrible hack of using BindingStrength to find top-level <>.
return true;
- } else if (Right.Type == TT_CtorInitializerComma &&
+ } else if ((Right.Type == TT_CtorInitializerComma ||
+ Right.Type == TT_CtorInitializerColon) &&
Style.BreakConstructorInitializersBeforeComma &&
!Style.ConstructorInitializerAllOnOneLineOrOnePerLine) {
return true;
- } else if (Right.Previous->BlockKind == BK_Block &&
- Right.Previous->isNot(tok::r_brace) && Right.isNot(tok::r_brace)) {
+ } else if (Right.is(tok::string_literal) &&
+ Right.TokenText.startswith("R\"")) {
+ // Raw string literals are special wrt. line breaks. The author has made a
+ // deliberate choice and might have aligned the contents of the string
+ // literal accordingly. Thus, we try keep existing line breaks.
+ return Right.NewlinesBefore > 0;
+ } else if (Right.Previous->is(tok::l_brace) && Right.NestingLevel == 1 &&
+ Style.Language == FormatStyle::LK_Proto) {
+ // Don't enums onto single lines in protocol buffers.
return true;
- } else if (Right.is(tok::l_brace) && (Right.BlockKind == BK_Block)) {
- return Style.BreakBeforeBraces == FormatStyle::BS_Allman;
+ } else if (isAllmanBrace(Left) || isAllmanBrace(Right)) {
+ return Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU;
}
+
+ // If the last token before a '}' is a comma or a comment, the intention is to
+ // insert a line break after it in order to make shuffling around entries
+ // easier.
+ const FormatToken *BeforeClosingBrace = nullptr;
+ if (Left.is(tok::l_brace) && Left.MatchingParen)
+ BeforeClosingBrace = Left.MatchingParen->Previous;
+ else if (Right.is(tok::r_brace))
+ BeforeClosingBrace = Right.Previous;
+ if (BeforeClosingBrace &&
+ BeforeClosingBrace->isOneOf(tok::comma, tok::comment))
+ return true;
+
+ if (Style.Language == FormatStyle::LK_JavaScript) {
+ // FIXME: This might apply to other languages and token kinds.
+ if (Right.is(tok::char_constant) && Left.is(tok::plus) && Left.Previous &&
+ Left.Previous->is(tok::char_constant))
+ return true;
+ }
+
return false;
}
bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
const FormatToken &Right) {
const FormatToken &Left = *Right.Previous;
- if (Right.Type == TT_StartOfName || Right.is(tok::kw_operator))
+ if (Left.is(tok::at))
+ return false;
+ if (Left.Tok.getObjCKeywordID() == tok::objc_interface)
+ return false;
+ if (Right.Type == TT_StartOfName ||
+ Right.Type == TT_FunctionDeclarationName || Right.is(tok::kw_operator))
return true;
if (Right.isTrailingComment())
// We rely on MustBreakBefore being set correctly here as we should not
// change the "binding" behavior of a comment.
- return false;
+ // The first comment in a braced lists is always interpreted as belonging to
+ // the first list element. Otherwise, it should be placed outside of the
+ // list.
+ return Left.BlockKind == BK_BracedInit;
if (Left.is(tok::question) && Right.is(tok::colon))
return false;
if (Right.Type == TT_ConditionalExpr || Right.is(tok::question))
return Style.BreakBeforeTernaryOperators;
if (Left.Type == TT_ConditionalExpr || Left.is(tok::question))
return !Style.BreakBeforeTernaryOperators;
- if (Right.is(tok::colon) &&
- (Right.Type == TT_DictLiteral || Right.Type == TT_ObjCMethodExpr))
+ if (Right.Type == TT_InheritanceColon)
+ return true;
+ if (Right.is(tok::colon) && (Right.Type != TT_CtorInitializerColon &&
+ Right.Type != TT_InlineASMColon))
return false;
if (Left.is(tok::colon) &&
(Left.Type == TT_DictLiteral || Left.Type == TT_ObjCMethodExpr))
return true;
- if (Right.Type == TT_ObjCSelectorName)
+ if (Right.Type == TT_SelectorName)
return true;
if (Left.is(tok::r_paren) && Line.Type == LT_ObjCProperty)
return true;
@@ -1452,14 +1756,12 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return false;
if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl)
return false;
- if (Left.Previous) {
- if (Left.is(tok::l_paren) && Right.is(tok::l_paren) &&
- Left.Previous->is(tok::kw___attribute))
- return false;
- if (Left.is(tok::l_paren) && (Left.Previous->Type == TT_BinaryOperator ||
- Left.Previous->Type == TT_CastRParen))
- return false;
- }
+ if (Left.is(tok::l_paren) && Left.Type == TT_AttributeParen)
+ return false;
+ if (Left.is(tok::l_paren) && Left.Previous &&
+ (Left.Previous->Type == TT_BinaryOperator ||
+ Left.Previous->Type == TT_CastRParen || Left.Previous->is(tok::kw_if)))
+ return false;
if (Right.Type == TT_ImplicitStringLiteral)
return false;
@@ -1471,11 +1773,11 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
if (Right.is(tok::r_brace))
return Right.MatchingParen && Right.MatchingParen->BlockKind == BK_Block;
- // Allow breaking after a trailing 'const', e.g. after a method declaration,
- // unless it is follow by ';', '{' or '='.
- if (Left.is(tok::kw_const) && Left.Previous != NULL &&
- Left.Previous->is(tok::r_paren))
- return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal);
+ // Allow breaking after a trailing annotation, e.g. after a method
+ // declaration.
+ if (Left.Type == TT_TrailingAnnotation)
+ return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal, tok::l_paren,
+ tok::less, tok::coloncolon);
if (Right.is(tok::kw___attribute))
return true;
@@ -1483,27 +1785,32 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
if (Left.is(tok::identifier) && Right.is(tok::string_literal))
return true;
+ if (Right.is(tok::identifier) && Right.Next &&
+ Right.Next->Type == TT_DictLiteral)
+ return true;
+
if (Left.Type == TT_CtorInitializerComma &&
Style.BreakConstructorInitializersBeforeComma)
return false;
if (Right.Type == TT_CtorInitializerComma &&
Style.BreakConstructorInitializersBeforeComma)
return true;
- if (Right.isBinaryOperator() && Style.BreakBeforeBinaryOperators)
- return true;
if (Left.is(tok::greater) && Right.is(tok::greater) &&
Left.Type != TT_TemplateCloser)
return false;
+ if (Right.Type == TT_BinaryOperator && Style.BreakBeforeBinaryOperators)
+ return true;
if (Left.Type == TT_ArrayInitializerLSquare)
return true;
- return (Left.isBinaryOperator() && Left.isNot(tok::lessless) &&
+ return (Left.isBinaryOperator() &&
+ !Left.isOneOf(tok::arrowstar, tok::lessless) &&
!Style.BreakBeforeBinaryOperators) ||
Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace,
tok::kw_class, tok::kw_struct) ||
- Right.isOneOf(tok::lessless, tok::arrow, tok::period, tok::colon,
- tok::l_square, tok::at) ||
+ Right.isMemberAccess() ||
+ Right.isOneOf(tok::lessless, tok::colon, tok::l_square, tok::at) ||
(Left.is(tok::r_paren) &&
- Right.isOneOf(tok::identifier, tok::kw_const, tok::kw___attribute)) ||
+ Right.isOneOf(tok::identifier, tok::kw_const)) ||
(Left.is(tok::l_paren) && !Right.is(tok::r_paren));
}
@@ -1514,13 +1821,14 @@ void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) {
llvm::errs() << " M=" << Tok->MustBreakBefore
<< " C=" << Tok->CanBreakBefore << " T=" << Tok->Type
<< " S=" << Tok->SpacesRequiredBefore
+ << " B=" << Tok->BlockParameterCount
<< " P=" << Tok->SplitPenalty << " Name=" << Tok->Tok.getName()
<< " L=" << Tok->TotalLength << " PPK=" << Tok->PackingKind
<< " FakeLParens=";
for (unsigned i = 0, e = Tok->FakeLParens.size(); i != e; ++i)
llvm::errs() << Tok->FakeLParens[i] << "/";
llvm::errs() << " FakeRParens=" << Tok->FakeRParens << "\n";
- if (Tok->Next == NULL)
+ if (!Tok->Next)
assert(Tok == Line.Last);
Tok = Tok->Next;
}
diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h
index aa49b2a5c078..36de010fc940 100644
--- a/lib/Format/TokenAnnotator.h
+++ b/lib/Format/TokenAnnotator.h
@@ -41,13 +41,14 @@ public:
: First(Line.Tokens.front().Tok), Level(Line.Level),
InPPDirective(Line.InPPDirective),
MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false),
- StartsDefinition(false) {
+ Affected(false), LeadingEmptyLinesAffected(false),
+ ChildrenAffected(false) {
assert(!Line.Tokens.empty());
// Calculate Next and Previous for all tokens. Note that we must overwrite
// Next and Previous for every token, as previous formatting runs might have
// left them in a different state.
- First->Previous = NULL;
+ First->Previous = nullptr;
FormatToken *Current = First;
for (std::list<UnwrappedLineNode>::const_iterator I = ++Line.Tokens.begin(),
E = Line.Tokens.end();
@@ -66,7 +67,7 @@ public:
}
}
Last = Current;
- Last->Next = NULL;
+ Last->Next = nullptr;
}
~AnnotatedLine() {
@@ -85,7 +86,17 @@ public:
bool InPPDirective;
bool MustBeDeclaration;
bool MightBeFunctionDecl;
- bool StartsDefinition;
+
+ /// \c True if this line should be formatted, i.e. intersects directly or
+ /// indirectly with one of the input ranges.
+ bool Affected;
+
+ /// \c True if the leading empty lines of this line intersect with one of the
+ /// input ranges.
+ bool LeadingEmptyLinesAffected;
+
+ /// \c True if a one of this line's children intersects with an input range.
+ bool ChildrenAffected;
private:
// Disallow copying.
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index e0b090f6abc9..20dd573162cc 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -13,11 +13,11 @@
///
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "format-parser"
-
#include "UnwrappedLineParser.h"
#include "llvm/Support/Debug.h"
+#define DEBUG_TYPE "format-parser"
+
namespace clang {
namespace format {
@@ -60,7 +60,7 @@ public:
: Line(Line), TokenSource(TokenSource), ResetToken(ResetToken),
PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource),
StructuralError(StructuralError),
- PreviousStructuralError(StructuralError), Token(NULL) {
+ PreviousStructuralError(StructuralError), Token(nullptr) {
TokenSource = this;
Line.Level = 0;
Line.InPPDirective = true;
@@ -74,7 +74,7 @@ public:
StructuralError = PreviousStructuralError;
}
- virtual FormatToken *getNextToken() {
+ FormatToken *getNextToken() override {
// The \c UnwrappedLineParser guards against this by never calling
// \c getNextToken() after it has encountered the first eof token.
assert(!eof());
@@ -84,9 +84,9 @@ public:
return Token;
}
- virtual unsigned getPosition() { return PreviousTokenSource->getPosition(); }
+ unsigned getPosition() override { return PreviousTokenSource->getPosition(); }
- virtual FormatToken *setPosition(unsigned Position) {
+ FormatToken *setPosition(unsigned Position) override {
Token = PreviousTokenSource->setPosition(Position);
return Token;
}
@@ -128,7 +128,7 @@ public:
Parser.CurrentLines = &Parser.PreprocessorDirectives;
else if (!Parser.Line->Tokens.empty())
Parser.CurrentLines = &Parser.Line->Tokens.back().Children;
- PreBlockLine = Parser.Line.take();
+ PreBlockLine = Parser.Line.release();
Parser.Line.reset(new UnwrappedLine());
Parser.Line->Level = PreBlockLine->Level;
Parser.Line->InPPDirective = PreBlockLine->InPPDirective;
@@ -152,6 +152,25 @@ private:
SmallVectorImpl<UnwrappedLine> *OriginalLines;
};
+class CompoundStatementIndenter {
+public:
+ CompoundStatementIndenter(UnwrappedLineParser *Parser,
+ const FormatStyle &Style, unsigned &LineLevel)
+ : LineLevel(LineLevel), OldLineLevel(LineLevel) {
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman) {
+ Parser->addUnwrappedLine();
+ } else if (Style.BreakBeforeBraces == FormatStyle::BS_GNU) {
+ Parser->addUnwrappedLine();
+ ++LineLevel;
+ }
+ }
+ ~CompoundStatementIndenter() { LineLevel = OldLineLevel; }
+
+private:
+ unsigned &LineLevel;
+ unsigned OldLineLevel;
+};
+
namespace {
class IndexedTokenSource : public FormatTokenSource {
@@ -159,17 +178,17 @@ public:
IndexedTokenSource(ArrayRef<FormatToken *> Tokens)
: Tokens(Tokens), Position(-1) {}
- virtual FormatToken *getNextToken() {
+ FormatToken *getNextToken() override {
++Position;
return Tokens[Position];
}
- virtual unsigned getPosition() {
+ unsigned getPosition() override {
assert(Position >= 0);
return Position;
}
- virtual FormatToken *setPosition(unsigned P) {
+ FormatToken *setPosition(unsigned P) override {
Position = P;
return Tokens[Position];
}
@@ -187,14 +206,15 @@ UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
ArrayRef<FormatToken *> Tokens,
UnwrappedLineConsumer &Callback)
: Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
- CurrentLines(&Lines), StructuralError(false), Style(Style), Tokens(NULL),
- Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1) {}
+ CurrentLines(&Lines), StructuralError(false), Style(Style),
+ Tokens(nullptr), Callback(Callback), AllTokens(Tokens),
+ PPBranchLevel(-1) {}
void UnwrappedLineParser::reset() {
PPBranchLevel = -1;
Line.reset(new UnwrappedLine);
CommentsBeforeNextToken.clear();
- FormatTok = NULL;
+ FormatTok = nullptr;
MustBreakBeforeNextToken = false;
PreprocessorDirectives.clear();
CurrentLines = &Lines;
@@ -314,18 +334,30 @@ void UnwrappedLineParser::calculateBraceTypes() {
case tok::r_brace:
if (!LBraceStack.empty()) {
if (LBraceStack.back()->BlockKind == BK_Unknown) {
- // If there is a comma, semicolon or right paren after the closing
- // brace, we assume this is a braced initializer list. Note that
- // regardless how we mark inner braces here, we will overwrite the
- // BlockKind later if we parse a braced list (where all blocks inside
- // are by default braced lists), or when we explicitly detect blocks
- // (for example while parsing lambdas).
- //
- // We exclude + and - as they can be ObjC visibility modifiers.
- if (NextTok->isOneOf(tok::comma, tok::semi, tok::r_paren,
- tok::r_square, tok::l_brace, tok::colon) ||
- (NextTok->isBinaryOperator() &&
- !NextTok->isOneOf(tok::plus, tok::minus))) {
+ bool ProbablyBracedList = false;
+ if (Style.Language == FormatStyle::LK_Proto) {
+ ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square);
+ } else {
+ // Using OriginalColumn to distinguish between ObjC methods and
+ // binary operators is a bit hacky.
+ bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) &&
+ NextTok->OriginalColumn == 0;
+
+ // If there is a comma, semicolon or right paren after the closing
+ // brace, we assume this is a braced initializer list. Note that
+ // regardless how we mark inner braces here, we will overwrite the
+ // BlockKind later if we parse a braced list (where all blocks
+ // inside are by default braced lists), or when we explicitly detect
+ // blocks (for example while parsing lambdas).
+ //
+ // We exclude + and - as they can be ObjC visibility modifiers.
+ ProbablyBracedList =
+ NextTok->isOneOf(tok::comma, tok::semi, tok::period, tok::colon,
+ tok::r_paren, tok::r_square, tok::l_brace,
+ tok::l_paren) ||
+ (NextTok->isBinaryOperator() && !NextIsObjCMethod);
+ }
+ if (ProbablyBracedList) {
Tok->BlockKind = BK_BracedInit;
LBraceStack.back()->BlockKind = BK_BracedInit;
} else {
@@ -336,6 +368,7 @@ void UnwrappedLineParser::calculateBraceTypes() {
LBraceStack.pop_back();
}
break;
+ case tok::at:
case tok::semi:
case tok::kw_if:
case tok::kw_while:
@@ -386,16 +419,34 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
Line->Level = InitialLevel;
}
+static bool IsGoogScope(const UnwrappedLine &Line) {
+ if (Line.Tokens.size() < 4)
+ return false;
+ auto I = Line.Tokens.begin();
+ if (I->Tok->TokenText != "goog")
+ return false;
+ ++I;
+ if (I->Tok->isNot(tok::period))
+ return false;
+ ++I;
+ if (I->Tok->TokenText != "scope")
+ return false;
+ ++I;
+ return I->Tok->is(tok::l_paren);
+}
+
void UnwrappedLineParser::parseChildBlock() {
FormatTok->BlockKind = BK_Block;
nextToken();
{
+ bool GoogScope =
+ Style.Language == FormatStyle::LK_JavaScript && IsGoogScope(*Line);
ScopedLineState LineState(*this);
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
/*MustBeDeclaration=*/false);
- Line->Level += 1;
+ Line->Level += GoogScope ? 0 : 1;
parseLevel(/*HasOpeningBrace=*/true);
- Line->Level -= 1;
+ Line->Level -= GoogScope ? 0 : 1;
}
nextToken();
}
@@ -405,7 +456,7 @@ void UnwrappedLineParser::parsePPDirective() {
ScopedMacroState MacroState(*Line, Tokens, FormatTok, StructuralError);
nextToken();
- if (FormatTok->Tok.getIdentifierInfo() == NULL) {
+ if (!FormatTok->Tok.getIdentifierInfo()) {
parsePPUnknown();
return;
}
@@ -436,14 +487,14 @@ void UnwrappedLineParser::parsePPDirective() {
}
}
-void UnwrappedLineParser::pushPPConditional() {
- if (!PPStack.empty() && PPStack.back() == PP_Unreachable)
+void UnwrappedLineParser::conditionalCompilationCondition(bool Unreachable) {
+ if (Unreachable || (!PPStack.empty() && PPStack.back() == PP_Unreachable))
PPStack.push_back(PP_Unreachable);
else
PPStack.push_back(PP_Conditional);
}
-void UnwrappedLineParser::parsePPIf(bool IfDef) {
+void UnwrappedLineParser::conditionalCompilationStart(bool Unreachable) {
++PPBranchLevel;
assert(PPBranchLevel >= 0 && PPBranchLevel <= (int)PPLevelBranchIndex.size());
if (PPBranchLevel == (int)PPLevelBranchIndex.size()) {
@@ -451,48 +502,56 @@ void UnwrappedLineParser::parsePPIf(bool IfDef) {
PPLevelBranchCount.push_back(0);
}
PPChainBranchIndex.push(0);
- nextToken();
- bool IsLiteralFalse = (FormatTok->Tok.isLiteral() &&
- StringRef(FormatTok->Tok.getLiteralData(),
- FormatTok->Tok.getLength()) == "0") ||
- FormatTok->Tok.is(tok::kw_false);
- if ((!IfDef && IsLiteralFalse) || PPLevelBranchIndex[PPBranchLevel] > 0) {
- PPStack.push_back(PP_Unreachable);
- } else {
- pushPPConditional();
- }
- parsePPUnknown();
+ bool Skip = PPLevelBranchIndex[PPBranchLevel] > 0;
+ conditionalCompilationCondition(Unreachable || Skip);
}
-void UnwrappedLineParser::parsePPElse() {
+void UnwrappedLineParser::conditionalCompilationAlternative() {
if (!PPStack.empty())
PPStack.pop_back();
assert(PPBranchLevel < (int)PPLevelBranchIndex.size());
if (!PPChainBranchIndex.empty())
++PPChainBranchIndex.top();
- if (PPBranchLevel >= 0 && !PPChainBranchIndex.empty() &&
- PPLevelBranchIndex[PPBranchLevel] != PPChainBranchIndex.top()) {
- PPStack.push_back(PP_Unreachable);
- } else {
- pushPPConditional();
- }
- parsePPUnknown();
+ conditionalCompilationCondition(
+ PPBranchLevel >= 0 && !PPChainBranchIndex.empty() &&
+ PPLevelBranchIndex[PPBranchLevel] != PPChainBranchIndex.top());
}
-void UnwrappedLineParser::parsePPElIf() { parsePPElse(); }
-
-void UnwrappedLineParser::parsePPEndIf() {
+void UnwrappedLineParser::conditionalCompilationEnd() {
assert(PPBranchLevel < (int)PPLevelBranchIndex.size());
if (PPBranchLevel >= 0 && !PPChainBranchIndex.empty()) {
if (PPChainBranchIndex.top() + 1 > PPLevelBranchCount[PPBranchLevel]) {
PPLevelBranchCount[PPBranchLevel] = PPChainBranchIndex.top() + 1;
}
}
- --PPBranchLevel;
+ // Guard against #endif's without #if.
+ if (PPBranchLevel > 0)
+ --PPBranchLevel;
if (!PPChainBranchIndex.empty())
PPChainBranchIndex.pop();
if (!PPStack.empty())
PPStack.pop_back();
+}
+
+void UnwrappedLineParser::parsePPIf(bool IfDef) {
+ nextToken();
+ bool IsLiteralFalse = (FormatTok->Tok.isLiteral() &&
+ StringRef(FormatTok->Tok.getLiteralData(),
+ FormatTok->Tok.getLength()) == "0") ||
+ FormatTok->Tok.is(tok::kw_false);
+ conditionalCompilationStart(!IfDef && IsLiteralFalse);
+ parsePPUnknown();
+}
+
+void UnwrappedLineParser::parsePPElse() {
+ conditionalCompilationAlternative();
+ parsePPUnknown();
+}
+
+void UnwrappedLineParser::parsePPElIf() { parsePPElse(); }
+
+void UnwrappedLineParser::parsePPEndIf() {
+ conditionalCompilationEnd();
parsePPUnknown();
}
@@ -551,7 +610,9 @@ bool tokenCanStartNewLine(clang::Token Tok) {
// Colon is used in labels, base class lists, initializer lists,
// range-based for loops, ternary operator, but should never be the
// first token in an unwrapped line.
- Tok.isNot(tok::colon);
+ Tok.isNot(tok::colon) &&
+ // 'noexcept' is a trailing annotation.
+ Tok.isNot(tok::kw_noexcept);
}
void UnwrappedLineParser::parseStructuralElement() {
@@ -620,8 +681,8 @@ void UnwrappedLineParser::parseStructuralElement() {
case tok::kw_case:
parseCaseLabel();
return;
- case tok::kw_return:
- parseReturn();
+ case tok::kw_try:
+ parseTryCatch();
return;
case tok::kw_extern:
nextToken();
@@ -633,6 +694,12 @@ void UnwrappedLineParser::parseStructuralElement() {
return;
}
}
+ break;
+ case tok::identifier:
+ if (FormatTok->IsForEachMacro) {
+ parseForOrWhileLoop();
+ return;
+ }
// In all other cases, parse the declaration.
break;
default:
@@ -648,6 +715,12 @@ void UnwrappedLineParser::parseStructuralElement() {
case tok::kw_enum:
parseEnum();
break;
+ case tok::kw_typedef:
+ nextToken();
+ // FIXME: Use the IdentifierTable instead.
+ if (FormatTok->TokenText == "NS_ENUM")
+ parseEnum();
+ break;
case tok::kw_struct:
case tok::kw_union:
case tok::kw_class:
@@ -667,9 +740,13 @@ void UnwrappedLineParser::parseStructuralElement() {
break;
case tok::caret:
nextToken();
- if (FormatTok->is(tok::l_brace)) {
+ if (FormatTok->Tok.isAnyIdentifier() ||
+ FormatTok->isSimpleTypeSpecifier())
+ nextToken();
+ if (FormatTok->is(tok::l_paren))
+ parseParens();
+ if (FormatTok->is(tok::l_brace))
parseChildBlock();
- }
break;
case tok::l_brace:
if (!tryToParseBracedList()) {
@@ -677,10 +754,9 @@ void UnwrappedLineParser::parseStructuralElement() {
// structural element.
// FIXME: Figure out cases where this is not true, and add projections
// for them (the one we know is missing are lambdas).
- if (Style.BreakBeforeBraces == FormatStyle::BS_Linux ||
- Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup ||
- Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ if (Style.BreakBeforeBraces != FormatStyle::BS_Attach)
addUnwrappedLine();
+ FormatTok->Type = TT_FunctionLBrace;
parseBlock(/*MustBeDeclaration=*/false);
addUnwrappedLine();
return;
@@ -688,8 +764,19 @@ void UnwrappedLineParser::parseStructuralElement() {
// Otherwise this was a braced init list, and the structural
// element continues.
break;
+ case tok::kw_try:
+ // We arrive here when parsing function-try blocks.
+ parseTryCatch();
+ return;
case tok::identifier: {
StringRef Text = FormatTok->TokenText;
+ // Parse function literal unless 'function' is the first token in a line
+ // in which case this should be treated as a free-standing function.
+ if (Style.Language == FormatStyle::LK_JavaScript && Text == "function" &&
+ Line->Tokens.size() > 0) {
+ tryToParseJSFunction();
+ break;
+ }
nextToken();
if (Line->Tokens.size() == 1) {
if (FormatTok->Tok.is(tok::colon)) {
@@ -699,8 +786,8 @@ void UnwrappedLineParser::parseStructuralElement() {
// Recognize function-like macro usages without trailing semicolon.
if (FormatTok->Tok.is(tok::l_paren)) {
parseParens();
- if (FormatTok->HasUnescapedNewline &&
- tokenCanStartNewLine(FormatTok->Tok)) {
+ if (FormatTok->NewlinesBefore > 0 &&
+ tokenCanStartNewLine(FormatTok->Tok) && Text == Text.upper()) {
addUnwrappedLine();
return;
}
@@ -720,7 +807,7 @@ void UnwrappedLineParser::parseStructuralElement() {
}
break;
case tok::l_square:
- tryToParseLambda();
+ parseSquare();
break;
default:
nextToken();
@@ -729,36 +816,50 @@ void UnwrappedLineParser::parseStructuralElement() {
} while (!eof());
}
-void UnwrappedLineParser::tryToParseLambda() {
+bool UnwrappedLineParser::tryToParseLambda() {
// FIXME: This is a dirty way to access the previous token. Find a better
// solution.
if (!Line->Tokens.empty() &&
- Line->Tokens.back().Tok->isOneOf(tok::identifier, tok::kw_operator)) {
+ (Line->Tokens.back().Tok->isOneOf(tok::identifier, tok::kw_operator) ||
+ Line->Tokens.back().Tok->closesScope() ||
+ Line->Tokens.back().Tok->isSimpleTypeSpecifier())) {
nextToken();
- return;
+ return false;
}
assert(FormatTok->is(tok::l_square));
FormatToken &LSquare = *FormatTok;
if (!tryToParseLambdaIntroducer())
- return;
+ return false;
while (FormatTok->isNot(tok::l_brace)) {
+ if (FormatTok->isSimpleTypeSpecifier()) {
+ nextToken();
+ continue;
+ }
switch (FormatTok->Tok.getKind()) {
case tok::l_brace:
break;
case tok::l_paren:
parseParens();
break;
+ case tok::less:
+ case tok::greater:
case tok::identifier:
+ case tok::coloncolon:
case tok::kw_mutable:
nextToken();
break;
+ case tok::arrow:
+ FormatTok->Type = TT_TrailingReturnArrow;
+ nextToken();
+ break;
default:
- return;
+ return true;
}
}
LSquare.Type = TT_LambdaLSquare;
parseChildBlock();
+ return true;
}
bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
@@ -793,6 +894,8 @@ bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
if (!FormatTok->isOneOf(tok::identifier, tok::kw_this))
return false;
nextToken();
+ if (FormatTok->is(tok::ellipsis))
+ nextToken();
if (FormatTok->is(tok::comma)) {
nextToken();
} else if (FormatTok->is(tok::r_square)) {
@@ -805,6 +908,27 @@ bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
return false;
}
+void UnwrappedLineParser::tryToParseJSFunction() {
+ nextToken();
+
+ // Consume function name.
+ if (FormatTok->is(tok::identifier))
+ nextToken();
+
+ if (FormatTok->isNot(tok::l_paren))
+ return;
+ nextToken();
+ while (FormatTok->isNot(tok::l_brace)) {
+ // Err on the side of caution in order to avoid consuming the full file in
+ // case of incomplete code.
+ if (!FormatTok->isOneOf(tok::identifier, tok::comma, tok::r_paren,
+ tok::comment))
+ return;
+ nextToken();
+ }
+ parseChildBlock();
+}
+
bool UnwrappedLineParser::tryToParseBracedList() {
if (FormatTok->BlockKind == BK_Unknown)
calculateBraceTypes();
@@ -822,9 +946,11 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
// FIXME: Once we have an expression parser in the UnwrappedLineParser,
// replace this by using parseAssigmentExpression() inside.
do {
- // FIXME: When we start to support lambdas, we'll want to parse them away
- // here, otherwise our bail-out scenarios below break. The better solution
- // might be to just implement a more or less complete expression parser.
+ if (Style.Language == FormatStyle::LK_JavaScript &&
+ FormatTok->TokenText == "function") {
+ tryToParseJSFunction();
+ continue;
+ }
switch (FormatTok->Tok.getKind()) {
case tok::caret:
nextToken();
@@ -861,33 +987,34 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
return false;
}
-void UnwrappedLineParser::parseReturn() {
+void UnwrappedLineParser::parseParens() {
+ assert(FormatTok->Tok.is(tok::l_paren) && "'(' expected.");
nextToken();
-
do {
switch (FormatTok->Tok.getKind()) {
- case tok::l_brace:
- parseBracedList();
- if (FormatTok->Tok.isNot(tok::semi)) {
- // Assume missing ';'.
- addUnwrappedLine();
- return;
- }
- break;
case tok::l_paren:
parseParens();
break;
- case tok::r_brace:
- // Assume missing ';'.
- addUnwrappedLine();
- return;
- case tok::semi:
+ case tok::r_paren:
nextToken();
- addUnwrappedLine();
+ return;
+ case tok::r_brace:
+ // A "}" inside parenthesis is an error if there wasn't a matching "{".
return;
case tok::l_square:
tryToParseLambda();
break;
+ case tok::l_brace: {
+ if (!tryToParseBracedList()) {
+ parseChildBlock();
+ }
+ break;
+ }
+ case tok::at:
+ nextToken();
+ if (FormatTok->Tok.is(tok::l_brace))
+ parseBracedList();
+ break;
default:
nextToken();
break;
@@ -895,22 +1022,23 @@ void UnwrappedLineParser::parseReturn() {
} while (!eof());
}
-void UnwrappedLineParser::parseParens() {
- assert(FormatTok->Tok.is(tok::l_paren) && "'(' expected.");
- nextToken();
+void UnwrappedLineParser::parseSquare() {
+ assert(FormatTok->Tok.is(tok::l_square) && "'[' expected.");
+ if (tryToParseLambda())
+ return;
do {
switch (FormatTok->Tok.getKind()) {
case tok::l_paren:
parseParens();
break;
- case tok::r_paren:
+ case tok::r_square:
nextToken();
return;
case tok::r_brace:
// A "}" inside parenthesis is an error if there wasn't a matching "{".
return;
case tok::l_square:
- tryToParseLambda();
+ parseSquare();
break;
case tok::l_brace: {
if (!tryToParseBracedList()) {
@@ -937,13 +1065,14 @@ void UnwrappedLineParser::parseIfThenElse() {
parseParens();
bool NeedsUnwrappedLine = false;
if (FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
- addUnwrappedLine();
+ CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(/*MustBeDeclaration=*/false);
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU) {
addUnwrappedLine();
- else
+ } else {
NeedsUnwrappedLine = true;
+ }
} else {
addUnwrappedLine();
++Line->Level;
@@ -953,8 +1082,7 @@ void UnwrappedLineParser::parseIfThenElse() {
if (FormatTok->Tok.is(tok::kw_else)) {
nextToken();
if (FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
- addUnwrappedLine();
+ CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(/*MustBeDeclaration=*/false);
addUnwrappedLine();
} else if (FormatTok->Tok.is(tok::kw_if)) {
@@ -970,6 +1098,72 @@ void UnwrappedLineParser::parseIfThenElse() {
}
}
+void UnwrappedLineParser::parseTryCatch() {
+ assert(FormatTok->is(tok::kw_try) && "'try' expected");
+ nextToken();
+ bool NeedsUnwrappedLine = false;
+ if (FormatTok->is(tok::colon)) {
+ // We are in a function try block, what comes is an initializer list.
+ nextToken();
+ while (FormatTok->is(tok::identifier)) {
+ nextToken();
+ if (FormatTok->is(tok::l_paren))
+ parseParens();
+ else
+ StructuralError = true;
+ if (FormatTok->is(tok::comma))
+ nextToken();
+ }
+ }
+ if (FormatTok->is(tok::l_brace)) {
+ CompoundStatementIndenter Indenter(this, Style, Line->Level);
+ parseBlock(/*MustBeDeclaration=*/false);
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU ||
+ Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup) {
+ addUnwrappedLine();
+ } else {
+ NeedsUnwrappedLine = true;
+ }
+ } else if (!FormatTok->is(tok::kw_catch)) {
+ // The C++ standard requires a compound-statement after a try.
+ // If there's none, we try to assume there's a structuralElement
+ // and try to continue.
+ StructuralError = true;
+ addUnwrappedLine();
+ ++Line->Level;
+ parseStructuralElement();
+ --Line->Level;
+ }
+ while (FormatTok->is(tok::kw_catch) ||
+ (Style.Language == FormatStyle::LK_JavaScript &&
+ FormatTok->TokenText == "finally")) {
+ nextToken();
+ while (FormatTok->isNot(tok::l_brace)) {
+ if (FormatTok->is(tok::l_paren)) {
+ parseParens();
+ continue;
+ }
+ if (FormatTok->isOneOf(tok::semi, tok::r_brace))
+ return;
+ nextToken();
+ }
+ NeedsUnwrappedLine = false;
+ CompoundStatementIndenter Indenter(this, Style, Line->Level);
+ parseBlock(/*MustBeDeclaration=*/false);
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU ||
+ Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup) {
+ addUnwrappedLine();
+ } else {
+ NeedsUnwrappedLine = true;
+ }
+ }
+ if (NeedsUnwrappedLine) {
+ addUnwrappedLine();
+ }
+}
+
void UnwrappedLineParser::parseNamespace() {
assert(FormatTok->Tok.is(tok::kw_namespace) && "'namespace' expected");
nextToken();
@@ -977,7 +1171,8 @@ void UnwrappedLineParser::parseNamespace() {
nextToken();
if (FormatTok->Tok.is(tok::l_brace)) {
if (Style.BreakBeforeBraces == FormatStyle::BS_Linux ||
- Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU)
addUnwrappedLine();
bool AddLevel = Style.NamespaceIndentation == FormatStyle::NI_All ||
@@ -994,14 +1189,14 @@ void UnwrappedLineParser::parseNamespace() {
}
void UnwrappedLineParser::parseForOrWhileLoop() {
- assert((FormatTok->Tok.is(tok::kw_for) || FormatTok->Tok.is(tok::kw_while)) &&
- "'for' or 'while' expected");
+ assert((FormatTok->Tok.is(tok::kw_for) || FormatTok->Tok.is(tok::kw_while) ||
+ FormatTok->IsForEachMacro) &&
+ "'for', 'while' or foreach macro expected");
nextToken();
if (FormatTok->Tok.is(tok::l_paren))
parseParens();
if (FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
- addUnwrappedLine();
+ CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(/*MustBeDeclaration=*/false);
addUnwrappedLine();
} else {
@@ -1016,9 +1211,10 @@ void UnwrappedLineParser::parseDoWhile() {
assert(FormatTok->Tok.is(tok::kw_do) && "'do' expected");
nextToken();
if (FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
- addUnwrappedLine();
+ CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(/*MustBeDeclaration=*/false);
+ if (Style.BreakBeforeBraces == FormatStyle::BS_GNU)
+ addUnwrappedLine();
} else {
addUnwrappedLine();
++Line->Level;
@@ -1042,17 +1238,20 @@ void UnwrappedLineParser::parseLabel() {
if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0))
--Line->Level;
if (CommentsBeforeNextToken.empty() && FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
- addUnwrappedLine();
+ CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(/*MustBeDeclaration=*/false);
if (FormatTok->Tok.is(tok::kw_break)) {
- // "break;" after "}" on its own line only for BS_Allman
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ // "break;" after "}" on its own line only for BS_Allman and BS_GNU
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU) {
addUnwrappedLine();
+ }
parseStructuralElement();
}
+ addUnwrappedLine();
+ } else {
+ addUnwrappedLine();
}
- addUnwrappedLine();
Line->Level = OldLineLevel;
}
@@ -1071,8 +1270,7 @@ void UnwrappedLineParser::parseSwitch() {
if (FormatTok->Tok.is(tok::l_paren))
parseParens();
if (FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
- addUnwrappedLine();
+ CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(/*MustBeDeclaration=*/false);
addUnwrappedLine();
} else {
@@ -1085,6 +1283,10 @@ void UnwrappedLineParser::parseSwitch() {
void UnwrappedLineParser::parseAccessSpecifier() {
nextToken();
+ // Understand Qt's slots.
+ if (FormatTok->is(tok::identifier) &&
+ (FormatTok->TokenText == "slots" || FormatTok->TokenText == "Q_SLOTS"))
+ nextToken();
// Otherwise, we don't know what it is, and we'd better keep the next token.
if (FormatTok->Tok.is(tok::colon))
nextToken();
@@ -1092,11 +1294,13 @@ void UnwrappedLineParser::parseAccessSpecifier() {
}
void UnwrappedLineParser::parseEnum() {
- nextToken();
+ if (FormatTok->Tok.is(tok::kw_enum)) {
+ // Won't be 'enum' for NS_ENUMs.
+ nextToken();
+ }
// Eat up enum class ...
- if (FormatTok->Tok.is(tok::kw_class) ||
- FormatTok->Tok.is(tok::kw_struct))
- nextToken();
+ if (FormatTok->Tok.is(tok::kw_class) || FormatTok->Tok.is(tok::kw_struct))
+ nextToken();
while (FormatTok->Tok.getIdentifierInfo() ||
FormatTok->isOneOf(tok::colon, tok::coloncolon)) {
nextToken();
@@ -1159,10 +1363,11 @@ void UnwrappedLineParser::parseRecord() {
}
if (FormatTok->Tok.is(tok::l_brace)) {
if (Style.BreakBeforeBraces == FormatStyle::BS_Linux ||
- Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU)
addUnwrappedLine();
- parseBlock(/*MustBeDeclaration=*/true, /*Addlevel=*/true,
+ parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/true,
/*MunchSemi=*/false);
}
// We fall through to parsing a structural element afterwards, so
@@ -1189,6 +1394,10 @@ void UnwrappedLineParser::parseObjCUntilAtEnd() {
parseBlock(/*MustBeDeclaration=*/false);
// In ObjC interfaces, nothing should be following the "}".
addUnwrappedLine();
+ } else if (FormatTok->is(tok::r_brace)) {
+ // Ignore stray "}". parseStructuralElement doesn't consume them.
+ nextToken();
+ addUnwrappedLine();
} else {
parseStructuralElement();
}
@@ -1210,9 +1419,12 @@ void UnwrappedLineParser::parseObjCInterfaceOrImplementation() {
if (FormatTok->Tok.is(tok::less))
parseObjCProtocolList();
- // If instance variables are present, keep the '{' on the first line too.
- if (FormatTok->Tok.is(tok::l_brace))
+ if (FormatTok->Tok.is(tok::l_brace)) {
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU)
+ addUnwrappedLine();
parseBlock(/*MustBeDeclaration=*/true);
+ }
// With instance variables, this puts '}' on its own line. Without instance
// variables, this ends the @interface line.
@@ -1283,13 +1495,18 @@ void UnwrappedLineParser::addUnwrappedLine() {
bool UnwrappedLineParser::eof() const { return FormatTok->Tok.is(tok::eof); }
+bool UnwrappedLineParser::isOnNewLine(const FormatToken &FormatTok) {
+ return (Line->InPPDirective || FormatTok.HasUnescapedNewline) &&
+ FormatTok.NewlinesBefore > 0;
+}
+
void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
bool JustComments = Line->Tokens.empty();
for (SmallVectorImpl<FormatToken *>::const_iterator
I = CommentsBeforeNextToken.begin(),
E = CommentsBeforeNextToken.end();
I != E; ++I) {
- if ((*I)->NewlinesBefore && JustComments) {
+ if (isOnNewLine(**I) && JustComments) {
addUnwrappedLine();
}
pushToken(*I);
@@ -1303,7 +1520,7 @@ void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
void UnwrappedLineParser::nextToken() {
if (eof())
return;
- flushComments(FormatTok->NewlinesBefore > 0);
+ flushComments(isOnNewLine(*FormatTok));
pushToken(FormatTok);
readToken();
}
@@ -1312,6 +1529,7 @@ void UnwrappedLineParser::readToken() {
bool CommentsInCurrentLine = true;
do {
FormatTok = Tokens->getNextToken();
+ assert(FormatTok);
while (!Line->InPPDirective && FormatTok->Tok.is(tok::hash) &&
(FormatTok->HasUnescapedNewline || FormatTok->IsFirst)) {
// If there is an unfinished unwrapped line, we flush the preprocessor
@@ -1322,9 +1540,22 @@ void UnwrappedLineParser::readToken() {
// Comments stored before the preprocessor directive need to be output
// before the preprocessor directive, at the same level as the
// preprocessor directive, as we consider them to apply to the directive.
- flushComments(FormatTok->NewlinesBefore > 0);
+ flushComments(isOnNewLine(*FormatTok));
parsePPDirective();
}
+ while (FormatTok->Type == TT_ConflictStart ||
+ FormatTok->Type == TT_ConflictEnd ||
+ FormatTok->Type == TT_ConflictAlternative) {
+ if (FormatTok->Type == TT_ConflictStart) {
+ conditionalCompilationStart(/*Unreachable=*/false);
+ } else if (FormatTok->Type == TT_ConflictAlternative) {
+ conditionalCompilationAlternative();
+ } else if (FormatTok->Type == TT_ConflictEnd) {
+ conditionalCompilationEnd();
+ }
+ FormatTok = Tokens->getNextToken();
+ FormatTok->MustBreakBefore = true;
+ }
if (!PPStack.empty() && (PPStack.back() == PP_Unreachable) &&
!Line->InPPDirective) {
@@ -1333,7 +1564,7 @@ void UnwrappedLineParser::readToken() {
if (!FormatTok->Tok.is(tok::comment))
return;
- if (FormatTok->NewlinesBefore > 0 || FormatTok->IsFirst) {
+ if (isOnNewLine(*FormatTok) || FormatTok->IsFirst) {
CommentsInCurrentLine = false;
}
if (CommentsInCurrentLine) {
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index f1f4e57a20b3..c9182e9d71d3 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -16,9 +16,9 @@
#ifndef LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H
#define LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H
+#include "FormatToken.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Format/Format.h"
-#include "FormatToken.h"
#include <list>
namespace clang {
@@ -82,9 +82,10 @@ private:
void parseStructuralElement();
bool tryToParseBracedList();
bool parseBracedList(bool ContinueOnSemicolons = false);
- void parseReturn();
void parseParens();
+ void parseSquare();
void parseIfThenElse();
+ void parseTryCatch();
void parseForOrWhileLoop();
void parseDoWhile();
void parseLabel();
@@ -98,8 +99,9 @@ private:
void parseObjCUntilAtEnd();
void parseObjCInterfaceOrImplementation();
void parseObjCProtocol();
- void tryToParseLambda();
+ bool tryToParseLambda();
bool tryToParseLambdaIntroducer();
+ void tryToParseJSFunction();
void addUnwrappedLine();
bool eof() const;
void nextToken();
@@ -107,12 +109,22 @@ private:
void flushComments(bool NewlineBeforeNext);
void pushToken(FormatToken *Tok);
void calculateBraceTypes();
- void pushPPConditional();
+
+ // Marks a conditional compilation edge (for example, an '#if', '#ifdef',
+ // '#else' or merge conflict marker). If 'Unreachable' is true, assumes
+ // this branch either cannot be taken (for example '#if false'), or should
+ // not be taken in this round.
+ void conditionalCompilationCondition(bool Unreachable);
+ void conditionalCompilationStart(bool Unreachable);
+ void conditionalCompilationAlternative();
+ void conditionalCompilationEnd();
+
+ bool isOnNewLine(const FormatToken &FormatTok);
// FIXME: We are constantly running into bugs where Line.Level is incorrectly
// subtracted from beyond 0. Introduce a method to subtract from Line.Level
// and use that everywhere in the Parser.
- OwningPtr<UnwrappedLine> Line;
+ std::unique_ptr<UnwrappedLine> Line;
// Comments are sorted into unwrapped lines by whether they are in the same
// line as the previous token, or not. If not, they belong to the next token.
@@ -185,10 +197,11 @@ private:
std::stack<int> PPChainBranchIndex;
friend class ScopedLineState;
+ friend class CompoundStatementIndenter;
};
struct UnwrappedLineNode {
- UnwrappedLineNode() : Tok(NULL) {}
+ UnwrappedLineNode() : Tok(nullptr) {}
UnwrappedLineNode(FormatToken *Tok) : Tok(Tok) {}
FormatToken *Tok;
diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp
index 26a8d41e8741..47b94de4c6f7 100644
--- a/lib/Format/WhitespaceManager.cpp
+++ b/lib/Format/WhitespaceManager.cpp
@@ -18,9 +18,8 @@
namespace clang {
namespace format {
-bool
-WhitespaceManager::Change::IsBeforeInFile::operator()(const Change &C1,
- const Change &C2) const {
+bool WhitespaceManager::Change::IsBeforeInFile::
+operator()(const Change &C1, const Change &C2) const {
return SourceMgr.isBeforeInTranslationUnit(
C1.OriginalWhitespaceRange.getBegin(),
C2.OriginalWhitespaceRange.getBegin());
@@ -28,7 +27,7 @@ WhitespaceManager::Change::IsBeforeInFile::operator()(const Change &C1,
WhitespaceManager::Change::Change(
bool CreateReplacement, const SourceRange &OriginalWhitespaceRange,
- unsigned IndentLevel, unsigned Spaces, unsigned StartOfTokenColumn,
+ unsigned IndentLevel, int Spaces, unsigned StartOfTokenColumn,
unsigned NewlinesBefore, StringRef PreviousLinePostfix,
StringRef CurrentLinePrefix, tok::TokenKind Kind, bool ContinuesPPDirective)
: CreateReplacement(CreateReplacement),
@@ -69,14 +68,14 @@ void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
void WhitespaceManager::replaceWhitespaceInToken(
const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,
- unsigned Newlines, unsigned IndentLevel, unsigned Spaces) {
+ unsigned Newlines, unsigned IndentLevel, int Spaces) {
if (Tok.Finalized)
return;
+ SourceLocation Start = Tok.getStartOfNonWhitespace().getLocWithOffset(Offset);
Changes.push_back(Change(
- true, SourceRange(Tok.getStartOfNonWhitespace().getLocWithOffset(Offset),
- Tok.getStartOfNonWhitespace().getLocWithOffset(
- Offset + ReplaceChars)),
- IndentLevel, Spaces, Spaces, Newlines, PreviousPostfix, CurrentPrefix,
+ true, SourceRange(Start, Start.getLocWithOffset(ReplaceChars)),
+ IndentLevel, Spaces, std::max(0, Spaces), Newlines, PreviousPostfix,
+ CurrentPrefix,
// If we don't add a newline this change doesn't start a comment. Thus,
// when we align line comments, we don't need to treat this change as one.
// FIXME: We still need to take this change in account to properly
@@ -122,6 +121,22 @@ void WhitespaceManager::calculateLineBreakInformation() {
// cases, setting TokenLength of the last token to 0 is wrong.
Changes.back().TokenLength = 0;
Changes.back().IsTrailingComment = Changes.back().Kind == tok::comment;
+
+ const WhitespaceManager::Change *LastBlockComment = nullptr;
+ for (auto &Change : Changes) {
+ Change.StartOfBlockComment = nullptr;
+ Change.IndentationOffset = 0;
+ if (Change.Kind == tok::comment) {
+ LastBlockComment = &Change;
+ } else if (Change.Kind == tok::unknown) {
+ if ((Change.StartOfBlockComment = LastBlockComment))
+ Change.IndentationOffset =
+ Change.StartOfTokenColumn -
+ Change.StartOfBlockComment->StartOfTokenColumn;
+ } else {
+ LastBlockComment = nullptr;
+ }
+ }
}
void WhitespaceManager::alignTrailingComments() {
@@ -131,58 +146,62 @@ void WhitespaceManager::alignTrailingComments() {
bool BreakBeforeNext = false;
unsigned Newlines = 0;
for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
+ if (Changes[i].StartOfBlockComment)
+ continue;
+ Newlines += Changes[i].NewlinesBefore;
+ if (!Changes[i].IsTrailingComment)
+ continue;
+
unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
- // FIXME: Correctly handle ChangeMaxColumn in PP directives.
unsigned ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength;
- Newlines += Changes[i].NewlinesBefore;
- if (Changes[i].IsTrailingComment) {
- // If this comment follows an } in column 0, it probably documents the
- // closing of a namespace and we don't want to align it.
- bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 0 &&
- Changes[i - 1].Kind == tok::r_brace &&
- Changes[i - 1].StartOfTokenColumn == 0;
- bool WasAlignedWithStartOfNextLine = false;
- if (Changes[i].NewlinesBefore == 1) { // A comment on its own line.
- for (unsigned j = i + 1; j != e; ++j) {
- if (Changes[j].Kind != tok::comment) { // Skip over comments.
- // The start of the next token was previously aligned with the
- // start of this comment.
- WasAlignedWithStartOfNextLine =
- (SourceMgr.getSpellingColumnNumber(
- Changes[i].OriginalWhitespaceRange.getEnd()) ==
- SourceMgr.getSpellingColumnNumber(
- Changes[j].OriginalWhitespaceRange.getEnd()));
- break;
- }
+ if (i + 1 != e && Changes[i + 1].ContinuesPPDirective)
+ ChangeMaxColumn -= 2;
+ // If this comment follows an } in column 0, it probably documents the
+ // closing of a namespace and we don't want to align it.
+ bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 0 &&
+ Changes[i - 1].Kind == tok::r_brace &&
+ Changes[i - 1].StartOfTokenColumn == 0;
+ bool WasAlignedWithStartOfNextLine = false;
+ if (Changes[i].NewlinesBefore == 1) { // A comment on its own line.
+ for (unsigned j = i + 1; j != e; ++j) {
+ if (Changes[j].Kind != tok::comment) { // Skip over comments.
+ // The start of the next token was previously aligned with the
+ // start of this comment.
+ WasAlignedWithStartOfNextLine =
+ (SourceMgr.getSpellingColumnNumber(
+ Changes[i].OriginalWhitespaceRange.getEnd()) ==
+ SourceMgr.getSpellingColumnNumber(
+ Changes[j].OriginalWhitespaceRange.getEnd()));
+ break;
}
}
- if (!Style.AlignTrailingComments || FollowsRBraceInColumn0) {
- alignTrailingComments(StartOfSequence, i, MinColumn);
- MinColumn = ChangeMinColumn;
- MaxColumn = ChangeMinColumn;
- StartOfSequence = i;
- } else if (BreakBeforeNext || Newlines > 1 ||
- (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||
- // Break the comment sequence if the previous line did not end
- // in a trailing comment.
- (Changes[i].NewlinesBefore == 1 && i > 0 &&
- !Changes[i - 1].IsTrailingComment) ||
- WasAlignedWithStartOfNextLine) {
- alignTrailingComments(StartOfSequence, i, MinColumn);
- MinColumn = ChangeMinColumn;
- MaxColumn = ChangeMaxColumn;
- StartOfSequence = i;
- } else {
- MinColumn = std::max(MinColumn, ChangeMinColumn);
- MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
- }
- BreakBeforeNext =
- (i == 0) || (Changes[i].NewlinesBefore > 1) ||
- // Never start a sequence with a comment at the beginning of
- // the line.
- (Changes[i].NewlinesBefore == 1 && StartOfSequence == i);
- Newlines = 0;
}
+ if (!Style.AlignTrailingComments || FollowsRBraceInColumn0) {
+ alignTrailingComments(StartOfSequence, i, MinColumn);
+ MinColumn = ChangeMinColumn;
+ MaxColumn = ChangeMinColumn;
+ StartOfSequence = i;
+ } else if (BreakBeforeNext || Newlines > 1 ||
+ (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||
+ // Break the comment sequence if the previous line did not end
+ // in a trailing comment.
+ (Changes[i].NewlinesBefore == 1 && i > 0 &&
+ !Changes[i - 1].IsTrailingComment) ||
+ WasAlignedWithStartOfNextLine) {
+ alignTrailingComments(StartOfSequence, i, MinColumn);
+ MinColumn = ChangeMinColumn;
+ MaxColumn = ChangeMaxColumn;
+ StartOfSequence = i;
+ } else {
+ MinColumn = std::max(MinColumn, ChangeMinColumn);
+ MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
+ }
+ BreakBeforeNext =
+ (i == 0) || (Changes[i].NewlinesBefore > 1) ||
+ // Never start a sequence with a comment at the beginning of
+ // the line.
+ (Changes[i].NewlinesBefore == 1 && StartOfSequence == i);
+ Newlines = 0;
}
alignTrailingComments(StartOfSequence, Changes.size(), MinColumn);
}
@@ -190,11 +209,20 @@ void WhitespaceManager::alignTrailingComments() {
void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End,
unsigned Column) {
for (unsigned i = Start; i != End; ++i) {
+ int Shift = 0;
if (Changes[i].IsTrailingComment) {
- assert(Column >= Changes[i].StartOfTokenColumn);
- Changes[i].Spaces += Column - Changes[i].StartOfTokenColumn;
- Changes[i].StartOfTokenColumn = Column;
+ Shift = Column - Changes[i].StartOfTokenColumn;
+ }
+ if (Changes[i].StartOfBlockComment) {
+ Shift = Changes[i].IndentationOffset +
+ Changes[i].StartOfBlockComment->StartOfTokenColumn -
+ Changes[i].StartOfTokenColumn;
}
+ assert(Shift >= 0);
+ Changes[i].Spaces += Shift;
+ if (i + 1 != End)
+ Changes[i + 1].PreviousEndOfTokenColumn += Shift;
+ Changes[i].StartOfTokenColumn += Shift;
}
}
@@ -241,8 +269,8 @@ void WhitespaceManager::generateChanges() {
C.PreviousEndOfTokenColumn, C.EscapedNewlineColumn);
else
appendNewlineText(ReplacementText, C.NewlinesBefore);
- appendIndentText(ReplacementText, C.IndentLevel, C.Spaces,
- C.StartOfTokenColumn - C.Spaces);
+ appendIndentText(ReplacementText, C.IndentLevel, std::max(0, C.Spaces),
+ C.StartOfTokenColumn - std::max(0, C.Spaces));
ReplacementText.append(C.CurrentLinePrefix);
storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
}
diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h
index ae6202395f6b..189b1aefa03f 100644
--- a/lib/Format/WhitespaceManager.h
+++ b/lib/Format/WhitespaceManager.h
@@ -51,7 +51,7 @@ public:
unsigned StartOfTokenColumn,
bool InPPDirective = false);
- /// \brief Adds information about an unchangable token's whitespace.
+ /// \brief Adds information about an unchangeable token's whitespace.
///
/// Needs to be called for every token for which \c replaceWhitespace
/// was not called.
@@ -63,6 +63,12 @@ public:
/// (in this order) at \p Offset inside \p Tok, replacing \p ReplaceChars
/// characters.
///
+ /// Note: \p Spaces can be negative to retain information about initial
+ /// relative column offset between a line of a block comment and the start of
+ /// the comment. This negative offset may be compensated by trailing comment
+ /// alignment here. In all other cases negative \p Spaces will be truncated to
+ /// 0.
+ ///
/// When \p InPPDirective is true, escaped newlines are inserted. \p Spaces is
/// used to align backslashes correctly.
void replaceWhitespaceInToken(const FormatToken &Tok, unsigned Offset,
@@ -70,7 +76,7 @@ public:
StringRef PreviousPostfix,
StringRef CurrentPrefix, bool InPPDirective,
unsigned Newlines, unsigned IndentLevel,
- unsigned Spaces);
+ int Spaces);
/// \brief Returns all the \c Replacements created during formatting.
const tooling::Replacements &generateReplacements();
@@ -101,7 +107,7 @@ private:
/// \p StartOfTokenColumn and \p InPPDirective will be used to lay out
/// trailing comments and escaped newlines.
Change(bool CreateReplacement, const SourceRange &OriginalWhitespaceRange,
- unsigned IndentLevel, unsigned Spaces, unsigned StartOfTokenColumn,
+ unsigned IndentLevel, int Spaces, unsigned StartOfTokenColumn,
unsigned NewlinesBefore, StringRef PreviousLinePostfix,
StringRef CurrentLinePrefix, tok::TokenKind Kind,
bool ContinuesPPDirective);
@@ -128,7 +134,10 @@ private:
// The number of spaces in front of the token or broken part of the token.
// This will be adapted when aligning tokens.
- unsigned Spaces;
+ // Can be negative to retain information about the initial relative offset
+ // of the lines in a block comment. This is used when aligning trailing
+ // comments. Uncompensated negative offset is truncated to 0.
+ int Spaces;
// \c IsTrailingComment, \c TokenLength, \c PreviousEndOfTokenColumn and
// \c EscapedNewlineColumn will be calculated in
@@ -137,6 +146,17 @@ private:
unsigned TokenLength;
unsigned PreviousEndOfTokenColumn;
unsigned EscapedNewlineColumn;
+
+ // These fields are used to retain correct relative line indentation in a
+ // block comment when aligning trailing comments.
+ //
+ // If this Change represents a continuation of a block comment,
+ // \c StartOfBlockComment is pointer to the first Change in the block
+ // comment. \c IndentationOffset is a relative column offset to this
+ // change, so that the correct column can be reconstructed at the end of
+ // the alignment process.
+ const Change *StartOfBlockComment;
+ int IndentationOffset;
};
/// \brief Calculate \c IsTrailingComment, \c TokenLength for the last tokens
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 1ef4c1868112..54a6d474c18a 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -36,12 +36,12 @@ namespace {
typedef RecursiveASTVisitor<ASTPrinter> base;
public:
- ASTPrinter(raw_ostream *Out = NULL, bool Dump = false,
+ ASTPrinter(raw_ostream *Out = nullptr, bool Dump = false,
StringRef FilterString = "", bool DumpLookups = false)
: Out(Out ? *Out : llvm::outs()), Dump(Dump),
FilterString(FilterString), DumpLookups(DumpLookups) {}
- virtual void HandleTranslationUnit(ASTContext &Context) {
+ void HandleTranslationUnit(ASTContext &Context) override {
TranslationUnitDecl *D = Context.getTranslationUnitDecl();
if (FilterString.empty())
@@ -53,7 +53,7 @@ namespace {
bool shouldWalkTypesOfTypeLocs() const { return false; }
bool TraverseDecl(Decl *D) {
- if (D != NULL && filterMatches(D)) {
+ if (D && filterMatches(D)) {
bool ShowColors = Out.has_colors();
if (ShowColors)
Out.changeColor(raw_ostream::BLUE);
@@ -98,16 +98,16 @@ namespace {
class ASTDeclNodeLister : public ASTConsumer,
public RecursiveASTVisitor<ASTDeclNodeLister> {
public:
- ASTDeclNodeLister(raw_ostream *Out = NULL)
+ ASTDeclNodeLister(raw_ostream *Out = nullptr)
: Out(Out ? *Out : llvm::outs()) {}
- virtual void HandleTranslationUnit(ASTContext &Context) {
+ void HandleTranslationUnit(ASTContext &Context) override {
TraverseDecl(Context.getTranslationUnitDecl());
}
bool shouldWalkTypesOfTypeLocs() const { return false; }
- virtual bool VisitNamedDecl(NamedDecl *D) {
+ bool VisitNamedDecl(NamedDecl *D) {
D->printQualifiedName(Out);
Out << '\n';
return true;
@@ -124,11 +124,11 @@ ASTConsumer *clang::CreateASTPrinter(raw_ostream *Out,
}
ASTConsumer *clang::CreateASTDumper(StringRef FilterString, bool DumpLookups) {
- return new ASTPrinter(0, /*Dump=*/ true, FilterString, DumpLookups);
+ return new ASTPrinter(nullptr, /*Dump=*/true, FilterString, DumpLookups);
}
ASTConsumer *clang::CreateASTDeclNodeLister() {
- return new ASTDeclNodeLister(0);
+ return new ASTDeclNodeLister(nullptr);
}
//===----------------------------------------------------------------------===//
@@ -138,11 +138,11 @@ namespace {
class ASTViewer : public ASTConsumer {
ASTContext *Context;
public:
- void Initialize(ASTContext &Context) {
+ void Initialize(ASTContext &Context) override {
this->Context = &Context;
}
- virtual bool HandleTopLevelDecl(DeclGroupRef D) {
+ bool HandleTopLevelDecl(DeclGroupRef D) override {
for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
HandleTopLevelSingleDecl(*I);
return true;
@@ -177,7 +177,7 @@ class DeclContextPrinter : public ASTConsumer {
public:
DeclContextPrinter() : Out(llvm::errs()) {}
- void HandleTranslationUnit(ASTContext &C) {
+ void HandleTranslationUnit(ASTContext &C) override {
PrintDeclContext(C.getTranslationUnitDecl(), 4);
}
@@ -259,13 +259,12 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
// Print the parameters.
Out << "(";
bool PrintComma = false;
- for (FunctionDecl::param_const_iterator I = FD->param_begin(),
- E = FD->param_end(); I != E; ++I) {
+ for (auto I : FD->params()) {
if (PrintComma)
Out << ", ";
else
PrintComma = true;
- Out << **I;
+ Out << *I;
}
Out << ")";
break;
@@ -369,8 +368,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "\n";
// Print decls in the DeclContext.
- for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
- I != E; ++I) {
+ for (auto *I : DC->decls()) {
for (unsigned i = 0; i < Indentation; ++i)
Out << " ";
@@ -394,58 +392,58 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
case Decl::CXXDestructor:
case Decl::CXXConversion:
{
- DeclContext* DC = cast<DeclContext>(*I);
+ DeclContext* DC = cast<DeclContext>(I);
PrintDeclContext(DC, Indentation+2);
break;
}
case Decl::IndirectField: {
- IndirectFieldDecl* IFD = cast<IndirectFieldDecl>(*I);
+ IndirectFieldDecl* IFD = cast<IndirectFieldDecl>(I);
Out << "<IndirectField> " << *IFD << '\n';
break;
}
case Decl::Label: {
- LabelDecl *LD = cast<LabelDecl>(*I);
+ LabelDecl *LD = cast<LabelDecl>(I);
Out << "<Label> " << *LD << '\n';
break;
}
case Decl::Field: {
- FieldDecl *FD = cast<FieldDecl>(*I);
+ FieldDecl *FD = cast<FieldDecl>(I);
Out << "<field> " << *FD << '\n';
break;
}
case Decl::Typedef:
case Decl::TypeAlias: {
- TypedefNameDecl* TD = cast<TypedefNameDecl>(*I);
+ TypedefNameDecl* TD = cast<TypedefNameDecl>(I);
Out << "<typedef> " << *TD << '\n';
break;
}
case Decl::EnumConstant: {
- EnumConstantDecl* ECD = cast<EnumConstantDecl>(*I);
+ EnumConstantDecl* ECD = cast<EnumConstantDecl>(I);
Out << "<enum constant> " << *ECD << '\n';
break;
}
case Decl::Var: {
- VarDecl* VD = cast<VarDecl>(*I);
+ VarDecl* VD = cast<VarDecl>(I);
Out << "<var> " << *VD << '\n';
break;
}
case Decl::ImplicitParam: {
- ImplicitParamDecl* IPD = cast<ImplicitParamDecl>(*I);
+ ImplicitParamDecl* IPD = cast<ImplicitParamDecl>(I);
Out << "<implicit parameter> " << *IPD << '\n';
break;
}
case Decl::ParmVar: {
- ParmVarDecl* PVD = cast<ParmVarDecl>(*I);
+ ParmVarDecl* PVD = cast<ParmVarDecl>(I);
Out << "<parameter> " << *PVD << '\n';
break;
}
case Decl::ObjCProperty: {
- ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I);
+ ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(I);
Out << "<objc property> " << *OPD << '\n';
break;
}
case Decl::FunctionTemplate: {
- FunctionTemplateDecl* FTD = cast<FunctionTemplateDecl>(*I);
+ FunctionTemplateDecl* FTD = cast<FunctionTemplateDecl>(I);
Out << "<function template> " << *FTD << '\n';
break;
}
@@ -458,21 +456,21 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
break;
}
case Decl::NamespaceAlias: {
- NamespaceAliasDecl* NAD = cast<NamespaceAliasDecl>(*I);
+ NamespaceAliasDecl* NAD = cast<NamespaceAliasDecl>(I);
Out << "<namespace alias> " << *NAD << '\n';
break;
}
case Decl::ClassTemplate: {
- ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(*I);
+ ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(I);
Out << "<class template> " << *CTD << '\n';
break;
}
case Decl::OMPThreadPrivate: {
- Out << "<omp threadprivate> " << '"' << *I << "\"\n";
+ Out << "<omp threadprivate> " << '"' << I << "\"\n";
break;
}
default:
- Out << "DeclKind: " << DK << '"' << *I << "\"\n";
+ Out << "DeclKind: " << DK << '"' << I << "\"\n";
llvm_unreachable("decl unhandled");
}
}
diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp
index b6c644eba783..ff6434c56945 100644
--- a/lib/Frontend/ASTMerge.cpp
+++ b/lib/Frontend/ASTMerge.cpp
@@ -57,16 +57,14 @@ void ASTMergeAction::ExecuteAction() {
/*MinimalImport=*/false);
TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
- for (DeclContext::decl_iterator D = TU->decls_begin(),
- DEnd = TU->decls_end();
- D != DEnd; ++D) {
+ for (auto *D : TU->decls()) {
// Don't re-import __va_list_tag, __builtin_va_list.
- if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
+ if (const auto *ND = dyn_cast<NamedDecl>(D))
if (IdentifierInfo *II = ND->getIdentifier())
if (II->isStr("__va_list_tag") || II->isStr("__builtin_va_list"))
continue;
- Importer.Import(*D);
+ Importer.Import(D);
}
delete Unit;
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index a8c587638a28..fc44d9f1b4c0 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -20,6 +20,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
+#include "clang/Basic/VirtualFileSystem.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
@@ -35,9 +36,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
-#include "llvm/Support/Atomic.h"
#include "llvm/Support/CrashRecoveryContext.h"
-#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Mutex.h"
@@ -45,9 +44,9 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
+#include <atomic>
#include <cstdio>
#include <cstdlib>
-#include <sys/stat.h>
using namespace clang;
using llvm::TimeRecord;
@@ -191,10 +190,7 @@ struct ASTUnit::ASTWriterData {
};
void ASTUnit::clearFileLevelDecls() {
- for (FileDeclsTy::iterator
- I = FileDecls.begin(), E = FileDecls.end(); I != E; ++I)
- delete I->second;
- FileDecls.clear();
+ llvm::DeleteContainerSeconds(FileDecls);
}
void ASTUnit::CleanTemporaryFiles() {
@@ -214,27 +210,25 @@ const unsigned DefaultPreambleRebuildInterval = 5;
/// \brief Tracks the number of ASTUnit objects that are currently active.
///
/// Used for debugging purposes only.
-static llvm::sys::cas_flag ActiveASTUnitObjects;
+static std::atomic<unsigned> ActiveASTUnitObjects;
ASTUnit::ASTUnit(bool _MainFileIsAST)
- : Reader(0), HadModuleLoaderFatalFailure(false),
+ : Reader(nullptr), HadModuleLoaderFatalFailure(false),
OnlyLocalDecls(false), CaptureDiagnostics(false),
MainFileIsAST(_MainFileIsAST),
TUKind(TU_Complete), WantTiming(getenv("LIBCLANG_TIMING")),
OwnsRemappedFileBuffers(true),
NumStoredDiagnosticsFromDriver(0),
- PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0),
- NumWarningsInPreamble(0),
+ PreambleRebuildCounter(0), SavedMainFileBuffer(nullptr),
+ PreambleBuffer(nullptr), NumWarningsInPreamble(0),
ShouldCacheCodeCompletionResults(false),
IncludeBriefCommentsInCodeCompletion(false), UserFilesAreVolatile(false),
CompletionCacheTopLevelHashValue(0),
PreambleTopLevelHashValue(0),
CurrentTopLevelHashValue(0),
UnsafeToFree(false) {
- if (getenv("LIBCLANG_OBJTRACKING")) {
- llvm::sys::AtomicIncrement(&ActiveASTUnitObjects);
- fprintf(stderr, "+++ %d translation units\n", ActiveASTUnitObjects);
- }
+ if (getenv("LIBCLANG_OBJTRACKING"))
+ fprintf(stderr, "+++ %u translation units\n", ++ActiveASTUnitObjects);
}
ASTUnit::~ASTUnit() {
@@ -252,14 +246,10 @@ ASTUnit::~ASTUnit() {
// perform this operation here because we explicitly request that the
// compiler instance *not* free these buffers for each invocation of the
// parser.
- if (Invocation.getPtr() && OwnsRemappedFileBuffers) {
+ if (Invocation.get() && OwnsRemappedFileBuffers) {
PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
- for (PreprocessorOptions::remapped_file_buffer_iterator
- FB = PPOpts.remapped_file_buffer_begin(),
- FBEnd = PPOpts.remapped_file_buffer_end();
- FB != FBEnd;
- ++FB)
- delete FB->second;
+ for (const auto &RB : PPOpts.RemappedFileBuffers)
+ delete RB.second;
}
delete SavedMainFileBuffer;
@@ -267,10 +257,8 @@ ASTUnit::~ASTUnit() {
ClearCachedCompletionResults();
- if (getenv("LIBCLANG_OBJTRACKING")) {
- llvm::sys::AtomicDecrement(&ActiveASTUnitObjects);
- fprintf(stderr, "--- %d translation units\n", ActiveASTUnitObjects);
- }
+ if (getenv("LIBCLANG_OBJTRACKING"))
+ fprintf(stderr, "--- %u translation units\n", --ActiveASTUnitObjects);
}
void ASTUnit::setPreprocessor(Preprocessor *pp) { PP = pp; }
@@ -500,7 +488,7 @@ void ASTUnit::CacheCodeCompletionResults() {
void ASTUnit::ClearCachedCompletionResults() {
CachedCompletionResults.clear();
CachedCompletionTypes.clear();
- CachedCompletionAllocator = 0;
+ CachedCompletionAllocator = nullptr;
}
namespace {
@@ -511,23 +499,20 @@ class ASTInfoCollector : public ASTReaderListener {
Preprocessor &PP;
ASTContext &Context;
LangOptions &LangOpt;
- IntrusiveRefCntPtr<TargetOptions> &TargetOpts;
+ std::shared_ptr<TargetOptions> &TargetOpts;
IntrusiveRefCntPtr<TargetInfo> &Target;
unsigned &Counter;
bool InitializedLanguage;
public:
- ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt,
- IntrusiveRefCntPtr<TargetOptions> &TargetOpts,
- IntrusiveRefCntPtr<TargetInfo> &Target,
- unsigned &Counter)
- : PP(PP), Context(Context), LangOpt(LangOpt),
- TargetOpts(TargetOpts), Target(Target),
- Counter(Counter),
- InitializedLanguage(false) {}
-
- virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
- bool Complain) {
+ ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt,
+ std::shared_ptr<TargetOptions> &TargetOpts,
+ IntrusiveRefCntPtr<TargetInfo> &Target, unsigned &Counter)
+ : PP(PP), Context(Context), LangOpt(LangOpt), TargetOpts(TargetOpts),
+ Target(Target), Counter(Counter), InitializedLanguage(false) {}
+
+ bool ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain) override {
if (InitializedLanguage)
return false;
@@ -538,21 +523,22 @@ public:
return false;
}
- virtual bool ReadTargetOptions(const TargetOptions &TargetOpts,
- bool Complain) {
+ bool ReadTargetOptions(const TargetOptions &TargetOpts,
+ bool Complain) override {
// If we've already initialized the target, don't do it again.
if (Target)
return false;
-
- this->TargetOpts = new TargetOptions(TargetOpts);
- Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(),
- &*this->TargetOpts);
+
+ this->TargetOpts = std::make_shared<TargetOptions>(TargetOpts);
+ Target =
+ TargetInfo::CreateTargetInfo(PP.getDiagnostics(), this->TargetOpts);
updated();
return false;
}
- virtual void ReadCounter(const serialization::ModuleFile &M, unsigned Value) {
+ void ReadCounter(const serialization::ModuleFile &M,
+ unsigned Value) override {
Counter = Value;
}
@@ -565,7 +551,7 @@ private:
//
// FIXME: We shouldn't need to do this, the target should be immutable once
// created. This complexity should be lifted elsewhere.
- Target->setForcedLangOptions(LangOpt);
+ Target->adjust(LangOpt);
// Initialize the preprocessor.
PP.Initialize(*Target);
@@ -588,16 +574,16 @@ class StoredDiagnosticConsumer : public DiagnosticConsumer {
public:
explicit StoredDiagnosticConsumer(
SmallVectorImpl<StoredDiagnostic> &StoredDiags)
- : StoredDiags(StoredDiags), SourceMgr(0) { }
+ : StoredDiags(StoredDiags), SourceMgr(nullptr) {}
- virtual void BeginSourceFile(const LangOptions &LangOpts,
- const Preprocessor *PP = 0) {
+ void BeginSourceFile(const LangOptions &LangOpts,
+ const Preprocessor *PP = nullptr) override {
if (PP)
SourceMgr = &PP->getSourceManager();
}
- virtual void HandleDiagnostic(DiagnosticsEngine::Level Level,
- const Diagnostic &Info);
+ void HandleDiagnostic(DiagnosticsEngine::Level Level,
+ const Diagnostic &Info) override;
};
/// \brief RAII object that optionally captures diagnostics, if
@@ -610,9 +596,9 @@ class CaptureDroppedDiagnostics {
public:
CaptureDroppedDiagnostics(bool RequestCapture, DiagnosticsEngine &Diags,
SmallVectorImpl<StoredDiagnostic> &StoredDiags)
- : Diags(Diags), Client(StoredDiags), PreviousClient(0)
+ : Diags(Diags), Client(StoredDiags), PreviousClient(nullptr)
{
- if (RequestCapture || Diags.getClient() == 0) {
+ if (RequestCapture || Diags.getClient() == nullptr) {
PreviousClient = Diags.takeClient();
Diags.setClient(&Client);
}
@@ -643,13 +629,13 @@ void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level,
ASTMutationListener *ASTUnit::getASTMutationListener() {
if (WriterData)
return &WriterData->Writer;
- return 0;
+ return nullptr;
}
ASTDeserializationListener *ASTUnit::getDeserializationListener() {
if (WriterData)
return &WriterData->Writer;
- return 0;
+ return nullptr;
}
llvm::MemoryBuffer *ASTUnit::getBufferForFile(StringRef Filename,
@@ -662,10 +648,10 @@ llvm::MemoryBuffer *ASTUnit::getBufferForFile(StringRef Filename,
void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags,
const char **ArgBegin, const char **ArgEnd,
ASTUnit &AST, bool CaptureDiagnostics) {
- if (!Diags.getPtr()) {
+ if (!Diags.get()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
- DiagnosticConsumer *Client = 0;
+ DiagnosticConsumer *Client = nullptr;
if (CaptureDiagnostics)
Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics);
Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(),
@@ -680,129 +666,74 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
const FileSystemOptions &FileSystemOpts,
bool OnlyLocalDecls,
- RemappedFile *RemappedFiles,
- unsigned NumRemappedFiles,
+ ArrayRef<RemappedFile> RemappedFiles,
bool CaptureDiagnostics,
bool AllowPCHWithCompilerErrors,
bool UserFilesAreVolatile) {
- OwningPtr<ASTUnit> AST(new ASTUnit(true));
+ std::unique_ptr<ASTUnit> AST(new ASTUnit(true));
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
ASTUnitCleanup(AST.get());
llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
- DiagCleanup(Diags.getPtr());
+ DiagCleanup(Diags.get());
- ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics);
+ ConfigureDiags(Diags, nullptr, nullptr, *AST, CaptureDiagnostics);
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->Diagnostics = Diags;
- AST->FileMgr = new FileManager(FileSystemOpts);
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS = vfs::getRealFileSystem();
+ AST->FileMgr = new FileManager(FileSystemOpts, VFS);
AST->UserFilesAreVolatile = UserFilesAreVolatile;
AST->SourceMgr = new SourceManager(AST->getDiagnostics(),
AST->getFileManager(),
UserFilesAreVolatile);
AST->HSOpts = new HeaderSearchOptions();
-
+
AST->HeaderInfo.reset(new HeaderSearch(AST->HSOpts,
AST->getSourceManager(),
AST->getDiagnostics(),
AST->ASTFileLangOpts,
- /*Target=*/0));
-
- for (unsigned I = 0; I != NumRemappedFiles; ++I) {
- FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second;
- if (const llvm::MemoryBuffer *
- memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) {
- // Create the file entry for the file that we're mapping from.
- const FileEntry *FromFile
- = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
- memBuf->getBufferSize(),
- 0);
- if (!FromFile) {
- AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file)
- << RemappedFiles[I].first;
- delete memBuf;
- continue;
- }
-
- // Override the contents of the "from" file with the contents of
- // the "to" file.
- AST->getSourceManager().overrideFileContents(FromFile, memBuf);
+ /*Target=*/nullptr));
- } else {
- const char *fname = fileOrBuf.get<const char *>();
- const FileEntry *ToFile = AST->FileMgr->getFile(fname);
- if (!ToFile) {
- AST->getDiagnostics().Report(diag::err_fe_remap_missing_to_file)
- << RemappedFiles[I].first << fname;
- continue;
- }
+ PreprocessorOptions *PPOpts = new PreprocessorOptions();
+
+ for (unsigned I = 0, N = RemappedFiles.size(); I != N; ++I)
+ PPOpts->addRemappedFile(RemappedFiles[I].first, RemappedFiles[I].second);
- // Create the file entry for the file that we're mapping from.
- const FileEntry *FromFile
- = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
- ToFile->getSize(),
- 0);
- if (!FromFile) {
- AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file)
- << RemappedFiles[I].first;
- delete memBuf;
- continue;
- }
-
- // Override the contents of the "from" file with the contents of
- // the "to" file.
- AST->getSourceManager().overrideFileContents(FromFile, ToFile);
- }
- }
-
// Gather Info for preprocessor construction later on.
HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
unsigned Counter;
- OwningPtr<ASTReader> Reader;
-
- AST->PP = new Preprocessor(new PreprocessorOptions(),
- AST->getDiagnostics(), AST->ASTFileLangOpts,
- /*Target=*/0, AST->getSourceManager(), HeaderInfo,
- *AST,
- /*IILookup=*/0,
- /*OwnsHeaderSearch=*/false,
- /*DelayInitialization=*/true);
+ AST->PP =
+ new Preprocessor(PPOpts, AST->getDiagnostics(), AST->ASTFileLangOpts,
+ AST->getSourceManager(), HeaderInfo, *AST,
+ /*IILookup=*/nullptr,
+ /*OwnsHeaderSearch=*/false);
Preprocessor &PP = *AST->PP;
- AST->Ctx = new ASTContext(AST->ASTFileLangOpts,
- AST->getSourceManager(),
- /*Target=*/0,
- PP.getIdentifierTable(),
- PP.getSelectorTable(),
- PP.getBuiltinInfo(),
- /* size_reserve = */0,
- /*DelayInitialization=*/true);
+ AST->Ctx = new ASTContext(AST->ASTFileLangOpts, AST->getSourceManager(),
+ PP.getIdentifierTable(), PP.getSelectorTable(),
+ PP.getBuiltinInfo());
ASTContext &Context = *AST->Ctx;
bool disableValid = false;
if (::getenv("LIBCLANG_DISABLE_PCH_VALIDATION"))
disableValid = true;
- Reader.reset(new ASTReader(PP, Context,
+ AST->Reader = new ASTReader(PP, Context,
/*isysroot=*/"",
/*DisableValidation=*/disableValid,
- AllowPCHWithCompilerErrors));
-
- // Recover resources if we crash before exiting this method.
- llvm::CrashRecoveryContextCleanupRegistrar<ASTReader>
- ReaderCleanup(Reader.get());
+ AllowPCHWithCompilerErrors);
- Reader->setListener(new ASTInfoCollector(*AST->PP, Context,
+ AST->Reader->setListener(new ASTInfoCollector(*AST->PP, Context,
AST->ASTFileLangOpts,
AST->TargetOpts, AST->Target,
Counter));
- switch (Reader->ReadAST(Filename, serialization::MK_MainFile,
+ switch (AST->Reader->ReadAST(Filename, serialization::MK_MainFile,
SourceLocation(), ASTReader::ARR_None)) {
case ASTReader::Success:
break;
@@ -814,24 +745,17 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
case ASTReader::ConfigurationMismatch:
case ASTReader::HadErrors:
AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch);
- return NULL;
+ return nullptr;
}
- AST->OriginalSourceFile = Reader->getOriginalSourceFile();
+ AST->OriginalSourceFile = AST->Reader->getOriginalSourceFile();
PP.setCounterValue(Counter);
// Attach the AST reader to the AST context as an external AST
// source, so that declarations will be deserialized from the
// AST file as needed.
- ASTReader *ReaderPtr = Reader.get();
- OwningPtr<ExternalASTSource> Source(Reader.take());
-
- // Unregister the cleanup for ASTReader. It will get cleaned up
- // by the ASTUnit cleanup.
- ReaderCleanup.unregister();
-
- Context.setExternalSource(Source);
+ Context.setExternalSource(AST->Reader);
// Create an AST consumer, even though it isn't used.
AST->Consumer.reset(new ASTConsumer);
@@ -839,13 +763,12 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
// Create a semantic analysis object and tell the AST reader about it.
AST->TheSema.reset(new Sema(PP, Context, *AST->Consumer));
AST->TheSema->Initialize();
- ReaderPtr->InitializeSema(*AST->TheSema);
- AST->Reader = ReaderPtr;
+ AST->Reader->InitializeSema(*AST->TheSema);
// Tell the diagnostic client that we have started a source file.
AST->getDiagnostics().getClient()->BeginSourceFile(Context.getLangOpts(),&PP);
- return AST.take();
+ return AST.release();
}
namespace {
@@ -857,9 +780,9 @@ class MacroDefinitionTrackerPPCallbacks : public PPCallbacks {
public:
explicit MacroDefinitionTrackerPPCallbacks(unsigned &Hash) : Hash(Hash) { }
-
- virtual void MacroDefined(const Token &MacroNameTok,
- const MacroDirective *MD) {
+
+ void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override {
Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash);
}
};
@@ -881,10 +804,9 @@ void AddTopLevelDeclarationToHash(Decl *D, unsigned &Hash) {
// For an unscoped enum include the enumerators in the hash since they
// enter the top-level namespace.
if (!EnumD->isScoped()) {
- for (EnumDecl::enumerator_iterator EI = EnumD->enumerator_begin(),
- EE = EnumD->enumerator_end(); EI != EE; ++EI) {
- if ((*EI)->getIdentifier())
- Hash = llvm::HashString((*EI)->getIdentifier()->getName(), Hash);
+ for (const auto *EI : EnumD->enumerators()) {
+ if (EI->getIdentifier())
+ Hash = llvm::HashString(EI->getIdentifier()->getName(), Hash);
}
}
}
@@ -937,31 +859,30 @@ public:
void handleFileLevelDecl(Decl *D) {
Unit.addFileLevelDecl(D);
if (NamespaceDecl *NSD = dyn_cast<NamespaceDecl>(D)) {
- for (NamespaceDecl::decl_iterator
- I = NSD->decls_begin(), E = NSD->decls_end(); I != E; ++I)
- handleFileLevelDecl(*I);
+ for (auto *I : NSD->decls())
+ handleFileLevelDecl(I);
}
}
- bool HandleTopLevelDecl(DeclGroupRef D) {
+ bool HandleTopLevelDecl(DeclGroupRef D) override {
for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it)
handleTopLevelDecl(*it);
return true;
}
// We're not interested in "interesting" decls.
- void HandleInterestingDecl(DeclGroupRef) {}
+ void HandleInterestingDecl(DeclGroupRef) override {}
- void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {
+ void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override {
for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it)
handleTopLevelDecl(*it);
}
- virtual ASTMutationListener *GetASTMutationListener() {
+ ASTMutationListener *GetASTMutationListener() override {
return Unit.getASTMutationListener();
}
- virtual ASTDeserializationListener *GetASTDeserializationListener() {
+ ASTDeserializationListener *GetASTDeserializationListener() override {
return Unit.getDeserializationListener();
}
};
@@ -970,8 +891,8 @@ class TopLevelDeclTrackerAction : public ASTFrontendAction {
public:
ASTUnit &Unit;
- virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
+ ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override {
CI.getPreprocessor().addPPCallbacks(
new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue()));
return new TopLevelDeclTrackerConsumer(Unit,
@@ -981,8 +902,8 @@ public:
public:
TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
- virtual bool hasCodeCompletionSupport() const { return false; }
- virtual TranslationUnitKind getTranslationUnitKind() {
+ bool hasCodeCompletionSupport() const override { return false; }
+ TranslationUnitKind getTranslationUnitKind() override {
return Unit.getTranslationUnitKind();
}
};
@@ -995,15 +916,15 @@ public:
explicit PrecompilePreambleAction(ASTUnit &Unit)
: Unit(Unit), HasEmittedPreamblePCH(false) {}
- virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile);
+ ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override;
bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; }
void setHasEmittedPreamblePCH() { HasEmittedPreamblePCH = true; }
- virtual bool shouldEraseOutputFiles() { return !hasEmittedPreamblePCH(); }
+ bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); }
- virtual bool hasCodeCompletionSupport() const { return false; }
- virtual bool hasASTFileSupport() const { return false; }
- virtual TranslationUnitKind getTranslationUnitKind() { return TU_Prefix; }
+ bool hasCodeCompletionSupport() const override { return false; }
+ bool hasASTFileSupport() const override { return false; }
+ TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; }
};
class PrecompilePreambleConsumer : public PCHGenerator {
@@ -1016,12 +937,12 @@ public:
PrecompilePreambleConsumer(ASTUnit &Unit, PrecompilePreambleAction *Action,
const Preprocessor &PP, StringRef isysroot,
raw_ostream *Out)
- : PCHGenerator(PP, "", 0, isysroot, Out, /*AllowASTWithErrors=*/true),
+ : PCHGenerator(PP, "", nullptr, isysroot, Out, /*AllowASTWithErrors=*/true),
Unit(Unit), Hash(Unit.getCurrentTopLevelHashValue()), Action(Action) {
Hash = 0;
}
- virtual bool HandleTopLevelDecl(DeclGroupRef D) {
+ bool HandleTopLevelDecl(DeclGroupRef D) override {
for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
Decl *D = *it;
// FIXME: Currently ObjC method declarations are incorrectly being
@@ -1036,7 +957,7 @@ public:
return true;
}
- virtual void HandleTranslationUnit(ASTContext &Ctx) {
+ void HandleTranslationUnit(ASTContext &Ctx) override {
PCHGenerator::HandleTranslationUnit(Ctx);
if (hasEmittedPCH()) {
// Translate the top-level declarations we captured during
@@ -1062,10 +983,10 @@ ASTConsumer *PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
std::string Sysroot;
std::string OutputFile;
- raw_ostream *OS = 0;
+ raw_ostream *OS = nullptr;
if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
OutputFile, OS))
- return 0;
+ return nullptr;
if (!CI.getFrontendOpts().RelocatablePCH)
Sysroot.clear();
@@ -1112,15 +1033,15 @@ static void checkAndSanitizeDiags(SmallVectorImpl<StoredDiagnostic> &
/// contain any translation-unit information, false otherwise.
bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
delete SavedMainFileBuffer;
- SavedMainFileBuffer = 0;
-
+ SavedMainFileBuffer = nullptr;
+
if (!Invocation) {
delete OverrideMainBuffer;
return true;
}
// Create the compiler instance to use for building the AST.
- OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+ std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
@@ -1129,7 +1050,7 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
IntrusiveRefCntPtr<CompilerInvocation>
CCInvocation(new CompilerInvocation(*Invocation));
- Clang->setInvocation(CCInvocation.getPtr());
+ Clang->setInvocation(CCInvocation.get());
OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile();
// Set up diagnostics, capturing any diagnostics that would
@@ -1137,8 +1058,8 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
Clang->setDiagnostics(&getDiagnostics());
// Create the target instance.
- Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
- &Clang->getTargetOpts()));
+ Clang->setTarget(TargetInfo::CreateTargetInfo(
+ Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
if (!Clang->hasTarget()) {
delete OverrideMainBuffer;
return true;
@@ -1148,7 +1069,7 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
//
// FIXME: We shouldn't need to do this, the target should be immutable once
// created. This complexity should be lifted elsewhere.
- Clang->getTarget().setForcedLangOptions(Clang->getLangOpts());
+ Clang->getTarget().adjust(Clang->getLangOpts());
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
@@ -1158,17 +1079,22 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
"IR inputs not support here!");
// Configure the various subsystems.
- // FIXME: Should we retain the previous file manager?
- LangOpts = &Clang->getLangOpts();
+ LangOpts = Clang->getInvocation().LangOpts;
FileSystemOpts = Clang->getFileSystemOpts();
- FileMgr = new FileManager(FileSystemOpts);
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS =
+ createVFSFromCompilerInvocation(Clang->getInvocation(), getDiagnostics());
+ if (!VFS) {
+ delete OverrideMainBuffer;
+ return true;
+ }
+ FileMgr = new FileManager(FileSystemOpts, VFS);
SourceMgr = new SourceManager(getDiagnostics(), *FileMgr,
UserFilesAreVolatile);
TheSema.reset();
- Ctx = 0;
- PP = 0;
- Reader = 0;
-
+ Ctx = nullptr;
+ PP = nullptr;
+ Reader = nullptr;
+
// Clear out old caches and data.
TopLevelDecls.clear();
clearFileLevelDecls();
@@ -1206,10 +1132,10 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
// Keep track of the override buffer;
SavedMainFileBuffer = OverrideMainBuffer;
}
-
- OwningPtr<TopLevelDeclTrackerAction> Act(
- new TopLevelDeclTrackerAction(*this));
-
+
+ std::unique_ptr<TopLevelDeclTrackerAction> Act(
+ new TopLevelDeclTrackerAction(*this));
+
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<TopLevelDeclTrackerAction>
ActCleanup(Act.get());
@@ -1219,9 +1145,8 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
if (OverrideMainBuffer) {
std::string ModName = getPreambleFile(this);
- TranslateStoredDiagnostics(Clang->getModuleManager(), ModName,
- getSourceManager(), PreambleDiagnostics,
- StoredDiagnostics);
+ TranslateStoredDiagnostics(getFileManager(), getSourceManager(),
+ PreambleDiagnostics, StoredDiagnostics);
}
if (!Act->Execute())
@@ -1239,7 +1164,7 @@ error:
// Remove the overridden buffer we used for the preamble.
if (OverrideMainBuffer) {
delete OverrideMainBuffer;
- SavedMainFileBuffer = 0;
+ SavedMainFileBuffer = nullptr;
}
// Keep the ownership of the data in the ASTUnit because the client may
@@ -1279,17 +1204,13 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
// Try to determine if the main file has been remapped, either from the
// command line (to another file) or directly through the compiler invocation
// (to a memory buffer).
- llvm::MemoryBuffer *Buffer = 0;
+ llvm::MemoryBuffer *Buffer = nullptr;
std::string MainFilePath(FrontendOpts.Inputs[0].getFile());
llvm::sys::fs::UniqueID MainFileID;
if (!llvm::sys::fs::getUniqueID(MainFilePath, MainFileID)) {
// Check whether there is a file-file remapping of the main file
- for (PreprocessorOptions::remapped_file_iterator
- M = PreprocessorOpts.remapped_file_begin(),
- E = PreprocessorOpts.remapped_file_end();
- M != E;
- ++M) {
- std::string MPath(M->first);
+ for (const auto &RF : PreprocessorOpts.RemappedFiles) {
+ std::string MPath(RF.first);
llvm::sys::fs::UniqueID MID;
if (!llvm::sys::fs::getUniqueID(MPath, MID)) {
if (MainFileID == MID) {
@@ -1298,11 +1219,10 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
delete Buffer;
CreatedBuffer = false;
}
-
- Buffer = getBufferForFile(M->second);
+
+ Buffer = getBufferForFile(RF.second);
if (!Buffer)
- return std::make_pair((llvm::MemoryBuffer*)0,
- std::make_pair(0, true));
+ return std::make_pair(nullptr, std::make_pair(0, true));
CreatedBuffer = true;
}
}
@@ -1310,12 +1230,8 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
// Check whether there is a file-buffer remapping. It supercedes the
// file-file remapping.
- for (PreprocessorOptions::remapped_file_buffer_iterator
- M = PreprocessorOpts.remapped_file_buffer_begin(),
- E = PreprocessorOpts.remapped_file_buffer_end();
- M != E;
- ++M) {
- std::string MPath(M->first);
+ for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
+ std::string MPath(RB.first);
llvm::sys::fs::UniqueID MID;
if (!llvm::sys::fs::getUniqueID(MPath, MID)) {
if (MainFileID == MID) {
@@ -1324,8 +1240,8 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
delete Buffer;
CreatedBuffer = false;
}
-
- Buffer = const_cast<llvm::MemoryBuffer *>(M->second);
+
+ Buffer = const_cast<llvm::MemoryBuffer *>(RB.second);
}
}
}
@@ -1335,8 +1251,8 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
if (!Buffer) {
Buffer = getBufferForFile(FrontendOpts.Inputs[0].getFile());
if (!Buffer)
- return std::make_pair((llvm::MemoryBuffer*)0, std::make_pair(0, true));
-
+ return std::make_pair(nullptr, std::make_pair(0, true));
+
CreatedBuffer = true;
}
@@ -1345,20 +1261,83 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
MaxLines));
}
-static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old,
- unsigned NewSize,
- StringRef NewName) {
- llvm::MemoryBuffer *Result
- = llvm::MemoryBuffer::getNewUninitMemBuffer(NewSize, NewName);
- memcpy(const_cast<char*>(Result->getBufferStart()),
- Old->getBufferStart(), Old->getBufferSize());
- memset(const_cast<char*>(Result->getBufferStart()) + Old->getBufferSize(),
- ' ', NewSize - Old->getBufferSize() - 1);
- const_cast<char*>(Result->getBufferEnd())[-1] = '\n';
-
+ASTUnit::PreambleFileHash
+ASTUnit::PreambleFileHash::createForFile(off_t Size, time_t ModTime) {
+ PreambleFileHash Result;
+ Result.Size = Size;
+ Result.ModTime = ModTime;
+ memset(Result.MD5, 0, sizeof(Result.MD5));
+ return Result;
+}
+
+ASTUnit::PreambleFileHash ASTUnit::PreambleFileHash::createForMemoryBuffer(
+ const llvm::MemoryBuffer *Buffer) {
+ PreambleFileHash Result;
+ Result.Size = Buffer->getBufferSize();
+ Result.ModTime = 0;
+
+ llvm::MD5 MD5Ctx;
+ MD5Ctx.update(Buffer->getBuffer().data());
+ MD5Ctx.final(Result.MD5);
+
return Result;
}
+namespace clang {
+bool operator==(const ASTUnit::PreambleFileHash &LHS,
+ const ASTUnit::PreambleFileHash &RHS) {
+ return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime &&
+ memcmp(LHS.MD5, RHS.MD5, sizeof(LHS.MD5)) == 0;
+}
+} // namespace clang
+
+static std::pair<unsigned, unsigned>
+makeStandaloneRange(CharSourceRange Range, const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ CharSourceRange FileRange = Lexer::makeFileCharRange(Range, SM, LangOpts);
+ unsigned Offset = SM.getFileOffset(FileRange.getBegin());
+ unsigned EndOffset = SM.getFileOffset(FileRange.getEnd());
+ return std::make_pair(Offset, EndOffset);
+}
+
+static void makeStandaloneFixIt(const SourceManager &SM,
+ const LangOptions &LangOpts,
+ const FixItHint &InFix,
+ ASTUnit::StandaloneFixIt &OutFix) {
+ OutFix.RemoveRange = makeStandaloneRange(InFix.RemoveRange, SM, LangOpts);
+ OutFix.InsertFromRange = makeStandaloneRange(InFix.InsertFromRange, SM,
+ LangOpts);
+ OutFix.CodeToInsert = InFix.CodeToInsert;
+ OutFix.BeforePreviousInsertions = InFix.BeforePreviousInsertions;
+}
+
+static void makeStandaloneDiagnostic(const LangOptions &LangOpts,
+ const StoredDiagnostic &InDiag,
+ ASTUnit::StandaloneDiagnostic &OutDiag) {
+ OutDiag.ID = InDiag.getID();
+ OutDiag.Level = InDiag.getLevel();
+ OutDiag.Message = InDiag.getMessage();
+ OutDiag.LocOffset = 0;
+ if (InDiag.getLocation().isInvalid())
+ return;
+ const SourceManager &SM = InDiag.getLocation().getManager();
+ SourceLocation FileLoc = SM.getFileLoc(InDiag.getLocation());
+ OutDiag.Filename = SM.getFilename(FileLoc);
+ if (OutDiag.Filename.empty())
+ return;
+ OutDiag.LocOffset = SM.getFileOffset(FileLoc);
+ for (StoredDiagnostic::range_iterator
+ I = InDiag.range_begin(), E = InDiag.range_end(); I != E; ++I) {
+ OutDiag.Ranges.push_back(makeStandaloneRange(*I, SM, LangOpts));
+ }
+ for (StoredDiagnostic::fixit_iterator
+ I = InDiag.fixit_begin(), E = InDiag.fixit_end(); I != E; ++I) {
+ ASTUnit::StandaloneFixIt Fix;
+ makeStandaloneFixIt(SM, LangOpts, *I, Fix);
+ OutDiag.FixIts.push_back(Fix);
+ }
+}
+
/// \brief Attempt to build or re-use a precompiled preamble when (re-)parsing
/// the source file.
///
@@ -1395,7 +1374,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
= ComputePreamble(*PreambleInvocation, MaxLines, CreatedPreambleBuffer);
// If ComputePreamble() Take ownership of the preamble buffer.
- OwningPtr<llvm::MemoryBuffer> OwnedPreambleBuffer;
+ std::unique_ptr<llvm::MemoryBuffer> OwnedPreambleBuffer;
if (CreatedPreambleBuffer)
OwnedPreambleBuffer.reset(NewPreamble.first);
@@ -1407,7 +1386,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// The next time we actually see a preamble, precompile it.
PreambleRebuildCounter = 1;
- return 0;
+ return nullptr;
}
if (!Preamble.empty()) {
@@ -1417,7 +1396,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// new main file.
if (Preamble.size() == NewPreamble.second.first &&
PreambleEndsAtStartOfLine == NewPreamble.second.second &&
- NewPreamble.first->getBufferSize() < PreambleReservedSize-2 &&
memcmp(Preamble.getBufferStart(), NewPreamble.first->getBufferStart(),
NewPreamble.second.first) == 0) {
// The preamble has not changed. We may be able to re-use the precompiled
@@ -1428,40 +1406,36 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// First, make a record of those files that have been overridden via
// remapping or unsaved_files.
- llvm::StringMap<std::pair<off_t, time_t> > OverriddenFiles;
- for (PreprocessorOptions::remapped_file_iterator
- R = PreprocessorOpts.remapped_file_begin(),
- REnd = PreprocessorOpts.remapped_file_end();
- !AnyFileChanged && R != REnd;
- ++R) {
- llvm::sys::fs::file_status Status;
- if (FileMgr->getNoncachedStatValue(R->second, Status)) {
+ llvm::StringMap<PreambleFileHash> OverriddenFiles;
+ for (const auto &R : PreprocessorOpts.RemappedFiles) {
+ if (AnyFileChanged)
+ break;
+
+ vfs::Status Status;
+ if (FileMgr->getNoncachedStatValue(R.second, Status)) {
// If we can't stat the file we're remapping to, assume that something
// horrible happened.
AnyFileChanged = true;
break;
}
- OverriddenFiles[R->first] = std::make_pair(
+ OverriddenFiles[R.first] = PreambleFileHash::createForFile(
Status.getSize(), Status.getLastModificationTime().toEpochTime());
}
- for (PreprocessorOptions::remapped_file_buffer_iterator
- R = PreprocessorOpts.remapped_file_buffer_begin(),
- REnd = PreprocessorOpts.remapped_file_buffer_end();
- !AnyFileChanged && R != REnd;
- ++R) {
- // FIXME: Should we actually compare the contents of file->buffer
- // remappings?
- OverriddenFiles[R->first] = std::make_pair(R->second->getBufferSize(),
- 0);
+
+ for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
+ if (AnyFileChanged)
+ break;
+ OverriddenFiles[RB.first] =
+ PreambleFileHash::createForMemoryBuffer(RB.second);
}
// Check whether anything has changed.
- for (llvm::StringMap<std::pair<off_t, time_t> >::iterator
+ for (llvm::StringMap<PreambleFileHash>::iterator
F = FilesInPreamble.begin(), FEnd = FilesInPreamble.end();
!AnyFileChanged && F != FEnd;
++F) {
- llvm::StringMap<std::pair<off_t, time_t> >::iterator Overridden
+ llvm::StringMap<PreambleFileHash>::iterator Overridden
= OverriddenFiles.find(F->first());
if (Overridden != OverriddenFiles.end()) {
// This file was remapped; check whether the newly-mapped file
@@ -1472,13 +1446,13 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
}
// The file was not remapped; check whether it has changed on disk.
- llvm::sys::fs::file_status Status;
+ vfs::Status Status;
if (FileMgr->getNoncachedStatValue(F->first(), Status)) {
// If we can't stat the file, assume that something horrible happened.
AnyFileChanged = true;
- } else if (Status.getSize() != uint64_t(F->second.first) ||
+ } else if (Status.getSize() != uint64_t(F->second.Size) ||
Status.getLastModificationTime().toEpochTime() !=
- uint64_t(F->second.second))
+ uint64_t(F->second.ModTime))
AnyFileChanged = true;
}
@@ -1492,18 +1466,15 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
PreambleInvocation->getDiagnosticOpts());
getDiagnostics().setNumWarnings(NumWarningsInPreamble);
- // Create a version of the main file buffer that is padded to
- // buffer size we reserved when creating the preamble.
- return CreatePaddedMainFileBuffer(NewPreamble.first,
- PreambleReservedSize,
- FrontendOpts.Inputs[0].getFile());
+ return llvm::MemoryBuffer::getMemBufferCopy(
+ NewPreamble.first->getBuffer(), FrontendOpts.Inputs[0].getFile());
}
}
// If we aren't allowed to rebuild the precompiled preamble, just
// return now.
if (!AllowRebuild)
- return 0;
+ return nullptr;
// We can't reuse the previously-computed preamble. Build a new one.
Preamble.clear();
@@ -1513,7 +1484,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
} else if (!AllowRebuild) {
// We aren't allowed to rebuild the precompiled preamble; just
// return now.
- return 0;
+ return nullptr;
}
// If the preamble rebuild counter > 1, it's because we previously
@@ -1521,7 +1492,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// again. Decrement the counter and return a failure.
if (PreambleRebuildCounter > 1) {
--PreambleRebuildCounter;
- return 0;
+ return nullptr;
}
// Create a temporary file for the precompiled preamble. In rare
@@ -1530,26 +1501,16 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
if (PreamblePCHPath.empty()) {
// Try again next time.
PreambleRebuildCounter = 1;
- return 0;
+ return nullptr;
}
// We did not previously compute a preamble, or it can't be reused anyway.
SimpleTimer PreambleTimer(WantTiming);
PreambleTimer.setOutput("Precompiling preamble");
-
- // Create a new buffer that stores the preamble. The buffer also contains
- // extra space for the original contents of the file (which will be present
- // when we actually parse the file) along with more room in case the file
- // grows.
- PreambleReservedSize = NewPreamble.first->getBufferSize();
- if (PreambleReservedSize < 4096)
- PreambleReservedSize = 8191;
- else
- PreambleReservedSize *= 2;
// Save the preamble text for later; we'll need to compare against it for
// subsequent reparses.
- StringRef MainFilename = PreambleInvocation->getFrontendOpts().Inputs[0].getFile();
+ StringRef MainFilename = FrontendOpts.Inputs[0].getFile();
Preamble.assign(FileMgr->getFile(MainFilename),
NewPreamble.first->getBufferStart(),
NewPreamble.first->getBufferStart()
@@ -1558,13 +1519,8 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
delete PreambleBuffer;
PreambleBuffer
- = llvm::MemoryBuffer::getNewUninitMemBuffer(PreambleReservedSize,
- FrontendOpts.Inputs[0].getFile());
- memcpy(const_cast<char*>(PreambleBuffer->getBufferStart()),
- NewPreamble.first->getBufferStart(), Preamble.size());
- memset(const_cast<char*>(PreambleBuffer->getBufferStart()) + Preamble.size(),
- ' ', PreambleReservedSize - Preamble.size() - 1);
- const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = '\n';
+ = llvm::MemoryBuffer::getMemBufferCopy(
+ NewPreamble.first->getBuffer().slice(0, Preamble.size()), MainFilename);
// Remap the main source file to the preamble buffer.
StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
@@ -1578,7 +1534,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
PreprocessorOpts.PrecompiledPreambleBytes.second = false;
// Create the compiler instance to use for building the precompiled preamble.
- OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+ std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
@@ -1591,22 +1547,21 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
Clang->setDiagnostics(&getDiagnostics());
// Create the target instance.
- Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
- &Clang->getTargetOpts()));
+ Clang->setTarget(TargetInfo::CreateTargetInfo(
+ Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
if (!Clang->hasTarget()) {
llvm::sys::fs::remove(FrontendOpts.OutputFile);
Preamble.clear();
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
- PreprocessorOpts.eraseRemappedFile(
- PreprocessorOpts.remapped_file_buffer_end() - 1);
- return 0;
+ PreprocessorOpts.RemappedFileBuffers.pop_back();
+ return nullptr;
}
// Inform the target of the language options.
//
// FIXME: We shouldn't need to do this, the target should be immutable once
// created. This complexity should be lifted elsewhere.
- Clang->getTarget().setForcedLangOptions(Clang->getLangOpts());
+ Clang->getTarget().adjust(Clang->getLangOpts());
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
@@ -1621,28 +1576,49 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
checkAndRemoveNonDriverDiags(StoredDiagnostics);
TopLevelDecls.clear();
TopLevelDeclsInPreamble.clear();
-
+ PreambleDiagnostics.clear();
+
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS =
+ createVFSFromCompilerInvocation(Clang->getInvocation(), getDiagnostics());
+ if (!VFS)
+ return nullptr;
+
// Create a file manager object to provide access to and cache the filesystem.
- Clang->setFileManager(new FileManager(Clang->getFileSystemOpts()));
+ Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
// Create the source manager.
Clang->setSourceManager(new SourceManager(getDiagnostics(),
Clang->getFileManager()));
-
- OwningPtr<PrecompilePreambleAction> Act;
+
+ auto PreambleDepCollector = std::make_shared<DependencyCollector>();
+ Clang->addDependencyCollector(PreambleDepCollector);
+
+ std::unique_ptr<PrecompilePreambleAction> Act;
Act.reset(new PrecompilePreambleAction(*this));
if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) {
llvm::sys::fs::remove(FrontendOpts.OutputFile);
Preamble.clear();
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
- PreprocessorOpts.eraseRemappedFile(
- PreprocessorOpts.remapped_file_buffer_end() - 1);
- return 0;
+ PreprocessorOpts.RemappedFileBuffers.pop_back();
+ return nullptr;
}
Act->Execute();
+
+ // Transfer any diagnostics generated when parsing the preamble into the set
+ // of preamble diagnostics.
+ for (stored_diag_iterator
+ I = stored_diag_afterDriver_begin(),
+ E = stored_diag_end(); I != E; ++I) {
+ StandaloneDiagnostic Diag;
+ makeStandaloneDiagnostic(Clang->getLangOpts(), *I, Diag);
+ PreambleDiagnostics.push_back(Diag);
+ }
+
Act->EndSourceFile();
+ checkAndRemoveNonDriverDiags(StoredDiagnostics);
+
if (!Act->hasEmittedPreamblePCH()) {
// The preamble PCH failed (e.g. there was a module loading fatal error),
// so no precompiled header was generated. Forget that we even tried.
@@ -1651,18 +1627,10 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
Preamble.clear();
TopLevelDeclsInPreamble.clear();
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
- PreprocessorOpts.eraseRemappedFile(
- PreprocessorOpts.remapped_file_buffer_end() - 1);
- return 0;
+ PreprocessorOpts.RemappedFileBuffers.pop_back();
+ return nullptr;
}
- // Transfer any diagnostics generated when parsing the preamble into the set
- // of preamble diagnostics.
- PreambleDiagnostics.clear();
- PreambleDiagnostics.insert(PreambleDiagnostics.end(),
- stored_diag_afterDriver_begin(), stored_diag_end());
- checkAndRemoveNonDriverDiags(StoredDiagnostics);
-
// Keep track of the preamble we precompiled.
setPreambleFile(this, FrontendOpts.OutputFile);
NumWarningsInPreamble = getDiagnostics().getNumWarnings();
@@ -1671,24 +1639,23 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// so we can verify whether they have changed or not.
FilesInPreamble.clear();
SourceManager &SourceMgr = Clang->getSourceManager();
- const llvm::MemoryBuffer *MainFileBuffer
- = SourceMgr.getBuffer(SourceMgr.getMainFileID());
- for (SourceManager::fileinfo_iterator F = SourceMgr.fileinfo_begin(),
- FEnd = SourceMgr.fileinfo_end();
- F != FEnd;
- ++F) {
- const FileEntry *File = F->second->OrigEntry;
- if (!File || F->second->getRawBuffer() == MainFileBuffer)
+ for (auto &Filename : PreambleDepCollector->getDependencies()) {
+ const FileEntry *File = Clang->getFileManager().getFile(Filename);
+ if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
continue;
-
- FilesInPreamble[File->getName()]
- = std::make_pair(F->second->getSize(), File->getModificationTime());
+ if (time_t ModTime = File->getModificationTime()) {
+ FilesInPreamble[File->getName()] = PreambleFileHash::createForFile(
+ File->getSize(), ModTime);
+ } else {
+ llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
+ FilesInPreamble[File->getName()] =
+ PreambleFileHash::createForMemoryBuffer(Buffer);
+ }
}
-
+
PreambleRebuildCounter = 1;
- PreprocessorOpts.eraseRemappedFile(
- PreprocessorOpts.remapped_file_buffer_end() - 1);
-
+ PreprocessorOpts.RemappedFileBuffers.pop_back();
+
// If the hash of top-level entities differs from the hash of the top-level
// entities the last time we rebuilt the preamble, clear out the completion
// cache.
@@ -1697,9 +1664,8 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
PreambleTopLevelHashValue = CurrentTopLevelHashValue;
}
- return CreatePaddedMainFileBuffer(NewPreamble.first,
- PreambleReservedSize,
- FrontendOpts.Inputs[0].getFile());
+ return llvm::MemoryBuffer::getMemBufferCopy(NewPreamble.first->getBuffer(),
+ MainFilename);
}
void ASTUnit::RealizeTopLevelDeclsFromPreamble() {
@@ -1718,14 +1684,20 @@ void ASTUnit::RealizeTopLevelDeclsFromPreamble() {
}
void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) {
- // Steal the created target, context, and preprocessor.
+ // Steal the created target, context, and preprocessor if they have been
+ // created.
+ assert(CI.hasInvocation() && "missing invocation");
+ LangOpts = CI.getInvocation().LangOpts;
TheSema.reset(CI.takeSema());
Consumer.reset(CI.takeASTConsumer());
- Ctx = &CI.getASTContext();
- PP = &CI.getPreprocessor();
- CI.setSourceManager(0);
- CI.setFileManager(0);
- Target = &CI.getTarget();
+ if (CI.hasASTContext())
+ Ctx = &CI.getASTContext();
+ if (CI.hasPreprocessor())
+ PP = &CI.getPreprocessor();
+ CI.setSourceManager(nullptr);
+ CI.setFileManager(nullptr);
+ if (CI.hasTarget())
+ Target = &CI.getTarget();
Reader = CI.getModuleManager();
HadModuleLoaderFatalFailure = CI.hadModuleLoaderFatalFailure();
}
@@ -1761,41 +1733,41 @@ ASTUnit *ASTUnit::create(CompilerInvocation *CI,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
bool CaptureDiagnostics,
bool UserFilesAreVolatile) {
- OwningPtr<ASTUnit> AST;
+ std::unique_ptr<ASTUnit> AST;
AST.reset(new ASTUnit(false));
- ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics);
+ ConfigureDiags(Diags, nullptr, nullptr, *AST, CaptureDiagnostics);
AST->Diagnostics = Diags;
AST->Invocation = CI;
AST->FileSystemOpts = CI->getFileSystemOpts();
- AST->FileMgr = new FileManager(AST->FileSystemOpts);
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS =
+ createVFSFromCompilerInvocation(*CI, *Diags);
+ if (!VFS)
+ return nullptr;
+ AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
AST->UserFilesAreVolatile = UserFilesAreVolatile;
AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr,
UserFilesAreVolatile);
- return AST.take();
+ return AST.release();
}
-ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
- ASTFrontendAction *Action,
- ASTUnit *Unit,
- bool Persistent,
- StringRef ResourceFilesPath,
- bool OnlyLocalDecls,
- bool CaptureDiagnostics,
- bool PrecompilePreamble,
- bool CacheCodeCompletionResults,
- bool IncludeBriefCommentsInCodeCompletion,
- bool UserFilesAreVolatile,
- OwningPtr<ASTUnit> *ErrAST) {
+ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
+ CompilerInvocation *CI, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ ASTFrontendAction *Action, ASTUnit *Unit, bool Persistent,
+ StringRef ResourceFilesPath, bool OnlyLocalDecls, bool CaptureDiagnostics,
+ bool PrecompilePreamble, bool CacheCodeCompletionResults,
+ bool IncludeBriefCommentsInCodeCompletion, bool UserFilesAreVolatile,
+ std::unique_ptr<ASTUnit> *ErrAST) {
assert(CI && "A CompilerInvocation is required");
- OwningPtr<ASTUnit> OwnAST;
+ std::unique_ptr<ASTUnit> OwnAST;
ASTUnit *AST = Unit;
if (!AST) {
// Create the AST unit.
OwnAST.reset(create(CI, Diags, CaptureDiagnostics, UserFilesAreVolatile));
AST = OwnAST.get();
+ if (!AST)
+ return nullptr;
}
if (!ResourceFilesPath.empty()) {
@@ -1816,7 +1788,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
ASTUnitCleanup(OwnAST.get());
llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
- DiagCleanup(Diags.getPtr());
+ DiagCleanup(Diags.get());
// We'll manage file buffers ourselves.
CI->getPreprocessorOpts().RetainRemappedFileBuffers = true;
@@ -1824,7 +1796,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
ProcessWarningOptions(AST->getDiagnostics(), CI->getDiagnosticOpts());
// Create the compiler instance to use for building the AST.
- OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+ std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
@@ -1838,16 +1810,16 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
Clang->setDiagnostics(&AST->getDiagnostics());
// Create the target instance.
- Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
- &Clang->getTargetOpts()));
+ Clang->setTarget(TargetInfo::CreateTargetInfo(
+ Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
if (!Clang->hasTarget())
- return 0;
+ return nullptr;
// Inform the target of the language options.
//
// FIXME: We shouldn't need to do this, the target should be immutable once
// created. This complexity should be lifted elsewhere.
- Clang->getTarget().setForcedLangOptions(Clang->getLangOpts());
+ Clang->getTarget().adjust(Clang->getLangOpts());
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
@@ -1858,10 +1830,10 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
// Configure the various subsystems.
AST->TheSema.reset();
- AST->Ctx = 0;
- AST->PP = 0;
- AST->Reader = 0;
-
+ AST->Ctx = nullptr;
+ AST->PP = nullptr;
+ AST->Reader = nullptr;
+
// Create a file manager object to provide access to and cache the filesystem.
Clang->setFileManager(&AST->getFileManager());
@@ -1870,7 +1842,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
ASTFrontendAction *Act = Action;
- OwningPtr<TopLevelDeclTrackerAction> TrackerAct;
+ std::unique_ptr<TopLevelDeclTrackerAction> TrackerAct;
if (!Act) {
TrackerAct.reset(new TopLevelDeclTrackerAction(*AST));
Act = TrackerAct.get();
@@ -1885,7 +1857,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
if (OwnAST && ErrAST)
ErrAST->swap(OwnAST);
- return 0;
+ return nullptr;
}
if (Persistent && !TrackerAct) {
@@ -1903,7 +1875,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
if (OwnAST && ErrAST)
ErrAST->swap(OwnAST);
- return 0;
+ return nullptr;
}
// Steal the created target, context, and preprocessor.
@@ -1912,7 +1884,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
Act->EndSourceFile();
if (OwnAST)
- return OwnAST.take();
+ return OwnAST.release();
else
return AST;
}
@@ -1926,7 +1898,7 @@ bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
Invocation->getFrontendOpts().DisableFree = false;
ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
- llvm::MemoryBuffer *OverrideMainBuffer = 0;
+ llvm::MemoryBuffer *OverrideMainBuffer = nullptr;
if (PrecompilePreamble) {
PreambleRebuildCounter = 2;
OverrideMainBuffer
@@ -1943,19 +1915,14 @@ bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
return Parse(OverrideMainBuffer);
}
-ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
- bool OnlyLocalDecls,
- bool CaptureDiagnostics,
- bool PrecompilePreamble,
- TranslationUnitKind TUKind,
- bool CacheCodeCompletionResults,
- bool IncludeBriefCommentsInCodeCompletion,
- bool UserFilesAreVolatile) {
+std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
+ CompilerInvocation *CI, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ bool OnlyLocalDecls, bool CaptureDiagnostics, bool PrecompilePreamble,
+ TranslationUnitKind TUKind, bool CacheCodeCompletionResults,
+ bool IncludeBriefCommentsInCodeCompletion, bool UserFilesAreVolatile) {
// Create the AST unit.
- OwningPtr<ASTUnit> AST;
- AST.reset(new ASTUnit(false));
- ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics);
+ std::unique_ptr<ASTUnit> AST(new ASTUnit(false));
+ ConfigureDiags(Diags, nullptr, nullptr, *AST, CaptureDiagnostics);
AST->Diagnostics = Diags;
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
@@ -1965,7 +1932,11 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
= IncludeBriefCommentsInCodeCompletion;
AST->Invocation = CI;
AST->FileSystemOpts = CI->getFileSystemOpts();
- AST->FileMgr = new FileManager(AST->FileSystemOpts);
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS =
+ createVFSFromCompilerInvocation(*CI, *Diags);
+ if (!VFS)
+ return nullptr;
+ AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
AST->UserFilesAreVolatile = UserFilesAreVolatile;
// Recover resources if we crash before exiting this method.
@@ -1973,30 +1944,24 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
ASTUnitCleanup(AST.get());
llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
- DiagCleanup(Diags.getPtr());
-
- return AST->LoadFromCompilerInvocation(PrecompilePreamble)? 0 : AST.take();
-}
-
-ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
- const char **ArgEnd,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
- StringRef ResourceFilesPath,
- bool OnlyLocalDecls,
- bool CaptureDiagnostics,
- RemappedFile *RemappedFiles,
- unsigned NumRemappedFiles,
- bool RemappedFilesKeepOriginalName,
- bool PrecompilePreamble,
- TranslationUnitKind TUKind,
- bool CacheCodeCompletionResults,
- bool IncludeBriefCommentsInCodeCompletion,
- bool AllowPCHWithCompilerErrors,
- bool SkipFunctionBodies,
- bool UserFilesAreVolatile,
- bool ForSerialization,
- OwningPtr<ASTUnit> *ErrAST) {
- if (!Diags.getPtr()) {
+ DiagCleanup(Diags.get());
+
+ if (AST->LoadFromCompilerInvocation(PrecompilePreamble))
+ return nullptr;
+ return AST;
+}
+
+ASTUnit *ASTUnit::LoadFromCommandLine(
+ const char **ArgBegin, const char **ArgEnd,
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
+ bool OnlyLocalDecls, bool CaptureDiagnostics,
+ ArrayRef<RemappedFile> RemappedFiles, bool RemappedFilesKeepOriginalName,
+ bool PrecompilePreamble, TranslationUnitKind TUKind,
+ bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion,
+ bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies,
+ bool UserFilesAreVolatile, bool ForSerialization,
+ std::unique_ptr<ASTUnit> *ErrAST) {
+ if (!Diags.get()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions());
@@ -2015,19 +1980,13 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
llvm::makeArrayRef(ArgBegin, ArgEnd),
Diags);
if (!CI)
- return 0;
+ return nullptr;
}
// Override any files that need remapping
- for (unsigned I = 0; I != NumRemappedFiles; ++I) {
- FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second;
- if (const llvm::MemoryBuffer *
- memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) {
- CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, memBuf);
- } else {
- const char *fname = fileOrBuf.get<const char *>();
- CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, fname);
- }
+ for (unsigned I = 0, N = RemappedFiles.size(); I != N; ++I) {
+ CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
+ RemappedFiles[I].second);
}
PreprocessorOptions &PPOpts = CI->getPreprocessorOpts();
PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName;
@@ -2039,13 +1998,17 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
CI->getFrontendOpts().SkipFunctionBodies = SkipFunctionBodies;
// Create the AST unit.
- OwningPtr<ASTUnit> AST;
+ std::unique_ptr<ASTUnit> AST;
AST.reset(new ASTUnit(false));
ConfigureDiags(Diags, ArgBegin, ArgEnd, *AST, CaptureDiagnostics);
AST->Diagnostics = Diags;
- Diags = 0; // Zero out now to ease cleanup during crash recovery.
+ Diags = nullptr; // Zero out now to ease cleanup during crash recovery.
AST->FileSystemOpts = CI->getFileSystemOpts();
- AST->FileMgr = new FileManager(AST->FileSystemOpts);
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS =
+ createVFSFromCompilerInvocation(*CI, *Diags);
+ if (!VFS)
+ return nullptr;
+ AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->TUKind = TUKind;
@@ -2058,8 +2021,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
AST->Invocation = CI;
if (ForSerialization)
AST->WriterData.reset(new ASTWriterData());
- CI = 0; // Zero out now to ease cleanup during crash recovery.
-
+ CI = nullptr; // Zero out now to ease cleanup during crash recovery.
+
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
ASTUnitCleanup(AST.get());
@@ -2071,13 +2034,13 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics);
ErrAST->swap(AST);
}
- return 0;
+ return nullptr;
}
- return AST.take();
+ return AST.release();
}
-bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
+bool ASTUnit::Reparse(ArrayRef<RemappedFile> RemappedFiles) {
if (!Invocation)
return true;
@@ -2088,30 +2051,18 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
// Remap files.
PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
- for (PreprocessorOptions::remapped_file_buffer_iterator
- R = PPOpts.remapped_file_buffer_begin(),
- REnd = PPOpts.remapped_file_buffer_end();
- R != REnd;
- ++R) {
- delete R->second;
- }
+ for (const auto &RB : PPOpts.RemappedFileBuffers)
+ delete RB.second;
+
Invocation->getPreprocessorOpts().clearRemappedFiles();
- for (unsigned I = 0; I != NumRemappedFiles; ++I) {
- FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second;
- if (const llvm::MemoryBuffer *
- memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) {
- Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
- memBuf);
- } else {
- const char *fname = fileOrBuf.get<const char *>();
- Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
- fname);
- }
+ for (unsigned I = 0, N = RemappedFiles.size(); I != N; ++I) {
+ Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
+ RemappedFiles[I].second);
}
-
+
// If we have a preamble file lying around, or if we might try to
// build a precompiled preamble, do so now.
- llvm::MemoryBuffer *OverrideMainBuffer = 0;
+ llvm::MemoryBuffer *OverrideMainBuffer = nullptr;
if (!getPreambleFile(this).empty() || PreambleRebuildCounter > 0)
OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(*Invocation);
@@ -2178,23 +2129,22 @@ namespace {
| (1LL << CodeCompletionContext::CCC_UnionTag)
| (1LL << CodeCompletionContext::CCC_ClassOrStructTag);
}
-
- virtual void ProcessCodeCompleteResults(Sema &S,
- CodeCompletionContext Context,
- CodeCompletionResult *Results,
- unsigned NumResults);
-
- virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
- OverloadCandidate *Candidates,
- unsigned NumCandidates) {
+
+ void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
+ CodeCompletionResult *Results,
+ unsigned NumResults) override;
+
+ void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
+ OverloadCandidate *Candidates,
+ unsigned NumCandidates) override {
Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates);
}
-
- virtual CodeCompletionAllocator &getAllocator() {
+
+ CodeCompletionAllocator &getAllocator() override {
return Next.getAllocator();
}
- virtual CodeCompletionTUInfo &getCodeCompletionTUInfo() {
+ CodeCompletionTUInfo &getCodeCompletionTUInfo() override {
return Next.getCodeCompletionTUInfo();
}
};
@@ -2378,8 +2328,7 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
- RemappedFile *RemappedFiles,
- unsigned NumRemappedFiles,
+ ArrayRef<RemappedFile> RemappedFiles,
bool IncludeMacros,
bool IncludeCodePatterns,
bool IncludeBriefComments,
@@ -2417,7 +2366,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
// Set the language options appropriately.
LangOpts = *CCInvocation->getLangOpts();
- OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+ std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
@@ -2434,10 +2383,10 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
ProcessWarningOptions(Diag, CCInvocation->getDiagnosticOpts());
// Create the target instance.
- Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
- &Clang->getTargetOpts()));
+ Clang->setTarget(TargetInfo::CreateTargetInfo(
+ Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
if (!Clang->hasTarget()) {
- Clang->setInvocation(0);
+ Clang->setInvocation(nullptr);
return;
}
@@ -2445,7 +2394,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
//
// FIXME: We shouldn't need to do this, the target should be immutable once
// created. This complexity should be lifted elsewhere.
- Clang->getTarget().setForcedLangOptions(Clang->getLangOpts());
+ Clang->getTarget().adjust(Clang->getLangOpts());
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
"Invocation must have exactly one source file!");
@@ -2462,18 +2411,12 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
// Remap files.
PreprocessorOpts.clearRemappedFiles();
PreprocessorOpts.RetainRemappedFileBuffers = true;
- for (unsigned I = 0; I != NumRemappedFiles; ++I) {
- FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second;
- if (const llvm::MemoryBuffer *
- memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) {
- PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, memBuf);
- OwnedBuffers.push_back(memBuf);
- } else {
- const char *fname = fileOrBuf.get<const char *>();
- PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, fname);
- }
+ for (unsigned I = 0, N = RemappedFiles.size(); I != N; ++I) {
+ PreprocessorOpts.addRemappedFile(RemappedFiles[I].first,
+ RemappedFiles[I].second);
+ OwnedBuffers.push_back(RemappedFiles[I].second);
}
-
+
// Use the code completion consumer we were given, but adding any cached
// code-completion results.
AugmentedCodeCompleteConsumer *AugmentedConsumer
@@ -2484,7 +2427,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
// the use of the precompiled preamble if we're if the completion
// point is within the main file, after the end of the precompiled
// preamble.
- llvm::MemoryBuffer *OverrideMainBuffer = 0;
+ llvm::MemoryBuffer *OverrideMainBuffer = nullptr;
if (!getPreambleFile(this).empty()) {
std::string CompleteFilePath(File);
llvm::sys::fs::UniqueID CompleteFileID;
@@ -2520,8 +2463,8 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
// Disable the preprocessing record if modules are not enabled.
if (!Clang->getLangOpts().Modules)
PreprocessorOpts.DetailedRecord = false;
-
- OwningPtr<SyntaxOnlyAction> Act;
+
+ std::unique_ptr<SyntaxOnlyAction> Act;
Act.reset(new SyntaxOnlyAction);
if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) {
Act->Execute();
@@ -2554,8 +2497,7 @@ bool ASTUnit::Save(StringRef File) {
}
if (llvm::sys::fs::rename(TempPath.str(), File)) {
- bool exists;
- llvm::sys::fs::remove(TempPath.str(), exists);
+ llvm::sys::fs::remove(TempPath.str());
return true;
}
@@ -2567,7 +2509,7 @@ static bool serializeUnit(ASTWriter &Writer,
Sema &S,
bool hasErrors,
raw_ostream &OS) {
- Writer.WriteAST(S, std::string(), 0, "", hasErrors);
+ Writer.WriteAST(S, std::string(), nullptr, "", hasErrors);
// Write the generated bitstream to "Out".
if (!Buffer.empty())
@@ -2591,68 +2533,57 @@ bool ASTUnit::serialize(raw_ostream &OS) {
typedef ContinuousRangeMap<unsigned, int, 2> SLocRemap;
-static void TranslateSLoc(SourceLocation &L, SLocRemap &Remap) {
- unsigned Raw = L.getRawEncoding();
- const unsigned MacroBit = 1U << 31;
- L = SourceLocation::getFromRawEncoding((Raw & MacroBit) |
- ((Raw & ~MacroBit) + Remap.find(Raw & ~MacroBit)->second));
-}
-
void ASTUnit::TranslateStoredDiagnostics(
- ASTReader *MMan,
- StringRef ModName,
+ FileManager &FileMgr,
SourceManager &SrcMgr,
- const SmallVectorImpl<StoredDiagnostic> &Diags,
+ const SmallVectorImpl<StandaloneDiagnostic> &Diags,
SmallVectorImpl<StoredDiagnostic> &Out) {
- // The stored diagnostic has the old source manager in it; update
- // the locations to refer into the new source manager. We also need to remap
- // all the locations to the new view. This includes the diag location, any
- // associated source ranges, and the source ranges of associated fix-its.
+ // Map the standalone diagnostic into the new source manager. We also need to
+ // remap all the locations to the new view. This includes the diag location,
+ // any associated source ranges, and the source ranges of associated fix-its.
// FIXME: There should be a cleaner way to do this.
SmallVector<StoredDiagnostic, 4> Result;
Result.reserve(Diags.size());
- assert(MMan && "Don't have a module manager");
- serialization::ModuleFile *Mod = MMan->ModuleMgr.lookup(ModName);
- assert(Mod && "Don't have preamble module");
- SLocRemap &Remap = Mod->SLocRemap;
for (unsigned I = 0, N = Diags.size(); I != N; ++I) {
// Rebuild the StoredDiagnostic.
- const StoredDiagnostic &SD = Diags[I];
- SourceLocation L = SD.getLocation();
- TranslateSLoc(L, Remap);
+ const StandaloneDiagnostic &SD = Diags[I];
+ if (SD.Filename.empty())
+ continue;
+ const FileEntry *FE = FileMgr.getFile(SD.Filename);
+ if (!FE)
+ continue;
+ FileID FID = SrcMgr.translateFile(FE);
+ SourceLocation FileLoc = SrcMgr.getLocForStartOfFile(FID);
+ if (FileLoc.isInvalid())
+ continue;
+ SourceLocation L = FileLoc.getLocWithOffset(SD.LocOffset);
FullSourceLoc Loc(L, SrcMgr);
SmallVector<CharSourceRange, 4> Ranges;
- Ranges.reserve(SD.range_size());
- for (StoredDiagnostic::range_iterator I = SD.range_begin(),
- E = SD.range_end();
- I != E; ++I) {
- SourceLocation BL = I->getBegin();
- TranslateSLoc(BL, Remap);
- SourceLocation EL = I->getEnd();
- TranslateSLoc(EL, Remap);
- Ranges.push_back(CharSourceRange(SourceRange(BL, EL), I->isTokenRange()));
+ Ranges.reserve(SD.Ranges.size());
+ for (std::vector<std::pair<unsigned, unsigned> >::const_iterator
+ I = SD.Ranges.begin(), E = SD.Ranges.end(); I != E; ++I) {
+ SourceLocation BL = FileLoc.getLocWithOffset((*I).first);
+ SourceLocation EL = FileLoc.getLocWithOffset((*I).second);
+ Ranges.push_back(CharSourceRange::getCharRange(BL, EL));
}
SmallVector<FixItHint, 2> FixIts;
- FixIts.reserve(SD.fixit_size());
- for (StoredDiagnostic::fixit_iterator I = SD.fixit_begin(),
- E = SD.fixit_end();
+ FixIts.reserve(SD.FixIts.size());
+ for (std::vector<StandaloneFixIt>::const_iterator
+ I = SD.FixIts.begin(), E = SD.FixIts.end();
I != E; ++I) {
FixIts.push_back(FixItHint());
FixItHint &FH = FixIts.back();
FH.CodeToInsert = I->CodeToInsert;
- SourceLocation BL = I->RemoveRange.getBegin();
- TranslateSLoc(BL, Remap);
- SourceLocation EL = I->RemoveRange.getEnd();
- TranslateSLoc(EL, Remap);
- FH.RemoveRange = CharSourceRange(SourceRange(BL, EL),
- I->RemoveRange.isTokenRange());
+ SourceLocation BL = FileLoc.getLocWithOffset(I->RemoveRange.first);
+ SourceLocation EL = FileLoc.getLocWithOffset(I->RemoveRange.second);
+ FH.RemoveRange = CharSourceRange::getCharRange(BL, EL);
}
- Result.push_back(StoredDiagnostic(SD.getLevel(), SD.getID(),
- SD.getMessage(), Loc, Ranges, FixIts));
+ Result.push_back(StoredDiagnostic(SD.Level, SD.ID,
+ SD.Message, Loc, Ranges, FixIts));
}
Result.swap(Out);
}
@@ -2677,7 +2608,7 @@ void ASTUnit::addFileLevelDecl(Decl *D) {
assert(SM.isLocalSourceLocation(FileLoc));
FileID FID;
unsigned Offset;
- llvm::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc);
+ std::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc);
if (FID.isInvalid())
return;
@@ -2719,7 +2650,8 @@ void ASTUnit::findFileRegionDecls(FileID File, unsigned Offset, unsigned Length,
LocDeclsTy::iterator BeginIt =
std::lower_bound(LocDecls.begin(), LocDecls.end(),
- std::make_pair(Offset, (Decl *)0), llvm::less_first());
+ std::make_pair(Offset, (Decl *)nullptr),
+ llvm::less_first());
if (BeginIt != LocDecls.begin())
--BeginIt;
@@ -2732,7 +2664,7 @@ void ASTUnit::findFileRegionDecls(FileID File, unsigned Offset, unsigned Length,
LocDeclsTy::iterator EndIt = std::upper_bound(
LocDecls.begin(), LocDecls.end(),
- std::make_pair(Offset + Length, (Decl *)0), llvm::less_first());
+ std::make_pair(Offset + Length, (Decl *)nullptr), llvm::less_first());
if (EndIt != LocDecls.end())
++EndIt;
@@ -2860,7 +2792,7 @@ bool ASTUnit::visitLocalTopLevelDecls(void *context, DeclVisitorFn Fn) {
serialization::ModuleFile &
Mod = Reader->getModuleManager().getPrimaryModule();
ASTReader::ModuleDeclIterator MDI, MDE;
- llvm::tie(MDI, MDE) = Reader->getModuleFileLevelDecls(Mod);
+ std::tie(MDI, MDE) = Reader->getModuleFileLevelDecls(Mod);
for (; MDI != MDE; ++MDI) {
if (!Fn(context, *MDI))
return false;
@@ -2882,7 +2814,7 @@ bool ASTUnit::visitLocalTopLevelDecls(void *context, DeclVisitorFn Fn) {
namespace {
struct PCHLocatorInfo {
serialization::ModuleFile *Mod;
- PCHLocatorInfo() : Mod(0) {}
+ PCHLocatorInfo() : Mod(nullptr) {}
};
}
@@ -2905,14 +2837,14 @@ static bool PCHLocator(serialization::ModuleFile &M, void *UserData) {
const FileEntry *ASTUnit::getPCHFile() {
if (!Reader)
- return 0;
+ return nullptr;
PCHLocatorInfo Info;
Reader->getModuleManager().visit(PCHLocator, &Info);
if (Info.Mod)
return Info.Mod->File;
- return 0;
+ return nullptr;
}
bool ASTUnit::isModuleFile() {
@@ -2953,7 +2885,7 @@ void ASTUnit::ConcurrencyState::finish() {
#else // NDEBUG
-ASTUnit::ConcurrencyState::ConcurrencyState() {}
+ASTUnit::ConcurrencyState::ConcurrencyState() { Mutex = 0; }
ASTUnit::ConcurrencyState::~ConcurrencyState() {}
void ASTUnit::ConcurrencyState::start() {}
void ASTUnit::ConcurrencyState::finish() {}
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 0566d54f36a7..403cc42927a6 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -1,3 +1,10 @@
+add_subdirectory(Rewrite)
+
+set(LLVM_LINK_COMPONENTS
+ Option
+ Support
+ )
+
add_clang_library(clangFrontend
ASTConsumers.cpp
ASTMerge.cpp
@@ -20,6 +27,7 @@ add_clang_library(clangFrontend
LangStandards.cpp
LayoutOverrideSource.cpp
LogDiagnosticPrinter.cpp
+ ModuleDependencyCollector.cpp
MultiplexConsumer.cpp
PrintPreprocessedOutput.cpp
SerializedDiagnosticPrinter.cpp
@@ -27,26 +35,11 @@ add_clang_library(clangFrontend
TextDiagnosticBuffer.cpp
TextDiagnosticPrinter.cpp
VerifyDiagnosticConsumer.cpp
- Warnings.cpp
- )
-add_dependencies(clangFrontend
- ClangAttrClasses
- ClangAttrList
- ClangAttrParsedAttrList
- ClangCommentNodes
- ClangDeclNodes
- ClangDiagnosticAST
- ClangDiagnosticCommon
- ClangDiagnosticDriver
- ClangDiagnosticFrontend
- ClangDiagnosticLex
- ClangDiagnosticSema
+ DEPENDS
ClangDriverOptions
- ClangStmtNodes
- )
-target_link_libraries(clangFrontend
+ LINK_LIBS
clangAST
clangBasic
clangDriver
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index 0c30b049579d..14f7027e4687 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -17,14 +17,15 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
#include "clang/Basic/IdentifierTable.h"
-#include "clang/Basic/OnDiskHashTable.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/EndianStream.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/OnDiskHashTable.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
@@ -34,12 +35,13 @@
#endif
using namespace clang;
-using namespace clang::io;
//===----------------------------------------------------------------------===//
// PTH-specific stuff.
//===----------------------------------------------------------------------===//
+typedef uint32_t Offset;
+
namespace {
class PTHEntry {
Offset TokenData, PPCondData;
@@ -61,13 +63,13 @@ class PTHEntryKeyVariant {
FileData *Data;
public:
- PTHEntryKeyVariant(const FileEntry *fe) : FE(fe), Kind(IsFE), Data(0) {}
+ PTHEntryKeyVariant(const FileEntry *fe) : FE(fe), Kind(IsFE), Data(nullptr) {}
PTHEntryKeyVariant(FileData *Data, const char *path)
: Path(path), Kind(IsDE), Data(new FileData(*Data)) {}
explicit PTHEntryKeyVariant(const char *path)
- : Path(path), Kind(IsNoExist), Data(0) {}
+ : Path(path), Kind(IsNoExist), Data(nullptr) {}
bool isFile() const { return Kind == IsFE; }
@@ -78,21 +80,23 @@ public:
unsigned getKind() const { return (unsigned) Kind; }
void EmitData(raw_ostream& Out) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
switch (Kind) {
case IsFE: {
// Emit stat information.
llvm::sys::fs::UniqueID UID = FE->getUniqueID();
- ::Emit64(Out, UID.getFile());
- ::Emit64(Out, UID.getDevice());
- ::Emit64(Out, FE->getModificationTime());
- ::Emit64(Out, FE->getSize());
+ LE.write<uint64_t>(UID.getFile());
+ LE.write<uint64_t>(UID.getDevice());
+ LE.write<uint64_t>(FE->getModificationTime());
+ LE.write<uint64_t>(FE->getSize());
} break;
case IsDE:
// Emit stat information.
- ::Emit64(Out, Data->UniqueID.getFile());
- ::Emit64(Out, Data->UniqueID.getDevice());
- ::Emit64(Out, Data->ModTime);
- ::Emit64(Out, Data->Size);
+ LE.write<uint64_t>(Data->UniqueID.getFile());
+ LE.write<uint64_t>(Data->UniqueID.getDevice());
+ LE.write<uint64_t>(Data->ModTime);
+ LE.write<uint64_t>(Data->Size);
delete Data;
break;
default:
@@ -113,39 +117,46 @@ public:
typedef PTHEntry data_type;
typedef const PTHEntry& data_type_ref;
- static unsigned ComputeHash(PTHEntryKeyVariant V) {
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
+ static hash_value_type ComputeHash(PTHEntryKeyVariant V) {
return llvm::HashString(V.getString());
}
static std::pair<unsigned,unsigned>
EmitKeyDataLength(raw_ostream& Out, PTHEntryKeyVariant V,
const PTHEntry& E) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
unsigned n = V.getString().size() + 1 + 1;
- ::Emit16(Out, n);
+ LE.write<uint16_t>(n);
unsigned m = V.getRepresentationLength() + (V.isFile() ? 4 + 4 : 0);
- ::Emit8(Out, m);
+ LE.write<uint8_t>(m);
return std::make_pair(n, m);
}
static void EmitKey(raw_ostream& Out, PTHEntryKeyVariant V, unsigned n){
+ using namespace llvm::support;
// Emit the entry kind.
- ::Emit8(Out, (unsigned) V.getKind());
+ endian::Writer<little>(Out).write<uint8_t>((unsigned)V.getKind());
// Emit the string.
Out.write(V.getString().data(), n - 1);
}
static void EmitData(raw_ostream& Out, PTHEntryKeyVariant V,
const PTHEntry& E, unsigned) {
-
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
// For file entries emit the offsets into the PTH file for token data
// and the preprocessor blocks table.
if (V.isFile()) {
- ::Emit32(Out, E.getTokenOffset());
- ::Emit32(Out, E.getPPCondTableOffset());
+ LE.write<uint32_t>(E.getTokenOffset());
+ LE.write<uint32_t>(E.getPPCondTableOffset());
}
// Emit any other data associated with the key (i.e., stat information).
@@ -164,7 +175,7 @@ public:
};
} // end anonymous namespace
-typedef OnDiskChainedHashTableGenerator<FileEntryPTHEntryInfo> PTHMap;
+typedef llvm::OnDiskChainedHashTableGenerator<FileEntryPTHEntryInfo> PTHMap;
namespace {
class PTHWriter {
@@ -186,18 +197,28 @@ class PTHWriter {
/// Emit a token to the PTH file.
void EmitToken(const Token& T);
- void Emit8(uint32_t V) { ::Emit8(Out, V); }
+ void Emit8(uint32_t V) {
+ using namespace llvm::support;
+ endian::Writer<little>(Out).write<uint8_t>(V);
+ }
- void Emit16(uint32_t V) { ::Emit16(Out, V); }
+ void Emit16(uint32_t V) {
+ using namespace llvm::support;
+ endian::Writer<little>(Out).write<uint16_t>(V);
+ }
- void Emit32(uint32_t V) { ::Emit32(Out, V); }
+ void Emit32(uint32_t V) {
+ using namespace llvm::support;
+ endian::Writer<little>(Out).write<uint32_t>(V);
+ }
void EmitBuf(const char *Ptr, unsigned NumBytes) {
Out.write(Ptr, NumBytes);
}
void EmitString(StringRef V) {
- ::Emit16(Out, V.size());
+ using namespace llvm::support;
+ endian::Writer<little>(Out).write<uint16_t>(V.size());
EmitBuf(V.data(), V.size());
}
@@ -270,8 +291,11 @@ void PTHWriter::EmitToken(const Token& T) {
PTHEntry PTHWriter::LexTokens(Lexer& L) {
// Pad 0's so that we emit tokens to a 4-byte alignment.
// This speed up reading them back in.
- Pad(Out, 4);
- Offset TokenOff = (Offset) Out.tell();
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+ uint32_t TokenOff = Out.tell();
+ for (uint64_t N = llvm::OffsetToAlignment(TokenOff, 4); N; --N, ++TokenOff)
+ LE.write<uint8_t>(0);
// Keep track of matching '#if' ... '#endif'.
typedef std::vector<std::pair<Offset, unsigned> > PPCondTable;
@@ -293,7 +317,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) {
Token Tmp = Tok;
Tmp.setKind(tok::eod);
Tmp.clearFlag(Token::StartOfLine);
- Tmp.setIdentifierInfo(0);
+ Tmp.setIdentifierInfo(nullptr);
EmitToken(Tmp);
ParsingPreprocessorDirective = false;
}
@@ -516,8 +540,9 @@ public:
~StatListener() {}
LookupResult getStat(const char *Path, FileData &Data, bool isFile,
- int *FileDescriptor) {
- LookupResult Result = statChained(Path, Data, isFile, FileDescriptor);
+ std::unique_ptr<vfs::File> *F,
+ vfs::FileSystem &FS) override {
+ LookupResult Result = statChained(Path, Data, isFile, F, FS);
if (Result == CacheMissing) // Failed 'stat'.
PM.insert(PTHEntryKeyVariant(Path), PTHEntry());
@@ -578,14 +603,18 @@ public:
typedef uint32_t data_type;
typedef data_type data_type_ref;
- static unsigned ComputeHash(PTHIdKey* key) {
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
+ static hash_value_type ComputeHash(PTHIdKey* key) {
return llvm::HashString(key->II->getName());
}
static std::pair<unsigned,unsigned>
EmitKeyDataLength(raw_ostream& Out, const PTHIdKey* key, uint32_t) {
+ using namespace llvm::support;
unsigned n = key->II->getLength() + 1;
- ::Emit16(Out, n);
+ endian::Writer<little>(Out).write<uint16_t>(n);
return std::make_pair(n, sizeof(uint32_t));
}
@@ -598,7 +627,8 @@ public:
static void EmitData(raw_ostream& Out, PTHIdKey*, uint32_t pID,
unsigned) {
- ::Emit32(Out, pID);
+ using namespace llvm::support;
+ endian::Writer<little>(Out).write<uint32_t>(pID);
}
};
} // end anonymous namespace
@@ -617,7 +647,7 @@ std::pair<Offset,Offset> PTHWriter::EmitIdentifierTable() {
PTHIdKey *IIDMap = (PTHIdKey*)calloc(idcount, sizeof(PTHIdKey));
// Create the hashtable.
- OnDiskChainedHashTableGenerator<PTHIdentifierTableTrait> IIOffMap;
+ llvm::OnDiskChainedHashTableGenerator<PTHIdentifierTableTrait> IIOffMap;
// Generate mapping from persistent IDs -> IdentifierInfo*.
for (IDMap::iterator I = IM.begin(), E = IM.end(); I != E; ++I) {
diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp
index 442177ec3197..e6e73ac963fb 100644
--- a/lib/Frontend/ChainedIncludesSource.cpp
+++ b/lib/Frontend/ChainedIncludesSource.cpp
@@ -12,7 +12,6 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/ChainedIncludesSource.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
@@ -25,13 +24,61 @@
using namespace clang;
-static ASTReader *createASTReader(CompilerInstance &CI,
- StringRef pchFile,
- SmallVectorImpl<llvm::MemoryBuffer *> &memBufs,
- SmallVectorImpl<std::string> &bufNames,
- ASTDeserializationListener *deserialListener = 0) {
+namespace {
+class ChainedIncludesSource : public ExternalSemaSource {
+public:
+ virtual ~ChainedIncludesSource();
+
+ ExternalSemaSource &getFinalReader() const { return *FinalReader; }
+
+ std::vector<CompilerInstance *> CIs;
+ IntrusiveRefCntPtr<ExternalSemaSource> FinalReader;
+
+protected:
+ //===----------------------------------------------------------------------===//
+ // ExternalASTSource interface.
+ //===----------------------------------------------------------------------===//
+
+ Decl *GetExternalDecl(uint32_t ID) override;
+ Selector GetExternalSelector(uint32_t ID) override;
+ uint32_t GetNumExternalSelectors() override;
+ Stmt *GetExternalDeclStmt(uint64_t Offset) override;
+ CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset) override;
+ bool FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name) override;
+ ExternalLoadResult
+ FindExternalLexicalDecls(const DeclContext *DC,
+ bool (*isKindWeWant)(Decl::Kind),
+ SmallVectorImpl<Decl *> &Result) override;
+ void CompleteType(TagDecl *Tag) override;
+ void CompleteType(ObjCInterfaceDecl *Class) override;
+ void StartedDeserializing() override;
+ void FinishedDeserializing() override;
+ void StartTranslationUnit(ASTConsumer *Consumer) override;
+ void PrintStats() override;
+
+ /// Return the amount of memory used by memory buffers, breaking down
+ /// by heap-backed versus mmap'ed memory.
+ void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override;
+
+ //===----------------------------------------------------------------------===//
+ // ExternalSemaSource interface.
+ //===----------------------------------------------------------------------===//
+
+ void InitializeSema(Sema &S) override;
+ void ForgetSema() override;
+ void ReadMethodPool(Selector Sel) override;
+ bool LookupUnqualified(LookupResult &R, Scope *S) override;
+};
+}
+
+static ASTReader *
+createASTReader(CompilerInstance &CI, StringRef pchFile,
+ SmallVectorImpl<llvm::MemoryBuffer *> &memBufs,
+ SmallVectorImpl<std::string> &bufNames,
+ ASTDeserializationListener *deserialListener = nullptr) {
Preprocessor &PP = CI.getPreprocessor();
- OwningPtr<ASTReader> Reader;
+ std::unique_ptr<ASTReader> Reader;
Reader.reset(new ASTReader(PP, CI.getASTContext(), /*isysroot=*/"",
/*DisableValidation=*/true));
for (unsigned ti = 0; ti < bufNames.size(); ++ti) {
@@ -44,7 +91,7 @@ static ASTReader *createASTReader(CompilerInstance &CI,
case ASTReader::Success:
// Set the predefines buffer as suggested by the PCH reader.
PP.setPredefines(Reader->getSuggestedPredefines());
- return Reader.take();
+ return Reader.release();
case ASTReader::Failure:
case ASTReader::Missing:
@@ -54,7 +101,7 @@ static ASTReader *createASTReader(CompilerInstance &CI,
case ASTReader::HadErrors:
break;
}
- return 0;
+ return nullptr;
}
ChainedIncludesSource::~ChainedIncludesSource() {
@@ -62,12 +109,13 @@ ChainedIncludesSource::~ChainedIncludesSource() {
delete CIs[i];
}
-ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
+IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
+ CompilerInstance &CI, IntrusiveRefCntPtr<ExternalSemaSource> &Reader) {
std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes;
assert(!includes.empty() && "No '-chain-include' in options!");
- OwningPtr<ChainedIncludesSource> source(new ChainedIncludesSource());
+ IntrusiveRefCntPtr<ChainedIncludesSource> source(new ChainedIncludesSource());
InputKind IK = CI.getFrontendOpts().Inputs[0].getKind();
SmallVector<llvm::MemoryBuffer *, 4> serialBufs;
@@ -75,7 +123,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
for (unsigned i = 0, e = includes.size(); i != e; ++i) {
bool firstInclude = (i == 0);
- OwningPtr<CompilerInvocation> CInvok;
+ std::unique_ptr<CompilerInvocation> CInvok;
CInvok.reset(new CompilerInvocation(CI.getInvocation()));
CInvok->getPreprocessorOpts().ChainedIncludes.clear();
@@ -96,27 +144,27 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
- OwningPtr<CompilerInstance> Clang(new CompilerInstance());
- Clang->setInvocation(CInvok.take());
- Clang->setDiagnostics(Diags.getPtr());
- Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
- &Clang->getTargetOpts()));
+ std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
+ Clang->setInvocation(CInvok.release());
+ Clang->setDiagnostics(Diags.get());
+ Clang->setTarget(TargetInfo::CreateTargetInfo(
+ Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
Clang->createFileManager();
Clang->createSourceManager(Clang->getFileManager());
- Clang->createPreprocessor();
+ Clang->createPreprocessor(TU_Prefix);
Clang->getDiagnosticClient().BeginSourceFile(Clang->getLangOpts(),
&Clang->getPreprocessor());
Clang->createASTContext();
SmallVector<char, 256> serialAST;
llvm::raw_svector_ostream OS(serialAST);
- OwningPtr<ASTConsumer> consumer;
- consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-", 0,
+ std::unique_ptr<ASTConsumer> consumer;
+ consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-", nullptr,
/*isysroot=*/"", &OS));
Clang->getASTContext().setASTMutationListener(
consumer->GetASTMutationListener());
- Clang->setASTConsumer(consumer.take());
- Clang->createSema(TU_Prefix, 0);
+ Clang->setASTConsumer(consumer.release());
+ Clang->createSema(TU_Prefix, nullptr);
if (firstInclude) {
Preprocessor &PP = Clang->getPreprocessor();
@@ -125,50 +173,42 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
} else {
assert(!serialBufs.empty());
SmallVector<llvm::MemoryBuffer *, 4> bufs;
- for (unsigned si = 0, se = serialBufs.size(); si != se; ++si) {
- bufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(
- StringRef(serialBufs[si]->getBufferStart(),
- serialBufs[si]->getBufferSize())));
- }
+ // TODO: Pass through the existing MemoryBuffer instances instead of
+ // allocating new ones.
+ for (auto *SB : serialBufs)
+ bufs.push_back(llvm::MemoryBuffer::getMemBuffer(SB->getBuffer()));
std::string pchName = includes[i-1];
llvm::raw_string_ostream os(pchName);
os << ".pch" << i-1;
- os.flush();
-
- serialBufNames.push_back(pchName);
-
- OwningPtr<ExternalASTSource> Reader;
+ serialBufNames.push_back(os.str());
- Reader.reset(createASTReader(*Clang, pchName, bufs, serialBufNames,
- Clang->getASTConsumer().GetASTDeserializationListener()));
+ IntrusiveRefCntPtr<ASTReader> Reader;
+ Reader = createASTReader(*Clang, pchName, bufs, serialBufNames,
+ Clang->getASTConsumer().GetASTDeserializationListener());
if (!Reader)
- return 0;
- Clang->setModuleManager(static_cast<ASTReader*>(Reader.get()));
+ return nullptr;
+ Clang->setModuleManager(Reader);
Clang->getASTContext().setExternalSource(Reader);
}
if (!Clang->InitializeSourceManager(InputFile))
- return 0;
+ return nullptr;
ParseAST(Clang->getSema());
- OS.flush();
Clang->getDiagnosticClient().EndSourceFile();
- serialBufs.push_back(
- llvm::MemoryBuffer::getMemBufferCopy(StringRef(serialAST.data(),
- serialAST.size())));
- source->CIs.push_back(Clang.take());
+ serialBufs.push_back(llvm::MemoryBuffer::getMemBufferCopy(OS.str()));
+ source->CIs.push_back(Clang.release());
}
assert(!serialBufs.empty());
std::string pchName = includes.back() + ".pch-final";
serialBufNames.push_back(pchName);
- OwningPtr<ASTReader> Reader;
- Reader.reset(createASTReader(CI, pchName, serialBufs, serialBufNames));
+ Reader = createASTReader(CI, pchName, serialBufs, serialBufNames);
if (!Reader)
- return 0;
+ return nullptr;
- source->FinalReader.reset(Reader.take());
- return source.take();
+ source->FinalReader = Reader;
+ return source;
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index eccb94cc4a4f..6af920d9fd78 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -16,6 +16,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
+#include "clang/Config/config.h"
#include "clang/Frontend/ChainedDiagnosticConsumer.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/FrontendActions.h"
@@ -31,9 +32,10 @@
#include "clang/Sema/CodeCompleteConsumer.h"
#include "clang/Sema/Sema.h"
#include "clang/Serialization/ASTReader.h"
+#include "clang/Serialization/GlobalModuleIndex.h"
#include "llvm/ADT/Statistic.h"
-#include "llvm/Config/config.h"
#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/LockFileManager.h"
@@ -43,15 +45,17 @@
#include "llvm/Support/Signals.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/system_error.h"
#include <sys/stat.h>
+#include <system_error>
#include <time.h>
using namespace clang;
-CompilerInstance::CompilerInstance()
- : Invocation(new CompilerInvocation()), ModuleManager(0),
- BuildGlobalModuleIndex(false), ModuleBuildFailed(false) {
+CompilerInstance::CompilerInstance(bool BuildingModule)
+ : ModuleLoader(BuildingModule),
+ Invocation(new CompilerInvocation()), ModuleManager(nullptr),
+ BuildGlobalModuleIndex(false), HaveFullGlobalModuleIndex(false),
+ ModuleBuildFailed(false) {
}
CompilerInstance::~CompilerInstance() {
@@ -79,6 +83,10 @@ void CompilerInstance::setTarget(TargetInfo *Value) {
void CompilerInstance::setFileManager(FileManager *Value) {
FileMgr = Value;
+ if (Value)
+ VirtualFileSystem = Value->getVirtualFileSystem();
+ else
+ VirtualFileSystem.reset();
}
void CompilerInstance::setSourceManager(SourceManager *Value) {
@@ -100,6 +108,23 @@ void CompilerInstance::setASTConsumer(ASTConsumer *Value) {
void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
CompletionConsumer.reset(Value);
}
+
+IntrusiveRefCntPtr<ASTReader> CompilerInstance::getModuleManager() const {
+ return ModuleManager;
+}
+void CompilerInstance::setModuleManager(IntrusiveRefCntPtr<ASTReader> Reader) {
+ ModuleManager = Reader;
+}
+
+std::shared_ptr<ModuleDependencyCollector>
+CompilerInstance::getModuleDepCollector() const {
+ return ModuleDepCollector;
+}
+
+void CompilerInstance::setModuleDepCollector(
+ std::shared_ptr<ModuleDependencyCollector> Collector) {
+ ModuleDepCollector = Collector;
+}
// Diagnostics
static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
@@ -110,9 +135,9 @@ static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
raw_ostream *OS = &llvm::errs();
if (DiagOpts->DiagnosticLogFile != "-") {
// Create the output stream.
- llvm::raw_fd_ostream *FileOS(
- new llvm::raw_fd_ostream(DiagOpts->DiagnosticLogFile.c_str(), ErrorInfo,
- llvm::sys::fs::F_Append));
+ llvm::raw_fd_ostream *FileOS(new llvm::raw_fd_ostream(
+ DiagOpts->DiagnosticLogFile.c_str(), ErrorInfo,
+ llvm::sys::fs::F_Append | llvm::sys::fs::F_Text));
if (!ErrorInfo.empty()) {
Diags.Report(diag::warn_fe_cc_log_diagnostics_failure)
<< DiagOpts->DiagnosticLogFile << ErrorInfo;
@@ -136,20 +161,19 @@ static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts,
DiagnosticsEngine &Diags,
StringRef OutputFile) {
std::string ErrorInfo;
- OwningPtr<llvm::raw_fd_ostream> OS;
+ std::unique_ptr<llvm::raw_fd_ostream> OS;
OS.reset(new llvm::raw_fd_ostream(OutputFile.str().c_str(), ErrorInfo,
- llvm::sys::fs::F_Binary));
+ llvm::sys::fs::F_None));
if (!ErrorInfo.empty()) {
Diags.Report(diag::warn_fe_serialized_diag_failure)
<< OutputFile << ErrorInfo;
return;
}
-
+
DiagnosticConsumer *SerializedConsumer =
- clang::serialized_diags::create(OS.take(), DiagOpts);
+ clang::serialized_diags::create(OS.release(), DiagOpts);
-
Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(),
SerializedConsumer));
}
@@ -197,7 +221,11 @@ CompilerInstance::createDiagnostics(DiagnosticOptions *Opts,
// File Manager
void CompilerInstance::createFileManager() {
- FileMgr = new FileManager(getFileSystemOpts());
+ if (!hasVirtualFileSystem()) {
+ // TODO: choose the virtual file system based on the CompilerInvocation.
+ setVirtualFileSystem(vfs::getRealFileSystem());
+ }
+ FileMgr = new FileManager(getFileSystemOpts(), VirtualFileSystem);
}
// Source Manager
@@ -206,13 +234,63 @@ void CompilerInstance::createSourceManager(FileManager &FileMgr) {
SourceMgr = new SourceManager(getDiagnostics(), FileMgr);
}
+// Initialize the remapping of files to alternative contents, e.g.,
+// those specified through other files.
+static void InitializeFileRemapping(DiagnosticsEngine &Diags,
+ SourceManager &SourceMgr,
+ FileManager &FileMgr,
+ const PreprocessorOptions &InitOpts) {
+ // Remap files in the source manager (with buffers).
+ for (const auto &RB : InitOpts.RemappedFileBuffers) {
+ // Create the file entry for the file that we're mapping from.
+ const FileEntry *FromFile =
+ FileMgr.getVirtualFile(RB.first, RB.second->getBufferSize(), 0);
+ if (!FromFile) {
+ Diags.Report(diag::err_fe_remap_missing_from_file) << RB.first;
+ if (!InitOpts.RetainRemappedFileBuffers)
+ delete RB.second;
+ continue;
+ }
+
+ // Override the contents of the "from" file with the contents of
+ // the "to" file.
+ SourceMgr.overrideFileContents(FromFile, RB.second,
+ InitOpts.RetainRemappedFileBuffers);
+ }
+
+ // Remap files in the source manager (with other files).
+ for (const auto &RF : InitOpts.RemappedFiles) {
+ // Find the file that we're mapping to.
+ const FileEntry *ToFile = FileMgr.getFile(RF.second);
+ if (!ToFile) {
+ Diags.Report(diag::err_fe_remap_missing_to_file) << RF.first << RF.second;
+ continue;
+ }
+
+ // Create the file entry for the file that we're mapping from.
+ const FileEntry *FromFile =
+ FileMgr.getVirtualFile(RF.first, ToFile->getSize(), 0);
+ if (!FromFile) {
+ Diags.Report(diag::err_fe_remap_missing_from_file) << RF.first;
+ continue;
+ }
+
+ // Override the contents of the "from" file with the contents of
+ // the "to" file.
+ SourceMgr.overrideFileContents(FromFile, ToFile);
+ }
+
+ SourceMgr.setOverridenFilesKeepOriginalName(
+ InitOpts.RemappedFilesKeepOriginalName);
+}
+
// Preprocessor
-void CompilerInstance::createPreprocessor() {
+void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) {
const PreprocessorOptions &PPOpts = getPreprocessorOpts();
// Create a PTH manager if we are using some form of a token cache.
- PTHManager *PTHMgr = 0;
+ PTHManager *PTHMgr = nullptr;
if (!PPOpts.TokenCache.empty())
PTHMgr = PTHManager::Create(PPOpts.TokenCache, getDiagnostics());
@@ -222,10 +300,10 @@ void CompilerInstance::createPreprocessor() {
getDiagnostics(),
getLangOpts(),
&getTarget());
- PP = new Preprocessor(&getPreprocessorOpts(),
- getDiagnostics(), getLangOpts(), &getTarget(),
+ PP = new Preprocessor(&getPreprocessorOpts(), getDiagnostics(), getLangOpts(),
getSourceManager(), *HeaderInfo, *this, PTHMgr,
- /*OwnsHeaderSearch=*/true);
+ /*OwnsHeaderSearch=*/true, TUKind);
+ PP->Initialize(getTarget());
// Note that this is different then passing PTHMgr to Preprocessor's ctor.
// That argument is used as the IdentifierInfoLookup argument to
@@ -238,7 +316,16 @@ void CompilerInstance::createPreprocessor() {
if (PPOpts.DetailedRecord)
PP->createPreprocessingRecord();
- InitializePreprocessor(*PP, PPOpts, getHeaderSearchOpts(), getFrontendOpts());
+ // Apply remappings to the source manager.
+ InitializeFileRemapping(PP->getDiagnostics(), PP->getSourceManager(),
+ PP->getFileManager(), PPOpts);
+
+ // Predefine macros and configure the preprocessor.
+ InitializePreprocessor(*PP, PPOpts, getFrontendOpts());
+
+ // Initialize the header search object.
+ ApplyHeaderSearchOptions(PP->getHeaderSearchInfo(), getHeaderSearchOpts(),
+ PP->getLangOpts(), PP->getTargetInfo().getTriple());
PP->setPreprocessedOutput(getPreprocessorOutputOpts().ShowCPP);
@@ -254,11 +341,20 @@ void CompilerInstance::createPreprocessor() {
// Handle generating dependencies, if requested.
const DependencyOutputOptions &DepOpts = getDependencyOutputOpts();
if (!DepOpts.OutputFile.empty())
- AttachDependencyFileGen(*PP, DepOpts);
+ TheDependencyFileGenerator.reset(
+ DependencyFileGenerator::CreateAndAttachToPreprocessor(*PP, DepOpts));
if (!DepOpts.DOTOutputFile.empty())
AttachDependencyGraphGen(*PP, DepOpts.DOTOutputFile,
getHeaderSearchOpts().Sysroot);
+ for (auto &Listener : DependencyCollectors)
+ Listener->attachToPreprocessor(*PP);
+
+ // If we don't have a collector, but we are collecting module dependencies,
+ // then we're the top level compiler instance and need to create one.
+ if (!ModuleDepCollector && !DepOpts.ModuleDependencyOutputDir.empty())
+ ModuleDepCollector = std::make_shared<ModuleDependencyCollector>(
+ DepOpts.ModuleDependencyOutputDir);
// Handle generating header include information, if requested.
if (DepOpts.ShowHeaderIncludes)
@@ -282,49 +378,46 @@ void CompilerInstance::createPreprocessor() {
void CompilerInstance::createASTContext() {
Preprocessor &PP = getPreprocessor();
Context = new ASTContext(getLangOpts(), PP.getSourceManager(),
- &getTarget(), PP.getIdentifierTable(),
- PP.getSelectorTable(), PP.getBuiltinInfo(),
- /*size_reserve=*/ 0);
+ PP.getIdentifierTable(), PP.getSelectorTable(),
+ PP.getBuiltinInfo());
+ Context->InitBuiltinTypes(getTarget());
}
// ExternalASTSource
-void CompilerInstance::createPCHExternalASTSource(StringRef Path,
- bool DisablePCHValidation,
- bool AllowPCHWithCompilerErrors,
- void *DeserializationListener){
- OwningPtr<ExternalASTSource> Source;
+void CompilerInstance::createPCHExternalASTSource(
+ StringRef Path, bool DisablePCHValidation, bool AllowPCHWithCompilerErrors,
+ void *DeserializationListener, bool OwnDeserializationListener) {
+ IntrusiveRefCntPtr<ExternalASTSource> Source;
bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
- Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot,
- DisablePCHValidation,
- AllowPCHWithCompilerErrors,
- getPreprocessor(), getASTContext(),
- DeserializationListener,
- Preamble,
- getFrontendOpts().UseGlobalModuleIndex));
+ Source = createPCHExternalASTSource(
+ Path, getHeaderSearchOpts().Sysroot, DisablePCHValidation,
+ AllowPCHWithCompilerErrors, getPreprocessor(), getASTContext(),
+ DeserializationListener, OwnDeserializationListener, Preamble,
+ getFrontendOpts().UseGlobalModuleIndex);
ModuleManager = static_cast<ASTReader*>(Source.get());
getASTContext().setExternalSource(Source);
}
-ExternalASTSource *
-CompilerInstance::createPCHExternalASTSource(StringRef Path,
- const std::string &Sysroot,
- bool DisablePCHValidation,
- bool AllowPCHWithCompilerErrors,
- Preprocessor &PP,
- ASTContext &Context,
- void *DeserializationListener,
- bool Preamble,
- bool UseGlobalModuleIndex) {
- OwningPtr<ASTReader> Reader;
+ExternalASTSource *CompilerInstance::createPCHExternalASTSource(
+ StringRef Path, const std::string &Sysroot, bool DisablePCHValidation,
+ bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context,
+ void *DeserializationListener, bool OwnDeserializationListener,
+ bool Preamble, bool UseGlobalModuleIndex) {
+ HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts();
+
+ std::unique_ptr<ASTReader> Reader;
Reader.reset(new ASTReader(PP, Context,
Sysroot.empty() ? "" : Sysroot.c_str(),
DisablePCHValidation,
AllowPCHWithCompilerErrors,
+ /*AllowConfigurationMismatch*/false,
+ HSOpts.ModulesValidateSystemHeaders,
UseGlobalModuleIndex));
Reader->setDeserializationListener(
- static_cast<ASTDeserializationListener *>(DeserializationListener));
+ static_cast<ASTDeserializationListener *>(DeserializationListener),
+ /*TakeOwnership=*/OwnDeserializationListener);
switch (Reader->ReadAST(Path,
Preamble ? serialization::MK_Preamble
: serialization::MK_PCH,
@@ -334,7 +427,7 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path,
// Set the predefines buffer as suggested by the PCH reader. Typically, the
// predefines buffer will be empty.
PP.setPredefines(Reader->getSuggestedPredefines());
- return Reader.take();
+ return Reader.release();
case ASTReader::Failure:
// Unrecoverable failure: don't even try to process the input file.
@@ -349,7 +442,7 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path,
break;
}
- return 0;
+ return nullptr;
}
// Code Completion
@@ -384,14 +477,14 @@ void CompilerInstance::createCodeCompletionConsumer() {
return;
} else if (EnableCodeCompletion(getPreprocessor(), Loc.FileName,
Loc.Line, Loc.Column)) {
- setCodeCompletionConsumer(0);
+ setCodeCompletionConsumer(nullptr);
return;
}
if (CompletionConsumer->isOutputBinary() &&
llvm::sys::ChangeStdoutToBinary()) {
getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary);
- setCodeCompletionConsumer(0);
+ setCodeCompletionConsumer(nullptr);
}
}
@@ -407,7 +500,7 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
const CodeCompleteOptions &Opts,
raw_ostream &OS) {
if (EnableCodeCompletion(PP, Filename, Line, Column))
- return 0;
+ return nullptr;
// Set up the creation routine for code-completion.
return new PrintingCodeCompleteConsumer(Opts, OS);
@@ -432,21 +525,19 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) {
delete it->OS;
if (!it->TempFilename.empty()) {
if (EraseFiles) {
- bool existed;
- llvm::sys::fs::remove(it->TempFilename, existed);
+ llvm::sys::fs::remove(it->TempFilename);
} else {
SmallString<128> NewOutFile(it->Filename);
// If '-working-directory' was passed, the output filename should be
// relative to that.
FileMgr->FixupRelativePath(NewOutFile);
- if (llvm::error_code ec = llvm::sys::fs::rename(it->TempFilename,
- NewOutFile.str())) {
+ if (std::error_code ec =
+ llvm::sys::fs::rename(it->TempFilename, NewOutFile.str())) {
getDiagnostics().Report(diag::err_unable_to_rename_temp)
<< it->TempFilename << it->Filename << ec.message();
- bool existed;
- llvm::sys::fs::remove(it->TempFilename, existed);
+ llvm::sys::fs::remove(it->TempFilename);
}
}
} else if (!it->Filename.empty() && EraseFiles)
@@ -465,6 +556,12 @@ CompilerInstance::createDefaultOutputFile(bool Binary,
/*UseTemporary=*/true);
}
+llvm::raw_null_ostream *CompilerInstance::createNullOutputFile() {
+ llvm::raw_null_ostream *OS = new llvm::raw_null_ostream();
+ addOutputFile(OutputFile("", "", OS));
+ return OS;
+}
+
llvm::raw_fd_ostream *
CompilerInstance::createOutputFile(StringRef OutputPath,
bool Binary, bool RemoveFileOnSignal,
@@ -483,7 +580,7 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
if (!OS) {
getDiagnostics().Report(diag::err_fe_unable_to_open_output)
<< OutputPath << Error;
- return 0;
+ return nullptr;
}
// Add the output file -- but don't try to remove "-", since this means we are
@@ -521,7 +618,7 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
OutFile = "-";
}
- OwningPtr<llvm::raw_fd_ostream> OS;
+ std::unique_ptr<llvm::raw_fd_ostream> OS;
std::string OSFile;
if (UseTemporary) {
@@ -533,7 +630,7 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
if (llvm::sys::fs::exists(Status)) {
// Fail early if we can't write to the final destination.
if (!llvm::sys::fs::can_write(OutputPath))
- return 0;
+ return nullptr;
// Don't use a temporary if the output is a special file. This handles
// things like '-o /dev/null'
@@ -549,7 +646,7 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
TempPath = OutFile;
TempPath += "-%%%%%%%%";
int fd;
- llvm::error_code EC =
+ std::error_code EC =
llvm::sys::fs::createUniqueFile(TempPath.str(), fd, TempPath);
if (CreateMissingDirectories &&
@@ -574,9 +671,9 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
OSFile = OutFile;
OS.reset(new llvm::raw_fd_ostream(
OSFile.c_str(), Error,
- (Binary ? llvm::sys::fs::F_Binary : llvm::sys::fs::F_None)));
+ (Binary ? llvm::sys::fs::F_None : llvm::sys::fs::F_Text)));
if (!Error.empty())
- return 0;
+ return nullptr;
}
// Make sure the out stream file gets removed if we crash.
@@ -588,7 +685,7 @@ CompilerInstance::createOutputFile(StringRef OutputPath,
if (TempPathName)
*TempPathName = TempFile;
- return OS.take();
+ return OS.release();
}
// Initialization Utilities
@@ -608,7 +705,7 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input,
Kind = Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User;
if (Input.isBuffer()) {
- SourceMgr.createMainFileIDForMemBuffer(Input.getBuffer(), Kind);
+ SourceMgr.setMainFileID(SourceMgr.createFileID(Input.getBuffer(), Kind));
assert(!SourceMgr.getMainFileID().isInvalid() &&
"Couldn't establish MainFileID!");
return true;
@@ -642,17 +739,22 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input,
}
}
- SourceMgr.createMainFileID(File, Kind);
+ SourceMgr.setMainFileID(
+ SourceMgr.createFileID(File, SourceLocation(), Kind));
} else {
- OwningPtr<llvm::MemoryBuffer> SB;
- if (llvm::error_code ec = llvm::MemoryBuffer::getSTDIN(SB)) {
- Diags.Report(diag::err_fe_error_reading_stdin) << ec.message();
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> SBOrErr =
+ llvm::MemoryBuffer::getSTDIN();
+ if (std::error_code EC = SBOrErr.getError()) {
+ Diags.Report(diag::err_fe_error_reading_stdin) << EC.message();
return false;
}
+ std::unique_ptr<llvm::MemoryBuffer> SB = std::move(SBOrErr.get());
+
const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(),
SB->getBufferSize(), 0);
- SourceMgr.createMainFileID(File, Kind);
- SourceMgr.overrideFileContents(File, SB.take());
+ SourceMgr.setMainFileID(
+ SourceMgr.createFileID(File, SourceLocation(), Kind));
+ SourceMgr.overrideFileContents(File, SB.release());
}
assert(!SourceMgr.getMainFileID().isInvalid() &&
@@ -672,7 +774,8 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
raw_ostream &OS = llvm::errs();
// Create the target instance.
- setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), &getTargetOpts()));
+ setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(),
+ getInvocation().TargetOpts));
if (!hasTarget())
return false;
@@ -680,7 +783,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
//
// FIXME: We shouldn't need to do this, the target should be immutable once
// created. This complexity should be lifted elsewhere.
- getTarget().setForcedLangOptions(getLangOpts());
+ getTarget().adjust(getLangOpts());
// rewriter project will change target built-in bool type from its default.
if (getFrontendOpts().ProgramAction == frontend::RewriteObjC)
@@ -689,7 +792,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
// Validate/process some options.
if (getHeaderSearchOpts().Verbose)
OS << "clang -cc1 version " CLANG_VERSION_STRING
- << " based upon " << PACKAGE_STRING
+ << " based upon " << BACKEND_PACKAGE_STRING
<< " default target " << llvm::sys::getDefaultTargetTriple() << "\n";
if (getFrontendOpts().ShowTimers)
@@ -748,65 +851,13 @@ static InputKind getSourceInputKindFromOptions(const LangOptions &LangOpts) {
return LangOpts.CPlusPlus? IK_CXX : IK_C;
}
-namespace {
- struct CompileModuleMapData {
- CompilerInstance &Instance;
- GenerateModuleAction &CreateModuleAction;
- };
-}
-
-/// \brief Helper function that executes the module-generating action under
-/// a crash recovery context.
-static void doCompileMapModule(void *UserData) {
- CompileModuleMapData &Data
- = *reinterpret_cast<CompileModuleMapData *>(UserData);
- Data.Instance.ExecuteAction(Data.CreateModuleAction);
-}
-
-namespace {
- /// \brief Function object that checks with the given macro definition should
- /// be removed, because it is one of the ignored macros.
- class RemoveIgnoredMacro {
- const HeaderSearchOptions &HSOpts;
-
- public:
- explicit RemoveIgnoredMacro(const HeaderSearchOptions &HSOpts)
- : HSOpts(HSOpts) { }
-
- bool operator()(const std::pair<std::string, bool> &def) const {
- StringRef MacroDef = def.first;
- return HSOpts.ModulesIgnoreMacros.count(MacroDef.split('=').first) > 0;
- }
- };
-}
-
/// \brief Compile a module file for the given module, using the options
-/// provided by the importing compiler instance.
-static void compileModule(CompilerInstance &ImportingInstance,
- SourceLocation ImportLoc,
- Module *Module,
- StringRef ModuleFileName) {
- // FIXME: have LockFileManager return an error_code so that we can
- // avoid the mkdir when the directory already exists.
- StringRef Dir = llvm::sys::path::parent_path(ModuleFileName);
- llvm::sys::fs::create_directories(Dir);
-
- llvm::LockFileManager Locked(ModuleFileName);
- switch (Locked) {
- case llvm::LockFileManager::LFS_Error:
- return;
-
- case llvm::LockFileManager::LFS_Owned:
- // We're responsible for building the module ourselves. Do so below.
- break;
-
- case llvm::LockFileManager::LFS_Shared:
- // Someone else is responsible for building the module. Wait for them to
- // finish.
- Locked.waitForUnlock();
- return;
- }
-
+/// provided by the importing compiler instance. Returns true if the module
+/// was built without errors.
+static bool compileModuleImpl(CompilerInstance &ImportingInstance,
+ SourceLocation ImportLoc,
+ Module *Module,
+ StringRef ModuleFileName) {
ModuleMap &ModMap
= ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
@@ -824,10 +875,13 @@ static void compileModule(CompilerInstance &ImportingInstance,
// Remove any macro definitions that are explicitly ignored by the module.
// They aren't supposed to affect how the module is built anyway.
const HeaderSearchOptions &HSOpts = Invocation->getHeaderSearchOpts();
- PPOpts.Macros.erase(std::remove_if(PPOpts.Macros.begin(), PPOpts.Macros.end(),
- RemoveIgnoredMacro(HSOpts)),
- PPOpts.Macros.end());
-
+ PPOpts.Macros.erase(
+ std::remove_if(PPOpts.Macros.begin(), PPOpts.Macros.end(),
+ [&HSOpts](const std::pair<std::string, bool> &def) {
+ StringRef MacroDef = def.first;
+ return HSOpts.ModulesIgnoreMacros.count(MacroDef.split('=').first) > 0;
+ }),
+ PPOpts.Macros.end());
// Note the name of the module we're building.
Invocation->getLangOpts()->CurrentModule = Module->getTopLevelModuleName();
@@ -860,16 +914,18 @@ static void compileModule(CompilerInstance &ImportingInstance,
// Construct a compiler instance that will be used to actually create the
// module.
- CompilerInstance Instance;
+ CompilerInstance Instance(/*BuildingModule=*/true);
Instance.setInvocation(&*Invocation);
Instance.createDiagnostics(new ForwardingDiagnosticConsumer(
ImportingInstance.getDiagnosticClient()),
/*ShouldOwnClient=*/true);
+ Instance.setVirtualFileSystem(&ImportingInstance.getVirtualFileSystem());
+
// Note that this module is part of the module build stack, so that we
// can detect cycles in the module graph.
- Instance.createFileManager(); // FIXME: Adopt file manager from importer?
+ Instance.setFileManager(&ImportingInstance.getFileManager());
Instance.createSourceManager(Instance.getFileManager());
SourceManager &SourceMgr = Instance.getSourceManager();
SourceMgr.setModuleBuildStack(
@@ -877,6 +933,10 @@ static void compileModule(CompilerInstance &ImportingInstance,
SourceMgr.pushModuleBuildStack(Module->getTopLevelModuleName(),
FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager()));
+ // If we're collecting module dependencies, we need to share a collector
+ // between all of the module CompilerInstances.
+ Instance.setModuleDepCollector(ImportingInstance.getModuleDepCollector());
+
// Get or create the module map that we'll use to build this module.
std::string InferredModuleMapContent;
if (const FileEntry *ModuleMapFile =
@@ -891,24 +951,24 @@ static void compileModule(CompilerInstance &ImportingInstance,
FrontendOpts.Inputs.push_back(
FrontendInputFile("__inferred_module.map", IK));
- const llvm::MemoryBuffer *ModuleMapBuffer =
+ llvm::MemoryBuffer *ModuleMapBuffer =
llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent);
ModuleMapFile = Instance.getFileManager().getVirtualFile(
"__inferred_module.map", InferredModuleMapContent.size(), 0);
SourceMgr.overrideFileContents(ModuleMapFile, ModuleMapBuffer);
}
- // Construct a module-generating action.
- GenerateModuleAction CreateModuleAction(Module->IsSystem);
+ // Construct a module-generating action. Passing through Module->ModuleMap is
+ // safe because the FileManager is shared between the compiler instances.
+ GenerateModuleAction CreateModuleAction(Module->ModuleMap, Module->IsSystem);
// Execute the action to actually build the module in-place. Use a separate
// thread so that we get a stack large enough.
const unsigned ThreadStackSize = 8 << 20;
llvm::CrashRecoveryContext CRC;
- CompileModuleMapData Data = { Instance, CreateModuleAction };
- CRC.RunSafelyOnThread(&doCompileMapModule, &Data, ThreadStackSize);
+ CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(CreateModuleAction); },
+ ThreadStackSize);
-
// Delete the temporary module map file.
// FIXME: Even though we're executing under crash protection, it would still
// be nice to do this with RemoveFileOnSignal when we can. However, that
@@ -920,6 +980,67 @@ static void compileModule(CompilerInstance &ImportingInstance,
if (ImportingInstance.getFrontendOpts().GenerateGlobalModuleIndex) {
ImportingInstance.setBuildGlobalModuleIndex(true);
}
+
+ return !Instance.getDiagnostics().hasErrorOccurred();
+}
+
+static bool compileAndLoadModule(CompilerInstance &ImportingInstance,
+ SourceLocation ImportLoc,
+ SourceLocation ModuleNameLoc, Module *Module,
+ StringRef ModuleFileName) {
+ auto diagnoseBuildFailure = [&] {
+ ImportingInstance.getDiagnostics().Report(ModuleNameLoc,
+ diag::err_module_not_built)
+ << Module->Name << SourceRange(ImportLoc, ModuleNameLoc);
+ };
+
+ // FIXME: have LockFileManager return an error_code so that we can
+ // avoid the mkdir when the directory already exists.
+ StringRef Dir = llvm::sys::path::parent_path(ModuleFileName);
+ llvm::sys::fs::create_directories(Dir);
+
+ while (1) {
+ unsigned ModuleLoadCapabilities = ASTReader::ARR_Missing;
+ llvm::LockFileManager Locked(ModuleFileName);
+ switch (Locked) {
+ case llvm::LockFileManager::LFS_Error:
+ return false;
+
+ case llvm::LockFileManager::LFS_Owned:
+ // We're responsible for building the module ourselves.
+ if (!compileModuleImpl(ImportingInstance, ModuleNameLoc, Module,
+ ModuleFileName)) {
+ diagnoseBuildFailure();
+ return false;
+ }
+ break;
+
+ case llvm::LockFileManager::LFS_Shared:
+ // Someone else is responsible for building the module. Wait for them to
+ // finish.
+ if (Locked.waitForUnlock() == llvm::LockFileManager::Res_OwnerDied)
+ continue; // try again to get the lock.
+ ModuleLoadCapabilities |= ASTReader::ARR_OutOfDate;
+ break;
+ }
+
+ // Try to read the module file, now that we've compiled it.
+ ASTReader::ASTReadResult ReadResult =
+ ImportingInstance.getModuleManager()->ReadAST(
+ ModuleFileName, serialization::MK_Module, ImportLoc,
+ ModuleLoadCapabilities);
+
+ if (ReadResult == ASTReader::OutOfDate &&
+ Locked == llvm::LockFileManager::LFS_Shared) {
+ // The module may be out of date in the presence of file system races,
+ // or if one of its imports depends on header search paths that are not
+ // consistent with this ImportingInstance. Try again...
+ continue;
+ } else if (ReadResult == ASTReader::Missing) {
+ diagnoseBuildFailure();
+ }
+ return ReadResult == ASTReader::Success;
+ }
}
/// \brief Diagnose differences between the current definition of the given
@@ -1012,7 +1133,7 @@ static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro,
static void writeTimestampFile(StringRef TimestampFile) {
std::string ErrorInfo;
llvm::raw_fd_ostream Out(TimestampFile.str().c_str(), ErrorInfo,
- llvm::sys::fs::F_Binary);
+ llvm::sys::fs::F_None);
}
/// \brief Prune the module cache of modules that haven't been accessed in
@@ -1035,7 +1156,7 @@ static void pruneModuleCache(const HeaderSearchOptions &HSOpts) {
// Check whether the time stamp is older than our pruning interval.
// If not, do nothing.
time_t TimeStampModTime = StatBuf.st_mtime;
- time_t CurrentTime = time(0);
+ time_t CurrentTime = time(nullptr);
if (CurrentTime - TimeStampModTime <= time_t(HSOpts.ModuleCachePruneInterval))
return;
@@ -1046,7 +1167,7 @@ static void pruneModuleCache(const HeaderSearchOptions &HSOpts) {
// Walk the entire module cache, looking for unused module files and module
// indices.
- llvm::error_code EC;
+ std::error_code EC;
SmallString<128> ModuleCachePathNative;
llvm::sys::path::native(HSOpts.ModuleCachePath, ModuleCachePathNative);
for (llvm::sys::fs::directory_iterator
@@ -1057,44 +1178,76 @@ static void pruneModuleCache(const HeaderSearchOptions &HSOpts) {
continue;
// Walk all of the files within this directory.
- bool RemovedAllFiles = true;
for (llvm::sys::fs::directory_iterator File(Dir->path(), EC), FileEnd;
File != FileEnd && !EC; File.increment(EC)) {
// We only care about module and global module index files.
- if (llvm::sys::path::extension(File->path()) != ".pcm" &&
- llvm::sys::path::filename(File->path()) != "modules.idx") {
- RemovedAllFiles = false;
+ StringRef Extension = llvm::sys::path::extension(File->path());
+ if (Extension != ".pcm" && Extension != ".timestamp" &&
+ llvm::sys::path::filename(File->path()) != "modules.idx")
continue;
- }
// Look at this file. If we can't stat it, there's nothing interesting
// there.
- if (::stat(File->path().c_str(), &StatBuf)) {
- RemovedAllFiles = false;
+ if (::stat(File->path().c_str(), &StatBuf))
continue;
- }
// If the file has been used recently enough, leave it there.
time_t FileAccessTime = StatBuf.st_atime;
if (CurrentTime - FileAccessTime <=
time_t(HSOpts.ModuleCachePruneAfter)) {
- RemovedAllFiles = false;
continue;
}
// Remove the file.
- bool Existed;
- if (llvm::sys::fs::remove(File->path(), Existed) || !Existed) {
- RemovedAllFiles = false;
- }
+ llvm::sys::fs::remove(File->path());
+
+ // Remove the timestamp file.
+ std::string TimpestampFilename = File->path() + ".timestamp";
+ llvm::sys::fs::remove(TimpestampFilename);
}
// If we removed all of the files in the directory, remove the directory
// itself.
- if (RemovedAllFiles) {
- bool Existed;
- llvm::sys::fs::remove(Dir->path(), Existed);
+ if (llvm::sys::fs::directory_iterator(Dir->path(), EC) ==
+ llvm::sys::fs::directory_iterator() && !EC)
+ llvm::sys::fs::remove(Dir->path());
+ }
+}
+
+void CompilerInstance::createModuleManager() {
+ if (!ModuleManager) {
+ if (!hasASTContext())
+ createASTContext();
+
+ // If we're not recursively building a module, check whether we
+ // need to prune the module cache.
+ if (getSourceManager().getModuleBuildStack().empty() &&
+ getHeaderSearchOpts().ModuleCachePruneInterval > 0 &&
+ getHeaderSearchOpts().ModuleCachePruneAfter > 0) {
+ pruneModuleCache(getHeaderSearchOpts());
+ }
+
+ HeaderSearchOptions &HSOpts = getHeaderSearchOpts();
+ std::string Sysroot = HSOpts.Sysroot;
+ const PreprocessorOptions &PPOpts = getPreprocessorOpts();
+ ModuleManager = new ASTReader(getPreprocessor(), *Context,
+ Sysroot.empty() ? "" : Sysroot.c_str(),
+ PPOpts.DisablePCHValidation,
+ /*AllowASTWithCompilerErrors=*/false,
+ /*AllowConfigurationMismatch=*/false,
+ HSOpts.ModulesValidateSystemHeaders,
+ getFrontendOpts().UseGlobalModuleIndex);
+ if (hasASTConsumer()) {
+ ModuleManager->setDeserializationListener(
+ getASTConsumer().GetASTDeserializationListener());
+ getASTContext().setASTMutationListener(
+ getASTConsumer().GetASTMutationListener());
}
+ getASTContext().setExternalSource(ModuleManager);
+ if (hasSema())
+ ModuleManager->InitializeSema(getSema());
+ if (hasASTConsumer())
+ ModuleManager->StartTranslationUnit(&getASTConsumer());
}
}
@@ -1118,7 +1271,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
return LastModuleImportResult;
}
- clang::Module *Module = 0;
+ clang::Module *Module = nullptr;
// If we don't already have information on this module, load the module now.
llvm::DenseMap<const IdentifierInfo *, clang::Module *>::iterator Known
@@ -1128,51 +1281,34 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
Module = Known->second;
} else if (ModuleName == getLangOpts().CurrentModule) {
// This is the module we're building.
- Module = PP->getHeaderSearchInfo().getModuleMap().findModule(ModuleName);
+ Module = PP->getHeaderSearchInfo().lookupModule(ModuleName);
Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first;
} else {
// Search for a module with the given name.
Module = PP->getHeaderSearchInfo().lookupModule(ModuleName);
- std::string ModuleFileName;
- if (Module) {
- ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(Module);
- } else
- ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(ModuleName);
+ if (!Module) {
+ getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found)
+ << ModuleName
+ << SourceRange(ImportLoc, ModuleNameLoc);
+ ModuleBuildFailed = true;
+ return ModuleLoadResult();
+ }
+
+ std::string ModuleFileName =
+ PP->getHeaderSearchInfo().getModuleFileName(Module);
// If we don't already have an ASTReader, create one now.
- if (!ModuleManager) {
- if (!hasASTContext())
- createASTContext();
-
- // If we're not recursively building a module, check whether we
- // need to prune the module cache.
- if (getSourceManager().getModuleBuildStack().empty() &&
- getHeaderSearchOpts().ModuleCachePruneInterval > 0 &&
- getHeaderSearchOpts().ModuleCachePruneAfter > 0) {
- pruneModuleCache(getHeaderSearchOpts());
- }
+ if (!ModuleManager)
+ createModuleManager();
- std::string Sysroot = getHeaderSearchOpts().Sysroot;
- const PreprocessorOptions &PPOpts = getPreprocessorOpts();
- ModuleManager = new ASTReader(getPreprocessor(), *Context,
- Sysroot.empty() ? "" : Sysroot.c_str(),
- PPOpts.DisablePCHValidation,
- /*AllowASTWithCompilerErrors=*/false,
- getFrontendOpts().UseGlobalModuleIndex);
- if (hasASTConsumer()) {
- ModuleManager->setDeserializationListener(
- getASTConsumer().GetASTDeserializationListener());
- getASTContext().setASTMutationListener(
- getASTConsumer().GetASTMutationListener());
- }
- OwningPtr<ExternalASTSource> Source;
- Source.reset(ModuleManager);
- getASTContext().setExternalSource(Source);
- if (hasSema())
- ModuleManager->InitializeSema(getSema());
- if (hasASTConsumer())
- ModuleManager->StartTranslationUnit(&getASTConsumer());
- }
+ if (TheDependencyFileGenerator)
+ TheDependencyFileGenerator->AttachToASTReader(*ModuleManager);
+
+ if (ModuleDepCollector)
+ ModuleDepCollector->attachToASTReader(*ModuleManager);
+
+ for (auto &Listener : DependencyCollectors)
+ Listener->attachToASTReader(*ModuleManager);
// Try to load the module file.
unsigned ARRFlags = ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing;
@@ -1184,17 +1320,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
case ASTReader::OutOfDate:
case ASTReader::Missing: {
// The module file is missing or out-of-date. Build it.
-
- // If we don't have a module, we don't know how to build the module file.
- // Complain and return.
- if (!Module) {
- getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found)
- << ModuleName
- << SourceRange(ImportLoc, ModuleNameLoc);
- ModuleBuildFailed = true;
- return ModuleLoadResult();
- }
-
+ assert(Module && "missing module file");
// Check whether there is a cycle in the module graph.
ModuleBuildStack ModPath = getSourceManager().getModuleBuildStack();
ModuleBuildStack::iterator Pos = ModPath.begin(), PosEnd = ModPath.end();
@@ -1216,6 +1342,9 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
return ModuleLoadResult();
}
+ getDiagnostics().Report(ImportLoc, diag::remark_module_build)
+ << ModuleName << ModuleFileName;
+
// Check whether we have already attempted to build this module (but
// failed).
if (getPreprocessorOpts().FailedModules &&
@@ -1227,26 +1356,12 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
return ModuleLoadResult();
}
- // Try to compile the module.
- compileModule(*this, ModuleNameLoc, Module, ModuleFileName);
-
- // Try to read the module file, now that we've compiled it.
- ASTReader::ASTReadResult ReadResult
- = ModuleManager->ReadAST(ModuleFileName,
- serialization::MK_Module, ImportLoc,
- ASTReader::ARR_Missing);
- if (ReadResult != ASTReader::Success) {
- if (ReadResult == ASTReader::Missing) {
- getDiagnostics().Report(ModuleNameLoc,
- Module? diag::err_module_not_built
- : diag::err_module_not_found)
- << ModuleName
- << SourceRange(ImportLoc, ModuleNameLoc);
- }
-
+ // Try to compile and then load the module.
+ if (!compileAndLoadModule(*this, ImportLoc, ModuleNameLoc, Module,
+ ModuleFileName)) {
if (getPreprocessorOpts().FailedModules)
getPreprocessorOpts().FailedModules->addFailed(ModuleName);
- KnownModules[Path[0].first] = 0;
+ KnownModules[Path[0].first] = nullptr;
ModuleBuildFailed = true;
return ModuleLoadResult();
}
@@ -1261,23 +1376,16 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
ModuleLoader::HadFatalFailure = true;
// FIXME: The ASTReader will already have complained, but can we showhorn
// that diagnostic information into a more useful form?
- KnownModules[Path[0].first] = 0;
+ KnownModules[Path[0].first] = nullptr;
return ModuleLoadResult();
case ASTReader::Failure:
ModuleLoader::HadFatalFailure = true;
// Already complained, but note now that we failed.
- KnownModules[Path[0].first] = 0;
+ KnownModules[Path[0].first] = nullptr;
ModuleBuildFailed = true;
return ModuleLoadResult();
}
-
- if (!Module) {
- // If we loaded the module directly, without finding a module map first,
- // we'll have loaded the module's information from the module itself.
- Module = PP->getHeaderSearchInfo().getModuleMap()
- .findModule((Path[0].first->getName()));
- }
// Cache the result of this top-level module lookup for later.
Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first;
@@ -1354,17 +1462,25 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
getDiagnostics().Report(ImportLoc, diag::warn_missing_submodule)
<< Module->getFullModuleName()
<< SourceRange(Path.front().second, Path.back().second);
-
- return ModuleLoadResult(0, true);
+
+ return ModuleLoadResult(nullptr, true);
}
// Check whether this module is available.
clang::Module::Requirement Requirement;
- if (!Module->isAvailable(getLangOpts(), getTarget(), Requirement)) {
- getDiagnostics().Report(ImportLoc, diag::err_module_unavailable)
- << Module->getFullModuleName()
- << Requirement.second << Requirement.first
- << SourceRange(Path.front().second, Path.back().second);
+ clang::Module::HeaderDirective MissingHeader;
+ if (!Module->isAvailable(getLangOpts(), getTarget(), Requirement,
+ MissingHeader)) {
+ if (MissingHeader.FileNameLoc.isValid()) {
+ getDiagnostics().Report(MissingHeader.FileNameLoc,
+ diag::err_module_header_missing)
+ << MissingHeader.IsUmbrella << MissingHeader.FileName;
+ } else {
+ getDiagnostics().Report(ImportLoc, diag::err_module_unavailable)
+ << Module->getFullModuleName()
+ << Requirement.second << Requirement.first
+ << SourceRange(Path.front().second, Path.back().second);
+ }
LastModuleImportLoc = ImportLoc;
LastModuleImportResult = ModuleLoadResult();
return ModuleLoadResult();
@@ -1405,3 +1521,84 @@ void CompilerInstance::makeModuleVisible(Module *Mod,
ModuleManager->makeModuleVisible(Mod, Visibility, ImportLoc, Complain);
}
+GlobalModuleIndex *CompilerInstance::loadGlobalModuleIndex(
+ SourceLocation TriggerLoc) {
+ if (!ModuleManager)
+ createModuleManager();
+ // Can't do anything if we don't have the module manager.
+ if (!ModuleManager)
+ return nullptr;
+ // Get an existing global index. This loads it if not already
+ // loaded.
+ ModuleManager->loadGlobalIndex();
+ GlobalModuleIndex *GlobalIndex = ModuleManager->getGlobalIndex();
+ // If the global index doesn't exist, create it.
+ if (!GlobalIndex && shouldBuildGlobalModuleIndex() && hasFileManager() &&
+ hasPreprocessor()) {
+ llvm::sys::fs::create_directories(
+ getPreprocessor().getHeaderSearchInfo().getModuleCachePath());
+ GlobalModuleIndex::writeIndex(
+ getFileManager(),
+ getPreprocessor().getHeaderSearchInfo().getModuleCachePath());
+ ModuleManager->resetForReload();
+ ModuleManager->loadGlobalIndex();
+ GlobalIndex = ModuleManager->getGlobalIndex();
+ }
+ // For finding modules needing to be imported for fixit messages,
+ // we need to make the global index cover all modules, so we do that here.
+ if (!HaveFullGlobalModuleIndex && GlobalIndex && !buildingModule()) {
+ ModuleMap &MMap = getPreprocessor().getHeaderSearchInfo().getModuleMap();
+ bool RecreateIndex = false;
+ for (ModuleMap::module_iterator I = MMap.module_begin(),
+ E = MMap.module_end(); I != E; ++I) {
+ Module *TheModule = I->second;
+ const FileEntry *Entry = TheModule->getASTFile();
+ if (!Entry) {
+ SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
+ Path.push_back(std::make_pair(
+ getPreprocessor().getIdentifierInfo(TheModule->Name), TriggerLoc));
+ std::reverse(Path.begin(), Path.end());
+ // Load a module as hidden. This also adds it to the global index.
+ loadModule(TheModule->DefinitionLoc, Path,
+ Module::Hidden, false);
+ RecreateIndex = true;
+ }
+ }
+ if (RecreateIndex) {
+ GlobalModuleIndex::writeIndex(
+ getFileManager(),
+ getPreprocessor().getHeaderSearchInfo().getModuleCachePath());
+ ModuleManager->resetForReload();
+ ModuleManager->loadGlobalIndex();
+ GlobalIndex = ModuleManager->getGlobalIndex();
+ }
+ HaveFullGlobalModuleIndex = true;
+ }
+ return GlobalIndex;
+}
+
+// Check global module index for missing imports.
+bool
+CompilerInstance::lookupMissingImports(StringRef Name,
+ SourceLocation TriggerLoc) {
+ // Look for the symbol in non-imported modules, but only if an error
+ // actually occurred.
+ if (!buildingModule()) {
+ // Load global module index, or retrieve a previously loaded one.
+ GlobalModuleIndex *GlobalIndex = loadGlobalModuleIndex(
+ TriggerLoc);
+
+ // Only if we have a global index.
+ if (GlobalIndex) {
+ GlobalModuleIndex::HitSet FoundModules;
+
+ // Find the modules that reference the identifier.
+ // Note that this only finds top-level modules.
+ // We'll let diagnoseTypo find the actual declaration module.
+ if (GlobalIndex->lookupIdentifier(Name, FoundModules))
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 8db5cf1bc21a..ce61a4653d2e 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -8,19 +8,19 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/CompilerInvocation.h"
-#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/Util.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/LangStandard.h"
#include "clang/Frontend/Utils.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/Hashing.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
@@ -28,13 +28,16 @@
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Option/Option.h"
+#include "llvm/Support/CodeGen.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
-#include "llvm/Support/system_error.h"
+#include <atomic>
+#include <memory>
#include <sys/stat.h>
+#include <system_error>
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -55,6 +58,8 @@ CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &X)
HeaderSearchOpts(new HeaderSearchOptions(X.getHeaderSearchOpts())),
PreprocessorOpts(new PreprocessorOptions(X.getPreprocessorOpts())) {}
+CompilerInvocationBase::~CompilerInvocationBase() {}
+
//===----------------------------------------------------------------------===//
// Deserialization (from args)
//===----------------------------------------------------------------------===//
@@ -106,25 +111,21 @@ static unsigned getOptimizationLevelSize(ArgList &Args) {
return 0;
}
-static void addWarningArgs(ArgList &Args, std::vector<std::string> &Warnings) {
- for (arg_iterator I = Args.filtered_begin(OPT_W_Group),
- E = Args.filtered_end(); I != E; ++I) {
- Arg *A = *I;
- // If the argument is a pure flag, add its name (minus the "W" at the beginning)
- // to the warning list. Else, add its value (for the OPT_W case).
+static void addDiagnosticArgs(ArgList &Args, OptSpecifier Group,
+ OptSpecifier GroupWithValue,
+ std::vector<std::string> &Diagnostics) {
+ for (Arg *A : Args.filtered(Group)) {
if (A->getOption().getKind() == Option::FlagClass) {
- Warnings.push_back(A->getOption().getName().substr(1));
+ // The argument is a pure flag (such as OPT_Wall or OPT_Wdeprecated). Add
+ // its name (minus the "W" or "R" at the beginning) to the warning list.
+ Diagnostics.push_back(A->getOption().getName().drop_front(1));
+ } else if (A->getOption().matches(GroupWithValue)) {
+ // This is -Wfoo= or -Rfoo=, where foo is the name of the diagnostic group.
+ Diagnostics.push_back(A->getOption().getName().drop_front(1).rtrim("=-"));
} else {
- for (unsigned Idx = 0, End = A->getNumValues();
- Idx < End; ++Idx) {
- StringRef V = A->getValue(Idx);
- // "-Wl," and such are not warning options.
- // FIXME: Should be handled by putting these in separate flags.
- if (V.startswith("l,") || V.startswith("a,") || V.startswith("p,"))
- continue;
-
- Warnings.push_back(V);
- }
+ // Otherwise, add its value (for OPT_W_Joined and similar).
+ for (const char *Arg : A->getValues())
+ Diagnostics.push_back(Arg);
}
}
}
@@ -262,7 +263,7 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
configList.split(configVals, ",");
for (unsigned i = 0, e = configVals.size(); i != e; ++i) {
StringRef key, val;
- llvm::tie(key, val) = configVals[i].split("=");
+ std::tie(key, val) = configVals[i].split("=");
if (val.empty()) {
Diags.Report(SourceLocation(),
diag::err_analyzer_config_no_value) << configVals[i];
@@ -294,8 +295,36 @@ static void ParseCommentArgs(CommentOptions &Opts, ArgList &Args) {
Opts.ParseAllComments = Args.hasArg(OPT_fparse_all_comments);
}
+static StringRef getCodeModel(ArgList &Args, DiagnosticsEngine &Diags) {
+ if (Arg *A = Args.getLastArg(OPT_mcode_model)) {
+ StringRef Value = A->getValue();
+ if (Value == "small" || Value == "kernel" || Value == "medium" ||
+ Value == "large")
+ return Value;
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Value;
+ }
+ return "default";
+}
+
+/// \brief Create a new Regex instance out of the string value in \p RpassArg.
+/// It returns a pointer to the newly generated Regex instance.
+static std::shared_ptr<llvm::Regex>
+GenerateOptimizationRemarkRegex(DiagnosticsEngine &Diags, ArgList &Args,
+ Arg *RpassArg) {
+ StringRef Val = RpassArg->getValue();
+ std::string RegexError;
+ std::shared_ptr<llvm::Regex> Pattern = std::make_shared<llvm::Regex>(Val);
+ if (!Pattern->isValid(RegexError)) {
+ Diags.Report(diag::err_drv_optimization_remark_pattern)
+ << RegexError << RpassArg->getAsString(Args);
+ Pattern.reset();
+ }
+ return Pattern;
+}
+
static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
- DiagnosticsEngine &Diags) {
+ DiagnosticsEngine &Diags,
+ const TargetOptions &TargetOpts) {
using namespace options;
bool Success = true;
@@ -322,10 +351,17 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.setDebugInfo(CodeGenOptions::DebugLineTablesOnly);
} else if (Args.hasArg(OPT_g_Flag) || Args.hasArg(OPT_gdwarf_2) ||
Args.hasArg(OPT_gdwarf_3) || Args.hasArg(OPT_gdwarf_4)) {
- if (Args.hasFlag(OPT_flimit_debug_info, OPT_fno_limit_debug_info, true))
- Opts.setDebugInfo(CodeGenOptions::LimitedDebugInfo);
- else
+ bool Default = false;
+ // Until dtrace (via CTF) and LLDB can deal with distributed debug info,
+ // Darwin and FreeBSD default to standalone/full debug info.
+ if (llvm::Triple(TargetOpts.Triple).isOSDarwin() ||
+ llvm::Triple(TargetOpts.Triple).isOSFreeBSD())
+ Default = true;
+
+ if (Args.hasFlag(OPT_fstandalone_debug, OPT_fno_standalone_debug, Default))
Opts.setDebugInfo(CodeGenOptions::FullDebugInfo);
+ else
+ Opts.setDebugInfo(CodeGenOptions::LimitedDebugInfo);
}
Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info);
Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
@@ -358,20 +394,22 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
(Opts.OptimizationLevel > 1 && !Opts.OptimizeSize));
Opts.RerollLoops = Args.hasArg(OPT_freroll_loops);
+ Opts.DisableIntegratedAS = Args.hasArg(OPT_fno_integrated_as);
Opts.Autolink = !Args.hasArg(OPT_fno_autolink);
Opts.SampleProfileFile = Args.getLastArgValue(OPT_fprofile_sample_use_EQ);
+ Opts.ProfileInstrGenerate = Args.hasArg(OPT_fprofile_instr_generate);
+ Opts.InstrProfileInput = Args.getLastArgValue(OPT_fprofile_instr_use_EQ);
Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose);
Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions);
Opts.CUDAIsDevice = Args.hasArg(OPT_fcuda_is_device);
Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit);
Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
- Opts.CodeModel = Args.getLastArgValue(OPT_mcode_model);
+ Opts.CodeModel = getCodeModel(Args, Diags);
Opts.DebugPass = Args.getLastArgValue(OPT_mdebug_pass);
Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim);
Opts.DisableFree = Args.hasArg(OPT_disable_free);
Opts.DisableTailCalls = Args.hasArg(OPT_mdisable_tail_calls);
Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi);
- Opts.HiddenWeakVTables = Args.hasArg(OPT_fhidden_weak_vtables);
Opts.LessPreciseFPMAD = Args.hasArg(OPT_cl_mad_enable);
Opts.LimitFloatPrecision = Args.getLastArgValue(OPT_mlimit_float_precision);
Opts.NoInfsFPMath = (Args.hasArg(OPT_menable_no_infinities) ||
@@ -389,7 +427,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer);
Opts.SaveTempLabels = Args.hasArg(OPT_msave_temp_labels);
- Opts.NoDwarf2CFIAsm = Args.hasArg(OPT_fno_dwarf2_cfi_asm);
Opts.NoDwarfDirectoryAsm = Args.hasArg(OPT_fno_dwarf_directory_asm);
Opts.SoftFloat = Args.hasArg(OPT_msoft_float);
Opts.StrictEnums = Args.hasArg(OPT_fstrict_enums);
@@ -437,15 +474,14 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);
Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info);
+ Opts.CompressDebugSections = Args.hasArg(OPT_compress_debug_sections);
Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir);
Opts.LinkBitcodeFile = Args.getLastArgValue(OPT_mlink_bitcode_file);
Opts.SanitizerBlacklistFile = Args.getLastArgValue(OPT_fsanitize_blacklist);
Opts.SanitizeMemoryTrackOrigins =
- Args.hasArg(OPT_fsanitize_memory_track_origins);
- Opts.SanitizeAddressZeroBaseShadow =
- Args.hasArg(OPT_fsanitize_address_zero_base_shadow);
+ getLastArgIntValue(Args, OPT_fsanitize_memory_track_origins_EQ, 0, Diags);
Opts.SanitizeUndefinedTrapOnError =
- Args.hasArg(OPT_fsanitize_undefined_trap_on_error);
+ Args.hasArg(OPT_fsanitize_undefined_trap_on_error);
Opts.SSPBufferSize =
getLastArgIntValue(Args, OPT_stack_protector_buffer_size, 8, Diags);
Opts.StackRealignment = Args.hasArg(OPT_mstackrealign);
@@ -510,6 +546,30 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
}
Opts.DependentLibraries = Args.getAllArgValues(OPT_dependent_lib);
+ bool NeedLocTracking = false;
+
+ if (Arg *A = Args.getLastArg(OPT_Rpass_EQ)) {
+ Opts.OptimizationRemarkPattern =
+ GenerateOptimizationRemarkRegex(Diags, Args, A);
+ NeedLocTracking = true;
+ }
+
+ if (Arg *A = Args.getLastArg(OPT_Rpass_missed_EQ)) {
+ Opts.OptimizationRemarkMissedPattern =
+ GenerateOptimizationRemarkRegex(Diags, Args, A);
+ NeedLocTracking = true;
+ }
+
+ if (Arg *A = Args.getLastArg(OPT_Rpass_analysis_EQ)) {
+ Opts.OptimizationRemarkAnalysisPattern =
+ GenerateOptimizationRemarkRegex(Diags, Args, A);
+ NeedLocTracking = true;
+ }
+
+ // If the user requested one of the flags in the -Rpass family, make sure
+ // that the backend tracks source location information.
+ if (NeedLocTracking && Opts.getDebugInfo() == CodeGenOptions::NoDebugInfo)
+ Opts.setDebugInfo(CodeGenOptions::LocTrackingOnly);
return Success;
}
@@ -520,12 +580,15 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
Opts.OutputFile = Args.getLastArgValue(OPT_dependency_file);
Opts.Targets = Args.getAllArgValues(OPT_MT);
Opts.IncludeSystemHeaders = Args.hasArg(OPT_sys_header_deps);
+ Opts.IncludeModuleFiles = Args.hasArg(OPT_module_file_deps);
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);
Opts.PrintShowIncludes = Args.hasArg(OPT_show_includes);
Opts.DOTOutputFile = Args.getLastArgValue(OPT_dependency_dot);
+ Opts.ModuleDependencyOutputDir =
+ Args.getLastArgValue(OPT_module_dependency_dir);
}
bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
@@ -632,7 +695,8 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
<< Opts.TabStop << DiagnosticOptions::DefaultTabStop;
}
Opts.MessageLength = getLastArgIntValue(Args, OPT_fmessage_length, 0, Diags);
- addWarningArgs(Args, Opts.Warnings);
+ addDiagnosticArgs(Args, OPT_W_Group, OPT_W_value_Group, Opts.Warnings);
+ addDiagnosticArgs(Args, OPT_R_Group, OPT_R_value_Group, Opts.Remarks);
return Success;
}
@@ -692,6 +756,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ProgramAction = frontend::ParseSyntaxOnly; break;
case OPT_module_file_info:
Opts.ProgramAction = frontend::ModuleFileInfo; break;
+ case OPT_verify_pch:
+ Opts.ProgramAction = frontend::VerifyPCH; break;
case OPT_print_decl_contexts:
Opts.ProgramAction = frontend::PrintDeclContext; break;
case OPT_print_preamble:
@@ -820,10 +886,12 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ObjCMTAction |= FrontendOptions::ObjCMT_AtomicProperty;
if (Args.hasArg(OPT_objcmt_ns_nonatomic_iosonly))
Opts.ObjCMTAction |= FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty;
+ if (Args.hasArg(OPT_objcmt_migrate_designated_init))
+ Opts.ObjCMTAction |= FrontendOptions::ObjCMT_DesignatedInitializer;
if (Args.hasArg(OPT_objcmt_migrate_all))
Opts.ObjCMTAction |= FrontendOptions::ObjCMT_MigrateDecls;
- Opts.ObjCMTWhiteListPath = Args.getLastArgValue(OPT_objcmt_white_list_dir_path);
+ Opts.ObjCMTWhiteListPath = Args.getLastArgValue(OPT_objcmt_whitelist_dir_path);
if (Opts.ARCMTAction != FrontendOptions::ARCMT_None &&
Opts.ObjCMTAction != FrontendOptions::ObjCMT_None) {
@@ -906,6 +974,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
Opts.UseLibcxx = (strcmp(A->getValue(), "libc++") == 0);
Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir);
Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodules_cache_path);
+ Opts.ModuleUserBuildPath = Args.getLastArgValue(OPT_fmodules_user_build_path);
Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash);
// -fmodules implies -fmodule-maps
Opts.ModuleMaps = Args.hasArg(OPT_fmodule_maps) || Args.hasArg(OPT_fmodules);
@@ -913,6 +982,13 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
getLastArgIntValue(Args, OPT_fmodules_prune_interval, 7 * 24 * 60 * 60);
Opts.ModuleCachePruneAfter =
getLastArgIntValue(Args, OPT_fmodules_prune_after, 31 * 24 * 60 * 60);
+ Opts.ModulesValidateOncePerBuildSession =
+ Args.hasArg(OPT_fmodules_validate_once_per_build_session);
+ Opts.BuildSessionTimestamp =
+ getLastArgUInt64Value(Args, OPT_fbuild_session_timestamp, 0);
+ Opts.ModulesValidateSystemHeaders =
+ Args.hasArg(OPT_fmodules_validate_system_headers);
+
for (arg_iterator it = Args.filtered_begin(OPT_fmodules_ignore_macro),
ie = Args.filtered_end();
it != ie; ++it) {
@@ -998,12 +1074,16 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
}
// Add the path prefixes which are implicitly treated as being system headers.
- for (arg_iterator I = Args.filtered_begin(OPT_isystem_prefix,
- OPT_ino_system_prefix),
+ for (arg_iterator I = Args.filtered_begin(OPT_system_header_prefix,
+ OPT_no_system_header_prefix),
E = Args.filtered_end();
I != E; ++I)
- Opts.AddSystemHeaderPrefix((*I)->getValue(),
- (*I)->getOption().matches(OPT_isystem_prefix));
+ Opts.AddSystemHeaderPrefix(
+ (*I)->getValue(), (*I)->getOption().matches(OPT_system_header_prefix));
+
+ for (arg_iterator I = Args.filtered_begin(OPT_ivfsoverlay),
+ E = Args.filtered_end(); I != E; ++I)
+ Opts.AddVFSOverlayFile((*I)->getValue());
}
void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
@@ -1056,6 +1136,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.CPlusPlus = Std.isCPlusPlus();
Opts.CPlusPlus11 = Std.isCPlusPlus11();
Opts.CPlusPlus1y = Std.isCPlusPlus1y();
+ Opts.CPlusPlus1z = Std.isCPlusPlus1z();
Opts.Digraphs = Std.hasDigraphs();
Opts.GNUMode = Std.isGNUMode();
Opts.GNUInline = !Std.isC99();
@@ -1063,18 +1144,13 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.ImplicitInt = Std.hasImplicitInt();
// Set OpenCL Version.
- if (LangStd == LangStandard::lang_opencl) {
- Opts.OpenCL = 1;
+ Opts.OpenCL = LangStd == LangStandard::lang_opencl || IK == IK_OpenCL;
+ if (LangStd == LangStandard::lang_opencl)
Opts.OpenCLVersion = 100;
- }
- else if (LangStd == LangStandard::lang_opencl11) {
- Opts.OpenCL = 1;
+ else if (LangStd == LangStandard::lang_opencl11)
Opts.OpenCLVersion = 110;
- }
- else if (LangStd == LangStandard::lang_opencl12) {
- Opts.OpenCL = 1;
+ else if (LangStd == LangStandard::lang_opencl12)
Opts.OpenCLVersion = 120;
- }
// OpenCL has some additional defaults.
if (Opts.OpenCL) {
@@ -1085,12 +1161,14 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.NativeHalfType = 1;
}
- if (LangStd == LangStandard::lang_cuda)
- Opts.CUDA = 1;
+ Opts.CUDA = LangStd == LangStandard::lang_cuda || IK == IK_CUDA;
// OpenCL and C++ both have bool, true, false keywords.
Opts.Bool = Opts.OpenCL || Opts.CPlusPlus;
+ // OpenCL has half keyword
+ Opts.Half = Opts.OpenCL;
+
// C++ has wchar_t keyword.
Opts.WChar = Opts.CPlusPlus;
@@ -1099,7 +1177,8 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
// Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs
// is specified, or -std is set to a conforming mode.
- Opts.Trigraphs = !Opts.GNUMode;
+ // Trigraphs are disabled by default in c++1z onwards.
+ Opts.Trigraphs = !Opts.GNUMode && !Opts.CPlusPlus1z;
Opts.DollarIdents = !Opts.AsmPreprocessor;
@@ -1125,6 +1204,43 @@ static Visibility parseVisibility(Arg *arg, ArgList &args,
return DefaultVisibility;
}
+static unsigned parseMSCVersion(ArgList &Args, DiagnosticsEngine &Diags) {
+ auto Arg = Args.getLastArg(OPT_fms_compatibility_version);
+ if (!Arg)
+ return 0;
+
+ // The MSC versioning scheme involves four versioning components:
+ // - Major
+ // - Minor
+ // - Build
+ // - Patch
+ //
+ // We accept either the old style (_MSC_VER) value, or a _MSC_FULL_VER value.
+ // Additionally, the value may be provided in the form of a more readable
+ // MM.mm.bbbbb.pp version.
+ //
+ // Unfortunately, due to the bit-width limitations, we cannot currently encode
+ // the value for the patch level.
+
+ unsigned VC[4] = {0};
+ StringRef Value = Arg->getValue();
+ SmallVector<StringRef, 4> Components;
+
+ Value.split(Components, ".", llvm::array_lengthof(VC));
+ for (unsigned CI = 0,
+ CE = std::min(Components.size(), llvm::array_lengthof(VC));
+ CI < CE; ++CI) {
+ if (Components[CI].getAsInteger(10, VC[CI])) {
+ Diags.Report(diag::err_drv_invalid_value)
+ << Arg->getAsString(Args) << Value;
+ return 0;
+ }
+ }
+
+ // FIXME we cannot encode the patch level
+ return VC[0] * 10000000 + VC[1] * 100000 + VC[2];
+}
+
static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
DiagnosticsEngine &Diags) {
// FIXME: Cleanup per-file based stuff.
@@ -1139,7 +1255,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
else {
- // Valid standard, check to make sure language and standard are compatable.
+ // Valid standard, check to make sure language and standard are
+ // compatible.
const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
switch (IK) {
case IK_C:
@@ -1290,11 +1407,11 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
OPT_fno_dollars_in_identifiers,
Opts.DollarIdents);
Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings);
- Opts.MicrosoftExt
- = Args.hasArg(OPT_fms_extensions) || Args.hasArg(OPT_fms_compatibility);
- Opts.MicrosoftMode = Args.hasArg(OPT_fms_compatibility);
+ Opts.MSVCCompat = Args.hasArg(OPT_fms_compatibility);
+ Opts.MicrosoftExt = Opts.MSVCCompat || Args.hasArg(OPT_fms_extensions);
Opts.AsmBlocks = Args.hasArg(OPT_fasm_blocks) || Opts.MicrosoftExt;
- Opts.MSCVersion = getLastArgIntValue(Args, OPT_fmsc_version, 0, Diags);
+ Opts.MSCompatibilityVersion = parseMSCVersion(Args, Diags);
+ Opts.VtorDispMode = getLastArgIntValue(Args, OPT_vtordisp_mode_EQ, 1, Diags);
Opts.Borland = Args.hasArg(OPT_fborland_extensions);
Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
Opts.ConstStrings = Args.hasFlag(OPT_fconst_strings, OPT_fno_const_strings,
@@ -1310,13 +1427,20 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.TraditionalCPP = Args.hasArg(OPT_traditional_cpp);
Opts.RTTI = !Args.hasArg(OPT_fno_rtti);
+ Opts.RTTIData = Opts.RTTI && !Args.hasArg(OPT_fno_rtti_data);
Opts.Blocks = Args.hasArg(OPT_fblocks);
Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional);
Opts.Modules = Args.hasArg(OPT_fmodules);
- Opts.ModulesDeclUse = Args.hasArg(OPT_fmodules_decluse);
+ Opts.ModulesStrictDeclUse = Args.hasArg(OPT_fmodules_strict_decluse);
+ Opts.ModulesDeclUse =
+ Args.hasArg(OPT_fmodules_decluse) || Opts.ModulesStrictDeclUse;
+ Opts.ModulesSearchAll = Opts.Modules &&
+ !Args.hasArg(OPT_fno_modules_search_all) &&
+ Args.hasArg(OPT_fmodules_search_all);
+ Opts.ModulesErrorRecovery = !Args.hasArg(OPT_fno_modules_error_recovery);
Opts.CharIsSigned = Opts.OpenCL || !Args.hasArg(OPT_fno_signed_char);
Opts.WChar = Opts.CPlusPlus && !Args.hasArg(OPT_fno_wchar);
- Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
+ Opts.ShortWChar = Args.hasFlag(OPT_fshort_wchar, OPT_fno_short_wchar, false);
Opts.ShortEnums = Args.hasArg(OPT_fshort_enums);
Opts.Freestanding = Args.hasArg(OPT_ffreestanding);
Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
@@ -1391,8 +1515,30 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
}
}
- // Check if -fopenmp is specified.
- Opts.OpenMP = Args.hasArg(OPT_fopenmp);
+ if (Arg *A = Args.getLastArg(OPT_fms_memptr_rep_EQ)) {
+ LangOptions::PragmaMSPointersToMembersKind InheritanceModel =
+ llvm::StringSwitch<LangOptions::PragmaMSPointersToMembersKind>(
+ A->getValue())
+ .Case("single",
+ LangOptions::PPTMK_FullGeneralitySingleInheritance)
+ .Case("multiple",
+ LangOptions::PPTMK_FullGeneralityMultipleInheritance)
+ .Case("virtual",
+ LangOptions::PPTMK_FullGeneralityVirtualInheritance)
+ .Default(LangOptions::PPTMK_BestCase);
+ if (InheritanceModel == LangOptions::PPTMK_BestCase)
+ Diags.Report(diag::err_drv_invalid_value)
+ << "-fms-memptr-rep=" << A->getValue();
+
+ Opts.setMSPointerToMemberRepresentationMethod(InheritanceModel);
+ }
+
+ // Check if -fopenmp= is specified.
+ if (const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ)) {
+ Opts.OpenMP = llvm::StringSwitch<bool>(A->getValue())
+ .Case("libiomp5", true)
+ .Default(false);
+ }
// Record whether the __DEPRECATED define was requested.
Opts.Deprecated = Args.hasFlag(OPT_fdeprecated_macro,
@@ -1424,7 +1570,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
break;
case 0: Opts.setStackProtector(LangOptions::SSPOff); break;
case 1: Opts.setStackProtector(LangOptions::SSPOn); break;
- case 2: Opts.setStackProtector(LangOptions::SSPReq); break;
+ case 2: Opts.setStackProtector(LangOptions::SSPStrong); break;
+ case 3: Opts.setStackProtector(LangOptions::SSPReq); break;
}
// Parse -fsanitize= arguments.
@@ -1575,6 +1722,7 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
case frontend::GeneratePTH:
case frontend::ParseSyntaxOnly:
case frontend::ModuleFileInfo:
+ case frontend::VerifyPCH:
case frontend::PluginAction:
case frontend::PrintDeclContext:
case frontend::RewriteObjC:
@@ -1605,7 +1753,6 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) {
using namespace options;
Opts.ABI = Args.getLastArgValue(OPT_target_abi);
- Opts.CXXABI = Args.getLastArgValue(OPT_cxx_abi);
Opts.CPU = Args.getLastArgValue(OPT_target_cpu);
Opts.FPMath = Args.getLastArgValue(OPT_mfpmath);
Opts.FeaturesAsWritten = Args.getAllArgValues(OPT_target_feature);
@@ -1617,8 +1764,6 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) {
Opts.Triple = llvm::sys::getDefaultTargetTriple();
}
-//
-
bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
const char *const *ArgBegin,
const char *const *ArgEnd,
@@ -1626,12 +1771,12 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
bool Success = true;
// Parse the arguments.
- OwningPtr<OptTable> Opts(createDriverOptTable());
+ std::unique_ptr<OptTable> Opts(createDriverOptTable());
const unsigned IncludedFlagsBitmask = options::CC1Option;
unsigned MissingArgIndex, MissingArgCount;
- OwningPtr<InputArgList> Args(
- Opts->ParseArgs(ArgBegin, ArgEnd, MissingArgIndex, MissingArgCount,
- IncludedFlagsBitmask));
+ std::unique_ptr<InputArgList> Args(
+ Opts->ParseArgs(ArgBegin, ArgEnd, MissingArgIndex, MissingArgCount,
+ IncludedFlagsBitmask));
// Check for missing argument error.
if (MissingArgCount) {
@@ -1656,8 +1801,9 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
ParseFileSystemArgs(Res.getFileSystemOpts(), *Args);
// FIXME: We shouldn't have to pass the DashX option around here
InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags);
- Success = ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, DashX, Diags)
- && Success;
+ ParseTargetArgs(Res.getTargetOpts(), *Args);
+ Success = ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, DashX, Diags,
+ Res.getTargetOpts()) && Success;
ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args);
if (DashX != IK_AST && DashX != IK_LLVM_IR) {
ParseLangArgs(*Res.getLangOpts(), *Args, DashX, Diags);
@@ -1672,8 +1818,6 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, FileMgr, Diags);
ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args,
Res.getFrontendOpts().ProgramAction);
- ParseTargetArgs(Res.getTargetOpts(), *Args);
-
return Success;
}
@@ -1753,8 +1897,7 @@ std::string CompilerInvocation::getModuleHash() const {
// Extend the signature with the target options.
code = hash_combine(code, TargetOpts->Triple, TargetOpts->CPU,
- TargetOpts->ABI, TargetOpts->CXXABI,
- TargetOpts->LinkerVersion);
+ TargetOpts->ABI);
for (unsigned i = 0, n = TargetOpts->FeaturesAsWritten.size(); i != n; ++i)
code = hash_combine(code, TargetOpts->FeaturesAsWritten[i]);
@@ -1763,7 +1906,6 @@ std::string CompilerInvocation::getModuleHash() const {
const HeaderSearchOptions &hsOpts = getHeaderSearchOpts();
code = hash_combine(code, ppOpts.UsePredefines, ppOpts.DetailedRecord);
- std::vector<StringRef> MacroDefs;
for (std::vector<std::pair<std::string, bool/*isUndef*/> >::const_iterator
I = getPreprocessorOpts().Macros.begin(),
IEnd = getPreprocessorOpts().Macros.end();
@@ -1785,20 +1927,26 @@ std::string CompilerInvocation::getModuleHash() const {
hsOpts.UseStandardSystemIncludes,
hsOpts.UseStandardCXXIncludes,
hsOpts.UseLibcxx);
+ code = hash_combine(code, hsOpts.ResourceDir);
+
+ // Extend the signature with the user build path.
+ code = hash_combine(code, hsOpts.ModuleUserBuildPath);
// Darwin-specific hack: if we have a sysroot, use the contents and
// modification time of
// $sysroot/System/Library/CoreServices/SystemVersion.plist
// as part of the module hash.
if (!hsOpts.Sysroot.empty()) {
- llvm::OwningPtr<llvm::MemoryBuffer> buffer;
SmallString<128> systemVersionFile;
systemVersionFile += hsOpts.Sysroot;
llvm::sys::path::append(systemVersionFile, "System");
llvm::sys::path::append(systemVersionFile, "Library");
llvm::sys::path::append(systemVersionFile, "CoreServices");
llvm::sys::path::append(systemVersionFile, "SystemVersion.plist");
- if (!llvm::MemoryBuffer::getFile(systemVersionFile.str(), buffer)) {
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer =
+ llvm::MemoryBuffer::getFile(systemVersionFile.str());
+ if (buffer) {
code = hash_combine(code, buffer.get()->getBuffer());
struct stat statBuf;
@@ -1812,10 +1960,11 @@ std::string CompilerInvocation::getModuleHash() const {
namespace clang {
-// Declared in clang/Frontend/Utils.h.
-int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default,
- DiagnosticsEngine *Diags) {
- int Res = Default;
+template<typename IntTy>
+static IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id,
+ IntTy Default,
+ DiagnosticsEngine *Diags) {
+ IntTy Res = Default;
if (Arg *A = Args.getLastArg(Id)) {
if (StringRef(A->getValue()).getAsInteger(10, Res)) {
if (Diags)
@@ -1825,4 +1974,60 @@ int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default,
}
return Res;
}
+
+
+// Declared in clang/Frontend/Utils.h.
+int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default,
+ DiagnosticsEngine *Diags) {
+ return getLastArgIntValueImpl<int>(Args, Id, Default, Diags);
+}
+
+uint64_t getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id,
+ uint64_t Default,
+ DiagnosticsEngine *Diags) {
+ return getLastArgIntValueImpl<uint64_t>(Args, Id, Default, Diags);
+}
+
+void BuryPointer(const void *Ptr) {
+ // This function may be called only a small fixed amount of times per each
+ // invocation, otherwise we do actually have a leak which we want to report.
+ // If this function is called more than kGraveYardMaxSize times, the pointers
+ // will not be properly buried and a leak detector will report a leak, which
+ // is what we want in such case.
+ static const size_t kGraveYardMaxSize = 16;
+ LLVM_ATTRIBUTE_UNUSED static const void *GraveYard[kGraveYardMaxSize];
+ static std::atomic<unsigned> GraveYardSize;
+ unsigned Idx = GraveYardSize++;
+ if (Idx >= kGraveYardMaxSize)
+ return;
+ GraveYard[Idx] = Ptr;
+}
+
+IntrusiveRefCntPtr<vfs::FileSystem>
+createVFSFromCompilerInvocation(const CompilerInvocation &CI,
+ DiagnosticsEngine &Diags) {
+ if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty())
+ return vfs::getRealFileSystem();
+
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem>
+ Overlay(new vfs::OverlayFileSystem(vfs::getRealFileSystem()));
+ // earlier vfs files are on the bottom
+ for (const std::string &File : CI.getHeaderSearchOpts().VFSOverlayFiles) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
+ llvm::MemoryBuffer::getFile(File);
+ if (!Buffer) {
+ Diags.Report(diag::err_missing_vfs_overlay_file) << File;
+ return IntrusiveRefCntPtr<vfs::FileSystem>();
+ }
+
+ IntrusiveRefCntPtr<vfs::FileSystem> FS =
+ vfs::getVFSFromYAML(Buffer->release(), /*DiagHandler*/ nullptr);
+ if (!FS.get()) {
+ Diags.Report(diag::err_invalid_vfs_overlay) << File;
+ return IntrusiveRefCntPtr<vfs::FileSystem>();
+ }
+ Overlay->pushOverlay(FS);
+ }
+ return Overlay;
}
+} // end namespace clang
diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp
index 78f39d4298af..f2f36e4cacb2 100644
--- a/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -32,7 +32,7 @@ using namespace llvm::opt;
CompilerInvocation *
clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags) {
- if (!Diags.getPtr()) {
+ if (!Diags.get()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions);
@@ -47,17 +47,17 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
// FIXME: We shouldn't have to pass in the path info.
driver::Driver TheDriver("clang", llvm::sys::getDefaultTargetTriple(),
- "a.out", *Diags);
+ *Diags);
// Don't check that inputs exist, they may have been remapped.
TheDriver.setCheckInputsExist(false);
- OwningPtr<driver::Compilation> C(TheDriver.BuildCompilation(Args));
+ std::unique_ptr<driver::Compilation> C(TheDriver.BuildCompilation(Args));
// Just print the cc1 options if -### was present.
if (C->getArgs().hasArg(driver::options::OPT__HASH_HASH_HASH)) {
C->getJobs().Print(llvm::errs(), "\n", true);
- return 0;
+ return nullptr;
}
// We expect to get back exactly one command job, if we didn't something
@@ -68,22 +68,22 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
llvm::raw_svector_ostream OS(Msg);
Jobs.Print(OS, "; ", true);
Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
- return 0;
+ return nullptr;
}
const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
if (StringRef(Cmd->getCreator().getName()) != "clang") {
Diags->Report(diag::err_fe_expected_clang_command);
- return 0;
+ return nullptr;
}
const ArgStringList &CCArgs = Cmd->getArguments();
- OwningPtr<CompilerInvocation> CI(new CompilerInvocation());
+ std::unique_ptr<CompilerInvocation> CI(new CompilerInvocation());
if (!CompilerInvocation::CreateFromArgs(*CI,
const_cast<const char **>(CCArgs.data()),
const_cast<const char **>(CCArgs.data()) +
CCArgs.size(),
*Diags))
- return 0;
- return CI.take();
+ return nullptr;
+ return CI.release();
}
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index 4037af9055d5..0b9c0d47dc36 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -20,6 +20,7 @@
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
@@ -28,7 +29,107 @@
using namespace clang;
namespace {
-class DependencyFileCallback : public PPCallbacks {
+struct DepCollectorPPCallbacks : public PPCallbacks {
+ DependencyCollector &DepCollector;
+ SourceManager &SM;
+ DepCollectorPPCallbacks(DependencyCollector &L, SourceManager &SM)
+ : DepCollector(L), SM(SM) { }
+
+ void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) override {
+ if (Reason != PPCallbacks::EnterFile)
+ return;
+
+ // Dependency generation really does want to go all the way to the
+ // file entry for a source location to find out what is depended on.
+ // We do not want #line markers to affect dependency generation!
+ const FileEntry *FE =
+ SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc)));
+ if (!FE)
+ return;
+
+ StringRef Filename = FE->getName();
+
+ // 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);
+ }
+
+ DepCollector.maybeAddDependency(Filename, /*FromModule*/false,
+ FileType != SrcMgr::C_User,
+ /*IsModuleFile*/false, /*IsMissing*/false);
+ }
+
+ void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+ StringRef FileName, bool IsAngled,
+ CharSourceRange FilenameRange, const FileEntry *File,
+ StringRef SearchPath, StringRef RelativePath,
+ const Module *Imported) override {
+ if (!File)
+ DepCollector.maybeAddDependency(FileName, /*FromModule*/false,
+ /*IsSystem*/false, /*IsModuleFile*/false,
+ /*IsMissing*/true);
+ // Files that actually exist are handled by FileChanged.
+ }
+
+ void EndOfMainFile() override {
+ DepCollector.finishedMainFile();
+ }
+};
+
+struct DepCollectorASTListener : public ASTReaderListener {
+ DependencyCollector &DepCollector;
+ DepCollectorASTListener(DependencyCollector &L) : DepCollector(L) { }
+ bool needsInputFileVisitation() override { return true; }
+ bool needsSystemInputFileVisitation() override {
+ return DepCollector.needSystemDependencies();
+ }
+ void visitModuleFile(StringRef Filename) override {
+ DepCollector.maybeAddDependency(Filename, /*FromModule*/true,
+ /*IsSystem*/false, /*IsModuleFile*/true,
+ /*IsMissing*/false);
+ }
+ bool visitInputFile(StringRef Filename, bool IsSystem,
+ bool IsOverridden) override {
+ if (IsOverridden)
+ return true;
+
+ DepCollector.maybeAddDependency(Filename, /*FromModule*/true, IsSystem,
+ /*IsModuleFile*/false, /*IsMissing*/false);
+ return true;
+ }
+};
+} // end anonymous namespace
+
+void DependencyCollector::maybeAddDependency(StringRef Filename, bool FromModule,
+ bool IsSystem, bool IsModuleFile,
+ bool IsMissing) {
+ if (Seen.insert(Filename) &&
+ sawDependency(Filename, FromModule, IsSystem, IsModuleFile, IsMissing))
+ Dependencies.push_back(Filename);
+}
+
+bool DependencyCollector::sawDependency(StringRef Filename, bool FromModule,
+ bool IsSystem, bool IsModuleFile,
+ bool IsMissing) {
+ return Filename != "<built-in>" && (needSystemDependencies() || !IsSystem);
+}
+
+DependencyCollector::~DependencyCollector() { }
+void DependencyCollector::attachToPreprocessor(Preprocessor &PP) {
+ PP.addPPCallbacks(new DepCollectorPPCallbacks(*this, PP.getSourceManager()));
+}
+void DependencyCollector::attachToASTReader(ASTReader &R) {
+ R.addListener(new DepCollectorASTListener(*this));
+}
+
+namespace {
+/// Private implementation for DependencyFileGenerator
+class DFGImpl : public PPCallbacks {
std::vector<std::string> Files;
llvm::StringSet<> FilesSet;
const Preprocessor *PP;
@@ -38,58 +139,84 @@ class DependencyFileCallback : public PPCallbacks {
bool PhonyTarget;
bool AddMissingHeaderDeps;
bool SeenMissingHeader;
+ bool IncludeModuleFiles;
private:
bool FileMatchesDepCriteria(const char *Filename,
SrcMgr::CharacteristicKind FileType);
- void AddFilename(StringRef Filename);
void OutputDependencyFile();
public:
- DependencyFileCallback(const Preprocessor *_PP,
- const DependencyOutputOptions &Opts)
+ DFGImpl(const Preprocessor *_PP, const DependencyOutputOptions &Opts)
: PP(_PP), OutputFile(Opts.OutputFile), Targets(Opts.Targets),
IncludeSystemHeaders(Opts.IncludeSystemHeaders),
PhonyTarget(Opts.UsePhonyTargets),
AddMissingHeaderDeps(Opts.AddMissingHeaderDeps),
- SeenMissingHeader(false) {}
-
- virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
- SrcMgr::CharacteristicKind FileType,
- FileID PrevFID);
- virtual void InclusionDirective(SourceLocation HashLoc,
- const Token &IncludeTok,
- StringRef FileName,
- bool IsAngled,
- CharSourceRange FilenameRange,
- const FileEntry *File,
- StringRef SearchPath,
- StringRef RelativePath,
- const Module *Imported);
-
- virtual void EndOfMainFile() {
+ SeenMissingHeader(false),
+ IncludeModuleFiles(Opts.IncludeModuleFiles) {}
+
+ void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) override;
+ void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+ StringRef FileName, bool IsAngled,
+ CharSourceRange FilenameRange, const FileEntry *File,
+ StringRef SearchPath, StringRef RelativePath,
+ const Module *Imported) override;
+
+ void EndOfMainFile() override {
OutputDependencyFile();
}
+
+ void AddFilename(StringRef Filename);
+ bool includeSystemHeaders() const { return IncludeSystemHeaders; }
+ bool includeModuleFiles() const { return IncludeModuleFiles; }
+};
+
+class DFGASTReaderListener : public ASTReaderListener {
+ DFGImpl &Parent;
+public:
+ DFGASTReaderListener(DFGImpl &Parent)
+ : Parent(Parent) { }
+ bool needsInputFileVisitation() override { return true; }
+ bool needsSystemInputFileVisitation() override {
+ return Parent.includeSystemHeaders();
+ }
+ void visitModuleFile(StringRef Filename) override;
+ bool visitInputFile(StringRef Filename, bool isSystem,
+ bool isOverridden) override;
};
}
-void clang::AttachDependencyFileGen(Preprocessor &PP,
- const DependencyOutputOptions &Opts) {
+DependencyFileGenerator::DependencyFileGenerator(void *Impl)
+: Impl(Impl) { }
+
+DependencyFileGenerator *DependencyFileGenerator::CreateAndAttachToPreprocessor(
+ clang::Preprocessor &PP, const clang::DependencyOutputOptions &Opts) {
+
if (Opts.Targets.empty()) {
PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT);
- return;
+ return nullptr;
}
// Disable the "file not found" diagnostic if the -MG option was given.
if (Opts.AddMissingHeaderDeps)
PP.SetSuppressIncludeNotFoundError(true);
- PP.addPPCallbacks(new DependencyFileCallback(&PP, Opts));
+ DFGImpl *Callback = new DFGImpl(&PP, Opts);
+ PP.addPPCallbacks(Callback); // PP owns the Callback
+ return new DependencyFileGenerator(Callback);
+}
+
+void DependencyFileGenerator::AttachToASTReader(ASTReader &R) {
+ DFGImpl *I = reinterpret_cast<DFGImpl *>(Impl);
+ assert(I && "missing implementation");
+ R.addListener(new DFGASTReaderListener(*I));
}
/// FileMatchesDepCriteria - Determine whether the given Filename should be
/// considered as a dependency.
-bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename,
- SrcMgr::CharacteristicKind FileType) {
+bool DFGImpl::FileMatchesDepCriteria(const char *Filename,
+ SrcMgr::CharacteristicKind FileType) {
if (strcmp("<built-in>", Filename) == 0)
return false;
@@ -99,10 +226,10 @@ bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename,
return FileType == SrcMgr::C_User;
}
-void DependencyFileCallback::FileChanged(SourceLocation Loc,
- FileChangeReason Reason,
- SrcMgr::CharacteristicKind FileType,
- FileID PrevFID) {
+void DFGImpl::FileChanged(SourceLocation Loc,
+ FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) {
if (Reason != PPCallbacks::EnterFile)
return;
@@ -113,7 +240,7 @@ void DependencyFileCallback::FileChanged(SourceLocation Loc,
const FileEntry *FE =
SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc)));
- if (FE == 0) return;
+ if (!FE) return;
StringRef Filename = FE->getName();
if (!FileMatchesDepCriteria(Filename.data(), FileType))
@@ -130,15 +257,15 @@ void DependencyFileCallback::FileChanged(SourceLocation Loc,
AddFilename(Filename);
}
-void DependencyFileCallback::InclusionDirective(SourceLocation HashLoc,
- const Token &IncludeTok,
- StringRef FileName,
- bool IsAngled,
- CharSourceRange FilenameRange,
- const FileEntry *File,
- StringRef SearchPath,
- StringRef RelativePath,
- const Module *Imported) {
+void DFGImpl::InclusionDirective(SourceLocation HashLoc,
+ const Token &IncludeTok,
+ StringRef FileName,
+ bool IsAngled,
+ CharSourceRange FilenameRange,
+ const FileEntry *File,
+ StringRef SearchPath,
+ StringRef RelativePath,
+ const Module *Imported) {
if (!File) {
if (AddMissingHeaderDeps)
AddFilename(FileName);
@@ -147,7 +274,7 @@ void DependencyFileCallback::InclusionDirective(SourceLocation HashLoc,
}
}
-void DependencyFileCallback::AddFilename(StringRef Filename) {
+void DFGImpl::AddFilename(StringRef Filename) {
if (FilesSet.insert(Filename))
Files.push_back(Filename);
}
@@ -164,15 +291,14 @@ static void PrintFilename(raw_ostream &OS, StringRef Filename) {
}
}
-void DependencyFileCallback::OutputDependencyFile() {
+void DFGImpl::OutputDependencyFile() {
if (SeenMissingHeader) {
- bool existed;
- llvm::sys::fs::remove(OutputFile, existed);
+ llvm::sys::fs::remove(OutputFile);
return;
}
std::string Err;
- llvm::raw_fd_ostream OS(OutputFile.c_str(), Err);
+ llvm::raw_fd_ostream OS(OutputFile.c_str(), Err, llvm::sys::fs::F_Text);
if (!Err.empty()) {
PP->getDiagnostics().Report(diag::err_fe_error_opening)
<< OutputFile << Err;
@@ -235,3 +361,17 @@ void DependencyFileCallback::OutputDependencyFile() {
}
}
+bool DFGASTReaderListener::visitInputFile(llvm::StringRef Filename,
+ bool IsSystem, bool IsOverridden) {
+ assert(!IsSystem || needsSystemInputFileVisitation());
+ if (IsOverridden)
+ return true;
+
+ Parent.AddFilename(Filename);
+ return true;
+}
+
+void DFGASTReaderListener::visitModuleFile(llvm::StringRef Filename) {
+ if (Parent.includeModuleFiles())
+ Parent.AddFilename(Filename);
+}
diff --git a/lib/Frontend/DependencyGraph.cpp b/lib/Frontend/DependencyGraph.cpp
index e128d91c4083..051b7f9e1412 100644
--- a/lib/Frontend/DependencyGraph.cpp
+++ b/lib/Frontend/DependencyGraph.cpp
@@ -46,17 +46,13 @@ public:
StringRef SysRoot)
: PP(_PP), OutputFile(OutputFile.str()), SysRoot(SysRoot.str()) { }
- virtual void InclusionDirective(SourceLocation HashLoc,
- const Token &IncludeTok,
- StringRef FileName,
- bool IsAngled,
- CharSourceRange FilenameRange,
- const FileEntry *File,
- StringRef SearchPath,
- StringRef RelativePath,
- const Module *Imported);
+ void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+ StringRef FileName, bool IsAngled,
+ CharSourceRange FilenameRange, const FileEntry *File,
+ StringRef SearchPath, StringRef RelativePath,
+ const Module *Imported) override;
- virtual void EndOfMainFile() {
+ void EndOfMainFile() override {
OutputGraphFile();
}
@@ -83,7 +79,7 @@ void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc,
SourceManager &SM = PP->getSourceManager();
const FileEntry *FromFile
= SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc)));
- if (FromFile == 0)
+ if (!FromFile)
return;
Dependencies[FromFile].push_back(File);
@@ -101,7 +97,7 @@ DependencyGraphCallback::writeNodeReference(raw_ostream &OS,
void DependencyGraphCallback::OutputGraphFile() {
std::string Err;
- llvm::raw_fd_ostream OS(OutputFile.c_str(), Err);
+ llvm::raw_fd_ostream OS(OutputFile.c_str(), Err, llvm::sys::fs::F_Text);
if (!Err.empty()) {
PP->getDiagnostics().Report(diag::err_fe_error_opening)
<< OutputFile << Err;
diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp
index 4eee59548c82..cff32b852bf4 100644
--- a/lib/Frontend/DiagnosticRenderer.cpp
+++ b/lib/Frontend/DiagnosticRenderer.cpp
@@ -79,10 +79,10 @@ class FixitReceiver : public edit::EditsReceiver {
public:
FixitReceiver(SmallVectorImpl<FixItHint> &MergedFixits)
: MergedFixits(MergedFixits) { }
- virtual void insert(SourceLocation loc, StringRef text) {
+ void insert(SourceLocation loc, StringRef text) override {
MergedFixits.push_back(FixItHint::CreateInsertion(loc, text));
}
- virtual void replace(CharSourceRange range, StringRef text) {
+ void replace(CharSourceRange range, StringRef text) override {
MergedFixits.push_back(FixItHint::CreateReplacement(range, text));
}
};
@@ -186,10 +186,16 @@ void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) {
emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(),
Diag.getRanges(), Diag.getFixIts(),
Diag.getLocation().isValid() ? &Diag.getLocation().getManager()
- : 0,
+ : nullptr,
&Diag);
}
+void DiagnosticRenderer::emitBasicNote(StringRef Message) {
+ emitDiagnosticMessage(
+ SourceLocation(), PresumedLoc(), DiagnosticsEngine::Note, Message,
+ ArrayRef<CharSourceRange>(), nullptr, DiagOrStoredDiag());
+}
+
/// \brief Prints an include stack when appropriate for a particular
/// diagnostic level and location.
///
@@ -499,12 +505,10 @@ DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc,
// Generate a note indicating the include location.
SmallString<200> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
- Message << "while building module '" << ModuleName << "' imported from "
- << PLoc.getFilename() << ':' << PLoc.getLine() << ":";
+ if (PLoc.getFilename())
+ Message << "while building module '" << ModuleName << "' imported from "
+ << PLoc.getFilename() << ':' << PLoc.getLine() << ":";
+ else
+ Message << "while building module '" << ModuleName << ":";
emitNote(Loc, Message.str(), &SM);
}
-
-
-void DiagnosticNoteRenderer::emitBasicNote(StringRef Message) {
- emitNote(SourceLocation(), Message, 0);
-}
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index 075fe93d5841..791017924d69 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -12,12 +12,12 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Frontend/ASTUnit.h"
-#include "clang/Frontend/ChainedIncludesSource.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Frontend/LayoutOverrideSource.h"
#include "clang/Frontend/MultiplexConsumer.h"
+#include "clang/Frontend/Utils.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseAST.h"
@@ -29,42 +29,49 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/system_error.h"
+#include <system_error>
using namespace clang;
+template class llvm::Registry<clang::PluginASTAction>;
+
namespace {
class DelegatingDeserializationListener : public ASTDeserializationListener {
ASTDeserializationListener *Previous;
+ bool DeletePrevious;
public:
explicit DelegatingDeserializationListener(
- ASTDeserializationListener *Previous)
- : Previous(Previous) { }
+ ASTDeserializationListener *Previous, bool DeletePrevious)
+ : Previous(Previous), DeletePrevious(DeletePrevious) {}
+ virtual ~DelegatingDeserializationListener() {
+ if (DeletePrevious)
+ delete Previous;
+ }
- virtual void ReaderInitialized(ASTReader *Reader) {
+ void ReaderInitialized(ASTReader *Reader) override {
if (Previous)
Previous->ReaderInitialized(Reader);
}
- virtual void IdentifierRead(serialization::IdentID ID,
- IdentifierInfo *II) {
+ void IdentifierRead(serialization::IdentID ID,
+ IdentifierInfo *II) override {
if (Previous)
Previous->IdentifierRead(ID, II);
}
- virtual void TypeRead(serialization::TypeIdx Idx, QualType T) {
+ void TypeRead(serialization::TypeIdx Idx, QualType T) override {
if (Previous)
Previous->TypeRead(Idx, T);
}
- virtual void DeclRead(serialization::DeclID ID, const Decl *D) {
+ void DeclRead(serialization::DeclID ID, const Decl *D) override {
if (Previous)
Previous->DeclRead(ID, D);
}
- virtual void SelectorRead(serialization::SelectorID ID, Selector Sel) {
+ void SelectorRead(serialization::SelectorID ID, Selector Sel) override {
if (Previous)
Previous->SelectorRead(ID, Sel);
}
- virtual void MacroDefinitionRead(serialization::PreprocessedEntityID PPID,
- MacroDefinition *MD) {
+ void MacroDefinitionRead(serialization::PreprocessedEntityID PPID,
+ MacroDefinition *MD) override {
if (Previous)
Previous->MacroDefinitionRead(PPID, MD);
}
@@ -73,10 +80,11 @@ public:
/// \brief Dumps deserialized declarations.
class DeserializedDeclsDumper : public DelegatingDeserializationListener {
public:
- explicit DeserializedDeclsDumper(ASTDeserializationListener *Previous)
- : DelegatingDeserializationListener(Previous) { }
+ explicit DeserializedDeclsDumper(ASTDeserializationListener *Previous,
+ bool DeletePrevious)
+ : DelegatingDeserializationListener(Previous, DeletePrevious) {}
- virtual void DeclRead(serialization::DeclID ID, const Decl *D) {
+ void DeclRead(serialization::DeclID ID, const Decl *D) override {
llvm::outs() << "PCH DECL: " << D->getDeclKindName();
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
llvm::outs() << " - " << *ND;
@@ -95,11 +103,12 @@ class DeserializedDeclsChecker : public DelegatingDeserializationListener {
public:
DeserializedDeclsChecker(ASTContext &Ctx,
const std::set<std::string> &NamesToCheck,
- ASTDeserializationListener *Previous)
- : DelegatingDeserializationListener(Previous),
- Ctx(Ctx), NamesToCheck(NamesToCheck) { }
+ ASTDeserializationListener *Previous,
+ bool DeletePrevious)
+ : DelegatingDeserializationListener(Previous, DeletePrevious), Ctx(Ctx),
+ NamesToCheck(NamesToCheck) {}
- virtual void DeclRead(serialization::DeclID ID, const Decl *D) {
+ void DeclRead(serialization::DeclID ID, const Decl *D) override {
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
if (NamesToCheck.find(ND->getNameAsString()) != NamesToCheck.end()) {
unsigned DiagID
@@ -115,7 +124,7 @@ public:
} // end anonymous namespace
-FrontendAction::FrontendAction() : Instance(0) {}
+FrontendAction::FrontendAction() : Instance(nullptr) {}
FrontendAction::~FrontendAction() {}
@@ -129,7 +138,7 @@ ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
StringRef InFile) {
ASTConsumer* Consumer = CreateASTConsumer(CI, InFile);
if (!Consumer)
- return 0;
+ return nullptr;
if (CI.getFrontendOpts().AddPluginActions.size() == 0)
return Consumer;
@@ -147,7 +156,7 @@ ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
ie = FrontendPluginRegistry::end();
it != ie; ++it) {
if (it->getName() == CI.getFrontendOpts().AddPluginActions[i]) {
- OwningPtr<PluginASTAction> P(it->instantiate());
+ std::unique_ptr<PluginASTAction> P(it->instantiate());
FrontendAction* c = P.get();
if (P->ParseArgs(CI, CI.getFrontendOpts().AddPluginArgs[i]))
Consumers.push_back(c->CreateASTConsumer(CI, InFile));
@@ -158,7 +167,6 @@ ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
return new MultiplexConsumer(Consumers);
}
-
bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
const FrontendInputFile &Input) {
assert(!Instance && "Already processing a source file!");
@@ -180,7 +188,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
"This action does not have AST file support!");
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
- std::string Error;
+
ASTUnit *AST = ASTUnit::LoadFromASTFile(InputFile, Diags,
CI.getFileSystemOpts());
if (!AST)
@@ -189,7 +197,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
setCurrentInput(Input, AST);
// Inform the diagnostic client we are processing a source file.
- CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0);
+ CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), nullptr);
HasBegunSourceFile = true;
// Set the shared objects, these are reset when we finish processing the
@@ -211,6 +219,15 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
return true;
}
+ if (!CI.hasVirtualFileSystem()) {
+ if (IntrusiveRefCntPtr<vfs::FileSystem> VFS =
+ createVFSFromCompilerInvocation(CI.getInvocation(),
+ CI.getDiagnostics()))
+ CI.setVirtualFileSystem(VFS);
+ else
+ goto failure;
+ }
+
// Set up the file and source managers, if needed.
if (!CI.hasFileManager())
CI.createFileManager();
@@ -223,13 +240,17 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
"This action does not have IR file support!");
// Inform the diagnostic client we are processing a source file.
- CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0);
+ CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), nullptr);
HasBegunSourceFile = true;
// Initialize the action.
if (!BeginSourceFileAction(CI, InputFile))
goto failure;
+ // Initialize the main file entry.
+ if (!CI.InitializeSourceManager(CurrentInput))
+ goto failure;
+
return true;
}
@@ -240,7 +261,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
StringRef PCHInclude = PPOpts.ImplicitPCHInclude;
if (const DirectoryEntry *PCHDir = FileMgr.getDirectory(PCHInclude)) {
- llvm::error_code EC;
+ std::error_code EC;
SmallString<128> DirNative;
llvm::sys::path::native(PCHDir->getName(), DirNative);
bool Found = false;
@@ -265,7 +286,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
}
// Set up the preprocessor.
- CI.createPreprocessor();
+ CI.createPreprocessor(getTranslationUnitKind());
// Inform the diagnostic client we are processing a source file.
CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
@@ -276,13 +297,18 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!BeginSourceFileAction(CI, InputFile))
goto failure;
+ // Initialize the main file entry. It is important that this occurs after
+ // BeginSourceFileAction, which may change CurrentInput during module builds.
+ if (!CI.InitializeSourceManager(CurrentInput))
+ goto failure;
+
// Create the AST context and consumer unless this is a preprocessor only
// action.
if (!usesPreprocessorOnly()) {
CI.createASTContext();
- OwningPtr<ASTConsumer> Consumer(
- CreateWrappedASTConsumer(CI, InputFile));
+ std::unique_ptr<ASTConsumer> Consumer(
+ CreateWrappedASTConsumer(CI, InputFile));
if (!Consumer)
goto failure;
@@ -290,35 +316,40 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) {
// Convert headers to PCH and chain them.
- OwningPtr<ExternalASTSource> source;
- source.reset(ChainedIncludesSource::create(CI));
+ IntrusiveRefCntPtr<ExternalSemaSource> source, FinalReader;
+ source = createChainedIncludesSource(CI, FinalReader);
if (!source)
goto failure;
- CI.setModuleManager(static_cast<ASTReader*>(
- &static_cast<ChainedIncludesSource*>(source.get())->getFinalReader()));
+ CI.setModuleManager(static_cast<ASTReader *>(FinalReader.get()));
CI.getASTContext().setExternalSource(source);
-
} else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
// Use PCH.
assert(hasPCHSupport() && "This action does not have PCH support!");
ASTDeserializationListener *DeserialListener =
Consumer->GetASTDeserializationListener();
- if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls)
- DeserialListener = new DeserializedDeclsDumper(DeserialListener);
- if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty())
- DeserialListener = new DeserializedDeclsChecker(CI.getASTContext(),
- CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn,
- DeserialListener);
+ bool DeleteDeserialListener = false;
+ if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls) {
+ DeserialListener = new DeserializedDeclsDumper(DeserialListener,
+ DeleteDeserialListener);
+ DeleteDeserialListener = true;
+ }
+ if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty()) {
+ DeserialListener = new DeserializedDeclsChecker(
+ CI.getASTContext(),
+ CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn,
+ DeserialListener, DeleteDeserialListener);
+ DeleteDeserialListener = true;
+ }
CI.createPCHExternalASTSource(
- CI.getPreprocessorOpts().ImplicitPCHInclude,
- CI.getPreprocessorOpts().DisablePCHValidation,
- CI.getPreprocessorOpts().AllowPCHWithCompilerErrors,
- DeserialListener);
+ CI.getPreprocessorOpts().ImplicitPCHInclude,
+ CI.getPreprocessorOpts().DisablePCHValidation,
+ CI.getPreprocessorOpts().AllowPCHWithCompilerErrors, DeserialListener,
+ DeleteDeserialListener);
if (!CI.getASTContext().getExternalSource())
goto failure;
}
- CI.setASTConsumer(Consumer.take());
+ CI.setASTConsumer(Consumer.release());
if (!CI.hasASTConsumer())
goto failure;
}
@@ -327,50 +358,56 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// source.
if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
Preprocessor &PP = CI.getPreprocessor();
+
+ // If modules are enabled, create the module manager before creating
+ // any builtins, so that all declarations know that they might be
+ // extended by an external source.
+ if (CI.getLangOpts().Modules)
+ CI.createModuleManager();
+
PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
PP.getLangOpts());
+ } else {
+ // FIXME: If this is a problem, recover from it by creating a multiplex
+ // source.
+ assert((!CI.getLangOpts().Modules || CI.getModuleManager()) &&
+ "modules enabled but created an external source that "
+ "doesn't support modules");
}
// If there is a layout overrides file, attach an external AST source that
// provides the layouts from that file.
if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() &&
CI.hasASTContext() && !CI.getASTContext().getExternalSource()) {
- OwningPtr<ExternalASTSource>
+ IntrusiveRefCntPtr<ExternalASTSource>
Override(new LayoutOverrideSource(
CI.getFrontendOpts().OverrideRecordLayoutsFile));
CI.getASTContext().setExternalSource(Override);
}
-
+
return true;
// If we failed, reset state since the client will not end up calling the
// matching EndSourceFile().
failure:
if (isCurrentFileAST()) {
- CI.setASTContext(0);
- CI.setPreprocessor(0);
- CI.setSourceManager(0);
- CI.setFileManager(0);
+ CI.setASTContext(nullptr);
+ CI.setPreprocessor(nullptr);
+ CI.setSourceManager(nullptr);
+ CI.setFileManager(nullptr);
}
if (HasBegunSourceFile)
CI.getDiagnosticClient().EndSourceFile();
CI.clearOutputFiles(/*EraseFiles=*/true);
setCurrentInput(FrontendInputFile());
- setCompilerInstance(0);
+ setCompilerInstance(nullptr);
return false;
}
bool FrontendAction::Execute() {
CompilerInstance &CI = getCompilerInstance();
- // Initialize the main file entry. This needs to be delayed until after PCH
- // has loaded.
- if (!isCurrentFileAST()) {
- if (!CI.InitializeSourceManager(getCurrentInput()))
- return false;
- }
-
if (CI.hasFrontendTimer()) {
llvm::TimeRegion Timer(CI.getFrontendTimer());
ExecuteAction();
@@ -398,22 +435,22 @@ void FrontendAction::EndSourceFile() {
// Finalize the action.
EndSourceFileAction();
- // Release the consumer and the AST, in that order since the consumer may
- // perform actions in its destructor which require the context.
+ // Sema references the ast consumer, so reset sema first.
//
// FIXME: There is more per-file stuff we could just drop here?
- if (CI.getFrontendOpts().DisableFree) {
- CI.takeASTConsumer();
+ bool DisableFree = CI.getFrontendOpts().DisableFree;
+ if (DisableFree) {
if (!isCurrentFileAST()) {
- CI.takeSema();
+ CI.resetAndLeakSema();
CI.resetAndLeakASTContext();
}
+ BuryPointer(CI.takeASTConsumer());
} else {
if (!isCurrentFileAST()) {
- CI.setSema(0);
- CI.setASTContext(0);
+ CI.setSema(nullptr);
+ CI.setASTContext(nullptr);
}
- CI.setASTConsumer(0);
+ CI.setASTConsumer(nullptr);
}
// Inform the preprocessor we are done.
@@ -433,15 +470,16 @@ void FrontendAction::EndSourceFile() {
// FrontendAction.
CI.clearOutputFiles(/*EraseFiles=*/shouldEraseOutputFiles());
+ // FIXME: Only do this if DisableFree is set.
if (isCurrentFileAST()) {
- CI.takeSema();
+ CI.resetAndLeakSema();
CI.resetAndLeakASTContext();
CI.resetAndLeakPreprocessor();
CI.resetAndLeakSourceManager();
CI.resetAndLeakFileManager();
}
- setCompilerInstance(0);
+ setCompilerInstance(nullptr);
setCurrentInput(FrontendInputFile());
}
@@ -465,7 +503,7 @@ void ASTFrontendAction::ExecuteAction() {
CI.createCodeCompletionConsumer();
// Use a code completion consumer?
- CodeCompleteConsumer *CompletionConsumer = 0;
+ CodeCompleteConsumer *CompletionConsumer = nullptr;
if (CI.hasCodeCompletionConsumer())
CompletionConsumer = &CI.getCodeCompletionConsumer();
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index a3ab1be4a97a..6dcaf382c3c4 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -21,11 +21,11 @@
#include "clang/Parse/Parser.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ASTWriter.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/system_error.h"
+#include <memory>
+#include <system_error>
using namespace clang;
@@ -49,7 +49,7 @@ ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile))
return CreateASTPrinter(OS, CI.getFrontendOpts().ASTDumpFilter);
- return 0;
+ return nullptr;
}
ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI,
@@ -77,13 +77,14 @@ ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
std::string Sysroot;
std::string OutputFile;
- raw_ostream *OS = 0;
+ raw_ostream *OS = nullptr;
if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS))
- return 0;
+ return nullptr;
if (!CI.getFrontendOpts().RelocatablePCH)
Sysroot.clear();
- return new PCHGenerator(CI.getPreprocessor(), OutputFile, 0, Sysroot, OS);
+ return new PCHGenerator(CI.getPreprocessor(), OutputFile, nullptr, Sysroot,
+ OS);
}
bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
@@ -114,10 +115,10 @@ ASTConsumer *GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
std::string Sysroot;
std::string OutputFile;
- raw_ostream *OS = 0;
+ raw_ostream *OS = nullptr;
if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS))
- return 0;
-
+ return nullptr;
+
return new PCHGenerator(CI.getPreprocessor(), OutputFile, Module,
Sysroot, OS);
}
@@ -128,21 +129,38 @@ operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) {
return Includes;
}
-static void addHeaderInclude(StringRef HeaderName,
- SmallVectorImpl<char> &Includes,
- const LangOptions &LangOpts) {
+static std::error_code addHeaderInclude(StringRef HeaderName,
+ SmallVectorImpl<char> &Includes,
+ const LangOptions &LangOpts,
+ bool IsExternC) {
+ if (IsExternC && LangOpts.CPlusPlus)
+ Includes += "extern \"C\" {\n";
if (LangOpts.ObjC1)
Includes += "#import \"";
else
Includes += "#include \"";
- Includes += HeaderName;
+ // Use an absolute path for the include; there's no reason to think that
+ // a relative path will work (. might not be on our include path) or that
+ // it will find the same file.
+ if (llvm::sys::path::is_absolute(HeaderName)) {
+ Includes += HeaderName;
+ } else {
+ SmallString<256> Header = HeaderName;
+ if (std::error_code Err = llvm::sys::fs::make_absolute(Header))
+ return Err;
+ Includes += Header;
+ }
Includes += "\"\n";
+ if (IsExternC && LangOpts.CPlusPlus)
+ Includes += "}\n";
+ return std::error_code();
}
-static void addHeaderInclude(const FileEntry *Header,
- SmallVectorImpl<char> &Includes,
- const LangOptions &LangOpts) {
- addHeaderInclude(Header->getName(), Includes, LangOpts);
+static std::error_code addHeaderInclude(const FileEntry *Header,
+ SmallVectorImpl<char> &Includes,
+ const LangOptions &LangOpts,
+ bool IsExternC) {
+ return addHeaderInclude(Header->getName(), Includes, LangOpts, IsExternC);
}
/// \brief Collect the set of header includes needed to construct the given
@@ -152,20 +170,21 @@ static void addHeaderInclude(const FileEntry *Header,
///
/// \param Includes Will be augmented with the set of \#includes or \#imports
/// needed to load all of the named headers.
-static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
- FileManager &FileMgr,
- ModuleMap &ModMap,
- clang::Module *Module,
- SmallVectorImpl<char> &Includes) {
+static std::error_code
+collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr,
+ ModuleMap &ModMap, clang::Module *Module,
+ SmallVectorImpl<char> &Includes) {
// Don't collect any headers for unavailable modules.
if (!Module->isAvailable())
- return;
+ return std::error_code();
// Add includes for each of these headers.
for (unsigned I = 0, N = Module->NormalHeaders.size(); I != N; ++I) {
const FileEntry *Header = Module->NormalHeaders[I];
Module->addTopHeader(Header);
- addHeaderInclude(Header, Includes, LangOpts);
+ if (std::error_code Err =
+ addHeaderInclude(Header, Includes, LangOpts, Module->IsExternC))
+ return Err;
}
// Note that Module->PrivateHeaders will not be a TopHeader.
@@ -173,11 +192,13 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
Module->addTopHeader(UmbrellaHeader);
if (Module->Parent) {
// Include the umbrella header for submodules.
- addHeaderInclude(UmbrellaHeader, Includes, LangOpts);
+ if (std::error_code Err = addHeaderInclude(UmbrellaHeader, Includes,
+ LangOpts, Module->IsExternC))
+ return Err;
}
} else if (const DirectoryEntry *UmbrellaDir = Module->getUmbrellaDir()) {
// Add all of the headers we find in this subdirectory.
- llvm::error_code EC;
+ std::error_code EC;
SmallString<128> DirNative;
llvm::sys::path::native(UmbrellaDir->getName(), DirNative);
for (llvm::sys::fs::recursive_directory_iterator Dir(DirNative.str(), EC),
@@ -193,21 +214,30 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
// If this header is marked 'unavailable' in this module, don't include
// it.
if (const FileEntry *Header = FileMgr.getFile(Dir->path())) {
- if (ModMap.isHeaderInUnavailableModule(Header))
+ if (ModMap.isHeaderUnavailableInModule(Header, Module))
continue;
Module->addTopHeader(Header);
}
- // Include this header umbrella header for submodules.
- addHeaderInclude(Dir->path(), Includes, LangOpts);
+ // Include this header as part of the umbrella directory.
+ if (std::error_code Err = addHeaderInclude(Dir->path(), Includes,
+ LangOpts, Module->IsExternC))
+ return Err;
}
+
+ if (EC)
+ return EC;
}
// Recurse into submodules.
for (clang::Module::submodule_iterator Sub = Module->submodule_begin(),
SubEnd = Module->submodule_end();
Sub != SubEnd; ++Sub)
- collectModuleHeaderIncludes(LangOpts, FileMgr, ModMap, *Sub, Includes);
+ if (std::error_code Err = collectModuleHeaderIncludes(
+ LangOpts, FileMgr, ModMap, *Sub, Includes))
+ return Err;
+
+ return std::error_code();
}
bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
@@ -234,7 +264,15 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
// map with a single module (the common case).
return false;
}
-
+
+ // If we're being run from the command-line, the module build stack will not
+ // have been filled in yet, so complete it now in order to allow us to detect
+ // module cycles.
+ SourceManager &SourceMgr = CI.getSourceManager();
+ if (SourceMgr.getModuleBuildStack().empty())
+ SourceMgr.pushModuleBuildStack(CI.getLangOpts().CurrentModule,
+ FullSourceLoc(SourceLocation(), SourceMgr));
+
// Dig out the module definition.
Module = HS.lookupModule(CI.getLangOpts().CurrentModule,
/*AllowSearch=*/false);
@@ -247,28 +285,51 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
// Check whether we can build this module at all.
clang::Module::Requirement Requirement;
- if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement)) {
- CI.getDiagnostics().Report(diag::err_module_unavailable)
- << Module->getFullModuleName()
- << Requirement.second << Requirement.first;
+ clang::Module::HeaderDirective MissingHeader;
+ if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement,
+ MissingHeader)) {
+ if (MissingHeader.FileNameLoc.isValid()) {
+ CI.getDiagnostics().Report(MissingHeader.FileNameLoc,
+ diag::err_module_header_missing)
+ << MissingHeader.IsUmbrella << MissingHeader.FileName;
+ } else {
+ CI.getDiagnostics().Report(diag::err_module_unavailable)
+ << Module->getFullModuleName()
+ << Requirement.second << Requirement.first;
+ }
return false;
}
+ if (!ModuleMapForUniquing)
+ ModuleMapForUniquing = ModuleMap;
+ Module->ModuleMap = ModuleMapForUniquing;
+ assert(Module->ModuleMap && "missing module map file");
+
FileManager &FileMgr = CI.getFileManager();
// Collect the set of #includes we need to build the module.
SmallString<256> HeaderContents;
+ std::error_code Err = std::error_code();
if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader())
- addHeaderInclude(UmbrellaHeader, HeaderContents, CI.getLangOpts());
- collectModuleHeaderIncludes(CI.getLangOpts(), FileMgr,
- CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(),
- Module, HeaderContents);
+ Err = addHeaderInclude(UmbrellaHeader, HeaderContents, CI.getLangOpts(),
+ Module->IsExternC);
+ if (!Err)
+ Err = collectModuleHeaderIncludes(
+ CI.getLangOpts(), FileMgr,
+ CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), Module,
+ HeaderContents);
+
+ if (Err) {
+ CI.getDiagnostics().Report(diag::err_module_cannot_create_includes)
+ << Module->getFullModuleName() << Err.message();
+ return false;
+ }
llvm::MemoryBuffer *InputBuffer =
llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
Module::getModuleInputBufferName());
- // Ownership of InputBuffer will be transfered to the SourceManager.
+ // Ownership of InputBuffer will be transferred to the SourceManager.
setCurrentInput(FrontendInputFile(InputBuffer, getCurrentFileKind(),
Module->IsSystem));
return true;
@@ -283,10 +344,9 @@ bool GenerateModuleAction::ComputeASTConsumerArguments(CompilerInstance &CI,
// in the module cache.
if (CI.getFrontendOpts().OutputFile.empty()) {
HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
- SmallString<256> ModuleFileName(HS.getModuleCachePath());
- llvm::sys::path::append(ModuleFileName,
- CI.getLangOpts().CurrentModule + ".pcm");
- CI.getFrontendOpts().OutputFile = ModuleFileName.str();
+ CI.getFrontendOpts().OutputFile =
+ HS.getModuleFileName(CI.getLangOpts().CurrentModule,
+ ModuleMapForUniquing->getName());
}
// We use createOutputFile here because this is exposed via libclang, and we
@@ -313,6 +373,30 @@ ASTConsumer *DumpModuleInfoAction::CreateASTConsumer(CompilerInstance &CI,
return new ASTConsumer();
}
+ASTConsumer *VerifyPCHAction::CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ return new ASTConsumer();
+}
+
+void VerifyPCHAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ bool Preamble = CI.getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
+ const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot;
+ std::unique_ptr<ASTReader> Reader(
+ new ASTReader(CI.getPreprocessor(), CI.getASTContext(),
+ Sysroot.empty() ? "" : Sysroot.c_str(),
+ /*DisableValidation*/ false,
+ /*AllowPCHWithCompilerErrors*/ false,
+ /*AllowConfigurationMismatch*/ true,
+ /*ValidateSystemInputs*/ true));
+
+ Reader->ReadAST(getCurrentFile(),
+ Preamble ? serialization::MK_Preamble
+ : serialization::MK_PCH,
+ SourceLocation(),
+ ASTReader::ARR_ConfigurationMismatch);
+}
+
namespace {
/// \brief AST reader listener that dumps module information for a module
/// file.
@@ -325,7 +409,7 @@ namespace {
#define DUMP_BOOLEAN(Value, Text) \
Out.indent(4) << Text << ": " << (Value? "Yes" : "No") << "\n"
- virtual bool ReadFullVersionInformation(StringRef FullVersion) {
+ bool ReadFullVersionInformation(StringRef FullVersion) override {
Out.indent(2)
<< "Generated by "
<< (FullVersion == getClangFullRepositoryVersion()? "this"
@@ -334,8 +418,15 @@ namespace {
return ASTReaderListener::ReadFullVersionInformation(FullVersion);
}
- virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
- bool Complain) {
+ void ReadModuleName(StringRef ModuleName) override {
+ Out.indent(2) << "Module name: " << ModuleName << "\n";
+ }
+ void ReadModuleMapFile(StringRef ModuleMapPath) override {
+ Out.indent(2) << "Module map file: " << ModuleMapPath << "\n";
+ }
+
+ bool ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain) override {
Out.indent(2) << "Language options:\n";
#define LANGOPT(Name, Bits, Default, Description) \
DUMP_BOOLEAN(LangOpts.Name, Description);
@@ -350,14 +441,12 @@ namespace {
return false;
}
- virtual bool ReadTargetOptions(const TargetOptions &TargetOpts,
- bool Complain) {
+ bool ReadTargetOptions(const TargetOptions &TargetOpts,
+ bool Complain) override {
Out.indent(2) << "Target options:\n";
Out.indent(4) << " Triple: " << TargetOpts.Triple << "\n";
Out.indent(4) << " CPU: " << TargetOpts.CPU << "\n";
Out.indent(4) << " ABI: " << TargetOpts.ABI << "\n";
- Out.indent(4) << " C++ ABI: " << TargetOpts.CXXABI << "\n";
- Out.indent(4) << " Linker version: " << TargetOpts.LinkerVersion << "\n";
if (!TargetOpts.FeaturesAsWritten.empty()) {
Out.indent(4) << "Target features:\n";
@@ -370,8 +459,28 @@ namespace {
return false;
}
- virtual bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
- bool Complain) {
+ virtual bool
+ ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
+ bool Complain) override {
+ Out.indent(2) << "Diagnostic options:\n";
+#define DIAGOPT(Name, Bits, Default) DUMP_BOOLEAN(DiagOpts->Name, #Name);
+#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
+ Out.indent(4) << #Name << ": " << DiagOpts->get##Name() << "\n";
+#define VALUE_DIAGOPT(Name, Bits, Default) \
+ Out.indent(4) << #Name << ": " << DiagOpts->Name << "\n";
+#include "clang/Basic/DiagnosticOptions.def"
+
+ Out.indent(4) << "Diagnostic flags:\n";
+ for (const std::string &Warning : DiagOpts->Warnings)
+ Out.indent(6) << "-W" << Warning << "\n";
+ for (const std::string &Remark : DiagOpts->Remarks)
+ Out.indent(6) << "-R" << Remark << "\n";
+
+ return false;
+ }
+
+ bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
+ bool Complain) override {
Out.indent(2) << "Header search options:\n";
Out.indent(4) << "System root [-isysroot=]: '" << HSOpts.Sysroot << "'\n";
DUMP_BOOLEAN(HSOpts.UseBuiltinIncludes,
@@ -385,9 +494,9 @@ namespace {
return false;
}
- virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
- bool Complain,
- std::string &SuggestedPredefines) {
+ bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ bool Complain,
+ std::string &SuggestedPredefines) override {
Out.indent(2) << "Preprocessor options:\n";
DUMP_BOOLEAN(PPOpts.UsePredefines,
"Uses compiler/target-specific predefines [-undef]");
@@ -416,12 +525,12 @@ namespace {
void DumpModuleInfoAction::ExecuteAction() {
// Set up the output file.
- llvm::OwningPtr<llvm::raw_fd_ostream> OutFile;
+ std::unique_ptr<llvm::raw_fd_ostream> OutFile;
StringRef OutputFileName = getCompilerInstance().getFrontendOpts().OutputFile;
if (!OutputFileName.empty() && OutputFileName != "-") {
std::string ErrorInfo;
OutFile.reset(new llvm::raw_fd_ostream(OutputFileName.str().c_str(),
- ErrorInfo));
+ ErrorInfo, llvm::sys::fs::F_Text));
}
llvm::raw_ostream &Out = OutFile.get()? *OutFile.get() : llvm::outs();
@@ -485,7 +594,7 @@ void PreprocessOnlyAction::ExecuteAction() {
Preprocessor &PP = getCompilerInstance().getPreprocessor();
// Ignore unknown pragmas.
- PP.AddPragmaHandler(new EmptyPragmaHandler());
+ PP.IgnorePragmas();
Token Tok;
// Start parsing the specified input file.
diff --git a/lib/Frontend/HeaderIncludeGen.cpp b/lib/Frontend/HeaderIncludeGen.cpp
index 237e5b1ac0c6..a2f5896746af 100644
--- a/lib/Frontend/HeaderIncludeGen.cpp
+++ b/lib/Frontend/HeaderIncludeGen.cpp
@@ -40,23 +40,24 @@ public:
delete OutputFile;
}
- virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
- SrcMgr::CharacteristicKind FileType,
- FileID PrevFID);
+ void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) override;
};
}
void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders,
StringRef OutputPath, bool ShowDepth,
bool MSStyle) {
- raw_ostream *OutputFile = &llvm::errs();
+ raw_ostream *OutputFile = MSStyle ? &llvm::outs() : &llvm::errs();
bool OwnsOutputFile = false;
// Open the output file, if used.
if (!OutputPath.empty()) {
std::string Error;
llvm::raw_fd_ostream *OS = new llvm::raw_fd_ostream(
- OutputPath.str().c_str(), Error, llvm::sys::fs::F_Append);
+ OutputPath.str().c_str(), Error,
+ llvm::sys::fs::F_Append | llvm::sys::fs::F_Text);
if (!Error.empty()) {
PP.getDiagnostics().Report(
clang::diag::warn_fe_cc_print_header_failure) << Error;
@@ -130,5 +131,6 @@ void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
Msg += '\n';
OutputFile->write(Msg.data(), Msg.size());
+ OutputFile->flush();
}
}
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index d144cbb8945d..d2edc9479f6b 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -110,7 +110,7 @@ public:
} // end anonymous namespace.
static bool CanPrefixSysroot(StringRef Path) {
-#if defined(_WIN32)
+#if defined(LLVM_ON_WIN32)
return !Path.empty() && llvm::sys::path::is_separator(Path[0]);
#else
return llvm::sys::path::is_absolute(Path);
@@ -268,7 +268,6 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
switch (os) {
case llvm::Triple::Linux:
- case llvm::Triple::Win32:
llvm_unreachable("Include management is handled in the driver.");
case llvm::Triple::Haiku:
@@ -307,10 +306,13 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
break;
case llvm::Triple::RTEMS:
break;
- case llvm::Triple::Cygwin:
- AddPath("/usr/include/w32api", System, false);
- break;
- case llvm::Triple::MinGW32: {
+ case llvm::Triple::Win32:
+ switch (triple.getEnvironment()) {
+ default: llvm_unreachable("Include management is handled in the driver.");
+ case llvm::Triple::Cygnus:
+ AddPath("/usr/include/w32api", System, false);
+ break;
+ case llvm::Triple::GNU:
// mingw-w64 crt include paths
// <sysroot>/i686-w64-mingw32/include
SmallString<128> P = StringRef(HSOpts.ResourceDir);
@@ -328,12 +330,12 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
llvm::sys::path::append(P, "../../../include");
AddPath(P.str(), System, false);
AddPath("/mingw/include", System, false);
-#if defined(_WIN32)
+#if defined(LLVM_ON_WIN32)
AddPath("c:/mingw/include", System, false);
#endif
+ break;
}
break;
-
default:
break;
}
@@ -376,58 +378,58 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1",
"arm-apple-darwin10", "v6", "", triple);
break;
+
+ case llvm::Triple::aarch64:
+ case llvm::Triple::arm64:
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1",
+ "arm64-apple-darwin10", "", "", triple);
+ break;
}
return;
}
switch (os) {
case llvm::Triple::Linux:
- case llvm::Triple::Win32:
llvm_unreachable("Include management is handled in the driver.");
- case llvm::Triple::Cygwin:
- // Cygwin-1.7
- AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.7.3");
- AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.5.3");
- AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.4");
- // g++-4 / Cygwin-1.5
- AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.2");
- break;
- case llvm::Triple::MinGW32:
- // 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.5.4");
- AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.6.0");
- AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.6.1");
- AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.6.2");
- AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.6.3");
- AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.7.0");
- // mingw.org C++ include paths
- AddMinGWCPlusPlusIncludePaths("/mingw/lib/gcc", "mingw32", "4.5.2"); //MSYS
-#if defined(_WIN32)
- AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.8.1");
- AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.6.2");
- AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.6.1");
- AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.2");
- AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0");
- AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0");
- AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0");
+ case llvm::Triple::Win32:
+ switch (triple.getEnvironment()) {
+ default: llvm_unreachable("Include management is handled in the driver.");
+ case llvm::Triple::Cygnus:
+ // Cygwin-1.7
+ AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.7.3");
+ AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.5.3");
+ AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.4");
+ // g++-4 / Cygwin-1.5
+ AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.2");
+ break;
+ case llvm::Triple::GNU:
+ // mingw-w64 C++ include paths (i686-w64-mingw32 and x86_64-w64-mingw32)
+ AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.7.0");
+ AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.7.1");
+ AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.7.2");
+ AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.7.3");
+ AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.8.0");
+ AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.8.1");
+ AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.8.2");
+ // mingw.org C++ include paths
+#if defined(LLVM_ON_WIN32)
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.7.0");
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.7.1");
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.7.2");
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.7.3");
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.8.0");
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.8.1");
+ AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.8.2");
#endif
- break;
+ break;
+ }
case llvm::Triple::DragonFly:
if (llvm::sys::fs::exists("/usr/lib/gcc47"))
AddPath("/usr/include/c++/4.7", CXXSystem, false);
else
AddPath("/usr/include/c++/4.4", CXXSystem, false);
break;
- case llvm::Triple::FreeBSD:
- // FreeBSD 8.0
- // FreeBSD 7.3
- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", "", "", "", triple);
- break;
case llvm::Triple::OpenBSD: {
std::string t = triple.getTriple();
if (t.substr(0, 6) == "x86_64")
@@ -466,8 +468,14 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
break; // Everything else continues to use this routine's logic.
case llvm::Triple::Linux:
- case llvm::Triple::Win32:
return;
+
+ case llvm::Triple::Win32:
+ if (triple.getEnvironment() == llvm::Triple::MSVC ||
+ triple.getEnvironment() == llvm::Triple::Itanium ||
+ triple.getObjectFormat() == llvm::Triple::MachO)
+ return;
+ break;
}
if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes &&
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index c7d25509e595..7a9d09a5e7ac 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -86,7 +86,7 @@ static void AddImplicitIncludePTH(MacroBuilder &Builder, Preprocessor &PP,
StringRef ImplicitIncludePTH) {
PTHManager *P = PP.getPTHManager();
// Null check 'P' in the corner case where it couldn't be created.
- const char *OriginalFile = P ? P->getOriginalSourceFile() : 0;
+ const char *OriginalFile = P ? P->getOriginalSourceFile() : nullptr;
if (!OriginalFile) {
PP.getDiagnostics().Report(diag::err_fe_pth_file_has_no_source_header)
@@ -180,7 +180,7 @@ static void DefineFloatMacros(MacroBuilder &Builder, StringRef Prefix,
/// DefineTypeSize - Emit a macro to the predefines buffer that declares a macro
/// named MacroName with the max value for a type with width 'TypeWidth' a
/// signedness of 'isSigned' and with a value suffix of 'ValSuffix' (e.g. LL).
-static void DefineTypeSize(StringRef MacroName, unsigned TypeWidth,
+static void DefineTypeSize(const Twine &MacroName, unsigned TypeWidth,
StringRef ValSuffix, bool isSigned,
MacroBuilder &Builder) {
llvm::APInt MaxVal = isSigned ? llvm::APInt::getSignedMaxValue(TypeWidth)
@@ -190,12 +190,22 @@ static void DefineTypeSize(StringRef MacroName, unsigned TypeWidth,
/// DefineTypeSize - An overloaded helper that uses TargetInfo to determine
/// the width, suffix, and signedness of the given type
-static void DefineTypeSize(StringRef MacroName, TargetInfo::IntType Ty,
+static void DefineTypeSize(const Twine &MacroName, TargetInfo::IntType Ty,
const TargetInfo &TI, MacroBuilder &Builder) {
DefineTypeSize(MacroName, TI.getTypeWidth(Ty), TI.getTypeConstantSuffix(Ty),
TI.isTypeSigned(Ty), Builder);
}
+static void DefineFmt(const Twine &Prefix, TargetInfo::IntType Ty,
+ const TargetInfo &TI, MacroBuilder &Builder) {
+ bool IsSigned = TI.isTypeSigned(Ty);
+ StringRef FmtModifier = TI.getTypeFormatModifier(Ty);
+ for (const char *Fmt = IsSigned ? "di" : "ouxX"; *Fmt; ++Fmt) {
+ Builder.defineMacro(Prefix + "_FMT" + Twine(*Fmt) + "__",
+ Twine("\"") + FmtModifier + Twine(*Fmt) + "\"");
+ }
+}
+
static void DefineType(const Twine &MacroName, TargetInfo::IntType Ty,
MacroBuilder &Builder) {
Builder.defineMacro(MacroName, TargetInfo::getTypeName(Ty));
@@ -212,23 +222,70 @@ static void DefineTypeSizeof(StringRef MacroName, unsigned BitWidth,
Twine(BitWidth / TI.getCharWidth()));
}
-static void DefineExactWidthIntType(TargetInfo::IntType Ty,
- const TargetInfo &TI, MacroBuilder &Builder) {
+static void DefineExactWidthIntType(TargetInfo::IntType Ty,
+ const TargetInfo &TI,
+ MacroBuilder &Builder) {
+ int TypeWidth = TI.getTypeWidth(Ty);
+ bool IsSigned = TI.isTypeSigned(Ty);
+
+ // Use the target specified int64 type, when appropriate, so that [u]int64_t
+ // ends up being defined in terms of the correct type.
+ if (TypeWidth == 64)
+ Ty = IsSigned ? TI.getInt64Type() : TI.getUInt64Type();
+
+ const char *Prefix = IsSigned ? "__INT" : "__UINT";
+
+ DefineType(Prefix + Twine(TypeWidth) + "_TYPE__", Ty, Builder);
+ DefineFmt(Prefix + Twine(TypeWidth), Ty, TI, Builder);
+
+ StringRef ConstSuffix(TI.getTypeConstantSuffix(Ty));
+ Builder.defineMacro(Prefix + Twine(TypeWidth) + "_C_SUFFIX__", ConstSuffix);
+}
+
+static void DefineExactWidthIntTypeSize(TargetInfo::IntType Ty,
+ const TargetInfo &TI,
+ MacroBuilder &Builder) {
int TypeWidth = TI.getTypeWidth(Ty);
+ bool IsSigned = TI.isTypeSigned(Ty);
// Use the target specified int64 type, when appropriate, so that [u]int64_t
// ends up being defined in terms of the correct type.
if (TypeWidth == 64)
- Ty = TI.getInt64Type();
+ Ty = IsSigned ? TI.getInt64Type() : TI.getUInt64Type();
+
+ const char *Prefix = IsSigned ? "__INT" : "__UINT";
+ DefineTypeSize(Prefix + Twine(TypeWidth) + "_MAX__", Ty, TI, Builder);
+}
+
+static void DefineLeastWidthIntType(unsigned TypeWidth, bool IsSigned,
+ const TargetInfo &TI,
+ MacroBuilder &Builder) {
+ TargetInfo::IntType Ty = TI.getLeastIntTypeByWidth(TypeWidth, IsSigned);
+ if (Ty == TargetInfo::NoInt)
+ return;
+
+ const char *Prefix = IsSigned ? "__INT_LEAST" : "__UINT_LEAST";
+ DefineType(Prefix + Twine(TypeWidth) + "_TYPE__", Ty, Builder);
+ DefineTypeSize(Prefix + Twine(TypeWidth) + "_MAX__", Ty, TI, Builder);
+ DefineFmt(Prefix + Twine(TypeWidth), Ty, TI, Builder);
+}
+
+static void DefineFastIntType(unsigned TypeWidth, bool IsSigned,
+ const TargetInfo &TI, MacroBuilder &Builder) {
+ // stdint.h currently defines the fast int types as equivalent to the least
+ // types.
+ TargetInfo::IntType Ty = TI.getLeastIntTypeByWidth(TypeWidth, IsSigned);
+ if (Ty == TargetInfo::NoInt)
+ return;
- DefineType("__INT" + Twine(TypeWidth) + "_TYPE__", Ty, Builder);
+ const char *Prefix = IsSigned ? "__INT_FAST" : "__UINT_FAST";
+ DefineType(Prefix + Twine(TypeWidth) + "_TYPE__", Ty, Builder);
+ DefineTypeSize(Prefix + Twine(TypeWidth) + "_MAX__", Ty, TI, Builder);
- StringRef ConstSuffix(TargetInfo::getTypeConstantSuffix(Ty));
- if (!ConstSuffix.empty())
- Builder.defineMacro("__INT" + Twine(TypeWidth) + "_C_SUFFIX__",
- ConstSuffix);
+ DefineFmt(Prefix + Twine(TypeWidth), Ty, TI, Builder);
}
+
/// Get the value the ATOMIC_*_LOCK_FREE macro should have for a type with
/// the specified properties.
static const char *getLockFreeValue(unsigned TypeWidth, unsigned TypeAlign,
@@ -300,7 +357,7 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
const LangOptions &LangOpts,
const FrontendOptions &FEOpts,
MacroBuilder &Builder) {
- if (!LangOpts.MicrosoftMode && !LangOpts.TraditionalCPP)
+ if (!LangOpts.MSVCCompat && !LangOpts.TraditionalCPP)
Builder.defineMacro("__STDC__");
if (LangOpts.Freestanding)
Builder.defineMacro("__STDC_HOSTED__", "0");
@@ -315,9 +372,14 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
else if (!LangOpts.GNUMode && LangOpts.Digraphs)
Builder.defineMacro("__STDC_VERSION__", "199409L");
} else {
- // FIXME: Use the right value for __cplusplus for C++1y once one is chosen.
- if (LangOpts.CPlusPlus1y)
- Builder.defineMacro("__cplusplus", "201305L");
+ // FIXME: Use correct value for C++17.
+ if (LangOpts.CPlusPlus1z)
+ Builder.defineMacro("__cplusplus", "201406L");
+ // C++1y [cpp.predefined]p1:
+ // The name __cplusplus is defined to the value 201402L when compiling a
+ // C++ translation unit.
+ else if (LangOpts.CPlusPlus1y)
+ Builder.defineMacro("__cplusplus", "201402L");
// C++11 [cpp.predefined]p1:
// The name __cplusplus is defined to the value 201103L when compiling a
// C++ translation unit.
@@ -399,7 +461,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
+ getClangFullRepositoryVersion() + "\"");
#undef TOSTR
#undef TOSTR2
- if (!LangOpts.MicrosoftMode) {
+ if (!LangOpts.MSVCCompat) {
// Currently claim to be compatible with GCC 4.2.1-5621, but only if we're
// not compiling for MSVC compatibility
Builder.defineMacro("__GNUC_MINOR__", "2");
@@ -428,10 +490,10 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// Initialize language-specific preprocessor defines.
// Standard conforming mode?
- if (!LangOpts.GNUMode)
+ if (!LangOpts.GNUMode && !LangOpts.MSVCCompat)
Builder.defineMacro("__STRICT_ANSI__");
- if (LangOpts.CPlusPlus11)
+ if (!LangOpts.MSVCCompat && LangOpts.CPlusPlus11)
Builder.defineMacro("__GXX_EXPERIMENTAL_CXX0X__");
if (LangOpts.ObjC1) {
@@ -489,9 +551,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__BLOCKS__");
}
- if (LangOpts.CXXExceptions)
+ if (!LangOpts.MSVCCompat && LangOpts.CXXExceptions)
Builder.defineMacro("__EXCEPTIONS");
- if (LangOpts.RTTI)
+ if (!LangOpts.MSVCCompat && LangOpts.RTTI)
Builder.defineMacro("__GXX_RTTI");
if (LangOpts.SjLjExceptions)
Builder.defineMacro("__USING_SJLJ_EXCEPTIONS__");
@@ -499,27 +561,18 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (LangOpts.Deprecated)
Builder.defineMacro("__DEPRECATED");
- if (LangOpts.CPlusPlus) {
+ if (!LangOpts.MSVCCompat && LangOpts.CPlusPlus) {
Builder.defineMacro("__GNUG__", "4");
Builder.defineMacro("__GXX_WEAK__");
Builder.defineMacro("__private_extern__", "extern");
}
if (LangOpts.MicrosoftExt) {
- // Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however
- // VC++ appears to only like __FUNCTION__.
- Builder.defineMacro("__PRETTY_FUNCTION__", "__FUNCTION__");
- // Work around some issues with Visual C++ headers.
if (LangOpts.WChar) {
// wchar_t supported as a keyword.
Builder.defineMacro("_WCHAR_T_DEFINED");
Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED");
}
- if (LangOpts.CPlusPlus) {
- // FIXME: Support Microsoft's __identifier extension in the lexer.
- Builder.append("#define __identifier(x) x");
- Builder.append("class type_info;");
- }
}
if (LangOpts.Optimize)
@@ -540,11 +593,13 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__ORDER_LITTLE_ENDIAN__", "1234");
Builder.defineMacro("__ORDER_BIG_ENDIAN__", "4321");
Builder.defineMacro("__ORDER_PDP_ENDIAN__", "3412");
- if (TI.isBigEndian())
+ if (TI.isBigEndian()) {
Builder.defineMacro("__BYTE_ORDER__", "__ORDER_BIG_ENDIAN__");
- else
+ Builder.defineMacro("__BIG_ENDIAN__");
+ } else {
Builder.defineMacro("__BYTE_ORDER__", "__ORDER_LITTLE_ENDIAN__");
-
+ Builder.defineMacro("__LITTLE_ENDIAN__");
+ }
if (TI.getPointerWidth(0) == 64 && TI.getLongWidth() == 64
&& TI.getIntWidth() == 32) {
@@ -552,6 +607,12 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__LP64__");
}
+ if (TI.getPointerWidth(0) == 32 && TI.getLongWidth() == 32
+ && TI.getIntWidth() == 32) {
+ Builder.defineMacro("_ILP32");
+ Builder.defineMacro("__ILP32__");
+ }
+
// Define type sizing macros based on the target properties.
assert(TI.getCharWidth() == 8 && "Only support 8-bit char so far");
Builder.defineMacro("__CHAR_BIT__", "8");
@@ -565,6 +626,13 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Builder);
DefineTypeSize("__SIZE_MAX__", TI.getSizeType(), TI, Builder);
+ if (!LangOpts.MSVCCompat) {
+ DefineTypeSize("__UINTMAX_MAX__", TI.getUIntMaxType(), TI, Builder);
+ DefineTypeSize("__PTRDIFF_MAX__", TI.getPtrDiffType(0), TI, Builder);
+ DefineTypeSize("__INTPTR_MAX__", TI.getIntPtrType(), TI, Builder);
+ DefineTypeSize("__UINTPTR_MAX__", TI.getUIntPtrType(), TI, Builder);
+ }
+
DefineTypeSizeof("__SIZEOF_DOUBLE__", TI.getDoubleWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_FLOAT__", TI.getFloatWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_INT__", TI.getIntWidth(), TI, Builder);
@@ -585,22 +653,39 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineTypeSizeof("__SIZEOF_INT128__", 128, TI, Builder);
DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Builder);
+ DefineFmt("__INTMAX", TI.getIntMaxType(), TI, Builder);
+ Builder.defineMacro("__INTMAX_C_SUFFIX__",
+ TI.getTypeConstantSuffix(TI.getIntMaxType()));
DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Builder);
+ DefineFmt("__UINTMAX", TI.getUIntMaxType(), TI, Builder);
+ Builder.defineMacro("__UINTMAX_C_SUFFIX__",
+ TI.getTypeConstantSuffix(TI.getUIntMaxType()));
DefineTypeWidth("__INTMAX_WIDTH__", TI.getIntMaxType(), TI, Builder);
DefineType("__PTRDIFF_TYPE__", TI.getPtrDiffType(0), Builder);
+ DefineFmt("__PTRDIFF", TI.getPtrDiffType(0), TI, Builder);
DefineTypeWidth("__PTRDIFF_WIDTH__", TI.getPtrDiffType(0), TI, Builder);
DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Builder);
+ DefineFmt("__INTPTR", TI.getIntPtrType(), TI, Builder);
DefineTypeWidth("__INTPTR_WIDTH__", TI.getIntPtrType(), TI, Builder);
DefineType("__SIZE_TYPE__", TI.getSizeType(), Builder);
+ DefineFmt("__SIZE", TI.getSizeType(), TI, Builder);
DefineTypeWidth("__SIZE_WIDTH__", TI.getSizeType(), TI, Builder);
DefineType("__WCHAR_TYPE__", TI.getWCharType(), Builder);
DefineTypeWidth("__WCHAR_WIDTH__", TI.getWCharType(), TI, Builder);
DefineType("__WINT_TYPE__", TI.getWIntType(), Builder);
DefineTypeWidth("__WINT_WIDTH__", TI.getWIntType(), TI, Builder);
DefineTypeWidth("__SIG_ATOMIC_WIDTH__", TI.getSigAtomicType(), TI, Builder);
+ DefineTypeSize("__SIG_ATOMIC_MAX__", TI.getSigAtomicType(), TI, Builder);
DefineType("__CHAR16_TYPE__", TI.getChar16Type(), Builder);
DefineType("__CHAR32_TYPE__", TI.getChar32Type(), Builder);
+ if (!LangOpts.MSVCCompat) {
+ DefineTypeWidth("__UINTMAX_WIDTH__", TI.getUIntMaxType(), TI, Builder);
+ DefineType("__UINTPTR_TYPE__", TI.getUIntPtrType(), Builder);
+ DefineFmt("__UINTPTR", TI.getUIntPtrType(), TI, Builder);
+ DefineTypeWidth("__UINTPTR_WIDTH__", TI.getUIntPtrType(), TI, Builder);
+ }
+
DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat(), "F");
DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat(), "");
DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat(), "L");
@@ -619,8 +704,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__WINT_UNSIGNED__");
// Define exact-width integer types for stdint.h
- Builder.defineMacro("__INT" + Twine(TI.getCharWidth()) + "_TYPE__",
- "char");
+ DefineExactWidthIntType(TargetInfo::SignedChar, TI, Builder);
if (TI.getShortWidth() > TI.getCharWidth())
DefineExactWidthIntType(TargetInfo::SignedShort, TI, Builder);
@@ -634,6 +718,54 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (TI.getLongLongWidth() > TI.getLongWidth())
DefineExactWidthIntType(TargetInfo::SignedLongLong, TI, Builder);
+ if (!LangOpts.MSVCCompat) {
+ DefineExactWidthIntType(TargetInfo::UnsignedChar, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::UnsignedChar, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::SignedChar, TI, Builder);
+
+ if (TI.getShortWidth() > TI.getCharWidth()) {
+ DefineExactWidthIntType(TargetInfo::UnsignedShort, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::UnsignedShort, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::SignedShort, TI, Builder);
+ }
+
+ if (TI.getIntWidth() > TI.getShortWidth()) {
+ DefineExactWidthIntType(TargetInfo::UnsignedInt, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::UnsignedInt, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::SignedInt, TI, Builder);
+ }
+
+ if (TI.getLongWidth() > TI.getIntWidth()) {
+ DefineExactWidthIntType(TargetInfo::UnsignedLong, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::UnsignedLong, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::SignedLong, TI, Builder);
+ }
+
+ if (TI.getLongLongWidth() > TI.getLongWidth()) {
+ DefineExactWidthIntType(TargetInfo::UnsignedLongLong, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::UnsignedLongLong, TI, Builder);
+ DefineExactWidthIntTypeSize(TargetInfo::SignedLongLong, TI, Builder);
+ }
+
+ DefineLeastWidthIntType(8, true, TI, Builder);
+ DefineLeastWidthIntType(8, false, TI, Builder);
+ DefineLeastWidthIntType(16, true, TI, Builder);
+ DefineLeastWidthIntType(16, false, TI, Builder);
+ DefineLeastWidthIntType(32, true, TI, Builder);
+ DefineLeastWidthIntType(32, false, TI, Builder);
+ DefineLeastWidthIntType(64, true, TI, Builder);
+ DefineLeastWidthIntType(64, false, TI, Builder);
+
+ DefineFastIntType(8, true, TI, Builder);
+ DefineFastIntType(8, false, TI, Builder);
+ DefineFastIntType(16, true, TI, Builder);
+ DefineFastIntType(16, false, TI, Builder);
+ DefineFastIntType(32, true, TI, Builder);
+ DefineFastIntType(32, false, TI, Builder);
+ DefineFastIntType(64, true, TI, Builder);
+ DefineFastIntType(64, false, TI, Builder);
+ }
+
if (const char *Prefix = TI.getUserLabelPrefix())
Builder.defineMacro("__USER_LABEL_PREFIX__", Prefix);
@@ -642,36 +774,38 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
else
Builder.defineMacro("__FINITE_MATH_ONLY__", "0");
- if (LangOpts.GNUInline)
- Builder.defineMacro("__GNUC_GNU_INLINE__");
- else
- Builder.defineMacro("__GNUC_STDC_INLINE__");
+ if (!LangOpts.MSVCCompat) {
+ if (LangOpts.GNUInline)
+ Builder.defineMacro("__GNUC_GNU_INLINE__");
+ else
+ Builder.defineMacro("__GNUC_STDC_INLINE__");
- // The value written by __atomic_test_and_set.
- // FIXME: This is target-dependent.
- Builder.defineMacro("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1");
+ // The value written by __atomic_test_and_set.
+ // FIXME: This is target-dependent.
+ Builder.defineMacro("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1");
- // Used by libstdc++ to implement ATOMIC_<foo>_LOCK_FREE.
- unsigned InlineWidthBits = TI.getMaxAtomicInlineWidth();
+ // Used by libstdc++ to implement ATOMIC_<foo>_LOCK_FREE.
+ unsigned InlineWidthBits = TI.getMaxAtomicInlineWidth();
#define DEFINE_LOCK_FREE_MACRO(TYPE, Type) \
- Builder.defineMacro("__GCC_ATOMIC_" #TYPE "_LOCK_FREE", \
- getLockFreeValue(TI.get##Type##Width(), \
- TI.get##Type##Align(), \
- InlineWidthBits));
- DEFINE_LOCK_FREE_MACRO(BOOL, Bool);
- DEFINE_LOCK_FREE_MACRO(CHAR, Char);
- DEFINE_LOCK_FREE_MACRO(CHAR16_T, Char16);
- DEFINE_LOCK_FREE_MACRO(CHAR32_T, Char32);
- DEFINE_LOCK_FREE_MACRO(WCHAR_T, WChar);
- DEFINE_LOCK_FREE_MACRO(SHORT, Short);
- DEFINE_LOCK_FREE_MACRO(INT, Int);
- DEFINE_LOCK_FREE_MACRO(LONG, Long);
- DEFINE_LOCK_FREE_MACRO(LLONG, LongLong);
- Builder.defineMacro("__GCC_ATOMIC_POINTER_LOCK_FREE",
- getLockFreeValue(TI.getPointerWidth(0),
- TI.getPointerAlign(0),
- InlineWidthBits));
+ Builder.defineMacro("__GCC_ATOMIC_" #TYPE "_LOCK_FREE", \
+ getLockFreeValue(TI.get##Type##Width(), \
+ TI.get##Type##Align(), \
+ InlineWidthBits));
+ DEFINE_LOCK_FREE_MACRO(BOOL, Bool);
+ DEFINE_LOCK_FREE_MACRO(CHAR, Char);
+ DEFINE_LOCK_FREE_MACRO(CHAR16_T, Char16);
+ DEFINE_LOCK_FREE_MACRO(CHAR32_T, Char32);
+ DEFINE_LOCK_FREE_MACRO(WCHAR_T, WChar);
+ DEFINE_LOCK_FREE_MACRO(SHORT, Short);
+ DEFINE_LOCK_FREE_MACRO(INT, Int);
+ DEFINE_LOCK_FREE_MACRO(LONG, Long);
+ DEFINE_LOCK_FREE_MACRO(LLONG, LongLong);
+ Builder.defineMacro("__GCC_ATOMIC_POINTER_LOCK_FREE",
+ getLockFreeValue(TI.getPointerWidth(0),
+ TI.getPointerAlign(0),
+ InlineWidthBits));
#undef DEFINE_LOCK_FREE_MACRO
+ }
if (LangOpts.NoInlineDefine)
Builder.defineMacro("__NO_INLINE__");
@@ -693,8 +827,10 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (LangOpts.getStackProtector() == LangOptions::SSPOn)
Builder.defineMacro("__SSP__");
+ else if (LangOpts.getStackProtector() == LangOptions::SSPStrong)
+ Builder.defineMacro("__SSP_STRONG__", "2");
else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
- Builder.defineMacro("__SSP_ALL__", "2");
+ Builder.defineMacro("__SSP_ALL__", "3");
if (FEOpts.ProgramAction == frontend::RewriteObjC)
Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
@@ -717,86 +853,23 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// OpenMP definition
if (LangOpts.OpenMP) {
- // OpenMP 2.2:
+ // OpenMP 2.2:
// In implementations that support a preprocessor, the _OPENMP
// macro name is defined to have the decimal value yyyymm where
// yyyy and mm are the year and the month designations of the
// version of the OpenMP API that the implementation support.
- Builder.defineMacro("_OPENMP", "201107");
+ Builder.defineMacro("_OPENMP", "201307");
}
// Get other target #defines.
TI.getTargetDefines(LangOpts, Builder);
}
-// Initialize the remapping of files to alternative contents, e.g.,
-// those specified through other files.
-static void InitializeFileRemapping(DiagnosticsEngine &Diags,
- SourceManager &SourceMgr,
- FileManager &FileMgr,
- const PreprocessorOptions &InitOpts) {
- // Remap files in the source manager (with buffers).
- for (PreprocessorOptions::const_remapped_file_buffer_iterator
- Remap = InitOpts.remapped_file_buffer_begin(),
- RemapEnd = InitOpts.remapped_file_buffer_end();
- Remap != RemapEnd;
- ++Remap) {
- // Create the file entry for the file that we're mapping from.
- const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first,
- Remap->second->getBufferSize(),
- 0);
- if (!FromFile) {
- Diags.Report(diag::err_fe_remap_missing_from_file)
- << Remap->first;
- if (!InitOpts.RetainRemappedFileBuffers)
- delete Remap->second;
- continue;
- }
-
- // Override the contents of the "from" file with the contents of
- // the "to" file.
- SourceMgr.overrideFileContents(FromFile, Remap->second,
- InitOpts.RetainRemappedFileBuffers);
- }
-
- // Remap files in the source manager (with other files).
- for (PreprocessorOptions::const_remapped_file_iterator
- Remap = InitOpts.remapped_file_begin(),
- RemapEnd = InitOpts.remapped_file_end();
- Remap != RemapEnd;
- ++Remap) {
- // Find the file that we're mapping to.
- const FileEntry *ToFile = FileMgr.getFile(Remap->second);
- if (!ToFile) {
- Diags.Report(diag::err_fe_remap_missing_to_file)
- << Remap->first << Remap->second;
- continue;
- }
-
- // Create the file entry for the file that we're mapping from.
- const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first,
- ToFile->getSize(), 0);
- if (!FromFile) {
- Diags.Report(diag::err_fe_remap_missing_from_file)
- << Remap->first;
- continue;
- }
-
- // Override the contents of the "from" file with the contents of
- // the "to" file.
- SourceMgr.overrideFileContents(FromFile, ToFile);
- }
-
- SourceMgr.setOverridenFilesKeepOriginalName(
- InitOpts.RemappedFilesKeepOriginalName);
-}
-
/// InitializePreprocessor - Initialize the preprocessor getting it and the
/// environment ready to process a single file. This returns true on error.
///
void clang::InitializePreprocessor(Preprocessor &PP,
const PreprocessorOptions &InitOpts,
- const HeaderSearchOptions &HSOpts,
const FrontendOptions &FEOpts) {
const LangOptions &LangOpts = PP.getLangOpts();
std::string PredefineBuffer;
@@ -804,9 +877,6 @@ void clang::InitializePreprocessor(Preprocessor &PP,
llvm::raw_string_ostream Predefines(PredefineBuffer);
MacroBuilder Builder(Predefines);
- InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(),
- PP.getFileManager(), InitOpts);
-
// Emit line markers for various builtin sections of the file. We don't do
// this in asm preprocessor mode, because "# 4" is not a line marker directive
// in this mode.
@@ -880,9 +950,4 @@ void clang::InitializePreprocessor(Preprocessor &PP,
// Copy PredefinedBuffer into the Preprocessor.
PP.setPredefines(Predefines.str());
-
- // Initialize the header search object.
- ApplyHeaderSearchOptions(PP.getHeaderSearchInfo(), HSOpts,
- PP.getLangOpts(),
- PP.getTargetInfo().getTriple());
}
diff --git a/lib/Frontend/LangStandards.cpp b/lib/Frontend/LangStandards.cpp
index f86a574c30ab..f133327f4298 100644
--- a/lib/Frontend/LangStandards.cpp
+++ b/lib/Frontend/LangStandards.cpp
@@ -35,7 +35,7 @@ const LangStandard *LangStandard::getLangStandardForName(StringRef Name) {
#include "clang/Frontend/LangStandards.def"
.Default(lang_unspecified);
if (K == lang_unspecified)
- return 0;
+ return nullptr;
return &getLangStandardForKind(K);
}
diff --git a/lib/Frontend/LogDiagnosticPrinter.cpp b/lib/Frontend/LogDiagnosticPrinter.cpp
index 2189b8658ed2..19539e0a5eb2 100644
--- a/lib/Frontend/LogDiagnosticPrinter.cpp
+++ b/lib/Frontend/LogDiagnosticPrinter.cpp
@@ -10,16 +10,18 @@
#include "clang/Frontend/LogDiagnosticPrinter.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/PlistSupport.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+using namespace markup;
LogDiagnosticPrinter::LogDiagnosticPrinter(raw_ostream &os,
DiagnosticOptions *diags,
bool _OwnsOutputStream)
- : OS(os), LangOpts(0), DiagOpts(diags),
+ : OS(os), LangOpts(nullptr), DiagOpts(diags),
OwnsOutputStream(_OwnsOutputStream) {
}
@@ -31,6 +33,7 @@ LogDiagnosticPrinter::~LogDiagnosticPrinter() {
static StringRef getLevelName(DiagnosticsEngine::Level Level) {
switch (Level) {
case DiagnosticsEngine::Ignored: return "ignored";
+ case DiagnosticsEngine::Remark: return "remark";
case DiagnosticsEngine::Note: return "note";
case DiagnosticsEngine::Warning: return "warning";
case DiagnosticsEngine::Error: return "error";
@@ -39,19 +42,34 @@ static StringRef getLevelName(DiagnosticsEngine::Level Level) {
llvm_unreachable("Invalid DiagnosticsEngine level!");
}
-// Escape XML characters inside the raw string.
-static void emitString(llvm::raw_svector_ostream &OS, const StringRef Raw) {
- for (StringRef::iterator I = Raw.begin(), E = Raw.end(); I != E; ++I) {
- char c = *I;
- switch (c) {
- default: OS << c; break;
- case '&': OS << "&amp;"; break;
- case '<': OS << "&lt;"; break;
- case '>': OS << "&gt;"; break;
- case '\'': OS << "&apos;"; break;
- case '\"': OS << "&quot;"; break;
- }
+void
+LogDiagnosticPrinter::EmitDiagEntry(llvm::raw_ostream &OS,
+ const LogDiagnosticPrinter::DiagEntry &DE) {
+ OS << " <dict>\n";
+ OS << " <key>level</key>\n"
+ << " ";
+ EmitString(OS, getLevelName(DE.DiagnosticLevel)) << '\n';
+ if (!DE.Filename.empty()) {
+ OS << " <key>filename</key>\n"
+ << " ";
+ EmitString(OS, DE.Filename) << '\n';
+ }
+ if (DE.Line != 0) {
+ OS << " <key>line</key>\n"
+ << " ";
+ EmitInteger(OS, DE.Line) << '\n';
+ }
+ if (DE.Column != 0) {
+ OS << " <key>column</key>\n"
+ << " ";
+ EmitInteger(OS, DE.Column) << '\n';
}
+ if (!DE.Message.empty()) {
+ OS << " <key>message</key>\n"
+ << " ";
+ EmitString(OS, DE.Message) << '\n';
+ }
+ OS << " </dict>\n";
}
void LogDiagnosticPrinter::EndSourceFile() {
@@ -71,48 +89,18 @@ void LogDiagnosticPrinter::EndSourceFile() {
OS << "<dict>\n";
if (!MainFilename.empty()) {
OS << " <key>main-file</key>\n"
- << " <string>";
- emitString(OS, MainFilename);
- OS << "</string>\n";
+ << " ";
+ EmitString(OS, MainFilename) << '\n';
}
if (!DwarfDebugFlags.empty()) {
OS << " <key>dwarf-debug-flags</key>\n"
- << " <string>";
- emitString(OS, DwarfDebugFlags);
- OS << "</string>\n";
+ << " ";
+ EmitString(OS, DwarfDebugFlags) << '\n';
}
OS << " <key>diagnostics</key>\n";
OS << " <array>\n";
- for (unsigned i = 0, e = Entries.size(); i != e; ++i) {
- DiagEntry &DE = Entries[i];
-
- OS << " <dict>\n";
- OS << " <key>level</key>\n"
- << " <string>";
- emitString(OS, getLevelName(DE.DiagnosticLevel));
- OS << "</string>\n";
- if (!DE.Filename.empty()) {
- OS << " <key>filename</key>\n"
- << " <string>";
- emitString(OS, DE.Filename);
- OS << "</string>\n";
- }
- if (DE.Line != 0) {
- OS << " <key>line</key>\n"
- << " <integer>" << DE.Line << "</integer>\n";
- }
- if (DE.Column != 0) {
- OS << " <key>column</key>\n"
- << " <integer>" << DE.Column << "</integer>\n";
- }
- if (!DE.Message.empty()) {
- OS << " <key>message</key>\n"
- << " <string>";
- emitString(OS, DE.Message);
- OS << "</string>\n";
- }
- OS << " </dict>\n";
- }
+ for (auto &DE : Entries)
+ EmitDiagEntry(OS, DE);
OS << " </array>\n";
OS << "</dict>\n";
@@ -130,7 +118,7 @@ void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
FileID FID = SM.getMainFileID();
if (!FID.isInvalid()) {
const FileEntry *FE = SM.getFileEntryForID(FID);
- if (FE && FE->getName())
+ if (FE && FE->isValid())
MainFilename = FE->getName();
}
}
@@ -157,7 +145,7 @@ void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
FileID FID = SM.getFileID(Info.getLocation());
if (!FID.isInvalid()) {
const FileEntry *FE = SM.getFileEntryForID(FID);
- if (FE && FE->getName())
+ if (FE && FE->isValid())
DE.Filename = FE->getName();
}
} else {
diff --git a/lib/Frontend/Makefile b/lib/Frontend/Makefile
index 3c13ad69cc67..8554b7649fa2 100644
--- a/lib/Frontend/Makefile
+++ b/lib/Frontend/Makefile
@@ -8,7 +8,7 @@
##===----------------------------------------------------------------------===##
CLANG_LEVEL := ../..
+DIRS := Rewrite
LIBRARYNAME := clangFrontend
include $(CLANG_LEVEL)/Makefile
-
diff --git a/lib/Frontend/ModuleDependencyCollector.cpp b/lib/Frontend/ModuleDependencyCollector.cpp
new file mode 100644
index 000000000000..d30f9214f82e
--- /dev/null
+++ b/lib/Frontend/ModuleDependencyCollector.cpp
@@ -0,0 +1,116 @@
+//===--- ModuleDependencyCollector.cpp - Collect module dependencies ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Collect the dependencies of a set of modules.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/Utils.h"
+#include "clang/Serialization/ASTReader.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+namespace {
+/// Private implementation for ModuleDependencyCollector
+class ModuleDependencyListener : public ASTReaderListener {
+ ModuleDependencyCollector &Collector;
+
+ std::error_code copyToRoot(StringRef Src);
+public:
+ ModuleDependencyListener(ModuleDependencyCollector &Collector)
+ : Collector(Collector) {}
+ bool needsInputFileVisitation() override { return true; }
+ bool needsSystemInputFileVisitation() override { return true; }
+ bool visitInputFile(StringRef Filename, bool IsSystem,
+ bool IsOverridden) override;
+};
+}
+
+void ModuleDependencyCollector::attachToASTReader(ASTReader &R) {
+ R.addListener(new ModuleDependencyListener(*this));
+}
+
+void ModuleDependencyCollector::writeFileMap() {
+ if (Seen.empty())
+ return;
+
+ SmallString<256> Dest = getDest();
+ llvm::sys::path::append(Dest, "vfs.yaml");
+
+ std::string ErrorInfo;
+ llvm::raw_fd_ostream OS(Dest.c_str(), ErrorInfo, llvm::sys::fs::F_Text);
+ if (!ErrorInfo.empty()) {
+ setHasErrors();
+ return;
+ }
+ VFSWriter.write(OS);
+}
+
+/// Remove traversal (ie, . or ..) from the given absolute path.
+static void removePathTraversal(SmallVectorImpl<char> &Path) {
+ using namespace llvm::sys;
+ SmallVector<StringRef, 16> ComponentStack;
+ StringRef P(Path.data(), Path.size());
+
+ // Skip the root path, then look for traversal in the components.
+ StringRef Rel = path::relative_path(P);
+ for (StringRef C : llvm::make_range(path::begin(Rel), path::end(Rel))) {
+ if (C == ".")
+ continue;
+ if (C == "..") {
+ assert(ComponentStack.size() && "Path traverses out of parent");
+ ComponentStack.pop_back();
+ } else
+ ComponentStack.push_back(C);
+ }
+
+ // The stack is now the path without any directory traversal.
+ SmallString<256> Buffer = path::root_path(P);
+ for (StringRef C : ComponentStack)
+ path::append(Buffer, C);
+
+ // Put the result in Path.
+ Path.swap(Buffer);
+}
+
+std::error_code ModuleDependencyListener::copyToRoot(StringRef Src) {
+ using namespace llvm::sys;
+
+ // We need an absolute path to append to the root.
+ SmallString<256> AbsoluteSrc = Src;
+ fs::make_absolute(AbsoluteSrc);
+ removePathTraversal(AbsoluteSrc);
+
+ // Build the destination path.
+ SmallString<256> Dest = Collector.getDest();
+ path::append(Dest, path::relative_path(AbsoluteSrc));
+
+ // Copy the file into place.
+ if (std::error_code EC = fs::create_directories(path::parent_path(Dest),
+ /*IgnoreExisting=*/true))
+ return EC;
+ if (std::error_code EC = fs::copy_file(AbsoluteSrc.str(), Dest.str()))
+ return EC;
+ // Use the absolute path under the root for the file mapping.
+ Collector.addFileMapping(AbsoluteSrc.str(), Dest.str());
+ return std::error_code();
+}
+
+bool ModuleDependencyListener::visitInputFile(StringRef Filename, bool IsSystem,
+ bool IsOverridden) {
+ if (Collector.insertSeen(Filename))
+ if (copyToRoot(Filename))
+ Collector.setHasErrors();
+ return true;
+}
diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp
index 9cf68a5e9b25..0e933a3f165f 100644
--- a/lib/Frontend/MultiplexConsumer.cpp
+++ b/lib/Frontend/MultiplexConsumer.cpp
@@ -30,14 +30,14 @@ public:
// Does NOT take ownership of the elements in L.
MultiplexASTDeserializationListener(
const std::vector<ASTDeserializationListener*>& L);
- virtual void ReaderInitialized(ASTReader *Reader);
- virtual void IdentifierRead(serialization::IdentID ID,
- IdentifierInfo *II);
- virtual void TypeRead(serialization::TypeIdx Idx, QualType T);
- virtual void DeclRead(serialization::DeclID ID, const Decl *D);
- virtual void SelectorRead(serialization::SelectorID iD, Selector Sel);
- virtual void MacroDefinitionRead(serialization::PreprocessedEntityID,
- MacroDefinition *MD);
+ void ReaderInitialized(ASTReader *Reader) override;
+ void IdentifierRead(serialization::IdentID ID,
+ IdentifierInfo *II) override;
+ void TypeRead(serialization::TypeIdx Idx, QualType T) override;
+ void DeclRead(serialization::DeclID ID, const Decl *D) override;
+ void SelectorRead(serialization::SelectorID iD, Selector Sel) override;
+ void MacroDefinitionRead(serialization::PreprocessedEntityID,
+ MacroDefinition *MD) override;
private:
std::vector<ASTDeserializationListener*> Listeners;
};
@@ -89,25 +89,24 @@ class MultiplexASTMutationListener : public ASTMutationListener {
public:
// Does NOT take ownership of the elements in L.
MultiplexASTMutationListener(ArrayRef<ASTMutationListener*> L);
- virtual void CompletedTagDefinition(const TagDecl *D);
- virtual void AddedVisibleDecl(const DeclContext *DC, const Decl *D);
- virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D);
- virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
- const ClassTemplateSpecializationDecl *D);
- virtual void
- AddedCXXTemplateSpecialization(const VarTemplateDecl *TD,
- const VarTemplateSpecializationDecl *D);
- virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
- const FunctionDecl *D);
- virtual void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType);
- virtual void CompletedImplicitDefinition(const FunctionDecl *D);
- virtual void StaticDataMemberInstantiated(const VarDecl *D);
- virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
- const ObjCInterfaceDecl *IFD);
- virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
- const ObjCPropertyDecl *OrigProp,
- const ObjCCategoryDecl *ClassExt);
- void DeclarationMarkedUsed(const Decl *D) LLVM_OVERRIDE;
+ void CompletedTagDefinition(const TagDecl *D) override;
+ void AddedVisibleDecl(const DeclContext *DC, const Decl *D) override;
+ void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) override;
+ void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
+ const ClassTemplateSpecializationDecl *D) override;
+ void AddedCXXTemplateSpecialization(const VarTemplateDecl *TD,
+ const VarTemplateSpecializationDecl *D) override;
+ void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
+ const FunctionDecl *D) override;
+ void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) override;
+ void CompletedImplicitDefinition(const FunctionDecl *D) override;
+ void StaticDataMemberInstantiated(const VarDecl *D) override;
+ void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
+ const ObjCInterfaceDecl *IFD) override;
+ void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
+ const ObjCPropertyDecl *OrigProp,
+ const ObjCCategoryDecl *ClassExt) override;
+ void DeclarationMarkedUsed(const Decl *D) override;
private:
std::vector<ASTMutationListener*> Listeners;
@@ -184,10 +183,9 @@ void MultiplexASTMutationListener::DeclarationMarkedUsed(const Decl *D) {
} // end namespace clang
-
-MultiplexConsumer::MultiplexConsumer(ArrayRef<ASTConsumer*> C)
- : Consumers(C.begin(), C.end()),
- MutationListener(0), DeserializationListener(0) {
+MultiplexConsumer::MultiplexConsumer(ArrayRef<ASTConsumer *> C)
+ : Consumers(C.begin(), C.end()), MutationListener(),
+ DeserializationListener() {
// Collect the mutation listeners and deserialization listeners of all
// children, and create a multiplex listener each if so.
std::vector<ASTMutationListener*> mutationListeners;
@@ -228,6 +226,11 @@ bool MultiplexConsumer::HandleTopLevelDecl(DeclGroupRef D) {
return Continue;
}
+void MultiplexConsumer::HandleInlineMethodDefinition(CXXMethodDecl *D) {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ Consumers[i]->HandleInlineMethodDefinition(D);
+}
+
void MultiplexConsumer::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
for (size_t i = 0, e = Consumers.size(); i != e; ++i)
Consumers[i]->HandleCXXStaticMemberVarInstantiation(VD);
@@ -248,6 +251,11 @@ void MultiplexConsumer::HandleTagDeclDefinition(TagDecl *D) {
Consumers[i]->HandleTagDeclDefinition(D);
}
+void MultiplexConsumer::HandleTagDeclRequiredDefinition(const TagDecl *D) {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ Consumers[i]->HandleTagDeclRequiredDefinition(D);
+}
+
void MultiplexConsumer::HandleCXXImplicitFunctionInstantiation(FunctionDecl *D){
for (size_t i = 0, e = Consumers.size(); i != e; ++i)
Consumers[i]->HandleCXXImplicitFunctionInstantiation(D);
@@ -258,6 +266,26 @@ void MultiplexConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {
Consumers[i]->HandleTopLevelDeclInObjCContainer(D);
}
+void MultiplexConsumer::HandleImplicitImportDecl(ImportDecl *D) {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ Consumers[i]->HandleImplicitImportDecl(D);
+}
+
+void MultiplexConsumer::HandleLinkerOptionPragma(llvm::StringRef Opts) {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ Consumers[i]->HandleLinkerOptionPragma(Opts);
+}
+
+void MultiplexConsumer::HandleDetectMismatch(llvm::StringRef Name, llvm::StringRef Value) {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ Consumers[i]->HandleDetectMismatch(Name, Value);
+}
+
+void MultiplexConsumer::HandleDependentLibrary(llvm::StringRef Lib) {
+ for (size_t i = 0, e = Consumers.size(); i != e; ++i)
+ Consumers[i]->HandleDependentLibrary(Lib);
+}
+
void MultiplexConsumer::CompleteTentativeDefinition(VarDecl *D) {
for (size_t i = 0, e = Consumers.size(); i != e; ++i)
Consumers[i]->CompleteTentativeDefinition(D);
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 55a66d87f8bf..4a6f8dbef928 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -123,39 +123,27 @@ public:
}
bool startNewLineIfNeeded(bool ShouldUpdateCurrentLine = true);
-
- virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
- SrcMgr::CharacteristicKind FileType,
- FileID PrevFID);
- virtual void InclusionDirective(SourceLocation HashLoc,
- const Token &IncludeTok,
- StringRef FileName,
- bool IsAngled,
- CharSourceRange FilenameRange,
- const FileEntry *File,
- StringRef SearchPath,
- StringRef RelativePath,
- const Module *Imported);
- virtual void Ident(SourceLocation Loc, const std::string &str);
- virtual void PragmaCaptured(SourceLocation Loc, StringRef Str);
- virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
- const std::string &Str);
- virtual void PragmaDetectMismatch(SourceLocation Loc,
- const std::string &Name,
- const std::string &Value);
- virtual void PragmaMessage(SourceLocation Loc, StringRef Namespace,
- PragmaMessageKind Kind, StringRef Str);
- virtual void PragmaDebug(SourceLocation Loc, StringRef DebugType);
- virtual void PragmaDiagnosticPush(SourceLocation Loc,
- StringRef Namespace);
- virtual void PragmaDiagnosticPop(SourceLocation Loc,
- StringRef Namespace);
- virtual void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,
- diag::Mapping Map, StringRef Str);
- virtual void PragmaWarning(SourceLocation Loc, StringRef WarningSpec,
- ArrayRef<int> Ids);
- virtual void PragmaWarningPush(SourceLocation Loc, int Level);
- virtual void PragmaWarningPop(SourceLocation Loc);
+
+ void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) override;
+ void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+ StringRef FileName, bool IsAngled,
+ CharSourceRange FilenameRange, const FileEntry *File,
+ StringRef SearchPath, StringRef RelativePath,
+ const Module *Imported) override;
+ void Ident(SourceLocation Loc, const std::string &str) override;
+ void PragmaMessage(SourceLocation Loc, StringRef Namespace,
+ PragmaMessageKind Kind, StringRef Str) override;
+ void PragmaDebug(SourceLocation Loc, StringRef DebugType) override;
+ void PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) override;
+ void PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) override;
+ void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,
+ diag::Severity Map, StringRef Str) override;
+ void PragmaWarning(SourceLocation Loc, StringRef WarningSpec,
+ ArrayRef<int> Ids) override;
+ void PragmaWarningPush(SourceLocation Loc, int Level) override;
+ void PragmaWarningPop(SourceLocation Loc) override;
bool HandleFirstTokOnLine(Token &Tok);
@@ -174,15 +162,18 @@ public:
const Token &Tok) {
return ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok);
}
- void WriteLineInfo(unsigned LineNo, const char *Extra=0, unsigned ExtraLen=0);
+ void WriteLineInfo(unsigned LineNo, const char *Extra=nullptr,
+ unsigned ExtraLen=0);
bool LineMarkersAreDisabled() const { return DisableLineMarkers; }
void HandleNewlinesInToken(const char *TokStr, unsigned Len);
/// MacroDefined - This hook is called whenever a macro definition is seen.
- void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD);
+ void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override;
/// MacroUndefined - This hook is called whenever a macro #undef is seen.
- void MacroUndefined(const Token &MacroNameTok, const MacroDirective *MD);
+ void MacroUndefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override;
};
} // end anonymous namespace
@@ -230,7 +221,7 @@ bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo) {
}
} else if (!DisableLineMarkers) {
// Emit a #line or line marker.
- WriteLineInfo(LineNo, 0, 0);
+ WriteLineInfo(LineNo, nullptr, 0);
} else {
// Okay, we're in -P mode, which turns off line markers. However, we still
// need to emit a newline between tokens on different lines.
@@ -355,15 +346,6 @@ void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) {
EmittedTokensOnThisLine = true;
}
-void PrintPPOutputPPCallbacks::PragmaCaptured(SourceLocation Loc,
- StringRef Str) {
- startNewLineIfNeeded();
- MoveToLine(Loc);
- OS << "#pragma captured";
-
- setEmittedDirectiveOnThisLine();
-}
-
/// MacroDefined - This hook is called whenever a macro definition is seen.
void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok,
const MacroDirective *MD) {
@@ -402,36 +384,6 @@ static void outputPrintable(llvm::raw_ostream& OS,
}
}
-void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
- const IdentifierInfo *Kind,
- const std::string &Str) {
- startNewLineIfNeeded();
- MoveToLine(Loc);
- OS << "#pragma comment(" << Kind->getName();
-
- if (!Str.empty()) {
- OS << ", \"";
- outputPrintable(OS, Str);
- OS << '"';
- }
-
- OS << ')';
- setEmittedDirectiveOnThisLine();
-}
-
-void PrintPPOutputPPCallbacks::PragmaDetectMismatch(SourceLocation Loc,
- const std::string &Name,
- const std::string &Value) {
- startNewLineIfNeeded();
- MoveToLine(Loc);
- OS << "#pragma detect_mismatch(\"" << Name << '"';
- outputPrintable(OS, Name);
- OS << "\", \"";
- outputPrintable(OS, Value);
- OS << "\")";
- setEmittedDirectiveOnThisLine();
-}
-
void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
StringRef Namespace,
PragmaMessageKind Kind,
@@ -487,23 +439,27 @@ PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) {
setEmittedDirectiveOnThisLine();
}
-void PrintPPOutputPPCallbacks::
-PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,
- diag::Mapping Map, StringRef Str) {
+void PrintPPOutputPPCallbacks::PragmaDiagnostic(SourceLocation Loc,
+ StringRef Namespace,
+ diag::Severity Map,
+ StringRef Str) {
startNewLineIfNeeded();
MoveToLine(Loc);
OS << "#pragma " << Namespace << " diagnostic ";
switch (Map) {
- case diag::MAP_WARNING:
+ case diag::Severity::Remark:
+ OS << "remark";
+ break;
+ case diag::Severity::Warning:
OS << "warning";
break;
- case diag::MAP_ERROR:
+ case diag::Severity::Error:
OS << "error";
break;
- case diag::MAP_IGNORE:
+ case diag::Severity::Ignored:
OS << "ignored";
break;
- case diag::MAP_FATAL:
+ case diag::Severity::Fatal:
OS << "fatal";
break;
}
@@ -556,6 +512,13 @@ bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) {
// indented for easy reading.
unsigned ColNo = SM.getExpansionColumnNumber(Tok.getLocation());
+ // The first token on a line can have a column number of 1, yet still expect
+ // leading white space, if a macro expansion in column 1 starts with an empty
+ // macro argument, or an empty nested macro expansion. In this case, move the
+ // token to column 2.
+ if (ColNo == 1 && Tok.hasLeadingSpace())
+ ColNo = 2;
+
// This hack prevents stuff like:
// #define HASH #
// HASH define foo bar
@@ -602,8 +565,8 @@ struct UnknownPragmaHandler : public PragmaHandler {
UnknownPragmaHandler(const char *prefix, PrintPPOutputPPCallbacks *callbacks)
: Prefix(prefix), Callbacks(callbacks) {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &PragmaTok) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &PragmaTok) override {
// Figure out what line we went to and insert the appropriate number of
// newline characters.
Callbacks->startNewLineIfNeeded();
@@ -615,7 +578,13 @@ struct UnknownPragmaHandler : public PragmaHandler {
Callbacks->OS << ' ';
std::string TokSpell = PP.getSpelling(PragmaTok);
Callbacks->OS.write(&TokSpell[0], TokSpell.size());
- PP.LexUnexpandedToken(PragmaTok);
+
+ // Expand macros in pragmas with -fms-extensions. The assumption is that
+ // the majority of pragmas in such a file will be Microsoft pragmas.
+ if (PP.getLangOpts().MicrosoftExt)
+ PP.Lex(PragmaTok);
+ else
+ PP.LexUnexpandedToken(PragmaTok);
}
Callbacks->setEmittedDirectiveOnThisLine();
}
@@ -657,7 +626,9 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
// -traditional-cpp the lexer keeps /all/ whitespace, including comments.
SourceLocation StartLoc = Tok.getLocation();
Callbacks->MoveToLine(StartLoc.getLocWithOffset(Tok.getLength()));
- } else if (Tok.is(tok::annot_module_include)) {
+ } else if (Tok.is(tok::annot_module_include) ||
+ Tok.is(tok::annot_module_begin) ||
+ Tok.is(tok::annot_module_end)) {
// PrintPPOutputPPCallbacks::InclusionDirective handles producing
// appropriate output here. Ignore this token entirely.
PP.Lex(Tok);
@@ -702,7 +673,7 @@ static int MacroIDCompare(const id_macro_pair *LHS, const id_macro_pair *RHS) {
static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS) {
// Ignore unknown pragmas.
- PP.AddPragmaHandler(new EmptyPragmaHandler());
+ PP.IgnorePragmas();
// -dM mode just scans and ignores all tokens in the files, then dumps out
// the macro table at the end.
diff --git a/lib/Frontend/Rewrite/CMakeLists.txt b/lib/Frontend/Rewrite/CMakeLists.txt
new file mode 100644
index 000000000000..924bf5d5ee28
--- /dev/null
+++ b/lib/Frontend/Rewrite/CMakeLists.txt
@@ -0,0 +1,22 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_clang_library(clangRewriteFrontend
+ FixItRewriter.cpp
+ FrontendActions.cpp
+ HTMLPrint.cpp
+ InclusionRewriter.cpp
+ RewriteMacros.cpp
+ RewriteModernObjC.cpp
+ RewriteObjC.cpp
+ RewriteTest.cpp
+
+ LINK_LIBS
+ clangAST
+ clangBasic
+ clangEdit
+ clangFrontend
+ clangLex
+ clangRewrite
+ )
diff --git a/lib/Rewrite/Frontend/FixItRewriter.cpp b/lib/Frontend/Rewrite/FixItRewriter.cpp
index 8930c35d06c4..8b7af7166c8f 100644
--- a/lib/Rewrite/Frontend/FixItRewriter.cpp
+++ b/lib/Frontend/Rewrite/FixItRewriter.cpp
@@ -20,10 +20,10 @@
#include "clang/Edit/Commit.h"
#include "clang/Edit/EditsReceiver.h"
#include "clang/Frontend/FrontendDiagnostic.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
+#include <memory>
using namespace clang;
@@ -62,10 +62,10 @@ class RewritesReceiver : public edit::EditsReceiver {
public:
RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { }
- virtual void insert(SourceLocation loc, StringRef text) {
+ void insert(SourceLocation loc, StringRef text) override {
Rewrite.InsertText(loc, text);
}
- virtual void replace(CharSourceRange range, StringRef text) {
+ void replace(CharSourceRange range, StringRef text) override {
Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text);
}
};
@@ -87,12 +87,12 @@ bool FixItRewriter::WriteFixedFiles(
int fd;
std::string Filename = FixItOpts->RewriteFilename(Entry->getName(), fd);
std::string Err;
- OwningPtr<llvm::raw_fd_ostream> OS;
+ std::unique_ptr<llvm::raw_fd_ostream> OS;
if (fd != -1) {
OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true));
} else {
OS.reset(new llvm::raw_fd_ostream(Filename.c_str(), Err,
- llvm::sys::fs::F_Binary));
+ llvm::sys::fs::F_None));
}
if (!Err.empty()) {
Diags.Report(clang::diag::err_fe_unable_to_open_output)
diff --git a/lib/Rewrite/Frontend/FrontendActions.cpp b/lib/Frontend/Rewrite/FrontendActions.cpp
index e9ec38818265..59fef736f16a 100644
--- a/lib/Rewrite/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/Rewrite/FrontendActions.cpp
@@ -19,10 +19,10 @@
#include "clang/Rewrite/Frontend/ASTConsumers.h"
#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Rewrite/Frontend/Rewriters.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
+#include <memory>
using namespace clang;
@@ -34,7 +34,7 @@ ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile))
return CreateHTMLPrinter(OS, CI.getPreprocessor());
- return 0;
+ return nullptr;
}
FixItAction::FixItAction() {}
@@ -48,7 +48,7 @@ ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI,
namespace {
class FixItRewriteInPlace : public FixItOptions {
public:
- std::string RewriteFilename(const std::string &Filename, int &fd) {
+ std::string RewriteFilename(const std::string &Filename, int &fd) override {
fd = -1;
return Filename;
}
@@ -63,7 +63,7 @@ public:
this->FixWhatYouCan = FixWhatYouCan;
}
- std::string RewriteFilename(const std::string &Filename, int &fd) {
+ std::string RewriteFilename(const std::string &Filename, int &fd) override {
fd = -1;
SmallString<128> Path(Filename);
llvm::sys::path::replace_extension(Path,
@@ -74,7 +74,7 @@ public:
class FixItRewriteToTemp : public FixItOptions {
public:
- std::string RewriteFilename(const std::string &Filename, int &fd) {
+ std::string RewriteFilename(const std::string &Filename, int &fd) override {
SmallString<128> Path;
llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename),
llvm::sys::path::extension(Filename), fd,
@@ -110,9 +110,9 @@ bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
bool err = false;
{
const FrontendOptions &FEOpts = CI.getFrontendOpts();
- OwningPtr<FrontendAction> FixAction(new SyntaxOnlyAction());
+ std::unique_ptr<FrontendAction> FixAction(new SyntaxOnlyAction());
if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) {
- OwningPtr<FixItOptions> FixItOpts;
+ std::unique_ptr<FixItOptions> FixItOpts;
if (FEOpts.FixToTemporaries)
FixItOpts.reset(new FixItRewriteToTemp());
else
@@ -127,8 +127,8 @@ bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
err = Rewriter.WriteFixedFiles(&RewrittenFiles);
FixAction->EndSourceFile();
- CI.setSourceManager(0);
- CI.setFileManager(0);
+ CI.setSourceManager(nullptr);
+ CI.setFileManager(nullptr);
} else {
err = true;
}
@@ -146,9 +146,7 @@ bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
return true;
}
-//===----------------------------------------------------------------------===//
-// Preprocessor Actions
-//===----------------------------------------------------------------------===//
+#ifdef CLANG_ENABLE_OBJC_REWRITER
ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
@@ -163,9 +161,15 @@ ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
CI.getDiagnostics(), CI.getLangOpts(),
CI.getDiagnosticOpts().NoRewriteMacros);
}
- return 0;
+ return nullptr;
}
+#endif
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Actions
+//===----------------------------------------------------------------------===//
+
void RewriteMacrosAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
diff --git a/lib/Rewrite/Frontend/HTMLPrint.cpp b/lib/Frontend/Rewrite/HTMLPrint.cpp
index 79e44470ada5..64da05fdde61 100644
--- a/lib/Rewrite/Frontend/HTMLPrint.cpp
+++ b/lib/Frontend/Rewrite/HTMLPrint.cpp
@@ -42,8 +42,8 @@ namespace {
: Out(OS), PP(pp), SyntaxHighlight(_SyntaxHighlight),
HighlightMacros(_HighlightMacros) {}
- void Initialize(ASTContext &context);
- void HandleTranslationUnit(ASTContext &Ctx);
+ void Initialize(ASTContext &context) override;
+ void HandleTranslationUnit(ASTContext &Ctx) override;
};
}
diff --git a/lib/Rewrite/Frontend/InclusionRewriter.cpp b/lib/Frontend/Rewrite/InclusionRewriter.cpp
index 71ceb5f0b6aa..aa7017baee26 100644
--- a/lib/Rewrite/Frontend/InclusionRewriter.cpp
+++ b/lib/Frontend/Rewrite/InclusionRewriter.cpp
@@ -55,21 +55,16 @@ public:
PredefinesBuffer = Buf;
}
private:
- virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
- SrcMgr::CharacteristicKind FileType,
- FileID PrevFID);
- virtual void FileSkipped(const FileEntry &ParentFile,
- const Token &FilenameTok,
- SrcMgr::CharacteristicKind FileType);
- virtual void InclusionDirective(SourceLocation HashLoc,
- const Token &IncludeTok,
- StringRef FileName,
- bool IsAngled,
- CharSourceRange FilenameRange,
- const FileEntry *File,
- StringRef SearchPath,
- StringRef RelativePath,
- const Module *Imported);
+ void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) override;
+ void FileSkipped(const FileEntry &ParentFile, const Token &FilenameTok,
+ SrcMgr::CharacteristicKind FileType) override;
+ void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+ StringRef FileName, bool IsAngled,
+ CharSourceRange FilenameRange, const FileEntry *File,
+ StringRef SearchPath, StringRef RelativePath,
+ const Module *Imported) override;
void WriteLineInfo(const char *Filename, int Line,
SrcMgr::CharacteristicKind FileType,
StringRef EOL, StringRef Extra = StringRef());
@@ -77,7 +72,7 @@ private:
void OutputContentUpTo(const MemoryBuffer &FromFile,
unsigned &WriteFrom, unsigned WriteTo,
StringRef EOL, int &lines,
- bool EnsureNewline = false);
+ bool EnsureNewline);
void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken,
const MemoryBuffer &FromFile, StringRef EOL,
unsigned &NextToWrite, int &Lines);
@@ -93,7 +88,7 @@ private:
/// Initializes an InclusionRewriter with a \p PP source and \p OS destination.
InclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS,
bool ShowLineMarkers)
- : PP(PP), SM(PP.getSourceManager()), OS(OS), PredefinesBuffer(0),
+ : PP(PP), SM(PP.getSourceManager()), OS(OS), PredefinesBuffer(nullptr),
ShowLineMarkers(ShowLineMarkers),
LastInsertedFileChange(FileChanges.end()) {
// If we're in microsoft mode, use normal #line instead of line markers.
@@ -196,7 +191,7 @@ InclusionRewriter::FindFileChangeLocation(SourceLocation Loc) const {
FileChangeMap::const_iterator I = FileChanges.find(Loc.getRawEncoding());
if (I != FileChanges.end())
return &I->second;
- return NULL;
+ return nullptr;
}
/// Detect the likely line ending style of \p FromFile by examining the first
@@ -205,7 +200,7 @@ static StringRef DetectEOL(const MemoryBuffer &FromFile) {
// detect what line endings the file uses, so that added content does not mix
// the style
const char *Pos = strchr(FromFile.getBufferStart(), '\n');
- if (Pos == NULL)
+ if (!Pos)
return "\n";
if (Pos + 1 < FromFile.getBufferEnd() && Pos[1] == '\r')
return "\n\r";
@@ -250,15 +245,19 @@ void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex,
StringRef EOL,
unsigned &NextToWrite, int &Line) {
OutputContentUpTo(FromFile, NextToWrite,
- SM.getFileOffset(StartToken.getLocation()), EOL, Line);
+ SM.getFileOffset(StartToken.getLocation()), EOL, Line, false);
Token DirectiveToken;
do {
DirectiveLex.LexFromRawLexer(DirectiveToken);
} while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof));
+ if (&FromFile == PredefinesBuffer) {
+ // OutputContentUpTo() would not output anything anyway.
+ return;
+ }
OS << "#if 0 /* expanded by -frewrite-includes */" << EOL;
OutputContentUpTo(FromFile, NextToWrite,
SM.getFileOffset(DirectiveToken.getLocation()) + DirectiveToken.getLength(),
- EOL, Line);
+ EOL, Line, true);
OS << "#endif /* expanded by -frewrite-includes */" << EOL;
}
@@ -335,10 +334,11 @@ bool InclusionRewriter::HandleHasInclude(
bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename);
const DirectoryLookup *CurDir;
const FileEntry *File = PP.getHeaderSearchInfo().LookupFile(
- Filename, isAngled, 0, CurDir,
- PP.getSourceManager().getFileEntryForID(FileId), 0, 0, 0, false);
+ Filename, SourceLocation(), isAngled, nullptr, CurDir,
+ PP.getSourceManager().getFileEntryForID(FileId), nullptr, nullptr,
+ nullptr, false);
- FileExists = File != 0;
+ FileExists = File != nullptr;
return true;
}
@@ -357,21 +357,21 @@ bool InclusionRewriter::Process(FileID FileId,
StringRef EOL = DetectEOL(FromFile);
- // Per the GNU docs: "1" indicates the start of a new file.
- WriteLineInfo(FileName, 1, FileType, EOL, " 1");
+ // Per the GNU docs: "1" indicates entering a new file.
+ if (FileId == SM.getMainFileID() || FileId == PP.getPredefinesFileID())
+ WriteLineInfo(FileName, 1, FileType, EOL, "");
+ else
+ WriteLineInfo(FileName, 1, FileType, EOL, " 1");
if (SM.getFileIDSize(FileId) == 0)
return false;
- // The next byte to be copied from the source file
- unsigned NextToWrite = 0;
+ // The next byte to be copied from the source file, which may be non-zero if
+ // the lexer handled a BOM.
+ unsigned NextToWrite = SM.getFileOffset(RawLex.getSourceLocation());
+ assert(SM.getLineNumber(FileId, NextToWrite) == 1);
int Line = 1; // The current input file line number.
- // Ignore UTF-8 BOM, otherwise it'd end up somewhere else than the start
- // of the resulting file.
- if (FromFile.getBuffer().startswith("\xEF\xBB\xBF"))
- NextToWrite = 3;
-
Token RawToken;
RawLex.LexFromRawLexer(RawToken);
@@ -384,13 +384,15 @@ bool InclusionRewriter::Process(FileID FileId,
RawLex.LexFromRawLexer(RawToken);
if (RawToken.is(tok::raw_identifier))
PP.LookUpIdentifierInfo(RawToken);
- if (RawToken.getIdentifierInfo() != NULL) {
+ if (RawToken.getIdentifierInfo() != nullptr) {
switch (RawToken.getIdentifierInfo()->getPPKeywordID()) {
case tok::pp_include:
case tok::pp_include_next:
case tok::pp_import: {
CommentOutDirective(RawLex, HashToken, FromFile, EOL, NextToWrite,
Line);
+ if (FileId != PP.getPredefinesFileID())
+ WriteLineInfo(FileName, Line - 1, FileType, EOL, "");
StringRef LineInfoExtra;
if (const FileChange *Change = FindFileChangeLocation(
HashToken.getLocation())) {
@@ -447,7 +449,8 @@ bool InclusionRewriter::Process(FileID FileId,
// Rewrite __has_include(x)
if (RawToken.getIdentifierInfo()->isStr("__has_include")) {
- if (!HandleHasInclude(FileId, RawLex, 0, RawToken, HasFile))
+ if (!HandleHasInclude(FileId, RawLex, nullptr, RawToken,
+ HasFile))
continue;
// Rewrite __has_include_next(x)
} else if (RawToken.getIdentifierInfo()->isStr(
@@ -465,12 +468,12 @@ bool InclusionRewriter::Process(FileID FileId,
// Replace the macro with (0) or (1), followed by the commented
// out macro for reference.
OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(Loc),
- EOL, Line);
+ EOL, Line, false);
OS << '(' << (int) HasFile << ")/*";
OutputContentUpTo(FromFile, NextToWrite,
SM.getFileOffset(RawToken.getLocation()) +
RawToken.getLength(),
- EOL, Line);
+ EOL, Line, false);
OS << "*/";
}
} while (RawToken.isNot(tok::eod));
@@ -522,13 +525,7 @@ void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS,
InclusionRewriter *Rewrite = new InclusionRewriter(PP, *OS,
Opts.ShowLineMarkers);
PP.addPPCallbacks(Rewrite);
- // Ignore all pragmas, otherwise there will be warnings about unknown pragmas
- // (because there's nothing to handle them).
- PP.AddPragmaHandler(new EmptyPragmaHandler());
- // Ignore also all pragma in all namespaces created
- // in Preprocessor::RegisterBuiltinPragmas().
- PP.AddPragmaHandler("GCC", new EmptyPragmaHandler());
- PP.AddPragmaHandler("clang", new EmptyPragmaHandler());
+ PP.IgnorePragmas();
// First let the preprocessor process the entire file and call callbacks.
// Callbacks will record which #include's were actually performed.
diff --git a/lib/Rewrite/Frontend/Makefile b/lib/Frontend/Rewrite/Makefile
index ac97d4074ecb..1d565477053c 100644
--- a/lib/Rewrite/Frontend/Makefile
+++ b/lib/Frontend/Rewrite/Makefile
@@ -16,3 +16,7 @@ LIBRARYNAME := clangRewriteFrontend
include $(CLANG_LEVEL)/Makefile
+ifeq ($(ENABLE_CLANG_ARCMT),1)
+ CXX.Flags += -DCLANG_ENABLE_OBJC_REWRITER
+endif
+
diff --git a/lib/Rewrite/Frontend/RewriteMacros.cpp b/lib/Frontend/Rewrite/RewriteMacros.cpp
index 4f6a93f7e0eb..0d0a991fa6f9 100644
--- a/lib/Rewrite/Frontend/RewriteMacros.cpp
+++ b/lib/Frontend/Rewrite/RewriteMacros.cpp
@@ -16,10 +16,10 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Core/Rewriter.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
+#include <memory>
using namespace clang;
diff --git a/lib/Rewrite/Frontend/RewriteModernObjC.cpp b/lib/Frontend/Rewrite/RewriteModernObjC.cpp
index ae33ac816e3d..3e18a8b415a3 100644
--- a/lib/Rewrite/Frontend/RewriteModernObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -24,11 +24,13 @@
#include "clang/Lex/Lexer.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
+#include <memory>
+
+#ifdef CLANG_ENABLE_OBJC_REWRITER
using namespace clang;
using llvm::utostr;
@@ -185,7 +187,7 @@ namespace {
public:
llvm::DenseMap<ObjCMethodDecl*, std::string> MethodInternalNames;
// Top Level Driver code.
- virtual bool HandleTopLevelDecl(DeclGroupRef D) {
+ bool HandleTopLevelDecl(DeclGroupRef D) override {
for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*I)) {
if (!Class->isThisDeclarationADefinition()) {
@@ -221,8 +223,8 @@ namespace {
}
return true;
}
-
- virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {
+
+ void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override {
for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(*I)) {
if (isTopLevelBlockPointerType(TD->getUnderlyingType()))
@@ -243,8 +245,8 @@ namespace {
bool silenceMacroWarn, bool LineInfo);
~RewriteModernObjC() {}
-
- virtual void HandleTranslationUnit(ASTContext &C);
+
+ void HandleTranslationUnit(ASTContext &C) override;
void ReplaceStmt(Stmt *Old, Stmt *New) {
Stmt *ReplacingStmt = ReplacedNodes[Old];
@@ -267,6 +269,7 @@ namespace {
}
void ReplaceStmtWithRange(Stmt *Old, Stmt *New, SourceRange SrcRange) {
+ assert(Old != nullptr && New != nullptr && "Expected non-null Stmt's");
if (DisableReplaceStmt)
return;
@@ -280,7 +283,7 @@ namespace {
// Get the new text.
std::string SStr;
llvm::raw_string_ostream S(SStr);
- New->printPretty(S, 0, PrintingPolicy(LangOpts));
+ New->printPretty(S, nullptr, PrintingPolicy(LangOpts));
const std::string &Str = S.str();
// If replacement succeeded or warning disabled return with no warning.
@@ -414,9 +417,9 @@ namespace {
void RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl,
std::string &Result);
-
- virtual void Initialize(ASTContext &context);
-
+
+ void Initialize(ASTContext &context) override;
+
// Misc. AST transformation routines. Sometimes they end up calling
// rewriting routines on the new ASTs.
CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD,
@@ -598,14 +601,22 @@ namespace {
CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty,
CastKind Kind, Expr *E) {
TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation());
- return CStyleCastExpr::Create(*Ctx, Ty, VK_RValue, Kind, E, 0, TInfo,
- SourceLocation(), SourceLocation());
+ return CStyleCastExpr::Create(*Ctx, Ty, VK_RValue, Kind, E, nullptr,
+ TInfo, SourceLocation(), SourceLocation());
}
bool ImplementationIsNonLazy(const ObjCImplDecl *OD) const {
IdentifierInfo* II = &Context->Idents.get("load");
Selector LoadSel = Context->Selectors.getSelector(0, &II);
- return OD->getClassMethod(LoadSel) != 0;
+ return OD->getClassMethod(LoadSel) != nullptr;
+ }
+
+ StringLiteral *getStringLiteral(StringRef Str) {
+ QualType StrType = Context->getConstantArrayType(
+ Context->CharTy, llvm::APInt(32, Str.size() + 1), ArrayType::Normal,
+ 0);
+ return StringLiteral::Create(*Context, Str, StringLiteral::Ascii,
+ /*Pascal=*/false, StrType, SourceLocation());
}
};
@@ -615,9 +626,8 @@ void RewriteModernObjC::RewriteBlocksInFunctionProtoType(QualType funcType,
NamedDecl *D) {
if (const FunctionProtoType *fproto
= dyn_cast<FunctionProtoType>(funcType.IgnoreParens())) {
- for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(),
- E = fproto->arg_type_end(); I && (I != E); ++I)
- if (isTopLevelBlockPointerType(*I)) {
+ for (const auto &I : fproto->param_types())
+ if (isTopLevelBlockPointerType(I)) {
// All the args are checked/rewritten. Don't call twice!
RewriteBlockPointerDecl(D);
break;
@@ -679,30 +689,30 @@ void RewriteModernObjC::InitializeCommon(ASTContext &context) {
Context = &context;
SM = &Context->getSourceManager();
TUDecl = Context->getTranslationUnitDecl();
- MsgSendFunctionDecl = 0;
- MsgSendSuperFunctionDecl = 0;
- MsgSendStretFunctionDecl = 0;
- MsgSendSuperStretFunctionDecl = 0;
- MsgSendFpretFunctionDecl = 0;
- GetClassFunctionDecl = 0;
- GetMetaClassFunctionDecl = 0;
- GetSuperClassFunctionDecl = 0;
- SelGetUidFunctionDecl = 0;
- CFStringFunctionDecl = 0;
- ConstantStringClassReference = 0;
- NSStringRecord = 0;
- CurMethodDef = 0;
- CurFunctionDef = 0;
- GlobalVarDecl = 0;
- GlobalConstructionExp = 0;
- SuperStructDecl = 0;
- ProtocolTypeDecl = 0;
- ConstantStringDecl = 0;
+ MsgSendFunctionDecl = nullptr;
+ MsgSendSuperFunctionDecl = nullptr;
+ MsgSendStretFunctionDecl = nullptr;
+ MsgSendSuperStretFunctionDecl = nullptr;
+ MsgSendFpretFunctionDecl = nullptr;
+ GetClassFunctionDecl = nullptr;
+ GetMetaClassFunctionDecl = nullptr;
+ GetSuperClassFunctionDecl = nullptr;
+ SelGetUidFunctionDecl = nullptr;
+ CFStringFunctionDecl = nullptr;
+ ConstantStringClassReference = nullptr;
+ NSStringRecord = nullptr;
+ CurMethodDef = nullptr;
+ CurFunctionDef = nullptr;
+ GlobalVarDecl = nullptr;
+ GlobalConstructionExp = nullptr;
+ SuperStructDecl = nullptr;
+ ProtocolTypeDecl = nullptr;
+ ConstantStringDecl = nullptr;
BcLabelCount = 0;
- SuperConstructorFunctionDecl = 0;
+ SuperConstructorFunctionDecl = nullptr;
NumObjCStringLiterals = 0;
- PropParentMap = 0;
- CurrentBody = 0;
+ PropParentMap = nullptr;
+ CurrentBody = nullptr;
DisableReplaceStmt = false;
objc_impl_method = false;
@@ -887,11 +897,11 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) {
Zero = NoTypeInfoCStyleCastExpr(Context, PtrStructIMPL, CK_BitCast, Zero);
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
Zero);
- FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get(D->getNameAsString()),
- IvarT, 0,
- /*BitWidth=*/0, /*Mutable=*/true,
+ IvarT, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
ICIS_NoInit);
MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
FD->getType(), VK_LValue,
@@ -974,8 +984,8 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
if (GenGetProperty) {
// return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1)
Getr += "typedef ";
- const FunctionType *FPRetType = 0;
- RewriteTypeIntoString(PD->getGetterMethodDecl()->getResultType(), Getr,
+ const FunctionType *FPRetType = nullptr;
+ RewriteTypeIntoString(PD->getGetterMethodDecl()->getReturnType(), Getr,
FPRetType);
Getr += " _TYPE";
if (FPRetType) {
@@ -984,14 +994,15 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
// Now, emit the argument types (if any).
if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(FPRetType)){
Getr += "(";
- for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) {
+ for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) {
if (i) Getr += ", ";
- std::string ParamStr = FT->getArgType(i).getAsString(
- Context->getPrintingPolicy());
+ std::string ParamStr =
+ FT->getParamType(i).getAsString(Context->getPrintingPolicy());
Getr += ParamStr;
}
if (FT->isVariadic()) {
- if (FT->getNumArgs()) Getr += ", ";
+ if (FT->getNumParams())
+ Getr += ", ";
Getr += "...";
}
Getr += ")";
@@ -1150,18 +1161,13 @@ void RewriteModernObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
ReplaceText(LocStart, 0, "// ");
}
- for (ObjCCategoryDecl::prop_iterator I = CatDecl->prop_begin(),
- E = CatDecl->prop_end(); I != E; ++I)
- RewriteProperty(*I);
+ for (auto *I : CatDecl->properties())
+ RewriteProperty(I);
- for (ObjCCategoryDecl::instmeth_iterator
- I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end();
- I != E; ++I)
- RewriteMethodDeclaration(*I);
- for (ObjCCategoryDecl::classmeth_iterator
- I = CatDecl->classmeth_begin(), E = CatDecl->classmeth_end();
- I != E; ++I)
- RewriteMethodDeclaration(*I);
+ for (auto *I : CatDecl->instance_methods())
+ RewriteMethodDeclaration(I);
+ for (auto *I : CatDecl->class_methods())
+ RewriteMethodDeclaration(I);
// Lastly, comment out the @end.
ReplaceText(CatDecl->getAtEndRange().getBegin(),
@@ -1175,18 +1181,12 @@ void RewriteModernObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
// FIXME: handle protocol headers that are declared across multiple lines.
ReplaceText(LocStart, 0, "// ");
- for (ObjCProtocolDecl::instmeth_iterator
- I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
- I != E; ++I)
- RewriteMethodDeclaration(*I);
- for (ObjCProtocolDecl::classmeth_iterator
- I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
- I != E; ++I)
- RewriteMethodDeclaration(*I);
-
- for (ObjCInterfaceDecl::prop_iterator I = PDecl->prop_begin(),
- E = PDecl->prop_end(); I != E; ++I)
- RewriteProperty(*I);
+ for (auto *I : PDecl->instance_methods())
+ RewriteMethodDeclaration(I);
+ for (auto *I : PDecl->class_methods())
+ RewriteMethodDeclaration(I);
+ for (auto *I : PDecl->properties())
+ RewriteProperty(I);
// Lastly, comment out the @end.
SourceLocation LocEnd = PDecl->getAtEndRange().getBegin();
@@ -1257,8 +1257,8 @@ void RewriteModernObjC::RewriteTypeIntoString(QualType T, std::string &ResultStr
else if (const BlockPointerType *BPT = retType->getAs<BlockPointerType>())
PointeeTy = BPT->getPointeeType();
if ((FPRetType = PointeeTy->getAs<FunctionType>())) {
- ResultStr += FPRetType->getResultType().getAsString(
- Context->getPrintingPolicy());
+ ResultStr +=
+ FPRetType->getReturnType().getAsString(Context->getPrintingPolicy());
ResultStr += "(*";
}
} else
@@ -1269,9 +1269,9 @@ void RewriteModernObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,
ObjCMethodDecl *OMD,
std::string &ResultStr) {
//fprintf(stderr,"In RewriteObjCMethodDecl\n");
- const FunctionType *FPRetType = 0;
+ const FunctionType *FPRetType = nullptr;
ResultStr += "\nstatic ";
- RewriteTypeIntoString(OMD->getResultType(), ResultStr, FPRetType);
+ RewriteTypeIntoString(OMD->getReturnType(), ResultStr, FPRetType);
ResultStr += " ";
// Unique method name
@@ -1327,9 +1327,7 @@ void RewriteModernObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,
ResultStr += " _cmd";
// Method arguments.
- for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(),
- E = OMD->param_end(); PI != E; ++PI) {
- ParmVarDecl *PDecl = *PI;
+ for (const auto *PDecl : OMD->params()) {
ResultStr += ", ";
if (PDecl->getType()->isObjCQualifiedIdType()) {
ResultStr += "id ";
@@ -1353,14 +1351,15 @@ void RewriteModernObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,
// Now, emit the argument types (if any).
if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(FPRetType)) {
ResultStr += "(";
- for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) {
+ for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) {
if (i) ResultStr += ", ";
- std::string ParamStr = FT->getArgType(i).getAsString(
- Context->getPrintingPolicy());
+ std::string ParamStr =
+ FT->getParamType(i).getAsString(Context->getPrintingPolicy());
ResultStr += ParamStr;
}
if (FT->isVariadic()) {
- if (FT->getNumArgs()) ResultStr += ", ";
+ if (FT->getNumParams())
+ ResultStr += ", ";
ResultStr += "...";
}
ResultStr += ")";
@@ -1385,12 +1384,8 @@ void RewriteModernObjC::RewriteImplementationDecl(Decl *OID) {
else
InsertText(CID->getLocStart(), "// ");
- for (ObjCCategoryImplDecl::instmeth_iterator
- I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(),
- E = IMD ? IMD->instmeth_end() : CID->instmeth_end();
- I != E; ++I) {
+ for (auto *OMD : IMD ? IMD->instance_methods() : CID->instance_methods()) {
std::string ResultStr;
- ObjCMethodDecl *OMD = *I;
RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr);
SourceLocation LocStart = OMD->getLocStart();
SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart();
@@ -1400,12 +1395,8 @@ void RewriteModernObjC::RewriteImplementationDecl(Decl *OID) {
ReplaceText(LocStart, endBuf-startBuf, ResultStr);
}
- for (ObjCCategoryImplDecl::classmeth_iterator
- I = IMD ? IMD->classmeth_begin() : CID->classmeth_begin(),
- E = IMD ? IMD->classmeth_end() : CID->classmeth_end();
- I != E; ++I) {
+ for (auto *OMD : IMD ? IMD->class_methods() : CID->class_methods()) {
std::string ResultStr;
- ObjCMethodDecl *OMD = *I;
RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr);
SourceLocation LocStart = OMD->getLocStart();
SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart();
@@ -1414,12 +1405,8 @@ void RewriteModernObjC::RewriteImplementationDecl(Decl *OID) {
const char *endBuf = SM->getCharacterData(LocEnd);
ReplaceText(LocStart, endBuf-startBuf, ResultStr);
}
- for (ObjCCategoryImplDecl::propimpl_iterator
- I = IMD ? IMD->propimpl_begin() : CID->propimpl_begin(),
- E = IMD ? IMD->propimpl_end() : CID->propimpl_end();
- I != E; ++I) {
- RewritePropertyImplDecl(*I, IMD, CID);
- }
+ for (auto *I : IMD ? IMD->property_impls() : CID->property_impls())
+ RewritePropertyImplDecl(I, IMD, CID);
InsertText(IMD ? IMD->getLocEnd() : CID->getLocEnd(), "// ");
}
@@ -1444,17 +1431,12 @@ void RewriteModernObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
// Mark this typedef as having been written into its c++ equivalent.
ObjCWrittenInterfaces.insert(ClassDecl->getCanonicalDecl());
- for (ObjCInterfaceDecl::prop_iterator I = ClassDecl->prop_begin(),
- E = ClassDecl->prop_end(); I != E; ++I)
- RewriteProperty(*I);
- for (ObjCInterfaceDecl::instmeth_iterator
- I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end();
- I != E; ++I)
- RewriteMethodDeclaration(*I);
- for (ObjCInterfaceDecl::classmeth_iterator
- I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end();
- I != E; ++I)
- RewriteMethodDeclaration(*I);
+ for (auto *I : ClassDecl->properties())
+ RewriteProperty(I);
+ for (auto *I : ClassDecl->instance_methods())
+ RewriteMethodDeclaration(I);
+ for (auto *I : ClassDecl->class_methods())
+ RewriteMethodDeclaration(I);
// Lastly, comment out the @end.
ReplaceText(ClassDecl->getAtEndRange().getBegin(), strlen("@end"),
@@ -1479,7 +1461,7 @@ Stmt *RewriteModernObjC::RewritePropertyOrImplicitSetter(PseudoObjectExpr *Pseud
DisableReplaceStmtScope S(*this);
// Rebuild the base expression if we have one.
- Base = 0;
+ Base = nullptr;
if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) {
Base = OldMsg->getInstanceReceiver();
Base = cast<OpaqueValueExpr>(Base)->getSourceExpr();
@@ -1500,7 +1482,7 @@ Stmt *RewriteModernObjC::RewritePropertyOrImplicitSetter(PseudoObjectExpr *Pseud
SmallVector<SourceLocation, 1> SelLocs;
OldMsg->getSelectorLocs(SelLocs);
- ObjCMessageExpr *NewMsg = 0;
+ ObjCMessageExpr *NewMsg = nullptr;
switch (OldMsg->getReceiverKind()) {
case ObjCMessageExpr::Class:
NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
@@ -1560,7 +1542,7 @@ Stmt *RewriteModernObjC::RewritePropertyOrImplicitGetter(PseudoObjectExpr *Pseud
// Because the rewriter doesn't allow us to rewrite rewritten code,
// we need to suppress rewriting the sub-statements.
- Expr *Base = 0;
+ Expr *Base = nullptr;
SmallVector<Expr*, 1> Args;
{
DisableReplaceStmtScope S(*this);
@@ -1583,7 +1565,7 @@ Stmt *RewriteModernObjC::RewritePropertyOrImplicitGetter(PseudoObjectExpr *Pseud
// Intentionally empty.
SmallVector<SourceLocation, 1> SelLocs;
- ObjCMessageExpr *NewMsg = 0;
+ ObjCMessageExpr *NewMsg = nullptr;
switch (OldMsg->getReceiverKind()) {
case ObjCMessageExpr::Class:
NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
@@ -1667,7 +1649,7 @@ Stmt *RewriteModernObjC::RewriteBreakStmt(BreakStmt *S) {
buf += utostr(ObjCBcLabelNo.back());
ReplaceText(startLoc, strlen("break"), buf);
- return 0;
+ return nullptr;
}
void RewriteModernObjC::ConvertSourceLocationToLineDirective(
@@ -1697,7 +1679,7 @@ Stmt *RewriteModernObjC::RewriteContinueStmt(ContinueStmt *S) {
buf += utostr(ObjCBcLabelNo.back());
ReplaceText(startLoc, strlen("continue"), buf);
- return 0;
+ return nullptr;
}
/// RewriteObjCForCollectionStmt - Rewriter for ObjC2's foreach statement.
@@ -1896,7 +1878,7 @@ Stmt *RewriteModernObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
}
Stmts.pop_back();
ObjCBcLabelNo.pop_back();
- return 0;
+ return nullptr;
}
static void Write_RethrowObject(std::string &buf) {
@@ -1958,7 +1940,7 @@ Stmt *RewriteModernObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S)
ReplaceText(startRBraceLoc, 1, buf);
- return 0;
+ return nullptr;
}
void RewriteModernObjC::WarnAboutReturnGotoStmts(Stmt *S)
@@ -1980,8 +1962,8 @@ Stmt *RewriteModernObjC::RewriteObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt
ReplaceText(startLoc, strlen("@autoreleasepool"), "/* @autoreleasepool */");
ReplaceText(S->getSubStmt()->getLocStart(), 1,
"{ __AtAutoreleasePool __autoreleasepool; ");
-
- return 0;
+
+ return nullptr;
}
Stmt *RewriteModernObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
@@ -2082,7 +2064,7 @@ Stmt *RewriteModernObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
WarnAboutReturnGotoStmts(S->getTryBody());
}
- return 0;
+ return nullptr;
}
// This can't be done with ReplaceStmt(S, ThrowExpr), since
@@ -2114,17 +2096,14 @@ Stmt *RewriteModernObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) {
SourceLocation semiLoc = startLoc.getLocWithOffset(semiBuf-startBuf);
if (S->getThrowExpr())
ReplaceText(semiLoc, 1, ");");
- return 0;
+ return nullptr;
}
Stmt *RewriteModernObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) {
// Create a new string expression.
- QualType StrType = Context->getPointerType(Context->CharTy);
std::string StrEncoding;
Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding);
- Expr *Replacement = StringLiteral::Create(*Context, StrEncoding,
- StringLiteral::Ascii, false,
- StrType, SourceLocation());
+ Expr *Replacement = getStringLiteral(StrEncoding);
ReplaceStmt(Exp, Replacement);
// Replace this subexpr in the parent.
@@ -2138,11 +2117,7 @@ Stmt *RewriteModernObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) {
assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
// Create a call to sel_registerName("selName").
SmallVector<Expr*, 8> SelExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
- SelExprs.push_back(StringLiteral::Create(*Context,
- Exp->getSelector().getAsString(),
- StringLiteral::Ascii, false,
- argType, SourceLocation()));
+ SelExprs.push_back(getStringLiteral(Exp->getSelector().getAsString()));
CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
&SelExprs[0], SelExprs.size());
ReplaceStmt(Exp, SelExp);
@@ -2164,7 +2139,7 @@ CallExpr *RewriteModernObjC::SynthesizeCallToFunctionDecl(
QualType pToFunc = Context->getPointerType(msgSendType);
ImplicitCastExpr *ICE =
ImplicitCastExpr::Create(*Context, pToFunc, CK_FunctionToPointerDecay,
- DRE, 0, VK_RValue);
+ DRE, nullptr, VK_RValue);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
@@ -2240,7 +2215,7 @@ void RewriteModernObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) {
const char *startBuf = SM->getCharacterData(Loc);
const char *endBuf = SM->getCharacterData(EndLoc);
- const char *startRef = 0, *endRef = 0;
+ const char *startRef = nullptr, *endRef = nullptr;
if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
// Get the locations of the startRef, endRef.
SourceLocation LessLoc = Loc.getLocWithOffset(startRef-startBuf);
@@ -2255,7 +2230,7 @@ void RewriteModernObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) {
void RewriteModernObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
SourceLocation Loc;
QualType Type;
- const FunctionProtoType *proto = 0;
+ const FunctionProtoType *proto = nullptr;
if (VarDecl *VD = dyn_cast<VarDecl>(Dcl)) {
Loc = VD->getLocation();
Type = VD->getType();
@@ -2269,7 +2244,7 @@ void RewriteModernObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
proto = dyn_cast<FunctionProtoType>(funcType);
if (!proto)
return;
- Type = proto->getResultType();
+ Type = proto->getReturnType();
}
else if (FieldDecl *FD = dyn_cast<FieldDecl>(Dcl)) {
Loc = FD->getLocation();
@@ -2289,7 +2264,7 @@ void RewriteModernObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
const char *startBuf = endBuf;
while (*startBuf != ';' && *startBuf != '<' && startBuf != MainFileStart)
startBuf--; // scan backward (from the decl location) for return type.
- const char *startRef = 0, *endRef = 0;
+ const char *startRef = nullptr, *endRef = nullptr;
if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
// Get the locations of the startRef, endRef.
SourceLocation LessLoc = Loc.getLocWithOffset(startRef-endBuf);
@@ -2304,14 +2279,14 @@ void RewriteModernObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
// Now check arguments.
const char *startBuf = SM->getCharacterData(Loc);
const char *startFuncBuf = startBuf;
- for (unsigned i = 0; i < proto->getNumArgs(); i++) {
- if (needToScanForQualifiers(proto->getArgType(i))) {
+ for (unsigned i = 0; i < proto->getNumParams(); i++) {
+ if (needToScanForQualifiers(proto->getParamType(i))) {
// Since types are unique, we need to scan the buffer.
const char *endBuf = startBuf;
// scan forward (from the decl location) for argument types.
scanToNextArgument(endBuf);
- const char *startRef = 0, *endRef = 0;
+ const char *startRef = nullptr, *endRef = nullptr;
if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
// Get the locations of the startRef, endRef.
SourceLocation LessLoc =
@@ -2380,8 +2355,8 @@ void RewriteModernObjC::SynthSelGetUidFunctionDecl() {
SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
- SelGetUidIdent, getFuncType, 0,
- SC_Extern);
+ SelGetUidIdent, getFuncType,
+ nullptr, SC_Extern);
}
void RewriteModernObjC::RewriteFunctionDecl(FunctionDecl *FD) {
@@ -2443,14 +2418,14 @@ void RewriteModernObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) {
const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(funcType);
if (!proto)
return;
- QualType Type = proto->getResultType();
+ QualType Type = proto->getReturnType();
std::string FdStr = Type.getAsString(Context->getPrintingPolicy());
FdStr += " ";
FdStr += FD->getName();
FdStr += "(";
- unsigned numArgs = proto->getNumArgs();
+ unsigned numArgs = proto->getNumParams();
for (unsigned i = 0; i < numArgs; i++) {
- QualType ArgType = proto->getArgType(i);
+ QualType ArgType = proto->getParamType(i);
RewriteBlockPointerType(FdStr, ArgType);
if (i+1 < numArgs)
FdStr += ", ";
@@ -2479,7 +2454,7 @@ void RewriteModernObjC::SynthSuperConstructorFunctionDecl() {
SourceLocation(),
SourceLocation(),
msgSendIdent, msgSendType,
- 0, SC_Extern);
+ nullptr, SC_Extern);
}
// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
@@ -2497,7 +2472,7 @@ void RewriteModernObjC::SynthMsgSendFunctionDecl() {
MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
- msgSendIdent, msgSendType, 0,
+ msgSendIdent, msgSendType, nullptr,
SC_Extern);
}
@@ -2511,8 +2486,8 @@ void RewriteModernObjC::SynthMsgSendSuperFunctionDecl() {
MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern);
+ msgSendIdent, msgSendType,
+ nullptr, SC_Extern);
}
// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...);
@@ -2530,8 +2505,8 @@ void RewriteModernObjC::SynthMsgSendStretFunctionDecl() {
MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern);
+ msgSendIdent, msgSendType,
+ nullptr, SC_Extern);
}
// SynthMsgSendSuperStretFunctionDecl -
@@ -2547,7 +2522,7 @@ void RewriteModernObjC::SynthMsgSendSuperStretFunctionDecl() {
SourceLocation(),
SourceLocation(),
msgSendIdent,
- msgSendType, 0,
+ msgSendType, nullptr,
SC_Extern);
}
@@ -2566,8 +2541,8 @@ void RewriteModernObjC::SynthMsgSendFpretFunctionDecl() {
MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern);
+ msgSendIdent, msgSendType,
+ nullptr, SC_Extern);
}
// SynthGetClassFunctionDecl - Class objc_getClass(const char *name);
@@ -2580,8 +2555,8 @@ void RewriteModernObjC::SynthGetClassFunctionDecl() {
GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
- getClassIdent, getClassType, 0,
- SC_Extern);
+ getClassIdent, getClassType,
+ nullptr, SC_Extern);
}
// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls);
@@ -2596,7 +2571,7 @@ void RewriteModernObjC::SynthGetSuperClassFunctionDecl() {
SourceLocation(),
SourceLocation(),
getSuperClassIdent,
- getClassType, 0,
+ getClassType, nullptr,
SC_Extern);
}
@@ -2611,10 +2586,11 @@ void RewriteModernObjC::SynthGetMetaClassFunctionDecl() {
SourceLocation(),
SourceLocation(),
getClassIdent, getClassType,
- 0, SC_Extern);
+ nullptr, SC_Extern);
}
Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
+ assert (Exp != nullptr && "Expected non-null ObjCStringLiteral");
QualType strType = getConstantStringStructType();
std::string S = "__NSConstantStringImpl_";
@@ -2623,7 +2599,7 @@ Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
unsigned i;
for (i=0; i < tmpName.length(); i++) {
char c = tmpName.at(i);
- // replace any non alphanumeric characters with '_'.
+ // replace any non-alphanumeric characters with '_'.
if (!isAlphanumeric(c))
tmpName[i] = '_';
}
@@ -2637,14 +2613,14 @@ Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
// The pretty printer for StringLiteral handles escape characters properly.
std::string prettyBufS;
llvm::raw_string_ostream prettyBuf(prettyBufS);
- Exp->getString()->printPretty(prettyBuf, 0, PrintingPolicy(LangOpts));
+ Exp->getString()->printPretty(prettyBuf, nullptr, PrintingPolicy(LangOpts));
Preamble += prettyBuf.str();
Preamble += ",";
Preamble += utostr(Exp->getString()->getByteLength()) + "};\n";
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), &Context->Idents.get(S),
- strType, 0, SC_Static);
+ strType, nullptr, SC_Static);
DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, strType, VK_LValue,
SourceLocation());
Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf,
@@ -2691,17 +2667,13 @@ Stmt *RewriteModernObjC::RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp) {
// Synthesize a call to objc_msgSend().
SmallVector<Expr*, 4> MsgExprs;
SmallVector<Expr*, 4> ClsExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
// Create a call to objc_getClass("<BoxingClass>"). It will be the 1st argument.
ObjCMethodDecl *BoxingMethod = Exp->getBoxingMethod();
ObjCInterfaceDecl *BoxingClass = BoxingMethod->getClassInterface();
IdentifierInfo *clsName = BoxingClass->getIdentifier();
- ClsExprs.push_back(StringLiteral::Create(*Context,
- clsName->getName(),
- StringLiteral::Ascii, false,
- argType, SourceLocation()));
+ ClsExprs.push_back(getStringLiteral(clsName->getName()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
@@ -2711,10 +2683,8 @@ Stmt *RewriteModernObjC::RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp) {
// Create a call to sel_registerName("<BoxingMethod>:"), etc.
// it will be the 2nd argument.
SmallVector<Expr*, 4> SelExprs;
- SelExprs.push_back(StringLiteral::Create(*Context,
- BoxingMethod->getSelector().getAsString(),
- StringLiteral::Ascii, false,
- argType, SourceLocation()));
+ SelExprs.push_back(
+ getStringLiteral(BoxingMethod->getSelector().getAsString()));
CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
&SelExprs[0], SelExprs.size(),
StartLoc, EndLoc);
@@ -2735,9 +2705,8 @@ Stmt *RewriteModernObjC::RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp) {
SmallVector<QualType, 4> ArgTypes;
ArgTypes.push_back(Context->getObjCIdType());
ArgTypes.push_back(Context->getObjCSelType());
- for (ObjCMethodDecl::param_iterator PI = BoxingMethod->param_begin(),
- E = BoxingMethod->param_end(); PI != E; ++PI)
- ArgTypes.push_back((*PI)->getType());
+ for (const auto PI : BoxingMethod->parameters())
+ ArgTypes.push_back(PI->getType());
QualType returnType = Exp->getType();
// Get the type, we will need to reference it in a couple spots.
@@ -2762,9 +2731,8 @@ Stmt *RewriteModernObjC::RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp) {
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs,
- FT->getResultType(), VK_RValue,
- EndLoc);
+ CallExpr *CE = new (Context)
+ CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc);
ReplaceStmt(Exp, CE);
return CE;
}
@@ -2806,13 +2774,13 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
Expr *NSArrayCallExpr =
new (Context) CallExpr(*Context, NSArrayDRE, InitExprs,
NSArrayFType, VK_LValue, SourceLocation());
-
- FieldDecl *ARRFD = FieldDecl::Create(*Context, 0, SourceLocation(),
+
+ FieldDecl *ARRFD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("arr"),
- Context->getPointerType(Context->VoidPtrTy), 0,
- /*BitWidth=*/0, /*Mutable=*/true,
- ICIS_NoInit);
+ Context->getPointerType(Context->VoidPtrTy),
+ nullptr, /*BitWidth=*/nullptr,
+ /*Mutable=*/true, ICIS_NoInit);
MemberExpr *ArrayLiteralME =
new (Context) MemberExpr(NSArrayCallExpr, false, ARRFD,
SourceLocation(),
@@ -2828,7 +2796,6 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
// Synthesize a call to objc_msgSend().
SmallVector<Expr*, 32> MsgExprs;
SmallVector<Expr*, 4> ClsExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
QualType expType = Exp->getType();
// Create a call to objc_getClass("NSArray"). It will be th 1st argument.
@@ -2836,10 +2803,7 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
expType->getPointeeType()->getAs<ObjCObjectType>()->getInterface();
IdentifierInfo *clsName = Class->getIdentifier();
- ClsExprs.push_back(StringLiteral::Create(*Context,
- clsName->getName(),
- StringLiteral::Ascii, false,
- argType, SourceLocation()));
+ ClsExprs.push_back(getStringLiteral(clsName->getName()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
@@ -2850,10 +2814,8 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
// it will be the 2nd argument.
SmallVector<Expr*, 4> SelExprs;
ObjCMethodDecl *ArrayMethod = Exp->getArrayWithObjectsMethod();
- SelExprs.push_back(StringLiteral::Create(*Context,
- ArrayMethod->getSelector().getAsString(),
- StringLiteral::Ascii, false,
- argType, SourceLocation()));
+ SelExprs.push_back(
+ getStringLiteral(ArrayMethod->getSelector().getAsString()));
CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
&SelExprs[0], SelExprs.size(),
StartLoc, EndLoc);
@@ -2872,9 +2834,8 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
SmallVector<QualType, 4> ArgTypes;
ArgTypes.push_back(Context->getObjCIdType());
ArgTypes.push_back(Context->getObjCSelType());
- for (ObjCMethodDecl::param_iterator PI = ArrayMethod->param_begin(),
- E = ArrayMethod->param_end(); PI != E; ++PI)
- ArgTypes.push_back((*PI)->getType());
+ for (const auto *PI : ArrayMethod->params())
+ ArgTypes.push_back(PI->getType());
QualType returnType = Exp->getType();
// Get the type, we will need to reference it in a couple spots.
@@ -2899,9 +2860,8 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs,
- FT->getResultType(), VK_RValue,
- EndLoc);
+ CallExpr *CE = new (Context)
+ CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc);
ReplaceStmt(Exp, CE);
return CE;
}
@@ -2951,13 +2911,13 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
Expr *NSValueCallExpr =
new (Context) CallExpr(*Context, NSDictDRE, ValueExprs,
NSDictFType, VK_LValue, SourceLocation());
-
- FieldDecl *ARRFD = FieldDecl::Create(*Context, 0, SourceLocation(),
+
+ FieldDecl *ARRFD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("arr"),
- Context->getPointerType(Context->VoidPtrTy), 0,
- /*BitWidth=*/0, /*Mutable=*/true,
- ICIS_NoInit);
+ Context->getPointerType(Context->VoidPtrTy),
+ nullptr, /*BitWidth=*/nullptr,
+ /*Mutable=*/true, ICIS_NoInit);
MemberExpr *DictLiteralValueME =
new (Context) MemberExpr(NSValueCallExpr, false, ARRFD,
SourceLocation(),
@@ -2991,7 +2951,6 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
// Synthesize a call to objc_msgSend().
SmallVector<Expr*, 32> MsgExprs;
SmallVector<Expr*, 4> ClsExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
QualType expType = Exp->getType();
// Create a call to objc_getClass("NSArray"). It will be th 1st argument.
@@ -2999,10 +2958,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
expType->getPointeeType()->getAs<ObjCObjectType>()->getInterface();
IdentifierInfo *clsName = Class->getIdentifier();
- ClsExprs.push_back(StringLiteral::Create(*Context,
- clsName->getName(),
- StringLiteral::Ascii, false,
- argType, SourceLocation()));
+ ClsExprs.push_back(getStringLiteral(clsName->getName()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
@@ -3013,10 +2969,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
// it will be the 2nd argument.
SmallVector<Expr*, 4> SelExprs;
ObjCMethodDecl *DictMethod = Exp->getDictWithObjectsMethod();
- SelExprs.push_back(StringLiteral::Create(*Context,
- DictMethod->getSelector().getAsString(),
- StringLiteral::Ascii, false,
- argType, SourceLocation()));
+ SelExprs.push_back(getStringLiteral(DictMethod->getSelector().getAsString()));
CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
&SelExprs[0], SelExprs.size(),
StartLoc, EndLoc);
@@ -3038,9 +2991,8 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
SmallVector<QualType, 8> ArgTypes;
ArgTypes.push_back(Context->getObjCIdType());
ArgTypes.push_back(Context->getObjCSelType());
- for (ObjCMethodDecl::param_iterator PI = DictMethod->param_begin(),
- E = DictMethod->param_end(); PI != E; ++PI) {
- QualType T = (*PI)->getType();
+ for (const auto *PI : DictMethod->params()) {
+ QualType T = PI->getType();
if (const PointerType* PT = T->getAs<PointerType>()) {
QualType PointeeTy = PT->getPointeeType();
convertToUnqualifiedObjCType(PointeeTy);
@@ -3072,9 +3024,8 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs,
- FT->getResultType(), VK_RValue,
- EndLoc);
+ CallExpr *CE = new (Context)
+ CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc);
ReplaceStmt(Exp, CE);
return CE;
}
@@ -3098,9 +3049,9 @@ QualType RewriteModernObjC::getSuperStructType() {
for (unsigned i = 0; i < 2; ++i) {
SuperStructDecl->addDecl(FieldDecl::Create(*Context, SuperStructDecl,
SourceLocation(),
- SourceLocation(), 0,
- FieldTypes[i], 0,
- /*BitWidth=*/0,
+ SourceLocation(), nullptr,
+ FieldTypes[i], nullptr,
+ /*BitWidth=*/nullptr,
/*Mutable=*/false,
ICIS_NoInit));
}
@@ -3131,9 +3082,9 @@ QualType RewriteModernObjC::getConstantStringStructType() {
ConstantStringDecl->addDecl(FieldDecl::Create(*Context,
ConstantStringDecl,
SourceLocation(),
- SourceLocation(), 0,
- FieldTypes[i], 0,
- /*BitWidth=*/0,
+ SourceLocation(), nullptr,
+ FieldTypes[i], nullptr,
+ /*BitWidth=*/nullptr,
/*Mutable=*/true,
ICIS_NoInit));
}
@@ -3284,19 +3235,19 @@ Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFla
// AST for __Stretn(receiver, args).s;
IdentifierInfo *ID = &Context->Idents.get(name);
FunctionDecl *FD = FunctionDecl::Create(*Context, TUDecl, SourceLocation(),
- SourceLocation(), ID, castType, 0,
- SC_Extern, false, false);
+ SourceLocation(), ID, castType,
+ nullptr, SC_Extern, false, false);
DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, castType, VK_RValue,
SourceLocation());
CallExpr *STCE = new (Context) CallExpr(*Context, DRE, MsgExprs,
castType, VK_LValue, SourceLocation());
-
- FieldDecl *FieldD = FieldDecl::Create(*Context, 0, SourceLocation(),
+
+ FieldDecl *FieldD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("s"),
- returnType, 0,
- /*BitWidth=*/0, /*Mutable=*/true,
- ICIS_NoInit);
+ returnType, nullptr,
+ /*BitWidth=*/nullptr,
+ /*Mutable=*/true, ICIS_NoInit);
MemberExpr *ME = new (Context) MemberExpr(STCE, false, FieldD, SourceLocation(),
FieldD->getType(), VK_LValue,
OK_Ordinary);
@@ -3329,9 +3280,9 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// default to objc_msgSend().
FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl;
// May need to use objc_msgSend_stret() as well.
- FunctionDecl *MsgSendStretFlavor = 0;
+ FunctionDecl *MsgSendStretFlavor = nullptr;
if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) {
- QualType resultType = mDecl->getResultType();
+ QualType resultType = mDecl->getReturnType();
if (resultType->isRecordType())
MsgSendStretFlavor = MsgSendStretFunctionDecl;
else if (resultType->isRealFloatingType())
@@ -3364,11 +3315,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
SmallVector<Expr*, 8> ClsExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
- ClsExprs.push_back(StringLiteral::Create(*Context,
- ClassDecl->getIdentifier()->getName(),
- StringLiteral::Ascii, false,
- argType, SourceLocation()));
+ ClsExprs.push_back(getStringLiteral(ClassDecl->getIdentifier()->getName()));
// (Class)objc_getClass("CurrentClass")
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
&ClsExprs[0],
@@ -3435,14 +3382,10 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
case ObjCMessageExpr::Class: {
SmallVector<Expr*, 8> ClsExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
ObjCInterfaceDecl *Class
= Exp->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
IdentifierInfo *clsName = Class->getIdentifier();
- ClsExprs.push_back(StringLiteral::Create(*Context,
- clsName->getName(),
- StringLiteral::Ascii, false,
- argType, SourceLocation()));
+ ClsExprs.push_back(getStringLiteral(clsName->getName()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
@@ -3473,11 +3416,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
SmallVector<Expr*, 8> ClsExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
- ClsExprs.push_back(StringLiteral::Create(*Context,
- ClassDecl->getIdentifier()->getName(),
- StringLiteral::Ascii, false, argType,
- SourceLocation()));
+ ClsExprs.push_back(getStringLiteral(ClassDecl->getIdentifier()->getName()));
// (Class)objc_getClass("CurrentClass")
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
&ClsExprs[0],
@@ -3555,11 +3494,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// Create a call to sel_registerName("selName"), it will be the 2nd argument.
SmallVector<Expr*, 8> SelExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
- SelExprs.push_back(StringLiteral::Create(*Context,
- Exp->getSelector().getAsString(),
- StringLiteral::Ascii, false,
- argType, SourceLocation()));
+ SelExprs.push_back(getStringLiteral(Exp->getSelector().getAsString()));
CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
&SelExprs[0], SelExprs.size(),
StartLoc,
@@ -3634,11 +3569,10 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
ArgTypes.push_back(Context->getObjCSelType());
if (ObjCMethodDecl *OMD = Exp->getMethodDecl()) {
// Push any user argument types.
- for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(),
- E = OMD->param_end(); PI != E; ++PI) {
- QualType t = (*PI)->getType()->isObjCQualifiedIdType()
+ for (const auto *PI : OMD->params()) {
+ QualType t = PI->getType()->isObjCQualifiedIdType()
? Context->getObjCIdType()
- : (*PI)->getType();
+ : PI->getType();
// Make sure we convert "t (^)(...)" to "t (*)(...)".
(void)convertBlockPointerToFunctionPointer(t);
ArgTypes.push_back(t);
@@ -3677,8 +3611,8 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs,
- FT->getResultType(), VK_RValue, EndLoc);
+ CallExpr *CE = new (Context)
+ CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc);
Stmt *ReplacingStmt = CE;
if (MsgSendStretFlavor) {
// We have the method which returns a struct/union. Must also generate
@@ -3729,16 +3663,13 @@ Stmt *RewriteModernObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
Exp->getProtocol()->getNameAsString();
IdentifierInfo *ID = &Context->Idents.get(Name);
VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
- SourceLocation(), ID, getProtocolType(), 0,
- SC_Extern);
+ SourceLocation(), ID, getProtocolType(),
+ nullptr, SC_Extern);
DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, false, getProtocolType(),
VK_LValue, SourceLocation());
- Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf,
- Context->getPointerType(DRE->getType()),
- VK_RValue, OK_Ordinary, SourceLocation());
- CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(),
- CK_BitCast,
- DerefExpr);
+ CastExpr *castExpr =
+ NoTypeInfoCStyleCastExpr(
+ Context, Context->getPointerType(DRE->getType()), CK_BitCast, DRE);
ReplaceStmt(Exp, castExpr);
ProtocolExprDecls.insert(Exp->getProtocol()->getCanonicalDecl());
// delete Exp; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.
@@ -3831,11 +3762,8 @@ bool RewriteModernObjC::RewriteObjCFieldDeclType(QualType &Type,
return true;
}
Result += " {\n";
- for (RecordDecl::field_iterator i = RD->field_begin(),
- e = RD->field_end(); i != e; ++i) {
- FieldDecl *FD = *i;
+ for (auto *FD : RD->fields())
RewriteObjCFieldDecl(FD, Result);
- }
Result += "\t} ";
return true;
}
@@ -3852,8 +3780,7 @@ bool RewriteModernObjC::RewriteObjCFieldDeclType(QualType &Type,
}
Result += " {\n";
- for (EnumDecl::enumerator_iterator EC = ED->enumerator_begin(),
- ECEnd = ED->enumerator_end(); EC != ECEnd; ++EC) {
+ for (const auto *EC : ED->enumerators()) {
Result += "\t"; Result += EC->getName(); Result += " = ";
llvm::APSInt Val = EC->getInitVal();
Result += Val.toString(10);
@@ -3911,8 +3838,8 @@ void RewriteModernObjC::RewriteLocallyDefinedNamedAggregates(FieldDecl *fieldDec
Type = Context->getBaseElementType(Type);
ObjCContainerDecl *IDecl =
dyn_cast<ObjCContainerDecl>(fieldDecl->getDeclContext());
-
- TagDecl *TD = 0;
+
+ TagDecl *TD = nullptr;
if (Type->isRecordType()) {
TD = Type->getAs<RecordType>()->getDecl();
}
@@ -3973,8 +3900,8 @@ QualType RewriteModernObjC::SynthesizeBitfieldGroupStructType(
RD->addDecl(FieldDecl::Create(*Context, RD, SourceLocation(), SourceLocation(),
&Context->Idents.get(Ivar->getName()),
Ivar->getType(),
- 0, /*Expr *BW */Ivar->getBitWidth(), false,
- ICIS_NoInit));
+ nullptr, /*Expr *BW */Ivar->getBitWidth(),
+ false, ICIS_NoInit));
}
RD->completeDefinition();
return Context->getTagDeclType(RD);
@@ -4226,7 +4153,7 @@ std::string RewriteModernObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
StringRef funcName,
std::string Tag) {
const FunctionType *AFT = CE->getFunctionType();
- QualType RT = AFT->getResultType();
+ QualType RT = AFT->getReturnType();
std::string StructRef = "struct " + Tag;
SourceLocation BlockLoc = CE->getExprLoc();
std::string S;
@@ -4604,12 +4531,12 @@ void RewriteModernObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
std::string SStr;
llvm::raw_string_ostream constructorExprBuf(SStr);
- GlobalConstructionExp->printPretty(constructorExprBuf, 0,
- PrintingPolicy(LangOpts));
+ GlobalConstructionExp->printPretty(constructorExprBuf, nullptr,
+ PrintingPolicy(LangOpts));
globalBuf += constructorExprBuf.str();
globalBuf += ";\n";
InsertText(FunLocStart, globalBuf);
- GlobalConstructionExp = 0;
+ GlobalConstructionExp = nullptr;
}
Blocks.clear();
@@ -4731,13 +4658,12 @@ QualType RewriteModernObjC::convertFunctionTypeOfBlocks(const FunctionType *FT)
// FTP will be null for closures that don't take arguments.
// Generate a funky cast.
SmallVector<QualType, 8> ArgTypes;
- QualType Res = FT->getResultType();
+ QualType Res = FT->getReturnType();
bool modified = convertObjCTypeToCStyleType(Res);
if (FTP) {
- for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
- E = FTP->arg_type_end(); I && (I != E); ++I) {
- QualType t = *I;
+ for (auto &I : FTP->param_types()) {
+ QualType t = I;
// Make sure we convert "t (^)(...)" to "t (*)(...)".
if (convertObjCTypeToCStyleType(t))
modified = true;
@@ -4753,7 +4679,7 @@ QualType RewriteModernObjC::convertFunctionTypeOfBlocks(const FunctionType *FT)
Stmt *RewriteModernObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
// Navigate to relevant type information.
- const BlockPointerType *CPT = 0;
+ const BlockPointerType *CPT = nullptr;
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BlockExp)) {
CPT = DRE->getType()->getAs<BlockPointerType>();
@@ -4803,9 +4729,8 @@ Stmt *RewriteModernObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp
// Push the block argument type.
ArgTypes.push_back(PtrBlock);
if (FTP) {
- for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
- E = FTP->arg_type_end(); I && (I != E); ++I) {
- QualType t = *I;
+ for (auto &I : FTP->param_types()) {
+ QualType t = I;
// Make sure we convert "t (^)(...)" to "t (*)(...)".
if (!convertBlockPointerToFunctionPointer(t))
convertToUnqualifiedObjCType(t);
@@ -4825,11 +4750,11 @@ Stmt *RewriteModernObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp
BlkCast);
//PE->dump();
- FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("FuncPtr"),
- Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true,
+ Context->VoidPtrTy, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
ICIS_NoInit);
MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
FD->getType(), VK_LValue,
@@ -4872,12 +4797,12 @@ Stmt *RewriteModernObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) {
// for each DeclRefExp where BYREFVAR is name of the variable.
ValueDecl *VD = DeclRefExp->getDecl();
bool isArrow = DeclRefExp->refersToEnclosingLocal();
-
- FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+
+ FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("__forwarding"),
- Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true,
+ Context->VoidPtrTy, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
ICIS_NoInit);
MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow,
FD, SourceLocation(),
@@ -4885,10 +4810,10 @@ Stmt *RewriteModernObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) {
OK_Ordinary);
StringRef Name = VD->getName();
- FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
+ FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(),
&Context->Idents.get(Name),
- Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true,
+ Context->VoidPtrTy, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
ICIS_NoInit);
ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(),
DeclRefExp->getType(), VK_LValue, OK_Ordinary);
@@ -5023,9 +4948,8 @@ bool RewriteModernObjC::PointerTypeTakesAnyBlockArguments(QualType QT) {
FTP = BPT->getPointeeType()->getAs<FunctionProtoType>();
}
if (FTP) {
- for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
- E = FTP->arg_type_end(); I != E; ++I)
- if (isTopLevelBlockPointerType(*I))
+ for (const auto &I : FTP->param_types())
+ if (isTopLevelBlockPointerType(I))
return true;
}
return false;
@@ -5042,12 +4966,11 @@ bool RewriteModernObjC::PointerTypeTakesAnyObjCQualifiedType(QualType QT) {
FTP = BPT->getPointeeType()->getAs<FunctionProtoType>();
}
if (FTP) {
- for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
- E = FTP->arg_type_end(); I != E; ++I) {
- if ((*I)->isObjCQualifiedIdType())
+ for (const auto &I : FTP->param_types()) {
+ if (I->isObjCQualifiedIdType())
return true;
- if ((*I)->isObjCObjectPointerType() &&
- (*I)->getPointeeType()->isObjCQualifiedInterfaceType())
+ if (I->isObjCObjectPointerType() &&
+ I->getPointeeType()->isObjCQualifiedInterfaceType())
return true;
}
@@ -5295,7 +5218,7 @@ void RewriteModernObjC::RewriteByRefVar(VarDecl *ND, bool firstDecl,
// struct __Block_byref_ND ND =
// {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND),
// initializer-if-any};
- bool hasInit = (ND->getInit() != 0);
+ bool hasInit = (ND->getInit() != nullptr);
// FIXME. rewriter does not support __block c++ objects which
// require construction.
if (hasInit)
@@ -5409,7 +5332,7 @@ FunctionDecl *RewriteModernObjC::SynthBlockInitFunctionDecl(StringRef name) {
IdentifierInfo *ID = &Context->Idents.get(name);
QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy);
return FunctionDecl::Create(*Context, TUDecl, SourceLocation(),
- SourceLocation(), ID, FType, 0, SC_Extern,
+ SourceLocation(), ID, FType, nullptr, SC_Extern,
false, false);
}
@@ -5510,7 +5433,7 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl,
SourceLocation(), SourceLocation(),
&Context->Idents.get(DescData.c_str()),
- Context->VoidPtrTy, 0,
+ Context->VoidPtrTy, nullptr,
SC_Static);
UnaryOperator *DescRefExpr =
new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD, false,
@@ -5580,11 +5503,10 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
SourceLocation());
bool isNestedCapturedVar = false;
if (block)
- for (BlockDecl::capture_const_iterator ci = block->capture_begin(),
- ce = block->capture_end(); ci != ce; ++ci) {
- const VarDecl *variable = ci->getVariable();
- if (variable == ND && ci->isNested()) {
- assert (ci->isByRef() &&
+ for (const auto &CI : block->captures()) {
+ const VarDecl *variable = CI.getVariable();
+ if (variable == ND && CI.isNested()) {
+ assert (CI.isByRef() &&
"SynthBlockInitExpr - captured block variable is not byref");
isNestedCapturedVar = true;
break;
@@ -5613,7 +5535,7 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
FType, VK_LValue, SourceLocation());
if (GlobalBlockExpr) {
- assert (GlobalConstructionExp == 0 &&
+ assert (!GlobalConstructionExp &&
"SynthBlockInitExpr - GlobalConstructionExp must be null");
GlobalConstructionExp = NewRep;
NewRep = DRE;
@@ -5689,7 +5611,7 @@ Stmt *RewriteModernObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
// Rewrite the block body in place.
Stmt *SaveCurrentBody = CurrentBody;
CurrentBody = BE->getBody();
- PropParentMap = 0;
+ PropParentMap = nullptr;
// block literal on rhs of a property-dot-sytax assignment
// must be replaced by its synthesize ast so getRewrittenText
// works as expected. In this case, what actually ends up on RHS
@@ -5700,7 +5622,7 @@ Stmt *RewriteModernObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
RewriteFunctionBodyOrGlobalInitializer(BE->getBody());
DisableReplaceStmt = saveDisableReplaceStmt;
CurrentBody = SaveCurrentBody;
- PropParentMap = 0;
+ PropParentMap = nullptr;
ImportedLocalExternalDecls.clear();
// Now we snarf the rewritten text and stash it away for later use.
std::string Str = Rewrite.getRewrittenText(BE->getSourceRange());
@@ -5887,9 +5809,7 @@ Stmt *RewriteModernObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
}
void RewriteModernObjC::RewriteRecordBody(RecordDecl *RD) {
- for (RecordDecl::field_iterator i = RD->field_begin(),
- e = RD->field_end(); i != e; ++i) {
- FieldDecl *FD = *i;
+ for (auto *FD : RD->fields()) {
if (isTopLevelBlockPointerType(FD->getType()))
RewriteBlockPointerDecl(FD);
if (FD->getType()->isObjCQualifiedIdType() ||
@@ -5922,16 +5842,16 @@ void RewriteModernObjC::HandleDeclInMainFile(Decl *D) {
Body =
cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
FD->setBody(Body);
- CurrentBody = 0;
+ CurrentBody = nullptr;
if (PropParentMap) {
delete PropParentMap;
- PropParentMap = 0;
+ PropParentMap = nullptr;
}
// This synthesizes and inserts the block "impl" struct, invoke function,
// and any copy/dispose helper functions.
InsertBlockLiteralsWithinFunction(FD);
RewriteLineDirective(D);
- CurFunctionDef = 0;
+ CurFunctionDef = nullptr;
}
break;
}
@@ -5943,14 +5863,14 @@ void RewriteModernObjC::HandleDeclInMainFile(Decl *D) {
Body =
cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
MD->setBody(Body);
- CurrentBody = 0;
+ CurrentBody = nullptr;
if (PropParentMap) {
delete PropParentMap;
- PropParentMap = 0;
+ PropParentMap = nullptr;
}
InsertBlockLiteralsWithinMethod(MD);
RewriteLineDirective(D);
- CurMethodDef = 0;
+ CurMethodDef = nullptr;
}
break;
}
@@ -5985,14 +5905,14 @@ void RewriteModernObjC::HandleDeclInMainFile(Decl *D) {
GlobalVarDecl = VD;
CurrentBody = VD->getInit();
RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
- CurrentBody = 0;
+ CurrentBody = nullptr;
if (PropParentMap) {
delete PropParentMap;
- PropParentMap = 0;
+ PropParentMap = nullptr;
}
SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName());
- GlobalVarDecl = 0;
-
+ GlobalVarDecl = nullptr;
+
// This is needed for blocks.
if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) {
RewriteCastExpr(CE);
@@ -6049,9 +5969,9 @@ void RewriteModernObjC::HandleTranslationUnit(ASTContext &C) {
RewriteInclude();
for (unsigned i = 0, e = FunctionDefinitionsSeen.size(); i < e; i++) {
- // translation of function bodies were postponed untill all class and
+ // translation of function bodies were postponed until all class and
// their extensions and implementations are seen. This is because, we
- // cannot build grouping structs for bitfields untill they are all seen.
+ // cannot build grouping structs for bitfields until they are all seen.
FunctionDecl *FDecl = FunctionDefinitionsSeen[i];
HandleTopLevelSingleDecl(FDecl);
}
@@ -6192,7 +6112,11 @@ void RewriteModernObjC::Initialize(ASTContext &context) {
Preamble += " int *isa;\n";
Preamble += " int flags;\n";
Preamble += " char *str;\n";
+ Preamble += "#if _WIN64\n";
+ Preamble += " long long length;\n";
+ Preamble += "#else\n";
Preamble += " long length;\n";
+ Preamble += "#endif\n";
Preamble += "};\n";
Preamble += "#ifdef CF_EXPORT_CONSTANT_STRING\n";
Preamble += "extern \"C\" __declspec(dllexport) int __CFConstantStringClassReference[];\n";
@@ -7065,17 +6989,13 @@ void RewriteModernObjC::RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl,
PDecl = Def;
// Must write out all protocol definitions in current qualifier list,
// and in their nested qualifiers before writing out current definition.
- for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(),
- E = PDecl->protocol_end(); I != E; ++I)
- RewriteObjCProtocolMetaData(*I, Result);
+ for (auto *I : PDecl->protocols())
+ RewriteObjCProtocolMetaData(I, Result);
// Construct method lists.
std::vector<ObjCMethodDecl *> InstanceMethods, ClassMethods;
std::vector<ObjCMethodDecl *> OptInstanceMethods, OptClassMethods;
- for (ObjCProtocolDecl::instmeth_iterator
- I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
- I != E; ++I) {
- ObjCMethodDecl *MD = *I;
+ for (auto *MD : PDecl->instance_methods()) {
if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
OptInstanceMethods.push_back(MD);
} else {
@@ -7083,10 +7003,7 @@ void RewriteModernObjC::RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl,
}
}
- for (ObjCProtocolDecl::classmeth_iterator
- I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
- I != E; ++I) {
- ObjCMethodDecl *MD = *I;
+ for (auto *MD : PDecl->class_methods()) {
if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
OptClassMethods.push_back(MD);
} else {
@@ -7108,11 +7025,7 @@ void RewriteModernObjC::RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl,
"_OBJC_PROTOCOL_METHOD_TYPES_",
PDecl->getNameAsString());
// Protocol's super protocol list
- std::vector<ObjCProtocolDecl *> SuperProtocols;
- for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(),
- E = PDecl->protocol_end(); I != E; ++I)
- SuperProtocols.push_back(*I);
-
+ SmallVector<ObjCProtocolDecl *, 8> SuperProtocols(PDecl->protocols());
Write_protocol_list_initializer(Context, Result, SuperProtocols,
"_OBJC_PROTOCOL_REFS_",
PDecl->getNameAsString());
@@ -7134,16 +7047,12 @@ void RewriteModernObjC::RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl,
PDecl->getNameAsString(), false);
// Protocol's property metadata.
- std::vector<ObjCPropertyDecl *> ProtocolProperties;
- for (ObjCContainerDecl::prop_iterator I = PDecl->prop_begin(),
- E = PDecl->prop_end(); I != E; ++I)
- ProtocolProperties.push_back(*I);
-
+ SmallVector<ObjCPropertyDecl *, 8> ProtocolProperties(PDecl->properties());
Write_prop_list_t_initializer(*this, Context, Result, ProtocolProperties,
- /* Container */0,
+ /* Container */nullptr,
"_OBJC_PROTOCOL_PROPERTIES_",
PDecl->getNameAsString());
-
+
// Writer out root metadata for current protocol: struct _protocol_t
Result += "\n";
if (LangOpts.MicrosoftExt)
@@ -7300,14 +7209,11 @@ void RewriteModernObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
CDecl);
// Build _objc_method_list for class's instance methods if needed
- SmallVector<ObjCMethodDecl *, 32>
- InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
+ SmallVector<ObjCMethodDecl *, 32> InstanceMethods(IDecl->instance_methods());
// If any of our property implementations have associated getters or
// setters, produce metadata for them as well.
- for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(),
- PropEnd = IDecl->propimpl_end();
- Prop != PropEnd; ++Prop) {
+ for (const auto *Prop : IDecl->property_impls()) {
if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
continue;
if (!Prop->getPropertyIvarDecl())
@@ -7329,8 +7235,7 @@ void RewriteModernObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
"_OBJC_$_INSTANCE_METHODS_",
IDecl->getNameAsString(), true);
- SmallVector<ObjCMethodDecl *, 32>
- ClassMethods(IDecl->classmeth_begin(), IDecl->classmeth_end());
+ SmallVector<ObjCMethodDecl *, 32> ClassMethods(IDecl->class_methods());
Write_method_list_t_initializer(*this, Context, Result, ClassMethods,
"_OBJC_$_CLASS_METHODS_",
@@ -7355,11 +7260,7 @@ void RewriteModernObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
IDecl->getNameAsString());
// Protocol's property metadata.
- std::vector<ObjCPropertyDecl *> ClassProperties;
- for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(),
- E = CDecl->prop_end(); I != E; ++I)
- ClassProperties.push_back(*I);
-
+ SmallVector<ObjCPropertyDecl *, 8> ClassProperties(CDecl->properties());
Write_prop_list_t_initializer(*this, Context, Result, ClassProperties,
/* Container */IDecl,
"_OBJC_$_PROP_LIST_",
@@ -7384,13 +7285,12 @@ void RewriteModernObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
Write__class_ro_t_initializer(Context, Result, flags,
InstanceStart, InstanceSize,
ClassMethods,
- 0,
- 0,
- 0,
+ nullptr,
+ nullptr,
+ nullptr,
"_OBJC_METACLASS_RO_$_",
CDecl->getNameAsString());
-
// Data for initializing _class_ro_t meta-data
flags = CLS;
if (classIsHidden)
@@ -7561,14 +7461,11 @@ void RewriteModernObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
FullCategoryName += CDecl->getNameAsString();
// Build _objc_method_list for class's instance methods if needed
- SmallVector<ObjCMethodDecl *, 32>
- InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
+ SmallVector<ObjCMethodDecl *, 32> InstanceMethods(IDecl->instance_methods());
// If any of our property implementations have associated getters or
// setters, produce metadata for them as well.
- for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(),
- PropEnd = IDecl->propimpl_end();
- Prop != PropEnd; ++Prop) {
+ for (const auto *Prop : IDecl->property_impls()) {
if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
continue;
if (!Prop->getPropertyIvarDecl())
@@ -7588,8 +7485,7 @@ void RewriteModernObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
"_OBJC_$_CATEGORY_INSTANCE_METHODS_",
FullCategoryName, true);
- SmallVector<ObjCMethodDecl *, 32>
- ClassMethods(IDecl->classmeth_begin(), IDecl->classmeth_end());
+ SmallVector<ObjCMethodDecl *, 32> ClassMethods(IDecl->class_methods());
Write_method_list_t_initializer(*this, Context, Result, ClassMethods,
"_OBJC_$_CATEGORY_CLASS_METHODS_",
@@ -7597,16 +7493,11 @@ void RewriteModernObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
// Protocols referenced in class declaration?
// Protocol's super protocol list
- std::vector<ObjCProtocolDecl *> RefedProtocols;
- for (ObjCInterfaceDecl::protocol_iterator I = CDecl->protocol_begin(),
- E = CDecl->protocol_end();
-
- I != E; ++I) {
- RefedProtocols.push_back(*I);
+ SmallVector<ObjCProtocolDecl *, 8> RefedProtocols(CDecl->protocols());
+ for (auto *I : CDecl->protocols())
// Must write out all protocol definitions in current qualifier list,
// and in their nested qualifiers before writing out current definition.
- RewriteObjCProtocolMetaData(*I, Result);
- }
+ RewriteObjCProtocolMetaData(I, Result);
Write_protocol_list_initializer(Context, Result,
RefedProtocols,
@@ -7614,11 +7505,7 @@ void RewriteModernObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
FullCategoryName);
// Protocol's property metadata.
- std::vector<ObjCPropertyDecl *> ClassProperties;
- for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(),
- E = CDecl->prop_end(); I != E; ++I)
- ClassProperties.push_back(*I);
-
+ SmallVector<ObjCPropertyDecl *, 8> ClassProperties(CDecl->properties());
Write_prop_list_t_initializer(*this, Context, Result, ClassProperties,
/* Container */IDecl,
"_OBJC_$_PROP_LIST_",
@@ -7759,7 +7646,7 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null");
// lookup which class implements the instance variable.
- ObjCInterfaceDecl *clsDeclared = 0;
+ ObjCInterfaceDecl *clsDeclared = nullptr;
iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
clsDeclared);
assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");
@@ -7780,7 +7667,8 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
BaseExpr);
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), &Context->Idents.get(IvarOffsetName),
- Context->UnsignedLongTy, 0, SC_Extern);
+ Context->UnsignedLongTy, nullptr,
+ SC_Extern);
DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false,
Context->UnsignedLongTy, VK_LValue,
SourceLocation());
@@ -7820,12 +7708,12 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
Zero = NoTypeInfoCStyleCastExpr(Context, PtrStructIMPL, CK_BitCast, Zero);
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
Zero);
- FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get(D->getNameAsString()),
- IvarT, 0,
- /*BitWidth=*/0, /*Mutable=*/true,
- ICIS_NoInit);
+ IvarT, nullptr,
+ /*BitWidth=*/nullptr,
+ /*Mutable=*/true, ICIS_NoInit);
MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
FD->getType(), VK_LValue,
OK_Ordinary);
@@ -7849,13 +7737,12 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
Exp);
if (D->isBitField()) {
- FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get(D->getNameAsString()),
- D->getType(), 0,
+ D->getType(), nullptr,
/*BitWidth=*/D->getBitWidth(),
- /*Mutable=*/true,
- ICIS_NoInit);
+ /*Mutable=*/true, ICIS_NoInit);
MemberExpr *ME = new (Context) MemberExpr(PE, /*isArrow*/false, FD, SourceLocation(),
FD->getType(), VK_LValue,
OK_Ordinary);
@@ -7869,3 +7756,5 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
ReplaceStmtWithRange(IV, Replacement, OldRange);
return Replacement;
}
+
+#endif
diff --git a/lib/Rewrite/Frontend/RewriteObjC.cpp b/lib/Frontend/Rewrite/RewriteObjC.cpp
index 3dda2c56f5dc..7a721771759a 100644
--- a/lib/Rewrite/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteObjC.cpp
@@ -23,11 +23,13 @@
#include "clang/Lex/Lexer.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
+#include <memory>
+
+#ifdef CLANG_ENABLE_OBJC_REWRITER
using namespace clang;
using llvm::utostr;
@@ -165,7 +167,7 @@ namespace {
public:
// Top Level Driver code.
- virtual bool HandleTopLevelDecl(DeclGroupRef D) {
+ bool HandleTopLevelDecl(DeclGroupRef D) override {
for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*I)) {
if (!Class->isThisDeclarationADefinition()) {
@@ -193,7 +195,7 @@ namespace {
~RewriteObjC() {}
- virtual void HandleTranslationUnit(ASTContext &C);
+ void HandleTranslationUnit(ASTContext &C) override;
void ReplaceStmt(Stmt *Old, Stmt *New) {
Stmt *ReplacingStmt = ReplacedNodes[Old];
@@ -216,6 +218,7 @@ namespace {
}
void ReplaceStmtWithRange(Stmt *Old, Stmt *New, SourceRange SrcRange) {
+ assert(Old != nullptr && New != nullptr && "Expected non-null Stmt's");
if (DisableReplaceStmt)
return;
@@ -229,7 +232,7 @@ namespace {
// Get the new text.
std::string SStr;
llvm::raw_string_ostream S(SStr);
- New->printPretty(S, 0, PrintingPolicy(LangOpts));
+ New->printPretty(S, nullptr, PrintingPolicy(LangOpts));
const std::string &Str = S.str();
// If replacement succeeded or warning disabled return with no warning.
@@ -328,9 +331,9 @@ namespace {
void RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
std::string &Result);
-
- virtual void Initialize(ASTContext &context) = 0;
-
+
+ virtual void Initialize(ASTContext &context) override = 0;
+
// Metadata Rewriting.
virtual void RewriteMetaDataIntoBuffer(std::string &Result) = 0;
virtual void RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Prots,
@@ -498,8 +501,16 @@ namespace {
CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty,
CastKind Kind, Expr *E) {
TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation());
- return CStyleCastExpr::Create(*Ctx, Ty, VK_RValue, Kind, E, 0, TInfo,
- SourceLocation(), SourceLocation());
+ return CStyleCastExpr::Create(*Ctx, Ty, VK_RValue, Kind, E, nullptr,
+ TInfo, SourceLocation(), SourceLocation());
+ }
+
+ StringLiteral *getStringLiteral(StringRef Str) {
+ QualType StrType = Context->getConstantArrayType(
+ Context->CharTy, llvm::APInt(32, Str.size() + 1), ArrayType::Normal,
+ 0);
+ return StringLiteral::Create(*Context, Str, StringLiteral::Ascii,
+ /*Pascal=*/false, StrType, SourceLocation());
}
};
@@ -513,8 +524,8 @@ namespace {
silenceMacroWarn) {}
~RewriteObjCFragileABI() {}
- virtual void Initialize(ASTContext &context);
-
+ virtual void Initialize(ASTContext &context) override;
+
// Rewriting metadata
template<typename MethodIterator>
void RewriteObjCMethodsMetaData(MethodIterator MethodBegin,
@@ -523,23 +534,22 @@ namespace {
StringRef prefix,
StringRef ClassName,
std::string &Result);
- virtual void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol,
- StringRef prefix,
- StringRef ClassName,
- std::string &Result);
- virtual void RewriteObjCProtocolListMetaData(
- const ObjCList<ObjCProtocolDecl> &Prots,
- StringRef prefix, StringRef ClassName, std::string &Result);
- virtual void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
- std::string &Result);
- virtual void RewriteMetaDataIntoBuffer(std::string &Result);
- virtual void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl,
- std::string &Result);
-
+ void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol,
+ StringRef prefix, StringRef ClassName,
+ std::string &Result) override;
+ void RewriteObjCProtocolListMetaData(
+ const ObjCList<ObjCProtocolDecl> &Prots,
+ StringRef prefix, StringRef ClassName, std::string &Result) override;
+ void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
+ std::string &Result) override;
+ void RewriteMetaDataIntoBuffer(std::string &Result) override;
+ void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl,
+ std::string &Result) override;
+
// Rewriting ivar
- virtual void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
- std::string &Result);
- virtual Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV);
+ void RewriteIvarOffsetComputation(ObjCIvarDecl *ivar,
+ std::string &Result) override;
+ Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) override;
};
}
@@ -547,9 +557,8 @@ void RewriteObjC::RewriteBlocksInFunctionProtoType(QualType funcType,
NamedDecl *D) {
if (const FunctionProtoType *fproto
= dyn_cast<FunctionProtoType>(funcType.IgnoreParens())) {
- for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(),
- E = fproto->arg_type_end(); I && (I != E); ++I)
- if (isTopLevelBlockPointerType(*I)) {
+ for (const auto &I : fproto->param_types())
+ if (isTopLevelBlockPointerType(I)) {
// All the args are checked/rewritten. Don't call twice!
RewriteBlockPointerDecl(D);
break;
@@ -603,30 +612,30 @@ void RewriteObjC::InitializeCommon(ASTContext &context) {
Context = &context;
SM = &Context->getSourceManager();
TUDecl = Context->getTranslationUnitDecl();
- MsgSendFunctionDecl = 0;
- MsgSendSuperFunctionDecl = 0;
- MsgSendStretFunctionDecl = 0;
- MsgSendSuperStretFunctionDecl = 0;
- MsgSendFpretFunctionDecl = 0;
- GetClassFunctionDecl = 0;
- GetMetaClassFunctionDecl = 0;
- GetSuperClassFunctionDecl = 0;
- SelGetUidFunctionDecl = 0;
- CFStringFunctionDecl = 0;
- ConstantStringClassReference = 0;
- NSStringRecord = 0;
- CurMethodDef = 0;
- CurFunctionDef = 0;
- CurFunctionDeclToDeclareForBlock = 0;
- GlobalVarDecl = 0;
- SuperStructDecl = 0;
- ProtocolTypeDecl = 0;
- ConstantStringDecl = 0;
+ MsgSendFunctionDecl = nullptr;
+ MsgSendSuperFunctionDecl = nullptr;
+ MsgSendStretFunctionDecl = nullptr;
+ MsgSendSuperStretFunctionDecl = nullptr;
+ MsgSendFpretFunctionDecl = nullptr;
+ GetClassFunctionDecl = nullptr;
+ GetMetaClassFunctionDecl = nullptr;
+ GetSuperClassFunctionDecl = nullptr;
+ SelGetUidFunctionDecl = nullptr;
+ CFStringFunctionDecl = nullptr;
+ ConstantStringClassReference = nullptr;
+ NSStringRecord = nullptr;
+ CurMethodDef = nullptr;
+ CurFunctionDef = nullptr;
+ CurFunctionDeclToDeclareForBlock = nullptr;
+ GlobalVarDecl = nullptr;
+ SuperStructDecl = nullptr;
+ ProtocolTypeDecl = nullptr;
+ ConstantStringDecl = nullptr;
BcLabelCount = 0;
- SuperConstructorFunctionDecl = 0;
+ SuperConstructorFunctionDecl = nullptr;
NumObjCStringLiterals = 0;
- PropParentMap = 0;
- CurrentBody = 0;
+ PropParentMap = nullptr;
+ CurrentBody = nullptr;
DisableReplaceStmt = false;
objc_impl_method = false;
@@ -808,8 +817,8 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
if (GenGetProperty) {
// return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1)
Getr += "typedef ";
- const FunctionType *FPRetType = 0;
- RewriteTypeIntoString(PD->getGetterMethodDecl()->getResultType(), Getr,
+ const FunctionType *FPRetType = nullptr;
+ RewriteTypeIntoString(PD->getGetterMethodDecl()->getReturnType(), Getr,
FPRetType);
Getr += " _TYPE";
if (FPRetType) {
@@ -818,14 +827,15 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
// Now, emit the argument types (if any).
if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(FPRetType)){
Getr += "(";
- for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) {
+ for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) {
if (i) Getr += ", ";
- std::string ParamStr = FT->getArgType(i).getAsString(
- Context->getPrintingPolicy());
+ std::string ParamStr =
+ FT->getParamType(i).getAsString(Context->getPrintingPolicy());
Getr += ParamStr;
}
if (FT->isVariadic()) {
- if (FT->getNumArgs()) Getr += ", ";
+ if (FT->getNumParams())
+ Getr += ", ";
Getr += "...";
}
Getr += ")";
@@ -970,18 +980,12 @@ void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
// FIXME: handle category headers that are declared across multiple lines.
ReplaceText(LocStart, 0, "// ");
- for (ObjCCategoryDecl::prop_iterator I = CatDecl->prop_begin(),
- E = CatDecl->prop_end(); I != E; ++I)
- RewriteProperty(*I);
-
- for (ObjCCategoryDecl::instmeth_iterator
- I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end();
- I != E; ++I)
- RewriteMethodDeclaration(*I);
- for (ObjCCategoryDecl::classmeth_iterator
- I = CatDecl->classmeth_begin(), E = CatDecl->classmeth_end();
- I != E; ++I)
- RewriteMethodDeclaration(*I);
+ for (auto *I : CatDecl->properties())
+ RewriteProperty(I);
+ for (auto *I : CatDecl->instance_methods())
+ RewriteMethodDeclaration(I);
+ for (auto *I : CatDecl->class_methods())
+ RewriteMethodDeclaration(I);
// Lastly, comment out the @end.
ReplaceText(CatDecl->getAtEndRange().getBegin(),
@@ -995,18 +999,12 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
// FIXME: handle protocol headers that are declared across multiple lines.
ReplaceText(LocStart, 0, "// ");
- for (ObjCProtocolDecl::instmeth_iterator
- I = PDecl->instmeth_begin(), E = PDecl->instmeth_end();
- I != E; ++I)
- RewriteMethodDeclaration(*I);
- for (ObjCProtocolDecl::classmeth_iterator
- I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
- I != E; ++I)
- RewriteMethodDeclaration(*I);
-
- for (ObjCInterfaceDecl::prop_iterator I = PDecl->prop_begin(),
- E = PDecl->prop_end(); I != E; ++I)
- RewriteProperty(*I);
+ for (auto *I : PDecl->instance_methods())
+ RewriteMethodDeclaration(I);
+ for (auto *I : PDecl->class_methods())
+ RewriteMethodDeclaration(I);
+ for (auto *I : PDecl->properties())
+ RewriteProperty(I);
// Lastly, comment out the @end.
SourceLocation LocEnd = PDecl->getAtEndRange().getBegin();
@@ -1061,8 +1059,8 @@ void RewriteObjC::RewriteTypeIntoString(QualType T, std::string &ResultStr,
else if (const BlockPointerType *BPT = retType->getAs<BlockPointerType>())
PointeeTy = BPT->getPointeeType();
if ((FPRetType = PointeeTy->getAs<FunctionType>())) {
- ResultStr += FPRetType->getResultType().getAsString(
- Context->getPrintingPolicy());
+ ResultStr +=
+ FPRetType->getReturnType().getAsString(Context->getPrintingPolicy());
ResultStr += "(*";
}
} else
@@ -1073,9 +1071,9 @@ void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,
ObjCMethodDecl *OMD,
std::string &ResultStr) {
//fprintf(stderr,"In RewriteObjCMethodDecl\n");
- const FunctionType *FPRetType = 0;
+ const FunctionType *FPRetType = nullptr;
ResultStr += "\nstatic ";
- RewriteTypeIntoString(OMD->getResultType(), ResultStr, FPRetType);
+ RewriteTypeIntoString(OMD->getReturnType(), ResultStr, FPRetType);
ResultStr += " ";
// Unique method name
@@ -1131,9 +1129,7 @@ void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,
ResultStr += " _cmd";
// Method arguments.
- for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(),
- E = OMD->param_end(); PI != E; ++PI) {
- ParmVarDecl *PDecl = *PI;
+ for (const auto *PDecl : OMD->params()) {
ResultStr += ", ";
if (PDecl->getType()->isObjCQualifiedIdType()) {
ResultStr += "id ";
@@ -1157,14 +1153,15 @@ void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,
// Now, emit the argument types (if any).
if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(FPRetType)) {
ResultStr += "(";
- for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) {
+ for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) {
if (i) ResultStr += ", ";
- std::string ParamStr = FT->getArgType(i).getAsString(
- Context->getPrintingPolicy());
+ std::string ParamStr =
+ FT->getParamType(i).getAsString(Context->getPrintingPolicy());
ResultStr += ParamStr;
}
if (FT->isVariadic()) {
- if (FT->getNumArgs()) ResultStr += ", ";
+ if (FT->getNumParams())
+ ResultStr += ", ";
ResultStr += "...";
}
ResultStr += ")";
@@ -1179,12 +1176,8 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
InsertText(IMD ? IMD->getLocStart() : CID->getLocStart(), "// ");
- for (ObjCCategoryImplDecl::instmeth_iterator
- I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(),
- E = IMD ? IMD->instmeth_end() : CID->instmeth_end();
- I != E; ++I) {
+ for (auto *OMD : IMD ? IMD->instance_methods() : CID->instance_methods()) {
std::string ResultStr;
- ObjCMethodDecl *OMD = *I;
RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr);
SourceLocation LocStart = OMD->getLocStart();
SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart();
@@ -1194,12 +1187,8 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
ReplaceText(LocStart, endBuf-startBuf, ResultStr);
}
- for (ObjCCategoryImplDecl::classmeth_iterator
- I = IMD ? IMD->classmeth_begin() : CID->classmeth_begin(),
- E = IMD ? IMD->classmeth_end() : CID->classmeth_end();
- I != E; ++I) {
+ for (auto *OMD : IMD ? IMD->class_methods() : CID->class_methods()) {
std::string ResultStr;
- ObjCMethodDecl *OMD = *I;
RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr);
SourceLocation LocStart = OMD->getLocStart();
SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart();
@@ -1208,12 +1197,8 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
const char *endBuf = SM->getCharacterData(LocEnd);
ReplaceText(LocStart, endBuf-startBuf, ResultStr);
}
- for (ObjCCategoryImplDecl::propimpl_iterator
- I = IMD ? IMD->propimpl_begin() : CID->propimpl_begin(),
- E = IMD ? IMD->propimpl_end() : CID->propimpl_end();
- I != E; ++I) {
- RewritePropertyImplDecl(*I, IMD, CID);
- }
+ for (auto *I : IMD ? IMD->property_impls() : CID->property_impls())
+ RewritePropertyImplDecl(I, IMD, CID);
InsertText(IMD ? IMD->getLocEnd() : CID->getLocEnd(), "// ");
}
@@ -1236,17 +1221,12 @@ void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
}
RewriteObjCInternalStruct(ClassDecl, ResultStr);
- for (ObjCInterfaceDecl::prop_iterator I = ClassDecl->prop_begin(),
- E = ClassDecl->prop_end(); I != E; ++I)
- RewriteProperty(*I);
- for (ObjCInterfaceDecl::instmeth_iterator
- I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end();
- I != E; ++I)
- RewriteMethodDeclaration(*I);
- for (ObjCInterfaceDecl::classmeth_iterator
- I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end();
- I != E; ++I)
- RewriteMethodDeclaration(*I);
+ for (auto *I : ClassDecl->properties())
+ RewriteProperty(I);
+ for (auto *I : ClassDecl->instance_methods())
+ RewriteMethodDeclaration(I);
+ for (auto *I : ClassDecl->class_methods())
+ RewriteMethodDeclaration(I);
// Lastly, comment out the @end.
ReplaceText(ClassDecl->getAtEndRange().getBegin(), strlen("@end"),
@@ -1269,7 +1249,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(PseudoObjectExpr *PseudoOp) {
DisableReplaceStmtScope S(*this);
// Rebuild the base expression if we have one.
- Base = 0;
+ Base = nullptr;
if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) {
Base = OldMsg->getInstanceReceiver();
Base = cast<OpaqueValueExpr>(Base)->getSourceExpr();
@@ -1286,7 +1266,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(PseudoObjectExpr *PseudoOp) {
SmallVector<SourceLocation, 1> SelLocs;
OldMsg->getSelectorLocs(SelLocs);
- ObjCMessageExpr *NewMsg = 0;
+ ObjCMessageExpr *NewMsg = nullptr;
switch (OldMsg->getReceiverKind()) {
case ObjCMessageExpr::Class:
NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
@@ -1346,7 +1326,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(PseudoObjectExpr *PseudoOp) {
// Because the rewriter doesn't allow us to rewrite rewritten code,
// we need to suppress rewriting the sub-statements.
- Expr *Base = 0;
+ Expr *Base = nullptr;
{
DisableReplaceStmtScope S(*this);
@@ -1362,7 +1342,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(PseudoObjectExpr *PseudoOp) {
SmallVector<SourceLocation, 1> SelLocs;
SmallVector<Expr*, 1> Args;
- ObjCMessageExpr *NewMsg = 0;
+ ObjCMessageExpr *NewMsg = nullptr;
switch (OldMsg->getReceiverKind()) {
case ObjCMessageExpr::Class:
NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
@@ -1446,7 +1426,7 @@ Stmt *RewriteObjC::RewriteBreakStmt(BreakStmt *S) {
buf += utostr(ObjCBcLabelNo.back());
ReplaceText(startLoc, strlen("break"), buf);
- return 0;
+ return nullptr;
}
/// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach
@@ -1463,7 +1443,7 @@ Stmt *RewriteObjC::RewriteContinueStmt(ContinueStmt *S) {
buf += utostr(ObjCBcLabelNo.back());
ReplaceText(startLoc, strlen("continue"), buf);
- return 0;
+ return nullptr;
}
/// RewriteObjCForCollectionStmt - Rewriter for ObjC2's foreach statement.
@@ -1659,7 +1639,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
}
Stmts.pop_back();
ObjCBcLabelNo.pop_back();
- return 0;
+ return nullptr;
}
/// RewriteObjCSynchronizedStmt -
@@ -1720,7 +1700,8 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
CK, syncExpr);
std::string syncExprBufS;
llvm::raw_string_ostream syncExprBuf(syncExprBufS);
- syncExpr->printPretty(syncExprBuf, 0, PrintingPolicy(LangOpts));
+ assert(syncExpr != nullptr && "Expected non-null Expr");
+ syncExpr->printPretty(syncExprBuf, nullptr, PrintingPolicy(LangOpts));
syncBuf += syncExprBuf.str();
syncBuf += ");";
@@ -1736,7 +1717,7 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
if (hasReturns)
RewriteSyncReturnStmts(S->getSynchBody(), syncBuf);
- return 0;
+ return nullptr;
}
void RewriteObjC::WarnAboutReturnGotoStmts(Stmt *S)
@@ -1853,7 +1834,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
buf += "}";
ReplaceText(lastCurlyLoc, 1, buf);
}
- Stmt *lastCatchBody = 0;
+ Stmt *lastCatchBody = nullptr;
for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) {
ObjCAtCatchStmt *Catch = S->getCatchStmt(I);
VarDecl *catchDecl = Catch->getCatchParamDecl();
@@ -1975,7 +1956,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
// Now emit the final closing curly brace...
lastCurlyLoc = lastCurlyLoc.getLocWithOffset(1);
InsertText(lastCurlyLoc, " } /* @try scope end */\n");
- return 0;
+ return nullptr;
}
// This can't be done with ReplaceStmt(S, ThrowExpr), since
@@ -2004,17 +1985,14 @@ Stmt *RewriteObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) {
assert((*semiBuf == ';') && "@throw: can't find ';'");
SourceLocation semiLoc = startLoc.getLocWithOffset(semiBuf-startBuf);
ReplaceText(semiLoc, 1, ");");
- return 0;
+ return nullptr;
}
Stmt *RewriteObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) {
// Create a new string expression.
- QualType StrType = Context->getPointerType(Context->CharTy);
std::string StrEncoding;
Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding);
- Expr *Replacement = StringLiteral::Create(*Context, StrEncoding,
- StringLiteral::Ascii, false,
- StrType, SourceLocation());
+ Expr *Replacement = getStringLiteral(StrEncoding);
ReplaceStmt(Exp, Replacement);
// Replace this subexpr in the parent.
@@ -2028,11 +2006,7 @@ Stmt *RewriteObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) {
assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl");
// Create a call to sel_registerName("selName").
SmallVector<Expr*, 8> SelExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
- SelExprs.push_back(StringLiteral::Create(*Context,
- Exp->getSelector().getAsString(),
- StringLiteral::Ascii, false,
- argType, SourceLocation()));
+ SelExprs.push_back(getStringLiteral(Exp->getSelector().getAsString()));
CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
&SelExprs[0], SelExprs.size());
ReplaceStmt(Exp, SelExp);
@@ -2052,9 +2026,9 @@ CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl(
// Now, we cast the reference to a pointer to the objc_msgSend type.
QualType pToFunc = Context->getPointerType(msgSendType);
- ImplicitCastExpr *ICE =
+ ImplicitCastExpr *ICE =
ImplicitCastExpr::Create(*Context, pToFunc, CK_FunctionToPointerDecay,
- DRE, 0, VK_RValue);
+ DRE, nullptr, VK_RValue);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
@@ -2130,7 +2104,7 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) {
const char *startBuf = SM->getCharacterData(Loc);
const char *endBuf = SM->getCharacterData(EndLoc);
- const char *startRef = 0, *endRef = 0;
+ const char *startRef = nullptr, *endRef = nullptr;
if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
// Get the locations of the startRef, endRef.
SourceLocation LessLoc = Loc.getLocWithOffset(startRef-startBuf);
@@ -2145,7 +2119,7 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) {
void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
SourceLocation Loc;
QualType Type;
- const FunctionProtoType *proto = 0;
+ const FunctionProtoType *proto = nullptr;
if (VarDecl *VD = dyn_cast<VarDecl>(Dcl)) {
Loc = VD->getLocation();
Type = VD->getType();
@@ -2159,7 +2133,7 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
proto = dyn_cast<FunctionProtoType>(funcType);
if (!proto)
return;
- Type = proto->getResultType();
+ Type = proto->getReturnType();
}
else if (FieldDecl *FD = dyn_cast<FieldDecl>(Dcl)) {
Loc = FD->getLocation();
@@ -2175,7 +2149,7 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
const char *startBuf = endBuf;
while (*startBuf != ';' && *startBuf != '<' && startBuf != MainFileStart)
startBuf--; // scan backward (from the decl location) for return type.
- const char *startRef = 0, *endRef = 0;
+ const char *startRef = nullptr, *endRef = nullptr;
if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
// Get the locations of the startRef, endRef.
SourceLocation LessLoc = Loc.getLocWithOffset(startRef-endBuf);
@@ -2190,14 +2164,14 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
// Now check arguments.
const char *startBuf = SM->getCharacterData(Loc);
const char *startFuncBuf = startBuf;
- for (unsigned i = 0; i < proto->getNumArgs(); i++) {
- if (needToScanForQualifiers(proto->getArgType(i))) {
+ for (unsigned i = 0; i < proto->getNumParams(); i++) {
+ if (needToScanForQualifiers(proto->getParamType(i))) {
// Since types are unique, we need to scan the buffer.
const char *endBuf = startBuf;
// scan forward (from the decl location) for argument types.
scanToNextArgument(endBuf);
- const char *startRef = 0, *endRef = 0;
+ const char *startRef = nullptr, *endRef = nullptr;
if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) {
// Get the locations of the startRef, endRef.
SourceLocation LessLoc =
@@ -2266,8 +2240,8 @@ void RewriteObjC::SynthSelGetUidFunctionDecl() {
SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
- SelGetUidIdent, getFuncType, 0,
- SC_Extern);
+ SelGetUidIdent, getFuncType,
+ nullptr, SC_Extern);
}
void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) {
@@ -2330,21 +2304,21 @@ void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) {
const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(funcType);
if (!proto)
return;
- QualType Type = proto->getResultType();
+ QualType Type = proto->getReturnType();
std::string FdStr = Type.getAsString(Context->getPrintingPolicy());
FdStr += " ";
FdStr += FD->getName();
FdStr += "(";
- unsigned numArgs = proto->getNumArgs();
+ unsigned numArgs = proto->getNumParams();
for (unsigned i = 0; i < numArgs; i++) {
- QualType ArgType = proto->getArgType(i);
+ QualType ArgType = proto->getParamType(i);
RewriteBlockPointerType(FdStr, ArgType);
if (i+1 < numArgs)
FdStr += ", ";
}
FdStr += ");\n";
InsertText(FunLocStart, FdStr);
- CurFunctionDeclToDeclareForBlock = 0;
+ CurFunctionDeclToDeclareForBlock = nullptr;
}
// SynthSuperConstructorFunctionDecl - id objc_super(id obj, id super);
@@ -2363,7 +2337,7 @@ void RewriteObjC::SynthSuperConstructorFunctionDecl() {
SourceLocation(),
SourceLocation(),
msgSendIdent, msgSendType,
- 0, SC_Extern);
+ nullptr, SC_Extern);
}
// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
@@ -2381,8 +2355,8 @@ void RewriteObjC::SynthMsgSendFunctionDecl() {
MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern);
+ msgSendIdent, msgSendType,
+ nullptr, SC_Extern);
}
// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...);
@@ -2403,8 +2377,8 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() {
MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern);
+ msgSendIdent, msgSendType,
+ nullptr, SC_Extern);
}
// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...);
@@ -2422,8 +2396,8 @@ void RewriteObjC::SynthMsgSendStretFunctionDecl() {
MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern);
+ msgSendIdent, msgSendType,
+ nullptr, SC_Extern);
}
// SynthMsgSendSuperStretFunctionDecl -
@@ -2447,7 +2421,7 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() {
SourceLocation(),
SourceLocation(),
msgSendIdent,
- msgSendType, 0,
+ msgSendType, nullptr,
SC_Extern);
}
@@ -2466,8 +2440,8 @@ void RewriteObjC::SynthMsgSendFpretFunctionDecl() {
MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern);
+ msgSendIdent, msgSendType,
+ nullptr, SC_Extern);
}
// SynthGetClassFunctionDecl - id objc_getClass(const char *name);
@@ -2480,8 +2454,8 @@ void RewriteObjC::SynthGetClassFunctionDecl() {
GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
- getClassIdent, getClassType, 0,
- SC_Extern);
+ getClassIdent, getClassType,
+ nullptr, SC_Extern);
}
// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls);
@@ -2496,7 +2470,7 @@ void RewriteObjC::SynthGetSuperClassFunctionDecl() {
SourceLocation(),
SourceLocation(),
getSuperClassIdent,
- getClassType, 0,
+ getClassType, nullptr,
SC_Extern);
}
@@ -2511,10 +2485,11 @@ void RewriteObjC::SynthGetMetaClassFunctionDecl() {
SourceLocation(),
SourceLocation(),
getClassIdent, getClassType,
- 0, SC_Extern);
+ nullptr, SC_Extern);
}
Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
+ assert(Exp != nullptr && "Expected non-null ObjCStringLiteral");
QualType strType = getConstantStringStructType();
std::string S = "__NSConstantStringImpl_";
@@ -2523,7 +2498,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
unsigned i;
for (i=0; i < tmpName.length(); i++) {
char c = tmpName.at(i);
- // replace any non alphanumeric characters with '_'.
+ // replace any non-alphanumeric characters with '_'.
if (!isAlphanumeric(c))
tmpName[i] = '_';
}
@@ -2537,14 +2512,14 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
// The pretty printer for StringLiteral handles escape characters properly.
std::string prettyBufS;
llvm::raw_string_ostream prettyBuf(prettyBufS);
- Exp->getString()->printPretty(prettyBuf, 0, PrintingPolicy(LangOpts));
+ Exp->getString()->printPretty(prettyBuf, nullptr, PrintingPolicy(LangOpts));
Preamble += prettyBuf.str();
Preamble += ",";
Preamble += utostr(Exp->getString()->getByteLength()) + "};\n";
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), &Context->Idents.get(S),
- strType, 0, SC_Static);
+ strType, nullptr, SC_Static);
DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, strType, VK_LValue,
SourceLocation());
Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf,
@@ -2576,9 +2551,9 @@ QualType RewriteObjC::getSuperStructType() {
for (unsigned i = 0; i < 2; ++i) {
SuperStructDecl->addDecl(FieldDecl::Create(*Context, SuperStructDecl,
SourceLocation(),
- SourceLocation(), 0,
- FieldTypes[i], 0,
- /*BitWidth=*/0,
+ SourceLocation(), nullptr,
+ FieldTypes[i], nullptr,
+ /*BitWidth=*/nullptr,
/*Mutable=*/false,
ICIS_NoInit));
}
@@ -2609,9 +2584,9 @@ QualType RewriteObjC::getConstantStringStructType() {
ConstantStringDecl->addDecl(FieldDecl::Create(*Context,
ConstantStringDecl,
SourceLocation(),
- SourceLocation(), 0,
- FieldTypes[i], 0,
- /*BitWidth=*/0,
+ SourceLocation(), nullptr,
+ FieldTypes[i], nullptr,
+ /*BitWidth=*/nullptr,
/*Mutable=*/true,
ICIS_NoInit));
}
@@ -2647,9 +2622,8 @@ CallExpr *RewriteObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavo
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *STCE = new (Context) CallExpr(*Context, PE, MsgExprs,
- FT->getResultType(), VK_RValue,
- SourceLocation());
+ CallExpr *STCE = new (Context) CallExpr(
+ *Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, SourceLocation());
return STCE;
}
@@ -2680,9 +2654,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// default to objc_msgSend().
FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl;
// May need to use objc_msgSend_stret() as well.
- FunctionDecl *MsgSendStretFlavor = 0;
+ FunctionDecl *MsgSendStretFlavor = nullptr;
if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) {
- QualType resultType = mDecl->getResultType();
+ QualType resultType = mDecl->getReturnType();
if (resultType->isRecordType())
MsgSendStretFlavor = MsgSendStretFunctionDecl;
else if (resultType->isRealFloatingType())
@@ -2715,11 +2689,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
SmallVector<Expr*, 8> ClsExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
- ClsExprs.push_back(StringLiteral::Create(*Context,
- ClassDecl->getIdentifier()->getName(),
- StringLiteral::Ascii, false,
- argType, SourceLocation()));
+ ClsExprs.push_back(getStringLiteral(ClassDecl->getIdentifier()->getName()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
@@ -2789,14 +2759,10 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
case ObjCMessageExpr::Class: {
SmallVector<Expr*, 8> ClsExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
ObjCInterfaceDecl *Class
= Exp->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
IdentifierInfo *clsName = Class->getIdentifier();
- ClsExprs.push_back(StringLiteral::Create(*Context,
- clsName->getName(),
- StringLiteral::Ascii, false,
- argType, SourceLocation()));
+ ClsExprs.push_back(getStringLiteral(clsName->getName()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
@@ -2824,11 +2790,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// (id)class_getSuperclass((Class)objc_getClass("CurrentClass"))
SmallVector<Expr*, 8> ClsExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
- ClsExprs.push_back(StringLiteral::Create(*Context,
- ClassDecl->getIdentifier()->getName(),
- StringLiteral::Ascii, false, argType,
- SourceLocation()));
+ ClsExprs.push_back(getStringLiteral(ClassDecl->getIdentifier()->getName()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
&ClsExprs[0],
ClsExprs.size(),
@@ -2909,11 +2871,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// Create a call to sel_registerName("selName"), it will be the 2nd argument.
SmallVector<Expr*, 8> SelExprs;
- QualType argType = Context->getPointerType(Context->CharTy);
- SelExprs.push_back(StringLiteral::Create(*Context,
- Exp->getSelector().getAsString(),
- StringLiteral::Ascii, false,
- argType, SourceLocation()));
+ SelExprs.push_back(getStringLiteral(Exp->getSelector().getAsString()));
CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
&SelExprs[0], SelExprs.size(),
StartLoc,
@@ -2988,11 +2946,10 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
ArgTypes.push_back(Context->getObjCSelType());
if (ObjCMethodDecl *OMD = Exp->getMethodDecl()) {
// Push any user argument types.
- for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(),
- E = OMD->param_end(); PI != E; ++PI) {
- QualType t = (*PI)->getType()->isObjCQualifiedIdType()
+ for (const auto *PI : OMD->params()) {
+ QualType t = PI->getType()->isObjCQualifiedIdType()
? Context->getObjCIdType()
- : (*PI)->getType();
+ : PI->getType();
// Make sure we convert "t (^)(...)" to "t (*)(...)".
(void)convertBlockPointerToFunctionPointer(t);
ArgTypes.push_back(t);
@@ -3031,9 +2988,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
const FunctionType *FT = msgSendType->getAs<FunctionType>();
- CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs,
- FT->getResultType(), VK_RValue,
- EndLoc);
+ CallExpr *CE = new (Context)
+ CallExpr(*Context, PE, MsgExprs, FT->getReturnType(), VK_RValue, EndLoc);
Stmt *ReplacingStmt = CE;
if (MsgSendStretFlavor) {
// We have the method which returns a struct/union. Must also generate
@@ -3111,8 +3067,8 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
std::string Name = "_OBJC_PROTOCOL_" + Exp->getProtocol()->getNameAsString();
IdentifierInfo *ID = &Context->Idents.get(Name);
VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
- SourceLocation(), ID, getProtocolType(), 0,
- SC_Extern);
+ SourceLocation(), ID, getProtocolType(),
+ nullptr, SC_Extern);
DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, false, getProtocolType(),
VK_LValue, SourceLocation());
Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf,
@@ -3327,7 +3283,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i,
StringRef funcName,
std::string Tag) {
const FunctionType *AFT = CE->getFunctionType();
- QualType RT = AFT->getResultType();
+ QualType RT = AFT->getReturnType();
std::string StructRef = "struct " + Tag;
std::string S = "static " + RT.getAsString(Context->getPrintingPolicy()) + " __" +
funcName.str() + "_" + "block_func_" + utostr(i);
@@ -3784,13 +3740,12 @@ QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) {
// FTP will be null for closures that don't take arguments.
// Generate a funky cast.
SmallVector<QualType, 8> ArgTypes;
- QualType Res = FT->getResultType();
+ QualType Res = FT->getReturnType();
bool HasBlockType = convertBlockPointerToFunctionPointer(Res);
if (FTP) {
- for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
- E = FTP->arg_type_end(); I && (I != E); ++I) {
- QualType t = *I;
+ for (auto &I : FTP->param_types()) {
+ QualType t = I;
// Make sure we convert "t (^)(...)" to "t (*)(...)".
if (convertBlockPointerToFunctionPointer(t))
HasBlockType = true;
@@ -3808,7 +3763,7 @@ QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) {
Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
// Navigate to relevant type information.
- const BlockPointerType *CPT = 0;
+ const BlockPointerType *CPT = nullptr;
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BlockExp)) {
CPT = DRE->getType()->getAs<BlockPointerType>();
@@ -3858,9 +3813,8 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
// Push the block argument type.
ArgTypes.push_back(PtrBlock);
if (FTP) {
- for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
- E = FTP->arg_type_end(); I && (I != E); ++I) {
- QualType t = *I;
+ for (auto &I : FTP->param_types()) {
+ QualType t = I;
// Make sure we convert "t (^)(...)" to "t (*)(...)".
if (!convertBlockPointerToFunctionPointer(t))
convertToUnqualifiedObjCType(t);
@@ -3880,11 +3834,11 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
BlkCast);
//PE->dump();
- FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("FuncPtr"),
- Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true,
+ Context->VoidPtrTy, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
ICIS_NoInit);
MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
FD->getType(), VK_LValue,
@@ -3927,12 +3881,12 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) {
// for each DeclRefExp where BYREFVAR is name of the variable.
ValueDecl *VD = DeclRefExp->getDecl();
bool isArrow = DeclRefExp->refersToEnclosingLocal();
-
- FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+
+ FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
SourceLocation(),
&Context->Idents.get("__forwarding"),
- Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true,
+ Context->VoidPtrTy, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
ICIS_NoInit);
MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow,
FD, SourceLocation(),
@@ -3940,10 +3894,10 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) {
OK_Ordinary);
StringRef Name = VD->getName();
- FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
+ FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(),
&Context->Idents.get(Name),
- Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true,
+ Context->VoidPtrTy, nullptr,
+ /*BitWidth=*/nullptr, /*Mutable=*/true,
ICIS_NoInit);
ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(),
DeclRefExp->getType(), VK_LValue, OK_Ordinary);
@@ -4061,9 +4015,8 @@ bool RewriteObjC::PointerTypeTakesAnyBlockArguments(QualType QT) {
FTP = BPT->getPointeeType()->getAs<FunctionProtoType>();
}
if (FTP) {
- for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
- E = FTP->arg_type_end(); I != E; ++I)
- if (isTopLevelBlockPointerType(*I))
+ for (const auto &I : FTP->param_types())
+ if (isTopLevelBlockPointerType(I))
return true;
}
return false;
@@ -4080,12 +4033,11 @@ bool RewriteObjC::PointerTypeTakesAnyObjCQualifiedType(QualType QT) {
FTP = BPT->getPointeeType()->getAs<FunctionProtoType>();
}
if (FTP) {
- for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
- E = FTP->arg_type_end(); I != E; ++I) {
- if ((*I)->isObjCQualifiedIdType())
+ for (const auto &I : FTP->param_types()) {
+ if (I->isObjCQualifiedIdType())
return true;
- if ((*I)->isObjCObjectPointerType() &&
- (*I)->getPointeeType()->isObjCQualifiedInterfaceType())
+ if (I->isObjCObjectPointerType() &&
+ I->getPointeeType()->isObjCQualifiedInterfaceType())
return true;
}
@@ -4336,7 +4288,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
// struct __Block_byref_ND ND =
// {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND),
// initializer-if-any};
- bool hasInit = (ND->getInit() != 0);
+ bool hasInit = (ND->getInit() != nullptr);
unsigned flags = 0;
if (HasCopyAndDispose)
flags |= BLOCK_HAS_COPY_DISPOSE;
@@ -4447,7 +4399,7 @@ FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(StringRef name) {
IdentifierInfo *ID = &Context->Idents.get(name);
QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy);
return FunctionDecl::Create(*Context, TUDecl, SourceLocation(),
- SourceLocation(), ID, FType, 0, SC_Extern,
+ SourceLocation(), ID, FType, nullptr, SC_Extern,
false, false);
}
@@ -4531,7 +4483,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl,
SourceLocation(), SourceLocation(),
&Context->Idents.get(DescData.c_str()),
- Context->VoidPtrTy, 0,
+ Context->VoidPtrTy, nullptr,
SC_Static);
UnaryOperator *DescRefExpr =
new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD, false,
@@ -4601,11 +4553,10 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
SourceLocation());
bool isNestedCapturedVar = false;
if (block)
- for (BlockDecl::capture_const_iterator ci = block->capture_begin(),
- ce = block->capture_end(); ci != ce; ++ci) {
- const VarDecl *variable = ci->getVariable();
- if (variable == ND && ci->isNested()) {
- assert (ci->isByRef() &&
+ for (const auto &CI : block->captures()) {
+ const VarDecl *variable = CI.getVariable();
+ if (variable == ND && CI.isNested()) {
+ assert (CI.isByRef() &&
"SynthBlockInitExpr - captured block variable is not byref");
isNestedCapturedVar = true;
break;
@@ -4700,7 +4651,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
// Rewrite the block body in place.
Stmt *SaveCurrentBody = CurrentBody;
CurrentBody = BE->getBody();
- PropParentMap = 0;
+ PropParentMap = nullptr;
// block literal on rhs of a property-dot-sytax assignment
// must be replaced by its synthesize ast so getRewrittenText
// works as expected. In this case, what actually ends up on RHS
@@ -4711,7 +4662,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
RewriteFunctionBodyOrGlobalInitializer(BE->getBody());
DisableReplaceStmt = saveDisableReplaceStmt;
CurrentBody = SaveCurrentBody;
- PropParentMap = 0;
+ PropParentMap = nullptr;
ImportedLocalExternalDecls.clear();
// Now we snarf the rewritten text and stash it away for later use.
std::string Str = Rewrite.getRewrittenText(BE->getSourceRange());
@@ -4795,9 +4746,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin());
// Blocks rewrite rules.
- for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
- DI != DE; ++DI) {
- Decl *SD = *DI;
+ for (auto *SD : DS->decls()) {
if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) {
if (isTopLevelBlockPointerType(ND->getType()))
RewriteBlockPointerDecl(ND);
@@ -4876,9 +4825,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
}
void RewriteObjC::RewriteRecordBody(RecordDecl *RD) {
- for (RecordDecl::field_iterator i = RD->field_begin(),
- e = RD->field_end(); i != e; ++i) {
- FieldDecl *FD = *i;
+ for (auto *FD : RD->fields()) {
if (isTopLevelBlockPointerType(FD->getType()))
RewriteBlockPointerDecl(FD);
if (FD->getType()->isObjCQualifiedIdType() ||
@@ -4912,16 +4859,16 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
Body =
cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
FD->setBody(Body);
- CurrentBody = 0;
+ CurrentBody = nullptr;
if (PropParentMap) {
delete PropParentMap;
- PropParentMap = 0;
+ PropParentMap = nullptr;
}
// This synthesizes and inserts the block "impl" struct, invoke function,
// and any copy/dispose helper functions.
InsertBlockLiteralsWithinFunction(FD);
- CurFunctionDef = 0;
- CurFunctionDeclToDeclareForBlock = 0;
+ CurFunctionDef = nullptr;
+ CurFunctionDeclToDeclareForBlock = nullptr;
}
break;
}
@@ -4933,13 +4880,13 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
Body =
cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
MD->setBody(Body);
- CurrentBody = 0;
+ CurrentBody = nullptr;
if (PropParentMap) {
delete PropParentMap;
- PropParentMap = 0;
+ PropParentMap = nullptr;
}
InsertBlockLiteralsWithinMethod(MD);
- CurMethodDef = 0;
+ CurMethodDef = nullptr;
}
break;
}
@@ -4974,14 +4921,14 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
GlobalVarDecl = VD;
CurrentBody = VD->getInit();
RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
- CurrentBody = 0;
+ CurrentBody = nullptr;
if (PropParentMap) {
delete PropParentMap;
- PropParentMap = 0;
+ PropParentMap = nullptr;
}
SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName());
- GlobalVarDecl = 0;
-
+ GlobalVarDecl = nullptr;
+
// This is needed for blocks.
if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) {
RewriteCastExpr(CE);
@@ -5428,10 +5375,8 @@ void RewriteObjCFragileABI::RewriteObjCClassMetaData(ObjCImplementationDecl *IDe
ObjCInterfaceDecl::ivar_iterator IVI, IVE;
SmallVector<ObjCIvarDecl *, 8> IVars;
if (!IDecl->ivar_empty()) {
- for (ObjCInterfaceDecl::ivar_iterator
- IV = IDecl->ivar_begin(), IVEnd = IDecl->ivar_end();
- IV != IVEnd; ++IV)
- IVars.push_back(*IV);
+ for (auto *IV : IDecl->ivars())
+ IVars.push_back(IV);
IVI = IDecl->ivar_begin();
IVE = IDecl->ivar_end();
} else {
@@ -5465,14 +5410,11 @@ void RewriteObjCFragileABI::RewriteObjCClassMetaData(ObjCImplementationDecl *IDe
}
// Build _objc_method_list for class's instance methods if needed
- SmallVector<ObjCMethodDecl *, 32>
- InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
+ SmallVector<ObjCMethodDecl *, 32> InstanceMethods(IDecl->instance_methods());
// If any of our property implementations have associated getters or
// setters, produce metadata for them as well.
- for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(),
- PropEnd = IDecl->propimpl_end();
- Prop != PropEnd; ++Prop) {
+ for (const auto *Prop : IDecl->property_impls()) {
if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
continue;
if (!Prop->getPropertyIvarDecl())
@@ -5536,7 +5478,7 @@ void RewriteObjCFragileABI::RewriteObjCClassMetaData(ObjCImplementationDecl *IDe
}
// Meta-class metadata generation.
- ObjCInterfaceDecl *RootClass = 0;
+ ObjCInterfaceDecl *RootClass = nullptr;
ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass();
while (SuperClass) {
RootClass = SuperClass;
@@ -5747,14 +5689,11 @@ void RewriteObjCFragileABI::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *ID
FullCategoryName += IDecl->getNameAsString();
// Build _objc_method_list for class's instance methods if needed
- SmallVector<ObjCMethodDecl *, 32>
- InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end());
+ SmallVector<ObjCMethodDecl *, 32> InstanceMethods(IDecl->instance_methods());
// If any of our property implementations have associated getters or
// setters, produce metadata for them as well.
- for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(),
- PropEnd = IDecl->propimpl_end();
- Prop != PropEnd; ++Prop) {
+ for (const auto *Prop : IDecl->property_impls()) {
if (Prop->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
continue;
if (!Prop->getPropertyIvarDecl())
@@ -5938,7 +5877,7 @@ Stmt *RewriteObjCFragileABI::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null");
// lookup which class implements the instance variable.
- ObjCInterfaceDecl *clsDeclared = 0;
+ ObjCInterfaceDecl *clsDeclared = nullptr;
iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
clsDeclared);
assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");
@@ -5979,7 +5918,7 @@ Stmt *RewriteObjCFragileABI::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
const ObjCInterfaceType *iFaceDecl =
dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType());
// lookup which class implements the instance variable.
- ObjCInterfaceDecl *clsDeclared = 0;
+ ObjCInterfaceDecl *clsDeclared = nullptr;
iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(),
clsDeclared);
assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class");
@@ -6009,3 +5948,5 @@ Stmt *RewriteObjCFragileABI::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
ReplaceStmtWithRange(IV, Replacement, OldRange);
return Replacement;
}
+
+#endif
diff --git a/lib/Rewrite/Frontend/RewriteTest.cpp b/lib/Frontend/Rewrite/RewriteTest.cpp
index 722c5e80b443..722c5e80b443 100644
--- a/lib/Rewrite/Frontend/RewriteTest.cpp
+++ b/lib/Frontend/Rewrite/RewriteTest.cpp
diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp
index 6514321f228d..29c58a8ac34e 100644
--- a/lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -59,32 +59,32 @@ public:
virtual ~SDiagsRenderer() {}
protected:
- virtual void emitDiagnosticMessage(SourceLocation Loc,
- PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- StringRef Message,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager *SM,
- DiagOrStoredDiag D);
-
- virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
- DiagnosticsEngine::Level Level,
- ArrayRef<CharSourceRange> Ranges,
- const SourceManager &SM) {}
-
- virtual void emitNote(SourceLocation Loc, StringRef Message,
- const SourceManager *SM);
-
- virtual void emitCodeContext(SourceLocation Loc,
- DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM);
-
- virtual void beginDiagnostic(DiagOrStoredDiag D,
- DiagnosticsEngine::Level Level);
- virtual void endDiagnostic(DiagOrStoredDiag D,
- DiagnosticsEngine::Level Level);
+ void emitDiagnosticMessage(SourceLocation Loc,
+ PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ StringRef Message,
+ ArrayRef<CharSourceRange> Ranges,
+ const SourceManager *SM,
+ DiagOrStoredDiag D) override;
+
+ void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges,
+ const SourceManager &SM) override {}
+
+ void emitNote(SourceLocation Loc, StringRef Message,
+ const SourceManager *SM) override;
+
+ void emitCodeContext(SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange>& Ranges,
+ ArrayRef<FixItHint> Hints,
+ const SourceManager &SM) override;
+
+ void beginDiagnostic(DiagOrStoredDiag D,
+ DiagnosticsEngine::Level Level) override;
+ void endDiagnostic(DiagOrStoredDiag D,
+ DiagnosticsEngine::Level Level) override;
};
class SDiagsWriter : public DiagnosticConsumer {
@@ -93,26 +93,26 @@ class SDiagsWriter : public DiagnosticConsumer {
struct SharedState;
explicit SDiagsWriter(IntrusiveRefCntPtr<SharedState> State)
- : LangOpts(0), OriginalInstance(false), State(State) { }
+ : LangOpts(nullptr), OriginalInstance(false), State(State) {}
public:
SDiagsWriter(raw_ostream *os, DiagnosticOptions *diags)
- : LangOpts(0), OriginalInstance(true), State(new SharedState(os, diags))
+ : LangOpts(nullptr), OriginalInstance(true),
+ State(new SharedState(os, diags))
{
EmitPreamble();
}
~SDiagsWriter() {}
-
+
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
- const Diagnostic &Info);
-
- void BeginSourceFile(const LangOptions &LO,
- const Preprocessor *PP) {
+ const Diagnostic &Info) override;
+
+ void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) override {
LangOpts = &LO;
}
- virtual void finish();
+ void finish() override;
private:
/// \brief Emit the preamble for the serialized diagnostics.
@@ -174,7 +174,7 @@ private:
const SourceManager &SM);
/// \brief The version of the diagnostics file.
- enum { Version = 1 };
+ enum { Version = 2 };
/// \brief Language options, which can differ from one clone of this client
/// to another.
@@ -200,7 +200,7 @@ private:
llvm::BitstreamWriter Stream;
/// \brief The name of the diagnostics file.
- OwningPtr<raw_ostream> OS;
+ std::unique_ptr<raw_ostream> OS;
/// \brief The set of constructed record abbreviations.
AbbreviationMap Abbrevs;
@@ -255,7 +255,7 @@ static void EmitBlockID(unsigned ID, const char *Name,
Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
// Emit the block name if present.
- if (Name == 0 || Name[0] == 0)
+ if (!Name || Name[0] == 0)
return;
Record.clear();
@@ -546,7 +546,7 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
EnterDiagBlock();
EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel,
- State->diagBuf, 0, &Info);
+ State->diagBuf, nullptr, &Info);
if (DiagLevel == DiagnosticsEngine::Note)
ExitDiagBlock();
@@ -560,12 +560,26 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
State->diagBuf.str(),
Info.getRanges(),
- llvm::makeArrayRef(Info.getFixItHints(),
- Info.getNumFixItHints()),
+ Info.getFixItHints(),
&Info.getSourceManager(),
&Info);
}
+static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level) {
+ switch (Level) {
+#define CASE(X) case DiagnosticsEngine::X: return serialized_diags::X;
+ CASE(Ignored)
+ CASE(Note)
+ CASE(Remark)
+ CASE(Warning)
+ CASE(Error)
+ CASE(Fatal)
+#undef CASE
+ }
+
+ llvm_unreachable("invalid diagnostic level");
+}
+
void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
@@ -579,7 +593,7 @@ void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
// Emit the RECORD_DIAG record.
Record.clear();
Record.push_back(RECORD_DIAG);
- Record.push_back(Level);
+ Record.push_back(getStableLevel(Level));
AddLocToRecord(Loc, SM, PLoc, Record);
if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) {
@@ -688,5 +702,5 @@ void SDiagsWriter::finish() {
State->OS->write((char *)&State->Buffer.front(), State->Buffer.size());
State->OS->flush();
- State->OS.reset(0);
+ State->OS.reset();
}
diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp
index a2dc9537bc05..6e6f3dd1bfee 100644
--- a/lib/Frontend/TextDiagnostic.cpp
+++ b/lib/Frontend/TextDiagnostic.cpp
@@ -26,6 +26,8 @@ using namespace clang;
static const enum raw_ostream::Colors noteColor =
raw_ostream::BLACK;
+static const enum raw_ostream::Colors remarkColor =
+ raw_ostream::BLUE;
static const enum raw_ostream::Colors fixitColor =
raw_ostream::GREEN;
static const enum raw_ostream::Colors caretColor =
@@ -312,14 +314,6 @@ private:
SmallVector<int,200> m_byteToColumn;
SmallVector<int,200> m_columnToByte;
};
-
-// used in assert in selectInterestingSourceRegion()
-struct char_out_of_range {
- const char lower,upper;
- char_out_of_range(char lower, char upper) :
- lower(lower), upper(upper) {}
- bool operator()(char c) { return c < lower || upper < c; }
-};
} // end anonymous namespace
/// \brief When the source code line we want to print is too long for
@@ -339,7 +333,7 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
// No special characters are allowed in CaretLine.
assert(CaretLine.end() ==
std::find_if(CaretLine.begin(), CaretLine.end(),
- char_out_of_range(' ','~')));
+ [](char c) { return c < ' ' || '~' < c; }));
// Find the slice that we need to display the full caret line
// correctly.
@@ -695,8 +689,9 @@ TextDiagnostic::emitDiagnosticMessage(SourceLocation Loc,
printDiagnosticLevel(OS, Level, DiagOpts->ShowColors,
DiagOpts->CLFallbackMode);
- printDiagnosticMessage(OS, Level, Message,
- OS.tell() - StartOfLocationInfo,
+ printDiagnosticMessage(OS,
+ /*IsSupplemental*/ Level == DiagnosticsEngine::Note,
+ Message, OS.tell() - StartOfLocationInfo,
DiagOpts->MessageLength, DiagOpts->ShowColors);
}
@@ -711,6 +706,7 @@ TextDiagnostic::printDiagnosticLevel(raw_ostream &OS,
case DiagnosticsEngine::Ignored:
llvm_unreachable("Invalid diagnostic type");
case DiagnosticsEngine::Note: OS.changeColor(noteColor, true); break;
+ case DiagnosticsEngine::Remark: OS.changeColor(remarkColor, true); break;
case DiagnosticsEngine::Warning: OS.changeColor(warningColor, true); break;
case DiagnosticsEngine::Error: OS.changeColor(errorColor, true); break;
case DiagnosticsEngine::Fatal: OS.changeColor(fatalColor, true); break;
@@ -721,6 +717,7 @@ TextDiagnostic::printDiagnosticLevel(raw_ostream &OS,
case DiagnosticsEngine::Ignored:
llvm_unreachable("Invalid diagnostic type");
case DiagnosticsEngine::Note: OS << "note"; break;
+ case DiagnosticsEngine::Remark: OS << "remark"; break;
case DiagnosticsEngine::Warning: OS << "warning"; break;
case DiagnosticsEngine::Error: OS << "error"; break;
case DiagnosticsEngine::Fatal: OS << "fatal error"; break;
@@ -739,24 +736,18 @@ TextDiagnostic::printDiagnosticLevel(raw_ostream &OS,
OS.resetColor();
}
-/*static*/ void
-TextDiagnostic::printDiagnosticMessage(raw_ostream &OS,
- DiagnosticsEngine::Level Level,
- StringRef Message,
- unsigned CurrentColumn, unsigned Columns,
- bool ShowColors) {
+/*static*/
+void TextDiagnostic::printDiagnosticMessage(raw_ostream &OS,
+ bool IsSupplemental,
+ StringRef Message,
+ unsigned CurrentColumn,
+ unsigned Columns, bool ShowColors) {
bool Bold = false;
- if (ShowColors) {
- // Print warnings, errors and fatal errors in bold, no color
- switch (Level) {
- case DiagnosticsEngine::Warning:
- case DiagnosticsEngine::Error:
- case DiagnosticsEngine::Fatal:
- OS.changeColor(savedColor, true);
- Bold = true;
- break;
- default: break; //don't bold notes
- }
+ if (ShowColors && !IsSupplemental) {
+ // Print primary diagnostic messages in bold and without color, to visually
+ // indicate the transition from continuation notes and other output.
+ OS.changeColor(savedColor, true);
+ Bold = true;
}
if (Columns)
@@ -787,7 +778,7 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
FileID FID = SM.getFileID(Loc);
if (!FID.isInvalid()) {
const FileEntry* FE = SM.getFileEntryForID(FID);
- if (FE && FE->getName()) {
+ if (FE && FE->isValid()) {
OS << FE->getName();
if (FE->isInPCH())
OS << " (in PCH)";
@@ -816,7 +807,10 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
if (unsigned ColNo = PLoc.getColumn()) {
if (DiagOpts->getFormat() == DiagnosticOptions::Msvc) {
OS << ',';
- ColNo--;
+ // Visual Studio 2010 or earlier expects column number to be off by one
+ if (LangOpts.MSCompatibilityVersion &&
+ LangOpts.MSCompatibilityVersion < 170000000)
+ ColNo--;
} else
OS << ':';
OS << ColNo;
@@ -877,12 +871,6 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
OS << ' ';
}
-void TextDiagnostic::emitBasicNote(StringRef Message) {
- // FIXME: Emit this as a real note diagnostic.
- // FIXME: Format an actual diagnostic rather than a hard coded string.
- OS << "note: " << Message << "\n";
-}
-
void TextDiagnostic::emitIncludeLocation(SourceLocation Loc,
PresumedLoc PLoc,
const SourceManager &SM) {
@@ -1143,7 +1131,7 @@ void TextDiagnostic::emitSnippetAndCaret(
std::string FixItInsertionLine = buildFixItInsertionLine(LineNo,
sourceColMap,
Hints, SM,
- DiagOpts.getPtr());
+ DiagOpts.get());
// If the source line is too long for our terminal, select only the
// "interesting" source region within that line.
diff --git a/lib/Frontend/TextDiagnosticBuffer.cpp b/lib/Frontend/TextDiagnosticBuffer.cpp
index 5821436a306f..9c6bebb07210 100644
--- a/lib/Frontend/TextDiagnosticBuffer.cpp
+++ b/lib/Frontend/TextDiagnosticBuffer.cpp
@@ -35,6 +35,9 @@ void TextDiagnosticBuffer::HandleDiagnostic(DiagnosticsEngine::Level Level,
case DiagnosticsEngine::Warning:
Warnings.push_back(std::make_pair(Info.getLocation(), Buf.str()));
break;
+ case DiagnosticsEngine::Remark:
+ Remarks.push_back(std::make_pair(Info.getLocation(), Buf.str()));
+ break;
case DiagnosticsEngine::Error:
case DiagnosticsEngine::Fatal:
Errors.push_back(std::make_pair(Info.getLocation(), Buf.str()));
@@ -42,36 +45,19 @@ void TextDiagnosticBuffer::HandleDiagnostic(DiagnosticsEngine::Level Level,
}
}
-/// \brief Escape diagnostic texts to avoid problems when they are fed into the
-/// diagnostic formatter a second time.
-static StringRef escapeDiag(StringRef Str, SmallVectorImpl<char> &Buf) {
- size_t Pos = Str.find('%');
- if (Pos == StringRef::npos)
- return Str;
-
- // We found a '%'. Replace this and all following '%' with '%%'.
- Buf.clear();
- Buf.append(Str.data(), Str.data() + Pos);
- for (size_t I = Pos, E = Str.size(); I != E; ++I) {
- if (Str[I] == '%')
- Buf.push_back('%');
- Buf.push_back(Str[I]);
- }
-
- return StringRef(Buf.data(), Buf.size());
-}
-
void TextDiagnosticBuffer::FlushDiagnostics(DiagnosticsEngine &Diags) const {
- SmallVector<char, 64> Buf;
// FIXME: Flush the diagnostics in order.
for (const_iterator it = err_begin(), ie = err_end(); it != ie; ++it)
- Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error,
- escapeDiag(it->second, Buf)));
+ Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0"))
+ << it->second;
for (const_iterator it = warn_begin(), ie = warn_end(); it != ie; ++it)
- Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Warning,
- escapeDiag(it->second, Buf)));
+ Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Warning, "%0"))
+ << it->second;
+ for (const_iterator it = remark_begin(), ie = remark_end(); it != ie; ++it)
+ Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Remark, "%0"))
+ << it->second;
for (const_iterator it = note_begin(), ie = note_end(); it != ie; ++it)
- Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Note,
- escapeDiag(it->second, Buf)));
+ Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Note, "%0"))
+ << it->second;
}
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 994a8f74ed46..66b46b7814eb 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -43,7 +43,7 @@ void TextDiagnosticPrinter::BeginSourceFile(const LangOptions &LO,
}
void TextDiagnosticPrinter::EndSourceFile() {
- TextDiag.reset(0);
+ TextDiag.reset();
}
/// \brief Print any diagnostic option information to a raw_ostream.
@@ -81,7 +81,11 @@ static void printDiagnosticOptions(raw_ostream &OS,
StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
if (!Opt.empty()) {
- OS << (Started ? "," : " [") << "-W" << Opt;
+ OS << (Started ? "," : " [")
+ << (Level == DiagnosticsEngine::Remark ? "-R" : "-W") << Opt;
+ StringRef OptValue = Info.getDiags()->getFlagValue();
+ if (!OptValue.empty())
+ OS << "=" << OptValue;
Started = true;
}
}
@@ -150,8 +154,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
TextDiag->emitDiagnostic(Info.getLocation(), Level, DiagMessageStream.str(),
Info.getRanges(),
- llvm::makeArrayRef(Info.getFixItHints(),
- Info.getNumFixItHints()),
+ Info.getFixItHints(),
&Info.getSourceManager());
OS.flush();
diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 045e60add1fc..b50950e9b300 100644
--- a/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -30,8 +30,9 @@ typedef VerifyDiagnosticConsumer::ExpectedData ExpectedData;
VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags)
: Diags(_Diags),
PrimaryClient(Diags.getClient()), OwnsPrimaryClient(Diags.ownsClient()),
- Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0),
- LangOpts(0), SrcManager(0), ActiveSourceFiles(0), Status(HasNoDirectives)
+ Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(nullptr),
+ LangOpts(nullptr), SrcManager(nullptr), ActiveSourceFiles(0),
+ Status(HasNoDirectives)
{
Diags.takeClient();
if (Diags.hasSourceManager())
@@ -41,7 +42,7 @@ VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags)
VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
assert(!ActiveSourceFiles && "Incomplete parsing of source files!");
assert(!CurrentPreprocessor && "CurrentPreprocessor should be invalid!");
- SrcManager = 0;
+ SrcManager = nullptr;
CheckDiagnostics();
Diags.takeClient();
if (OwnsPrimaryClient)
@@ -104,8 +105,8 @@ void VerifyDiagnosticConsumer::EndSourceFile() {
// Check diagnostics once last file completed.
CheckDiagnostics();
- CurrentPreprocessor = 0;
- LangOpts = 0;
+ CurrentPreprocessor = nullptr;
+ LangOpts = nullptr;
}
}
@@ -163,15 +164,16 @@ namespace {
class StandardDirective : public Directive {
public:
StandardDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
- StringRef Text, unsigned Min, unsigned Max)
- : Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max) { }
+ bool MatchAnyLine, StringRef Text, unsigned Min,
+ unsigned Max)
+ : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max) { }
- virtual bool isValid(std::string &Error) {
+ bool isValid(std::string &Error) override {
// all strings are considered valid; even empty ones
return true;
}
- virtual bool match(StringRef S) {
+ bool match(StringRef S) override {
return S.find(Text) != StringRef::npos;
}
};
@@ -181,16 +183,18 @@ public:
class RegexDirective : public Directive {
public:
RegexDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
- StringRef Text, unsigned Min, unsigned Max)
- : Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max), Regex(Text) { }
+ bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max,
+ StringRef RegexStr)
+ : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max),
+ Regex(RegexStr) { }
- virtual bool isValid(std::string &Error) {
+ bool isValid(std::string &Error) override {
if (Regex.isValid(Error))
return true;
return false;
}
- virtual bool match(StringRef S) {
+ bool match(StringRef S) override {
return Regex.match(S);
}
@@ -202,7 +206,7 @@ class ParseHelper
{
public:
ParseHelper(StringRef S)
- : Begin(S.begin()), End(S.end()), C(Begin), P(Begin), PEnd(NULL) { }
+ : Begin(S.begin()), End(S.end()), C(Begin), P(Begin), PEnd(nullptr) {}
// Return true if string literal is next.
bool Next(StringRef S) {
@@ -240,7 +244,7 @@ public:
if (!EnsureStartOfWord
// Check if string literal starts a new word.
|| P == Begin || isWhitespace(P[-1])
- // Or it could be preceeded by the start of a comment.
+ // Or it could be preceded by the start of a comment.
|| (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')
&& P[-2] == '/'))
return true;
@@ -249,6 +253,30 @@ public:
return false;
}
+ // Return true if a CloseBrace that closes the OpenBrace at the current nest
+ // level is found. When true, P marks begin-position of CloseBrace.
+ bool SearchClosingBrace(StringRef OpenBrace, StringRef CloseBrace) {
+ unsigned Depth = 1;
+ P = C;
+ while (P < End) {
+ StringRef S(P, End - P);
+ if (S.startswith(OpenBrace)) {
+ ++Depth;
+ P += OpenBrace.size();
+ } else if (S.startswith(CloseBrace)) {
+ --Depth;
+ if (Depth == 0) {
+ PEnd = P + CloseBrace.size();
+ return true;
+ }
+ P += CloseBrace.size();
+ } else {
+ ++P;
+ }
+ }
+ return false;
+ }
+
// Advance 1-past previous next/search.
// Behavior is undefined if previous next/search failed.
bool Advance() {
@@ -301,13 +329,15 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
PH.Advance();
// Next token: { error | warning | note }
- DirectiveList* DL = NULL;
+ DirectiveList *DL = nullptr;
if (PH.Next("error"))
- DL = ED ? &ED->Errors : NULL;
+ DL = ED ? &ED->Errors : nullptr;
else if (PH.Next("warning"))
- DL = ED ? &ED->Warnings : NULL;
+ DL = ED ? &ED->Warnings : nullptr;
+ else if (PH.Next("remark"))
+ DL = ED ? &ED->Remarks : nullptr;
else if (PH.Next("note"))
- DL = ED ? &ED->Notes : NULL;
+ DL = ED ? &ED->Notes : nullptr;
else if (PH.Next("no-diagnostics")) {
if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives)
Diags.Report(Pos, diag::err_verify_invalid_no_diags)
@@ -344,6 +374,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
// Next optional token: @
SourceLocation ExpectedLoc;
+ bool MatchAnyLine = false;
if (!PH.Next("@")) {
ExpectedLoc = Pos;
} else {
@@ -371,8 +402,8 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
// Lookup file via Preprocessor, like a #include.
const DirectoryLookup *CurDir;
- const FileEntry *FE = PP->LookupFile(Pos, Filename, false, NULL, CurDir,
- NULL, NULL, 0);
+ const FileEntry *FE = PP->LookupFile(Pos, Filename, false, nullptr,
+ CurDir, nullptr, nullptr, nullptr);
if (!FE) {
Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
diag::err_verify_missing_file) << Filename << KindStr;
@@ -384,6 +415,10 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
if (PH.Next(Line) && Line > 0)
ExpectedLoc = SM.translateFileLineCol(FE, Line, 1);
+ else if (PH.Next("*")) {
+ MatchAnyLine = true;
+ ExpectedLoc = SM.translateFileLineCol(FE, 1, 1);
+ }
}
if (ExpectedLoc.isInvalid()) {
@@ -437,7 +472,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
const char* const ContentBegin = PH.C; // mark content begin
// Search for token: }}
- if (!PH.Search("}}")) {
+ if (!PH.SearchClosingBrace("{{", "}}")) {
Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
diag::err_verify_missing_end) << KindStr;
continue;
@@ -459,12 +494,21 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
if (Text.empty())
Text.assign(ContentBegin, ContentEnd);
+ // Check that regex directives contain at least one regex.
+ if (RegexKind && Text.find("{{") == StringRef::npos) {
+ Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
+ diag::err_verify_missing_regex) << Text;
+ return false;
+ }
+
// Construct new directive.
- Directive *D = Directive::create(RegexKind, Pos, ExpectedLoc, Text,
- Min, Max);
+ std::unique_ptr<Directive> D(
+ Directive::create(RegexKind, Pos, ExpectedLoc, MatchAnyLine, Text,
+ Min, Max));
+
std::string Error;
if (D->isValid(Error)) {
- DL->push_back(D);
+ DL->push_back(D.release());
FoundDirective = true;
} else {
Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
@@ -562,7 +606,8 @@ static bool findDirectives(SourceManager &SM, FileID FID,
if (Comment.empty()) continue;
// Find first directive.
- if (ParseDirective(Comment, 0, SM, 0, Tok.getLocation(), Status))
+ if (ParseDirective(Comment, nullptr, SM, nullptr, Tok.getLocation(),
+ Status))
return true;
}
return false;
@@ -608,8 +653,11 @@ static unsigned PrintExpected(DiagnosticsEngine &Diags, SourceManager &SourceMgr
llvm::raw_svector_ostream OS(Fmt);
for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) {
Directive &D = **I;
- OS << "\n File " << SourceMgr.getFilename(D.DiagnosticLoc)
- << " Line " << SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);
+ OS << "\n File " << SourceMgr.getFilename(D.DiagnosticLoc);
+ if (D.MatchAnyLine)
+ OS << " Line *";
+ else
+ OS << " Line " << SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);
if (D.DirectiveLoc != D.DiagnosticLoc)
OS << " (directive at "
<< SourceMgr.getFilename(D.DirectiveLoc) << ':'
@@ -656,9 +704,11 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
for (unsigned i = 0; i < D.Max; ++i) {
DiagList::iterator II, IE;
for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
- unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);
- if (LineNo1 != LineNo2)
- continue;
+ if (!D.MatchAnyLine) {
+ unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);
+ if (LineNo1 != LineNo2)
+ continue;
+ }
if (!IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first))
continue;
@@ -705,6 +755,10 @@ static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings,
Buffer.warn_begin(), Buffer.warn_end());
+ // See if there are remark mismatches.
+ NumProblems += CheckLists(Diags, SourceMgr, "remark", ED.Remarks,
+ Buffer.remark_begin(), Buffer.remark_end());
+
// See if there are note mismatches.
NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes,
Buffer.note_begin(), Buffer.note_end());
@@ -802,11 +856,11 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() {
// Check that the expected diagnostics occurred.
NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED);
} else {
- NumErrors += (PrintUnexpected(Diags, 0, Buffer->err_begin(),
+ NumErrors += (PrintUnexpected(Diags, nullptr, Buffer->err_begin(),
Buffer->err_end(), "error") +
- PrintUnexpected(Diags, 0, Buffer->warn_begin(),
+ PrintUnexpected(Diags, nullptr, Buffer->warn_begin(),
Buffer->warn_end(), "warn") +
- PrintUnexpected(Diags, 0, Buffer->note_begin(),
+ PrintUnexpected(Diags, nullptr, Buffer->note_begin(),
Buffer->note_end(), "note"));
}
@@ -815,15 +869,39 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() {
// Reset the buffer, we have processed all the diagnostics in it.
Buffer.reset(new TextDiagnosticBuffer());
- ED.Errors.clear();
- ED.Warnings.clear();
- ED.Notes.clear();
+ ED.Reset();
}
Directive *Directive::create(bool RegexKind, SourceLocation DirectiveLoc,
- SourceLocation DiagnosticLoc, StringRef Text,
- unsigned Min, unsigned Max) {
- if (RegexKind)
- return new RegexDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max);
- return new StandardDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max);
+ SourceLocation DiagnosticLoc, bool MatchAnyLine,
+ StringRef Text, unsigned Min, unsigned Max) {
+ if (!RegexKind)
+ return new StandardDirective(DirectiveLoc, DiagnosticLoc, MatchAnyLine,
+ Text, Min, Max);
+
+ // Parse the directive into a regular expression.
+ std::string RegexStr;
+ StringRef S = Text;
+ while (!S.empty()) {
+ if (S.startswith("{{")) {
+ S = S.drop_front(2);
+ size_t RegexMatchLength = S.find("}}");
+ assert(RegexMatchLength != StringRef::npos);
+ // Append the regex, enclosed in parentheses.
+ RegexStr += "(";
+ RegexStr.append(S.data(), RegexMatchLength);
+ RegexStr += ")";
+ S = S.drop_front(RegexMatchLength + 2);
+ } else {
+ size_t VerbatimMatchLength = S.find("{{");
+ if (VerbatimMatchLength == StringRef::npos)
+ VerbatimMatchLength = S.size();
+ // Escape and append the fixed string.
+ RegexStr += llvm::Regex::escape(S.substr(0, VerbatimMatchLength));
+ S = S.drop_front(VerbatimMatchLength);
+ }
+ }
+
+ return new RegexDirective(DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text,
+ Min, Max, RegexStr);
}
diff --git a/lib/FrontendTool/CMakeLists.txt b/lib/FrontendTool/CMakeLists.txt
index 28a864a633ed..7e11be0ce4c5 100644
--- a/lib/FrontendTool/CMakeLists.txt
+++ b/lib/FrontendTool/CMakeLists.txt
@@ -1,31 +1,34 @@
-add_clang_library(clangFrontendTool
- ExecuteCompilerInvocation.cpp
+set(LLVM_LINK_COMPONENTS
+ Option
+ Support
)
-add_dependencies(clangFrontendTool
- ClangDiagnosticCommon
- ClangDiagnosticFrontend
- ClangDriverOptions
- )
-
-target_link_libraries(clangFrontendTool
+set(link_libs
+ clangBasic
+ clangCodeGen
clangDriver
clangFrontend
- clangRewriteCore
clangRewriteFrontend
- clangCodeGen
)
if(CLANG_ENABLE_ARCMT)
- target_link_libraries(clangFrontendTool
+ list(APPEND link_libs
clangARCMigrate
)
endif()
if(CLANG_ENABLE_STATIC_ANALYZER)
- target_link_libraries(clangFrontendTool
+ list(APPEND link_libs
clangStaticAnalyzerFrontend
- clangStaticAnalyzerCheckers
- clangStaticAnalyzerCore
)
endif()
+
+add_clang_library(clangFrontendTool
+ ExecuteCompilerInvocation.cpp
+
+ DEPENDS
+ ClangDriverOptions
+
+ LINK_LIBS
+ ${link_libs}
+ )
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index d755839c0f77..de864f653562 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -21,6 +21,7 @@
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Frontend/Utils.h"
#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "llvm/Option/OptTable.h"
@@ -33,6 +34,7 @@ using namespace llvm::opt;
static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
using namespace clang::frontend;
StringRef Action("unknown");
+ (void)Action;
switch (CI.getFrontendOpts().ProgramAction) {
case ASTDeclList: return new ASTDeclListAction();
@@ -43,66 +45,51 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
case DumpTokens: return new DumpTokensAction();
case EmitAssembly: return new EmitAssemblyAction();
case EmitBC: return new EmitBCAction();
-#ifdef CLANG_ENABLE_REWRITER
case EmitHTML: return new HTMLPrintAction();
-#else
- case EmitHTML: Action = "EmitHTML"; break;
-#endif
case EmitLLVM: return new EmitLLVMAction();
case EmitLLVMOnly: return new EmitLLVMOnlyAction();
case EmitCodeGenOnly: return new EmitCodeGenOnlyAction();
case EmitObj: return new EmitObjAction();
-#ifdef CLANG_ENABLE_REWRITER
case FixIt: return new FixItAction();
-#else
- case FixIt: Action = "FixIt"; break;
-#endif
case GenerateModule: return new GenerateModuleAction;
case GeneratePCH: return new GeneratePCHAction;
case GeneratePTH: return new GeneratePTHAction();
case InitOnly: return new InitOnlyAction();
case ParseSyntaxOnly: return new SyntaxOnlyAction();
case ModuleFileInfo: return new DumpModuleInfoAction();
+ case VerifyPCH: return new VerifyPCHAction();
case PluginAction: {
for (FrontendPluginRegistry::iterator it =
FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end();
it != ie; ++it) {
if (it->getName() == CI.getFrontendOpts().ActionName) {
- OwningPtr<PluginASTAction> P(it->instantiate());
+ std::unique_ptr<PluginASTAction> P(it->instantiate());
if (!P->ParseArgs(CI, CI.getFrontendOpts().PluginArgs))
- return 0;
- return P.take();
+ return nullptr;
+ return P.release();
}
}
CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name)
<< CI.getFrontendOpts().ActionName;
- return 0;
+ return nullptr;
}
case PrintDeclContext: return new DeclContextPrintAction();
case PrintPreamble: return new PrintPreambleAction();
case PrintPreprocessedInput: {
- if (CI.getPreprocessorOutputOpts().RewriteIncludes) {
-#ifdef CLANG_ENABLE_REWRITER
+ if (CI.getPreprocessorOutputOpts().RewriteIncludes)
return new RewriteIncludesAction();
-#else
- Action = "RewriteIncludesAction";
- break;
-#endif
- }
return new PrintPreprocessedAction();
}
-#ifdef CLANG_ENABLE_REWRITER
case RewriteMacros: return new RewriteMacrosAction();
- case RewriteObjC: return new RewriteObjCAction();
case RewriteTest: return new RewriteTestAction();
+#ifdef CLANG_ENABLE_OBJC_REWRITER
+ case RewriteObjC: return new RewriteObjCAction();
#else
- case RewriteMacros: Action = "RewriteMacros"; break;
case RewriteObjC: Action = "RewriteObjC"; break;
- case RewriteTest: Action = "RewriteTest"; break;
#endif
#ifdef CLANG_ENABLE_ARCMT
case MigrateSource: return new arcmt::MigrateSourceAction();
@@ -118,7 +105,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
}
#if !defined(CLANG_ENABLE_ARCMT) || !defined(CLANG_ENABLE_STATIC_ANALYZER) \
- || !defined(CLANG_ENABLE_REWRITER)
+ || !defined(CLANG_ENABLE_OBJC_REWRITER)
CI.getDiagnostics().Report(diag::err_fe_action_not_available) << Action;
return 0;
#else
@@ -130,18 +117,17 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
// Create the underlying action.
FrontendAction *Act = CreateFrontendBaseAction(CI);
if (!Act)
- return 0;
+ return nullptr;
const FrontendOptions &FEOpts = CI.getFrontendOpts();
-#ifdef CLANG_ENABLE_REWRITER
if (FEOpts.FixAndRecompile) {
Act = new FixItRecompile(Act);
}
-#endif
#ifdef CLANG_ENABLE_ARCMT
- if (CI.getFrontendOpts().ProgramAction != frontend::MigrateSource) {
+ if (CI.getFrontendOpts().ProgramAction != frontend::MigrateSource &&
+ CI.getFrontendOpts().ProgramAction != frontend::GeneratePCH) {
// Potentially wrap the base FE action in an ARC Migrate Tool action.
switch (FEOpts.ARCMTAction) {
case FrontendOptions::ARCMT_None:
@@ -178,7 +164,7 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
// Honor -help.
if (Clang->getFrontendOpts().ShowHelp) {
- OwningPtr<OptTable> Opts(driver::createDriverOptTable());
+ std::unique_ptr<OptTable> Opts(driver::createDriverOptTable());
Opts->PrintHelp(llvm::outs(), "clang -cc1",
"LLVM 'Clang' Compiler: http://clang.llvm.org",
/*Include=*/ driver::options::CC1Option, /*Exclude=*/ 0);
@@ -209,12 +195,12 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
// This should happen AFTER plugins have been loaded!
if (!Clang->getFrontendOpts().LLVMArgs.empty()) {
unsigned NumArgs = Clang->getFrontendOpts().LLVMArgs.size();
- const char **Args = new const char*[NumArgs + 2];
+ auto Args = llvm::make_unique<const char*[]>(NumArgs + 2);
Args[0] = "clang (LLVM option parsing)";
for (unsigned i = 0; i != NumArgs; ++i)
Args[i + 1] = Clang->getFrontendOpts().LLVMArgs[i].c_str();
- Args[NumArgs + 1] = 0;
- llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args);
+ Args[NumArgs + 1] = nullptr;
+ llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
}
#ifdef CLANG_ENABLE_STATIC_ANALYZER
@@ -230,11 +216,11 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
if (Clang->getDiagnostics().hasErrorOccurred())
return false;
// Create and execute the frontend action.
- OwningPtr<FrontendAction> Act(CreateFrontendAction(*Clang));
+ std::unique_ptr<FrontendAction> Act(CreateFrontendAction(*Clang));
if (!Act)
return false;
bool Success = Clang->ExecuteAction(*Act);
if (Clang->getFrontendOpts().DisableFree)
- Act.take();
+ BuryPointer(Act.release());
return Success;
}
diff --git a/lib/FrontendTool/Makefile b/lib/FrontendTool/Makefile
index 9ce4b767fe58..dfd282079219 100644
--- a/lib/FrontendTool/Makefile
+++ b/lib/FrontendTool/Makefile
@@ -15,10 +15,7 @@ include $(CLANG_LEVEL)/../../Makefile.config
ifeq ($(ENABLE_CLANG_ARCMT),1)
CXX.Flags += -DCLANG_ENABLE_ARCMT
-endif
-
-ifeq ($(ENABLE_CLANG_REWRITER),1)
- CXX.Flags += -DCLANG_ENABLE_REWRITER
+ CXX.Flags += -DCLANG_ENABLE_OBJC_REWRITER
endif
ifeq ($(ENABLE_CLANG_STATIC_ANALYZER),1)
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index 2da1a28aca42..edee7d764250 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -1,6 +1,7 @@
set(files
altivec.h
ammintrin.h
+ arm_acle.h
avxintrin.h
avx2intrin.h
bmiintrin.h
@@ -10,6 +11,7 @@ set(files
float.h
fma4intrin.h
fmaintrin.h
+ ia32intrin.h
immintrin.h
iso646.h
Intrin.h
@@ -44,20 +46,13 @@ set(files
xopintrin.h
cpuid.h
unwind.h
- module.map
+ module.modulemap
)
-set(output_dir ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/clang/${CLANG_VERSION}/include)
-
-# If we are in an IDE that has a configuration directory, we need to
-# create a second copy of the headers so that 'clang' can find them if
-# it's run from the build directory.
-if(MSVC_IDE OR XCODE)
- set(other_output_dir ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/lib/clang/${CLANG_VERSION}/include)
-endif()
+set(output_dir ${LLVM_LIBRARY_OUTPUT_INTDIR}/clang/${CLANG_VERSION}/include)
# Generate arm_neon.h
-clang_tablegen(arm_neon.h.inc -gen-arm-neon
+clang_tablegen(arm_neon.h -gen-arm-neon
SOURCE ${CLANG_SOURCE_DIR}/include/clang/Basic/arm_neon.td)
set(out_files)
@@ -69,43 +64,18 @@ foreach( f ${files} )
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
COMMENT "Copying clang's ${f}...")
list(APPEND out_files ${dst})
-
- if(other_output_dir)
- set(other_dst ${other_output_dir}/${f})
- add_custom_command(OUTPUT ${other_dst}
- DEPENDS ${src}
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${other_dst}
- COMMENT "Copying clang's ${f}...")
- list(APPEND out_files ${other_dst})
- endif()
endforeach( f )
add_custom_command(OUTPUT ${output_dir}/arm_neon.h
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/arm_neon.h.inc
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/arm_neon.h.inc ${output_dir}/arm_neon.h
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/arm_neon.h
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/arm_neon.h ${output_dir}/arm_neon.h
COMMENT "Copying clang's arm_neon.h...")
list(APPEND out_files ${output_dir}/arm_neon.h)
-if (other_output_dir)
- set(other_dst ${other_output_dir}/arm_neon.h)
- add_custom_command(OUTPUT ${other_dst}
- DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/arm_neon.h.inc
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/arm_neon.h.inc ${other_dst}
- COMMENT "Copying clang's arm_neon.h...")
- list(APPEND out_files ${other_dst})
-endif ()
-
add_custom_target(clang-headers ALL DEPENDS ${out_files})
set_target_properties(clang-headers PROPERTIES FOLDER "Misc")
-if (other_output_dir)
- if(UNIX)
- add_custom_command(TARGET clang-headers POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}"
- COMMAND ${CMAKE_COMMAND} -E create_symlink "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/lib/clang" "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/clang")
- endif()
-endif ()
-
-install(FILES ${files} ${output_dir}/arm_neon.h
+install(
+ FILES ${files} ${CMAKE_CURRENT_BINARY_DIR}/arm_neon.h
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
DESTINATION lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION}/include)
diff --git a/lib/Headers/Intrin.h b/lib/Headers/Intrin.h
index 437646471dab..13e105ec1782 100644
--- a/lib/Headers/Intrin.h
+++ b/lib/Headers/Intrin.h
@@ -30,31 +30,43 @@
#define __INTRIN_H
/* First include the standard intrinsics. */
+#if defined(__i386__) || defined(__x86_64__)
#include <x86intrin.h>
+#endif
+
+/* For the definition of jmp_buf. */
+#if __STDC_HOSTED__
+#include <setjmp.h>
+#endif
#ifdef __cplusplus
extern "C" {
#endif
+#if defined(__MMX__)
/* And the random ones that aren't in those files. */
__m64 _m_from_float(float);
__m64 _m_from_int(int _l);
void _m_prefetch(void *);
float _m_to_float(__m64);
int _m_to_int(__m64 _M);
+#endif
/* Other assorted instruction intrinsics. */
void __addfsbyte(unsigned long, unsigned char);
void __addfsdword(unsigned long, unsigned long);
void __addfsword(unsigned long, unsigned short);
void __code_seg(const char *);
+static __inline__
void __cpuid(int[4], int);
+static __inline__
void __cpuidex(int[4], int, int);
void __debugbreak(void);
__int64 __emul(int, int);
unsigned __int64 __emulu(unsigned int, unsigned int);
void __cdecl __fastfail(unsigned int);
unsigned int __getcallerseflags(void);
+static __inline__
void __halt(void);
unsigned char __inbyte(unsigned short);
void __inbytestring(unsigned short, unsigned char *, unsigned long);
@@ -75,8 +87,11 @@ unsigned char __lwpins32(unsigned int, unsigned int, unsigned int);
void __lwpval32(unsigned int, unsigned int, unsigned int);
unsigned int __lzcnt(unsigned int);
unsigned short __lzcnt16(unsigned short);
+static __inline__
void __movsb(unsigned char *, unsigned char const *, size_t);
+static __inline__
void __movsd(unsigned long *, unsigned long const *, size_t);
+static __inline__
void __movsw(unsigned short *, unsigned short const *, size_t);
void __nop(void);
void __nvreg_restore_fence(void);
@@ -91,26 +106,34 @@ static __inline__
unsigned int __popcnt(unsigned int);
static __inline__
unsigned short __popcnt16(unsigned short);
-unsigned __int64 __rdtsc(void);
-unsigned __int64 __rdtscp(unsigned int *);
unsigned long __readcr0(void);
unsigned long __readcr2(void);
+static __inline__
unsigned long __readcr3(void);
-unsigned long __readcr5(void);
+unsigned long __readcr4(void);
unsigned long __readcr8(void);
unsigned int __readdr(unsigned int);
-unsigned int __readeflags(void);
+#ifdef __i386__
+static __inline__
unsigned char __readfsbyte(unsigned long);
+static __inline__
unsigned long __readfsdword(unsigned long);
+static __inline__
unsigned __int64 __readfsqword(unsigned long);
+static __inline__
unsigned short __readfsword(unsigned long);
+#endif
+static __inline__
unsigned __int64 __readmsr(unsigned long);
unsigned __int64 __readpmc(unsigned long);
unsigned long __segmentlimit(unsigned long);
void __sidt(void *);
void *__slwpcb(void);
+static __inline__
void __stosb(unsigned char *, unsigned char, size_t);
+static __inline__
void __stosd(unsigned long *, unsigned long, size_t);
+static __inline__
void __stosw(unsigned short *, unsigned short, size_t);
void __svm_clgi(void);
void __svm_invlpga(void *, int);
@@ -125,11 +148,11 @@ void __vmx_off(void);
void __vmx_vmptrst(unsigned __int64 *);
void __wbinvd(void);
void __writecr0(unsigned int);
+static __inline__
void __writecr3(unsigned int);
void __writecr4(unsigned int);
void __writecr8(unsigned int);
void __writedr(unsigned int, unsigned int);
-void __writeeflags(unsigned int);
void __writefsbyte(unsigned long, unsigned char);
void __writefsdword(unsigned long, unsigned long);
void __writefsqword(unsigned long, unsigned __int64);
@@ -139,7 +162,6 @@ static __inline__
void *_AddressOfReturnAddress(void);
unsigned int _andn_u32(unsigned int, unsigned int);
unsigned int _bextr_u32(unsigned int, unsigned int, unsigned int);
-unsigned int _bextr_u32(unsigned int, unsigned int, unsigned int);
unsigned int _bextri_u32(unsigned int, unsigned int);
static __inline__
unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask);
@@ -162,8 +184,6 @@ unsigned int _blsfill_u32(unsigned int);
unsigned int _blsi_u32(unsigned int);
unsigned int _blsic_u32(unsigned int);
unsigned int _blsmsk_u32(unsigned int);
-unsigned int _blsmsk_u32(unsigned int);
-unsigned int _blsr_u32(unsigned int);
unsigned int _blsr_u32(unsigned int);
unsigned __int64 __cdecl _byteswap_uint64(unsigned __int64);
unsigned long __cdecl _byteswap_ulong(unsigned long);
@@ -181,6 +201,7 @@ short _InterlockedAnd16(short volatile *_Value, short _Mask);
static __inline__
char _InterlockedAnd8(char volatile *_Value, char _Mask);
unsigned char _interlockedbittestandreset(long volatile *, long);
+static __inline__
unsigned char _interlockedbittestandset(long volatile *, long);
static __inline__
long __cdecl _InterlockedCompareExchange(long volatile *_Destination,
@@ -208,8 +229,7 @@ static __inline__
long __cdecl _InterlockedDecrement(long volatile *_Addend);
static __inline__
short _InterlockedDecrement16(short volatile *_Addend);
-static __inline__
-long __cdecl _InterlockedExchange(long volatile *_Target, long _Value);
+long _InterlockedExchange(long volatile *_Target, long _Value);
static __inline__
short _InterlockedExchange16(short volatile *_Target, short _Value);
static __inline__
@@ -219,6 +239,10 @@ long __cdecl _InterlockedExchangeAdd(long volatile *_Addend, long _Value);
long _InterlockedExchangeAdd_HLEAcquire(long volatile *, long);
long _InterlockedExchangeAdd_HLERelease(long volatile *, long);
static __inline__
+short _InterlockedExchangeAdd16(short volatile *_Addend, short _Value);
+__int64 _InterlockedExchangeAdd64_HLEAcquire(__int64 volatile *, __int64);
+__int64 _InterlockedExchangeAdd64_HLERelease(__int64 volatile *, __int64);
+static __inline__
char _InterlockedExchangeAdd8(char volatile *_Addend, char _Value);
static __inline__
long __cdecl _InterlockedIncrement(long volatile *_Addend);
@@ -269,10 +293,9 @@ unsigned __int64 __cdecl _rotr64(unsigned __int64 _Value, int _Shift);
static __inline__
unsigned char _rotr8(unsigned char _Value, unsigned char _Shift);
int _sarx_i32(int, unsigned int);
-
-/* FIXME: Need definition for jmp_buf.
- int __cdecl _setjmp(jmp_buf); */
-
+#if __STDC_HOSTED__
+int __cdecl _setjmp(jmp_buf);
+#endif
unsigned int _shlx_u32(unsigned int, unsigned int);
unsigned int _shrx_u32(unsigned int, unsigned int);
void _Store_HLERelease(long volatile *, long);
@@ -280,13 +303,13 @@ void _Store64_HLERelease(__int64 volatile *, __int64);
void _StorePointer_HLERelease(void *volatile *, void *);
unsigned int _t1mskc_u32(unsigned int);
unsigned int _tzcnt_u32(unsigned int);
-unsigned int _tzcnt_u32(unsigned int);
unsigned int _tzmsk_u32(unsigned int);
static __inline__
void _WriteBarrier(void);
void _xabort(const unsigned int imm);
unsigned __int32 xbegin(void);
void _xend(void);
+static __inline__
unsigned __int64 __cdecl _xgetbv(unsigned int);
void __cdecl _xrstor(void const *, unsigned __int64);
void __cdecl _xsave(void *, unsigned __int64);
@@ -300,19 +323,47 @@ void __addgsbyte(unsigned long, unsigned char);
void __addgsdword(unsigned long, unsigned long);
void __addgsqword(unsigned long, unsigned __int64);
void __addgsword(unsigned long, unsigned short);
+static __inline__
void __faststorefence(void);
void __incgsbyte(unsigned long);
void __incgsdword(unsigned long);
void __incgsqword(unsigned long);
void __incgsword(unsigned long);
+unsigned char __lwpins64(unsigned __int64, unsigned int, unsigned int);
+void __lwpval64(unsigned __int64, unsigned int, unsigned int);
+unsigned __int64 __lzcnt64(unsigned __int64);
+static __inline__
+void __movsq(unsigned long long *, unsigned long long const *, size_t);
+__int64 __mulh(__int64, __int64);
+static __inline__
unsigned __int64 __popcnt64(unsigned __int64);
+static __inline__
+unsigned char __readgsbyte(unsigned long);
+static __inline__
+unsigned long __readgsdword(unsigned long);
+static __inline__
+unsigned __int64 __readgsqword(unsigned long);
+unsigned short __readgsword(unsigned long);
unsigned __int64 __shiftleft128(unsigned __int64 _LowPart,
unsigned __int64 _HighPart,
unsigned char _Shift);
unsigned __int64 __shiftright128(unsigned __int64 _LowPart,
unsigned __int64 _HighPart,
unsigned char _Shift);
+static __inline__
void __stosq(unsigned __int64 *, unsigned __int64, size_t);
+unsigned __int64 __umulh(unsigned __int64, unsigned __int64);
+unsigned char __vmx_on(unsigned __int64 *);
+unsigned char __vmx_vmclear(unsigned __int64 *);
+unsigned char __vmx_vmlaunch(void);
+unsigned char __vmx_vmptrld(unsigned __int64 *);
+unsigned char __vmx_vmread(size_t, size_t *);
+unsigned char __vmx_vmresume(void);
+unsigned char __vmx_vmwrite(size_t, size_t);
+void __writegsbyte(unsigned long, unsigned char);
+void __writegsdword(unsigned long, unsigned long);
+void __writegsqword(unsigned long, unsigned __int64);
+void __writegsword(unsigned long, unsigned short);
unsigned __int64 _andn_u64(unsigned __int64, unsigned __int64);
unsigned __int64 _bextr_u64(unsigned __int64, unsigned int, unsigned int);
unsigned __int64 _bextri_u64(unsigned __int64, unsigned int);
@@ -336,7 +387,7 @@ unsigned __int64 _blcs_u64(unsigned __int64);
unsigned __int64 _blsfill_u64(unsigned __int64);
unsigned __int64 _blsi_u64(unsigned __int64);
unsigned __int64 _blsic_u64(unsigned __int64);
-unsigned __int64 _blmsk_u64(unsigned __int64);
+unsigned __int64 _blsmsk_u64(unsigned __int64);
unsigned __int64 _blsr_u64(unsigned __int64);
unsigned __int64 __cdecl _byteswap_uint64(unsigned __int64);
unsigned __int64 _bzhi_u64(unsigned __int64, unsigned int);
@@ -347,6 +398,7 @@ short _InterlockedAnd16_np(short volatile *_Value, short _Mask);
__int64 _InterlockedAnd64_np(__int64 volatile *_Value, __int64 _Mask);
char _InterlockedAnd8_np(char volatile *_Value, char _Mask);
unsigned char _interlockedbittestandreset64(__int64 volatile *, __int64);
+static __inline__
unsigned char _interlockedbittestandset64(__int64 volatile *, __int64);
long _InterlockedCompareExchange_np(long volatile *_Destination, long _Exchange,
long _Comparand);
@@ -360,18 +412,38 @@ unsigned char _InterlockedCompareExchange128_np(__int64 volatile *_Destination,
__int64 *_ComparandResult);
short _InterlockedCompareExchange16_np(short volatile *_Destination,
short _Exchange, short _Comparand);
+__int64 _InterlockedCompareExchange64_HLEAcquire(__int64 volatile *, __int64,
+ __int64);
+__int64 _InterlockedCompareExchange64_HLERelease(__int64 volatile *, __int64,
+ __int64);
__int64 _InterlockedCompareExchange64_np(__int64 volatile *_Destination,
__int64 _Exchange, __int64 _Comparand);
+void *_InterlockedCompareExchangePointer(void *volatile *_Destination,
+ void *_Exchange, void *_Comparand);
void *_InterlockedCompareExchangePointer_np(void *volatile *_Destination,
void *_Exchange, void *_Comparand);
+static __inline__
+__int64 _InterlockedDecrement64(__int64 volatile *_Addend);
+static __inline__
+__int64 _InterlockedExchange64(__int64 volatile *_Target, __int64 _Value);
+static __inline__
+__int64 _InterlockedExchangeAdd64(__int64 volatile *_Addend, __int64 _Value);
+void *_InterlockedExchangePointer(void *volatile *_Target, void *_Value);
+static __inline__
+__int64 _InterlockedIncrement64(__int64 volatile *_Addend);
long _InterlockedOr_np(long volatile *_Value, long _Mask);
short _InterlockedOr16_np(short volatile *_Value, short _Mask);
+static __inline__
+__int64 _InterlockedOr64(__int64 volatile *_Value, __int64 _Mask);
__int64 _InterlockedOr64_np(__int64 volatile *_Value, __int64 _Mask);
char _InterlockedOr8_np(char volatile *_Value, char _Mask);
long _InterlockedXor_np(long volatile *_Value, long _Mask);
short _InterlockedXor16_np(short volatile *_Value, short _Mask);
+static __inline__
+__int64 _InterlockedXor64(__int64 volatile *_Value, __int64 _Mask);
__int64 _InterlockedXor64_np(__int64 volatile *_Value, __int64 _Mask);
char _InterlockedXor8_np(char volatile *_Value, char _Mask);
+static __inline__
unsigned __int64 _lzcnt_u64(unsigned __int64);
__int64 _mul128(__int64 _Multiplier, __int64 _Multiplicand,
__int64 *_HighProduct);
@@ -380,6 +452,12 @@ unsigned __int64 __cdecl _readfsbase_u64(void);
unsigned int __cdecl _readgsbase_u32(void);
unsigned __int64 __cdecl _readgsbase_u64(void);
unsigned __int64 _rorx_u64(unsigned __int64, const unsigned int);
+__int64 _sarx_i64(__int64, unsigned int);
+#if __STDC_HOSTED__
+int __cdecl _setjmpex(jmp_buf);
+#endif
+unsigned __int64 _shlx_u64(unsigned __int64, unsigned int);
+unsigned __int64 shrx_u64(unsigned __int64, unsigned int);
unsigned __int64 _tzcnt_u64(unsigned __int64);
unsigned __int64 _tzmsk_u64(unsigned __int64);
unsigned __int64 _umul128(unsigned __int64 _Multiplier,
@@ -503,6 +581,18 @@ _bittestandset(long *a, long b) {
*a = *a | (1 << b);
return x;
}
+#if defined(__i386__) || defined(__x86_64__)
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+_interlockedbittestandset(long volatile *__BitBase, long __BitPos) {
+ unsigned char __Res;
+ __asm__ ("xor %0, %0\n"
+ "lock bts %2, %1\n"
+ "setc %0\n"
+ : "=r" (__Res), "+m"(*__BitBase)
+ : "Ir"(__BitPos));
+ return __Res;
+}
+#endif
#ifdef __x86_64__
static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
_BitScanForward64(unsigned long *_Index, unsigned __int64 _Mask) {
@@ -552,6 +642,16 @@ _bittestandset64(__int64 *a, __int64 b) {
*a = *a | (1ll << b);
return x;
}
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+_interlockedbittestandset64(__int64 volatile *__BitBase, __int64 __BitPos) {
+ unsigned char __Res;
+ __asm__ ("xor %0, %0\n"
+ "lock bts %2, %1\n"
+ "setc %0\n"
+ : "=r" (__Res), "+m"(*__BitBase)
+ : "Ir"(__BitPos));
+ return __Res;
+}
#endif
/*----------------------------------------------------------------------------*\
|* Interlocked Exchange Add
@@ -564,10 +664,6 @@ static __inline__ short __attribute__((__always_inline__, __nodebug__))
_InterlockedExchangeAdd16(short volatile *_Addend, short _Value) {
return __atomic_add_fetch(_Addend, _Value, 0) - _Value;
}
-static __inline__ long __attribute__((__always_inline__, __nodebug__))
-_InterlockedExchangeAdd(long volatile *_Addend, long _Value) {
- return __atomic_add_fetch(_Addend, _Value, 0) - _Value;
-}
#ifdef __x86_64__
static __inline__ __int64 __attribute__((__always_inline__, __nodebug__))
_InterlockedExchangeAdd64(__int64 volatile *_Addend, __int64 _Value) {
@@ -598,12 +694,8 @@ _InterlockedExchangeSub64(__int64 volatile *_Subend, __int64 _Value) {
/*----------------------------------------------------------------------------*\
|* Interlocked Increment
\*----------------------------------------------------------------------------*/
-static __inline__ char __attribute__((__always_inline__, __nodebug__))
-_InterlockedIncrement16(char volatile *_Value) {
- return __atomic_add_fetch(_Value, 1, 0);
-}
-static __inline__ long __attribute__((__always_inline__, __nodebug__))
-_InterlockedIncrement(long volatile *_Value) {
+static __inline__ short __attribute__((__always_inline__, __nodebug__))
+_InterlockedIncrement16(short volatile *_Value) {
return __atomic_add_fetch(_Value, 1, 0);
}
#ifdef __x86_64__
@@ -615,12 +707,8 @@ _InterlockedIncrement64(__int64 volatile *_Value) {
/*----------------------------------------------------------------------------*\
|* Interlocked Decrement
\*----------------------------------------------------------------------------*/
-static __inline__ char __attribute__((__always_inline__, __nodebug__))
-_InterlockedDecrement16(char volatile *_Value) {
- return __atomic_sub_fetch(_Value, 1, 0);
-}
-static __inline__ long __attribute__((__always_inline__, __nodebug__))
-_InterlockedDecrement(long volatile *_Value) {
+static __inline__ short __attribute__((__always_inline__, __nodebug__))
+_InterlockedDecrement16(short volatile *_Value) {
return __atomic_sub_fetch(_Value, 1, 0);
}
#ifdef __x86_64__
@@ -705,11 +793,6 @@ _InterlockedExchange16(short volatile *_Target, short _Value) {
__atomic_exchange(_Target, &_Value, &_Value, 0);
return _Value;
}
-static __inline__ long __attribute__((__always_inline__, __nodebug__))
-_InterlockedExchange(long volatile *_Target, long _Value) {
- __atomic_exchange(_Target, &_Value, &_Value, 0);
- return _Value;
-}
#ifdef __x86_64__
static __inline__ __int64 __attribute__((__always_inline__, __nodebug__))
_InterlockedExchange64(__int64 volatile *_Target, __int64 _Value) {
@@ -732,23 +815,16 @@ _InterlockedCompareExchange16(short volatile *_Destination,
__atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, 0, 0);
return _Comparand;
}
-static __inline__ long __attribute__((__always_inline__, __nodebug__))
-_InterlockedCompareExchange(long volatile *_Destination,
- long _Exchange, long _Comparand) {
- __atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, 0, 0);
- return _Comparand;
-}
-#ifdef __x86_64__
static __inline__ __int64 __attribute__((__always_inline__, __nodebug__))
_InterlockedCompareExchange64(__int64 volatile *_Destination,
__int64 _Exchange, __int64 _Comparand) {
__atomic_compare_exchange(_Destination, &_Comparand, &_Exchange, 0, 0, 0);
return _Comparand;
}
-#endif
/*----------------------------------------------------------------------------*\
|* Barriers
\*----------------------------------------------------------------------------*/
+#if defined(__i386__) || defined(__x86_64__)
static __inline__ void __attribute__((__always_inline__, __nodebug__))
__attribute__((deprecated("use other intrinsics or C++11 atomics instead")))
_ReadWriteBarrier(void) {
@@ -764,6 +840,107 @@ __attribute__((deprecated("use other intrinsics or C++11 atomics instead")))
_WriteBarrier(void) {
__asm__ volatile ("" : : : "memory");
}
+#endif
+#ifdef __x86_64__
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+__faststorefence(void) {
+ __asm__ volatile("lock orq $0, (%%rsp)" : : : "memory");
+}
+#endif
+/*----------------------------------------------------------------------------*\
+|* readfs, readgs
+|* (Pointers in address space #256 and #257 are relative to the GS and FS
+|* segment registers, respectively.)
+\*----------------------------------------------------------------------------*/
+#define __ptr_to_addr_space(__addr_space_nbr, __type, __offset) \
+ ((volatile __type __attribute__((__address_space__(__addr_space_nbr)))*) \
+ (__offset))
+
+#ifdef __i386__
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+__readfsbyte(unsigned long __offset) {
+ return *__ptr_to_addr_space(257, unsigned char, __offset);
+}
+static __inline__ unsigned long __attribute__((__always_inline__, __nodebug__))
+__readfsdword(unsigned long __offset) {
+ return *__ptr_to_addr_space(257, unsigned long, __offset);
+}
+static __inline__ unsigned __int64 __attribute__((__always_inline__, __nodebug__))
+__readfsqword(unsigned long __offset) {
+ return *__ptr_to_addr_space(257, unsigned __int64, __offset);
+}
+static __inline__ unsigned short __attribute__((__always_inline__, __nodebug__))
+__readfsword(unsigned long __offset) {
+ return *__ptr_to_addr_space(257, unsigned short, __offset);
+}
+#endif
+#ifdef __x86_64__
+static __inline__ unsigned char __attribute__((__always_inline__, __nodebug__))
+__readgsbyte(unsigned long __offset) {
+ return *__ptr_to_addr_space(256, unsigned char, __offset);
+}
+static __inline__ unsigned long __attribute__((__always_inline__, __nodebug__))
+__readgsdword(unsigned long __offset) {
+ return *__ptr_to_addr_space(256, unsigned long, __offset);
+}
+static __inline__ unsigned __int64 __attribute__((__always_inline__, __nodebug__))
+__readgsqword(unsigned long __offset) {
+ return *__ptr_to_addr_space(256, unsigned __int64, __offset);
+}
+static __inline__ unsigned short __attribute__((__always_inline__, __nodebug__))
+__readgsword(unsigned long __offset) {
+ return *__ptr_to_addr_space(256, unsigned short, __offset);
+}
+#endif
+#undef __ptr_to_addr_space
+/*----------------------------------------------------------------------------*\
+|* movs, stos
+\*----------------------------------------------------------------------------*/
+#if defined(__i386__) || defined(__x86_64__)
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+__movsb(unsigned char *__dst, unsigned char const *__src, size_t __n) {
+ __asm__("rep movsb" : : "D"(__dst), "S"(__src), "c"(__n)
+ : "%edi", "%esi", "%ecx");
+}
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+__movsd(unsigned long *__dst, unsigned long const *__src, size_t __n) {
+ __asm__("rep movsl" : : "D"(__dst), "S"(__src), "c"(__n)
+ : "%edi", "%esi", "%ecx");
+}
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+__movsw(unsigned short *__dst, unsigned short const *__src, size_t __n) {
+ __asm__("rep movsh" : : "D"(__dst), "S"(__src), "c"(__n)
+ : "%edi", "%esi", "%ecx");
+}
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+__stosb(unsigned char *__dst, unsigned char __x, size_t __n) {
+ __asm__("rep stosb" : : "D"(__dst), "a"(__x), "c"(__n)
+ : "%edi", "%ecx");
+}
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+__stosd(unsigned long *__dst, unsigned long __x, size_t __n) {
+ __asm__("rep stosl" : : "D"(__dst), "a"(__x), "c"(__n)
+ : "%edi", "%ecx");
+}
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+__stosw(unsigned short *__dst, unsigned short __x, size_t __n) {
+ __asm__("rep stosh" : : "D"(__dst), "a"(__x), "c"(__n)
+ : "%edi", "%ecx");
+}
+#endif
+#ifdef __x86_64__
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+__movsq(unsigned long long *__dst, unsigned long long const *__src, size_t __n) {
+ __asm__("rep movsq" : : "D"(__dst), "S"(__src), "c"(__n)
+ : "%edi", "%esi", "%ecx");
+}
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+__stosq(unsigned __int64 *__dst, unsigned __int64 __x, size_t __n) {
+ __asm__("rep stosq" : : "D"(__dst), "a"(__x), "c"(__n)
+ : "%edi", "%ecx");
+}
+#endif
+
/*----------------------------------------------------------------------------*\
|* Misc
\*----------------------------------------------------------------------------*/
@@ -775,6 +952,59 @@ static __inline__ void * __attribute__((__always_inline__, __nodebug__))
_ReturnAddress(void) {
return __builtin_return_address(0);
}
+#if defined(__i386__) || defined(__x86_64__)
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+__cpuid(int __info[4], int __level) {
+ __asm__ ("cpuid" : "=a"(__info[0]), "=b" (__info[1]), "=c"(__info[2]), "=d"(__info[3])
+ : "a"(__level));
+}
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+__cpuidex(int __info[4], int __level, int __ecx) {
+ __asm__ ("cpuid" : "=a"(__info[0]), "=b" (__info[1]), "=c"(__info[2]), "=d"(__info[3])
+ : "a"(__level), "c"(__ecx));
+}
+static __inline__ unsigned __int64 __cdecl __attribute__((__always_inline__, __nodebug__))
+_xgetbv(unsigned int __xcr_no) {
+ unsigned int __eax, __edx;
+ __asm__ ("xgetbv" : "=a" (__eax), "=d" (__edx) : "c" (__xcr_no));
+ return ((unsigned __int64)__edx << 32) | __eax;
+}
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+__halt(void) {
+ __asm__ volatile ("hlt");
+}
+#endif
+
+/*----------------------------------------------------------------------------*\
+|* Privileged intrinsics
+\*----------------------------------------------------------------------------*/
+#if defined(__i386__) || defined(__x86_64__)
+static __inline__ unsigned __int64 __attribute__((__always_inline__, __nodebug__))
+__readmsr(unsigned long __register) {
+ // Loads the contents of a 64-bit model specific register (MSR) specified in
+ // the ECX register into registers EDX:EAX. The EDX register is loaded with
+ // the high-order 32 bits of the MSR and the EAX register is loaded with the
+ // low-order 32 bits. If less than 64 bits are implemented in the MSR being
+ // read, the values returned to EDX:EAX in unimplemented bit locations are
+ // undefined.
+ unsigned long __edx;
+ unsigned long __eax;
+ __asm__ ("rdmsr" : "=d"(__edx), "=a"(__eax) : "c"(__register));
+ return (((unsigned __int64)__edx) << 32) | (unsigned __int64)__eax;
+}
+
+static __inline__ unsigned long __attribute__((always_inline, __nodebug__))
+__readcr3(void) {
+ unsigned long __cr3_val;
+ __asm__ __volatile__ ("mov %%cr3, %0" : "=q"(__cr3_val) : : "memory");
+ return __cr3_val;
+}
+
+static __inline__ void __attribute__((always_inline, __nodebug__))
+__writecr3(unsigned int __cr3_val) {
+ __asm__ ("mov %0, %%cr3" : : "q"(__cr3_val) : "memory");
+}
+#endif
#ifdef __cplusplus
}
diff --git a/lib/Headers/Makefile b/lib/Headers/Makefile
index 42219c4082be..903acacc8ac6 100644
--- a/lib/Headers/Makefile
+++ b/lib/Headers/Makefile
@@ -32,13 +32,13 @@ $(HeaderDir)/arm_neon.h: $(BUILT_SOURCES) $(HeaderDir)/.dir
$(Verb) cp $< $@
$(Echo) Copying $(notdir $<) to build dir
-$(HeaderDir)/module.map: $(PROJ_SRC_DIR)/module.map $(HeaderDir)/.dir
+$(HeaderDir)/module.modulemap: $(PROJ_SRC_DIR)/module.modulemap $(HeaderDir)/.dir
$(Verb) cp $< $@
$(Echo) Copying $(notdir $<) to build dir
# Hook into the standard Makefile rules.
-all-local:: $(OBJHEADERS) $(HeaderDir)/module.map
+all-local:: $(OBJHEADERS) $(HeaderDir)/module.modulemap
PROJ_headers := $(DESTDIR)$(PROJ_prefix)/lib/clang/$(CLANG_VERSION)/include
@@ -52,12 +52,12 @@ $(INSTHEADERS): $(PROJ_headers)/%.h: $(HeaderDir)/%.h | $(PROJ_headers)
$(Verb) $(DataInstall) $< $(PROJ_headers)
$(Echo) Installing compiler include file: $(notdir $<)
-$(PROJ_headers)/module.map: $(HeaderDir)/module.map | $(PROJ_headers)
+$(PROJ_headers)/module.modulemap: $(HeaderDir)/module.modulemap | $(PROJ_headers)
$(Verb) $(DataInstall) $< $(PROJ_headers)
$(Echo) Installing compiler module map file: $(notdir $<)
-install-local:: $(INSTHEADERS) $(PROJ_headers)/module.map
+install-local:: $(INSTHEADERS) $(PROJ_headers)/module.modulemap
$(ObjDir)/arm_neon.h.inc.tmp : $(CLANG_LEVEL)/include/clang/Basic/arm_neon.td $(CLANG_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang arm_neon.h.inc with tblgen"
diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h
index 74ce08aa6fea..f9fc64af3e74 100644
--- a/lib/Headers/altivec.h
+++ b/lib/Headers/altivec.h
@@ -73,6 +73,9 @@ vec_perm(vector bool int __a, vector bool int __b, vector unsigned char __c);
static vector float __ATTRS_o_ai
vec_perm(vector float __a, vector float __b, vector unsigned char __c);
+static vector unsigned char __ATTRS_o_ai
+vec_xor(vector unsigned char __a, vector unsigned char __b);
+
/* vec_abs */
#define __builtin_altivec_abs_v16qi vec_abs
@@ -3485,30 +3488,49 @@ vec_mtvscr(vector float __a)
__builtin_altivec_mtvscr((vector int)__a);
}
+/* The vmulos* and vmules* instructions have a big endian bias, so
+ we must reverse the meaning of "even" and "odd" for little endian. */
+
/* vec_mule */
static vector short __ATTRS_o_ai
vec_mule(vector signed char __a, vector signed char __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmulosb(__a, __b);
+#else
return __builtin_altivec_vmulesb(__a, __b);
+#endif
}
static vector unsigned short __ATTRS_o_ai
vec_mule(vector unsigned char __a, vector unsigned char __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmuloub(__a, __b);
+#else
return __builtin_altivec_vmuleub(__a, __b);
+#endif
}
static vector int __ATTRS_o_ai
vec_mule(vector short __a, vector short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmulosh(__a, __b);
+#else
return __builtin_altivec_vmulesh(__a, __b);
+#endif
}
static vector unsigned int __ATTRS_o_ai
vec_mule(vector unsigned short __a, vector unsigned short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmulouh(__a, __b);
+#else
return __builtin_altivec_vmuleuh(__a, __b);
+#endif
}
/* vec_vmulesb */
@@ -3516,7 +3538,11 @@ vec_mule(vector unsigned short __a, vector unsigned short __b)
static vector short __attribute__((__always_inline__))
vec_vmulesb(vector signed char __a, vector signed char __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmulosb(__a, __b);
+#else
return __builtin_altivec_vmulesb(__a, __b);
+#endif
}
/* vec_vmuleub */
@@ -3524,7 +3550,11 @@ vec_vmulesb(vector signed char __a, vector signed char __b)
static vector unsigned short __attribute__((__always_inline__))
vec_vmuleub(vector unsigned char __a, vector unsigned char __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmuloub(__a, __b);
+#else
return __builtin_altivec_vmuleub(__a, __b);
+#endif
}
/* vec_vmulesh */
@@ -3532,7 +3562,11 @@ vec_vmuleub(vector unsigned char __a, vector unsigned char __b)
static vector int __attribute__((__always_inline__))
vec_vmulesh(vector short __a, vector short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmulosh(__a, __b);
+#else
return __builtin_altivec_vmulesh(__a, __b);
+#endif
}
/* vec_vmuleuh */
@@ -3540,7 +3574,11 @@ vec_vmulesh(vector short __a, vector short __b)
static vector unsigned int __attribute__((__always_inline__))
vec_vmuleuh(vector unsigned short __a, vector unsigned short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmulouh(__a, __b);
+#else
return __builtin_altivec_vmuleuh(__a, __b);
+#endif
}
/* vec_mulo */
@@ -3548,25 +3586,41 @@ vec_vmuleuh(vector unsigned short __a, vector unsigned short __b)
static vector short __ATTRS_o_ai
vec_mulo(vector signed char __a, vector signed char __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmulesb(__a, __b);
+#else
return __builtin_altivec_vmulosb(__a, __b);
+#endif
}
static vector unsigned short __ATTRS_o_ai
vec_mulo(vector unsigned char __a, vector unsigned char __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmuleub(__a, __b);
+#else
return __builtin_altivec_vmuloub(__a, __b);
+#endif
}
static vector int __ATTRS_o_ai
vec_mulo(vector short __a, vector short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmulesh(__a, __b);
+#else
return __builtin_altivec_vmulosh(__a, __b);
+#endif
}
static vector unsigned int __ATTRS_o_ai
vec_mulo(vector unsigned short __a, vector unsigned short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmuleuh(__a, __b);
+#else
return __builtin_altivec_vmulouh(__a, __b);
+#endif
}
/* vec_vmulosb */
@@ -3574,7 +3628,11 @@ vec_mulo(vector unsigned short __a, vector unsigned short __b)
static vector short __attribute__((__always_inline__))
vec_vmulosb(vector signed char __a, vector signed char __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmulesb(__a, __b);
+#else
return __builtin_altivec_vmulosb(__a, __b);
+#endif
}
/* vec_vmuloub */
@@ -3582,7 +3640,11 @@ vec_vmulosb(vector signed char __a, vector signed char __b)
static vector unsigned short __attribute__((__always_inline__))
vec_vmuloub(vector unsigned char __a, vector unsigned char __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmuleub(__a, __b);
+#else
return __builtin_altivec_vmuloub(__a, __b);
+#endif
}
/* vec_vmulosh */
@@ -3590,7 +3652,11 @@ vec_vmuloub(vector unsigned char __a, vector unsigned char __b)
static vector int __attribute__((__always_inline__))
vec_vmulosh(vector short __a, vector short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmulesh(__a, __b);
+#else
return __builtin_altivec_vmulosh(__a, __b);
+#endif
}
/* vec_vmulouh */
@@ -3598,7 +3664,11 @@ vec_vmulosh(vector short __a, vector short __b)
static vector unsigned int __attribute__((__always_inline__))
vec_vmulouh(vector unsigned short __a, vector unsigned short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vmuleuh(__a, __b);
+#else
return __builtin_altivec_vmulouh(__a, __b);
+#endif
}
/* vec_nmsub */
@@ -4047,52 +4117,91 @@ vec_vor(vector float __a, vector bool int __b)
/* vec_pack */
+/* The various vector pack instructions have a big-endian bias, so for
+ little endian we must handle reversed element numbering. */
+
static vector signed char __ATTRS_o_ai
vec_pack(vector signed short __a, vector signed short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector signed char)vec_perm(__a, __b, (vector unsigned char)
+ (0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,
+ 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E));
+#else
return (vector signed char)vec_perm(__a, __b, (vector unsigned char)
(0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F));
+#endif
}
static vector unsigned char __ATTRS_o_ai
vec_pack(vector unsigned short __a, vector unsigned short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector unsigned char)vec_perm(__a, __b, (vector unsigned char)
+ (0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,
+ 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E));
+#else
return (vector unsigned char)vec_perm(__a, __b, (vector unsigned char)
(0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F));
+#endif
}
static vector bool char __ATTRS_o_ai
vec_pack(vector bool short __a, vector bool short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector bool char)vec_perm(__a, __b, (vector unsigned char)
+ (0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,
+ 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E));
+#else
return (vector bool char)vec_perm(__a, __b, (vector unsigned char)
(0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F));
+#endif
}
static vector short __ATTRS_o_ai
vec_pack(vector int __a, vector int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector short)vec_perm(__a, __b, (vector unsigned char)
+ (0x00, 0x01, 0x04, 0x05, 0x08, 0x09, 0x0C, 0x0D,
+ 0x10, 0x11, 0x14, 0x15, 0x18, 0x19, 0x1C, 0x1D));
+#else
return (vector short)vec_perm(__a, __b, (vector unsigned char)
(0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F,
0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F));
+#endif
}
static vector unsigned short __ATTRS_o_ai
vec_pack(vector unsigned int __a, vector unsigned int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector unsigned short)vec_perm(__a, __b, (vector unsigned char)
+ (0x00, 0x01, 0x04, 0x05, 0x08, 0x09, 0x0C, 0x0D,
+ 0x10, 0x11, 0x14, 0x15, 0x18, 0x19, 0x1C, 0x1D));
+#else
return (vector unsigned short)vec_perm(__a, __b, (vector unsigned char)
(0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F,
0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F));
+#endif
}
static vector bool short __ATTRS_o_ai
vec_pack(vector bool int __a, vector bool int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector bool short)vec_perm(__a, __b, (vector unsigned char)
+ (0x00, 0x01, 0x04, 0x05, 0x08, 0x09, 0x0C, 0x0D,
+ 0x10, 0x11, 0x14, 0x15, 0x18, 0x19, 0x1C, 0x1D));
+#else
return (vector bool short)vec_perm(__a, __b, (vector unsigned char)
(0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F,
0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F));
+#endif
}
/* vec_vpkuhum */
@@ -4102,25 +4211,43 @@ vec_pack(vector bool int __a, vector bool int __b)
static vector signed char __ATTRS_o_ai
vec_vpkuhum(vector signed short __a, vector signed short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector signed char)vec_perm(__a, __b, (vector unsigned char)
+ (0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,
+ 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E));
+#else
return (vector signed char)vec_perm(__a, __b, (vector unsigned char)
(0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F));
+#endif
}
static vector unsigned char __ATTRS_o_ai
vec_vpkuhum(vector unsigned short __a, vector unsigned short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector unsigned char)vec_perm(__a, __b, (vector unsigned char)
+ (0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,
+ 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E));
+#else
return (vector unsigned char)vec_perm(__a, __b, (vector unsigned char)
(0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F));
+#endif
}
static vector bool char __ATTRS_o_ai
vec_vpkuhum(vector bool short __a, vector bool short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector bool char)vec_perm(__a, __b, (vector unsigned char)
+ (0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,
+ 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E));
+#else
return (vector bool char)vec_perm(__a, __b, (vector unsigned char)
(0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F));
+#endif
}
/* vec_vpkuwum */
@@ -4130,25 +4257,43 @@ vec_vpkuhum(vector bool short __a, vector bool short __b)
static vector short __ATTRS_o_ai
vec_vpkuwum(vector int __a, vector int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector short)vec_perm(__a, __b, (vector unsigned char)
+ (0x00, 0x01, 0x04, 0x05, 0x08, 0x09, 0x0C, 0x0D,
+ 0x10, 0x11, 0x14, 0x15, 0x18, 0x19, 0x1C, 0x1D));
+#else
return (vector short)vec_perm(__a, __b, (vector unsigned char)
(0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F,
0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F));
+#endif
}
static vector unsigned short __ATTRS_o_ai
vec_vpkuwum(vector unsigned int __a, vector unsigned int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector unsigned short)vec_perm(__a, __b, (vector unsigned char)
+ (0x00, 0x01, 0x04, 0x05, 0x08, 0x09, 0x0C, 0x0D,
+ 0x10, 0x11, 0x14, 0x15, 0x18, 0x19, 0x1C, 0x1D));
+#else
return (vector unsigned short)vec_perm(__a, __b, (vector unsigned char)
(0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F,
0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F));
+#endif
}
static vector bool short __ATTRS_o_ai
vec_vpkuwum(vector bool int __a, vector bool int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector bool short)vec_perm(__a, __b, (vector unsigned char)
+ (0x00, 0x01, 0x04, 0x05, 0x08, 0x09, 0x0C, 0x0D,
+ 0x10, 0x11, 0x14, 0x15, 0x18, 0x19, 0x1C, 0x1D));
+#else
return (vector bool short)vec_perm(__a, __b, (vector unsigned char)
(0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F,
0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F));
+#endif
}
/* vec_packpx */
@@ -4156,7 +4301,11 @@ vec_vpkuwum(vector bool int __a, vector bool int __b)
static vector pixel __attribute__((__always_inline__))
vec_packpx(vector unsigned int __a, vector unsigned int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector pixel)__builtin_altivec_vpkpx(__b, __a);
+#else
return (vector pixel)__builtin_altivec_vpkpx(__a, __b);
+#endif
}
/* vec_vpkpx */
@@ -4164,7 +4313,11 @@ vec_packpx(vector unsigned int __a, vector unsigned int __b)
static vector pixel __attribute__((__always_inline__))
vec_vpkpx(vector unsigned int __a, vector unsigned int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector pixel)__builtin_altivec_vpkpx(__b, __a);
+#else
return (vector pixel)__builtin_altivec_vpkpx(__a, __b);
+#endif
}
/* vec_packs */
@@ -4172,25 +4325,41 @@ vec_vpkpx(vector unsigned int __a, vector unsigned int __b)
static vector signed char __ATTRS_o_ai
vec_packs(vector short __a, vector short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vpkshss(__b, __a);
+#else
return __builtin_altivec_vpkshss(__a, __b);
+#endif
}
static vector unsigned char __ATTRS_o_ai
vec_packs(vector unsigned short __a, vector unsigned short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vpkuhus(__b, __a);
+#else
return __builtin_altivec_vpkuhus(__a, __b);
+#endif
}
static vector signed short __ATTRS_o_ai
vec_packs(vector int __a, vector int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vpkswss(__b, __a);
+#else
return __builtin_altivec_vpkswss(__a, __b);
+#endif
}
static vector unsigned short __ATTRS_o_ai
vec_packs(vector unsigned int __a, vector unsigned int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vpkuwus(__b, __a);
+#else
return __builtin_altivec_vpkuwus(__a, __b);
+#endif
}
/* vec_vpkshss */
@@ -4198,7 +4367,11 @@ vec_packs(vector unsigned int __a, vector unsigned int __b)
static vector signed char __attribute__((__always_inline__))
vec_vpkshss(vector short __a, vector short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vpkshss(__b, __a);
+#else
return __builtin_altivec_vpkshss(__a, __b);
+#endif
}
/* vec_vpkuhus */
@@ -4206,7 +4379,11 @@ vec_vpkshss(vector short __a, vector short __b)
static vector unsigned char __attribute__((__always_inline__))
vec_vpkuhus(vector unsigned short __a, vector unsigned short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vpkuhus(__b, __a);
+#else
return __builtin_altivec_vpkuhus(__a, __b);
+#endif
}
/* vec_vpkswss */
@@ -4214,7 +4391,11 @@ vec_vpkuhus(vector unsigned short __a, vector unsigned short __b)
static vector signed short __attribute__((__always_inline__))
vec_vpkswss(vector int __a, vector int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vpkswss(__b, __a);
+#else
return __builtin_altivec_vpkswss(__a, __b);
+#endif
}
/* vec_vpkuwus */
@@ -4222,7 +4403,11 @@ vec_vpkswss(vector int __a, vector int __b)
static vector unsigned short __attribute__((__always_inline__))
vec_vpkuwus(vector unsigned int __a, vector unsigned int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vpkuwus(__b, __a);
+#else
return __builtin_altivec_vpkuwus(__a, __b);
+#endif
}
/* vec_packsu */
@@ -4230,25 +4415,41 @@ vec_vpkuwus(vector unsigned int __a, vector unsigned int __b)
static vector unsigned char __ATTRS_o_ai
vec_packsu(vector short __a, vector short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vpkshus(__b, __a);
+#else
return __builtin_altivec_vpkshus(__a, __b);
+#endif
}
static vector unsigned char __ATTRS_o_ai
vec_packsu(vector unsigned short __a, vector unsigned short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vpkuhus(__b, __a);
+#else
return __builtin_altivec_vpkuhus(__a, __b);
+#endif
}
static vector unsigned short __ATTRS_o_ai
vec_packsu(vector int __a, vector int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vpkswus(__b, __a);
+#else
return __builtin_altivec_vpkswus(__a, __b);
+#endif
}
static vector unsigned short __ATTRS_o_ai
vec_packsu(vector unsigned int __a, vector unsigned int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vpkuwus(__b, __a);
+#else
return __builtin_altivec_vpkuwus(__a, __b);
+#endif
}
/* vec_vpkshus */
@@ -4256,13 +4457,21 @@ vec_packsu(vector unsigned int __a, vector unsigned int __b)
static vector unsigned char __ATTRS_o_ai
vec_vpkshus(vector short __a, vector short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vpkshus(__b, __a);
+#else
return __builtin_altivec_vpkshus(__a, __b);
+#endif
}
static vector unsigned char __ATTRS_o_ai
vec_vpkshus(vector unsigned short __a, vector unsigned short __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vpkuhus(__b, __a);
+#else
return __builtin_altivec_vpkuhus(__a, __b);
+#endif
}
/* vec_vpkswus */
@@ -4270,22 +4479,46 @@ vec_vpkshus(vector unsigned short __a, vector unsigned short __b)
static vector unsigned short __ATTRS_o_ai
vec_vpkswus(vector int __a, vector int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vpkswus(__b, __a);
+#else
return __builtin_altivec_vpkswus(__a, __b);
+#endif
}
static vector unsigned short __ATTRS_o_ai
vec_vpkswus(vector unsigned int __a, vector unsigned int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vpkuwus(__b, __a);
+#else
return __builtin_altivec_vpkuwus(__a, __b);
+#endif
}
/* vec_perm */
+// The vperm instruction is defined architecturally with a big-endian bias.
+// For little endian, we swap the input operands and invert the permute
+// control vector. Only the rightmost 5 bits matter, so we could use
+// a vector of all 31s instead of all 255s to perform the inversion.
+// However, when the PCV is not a constant, using 255 has an advantage
+// in that the vec_xor can be recognized as a vec_nor (and for P8 and
+// later, possibly a vec_nand).
+
vector signed char __ATTRS_o_ai
vec_perm(vector signed char __a, vector signed char __b, vector unsigned char __c)
{
+#ifdef __LITTLE_ENDIAN__
+ vector unsigned char __d = {255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+ __d = vec_xor(__c, __d);
+ return (vector signed char)
+ __builtin_altivec_vperm_4si((vector int)__b, (vector int)__a, __d);
+#else
return (vector signed char)
__builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+#endif
}
vector unsigned char __ATTRS_o_ai
@@ -4293,22 +4526,46 @@ vec_perm(vector unsigned char __a,
vector unsigned char __b,
vector unsigned char __c)
{
+#ifdef __LITTLE_ENDIAN__
+ vector unsigned char __d = {255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+ __d = vec_xor(__c, __d);
+ return (vector unsigned char)
+ __builtin_altivec_vperm_4si((vector int)__b, (vector int)__a, __d);
+#else
return (vector unsigned char)
__builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+#endif
}
vector bool char __ATTRS_o_ai
vec_perm(vector bool char __a, vector bool char __b, vector unsigned char __c)
{
+#ifdef __LITTLE_ENDIAN__
+ vector unsigned char __d = {255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+ __d = vec_xor(__c, __d);
+ return (vector bool char)
+ __builtin_altivec_vperm_4si((vector int)__b, (vector int)__a, __d);
+#else
return (vector bool char)
__builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+#endif
}
vector short __ATTRS_o_ai
vec_perm(vector short __a, vector short __b, vector unsigned char __c)
{
+#ifdef __LITTLE_ENDIAN__
+ vector unsigned char __d = {255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+ __d = vec_xor(__c, __d);
+ return (vector short)
+ __builtin_altivec_vperm_4si((vector int)__b, (vector int)__a, __d);
+#else
return (vector short)
__builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+#endif
}
vector unsigned short __ATTRS_o_ai
@@ -4316,49 +4573,104 @@ vec_perm(vector unsigned short __a,
vector unsigned short __b,
vector unsigned char __c)
{
+#ifdef __LITTLE_ENDIAN__
+ vector unsigned char __d = {255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+ __d = vec_xor(__c, __d);
+ return (vector unsigned short)
+ __builtin_altivec_vperm_4si((vector int)__b, (vector int)__a, __d);
+#else
return (vector unsigned short)
__builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+#endif
}
vector bool short __ATTRS_o_ai
vec_perm(vector bool short __a, vector bool short __b, vector unsigned char __c)
{
+#ifdef __LITTLE_ENDIAN__
+ vector unsigned char __d = {255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+ __d = vec_xor(__c, __d);
+ return (vector bool short)
+ __builtin_altivec_vperm_4si((vector int)__b, (vector int)__a, __d);
+#else
return (vector bool short)
__builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+#endif
}
vector pixel __ATTRS_o_ai
vec_perm(vector pixel __a, vector pixel __b, vector unsigned char __c)
{
+#ifdef __LITTLE_ENDIAN__
+ vector unsigned char __d = {255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+ __d = vec_xor(__c, __d);
+ return (vector pixel)
+ __builtin_altivec_vperm_4si((vector int)__b, (vector int)__a, __d);
+#else
return (vector pixel)
__builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+#endif
}
vector int __ATTRS_o_ai
vec_perm(vector int __a, vector int __b, vector unsigned char __c)
{
+#ifdef __LITTLE_ENDIAN__
+ vector unsigned char __d = {255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+ __d = vec_xor(__c, __d);
+ return (vector int)__builtin_altivec_vperm_4si(__b, __a, __d);
+#else
return (vector int)__builtin_altivec_vperm_4si(__a, __b, __c);
+#endif
}
vector unsigned int __ATTRS_o_ai
vec_perm(vector unsigned int __a, vector unsigned int __b, vector unsigned char __c)
{
+#ifdef __LITTLE_ENDIAN__
+ vector unsigned char __d = {255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+ __d = vec_xor(__c, __d);
+ return (vector unsigned int)
+ __builtin_altivec_vperm_4si((vector int)__b, (vector int)__a, __d);
+#else
return (vector unsigned int)
__builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+#endif
}
vector bool int __ATTRS_o_ai
vec_perm(vector bool int __a, vector bool int __b, vector unsigned char __c)
{
+#ifdef __LITTLE_ENDIAN__
+ vector unsigned char __d = {255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+ __d = vec_xor(__c, __d);
+ return (vector bool int)
+ __builtin_altivec_vperm_4si((vector int)__b, (vector int)__a, __d);
+#else
return (vector bool int)
__builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+#endif
}
vector float __ATTRS_o_ai
vec_perm(vector float __a, vector float __b, vector unsigned char __c)
{
+#ifdef __LITTLE_ENDIAN__
+ vector unsigned char __d = {255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+ __d = vec_xor(__c, __d);
+ return (vector float)
+ __builtin_altivec_vperm_4si((vector int)__b, (vector int)__a, __d);
+#else
return (vector float)
__builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+#endif
}
/* vec_vperm */
@@ -4366,8 +4678,7 @@ vec_perm(vector float __a, vector float __b, vector unsigned char __c)
static vector signed char __ATTRS_o_ai
vec_vperm(vector signed char __a, vector signed char __b, vector unsigned char __c)
{
- return (vector signed char)
- __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+ return vec_perm(__a, __b, __c);
}
static vector unsigned char __ATTRS_o_ai
@@ -4375,22 +4686,19 @@ vec_vperm(vector unsigned char __a,
vector unsigned char __b,
vector unsigned char __c)
{
- return (vector unsigned char)
- __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+ return vec_perm(__a, __b, __c);
}
static vector bool char __ATTRS_o_ai
vec_vperm(vector bool char __a, vector bool char __b, vector unsigned char __c)
{
- return (vector bool char)
- __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+ return vec_perm(__a, __b, __c);
}
static vector short __ATTRS_o_ai
vec_vperm(vector short __a, vector short __b, vector unsigned char __c)
{
- return (vector short)
- __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+ return vec_perm(__a, __b, __c);
}
static vector unsigned short __ATTRS_o_ai
@@ -4398,49 +4706,43 @@ vec_vperm(vector unsigned short __a,
vector unsigned short __b,
vector unsigned char __c)
{
- return (vector unsigned short)
- __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+ return vec_perm(__a, __b, __c);
}
static vector bool short __ATTRS_o_ai
vec_vperm(vector bool short __a, vector bool short __b, vector unsigned char __c)
{
- return (vector bool short)
- __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+ return vec_perm(__a, __b, __c);
}
static vector pixel __ATTRS_o_ai
vec_vperm(vector pixel __a, vector pixel __b, vector unsigned char __c)
{
- return (vector pixel)
- __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+ return vec_perm(__a, __b, __c);
}
static vector int __ATTRS_o_ai
vec_vperm(vector int __a, vector int __b, vector unsigned char __c)
{
- return (vector int)__builtin_altivec_vperm_4si(__a, __b, __c);
+ return vec_perm(__a, __b, __c);
}
static vector unsigned int __ATTRS_o_ai
vec_vperm(vector unsigned int __a, vector unsigned int __b, vector unsigned char __c)
{
- return (vector unsigned int)
- __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+ return vec_perm(__a, __b, __c);
}
static vector bool int __ATTRS_o_ai
vec_vperm(vector bool int __a, vector bool int __b, vector unsigned char __c)
{
- return (vector bool int)
- __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+ return vec_perm(__a, __b, __c);
}
static vector float __ATTRS_o_ai
vec_vperm(vector float __a, vector float __b, vector unsigned char __c)
{
- return (vector float)
- __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
+ return vec_perm(__a, __b, __c);
}
/* vec_re */
@@ -8054,10 +8356,26 @@ vec_vsum4shs(vector signed short __a, vector int __b)
/* vec_sum2s */
+/* The vsum2sws instruction has a big-endian bias, so that the second
+ input vector and the result always reference big-endian elements
+ 1 and 3 (little-endian element 0 and 2). For ease of porting the
+ programmer wants elements 1 and 3 in both cases, so for little
+ endian we must perform some permutes. */
+
static vector signed int __attribute__((__always_inline__))
vec_sum2s(vector int __a, vector int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ vector int __c = (vector signed int)
+ vec_perm(__b, __b, (vector unsigned char)
+ (4,5,6,7,0,1,2,3,12,13,14,15,8,9,10,11));
+ __c = __builtin_altivec_vsum2sws(__a, __c);
+ return (vector signed int)
+ vec_perm(__c, __c, (vector unsigned char)
+ (4,5,6,7,0,1,2,3,12,13,14,15,8,9,10,11));
+#else
return __builtin_altivec_vsum2sws(__a, __b);
+#endif
}
/* vec_vsum2sws */
@@ -8065,15 +8383,37 @@ vec_sum2s(vector int __a, vector int __b)
static vector signed int __attribute__((__always_inline__))
vec_vsum2sws(vector int __a, vector int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ vector int __c = (vector signed int)
+ vec_perm(__b, __b, (vector unsigned char)
+ (4,5,6,7,0,1,2,3,12,13,14,15,8,9,10,11));
+ __c = __builtin_altivec_vsum2sws(__a, __c);
+ return (vector signed int)
+ vec_perm(__c, __c, (vector unsigned char)
+ (4,5,6,7,0,1,2,3,12,13,14,15,8,9,10,11));
+#else
return __builtin_altivec_vsum2sws(__a, __b);
+#endif
}
/* vec_sums */
+/* The vsumsws instruction has a big-endian bias, so that the second
+ input vector and the result always reference big-endian element 3
+ (little-endian element 0). For ease of porting the programmer
+ wants element 3 in both cases, so for little endian we must perform
+ some permutes. */
+
static vector signed int __attribute__((__always_inline__))
vec_sums(vector signed int __a, vector signed int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ __b = (vector signed int)vec_splat(__b, 3);
+ __b = __builtin_altivec_vsumsws(__a, __b);
+ return (vector signed int)(0, 0, 0, __b[0]);
+#else
return __builtin_altivec_vsumsws(__a, __b);
+#endif
}
/* vec_vsumsws */
@@ -8081,7 +8421,13 @@ vec_sums(vector signed int __a, vector signed int __b)
static vector signed int __attribute__((__always_inline__))
vec_vsumsws(vector signed int __a, vector signed int __b)
{
+#ifdef __LITTLE_ENDIAN__
+ __b = (vector signed int)vec_splat(__b, 3);
+ __b = __builtin_altivec_vsumsws(__a, __b);
+ return (vector signed int)(0, 0, 0, __b[0]);
+#else
return __builtin_altivec_vsumsws(__a, __b);
+#endif
}
/* vec_trunc */
@@ -8102,34 +8448,57 @@ vec_vrfiz(vector float __a)
/* vec_unpackh */
+/* The vector unpack instructions all have a big-endian bias, so for
+ little endian we must reverse the meanings of "high" and "low." */
+
static vector short __ATTRS_o_ai
vec_unpackh(vector signed char __a)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vupklsb((vector char)__a);
+#else
return __builtin_altivec_vupkhsb((vector char)__a);
+#endif
}
static vector bool short __ATTRS_o_ai
vec_unpackh(vector bool char __a)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector bool short)__builtin_altivec_vupklsb((vector char)__a);
+#else
return (vector bool short)__builtin_altivec_vupkhsb((vector char)__a);
+#endif
}
static vector int __ATTRS_o_ai
vec_unpackh(vector short __a)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vupklsh(__a);
+#else
return __builtin_altivec_vupkhsh(__a);
+#endif
}
static vector bool int __ATTRS_o_ai
vec_unpackh(vector bool short __a)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector bool int)__builtin_altivec_vupklsh((vector short)__a);
+#else
return (vector bool int)__builtin_altivec_vupkhsh((vector short)__a);
+#endif
}
static vector unsigned int __ATTRS_o_ai
vec_unpackh(vector pixel __a)
{
- return (vector unsigned int)__builtin_altivec_vupkhsh((vector short)__a);
+#ifdef __LITTLE_ENDIAN__
+ return (vector unsigned int)__builtin_altivec_vupklpx((vector short)__a);
+#else
+ return (vector unsigned int)__builtin_altivec_vupkhpx((vector short)__a);
+#endif
}
/* vec_vupkhsb */
@@ -8137,13 +8506,21 @@ vec_unpackh(vector pixel __a)
static vector short __ATTRS_o_ai
vec_vupkhsb(vector signed char __a)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vupklsb((vector char)__a);
+#else
return __builtin_altivec_vupkhsb((vector char)__a);
+#endif
}
static vector bool short __ATTRS_o_ai
vec_vupkhsb(vector bool char __a)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector bool short)__builtin_altivec_vupklsb((vector char)__a);
+#else
return (vector bool short)__builtin_altivec_vupkhsb((vector char)__a);
+#endif
}
/* vec_vupkhsh */
@@ -8151,19 +8528,31 @@ vec_vupkhsb(vector bool char __a)
static vector int __ATTRS_o_ai
vec_vupkhsh(vector short __a)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vupklsh(__a);
+#else
return __builtin_altivec_vupkhsh(__a);
+#endif
}
static vector bool int __ATTRS_o_ai
vec_vupkhsh(vector bool short __a)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector bool int)__builtin_altivec_vupklsh((vector short)__a);
+#else
return (vector bool int)__builtin_altivec_vupkhsh((vector short)__a);
+#endif
}
static vector unsigned int __ATTRS_o_ai
vec_vupkhsh(vector pixel __a)
{
- return (vector unsigned int)__builtin_altivec_vupkhsh((vector short)__a);
+#ifdef __LITTLE_ENDIAN__
+ return (vector unsigned int)__builtin_altivec_vupklpx((vector short)__a);
+#else
+ return (vector unsigned int)__builtin_altivec_vupkhpx((vector short)__a);
+#endif
}
/* vec_unpackl */
@@ -8171,31 +8560,51 @@ vec_vupkhsh(vector pixel __a)
static vector short __ATTRS_o_ai
vec_unpackl(vector signed char __a)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vupkhsb((vector char)__a);
+#else
return __builtin_altivec_vupklsb((vector char)__a);
+#endif
}
static vector bool short __ATTRS_o_ai
vec_unpackl(vector bool char __a)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector bool short)__builtin_altivec_vupkhsb((vector char)__a);
+#else
return (vector bool short)__builtin_altivec_vupklsb((vector char)__a);
+#endif
}
static vector int __ATTRS_o_ai
vec_unpackl(vector short __a)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vupkhsh(__a);
+#else
return __builtin_altivec_vupklsh(__a);
+#endif
}
static vector bool int __ATTRS_o_ai
vec_unpackl(vector bool short __a)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector bool int)__builtin_altivec_vupkhsh((vector short)__a);
+#else
return (vector bool int)__builtin_altivec_vupklsh((vector short)__a);
+#endif
}
static vector unsigned int __ATTRS_o_ai
vec_unpackl(vector pixel __a)
{
- return (vector unsigned int)__builtin_altivec_vupklsh((vector short)__a);
+#ifdef __LITTLE_ENDIAN__
+ return (vector unsigned int)__builtin_altivec_vupkhpx((vector short)__a);
+#else
+ return (vector unsigned int)__builtin_altivec_vupklpx((vector short)__a);
+#endif
}
/* vec_vupklsb */
@@ -8203,13 +8612,21 @@ vec_unpackl(vector pixel __a)
static vector short __ATTRS_o_ai
vec_vupklsb(vector signed char __a)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vupkhsb((vector char)__a);
+#else
return __builtin_altivec_vupklsb((vector char)__a);
+#endif
}
static vector bool short __ATTRS_o_ai
vec_vupklsb(vector bool char __a)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector bool short)__builtin_altivec_vupkhsb((vector char)__a);
+#else
return (vector bool short)__builtin_altivec_vupklsb((vector char)__a);
+#endif
}
/* vec_vupklsh */
@@ -8217,19 +8634,31 @@ vec_vupklsb(vector bool char __a)
static vector int __ATTRS_o_ai
vec_vupklsh(vector short __a)
{
+#ifdef __LITTLE_ENDIAN__
+ return __builtin_altivec_vupkhsh(__a);
+#else
return __builtin_altivec_vupklsh(__a);
+#endif
}
static vector bool int __ATTRS_o_ai
vec_vupklsh(vector bool short __a)
{
+#ifdef __LITTLE_ENDIAN__
+ return (vector bool int)__builtin_altivec_vupkhsh((vector short)__a);
+#else
return (vector bool int)__builtin_altivec_vupklsh((vector short)__a);
+#endif
}
static vector unsigned int __ATTRS_o_ai
vec_vupklsh(vector pixel __a)
{
- return (vector unsigned int)__builtin_altivec_vupklsh((vector short)__a);
+#ifdef __LITTLE_ENDIAN__
+ return (vector unsigned int)__builtin_altivec_vupkhpx((vector short)__a);
+#else
+ return (vector unsigned int)__builtin_altivec_vupklpx((vector short)__a);
+#endif
}
/* vec_xor */
diff --git a/lib/Headers/arm_acle.h b/lib/Headers/arm_acle.h
new file mode 100644
index 000000000000..a0fd6894ab96
--- /dev/null
+++ b/lib/Headers/arm_acle.h
@@ -0,0 +1,191 @@
+/*===---- arm_acle.h - ARM Non-Neon intrinsics -----------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __ARM_ACLE_H
+#define __ARM_ACLE_H
+
+#ifndef __ARM_ACLE
+#error "ACLE intrinsics support not enabled."
+#endif
+
+#include <stdint.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* 8 SYNCHRONIZATION, BARRIER AND HINT INTRINSICS */
+/* 8.3 Memory barriers */
+#if !defined(_MSC_VER)
+#define __dmb(i) __builtin_arm_dmb(i)
+#define __dsb(i) __builtin_arm_dsb(i)
+#define __isb(i) __builtin_arm_isb(i)
+#endif
+
+/* 8.4 Hints */
+
+#if !defined(_MSC_VER)
+static __inline__ void __attribute__((always_inline, nodebug)) __wfi(void) {
+ __builtin_arm_wfi();
+}
+
+static __inline__ void __attribute__((always_inline, nodebug)) __wfe(void) {
+ __builtin_arm_wfe();
+}
+
+static __inline__ void __attribute__((always_inline, nodebug)) __sev(void) {
+ __builtin_arm_sev();
+}
+
+static __inline__ void __attribute__((always_inline, nodebug)) __sevl(void) {
+ __builtin_arm_sevl();
+}
+
+static __inline__ void __attribute__((always_inline, nodebug)) __yield(void) {
+ __builtin_arm_yield();
+}
+#endif
+
+/* 8.7 NOP */
+static __inline__ void __attribute__((always_inline, nodebug)) __nop(void) {
+ __builtin_arm_nop();
+}
+
+/* 9 DATA-PROCESSING INTRINSICS */
+/* 9.2 Miscellaneous data-processing intrinsics */
+static __inline__ uint32_t __attribute__((always_inline, nodebug))
+ __clz(uint32_t t) {
+ return __builtin_clz(t);
+}
+
+static __inline__ unsigned long __attribute__((always_inline, nodebug))
+ __clzl(unsigned long t) {
+ return __builtin_clzl(t);
+}
+
+static __inline__ uint64_t __attribute__((always_inline, nodebug))
+ __clzll(uint64_t t) {
+#if __SIZEOF_LONG_LONG__ == 8
+ return __builtin_clzll(t);
+#else
+ return __builtin_clzl(t);
+#endif
+}
+
+static __inline__ uint32_t __attribute__((always_inline, nodebug))
+ __rev(uint32_t t) {
+ return __builtin_bswap32(t);
+}
+
+static __inline__ unsigned long __attribute__((always_inline, nodebug))
+ __revl(unsigned long t) {
+#if __SIZEOF_LONG__ == 4
+ return __builtin_bswap32(t);
+#else
+ return __builtin_bswap64(t);
+#endif
+}
+
+static __inline__ uint64_t __attribute__((always_inline, nodebug))
+ __revll(uint64_t t) {
+ return __builtin_bswap64(t);
+}
+
+/*
+ * 9.4 Saturating intrinsics
+ *
+ * FIXME: Change guard to their corrosponding __ARM_FEATURE flag when Q flag
+ * intrinsics are implemented and the flag is enabled.
+ */
+/* 9.4.1 Width-specified saturation intrinsics */
+#if __ARM_32BIT_STATE
+#define __ssat(x, y) __builtin_arm_ssat(x, y)
+#define __usat(x, y) __builtin_arm_usat(x, y)
+#endif
+
+/* 9.4.2 Saturating addition and subtraction intrinsics */
+#if __ARM_32BIT_STATE
+static __inline__ int32_t __attribute__((always_inline, nodebug))
+ __qadd(int32_t t, int32_t v) {
+ return __builtin_arm_qadd(t, v);
+}
+
+static __inline__ int32_t __attribute__((always_inline, nodebug))
+ __qsub(int32_t t, int32_t v) {
+ return __builtin_arm_qsub(t, v);
+}
+
+static __inline__ int32_t __attribute__((always_inline, nodebug))
+__qdbl(int32_t t) {
+ return __builtin_arm_qadd(t, t);
+}
+#endif
+
+/* 9.7 CRC32 intrinsics */
+#if __ARM_FEATURE_CRC32
+static __inline__ uint32_t __attribute__((always_inline, nodebug))
+ __crc32b(uint32_t a, uint8_t b) {
+ return __builtin_arm_crc32b(a, b);
+}
+
+static __inline__ uint32_t __attribute__((always_inline, nodebug))
+ __crc32h(uint32_t a, uint16_t b) {
+ return __builtin_arm_crc32h(a, b);
+}
+
+static __inline__ uint32_t __attribute__((always_inline, nodebug))
+ __crc32w(uint32_t a, uint32_t b) {
+ return __builtin_arm_crc32w(a, b);
+}
+
+static __inline__ uint32_t __attribute__((always_inline, nodebug))
+ __crc32d(uint32_t a, uint64_t b) {
+ return __builtin_arm_crc32d(a, b);
+}
+
+static __inline__ uint32_t __attribute__((always_inline, nodebug))
+ __crc32cb(uint32_t a, uint8_t b) {
+ return __builtin_arm_crc32cb(a, b);
+}
+
+static __inline__ uint32_t __attribute__((always_inline, nodebug))
+ __crc32ch(uint32_t a, uint16_t b) {
+ return __builtin_arm_crc32ch(a, b);
+}
+
+static __inline__ uint32_t __attribute__((always_inline, nodebug))
+ __crc32cw(uint32_t a, uint32_t b) {
+ return __builtin_arm_crc32cw(a, b);
+}
+
+static __inline__ uint32_t __attribute__((always_inline, nodebug))
+ __crc32cd(uint32_t a, uint64_t b) {
+ return __builtin_arm_crc32cd(a, b);
+}
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ARM_ACLE_H */
diff --git a/lib/Headers/avx2intrin.h b/lib/Headers/avx2intrin.h
index 95744693ac77..394fdfee9652 100644
--- a/lib/Headers/avx2intrin.h
+++ b/lib/Headers/avx2intrin.h
@@ -160,7 +160,23 @@ _mm256_blendv_epi8(__m256i __V1, __m256i __V2, __m256i __M)
#define _mm256_blend_epi16(V1, V2, M) __extension__ ({ \
__m256i __V1 = (V1); \
__m256i __V2 = (V2); \
- (__m256i)__builtin_ia32_pblendw256((__v16hi)__V1, (__v16hi)__V2, (M)); })
+ (__m256d)__builtin_shufflevector((__v16hi)__V1, (__v16hi)__V2, \
+ (((M) & 0x01) ? 16 : 0), \
+ (((M) & 0x02) ? 17 : 1), \
+ (((M) & 0x04) ? 18 : 2), \
+ (((M) & 0x08) ? 19 : 3), \
+ (((M) & 0x10) ? 20 : 4), \
+ (((M) & 0x20) ? 21 : 5), \
+ (((M) & 0x40) ? 22 : 6), \
+ (((M) & 0x80) ? 23 : 7), \
+ (((M) & 0x01) ? 24 : 8), \
+ (((M) & 0x02) ? 25 : 9), \
+ (((M) & 0x04) ? 26 : 10), \
+ (((M) & 0x08) ? 27 : 11), \
+ (((M) & 0x10) ? 28 : 12), \
+ (((M) & 0x20) ? 29 : 13), \
+ (((M) & 0x40) ? 30 : 14), \
+ (((M) & 0x80) ? 31 : 15)); })
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
_mm256_cmpeq_epi8(__m256i __a, __m256i __b)
@@ -761,12 +777,24 @@ _mm256_broadcastsi128_si256(__m128i __X)
#define _mm_blend_epi32(V1, V2, M) __extension__ ({ \
__m128i __V1 = (V1); \
__m128i __V2 = (V2); \
- (__m128i)__builtin_ia32_pblendd128((__v4si)__V1, (__v4si)__V2, (M)); })
+ (__m128i)__builtin_shufflevector((__v4si)__V1, (__v4si)__V2, \
+ (((M) & 0x01) ? 4 : 0), \
+ (((M) & 0x02) ? 5 : 1), \
+ (((M) & 0x04) ? 6 : 2), \
+ (((M) & 0x08) ? 7 : 3)); })
#define _mm256_blend_epi32(V1, V2, M) __extension__ ({ \
__m256i __V1 = (V1); \
__m256i __V2 = (V2); \
- (__m256i)__builtin_ia32_pblendd256((__v8si)__V1, (__v8si)__V2, (M)); })
+ (__m256i)__builtin_shufflevector((__v8si)__V1, (__v8si)__V2, \
+ (((M) & 0x01) ? 8 : 0), \
+ (((M) & 0x02) ? 9 : 1), \
+ (((M) & 0x04) ? 10 : 2), \
+ (((M) & 0x08) ? 11 : 3), \
+ (((M) & 0x10) ? 12 : 4), \
+ (((M) & 0x20) ? 13 : 5), \
+ (((M) & 0x40) ? 14 : 6), \
+ (((M) & 0x80) ? 15 : 7)); })
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
_mm256_broadcastb_epi8(__m128i __X)
diff --git a/lib/Headers/avxintrin.h b/lib/Headers/avxintrin.h
index 141c4d994bbc..4e1044af5611 100644
--- a/lib/Headers/avxintrin.h
+++ b/lib/Headers/avxintrin.h
@@ -308,12 +308,24 @@ _mm256_permutevar_ps(__m256 __a, __m256i __c)
#define _mm256_blend_pd(V1, V2, M) __extension__ ({ \
__m256d __V1 = (V1); \
__m256d __V2 = (V2); \
- (__m256d)__builtin_ia32_blendpd256((__v4df)__V1, (__v4df)__V2, (M)); })
+ (__m256d)__builtin_shufflevector((__v4df)__V1, (__v4df)__V2, \
+ (((M) & 0x01) ? 4 : 0), \
+ (((M) & 0x02) ? 5 : 1), \
+ (((M) & 0x04) ? 6 : 2), \
+ (((M) & 0x08) ? 7 : 3)); })
#define _mm256_blend_ps(V1, V2, M) __extension__ ({ \
__m256 __V1 = (V1); \
__m256 __V2 = (V2); \
- (__m256)__builtin_ia32_blendps256((__v8sf)__V1, (__v8sf)__V2, (M)); })
+ (__m256)__builtin_shufflevector((__v8sf)__V1, (__v8sf)__V2, \
+ (((M) & 0x01) ? 8 : 0), \
+ (((M) & 0x02) ? 9 : 1), \
+ (((M) & 0x04) ? 10 : 2), \
+ (((M) & 0x08) ? 11 : 3), \
+ (((M) & 0x10) ? 12 : 4), \
+ (((M) & 0x20) ? 13 : 5), \
+ (((M) & 0x40) ? 14 : 6), \
+ (((M) & 0x80) ? 15 : 7)); })
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
_mm256_blendv_pd(__m256d __a, __m256d __b, __m256d __c)
@@ -725,19 +737,22 @@ _mm256_zeroupper(void)
static __inline __m128 __attribute__((__always_inline__, __nodebug__))
_mm_broadcast_ss(float const *__a)
{
- return (__m128)__builtin_ia32_vbroadcastss(__a);
+ float __f = *__a;
+ return (__m128)(__v4sf){ __f, __f, __f, __f };
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
_mm256_broadcast_sd(double const *__a)
{
- return (__m256d)__builtin_ia32_vbroadcastsd256(__a);
+ double __d = *__a;
+ return (__m256d)(__v4df){ __d, __d, __d, __d };
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
_mm256_broadcast_ss(float const *__a)
{
- return (__m256)__builtin_ia32_vbroadcastss256(__a);
+ float __f = *__a;
+ return (__m256)(__v8sf){ __f, __f, __f, __f, __f, __f, __f, __f };
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Headers/bmiintrin.h b/lib/Headers/bmiintrin.h
index 8cb00f51d3ef..43c4a5e5de3c 100644
--- a/lib/Headers/bmiintrin.h
+++ b/lib/Headers/bmiintrin.h
@@ -32,6 +32,14 @@
#ifndef __BMIINTRIN_H
#define __BMIINTRIN_H
+#define _tzcnt_u16(a) (__tzcnt_u16((a)))
+#define _andn_u32(a, b) (__andn_u32((a), (b)))
+/* _bextr_u32 != __bextr_u32 */
+#define _blsi_u32(a) (__blsi_u32((a)))
+#define _blsmsk_u32(a) (__blsmsk_u32((a)))
+#define _blsr_u32(a) (__blsr_u32((a)))
+#define _tzcnt_u32(a) (__tzcnt_u32((a)))
+
static __inline__ unsigned short __attribute__((__always_inline__, __nodebug__))
__tzcnt_u16(unsigned short __X)
{
@@ -44,12 +52,20 @@ __andn_u32(unsigned int __X, unsigned int __Y)
return ~__X & __Y;
}
+/* AMD-specified, double-leading-underscore version of BEXTR */
static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
__bextr_u32(unsigned int __X, unsigned int __Y)
{
return __builtin_ia32_bextr_u32(__X, __Y);
}
+/* Intel-specified, single-leading-underscore version of BEXTR */
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+_bextr_u32(unsigned int __X, unsigned int __Y, unsigned int __Z)
+{
+ return __builtin_ia32_bextr_u32 (__X, ((__Y & 0xff) | ((__Z & 0xff) << 8)));
+}
+
static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
__blsi_u32(unsigned int __X)
{
@@ -75,18 +91,34 @@ __tzcnt_u32(unsigned int __X)
}
#ifdef __x86_64__
+
+#define _andn_u64(a, b) (__andn_u64((a), (b)))
+/* _bextr_u64 != __bextr_u64 */
+#define _blsi_u64(a) (__blsi_u64((a)))
+#define _blsmsk_u64(a) (__blsmsk_u64((a)))
+#define _blsr_u64(a) (__blsr_u64((a)))
+#define _tzcnt_u64(a) (__tzcnt_u64((a)))
+
static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
__andn_u64 (unsigned long long __X, unsigned long long __Y)
{
return ~__X & __Y;
}
+/* AMD-specified, double-leading-underscore version of BEXTR */
static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
__bextr_u64(unsigned long long __X, unsigned long long __Y)
{
return __builtin_ia32_bextr_u64(__X, __Y);
}
+/* Intel-specified, single-leading-underscore version of BEXTR */
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+_bextr_u64(unsigned long long __X, unsigned int __Y, unsigned int __Z)
+{
+ return __builtin_ia32_bextr_u64 (__X, ((__Y & 0xff) | ((__Z & 0xff) << 8)));
+}
+
static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
__blsi_u64(unsigned long long __X)
{
@@ -110,6 +142,7 @@ __tzcnt_u64(unsigned long long __X)
{
return __builtin_ctzll(__X);
}
-#endif
+
+#endif /* __x86_64__ */
#endif /* __BMIINTRIN_H */
diff --git a/lib/Headers/cpuid.h b/lib/Headers/cpuid.h
index 8f12caeb4978..f9254e9738e7 100644
--- a/lib/Headers/cpuid.h
+++ b/lib/Headers/cpuid.h
@@ -79,6 +79,7 @@
#define bit_ACPI 0x00400000
#define bit_MMX 0x00800000
#define bit_FXSR 0x01000000
+#define bit_FXSAVE bit_FXSR /* for gcc compat */
#define bit_SSE 0x02000000
#define bit_SSE2 0x04000000
#define bit_SS 0x08000000
diff --git a/lib/Headers/float.h b/lib/Headers/float.h
index 2cb13d3ed551..02ef6bf611a3 100644
--- a/lib/Headers/float.h
+++ b/lib/Headers/float.h
@@ -29,7 +29,7 @@
* For more details see http://msdn.microsoft.com/en-us/library/y0ybw9fy.aspx
*/
#if (defined(__MINGW32__) || defined(_MSC_VER)) && \
- defined(__has_include_next) && __has_include_next(<float.h>)
+ __has_include_next(<float.h>)
# include_next <float.h>
/* Undefine anything that we'll be redefining below. */
diff --git a/lib/Headers/ia32intrin.h b/lib/Headers/ia32intrin.h
new file mode 100644
index 000000000000..5adf3f1f5d83
--- /dev/null
+++ b/lib/Headers/ia32intrin.h
@@ -0,0 +1,101 @@
+/* ===-------- ia32intrin.h ---------------------------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __X86INTRIN_H
+#error "Never use <ia32intrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifndef __IA32INTRIN_H
+#define __IA32INTRIN_H
+
+#ifdef __x86_64__
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+__readeflags(void)
+{
+ unsigned long long __res = 0;
+ __asm__ __volatile__ ("pushf\n\t"
+ "popq %0\n"
+ :"=r"(__res)
+ :
+ :
+ );
+ return __res;
+}
+
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+__writeeflags(unsigned long long __f)
+{
+ __asm__ __volatile__ ("pushq %0\n\t"
+ "popf\n"
+ :
+ :"r"(__f)
+ :"flags"
+ );
+}
+
+#else /* !__x86_64__ */
+static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
+__readeflags(void)
+{
+ unsigned int __res = 0;
+ __asm__ __volatile__ ("pushf\n\t"
+ "popl %0\n"
+ :"=r"(__res)
+ :
+ :
+ );
+ return __res;
+}
+
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+__writeeflags(unsigned int __f)
+{
+ __asm__ __volatile__ ("pushl %0\n\t"
+ "popf\n"
+ :
+ :"r"(__f)
+ :"flags"
+ );
+}
+#endif /* !__x86_64__ */
+
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+__rdpmc(int __A) {
+ return __builtin_ia32_rdpmc(__A);
+}
+
+/* __rdtsc */
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+__rdtsc(void) {
+ return __builtin_ia32_rdtsc();
+}
+
+/* __rdtscp */
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+__rdtscp(unsigned int *__A) {
+ return __builtin_ia32_rdtscp(__A);
+}
+
+#define _rdtsc() __rdtsc()
+
+#endif /* __IA32INTRIN_H */
diff --git a/lib/Headers/immintrin.h b/lib/Headers/immintrin.h
index 15d6e05f979a..df4bea8c950e 100644
--- a/lib/Headers/immintrin.h
+++ b/lib/Headers/immintrin.h
@@ -48,7 +48,7 @@
#include <smmintrin.h>
#endif
-#if defined (__AES__)
+#if defined (__AES__) || defined (__PCLMUL__)
#include <wmmintrin.h>
#endif
diff --git a/lib/Headers/limits.h b/lib/Headers/limits.h
index 91bd404650e8..f04187ced26d 100644
--- a/lib/Headers/limits.h
+++ b/lib/Headers/limits.h
@@ -33,8 +33,7 @@
/* System headers include a number of constants from POSIX in <limits.h>.
Include it if we're hosted. */
-#if __STDC_HOSTED__ && \
- defined(__has_include_next) && __has_include_next(<limits.h>)
+#if __STDC_HOSTED__ && __has_include_next(<limits.h>)
#include_next <limits.h>
#endif
@@ -90,7 +89,7 @@
/* C99 5.2.4.2.1: Added long long.
C++11 18.3.3.2: same contents as the Standard C Library header <limits.h>.
*/
-#if __STDC_VERSION__ >= 199901 || __cplusplus >= 201103L
+#if __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L
#undef LLONG_MIN
#undef LLONG_MAX
diff --git a/lib/Headers/module.map b/lib/Headers/module.modulemap
index 9f7944dedbb0..9f7944dedbb0 100644
--- a/lib/Headers/module.map
+++ b/lib/Headers/module.modulemap
diff --git a/lib/Headers/smmintrin.h b/lib/Headers/smmintrin.h
index 53b3ccb4310c..6e35734f6e0d 100644
--- a/lib/Headers/smmintrin.h
+++ b/lib/Headers/smmintrin.h
@@ -79,12 +79,18 @@
#define _mm_blend_pd(V1, V2, M) __extension__ ({ \
__m128d __V1 = (V1); \
__m128d __V2 = (V2); \
- (__m128d) __builtin_ia32_blendpd ((__v2df)__V1, (__v2df)__V2, (M)); })
+ (__m128d)__builtin_shufflevector((__v2df)__V1, (__v2df)__V2, \
+ (((M) & 0x01) ? 2 : 0), \
+ (((M) & 0x02) ? 3 : 1)); })
#define _mm_blend_ps(V1, V2, M) __extension__ ({ \
__m128 __V1 = (V1); \
__m128 __V2 = (V2); \
- (__m128) __builtin_ia32_blendps ((__v4sf)__V1, (__v4sf)__V2, (M)); })
+ (__m128)__builtin_shufflevector((__v4sf)__V1, (__v4sf)__V2, \
+ (((M) & 0x01) ? 4 : 0), \
+ (((M) & 0x02) ? 5 : 1), \
+ (((M) & 0x04) ? 6 : 2), \
+ (((M) & 0x08) ? 7 : 3)); })
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_blendv_pd (__m128d __V1, __m128d __V2, __m128d __M)
@@ -110,7 +116,15 @@ _mm_blendv_epi8 (__m128i __V1, __m128i __V2, __m128i __M)
#define _mm_blend_epi16(V1, V2, M) __extension__ ({ \
__m128i __V1 = (V1); \
__m128i __V2 = (V2); \
- (__m128i) __builtin_ia32_pblendw128 ((__v8hi)__V1, (__v8hi)__V2, (M)); })
+ (__m128i)__builtin_shufflevector((__v8hi)__V1, (__v8hi)__V2, \
+ (((M) & 0x01) ? 8 : 0), \
+ (((M) & 0x02) ? 9 : 1), \
+ (((M) & 0x04) ? 10 : 2), \
+ (((M) & 0x08) ? 11 : 3), \
+ (((M) & 0x10) ? 12 : 4), \
+ (((M) & 0x20) ? 13 : 5), \
+ (((M) & 0x40) ? 14 : 6), \
+ (((M) & 0x80) ? 15 : 7)); })
/* SSE4 Dword Multiply Instructions. */
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Headers/stdarg.h b/lib/Headers/stdarg.h
index 2957bf058ea8..a57e18364871 100644
--- a/lib/Headers/stdarg.h
+++ b/lib/Headers/stdarg.h
@@ -39,12 +39,14 @@ typedef __builtin_va_list va_list;
*/
#define __va_copy(d,s) __builtin_va_copy(d,s)
-#if __STDC_VERSION__ >= 199900L || __cplusplus >= 201103L || !defined(__STRICT_ANSI__)
+#if __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L || !defined(__STRICT_ANSI__)
#define va_copy(dest, src) __builtin_va_copy(dest, src)
#endif
/* Hack required to make standard headers work, at least on Ubuntu */
+#ifndef __GNUC_VA_LIST
#define __GNUC_VA_LIST 1
+#endif
typedef __builtin_va_list __gnuc_va_list;
#endif /* __STDARG_H */
diff --git a/lib/Headers/stddef.h b/lib/Headers/stddef.h
index 6a64d6d32a8a..2dfe0a29b2a2 100644
--- a/lib/Headers/stddef.h
+++ b/lib/Headers/stddef.h
@@ -23,9 +23,22 @@
*===-----------------------------------------------------------------------===
*/
-#ifndef __STDDEF_H
+#if !defined(__STDDEF_H) || defined(__need_ptrdiff_t) || \
+ defined(__need_size_t) || defined(__need_wchar_t) || \
+ defined(__need_NULL) || defined(__need_wint_t)
+
+#if !defined(__need_ptrdiff_t) && !defined(__need_size_t) && \
+ !defined(__need_wchar_t) && !defined(__need_NULL) && \
+ !defined(__need_wint_t)
#define __STDDEF_H
+#define __need_ptrdiff_t
+#define __need_size_t
+#define __need_wchar_t
+#define __need_NULL
+/* __need_wint_t is intentionally not defined here. */
+#endif
+#if defined(__need_ptrdiff_t)
#if !defined(_PTRDIFF_T) || __has_feature(modules)
/* Always define ptrdiff_t when modules are available. */
#if !__has_feature(modules)
@@ -33,7 +46,10 @@
#endif
typedef __PTRDIFF_TYPE__ ptrdiff_t;
#endif
+#undef __need_ptrdiff_t
+#endif /* defined(__need_ptrdiff_t) */
+#if defined(__need_size_t)
#if !defined(_SIZE_T) || __has_feature(modules)
/* Always define size_t when modules are available. */
#if !__has_feature(modules)
@@ -41,7 +57,10 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t;
#endif
typedef __SIZE_TYPE__ size_t;
#endif
+#undef __need_size_t
+#endif /*defined(__need_size_t) */
+#if defined(__STDDEF_H)
/* ISO9899:2011 7.20 (C11 Annex K): Define rsize_t if __STDC_WANT_LIB_EXT1__ is
* enabled. */
#if (defined(__STDC_WANT_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ >= 1 && \
@@ -52,7 +71,9 @@ typedef __SIZE_TYPE__ size_t;
#endif
typedef __SIZE_TYPE__ rsize_t;
#endif
+#endif /* defined(__STDDEF_H) */
+#if defined(__need_wchar_t)
#ifndef __cplusplus
/* Always define wchar_t when modules are available. */
#if !defined(_WCHAR_T) || __has_feature(modules)
@@ -65,7 +86,10 @@ typedef __SIZE_TYPE__ rsize_t;
typedef __WCHAR_TYPE__ wchar_t;
#endif
#endif
+#undef __need_wchar_t
+#endif /* defined(__need_wchar_t) */
+#if defined(__need_NULL)
#undef NULL
#ifdef __cplusplus
# if !defined(__MINGW32__) && !defined(_MSC_VER)
@@ -76,17 +100,35 @@ typedef __WCHAR_TYPE__ wchar_t;
#else
# define NULL ((void*)0)
#endif
-
#ifdef __cplusplus
#if defined(_MSC_EXTENSIONS) && defined(_NATIVE_NULLPTR_SUPPORTED)
namespace std { typedef decltype(nullptr) nullptr_t; }
using ::std::nullptr_t;
#endif
#endif
+#undef __need_NULL
+#endif /* defined(__need_NULL) */
-#define offsetof(t, d) __builtin_offsetof(t, d)
+#if defined(__STDDEF_H)
+
+#if __STDC_VERSION__ >= 201112L || __cplusplus >= 201103L
+#if !defined(__CLANG_MAX_ALIGN_T_DEFINED) || __has_feature(modules)
+#ifndef _MSC_VER
+typedef struct {
+ long long __clang_max_align_nonce1
+ __attribute__((__aligned__(__alignof__(long long))));
+ long double __clang_max_align_nonce2
+ __attribute__((__aligned__(__alignof__(long double))));
+} max_align_t;
+#else
+typedef double max_align_t;
+#endif
+#define __CLANG_MAX_ALIGN_T_DEFINED
+#endif
+#endif
-#endif /* __STDDEF_H */
+#define offsetof(t, d) __builtin_offsetof(t, d)
+#endif /* __STDDEF_H */
/* Some C libraries expect to see a wint_t here. Others (notably MinGW) will use
__WINT_TYPE__ directly; accommodate both by requiring __need_wint_t */
@@ -100,3 +142,5 @@ typedef __WINT_TYPE__ wint_t;
#endif
#undef __need_wint_t
#endif /* __need_wint_t */
+
+#endif
diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h
index 11529c0c674b..0303db90be1f 100644
--- a/lib/Headers/stdint.h
+++ b/lib/Headers/stdint.h
@@ -28,8 +28,7 @@
/* If we're hosted, fall back to the system's stdint.h, which might have
* additional definitions.
*/
-#if __STDC_HOSTED__ && \
- defined(__has_include_next) && __has_include_next(<stdint.h>)
+#if __STDC_HOSTED__ && __has_include_next(<stdint.h>)
// C99 7.18.3 Limits of other integer types
//
@@ -105,9 +104,9 @@
#ifdef __INT64_TYPE__
# ifndef __int8_t_defined /* glibc sys/types.h also defines int64_t*/
-typedef signed __INT64_TYPE__ int64_t;
+typedef __INT64_TYPE__ int64_t;
# endif /* __int8_t_defined */
-typedef unsigned __INT64_TYPE__ uint64_t;
+typedef __UINT64_TYPE__ uint64_t;
# define __int_least64_t int64_t
# define __uint_least64_t uint64_t
# define __int_least32_t int64_t
@@ -126,8 +125,8 @@ typedef __uint_least64_t uint_fast64_t;
#endif /* __int_least64_t */
#ifdef __INT56_TYPE__
-typedef signed __INT56_TYPE__ int56_t;
-typedef unsigned __INT56_TYPE__ uint56_t;
+typedef __INT56_TYPE__ int56_t;
+typedef __UINT56_TYPE__ uint56_t;
typedef int56_t int_least56_t;
typedef uint56_t uint_least56_t;
typedef int56_t int_fast56_t;
@@ -142,8 +141,8 @@ typedef uint56_t uint_fast56_t;
#ifdef __INT48_TYPE__
-typedef signed __INT48_TYPE__ int48_t;
-typedef unsigned __INT48_TYPE__ uint48_t;
+typedef __INT48_TYPE__ int48_t;
+typedef __UINT48_TYPE__ uint48_t;
typedef int48_t int_least48_t;
typedef uint48_t uint_least48_t;
typedef int48_t int_fast48_t;
@@ -158,8 +157,8 @@ typedef uint48_t uint_fast48_t;
#ifdef __INT40_TYPE__
-typedef signed __INT40_TYPE__ int40_t;
-typedef unsigned __INT40_TYPE__ uint40_t;
+typedef __INT40_TYPE__ int40_t;
+typedef __UINT40_TYPE__ uint40_t;
typedef int40_t int_least40_t;
typedef uint40_t uint_least40_t;
typedef int40_t int_fast40_t;
@@ -176,12 +175,12 @@ typedef uint40_t uint_fast40_t;
#ifdef __INT32_TYPE__
# ifndef __int8_t_defined /* glibc sys/types.h also defines int32_t*/
-typedef signed __INT32_TYPE__ int32_t;
+typedef __INT32_TYPE__ int32_t;
# endif /* __int8_t_defined */
# ifndef __uint32_t_defined /* more glibc compatibility */
# define __uint32_t_defined
-typedef unsigned __INT32_TYPE__ uint32_t;
+typedef __UINT32_TYPE__ uint32_t;
# endif /* __uint32_t_defined */
# define __int_least32_t int32_t
@@ -200,8 +199,8 @@ typedef __uint_least32_t uint_fast32_t;
#endif /* __int_least32_t */
#ifdef __INT24_TYPE__
-typedef signed __INT24_TYPE__ int24_t;
-typedef unsigned __INT24_TYPE__ uint24_t;
+typedef __INT24_TYPE__ int24_t;
+typedef __UINT24_TYPE__ uint24_t;
typedef int24_t int_least24_t;
typedef uint24_t uint_least24_t;
typedef int24_t int_fast24_t;
@@ -214,9 +213,9 @@ typedef uint24_t uint_fast24_t;
#ifdef __INT16_TYPE__
#ifndef __int8_t_defined /* glibc sys/types.h also defines int16_t*/
-typedef signed __INT16_TYPE__ int16_t;
+typedef __INT16_TYPE__ int16_t;
#endif /* __int8_t_defined */
-typedef unsigned __INT16_TYPE__ uint16_t;
+typedef __UINT16_TYPE__ uint16_t;
# define __int_least16_t int16_t
# define __uint_least16_t uint16_t
# define __int_least8_t int16_t
@@ -233,9 +232,9 @@ typedef __uint_least16_t uint_fast16_t;
#ifdef __INT8_TYPE__
#ifndef __int8_t_defined /* glibc sys/types.h also defines int8_t*/
-typedef signed __INT8_TYPE__ int8_t;
+typedef __INT8_TYPE__ int8_t;
#endif /* __int8_t_defined */
-typedef unsigned __INT8_TYPE__ uint8_t;
+typedef __UINT8_TYPE__ uint8_t;
# define __int_least8_t int8_t
# define __uint_least8_t uint8_t
#endif /* __INT8_TYPE__ */
diff --git a/lib/Headers/x86intrin.h b/lib/Headers/x86intrin.h
index 399016f11c97..21a43daf3c2d 100644
--- a/lib/Headers/x86intrin.h
+++ b/lib/Headers/x86intrin.h
@@ -24,6 +24,8 @@
#ifndef __X86INTRIN_H
#define __X86INTRIN_H
+#include <ia32intrin.h>
+
#include <immintrin.h>
#ifdef __3dNOW__
@@ -74,6 +76,6 @@
#include <f16cintrin.h>
#endif
-// FIXME: LWP
+/* FIXME: LWP */
#endif /* __X86INTRIN_H */
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index c68d3ed7b678..c9befcb456f6 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -34,8 +34,8 @@ typedef int __v4si __attribute__((__vector_size__(16)));
typedef float __v4sf __attribute__((__vector_size__(16)));
typedef float __m128 __attribute__((__vector_size__(16)));
-// This header should only be included in a hosted environment as it depends on
-// a standard library to provide allocation routines.
+/* This header should only be included in a hosted environment as it depends on
+ * a standard library to provide allocation routines. */
#if __STDC_HOSTED__
#include <mm_malloc.h>
#endif
@@ -589,7 +589,7 @@ _mm_set1_ps(float __w)
return (__m128){ __w, __w, __w, __w };
}
-// Microsoft specific.
+/* Microsoft specific. */
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_set_ps1(float __w)
{
@@ -672,10 +672,12 @@ _mm_storer_ps(float *__p, __m128 __a)
#define _MM_HINT_T2 1
#define _MM_HINT_NTA 0
+#ifndef _MSC_VER
/* FIXME: We have to #define this because "sel" must be a constant integer, and
Sema doesn't do any form of constant propagation yet. */
#define _mm_prefetch(a, sel) (__builtin_prefetch((void *)(a), 0, (sel)))
+#endif
static __inline__ void __attribute__((__always_inline__, __nodebug__))
_mm_stream_pi(__m64 *__p, __m64 __a)
@@ -903,7 +905,7 @@ _mm_cvtps_pi16(__m128 __a)
__a = _mm_movehl_ps(__a, __a);
__c = _mm_cvtps_pi32(__a);
- return _mm_packs_pi16(__b, __c);
+ return _mm_packs_pi32(__b, __c);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Index/CMakeLists.txt b/lib/Index/CMakeLists.txt
index c4ff5a01307e..1ebb636e8eca 100644
--- a/lib/Index/CMakeLists.txt
+++ b/lib/Index/CMakeLists.txt
@@ -1,11 +1,19 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
add_clang_library(clangIndex
CommentToXML.cpp
- SimpleFormatContext.h
USRGeneration.cpp
- )
-target_link_libraries(clangIndex
- clangBasic
+ ADDITIONAL_HEADERS
+ SimpleFormatContext.h
+
+ LINK_LIBS
clangAST
+ clangBasic
clangFormat
+ clangLex
+ clangRewrite
+ clangTooling
)
diff --git a/lib/Index/CommentToXML.cpp b/lib/Index/CommentToXML.cpp
index 0a9619dfe086..a67c806550d8 100644
--- a/lib/Index/CommentToXML.cpp
+++ b/lib/Index/CommentToXML.cpp
@@ -9,8 +9,8 @@
#include "clang/Index/CommentToXML.h"
#include "SimpleFormatContext.h"
-#include "clang/AST/Attr.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Comment.h"
#include "clang/AST/CommentVisitor.h"
#include "clang/Format/Format.h"
@@ -97,7 +97,7 @@ struct FullCommentParts {
FullCommentParts::FullCommentParts(const FullComment *C,
const CommandTraits &Traits) :
- Brief(NULL), Headerfile(NULL), FirstParagraph(NULL) {
+ Brief(nullptr), Headerfile(nullptr), FirstParagraph(nullptr) {
for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
I != E; ++I) {
const Comment *Child = *I;
@@ -563,6 +563,7 @@ public:
// Helpers.
void appendToResultWithXMLEscaping(StringRef S);
+ void appendToResultWithCDATAEscaping(StringRef S);
void formatTextOfDeclaration(const DeclInfo *DI,
SmallString<128> &Declaration);
@@ -667,14 +668,27 @@ void CommentASTToXMLConverter::visitInlineCommandComment(
void CommentASTToXMLConverter::visitHTMLStartTagComment(
const HTMLStartTagComment *C) {
- Result << "<rawHTML><![CDATA[";
- printHTMLStartTagComment(C, Result);
- Result << "]]></rawHTML>";
+ Result << "<rawHTML";
+ if (C->isMalformed())
+ Result << " isMalformed=\"1\"";
+ Result << ">";
+ {
+ SmallString<32> Tag;
+ {
+ llvm::raw_svector_ostream TagOS(Tag);
+ printHTMLStartTagComment(C, TagOS);
+ }
+ appendToResultWithCDATAEscaping(Tag);
+ }
+ Result << "</rawHTML>";
}
void
CommentASTToXMLConverter::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
- Result << "<rawHTML>&lt;/" << C->getTagName() << "&gt;</rawHTML>";
+ Result << "<rawHTML";
+ if (C->isMalformed())
+ Result << " isMalformed=\"1\"";
+ Result << ">&lt;/" << C->getTagName() << "&gt;</rawHTML>";
}
void
@@ -1100,6 +1114,31 @@ void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
}
}
+void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) {
+ if (S.empty())
+ return;
+
+ Result << "<![CDATA[";
+ while (!S.empty()) {
+ size_t Pos = S.find("]]>");
+ if (Pos == 0) {
+ Result << "]]]]><![CDATA[>";
+ S = S.drop_front(3);
+ continue;
+ }
+ if (Pos == StringRef::npos)
+ Pos = S.size();
+
+ Result << S.substr(0, Pos);
+
+ S = S.drop_front(Pos);
+ }
+ Result << "]]>";
+}
+
+CommentToXMLConverter::CommentToXMLConverter() : FormatInMemoryUniqueId(0) {}
+CommentToXMLConverter::~CommentToXMLConverter() {}
+
void CommentToXMLConverter::convertCommentToHTML(const FullComment *FC,
SmallVectorImpl<char> &HTML,
const ASTContext &Context) {
@@ -1111,7 +1150,7 @@ void CommentToXMLConverter::convertCommentToHTML(const FullComment *FC,
void CommentToXMLConverter::convertHTMLTagNodeToText(
const comments::HTMLTagComment *HTC, SmallVectorImpl<char> &Text,
const ASTContext &Context) {
- CommentASTToHTMLConverter Converter(0, Text,
+ CommentASTToHTMLConverter Converter(nullptr, Text,
Context.getCommentCommandTraits());
Converter.visit(HTC);
}
@@ -1119,13 +1158,10 @@ void CommentToXMLConverter::convertHTMLTagNodeToText(
void CommentToXMLConverter::convertCommentToXML(const FullComment *FC,
SmallVectorImpl<char> &XML,
const ASTContext &Context) {
- if (!FormatContext) {
- FormatContext = new SimpleFormatContext(Context.getLangOpts());
- } else if ((FormatInMemoryUniqueId % 1000) == 0) {
- // Delete after some number of iterations, so the buffers don't grow
- // too large.
- delete FormatContext;
- FormatContext = new SimpleFormatContext(Context.getLangOpts());
+ if (!FormatContext || (FormatInMemoryUniqueId % 1000) == 0) {
+ // Create a new format context, or re-create it after some number of
+ // iterations, so the buffers don't grow too large.
+ FormatContext.reset(new SimpleFormatContext(Context.getLangOpts()));
}
CommentASTToXMLConverter Converter(FC, XML, Context.getCommentCommandTraits(),
diff --git a/lib/Index/SimpleFormatContext.h b/lib/Index/SimpleFormatContext.h
index fde43aed211f..a460863f803e 100644
--- a/lib/Index/SimpleFormatContext.h
+++ b/lib/Index/SimpleFormatContext.h
@@ -37,7 +37,7 @@ public:
SimpleFormatContext(LangOptions Options)
: DiagOpts(new DiagnosticOptions()),
Diagnostics(new DiagnosticsEngine(new DiagnosticIDs,
- DiagOpts.getPtr())),
+ DiagOpts.get())),
Files((FileSystemOptions())),
Sources(*Diagnostics, Files),
Rewrite(Sources, Options) {
@@ -47,12 +47,11 @@ public:
~SimpleFormatContext() { }
FileID createInMemoryFile(StringRef Name, StringRef Content) {
- const llvm::MemoryBuffer *Source =
- llvm::MemoryBuffer::getMemBuffer(Content);
+ llvm::MemoryBuffer *Source = llvm::MemoryBuffer::getMemBuffer(Content);
const FileEntry *Entry =
Files.getVirtualFile(Name, Source->getBufferSize(), 0);
- Sources.overrideFileContents(Entry, Source, true);
- assert(Entry != NULL);
+ Sources.overrideFileContents(Entry, Source);
+ assert(Entry != nullptr);
return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
}
diff --git a/lib/Index/USRGeneration.cpp b/lib/Index/USRGeneration.cpp
index 16d89f8944a7..e08b85e9f868 100644
--- a/lib/Index/USRGeneration.cpp
+++ b/lib/Index/USRGeneration.cpp
@@ -11,6 +11,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
+#include "clang/Lex/PreprocessingRecord.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
@@ -22,6 +23,30 @@ using namespace clang::index;
// USR generation.
//===----------------------------------------------------------------------===//
+/// \returns true on error.
+static bool printLoc(llvm::raw_ostream &OS, SourceLocation Loc,
+ const SourceManager &SM, bool IncludeOffset) {
+ if (Loc.isInvalid()) {
+ return true;
+ }
+ Loc = SM.getExpansionLoc(Loc);
+ const std::pair<FileID, unsigned> &Decomposed = SM.getDecomposedLoc(Loc);
+ const FileEntry *FE = SM.getFileEntryForID(Decomposed.first);
+ if (FE) {
+ OS << llvm::sys::path::filename(FE->getName());
+ } else {
+ // This case really isn't interesting.
+ return true;
+ }
+ if (IncludeOffset) {
+ // Use the offest into the FileID to represent the location. Using
+ // a line/column can cause us to look back at the original source file,
+ // which is expensive.
+ OS << '@' << Decomposed.second;
+ }
+ return false;
+}
+
namespace {
class USRGenerator : public ConstDeclVisitor<USRGenerator> {
SmallVectorImpl<char> &Buf;
@@ -80,10 +105,16 @@ public:
void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) {
IgnoreResults = true;
}
-
+
+ bool ShouldGenerateLocation(const NamedDecl *D);
+
+ bool isLocal(const NamedDecl *D) {
+ return D->getParentFunctionOrMethod() != nullptr;
+ }
+
/// Generate the string component containing the location of the
/// declaration.
- bool GenLoc(const Decl *D);
+ bool GenLoc(const Decl *D, bool IncludeOffset);
/// String generation methods used both by the visitation methods
/// and from other clients that want to directly generate USRs. These
@@ -99,16 +130,6 @@ public:
void GenObjCCategory(StringRef cls, StringRef cat) {
generateUSRForObjCCategory(cls, cat, Out);
}
- /// Generate a USR fragment for an Objective-C instance variable. The
- /// complete USR can be created by concatenating the USR for the
- /// encompassing class with this USR fragment.
- void GenObjCIvar(StringRef ivar) {
- generateUSRForObjCIvar(ivar, Out);
- }
- /// Generate a USR fragment for an Objective-C method.
- void GenObjCMethod(StringRef sel, bool isInstanceMethod) {
- generateUSRForObjCMethod(sel, isInstanceMethod, Out);
- }
/// Generate a USR fragment for an Objective-C property.
void GenObjCProperty(StringRef prop) {
generateUSRForObjCProperty(prop, Out);
@@ -143,8 +164,13 @@ bool USRGenerator::EmitDeclName(const NamedDecl *D) {
return startSize == endSize;
}
-static inline bool ShouldGenerateLocation(const NamedDecl *D) {
- return !D->isExternallyVisible();
+bool USRGenerator::ShouldGenerateLocation(const NamedDecl *D) {
+ if (D->isExternallyVisible())
+ return false;
+ if (D->getParentFunctionOrMethod())
+ return true;
+ const SourceManager &SM = Context->getSourceManager();
+ return !SM.isInSystemHeader(D->getLocation());
}
void USRGenerator::VisitDeclContext(const DeclContext *DC) {
@@ -168,7 +194,7 @@ void USRGenerator::VisitFieldDecl(const FieldDecl *D) {
}
void USRGenerator::VisitFunctionDecl(const FunctionDecl *D) {
- if (ShouldGenerateLocation(D) && GenLoc(D))
+ if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))
return;
VisitDeclContext(D->getDeclContext());
@@ -194,12 +220,9 @@ void USRGenerator::VisitFunctionDecl(const FunctionDecl *D) {
}
// Mangle in type information for the arguments.
- for (FunctionDecl::param_const_iterator I = D->param_begin(),
- E = D->param_end();
- I != E; ++I) {
+ for (auto PD : D->params()) {
Out << '#';
- if (ParmVarDecl *PD = *I)
- VisitType(PD->getType());
+ VisitType(PD->getType());
}
if (D->isVariadic())
Out << '.';
@@ -229,7 +252,7 @@ void USRGenerator::VisitVarDecl(const VarDecl *D) {
// VarDecls can be declared 'extern' within a function or method body,
// but their enclosing DeclContext is the function, not the TU. We need
// to check the storage class to correctly generate the USR.
- if (ShouldGenerateLocation(D) && GenLoc(D))
+ if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))
return;
VisitDeclContext(D->getDeclContext());
@@ -249,13 +272,13 @@ void USRGenerator::VisitVarDecl(const VarDecl *D) {
void USRGenerator::VisitNonTypeTemplateParmDecl(
const NonTypeTemplateParmDecl *D) {
- GenLoc(D);
+ GenLoc(D, /*IncludeOffset=*/true);
return;
}
void USRGenerator::VisitTemplateTemplateParmDecl(
const TemplateTemplateParmDecl *D) {
- GenLoc(D);
+ GenLoc(D, /*IncludeOffset=*/true);
return;
}
@@ -329,7 +352,7 @@ void USRGenerator::VisitObjCContainerDecl(const ObjCContainerDecl *D) {
// We want to mangle in the location to uniquely distinguish them.
if (CD->IsClassExtension()) {
Out << "objc(ext)" << ID->getName() << '@';
- GenLoc(CD);
+ GenLoc(CD, /*IncludeOffset=*/true);
}
else
GenObjCCategory(ID->getName(), CD->getName());
@@ -378,7 +401,7 @@ void USRGenerator::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
void USRGenerator::VisitTagDecl(const TagDecl *D) {
// Add the location of the tag decl to handle resolution across
// translation units.
- if (ShouldGenerateLocation(D) && GenLoc(D))
+ if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))
return;
D = D->getCanonicalDecl();
@@ -449,7 +472,7 @@ void USRGenerator::VisitTagDecl(const TagDecl *D) {
}
void USRGenerator::VisitTypedefDecl(const TypedefDecl *D) {
- if (ShouldGenerateLocation(D) && GenLoc(D))
+ if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))
return;
const DeclContext *DC = D->getDeclContext();
if (const NamedDecl *DCN = dyn_cast<NamedDecl>(DC))
@@ -459,15 +482,15 @@ void USRGenerator::VisitTypedefDecl(const TypedefDecl *D) {
}
void USRGenerator::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
- GenLoc(D);
+ GenLoc(D, /*IncludeOffset=*/true);
return;
}
-bool USRGenerator::GenLoc(const Decl *D) {
+bool USRGenerator::GenLoc(const Decl *D, bool IncludeOffset) {
if (generatedLoc)
return IgnoreResults;
generatedLoc = true;
-
+
// Guard against null declarations in invalid code.
if (!D) {
IgnoreResults = true;
@@ -477,27 +500,10 @@ bool USRGenerator::GenLoc(const Decl *D) {
// Use the location of canonical decl.
D = D->getCanonicalDecl();
- const SourceManager &SM = Context->getSourceManager();
- SourceLocation L = D->getLocStart();
- if (L.isInvalid()) {
- IgnoreResults = true;
- return true;
- }
- L = SM.getExpansionLoc(L);
- const std::pair<FileID, unsigned> &Decomposed = SM.getDecomposedLoc(L);
- const FileEntry *FE = SM.getFileEntryForID(Decomposed.first);
- if (FE) {
- Out << llvm::sys::path::filename(FE->getName());
- }
- else {
- // This case really isn't interesting.
- IgnoreResults = true;
- return true;
- }
- // Use the offest into the FileID to represent the location. Using
- // a line/column can cause us to look back at the original source file,
- // which is expensive.
- Out << '@' << Decomposed.second;
+ IgnoreResults =
+ IgnoreResults || printLoc(Out, D->getLocStart(),
+ Context->getSourceManager(), IncludeOffset);
+
return IgnoreResults;
}
@@ -627,11 +633,9 @@ void USRGenerator::VisitType(QualType T) {
}
if (const FunctionProtoType *FT = T->getAs<FunctionProtoType>()) {
Out << 'F';
- VisitType(FT->getResultType());
- for (FunctionProtoType::arg_type_iterator
- I = FT->arg_type_begin(), E = FT->arg_type_end(); I!=E; ++I) {
- VisitType(*I);
- }
+ VisitType(FT->getReturnType());
+ for (const auto &I : FT->param_types())
+ VisitType(I);
if (FT->isVariadic())
Out << '.';
return;
@@ -743,9 +747,8 @@ void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) {
case TemplateArgument::Pack:
Out << 'p' << Arg.pack_size();
- for (TemplateArgument::pack_iterator P = Arg.pack_begin(), PEnd = Arg.pack_end();
- P != PEnd; ++P)
- VisitTemplateArgument(*P);
+ for (const auto &P : Arg.pack_elements())
+ VisitTemplateArgument(P);
break;
case TemplateArgument::Type:
@@ -801,3 +804,26 @@ bool clang::index::generateUSRForDecl(const Decl *D,
UG.Visit(D);
return UG.ignoreResults();
}
+
+bool clang::index::generateUSRForMacro(const MacroDefinition *MD,
+ const SourceManager &SM,
+ SmallVectorImpl<char> &Buf) {
+ // Don't generate USRs for things with invalid locations.
+ if (!MD || MD->getLocation().isInvalid())
+ return true;
+
+ llvm::raw_svector_ostream Out(Buf);
+
+ // Assume that system headers are sane. Don't put source location
+ // information into the USR if the macro comes from a system header.
+ SourceLocation Loc = MD->getLocation();
+ bool ShouldGenerateLocation = !SM.isInSystemHeader(Loc);
+
+ Out << getUSRSpacePrefix();
+ if (ShouldGenerateLocation)
+ printLoc(Out, Loc, SM, /*IncludeOffset=*/true);
+ Out << "@macro@";
+ Out << MD->getName()->getName();
+ return false;
+}
+
diff --git a/lib/Lex/CMakeLists.txt b/lib/Lex/CMakeLists.txt
index 2ee468294ae7..38df144adf9a 100644
--- a/lib/Lex/CMakeLists.txt
+++ b/lib/Lex/CMakeLists.txt
@@ -25,14 +25,7 @@ add_clang_library(clangLex
ScratchBuffer.cpp
TokenConcatenation.cpp
TokenLexer.cpp
- )
-
-add_dependencies(clangLex
- ClangAttrSpellings
- ClangDiagnosticCommon
- ClangDiagnosticLex
- )
-target_link_libraries(clangLex
+ LINK_LIBS
clangBasic
)
diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp
index 478462c3c20d..f6c658e11926 100644
--- a/lib/Lex/HeaderMap.cpp
+++ b/lib/Lex/HeaderMap.cpp
@@ -14,12 +14,12 @@
#include "clang/Lex/HeaderMap.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/FileManager.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MemoryBuffer.h"
#include <cstdio>
+#include <memory>
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -79,10 +79,10 @@ static inline unsigned HashHMapKey(StringRef Str) {
const HeaderMap *HeaderMap::Create(const FileEntry *FE, FileManager &FM) {
// If the file is too small to be a header map, ignore it.
unsigned FileSize = FE->getSize();
- if (FileSize <= sizeof(HMapHeader)) return 0;
+ if (FileSize <= sizeof(HMapHeader)) return nullptr;
- OwningPtr<const llvm::MemoryBuffer> FileBuffer(FM.getBufferForFile(FE));
- if (!FileBuffer) return 0; // Unreadable file?
+ std::unique_ptr<const llvm::MemoryBuffer> FileBuffer(FM.getBufferForFile(FE));
+ if (!FileBuffer) return nullptr; // Unreadable file?
const char *FileStart = FileBuffer->getBufferStart();
// We know the file is at least as big as the header, check it now.
@@ -98,12 +98,12 @@ const HeaderMap *HeaderMap::Create(const FileEntry *FE, FileManager &FM) {
Header->Version == llvm::ByteSwap_16(HMAP_HeaderVersion))
NeedsByteSwap = true; // Mixed endianness headermap.
else
- return 0; // Not a header map.
+ return nullptr; // Not a header map.
- if (Header->Reserved != 0) return 0;
+ if (Header->Reserved != 0) return nullptr;
// Okay, everything looks good, create the header map.
- return new HeaderMap(FileBuffer.take(), NeedsByteSwap);
+ return new HeaderMap(FileBuffer.release(), NeedsByteSwap);
}
HeaderMap::~HeaderMap() {
@@ -165,7 +165,7 @@ const char *HeaderMap::getString(unsigned StrTabIdx) const {
// Check for invalid index.
if (StrTabIdx >= FileBuffer->getBufferSize())
- return 0;
+ return nullptr;
// Otherwise, we have a valid pointer into the file. Just return it. We know
// that the "string" can not overrun the end of the file, because the buffer
@@ -201,18 +201,29 @@ void HeaderMap::dump() const {
/// this HeaderMap. If so, open it and return its FileEntry.
const FileEntry *HeaderMap::LookupFile(
StringRef Filename, FileManager &FM) const {
+
+ SmallString<1024> Path;
+ StringRef Dest = lookupFilename(Filename, Path);
+ if (Dest.empty())
+ return nullptr;
+
+ return FM.getFile(Dest);
+}
+
+StringRef HeaderMap::lookupFilename(StringRef Filename,
+ SmallVectorImpl<char> &DestPath) const {
const HMapHeader &Hdr = getHeader();
unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);
// If the number of buckets is not a power of two, the headermap is corrupt.
// Don't probe infinitely.
if (NumBuckets & (NumBuckets-1))
- return 0;
+ return StringRef();
// Linearly probe the hash table.
for (unsigned Bucket = HashHMapKey(Filename);; ++Bucket) {
HMapBucket B = getBucket(Bucket & (NumBuckets-1));
- if (B.Key == HMAP_EmptyBucketKey) return 0; // Hash miss.
+ if (B.Key == HMAP_EmptyBucketKey) return StringRef(); // Hash miss.
// See if the key matches. If not, probe on.
if (!Filename.equals_lower(getString(B.Key)))
@@ -220,9 +231,11 @@ const FileEntry *HeaderMap::LookupFile(
// If so, we have a match in the hash table. Construct the destination
// path.
- SmallString<1024> DestPath;
- DestPath += getString(B.Prefix);
- DestPath += getString(B.Suffix);
- return FM.getFile(DestPath.str());
+ StringRef Prefix = getString(B.Prefix);
+ StringRef Suffix = getString(B.Suffix);
+ DestPath.clear();
+ DestPath.append(Prefix.begin(), Prefix.end());
+ DestPath.append(Suffix.begin(), Suffix.end());
+ return StringRef(DestPath.begin(), DestPath.size());
}
}
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 9e43dda226bf..c12d7314ee23 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -12,12 +12,14 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/HeaderSearch.h"
-#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Lex/HeaderMap.h"
#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Capacity.h"
#include "llvm/Support/FileSystem.h"
@@ -35,7 +37,7 @@ HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) {
return ControllingMacro;
if (!ControllingMacroID || !External)
- return 0;
+ return nullptr;
ControllingMacro = External->GetIdentifier(ControllingMacroID);
return ControllingMacro;
@@ -45,20 +47,21 @@ ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {}
HeaderSearch::HeaderSearch(IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
SourceManager &SourceMgr, DiagnosticsEngine &Diags,
- const LangOptions &LangOpts,
+ const LangOptions &LangOpts,
const TargetInfo *Target)
- : HSOpts(HSOpts), FileMgr(SourceMgr.getFileManager()), FrameworkMap(64),
- ModMap(SourceMgr, *Diags.getClient(), LangOpts, Target, *this)
-{
+ : HSOpts(HSOpts), Diags(Diags), FileMgr(SourceMgr.getFileManager()),
+ FrameworkMap(64), ModMap(SourceMgr, Diags, LangOpts, Target, *this) {
AngledDirIdx = 0;
SystemDirIdx = 0;
NoCurDirSearch = false;
- ExternalLookup = 0;
- ExternalSource = 0;
+ ExternalLookup = nullptr;
+ ExternalSource = nullptr;
NumIncluded = 0;
NumMultiIncludeFileOptzn = 0;
NumFrameworkLookups = NumSubFrameworkLookups = 0;
+
+ EnabledModules = LangOpts.Modules;
}
HeaderSearch::~HeaderSearch() {
@@ -107,28 +110,37 @@ const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) {
return HM;
}
- return 0;
+ return nullptr;
}
std::string HeaderSearch::getModuleFileName(Module *Module) {
- // If we don't have a module cache path, we can't do anything.
- if (ModuleCachePath.empty())
- return std::string();
-
-
- SmallString<256> Result(ModuleCachePath);
- llvm::sys::path::append(Result, Module->getTopLevelModule()->Name + ".pcm");
- return Result.str().str();
+ return getModuleFileName(Module->Name, Module->ModuleMap->getName());
}
-std::string HeaderSearch::getModuleFileName(StringRef ModuleName) {
+std::string HeaderSearch::getModuleFileName(StringRef ModuleName,
+ StringRef ModuleMapPath) {
// If we don't have a module cache path, we can't do anything.
if (ModuleCachePath.empty())
return std::string();
-
-
+
SmallString<256> Result(ModuleCachePath);
- llvm::sys::path::append(Result, ModuleName + ".pcm");
+ llvm::sys::fs::make_absolute(Result);
+
+ if (HSOpts->DisableModuleHash) {
+ llvm::sys::path::append(Result, ModuleName + ".pcm");
+ } else {
+ // Construct the name <ModuleName>-<hash of ModuleMapPath>.pcm which should
+ // be globally unique to this particular module. To avoid false-negatives
+ // on case-insensitive filesystems, we use lower-case, which is safe because
+ // to cause a collision the modules must have the same name, which is an
+ // error if they are imported in the same translation.
+ SmallString<256> AbsModuleMapPath(ModuleMapPath);
+ llvm::sys::fs::make_absolute(AbsModuleMapPath);
+ llvm::APInt Code(64, llvm::hash_value(AbsModuleMapPath.str().lower()));
+ SmallString<128> HashStr;
+ Code.toStringUnsigned(HashStr, /*Radix*/36);
+ llvm::sys::path::append(Result, ModuleName + "-" + HashStr.str() + ".pcm");
+ }
return Result.str().str();
}
@@ -164,8 +176,8 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
bool IsSystem = SearchDirs[Idx].isSystemHeaderDirectory();
// Search for a module map file in this directory.
- if (loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem)
- == LMM_NewlyLoaded) {
+ if (loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem,
+ /*IsFramework*/false) == LMM_NewlyLoaded) {
// We just loaded a module map file; check whether the module is
// available now.
Module = ModMap.findModule(ModuleName);
@@ -178,7 +190,8 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
SmallString<128> NestedModuleMapDirName;
NestedModuleMapDirName = SearchDirs[Idx].getDir()->getName();
llvm::sys::path::append(NestedModuleMapDirName, ModuleName);
- if (loadModuleMapFile(NestedModuleMapDirName, IsSystem) == LMM_NewlyLoaded){
+ if (loadModuleMapFile(NestedModuleMapDirName, IsSystem,
+ /*IsFramework*/false) == LMM_NewlyLoaded){
// If we just loaded a module map file, look for the module again.
Module = ModMap.findModule(ModuleName);
if (Module)
@@ -218,51 +231,65 @@ const char *DirectoryLookup::getName() const {
return getHeaderMap()->getFileName();
}
+static const FileEntry *
+getFileAndSuggestModule(HeaderSearch &HS, StringRef FileName,
+ const DirectoryEntry *Dir, bool IsSystemHeaderDir,
+ ModuleMap::KnownHeader *SuggestedModule) {
+ // If we have a module map that might map this header, load it and
+ // check whether we'll have a suggestion for a module.
+ HS.hasModuleMap(FileName, Dir, IsSystemHeaderDir);
+ if (SuggestedModule) {
+ const FileEntry *File = HS.getFileMgr().getFile(FileName,
+ /*OpenFile=*/false);
+ if (File) {
+ // If there is a module that corresponds to this header, suggest it.
+ *SuggestedModule = HS.findModuleForHeader(File);
+
+ // FIXME: This appears to be a no-op. We loaded the module map for this
+ // directory at the start of this function.
+ if (!SuggestedModule->getModule() &&
+ HS.hasModuleMap(FileName, Dir, IsSystemHeaderDir))
+ *SuggestedModule = HS.findModuleForHeader(File);
+ }
+
+ return File;
+ }
+
+ return HS.getFileMgr().getFile(FileName, /*openFile=*/true);
+}
/// LookupFile - Lookup the specified file in this search path, returning it
/// if it exists or returning null if not.
const FileEntry *DirectoryLookup::LookupFile(
- StringRef Filename,
+ StringRef &Filename,
HeaderSearch &HS,
SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
ModuleMap::KnownHeader *SuggestedModule,
- bool &InUserSpecifiedSystemFramework) const {
+ bool &InUserSpecifiedSystemFramework,
+ bool &HasBeenMapped,
+ SmallVectorImpl<char> &MappedName) const {
InUserSpecifiedSystemFramework = false;
+ HasBeenMapped = false;
SmallString<1024> TmpDir;
if (isNormalDir()) {
// Concatenate the requested file onto the directory.
TmpDir = getDir()->getName();
llvm::sys::path::append(TmpDir, Filename);
- if (SearchPath != NULL) {
+ if (SearchPath) {
StringRef SearchPathRef(getDir()->getName());
SearchPath->clear();
SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
}
- if (RelativePath != NULL) {
+ if (RelativePath) {
RelativePath->clear();
RelativePath->append(Filename.begin(), Filename.end());
}
-
- // If we have a module map that might map this header, load it and
- // check whether we'll have a suggestion for a module.
- HS.hasModuleMap(TmpDir, getDir(), isSystemHeaderDirectory());
- if (SuggestedModule) {
- const FileEntry *File = HS.getFileMgr().getFile(TmpDir.str(),
- /*openFile=*/false);
- if (!File)
- return File;
-
- // If there is a module that corresponds to this header, suggest it.
- *SuggestedModule = HS.findModuleForHeader(File);
- if (!SuggestedModule->getModule() &&
- HS.hasModuleMap(TmpDir, getDir(), isSystemHeaderDirectory()))
- *SuggestedModule = HS.findModuleForHeader(File);
- return File;
- }
-
- return HS.getFileMgr().getFile(TmpDir.str(), /*openFile=*/true);
+
+ return getFileAndSuggestModule(HS, TmpDir.str(), getDir(),
+ isSystemHeaderDirectory(),
+ SuggestedModule);
}
if (isFramework())
@@ -270,15 +297,35 @@ const FileEntry *DirectoryLookup::LookupFile(
SuggestedModule, InUserSpecifiedSystemFramework);
assert(isHeaderMap() && "Unknown directory lookup");
- const FileEntry * const Result = getHeaderMap()->LookupFile(
- Filename, HS.getFileMgr());
+ const HeaderMap *HM = getHeaderMap();
+ SmallString<1024> Path;
+ StringRef Dest = HM->lookupFilename(Filename, Path);
+ if (Dest.empty())
+ return nullptr;
+
+ const FileEntry *Result;
+
+ // Check if the headermap maps the filename to a framework include
+ // ("Foo.h" -> "Foo/Foo.h"), in which case continue header lookup using the
+ // framework include.
+ if (llvm::sys::path::is_relative(Dest)) {
+ MappedName.clear();
+ MappedName.append(Dest.begin(), Dest.end());
+ Filename = StringRef(MappedName.begin(), MappedName.size());
+ HasBeenMapped = true;
+ Result = HM->LookupFile(Filename, HS.getFileMgr());
+
+ } else {
+ Result = HS.getFileMgr().getFile(Dest);
+ }
+
if (Result) {
- if (SearchPath != NULL) {
+ if (SearchPath) {
StringRef SearchPathRef(getName());
SearchPath->clear();
SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
}
- if (RelativePath != NULL) {
+ if (RelativePath) {
RelativePath->clear();
RelativePath->append(Filename.begin(), Filename.end());
}
@@ -350,7 +397,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
// Framework names must have a '/' in the filename.
size_t SlashPos = Filename.find('/');
- if (SlashPos == StringRef::npos) return 0;
+ if (SlashPos == StringRef::npos) return nullptr;
// Find out if this is the home for the specified framework, by checking
// HeaderSearch. Possible answers are yes/no and unknown.
@@ -359,7 +406,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
// If it is known and in some other directory, fail.
if (CacheEntry.Directory && CacheEntry.Directory != getFrameworkDir())
- return 0;
+ return nullptr;
// Otherwise, construct the path to this framework dir.
@@ -377,12 +424,12 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
FrameworkName += ".framework/";
// If the cache entry was unresolved, populate it now.
- if (CacheEntry.Directory == 0) {
+ if (!CacheEntry.Directory) {
HS.IncrementFrameworkLookupCount();
// If the framework dir doesn't exist, we fail.
const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.str());
- if (Dir == 0) return 0;
+ if (!Dir) return nullptr;
// Otherwise, if it does, remember that this is the right direntry for this
// framework.
@@ -402,7 +449,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
// Set the 'user-specified system framework' flag.
InUserSpecifiedSystemFramework = CacheEntry.IsUserSpecifiedSystemFramework;
- if (RelativePath != NULL) {
+ if (RelativePath) {
RelativePath->clear();
RelativePath->append(Filename.begin()+SlashPos+1, Filename.end());
}
@@ -412,7 +459,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
FrameworkName += "Headers/";
- if (SearchPath != NULL) {
+ if (SearchPath) {
SearchPath->clear();
// Without trailing '/'.
SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1);
@@ -426,7 +473,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
const char *Private = "Private";
FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
Private+strlen(Private));
- if (SearchPath != NULL)
+ if (SearchPath)
SearchPath->insert(SearchPath->begin()+OrigSize, Private,
Private+strlen(Private));
@@ -436,14 +483,9 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
// If we found the header and are allowed to suggest a module, do so now.
if (FE && SuggestedModule) {
// Find the framework in which this header occurs.
- StringRef FrameworkPath = FE->getName();
+ StringRef FrameworkPath = FE->getDir()->getName();
bool FoundFramework = false;
do {
- // Get the parent directory name.
- FrameworkPath = llvm::sys::path::parent_path(FrameworkPath);
- if (FrameworkPath.empty())
- break;
-
// Determine whether this directory exists.
const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkPath);
if (!Dir)
@@ -455,6 +497,11 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
FoundFramework = true;
break;
}
+
+ // Get the parent directory name.
+ FrameworkPath = llvm::sys::path::parent_path(FrameworkPath);
+ if (FrameworkPath.empty())
+ break;
} while (true);
if (FoundFramework) {
@@ -488,28 +535,43 @@ void HeaderSearch::setTarget(const TargetInfo &Target) {
// Header File Location.
//===----------------------------------------------------------------------===//
+/// \brief Return true with a diagnostic if the file that MSVC would have found
+/// fails to match the one that Clang would have found with MSVC header search
+/// disabled.
+static bool checkMSVCHeaderSearch(DiagnosticsEngine &Diags,
+ const FileEntry *MSFE, const FileEntry *FE,
+ SourceLocation IncludeLoc) {
+ if (MSFE && FE != MSFE) {
+ Diags.Report(IncludeLoc, diag::ext_pp_include_search_ms) << MSFE->getName();
+ return true;
+ }
+ return false;
+}
+
+static const char *copyString(StringRef Str, llvm::BumpPtrAllocator &Alloc) {
+ assert(!Str.empty());
+ char *CopyStr = Alloc.Allocate<char>(Str.size()+1);
+ std::copy(Str.begin(), Str.end(), CopyStr);
+ CopyStr[Str.size()] = '\0';
+ return CopyStr;
+}
/// LookupFile - Given a "foo" or \<foo> reference, look up the indicated file,
/// return null on failure. isAngled indicates whether the file reference is
-/// for system \#include's or not (i.e. using <> instead of ""). CurFileEnt, if
-/// non-null, indicates where the \#including file is, in case a relative search
-/// is needed.
+/// for system \#include's or not (i.e. using <> instead of ""). Includers, if
+/// non-empty, indicates where the \#including file(s) are, in case a relative
+/// search is needed. Microsoft mode will pass all \#including files.
const FileEntry *HeaderSearch::LookupFile(
- StringRef Filename,
- bool isAngled,
- const DirectoryLookup *FromDir,
- const DirectoryLookup *&CurDir,
- const FileEntry *CurFileEnt,
- SmallVectorImpl<char> *SearchPath,
+ StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
+ const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
+ ArrayRef<const FileEntry *> Includers, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
- ModuleMap::KnownHeader *SuggestedModule,
- bool SkipCache)
-{
+ ModuleMap::KnownHeader *SuggestedModule, bool SkipCache) {
if (!HSOpts->ModuleMapFiles.empty()) {
// Preload all explicitly specified module map files. This enables modules
// map files lying in a directory structure separate from the header files
// that they describe. These cannot be loaded lazily upon encountering a
- // header file, as there is no other knwon mapping from a header file to its
+ // header file, as there is no other known mapping from a header file to its
// module map file.
for (llvm::SetVector<std::string>::iterator
I = HSOpts->ModuleMapFiles.begin(),
@@ -528,14 +590,14 @@ const FileEntry *HeaderSearch::LookupFile(
// If 'Filename' is absolute, check to see if it exists and no searching.
if (llvm::sys::path::is_absolute(Filename)) {
- CurDir = 0;
+ CurDir = nullptr;
// If this was an #include_next "/absolute/file", fail.
- if (FromDir) return 0;
+ if (FromDir) return nullptr;
- if (SearchPath != NULL)
+ if (SearchPath)
SearchPath->clear();
- if (RelativePath != NULL) {
+ if (RelativePath) {
RelativePath->clear();
RelativePath->append(Filename.begin(), Filename.end());
}
@@ -543,49 +605,82 @@ const FileEntry *HeaderSearch::LookupFile(
return FileMgr.getFile(Filename, /*openFile=*/true);
}
+ // This is the header that MSVC's header search would have found.
+ const FileEntry *MSFE = nullptr;
+ ModuleMap::KnownHeader MSSuggestedModule;
+
// Unless disabled, check to see if the file is in the #includer's
- // directory. This has to be based on CurFileEnt, not CurDir, because
- // CurFileEnt could be a #include of a subdirectory (#include "foo/bar.h") and
- // a subsequent include of "baz.h" should resolve to "whatever/foo/baz.h".
+ // directory. This cannot be based on CurDir, because each includer could be
+ // a #include of a subdirectory (#include "foo/bar.h") and a subsequent
+ // include of "baz.h" should resolve to "whatever/foo/baz.h".
// This search is not done for <> headers.
- if (CurFileEnt && !isAngled && !NoCurDirSearch) {
+ if (!Includers.empty() && !isAngled && !NoCurDirSearch) {
SmallString<1024> TmpDir;
- // Concatenate the requested file onto the directory.
- // FIXME: Portability. Filename concatenation should be in sys::Path.
- TmpDir += CurFileEnt->getDir()->getName();
- TmpDir.push_back('/');
- TmpDir.append(Filename.begin(), Filename.end());
- if (const FileEntry *FE = FileMgr.getFile(TmpDir.str(),/*openFile=*/true)) {
- // Leave CurDir unset.
- // This file is a system header or C++ unfriendly if the old file is.
- //
- // Note that we only use one of FromHFI/ToHFI at once, due to potential
- // reallocation of the underlying vector potentially making the first
- // reference binding dangling.
- HeaderFileInfo &FromHFI = getFileInfo(CurFileEnt);
- unsigned DirInfo = FromHFI.DirInfo;
- bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader;
- StringRef Framework = FromHFI.Framework;
-
- HeaderFileInfo &ToHFI = getFileInfo(FE);
- ToHFI.DirInfo = DirInfo;
- ToHFI.IndexHeaderMapHeader = IndexHeaderMapHeader;
- ToHFI.Framework = Framework;
-
- if (SearchPath != NULL) {
- StringRef SearchPathRef(CurFileEnt->getDir()->getName());
- SearchPath->clear();
- SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
- }
- if (RelativePath != NULL) {
- RelativePath->clear();
- RelativePath->append(Filename.begin(), Filename.end());
+ for (ArrayRef<const FileEntry *>::iterator I = Includers.begin(),
+ E = Includers.end();
+ I != E; ++I) {
+ const FileEntry *Includer = *I;
+ // Concatenate the requested file onto the directory.
+ // FIXME: Portability. Filename concatenation should be in sys::Path.
+ TmpDir = Includer->getDir()->getName();
+ TmpDir.push_back('/');
+ TmpDir.append(Filename.begin(), Filename.end());
+
+ // FIXME: We don't cache the result of getFileInfo across the call to
+ // getFileAndSuggestModule, because it's a reference to an element of
+ // a container that could be reallocated across this call.
+ bool IncluderIsSystemHeader =
+ getFileInfo(Includer).DirInfo != SrcMgr::C_User;
+ if (const FileEntry *FE =
+ getFileAndSuggestModule(*this, TmpDir.str(), Includer->getDir(),
+ IncluderIsSystemHeader,
+ SuggestedModule)) {
+ // Leave CurDir unset.
+ // This file is a system header or C++ unfriendly if the old file is.
+ //
+ // Note that we only use one of FromHFI/ToHFI at once, due to potential
+ // reallocation of the underlying vector potentially making the first
+ // reference binding dangling.
+ HeaderFileInfo &FromHFI = getFileInfo(Includer);
+ unsigned DirInfo = FromHFI.DirInfo;
+ bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader;
+ StringRef Framework = FromHFI.Framework;
+
+ HeaderFileInfo &ToHFI = getFileInfo(FE);
+ ToHFI.DirInfo = DirInfo;
+ ToHFI.IndexHeaderMapHeader = IndexHeaderMapHeader;
+ ToHFI.Framework = Framework;
+
+ if (SearchPath) {
+ StringRef SearchPathRef(Includer->getDir()->getName());
+ SearchPath->clear();
+ SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
+ }
+ if (RelativePath) {
+ RelativePath->clear();
+ RelativePath->append(Filename.begin(), Filename.end());
+ }
+ if (I == Includers.begin())
+ return FE;
+
+ // Otherwise, we found the path via MSVC header search rules. If
+ // -Wmsvc-include is enabled, we have to keep searching to see if we
+ // would've found this header in -I or -isystem directories.
+ if (Diags.isIgnored(diag::ext_pp_include_search_ms, IncludeLoc)) {
+ return FE;
+ } else {
+ MSFE = FE;
+ if (SuggestedModule) {
+ MSSuggestedModule = *SuggestedModule;
+ *SuggestedModule = ModuleMap::KnownHeader();
+ }
+ break;
+ }
}
- return FE;
}
}
- CurDir = 0;
+ CurDir = nullptr;
// If this is a system #include, ignore the user #include locs.
unsigned i = isAngled ? AngledDirIdx : 0;
@@ -599,28 +694,38 @@ const FileEntry *HeaderSearch::LookupFile(
// multiply included, and the "pragma once" optimization prevents them from
// being relex/pp'd, but they would still have to search through a
// (potentially huge) series of SearchDirs to find it.
- std::pair<unsigned, unsigned> &CacheLookup =
+ LookupFileCacheInfo &CacheLookup =
LookupFileCache.GetOrCreateValue(Filename).getValue();
// If the entry has been previously looked up, the first value will be
// non-zero. If the value is equal to i (the start point of our search), then
// this is a matching hit.
- if (!SkipCache && CacheLookup.first == i+1) {
+ if (!SkipCache && CacheLookup.StartIdx == i+1) {
// Skip querying potentially lots of directories for this lookup.
- i = CacheLookup.second;
+ i = CacheLookup.HitIdx;
+ if (CacheLookup.MappedName)
+ Filename = CacheLookup.MappedName;
} else {
// Otherwise, this is the first query, or the previous query didn't match
// our search start. We will fill in our found location below, so prime the
// start point value.
- CacheLookup.first = i+1;
+ CacheLookup.reset(/*StartIdx=*/i+1);
}
+ SmallString<64> MappedName;
+
// Check each directory in sequence to see if it contains this file.
for (; i != SearchDirs.size(); ++i) {
bool InUserSpecifiedSystemFramework = false;
+ bool HasBeenMapped = false;
const FileEntry *FE =
SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath,
- SuggestedModule, InUserSpecifiedSystemFramework);
+ SuggestedModule, InUserSpecifiedSystemFramework,
+ HasBeenMapped, MappedName);
+ if (HasBeenMapped) {
+ CacheLookup.MappedName =
+ copyString(Filename, LookupFileCache.getAllocator());
+ }
if (!FE) continue;
CurDir = &SearchDirs[i];
@@ -655,9 +760,15 @@ const FileEntry *HeaderSearch::LookupFile(
SlashPos));
}
}
-
+
+ if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) {
+ if (SuggestedModule)
+ *SuggestedModule = MSSuggestedModule;
+ return MSFE;
+ }
+
// Remember this location for the next lookup we do.
- CacheLookup.second = i;
+ CacheLookup.HitIdx = i;
return FE;
}
@@ -665,29 +776,43 @@ const FileEntry *HeaderSearch::LookupFile(
// a header in a framework that is currently being built, and we couldn't
// resolve "foo.h" any other way, change the include to <Foo/foo.h>, where
// "Foo" is the name of the framework in which the including header was found.
- if (CurFileEnt && !isAngled && Filename.find('/') == StringRef::npos) {
- HeaderFileInfo &IncludingHFI = getFileInfo(CurFileEnt);
+ if (!Includers.empty() && !isAngled &&
+ Filename.find('/') == StringRef::npos) {
+ HeaderFileInfo &IncludingHFI = getFileInfo(Includers.front());
if (IncludingHFI.IndexHeaderMapHeader) {
SmallString<128> ScratchFilename;
ScratchFilename += IncludingHFI.Framework;
ScratchFilename += '/';
ScratchFilename += Filename;
-
- const FileEntry *Result = LookupFile(ScratchFilename, /*isAngled=*/true,
- FromDir, CurDir, CurFileEnt,
- SearchPath, RelativePath,
- SuggestedModule);
- std::pair<unsigned, unsigned> &CacheLookup
+
+ const FileEntry *FE = LookupFile(
+ ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, CurDir,
+ Includers.front(), SearchPath, RelativePath, SuggestedModule);
+
+ if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) {
+ if (SuggestedModule)
+ *SuggestedModule = MSSuggestedModule;
+ return MSFE;
+ }
+
+ LookupFileCacheInfo &CacheLookup
= LookupFileCache.GetOrCreateValue(Filename).getValue();
- CacheLookup.second
- = LookupFileCache.GetOrCreateValue(ScratchFilename).getValue().second;
- return Result;
+ CacheLookup.HitIdx
+ = LookupFileCache.GetOrCreateValue(ScratchFilename).getValue().HitIdx;
+ // FIXME: SuggestedModule.
+ return FE;
}
}
+ if (checkMSVCHeaderSearch(Diags, MSFE, nullptr, IncludeLoc)) {
+ if (SuggestedModule)
+ *SuggestedModule = MSSuggestedModule;
+ return MSFE;
+ }
+
// Otherwise, didn't find it. Remember we didn't find this.
- CacheLookup.second = SearchDirs.size();
- return 0;
+ CacheLookup.HitIdx = SearchDirs.size();
+ return nullptr;
}
/// LookupSubframeworkHeader - Look up a subframework for the specified
@@ -706,7 +831,7 @@ LookupSubframeworkHeader(StringRef Filename,
// Framework names must have a '/' in the filename. Find it.
// FIXME: Should we permit '\' on Windows?
size_t SlashPos = Filename.find('/');
- if (SlashPos == StringRef::npos) return 0;
+ if (SlashPos == StringRef::npos) return nullptr;
// Look up the base framework name of the ContextFileEnt.
const char *ContextName = ContextFileEnt->getName();
@@ -714,10 +839,10 @@ LookupSubframeworkHeader(StringRef Filename,
// If the context info wasn't a framework, couldn't be a subframework.
const unsigned DotFrameworkLen = 10;
const char *FrameworkPos = strstr(ContextName, ".framework");
- if (FrameworkPos == 0 ||
+ if (FrameworkPos == nullptr ||
(FrameworkPos[DotFrameworkLen] != '/' &&
FrameworkPos[DotFrameworkLen] != '\\'))
- return 0;
+ return nullptr;
SmallString<1024> FrameworkName(ContextName, FrameworkPos+DotFrameworkLen+1);
@@ -734,24 +859,24 @@ LookupSubframeworkHeader(StringRef Filename,
CacheLookup.getKeyLength() == FrameworkName.size() &&
memcmp(CacheLookup.getKeyData(), &FrameworkName[0],
CacheLookup.getKeyLength()) != 0)
- return 0;
+ return nullptr;
// Cache subframework.
- if (CacheLookup.getValue().Directory == 0) {
+ if (!CacheLookup.getValue().Directory) {
++NumSubFrameworkLookups;
// If the framework dir doesn't exist, we fail.
const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.str());
- if (Dir == 0) return 0;
+ if (!Dir) return nullptr;
// Otherwise, if it does, remember that this is the right direntry for this
// framework.
CacheLookup.getValue().Directory = Dir;
}
- const FileEntry *FE = 0;
+ const FileEntry *FE = nullptr;
- if (RelativePath != NULL) {
+ if (RelativePath) {
RelativePath->clear();
RelativePath->append(Filename.begin()+SlashPos+1, Filename.end());
}
@@ -759,7 +884,7 @@ LookupSubframeworkHeader(StringRef Filename,
// Check ".../Frameworks/HIToolbox.framework/Headers/HIToolbox.h"
SmallString<1024> HeadersFilename(FrameworkName);
HeadersFilename += "Headers/";
- if (SearchPath != NULL) {
+ if (SearchPath) {
SearchPath->clear();
// Without trailing '/'.
SearchPath->append(HeadersFilename.begin(), HeadersFilename.end()-1);
@@ -771,7 +896,7 @@ LookupSubframeworkHeader(StringRef Filename,
// Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
HeadersFilename = FrameworkName;
HeadersFilename += "PrivateHeaders/";
- if (SearchPath != NULL) {
+ if (SearchPath) {
SearchPath->clear();
// Without trailing '/'.
SearchPath->append(HeadersFilename.begin(), HeadersFilename.end()-1);
@@ -779,7 +904,7 @@ LookupSubframeworkHeader(StringRef Filename,
HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
if (!(FE = FileMgr.getFile(HeadersFilename.str(), /*openFile=*/true)))
- return 0;
+ return nullptr;
}
// This file is a system header or C++ unfriendly if the old file is.
@@ -873,9 +998,21 @@ HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
HeaderFileInfo &HFI = FileInfo[FE->getUID()];
if (ExternalSource && !HFI.Resolved)
mergeHeaderFileInfo(HFI, ExternalSource->GetHeaderFileInfo(FE));
+ HFI.IsValid = 1;
return HFI;
}
+bool HeaderSearch::tryGetFileInfo(const FileEntry *FE, HeaderFileInfo &Result) const {
+ if (FE->getUID() >= FileInfo.size())
+ return false;
+ const HeaderFileInfo &HFI = FileInfo[FE->getUID()];
+ if (HFI.IsValid) {
+ Result = HFI;
+ return true;
+ }
+ return false;
+}
+
bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) {
// Check if we've ever seen this file as a header.
if (File->getUID() >= FileInfo.size())
@@ -953,6 +1090,9 @@ StringRef HeaderSearch::getUniqueFrameworkName(StringRef Framework) {
bool HeaderSearch::hasModuleMap(StringRef FileName,
const DirectoryEntry *Root,
bool IsSystem) {
+ if (!enabledModules())
+ return false;
+
SmallVector<const DirectoryEntry *, 2> FixUpDirectories;
StringRef DirName = FileName;
@@ -967,8 +1107,8 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
if (!Dir)
return false;
- // Try to load the "module.map" file in this directory.
- switch (loadModuleMapFile(Dir, IsSystem)) {
+ // Try to load the module map file in this directory.
+ switch (loadModuleMapFile(Dir, IsSystem, /*IsFramework*/false)) {
case LMM_NewlyLoaded:
case LMM_AlreadyLoaded:
// Success. All of the directories we stepped through inherit this module
@@ -1002,122 +1142,127 @@ HeaderSearch::findModuleForHeader(const FileEntry *File) const {
return ModMap.findModuleForHeader(File);
}
+static const FileEntry *getPrivateModuleMap(StringRef ModuleMapPath,
+ const DirectoryEntry *Directory,
+ FileManager &FileMgr) {
+ StringRef Filename = llvm::sys::path::filename(ModuleMapPath);
+ SmallString<128> PrivateFilename(Directory->getName());
+ if (Filename == "module.map")
+ llvm::sys::path::append(PrivateFilename, "module_private.map");
+ else if (Filename == "module.modulemap")
+ llvm::sys::path::append(PrivateFilename, "module.private.modulemap");
+ else
+ return nullptr;
+ return FileMgr.getFile(PrivateFilename);
+}
+
bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem) {
+ switch (loadModuleMapFileImpl(File, IsSystem)) {
+ case LMM_AlreadyLoaded:
+ case LMM_NewlyLoaded:
+ return false;
+ case LMM_NoDirectory:
+ case LMM_InvalidModuleMap:
+ return true;
+ }
+ llvm_unreachable("Unknown load module map result");
+}
+
+HeaderSearch::LoadModuleMapResult
+HeaderSearch::loadModuleMapFileImpl(const FileEntry *File, bool IsSystem) {
+ assert(File && "expected FileEntry");
+
const DirectoryEntry *Dir = File->getDir();
-
- llvm::DenseMap<const DirectoryEntry *, bool>::iterator KnownDir
- = DirectoryHasModuleMap.find(Dir);
+ auto KnownDir = DirectoryHasModuleMap.find(Dir);
if (KnownDir != DirectoryHasModuleMap.end())
- return !KnownDir->second;
-
- bool Result = ModMap.parseModuleMapFile(File, IsSystem);
- if (!Result && llvm::sys::path::filename(File->getName()) == "module.map") {
- // If the file we loaded was a module.map, look for the corresponding
- // module_private.map.
- SmallString<128> PrivateFilename(Dir->getName());
- llvm::sys::path::append(PrivateFilename, "module_private.map");
- if (const FileEntry *PrivateFile = FileMgr.getFile(PrivateFilename))
- Result = ModMap.parseModuleMapFile(PrivateFile, IsSystem);
+ return KnownDir->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
+
+ if (ModMap.parseModuleMapFile(File, IsSystem)) {
+ DirectoryHasModuleMap[Dir] = false;
+ return LMM_InvalidModuleMap;
}
-
- DirectoryHasModuleMap[Dir] = !Result;
- return Result;
+
+ // Try to load a corresponding private module map.
+ if (const FileEntry *PMMFile =
+ getPrivateModuleMap(File->getName(), Dir, FileMgr)) {
+ if (ModMap.parseModuleMapFile(PMMFile, IsSystem)) {
+ DirectoryHasModuleMap[Dir] = false;
+ return LMM_InvalidModuleMap;
+ }
+ }
+
+ // This directory has a module map.
+ DirectoryHasModuleMap[Dir] = true;
+ return LMM_NewlyLoaded;
}
-Module *HeaderSearch::loadFrameworkModule(StringRef Name,
+const FileEntry *
+HeaderSearch::lookupModuleMapFile(const DirectoryEntry *Dir, bool IsFramework) {
+ // For frameworks, the preferred spelling is Modules/module.modulemap, but
+ // module.map at the framework root is also accepted.
+ SmallString<128> ModuleMapFileName(Dir->getName());
+ if (IsFramework)
+ llvm::sys::path::append(ModuleMapFileName, "Modules");
+ llvm::sys::path::append(ModuleMapFileName, "module.modulemap");
+ if (const FileEntry *F = FileMgr.getFile(ModuleMapFileName))
+ return F;
+
+ // Continue to allow module.map
+ ModuleMapFileName = Dir->getName();
+ llvm::sys::path::append(ModuleMapFileName, "module.map");
+ return FileMgr.getFile(ModuleMapFileName);
+}
+
+Module *HeaderSearch::loadFrameworkModule(StringRef Name,
const DirectoryEntry *Dir,
bool IsSystem) {
if (Module *Module = ModMap.findModule(Name))
return Module;
// Try to load a module map file.
- switch (loadModuleMapFile(Dir, IsSystem)) {
+ switch (loadModuleMapFile(Dir, IsSystem, /*IsFramework*/true)) {
case LMM_InvalidModuleMap:
break;
case LMM_AlreadyLoaded:
case LMM_NoDirectory:
- return 0;
-
+ return nullptr;
+
case LMM_NewlyLoaded:
return ModMap.findModule(Name);
}
- // Figure out the top-level framework directory and the submodule path from
- // that top-level framework to the requested framework.
- SmallVector<std::string, 2> SubmodulePath;
- SubmodulePath.push_back(Name);
- const DirectoryEntry *TopFrameworkDir
- = ::getTopFrameworkDir(FileMgr, Dir->getName(), SubmodulePath);
-
-
- // Try to infer a module map from the top-level framework directory.
- Module *Result = ModMap.inferFrameworkModule(SubmodulePath.back(),
- TopFrameworkDir,
- IsSystem,
- /*Parent=*/0);
- if (!Result)
- return 0;
-
- // Follow the submodule path to find the requested (sub)framework module
- // within the top-level framework module.
- SubmodulePath.pop_back();
- while (!SubmodulePath.empty() && Result) {
- Result = ModMap.lookupModuleQualified(SubmodulePath.back(), Result);
- SubmodulePath.pop_back();
- }
- return Result;
+
+ // Try to infer a module map from the framework directory.
+ return ModMap.inferFrameworkModule(Name, Dir, IsSystem, /*Parent=*/nullptr);
}
HeaderSearch::LoadModuleMapResult
-HeaderSearch::loadModuleMapFile(StringRef DirName, bool IsSystem) {
+HeaderSearch::loadModuleMapFile(StringRef DirName, bool IsSystem,
+ bool IsFramework) {
if (const DirectoryEntry *Dir = FileMgr.getDirectory(DirName))
- return loadModuleMapFile(Dir, IsSystem);
+ return loadModuleMapFile(Dir, IsSystem, IsFramework);
return LMM_NoDirectory;
}
HeaderSearch::LoadModuleMapResult
-HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir, bool IsSystem) {
- llvm::DenseMap<const DirectoryEntry *, bool>::iterator KnownDir
- = DirectoryHasModuleMap.find(Dir);
+HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir, bool IsSystem,
+ bool IsFramework) {
+ auto KnownDir = DirectoryHasModuleMap.find(Dir);
if (KnownDir != DirectoryHasModuleMap.end())
return KnownDir->second? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
-
- SmallString<128> ModuleMapFileName;
- ModuleMapFileName += Dir->getName();
- unsigned ModuleMapDirNameLen = ModuleMapFileName.size();
- llvm::sys::path::append(ModuleMapFileName, "module.map");
- if (const FileEntry *ModuleMapFile = FileMgr.getFile(ModuleMapFileName)) {
- // We have found a module map file. Try to parse it.
- if (ModMap.parseModuleMapFile(ModuleMapFile, IsSystem)) {
- // No suitable module map.
- DirectoryHasModuleMap[Dir] = false;
- return LMM_InvalidModuleMap;
- }
- // This directory has a module map.
- DirectoryHasModuleMap[Dir] = true;
-
- // Check whether there is a private module map that we need to load as well.
- ModuleMapFileName.erase(ModuleMapFileName.begin() + ModuleMapDirNameLen,
- ModuleMapFileName.end());
- llvm::sys::path::append(ModuleMapFileName, "module_private.map");
- if (const FileEntry *PrivateModuleMapFile
- = FileMgr.getFile(ModuleMapFileName)) {
- if (ModMap.parseModuleMapFile(PrivateModuleMapFile, IsSystem)) {
- // No suitable module map.
- DirectoryHasModuleMap[Dir] = false;
- return LMM_InvalidModuleMap;
- }
- }
-
- return LMM_NewlyLoaded;
+ if (const FileEntry *ModuleMapFile = lookupModuleMapFile(Dir, IsFramework)) {
+ LoadModuleMapResult Result = loadModuleMapFileImpl(ModuleMapFile, IsSystem);
+ // Add Dir explicitly in case ModuleMapFile is in a subdirectory.
+ // E.g. Foo.framework/Modules/module.modulemap
+ // ^Dir ^ModuleMapFile
+ if (Result == LMM_NewlyLoaded)
+ DirectoryHasModuleMap[Dir] = true;
+ return Result;
}
-
- // No suitable module map.
- DirectoryHasModuleMap[Dir] = false;
return LMM_InvalidModuleMap;
}
@@ -1128,7 +1273,7 @@ void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
bool IsSystem = SearchDirs[Idx].isSystemHeaderDirectory();
if (SearchDirs[Idx].isFramework()) {
- llvm::error_code EC;
+ std::error_code EC;
SmallString<128> DirNative;
llvm::sys::path::native(SearchDirs[Idx].getFrameworkDir()->getName(),
DirNative);
@@ -1155,7 +1300,7 @@ void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
continue;
// Try to load a module map file for the search directory.
- loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem);
+ loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem, /*IsFramework*/false);
// Try to load module map files for immediate subdirectories of this search
// directory.
@@ -1180,20 +1325,22 @@ void HeaderSearch::loadTopLevelSystemModules() {
// Try to load a module map file for the search directory.
loadModuleMapFile(SearchDirs[Idx].getDir(),
- SearchDirs[Idx].isSystemHeaderDirectory());
+ SearchDirs[Idx].isSystemHeaderDirectory(),
+ SearchDirs[Idx].isFramework());
}
}
void HeaderSearch::loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir) {
if (SearchDir.haveSearchedAllModuleMaps())
return;
-
- llvm::error_code EC;
+
+ std::error_code EC;
SmallString<128> DirNative;
llvm::sys::path::native(SearchDir.getDir()->getName(), DirNative);
for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
- loadModuleMapFile(Dir->path(), SearchDir.isSystemHeaderDirectory());
+ loadModuleMapFile(Dir->path(), SearchDir.isSystemHeaderDirectory(),
+ SearchDir.isFramework());
}
SearchDir.setSearchedAllModuleMaps(true);
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index c071455da662..6f6b50b246d7 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -10,21 +10,9 @@
// This file implements the Lexer and Token interfaces.
//
//===----------------------------------------------------------------------===//
-//
-// TODO: GCC Diagnostics emitted by the lexer:
-// PEDWARN: (form feed|vertical tab) in preprocessing directive
-//
-// Universal characters, unicode, char mapping:
-// WARNING: `%.*s' is not in NFKC
-// WARNING: `%.*s' is not in NFC
-//
-// Other:
-// TODO: Options to support:
-// -fexec-charset,-fwide-exec-charset
-//
-//===----------------------------------------------------------------------===//
#include "clang/Lex/Lexer.h"
+#include "UnicodeCharSets.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/CodeCompletionHandler.h"
@@ -37,7 +25,6 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "UnicodeCharSets.h"
#include <cstring>
using namespace clang;
@@ -174,7 +161,7 @@ Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *FromFile,
/// 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
+/// TODO: It would really be nice to make _Pragma just be a wrapper around a
/// normal lexer that remaps tokens as they fly by. This would require making
/// Preprocessor::Lex virtual. Given that, we could just dump in a magic lexer
/// interface that could handle this stuff. This would pull GetMappedTokenLoc
@@ -379,10 +366,10 @@ unsigned Lexer::getSpelling(const Token &Tok, const char *&Buffer,
const LangOptions &LangOpts, bool *Invalid) {
assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
- const char *TokStart = 0;
+ const char *TokStart = nullptr;
// NOTE: this has to be checked *before* testing for an IdentifierInfo.
if (Tok.is(tok::raw_identifier))
- TokStart = Tok.getRawIdentifierData();
+ TokStart = Tok.getRawIdentifier().data();
else if (!Tok.hasUCN()) {
if (const IdentifierInfo *II = Tok.getIdentifierInfo()) {
// Just return the string from the identifier table, which is very quick.
@@ -395,7 +382,7 @@ unsigned Lexer::getSpelling(const Token &Tok, const char *&Buffer,
if (Tok.isLiteral())
TokStart = Tok.getLiteralData();
- if (TokStart == 0) {
+ if (!TokStart) {
// Compute the start of the token in the input lexer buffer.
bool CharDataInvalid = false;
TokStart = SourceMgr.getCharacterData(Tok.getLocation(), &CharDataInvalid);
@@ -637,8 +624,7 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer,
// the raw identifier to recognize and categorize preprocessor directives.
TheLexer.LexFromRawLexer(TheTok);
if (TheTok.getKind() == tok::raw_identifier && !TheTok.needsCleaning()) {
- StringRef Keyword(TheTok.getRawIdentifierData(),
- TheTok.getLength());
+ StringRef Keyword = TheTok.getRawIdentifier();
PreambleDirectiveKind PDK
= llvm::StringSwitch<PreambleDirectiveKind>(Keyword)
.Case("include", PDK_Skipped)
@@ -861,7 +847,7 @@ static CharSourceRange makeRangeFromFileLocs(CharSourceRange Range,
// Break down the source locations.
FileID FID;
unsigned BeginOffs;
- llvm::tie(FID, BeginOffs) = SM.getDecomposedLoc(Begin);
+ std::tie(FID, BeginOffs) = SM.getDecomposedLoc(Begin);
if (FID.isInvalid())
return CharSourceRange();
@@ -1287,7 +1273,7 @@ Slash:
if (Ptr[0] == '?' && Ptr[1] == '?') {
// If this is actually a legal trigraph (not something like "??x"), emit
// a trigraph warning. If so, and if trigraphs are enabled, return it.
- if (char C = DecodeTrigraphChar(Ptr+2, Tok ? this : 0)) {
+ if (char C = DecodeTrigraphChar(Ptr+2, Tok ? this : nullptr)) {
// Remember that this token needs to be cleaned.
if (Tok) Tok->setFlag(Token::NeedsCleaning);
@@ -1413,8 +1399,7 @@ static inline CharSourceRange makeCharRange(Lexer &L, const char *Begin,
static void maybeDiagnoseIDCharCompat(DiagnosticsEngine &Diags, uint32_t C,
CharSourceRange Range, bool IsFirst) {
// Check C99 compatibility.
- if (Diags.getDiagnosticLevel(diag::warn_c99_compat_unicode_id,
- Range.getBegin()) > DiagnosticsEngine::Ignored) {
+ if (!Diags.isIgnored(diag::warn_c99_compat_unicode_id, Range.getBegin())) {
enum {
CannotAppearInIdentifier = 0,
CannotStartIdentifier
@@ -1436,8 +1421,7 @@ static void maybeDiagnoseIDCharCompat(DiagnosticsEngine &Diags, uint32_t C,
}
// Check C++98 compatibility.
- if (Diags.getDiagnosticLevel(diag::warn_cxx98_compat_unicode_id,
- Range.getBegin()) > DiagnosticsEngine::Ignored) {
+ if (!Diags.isIgnored(diag::warn_cxx98_compat_unicode_id, Range.getBegin())) {
static const llvm::sys::UnicodeCharSet CXX03AllowedIDChars(
CXX03AllowedIDCharRanges);
if (!CXX03AllowedIDChars.contains(C)) {
@@ -1445,7 +1429,50 @@ static void maybeDiagnoseIDCharCompat(DiagnosticsEngine &Diags, uint32_t C,
<< Range;
}
}
- }
+}
+
+bool Lexer::tryConsumeIdentifierUCN(const char *&CurPtr, unsigned Size,
+ Token &Result) {
+ const char *UCNPtr = CurPtr + Size;
+ uint32_t CodePoint = tryReadUCN(UCNPtr, CurPtr, /*Token=*/nullptr);
+ if (CodePoint == 0 || !isAllowedIDChar(CodePoint, LangOpts))
+ return false;
+
+ if (!isLexingRawMode())
+ maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint,
+ makeCharRange(*this, CurPtr, UCNPtr),
+ /*IsFirst=*/false);
+
+ Result.setFlag(Token::HasUCN);
+ if ((UCNPtr - CurPtr == 6 && CurPtr[1] == 'u') ||
+ (UCNPtr - CurPtr == 10 && CurPtr[1] == 'U'))
+ CurPtr = UCNPtr;
+ else
+ while (CurPtr != UCNPtr)
+ (void)getAndAdvanceChar(CurPtr, Result);
+ return true;
+}
+
+bool Lexer::tryConsumeIdentifierUTF8Char(const char *&CurPtr) {
+ const char *UnicodePtr = CurPtr;
+ UTF32 CodePoint;
+ ConversionResult Result =
+ llvm::convertUTF8Sequence((const UTF8 **)&UnicodePtr,
+ (const UTF8 *)BufferEnd,
+ &CodePoint,
+ strictConversion);
+ if (Result != conversionOK ||
+ !isAllowedIDChar(static_cast<uint32_t>(CodePoint), LangOpts))
+ return false;
+
+ if (!isLexingRawMode())
+ maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint,
+ makeCharRange(*this, CurPtr, UnicodePtr),
+ /*IsFirst=*/false);
+
+ CurPtr = UnicodePtr;
+ return true;
+}
bool Lexer::LexIdentifier(Token &Result, const char *CurPtr) {
// Match [_A-Za-z0-9]*, we have already matched [_A-Za-z$]
@@ -1500,47 +1527,10 @@ FinishIdentifier:
C = getCharAndSize(CurPtr, Size);
continue;
- } else if (C == '\\') {
- const char *UCNPtr = CurPtr + Size;
- uint32_t CodePoint = tryReadUCN(UCNPtr, CurPtr, /*Token=*/0);
- if (CodePoint == 0 || !isAllowedIDChar(CodePoint, LangOpts))
- goto FinishIdentifier;
-
- if (!isLexingRawMode()) {
- maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint,
- makeCharRange(*this, CurPtr, UCNPtr),
- /*IsFirst=*/false);
- }
-
- Result.setFlag(Token::HasUCN);
- if ((UCNPtr - CurPtr == 6 && CurPtr[1] == 'u') ||
- (UCNPtr - CurPtr == 10 && CurPtr[1] == 'U'))
- CurPtr = UCNPtr;
- else
- while (CurPtr != UCNPtr)
- (void)getAndAdvanceChar(CurPtr, Result);
-
+ } else if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) {
C = getCharAndSize(CurPtr, Size);
continue;
- } else if (!isASCII(C)) {
- const char *UnicodePtr = CurPtr;
- UTF32 CodePoint;
- ConversionResult Result =
- llvm::convertUTF8Sequence((const UTF8 **)&UnicodePtr,
- (const UTF8 *)BufferEnd,
- &CodePoint,
- strictConversion);
- if (Result != conversionOK ||
- !isAllowedIDChar(static_cast<uint32_t>(CodePoint), LangOpts))
- goto FinishIdentifier;
-
- if (!isLexingRawMode()) {
- maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint,
- makeCharRange(*this, CurPtr, UnicodePtr),
- /*IsFirst=*/false);
- }
-
- CurPtr = UnicodePtr;
+ } else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) {
C = getCharAndSize(CurPtr, Size);
continue;
} else if (!isIdentifierBody(C)) {
@@ -1576,7 +1566,7 @@ bool Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
unsigned Size;
char C = getCharAndSize(CurPtr, Size);
char PrevCh = 0;
- while (isPreprocessingNumberBody(C)) { // FIXME: UCNs in ud-suffix.
+ while (isPreprocessingNumberBody(C)) {
CurPtr = ConsumeChar(CurPtr, Size, Result);
PrevCh = C;
C = getCharAndSize(CurPtr, Size);
@@ -1614,10 +1604,17 @@ bool Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
if (!isLexingRawMode())
Diag(CurPtr, diag::warn_cxx11_compat_digit_separator);
CurPtr = ConsumeChar(CurPtr, Size, Result);
+ CurPtr = ConsumeChar(CurPtr, NextSize, Result);
return LexNumericConstant(Result, CurPtr);
}
}
+ // If we have a UCN or UTF-8 character (perhaps in a ud-suffix), continue.
+ if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result))
+ return LexNumericConstant(Result, CurPtr);
+ if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr))
+ return LexNumericConstant(Result, CurPtr);
+
// Update the location of token as well as BufferPtr.
const char *TokStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, tok::numeric_constant);
@@ -1631,23 +1628,35 @@ const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr,
bool IsStringLiteral) {
assert(getLangOpts().CPlusPlus);
- // Maximally munch an identifier. FIXME: UCNs.
+ // Maximally munch an identifier.
unsigned Size;
char C = getCharAndSize(CurPtr, Size);
- if (isIdentifierHead(C)) {
- if (!getLangOpts().CPlusPlus11) {
- if (!isLexingRawMode())
- Diag(CurPtr,
- C == '_' ? diag::warn_cxx11_compat_user_defined_literal
- : diag::warn_cxx11_compat_reserved_user_defined_literal)
- << FixItHint::CreateInsertion(getSourceLocation(CurPtr), " ");
+ bool Consumed = false;
+
+ if (!isIdentifierHead(C)) {
+ if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result))
+ Consumed = true;
+ else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr))
+ Consumed = true;
+ else
return CurPtr;
- }
+ }
- // C++11 [lex.ext]p10, [usrlit.suffix]p1: A program containing a ud-suffix
- // that does not start with an underscore is ill-formed. As a conforming
- // extension, we treat all such suffixes as if they had whitespace before
- // them.
+ if (!getLangOpts().CPlusPlus11) {
+ if (!isLexingRawMode())
+ Diag(CurPtr,
+ C == '_' ? diag::warn_cxx11_compat_user_defined_literal
+ : diag::warn_cxx11_compat_reserved_user_defined_literal)
+ << FixItHint::CreateInsertion(getSourceLocation(CurPtr), " ");
+ return CurPtr;
+ }
+
+ // C++11 [lex.ext]p10, [usrlit.suffix]p1: A program containing a ud-suffix
+ // that does not start with an underscore is ill-formed. As a conforming
+ // extension, we treat all such suffixes as if they had whitespace before
+ // them. We assume a suffix beginning with a UCN or UTF-8 character is more
+ // likely to be a ud-suffix than a macro, however, and accept that.
+ if (!Consumed) {
bool IsUDSuffix = false;
if (C == '_')
IsUDSuffix = true;
@@ -1682,19 +1691,25 @@ const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr,
if (!IsUDSuffix) {
if (!isLexingRawMode())
- Diag(CurPtr, getLangOpts().MicrosoftMode ?
- diag::ext_ms_reserved_user_defined_literal :
- diag::ext_reserved_user_defined_literal)
+ Diag(CurPtr, getLangOpts().MSVCCompat
+ ? diag::ext_ms_reserved_user_defined_literal
+ : diag::ext_reserved_user_defined_literal)
<< FixItHint::CreateInsertion(getSourceLocation(CurPtr), " ");
return CurPtr;
}
- Result.setFlag(Token::HasUDSuffix);
- do {
- CurPtr = ConsumeChar(CurPtr, Size, Result);
- C = getCharAndSize(CurPtr, Size);
- } while (isIdentifierBody(C));
+ CurPtr = ConsumeChar(CurPtr, Size, Result);
+ }
+
+ Result.setFlag(Token::HasUDSuffix);
+ while (true) {
+ C = getCharAndSize(CurPtr, Size);
+ if (isIdentifierBody(C)) { CurPtr = ConsumeChar(CurPtr, Size, Result); }
+ else if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) {}
+ else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) {}
+ else break;
}
+
return CurPtr;
}
@@ -1702,7 +1717,8 @@ const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr,
/// either " or L" or u8" or u" or U".
bool Lexer::LexStringLiteral(Token &Result, const char *CurPtr,
tok::TokenKind Kind) {
- const char *NulCharacter = 0; // Does this string contain the \0 character?
+ // Does this string contain the \0 character?
+ const char *NulCharacter = nullptr;
if (!isLexingRawMode() &&
(Kind == tok::utf8_string_literal ||
@@ -1838,7 +1854,8 @@ bool Lexer::LexRawStringLiteral(Token &Result, const char *CurPtr,
/// LexAngledStringLiteral - Lex the remainder of an angled string literal,
/// after having lexed the '<' character. This is used for #include filenames.
bool Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) {
- const char *NulCharacter = 0; // Does this string contain the \0 character?
+ // Does this string contain the \0 character?
+ const char *NulCharacter = nullptr;
const char *AfterLessPos = CurPtr;
char C = getAndAdvanceChar(CurPtr, Result);
while (C != '>') {
@@ -1875,7 +1892,8 @@ bool Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) {
/// lexed either ' or L' or u' or U'.
bool Lexer::LexCharConstant(Token &Result, const char *CurPtr,
tok::TokenKind Kind) {
- const char *NulCharacter = 0; // Does this character contain the \0 character?
+ // Does this character contain the \0 character?
+ const char *NulCharacter = nullptr;
if (!isLexingRawMode() &&
(Kind == tok::utf16_char_constant || Kind == tok::utf32_char_constant))
@@ -2023,8 +2041,11 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
if (C != 0) {
// We found a newline, see if it's escaped.
const char *EscapePtr = CurPtr-1;
- while (isHorizontalWhitespace(*EscapePtr)) // Skip whitespace.
+ bool HasSpace = false;
+ while (isHorizontalWhitespace(*EscapePtr)) { // Skip whitespace.
--EscapePtr;
+ HasSpace = true;
+ }
if (*EscapePtr == '\\') // Escaped newline.
CurPtr = EscapePtr;
@@ -2033,6 +2054,10 @@ bool Lexer::SkipLineComment(Token &Result, const char *CurPtr,
CurPtr = EscapePtr-2;
else
break; // This is a newline, we're done.
+
+ // If there was space between the backslash and newline, warn about it.
+ if (HasSpace && !isLexingRawMode())
+ Diag(EscapePtr, diag::backslash_newline_space);
}
// Otherwise, this is a hard case. Fall back on getAndAdvanceChar to
@@ -2460,7 +2485,8 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
FormTokenWithChars(Result, CurPtr, tok::eod);
// Restore comment saving mode, in case it was disabled for directive.
- resetExtendedTokenMode();
+ if (PP)
+ resetExtendedTokenMode();
return true; // Have a token.
}
@@ -2494,8 +2520,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
// C++11 [lex.phases] 2.2 p2
// Prefer the C++98 pedantic compatibility warning over the generic,
// non-extension, user-requested "missing newline at EOF" warning.
- if (Diags.getDiagnosticLevel(diag::warn_cxx98_compat_no_newline_eof,
- EndLoc) != DiagnosticsEngine::Ignored) {
+ if (!Diags.isIgnored(diag::warn_cxx98_compat_no_newline_eof, EndLoc)) {
DiagID = diag::warn_cxx98_compat_no_newline_eof;
} else {
DiagID = diag::warn_no_newline_eof;
@@ -2568,7 +2593,7 @@ static const char *FindConflictEnd(const char *CurPtr, const char *BufferEnd,
}
return RestOfBuffer.data()+Pos;
}
- return 0;
+ return nullptr;
}
/// IsStartOfConflictMarker - If the specified pointer is the start of a version
@@ -2878,7 +2903,7 @@ bool Lexer::LexTokenInternal(Token &Result, bool TokAtPhysicalStartOfLine) {
LexNextToken:
// New token, can't need cleaning yet.
Result.clearFlag(Token::NeedsCleaning);
- Result.setIdentifierInfo(0);
+ Result.setIdentifierInfo(nullptr);
// CurPtr - Cache BufferPtr in an automatic variable.
const char *CurPtr = BufferPtr;
@@ -3344,7 +3369,7 @@ LexNextToken:
// We parsed a # character. If this occurs at the start of the line,
// it's actually the start of a preprocessing directive. Callback to
// the preprocessor to handle it.
- // FIXME: -fpreprocessed mode??
+ // TODO: -fpreprocessed mode??
if (TokAtPhysicalStartOfLine && !LexingRawMode && !Is_PragmaLexer)
goto HandleDirective;
@@ -3510,7 +3535,7 @@ LexNextToken:
// We parsed a # character. If this occurs at the start of the line,
// it's actually the start of a preprocessing directive. Callback to
// the preprocessor to handle it.
- // FIXME: -fpreprocessed mode??
+ // TODO: -fpreprocessed mode??
if (TokAtPhysicalStartOfLine && !LexingRawMode && !Is_PragmaLexer)
goto HandleDirective;
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 17c6bb3049bc..6417d0f0f5f2 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -195,7 +195,7 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin,
<< std::string(1, ResultChar);
break;
default:
- if (Diags == 0)
+ if (!Diags)
break;
if (isPrintable(ResultChar))
@@ -212,6 +212,48 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin,
return ResultChar;
}
+static void appendCodePoint(unsigned Codepoint,
+ llvm::SmallVectorImpl<char> &Str) {
+ char ResultBuf[4];
+ char *ResultPtr = ResultBuf;
+ bool Res = llvm::ConvertCodePointToUTF8(Codepoint, ResultPtr);
+ (void)Res;
+ assert(Res && "Unexpected conversion failure");
+ Str.append(ResultBuf, ResultPtr);
+}
+
+void clang::expandUCNs(SmallVectorImpl<char> &Buf, StringRef Input) {
+ for (StringRef::iterator I = Input.begin(), E = Input.end(); I != E; ++I) {
+ if (*I != '\\') {
+ Buf.push_back(*I);
+ continue;
+ }
+
+ ++I;
+ assert(*I == 'u' || *I == 'U');
+
+ unsigned NumHexDigits;
+ if (*I == 'u')
+ NumHexDigits = 4;
+ else
+ NumHexDigits = 8;
+
+ assert(I + NumHexDigits <= E);
+
+ uint32_t CodePoint = 0;
+ for (++I; NumHexDigits != 0; ++I, --NumHexDigits) {
+ unsigned Value = llvm::hexDigitValue(*I);
+ assert(Value != -1U);
+
+ CodePoint <<= 4;
+ CodePoint += Value;
+ }
+
+ appendCodePoint(CodePoint, Buf);
+ --I;
+ }
+}
+
/// ProcessUCNEscape - Read the Universal Character Name, check constraints and
/// return the UTF32.
static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
@@ -298,7 +340,7 @@ static int MeasureUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
FullSourceLoc Loc;
if (!ProcessUCNEscape(ThisTokBegin, ThisTokBuf, ThisTokEnd, UcnVal,
- UcnLen, Loc, 0, Features, true)) {
+ UcnLen, Loc, nullptr, Features, true)) {
HadError = true;
return 0;
}
@@ -480,7 +522,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
isLongLong = false;
isFloat = false;
isImaginary = false;
- isMicrosoftInteger = false;
+ MicrosoftInteger = 0;
hadError = false;
if (*s == '0') { // parse radix
@@ -529,7 +571,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
// Parse the suffix. At this point we can classify whether we have an FP or
// integer constant.
bool isFPConstant = isFloatingLiteral();
- const char *ImaginarySuffixLoc = 0;
+ const char *ImaginarySuffixLoc = nullptr;
// Loop over all of the characters of the suffix. If we see something bad,
// we break out of the loop.
@@ -564,49 +606,53 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
case 'i':
case 'I':
if (PP.getLangOpts().MicrosoftExt) {
- if (isFPConstant || isLong || isLongLong) break;
+ if (isLong || isLongLong || MicrosoftInteger)
+ break;
// Allow i8, i16, i32, i64, and i128.
if (s + 1 != ThisTokEnd) {
switch (s[1]) {
case '8':
+ if (isFPConstant) break;
s += 2; // i8 suffix
- isMicrosoftInteger = true;
+ MicrosoftInteger = 8;
break;
case '1':
+ if (isFPConstant) break;
if (s + 2 == ThisTokEnd) break;
if (s[2] == '6') {
s += 3; // i16 suffix
- isMicrosoftInteger = true;
+ MicrosoftInteger = 16;
}
else if (s[2] == '2') {
if (s + 3 == ThisTokEnd) break;
if (s[3] == '8') {
s += 4; // i128 suffix
- isMicrosoftInteger = true;
+ MicrosoftInteger = 128;
}
}
break;
case '3':
+ if (isFPConstant) break;
if (s + 2 == ThisTokEnd) break;
if (s[2] == '2') {
s += 3; // i32 suffix
- isLong = true;
- isMicrosoftInteger = true;
+ MicrosoftInteger = 32;
}
break;
case '6':
+ if (isFPConstant) break;
if (s + 2 == ThisTokEnd) break;
if (s[2] == '4') {
s += 3; // i64 suffix
- isLongLong = true;
- isMicrosoftInteger = true;
+ MicrosoftInteger = 64;
}
break;
default:
break;
}
- break;
+ if (MicrosoftInteger)
+ break;
}
}
// "i", "if", and "il" are user-defined suffixes in C++1y.
@@ -625,8 +671,9 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
}
if (s != ThisTokEnd) {
- if (isValidUDSuffix(PP.getLangOpts(),
- StringRef(SuffixBegin, ThisTokEnd - SuffixBegin))) {
+ // FIXME: Don't bother expanding UCNs if !tok.hasUCN().
+ expandUCNs(UDSuffixBuf, StringRef(SuffixBegin, ThisTokEnd - SuffixBegin));
+ if (isValidUDSuffix(PP.getLangOpts(), UDSuffixBuf)) {
// Any suffix pieces we might have parsed are actually part of the
// ud-suffix.
isLong = false;
@@ -634,7 +681,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
isLongLong = false;
isFloat = false;
isImaginary = false;
- isMicrosoftInteger = false;
+ MicrosoftInteger = 0;
saw_ud_suffix = true;
return;
@@ -722,6 +769,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
s++;
saw_period = true;
const char *floatDigitsBegin = s;
+ checkSeparator(TokLoc, s, CSK_BeforeDigits);
s = SkipHexDigits(s);
noSignificand &= (floatDigitsBegin == s);
}
@@ -736,6 +784,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
// A binary exponent can appear with or with a '.'. If dotted, the
// binary exponent is required.
if (*s == 'p' || *s == 'P') {
+ checkSeparator(TokLoc, s, CSK_AfterDigits);
const char *Exponent = s;
s++;
saw_exponent = true;
@@ -747,6 +796,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
hadError = true;
return;
}
+ checkSeparator(TokLoc, s, CSK_BeforeDigits);
s = first_non_digit;
if (!PP.getLangOpts().HexFloats)
@@ -815,9 +865,11 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
s++;
radix = 10;
saw_period = true;
+ checkSeparator(TokLoc, s, CSK_BeforeDigits);
s = SkipDigits(s); // Skip suffix.
}
if (*s == 'e' || *s == 'E') { // exponent
+ checkSeparator(TokLoc, s, CSK_AfterDigits);
const char *Exponent = s;
s++;
radix = 10;
@@ -825,6 +877,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
if (*s == '+' || *s == '-') s++; // sign
const char *first_non_digit = SkipDigits(s);
if (first_non_digit != s) {
+ checkSeparator(TokLoc, s, CSK_BeforeDigits);
s = first_non_digit;
} else {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, Exponent-ThisTokBegin),
@@ -992,7 +1045,8 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
do {
--end;
} while (end[-1] != '\'');
- UDSuffixBuf.assign(end, UDSuffixEnd);
+ // FIXME: Don't bother with this if !tok.hasUCN().
+ expandUCNs(UDSuffixBuf, StringRef(end, UDSuffixEnd - end));
UDSuffixOffset = end - TokBegin;
}
@@ -1201,26 +1255,26 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end,
/// \endverbatim
///
StringLiteralParser::
-StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
+StringLiteralParser(ArrayRef<Token> StringToks,
Preprocessor &PP, bool Complain)
: SM(PP.getSourceManager()), Features(PP.getLangOpts()),
- Target(PP.getTargetInfo()), Diags(Complain ? &PP.getDiagnostics() : 0),
+ Target(PP.getTargetInfo()), Diags(Complain ? &PP.getDiagnostics() :nullptr),
MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown),
ResultPtr(ResultBuf.data()), hadError(false), Pascal(false) {
- init(StringToks, NumStringToks);
+ init(StringToks);
}
-void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
+void StringLiteralParser::init(ArrayRef<Token> StringToks){
// The literal token may have come from an invalid source location (e.g. due
// to a PCH error), in which case the token length will be 0.
- if (NumStringToks == 0 || StringToks[0].getLength() < 2)
+ if (StringToks.empty() || StringToks[0].getLength() < 2)
return DiagnoseLexingError(SourceLocation());
// Scan all of the string portions, remember the max individual token length,
// computing a bound on the concatenated string length, and see whether any
// piece is a wide-string. If any of the string portions is a wide-string
// literal, the result is a wide-string literal [C99 6.4.5p4].
- assert(NumStringToks && "expected at least one token");
+ assert(!StringToks.empty() && "expected at least one token");
MaxTokenLength = StringToks[0].getLength();
assert(StringToks[0].getLength() >= 2 && "literal token is invalid!");
SizeBound = StringToks[0].getLength()-2; // -2 for "".
@@ -1230,7 +1284,7 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
// Implement Translation Phase #6: concatenation of string literals
/// (C99 5.1.1.2p1). The common case is only one string fragment.
- for (unsigned i = 1; i != NumStringToks; ++i) {
+ for (unsigned i = 1; i != StringToks.size(); ++i) {
if (StringToks[i].getLength() < 2)
return DiagnoseLexingError(StringToks[i].getLocation());
@@ -1286,7 +1340,7 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
SourceLocation UDSuffixTokLoc;
- for (unsigned i = 0, e = NumStringToks; i != e; ++i) {
+ for (unsigned i = 0, e = StringToks.size(); i != e; ++i) {
const char *ThisTokBuf = &TokenBuf[0];
// Get the spelling of the token, which eliminates trigraphs, etc. We know
// that ThisTokBuf points to a buffer that is big enough for the whole token
@@ -1311,23 +1365,34 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
StringRef UDSuffix(ThisTokEnd, UDSuffixEnd - ThisTokEnd);
if (UDSuffixBuf.empty()) {
- UDSuffixBuf.assign(UDSuffix);
+ if (StringToks[i].hasUCN())
+ expandUCNs(UDSuffixBuf, UDSuffix);
+ else
+ UDSuffixBuf.assign(UDSuffix);
UDSuffixToken = i;
UDSuffixOffset = ThisTokEnd - ThisTokBuf;
UDSuffixTokLoc = StringToks[i].getLocation();
- } else if (!UDSuffixBuf.equals(UDSuffix)) {
+ } else {
+ SmallString<32> ExpandedUDSuffix;
+ if (StringToks[i].hasUCN()) {
+ expandUCNs(ExpandedUDSuffix, UDSuffix);
+ UDSuffix = ExpandedUDSuffix;
+ }
+
// C++11 [lex.ext]p8: At the end of phase 6, if a string literal is the
// result of a concatenation involving at least one user-defined-string-
// literal, all the participating user-defined-string-literals shall
// have the same ud-suffix.
- if (Diags) {
- SourceLocation TokLoc = StringToks[i].getLocation();
- Diags->Report(TokLoc, diag::err_string_concat_mixed_suffix)
- << UDSuffixBuf << UDSuffix
- << SourceRange(UDSuffixTokLoc, UDSuffixTokLoc)
- << SourceRange(TokLoc, TokLoc);
+ if (UDSuffixBuf != UDSuffix) {
+ if (Diags) {
+ SourceLocation TokLoc = StringToks[i].getLocation();
+ Diags->Report(TokLoc, diag::err_string_concat_mixed_suffix)
+ << UDSuffixBuf << UDSuffix
+ << SourceRange(UDSuffixTokLoc, UDSuffixTokLoc)
+ << SourceRange(TokLoc, TokLoc);
+ }
+ hadError = true;
}
- hadError = true;
}
}
@@ -1449,10 +1514,10 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
// Verify that pascal strings aren't too large.
if (GetStringLength() > 256) {
if (Diags)
- Diags->Report(StringToks[0].getLocation(),
+ Diags->Report(StringToks.front().getLocation(),
diag::err_pascal_string_too_long)
- << SourceRange(StringToks[0].getLocation(),
- StringToks[NumStringToks-1].getLocation());
+ << SourceRange(StringToks.front().getLocation(),
+ StringToks.back().getLocation());
hadError = true;
return;
}
@@ -1461,12 +1526,12 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
unsigned MaxChars = Features.CPlusPlus? 65536 : Features.C99 ? 4095 : 509;
if (GetNumStringChars() > MaxChars)
- Diags->Report(StringToks[0].getLocation(),
+ Diags->Report(StringToks.front().getLocation(),
diag::ext_string_too_long)
<< GetNumStringChars() << MaxChars
<< (Features.CPlusPlus ? 2 : Features.C99 ? 1 : 0)
- << SourceRange(StringToks[0].getLocation(),
- StringToks[NumStringToks-1].getLocation());
+ << SourceRange(StringToks.front().getLocation(),
+ StringToks.back().getLocation());
}
}
@@ -1516,8 +1581,7 @@ bool StringLiteralParser::CopyStringFragment(const Token &Tok,
Dummy.reserve(Fragment.size() * CharByteWidth);
char *Ptr = Dummy.data();
- while (!Builder.hasMaxRanges() &&
- !ConvertUTF8toWide(CharByteWidth, NextFragment, Ptr, ErrorPtrTmp)) {
+ while (!ConvertUTF8toWide(CharByteWidth, NextFragment, Ptr, ErrorPtrTmp)) {
const char *ErrorPtr = reinterpret_cast<const char *>(ErrorPtrTmp);
NextStart = resyncUTF8(ErrorPtr, Fragment.end());
Builder << MakeCharSourceRange(Features, SourceLoc, TokBegin,
diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp
index d2dc04b36cf7..a746fb7f48bf 100644
--- a/lib/Lex/MacroArgs.cpp
+++ b/lib/Lex/MacroArgs.cpp
@@ -1,4 +1,4 @@
-//===--- TokenLexer.cpp - Lex from a token stream -------------------------===//
+//===--- MacroArgs.cpp - Formal argument info for Macros ------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the TokenLexer interface.
+// This file implements the MacroArgs interface.
//
//===----------------------------------------------------------------------===//
@@ -27,7 +27,7 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI,
bool VarargsElided, Preprocessor &PP) {
assert(MI->isFunctionLike() &&
"Can't have args for an object-like macro!");
- MacroArgs **ResultEnt = 0;
+ MacroArgs **ResultEnt = nullptr;
unsigned ClosestMatch = ~0U;
// See if we have an entry with a big enough argument list to reuse on the
@@ -46,7 +46,7 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI,
}
MacroArgs *Result;
- if (ResultEnt == 0) {
+ if (!ResultEnt) {
// Allocate memory for a MacroArgs object with the lexer tokens at the end.
Result = (MacroArgs*)malloc(sizeof(MacroArgs) +
UnexpArgTokens.size() * sizeof(Token));
diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp
index b61ff71d1767..5416886cc9f7 100644
--- a/lib/Lex/MacroInfo.cpp
+++ b/lib/Lex/MacroInfo.cpp
@@ -17,7 +17,7 @@ using namespace clang;
MacroInfo::MacroInfo(SourceLocation DefLoc)
: Location(DefLoc),
- ArgumentList(0),
+ ArgumentList(nullptr),
NumArguments(0),
IsDefinitionLengthCached(false),
IsFunctionLike(false),
@@ -29,7 +29,8 @@ MacroInfo::MacroInfo(SourceLocation DefLoc)
IsUsed(false),
IsAllowRedefinitionsWithoutWarning(false),
IsWarnIfUnused(false),
- FromASTFile(false) {
+ FromASTFile(false),
+ UsedForHeaderGuard(false) {
}
unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const {
@@ -125,14 +126,54 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP,
return true;
}
-MacroDirective::DefInfo MacroDirective::getDefinition(bool AllowHidden) {
+void MacroInfo::dump() const {
+ llvm::raw_ostream &Out = llvm::errs();
+
+ // FIXME: Dump locations.
+ Out << "MacroInfo " << this;
+ if (IsBuiltinMacro) Out << " builtin";
+ if (IsDisabled) Out << " disabled";
+ if (IsUsed) Out << " used";
+ if (IsAllowRedefinitionsWithoutWarning)
+ Out << " allow_redefinitions_without_warning";
+ if (IsWarnIfUnused) Out << " warn_if_unused";
+ if (FromASTFile) Out << " imported";
+ if (UsedForHeaderGuard) Out << " header_guard";
+
+ Out << "\n #define <macro>";
+ if (IsFunctionLike) {
+ Out << "(";
+ for (unsigned I = 0; I != NumArguments; ++I) {
+ if (I) Out << ", ";
+ Out << ArgumentList[I]->getName();
+ }
+ if (IsC99Varargs || IsGNUVarargs) {
+ if (NumArguments && IsC99Varargs) Out << ", ";
+ Out << "...";
+ }
+ Out << ")";
+ }
+
+ for (const Token &Tok : ReplacementTokens) {
+ Out << " ";
+ if (const char *Punc = tok::getPunctuatorSpelling(Tok.getKind()))
+ Out << Punc;
+ else if (const char *Kwd = tok::getKeywordSpelling(Tok.getKind()))
+ Out << Kwd;
+ else if (Tok.is(tok::identifier))
+ Out << Tok.getIdentifierInfo()->getName();
+ else if (Tok.isLiteral() && Tok.getLiteralData())
+ Out << StringRef(Tok.getLiteralData(), Tok.getLength());
+ else
+ Out << Tok.getName();
+ }
+}
+
+MacroDirective::DefInfo MacroDirective::getDefinition() {
MacroDirective *MD = this;
SourceLocation UndefLoc;
Optional<bool> isPublic;
for (; MD; MD = MD->getPrevious()) {
- if (!AllowHidden && MD->isHidden())
- continue;
-
if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD))
return DefInfo(DefMD, UndefLoc,
!isPublic.hasValue() || isPublic.getValue());
@@ -147,7 +188,8 @@ MacroDirective::DefInfo MacroDirective::getDefinition(bool AllowHidden) {
isPublic = VisMD->isPublic();
}
- return DefInfo();
+ return DefInfo(nullptr, UndefLoc,
+ !isPublic.hasValue() || isPublic.getValue());
}
const MacroDirective::DefInfo
@@ -162,3 +204,33 @@ MacroDirective::findDirectiveAtLoc(SourceLocation L, SourceManager &SM) const {
}
return DefInfo();
}
+
+void MacroDirective::dump() const {
+ llvm::raw_ostream &Out = llvm::errs();
+
+ switch (getKind()) {
+ case MD_Define: Out << "DefMacroDirective"; break;
+ case MD_Undefine: Out << "UndefMacroDirective"; break;
+ case MD_Visibility: Out << "VisibilityMacroDirective"; break;
+ }
+ Out << " " << this;
+ // FIXME: Dump SourceLocation.
+ if (auto *Prev = getPrevious())
+ Out << " prev " << Prev;
+ if (IsFromPCH) Out << " from_pch";
+ if (IsImported) Out << " imported";
+ if (IsAmbiguous) Out << " ambiguous";
+
+ if (IsPublic)
+ Out << " public";
+ else if (isa<VisibilityMacroDirective>(this))
+ Out << " private";
+
+ if (auto *DMD = dyn_cast<DefMacroDirective>(this)) {
+ if (auto *Info = DMD->getInfo()) {
+ Out << "\n ";
+ Info->dump();
+ }
+ }
+ Out << "\n";
+}
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index f4dfa12854a3..8fae9c933d33 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -42,7 +42,7 @@ ModuleMap::resolveExport(Module *Mod,
// We may have just a wildcard.
if (Unresolved.Id.empty()) {
assert(Unresolved.Wildcard && "Invalid unresolved export");
- return Module::ExportDecl(0, true);
+ return Module::ExportDecl(nullptr, true);
}
// Resolve the module-id.
@@ -59,10 +59,10 @@ Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod,
Module *Context = lookupModuleUnqualified(Id[0].first, Mod);
if (!Context) {
if (Complain)
- Diags->Report(Id[0].second, diag::err_mmap_missing_module_unqualified)
+ Diags.Report(Id[0].second, diag::err_mmap_missing_module_unqualified)
<< Id[0].first << Mod->getFullModuleName();
- return 0;
+ return nullptr;
}
// Dig into the module path.
@@ -70,11 +70,11 @@ Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod,
Module *Sub = lookupModuleQualified(Id[I].first, Context);
if (!Sub) {
if (Complain)
- Diags->Report(Id[I].second, diag::err_mmap_missing_module_qualified)
+ Diags.Report(Id[I].second, diag::err_mmap_missing_module_qualified)
<< Id[I].first << Context->getFullModuleName()
<< SourceRange(Id[0].second, Id[I-1].second);
- return 0;
+ return nullptr;
}
Context = Sub;
@@ -83,19 +83,12 @@ Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod,
return Context;
}
-ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticConsumer &DC,
+ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticsEngine &Diags,
const LangOptions &LangOpts, const TargetInfo *Target,
HeaderSearch &HeaderInfo)
- : SourceMgr(SourceMgr), LangOpts(LangOpts), Target(Target),
- HeaderInfo(HeaderInfo), BuiltinIncludeDir(0), CompilingModule(0),
- SourceModule(0) {
- IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs);
- Diags = IntrusiveRefCntPtr<DiagnosticsEngine>(
- new DiagnosticsEngine(DiagIDs, new DiagnosticOptions));
- Diags->setClient(new ForwardingDiagnosticConsumer(DC),
- /*ShouldOwnClient=*/true);
- Diags->setSourceManager(&SourceMgr);
-}
+ : SourceMgr(SourceMgr), Diags(Diags), LangOpts(LangOpts), Target(Target),
+ HeaderInfo(HeaderInfo), BuiltinIncludeDir(nullptr),
+ CompilingModule(nullptr), SourceModule(nullptr) {}
ModuleMap::~ModuleMap() {
for (llvm::StringMap<Module *>::iterator I = Modules.begin(),
@@ -166,10 +159,165 @@ static bool isBuiltinHeader(StringRef FileName) {
.Default(false);
}
+ModuleMap::HeadersMap::iterator
+ModuleMap::findKnownHeader(const FileEntry *File) {
+ HeadersMap::iterator Known = Headers.find(File);
+ if (Known == Headers.end() && File->getDir() == BuiltinIncludeDir &&
+ isBuiltinHeader(llvm::sys::path::filename(File->getName()))) {
+ HeaderInfo.loadTopLevelSystemModules();
+ return Headers.find(File);
+ }
+ return Known;
+}
+
+ModuleMap::KnownHeader
+ModuleMap::findHeaderInUmbrellaDirs(const FileEntry *File,
+ SmallVectorImpl<const DirectoryEntry *> &IntermediateDirs) {
+ const DirectoryEntry *Dir = File->getDir();
+ assert(Dir && "file in no directory");
+
+ // Note: as an egregious but useful hack we use the real path here, because
+ // frameworks moving from top-level frameworks to embedded frameworks tend
+ // to be symlinked from the top-level location to the embedded location,
+ // and we need to resolve lookups as if we had found the embedded location.
+ StringRef DirName = SourceMgr.getFileManager().getCanonicalName(Dir);
+
+ // Keep walking up the directory hierarchy, looking for a directory with
+ // an umbrella header.
+ do {
+ auto KnownDir = UmbrellaDirs.find(Dir);
+ if (KnownDir != UmbrellaDirs.end())
+ return KnownHeader(KnownDir->second, NormalHeader);
+
+ IntermediateDirs.push_back(Dir);
+
+ // Retrieve our parent path.
+ DirName = llvm::sys::path::parent_path(DirName);
+ if (DirName.empty())
+ break;
+
+ // Resolve the parent path to a directory entry.
+ Dir = SourceMgr.getFileManager().getDirectory(DirName);
+ } while (Dir);
+ return KnownHeader();
+}
+
+// Returns 'true' if 'RequestingModule directly uses 'RequestedModule'.
+static bool directlyUses(const Module *RequestingModule,
+ const Module *RequestedModule) {
+ return std::find(RequestingModule->DirectUses.begin(),
+ RequestingModule->DirectUses.end(),
+ RequestedModule) != RequestingModule->DirectUses.end();
+}
+
+static bool violatesPrivateInclude(Module *RequestingModule,
+ const FileEntry *IncFileEnt,
+ ModuleMap::ModuleHeaderRole Role,
+ Module *RequestedModule) {
+ #ifndef NDEBUG
+ // Check for consistency between the module header role
+ // as obtained from the lookup and as obtained from the module.
+ // This check is not cheap, so enable it only for debugging.
+ SmallVectorImpl<const FileEntry *> &PvtHdrs
+ = RequestedModule->PrivateHeaders;
+ SmallVectorImpl<const FileEntry *>::iterator Look
+ = std::find(PvtHdrs.begin(), PvtHdrs.end(), IncFileEnt);
+ bool IsPrivate = Look != PvtHdrs.end();
+ assert((IsPrivate && Role == ModuleMap::PrivateHeader)
+ || (!IsPrivate && Role != ModuleMap::PrivateHeader));
+ #endif
+ return Role == ModuleMap::PrivateHeader &&
+ RequestedModule->getTopLevelModule() != RequestingModule;
+}
+
+static Module *getTopLevelOrNull(Module *M) {
+ return M ? M->getTopLevelModule() : nullptr;
+}
+
+void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
+ SourceLocation FilenameLoc,
+ StringRef Filename,
+ const FileEntry *File) {
+ // No errors for indirect modules. This may be a bit of a problem for modules
+ // with no source files.
+ if (getTopLevelOrNull(RequestingModule) != getTopLevelOrNull(SourceModule))
+ return;
+
+ if (RequestingModule)
+ resolveUses(RequestingModule, /*Complain=*/false);
+
+ bool Excluded = false;
+ Module *Private = nullptr;
+ Module *NotUsed = nullptr;
+
+ HeadersMap::iterator Known = findKnownHeader(File);
+ if (Known != Headers.end()) {
+ for (const KnownHeader &Header : Known->second) {
+ // Excluded headers don't really belong to a module.
+ if (Header.getRole() == ModuleMap::ExcludedHeader) {
+ Excluded = true;
+ continue;
+ }
+
+ // If 'File' is part of 'RequestingModule' we can definitely include it.
+ if (Header.getModule() == RequestingModule)
+ return;
+
+ // Remember private headers for later printing of a diagnostic.
+ if (violatesPrivateInclude(RequestingModule, File, Header.getRole(),
+ Header.getModule())) {
+ Private = Header.getModule();
+ continue;
+ }
+
+ // If uses need to be specified explicitly, we are only allowed to return
+ // modules that are explicitly used by the requesting module.
+ if (RequestingModule && LangOpts.ModulesDeclUse &&
+ !directlyUses(RequestingModule, Header.getModule())) {
+ NotUsed = Header.getModule();
+ continue;
+ }
+
+ // We have found a module that we can happily use.
+ return;
+ }
+ }
+
+ // We have found a header, but it is private.
+ if (Private) {
+ Diags.Report(FilenameLoc, diag::error_use_of_private_header_outside_module)
+ << Filename;
+ return;
+ }
+
+ // We have found a module, but we don't use it.
+ if (NotUsed) {
+ Diags.Report(FilenameLoc, diag::error_undeclared_use_of_module)
+ << RequestingModule->getFullModuleName() << Filename;
+ return;
+ }
+
+ if (Excluded || isHeaderInUmbrellaDirs(File))
+ return;
+
+ // At this point, only non-modular includes remain.
+
+ if (LangOpts.ModulesStrictDeclUse) {
+ Diags.Report(FilenameLoc, diag::error_undeclared_use_of_module)
+ << RequestingModule->getFullModuleName() << Filename;
+ } else if (RequestingModule) {
+ diag::kind DiagID = RequestingModule->getTopLevelModule()->IsFramework ?
+ diag::warn_non_modular_include_in_framework_module :
+ diag::warn_non_modular_include_in_module;
+ Diags.Report(FilenameLoc, DiagID) << RequestingModule->getFullModuleName();
+ }
+}
+
ModuleMap::KnownHeader
ModuleMap::findModuleForHeader(const FileEntry *File,
Module *RequestingModule) {
- HeadersMap::iterator Known = Headers.find(File);
+ HeadersMap::iterator Known = findKnownHeader(File);
+
if (Known != Headers.end()) {
ModuleMap::KnownHeader Result = KnownHeader();
@@ -177,9 +325,12 @@ ModuleMap::findModuleForHeader(const FileEntry *File,
for (SmallVectorImpl<KnownHeader>::iterator I = Known->second.begin(),
E = Known->second.end();
I != E; ++I) {
- // Cannot use a module if the header is excluded or unavailable in it.
- if (I->getRole() == ModuleMap::ExcludedHeader ||
- !I->getModule()->isAvailable())
+ // Cannot use a module if the header is excluded in it.
+ if (I->getRole() == ModuleMap::ExcludedHeader)
+ continue;
+
+ // Cannot use a module if it is unavailable.
+ if (!I->getModule()->isAvailable())
continue;
// If 'File' is part of 'RequestingModule', 'RequestingModule' is the
@@ -190,146 +341,125 @@ ModuleMap::findModuleForHeader(const FileEntry *File,
// If uses need to be specified explicitly, we are only allowed to return
// modules that are explicitly used by the requesting module.
if (RequestingModule && LangOpts.ModulesDeclUse &&
- std::find(RequestingModule->DirectUses.begin(),
- RequestingModule->DirectUses.end(),
- I->getModule()) == RequestingModule->DirectUses.end())
+ !directlyUses(RequestingModule, I->getModule()))
continue;
+
Result = *I;
// If 'File' is a public header of this module, this is as good as we
// are going to get.
+ // FIXME: If we have a RequestingModule, we should prefer the header from
+ // that module.
if (I->getRole() == ModuleMap::NormalHeader)
break;
}
return Result;
}
- // If we've found a builtin header within Clang's builtin include directory,
- // load all of the module maps to see if it will get associated with a
- // specific module (e.g., in /usr/include).
- if (File->getDir() == BuiltinIncludeDir &&
- isBuiltinHeader(llvm::sys::path::filename(File->getName()))) {
- HeaderInfo.loadTopLevelSystemModules();
-
- // Check again.
- if (Headers.find(File) != Headers.end())
- return findModuleForHeader(File, RequestingModule);
- }
-
- const DirectoryEntry *Dir = File->getDir();
SmallVector<const DirectoryEntry *, 2> SkippedDirs;
-
- // Note: as an egregious but useful hack we use the real path here, because
- // frameworks moving from top-level frameworks to embedded frameworks tend
- // to be symlinked from the top-level location to the embedded location,
- // and we need to resolve lookups as if we had found the embedded location.
- StringRef DirName = SourceMgr.getFileManager().getCanonicalName(Dir);
-
- // Keep walking up the directory hierarchy, looking for a directory with
- // an umbrella header.
- do {
- llvm::DenseMap<const DirectoryEntry *, Module *>::iterator KnownDir
- = UmbrellaDirs.find(Dir);
- if (KnownDir != UmbrellaDirs.end()) {
- Module *Result = KnownDir->second;
-
- // Search up the module stack until we find a module with an umbrella
- // directory.
- Module *UmbrellaModule = Result;
- while (!UmbrellaModule->getUmbrellaDir() && UmbrellaModule->Parent)
- UmbrellaModule = UmbrellaModule->Parent;
-
- if (UmbrellaModule->InferSubmodules) {
- // Infer submodules for each of the directories we found between
- // the directory of the umbrella header and the directory where
- // the actual header is located.
- bool Explicit = UmbrellaModule->InferExplicitSubmodules;
-
- for (unsigned I = SkippedDirs.size(); I != 0; --I) {
- // Find or create the module that corresponds to this directory name.
- SmallString<32> NameBuf;
- StringRef Name = sanitizeFilenameAsIdentifier(
- llvm::sys::path::stem(SkippedDirs[I-1]->getName()),
- NameBuf);
- Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
- Explicit).first;
-
- // Associate the module and the directory.
- UmbrellaDirs[SkippedDirs[I-1]] = Result;
-
- // If inferred submodules export everything they import, add a
- // wildcard to the set of exports.
- if (UmbrellaModule->InferExportWildcard && Result->Exports.empty())
- Result->Exports.push_back(Module::ExportDecl(0, true));
- }
-
- // Infer a submodule with the same name as this header file.
+ KnownHeader H = findHeaderInUmbrellaDirs(File, SkippedDirs);
+ if (H) {
+ Module *Result = H.getModule();
+
+ // Search up the module stack until we find a module with an umbrella
+ // directory.
+ Module *UmbrellaModule = Result;
+ while (!UmbrellaModule->getUmbrellaDir() && UmbrellaModule->Parent)
+ UmbrellaModule = UmbrellaModule->Parent;
+
+ if (UmbrellaModule->InferSubmodules) {
+ // Infer submodules for each of the directories we found between
+ // the directory of the umbrella header and the directory where
+ // the actual header is located.
+ bool Explicit = UmbrellaModule->InferExplicitSubmodules;
+
+ for (unsigned I = SkippedDirs.size(); I != 0; --I) {
+ // Find or create the module that corresponds to this directory name.
SmallString<32> NameBuf;
StringRef Name = sanitizeFilenameAsIdentifier(
- llvm::sys::path::stem(File->getName()), NameBuf);
- Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
- Explicit).first;
- Result->addTopHeader(File);
-
- // If inferred submodules export everything they import, add a
+ llvm::sys::path::stem(SkippedDirs[I-1]->getName()), NameBuf);
+ Result = findOrCreateModule(Name, Result, UmbrellaModule->ModuleMap,
+ /*IsFramework=*/false, Explicit).first;
+ Result->IsInferred = true;
+
+ // Associate the module and the directory.
+ UmbrellaDirs[SkippedDirs[I-1]] = Result;
+
+ // If inferred submodules export everything they import, add a
// wildcard to the set of exports.
if (UmbrellaModule->InferExportWildcard && Result->Exports.empty())
- Result->Exports.push_back(Module::ExportDecl(0, true));
- } else {
- // Record each of the directories we stepped through as being part of
- // the module we found, since the umbrella header covers them all.
- for (unsigned I = 0, N = SkippedDirs.size(); I != N; ++I)
- UmbrellaDirs[SkippedDirs[I]] = Result;
+ Result->Exports.push_back(Module::ExportDecl(nullptr, true));
}
-
- Headers[File].push_back(KnownHeader(Result, NormalHeader));
-
- // If a header corresponds to an unavailable module, don't report
- // that it maps to anything.
- if (!Result->isAvailable())
- return KnownHeader();
- return Headers[File].back();
+ // Infer a submodule with the same name as this header file.
+ SmallString<32> NameBuf;
+ StringRef Name = sanitizeFilenameAsIdentifier(
+ llvm::sys::path::stem(File->getName()), NameBuf);
+ Result = findOrCreateModule(Name, Result, UmbrellaModule->ModuleMap,
+ /*IsFramework=*/false, Explicit).first;
+ Result->IsInferred = true;
+ Result->addTopHeader(File);
+
+ // If inferred submodules export everything they import, add a
+ // wildcard to the set of exports.
+ if (UmbrellaModule->InferExportWildcard && Result->Exports.empty())
+ Result->Exports.push_back(Module::ExportDecl(nullptr, true));
+ } else {
+ // Record each of the directories we stepped through as being part of
+ // the module we found, since the umbrella header covers them all.
+ for (unsigned I = 0, N = SkippedDirs.size(); I != N; ++I)
+ UmbrellaDirs[SkippedDirs[I]] = Result;
}
-
- SkippedDirs.push_back(Dir);
-
- // Retrieve our parent path.
- DirName = llvm::sys::path::parent_path(DirName);
- if (DirName.empty())
- break;
-
- // Resolve the parent path to a directory entry.
- Dir = SourceMgr.getFileManager().getDirectory(DirName);
- } while (Dir);
+
+ Headers[File].push_back(KnownHeader(Result, NormalHeader));
+
+ // If a header corresponds to an unavailable module, don't report
+ // that it maps to anything.
+ if (!Result->isAvailable())
+ return KnownHeader();
+
+ return Headers[File].back();
+ }
return KnownHeader();
}
bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
+ return isHeaderUnavailableInModule(Header, nullptr);
+}
+
+bool
+ModuleMap::isHeaderUnavailableInModule(const FileEntry *Header,
+ const Module *RequestingModule) const {
HeadersMap::const_iterator Known = Headers.find(Header);
if (Known != Headers.end()) {
for (SmallVectorImpl<KnownHeader>::const_iterator
I = Known->second.begin(),
E = Known->second.end();
I != E; ++I) {
- if (I->isAvailable())
+ if (I->isAvailable() && (!RequestingModule ||
+ I->getModule()->isSubModuleOf(RequestingModule)))
return false;
}
return true;
}
-
+
const DirectoryEntry *Dir = Header->getDir();
SmallVector<const DirectoryEntry *, 2> SkippedDirs;
StringRef DirName = Dir->getName();
+ auto IsUnavailable = [&](const Module *M) {
+ return !M->isAvailable() && (!RequestingModule ||
+ M->isSubModuleOf(RequestingModule));
+ };
+
// Keep walking up the directory hierarchy, looking for a directory with
// an umbrella header.
- do {
+ do {
llvm::DenseMap<const DirectoryEntry *, Module *>::const_iterator KnownDir
= UmbrellaDirs.find(Dir);
if (KnownDir != UmbrellaDirs.end()) {
Module *Found = KnownDir->second;
- if (!Found->isAvailable())
+ if (IsUnavailable(Found))
return true;
// Search up the module stack until we find a module with an umbrella
@@ -348,7 +478,7 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
Found = lookupModuleQualified(Name, Found);
if (!Found)
return false;
- if (!Found->isAvailable())
+ if (IsUnavailable(Found))
return true;
}
@@ -362,7 +492,7 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
return false;
}
- return !Found->isAvailable();
+ return IsUnavailable(Found);
}
SkippedDirs.push_back(Dir);
@@ -383,8 +513,8 @@ Module *ModuleMap::findModule(StringRef Name) const {
llvm::StringMap<Module *>::const_iterator Known = Modules.find(Name);
if (Known != Modules.end())
return Known->getValue();
-
- return 0;
+
+ return nullptr;
}
Module *ModuleMap::lookupModuleUnqualified(StringRef Name,
@@ -405,15 +535,16 @@ Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) const{
}
std::pair<Module *, bool>
-ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
+ModuleMap::findOrCreateModule(StringRef Name, Module *Parent,
+ const FileEntry *ModuleMap, bool IsFramework,
bool IsExplicit) {
// Try to find an existing module with this name.
if (Module *Sub = lookupModuleQualified(Name, Parent))
return std::make_pair(Sub, false);
// Create a new module with this name.
- Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework,
- IsExplicit);
+ Module *Result = new Module(Name, SourceLocation(), Parent, ModuleMap,
+ IsFramework, IsExplicit);
if (LangOpts.CurrentModule == Name) {
SourceModule = Result;
SourceModuleName = Name;
@@ -482,6 +613,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// If the framework has a parent path from which we're allowed to infer
// a framework module, do so.
+ const FileEntry *ModuleMapFile = nullptr;
if (!Parent) {
// Determine whether we're allowed to infer a module map.
@@ -492,6 +624,12 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
StringRef FrameworkDirName
= SourceMgr.getFileManager().getCanonicalName(FrameworkDir);
+ // In case this is a case-insensitive filesystem, make sure the canonical
+ // directory name matches ModuleName exactly. Modules are case-sensitive.
+ // FIXME: we should be able to give a fix-it hint for the correct spelling.
+ if (llvm::sys::path::stem(FrameworkDirName) != ModuleName)
+ return nullptr;
+
bool canInfer = false;
if (llvm::sys::path::has_parent_path(FrameworkDirName)) {
// Figure out the parent path.
@@ -504,9 +642,9 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
if (inferred == InferredDirectories.end()) {
// We haven't looked here before. Load a module map, if there is
// one.
- SmallString<128> ModMapPath = Parent;
- llvm::sys::path::append(ModMapPath, "module.map");
- if (const FileEntry *ModMapFile = FileMgr.getFile(ModMapPath)) {
+ bool IsFrameworkDir = Parent.endswith(".framework");
+ if (const FileEntry *ModMapFile =
+ HeaderInfo.lookupModuleMapFile(ParentDir, IsFrameworkDir)) {
parseModuleMapFile(ModMapFile, IsSystem);
inferred = InferredDirectories.find(ParentDir);
}
@@ -526,14 +664,16 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
if (inferred->second.InferSystemModules)
IsSystem = true;
+ ModuleMapFile = inferred->second.ModuleMapFile;
}
}
}
// If we're not allowed to infer a framework module, don't.
if (!canInfer)
- return 0;
- }
+ return nullptr;
+ } else
+ ModuleMapFile = Parent->ModuleMap;
// Look for an umbrella header.
@@ -545,9 +685,9 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// framework to load *everything*. But, it's not clear that this is a good
// idea.
if (!UmbrellaHeader)
- return 0;
-
- Module *Result = new Module(ModuleName, SourceLocation(), Parent,
+ return nullptr;
+
+ Module *Result = new Module(ModuleName, SourceLocation(), Parent, ModuleMapFile,
/*IsFramework=*/true, /*IsExplicit=*/false);
if (LangOpts.CurrentModule == ModuleName) {
SourceModule = Result;
@@ -565,14 +705,14 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
UmbrellaDirs[UmbrellaHeader->getDir()] = Result;
// export *
- Result->Exports.push_back(Module::ExportDecl(0, true));
-
+ Result->Exports.push_back(Module::ExportDecl(nullptr, true));
+
// module * { export * }
Result->InferSubmodules = true;
Result->InferExportWildcard = true;
// Look for subframeworks.
- llvm::error_code EC;
+ std::error_code EC;
SmallString<128> SubframeworksDirName
= StringRef(FrameworkDir->getName());
llvm::sys::path::append(SubframeworksDirName, "Frameworks");
@@ -653,7 +793,7 @@ void ModuleMap::addHeader(Module *Mod, const FileEntry *Header,
const FileEntry *
ModuleMap::getContainingModuleMapFile(Module *Module) const {
if (Module->DefinitionLoc.isInvalid())
- return 0;
+ return nullptr;
return SourceMgr.getFileEntryForID(
SourceMgr.getFileID(Module->DefinitionLoc));
@@ -730,14 +870,13 @@ bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) {
Module *ModuleMap::inferModuleFromLocation(FullSourceLoc Loc) {
if (Loc.isInvalid())
- return 0;
-
+ return nullptr;
+
// Use the expansion location to determine which module we're in.
FullSourceLoc ExpansionLoc = Loc.getExpansionLoc();
if (!ExpansionLoc.isFileID())
- return 0;
-
-
+ return nullptr;
+
const SourceManager &SrcMgr = Loc.getManager();
FileID ExpansionFileID = ExpansionLoc.getFileID();
@@ -751,12 +890,12 @@ Module *ModuleMap::inferModuleFromLocation(FullSourceLoc Loc) {
// any included header has an associated module.
SourceLocation IncludeLoc = SrcMgr.getIncludeLoc(ExpansionFileID);
if (IncludeLoc.isInvalid())
- return 0;
-
+ return nullptr;
+
ExpansionFileID = SrcMgr.getFileID(IncludeLoc);
}
-
- return 0;
+
+ return nullptr;
}
//----------------------------------------------------------------------------//
@@ -802,7 +941,7 @@ namespace clang {
Kind = EndOfFile;
Location = 0;
StringLength = 0;
- StringData = 0;
+ StringData = nullptr;
}
bool is(TokenKind K) const { return Kind == K; }
@@ -818,11 +957,14 @@ namespace clang {
/// \brief The set of attributes that can be attached to a module.
struct Attributes {
- Attributes() : IsSystem(), IsExhaustive() { }
+ Attributes() : IsSystem(), IsExternC(), IsExhaustive() { }
/// \brief Whether this is a system module.
unsigned IsSystem : 1;
+ /// \brief Whether this is an extern "C" module.
+ unsigned IsExternC : 1;
+
/// \brief Whether this is an exhaustive set of configuration macros.
unsigned IsExhaustive : 1;
};
@@ -838,6 +980,9 @@ namespace clang {
DiagnosticsEngine &Diags;
ModuleMap &Map;
+
+ /// \brief The current module map file.
+ const FileEntry *ModuleMapFile;
/// \brief The directory that this module map resides in.
const DirectoryEntry *Directory;
@@ -883,20 +1028,20 @@ namespace clang {
void parseConflict();
void parseInferredModuleDecl(bool Framework, bool Explicit);
bool parseOptionalAttributes(Attributes &Attrs);
-
- const DirectoryEntry *getOverriddenHeaderSearchDir();
public:
explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
const TargetInfo *Target,
DiagnosticsEngine &Diags,
ModuleMap &Map,
+ const FileEntry *ModuleMapFile,
const DirectoryEntry *Directory,
const DirectoryEntry *BuiltinIncludeDir,
bool IsSystem)
: L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map),
- Directory(Directory), BuiltinIncludeDir(BuiltinIncludeDir),
- IsSystem(IsSystem), HadError(false), ActiveModule(0)
+ ModuleMapFile(ModuleMapFile), Directory(Directory),
+ BuiltinIncludeDir(BuiltinIncludeDir), IsSystem(IsSystem),
+ HadError(false), ActiveModule(nullptr)
{
Tok.clear();
consumeToken();
@@ -915,10 +1060,11 @@ retry:
L.LexFromRawLexer(LToken);
Tok.Location = LToken.getLocation().getRawEncoding();
switch (LToken.getKind()) {
- case tok::raw_identifier:
- Tok.StringData = LToken.getRawIdentifierData();
- Tok.StringLength = LToken.getLength();
- Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(Tok.getString())
+ case tok::raw_identifier: {
+ StringRef RI = LToken.getRawIdentifier();
+ Tok.StringData = RI.data();
+ Tok.StringLength = RI.size();
+ Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(RI)
.Case("config_macros", MMToken::ConfigMacros)
.Case("conflict", MMToken::Conflict)
.Case("exclude", MMToken::ExcludeKeyword)
@@ -935,6 +1081,7 @@ retry:
.Case("use", MMToken::UseKeyword)
.Default(MMToken::Identifier);
break;
+ }
case tok::comma:
Tok.Kind = MMToken::Comma;
@@ -981,7 +1128,7 @@ retry:
// Parse the string literal.
LangOptions LangOpts;
- StringLiteralParser StringLiteral(&LToken, 1, SourceMgr, LangOpts, *Target);
+ StringLiteralParser StringLiteral(LToken, SourceMgr, LangOpts, *Target);
if (StringLiteral.hadError)
goto retry;
@@ -1066,7 +1213,7 @@ void ModuleMapParser::skipUntil(MMToken::TokenKind K) {
bool ModuleMapParser::parseModuleId(ModuleId &Id) {
Id.clear();
do {
- if (Tok.is(MMToken::Identifier)) {
+ if (Tok.is(MMToken::Identifier) || Tok.is(MMToken::StringLiteral)) {
Id.push_back(std::make_pair(Tok.getString(), Tok.getLocation()));
consumeToken();
} else {
@@ -1090,6 +1237,8 @@ namespace {
AT_unknown,
/// \brief The 'system' attribute.
AT_system,
+ /// \brief The 'extern_c' attribute.
+ AT_extern_c,
/// \brief The 'exhaustive' attribute.
AT_exhaustive
};
@@ -1178,7 +1327,7 @@ void ModuleMapParser::parseModuleDecl() {
if (Id.size() > 1) {
// This module map defines a submodule. Go find the module of which it
// is a submodule.
- ActiveModule = 0;
+ ActiveModule = nullptr;
for (unsigned I = 0, N = Id.size() - 1; I != N; ++I) {
if (Module *Next = Map.lookupModuleQualified(Id[I].first, ActiveModule)) {
ActiveModule = Next;
@@ -1187,7 +1336,8 @@ void ModuleMapParser::parseModuleDecl() {
if (ActiveModule) {
Diags.Report(Id[I].second, diag::err_mmap_missing_module_qualified)
- << Id[I].first << ActiveModule->getTopLevelModule();
+ << Id[I].first
+ << ActiveModule->getTopLevelModule()->getFullModuleName();
} else {
Diags.Report(Id[I].second, diag::err_mmap_expected_module_name);
}
@@ -1240,13 +1390,20 @@ void ModuleMapParser::parseModuleDecl() {
return;
}
+ // If this is a submodule, use the parent's module map, since we don't want
+ // the private module map file.
+ const FileEntry *ModuleMap = ActiveModule ? ActiveModule->ModuleMap
+ : ModuleMapFile;
+
// Start defining this module.
- ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, Framework,
- Explicit).first;
+ ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, ModuleMap,
+ Framework, Explicit).first;
ActiveModule->DefinitionLoc = ModuleNameLoc;
if (Attrs.IsSystem || IsSystem)
ActiveModule->IsSystem = true;
-
+ if (Attrs.IsExternC)
+ ActiveModule->IsExternC = true;
+
bool Done = false;
do {
switch (Tok.Kind) {
@@ -1343,6 +1500,15 @@ void ModuleMapParser::parseModuleDecl() {
inferFrameworkLink(ActiveModule, Directory, SourceMgr.getFileManager());
}
+ // If the module meets all requirements but is still unavailable, mark the
+ // whole tree as unavailable to prevent it from building.
+ if (!ActiveModule->IsAvailable && !ActiveModule->IsMissingRequirement &&
+ ActiveModule->Parent) {
+ ActiveModule->getTopLevelModule()->markUnavailable();
+ ActiveModule->getTopLevelModule()->MissingHeaders.append(
+ ActiveModule->MissingHeaders.begin(), ActiveModule->MissingHeaders.end());
+ }
+
// We're done parsing this module. Pop back to the previous module.
ActiveModule = PreviousActiveModule;
}
@@ -1474,27 +1640,24 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
HadError = true;
return;
}
- std::string FileName = Tok.getString();
- SourceLocation FileNameLoc = consumeToken();
+ Module::HeaderDirective Header;
+ Header.FileName = Tok.getString();
+ Header.FileNameLoc = consumeToken();
// Check whether we already have an umbrella.
if (LeadingToken == MMToken::UmbrellaKeyword && ActiveModule->Umbrella) {
- Diags.Report(FileNameLoc, diag::err_mmap_umbrella_clash)
+ Diags.Report(Header.FileNameLoc, diag::err_mmap_umbrella_clash)
<< ActiveModule->getFullModuleName();
HadError = true;
return;
}
// Look for this file.
- const FileEntry *File = 0;
- const FileEntry *BuiltinFile = 0;
+ const FileEntry *File = nullptr;
+ const FileEntry *BuiltinFile = nullptr;
SmallString<128> PathName;
- if (llvm::sys::path::is_absolute(FileName)) {
- PathName = FileName;
- File = SourceMgr.getFileManager().getFile(PathName);
- } else if (const DirectoryEntry *Dir = getOverriddenHeaderSearchDir()) {
- PathName = Dir->getName();
- llvm::sys::path::append(PathName, FileName);
+ if (llvm::sys::path::is_absolute(Header.FileName)) {
+ PathName = Header.FileName;
File = SourceMgr.getFileManager().getFile(PathName);
} else {
// Search for the header file within the search directory.
@@ -1505,18 +1668,18 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
appendSubframeworkPaths(ActiveModule, PathName);
// Check whether this file is in the public headers.
- llvm::sys::path::append(PathName, "Headers", FileName);
+ llvm::sys::path::append(PathName, "Headers", Header.FileName);
File = SourceMgr.getFileManager().getFile(PathName);
if (!File) {
// Check whether this file is in the private headers.
PathName.resize(PathLength);
- llvm::sys::path::append(PathName, "PrivateHeaders", FileName);
+ llvm::sys::path::append(PathName, "PrivateHeaders", Header.FileName);
File = SourceMgr.getFileManager().getFile(PathName);
}
} else {
// Lookup for normal headers.
- llvm::sys::path::append(PathName, FileName);
+ llvm::sys::path::append(PathName, Header.FileName);
File = SourceMgr.getFileManager().getFile(PathName);
// If this is a system module with a top-level header, this header
@@ -1524,9 +1687,9 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
// supplied by Clang. Find that builtin header.
if (ActiveModule->IsSystem && LeadingToken != MMToken::UmbrellaKeyword &&
BuiltinIncludeDir && BuiltinIncludeDir != Directory &&
- isBuiltinHeader(FileName)) {
+ isBuiltinHeader(Header.FileName)) {
SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName());
- llvm::sys::path::append(BuiltinPathName, FileName);
+ llvm::sys::path::append(BuiltinPathName, Header.FileName);
BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName);
// If Clang supplies this header but the underlying system does not,
@@ -1534,7 +1697,7 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
// up adding both (later).
if (!File && BuiltinFile) {
File = BuiltinFile;
- BuiltinFile = 0;
+ BuiltinFile = nullptr;
}
}
}
@@ -1571,10 +1734,12 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
}
} else if (LeadingToken != MMToken::ExcludeKeyword) {
// Ignore excluded header files. They're optional anyway.
-
- Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
- << (LeadingToken == MMToken::UmbrellaKeyword) << FileName;
- HadError = true;
+
+ // If we find a module that has a missing header, we mark this module as
+ // unavailable and store the header directive for displaying diagnostics.
+ Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword;
+ ActiveModule->markUnavailable();
+ ActiveModule->MissingHeaders.push_back(Header);
}
}
@@ -1603,7 +1768,7 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
}
// Look for this file.
- const DirectoryEntry *Dir = 0;
+ const DirectoryEntry *Dir = nullptr;
if (llvm::sys::path::is_absolute(DirName))
Dir = SourceMgr.getFileManager().getDirectory(DirName);
else {
@@ -1687,25 +1852,7 @@ void ModuleMapParser::parseUseDecl() {
consumeToken();
// Parse the module-id.
ModuleId ParsedModuleId;
-
- do {
- if (Tok.is(MMToken::Identifier)) {
- ParsedModuleId.push_back(
- std::make_pair(Tok.getString(), Tok.getLocation()));
- consumeToken();
-
- if (Tok.is(MMToken::Period)) {
- consumeToken();
- continue;
- }
-
- break;
- }
-
- Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);
- HadError = true;
- return;
- } while (true);
+ parseModuleId(ParsedModuleId);
ActiveModule->UnresolvedDirectUses.push_back(ParsedModuleId);
}
@@ -1864,7 +2011,8 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
if (ActiveModule) {
// Inferred modules must have umbrella directories.
- if (!Failed && !ActiveModule->getUmbrellaDir()) {
+ if (!Failed && ActiveModule->IsAvailable &&
+ !ActiveModule->getUmbrellaDir()) {
Diags.Report(StarLoc, diag::err_mmap_inferred_no_umbrella);
Failed = true;
}
@@ -1913,6 +2061,8 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
// We'll be inferring framework modules for this directory.
Map.InferredDirectories[Directory].InferModules = true;
Map.InferredDirectories[Directory].InferSystemModules = Attrs.IsSystem;
+ Map.InferredDirectories[Directory].ModuleMapFile = ModuleMapFile;
+ // FIXME: Handle the 'framework' keyword.
}
// Parse the opening brace.
@@ -1935,7 +2085,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
case MMToken::ExcludeKeyword: {
if (ActiveModule) {
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)
- << (ActiveModule != 0);
+ << (ActiveModule != nullptr);
consumeToken();
break;
}
@@ -1955,7 +2105,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
case MMToken::ExportKeyword:
if (!ActiveModule) {
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)
- << (ActiveModule != 0);
+ << (ActiveModule != nullptr);
consumeToken();
break;
}
@@ -1976,7 +2126,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
case MMToken::UmbrellaKeyword:
default:
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)
- << (ActiveModule != 0);
+ << (ActiveModule != nullptr);
consumeToken();
break;
}
@@ -2023,6 +2173,7 @@ bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) {
AttributeKind Attribute
= llvm::StringSwitch<AttributeKind>(Tok.getString())
.Case("exhaustive", AT_exhaustive)
+ .Case("extern_c", AT_extern_c)
.Case("system", AT_system)
.Default(AT_unknown);
switch (Attribute) {
@@ -2035,6 +2186,10 @@ bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) {
Attrs.IsSystem = true;
break;
+ case AT_extern_c:
+ Attrs.IsExternC = true;
+ break;
+
case AT_exhaustive:
Attrs.IsExhaustive = true;
break;
@@ -2056,22 +2211,6 @@ bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) {
return HadError;
}
-/// \brief If there is a specific header search directory due the presence
-/// of an umbrella directory, retrieve that directory. Otherwise, returns null.
-const DirectoryEntry *ModuleMapParser::getOverriddenHeaderSearchDir() {
- for (Module *Mod = ActiveModule; Mod; Mod = Mod->Parent) {
- // If we have an umbrella directory, use that.
- if (Mod->hasUmbrellaDir())
- return Mod->getUmbrellaDir();
-
- // If we have a framework directory, stop looking.
- if (Mod->IsFramework)
- return 0;
- }
-
- return 0;
-}
-
/// \brief Parse a module map file.
///
/// module-map-file:
@@ -2123,19 +2262,29 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem) {
if (Known != ParsedModuleMap.end())
return Known->second;
- assert(Target != 0 && "Missing target information");
- FileID ID = SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
+ assert(Target && "Missing target information");
+ auto FileCharacter = IsSystem ? SrcMgr::C_System : SrcMgr::C_User;
+ FileID ID = SourceMgr.createFileID(File, SourceLocation(), FileCharacter);
const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(ID);
if (!Buffer)
return ParsedModuleMap[File] = true;
+
+ // Find the directory for the module. For frameworks, that may require going
+ // up from the 'Modules' directory.
+ const DirectoryEntry *Dir = File->getDir();
+ StringRef DirName(Dir->getName());
+ if (llvm::sys::path::filename(DirName) == "Modules") {
+ DirName = llvm::sys::path::parent_path(DirName);
+ if (DirName.endswith(".framework"))
+ Dir = SourceMgr.getFileManager().getDirectory(DirName);
+ assert(Dir && "parent must exist");
+ }
// Parse this module map file.
Lexer L(ID, SourceMgr.getBuffer(ID), SourceMgr, MMapLangOpts);
- Diags->getClient()->BeginSourceFile(MMapLangOpts);
- ModuleMapParser Parser(L, SourceMgr, Target, *Diags, *this, File->getDir(),
+ ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File, Dir,
BuiltinIncludeDir, IsSystem);
bool Result = Parser.parseModuleMapFile();
- Diags->getClient()->EndSourceFile();
ParsedModuleMap[File] = Result;
return Result;
}
diff --git a/lib/Lex/PPCaching.cpp b/lib/Lex/PPCaching.cpp
index 6f4c189b4f6a..bd48ae64ab4b 100644
--- a/lib/Lex/PPCaching.cpp
+++ b/lib/Lex/PPCaching.cpp
@@ -15,28 +15,28 @@
#include "clang/Lex/Preprocessor.h"
using namespace clang;
-/// EnableBacktrackAtThisPos - From the point that this method is called, and
-/// until CommitBacktrackedTokens() or Backtrack() is called, the Preprocessor
-/// keeps track of the lexed tokens so that a subsequent Backtrack() call will
-/// make the Preprocessor re-lex the same tokens.
-///
-/// Nested backtracks are allowed, meaning that EnableBacktrackAtThisPos can
-/// be called multiple times and CommitBacktrackedTokens/Backtrack calls will
-/// be combined with the EnableBacktrackAtThisPos calls in reverse order.
+// EnableBacktrackAtThisPos - From the point that this method is called, and
+// until CommitBacktrackedTokens() or Backtrack() is called, the Preprocessor
+// keeps track of the lexed tokens so that a subsequent Backtrack() call will
+// make the Preprocessor re-lex the same tokens.
+//
+// Nested backtracks are allowed, meaning that EnableBacktrackAtThisPos can
+// be called multiple times and CommitBacktrackedTokens/Backtrack calls will
+// be combined with the EnableBacktrackAtThisPos calls in reverse order.
void Preprocessor::EnableBacktrackAtThisPos() {
BacktrackPositions.push_back(CachedLexPos);
EnterCachingLexMode();
}
-/// CommitBacktrackedTokens - Disable the last EnableBacktrackAtThisPos call.
+// Disable the last EnableBacktrackAtThisPos call.
void Preprocessor::CommitBacktrackedTokens() {
assert(!BacktrackPositions.empty()
&& "EnableBacktrackAtThisPos was not called!");
BacktrackPositions.pop_back();
}
-/// Backtrack - Make Preprocessor re-lex the tokens that were lexed since
-/// EnableBacktrackAtThisPos() was previously called.
+// Make Preprocessor re-lex the tokens that were lexed since
+// EnableBacktrackAtThisPos() was previously called.
void Preprocessor::Backtrack() {
assert(!BacktrackPositions.empty()
&& "EnableBacktrackAtThisPos was not called!");
diff --git a/lib/Lex/PPConditionalDirectiveRecord.cpp b/lib/Lex/PPConditionalDirectiveRecord.cpp
index 16dc1d8f0913..99b87a0a1525 100644
--- a/lib/Lex/PPConditionalDirectiveRecord.cpp
+++ b/lib/Lex/PPConditionalDirectiveRecord.cpp
@@ -77,7 +77,7 @@ void PPConditionalDirectiveRecord::addCondDirectiveLoc(
void PPConditionalDirectiveRecord::If(SourceLocation Loc,
SourceRange ConditionRange,
- bool ConditionValue) {
+ ConditionValueKind ConditionValue) {
addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
CondDirectiveStack.push_back(Loc);
}
@@ -98,7 +98,7 @@ void PPConditionalDirectiveRecord::Ifndef(SourceLocation Loc,
void PPConditionalDirectiveRecord::Elif(SourceLocation Loc,
SourceRange ConditionRange,
- bool ConditionValue,
+ ConditionValueKind ConditionValue,
SourceLocation IfLoc) {
addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
CondDirectiveStack.back() = Loc;
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 86c508fe9b1b..1741c302f338 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -25,6 +25,7 @@
#include "clang/Lex/Pragma.h"
#include "llvm/ADT/APInt.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
@@ -44,7 +45,7 @@ MacroInfo *Preprocessor::AllocateMacroInfo() {
}
MIChain->Next = MIChainHead;
- MIChain->Prev = 0;
+ MIChain->Prev = nullptr;
if (MIChainHead)
MIChainHead->Prev = MIChain;
MIChainHead = MIChain;
@@ -60,8 +61,8 @@ MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) {
MacroInfo *Preprocessor::AllocateDeserializedMacroInfo(SourceLocation L,
unsigned SubModuleID) {
- LLVM_STATIC_ASSERT(llvm::AlignOf<MacroInfo>::Alignment >= sizeof(SubModuleID),
- "alignment for MacroInfo is less than the ID");
+ static_assert(llvm::AlignOf<MacroInfo>::Alignment >= sizeof(SubModuleID),
+ "alignment for MacroInfo is less than the ID");
DeserializedMacroInfoChain *MIChain =
BP.Allocate<DeserializedMacroInfoChain>();
MIChain->Next = DeserialMIChainHead;
@@ -100,17 +101,16 @@ Preprocessor::AllocateVisibilityMacroDirective(SourceLocation Loc,
/// \brief Release the specified MacroInfo to be reused for allocating
/// new MacroInfo objects.
void Preprocessor::ReleaseMacroInfo(MacroInfo *MI) {
- MacroInfoChain *MIChain = (MacroInfoChain*) MI;
+ MacroInfoChain *MIChain = (MacroInfoChain *)MI;
if (MacroInfoChain *Prev = MIChain->Prev) {
MacroInfoChain *Next = MIChain->Next;
Prev->Next = Next;
if (Next)
Next->Prev = Prev;
- }
- else {
+ } else {
assert(MIChainHead == MIChain);
MIChainHead = MIChain->Next;
- MIChainHead->Prev = 0;
+ MIChainHead->Prev = nullptr;
}
MIChain->Next = MICache;
MICache = MIChain;
@@ -128,6 +128,50 @@ void Preprocessor::DiscardUntilEndOfDirective() {
} while (Tmp.isNot(tok::eod));
}
+bool Preprocessor::CheckMacroName(Token &MacroNameTok, char isDefineUndef) {
+ // Missing macro name?
+ if (MacroNameTok.is(tok::eod))
+ return Diag(MacroNameTok, diag::err_pp_missing_macro_name);
+
+ IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
+ if (!II) {
+ bool Invalid = false;
+ std::string Spelling = getSpelling(MacroNameTok, &Invalid);
+ if (Invalid)
+ return Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
+ II = getIdentifierInfo(Spelling);
+
+ if (!II->isCPlusPlusOperatorKeyword())
+ return Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
+
+ // C++ 2.5p2: Alternative tokens behave the same as its primary token
+ // except for their spellings.
+ Diag(MacroNameTok, getLangOpts().MicrosoftExt
+ ? diag::ext_pp_operator_used_as_macro_name
+ : diag::err_pp_operator_used_as_macro_name)
+ << II << MacroNameTok.getKind();
+
+ // Allow #defining |and| and friends for Microsoft compatibility or
+ // recovery when legacy C headers are included in C++.
+ MacroNameTok.setIdentifierInfo(II);
+ }
+
+ if (isDefineUndef && II->getPPKeywordID() == tok::pp_defined) {
+ // Error if defining "defined": C99 6.10.8/4, C++ [cpp.predefined]p4.
+ return Diag(MacroNameTok, diag::err_defined_macro_name);
+ }
+
+ if (isDefineUndef == 2 && II->hasMacroDefinition() &&
+ getMacroInfo(II)->isBuiltinMacro()) {
+ // Warn if undefining "__LINE__" and other builtins, per C99 6.10.8/4
+ // and C++ [cpp.predefined]p4], but allow it as an extension.
+ Diag(MacroNameTok, diag::ext_pp_undef_builtin_macro);
+ }
+
+ // Okay, we got a good identifier.
+ return false;
+}
+
/// \brief Lex and validate a macro name, which occurs after a
/// \#define or \#undef.
///
@@ -145,53 +189,16 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
setCodeCompletionReached();
LexUnexpandedToken(MacroNameTok);
}
-
- // Missing macro name?
- if (MacroNameTok.is(tok::eod)) {
- Diag(MacroNameTok, diag::err_pp_missing_macro_name);
- return;
- }
- IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
- if (II == 0) {
- bool Invalid = false;
- std::string Spelling = getSpelling(MacroNameTok, &Invalid);
- if (Invalid)
- return;
-
- const IdentifierInfo &Info = Identifiers.get(Spelling);
-
- // Allow #defining |and| and friends in microsoft mode.
- if (Info.isCPlusPlusOperatorKeyword() && getLangOpts().MicrosoftMode) {
- MacroNameTok.setIdentifierInfo(getIdentifierInfo(Spelling));
- return;
- }
-
- if (Info.isCPlusPlusOperatorKeyword())
- // C++ 2.5p2: Alternative tokens behave the same as its primary token
- // except for their spellings.
- Diag(MacroNameTok, diag::err_pp_operator_used_as_macro_name) << Spelling;
- else
- Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
- // Fall through on error.
- } else if (isDefineUndef && II->getPPKeywordID() == tok::pp_defined) {
- // Error if defining "defined": C99 6.10.8/4, C++ [cpp.predefined]p4.
- Diag(MacroNameTok, diag::err_defined_macro_name);
- } else if (isDefineUndef == 2 && II->hasMacroDefinition() &&
- getMacroInfo(II)->isBuiltinMacro()) {
- // Warn if undefining "__LINE__" and other builtins, per C99 6.10.8/4
- // and C++ [cpp.predefined]p4], but allow it as an extension.
- Diag(MacroNameTok, diag::ext_pp_undef_builtin_macro);
+ if (!CheckMacroName(MacroNameTok, isDefineUndef))
return;
- } else {
- // Okay, we got a good identifier node. Return it.
- return;
- }
- // Invalid macro name, read and discard the rest of the line. Then set the
- // token kind to tok::eod.
- MacroNameTok.setKind(tok::eod);
- return DiscardUntilEndOfDirective();
+ // Invalid macro name, read and discard the rest of the line and set the
+ // token kind to tok::eod if necessary.
+ if (MacroNameTok.isNot(tok::eod)) {
+ MacroNameTok.setKind(tok::eod);
+ DiscardUntilEndOfDirective();
+ }
}
/// \brief Ensure that the next token is a tok::eod token.
@@ -309,9 +316,9 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// to spell an i/e in a strange way that is another letter. Skipping this
// allows us to avoid looking up the identifier info for #define/#undef and
// other common directives.
- const char *RawCharData = Tok.getRawIdentifierData();
+ StringRef RI = Tok.getRawIdentifier();
- char FirstChar = RawCharData[0];
+ char FirstChar = RI[0];
if (FirstChar >= 'a' && FirstChar <= 'z' &&
FirstChar != 'i' && FirstChar != 'e') {
CurPPLexer->ParsingPreprocessorDirective = false;
@@ -325,8 +332,8 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// when skipping.
char DirectiveBuf[20];
StringRef Directive;
- if (!Tok.needsCleaning() && Tok.getLength() < 20) {
- Directive = StringRef(RawCharData, Tok.getLength());
+ if (!Tok.needsCleaning() && RI.size() < 20) {
+ Directive = RI;
} else {
std::string DirectiveStr = getSpelling(Tok);
unsigned IdLen = DirectiveStr.size();
@@ -404,35 +411,33 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
} else if (Sub == "lif") { // "elif".
PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel();
- bool ShouldEnter;
- const SourceLocation ConditionalBegin = CurPPLexer->getSourceLocation();
+ // If this is a #elif with a #else before it, report the error.
+ if (CondInfo.FoundElse) Diag(Tok, diag::pp_err_elif_after_else);
+
// If this is in a skipping block or if we're already handled this #if
// block, don't bother parsing the condition.
if (CondInfo.WasSkipping || CondInfo.FoundNonSkip) {
DiscardUntilEndOfDirective();
- ShouldEnter = false;
} else {
+ const SourceLocation CondBegin = CurPPLexer->getSourceLocation();
// Restore the value of LexingRawMode so that identifiers are
// looked up, etc, inside the #elif expression.
assert(CurPPLexer->LexingRawMode && "We have to be skipping here!");
CurPPLexer->LexingRawMode = false;
- IdentifierInfo *IfNDefMacro = 0;
- ShouldEnter = EvaluateDirectiveExpression(IfNDefMacro);
+ IdentifierInfo *IfNDefMacro = nullptr;
+ const bool CondValue = EvaluateDirectiveExpression(IfNDefMacro);
CurPPLexer->LexingRawMode = true;
- }
- const SourceLocation ConditionalEnd = CurPPLexer->getSourceLocation();
-
- // If this is a #elif with a #else before it, report the error.
- if (CondInfo.FoundElse) Diag(Tok, diag::pp_err_elif_after_else);
-
- // If this condition is true, enter it!
- if (ShouldEnter) {
- CondInfo.FoundNonSkip = true;
- if (Callbacks)
+ if (Callbacks) {
+ const SourceLocation CondEnd = CurPPLexer->getSourceLocation();
Callbacks->Elif(Tok.getLocation(),
- SourceRange(ConditionalBegin, ConditionalEnd),
- ShouldEnter, CondInfo.IfLoc);
- break;
+ SourceRange(CondBegin, CondEnd),
+ (CondValue ? PPCallbacks::CVK_True : PPCallbacks::CVK_False), CondInfo.IfLoc);
+ }
+ // If this condition is true, enter it!
+ if (CondValue) {
+ CondInfo.FoundNonSkip = true;
+ break;
+ }
}
}
}
@@ -516,7 +521,7 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() {
continue;
// Evaluate the condition of the #elif.
- IdentifierInfo *IfNDefMacro = 0;
+ IdentifierInfo *IfNDefMacro = nullptr;
CurPTHLexer->ParsingPreprocessorDirective = true;
bool ShouldEnter = EvaluateDirectiveExpression(IfNDefMacro);
CurPTHLexer->ParsingPreprocessorDirective = false;
@@ -540,7 +545,8 @@ Module *Preprocessor::getModuleForLocation(SourceLocation FilenameLoc) {
return HeaderInfo.getModuleMap().SourceModule; // Compiling a source.
}
// Try to determine the module of the include directive.
- FileID IDOfIncl = SourceMgr.getFileID(FilenameLoc);
+ // FIXME: Look into directly passing the FileEntry from LookupFile instead.
+ FileID IDOfIncl = SourceMgr.getFileID(SourceMgr.getExpansionLoc(FilenameLoc));
if (const FileEntry *EntryOfIncl = SourceMgr.getFileEntryForID(IDOfIncl)) {
// The include comes from a file.
return ModMap.findModuleForHeader(EntryOfIncl).getModule();
@@ -551,69 +557,6 @@ Module *Preprocessor::getModuleForLocation(SourceLocation FilenameLoc) {
}
}
-bool Preprocessor::violatesPrivateInclude(
- Module *RequestingModule,
- const FileEntry *IncFileEnt,
- ModuleMap::ModuleHeaderRole Role,
- Module *RequestedModule) {
- #ifndef NDEBUG
- // Check for consistency between the module header role
- // as obtained from the lookup and as obtained from the module.
- // This check is not cheap, so enable it only for debugging.
- SmallVectorImpl<const FileEntry *> &PvtHdrs
- = RequestedModule->PrivateHeaders;
- SmallVectorImpl<const FileEntry *>::iterator Look
- = std::find(PvtHdrs.begin(), PvtHdrs.end(), IncFileEnt);
- bool IsPrivate = Look != PvtHdrs.end();
- assert((IsPrivate && Role == ModuleMap::PrivateHeader)
- || (!IsPrivate && Role != ModuleMap::PrivateHeader));
- #endif
- return Role == ModuleMap::PrivateHeader &&
- RequestedModule->getTopLevelModule() != RequestingModule;
-}
-
-bool Preprocessor::violatesUseDeclarations(
- Module *RequestingModule,
- Module *RequestedModule) {
- ModuleMap &ModMap = HeaderInfo.getModuleMap();
- ModMap.resolveUses(RequestingModule, /*Complain=*/false);
- const SmallVectorImpl<Module *> &AllowedUses = RequestingModule->DirectUses;
- SmallVectorImpl<Module *>::const_iterator Declared =
- std::find(AllowedUses.begin(), AllowedUses.end(), RequestedModule);
- return Declared == AllowedUses.end();
-}
-
-void Preprocessor::verifyModuleInclude(SourceLocation FilenameLoc,
- StringRef Filename,
- const FileEntry *IncFileEnt) {
- Module *RequestingModule = getModuleForLocation(FilenameLoc);
- if (RequestingModule)
- HeaderInfo.getModuleMap().resolveUses(RequestingModule, /*Complain=*/false);
- ModuleMap::KnownHeader RequestedModule =
- HeaderInfo.getModuleMap().findModuleForHeader(IncFileEnt,
- RequestingModule);
-
- if (RequestingModule == RequestedModule.getModule())
- return; // No faults wihin a module, or between files both not in modules.
-
- if (RequestingModule != HeaderInfo.getModuleMap().SourceModule)
- return; // No errors for indirect modules.
- // This may be a bit of a problem for modules with no source files.
-
- if (RequestedModule && violatesPrivateInclude(RequestingModule, IncFileEnt,
- RequestedModule.getRole(),
- RequestedModule.getModule()))
- Diag(FilenameLoc, diag::error_use_of_private_header_outside_module)
- << Filename;
-
- // FIXME: Add support for FixIts in module map files and offer adding the
- // required use declaration.
- if (RequestingModule && getLangOpts().ModulesDeclUse &&
- violatesUseDeclarations(RequestingModule, RequestedModule.getModule()))
- Diag(FilenameLoc, diag::error_undeclared_use_of_module)
- << Filename;
-}
-
const FileEntry *Preprocessor::LookupFile(
SourceLocation FilenameLoc,
StringRef Filename,
@@ -624,12 +567,12 @@ const FileEntry *Preprocessor::LookupFile(
SmallVectorImpl<char> *RelativePath,
ModuleMap::KnownHeader *SuggestedModule,
bool SkipCache) {
- // If the header lookup mechanism may be relative to the current file, pass in
- // info about where the current file is.
- const FileEntry *CurFileEnt = 0;
+ // If the header lookup mechanism may be relative to the current inclusion
+ // stack, record the parent #includes.
+ SmallVector<const FileEntry *, 16> Includers;
if (!FromDir) {
FileID FID = getCurrentFileLexer()->getFileID();
- CurFileEnt = SourceMgr.getFileEntryForID(FID);
+ const FileEntry *FileEnt = SourceMgr.getFileEntryForID(FID);
// If there is no file entry associated with this file, it must be the
// predefines buffer. Any other file is not lexed with a normal lexer, so
@@ -637,48 +580,74 @@ const FileEntry *Preprocessor::LookupFile(
// predefines buffer, resolve #include references (which come from the
// -include command line argument) as if they came from the main file, this
// affects file lookup etc.
- if (CurFileEnt == 0) {
- FID = SourceMgr.getMainFileID();
- CurFileEnt = SourceMgr.getFileEntryForID(FID);
+ if (!FileEnt)
+ FileEnt = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
+
+ if (FileEnt)
+ Includers.push_back(FileEnt);
+
+ // MSVC searches the current include stack from top to bottom for
+ // headers included by quoted include directives.
+ // See: http://msdn.microsoft.com/en-us/library/36k2cdd4.aspx
+ if (LangOpts.MSVCCompat && !isAngled) {
+ for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) {
+ IncludeStackInfo &ISEntry = IncludeMacroStack[e - i - 1];
+ if (IsFileLexer(ISEntry))
+ if ((FileEnt = SourceMgr.getFileEntryForID(
+ ISEntry.ThePPLexer->getFileID())))
+ Includers.push_back(FileEnt);
+ }
}
}
// Do a standard file entry lookup.
CurDir = CurDirLookup;
const FileEntry *FE = HeaderInfo.LookupFile(
- Filename, isAngled, FromDir, CurDir, CurFileEnt,
- SearchPath, RelativePath, SuggestedModule, SkipCache);
+ Filename, FilenameLoc, isAngled, FromDir, CurDir, Includers, SearchPath,
+ RelativePath, SuggestedModule, SkipCache);
if (FE) {
- if (SuggestedModule)
- verifyModuleInclude(FilenameLoc, Filename, FE);
+ if (SuggestedModule && !LangOpts.AsmPreprocessor)
+ HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
+ getModuleForLocation(FilenameLoc), FilenameLoc, Filename, FE);
return FE;
}
+ const FileEntry *CurFileEnt;
// Otherwise, see if this is a subframework header. If so, this is relative
// to one of the headers on the #include stack. Walk the list of the current
// headers on the #include stack and pass them to HeaderInfo.
if (IsFileLexer()) {
- if ((CurFileEnt = SourceMgr.getFileEntryForID(CurPPLexer->getFileID())))
+ if ((CurFileEnt = SourceMgr.getFileEntryForID(CurPPLexer->getFileID()))) {
if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt,
SearchPath, RelativePath,
- SuggestedModule)))
+ SuggestedModule))) {
+ if (SuggestedModule && !LangOpts.AsmPreprocessor)
+ HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
+ getModuleForLocation(FilenameLoc), FilenameLoc, Filename, FE);
return FE;
+ }
+ }
}
for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) {
IncludeStackInfo &ISEntry = IncludeMacroStack[e-i-1];
if (IsFileLexer(ISEntry)) {
if ((CurFileEnt =
- SourceMgr.getFileEntryForID(ISEntry.ThePPLexer->getFileID())))
+ SourceMgr.getFileEntryForID(ISEntry.ThePPLexer->getFileID()))) {
if ((FE = HeaderInfo.LookupSubframeworkHeader(
Filename, CurFileEnt, SearchPath, RelativePath,
- SuggestedModule)))
+ SuggestedModule))) {
+ if (SuggestedModule && !LangOpts.AsmPreprocessor)
+ HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
+ getModuleForLocation(FilenameLoc), FilenameLoc, Filename, FE);
return FE;
+ }
+ }
}
}
// Otherwise, we really couldn't find the file.
- return 0;
+ return nullptr;
}
@@ -776,7 +745,7 @@ void Preprocessor::HandleDirective(Token &Result) {
return HandleDigitDirective(Result);
default:
IdentifierInfo *II = Result.getIdentifierInfo();
- if (II == 0) break; // Not an identifier.
+ if (!II) break; // Not an identifier.
// Ask what the preprocessor keyword ID is.
switch (II->getPPKeywordID()) {
@@ -986,7 +955,7 @@ void Preprocessor::HandleLineDirective(Token &Tok) {
return DiscardUntilEndOfDirective();
} else {
// Parse and validate the string, converting it into a unique ID.
- StringLiteralParser Literal(&StrTok, 1, *this);
+ StringLiteralParser Literal(StrTok, *this);
assert(Literal.isAscii() && "Didn't allow wide strings in");
if (Literal.hadError)
return DiscardUntilEndOfDirective();
@@ -1122,7 +1091,7 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
return DiscardUntilEndOfDirective();
} else {
// Parse and validate the string, converting it into a unique ID.
- StringLiteralParser Literal(&StrTok, 1, *this);
+ StringLiteralParser Literal(StrTok, *this);
assert(Literal.isAscii() && "Didn't allow wide strings in");
if (Literal.hadError)
return DiscardUntilEndOfDirective();
@@ -1241,7 +1210,7 @@ void Preprocessor::HandleMacroPublicDirective(Token &Tok) {
MacroDirective *MD = getMacroDirective(II);
// If the macro is not defined, this is an error.
- if (MD == 0) {
+ if (!MD) {
Diag(MacroNameTok, diag::err_pp_visibility_non_macro) << II;
return;
}
@@ -1268,7 +1237,7 @@ void Preprocessor::HandleMacroPrivateDirective(Token &Tok) {
MacroDirective *MD = getMacroDirective(II);
// If the macro is not defined, this is an error.
- if (MD == 0) {
+ if (!MD) {
Diag(MacroNameTok, diag::err_pp_visibility_non_macro) << II;
return;
}
@@ -1327,21 +1296,20 @@ bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc,
return isAngled;
}
-/// \brief Handle cases where the \#include name is expanded from a macro
-/// as multiple tokens, which need to be glued together.
-///
-/// This occurs for code like:
-/// \code
-/// \#define FOO <a/b.h>
-/// \#include FOO
-/// \endcode
-/// because in this case, "<a/b.h>" is returned as 7 tokens, not one.
-///
-/// This code concatenates and consumes tokens up to the '>' token. It returns
-/// false if the > was found, otherwise it returns true if it finds and consumes
-/// the EOD marker.
-bool Preprocessor::ConcatenateIncludeName(
- SmallString<128> &FilenameBuffer,
+// \brief Handle cases where the \#include name is expanded from a macro
+// as multiple tokens, which need to be glued together.
+//
+// This occurs for code like:
+// \code
+// \#define FOO <a/b.h>
+// \#include FOO
+// \endcode
+// because in this case, "<a/b.h>" is returned as 7 tokens, not one.
+//
+// This code concatenates and consumes tokens up to the '>' token. It returns
+// false if the > was found, otherwise it returns true if it finds and consumes
+// the EOD marker.
+bool Preprocessor::ConcatenateIncludeName(SmallString<128> &FilenameBuffer,
SourceLocation &End) {
Token CurTok;
@@ -1389,6 +1357,19 @@ bool Preprocessor::ConcatenateIncludeName(
return true;
}
+/// \brief Push a token onto the token stream containing an annotation.
+static void EnterAnnotationToken(Preprocessor &PP,
+ SourceLocation Begin, SourceLocation End,
+ tok::TokenKind Kind, void *AnnotationVal) {
+ Token *Tok = new Token[1];
+ Tok[0].startToken();
+ Tok[0].setKind(Kind);
+ Tok[0].setLocation(Begin);
+ Tok[0].setAnnotationEndLoc(End);
+ Tok[0].setAnnotationValue(AnnotationVal);
+ PP.EnterTokenStream(Tok, 1, true, true);
+}
+
/// HandleIncludeDirective - The "\#include" tokens have just been read, read
/// the file to be included from the lexer, then include it! This is a common
/// routine with functionality shared between \#include, \#include_next and
@@ -1485,10 +1466,16 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// the path.
ModuleMap::KnownHeader SuggestedModule;
SourceLocation FilenameLoc = FilenameTok.getLocation();
+ SmallString<128> NormalizedPath;
+ if (LangOpts.MSVCCompat) {
+ NormalizedPath = Filename.str();
+ llvm::sys::fs::normalize_separators(NormalizedPath);
+ }
const FileEntry *File = LookupFile(
- FilenameLoc, Filename, isAngled, LookupFrom, CurDir,
- Callbacks ? &SearchPath : NULL, Callbacks ? &RelativePath : NULL,
- HeaderInfo.getHeaderSearchOpts().ModuleMaps ? &SuggestedModule : 0);
+ FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename,
+ isAngled, LookupFrom, CurDir, Callbacks ? &SearchPath : nullptr,
+ Callbacks ? &RelativePath : nullptr,
+ HeaderInfo.getHeaderSearchOpts().ModuleMaps ? &SuggestedModule : nullptr);
if (Callbacks) {
if (!File) {
@@ -1501,10 +1488,13 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
HeaderInfo.AddSearchPath(DL, isAngled);
// Try the lookup again, skipping the cache.
- File = LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, CurDir,
- 0, 0, HeaderInfo.getHeaderSearchOpts().ModuleMaps
+ File = LookupFile(FilenameLoc,
+ LangOpts.MSVCCompat ? NormalizedPath.c_str()
+ : Filename,
+ isAngled, LookupFrom, CurDir, nullptr, nullptr,
+ HeaderInfo.getHeaderSearchOpts().ModuleMaps
? &SuggestedModule
- : 0,
+ : nullptr,
/*SkipCache*/ true);
}
}
@@ -1512,23 +1502,26 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
if (!SuggestedModule || !getLangOpts().Modules) {
// Notify the callback object that we've seen an inclusion directive.
- Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled,
- FilenameRange, File,
- SearchPath, RelativePath,
- /*ImportedModule=*/0);
+ Callbacks->InclusionDirective(HashLoc, IncludeTok,
+ LangOpts.MSVCCompat ? NormalizedPath.c_str()
+ : Filename,
+ isAngled, FilenameRange, File, SearchPath,
+ RelativePath, /*ImportedModule=*/nullptr);
}
}
-
- if (File == 0) {
+
+ if (!File) {
if (!SuppressIncludeNotFoundError) {
// If the file could not be located and it was included via angle
// brackets, we can attempt a lookup as though it were a quoted path to
// provide the user with a possible fixit.
if (isAngled) {
File = LookupFile(
- FilenameLoc, Filename, false, LookupFrom, CurDir,
- Callbacks ? &SearchPath : 0, Callbacks ? &RelativePath : 0,
- HeaderInfo.getHeaderSearchOpts().ModuleMaps ? &SuggestedModule : 0);
+ FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename,
+ false, LookupFrom, CurDir, Callbacks ? &SearchPath : nullptr,
+ Callbacks ? &RelativePath : nullptr,
+ HeaderInfo.getHeaderSearchOpts().ModuleMaps ? &SuggestedModule
+ : nullptr);
if (File) {
SourceRange Range(FilenameTok.getLocation(), CharEnd);
Diag(FilenameTok, diag::err_pp_file_not_found_not_fatal) <<
@@ -1590,7 +1583,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// include directive maps to.
bool BuildingImportedModule
= Path[0].first->getName() == getLangOpts().CurrentModule;
-
+
if (!BuildingImportedModule && getLangOpts().ObjC2) {
// If we're not building the imported module, warn that we're going
// to automatically turn this inclusion directive into a module import.
@@ -1609,7 +1602,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
ModuleLoadResult Imported
= TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility,
/*IsIncludeDirective=*/true);
- assert((Imported == 0 || Imported == SuggestedModule.getModule()) &&
+ assert((Imported == nullptr || Imported == SuggestedModule.getModule()) &&
"the imported module is different than the suggested one");
if (!Imported && hadModuleLoaderFatalFailure()) {
@@ -1639,13 +1632,8 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// make the module visible.
// FIXME: Produce this as the current token directly, rather than
// allocating a new token for it.
- Token *Tok = new Token[1];
- Tok[0].startToken();
- Tok[0].setKind(tok::annot_module_include);
- Tok[0].setLocation(HashLoc);
- Tok[0].setAnnotationEndLoc(End);
- Tok[0].setAnnotationValue(Imported);
- EnterTokenStream(Tok, 1, true, true);
+ EnterAnnotationToken(*this, HashLoc, End, tok::annot_module_include,
+ Imported);
}
return;
}
@@ -1665,7 +1653,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled,
FilenameRange, File,
SearchPath, RelativePath,
- /*ImportedModule=*/0);
+ /*ImportedModule=*/nullptr);
}
// The #included file will be considered to be a system header if either it is
@@ -1692,8 +1680,27 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
FileID FID = SourceMgr.createFileID(File, IncludePos, FileCharacter);
assert(!FID.isInvalid() && "Expected valid file ID");
- // Finally, if all is good, enter the new file!
- EnterSourceFile(FID, CurDir, FilenameTok.getLocation());
+ // Determine if we're switching to building a new submodule, and which one.
+ ModuleMap::KnownHeader BuildingModule;
+ if (getLangOpts().Modules && !getLangOpts().CurrentModule.empty()) {
+ Module *RequestingModule = getModuleForLocation(FilenameLoc);
+ BuildingModule =
+ HeaderInfo.getModuleMap().findModuleForHeader(File, RequestingModule);
+ }
+
+ // If all is good, enter the new file!
+ if (EnterSourceFile(FID, CurDir, FilenameTok.getLocation()))
+ return;
+
+ // If we're walking into another part of the same module, let the parser
+ // know that any future declarations are within that other submodule.
+ if (BuildingModule) {
+ assert(!CurSubmodule && "should not have marked this as a module yet");
+ CurSubmodule = BuildingModule.getModule();
+
+ EnterAnnotationToken(*this, HashLoc, End, tok::annot_module_begin,
+ CurSubmodule);
+ }
}
/// HandleIncludeNextDirective - Implements \#include_next.
@@ -1707,9 +1714,9 @@ void Preprocessor::HandleIncludeNextDirective(SourceLocation HashLoc,
// diagnostic.
const DirectoryLookup *Lookup = CurDirLookup;
if (isInPrimaryFile()) {
- Lookup = 0;
+ Lookup = nullptr;
Diag(IncludeNextTok, diag::pp_include_next_in_primary);
- } else if (Lookup == 0) {
+ } else if (!Lookup) {
Diag(IncludeNextTok, diag::pp_include_next_absolute_path);
} else {
// Start looking up in the next directory.
@@ -1738,11 +1745,11 @@ void Preprocessor::HandleMicrosoftImportDirective(Token &Tok) {
void Preprocessor::HandleImportDirective(SourceLocation HashLoc,
Token &ImportTok) {
if (!LangOpts.ObjC1) { // #import is standard for ObjC.
- if (LangOpts.MicrosoftMode)
+ if (LangOpts.MSVCCompat)
return HandleMicrosoftImportDirective(ImportTok);
Diag(ImportTok, diag::ext_pp_import_directive);
}
- return HandleIncludeDirective(HashLoc, ImportTok, 0, true);
+ return HandleIncludeDirective(HashLoc, ImportTok, nullptr, true);
}
/// HandleIncludeMacrosDirective - The -imacros command line option turns into a
@@ -1763,7 +1770,7 @@ void Preprocessor::HandleIncludeMacrosDirective(SourceLocation HashLoc,
// Treat this as a normal #include for checking purposes. If this is
// successful, it will push a new lexer onto the include stack.
- HandleIncludeDirective(HashLoc, IncludeMacrosTok, 0, false);
+ HandleIncludeDirective(HashLoc, IncludeMacrosTok, nullptr, false);
Token TmpTok;
do {
@@ -1823,7 +1830,7 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI, Token &Tok) {
// Handle keywords and identifiers here to accept things like
// #define Foo(for) for.
IdentifierInfo *II = Tok.getIdentifierInfo();
- if (II == 0) {
+ if (!II) {
// #define X(1
Diag(Tok, diag::err_pp_invalid_tok_in_arg_list);
return true;
@@ -2027,7 +2034,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok,
LexUnexpandedToken(Tok);
// Check for a valid macro arg identifier.
- if (Tok.getIdentifierInfo() == 0 ||
+ if (Tok.getIdentifierInfo() == nullptr ||
MI->getArgumentNum(Tok.getIdentifierInfo()) == -1) {
// If this is assembler-with-cpp mode, we accept random gibberish after
@@ -2115,8 +2122,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok,
// If we need warning for not using the macro, add its location in the
// warn-because-unused-macro set. If it gets used it will be removed from set.
if (getSourceManager().isInMainFile(MI->getDefinitionLoc()) &&
- Diags->getDiagnosticLevel(diag::pp_macro_not_used,
- MI->getDefinitionLoc()) != DiagnosticsEngine::Ignored) {
+ !Diags->isIgnored(diag::pp_macro_not_used, MI->getDefinitionLoc())) {
MI->setIsWarnIfUnused(true);
WarnUnusedMacroLocs.insert(MI->getDefinitionLoc());
}
@@ -2143,7 +2149,7 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) {
// Okay, we finally have a valid identifier to undef.
MacroDirective *MD = getMacroDirective(MacroNameTok.getIdentifierInfo());
- const MacroInfo *MI = MD ? MD->getMacroInfo() : 0;
+ const MacroInfo *MI = MD ? MD->getMacroInfo() : nullptr;
// If the callbacks want to know, tell them about the macro #undef.
// Note: no matter if the macro was defined or not.
@@ -2151,7 +2157,8 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) {
Callbacks->MacroUndefined(MacroNameTok, MD);
// If the macro is not defined, this is a noop undef, just return.
- if (MI == 0) return;
+ if (!MI)
+ return;
if (!MI->isUsed() && MI->isWarnIfUnused())
Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used);
@@ -2195,14 +2202,14 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
IdentifierInfo *MII = MacroNameTok.getIdentifierInfo();
MacroDirective *MD = getMacroDirective(MII);
- MacroInfo *MI = MD ? MD->getMacroInfo() : 0;
+ MacroInfo *MI = MD ? MD->getMacroInfo() : nullptr;
if (CurPPLexer->getConditionalStackDepth() == 0) {
// If the start of a top-level #ifdef and if the macro is not defined,
// inform MIOpt that this might be the start of a proper include guard.
// Otherwise it is some other form of unknown conditional which we can't
// handle.
- if (!ReadAnyTokensBeforeDirective && MI == 0) {
+ if (!ReadAnyTokensBeforeDirective && !MI) {
assert(isIfndef && "#ifdef shouldn't reach here");
CurPPLexer->MIOpt.EnterTopLevelIfndef(MII, MacroNameTok.getLocation());
} else
@@ -2241,7 +2248,7 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
++NumIf;
// Parse and evaluate the conditional expression.
- IdentifierInfo *IfNDefMacro = 0;
+ IdentifierInfo *IfNDefMacro = nullptr;
const SourceLocation ConditionalBegin = CurPPLexer->getSourceLocation();
const bool ConditionalTrue = EvaluateDirectiveExpression(IfNDefMacro);
const SourceLocation ConditionalEnd = CurPPLexer->getSourceLocation();
@@ -2259,7 +2266,7 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
if (Callbacks)
Callbacks->If(IfToken.getLocation(),
SourceRange(ConditionalBegin, ConditionalEnd),
- ConditionalTrue);
+ (ConditionalTrue ? PPCallbacks::CVK_True : PPCallbacks::CVK_False));
// Should we include the stuff contained by this directive?
if (ConditionalTrue) {
@@ -2356,7 +2363,7 @@ void Preprocessor::HandleElifDirective(Token &ElifToken) {
if (Callbacks)
Callbacks->Elif(ElifToken.getLocation(),
SourceRange(ConditionalBegin, ConditionalEnd),
- true, CI.IfLoc);
+ PPCallbacks::CVK_NotEvaluated, CI.IfLoc);
// Finally, skip the rest of the contents of this block.
SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index 87c0a6ace6cb..2260bf98f7a5 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -81,7 +81,6 @@ struct DefinedTracker {
/// EvaluateDefined - Process a 'defined(sym)' expression.
static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
bool ValueLive, Preprocessor &PP) {
- IdentifierInfo *II;
SourceLocation beginLoc(PeekTok.getLocation());
Result.setBegin(beginLoc);
@@ -102,18 +101,17 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
PP.setCodeCompletionReached();
PP.LexUnexpandedNonComment(PeekTok);
}
-
+
// If we don't have a pp-identifier now, this is an error.
- if ((II = PeekTok.getIdentifierInfo()) == 0) {
- PP.Diag(PeekTok, diag::err_pp_defined_requires_identifier);
+ if (PP.CheckMacroName(PeekTok, 0))
return true;
- }
// Otherwise, we got an identifier, is it defined to something?
+ IdentifierInfo *II = PeekTok.getIdentifierInfo();
Result.Val = II->hasMacroDefinition();
Result.Val.setIsUnsigned(false); // Result is signed intmax_t.
- MacroDirective *Macro = 0;
+ MacroDirective *Macro = nullptr;
// If there is a macro, mark it used.
if (Result.Val != 0 && ValueLive) {
Macro = PP.getMacroDirective(II);
@@ -130,8 +128,9 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
PP.LexUnexpandedNonComment(PeekTok);
if (PeekTok.isNot(tok::r_paren)) {
- PP.Diag(PeekTok.getLocation(), diag::err_pp_missing_rparen) << "defined";
- PP.Diag(LParenLoc, diag::note_matching) << "(";
+ PP.Diag(PeekTok.getLocation(), diag::err_pp_expected_after)
+ << "'defined'" << tok::r_paren;
+ PP.Diag(LParenLoc, diag::note_matching) << tok::l_paren;
return true;
}
// Consume the ).
@@ -257,9 +256,10 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
// large that it is unsigned" e.g. on 12345678901234567890 where intmax_t
// is 64-bits.
if (!Literal.isUnsigned && Result.Val.isNegative()) {
- // Don't warn for a hex or octal literal: 0x8000..0 shouldn't warn.
+ // Octal, hexadecimal, and binary literals are implicitly unsigned if
+ // the value does not fit into a signed integer type.
if (ValueLive && Literal.getRadix() == 10)
- PP.Diag(PeekTok, diag::warn_integer_too_large_for_signed);
+ PP.Diag(PeekTok, diag::ext_integer_too_large_for_signed);
Result.Val.setIsUnsigned(true);
}
}
@@ -342,7 +342,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
if (PeekTok.isNot(tok::r_paren)) {
PP.Diag(PeekTok.getLocation(), diag::err_pp_expected_rparen)
<< Result.getRange();
- PP.Diag(Start, diag::note_matching) << "(";
+ PP.Diag(Start, diag::note_matching) << tok::l_paren;
return true;
}
DT.State = DefinedTracker::Unknown;
@@ -680,9 +680,9 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
case tok::question: {
// Parse the : part of the expression.
if (PeekTok.isNot(tok::colon)) {
- PP.Diag(PeekTok.getLocation(), diag::err_expected_colon)
- << LHS.getRange(), RHS.getRange();
- PP.Diag(OpLoc, diag::note_matching) << "?";
+ PP.Diag(PeekTok.getLocation(), diag::err_expected)
+ << tok::colon << LHS.getRange() << RHS.getRange();
+ PP.Diag(OpLoc, diag::note_matching) << tok::question;
return true;
}
// Consume the :.
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index 1f970a4450de..22ee971f4889 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -58,7 +58,7 @@ PreprocessorLexer *Preprocessor::getCurrentFileLexer() const {
if (IsFileLexer(ISI))
return ISI.ThePPLexer;
}
- return 0;
+ return nullptr;
}
@@ -68,7 +68,7 @@ PreprocessorLexer *Preprocessor::getCurrentFileLexer() const {
/// EnterSourceFile - Add a source file to the top of the include stack and
/// start lexing tokens from it instead of the current buffer.
-void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
+bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
SourceLocation Loc) {
assert(!CurTokenLexer && "Cannot #include a file inside a macro!");
++NumEnteredSourceFiles;
@@ -79,7 +79,7 @@ void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
if (PTH) {
if (PTHLexer *PL = PTH->CreateLexer(FID)) {
EnterSourceFileWithPTH(PL, CurDir);
- return;
+ return false;
}
}
@@ -91,7 +91,7 @@ void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
SourceLocation FileStart = SourceMgr.getLocForStartOfFile(FID);
Diag(Loc, diag::err_pp_error_opening_file)
<< std::string(SourceMgr.getBufferName(FileStart)) << "";
- return;
+ return true;
}
if (isCodeCompletionEnabled() &&
@@ -102,7 +102,7 @@ void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
}
EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir);
- return;
+ return false;
}
/// EnterSourceFileWithLexer - Add a source file to the top of the include stack
@@ -117,6 +117,7 @@ void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer,
CurLexer.reset(TheLexer);
CurPPLexer = TheLexer;
CurDirLookup = CurDir;
+ CurSubmodule = nullptr;
if (CurLexerKind != CLK_LexAfterModuleImport)
CurLexerKind = CLK_Lexer;
@@ -141,6 +142,7 @@ void Preprocessor::EnterSourceFileWithPTH(PTHLexer *PL,
CurDirLookup = CurDir;
CurPTHLexer.reset(PL);
CurPPLexer = CurPTHLexer.get();
+ CurSubmodule = nullptr;
if (CurLexerKind != CLK_LexAfterModuleImport)
CurLexerKind = CLK_PTHLexer;
@@ -167,7 +169,7 @@ void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd,
}
PushIncludeMacroStack();
- CurDirLookup = 0;
+ CurDirLookup = nullptr;
CurTokenLexer.reset(TokLexer);
if (CurLexerKind != CLK_LexAfterModuleImport)
CurLexerKind = CLK_TokenLexer;
@@ -200,7 +202,7 @@ void Preprocessor::EnterTokenStream(const Token *Toks, unsigned NumToks,
// Save our current state.
PushIncludeMacroStack();
- CurDirLookup = 0;
+ CurDirLookup = nullptr;
CurTokenLexer.reset(TokLexer);
if (CurLexerKind != CLK_LexAfterModuleImport)
CurLexerKind = CLK_TokenLexer;
@@ -244,6 +246,29 @@ void Preprocessor::PropagateLineStartLeadingSpaceInfo(Token &Result) {
// but it might if they're empty?
}
+/// \brief Determine the location to use as the end of the buffer for a lexer.
+///
+/// If the file ends with a newline, form the EOF token on the newline itself,
+/// rather than "on the line following it", which doesn't exist. This makes
+/// diagnostics relating to the end of file include the last file that the user
+/// actually typed, which is goodness.
+const char *Preprocessor::getCurLexerEndPos() {
+ const char *EndPos = CurLexer->BufferEnd;
+ if (EndPos != CurLexer->BufferStart &&
+ (EndPos[-1] == '\n' || EndPos[-1] == '\r')) {
+ --EndPos;
+
+ // Handle \n\r and \r\n:
+ if (EndPos != CurLexer->BufferStart &&
+ (EndPos[-1] == '\n' || EndPos[-1] == '\r') &&
+ EndPos[-1] != EndPos[0])
+ --EndPos;
+ }
+
+ return EndPos;
+}
+
+
/// HandleEndOfFile - This callback is invoked when the lexer hits the end of
/// the current file. This either returns the EOF token or pops a level off
/// the include stack and keeps going.
@@ -259,6 +284,10 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
if (const FileEntry *FE =
SourceMgr.getFileEntryForID(CurPPLexer->getFileID())) {
HeaderInfo.SetFileControllingMacro(FE, ControllingMacro);
+ if (MacroInfo *MI =
+ getMacroInfo(const_cast<IdentifierInfo*>(ControllingMacro))) {
+ MI->UsedForHeaderGuard = true;
+ }
if (const IdentifierInfo *DefinedMacro =
CurPPLexer->MIOpt.GetDefinedMacro()) {
if (!ControllingMacro->hasMacroDefinition() &&
@@ -325,7 +354,7 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
CurPTHLexer.reset();
}
- CurPPLexer = 0;
+ CurPPLexer = nullptr;
return true;
}
@@ -342,7 +371,18 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
FileID ExitedFID;
if (Callbacks && !isEndOfMacro && CurPPLexer)
ExitedFID = CurPPLexer->getFileID();
-
+
+ bool LeavingSubmodule = CurSubmodule && CurLexer;
+ if (LeavingSubmodule) {
+ // Notify the parser that we've left the module.
+ const char *EndPos = getCurLexerEndPos();
+ Result.startToken();
+ CurLexer->BufferPtr = EndPos;
+ CurLexer->FormTokenWithChars(Result, EndPos, tok::annot_module_end);
+ Result.setAnnotationEndLoc(Result.getLocation());
+ Result.setAnnotationValue(CurSubmodule);
+ }
+
// We're done with the #included file.
RemoveTopOfLexerStack();
@@ -357,27 +397,13 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
PPCallbacks::ExitFile, FileType, ExitedFID);
}
- // Client should lex another token.
- return false;
+ // Client should lex another token unless we generated an EOM.
+ return LeavingSubmodule;
}
- // If the file ends with a newline, form the EOF token on the newline itself,
- // rather than "on the line following it", which doesn't exist. This makes
- // diagnostics relating to the end of file include the last file that the user
- // actually typed, which is goodness.
+ // If this is the end of the main file, form an EOF token.
if (CurLexer) {
- const char *EndPos = CurLexer->BufferEnd;
- if (EndPos != CurLexer->BufferStart &&
- (EndPos[-1] == '\n' || EndPos[-1] == '\r')) {
- --EndPos;
-
- // Handle \n\r and \r\n:
- if (EndPos != CurLexer->BufferStart &&
- (EndPos[-1] == '\n' || EndPos[-1] == '\r') &&
- EndPos[-1] != EndPos[0])
- --EndPos;
- }
-
+ const char *EndPos = getCurLexerEndPos();
Result.startToken();
CurLexer->BufferPtr = EndPos;
CurLexer->FormTokenWithChars(Result, EndPos, tok::eof);
@@ -403,13 +429,17 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
}
if (!isIncrementalProcessingEnabled())
- CurPPLexer = 0;
-
- // This is the end of the top-level file. 'WarnUnusedMacroLocs' has collected
- // all macro locations that we need to warn because they are not used.
- for (WarnUnusedMacroLocsTy::iterator
- I=WarnUnusedMacroLocs.begin(), E=WarnUnusedMacroLocs.end(); I!=E; ++I)
- Diag(*I, diag::pp_macro_not_used);
+ CurPPLexer = nullptr;
+
+ if (TUKind == TU_Complete) {
+ // This is the end of the top-level file. 'WarnUnusedMacroLocs' has
+ // collected all macro locations that we need to warn because they are not
+ // used.
+ for (WarnUnusedMacroLocsTy::iterator
+ I=WarnUnusedMacroLocs.begin(), E=WarnUnusedMacroLocs.end();
+ I!=E; ++I)
+ Diag(*I, diag::pp_macro_not_used);
+ }
// If we are building a module that has an umbrella header, make sure that
// each of the headers within the directory covered by the umbrella header
@@ -419,26 +449,25 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
SourceLocation StartLoc
= SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
- if (getDiagnostics().getDiagnosticLevel(
- diag::warn_uncovered_module_header,
- StartLoc) != DiagnosticsEngine::Ignored) {
+ if (!getDiagnostics().isIgnored(diag::warn_uncovered_module_header,
+ StartLoc)) {
ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap();
- typedef llvm::sys::fs::recursive_directory_iterator
- recursive_directory_iterator;
const DirectoryEntry *Dir = Mod->getUmbrellaDir();
- llvm::error_code EC;
- for (recursive_directory_iterator Entry(Dir->getName(), EC), End;
+ vfs::FileSystem &FS = *FileMgr.getVirtualFileSystem();
+ std::error_code EC;
+ for (vfs::recursive_directory_iterator Entry(FS, Dir->getName(), EC), End;
Entry != End && !EC; Entry.increment(EC)) {
using llvm::StringSwitch;
// Check whether this entry has an extension typically associated with
// headers.
- if (!StringSwitch<bool>(llvm::sys::path::extension(Entry->path()))
+ if (!StringSwitch<bool>(llvm::sys::path::extension(Entry->getName()))
.Cases(".h", ".H", ".hh", ".hpp", true)
.Default(false))
continue;
- if (const FileEntry *Header = getFileManager().getFile(Entry->path()))
+ if (const FileEntry *Header =
+ getFileManager().getFile(Entry->getName()))
if (!getSourceManager().hasFileInfo(Header)) {
if (!ModMap.isHeaderInUnavailableModule(Header)) {
// Find the relative path that would access this header.
@@ -456,9 +485,8 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
// mentioned at all in the module map. Such headers
SourceLocation StartLoc
= SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
- if (getDiagnostics().getDiagnosticLevel(diag::warn_forgotten_module_header,
- StartLoc)
- != DiagnosticsEngine::Ignored) {
+ if (!getDiagnostics().isIgnored(diag::warn_forgotten_module_header,
+ StartLoc)) {
ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap();
for (unsigned I = 0, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) {
// We only care about file entries.
@@ -498,7 +526,7 @@ bool Preprocessor::HandleEndOfTokenLexer(Token &Result) {
if (NumCachedTokenLexers == TokenLexerCacheSize)
CurTokenLexer.reset();
else
- TokenLexerCache[NumCachedTokenLexers++] = CurTokenLexer.take();
+ TokenLexerCache[NumCachedTokenLexers++] = CurTokenLexer.release();
// Handle this like a #include file being popped off the stack.
return HandleEndOfFile(Result, true);
@@ -515,7 +543,7 @@ void Preprocessor::RemoveTopOfLexerStack() {
if (NumCachedTokenLexers == TokenLexerCacheSize)
CurTokenLexer.reset();
else
- TokenLexerCache[NumCachedTokenLexers++] = CurTokenLexer.take();
+ TokenLexerCache[NumCachedTokenLexers++] = CurTokenLexer.release();
}
PopIncludeMacroStack();
@@ -531,11 +559,11 @@ void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) {
// We handle this by scanning for the closest real lexer, switching it to
// raw mode and preprocessor mode. This will cause it to return \n as an
// explicit EOD token.
- PreprocessorLexer *FoundLexer = 0;
+ PreprocessorLexer *FoundLexer = nullptr;
bool LexerWasInPPMode = false;
for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) {
IncludeStackInfo &ISI = *(IncludeMacroStack.end()-i-1);
- if (ISI.ThePPLexer == 0) continue; // Scan for a real lexer.
+ if (ISI.ThePPLexer == nullptr) continue; // Scan for a real lexer.
// Once we find a real lexer, mark it as raw mode (disabling macro
// expansions) and preprocessor mode (return EOD). We know that the lexer
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index f20633fda8c9..2d7c6d4b5227 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -7,19 +7,20 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the top level handling of macro expasion for the
+// This file implements the top level handling of macro expansion for the
// preprocessor.
//
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/MacroArgs.h"
+#include "clang/Basic/Attributes.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Lex/ExternalPreprocessorSource.h"
#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/MacroArgs.h"
#include "clang/Lex/MacroInfo.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
@@ -97,6 +98,15 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__INCLUDE_LEVEL__ = RegisterBuiltinMacro(*this, "__INCLUDE_LEVEL__");
Ident__TIMESTAMP__ = RegisterBuiltinMacro(*this, "__TIMESTAMP__");
+ // Microsoft Extensions.
+ if (LangOpts.MicrosoftExt) {
+ Ident__identifier = RegisterBuiltinMacro(*this, "__identifier");
+ Ident__pragma = RegisterBuiltinMacro(*this, "__pragma");
+ } else {
+ Ident__identifier = nullptr;
+ Ident__pragma = nullptr;
+ }
+
// Clang Extensions.
Ident__has_feature = RegisterBuiltinMacro(*this, "__has_feature");
Ident__has_extension = RegisterBuiltinMacro(*this, "__has_extension");
@@ -105,6 +115,7 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__has_include = RegisterBuiltinMacro(*this, "__has_include");
Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next");
Ident__has_warning = RegisterBuiltinMacro(*this, "__has_warning");
+ Ident__is_identifier = RegisterBuiltinMacro(*this, "__is_identifier");
// Modules.
if (LangOpts.Modules) {
@@ -114,17 +125,11 @@ void Preprocessor::RegisterBuiltinMacros() {
if (!LangOpts.CurrentModule.empty())
Ident__MODULE__ = RegisterBuiltinMacro(*this, "__MODULE__");
else
- Ident__MODULE__ = 0;
+ Ident__MODULE__ = nullptr;
} else {
- Ident__building_module = 0;
- Ident__MODULE__ = 0;
+ Ident__building_module = nullptr;
+ Ident__MODULE__ = nullptr;
}
-
- // Microsoft Extensions.
- if (LangOpts.MicrosoftExt)
- Ident__pragma = RegisterBuiltinMacro(*this, "__pragma");
- else
- Ident__pragma = 0;
}
/// isTrivialSingleTokenExpansion - Return true if MI, which has a single token
@@ -135,7 +140,7 @@ static bool isTrivialSingleTokenExpansion(const MacroInfo *MI,
IdentifierInfo *II = MI->getReplacementToken(0).getIdentifierInfo();
// If the token isn't an identifier, it's always literally expanded.
- if (II == 0) return true;
+ if (!II) return true;
// If the information about this identifier is out of date, update it from
// the external source.
@@ -223,7 +228,8 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// If this is a builtin macro, like __LINE__ or _Pragma, handle it specially.
if (MI->isBuiltinMacro()) {
if (Callbacks) Callbacks->MacroExpands(Identifier, MD,
- Identifier.getLocation(),/*Args=*/0);
+ Identifier.getLocation(),
+ /*Args=*/nullptr);
ExpandBuiltinMacro(Identifier);
return true;
}
@@ -231,7 +237,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
/// Args - If this is a function-like macro expansion, this contains,
/// for each macro argument, the list of tokens that were provided to the
/// invocation.
- MacroArgs *Args = 0;
+ MacroArgs *Args = nullptr;
// 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 ')'.
@@ -249,7 +255,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
InMacroArgs = false;
// If there was an error parsing the arguments, bail out.
- if (Args == 0) return true;
+ if (!Args) return true;
++NumFnMacroExpanded;
} else {
@@ -277,7 +283,8 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
for (unsigned i=0, e = DelayedMacroExpandsCallbacks.size(); i!=e; ++i) {
MacroExpandsInfo &Info = DelayedMacroExpandsCallbacks[i];
// FIXME: We lose macro args info with delayed callback.
- Callbacks->MacroExpands(Info.Tok, Info.MD, Info.Range, /*Args=*/0);
+ Callbacks->MacroExpands(Info.Tok, Info.MD, Info.Range,
+ /*Args=*/nullptr);
}
DelayedMacroExpandsCallbacks.clear();
}
@@ -293,11 +300,11 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
for (MacroDirective::DefInfo PrevDef = Def.getPreviousDefinition();
PrevDef && !PrevDef.isUndefined();
PrevDef = PrevDef.getPreviousDefinition()) {
- if (PrevDef.getDirective()->isAmbiguous()) {
- Diag(PrevDef.getMacroInfo()->getDefinitionLoc(),
- diag::note_pp_ambiguous_macro_other)
- << Identifier.getIdentifierInfo();
- }
+ Diag(PrevDef.getMacroInfo()->getDefinitionLoc(),
+ diag::note_pp_ambiguous_macro_other)
+ << Identifier.getIdentifierInfo();
+ if (!PrevDef.getDirective()->isAmbiguous())
+ break;
}
}
@@ -552,7 +559,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
<< MacroName.getIdentifierInfo();
// Do not lose the EOF/EOD. Return it to the client.
MacroName = Tok;
- return 0;
+ return nullptr;
} else {
// Do not lose the EOF/EOD.
Token *Toks = new Token[1];
@@ -584,7 +591,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// If this is a comment token in the argument list and we're just in
// -C mode (not -CC mode), discard the comment.
continue;
- } else if (Tok.getIdentifierInfo() != 0) {
+ } else if (Tok.getIdentifierInfo() != nullptr) {
// Reading macro arguments can cause macros that we are currently
// expanding from to be popped off the expansion stack. Doing so causes
// them to be reenabled for expansion. Here we record whether any
@@ -668,29 +675,18 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
DiagnosticBuilder DB =
Diag(MacroName,
diag::note_init_list_at_beginning_of_macro_argument);
- for (SmallVector<SourceRange, 4>::iterator
- Range = InitLists.begin(), RangeEnd = InitLists.end();
- Range != RangeEnd; ++Range) {
- if (DB.hasMaxRanges())
- break;
- DB << *Range;
- }
+ for (const SourceRange &Range : InitLists)
+ DB << Range;
}
- return 0;
+ return nullptr;
}
if (FixedNumArgs != MinArgsExpected)
- return 0;
+ return nullptr;
DiagnosticBuilder DB = Diag(MacroName, diag::note_suggest_parens_for_macro);
- for (SmallVector<SourceRange, 4>::iterator
- ParenLocation = ParenHints.begin(), ParenEnd = ParenHints.end();
- ParenLocation != ParenEnd; ++ParenLocation) {
- if (DB.hasMaxFixItHints())
- break;
- DB << FixItHint::CreateInsertion(ParenLocation->getBegin(), "(");
- if (DB.hasMaxFixItHints())
- break;
- DB << FixItHint::CreateInsertion(ParenLocation->getEnd(), ")");
+ for (const SourceRange &ParenLocation : ParenHints) {
+ DB << FixItHint::CreateInsertion(ParenLocation.getBegin(), "(");
+ DB << FixItHint::CreateInsertion(ParenLocation.getEnd(), ")");
}
ArgTokens.swap(FixedArgTokens);
NumActuals = FixedNumArgs;
@@ -746,7 +742,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
Diag(Tok, diag::err_too_few_args_in_macro_invoc);
Diag(MI->getDefinitionLoc(), diag::note_macro_here)
<< MacroName.getIdentifierInfo();
- return 0;
+ return nullptr;
}
// Add a marker EOF token to the end of the token list for this argument.
@@ -768,7 +764,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
Diag(MacroName, diag::err_too_many_args_in_macro_invoc);
Diag(MI->getDefinitionLoc(), diag::note_macro_here)
<< MacroName.getIdentifierInfo();
- return 0;
+ return nullptr;
}
return MacroArgs::create(MI, ArgTokens, isVarargsElided, *this);
@@ -783,7 +779,7 @@ Token *Preprocessor::cacheMacroExpandedTokens(TokenLexer *tokLexer,
ArrayRef<Token> tokens) {
assert(tokLexer);
if (tokens.empty())
- return 0;
+ return nullptr;
size_t newIndex = MacroExpandedTokens.size();
bool cacheNeedsToGrow = tokens.size() >
@@ -796,7 +792,7 @@ Token *Preprocessor::cacheMacroExpandedTokens(TokenLexer *tokLexer,
for (unsigned i = 0, e = MacroExpandingLexersStack.size(); i != e; ++i) {
TokenLexer *prevLexer;
size_t tokIndex;
- llvm::tie(prevLexer, tokIndex) = MacroExpandingLexersStack[i];
+ std::tie(prevLexer, tokIndex) = MacroExpandingLexersStack[i];
prevLexer->Tokens = MacroExpandedTokens.data() + tokIndex;
}
}
@@ -819,7 +815,7 @@ void Preprocessor::removeCachedMacroExpandedTokensOfLastLexer() {
/// the identifier tokens inserted.
static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc,
Preprocessor &PP) {
- time_t TT = time(0);
+ time_t TT = time(nullptr);
struct tm *TM = localtime(&TT);
static const char * const Months[] = {
@@ -881,7 +877,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("attribute_unused_on_fields", true)
.Case("blocks", LangOpts.Blocks)
.Case("c_thread_safety_attributes", true)
- .Case("cxx_exceptions", LangOpts.Exceptions)
+ .Case("cxx_exceptions", LangOpts.CXXExceptions)
.Case("cxx_rtti", LangOpts.RTTI)
.Case("enumerator_attributes", true)
.Case("memory_sanitizer", LangOpts.Sanitize.Memory)
@@ -913,7 +909,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("c_atomic", LangOpts.C11)
.Case("c_generic_selections", LangOpts.C11)
.Case("c_static_assert", LangOpts.C11)
- .Case("c_thread_local",
+ .Case("c_thread_local",
LangOpts.C11 && PP.getTargetInfo().isTLSSupported())
// C++11 features
.Case("cxx_access_control_sfinae", LangOpts.CPlusPlus11)
@@ -957,12 +953,17 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("cxx_aggregate_nsdmi", LangOpts.CPlusPlus1y)
.Case("cxx_binary_literals", LangOpts.CPlusPlus1y)
.Case("cxx_contextual_conversions", LangOpts.CPlusPlus1y)
- //.Case("cxx_generic_lambdas", LangOpts.CPlusPlus1y)
+ .Case("cxx_decltype_auto", LangOpts.CPlusPlus1y)
+ .Case("cxx_generic_lambdas", LangOpts.CPlusPlus1y)
.Case("cxx_init_captures", LangOpts.CPlusPlus1y)
.Case("cxx_relaxed_constexpr", LangOpts.CPlusPlus1y)
.Case("cxx_return_type_deduction", LangOpts.CPlusPlus1y)
- //.Case("cxx_runtime_arrays", LangOpts.CPlusPlus1y)
.Case("cxx_variable_templates", LangOpts.CPlusPlus1y)
+ // C++ TSes
+ //.Case("cxx_runtime_arrays", LangOpts.CPlusPlusTSArrays)
+ //.Case("cxx_concepts", LangOpts.CPlusPlusTSConcepts)
+ // FIXME: Should this be __has_feature or __has_extension?
+ //.Case("raw_invocation_type", LangOpts.CPlusPlus)
// Type traits
.Case("has_nothrow_assign", LangOpts.CPlusPlus)
.Case("has_nothrow_copy", LangOpts.CPlusPlus)
@@ -975,6 +976,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("is_abstract", LangOpts.CPlusPlus)
.Case("is_base_of", LangOpts.CPlusPlus)
.Case("is_class", LangOpts.CPlusPlus)
+ .Case("is_constructible", LangOpts.CPlusPlus)
.Case("is_convertible_to", LangOpts.CPlusPlus)
.Case("is_empty", LangOpts.CPlusPlus)
.Case("is_enum", LangOpts.CPlusPlus)
@@ -1004,8 +1006,8 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) {
// If the use of an extension results in an error diagnostic, extensions are
// effectively unavailable, so just return false here.
- if (PP.getDiagnostics().getExtensionHandlingBehavior() ==
- DiagnosticsEngine::Ext_Error)
+ if (PP.getDiagnostics().getExtensionHandlingBehavior() >=
+ diag::Severity::Error)
return false;
const LangOptions &LangOpts = PP.getLangOpts();
@@ -1039,24 +1041,10 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) {
// C++1y features supported by other languages as extensions.
.Case("cxx_binary_literals", true)
.Case("cxx_init_captures", LangOpts.CPlusPlus11)
- .Case("cxx_variable_templates", true)
+ .Case("cxx_variable_templates", LangOpts.CPlusPlus)
.Default(false);
}
-/// HasAttribute - Return true if we recognize and implement the attribute
-/// specified by the given identifier.
-static bool HasAttribute(const IdentifierInfo *II) {
- StringRef Name = II->getName();
- // Normalize the attribute name, __foo__ becomes foo.
- if (Name.startswith("__") && Name.endswith("__") && Name.size() >= 4)
- Name = Name.substr(2, Name.size() - 4);
-
- // FIXME: Do we need to handle namespaces here?
- return llvm::StringSwitch<bool>(Name)
-#include "clang/Lex/AttrSpellings.inc"
- .Default(false);
-}
-
/// EvaluateHasIncludeCommon - Process a '__has_include("path")'
/// or '__has_include_next("path")' expression.
/// Returns true if successful.
@@ -1080,7 +1068,7 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
if (Tok.isNot(tok::l_paren)) {
// No '(', use end of last token.
LParenLoc = PP.getLocForEndOfToken(LParenLoc);
- PP.Diag(LParenLoc, diag::err_pp_missing_lparen) << II->getName();
+ PP.Diag(LParenLoc, diag::err_pp_expected_after) << II << tok::l_paren;
// If the next token looks like a filename or the start of one,
// assume it is and process it as such.
if (!Tok.is(tok::angle_string_literal) && !Tok.is(tok::string_literal) &&
@@ -1142,9 +1130,9 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
// Ensure we have a trailing ).
if (Tok.isNot(tok::r_paren)) {
- PP.Diag(PP.getLocForEndOfToken(FilenameLoc), diag::err_pp_missing_rparen)
- << II->getName();
- PP.Diag(LParenLoc, diag::note_matching) << "(";
+ PP.Diag(PP.getLocForEndOfToken(FilenameLoc), diag::err_pp_expected_after)
+ << II << tok::r_paren;
+ PP.Diag(LParenLoc, diag::note_matching) << tok::l_paren;
return false;
}
@@ -1157,18 +1145,18 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
// Search include directories.
const DirectoryLookup *CurDir;
const FileEntry *File =
- PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, CurDir, NULL,
- NULL, NULL);
+ PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, CurDir,
+ nullptr, nullptr, nullptr);
// Get the result value. A result of true means the file exists.
- return File != 0;
+ return File != nullptr;
}
/// EvaluateHasInclude - Process a '__has_include("path")' expression.
/// Returns true if successful.
static bool EvaluateHasInclude(Token &Tok, IdentifierInfo *II,
Preprocessor &PP) {
- return EvaluateHasIncludeCommon(Tok, II, PP, NULL);
+ return EvaluateHasIncludeCommon(Tok, II, PP, nullptr);
}
/// EvaluateHasIncludeNext - Process '__has_include_next("path")' expression.
@@ -1180,9 +1168,9 @@ static bool EvaluateHasIncludeNext(Token &Tok,
// issue a diagnostic.
const DirectoryLookup *Lookup = PP.GetCurDirLookup();
if (PP.isInPrimaryFile()) {
- Lookup = 0;
+ Lookup = nullptr;
PP.Diag(Tok, diag::pp_include_next_in_primary);
- } else if (Lookup == 0) {
+ } else if (!Lookup) {
PP.Diag(Tok, diag::pp_include_next_absolute_path);
} else {
// Start looking up in the next directory.
@@ -1201,7 +1189,8 @@ static bool EvaluateBuildingModule(Token &Tok,
// Ensure we have a '('.
if (Tok.isNot(tok::l_paren)) {
- PP.Diag(Tok.getLocation(), diag::err_pp_missing_lparen) << II->getName();
+ PP.Diag(Tok.getLocation(), diag::err_pp_expected_after) << II
+ << tok::l_paren;
return false;
}
@@ -1225,8 +1214,9 @@ static bool EvaluateBuildingModule(Token &Tok,
// Ensure we have a trailing ).
if (Tok.isNot(tok::r_paren)) {
- PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName();
- PP.Diag(LParenLoc, diag::note_matching) << "(";
+ PP.Diag(Tok.getLocation(), diag::err_pp_expected_after) << II
+ << tok::r_paren;
+ PP.Diag(LParenLoc, diag::note_matching) << tok::l_paren;
return false;
}
@@ -1253,7 +1243,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
llvm::raw_svector_ostream OS(TmpBuffer);
// Set up the return result.
- Tok.setIdentifierInfo(0);
+ Tok.setIdentifierInfo(nullptr);
Tok.clearFlag(Token::NeedsCleaning);
if (II == Ident__LINE__) {
@@ -1304,6 +1294,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
}
Tok.setKind(tok::string_literal);
} else if (II == Ident__DATE__) {
+ Diag(Tok.getLocation(), diag::warn_pp_date_time);
if (!DATELoc.isValid())
ComputeDATE_TIME(DATELoc, TIMELoc, *this);
Tok.setKind(tok::string_literal);
@@ -1313,6 +1304,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Tok.getLength()));
return;
} else if (II == Ident__TIME__) {
+ Diag(Tok.getLocation(), diag::warn_pp_date_time);
if (!TIMELoc.isValid())
ComputeDATE_TIME(DATELoc, TIMELoc, *this);
Tok.setKind(tok::string_literal);
@@ -1337,12 +1329,13 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
OS << Depth;
Tok.setKind(tok::numeric_constant);
} else if (II == Ident__TIMESTAMP__) {
+ Diag(Tok.getLocation(), diag::warn_pp_date_time);
// MSVC, ICC, GCC, VisualAge C++ extension. The generated string should be
// of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime.
// Get the file that we are lexing out of. If we're currently lexing from
// a macro, dig into the include stack.
- const FileEntry *CurFile = 0;
+ const FileEntry *CurFile = nullptr;
PreprocessorLexer *TheLexer = getCurrentFileLexer();
if (TheLexer)
@@ -1357,7 +1350,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Result = "??? ??? ?? ??:??:?? ????\n";
}
// Surround the string with " and strip the trailing newline.
- OS << '"' << StringRef(Result, strlen(Result)-1) << '"';
+ OS << '"' << StringRef(Result).drop_back() << '"';
Tok.setKind(tok::string_literal);
} else if (II == Ident__COUNTER__) {
// __COUNTER__ expands to a simple numeric value.
@@ -1366,12 +1359,13 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
} else if (II == Ident__has_feature ||
II == Ident__has_extension ||
II == Ident__has_builtin ||
+ II == Ident__is_identifier ||
II == Ident__has_attribute) {
// The argument to these builtins should be a parenthesized identifier.
SourceLocation StartLoc = Tok.getLocation();
bool IsValid = false;
- IdentifierInfo *FeatureII = 0;
+ IdentifierInfo *FeatureII = nullptr;
// Read the '('.
LexUnexpandedToken(Tok);
@@ -1389,11 +1383,14 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
bool Value = false;
if (!IsValid)
Diag(StartLoc, diag::err_feature_check_malformed);
+ else if (II == Ident__is_identifier)
+ Value = FeatureII->getTokenID() == tok::identifier;
else if (II == Ident__has_builtin) {
// Check for a builtin is trivial.
Value = FeatureII->getBuiltinID() != 0;
} else if (II == Ident__has_attribute)
- Value = HasAttribute(FeatureII);
+ Value = hasAttribute(AttrSyntax::Generic, nullptr, FeatureII,
+ getTargetInfo().getTriple(), getLangOpts());
else if (II == Ident__has_extension)
Value = HasExtension(*this, FeatureII);
else {
@@ -1449,6 +1446,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
break;
}
+ // FIXME: Should we accept "-R..." flags here, or should that be handled
+ // by a separate __has_remark?
if (WarningName.size() < 3 || WarningName[0] != '-' ||
WarningName[1] != 'W') {
Diag(StrStartLoc, diag::warn_has_warning_invalid_option);
@@ -1461,7 +1460,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
// worth special casing.
SmallVector<diag::kind, 10> Diags;
Value = !getDiagnostics().getDiagnosticIDs()->
- getDiagnosticsInGroup(WarningName.substr(2), Diags);
+ getDiagnosticsInGroup(diag::Flavor::WarningOrError,
+ WarningName.substr(2), Diags);
} while (false);
OS << (int)Value;
@@ -1479,6 +1479,44 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
IdentifierInfo *ModuleII = getIdentifierInfo(getLangOpts().CurrentModule);
Tok.setIdentifierInfo(ModuleII);
Tok.setKind(ModuleII->getTokenID());
+ } else if (II == Ident__identifier) {
+ SourceLocation Loc = Tok.getLocation();
+
+ // We're expecting '__identifier' '(' identifier ')'. Try to recover
+ // if the parens are missing.
+ LexNonComment(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ // No '(', use end of last token.
+ Diag(getLocForEndOfToken(Loc), diag::err_pp_expected_after)
+ << II << tok::l_paren;
+ // If the next token isn't valid as our argument, we can't recover.
+ if (!Tok.isAnnotation() && Tok.getIdentifierInfo())
+ Tok.setKind(tok::identifier);
+ return;
+ }
+
+ SourceLocation LParenLoc = Tok.getLocation();
+ LexNonComment(Tok);
+
+ if (!Tok.isAnnotation() && Tok.getIdentifierInfo())
+ Tok.setKind(tok::identifier);
+ else {
+ Diag(Tok.getLocation(), diag::err_pp_identifier_arg_not_identifier)
+ << Tok.getKind();
+ // Don't walk past anything that's not a real token.
+ if (Tok.is(tok::eof) || Tok.is(tok::eod) || Tok.isAnnotation())
+ return;
+ }
+
+ // Discard the ')', preserving 'Tok' as our result.
+ Token RParen;
+ LexNonComment(RParen);
+ if (RParen.isNot(tok::r_paren)) {
+ Diag(getLocForEndOfToken(Tok.getLocation()), diag::err_pp_expected_after)
+ << Tok.getKind() << tok::r_paren;
+ Diag(LParenLoc, diag::note_matching) << tok::l_paren;
+ }
+ return;
} else {
llvm_unreachable("Unknown identifier!");
}
diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp
index e2629a3b2c49..fce31c4be296 100644
--- a/lib/Lex/PTHLexer.cpp
+++ b/lib/Lex/PTHLexer.cpp
@@ -15,21 +15,21 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
#include "clang/Basic/IdentifierTable.h"
-#include "clang/Basic/OnDiskHashTable.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/PTHManager.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/Token.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/EndianStream.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/system_error.h"
+#include "llvm/Support/OnDiskHashTable.h"
+#include <memory>
+#include <system_error>
using namespace clang;
-using namespace clang::io;
-#define DISK_TOKEN_SIZE (1+1+2+4+4)
+static const unsigned StoredTokenSize = 1 + 1 + 2 + 4 + 4;
//===----------------------------------------------------------------------===//
// PTHLexer methods.
@@ -37,7 +37,7 @@ using namespace clang::io;
PTHLexer::PTHLexer(Preprocessor &PP, FileID FID, const unsigned char *D,
const unsigned char *ppcond, PTHManager &PM)
- : PreprocessorLexer(&PP, FID), TokBuf(D), CurPtr(D), LastHashTokPtr(0),
+ : PreprocessorLexer(&PP, FID), TokBuf(D), CurPtr(D), LastHashTokPtr(nullptr),
PPCond(ppcond), CurPPCondPtr(ppcond), PTHMgr(PM) {
FileStartLoc = PP.getSourceManager().getLocForStartOfFile(FID);
@@ -47,14 +47,17 @@ bool PTHLexer::Lex(Token& Tok) {
//===--------------------------------------==//
// Read the raw token data.
//===--------------------------------------==//
+ using namespace llvm::support;
// Shadow CurPtr into an automatic variable.
const unsigned char *CurPtrShadow = CurPtr;
// Read in the data for the token.
- unsigned Word0 = ReadLE32(CurPtrShadow);
- uint32_t IdentifierID = ReadLE32(CurPtrShadow);
- uint32_t FileOffset = ReadLE32(CurPtrShadow);
+ unsigned Word0 = endian::readNext<uint32_t, little, aligned>(CurPtrShadow);
+ uint32_t IdentifierID =
+ endian::readNext<uint32_t, little, aligned>(CurPtrShadow);
+ uint32_t FileOffset =
+ endian::readNext<uint32_t, little, aligned>(CurPtrShadow);
tok::TokenKind TKind = (tok::TokenKind) (Word0 & 0xFF);
Token::TokenFlags TFlags = (Token::TokenFlags) ((Word0 >> 8) & 0xFF);
@@ -107,7 +110,7 @@ bool PTHLexer::Lex(Token& Tok) {
}
if (TKind == tok::hash && Tok.isAtStartOfLine()) {
- LastHashTokPtr = CurPtr - DISK_TOKEN_SIZE;
+ LastHashTokPtr = CurPtr - StoredTokenSize;
assert(!LexingRawMode);
PP->HandleDirective(Tok);
@@ -176,7 +179,7 @@ void PTHLexer::DiscardToEndOfLine() {
if (y & Token::StartOfLine) break;
// Skip to the next token.
- p += DISK_TOKEN_SIZE;
+ p += StoredTokenSize;
}
CurPtr = p;
@@ -184,18 +187,19 @@ void PTHLexer::DiscardToEndOfLine() {
/// SkipBlock - Used by Preprocessor to skip the current conditional block.
bool PTHLexer::SkipBlock() {
+ using namespace llvm::support;
assert(CurPPCondPtr && "No cached PP conditional information.");
assert(LastHashTokPtr && "No known '#' token.");
- const unsigned char* HashEntryI = 0;
+ const unsigned char *HashEntryI = nullptr;
uint32_t TableIdx;
do {
// Read the token offset from the side-table.
- uint32_t Offset = ReadLE32(CurPPCondPtr);
+ uint32_t Offset = endian::readNext<uint32_t, little, aligned>(CurPPCondPtr);
// Read the target table index from the side-table.
- TableIdx = ReadLE32(CurPPCondPtr);
+ TableIdx = endian::readNext<uint32_t, little, aligned>(CurPPCondPtr);
// Compute the actual memory address of the '#' token data for this entry.
HashEntryI = TokBuf + Offset;
@@ -212,12 +216,13 @@ bool PTHLexer::SkipBlock() {
PPCond + TableIdx*(sizeof(uint32_t)*2);
assert(NextPPCondPtr >= CurPPCondPtr);
// Read where we should jump to.
- const unsigned char* HashEntryJ = TokBuf + ReadLE32(NextPPCondPtr);
+ const unsigned char *HashEntryJ =
+ TokBuf + endian::readNext<uint32_t, little, aligned>(NextPPCondPtr);
if (HashEntryJ <= LastHashTokPtr) {
// Jump directly to the next entry in the side table.
HashEntryI = HashEntryJ;
- TableIdx = ReadLE32(NextPPCondPtr);
+ TableIdx = endian::readNext<uint32_t, little, aligned>(NextPPCondPtr);
CurPPCondPtr = NextPPCondPtr;
}
}
@@ -232,8 +237,9 @@ bool PTHLexer::SkipBlock() {
CurPPCondPtr = NextPPCondPtr;
// Read where we should jump to.
- HashEntryI = TokBuf + ReadLE32(NextPPCondPtr);
- uint32_t NextIdx = ReadLE32(NextPPCondPtr);
+ HashEntryI =
+ TokBuf + endian::readNext<uint32_t, little, aligned>(NextPPCondPtr);
+ uint32_t NextIdx = endian::readNext<uint32_t, little, aligned>(NextPPCondPtr);
// By construction NextIdx will be zero if this is a #endif. This is useful
// to know to obviate lexing another token.
@@ -249,10 +255,10 @@ bool PTHLexer::SkipBlock() {
// already points 'elif'. Just return.
if (CurPtr > HashEntryI) {
- assert(CurPtr == HashEntryI + DISK_TOKEN_SIZE);
+ assert(CurPtr == HashEntryI + StoredTokenSize);
// Did we reach a #endif? If so, go ahead and consume that token as well.
if (isEndif)
- CurPtr += DISK_TOKEN_SIZE*2;
+ CurPtr += StoredTokenSize * 2;
else
LastHashTokPtr = HashEntryI;
@@ -268,10 +274,12 @@ bool PTHLexer::SkipBlock() {
// Skip the '#' token.
assert(((tok::TokenKind)*CurPtr) == tok::hash);
- CurPtr += DISK_TOKEN_SIZE;
+ CurPtr += StoredTokenSize;
// Did we reach a #endif? If so, go ahead and consume that token as well.
- if (isEndif) { CurPtr += DISK_TOKEN_SIZE*2; }
+ if (isEndif) {
+ CurPtr += StoredTokenSize * 2;
+ }
return isEndif;
}
@@ -282,8 +290,10 @@ SourceLocation PTHLexer::getSourceLocation() {
// handling a #included file. Just read the necessary data from the token
// data buffer to construct the SourceLocation object.
// NOTE: This is a virtual function; hence it is defined out-of-line.
- const unsigned char *OffsetPtr = CurPtr + (DISK_TOKEN_SIZE - 4);
- uint32_t Offset = ReadLE32(OffsetPtr);
+ using namespace llvm::support;
+
+ const unsigned char *OffsetPtr = CurPtr + (StoredTokenSize - 4);
+ uint32_t Offset = endian::readNext<uint32_t, little, aligned>(OffsetPtr);
return FileStartLoc.getLocWithOffset(Offset);
}
@@ -310,14 +320,18 @@ public:
class PTHFileLookupCommonTrait {
public:
typedef std::pair<unsigned char, const char*> internal_key_type;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
- static unsigned ComputeHash(internal_key_type x) {
+ static hash_value_type ComputeHash(internal_key_type x) {
return llvm::HashString(x.second);
}
static std::pair<unsigned, unsigned>
ReadKeyDataLength(const unsigned char*& d) {
- unsigned keyLen = (unsigned) ReadUnalignedLE16(d);
+ using namespace llvm::support;
+ unsigned keyLen =
+ (unsigned)endian::readNext<uint16_t, little, unaligned>(d);
unsigned dataLen = (unsigned) *(d++);
return std::make_pair(keyLen, dataLen);
}
@@ -344,21 +358,20 @@ public:
static PTHFileData ReadData(const internal_key_type& k,
const unsigned char* d, unsigned) {
assert(k.first == 0x1 && "Only file lookups can match!");
- uint32_t x = ::ReadUnalignedLE32(d);
- uint32_t y = ::ReadUnalignedLE32(d);
+ using namespace llvm::support;
+ uint32_t x = endian::readNext<uint32_t, little, unaligned>(d);
+ uint32_t y = endian::readNext<uint32_t, little, unaligned>(d);
return PTHFileData(x, y);
}
};
class PTHStringLookupTrait {
public:
- typedef uint32_t
- data_type;
-
- typedef const std::pair<const char*, unsigned>
- external_key_type;
-
+ typedef uint32_t data_type;
+ typedef const std::pair<const char*, unsigned> external_key_type;
typedef external_key_type internal_key_type;
+ typedef uint32_t hash_value_type;
+ typedef unsigned offset_type;
static bool EqualKey(const internal_key_type& a,
const internal_key_type& b) {
@@ -366,7 +379,7 @@ public:
: false;
}
- static unsigned ComputeHash(const internal_key_type& a) {
+ static hash_value_type ComputeHash(const internal_key_type& a) {
return llvm::HashString(StringRef(a.first, a.second));
}
@@ -376,7 +389,10 @@ public:
static std::pair<unsigned, unsigned>
ReadKeyDataLength(const unsigned char*& d) {
- return std::make_pair((unsigned) ReadUnalignedLE16(d), sizeof(uint32_t));
+ using namespace llvm::support;
+ return std::make_pair(
+ (unsigned)endian::readNext<uint16_t, little, unaligned>(d),
+ sizeof(uint32_t));
}
static std::pair<const char*, unsigned>
@@ -387,14 +403,15 @@ public:
static uint32_t ReadData(const internal_key_type& k, const unsigned char* d,
unsigned) {
- return ::ReadUnalignedLE32(d);
+ using namespace llvm::support;
+ return endian::readNext<uint32_t, little, unaligned>(d);
}
};
} // end anonymous namespace
-typedef OnDiskChainedHashTable<PTHFileLookupTrait> PTHFileLookup;
-typedef OnDiskChainedHashTable<PTHStringLookupTrait> PTHStringIdLookup;
+typedef llvm::OnDiskChainedHashTable<PTHFileLookupTrait> PTHFileLookup;
+typedef llvm::OnDiskChainedHashTable<PTHStringLookupTrait> PTHStringIdLookup;
//===----------------------------------------------------------------------===//
// PTHManager methods.
@@ -408,7 +425,7 @@ PTHManager::PTHManager(const llvm::MemoryBuffer* buf, void* fileLookup,
const char* originalSourceFile)
: Buf(buf), PerIDCache(perIDCache), FileLookup(fileLookup),
IdDataTable(idDataTable), StringIdLookup(stringIdLookup),
- NumIds(numIds), PP(0), SpellingBase(spellingBase),
+ NumIds(numIds), PP(nullptr), SpellingBase(spellingBase),
OriginalSourceFile(originalSourceFile) {}
PTHManager::~PTHManager() {
@@ -419,19 +436,23 @@ PTHManager::~PTHManager() {
}
static void InvalidPTH(DiagnosticsEngine &Diags, const char *Msg) {
- Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, Msg));
+ Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0")) << Msg;
}
PTHManager *PTHManager::Create(const std::string &file,
DiagnosticsEngine &Diags) {
// Memory map the PTH file.
- OwningPtr<llvm::MemoryBuffer> File;
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileOrErr =
+ llvm::MemoryBuffer::getFile(file);
- if (llvm::MemoryBuffer::getFile(file, File)) {
+ if (!FileOrErr) {
// FIXME: Add ec.message() to this diag.
Diags.Report(diag::err_invalid_pth_file) << file;
- return 0;
+ return nullptr;
}
+ std::unique_ptr<llvm::MemoryBuffer> File = std::move(FileOrErr.get());
+
+ using namespace llvm::support;
// Get the buffer ranges and check if there are at least three 32-bit
// words at the end of the file.
@@ -442,19 +463,19 @@ PTHManager *PTHManager::Create(const std::string &file,
if ((BufEnd - BufBeg) < (signed)(sizeof("cfe-pth") + 4 + 4) ||
memcmp(BufBeg, "cfe-pth", sizeof("cfe-pth")) != 0) {
Diags.Report(diag::err_invalid_pth_file) << file;
- return 0;
+ return nullptr;
}
// Read the PTH version.
const unsigned char *p = BufBeg + (sizeof("cfe-pth"));
- unsigned Version = ReadLE32(p);
+ unsigned Version = endian::readNext<uint32_t, little, aligned>(p);
if (Version < PTHManager::Version) {
InvalidPTH(Diags,
Version < PTHManager::Version
? "PTH file uses an older PTH format that is no longer supported"
: "PTH file uses a newer PTH format that cannot be read");
- return 0;
+ return nullptr;
}
// Compute the address of the index table at the end of the PTH file.
@@ -462,20 +483,21 @@ PTHManager *PTHManager::Create(const std::string &file,
if (PrologueOffset >= BufEnd) {
Diags.Report(diag::err_invalid_pth_file) << file;
- return 0;
+ return nullptr;
}
// Construct the file lookup table. This will be used for mapping from
// FileEntry*'s to cached tokens.
const unsigned char* FileTableOffset = PrologueOffset + sizeof(uint32_t)*2;
- const unsigned char* FileTable = BufBeg + ReadLE32(FileTableOffset);
+ const unsigned char *FileTable =
+ BufBeg + endian::readNext<uint32_t, little, aligned>(FileTableOffset);
if (!(FileTable > BufBeg && FileTable < BufEnd)) {
Diags.Report(diag::err_invalid_pth_file) << file;
- return 0; // FIXME: Proper error diagnostic?
+ return nullptr; // FIXME: Proper error diagnostic?
}
- OwningPtr<PTHFileLookup> FL(PTHFileLookup::Create(FileTable, BufBeg));
+ std::unique_ptr<PTHFileLookup> FL(PTHFileLookup::Create(FileTable, BufBeg));
// Warn if the PTH file is empty. We still want to create a PTHManager
// as the PTH could be used with -include-pth.
@@ -485,65 +507,71 @@ PTHManager *PTHManager::Create(const std::string &file,
// Get the location of the table mapping from persistent ids to the
// data needed to reconstruct identifiers.
const unsigned char* IDTableOffset = PrologueOffset + sizeof(uint32_t)*0;
- const unsigned char* IData = BufBeg + ReadLE32(IDTableOffset);
+ const unsigned char *IData =
+ BufBeg + endian::readNext<uint32_t, little, aligned>(IDTableOffset);
if (!(IData >= BufBeg && IData < BufEnd)) {
Diags.Report(diag::err_invalid_pth_file) << file;
- return 0;
+ return nullptr;
}
// Get the location of the hashtable mapping between strings and
// persistent IDs.
const unsigned char* StringIdTableOffset = PrologueOffset + sizeof(uint32_t)*1;
- const unsigned char* StringIdTable = BufBeg + ReadLE32(StringIdTableOffset);
+ const unsigned char *StringIdTable =
+ BufBeg + endian::readNext<uint32_t, little, aligned>(StringIdTableOffset);
if (!(StringIdTable >= BufBeg && StringIdTable < BufEnd)) {
Diags.Report(diag::err_invalid_pth_file) << file;
- return 0;
+ return nullptr;
}
- OwningPtr<PTHStringIdLookup> SL(PTHStringIdLookup::Create(StringIdTable,
- BufBeg));
+ std::unique_ptr<PTHStringIdLookup> SL(
+ PTHStringIdLookup::Create(StringIdTable, BufBeg));
// Get the location of the spelling cache.
const unsigned char* spellingBaseOffset = PrologueOffset + sizeof(uint32_t)*3;
- const unsigned char* spellingBase = BufBeg + ReadLE32(spellingBaseOffset);
+ const unsigned char *spellingBase =
+ BufBeg + endian::readNext<uint32_t, little, aligned>(spellingBaseOffset);
if (!(spellingBase >= BufBeg && spellingBase < BufEnd)) {
Diags.Report(diag::err_invalid_pth_file) << file;
- return 0;
+ return nullptr;
}
// Get the number of IdentifierInfos and pre-allocate the identifier cache.
- uint32_t NumIds = ReadLE32(IData);
+ uint32_t NumIds = endian::readNext<uint32_t, little, aligned>(IData);
// Pre-allocate the persistent ID -> IdentifierInfo* cache. We use calloc()
// so that we in the best case only zero out memory once when the OS returns
// us new pages.
- IdentifierInfo** PerIDCache = 0;
+ IdentifierInfo **PerIDCache = nullptr;
if (NumIds) {
PerIDCache = (IdentifierInfo**)calloc(NumIds, sizeof(*PerIDCache));
if (!PerIDCache) {
InvalidPTH(Diags, "Could not allocate memory for processing PTH file");
- return 0;
+ return nullptr;
}
}
// Compute the address of the original source file.
const unsigned char* originalSourceBase = PrologueOffset + sizeof(uint32_t)*4;
- unsigned len = ReadUnalignedLE16(originalSourceBase);
- if (!len) originalSourceBase = 0;
+ unsigned len =
+ endian::readNext<uint16_t, little, unaligned>(originalSourceBase);
+ if (!len) originalSourceBase = nullptr;
// Create the new PTHManager.
- return new PTHManager(File.take(), FL.take(), IData, PerIDCache,
- SL.take(), NumIds, spellingBase,
- (const char*) originalSourceBase);
+ return new PTHManager(File.release(), FL.release(), IData, PerIDCache,
+ SL.release(), NumIds, spellingBase,
+ (const char *)originalSourceBase);
}
IdentifierInfo* PTHManager::LazilyCreateIdentifierInfo(unsigned PersistentID) {
+ using namespace llvm::support;
// Look in the PTH file for the string data for the IdentifierInfo object.
const unsigned char* TableEntry = IdDataTable + sizeof(uint32_t)*PersistentID;
- const unsigned char* IDData =
- (const unsigned char*)Buf->getBufferStart() + ReadLE32(TableEntry);
+ const unsigned char *IDData =
+ (const unsigned char *)Buf->getBufferStart() +
+ endian::readNext<uint32_t, little, aligned>(TableEntry);
assert(IDData < (const unsigned char*)Buf->getBufferEnd());
// Allocate the object.
@@ -567,7 +595,7 @@ IdentifierInfo* PTHManager::get(StringRef Name) {
PTHStringIdLookup::iterator I = SL.find(std::make_pair(Name.data(),
Name.size()));
if (I == SL.end()) // No identifier found?
- return 0;
+ return nullptr;
// Match found. Return the identifier!
assert(*I > 0);
@@ -577,7 +605,9 @@ IdentifierInfo* PTHManager::get(StringRef Name) {
PTHLexer *PTHManager::CreateLexer(FileID FID) {
const FileEntry *FE = PP->getSourceManager().getFileEntryForID(FID);
if (!FE)
- return 0;
+ return nullptr;
+
+ using namespace llvm::support;
// Lookup the FileEntry object in our file lookup data structure. It will
// return a variant that indicates whether or not there is an offset within
@@ -586,7 +616,7 @@ PTHLexer *PTHManager::CreateLexer(FileID FID) {
PTHFileLookup::iterator I = PFL.find(FE);
if (I == PFL.end()) // No tokens available?
- return 0;
+ return nullptr;
const PTHFileData& FileData = *I;
@@ -596,8 +626,8 @@ PTHLexer *PTHManager::CreateLexer(FileID FID) {
// Get the location of pp-conditional table.
const unsigned char* ppcond = BufStart + FileData.getPPCondOffset();
- uint32_t Len = ReadLE32(ppcond);
- if (Len == 0) ppcond = 0;
+ uint32_t Len = endian::readNext<uint32_t, little, aligned>(ppcond);
+ if (Len == 0) ppcond = nullptr;
assert(PP && "No preprocessor set yet!");
return new PTHLexer(*PP, FID, data, ppcond, *this);
@@ -650,11 +680,13 @@ public:
d += 4 * 2; // Skip the first 2 words.
}
- uint64_t File = ReadUnalignedLE64(d);
- uint64_t Device = ReadUnalignedLE64(d);
+ using namespace llvm::support;
+
+ uint64_t File = endian::readNext<uint64_t, little, unaligned>(d);
+ uint64_t Device = endian::readNext<uint64_t, little, unaligned>(d);
llvm::sys::fs::UniqueID UniqueID(File, Device);
- time_t ModTime = ReadUnalignedLE64(d);
- uint64_t Size = ReadUnalignedLE64(d);
+ time_t ModTime = endian::readNext<uint64_t, little, unaligned>(d);
+ uint64_t Size = endian::readNext<uint64_t, little, unaligned>(d);
return data_type(Size, ModTime, UniqueID, IsDirectory);
}
@@ -664,7 +696,7 @@ public:
};
class PTHStatCache : public FileSystemStatCache {
- typedef OnDiskChainedHashTable<PTHStatLookupTrait> CacheTy;
+ typedef llvm::OnDiskChainedHashTable<PTHStatLookupTrait> CacheTy;
CacheTy Cache;
public:
@@ -672,22 +704,22 @@ public:
Cache(FL.getNumBuckets(), FL.getNumEntries(), FL.getBuckets(),
FL.getBase()) {}
- ~PTHStatCache() {}
-
LookupResult getStat(const char *Path, FileData &Data, bool isFile,
- int *FileDescriptor) {
+ std::unique_ptr<vfs::File> *F,
+ vfs::FileSystem &FS) override {
// Do the lookup for the file's data in the PTH file.
CacheTy::iterator I = Cache.find(Path);
// If we don't get a hit in the PTH file just forward to 'stat'.
if (I == Cache.end())
- return statChained(Path, Data, isFile, FileDescriptor);
+ return statChained(Path, Data, isFile, F, FS);
const PTHStatData &D = *I;
if (!D.HasData)
return CacheMissing;
+ Data.Name = Path;
Data.Size = D.Size;
Data.ModTime = D.ModTime;
Data.UniqueID = D.UniqueID;
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index e4059eeb6fc0..cf76bdb7a913 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -48,9 +48,7 @@ void EmptyPragmaHandler::HandlePragma(Preprocessor &PP,
//===----------------------------------------------------------------------===//
PragmaNamespace::~PragmaNamespace() {
- for (llvm::StringMap<PragmaHandler*>::iterator
- I = Handlers.begin(), E = Handlers.end(); I != E; ++I)
- delete I->second;
+ llvm::DeleteContainerSeconds(Handlers);
}
/// FindHandler - Check to see if there is already a handler for the
@@ -61,7 +59,7 @@ PragmaHandler *PragmaNamespace::FindHandler(StringRef Name,
bool IgnoreNull) const {
if (PragmaHandler *Handler = Handlers.lookup(Name))
return Handler;
- return IgnoreNull ? 0 : Handlers.lookup(StringRef());
+ return IgnoreNull ? nullptr : Handlers.lookup(StringRef());
}
void PragmaNamespace::AddPragma(PragmaHandler *Handler) {
@@ -90,7 +88,7 @@ void PragmaNamespace::HandlePragma(Preprocessor &PP,
= FindHandler(Tok.getIdentifierInfo() ? Tok.getIdentifierInfo()->getName()
: StringRef(),
/*IgnoreNull=*/false);
- if (Handler == 0) {
+ if (!Handler) {
PP.Diag(Tok, diag::warn_pragma_ignored);
return;
}
@@ -292,7 +290,7 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
Lexer *TL = Lexer::Create_PragmaLexer(TokLoc, PragmaLoc, RParenLoc,
StrVal.size(), *this);
- EnterSourceFileWithLexer(TL, 0);
+ EnterSourceFileWithLexer(TL, nullptr);
// With everything set up, lex this as a #pragma directive.
HandlePragmaDirective(PragmaLoc, PIK__Pragma);
@@ -475,8 +473,9 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
// Search include directories for this file.
const DirectoryLookup *CurDir;
const FileEntry *File = LookupFile(FilenameTok.getLocation(), Filename,
- isAngled, 0, CurDir, NULL, NULL, NULL);
- if (File == 0) {
+ isAngled, nullptr, CurDir, nullptr,
+ nullptr, nullptr);
+ if (!File) {
if (!SuppressIncludeNotFoundError)
Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
return;
@@ -512,7 +511,7 @@ IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) {
if (Tok.isNot(tok::l_paren)) {
Diag(PragmaTok.getLocation(), diag::err_pragma_push_pop_macro_malformed)
<< getSpelling(PragmaTok);
- return 0;
+ return nullptr;
}
// Read the macro name string.
@@ -520,12 +519,12 @@ IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) {
if (Tok.isNot(tok::string_literal)) {
Diag(PragmaTok.getLocation(), diag::err_pragma_push_pop_macro_malformed)
<< getSpelling(PragmaTok);
- return 0;
+ return nullptr;
}
if (Tok.hasUDSuffix()) {
Diag(Tok, diag::err_invalid_string_udl);
- return 0;
+ return nullptr;
}
// Remember the macro string.
@@ -536,7 +535,7 @@ IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) {
if (Tok.isNot(tok::r_paren)) {
Diag(PragmaTok.getLocation(), diag::err_pragma_push_pop_macro_malformed)
<< getSpelling(PragmaTok);
- return 0;
+ return nullptr;
}
assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' &&
@@ -738,7 +737,7 @@ void Preprocessor::AddPragmaHandler(StringRef Namespace,
// we already have the namespace to insert into.
if (PragmaHandler *Existing = PragmaHandlers->FindHandler(Namespace)) {
InsertNS = Existing->getIfNamespace();
- assert(InsertNS != 0 && "Cannot have a pragma namespace and pragma"
+ assert(InsertNS != nullptr && "Cannot have a pragma namespace and pragma"
" handler with the same name!");
} else {
// Otherwise, this namespace doesn't exist yet, create and insert the
@@ -812,8 +811,8 @@ namespace {
/// PragmaOnceHandler - "\#pragma once" marks the file as atomically included.
struct PragmaOnceHandler : public PragmaHandler {
PragmaOnceHandler() : PragmaHandler("once") {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &OnceTok) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &OnceTok) override {
PP.CheckEndOfDirective("pragma once");
PP.HandlePragmaOnce(OnceTok);
}
@@ -823,8 +822,8 @@ struct PragmaOnceHandler : public PragmaHandler {
/// rest of the line is not lexed.
struct PragmaMarkHandler : public PragmaHandler {
PragmaMarkHandler() : PragmaHandler("mark") {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &MarkTok) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &MarkTok) override {
PP.HandlePragmaMark();
}
};
@@ -832,8 +831,8 @@ struct PragmaMarkHandler : public PragmaHandler {
/// PragmaPoisonHandler - "\#pragma poison x" marks x as not usable.
struct PragmaPoisonHandler : public PragmaHandler {
PragmaPoisonHandler() : PragmaHandler("poison") {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &PoisonTok) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &PoisonTok) override {
PP.HandlePragmaPoison(PoisonTok);
}
};
@@ -842,24 +841,24 @@ struct PragmaPoisonHandler : public PragmaHandler {
/// as a system header, which silences warnings in it.
struct PragmaSystemHeaderHandler : public PragmaHandler {
PragmaSystemHeaderHandler() : PragmaHandler("system_header") {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &SHToken) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &SHToken) override {
PP.HandlePragmaSystemHeader(SHToken);
PP.CheckEndOfDirective("pragma");
}
};
struct PragmaDependencyHandler : public PragmaHandler {
PragmaDependencyHandler() : PragmaHandler("dependency") {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &DepToken) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &DepToken) override {
PP.HandlePragmaDependency(DepToken);
}
};
struct PragmaDebugHandler : public PragmaHandler {
PragmaDebugHandler() : PragmaHandler("__debug") {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &DepToken) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &DepToken) override {
Token Tok;
PP.LexUnexpandedToken(Tok);
if (Tok.isNot(tok::identifier)) {
@@ -926,8 +925,9 @@ struct PragmaDebugHandler : public PragmaHandler {
#ifdef _MSC_VER
#pragma warning(disable : 4717)
#endif
- void DebugOverflowStack() {
- DebugOverflowStack();
+ static void DebugOverflowStack() {
+ void (*volatile Self)() = DebugOverflowStack;
+ Self();
}
#ifdef _MSC_VER
#pragma warning(default : 4717)
@@ -942,8 +942,8 @@ private:
public:
explicit PragmaDiagnosticHandler(const char *NS) :
PragmaHandler("diagnostic"), Namespace(NS) {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &DiagToken) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &DiagToken) override {
SourceLocation DiagLoc = DiagToken.getLocation();
Token Tok;
PP.LexUnexpandedToken(Tok);
@@ -954,16 +954,7 @@ public:
IdentifierInfo *II = Tok.getIdentifierInfo();
PPCallbacks *Callbacks = PP.getPPCallbacks();
- diag::Mapping Map;
- if (II->isStr("warning"))
- Map = diag::MAP_WARNING;
- else if (II->isStr("error"))
- Map = diag::MAP_ERROR;
- else if (II->isStr("ignored"))
- Map = diag::MAP_IGNORE;
- else if (II->isStr("fatal"))
- Map = diag::MAP_FATAL;
- else if (II->isStr("pop")) {
+ if (II->isStr("pop")) {
if (!PP.getDiagnostics().popMappings(DiagLoc))
PP.Diag(Tok, diag::warn_pragma_diagnostic_cannot_pop);
else if (Callbacks)
@@ -974,7 +965,16 @@ public:
if (Callbacks)
Callbacks->PragmaDiagnosticPush(DiagLoc, Namespace);
return;
- } else {
+ }
+
+ diag::Severity SV = llvm::StringSwitch<diag::Severity>(II->getName())
+ .Case("ignored", diag::Severity::Ignored)
+ .Case("warning", diag::Severity::Warning)
+ .Case("error", diag::Severity::Error)
+ .Case("fatal", diag::Severity::Fatal)
+ .Default(diag::Severity());
+
+ if (SV == diag::Severity()) {
PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid);
return;
}
@@ -993,46 +993,30 @@ public:
}
if (WarningName.size() < 3 || WarningName[0] != '-' ||
- WarningName[1] != 'W') {
+ (WarningName[1] != 'W' && WarningName[1] != 'R')) {
PP.Diag(StringLoc, diag::warn_pragma_diagnostic_invalid_option);
return;
}
- if (PP.getDiagnostics().setDiagnosticGroupMapping(WarningName.substr(2),
- Map, DiagLoc))
+ if (PP.getDiagnostics().setSeverityForGroup(
+ WarningName[1] == 'W' ? diag::Flavor::WarningOrError
+ : diag::Flavor::Remark,
+ WarningName.substr(2), SV, DiagLoc))
PP.Diag(StringLoc, diag::warn_pragma_diagnostic_unknown_warning)
<< WarningName;
else if (Callbacks)
- Callbacks->PragmaDiagnostic(DiagLoc, Namespace, Map, WarningName);
+ Callbacks->PragmaDiagnostic(DiagLoc, Namespace, SV, WarningName);
}
};
-// Returns -1 on failure.
-static int LexSimpleInt(Preprocessor &PP, Token &Tok) {
- assert(Tok.is(tok::numeric_constant));
- SmallString<8> IntegerBuffer;
- bool NumberInvalid = false;
- StringRef Spelling = PP.getSpelling(Tok, IntegerBuffer, &NumberInvalid);
- if (NumberInvalid)
- return -1;
- NumericLiteralParser Literal(Spelling, Tok.getLocation(), PP);
- if (Literal.hadError || !Literal.isIntegerLiteral() || Literal.hasUDSuffix())
- return -1;
- llvm::APInt APVal(32, 0);
- if (Literal.GetIntegerValue(APVal))
- return -1;
- PP.Lex(Tok);
- return int(APVal.getLimitedValue(INT_MAX));
-}
-
/// "\#pragma warning(...)". MSVC's diagnostics do not map cleanly to clang's
/// diagnostics, so we don't really implement this pragma. We parse it and
/// ignore it to avoid -Wunknown-pragma warnings.
struct PragmaWarningHandler : public PragmaHandler {
PragmaWarningHandler() : PragmaHandler("warning") {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &Tok) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &Tok) override {
// Parse things like:
// warning(push, 1)
// warning(pop)
@@ -1059,8 +1043,10 @@ struct PragmaWarningHandler : public PragmaHandler {
PP.Lex(Tok);
if (Tok.is(tok::comma)) {
PP.Lex(Tok);
- if (Tok.is(tok::numeric_constant))
- Level = LexSimpleInt(PP, Tok);
+ uint64_t Value;
+ if (Tok.is(tok::numeric_constant) &&
+ PP.parseSimpleIntegerLiteral(Tok, Value))
+ Level = int(Value);
if (Level < 0 || Level > 4) {
PP.Diag(Tok, diag::warn_pragma_warning_push_level);
return;
@@ -1104,12 +1090,13 @@ struct PragmaWarningHandler : public PragmaHandler {
SmallVector<int, 4> Ids;
PP.Lex(Tok);
while (Tok.is(tok::numeric_constant)) {
- int Id = LexSimpleInt(PP, Tok);
- if (Id <= 0) {
+ uint64_t Value;
+ if (!PP.parseSimpleIntegerLiteral(Tok, Value) || Value == 0 ||
+ Value > INT_MAX) {
PP.Diag(Tok, diag::warn_pragma_warning_expected_number);
return;
}
- Ids.push_back(Id);
+ Ids.push_back(int(Value));
}
if (Callbacks)
Callbacks->PragmaWarning(DiagLoc, Specifier, Ids);
@@ -1135,8 +1122,8 @@ struct PragmaWarningHandler : public PragmaHandler {
/// PragmaIncludeAliasHandler - "\#pragma include_alias("...")".
struct PragmaIncludeAliasHandler : public PragmaHandler {
PragmaIncludeAliasHandler() : PragmaHandler("include_alias") {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &IncludeAliasTok) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &IncludeAliasTok) override {
PP.HandlePragmaIncludeAlias(IncludeAliasTok);
}
};
@@ -1177,8 +1164,8 @@ public:
StringRef Namespace = StringRef())
: PragmaHandler(PragmaKind(Kind, true)), Kind(Kind), Namespace(Namespace) {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &Tok) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &Tok) override {
SourceLocation MessageLoc = Tok.getLocation();
PP.Lex(Tok);
bool ExpectClosingParen = false;
@@ -1230,8 +1217,8 @@ public:
/// macro on the top of the stack.
struct PragmaPushMacroHandler : public PragmaHandler {
PragmaPushMacroHandler() : PragmaHandler("push_macro") {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &PushMacroTok) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &PushMacroTok) override {
PP.HandlePragmaPushMacro(PushMacroTok);
}
};
@@ -1241,8 +1228,8 @@ struct PragmaPushMacroHandler : public PragmaHandler {
/// macro to the value on the top of the stack.
struct PragmaPopMacroHandler : public PragmaHandler {
PragmaPopMacroHandler() : PragmaHandler("pop_macro") {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &PopMacroTok) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &PopMacroTok) override {
PP.HandlePragmaPopMacro(PopMacroTok);
}
};
@@ -1252,8 +1239,8 @@ struct PragmaPopMacroHandler : public PragmaHandler {
/// PragmaSTDC_FENV_ACCESSHandler - "\#pragma STDC FENV_ACCESS ...".
struct PragmaSTDC_FENV_ACCESSHandler : public PragmaHandler {
PragmaSTDC_FENV_ACCESSHandler() : PragmaHandler("FENV_ACCESS") {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &Tok) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &Tok) override {
tok::OnOffSwitch OOS;
if (PP.LexOnOffSwitch(OOS))
return;
@@ -1266,8 +1253,8 @@ struct PragmaSTDC_FENV_ACCESSHandler : public PragmaHandler {
struct PragmaSTDC_CX_LIMITED_RANGEHandler : public PragmaHandler {
PragmaSTDC_CX_LIMITED_RANGEHandler()
: PragmaHandler("CX_LIMITED_RANGE") {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &Tok) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &Tok) override {
tok::OnOffSwitch OOS;
PP.LexOnOffSwitch(OOS);
}
@@ -1276,8 +1263,8 @@ struct PragmaSTDC_CX_LIMITED_RANGEHandler : public PragmaHandler {
/// PragmaSTDC_UnknownHandler - "\#pragma STDC ...".
struct PragmaSTDC_UnknownHandler : public PragmaHandler {
PragmaSTDC_UnknownHandler() {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &UnknownTok) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &UnknownTok) override {
// C99 6.10.6p2, unknown forms are not allowed.
PP.Diag(UnknownTok, diag::ext_stdc_pragma_ignored);
}
@@ -1287,8 +1274,8 @@ struct PragmaSTDC_UnknownHandler : public PragmaHandler {
/// \#pragma clang arc_cf_code_audited begin/end
struct PragmaARCCFCodeAuditedHandler : public PragmaHandler {
PragmaARCCFCodeAuditedHandler() : PragmaHandler("arc_cf_code_audited") {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &NameTok) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &NameTok) override {
SourceLocation Loc = NameTok.getLocation();
bool IsBegin;
@@ -1351,8 +1338,8 @@ struct PragmaARCCFCodeAuditedHandler : public PragmaHandler {
struct PragmaRegionHandler : public PragmaHandler {
PragmaRegionHandler(const char *pragma) : PragmaHandler(pragma) { }
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &NameTok) {
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &NameTok) override {
// #pragma region: endregion matches can be verified
// __pragma(region): no sense, but ignored by msvc
// _Pragma is not valid for MSVC, but there isn't any point
@@ -1401,3 +1388,26 @@ void Preprocessor::RegisterBuiltinPragmas() {
AddPragmaHandler(new PragmaRegionHandler("endregion"));
}
}
+
+/// Ignore all pragmas, useful for modes such as -Eonly which would otherwise
+/// warn about those pragmas being unknown.
+void Preprocessor::IgnorePragmas() {
+ AddPragmaHandler(new EmptyPragmaHandler());
+ // Also ignore all pragmas in all namespaces created
+ // in Preprocessor::RegisterBuiltinPragmas().
+ AddPragmaHandler("GCC", new EmptyPragmaHandler());
+ AddPragmaHandler("clang", new EmptyPragmaHandler());
+ if (PragmaHandler *NS = PragmaHandlers->FindHandler("STDC")) {
+ // Preprocessor::RegisterBuiltinPragmas() already registers
+ // PragmaSTDC_UnknownHandler as the empty handler, so remove it first,
+ // otherwise there will be an assert about a duplicate handler.
+ PragmaNamespace *STDCNamespace = NS->getIfNamespace();
+ assert(STDCNamespace &&
+ "Invalid namespace, registered as a regular pragma handler!");
+ if (PragmaHandler *Existing = STDCNamespace->FindHandler("", false)) {
+ RemovePragmaHandler("STDC", Existing);
+ delete Existing;
+ }
+ }
+ AddPragmaHandler("STDC", new EmptyPragmaHandler());
+}
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
index 090aeedb7150..41bb581bb0aa 100644
--- a/lib/Lex/PreprocessingRecord.cpp
+++ b/lib/Lex/PreprocessingRecord.cpp
@@ -40,7 +40,7 @@ InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec,
PreprocessingRecord::PreprocessingRecord(SourceManager &SM)
: SourceMgr(SM),
- ExternalSource(0) {
+ ExternalSource(nullptr) {
}
/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities
@@ -334,7 +334,7 @@ PreprocessedEntity *PreprocessingRecord::getPreprocessedEntity(PPEntityID PPID){
}
if (PPID.ID == 0)
- return 0;
+ return nullptr;
unsigned Index = PPID.ID - 1;
assert(Index < PreprocessedEntities.size() &&
"Out-of bounds local preprocessed entity");
@@ -361,7 +361,7 @@ MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) {
llvm::DenseMap<const MacroInfo *, MacroDefinition *>::iterator Pos
= MacroDefinitions.find(MI);
if (Pos == MacroDefinitions.end())
- return 0;
+ return nullptr;
return Pos->second;
}
@@ -406,6 +406,10 @@ void PreprocessingRecord::Defined(const Token &MacroNameTok,
MacroNameTok.getLocation());
}
+void PreprocessingRecord::SourceRangeSkipped(SourceRange Range) {
+ SkippedRanges.push_back(Range);
+}
+
void PreprocessingRecord::MacroExpands(const Token &Id,const MacroDirective *MD,
SourceRange Range,
const MacroArgs *Args) {
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index b500efee4e61..4a11803aa954 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -26,7 +26,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/MacroArgs.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -35,6 +34,7 @@
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/LiteralSupport.h"
+#include "clang/Lex/MacroArgs.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/Pragma.h"
@@ -42,8 +42,8 @@
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Lex/ScratchBuffer.h"
#include "llvm/ADT/APFloat.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Capacity.h"
#include "llvm/Support/ConvertUTF.h"
@@ -56,20 +56,21 @@ ExternalPreprocessorSource::~ExternalPreprocessorSource() { }
Preprocessor::Preprocessor(IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
DiagnosticsEngine &diags, LangOptions &opts,
- const TargetInfo *target, SourceManager &SM,
- HeaderSearch &Headers, ModuleLoader &TheModuleLoader,
+ SourceManager &SM, HeaderSearch &Headers,
+ ModuleLoader &TheModuleLoader,
IdentifierInfoLookup *IILookup, bool OwnsHeaders,
- bool DelayInitialization, bool IncrProcessing)
- : PPOpts(PPOpts), Diags(&diags), LangOpts(opts), Target(target),
+ TranslationUnitKind TUKind)
+ : PPOpts(PPOpts), Diags(&diags), LangOpts(opts), Target(nullptr),
FileMgr(Headers.getFileMgr()), SourceMgr(SM), HeaderInfo(Headers),
- TheModuleLoader(TheModuleLoader), ExternalSource(0),
- Identifiers(opts, IILookup), IncrementalProcessing(IncrProcessing),
- CodeComplete(0), CodeCompletionFile(0), CodeCompletionOffset(0),
- LastTokenWasAt(false), ModuleImportExpectsIdentifier(false),
- CodeCompletionReached(0), SkipMainFilePreamble(0, true), CurPPLexer(0),
- CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0),
- MacroArgCache(0), Record(0), MIChainHead(0), MICache(0),
- DeserialMIChainHead(0) {
+ TheModuleLoader(TheModuleLoader), ExternalSource(nullptr),
+ Identifiers(opts, IILookup), IncrementalProcessing(false), TUKind(TUKind),
+ CodeComplete(nullptr), CodeCompletionFile(nullptr),
+ CodeCompletionOffset(0), LastTokenWasAt(false),
+ ModuleImportExpectsIdentifier(false), CodeCompletionReached(0),
+ SkipMainFilePreamble(0, true), CurPPLexer(nullptr),
+ CurDirLookup(nullptr), CurLexerKind(CLK_Lexer), CurSubmodule(nullptr),
+ Callbacks(nullptr), MacroArgCache(nullptr), Record(nullptr),
+ MIChainHead(nullptr), MICache(nullptr), DeserialMIChainHead(nullptr) {
OwnsHeaderSearch = OwnsHeaders;
ScratchBuf = new ScratchBuffer(SourceMgr);
@@ -127,39 +128,35 @@ Preprocessor::Preprocessor(IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
Ident___abnormal_termination = getIdentifierInfo("__abnormal_termination");
Ident_AbnormalTermination = getIdentifierInfo("AbnormalTermination");
} else {
- Ident__exception_info = Ident__exception_code = Ident__abnormal_termination = 0;
- Ident___exception_info = Ident___exception_code = Ident___abnormal_termination = 0;
- Ident_GetExceptionInfo = Ident_GetExceptionCode = Ident_AbnormalTermination = 0;
- }
-
- if (!DelayInitialization) {
- assert(Target && "Must provide target information for PP initialization");
- Initialize(*Target);
+ Ident__exception_info = Ident__exception_code = nullptr;
+ Ident__abnormal_termination = Ident___exception_info = nullptr;
+ Ident___exception_code = Ident___abnormal_termination = nullptr;
+ Ident_GetExceptionInfo = Ident_GetExceptionCode = nullptr;
+ Ident_AbnormalTermination = nullptr;
}
}
Preprocessor::~Preprocessor() {
assert(BacktrackPositions.empty() && "EnableBacktrack/Backtrack imbalance!");
- while (!IncludeMacroStack.empty()) {
- delete IncludeMacroStack.back().TheLexer;
- delete IncludeMacroStack.back().TheTokenLexer;
- IncludeMacroStack.pop_back();
- }
+ IncludeMacroStack.clear();
// Free any macro definitions.
for (MacroInfoChain *I = MIChainHead ; I ; I = I->Next)
I->MI.Destroy();
// Free any cached macro expanders.
+ // This populates MacroArgCache, so all TokenLexers need to be destroyed
+ // before the code below that frees up the MacroArgCache list.
for (unsigned i = 0, e = NumCachedTokenLexers; i != e; ++i)
delete TokenLexerCache[i];
+ CurTokenLexer.reset();
for (DeserializedMacroInfoChain *I = DeserialMIChainHead ; I ; I = I->Next)
I->MI.Destroy();
// Free any cached MacroArgs.
- for (MacroArgs *ArgList = MacroArgCache; ArgList; )
+ for (MacroArgs *ArgList = MacroArgCache; ArgList;)
ArgList = ArgList->deallocate();
// Release pragma information.
@@ -444,8 +441,8 @@ void Preprocessor::CreateString(StringRef Str, Token &Tok,
Module *Preprocessor::getCurrentModule() {
if (getLangOpts().CurrentModule.empty())
- return 0;
-
+ return nullptr;
+
return getHeaderSearchInfo().lookupModule(getLangOpts().CurrentModule);
}
@@ -467,8 +464,8 @@ void Preprocessor::EnterMainSourceFile() {
// a main file.
if (!SourceMgr.isLoadedFileID(MainFileID)) {
// Enter the main file source buffer.
- EnterSourceFile(MainFileID, 0, SourceLocation());
-
+ EnterSourceFile(MainFileID, nullptr, SourceLocation());
+
// If we've been asked to skip bytes in the main file (e.g., as part of a
// precompiled preamble), do so now.
if (SkipMainFilePreamble.first > 0)
@@ -485,12 +482,12 @@ void Preprocessor::EnterMainSourceFile() {
llvm::MemoryBuffer *SB =
llvm::MemoryBuffer::getMemBufferCopy(Predefines, "<built-in>");
assert(SB && "Cannot create predefined source buffer");
- FileID FID = SourceMgr.createFileIDForMemBuffer(SB);
+ FileID FID = SourceMgr.createFileID(SB);
assert(!FID.isInvalid() && "Could not create FileID for predefines?");
setPredefinesFileID(FID);
// Start parsing the predefines.
- EnterSourceFile(FID, 0, SourceLocation());
+ EnterSourceFile(FID, nullptr, SourceLocation());
}
void Preprocessor::EndSourceFile() {
@@ -503,60 +500,17 @@ void Preprocessor::EndSourceFile() {
// Lexer Event Handling.
//===----------------------------------------------------------------------===//
-static void appendCodePoint(unsigned Codepoint,
- llvm::SmallVectorImpl<char> &Str) {
- char ResultBuf[4];
- char *ResultPtr = ResultBuf;
- bool Res = llvm::ConvertCodePointToUTF8(Codepoint, ResultPtr);
- (void)Res;
- assert(Res && "Unexpected conversion failure");
- Str.append(ResultBuf, ResultPtr);
-}
-
-static void expandUCNs(SmallVectorImpl<char> &Buf, StringRef Input) {
- for (StringRef::iterator I = Input.begin(), E = Input.end(); I != E; ++I) {
- if (*I != '\\') {
- Buf.push_back(*I);
- continue;
- }
-
- ++I;
- assert(*I == 'u' || *I == 'U');
-
- unsigned NumHexDigits;
- if (*I == 'u')
- NumHexDigits = 4;
- else
- NumHexDigits = 8;
-
- assert(I + NumHexDigits <= E);
-
- uint32_t CodePoint = 0;
- for (++I; NumHexDigits != 0; ++I, --NumHexDigits) {
- unsigned Value = llvm::hexDigitValue(*I);
- assert(Value != -1U);
-
- CodePoint <<= 4;
- CodePoint += Value;
- }
-
- appendCodePoint(CodePoint, Buf);
- --I;
- }
-}
-
/// LookUpIdentifierInfo - Given a tok::raw_identifier token, look up the
/// identifier information for the token and install it into the token,
/// updating the token kind accordingly.
IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier) const {
- assert(Identifier.getRawIdentifierData() != 0 && "No raw identifier data!");
+ assert(!Identifier.getRawIdentifier().empty() && "No raw identifier data!");
// Look up this token, see if it is a macro, or if it is a language keyword.
IdentifierInfo *II;
if (!Identifier.needsCleaning() && !Identifier.hasUCN()) {
// No cleaning needed, just use the characters from the lexed buffer.
- II = getIdentifierInfo(StringRef(Identifier.getRawIdentifierData(),
- Identifier.getLength()));
+ II = getIdentifierInfo(Identifier.getRawIdentifier());
} else {
// Cleaning needed, alloca a buffer, clean into it, then use the buffer.
SmallString<64> IdentifierBuffer;
@@ -669,7 +623,7 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
// name of a macro.
// FIXME: This warning is disabled in cases where it shouldn't be, like
// "#define constexpr constexpr", "int constexpr;"
- if (II.isCXX11CompatKeyword() & !DisableMacroExpansion) {
+ if (II.isCXX11CompatKeyword() && !DisableMacroExpansion) {
Diag(Identifier, diag::warn_cxx11_keyword) << II.getName();
// Don't diagnose this keyword again in this translation unit.
II.setIsCXX11CompatKeyword(false);
@@ -679,7 +633,7 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
// then we act as if it is the actual operator and not the textual
// representation of it.
if (II.isCPlusPlusOperatorKeyword())
- Identifier.setIdentifierInfo(0);
+ Identifier.setIdentifierInfo(nullptr);
// If this is an extension token, diagnose its use.
// We avoid diagnosing tokens that originate from macro definitions.
@@ -803,7 +757,7 @@ bool Preprocessor::FinishLexStringLiteral(Token &Result, std::string &String,
} while (Result.is(tok::string_literal));
// Concatenate and parse the strings.
- StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this);
+ StringLiteralParser Literal(StrToks, *this);
assert(Literal.isAscii() && "Didn't allow wide strings in");
if (Literal.hadError)
@@ -819,6 +773,24 @@ bool Preprocessor::FinishLexStringLiteral(Token &Result, std::string &String,
return true;
}
+bool Preprocessor::parseSimpleIntegerLiteral(Token &Tok, uint64_t &Value) {
+ assert(Tok.is(tok::numeric_constant));
+ SmallString<8> IntegerBuffer;
+ bool NumberInvalid = false;
+ StringRef Spelling = getSpelling(Tok, IntegerBuffer, &NumberInvalid);
+ if (NumberInvalid)
+ return false;
+ NumericLiteralParser Literal(Spelling, Tok.getLocation(), *this);
+ if (Literal.hadError || !Literal.isIntegerLiteral() || Literal.hasUDSuffix())
+ return false;
+ llvm::APInt APVal(64, 0);
+ if (Literal.GetIntegerValue(APVal))
+ return false;
+ Lex(Tok);
+ Value = APVal.getLimitedValue();
+ return true;
+}
+
void Preprocessor::addCommentHandler(CommentHandler *Handler) {
assert(Handler && "NULL comment handler");
assert(std::find(CommentHandlers.begin(), CommentHandlers.end(), Handler) ==
diff --git a/lib/Lex/ScratchBuffer.cpp b/lib/Lex/ScratchBuffer.cpp
index 3d363fa4b472..d7104b178860 100644
--- a/lib/Lex/ScratchBuffer.cpp
+++ b/lib/Lex/ScratchBuffer.cpp
@@ -21,7 +21,8 @@ using namespace clang;
//than a page, almost certainly enough for anything. :)
static const unsigned ScratchBufSize = 4060;
-ScratchBuffer::ScratchBuffer(SourceManager &SM) : SourceMgr(SM), CurBuffer(0) {
+ScratchBuffer::ScratchBuffer(SourceManager &SM)
+ : SourceMgr(SM), CurBuffer(nullptr) {
// Set BytesUsed so that the first call to getToken will require an alloc.
BytesUsed = ScratchBufSize;
}
@@ -65,7 +66,7 @@ void ScratchBuffer::AllocScratchBuffer(unsigned RequestLen) {
llvm::MemoryBuffer *Buf =
llvm::MemoryBuffer::getNewMemBuffer(RequestLen, "<scratch space>");
- FileID FID = SourceMgr.createFileIDForMemBuffer(Buf);
+ FileID FID = SourceMgr.createFileID(Buf);
BufferStartLoc = SourceMgr.getLocForStartOfFile(FID);
CurBuffer = const_cast<char*>(Buf->getBufferStart());
BytesUsed = 1;
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index 0213afcee921..9d03e8d30b8b 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -12,9 +12,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/TokenLexer.h"
-#include "clang/Lex/MacroArgs.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/MacroArgs.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallString.h"
@@ -37,6 +37,7 @@ void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, MacroInfo *MI,
ExpandLocEnd = ELEnd;
AtStartOfLine = Tok.isAtStartOfLine();
HasLeadingSpace = Tok.hasLeadingSpace();
+ NextTokGetsSpace = false;
Tokens = &*Macro->tokens_begin();
OwnsTokens = false;
DisableMacroExpansion = false;
@@ -85,8 +86,8 @@ void TokenLexer::Init(const Token *TokArray, unsigned NumToks,
// associated with it.
destroy();
- Macro = 0;
- ActualArgs = 0;
+ Macro = nullptr;
+ ActualArgs = nullptr;
Tokens = TokArray;
OwnsTokens = ownsTokens;
DisableMacroExpansion = disableMacroExpansion;
@@ -95,6 +96,7 @@ void TokenLexer::Init(const Token *TokArray, unsigned NumToks,
ExpandLocStart = ExpandLocEnd = SourceLocation();
AtStartOfLine = false;
HasLeadingSpace = false;
+ NextTokGetsSpace = false;
MacroExpansionStart = SourceLocation();
// Set HasLeadingSpace/AtStartOfLine so that the first token will be
@@ -111,7 +113,7 @@ void TokenLexer::destroy() {
// the expanded tokens.
if (OwnsTokens) {
delete [] Tokens;
- Tokens = 0;
+ Tokens = nullptr;
OwnsTokens = false;
}
@@ -119,13 +121,9 @@ void TokenLexer::destroy() {
if (ActualArgs) ActualArgs->destroy(PP);
}
-/// Remove comma ahead of __VA_ARGS__, if present, according to compiler dialect
-/// settings. Returns true if the comma is removed.
-static bool MaybeRemoveCommaBeforeVaArgs(SmallVectorImpl<Token> &ResultToks,
- bool &NextTokGetsSpace,
- bool HasPasteOperator,
- MacroInfo *Macro, unsigned MacroArgNo,
- Preprocessor &PP) {
+bool TokenLexer::MaybeRemoveCommaBeforeVaArgs(
+ SmallVectorImpl<Token> &ResultToks, bool HasPasteOperator, MacroInfo *Macro,
+ unsigned MacroArgNo, Preprocessor &PP) {
// Is the macro argument __VA_ARGS__?
if (!Macro->isVariadic() || MacroArgNo != Macro->getNumArgs()-1)
return false;
@@ -133,7 +131,7 @@ static bool MaybeRemoveCommaBeforeVaArgs(SmallVectorImpl<Token> &ResultToks,
// In Microsoft-compatibility mode, a comma is removed in the expansion
// of " ... , __VA_ARGS__ " if __VA_ARGS__ is empty. This extension is
// not supported by gcc.
- if (!HasPasteOperator && !PP.getLangOpts().MicrosoftMode)
+ if (!HasPasteOperator && !PP.getLangOpts().MSVCCompat)
return false;
// GCC removes the comma in the expansion of " ... , ## __VA_ARGS__ " if
@@ -179,16 +177,14 @@ void TokenLexer::ExpandFunctionArguments() {
// we install the newly expanded sequence as the new 'Tokens' list.
bool MadeChange = false;
- // NextTokGetsSpace - When this is true, the next token appended to the
- // output list will get a leading space, regardless of whether it had one to
- // begin with or not. This is used for placemarker support.
- bool NextTokGetsSpace = false;
-
for (unsigned i = 0, e = NumTokens; i != e; ++i) {
// If we found the stringify operator, get the argument stringified. The
// preprocessor already verified that the following token is a macro name
// when the #define was parsed.
const Token &CurTok = Tokens[i];
+ if (i != 0 && !Tokens[i-1].is(tok::hashhash) && CurTok.hasLeadingSpace())
+ NextTokGetsSpace = true;
+
if (CurTok.is(tok::hash) || CurTok.is(tok::hashat)) {
int ArgNo = Macro->getArgumentNum(Tokens[i+1].getIdentifierInfo());
assert(ArgNo != -1 && "Token following # is not an argument?");
@@ -213,7 +209,7 @@ void TokenLexer::ExpandFunctionArguments() {
// The stringified/charified string leading space flag gets set to match
// the #/#@ operator.
- if (CurTok.hasLeadingSpace() || NextTokGetsSpace)
+ if (NextTokGetsSpace)
Res.setFlag(Token::LeadingSpace);
ResultToks.push_back(Res);
@@ -223,6 +219,13 @@ void TokenLexer::ExpandFunctionArguments() {
continue;
}
+ // Find out if there is a paste (##) operator before or after the token.
+ bool NonEmptyPasteBefore =
+ !ResultToks.empty() && ResultToks.back().is(tok::hashhash);
+ bool PasteBefore = i != 0 && Tokens[i-1].is(tok::hashhash);
+ bool PasteAfter = i+1 != e && Tokens[i+1].is(tok::hashhash);
+ assert(!NonEmptyPasteBefore || PasteBefore);
+
// Otherwise, if this is not an argument token, just add the token to the
// output buffer.
IdentifierInfo *II = CurTok.getIdentifierInfo();
@@ -234,7 +237,9 @@ void TokenLexer::ExpandFunctionArguments() {
if (NextTokGetsSpace) {
ResultToks.back().setFlag(Token::LeadingSpace);
NextTokGetsSpace = false;
- }
+ } else if (PasteBefore && !NonEmptyPasteBefore)
+ ResultToks.back().clearFlag(Token::LeadingSpace);
+
continue;
}
@@ -242,18 +247,12 @@ void TokenLexer::ExpandFunctionArguments() {
// input.
MadeChange = true;
- // Otherwise, this is a use of the argument. Find out if there is a paste
- // (##) operator before or after the argument.
- bool NonEmptyPasteBefore =
- !ResultToks.empty() && ResultToks.back().is(tok::hashhash);
- bool PasteBefore = i != 0 && Tokens[i-1].is(tok::hashhash);
- bool PasteAfter = i+1 != e && Tokens[i+1].is(tok::hashhash);
- assert(!NonEmptyPasteBefore || PasteBefore);
+ // Otherwise, this is a use of the argument.
// In Microsoft mode, remove the comma before __VA_ARGS__ to ensure there
// are no trailing commas if __VA_ARGS__ is empty.
if (!PasteBefore && ActualArgs->isVarargsElidedUse() &&
- MaybeRemoveCommaBeforeVaArgs(ResultToks, NextTokGetsSpace,
+ MaybeRemoveCommaBeforeVaArgs(ResultToks,
/*HasPasteOperator=*/false,
Macro, ArgNo, PP))
continue;
@@ -282,7 +281,7 @@ void TokenLexer::ExpandFunctionArguments() {
// behavior by not considering single commas from nested macro
// expansions as argument separators. Set a flag on the token so we can
// test for this later when the macro expansion is processed.
- if (PP.getLangOpts().MicrosoftMode && NumToks == 1 &&
+ if (PP.getLangOpts().MSVCCompat && NumToks == 1 &&
ResultToks.back().is(tok::comma))
ResultToks.back().setFlag(Token::IgnoredComma);
@@ -304,13 +303,8 @@ void TokenLexer::ExpandFunctionArguments() {
// before the first token should match the whitespace of the arg
// identifier.
ResultToks[FirstResult].setFlagValue(Token::LeadingSpace,
- CurTok.hasLeadingSpace() ||
NextTokGetsSpace);
NextTokGetsSpace = false;
- } else {
- // If this is an empty argument, and if there was whitespace before the
- // formal token, make sure the next token gets whitespace before it.
- NextTokGetsSpace = CurTok.hasLeadingSpace();
}
continue;
}
@@ -358,8 +352,7 @@ void TokenLexer::ExpandFunctionArguments() {
// assembler-with-cpp mode, invalid pastes are allowed through: in this
// case, we do not want the extra whitespace to be added. For example,
// we want ". ## foo" -> ".foo" not ". foo".
- if ((CurTok.hasLeadingSpace() || NextTokGetsSpace) &&
- !NonEmptyPasteBefore)
+ if (NextTokGetsSpace)
ResultToks[ResultToks.size()-NumToks].setFlag(Token::LeadingSpace);
NextTokGetsSpace = false;
@@ -370,11 +363,9 @@ void TokenLexer::ExpandFunctionArguments() {
// 6.10.3.3p2,3) calls for a bunch of placemarker stuff to occur. We
// implement this by eating ## operators when a LHS or RHS expands to
// empty.
- NextTokGetsSpace |= CurTok.hasLeadingSpace();
if (PasteAfter) {
// Discard the argument token and skip (don't copy to the expansion
// buffer) the paste operator after it.
- NextTokGetsSpace |= Tokens[i+1].hasLeadingSpace();
++i;
continue;
}
@@ -385,7 +376,7 @@ void TokenLexer::ExpandFunctionArguments() {
assert(PasteBefore);
if (NonEmptyPasteBefore) {
assert(ResultToks.back().is(tok::hashhash));
- NextTokGetsSpace |= ResultToks.pop_back_val().hasLeadingSpace();
+ ResultToks.pop_back();
}
// If this is the __VA_ARGS__ token, and if the argument wasn't provided,
@@ -393,7 +384,7 @@ void TokenLexer::ExpandFunctionArguments() {
// the ## was a comma, remove the comma. This is a GCC extension which is
// disabled when using -std=c99.
if (ActualArgs->isVarargsElidedUse())
- MaybeRemoveCommaBeforeVaArgs(ResultToks, NextTokGetsSpace,
+ MaybeRemoveCommaBeforeVaArgs(ResultToks,
/*HasPasteOperator=*/true,
Macro, ArgNo, PP);
@@ -425,7 +416,7 @@ bool TokenLexer::Lex(Token &Tok) {
Tok.startToken();
Tok.setFlagValue(Token::StartOfLine , AtStartOfLine);
- Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace);
+ Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace || NextTokGetsSpace);
if (CurToken == 0)
Tok.setFlag(Token::LeadingEmptyMacro);
return PP.HandleEndOfTokenLexer(Tok);
@@ -479,12 +470,17 @@ bool TokenLexer::Lex(Token &Tok) {
if (isFirstToken) {
Tok.setFlagValue(Token::StartOfLine , AtStartOfLine);
Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace);
- AtStartOfLine = false;
- HasLeadingSpace = false;
+ } else {
+ // If this is not the first token, we may still need to pass through
+ // leading whitespace if we've expanded a macro.
+ if (AtStartOfLine) Tok.setFlag(Token::StartOfLine);
+ if (HasLeadingSpace) Tok.setFlag(Token::LeadingSpace);
}
+ AtStartOfLine = false;
+ HasLeadingSpace = false;
// Handle recursive expansion!
- if (!Tok.isAnnotation() && Tok.getIdentifierInfo() != 0) {
+ if (!Tok.isAnnotation() && Tok.getIdentifierInfo() != nullptr) {
// Change the kind of this identifier to the appropriate token kind, e.g.
// turning "for" into a keyword.
IdentifierInfo *II = Tok.getIdentifierInfo();
@@ -511,7 +507,7 @@ bool TokenLexer::Lex(Token &Tok) {
/// If this returns true, the caller should immediately return the token.
bool TokenLexer::PasteTokens(Token &Tok) {
SmallString<128> Buffer;
- const char *ResultTokStrPtr = 0;
+ const char *ResultTokStrPtr = nullptr;
SourceLocation StartLoc = Tok.getLocation();
SourceLocation PasteOpLoc;
do {
@@ -620,12 +616,11 @@ bool TokenLexer::PasteTokens(Token &Tok) {
SourceLocation Loc =
SM.createExpansionLoc(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
+ // error to an extension that defaults to an error. This allows
// disabling it.
- PP.Diag(Loc,
- PP.getLangOpts().MicrosoftExt ? diag::err_pp_bad_paste_ms
- : diag::err_pp_bad_paste)
- << Buffer.str();
+ PP.Diag(Loc, PP.getLangOpts().MicrosoftExt ? diag::ext_pp_bad_paste_ms
+ : diag::err_pp_bad_paste)
+ << Buffer.str();
}
// An error has occurred so exit loop.
diff --git a/lib/Lex/UnicodeCharSets.h b/lib/Lex/UnicodeCharSets.h
index 01ae7e839dfd..12b24564bfd3 100644
--- a/lib/Lex/UnicodeCharSets.h
+++ b/lib/Lex/UnicodeCharSets.h
@@ -298,7 +298,7 @@ static const llvm::sys::UnicodeCharRange C99AllowedIDCharRanges[] = {
// Malayam
{ 0x0D02, 0x0D03 }, { 0x0D05, 0x0D0C }, { 0x0D0E, 0x0D10 },
{ 0x0D12, 0x0D28 }, { 0x0D2A, 0x0D39 }, { 0x0D3E, 0x0D43 },
- { 0x0D46, 0x0D48 }, { 0x0D4A, 0x0D4D }, { 0x0D60, 0x0D60 },
+ { 0x0D46, 0x0D48 }, { 0x0D4A, 0x0D4D }, { 0x0D60, 0x0D61 },
// Digits (11)
{ 0x0D66, 0x0D6F },
diff --git a/lib/Makefile b/lib/Makefile
index 66632688d933..acf8089629e4 100755
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -11,14 +11,10 @@ CLANG_LEVEL := ..
# ARCMigrate and Rewrite are always needed because of libclang.
PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis Frontend \
FrontendTool Tooling Driver Format Edit Rewrite Serialization \
- Index
+ Index ASTMatchers
include $(CLANG_LEVEL)/../../Makefile.config
-ifeq ($(ENABLE_CLANG_REWRITER),1)
-PARALLEL_DIRS += ASTMatchers
-endif
-
ifeq ($(ENABLE_CLANG_STATIC_ANALYZER),1)
PARALLEL_DIRS += StaticAnalyzer
endif
diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt
index 08bf4e196155..b868696eb6bb 100644
--- a/lib/Parse/CMakeLists.txt
+++ b/lib/Parse/CMakeLists.txt
@@ -1,3 +1,9 @@
+set(LLVM_LINK_COMPONENTS
+ MC
+ MCParser
+ Support
+ )
+
add_clang_library(clangParse
ParseAST.cpp
ParseCXXInlineMethods.cpp
@@ -10,28 +16,14 @@ add_clang_library(clangParse
ParseOpenMP.cpp
ParsePragma.cpp
ParseStmt.cpp
+ ParseStmtAsm.cpp
ParseTemplate.cpp
ParseTentative.cpp
Parser.cpp
- )
-add_dependencies(clangParse
- ClangAttrClasses
- ClangAttrIdentifierArg
- ClangAttrLateParsed
- ClangAttrList
- ClangAttrParsedAttrList
- ClangAttrTypeArg
- ClangCommentNodes
- ClangDeclNodes
- ClangDiagnosticCommon
- ClangDiagnosticParse
- ClangStmtNodes
- )
-
-target_link_libraries(clangParse
- clangBasic
+ LINK_LIBS
clangAST
+ clangBasic
clangLex
clangSema
)
diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp
index 5678ece0c822..0f5a1b3ffbd6 100644
--- a/lib/Parse/ParseAST.cpp
+++ b/lib/Parse/ParseAST.cpp
@@ -23,9 +23,9 @@
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaConsumer.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include <cstdio>
+#include <memory>
using namespace clang;
@@ -36,7 +36,7 @@ class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry {
const Parser &P;
public:
PrettyStackTraceParserEntry(const Parser &p) : P(p) {}
- virtual void print(raw_ostream &OS) const;
+ void print(raw_ostream &OS) const override;
};
/// If a crash happens while the parser is active, print out a line indicating
@@ -88,7 +88,8 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
CodeCompleteConsumer *CompletionConsumer,
bool SkipFunctionBodies) {
- OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer));
+ std::unique_ptr<Sema> S(
+ new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer));
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(S.get());
@@ -109,8 +110,8 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
ASTConsumer *Consumer = &S.getASTConsumer();
- OwningPtr<Parser> ParseOP(new Parser(S.getPreprocessor(), S,
- SkipFunctionBodies));
+ std::unique_ptr<Parser> ParseOP(
+ new Parser(S.getPreprocessor(), S, SkipFunctionBodies));
Parser &P = *ParseOP.get();
PrettyStackTraceParserEntry CrashInfo(P);
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 779230516532..30a9120a5106 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -19,13 +19,6 @@
#include "clang/Sema/Scope.h"
using namespace clang;
-/// Get the FunctionDecl for a function or function template decl.
-static FunctionDecl *getFunctionDecl(Decl *D) {
- if (FunctionDecl *fn = dyn_cast<FunctionDecl>(D))
- return fn;
- return cast<FunctionTemplateDecl>(D)->getTemplatedDecl();
-}
-
/// ParseCXXInlineMethodDef - We parsed and verified that the specified
/// Declarator is a well formed C++ inline method definition. Now lex its body
/// and store its tokens for parsing after the C++ class is complete.
@@ -42,8 +35,9 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
"Current token not a '{', ':', '=', or 'try'!");
MultiTemplateParamsArg TemplateParams(
- TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0,
- TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0);
+ TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data()
+ : nullptr,
+ TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0);
NamedDecl *FnD;
D.setFunctionDefinitionKind(DefinitionKind);
@@ -52,7 +46,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
TemplateParams);
else {
FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D,
- TemplateParams, 0,
+ TemplateParams, nullptr,
VS, ICIS_NoInit);
if (FnD) {
Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs);
@@ -69,30 +63,24 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
D.complete(FnD);
- if (Tok.is(tok::equal)) {
- ConsumeToken();
-
+ if (TryConsumeToken(tok::equal)) {
if (!FnD) {
SkipUntil(tok::semi);
- return 0;
+ return nullptr;
}
bool Delete = false;
SourceLocation KWLoc;
- if (Tok.is(tok::kw_delete)) {
- Diag(Tok, getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_deleted_function :
- diag::ext_deleted_function);
-
- KWLoc = ConsumeToken();
+ if (TryConsumeToken(tok::kw_delete, KWLoc)) {
+ Diag(KWLoc, getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_deleted_function
+ : diag::ext_deleted_function);
Actions.SetDeclDeleted(FnD, KWLoc);
Delete = true;
- } else if (Tok.is(tok::kw_default)) {
- Diag(Tok, getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_defaulted_function :
- diag::ext_defaulted_function);
-
- KWLoc = ConsumeToken();
+ } else if (TryConsumeToken(tok::kw_default, KWLoc)) {
+ Diag(KWLoc, getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_defaulted_function
+ : diag::ext_defaulted_function);
Actions.SetDeclDefaulted(FnD, KWLoc);
} else {
llvm_unreachable("function definition after = not 'delete' or 'default'");
@@ -102,9 +90,9 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
Diag(KWLoc, diag::err_default_delete_in_multiple_declaration)
<< Delete;
SkipUntil(tok::semi);
- } else {
- ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
- Delete ? "delete" : "default", tok::semi);
+ } else if (ExpectAndConsume(tok::semi, diag::err_expected_after,
+ Delete ? "delete" : "default")) {
+ SkipUntil(tok::semi);
}
return FnD;
@@ -115,9 +103,9 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
// the tokens and store them for parsing at the end of the translation unit.
if (getLangOpts().DelayedTemplateParsing &&
DefinitionKind == FDK_Definition &&
- !D.getDeclSpec().isConstexprSpecified() &&
- !(FnD && getFunctionDecl(FnD) &&
- getFunctionDecl(FnD)->getResultType()->getContainedAutoType()) &&
+ !D.getDeclSpec().isConstexprSpecified() &&
+ !(FnD && FnD->getAsFunction() &&
+ FnD->getAsFunction()->getReturnType()->getContainedAutoType()) &&
((Actions.CurContext->isDependentContext() ||
(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
TemplateInfo.Kind != ParsedTemplateInfo::ExplicitSpecialization)) &&
@@ -127,7 +115,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
LexTemplateFunctionForLateParsing(Toks);
if (FnD) {
- FunctionDecl *FD = getFunctionDecl(FnD);
+ FunctionDecl *FD = FnD->getAsFunction();
Actions.CheckForFunctionRedefinition(FD);
Actions.MarkAsLateParsedTemplate(FD, FnD, Toks);
}
@@ -179,7 +167,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
// If you remove this, you can remove the code that clears the flag
// after parsing the member.
if (D.getDeclSpec().isFriendSpecified()) {
- FunctionDecl *FD = getFunctionDecl(FnD);
+ FunctionDecl *FD = FnD->getAsFunction();
Actions.CheckForFunctionRedefinition(FD);
FD->setLateTemplateParsed(true);
}
@@ -275,7 +263,8 @@ void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() {
/// delayed (such as default arguments) and parse them.
void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
- ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope);
+ ParseScope ClassTemplateScope(this, Scope::TemplateParamScope,
+ HasTemplateScope);
TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
if (HasTemplateScope) {
Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
@@ -288,14 +277,16 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope,
HasClassScope);
if (HasClassScope)
- Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate);
+ Actions.ActOnStartDelayedMemberDeclarations(getCurScope(),
+ Class.TagOrTemplate);
for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) {
Class.LateParsedDeclarations[i]->ParseLexedMethodDeclarations();
}
if (HasClassScope)
- Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate);
+ Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(),
+ Class.TagOrTemplate);
}
void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
@@ -315,7 +306,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
Scope::FunctionDeclarationScope | Scope::DeclScope);
for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) {
// Introduce the parameter into scope.
- Actions.ActOnDelayedCXXMethodParameter(getCurScope(),
+ Actions.ActOnDelayedCXXMethodParameter(getCurScope(),
LM.DefaultArgs[I].Param);
if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) {
@@ -346,11 +337,10 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
} else
DefArgResult = ParseAssignmentExpression();
if (DefArgResult.isInvalid())
- Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param);
+ Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param,
+ EqualLoc);
else {
- if (Tok.is(tok::cxx_defaultarg_end))
- ConsumeToken();
- else {
+ if (!TryConsumeToken(tok::cxx_defaultarg_end)) {
// The last two tokens are the terminator and the saved value of
// Tok; the last token in the default argument is the one before
// those.
@@ -360,7 +350,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
(*Toks)[Toks->size() - 3].getLocation());
}
Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc,
- DefArgResult.take());
+ DefArgResult.get());
}
assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc,
@@ -372,7 +362,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
ConsumeAnyToken();
delete Toks;
- LM.DefaultArgs[I].Toks = 0;
+ LM.DefaultArgs[I].Toks = nullptr;
}
}
@@ -446,7 +436,7 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
// Error recovery.
if (!Tok.is(tok::l_brace)) {
FnScope.Exit();
- Actions.ActOnFinishFunctionBody(LM.D, 0);
+ Actions.ActOnFinishFunctionBody(LM.D, nullptr);
while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof))
ConsumeAnyToken();
return;
@@ -464,7 +454,8 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
ParseFunctionStatementBody(LM.D, FnScope);
// Clear the late-template-parsed bit if we set it before.
- if (LM.D) getFunctionDecl(LM.D)->setLateTemplateParsed(false);
+ if (LM.D)
+ LM.D->getAsFunction()->setLateTemplateParsed(false);
if (Tok.getLocation() != origLoc) {
// Due to parsing error, we either went over the cached tokens or
@@ -477,6 +468,9 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof))
ConsumeAnyToken();
}
+
+ if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(LM.D))
+ Actions.ActOnFinishInlineMethodDef(MD);
}
/// ParseLexedMemberInitializers - We finished parsing the member specification
@@ -536,10 +530,13 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
SourceLocation EqualLoc;
+ Actions.ActOnStartCXXInClassMemberInitializer();
+
ExprResult Init = ParseCXXMemberInitializer(MI.Field, /*IsFunction=*/false,
EqualLoc);
- Actions.ActOnCXXInClassMemberInitializer(MI.Field, EqualLoc, Init.release());
+ Actions.ActOnFinishCXXInClassMemberInitializer(MI.Field, EqualLoc,
+ Init.get());
// The next token should be our artificial terminating EOF token.
if (Tok.isNot(tok::eof)) {
@@ -580,6 +577,9 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
switch (Tok.getKind()) {
case tok::eof:
+ case tok::annot_module_begin:
+ case tok::annot_module_end:
+ case tok::annot_module_include:
// Ran out of tokens.
return false;
@@ -675,7 +675,7 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) {
/*StopAtSemi=*/true,
/*ConsumeFinalToken=*/false);
if (Tok.isNot(tok::l_brace))
- return Diag(Tok.getLocation(), diag::err_expected_lbrace);
+ return Diag(Tok.getLocation(), diag::err_expected) << tok::l_brace;
Toks.push_back(Tok);
ConsumeBrace();
@@ -708,8 +708,8 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) {
Toks.push_back(Tok);
ConsumeParen();
if (!ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/true)) {
- Diag(Tok.getLocation(), diag::err_expected_rparen);
- Diag(OpenLoc, diag::note_matching) << "(";
+ Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
+ Diag(OpenLoc, diag::note_matching) << tok::l_paren;
return true;
}
}
@@ -756,13 +756,15 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) {
/*ConsumeFinalToken=*/false)) {
// We're not just missing the initializer, we're also missing the
// function body!
- return Diag(Tok.getLocation(), diag::err_expected_lbrace);
+ return Diag(Tok.getLocation(), diag::err_expected) << tok::l_brace;
}
} else if (Tok.isNot(tok::l_paren) && Tok.isNot(tok::l_brace)) {
// We found something weird in a mem-initializer-id.
- return Diag(Tok.getLocation(), getLangOpts().CPlusPlus11
- ? diag::err_expected_lparen_or_lbrace
- : diag::err_expected_lparen);
+ if (getLangOpts().CPlusPlus11)
+ return Diag(Tok.getLocation(), diag::err_expected_either)
+ << tok::l_paren << tok::l_brace;
+ else
+ return Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
}
tok::TokenKind kind = Tok.getKind();
@@ -784,11 +786,10 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) {
// Grab the initializer (or the subexpression of the template argument).
// FIXME: If we support lambdas here, we'll need to set StopAtSemi to false
// if we might be inside the braces of a lambda-expression.
- if (!ConsumeAndStoreUntil(IsLParen ? tok::r_paren : tok::r_brace,
- Toks, /*StopAtSemi=*/true)) {
- Diag(Tok, IsLParen ? diag::err_expected_rparen :
- diag::err_expected_rbrace);
- Diag(OpenLoc, diag::note_matching) << (IsLParen ? "(" : "{");
+ tok::TokenKind CloseKind = IsLParen ? tok::r_paren : tok::r_brace;
+ if (!ConsumeAndStoreUntil(CloseKind, Toks, /*StopAtSemi=*/true)) {
+ Diag(Tok, diag::err_expected) << CloseKind;
+ Diag(OpenLoc, diag::note_matching) << kind;
return true;
}
@@ -822,7 +823,8 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) {
ConsumeBrace();
return false;
} else if (!MightBeTemplateArgument) {
- return Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma);
+ return Diag(Tok.getLocation(), diag::err_expected_either) << tok::l_brace
+ << tok::comma;
}
}
}
@@ -836,8 +838,9 @@ bool Parser::ConsumeAndStoreConditional(CachedTokens &Toks) {
ConsumeToken();
while (Tok.isNot(tok::colon)) {
- if (!ConsumeAndStoreUntil(tok::question, tok::colon, Toks, /*StopAtSemi*/true,
- /*ConsumeFinalToken*/false))
+ if (!ConsumeAndStoreUntil(tok::question, tok::colon, Toks,
+ /*StopAtSemi=*/true,
+ /*ConsumeFinalToken=*/false))
return false;
// If we found a nested conditional, consume it.
@@ -925,15 +928,15 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks,
? tok::semi : tok::r_paren);
Sema::TentativeAnalysisScope Scope(Actions);
- TPResult Result = TPResult::Error();
+ TPResult Result = TPResult::Error;
ConsumeToken();
switch (CIK) {
case CIK_DefaultInitializer:
Result = TryParseInitDeclaratorList();
// If we parsed a complete, ambiguous init-declarator-list, this
// is only syntactically-valid if it's followed by a semicolon.
- if (Result == TPResult::Ambiguous() && Tok.isNot(tok::semi))
- Result = TPResult::False();
+ if (Result == TPResult::Ambiguous && Tok.isNot(tok::semi))
+ Result = TPResult::False;
break;
case CIK_DefaultArgument:
@@ -942,13 +945,13 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks,
&InvalidAsDeclaration, /*VersusTemplateArgument*/true);
// If this is an expression or a declaration with a missing
// 'typename', assume it's not a declaration.
- if (Result == TPResult::Ambiguous() && InvalidAsDeclaration)
- Result = TPResult::False();
+ if (Result == TPResult::Ambiguous && InvalidAsDeclaration)
+ Result = TPResult::False;
break;
}
// If what follows could be a declaration, it is a declaration.
- if (Result != TPResult::False() && Result != TPResult::Error()) {
+ if (Result != TPResult::False && Result != TPResult::Error) {
PA.Revert();
return true;
}
@@ -965,6 +968,9 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks,
goto consume_token;
case tok::eof:
+ case tok::annot_module_begin:
+ case tok::annot_module_end:
+ case tok::annot_module_include:
// Ran out of tokens.
return false;
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 7b8093408bfd..62d43768bff4 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -13,10 +13,12 @@
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/AddressSpaces.h"
+#include "clang/Basic/Attributes.h"
#include "clang/Basic/CharInfo.h"
-#include "clang/Basic/OpenCL.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ParsedTemplate.h"
@@ -51,7 +53,7 @@ TypeResult Parser::ParseTypeName(SourceRange *Range,
DS.addAttributes(Attrs->getList());
ParseSpecifierQualifierList(DS, AS, DSC);
if (OwnedType)
- *OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0;
+ *OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : nullptr;
// Parse the abstract-declarator, if present.
Declarator DeclaratorInfo(DS, Context);
@@ -69,9 +71,11 @@ TypeResult Parser::ParseTypeName(SourceRange *Range,
/// isAttributeLateParsed - Return true if the attribute has arguments that
/// require late parsing.
static bool isAttributeLateParsed(const IdentifierInfo &II) {
+#define CLANG_ATTR_LATE_PARSED_LIST
return llvm::StringSwitch<bool>(II.getName())
-#include "clang/Parse/AttrLateParsed.inc"
+#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(false);
+#undef CLANG_ATTR_LATE_PARSED_LIST
}
/// ParseGNUAttributes - Parse a non-empty attributes list.
@@ -117,7 +121,8 @@ static bool isAttributeLateParsed(const IdentifierInfo &II) {
/// We follow the C++ model, but don't allow junk after the identifier.
void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
SourceLocation *endLoc,
- LateParsedAttrList *LateAttrs) {
+ LateParsedAttrList *LateAttrs,
+ Declarator *D) {
assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!");
while (Tok.is(tok::kw___attribute)) {
@@ -132,49 +137,54 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
return;
}
// Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") ))
- while (Tok.is(tok::identifier) || isDeclarationSpecifier() ||
- Tok.is(tok::comma)) {
- if (Tok.is(tok::comma)) {
- // allows for empty/non-empty attributes. ((__vector_size__(16),,,,))
- ConsumeToken();
+ while (true) {
+ // Allow empty/non-empty attributes. ((__vector_size__(16),,,,))
+ if (TryConsumeToken(tok::comma))
continue;
- }
- // we have an identifier or declaration specifier (const, int, etc.)
+
+ // Expect an identifier or declaration specifier (const, int, etc.)
+ if (Tok.isNot(tok::identifier) && !isDeclarationSpecifier())
+ break;
+
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
- if (Tok.is(tok::l_paren)) {
- // handle "parameterized" attributes
- if (LateAttrs && isAttributeLateParsed(*AttrName)) {
- LateParsedAttribute *LA =
- new LateParsedAttribute(this, *AttrName, AttrNameLoc);
- LateAttrs->push_back(LA);
-
- // Attributes in a class are parsed at the end of the class, along
- // with other late-parsed declarations.
- if (!ClassStack.empty() && !LateAttrs->parseSoon())
- getCurrentClass().LateParsedDeclarations.push_back(LA);
-
- // consume everything up to and including the matching right parens
- ConsumeAndStoreUntil(tok::r_paren, LA->Toks, true, false);
-
- Token Eof;
- Eof.startToken();
- Eof.setLocation(Tok.getLocation());
- LA->Toks.push_back(Eof);
- } else {
- ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc,
- 0, SourceLocation(), AttributeList::AS_GNU);
- }
- } else {
- attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0,
+ if (Tok.isNot(tok::l_paren)) {
+ attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
AttributeList::AS_GNU);
+ continue;
+ }
+
+ // Handle "parameterized" attributes
+ if (!LateAttrs || !isAttributeLateParsed(*AttrName)) {
+ ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc, nullptr,
+ SourceLocation(), AttributeList::AS_GNU, D);
+ continue;
}
+
+ // Handle attributes with arguments that require late parsing.
+ LateParsedAttribute *LA =
+ new LateParsedAttribute(this, *AttrName, AttrNameLoc);
+ LateAttrs->push_back(LA);
+
+ // Attributes in a class are parsed at the end of the class, along
+ // with other late-parsed declarations.
+ if (!ClassStack.empty() && !LateAttrs->parseSoon())
+ getCurrentClass().LateParsedDeclarations.push_back(LA);
+
+ // consume everything up to and including the matching right parens
+ ConsumeAndStoreUntil(tok::r_paren, LA->Toks, true, false);
+
+ Token Eof;
+ Eof.startToken();
+ Eof.setLocation(Tok.getLocation());
+ LA->Toks.push_back(Eof);
}
- if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
+
+ if (ExpectAndConsume(tok::r_paren))
SkipUntil(tok::r_paren, StopAtSemi);
SourceLocation Loc = Tok.getLocation();
- if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
+ if (ExpectAndConsume(tok::r_paren))
SkipUntil(tok::r_paren, StopAtSemi);
if (endLoc)
*endLoc = Loc;
@@ -190,16 +200,30 @@ static StringRef normalizeAttrName(StringRef Name) {
/// \brief Determine whether the given attribute has an identifier argument.
static bool attributeHasIdentifierArg(const IdentifierInfo &II) {
+#define CLANG_ATTR_IDENTIFIER_ARG_LIST
return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
-#include "clang/Parse/AttrIdentifierArg.inc"
+#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(false);
+#undef CLANG_ATTR_IDENTIFIER_ARG_LIST
}
/// \brief Determine whether the given attribute parses a type argument.
static bool attributeIsTypeArgAttr(const IdentifierInfo &II) {
+#define CLANG_ATTR_TYPE_ARG_LIST
+ return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
+#include "clang/Parse/AttrParserStringSwitches.inc"
+ .Default(false);
+#undef CLANG_ATTR_TYPE_ARG_LIST
+}
+
+/// \brief Determine whether the given attribute requires parsing its arguments
+/// in an unevaluated context or not.
+static bool attributeParsedArgsUnevaluated(const IdentifierInfo &II) {
+#define CLANG_ATTR_ARG_CONTEXT_LIST
return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
-#include "clang/Parse/AttrTypeArg.inc"
+#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(false);
+#undef CLANG_ATTR_ARG_CONTEXT_LIST
}
IdentifierLoc *Parser::ParseIdentifierLoc() {
@@ -214,7 +238,10 @@ IdentifierLoc *Parser::ParseIdentifierLoc() {
void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,
- SourceLocation *EndLoc) {
+ SourceLocation *EndLoc,
+ IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax) {
BalancedDelimiterTracker Parens(*this, tok::l_paren);
Parens.consumeOpen();
@@ -230,61 +257,26 @@ void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName,
if (T.isUsable())
Attrs.addNewTypeAttr(&AttrName,
- SourceRange(AttrNameLoc, Parens.getCloseLocation()), 0,
- AttrNameLoc, T.get(), AttributeList::AS_GNU);
+ SourceRange(AttrNameLoc, Parens.getCloseLocation()),
+ ScopeName, ScopeLoc, T.get(), Syntax);
else
Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, Parens.getCloseLocation()),
- 0, AttrNameLoc, 0, 0, AttributeList::AS_GNU);
+ ScopeName, ScopeLoc, nullptr, 0, Syntax);
}
-/// Parse the arguments to a parameterized GNU attribute or
-/// a C++11 attribute in "gnu" namespace.
-void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
- SourceLocation AttrNameLoc,
- ParsedAttributes &Attrs,
- SourceLocation *EndLoc,
- IdentifierInfo *ScopeName,
- SourceLocation ScopeLoc,
- AttributeList::Syntax Syntax) {
-
- assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
-
- AttributeList::Kind AttrKind =
- AttributeList::getKind(AttrName, ScopeName, Syntax);
-
- // Availability attributes have their own grammar.
- // FIXME: All these cases fail to pass in the syntax and scope, and might be
- // written as C++11 gnu:: attributes.
- if (AttrKind == AttributeList::AT_Availability) {
- ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
- return;
- }
- // Thread safety attributes are parsed in an unevaluated context.
- // FIXME: Share the bulk of the parsing code here and just pull out
- // the unevaluated context.
- if (IsThreadSafetyAttribute(AttrName->getName())) {
- ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
- return;
- }
- // Type safety attributes have their own grammar.
- if (AttrKind == AttributeList::AT_TypeTagForDatatype) {
- ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
- return;
- }
- // Some attributes expect solely a type parameter.
- if (attributeIsTypeArgAttr(*AttrName)) {
- ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, EndLoc);
- return;
- }
-
+unsigned Parser::ParseAttributeArgsCommon(
+ IdentifierInfo *AttrName, SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc, AttributeList::Syntax Syntax) {
// Ignore the left paren location for now.
ConsumeParen();
ArgsVector ArgExprs;
-
if (Tok.is(tok::identifier)) {
// If this attribute wants an 'identifier' argument, make it so.
bool IsIdentifierArg = attributeHasIdentifierArg(*AttrName);
+ AttributeList::Kind AttrKind =
+ AttributeList::getKind(AttrName, ScopeName, Syntax);
// If we don't know how to parse this attribute, but this is the only
// token in this argument, assume it's meant to be an identifier.
@@ -304,112 +296,117 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
ConsumeToken();
// Parse the non-empty comma-separated list of expressions.
- while (1) {
+ do {
+ std::unique_ptr<EnterExpressionEvaluationContext> Unevaluated;
+ if (attributeParsedArgsUnevaluated(*AttrName))
+ Unevaluated.reset(
+ new EnterExpressionEvaluationContext(Actions, Sema::Unevaluated));
+
ExprResult ArgExpr(ParseAssignmentExpression());
if (ArgExpr.isInvalid()) {
SkipUntil(tok::r_paren, StopAtSemi);
- return;
+ return 0;
}
- ArgExprs.push_back(ArgExpr.release());
- if (Tok.isNot(tok::comma))
- break;
- ConsumeToken(); // Eat the comma, move to the next argument
- }
+ ArgExprs.push_back(ArgExpr.get());
+ // Eat the comma, move to the next argument
+ } while (TryConsumeToken(tok::comma));
}
SourceLocation RParen = Tok.getLocation();
- if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
+ if (!ExpectAndConsume(tok::r_paren)) {
SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc;
Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc,
ArgExprs.data(), ArgExprs.size(), Syntax);
}
+
+ if (EndLoc)
+ *EndLoc = RParen;
+
+ return static_cast<unsigned>(ArgExprs.size());
}
-/// \brief Parses a single argument for a declspec, including the
-/// surrounding parens.
-void Parser::ParseMicrosoftDeclSpecWithSingleArg(IdentifierInfo *AttrName,
- SourceLocation AttrNameLoc,
- ParsedAttributes &Attrs)
-{
- BalancedDelimiterTracker T(*this, tok::l_paren);
- if (T.expectAndConsume(diag::err_expected_lparen_after,
- AttrName->getNameStart(), tok::r_paren))
- return;
+/// Parse the arguments to a parameterized GNU attribute or
+/// a C++11 attribute in "gnu" namespace.
+void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
+ SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs,
+ SourceLocation *EndLoc,
+ IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax,
+ Declarator *D) {
- ExprResult ArgExpr(ParseConstantExpression());
- if (ArgExpr.isInvalid()) {
- T.skipToEnd();
+ assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
+
+ AttributeList::Kind AttrKind =
+ AttributeList::getKind(AttrName, ScopeName, Syntax);
+
+ if (AttrKind == AttributeList::AT_Availability) {
+ ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
+ ScopeLoc, Syntax);
+ return;
+ } else if (AttrKind == AttributeList::AT_ObjCBridgeRelated) {
+ ParseObjCBridgeRelatedAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
+ ScopeName, ScopeLoc, Syntax);
+ return;
+ } else if (AttrKind == AttributeList::AT_TypeTagForDatatype) {
+ ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
+ ScopeName, ScopeLoc, Syntax);
+ return;
+ } else if (attributeIsTypeArgAttr(*AttrName)) {
+ ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
+ ScopeLoc, Syntax);
return;
}
- ArgsUnion ExprList = ArgExpr.take();
- Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, &ExprList, 1,
- AttributeList::AS_Declspec);
- T.consumeClose();
-}
+ // These may refer to the function arguments, but need to be parsed early to
+ // participate in determining whether it's a redeclaration.
+ std::unique_ptr<ParseScope> PrototypeScope;
+ if (AttrName->isStr("enable_if") && D && D->isFunctionDeclarator()) {
+ DeclaratorChunk::FunctionTypeInfo FTI = D->getFunctionTypeInfo();
+ PrototypeScope.reset(new ParseScope(this, Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope |
+ Scope::DeclScope));
+ for (unsigned i = 0; i != FTI.NumParams; ++i) {
+ ParmVarDecl *Param = cast<ParmVarDecl>(FTI.Params[i].Param);
+ Actions.ActOnReenterCXXMethodParameter(getCurScope(), Param);
+ }
+ }
-/// \brief Determines whether a declspec is a "simple" one requiring no
-/// arguments.
-bool Parser::IsSimpleMicrosoftDeclSpec(IdentifierInfo *Ident) {
- return llvm::StringSwitch<bool>(Ident->getName())
- .Case("dllimport", true)
- .Case("dllexport", true)
- .Case("noreturn", true)
- .Case("nothrow", true)
- .Case("noinline", true)
- .Case("naked", true)
- .Case("appdomain", true)
- .Case("process", true)
- .Case("jitintrinsic", true)
- .Case("noalias", true)
- .Case("restrict", true)
- .Case("novtable", true)
- .Case("selectany", true)
- .Case("thread", true)
- .Case("safebuffers", true )
- .Default(false);
+ ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
+ ScopeLoc, Syntax);
}
-/// \brief Attempts to parse a declspec which is not simple (one that takes
-/// parameters). Will return false if we properly handled the declspec, or
-/// true if it is an unknown declspec.
-void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident,
- SourceLocation Loc,
- ParsedAttributes &Attrs) {
- // Try to handle the easy case first -- these declspecs all take a single
- // parameter as their argument.
- if (llvm::StringSwitch<bool>(Ident->getName())
- .Case("uuid", true)
- .Case("align", true)
- .Case("allocate", true)
- .Default(false)) {
- ParseMicrosoftDeclSpecWithSingleArg(Ident, Loc, Attrs);
- } else if (Ident->getName() == "deprecated") {
- // The deprecated declspec has an optional single argument, so we will
- // check for a l-paren to decide whether we should parse an argument or
- // not.
- if (Tok.getKind() == tok::l_paren)
- ParseMicrosoftDeclSpecWithSingleArg(Ident, Loc, Attrs);
- else
- Attrs.addNew(Ident, Loc, 0, Loc, 0, 0, AttributeList::AS_Declspec);
- } else if (Ident->getName() == "property") {
+bool Parser::ParseMicrosoftDeclSpecArgs(IdentifierInfo *AttrName,
+ SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs) {
+ // If the attribute isn't known, we will not attempt to parse any
+ // arguments.
+ if (!hasAttribute(AttrSyntax::Declspec, nullptr, AttrName,
+ getTargetInfo().getTriple(), getLangOpts())) {
+ // Eat the left paren, then skip to the ending right paren.
+ ConsumeParen();
+ SkipUntil(tok::r_paren);
+ return false;
+ }
+
+ SourceLocation OpenParenLoc = Tok.getLocation();
+
+ if (AttrName->getName() == "property") {
// The property declspec is more complex in that it can take one or two
// assignment expressions as a parameter, but the lhs of the assignment
// must be named get or put.
- if (Tok.isNot(tok::l_paren)) {
- Diag(Tok.getLocation(), diag::err_expected_lparen_after)
- << Ident->getNameStart();
- return;
- }
+
BalancedDelimiterTracker T(*this, tok::l_paren);
T.expectAndConsume(diag::err_expected_lparen_after,
- Ident->getNameStart(), tok::r_paren);
+ AttrName->getNameStart(), tok::r_paren);
enum AccessorKind {
AK_Invalid = -1,
- AK_Put = 0, AK_Get = 1 // indices into AccessorNames
+ AK_Put = 0,
+ AK_Get = 1 // indices into AccessorNames
};
- IdentifierInfo *AccessorNames[] = { 0, 0 };
+ IdentifierInfo *AccessorNames[] = {nullptr, nullptr};
bool HasInvalidAccessor = false;
// Parse the accessor specifications.
@@ -418,8 +415,9 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident,
if (!Tok.is(tok::identifier)) {
// If the user wrote a completely empty list, use a special diagnostic.
if (Tok.is(tok::r_paren) && !HasInvalidAccessor &&
- AccessorNames[AK_Put] == 0 && AccessorNames[AK_Get] == 0) {
- Diag(Loc, diag::err_ms_property_no_getter_or_putter);
+ AccessorNames[AK_Put] == nullptr &&
+ AccessorNames[AK_Get] == nullptr) {
+ Diag(AttrNameLoc, diag::err_ms_property_no_getter_or_putter);
break;
}
@@ -435,39 +433,38 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident,
} else if (KindStr == "put") {
Kind = AK_Put;
- // Recover from the common mistake of using 'set' instead of 'put'.
+ // Recover from the common mistake of using 'set' instead of 'put'.
} else if (KindStr == "set") {
Diag(KindLoc, diag::err_ms_property_has_set_accessor)
- << FixItHint::CreateReplacement(KindLoc, "put");
+ << FixItHint::CreateReplacement(KindLoc, "put");
Kind = AK_Put;
- // Handle the mistake of forgetting the accessor kind by skipping
- // this accessor.
+ // Handle the mistake of forgetting the accessor kind by skipping
+ // this accessor.
} else if (NextToken().is(tok::comma) || NextToken().is(tok::r_paren)) {
Diag(KindLoc, diag::err_ms_property_missing_accessor_kind);
ConsumeToken();
HasInvalidAccessor = true;
goto next_property_accessor;
- // Otherwise, complain about the unknown accessor kind.
+ // Otherwise, complain about the unknown accessor kind.
} else {
Diag(KindLoc, diag::err_ms_property_unknown_accessor);
HasInvalidAccessor = true;
Kind = AK_Invalid;
// Try to keep parsing unless it doesn't look like an accessor spec.
- if (!NextToken().is(tok::equal)) break;
+ if (!NextToken().is(tok::equal))
+ break;
}
// Consume the identifier.
ConsumeToken();
// Consume the '='.
- if (Tok.is(tok::equal)) {
- ConsumeToken();
- } else {
+ if (!TryConsumeToken(tok::equal)) {
Diag(Tok.getLocation(), diag::err_ms_property_expected_equal)
- << KindStr;
+ << KindStr;
break;
}
@@ -479,7 +476,7 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident,
if (Kind == AK_Invalid) {
// Just drop invalid accessors.
- } else if (AccessorNames[Kind] != NULL) {
+ } else if (AccessorNames[Kind] != nullptr) {
// Complain about the repeated accessor, ignore it, and keep parsing.
Diag(KindLoc, diag::err_ms_property_duplicate_accessor) << KindStr;
} else {
@@ -489,41 +486,38 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident,
next_property_accessor:
// Keep processing accessors until we run out.
- if (Tok.is(tok::comma)) {
- ConsumeAnyToken();
+ if (TryConsumeToken(tok::comma))
continue;
// If we run into the ')', stop without consuming it.
- } else if (Tok.is(tok::r_paren)) {
+ if (Tok.is(tok::r_paren))
break;
- } else {
- Diag(Tok.getLocation(), diag::err_ms_property_expected_comma_or_rparen);
- break;
- }
+
+ Diag(Tok.getLocation(), diag::err_ms_property_expected_comma_or_rparen);
+ break;
}
// Only add the property attribute if it was well-formed.
- if (!HasInvalidAccessor) {
- Attrs.addNewPropertyAttr(Ident, Loc, 0, SourceLocation(),
+ if (!HasInvalidAccessor)
+ Attrs.addNewPropertyAttr(AttrName, AttrNameLoc, nullptr, SourceLocation(),
AccessorNames[AK_Get], AccessorNames[AK_Put],
AttributeList::AS_Declspec);
- }
T.skipToEnd();
- } else {
- // We don't recognize this as a valid declspec, but instead of creating the
- // attribute and allowing sema to warn about it, we will warn here instead.
- // This is because some attributes have multiple spellings, but we need to
- // disallow that for declspecs (such as align vs aligned). If we made the
- // attribute, we'd have to split the valid declspec spelling logic into
- // both locations.
- Diag(Loc, diag::warn_ms_declspec_unknown) << Ident;
-
- // If there's an open paren, we should eat the open and close parens under
- // the assumption that this unknown declspec has parameters.
- BalancedDelimiterTracker T(*this, tok::l_paren);
- if (!T.consumeOpen())
- T.skipToEnd();
+ return !HasInvalidAccessor;
}
+
+ unsigned NumArgs =
+ ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, nullptr, nullptr,
+ SourceLocation(), AttributeList::AS_Declspec);
+
+ // If this attribute's args were parsed, and it was expected to have
+ // arguments but none were provided, emit a diagnostic.
+ const AttributeList *Attr = Attrs.getList();
+ if (Attr && Attr->getMaxArgs() && !NumArgs) {
+ Diag(OpenParenLoc, diag::err_attribute_requires_arguments) << AttrName;
+ return false;
+ }
+ return true;
}
/// [MS] decl-specifier:
@@ -543,7 +537,11 @@ void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &Attrs) {
// An empty declspec is perfectly legal and should not warn. Additionally,
// you can specify multiple attributes per declspec.
- while (Tok.getKind() != tok::r_paren) {
+ while (Tok.isNot(tok::r_paren)) {
+ // Attribute not present.
+ if (TryConsumeToken(tok::comma))
+ continue;
+
// We expect either a well-known identifier or a generic string. Anything
// else is a malformed declspec.
bool IsString = Tok.getKind() == tok::string_literal ? true : false;
@@ -571,17 +569,19 @@ void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &Attrs) {
AttrNameLoc = ConsumeToken();
}
- if (IsString || IsSimpleMicrosoftDeclSpec(AttrName))
- // If we have a generic string, we will allow it because there is no
- // documented list of allowable string declspecs, but we know they exist
- // (for instance, SAL declspecs in older versions of MSVC).
- //
- // Alternatively, if the identifier is a simple one, then it requires no
- // arguments and can be turned into an attribute directly.
- Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0,
+ bool AttrHandled = false;
+
+ // Parse attribute arguments.
+ if (Tok.is(tok::l_paren))
+ AttrHandled = ParseMicrosoftDeclSpecArgs(AttrName, AttrNameLoc, Attrs);
+ else if (AttrName->getName() == "property")
+ // The property attribute must have an argument list.
+ Diag(Tok.getLocation(), diag::err_expected_lparen_after)
+ << AttrName->getName();
+
+ if (!AttrHandled)
+ Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
AttributeList::AS_Declspec);
- else
- ParseComplexMicrosoftDeclSpec(AttrName, AttrNameLoc, Attrs);
}
T.consumeClose();
}
@@ -595,7 +595,7 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) {
Tok.is(tok::kw___sptr) || Tok.is(tok::kw___uptr)) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
- attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0,
+ attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
AttributeList::AS_Keyword);
}
}
@@ -605,7 +605,7 @@ void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) {
while (Tok.is(tok::kw___pascal)) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
- attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0,
+ attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
AttributeList::AS_Keyword);
}
}
@@ -615,61 +615,16 @@ void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) {
while (Tok.is(tok::kw___kernel)) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
- attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0,
+ attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
AttributeList::AS_Keyword);
}
}
-void Parser::ParseOpenCLQualifiers(DeclSpec &DS) {
- // FIXME: The mapping from attribute spelling to semantics should be
- // performed in Sema, not here.
- SourceLocation Loc = Tok.getLocation();
- switch(Tok.getKind()) {
- // OpenCL qualifiers:
- case tok::kw___private:
- case tok::kw_private:
- DS.getAttributes().addNewInteger(
- Actions.getASTContext(),
- PP.getIdentifierInfo("address_space"), Loc, 0);
- break;
-
- case tok::kw___global:
- DS.getAttributes().addNewInteger(
- Actions.getASTContext(),
- PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_global);
- break;
-
- case tok::kw___local:
- DS.getAttributes().addNewInteger(
- Actions.getASTContext(),
- PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_local);
- break;
-
- case tok::kw___constant:
- DS.getAttributes().addNewInteger(
- Actions.getASTContext(),
- PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_constant);
- break;
-
- case tok::kw___read_only:
- DS.getAttributes().addNewInteger(
- Actions.getASTContext(),
- PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_read_only);
- break;
-
- case tok::kw___write_only:
- DS.getAttributes().addNewInteger(
- Actions.getASTContext(),
- PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_write_only);
- break;
-
- case tok::kw___read_write:
- DS.getAttributes().addNewInteger(
- Actions.getASTContext(),
- PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_read_write);
- break;
- default: break;
- }
+void Parser::ParseOpenCLQualifiers(ParsedAttributes &Attrs) {
+ IdentifierInfo *AttrName = Tok.getIdentifierInfo();
+ SourceLocation AttrNameLoc = Tok.getLocation();
+ Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
+ AttributeList::AS_Keyword);
}
/// \brief Parse a version number.
@@ -804,7 +759,10 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
SourceLocation AvailabilityLoc,
ParsedAttributes &attrs,
- SourceLocation *endLoc) {
+ SourceLocation *endLoc,
+ IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax) {
enum { Introduced, Deprecated, Obsoleted, Unknown };
AvailabilityChange Changes[Unknown];
ExprResult MessageExpr;
@@ -812,7 +770,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
// Opening '('.
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.consumeOpen()) {
- Diag(Tok, diag::err_expected_lparen);
+ Diag(Tok, diag::err_expected) << tok::l_paren;
return;
}
@@ -825,8 +783,10 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
IdentifierLoc *Platform = ParseIdentifierLoc();
// Parse the ',' following the platform name.
- if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::r_paren))
+ if (ExpectAndConsume(tok::comma)) {
+ SkipUntil(tok::r_paren, StopAtSemi);
return;
+ }
// If we haven't grabbed the pointers for the identifiers
// "introduced", "deprecated", and "obsoleted", do so now.
@@ -855,29 +815,34 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
<< Keyword << SourceRange(UnavailableLoc);
}
UnavailableLoc = KeywordLoc;
-
- if (Tok.isNot(tok::comma))
- break;
-
- ConsumeToken();
continue;
}
if (Tok.isNot(tok::equal)) {
- Diag(Tok, diag::err_expected_equal_after)
- << Keyword;
+ Diag(Tok, diag::err_expected_after) << Keyword << tok::equal;
SkipUntil(tok::r_paren, StopAtSemi);
return;
}
ConsumeToken();
if (Keyword == Ident_message) {
- if (Tok.isNot(tok::string_literal)) { // Also reject wide string literals.
+ if (Tok.isNot(tok::string_literal)) {
Diag(Tok, diag::err_expected_string_literal)
<< /*Source='availability attribute'*/2;
SkipUntil(tok::r_paren, StopAtSemi);
return;
}
MessageExpr = ParseStringLiteralExpression();
+ // Also reject wide string literals.
+ if (StringLiteral *MessageStringLiteral =
+ cast_or_null<StringLiteral>(MessageExpr.get())) {
+ if (MessageStringLiteral->getCharByteWidth() != 1) {
+ Diag(MessageStringLiteral->getSourceRange().getBegin(),
+ diag::err_expected_string_literal)
+ << /*Source='availability attribute'*/ 2;
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
+ }
+ }
break;
}
@@ -915,11 +880,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
<< Keyword << VersionRange;
}
- if (Tok.isNot(tok::comma))
- break;
-
- ConsumeToken();
- } while (true);
+ } while (TryConsumeToken(tok::comma));
// Closing ')'.
if (T.consumeClose())
@@ -950,15 +911,97 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
// Record this attribute
attrs.addNew(&Availability,
SourceRange(AvailabilityLoc, T.getCloseLocation()),
- 0, AvailabilityLoc,
+ ScopeName, ScopeLoc,
Platform,
Changes[Introduced],
Changes[Deprecated],
Changes[Obsoleted],
- UnavailableLoc, MessageExpr.take(),
- AttributeList::AS_GNU);
+ UnavailableLoc, MessageExpr.get(),
+ Syntax);
}
+/// \brief Parse the contents of the "objc_bridge_related" attribute.
+/// objc_bridge_related '(' related_class ',' opt-class_method ',' opt-instance_method ')'
+/// related_class:
+/// Identifier
+///
+/// opt-class_method:
+/// Identifier: | <empty>
+///
+/// opt-instance_method:
+/// Identifier | <empty>
+///
+void Parser::ParseObjCBridgeRelatedAttribute(IdentifierInfo &ObjCBridgeRelated,
+ SourceLocation ObjCBridgeRelatedLoc,
+ ParsedAttributes &attrs,
+ SourceLocation *endLoc,
+ IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax) {
+ // Opening '('.
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.consumeOpen()) {
+ Diag(Tok, diag::err_expected) << tok::l_paren;
+ return;
+ }
+
+ // Parse the related class name.
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_objcbridge_related_expected_related_class);
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
+ }
+ IdentifierLoc *RelatedClass = ParseIdentifierLoc();
+ if (ExpectAndConsume(tok::comma)) {
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
+ }
+
+ // Parse optional class method name.
+ IdentifierLoc *ClassMethod = nullptr;
+ if (Tok.is(tok::identifier)) {
+ ClassMethod = ParseIdentifierLoc();
+ if (!TryConsumeToken(tok::colon)) {
+ Diag(Tok, diag::err_objcbridge_related_selector_name);
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
+ }
+ }
+ if (!TryConsumeToken(tok::comma)) {
+ if (Tok.is(tok::colon))
+ Diag(Tok, diag::err_objcbridge_related_selector_name);
+ else
+ Diag(Tok, diag::err_expected) << tok::comma;
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
+ }
+
+ // Parse optional instance method name.
+ IdentifierLoc *InstanceMethod = nullptr;
+ if (Tok.is(tok::identifier))
+ InstanceMethod = ParseIdentifierLoc();
+ else if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected) << tok::r_paren;
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
+ }
+
+ // Closing ')'.
+ if (T.consumeClose())
+ return;
+
+ if (endLoc)
+ *endLoc = T.getCloseLocation();
+
+ // Record this attribute
+ attrs.addNew(&ObjCBridgeRelated,
+ SourceRange(ObjCBridgeRelatedLoc, T.getCloseLocation()),
+ ScopeName, ScopeLoc,
+ RelatedClass,
+ ClassMethod,
+ InstanceMethod,
+ Syntax);
+}
// Late Parsed Attributes:
// See other examples of late parsing in lib/Parse/ParseCXXInlineMethods
@@ -1038,13 +1081,6 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
// Consume the previously pushed token.
ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
- if (OnDefinition && !IsThreadSafetyAttribute(LA.AttrName.getName())) {
- // FIXME: Do not warn on C++11 attributes, once we start supporting
- // them here.
- Diag(Tok, diag::warn_attribute_on_function_definition)
- << LA.AttrName.getName();
- }
-
ParsedAttributes Attrs(AttrFactory);
SourceLocation endLoc;
@@ -1071,7 +1107,8 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
Actions.ActOnReenterFunctionContext(Actions.CurScope, D);
ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc,
- 0, SourceLocation(), AttributeList::AS_GNU);
+ nullptr, SourceLocation(), AttributeList::AS_GNU,
+ nullptr);
if (HasFunScope) {
Actions.ActOnExitFunctionContext();
@@ -1084,15 +1121,21 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
// If there are multiple decls, then the decl cannot be within the
// function scope.
ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc,
- 0, SourceLocation(), AttributeList::AS_GNU);
+ nullptr, SourceLocation(), AttributeList::AS_GNU,
+ nullptr);
}
} else {
Diag(Tok, diag::warn_attribute_no_decl) << LA.AttrName.getName();
}
- for (unsigned i = 0, ni = LA.Decls.size(); i < ni; ++i) {
+ const AttributeList *AL = Attrs.getList();
+ if (OnDefinition && AL && !AL->isCXX11Attribute() &&
+ AL->isKnownToGCC())
+ Diag(Tok, diag::warn_attribute_on_function_definition)
+ << &LA.AttrName;
+
+ for (unsigned i = 0, ni = LA.Decls.size(); i < ni; ++i)
Actions.ActOnFinishDelayedAttribute(getCurScope(), LA.Decls[i], Attrs);
- }
if (Tok.getLocation() != OrigLoc) {
// Due to a parsing error, we either went over the cached tokens or
@@ -1106,101 +1149,29 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
}
}
-/// \brief Wrapper around a case statement checking if AttrName is
-/// one of the thread safety attributes
-bool Parser::IsThreadSafetyAttribute(StringRef AttrName) {
- return llvm::StringSwitch<bool>(AttrName)
- .Case("guarded_by", true)
- .Case("guarded_var", true)
- .Case("pt_guarded_by", true)
- .Case("pt_guarded_var", true)
- .Case("lockable", true)
- .Case("scoped_lockable", true)
- .Case("no_thread_safety_analysis", true)
- .Case("acquired_after", true)
- .Case("acquired_before", true)
- .Case("exclusive_lock_function", true)
- .Case("shared_lock_function", true)
- .Case("exclusive_trylock_function", true)
- .Case("shared_trylock_function", true)
- .Case("unlock_function", true)
- .Case("lock_returned", true)
- .Case("locks_excluded", true)
- .Case("exclusive_locks_required", true)
- .Case("shared_locks_required", true)
- .Default(false);
-}
-
-/// \brief Parse the contents of thread safety attributes. These
-/// should always be parsed as an expression list.
-///
-/// We need to special case the parsing due to the fact that if the first token
-/// of the first argument is an identifier, the main parse loop will store
-/// that token as a "parameter" and the rest of
-/// the arguments will be added to a list of "arguments". However,
-/// subsequent tokens in the first argument are lost. We instead parse each
-/// argument as an expression and add all arguments to the list of "arguments".
-/// In future, we will take advantage of this special case to also
-/// deal with some argument scoping issues here (for example, referring to a
-/// function parameter in the attribute on that function).
-void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
- SourceLocation AttrNameLoc,
- ParsedAttributes &Attrs,
- SourceLocation *EndLoc) {
- assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
-
- BalancedDelimiterTracker T(*this, tok::l_paren);
- T.consumeOpen();
-
- ArgsVector ArgExprs;
- bool ArgExprsOk = true;
-
- // now parse the list of expressions
- while (Tok.isNot(tok::r_paren)) {
- EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
- ExprResult ArgExpr(ParseAssignmentExpression());
- if (ArgExpr.isInvalid()) {
- ArgExprsOk = false;
- T.consumeClose();
- break;
- } else {
- ArgExprs.push_back(ArgExpr.release());
- }
- if (Tok.isNot(tok::comma))
- break;
- ConsumeToken(); // Eat the comma, move to the next argument
- }
- // Match the ')'.
- if (ArgExprsOk && !T.consumeClose()) {
- Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, ArgExprs.data(),
- ArgExprs.size(), AttributeList::AS_GNU);
- }
- if (EndLoc)
- *EndLoc = T.getCloseLocation();
-}
-
void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,
- SourceLocation *EndLoc) {
+ SourceLocation *EndLoc,
+ IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax) {
assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
+ Diag(Tok, diag::err_expected) << tok::identifier;
T.skipToEnd();
return;
}
IdentifierLoc *ArgumentKind = ParseIdentifierLoc();
- if (Tok.isNot(tok::comma)) {
- Diag(Tok, diag::err_expected_comma);
+ if (ExpectAndConsume(tok::comma)) {
T.skipToEnd();
return;
}
- ConsumeToken();
SourceRange MatchingCTypeRange;
TypeResult MatchingCType = ParseTypeName(&MatchingCTypeRange);
@@ -1211,10 +1182,9 @@ void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
bool LayoutCompatible = false;
bool MustBeNull = false;
- while (Tok.is(tok::comma)) {
- ConsumeToken();
+ while (TryConsumeToken(tok::comma)) {
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
+ Diag(Tok, diag::err_expected) << tok::identifier;
T.skipToEnd();
return;
}
@@ -1232,10 +1202,9 @@ void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
}
if (!T.consumeClose()) {
- Attrs.addNewTypeTagForDatatype(&AttrName, AttrNameLoc, 0, AttrNameLoc,
- ArgumentKind, MatchingCType.release(),
- LayoutCompatible, MustBeNull,
- AttributeList::AS_GNU);
+ Attrs.addNewTypeTagForDatatype(&AttrName, AttrNameLoc, ScopeName, ScopeLoc,
+ ArgumentKind, MatchingCType.get(),
+ LayoutCompatible, MustBeNull, Syntax);
}
if (EndLoc)
@@ -1337,8 +1306,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
// parsing c none objective-c decls.
ObjCDeclContextSwitch ObjCDC(*this);
- Decl *SingleDecl = 0;
- Decl *OwnedType = 0;
+ Decl *SingleDecl = nullptr;
+ Decl *OwnedType = nullptr;
switch (Tok.getKind()) {
case tok::kw_template:
case tok::kw_export:
@@ -1508,8 +1477,7 @@ void Parser::SkipMalformedDecl() {
// This declaration isn't over yet. Keep skipping.
continue;
}
- if (Tok.is(tok::semi))
- ConsumeToken();
+ TryConsumeToken(tok::semi);
return;
case tok::l_square:
@@ -1562,6 +1530,9 @@ void Parser::SkipMalformedDecl() {
break;
case tok::eof:
+ case tok::annot_module_begin:
+ case tok::annot_module_end:
+ case tok::annot_module_include:
return;
default:
@@ -1632,7 +1603,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
} else {
if (Tok.is(tok::l_brace)) {
Diag(Tok, diag::err_function_definition_not_allowed);
- SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
+ SkipMalformedDecl();
+ return DeclGroupPtrTy();
}
}
}
@@ -1648,9 +1620,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// don't need to parse the container in advance.
if (FRI && (Tok.is(tok::colon) || isTokIdentifier_in())) {
bool IsForRangeLoop = false;
- if (Tok.is(tok::colon)) {
+ if (TryConsumeToken(tok::colon, FRI->ColonLoc)) {
IsForRangeLoop = true;
- FRI->ColonLoc = ConsumeToken();
if (Tok.is(tok::l_brace))
FRI->RangeExpr = ParseBraceInitializer();
else
@@ -1666,7 +1637,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
}
SmallVector<Decl *, 8> DeclsInGroup;
- Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D);
+ Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(
+ D, ParsedTemplateInfo(), FRI);
if (LateParsedAttrs.size() > 0)
ParseLexedAttributeList(LateParsedAttrs, FirstDecl, true, false);
D.complete(FirstDecl);
@@ -1677,9 +1649,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// If we don't have a comma, it is either the end of the list (a ';') or an
// error, bail out.
- while (Tok.is(tok::comma)) {
- SourceLocation CommaLoc = ConsumeToken();
-
+ SourceLocation CommaLoc;
+ while (TryConsumeToken(tok::comma, CommaLoc)) {
if (Tok.isAtStartOfLine() && ExpectSemi && !MightBeDeclarator(Context)) {
// This comma was followed by a line-break and something which can't be
// the start of a declarator. The comma was probably a typo for a
@@ -1724,8 +1695,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// Otherwise things are very confused and we skip to recover.
if (!isDeclarationSpecifier()) {
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
- if (Tok.is(tok::semi))
- ConsumeToken();
+ TryConsumeToken(tok::semi);
}
}
@@ -1744,7 +1714,7 @@ bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) {
return true;
}
- D.setAsmLabel(AsmLabel.release());
+ D.setAsmLabel(AsmLabel.get());
D.SetRangeEnd(Loc);
}
@@ -1774,18 +1744,18 @@ bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) {
/// According to the standard grammar, =default and =delete are function
/// definitions, but that definitely doesn't fit with the parser here.
///
-Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D,
- const ParsedTemplateInfo &TemplateInfo) {
+Decl *Parser::ParseDeclarationAfterDeclarator(
+ Declarator &D, const ParsedTemplateInfo &TemplateInfo) {
if (ParseAsmAttributesAfterDeclarator(D))
- return 0;
+ return nullptr;
return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo);
}
-Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
- const ParsedTemplateInfo &TemplateInfo) {
+Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
+ Declarator &D, const ParsedTemplateInfo &TemplateInfo, ForRangeInit *FRI) {
// Inform the current actions module that we just parsed this declarator.
- Decl *ThisDecl = 0;
+ Decl *ThisDecl = nullptr;
switch (TemplateInfo.Kind) {
case ParsedTemplateInfo::NonTemplate:
ThisDecl = Actions.ActOnDeclarator(getCurScope(), D);
@@ -1808,7 +1778,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
getCurScope(), TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, D);
if (ThisRes.isInvalid()) {
SkipUntil(tok::semi, StopBeforeMatch);
- return 0;
+ return nullptr;
}
ThisDecl = ThisRes.get();
} else {
@@ -1832,8 +1802,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
// Recover as if it were an explicit specialization.
TemplateParameterLists FakedParamLists;
FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
- 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0,
- LAngleLoc));
+ 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, nullptr,
+ 0, LAngleLoc));
ThisDecl =
Actions.ActOnTemplateDeclarator(getCurScope(), FakedParamLists, D);
@@ -1848,7 +1818,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
// Parse declarator '=' initializer.
// If a '==' or '+=' is found, suggest a fixit to '='.
if (isTokenEqualOrEqualTypo()) {
- ConsumeToken();
+ SourceLocation EqualLoc = ConsumeToken();
if (Tok.is(tok::kw_delete)) {
if (D.isFunctionDeclarator())
@@ -1872,21 +1842,37 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
Actions.CodeCompleteInitializer(getCurScope(), ThisDecl);
Actions.FinalizeDeclaration(ThisDecl);
cutOffParsing();
- return 0;
+ return nullptr;
}
ExprResult Init(ParseInitializer());
+ // If this is the only decl in (possibly) range based for statement,
+ // our best guess is that the user meant ':' instead of '='.
+ if (Tok.is(tok::r_paren) && FRI && D.isFirstDeclarator()) {
+ Diag(EqualLoc, diag::err_single_decl_assign_in_for_range)
+ << FixItHint::CreateReplacement(EqualLoc, ":");
+ // We are trying to stop parser from looking for ';' in this for
+ // statement, therefore preventing spurious errors to be issued.
+ FRI->ColonLoc = EqualLoc;
+ Init = ExprError();
+ FRI->RangeExpr = Init;
+ }
+
if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) {
Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl);
ExitScope();
}
if (Init.isInvalid()) {
- SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
+ SmallVector<tok::TokenKind, 2> StopTokens;
+ StopTokens.push_back(tok::comma);
+ if (D.getContext() == Declarator::ForContext)
+ StopTokens.push_back(tok::r_paren);
+ SkipUntil(StopTokens, StopAtSemi | StopBeforeMatch);
Actions.ActOnInitializerError(ThisDecl);
} else
- Actions.AddInitializerToDecl(ThisDecl, Init.take(),
+ Actions.AddInitializerToDecl(ThisDecl, Init.get(),
/*DirectInit=*/false, TypeContainsAuto);
}
} else if (Tok.is(tok::l_paren)) {
@@ -1925,7 +1911,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(),
T.getCloseLocation(),
Exprs);
- Actions.AddInitializerToDecl(ThisDecl, Initializer.take(),
+ Actions.AddInitializerToDecl(ThisDecl, Initializer.get(),
/*DirectInit=*/true, TypeContainsAuto);
}
} else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace) &&
@@ -1948,7 +1934,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
if (Init.isInvalid()) {
Actions.ActOnInitializerError(ThisDecl);
} else
- Actions.AddInitializerToDecl(ThisDecl, Init.take(),
+ Actions.AddInitializerToDecl(ThisDecl, Init.get(),
/*DirectInit=*/true, TypeContainsAuto);
} else {
@@ -1975,8 +1961,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
// Validate declspec for type-name.
unsigned Specs = DS.getParsedSpecifiers();
- if ((DSC == DSC_type_specifier || DSC == DSC_trailing) &&
- !DS.hasTypeSpecifier()) {
+ if (isTypeSpecifier(DSC) && !DS.hasTypeSpecifier()) {
Diag(Tok, diag::err_expected_type);
DS.SetTypeSpecError();
} else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() &&
@@ -2050,7 +2035,7 @@ static bool isValidAfterIdentifierInDeclarator(const Token &T) {
///
bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
const ParsedTemplateInfo &TemplateInfo,
- AccessSpecifier AS, DeclSpecContext DSC,
+ AccessSpecifier AS, DeclSpecContext DSC,
ParsedAttributesWithRange &Attrs) {
assert(Tok.is(tok::identifier) && "should have identifier");
@@ -2074,8 +2059,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
// within a type specifier. Outside of C++, we allow this even if the
// language doesn't "officially" support implicit int -- we support
// implicit int as an extension in C99 and C11.
- if (DSC != DSC_type_specifier && DSC != DSC_trailing &&
- !getLangOpts().CPlusPlus &&
+ if (!isTypeSpecifier(DSC) && !getLangOpts().CPlusPlus &&
isValidAfterIdentifierInDeclarator(NextToken())) {
// If this token is valid for implicit int, e.g. "static x = 4", then
// we just avoid eating the identifier, so it will be parsed as the
@@ -2098,8 +2082,8 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
// This is a common problem in C (saying 'foo' instead of 'struct foo').
//
// C++ doesn't need this, and isTagName doesn't take SS.
- if (SS == 0) {
- const char *TagName = 0, *FixitTagName = 0;
+ if (SS == nullptr) {
+ const char *TagName = nullptr, *FixitTagName = nullptr;
tok::TokenKind TagKind = tok::unknown;
switch (Actions.isTagName(*Tok.getIdentifierInfo(), getCurScope())) {
@@ -2145,7 +2129,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
// Determine whether this identifier could plausibly be the name of something
// being declared (with a missing type).
- if (DSC != DSC_type_specifier && DSC != DSC_trailing &&
+ if (!isTypeSpecifier(DSC) &&
(!SS || DSC == DSC_top_level || DSC == DSC_class)) {
// Look ahead to the next token to try to figure out what this declaration
// was supposed to be.
@@ -2155,15 +2139,14 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
// x(int n); // 'x' is not a type
// x (*p)[]; // 'x' is a type
//
- // Since we're in an error case (or the rare 'implicit int in C++' MS
- // extension), we can afford to perform a tentative parse to determine
- // which case we're in.
+ // Since we're in an error case, we can afford to perform a tentative
+ // parse to determine which case we're in.
TentativeParsingAction PA(*this);
ConsumeToken();
TPResult TPR = TryParseDeclarator(/*mayBeAbstract*/false);
PA.Revert();
- if (TPR != TPResult::False()) {
+ if (TPR != TPResult::False) {
// The identifier is followed by a parenthesized declarator.
// It's supposed to be a type.
break;
@@ -2202,39 +2185,33 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
}
}
- // This is almost certainly an invalid type name. Let the action emit a
- // diagnostic and attempt to recover.
+ // This is almost certainly an invalid type name. Let Sema emit a diagnostic
+ // and attempt to recover.
ParsedType T;
IdentifierInfo *II = Tok.getIdentifierInfo();
- if (Actions.DiagnoseUnknownTypeName(II, Loc, getCurScope(), SS, T)) {
- // The action emitted a diagnostic, so we don't have to.
- if (T) {
- // The action has suggested that the type T could be used. Set that as
- // the type in the declaration specifiers, consume the would-be type
- // name token, and we're done.
- const char *PrevSpec;
- unsigned DiagID;
- DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, T);
- DS.SetRangeEnd(Tok.getLocation());
- ConsumeToken();
- // There may be other declaration specifiers after this.
- return true;
- } else if (II != Tok.getIdentifierInfo()) {
- // If no type was suggested, the correction is to a keyword
- Tok.setKind(II->getTokenID());
- // There may be other declaration specifiers after this.
- return true;
- }
-
- // Fall through; the action had no suggestion for us.
- } else {
- // The action did not emit a diagnostic, so emit one now.
- SourceRange R;
- if (SS) R = SS->getRange();
- Diag(Loc, diag::err_unknown_typename) << Tok.getIdentifierInfo() << R;
+ Actions.DiagnoseUnknownTypeName(II, Loc, getCurScope(), SS, T,
+ getLangOpts().CPlusPlus &&
+ NextToken().is(tok::less));
+ if (T) {
+ // The action has suggested that the type T could be used. Set that as
+ // the type in the declaration specifiers, consume the would-be type
+ // name token, and we're done.
+ const char *PrevSpec;
+ unsigned DiagID;
+ DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, T,
+ Actions.getASTContext().getPrintingPolicy());
+ DS.SetRangeEnd(Tok.getLocation());
+ ConsumeToken();
+ // There may be other declaration specifiers after this.
+ return true;
+ } else if (II != Tok.getIdentifierInfo()) {
+ // If no type was suggested, the correction is to a keyword
+ Tok.setKind(II->getTokenID());
+ // There may be other declaration specifiers after this.
+ return true;
}
- // Mark this as an error.
+ // Otherwise, the action had no suggestion for us. Mark this as an error.
DS.SetTypeSpecError();
DS.SetRangeEnd(Tok.getLocation());
ConsumeToken();
@@ -2256,8 +2233,13 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) {
return DSC_class;
if (Context == Declarator::FileContext)
return DSC_top_level;
+ if (Context == Declarator::TemplateTypeArgContext)
+ return DSC_template_type_arg;
if (Context == Declarator::TrailingReturnContext)
return DSC_trailing;
+ if (Context == Declarator::AliasDeclContext ||
+ Context == Declarator::AliasTemplateContext)
+ return DSC_alias_declaration;
return DSC_normal;
}
@@ -2282,8 +2264,8 @@ ExprResult Parser::ParseAlignArgument(SourceLocation Start,
} else
ER = ParseConstantExpression();
- if (getLangOpts().CPlusPlus11 && Tok.is(tok::ellipsis))
- EllipsisLoc = ConsumeToken();
+ if (getLangOpts().CPlusPlus11)
+ TryConsumeToken(tok::ellipsis, EllipsisLoc);
return ER;
}
@@ -2305,7 +2287,7 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
SourceLocation KWLoc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
- if (T.expectAndConsume(diag::err_expected_lparen))
+ if (T.expectAndConsume())
return;
SourceLocation EllipsisLoc;
@@ -2320,8 +2302,8 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
*EndLoc = T.getCloseLocation();
ArgsVector ArgExprs;
- ArgExprs.push_back(ArgExpr.release());
- Attrs.addNew(KWName, KWLoc, 0, KWLoc, ArgExprs.data(), 1,
+ ArgExprs.push_back(ArgExpr.get());
+ Attrs.addNew(KWName, KWLoc, nullptr, KWLoc, ArgExprs.data(), 1,
AttributeList::AS_Keyword, EllipsisLoc);
}
@@ -2339,7 +2321,6 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
assert(DS.hasTagDefinition() && "shouldn't call this");
bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level);
- bool HasMissingSemi = false;
if (getLangOpts().CPlusPlus &&
(Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
@@ -2349,63 +2330,77 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
return true;
}
+ bool HasScope = Tok.is(tok::annot_cxxscope);
+ // Make a copy in case GetLookAheadToken invalidates the result of NextToken.
+ Token AfterScope = HasScope ? NextToken() : Tok;
+
// Determine whether the following tokens could possibly be a
// declarator.
- if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) {
- const Token &Next = NextToken();
+ bool MightBeDeclarator = true;
+ if (Tok.is(tok::kw_typename) || Tok.is(tok::annot_typename)) {
+ // A declarator-id can't start with 'typename'.
+ MightBeDeclarator = false;
+ } else if (AfterScope.is(tok::annot_template_id)) {
+ // If we have a type expressed as a template-id, this cannot be a
+ // declarator-id (such a type cannot be redeclared in a simple-declaration).
+ TemplateIdAnnotation *Annot =
+ static_cast<TemplateIdAnnotation *>(AfterScope.getAnnotationValue());
+ if (Annot->Kind == TNK_Type_template)
+ MightBeDeclarator = false;
+ } else if (AfterScope.is(tok::identifier)) {
+ const Token &Next = HasScope ? GetLookAheadToken(2) : NextToken();
+
// These tokens cannot come after the declarator-id in a
// simple-declaration, and are likely to come after a type-specifier.
- HasMissingSemi = Next.is(tok::star) || Next.is(tok::amp) ||
- Next.is(tok::ampamp) || Next.is(tok::identifier) ||
- Next.is(tok::annot_cxxscope) ||
- Next.is(tok::coloncolon);
- } else if (Tok.is(tok::annot_cxxscope) &&
- NextToken().is(tok::identifier) &&
- DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
- // We almost certainly have a missing semicolon. Look up the name and
- // check; if it names a type, we're missing a semicolon.
- CXXScopeSpec SS;
- Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
- Tok.getAnnotationRange(), SS);
- const Token &Next = NextToken();
- IdentifierInfo *Name = Next.getIdentifierInfo();
- Sema::NameClassification Classification =
- Actions.ClassifyName(getCurScope(), SS, Name, Next.getLocation(),
- NextToken(), /*IsAddressOfOperand*/false);
- switch (Classification.getKind()) {
- case Sema::NC_Error:
- SkipMalformedDecl();
- return true;
+ if (Next.is(tok::star) || Next.is(tok::amp) || Next.is(tok::ampamp) ||
+ Next.is(tok::identifier) || Next.is(tok::annot_cxxscope) ||
+ Next.is(tok::coloncolon)) {
+ // Missing a semicolon.
+ MightBeDeclarator = false;
+ } else if (HasScope) {
+ // If the declarator-id has a scope specifier, it must redeclare a
+ // previously-declared entity. If that's a type (and this is not a
+ // typedef), that's an error.
+ CXXScopeSpec SS;
+ Actions.RestoreNestedNameSpecifierAnnotation(
+ Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS);
+ IdentifierInfo *Name = AfterScope.getIdentifierInfo();
+ Sema::NameClassification Classification = Actions.ClassifyName(
+ getCurScope(), SS, Name, AfterScope.getLocation(), Next,
+ /*IsAddressOfOperand*/false);
+ switch (Classification.getKind()) {
+ case Sema::NC_Error:
+ SkipMalformedDecl();
+ return true;
- case Sema::NC_Keyword:
- case Sema::NC_NestedNameSpecifier:
- llvm_unreachable("typo correction and nested name specifiers not "
- "possible here");
+ case Sema::NC_Keyword:
+ case Sema::NC_NestedNameSpecifier:
+ llvm_unreachable("typo correction and nested name specifiers not "
+ "possible here");
- case Sema::NC_Type:
- case Sema::NC_TypeTemplate:
- // Not a previously-declared non-type entity.
- HasMissingSemi = true;
- break;
+ case Sema::NC_Type:
+ case Sema::NC_TypeTemplate:
+ // Not a previously-declared non-type entity.
+ MightBeDeclarator = false;
+ break;
- case Sema::NC_Unknown:
- case Sema::NC_Expression:
- case Sema::NC_VarTemplate:
- case Sema::NC_FunctionTemplate:
- // Might be a redeclaration of a prior entity.
- HasMissingSemi = false;
- break;
+ case Sema::NC_Unknown:
+ case Sema::NC_Expression:
+ case Sema::NC_VarTemplate:
+ case Sema::NC_FunctionTemplate:
+ // Might be a redeclaration of a prior entity.
+ break;
+ }
}
- } else if (Tok.is(tok::kw_typename) || Tok.is(tok::annot_typename)) {
- HasMissingSemi = true;
}
- if (!HasMissingSemi)
+ if (MightBeDeclarator)
return false;
+ const PrintingPolicy &PPol = Actions.getASTContext().getPrintingPolicy();
Diag(PP.getLocForEndOfToken(DS.getRepAsDecl()->getLocEnd()),
- diag::err_expected_semi_after_tagdecl)
- << DeclSpec::getSpecifierName(DS.getTypeSpecType());
+ diag::err_expected_after)
+ << DeclSpec::getSpecifierName(DS.getTypeSpecType(), PPol) << tok::semi;
// Try to recover from the typo, by dropping the tag definition and parsing
// the problematic tokens as a type.
@@ -2461,9 +2456,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level);
bool AttrsLastTime = false;
ParsedAttributesWithRange attrs(AttrFactory);
+ const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy();
while (1) {
bool isInvalid = false;
- const char *PrevSpec = 0;
+ const char *PrevSpec = nullptr;
unsigned DiagID = 0;
SourceLocation Loc = Tok.getLocation();
@@ -2484,7 +2480,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// If this is not a declaration specifier token, we're done reading decl
// specifiers. First verify that DeclSpec's are consistent.
- DS.Finish(Diags, PP);
+ DS.Finish(Diags, PP, Policy);
return;
case tok::l_square:
@@ -2586,7 +2582,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if ((DSContext == DSC_top_level || DSContext == DSC_class) &&
TemplateId->Name &&
Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) {
- if (isConstructorDeclarator()) {
+ if (isConstructorDeclarator(/*Unqualified*/false)) {
// The user meant this to be an out-of-line constructor
// definition, but template arguments are not allowed
// there. Just allow this as a constructor; we'll
@@ -2618,7 +2614,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ParsedType T = getTypeAnnotation(Tok);
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename,
Tok.getAnnotationEndLoc(),
- PrevSpec, DiagID, T);
+ PrevSpec, DiagID, T, Policy);
if (isInvalid)
break;
}
@@ -2636,7 +2632,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if ((DSContext == DSC_top_level || DSContext == DSC_class) &&
Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(),
&SS)) {
- if (isConstructorDeclarator())
+ if (isConstructorDeclarator(/*Unqualified*/false))
goto DoneWithDeclSpec;
// As noted in C++ [class.qual]p2 (cited above), when the name
@@ -2677,7 +2673,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ConsumeToken(); // The C++ scope.
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
- DiagID, TypeRep);
+ DiagID, TypeRep, Policy);
if (isInvalid)
break;
@@ -2696,7 +2692,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (Tok.getAnnotationValue()) {
ParsedType T = getTypeAnnotation(Tok);
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
- DiagID, T);
+ DiagID, T, Policy);
} else
DS.SetTypeSpecError();
@@ -2734,24 +2730,23 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// typedef-name
case tok::kw_decltype:
case tok::identifier: {
+ // This identifier can only be a typedef name if we haven't already seen
+ // a type-specifier. Without this check we misparse:
+ // typedef int X; struct Y { short X; }; as 'short int'.
+ if (DS.hasTypeSpecifier())
+ goto DoneWithDeclSpec;
+
// In C++, check to see if this is a scope specifier like foo::bar::, if
// so handle it as such. This is important for ctor parsing.
if (getLangOpts().CPlusPlus) {
if (TryAnnotateCXXScopeToken(EnteringContext)) {
- if (!DS.hasTypeSpecifier())
- DS.SetTypeSpecError();
+ DS.SetTypeSpecError();
goto DoneWithDeclSpec;
}
if (!Tok.is(tok::identifier))
continue;
}
- // This identifier can only be a typedef name if we haven't already seen
- // a type-specifier. Without this check we misparse:
- // typedef int X; struct Y { short X; }; as 'short int'.
- if (DS.hasTypeSpecifier())
- goto DoneWithDeclSpec;
-
// Check for need to substitute AltiVec keyword tokens.
if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
break;
@@ -2765,11 +2760,21 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
Actions.getTypeName(*Tok.getIdentifierInfo(),
Tok.getLocation(), getCurScope());
+ // MSVC: If we weren't able to parse a default template argument, and it's
+ // just a simple identifier, create a DependentNameType. This will allow us
+ // to defer the name lookup to template instantiation time, as long we forge a
+ // NestedNameSpecifier for the current context.
+ if (!TypeRep && DSContext == DSC_template_type_arg &&
+ getLangOpts().MSVCCompat && getCurScope()->isTemplateParamScope()) {
+ TypeRep = Actions.ActOnDelayedDefaultTemplateArg(
+ *Tok.getIdentifierInfo(), Tok.getLocation());
+ }
+
// If this is not a typedef name, don't parse it as part of the declspec,
// it must be an implicit int or an error.
if (!TypeRep) {
ParsedAttributesWithRange Attrs(AttrFactory);
- if (ParseImplicitInt(DS, 0, TemplateInfo, AS, DSContext, Attrs)) {
+ if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) {
if (!Attrs.empty()) {
AttrsLastTime = true;
attrs.takeAllFrom(Attrs);
@@ -2783,11 +2788,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// check whether this is a constructor declaration.
if (getLangOpts().CPlusPlus && DSContext == DSC_class &&
Actions.isCurrentClassName(*Tok.getIdentifierInfo(), getCurScope()) &&
- isConstructorDeclarator())
+ isConstructorDeclarator(/*Unqualified*/true))
goto DoneWithDeclSpec;
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
- DiagID, TypeRep);
+ DiagID, TypeRep, Policy);
if (isInvalid)
break;
@@ -2819,7 +2824,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// constructor declaration.
if (getLangOpts().CPlusPlus && DSContext == DSC_class &&
Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) &&
- isConstructorDeclarator())
+ isConstructorDeclarator(TemplateId->SS.isEmpty()))
goto DoneWithDeclSpec;
// Turn the template-id annotation token into a type annotation
@@ -2830,7 +2835,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// GNU attributes support.
case tok::kw___attribute:
- ParseGNUAttributes(DS.getAttributes(), 0, LateAttrs);
+ ParseGNUAttributes(DS.getAttributes(), nullptr, LateAttrs);
continue;
// Microsoft declspec support.
@@ -2843,10 +2848,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.setFunctionSpecForceInline(Loc, PrevSpec, DiagID);
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = Tok.getLocation();
- // FIXME: This does not work correctly if it is set to be a declspec
- // attribute, and a GNU attribute is simply incorrect.
- DS.getAttributes().addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0,
- AttributeList::AS_GNU);
+ DS.getAttributes().addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc,
+ nullptr, 0, AttributeList::AS_Keyword);
break;
}
@@ -2876,46 +2879,46 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// storage-class-specifier
case tok::kw_typedef:
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_typedef, Loc,
- PrevSpec, DiagID);
+ PrevSpec, DiagID, Policy);
break;
case tok::kw_extern:
if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread)
Diag(Tok, diag::ext_thread_before) << "extern";
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_extern, Loc,
- PrevSpec, DiagID);
+ PrevSpec, DiagID, Policy);
break;
case tok::kw___private_extern__:
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_private_extern,
- Loc, PrevSpec, DiagID);
+ Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_static:
if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread)
Diag(Tok, diag::ext_thread_before) << "static";
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_static, Loc,
- PrevSpec, DiagID);
+ PrevSpec, DiagID, Policy);
break;
case tok::kw_auto:
if (getLangOpts().CPlusPlus11) {
if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
- PrevSpec, DiagID);
+ PrevSpec, DiagID, Policy);
if (!isInvalid)
Diag(Tok, diag::ext_auto_storage_class)
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
} else
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
} else
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
- PrevSpec, DiagID);
+ PrevSpec, DiagID, Policy);
break;
case tok::kw_register:
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_register, Loc,
- PrevSpec, DiagID);
+ PrevSpec, DiagID, Policy);
break;
case tok::kw_mutable:
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_mutable, Loc,
- PrevSpec, DiagID);
+ PrevSpec, DiagID, Policy);
break;
case tok::kw___thread:
isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS___thread, Loc,
@@ -2977,19 +2980,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// type-specifier
case tok::kw_short:
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
break;
case tok::kw_long:
if (DS.getTypeSpecWidth() != DeclSpec::TSW_long)
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
else
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
break;
case tok::kw___int64:
isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
break;
case tok::kw_signed:
isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec,
@@ -3009,43 +3012,43 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
break;
case tok::kw_void:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
break;
case tok::kw_char:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
break;
case tok::kw_int:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
break;
case tok::kw___int128:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
break;
case tok::kw_half:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
break;
case tok::kw_float:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
break;
case tok::kw_double:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
break;
case tok::kw_wchar_t:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
break;
case tok::kw_char16_t:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
break;
case tok::kw_char32_t:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
break;
case tok::kw_bool:
case tok::kw__Bool:
@@ -3059,62 +3062,30 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = true;
} else {
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
}
break;
case tok::kw__Decimal32:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal32, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
break;
case tok::kw__Decimal64:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal64, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
break;
case tok::kw__Decimal128:
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_decimal128, Loc, PrevSpec,
- DiagID);
+ DiagID, Policy);
break;
case tok::kw___vector:
- isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
+ isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw___pixel:
- isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID);
- break;
- case tok::kw_image1d_t:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image1d_t, Loc,
- PrevSpec, DiagID);
- break;
- case tok::kw_image1d_array_t:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image1d_array_t, Loc,
- PrevSpec, DiagID);
- break;
- case tok::kw_image1d_buffer_t:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image1d_buffer_t, Loc,
- PrevSpec, DiagID);
- break;
- case tok::kw_image2d_t:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image2d_t, Loc,
- PrevSpec, DiagID);
- break;
- case tok::kw_image2d_array_t:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image2d_array_t, Loc,
- PrevSpec, DiagID);
- break;
- case tok::kw_image3d_t:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image3d_t, Loc,
- PrevSpec, DiagID);
- break;
- case tok::kw_sampler_t:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_sampler_t, Loc,
- PrevSpec, DiagID);
- break;
- case tok::kw_event_t:
- isInvalid = DS.SetTypeSpecType(DeclSpec::TST_event_t, Loc,
- PrevSpec, DiagID);
+ isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw___unknown_anytype:
isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc,
- PrevSpec, DiagID);
+ PrevSpec, DiagID, Policy);
break;
// class-specifier:
@@ -3198,9 +3169,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
break;
// OpenCL qualifiers:
- case tok::kw_private:
- if (!getLangOpts().OpenCL)
- goto DoneWithDeclSpec;
case tok::kw___private:
case tok::kw___global:
case tok::kw___local:
@@ -3208,7 +3176,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw___read_only:
case tok::kw___write_only:
case tok::kw___read_write:
- ParseOpenCLQualifiers(DS);
+ ParseOpenCLQualifiers(DS.getAttributes());
break;
case tok::less:
@@ -3305,13 +3273,12 @@ ParseStructDeclaration(ParsingDeclSpec &DS, FieldCallback &Fields) {
ParseDeclarator(DeclaratorInfo.D);
}
- if (Tok.is(tok::colon)) {
- ConsumeToken();
+ if (TryConsumeToken(tok::colon)) {
ExprResult Res(ParseConstantExpression());
if (Res.isInvalid())
SkipUntil(tok::semi, StopBeforeMatch);
else
- DeclaratorInfo.BitfieldSize = Res.release();
+ DeclaratorInfo.BitfieldSize = Res.get();
}
// If attributes exist after the declarator, parse them.
@@ -3322,12 +3289,9 @@ ParseStructDeclaration(ParsingDeclSpec &DS, FieldCallback &Fields) {
// If we don't have a comma, it is either the end of the list (a ';')
// or an error, bail out.
- if (Tok.isNot(tok::comma))
+ if (!TryConsumeToken(tok::comma, CommaLoc))
return;
- // Consume the comma.
- CommaLoc = ConsumeToken();
-
FirstDeclarator = false;
}
}
@@ -3358,7 +3322,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
SmallVector<Decl *, 32> FieldDecls;
// While we still have something to read, read the declarations in the struct.
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
// Each iteration of this loop reads one struct-declaration.
// Check for extraneous top-level semicolon.
@@ -3394,7 +3358,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
SmallVectorImpl<Decl *> &FieldDecls) :
P(P), TagDecl(TagDecl), FieldDecls(FieldDecls) {}
- void invoke(ParsingFieldDeclarator &FD) {
+ void invoke(ParsingFieldDeclarator &FD) override {
// Install the declarator into the current TagDecl.
Decl *Field = P.Actions.ActOnField(P.getCurScope(), TagDecl,
FD.D.getDeclSpec().getSourceRange().getBegin(),
@@ -3415,9 +3379,9 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
continue;
}
ConsumeToken();
- ExpectAndConsume(tok::l_paren, diag::err_expected_lparen);
+ ExpectAndConsume(tok::l_paren);
if (!Tok.is(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
+ Diag(Tok, diag::err_expected) << tok::identifier;
SkipUntil(tok::semi);
continue;
}
@@ -3426,21 +3390,22 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
Tok.getIdentifierInfo(), Fields);
FieldDecls.insert(FieldDecls.end(), Fields.begin(), Fields.end());
ConsumeToken();
- ExpectAndConsume(tok::r_paren, diag::err_expected_rparen);
+ ExpectAndConsume(tok::r_paren);
}
- if (Tok.is(tok::semi)) {
- ConsumeToken();
- } else if (Tok.is(tok::r_brace)) {
+ if (TryConsumeToken(tok::semi))
+ continue;
+
+ if (Tok.is(tok::r_brace)) {
ExpectAndConsume(tok::semi, diag::ext_expected_semi_decl_list);
break;
- } else {
- ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list);
- // Skip to end of block or statement to avoid ext-warning on extra ';'.
- SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
- // If we stopped at a ';', eat it.
- if (Tok.is(tok::semi)) ConsumeToken();
}
+
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list);
+ // Skip to end of block or statement to avoid ext-warning on extra ';'.
+ SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
+ // If we stopped at a ';', eat it.
+ TryConsumeToken(tok::semi);
}
T.consumeClose();
@@ -3557,7 +3522,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
return;
if (SS.isSet() && Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
+ Diag(Tok, diag::err_expected) << tok::identifier;
if (Tok.isNot(tok::l_brace)) {
// Has no name and is not a definition.
// Skip the rest of this declarator, up until the comma or semicolon.
@@ -3570,7 +3535,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// Must have either 'enum name' or 'enum {...}'.
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace) &&
!(AllowFixedUnderlyingType && Tok.is(tok::colon))) {
- Diag(Tok, diag::err_expected_ident_lbrace);
+ Diag(Tok, diag::err_expected_either) << tok::identifier << tok::l_brace;
// Skip the rest of this declarator, up until the comma or semicolon.
SkipUntil(tok::comma, StopAtSemi);
@@ -3578,7 +3543,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
}
// If an identifier is present, consume and remember it.
- IdentifierInfo *Name = 0;
+ IdentifierInfo *Name = nullptr;
SourceLocation NameLoc;
if (Tok.is(tok::identifier)) {
Name = Tok.getIdentifierInfo();
@@ -3617,13 +3582,13 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
TPResult TPR = isExpressionOrTypeSpecifierSimple(NextToken().getKind());
// If the next token starts an expression, we know we're parsing a
// bit-field. This is the common case.
- if (TPR == TPResult::True())
+ if (TPR == TPResult::True)
PossibleBitfield = true;
// If the next token starts a type-specifier-seq, it may be either a
// a fixed underlying type or the start of a function-style cast in C++;
// lookahead one more token to see if it's obvious that we have a
// fixed underlying type.
- else if (TPR == TPResult::False() &&
+ else if (TPR == TPResult::False &&
GetLookAheadToken(2).getKind() == tok::semi) {
// Consume the ':'.
ConsumeToken();
@@ -3643,7 +3608,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// FIXME: The standard is not entirely clear on how to disambiguate in
// this case.
if ((getLangOpts().CPlusPlus &&
- isCXXDeclarationSpecifier(TPResult::True()) != TPResult::True()) ||
+ isCXXDeclarationSpecifier(TPResult::True) != TPResult::True) ||
(!getLangOpts().CPlusPlus && !isDeclarationSpecifier(true))) {
// We'll parse this as a bitfield later.
PossibleBitfield = true;
@@ -3696,15 +3661,14 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
} else {
TUK = Sema::TUK_Definition;
}
- } else if (DSC != DSC_type_specifier &&
+ } else if (!isTypeSpecifier(DSC) &&
(Tok.is(tok::semi) ||
(Tok.isAtStartOfLine() &&
!isValidAfterTypeSpecifier(CanBeBitfield)))) {
TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration;
if (Tok.isNot(tok::semi)) {
// A semicolon was missing after this declaration. Diagnose and recover.
- ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
- "enum");
+ ExpectAndConsume(tok::semi, diag::err_expected_after, "enum");
PP.EnterToken(Tok);
Tok.setKind(tok::semi);
}
@@ -3753,13 +3717,14 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
bool Owned = false;
bool IsDependent = false;
- const char *PrevSpec = 0;
+ const char *PrevSpec = nullptr;
unsigned DiagID;
Decl *TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK,
StartLoc, SS, Name, NameLoc, attrs.getList(),
AS, DS.getModulePrivateSpecLoc(), TParams,
Owned, IsDependent, ScopedEnumKWLoc,
- IsScopedUsingClassTag, BaseType);
+ IsScopedUsingClassTag, BaseType,
+ DSC == DSC_type_specifier);
if (IsDependent) {
// This enum has a dependent nested-name-specifier. Handle it as a
@@ -3770,9 +3735,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
return;
}
- TypeResult Type = Actions.ActOnDependentTag(getCurScope(), DeclSpec::TST_enum,
- TUK, SS, Name, StartLoc,
- NameLoc);
+ TypeResult Type = Actions.ActOnDependentTag(
+ getCurScope(), DeclSpec::TST_enum, TUK, SS, Name, StartLoc, NameLoc);
if (Type.isInvalid()) {
DS.SetTypeSpecError();
return;
@@ -3780,7 +3744,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc,
NameLoc.isValid() ? NameLoc : StartLoc,
- PrevSpec, DiagID, Type.get()))
+ PrevSpec, DiagID, Type.get(),
+ Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
return;
@@ -3803,7 +3768,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
NameLoc.isValid() ? NameLoc : StartLoc,
- PrevSpec, DiagID, TagDecl, Owned))
+ PrevSpec, DiagID, TagDecl, Owned,
+ Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
}
@@ -3819,7 +3785,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
///
void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
// Enter the scope of the enum body and start the definition.
- ParseScope EnumScope(this, Scope::DeclScope);
+ ParseScope EnumScope(this, Scope::DeclScope | Scope::EnumScope);
Actions.ActOnTagStartDefinition(getCurScope(), EnumDecl);
BalancedDelimiterTracker T(*this, tok::l_brace);
@@ -3831,10 +3797,19 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
SmallVector<Decl *, 32> EnumConstantDecls;
- Decl *LastEnumConstDecl = 0;
+ Decl *LastEnumConstDecl = nullptr;
// Parse the enumerator-list.
- while (Tok.is(tok::identifier)) {
+ while (Tok.isNot(tok::r_brace)) {
+ // Parse enumerator. If failed, try skipping till the start of the next
+ // enumerator definition.
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
+ if (SkipUntil(tok::comma, tok::r_brace, StopBeforeMatch) &&
+ TryConsumeToken(tok::comma))
+ continue;
+ break;
+ }
IdentifierInfo *Ident = Tok.getIdentifierInfo();
SourceLocation IdentLoc = ConsumeToken();
@@ -3848,11 +3823,10 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
ExprResult AssignedVal;
ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent);
- if (Tok.is(tok::equal)) {
- EqualLoc = ConsumeToken();
+ if (TryConsumeToken(tok::equal, EqualLoc)) {
AssignedVal = ParseConstantExpression();
if (AssignedVal.isInvalid())
- SkipUntil(tok::comma, tok::r_brace, StopAtSemi | StopBeforeMatch);
+ SkipUntil(tok::comma, tok::r_brace, StopBeforeMatch);
}
// Install the enumerator constant into EnumDecl.
@@ -3860,7 +3834,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
LastEnumConstDecl,
IdentLoc, Ident,
attrs.getList(), EqualLoc,
- AssignedVal.release());
+ AssignedVal.get());
PD.complete(EnumConstDecl);
EnumConstantDecls.push_back(EnumConstDecl);
@@ -3874,11 +3848,25 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
continue;
}
- if (Tok.isNot(tok::comma))
- break;
- SourceLocation CommaLoc = ConsumeToken();
+ // Emumerator definition must be finished, only comma or r_brace are
+ // allowed here.
+ SourceLocation CommaLoc;
+ if (Tok.isNot(tok::r_brace) && !TryConsumeToken(tok::comma, CommaLoc)) {
+ if (EqualLoc.isValid())
+ Diag(Tok.getLocation(), diag::err_expected_either) << tok::r_brace
+ << tok::comma;
+ else
+ Diag(Tok.getLocation(), diag::err_expected_end_of_enumerator);
+ if (SkipUntil(tok::comma, tok::r_brace, StopBeforeMatch)) {
+ if (TryConsumeToken(tok::comma, CommaLoc))
+ continue;
+ } else {
+ break;
+ }
+ }
- if (Tok.isNot(tok::identifier)) {
+ // If comma is followed by r_brace, emit appropriate warning.
+ if (Tok.is(tok::r_brace) && CommaLoc.isValid()) {
if (!getLangOpts().C99 && !getLangOpts().CPlusPlus11)
Diag(CommaLoc, getLangOpts().CPlusPlus ?
diag::ext_enumerator_list_comma_cxx :
@@ -3887,6 +3875,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
else if (getLangOpts().CPlusPlus11)
Diag(CommaLoc, diag::warn_cxx98_compat_enumerator_list_comma)
<< FixItHint::CreateRemoval(CommaLoc);
+ break;
}
}
@@ -3910,7 +3899,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
// was probably forgotten.
bool CanBeBitfield = getCurScope()->getFlags() & Scope::ClassScope;
if (!isValidAfterTypeSpecifier(CanBeBitfield)) {
- ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, "enum");
+ ExpectAndConsume(tok::semi, diag::err_expected_after, "enum");
// Push this token back into the preprocessor and change our current token
// to ';' so that the rest of the code recovers as though there were an
// ';' after the definition.
@@ -3924,12 +3913,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
bool Parser::isTypeQualifier() const {
switch (Tok.getKind()) {
default: return false;
-
- // type-qualifier only in OpenCL
- case tok::kw_private:
- return getLangOpts().OpenCL;
-
- // type-qualifier
+ // type-qualifier
case tok::kw_const:
case tok::kw_volatile:
case tok::kw_restrict:
@@ -3975,16 +3959,6 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const {
case tok::kw__Decimal128:
case tok::kw___vector:
- // OpenCL specific types:
- case tok::kw_image1d_t:
- case tok::kw_image1d_array_t:
- case tok::kw_image1d_buffer_t:
- case tok::kw_image2d_t:
- case tok::kw_image2d_array_t:
- case tok::kw_image3d_t:
- case tok::kw_sampler_t:
- case tok::kw_event_t:
-
// struct-or-union-specifier (C99) or class-specifier (C++)
case tok::kw_class:
case tok::kw_struct:
@@ -4057,16 +4031,6 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw__Decimal128:
case tok::kw___vector:
- // OpenCL specific types:
- case tok::kw_image1d_t:
- case tok::kw_image1d_array_t:
- case tok::kw_image1d_buffer_t:
- case tok::kw_image2d_t:
- case tok::kw_image2d_array_t:
- case tok::kw_image3d_t:
- case tok::kw_sampler_t:
- case tok::kw_event_t:
-
// struct-or-union-specifier (C99) or class-specifier (C++)
case tok::kw_class:
case tok::kw_struct:
@@ -4111,9 +4075,6 @@ bool Parser::isTypeSpecifierQualifier() {
return true;
- case tok::kw_private:
- return getLangOpts().OpenCL;
-
// C11 _Atomic
case tok::kw__Atomic:
return true;
@@ -4129,9 +4090,6 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
switch (Tok.getKind()) {
default: return false;
- case tok::kw_private:
- return getLangOpts().OpenCL;
-
case tok::identifier: // foo::bar
// Unfortunate hack to support "Class.factoryMethod" notation.
if (getLangOpts().ObjC1 && NextToken().is(tok::period))
@@ -4213,16 +4171,6 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw__Decimal128:
case tok::kw___vector:
- // OpenCL specific types:
- case tok::kw_image1d_t:
- case tok::kw_image1d_array_t:
- case tok::kw_image1d_buffer_t:
- case tok::kw_image2d_t:
- case tok::kw_image2d_array_t:
- case tok::kw_image3d_t:
- case tok::kw_sampler_t:
- case tok::kw_event_t:
-
// struct-or-union-specifier (C99) or class-specifier (C++)
case tok::kw_class:
case tok::kw_struct:
@@ -4300,7 +4248,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
}
}
-bool Parser::isConstructorDeclarator() {
+bool Parser::isConstructorDeclarator(bool IsUnqualified) {
TentativeParsingAction TPA(*this);
// Parse the C++ scope specifier.
@@ -4382,12 +4330,35 @@ bool Parser::isConstructorDeclarator() {
case tok::coloncolon:
// C(X :: Y);
// C(X :: *p);
- case tok::r_paren:
- // C(X )
// Assume this isn't a constructor, rather than assuming it's a
// constructor with an unnamed parameter of an ill-formed type.
break;
+ case tok::r_paren:
+ // C(X )
+ if (NextToken().is(tok::colon) || NextToken().is(tok::kw_try)) {
+ // Assume these were meant to be constructors:
+ // C(X) : (the name of a bit-field cannot be parenthesized).
+ // C(X) try (this is otherwise ill-formed).
+ IsConstructor = true;
+ }
+ if (NextToken().is(tok::semi) || NextToken().is(tok::l_brace)) {
+ // If we have a constructor name within the class definition,
+ // assume these were meant to be constructors:
+ // C(X) {
+ // C(X) ;
+ // ... because otherwise we would be declaring a non-static data
+ // member that is ill-formed because it's of the same type as its
+ // surrounding class.
+ //
+ // FIXME: We can actually do this whether or not the name is qualified,
+ // because if it is qualified in this context it must be being used as
+ // a constructor name. However, we do not implement that rule correctly
+ // currently, so we're somewhat conservative here.
+ IsConstructor = IsUnqualified;
+ }
+ break;
+
default:
IsConstructor = true;
break;
@@ -4426,7 +4397,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
while (1) {
bool isInvalid = false;
- const char *PrevSpec = 0;
+ const char *PrevSpec = nullptr;
unsigned DiagID = 0;
SourceLocation Loc = Tok.getLocation();
@@ -4455,9 +4426,6 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
break;
// OpenCL qualifiers:
- case tok::kw_private:
- if (!getLangOpts().OpenCL)
- goto DoneWithTypeQuals;
case tok::kw___private:
case tok::kw___global:
case tok::kw___local:
@@ -4465,7 +4433,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
case tok::kw___read_only:
case tok::kw___write_only:
case tok::kw___read_write:
- ParseOpenCLQualifiers(DS);
+ ParseOpenCLQualifiers(DS.getAttributes());
break;
case tok::kw___uptr:
@@ -4506,7 +4474,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
DoneWithTypeQuals:
// If this is not a type-qualifier token, we're done reading type
// qualifiers. First verify that DeclSpec's are consistent.
- DS.Finish(Diags, PP);
+ DS.Finish(Diags, PP, Actions.getASTContext().getPrintingPolicy());
if (EndLoc.isValid())
DS.SetRangeEnd(EndLoc);
return;
@@ -4575,7 +4543,9 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
// Member pointers get special handling, since there's no place for the
// scope spec in the generic path below.
if (getLangOpts().CPlusPlus &&
- (Tok.is(tok::coloncolon) || Tok.is(tok::identifier) ||
+ (Tok.is(tok::coloncolon) ||
+ (Tok.is(tok::identifier) &&
+ (NextToken().is(tok::coloncolon) || NextToken().is(tok::less))) ||
Tok.is(tok::annot_cxxscope))) {
bool EnteringContext = D.getContext() == Declarator::FileContext ||
D.getContext() == Declarator::MemberContext;
@@ -4710,17 +4680,17 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
}
}
-static void diagnoseMisplacedEllipsis(Parser &P, Declarator &D,
- SourceLocation EllipsisLoc) {
- if (EllipsisLoc.isValid()) {
- FixItHint Insertion;
- if (!D.getEllipsisLoc().isValid()) {
- Insertion = FixItHint::CreateInsertion(D.getIdentifierLoc(), "...");
- D.setEllipsisLoc(EllipsisLoc);
- }
- P.Diag(EllipsisLoc, diag::err_misplaced_ellipsis_in_declaration)
- << FixItHint::CreateRemoval(EllipsisLoc) << Insertion << !D.hasName();
- }
+// When correcting from misplaced brackets before the identifier, the location
+// is saved inside the declarator so that other diagnostic messages can use
+// them. This extracts and returns that location, or returns the provided
+// location if a stored location does not exist.
+static SourceLocation getMissingDeclaratorIdLoc(Declarator &D,
+ SourceLocation Loc) {
+ if (D.getName().StartLocation.isInvalid() &&
+ D.getName().EndLocation.isValid())
+ return D.getName().EndLocation;
+
+ return Loc;
}
/// ParseDirectDeclarator
@@ -4768,6 +4738,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec());
if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) {
+ // Don't parse FOO:BAR as if it were a typo for FOO::BAR inside a class, in
+ // this context it is a bitfield. Also in range-based for statement colon
+ // may delimit for-range-declaration.
+ ColonProtectionRAIIObject X(*this,
+ D.getContext() == Declarator::MemberContext ||
+ (D.getContext() == Declarator::ForContext &&
+ getLangOpts().CPlusPlus11));
+
// ParseDeclaratorInternal might already have parsed the scope.
if (D.getCXXScopeSpec().isEmpty()) {
bool EnteringContext = D.getContext() == Declarator::FileContext ||
@@ -4802,7 +4780,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// The ellipsis was put in the wrong place. Recover, and explain to
// the user what they should have done.
ParseDeclarator(D);
- diagnoseMisplacedEllipsis(*this, D, EllipsisLoc);
+ if (EllipsisLoc.isValid())
+ DiagnoseMisplacedEllipsisInDeclarator(EllipsisLoc, D);
return;
} else
D.setEllipsisLoc(EllipsisLoc);
@@ -4837,7 +4816,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// Once we're past the identifier, if the scope was bad, mark the
// whole declarator bad.
D.getCXXScopeSpec().isInvalid()) {
- D.SetIdentifier(0, Tok.getLocation());
+ D.SetIdentifier(nullptr, Tok.getLocation());
D.setInvalidType(true);
} else {
// Parsed the unqualified-id; update range information and move along.
@@ -4852,6 +4831,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
"There's a C++-specific check for tok::identifier above");
assert(Tok.getIdentifierInfo() && "Not an identifier?");
D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
+ D.SetRangeEnd(Tok.getLocation());
ConsumeToken();
goto PastIdentifier;
} else if (Tok.is(tok::identifier) && D.diagnoseIdentifier()) {
@@ -4861,7 +4841,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
!isCXX11VirtSpecifier(Tok)) {
Diag(Tok.getLocation(), diag::err_unexpected_unqualified_id)
<< FixItHint::CreateRemoval(Tok.getLocation());
- D.SetIdentifier(0, Tok.getLocation());
+ D.SetIdentifier(nullptr, Tok.getLocation());
ConsumeToken();
goto PastIdentifier;
}
@@ -4888,7 +4868,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
} else if (D.mayOmitIdentifier()) {
// This could be something simple like "int" (in which case the declarator
// portion is empty), if an abstract-declarator is allowed.
- D.SetIdentifier(0, Tok.getLocation());
+ D.SetIdentifier(nullptr, Tok.getLocation());
// The grammar for abstract-pack-declarator does not allow grouping parens.
// FIXME: Revisit this once core issue 1488 is resolved.
@@ -4898,10 +4878,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
} else {
if (Tok.getKind() == tok::annot_pragma_parser_crash)
LLVM_BUILTIN_TRAP;
- if (D.getContext() == Declarator::MemberContext)
- Diag(Tok, diag::err_expected_member_name_or_semi)
- << D.getDeclSpec().getSourceRange();
- else if (getLangOpts().CPlusPlus) {
+ if (Tok.is(tok::l_square))
+ return ParseMisplacedBracketDeclarator(D);
+ if (D.getContext() == Declarator::MemberContext) {
+ Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
+ diag::err_expected_member_name_or_semi)
+ << (D.getDeclSpec().isEmpty() ? SourceRange()
+ : D.getDeclSpec().getSourceRange());
+ } else if (getLangOpts().CPlusPlus) {
if (Tok.is(tok::period) || Tok.is(tok::arrow))
Diag(Tok, diag::err_invalid_operator_on_type) << Tok.is(tok::arrow);
else {
@@ -4910,12 +4894,16 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
Diag(PP.getLocForEndOfToken(Loc), diag::err_expected_unqualified_id)
<< getLangOpts().CPlusPlus;
else
- Diag(Tok, diag::err_expected_unqualified_id)
+ Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
+ diag::err_expected_unqualified_id)
<< getLangOpts().CPlusPlus;
}
- } else
- Diag(Tok, diag::err_expected_ident_lparen);
- D.SetIdentifier(0, Tok.getLocation());
+ } else {
+ Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
+ diag::err_expected_either)
+ << tok::identifier << tok::l_paren;
+ }
+ D.SetIdentifier(nullptr, Tok.getLocation());
D.setInvalidType(true);
}
@@ -5051,7 +5039,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// An ellipsis cannot be placed outside parentheses.
if (EllipsisLoc.isValid())
- diagnoseMisplacedEllipsis(*this, D, EllipsisLoc);
+ DiagnoseMisplacedEllipsisInDeclarator(EllipsisLoc, D);
return;
}
@@ -5060,7 +5048,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// argument list. Recognize that this declarator will never have an
// identifier (and remember where it would have been), then call into
// ParseFunctionDeclarator to handle of argument list.
- D.SetIdentifier(0, Tok.getLocation());
+ D.SetIdentifier(nullptr, Tok.getLocation());
// Enter function-declaration scope, limiting any declarators to the
// function prototype scope, including parameter declarators.
@@ -5122,7 +5110,6 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
ParsedAttributes FnAttrs(AttrFactory);
TypeResult TrailingReturnType;
- Actions.ActOnStartFunctionDeclarator();
/* LocalEndLoc is the end location for the local FunctionTypeLoc.
EndLoc is the end location for the function declarator.
They differ for trailing return types. */
@@ -5191,6 +5178,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
// FIXME: currently, "static" case isn't handled correctly.
bool IsCXX11MemberFunction =
getLangOpts().CPlusPlus11 &&
+ D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
(D.getContext() == Declarator::MemberContext
? !D.getDeclSpec().isFriendSpecified()
: D.getContext() == Declarator::FileContext &&
@@ -5246,12 +5234,10 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
DynamicExceptionRanges.data(),
DynamicExceptions.size(),
NoexceptExpr.isUsable() ?
- NoexceptExpr.get() : 0,
+ NoexceptExpr.get() : nullptr,
StartLoc, LocalEndLoc, D,
TrailingReturnType),
FnAttrs, EndLoc);
-
- Actions.ActOnEndFunctionDeclarator();
}
/// isFunctionDeclaratorIdentifierList - This parameter list may have an
@@ -5303,10 +5289,10 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
// Maintain an efficient lookup of params we have seen so far.
llvm::SmallSet<const IdentifierInfo*, 16> ParamsSoFar;
- while (1) {
+ do {
// If this isn't an identifier, report the error and skip until ')'.
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
+ Diag(Tok, diag::err_expected) << tok::identifier;
SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch);
// Forget we parsed anything.
ParamInfo.clear();
@@ -5326,17 +5312,13 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
// Remember this identifier in ParamInfo.
ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
Tok.getLocation(),
- 0));
+ nullptr));
}
// Eat the identifier.
ConsumeToken();
-
// The list continues if we see a comma.
- if (Tok.isNot(tok::comma))
- break;
- ConsumeToken();
- }
+ } while (TryConsumeToken(tok::comma));
}
/// ParseParameterDeclarationClause - Parse a (possibly empty) parameter-list
@@ -5375,13 +5357,11 @@ void Parser::ParseParameterDeclarationClause(
ParsedAttributes &FirstArgAttrs,
SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo,
SourceLocation &EllipsisLoc) {
- while (1) {
- if (Tok.is(tok::ellipsis)) {
- // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq
- // before deciding this was a parameter-declaration-clause.
- EllipsisLoc = ConsumeToken(); // Consume the ellipsis.
+ do {
+ // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq
+ // before deciding this was a parameter-declaration-clause.
+ if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
break;
- }
// Parse the declaration-specifiers.
// Just use the ParsingDeclaration "scope" of the declarator.
@@ -5422,11 +5402,11 @@ void Parser::ParseParameterDeclarationClause(
// DefArgToks is used when the parsing of default arguments needs
// to be delayed.
- CachedTokens *DefArgToks = 0;
+ CachedTokens *DefArgToks = nullptr;
// If no parameter was specified, verify that *something* was specified,
// otherwise we have a missing type and identifier.
- if (DS.isEmpty() && ParmDeclarator.getIdentifier() == 0 &&
+ if (DS.isEmpty() && ParmDeclarator.getIdentifier() == nullptr &&
ParmDeclarator.getNumTypeObjects() == 0) {
// Completely missing, emit error.
Diag(DSStart, diag::err_missing_param);
@@ -5455,8 +5435,8 @@ void Parser::ParseParameterDeclarationClause(
if (!ConsumeAndStoreInitializer(*DefArgToks, CIK_DefaultArgument)) {
delete DefArgToks;
- DefArgToks = 0;
- Actions.ActOnParamDefaultArgumentError(Param);
+ DefArgToks = nullptr;
+ Actions.ActOnParamDefaultArgumentError(Param, EqualLoc);
} else {
// Mark the end of the default argument so that we know when to
// stop when we parse it later on.
@@ -5485,12 +5465,12 @@ void Parser::ParseParameterDeclarationClause(
} else
DefArgResult = ParseAssignmentExpression();
if (DefArgResult.isInvalid()) {
- Actions.ActOnParamDefaultArgumentError(Param);
+ Actions.ActOnParamDefaultArgumentError(Param, EqualLoc);
SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch);
} else {
// Inform the actions module about the default argument
Actions.ActOnParamDefaultArgument(Param, EqualLoc,
- DefArgResult.take());
+ DefArgResult.get());
}
}
}
@@ -5500,26 +5480,17 @@ void Parser::ParseParameterDeclarationClause(
Param, DefArgToks));
}
- // If the next token is a comma, consume it and keep reading arguments.
- if (Tok.isNot(tok::comma)) {
- if (Tok.is(tok::ellipsis)) {
- EllipsisLoc = ConsumeToken(); // Consume the ellipsis.
-
- if (!getLangOpts().CPlusPlus) {
- // We have ellipsis without a preceding ',', which is ill-formed
- // in C. Complain and provide the fix.
- Diag(EllipsisLoc, diag::err_missing_comma_before_ellipsis)
- << FixItHint::CreateInsertion(EllipsisLoc, ", ");
- }
- }
-
+ if (TryConsumeToken(tok::ellipsis, EllipsisLoc) &&
+ !getLangOpts().CPlusPlus) {
+ // We have ellipsis without a preceding ',', which is ill-formed
+ // in C. Complain and provide the fix.
+ Diag(EllipsisLoc, diag::err_missing_comma_before_ellipsis)
+ << FixItHint::CreateInsertion(EllipsisLoc, ", ");
break;
}
- // Consume the comma.
- ConsumeToken();
- }
-
+ // If the next token is a comma, consume it and keep reading arguments.
+ } while (TryConsumeToken(tok::comma));
}
/// [C90] direct-declarator '[' constant-expression[opt] ']'
@@ -5544,8 +5515,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
MaybeParseCXX11Attributes(attrs);
// Remember that we parsed the empty array type.
- ExprResult NumElements;
- D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0,
+ D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, nullptr,
T.getOpenLocation(),
T.getCloseLocation()),
attrs, T.getCloseLocation());
@@ -5562,7 +5532,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
// Remember that we parsed a array type, and remember its features.
D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false,
- ExprRes.release(),
+ ExprRes.get(),
T.getOpenLocation(),
T.getCloseLocation()),
attrs, T.getCloseLocation());
@@ -5571,8 +5541,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
// If valid, this location is the position where we read the 'static' keyword.
SourceLocation StaticLoc;
- if (Tok.is(tok::kw_static))
- StaticLoc = ConsumeToken();
+ TryConsumeToken(tok::kw_static, StaticLoc);
// If there is a type-qualifier-list, read it now.
// Type qualifiers in an array subscript are a C99 feature.
@@ -5581,8 +5550,8 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
// If we haven't already read 'static', check to see if there is one after the
// type-qualifier-list.
- if (!StaticLoc.isValid() && Tok.is(tok::kw_static))
- StaticLoc = ConsumeToken();
+ if (!StaticLoc.isValid())
+ TryConsumeToken(tok::kw_static, StaticLoc);
// Handle "direct-declarator [ type-qual-list[opt] * ]".
bool isStar = false;
@@ -5633,12 +5602,102 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
// Remember that we parsed a array type, and remember its features.
D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(),
StaticLoc.isValid(), isStar,
- NumElements.release(),
+ NumElements.get(),
T.getOpenLocation(),
T.getCloseLocation()),
attrs, T.getCloseLocation());
}
+/// Diagnose brackets before an identifier.
+void Parser::ParseMisplacedBracketDeclarator(Declarator &D) {
+ assert(Tok.is(tok::l_square) && "Missing opening bracket");
+ assert(!D.mayOmitIdentifier() && "Declarator cannot omit identifier");
+
+ SourceLocation StartBracketLoc = Tok.getLocation();
+ Declarator TempDeclarator(D.getDeclSpec(), D.getContext());
+
+ while (Tok.is(tok::l_square)) {
+ ParseBracketDeclarator(TempDeclarator);
+ }
+
+ // Stuff the location of the start of the brackets into the Declarator.
+ // The diagnostics from ParseDirectDeclarator will make more sense if
+ // they use this location instead.
+ if (Tok.is(tok::semi))
+ D.getName().EndLocation = StartBracketLoc;
+
+ SourceLocation SuggestParenLoc = Tok.getLocation();
+
+ // Now that the brackets are removed, try parsing the declarator again.
+ ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
+
+ // Something went wrong parsing the brackets, in which case,
+ // ParseBracketDeclarator has emitted an error, and we don't need to emit
+ // one here.
+ if (TempDeclarator.getNumTypeObjects() == 0)
+ return;
+
+ // Determine if parens will need to be suggested in the diagnostic.
+ bool NeedParens = false;
+ if (D.getNumTypeObjects() != 0) {
+ switch (D.getTypeObject(D.getNumTypeObjects() - 1).Kind) {
+ case DeclaratorChunk::Pointer:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::MemberPointer:
+ NeedParens = true;
+ break;
+ case DeclaratorChunk::Array:
+ case DeclaratorChunk::Function:
+ case DeclaratorChunk::Paren:
+ break;
+ }
+ }
+
+ if (NeedParens) {
+ // Create a DeclaratorChunk for the inserted parens.
+ ParsedAttributes attrs(AttrFactory);
+ SourceLocation EndLoc = PP.getLocForEndOfToken(D.getLocEnd());
+ D.AddTypeInfo(DeclaratorChunk::getParen(SuggestParenLoc, EndLoc), attrs,
+ SourceLocation());
+ }
+
+ // Adding back the bracket info to the end of the Declarator.
+ for (unsigned i = 0, e = TempDeclarator.getNumTypeObjects(); i < e; ++i) {
+ const DeclaratorChunk &Chunk = TempDeclarator.getTypeObject(i);
+ ParsedAttributes attrs(AttrFactory);
+ attrs.set(Chunk.Common.AttrList);
+ D.AddTypeInfo(Chunk, attrs, SourceLocation());
+ }
+
+ // The missing identifier would have been diagnosed in ParseDirectDeclarator.
+ // If parentheses are required, always suggest them.
+ if (!D.getIdentifier() && !NeedParens)
+ return;
+
+ SourceLocation EndBracketLoc = TempDeclarator.getLocEnd();
+
+ // Generate the move bracket error message.
+ SourceRange BracketRange(StartBracketLoc, EndBracketLoc);
+ SourceLocation EndLoc = PP.getLocForEndOfToken(D.getLocEnd());
+
+ if (NeedParens) {
+ Diag(EndLoc, diag::err_brackets_go_after_unqualified_id)
+ << getLangOpts().CPlusPlus
+ << FixItHint::CreateInsertion(SuggestParenLoc, "(")
+ << FixItHint::CreateInsertion(EndLoc, ")")
+ << FixItHint::CreateInsertionFromRange(
+ EndLoc, CharSourceRange(BracketRange, true))
+ << FixItHint::CreateRemoval(BracketRange);
+ } else {
+ Diag(EndLoc, diag::err_brackets_go_after_unqualified_id)
+ << getLangOpts().CPlusPlus
+ << FixItHint::CreateInsertionFromRange(
+ EndLoc, CharSourceRange(BracketRange, true))
+ << FixItHint::CreateRemoval(BracketRange);
+ }
+}
+
/// [GNU] typeof-specifier:
/// typeof ( expressions )
/// typeof ( type-name )
@@ -5674,11 +5733,12 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
return;
}
- const char *PrevSpec = 0;
+ const char *PrevSpec = nullptr;
unsigned DiagID;
// Check for duplicate type specifiers (e.g. "int typeof(int)").
if (DS.SetTypeSpecType(DeclSpec::TST_typeofType, StartLoc, PrevSpec,
- DiagID, CastTy))
+ DiagID, CastTy,
+ Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
return;
}
@@ -5696,11 +5756,12 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
return;
}
- const char *PrevSpec = 0;
+ const char *PrevSpec = nullptr;
unsigned DiagID;
// Check for duplicate type specifiers (e.g. "int typeof(int)").
if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec,
- DiagID, Operand.get()))
+ DiagID, Operand.get(),
+ Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
}
@@ -5731,10 +5792,11 @@ void Parser::ParseAtomicSpecifier(DeclSpec &DS) {
DS.setTypeofParensRange(T.getRange());
DS.SetRangeEnd(T.getCloseLocation());
- const char *PrevSpec = 0;
+ const char *PrevSpec = nullptr;
unsigned DiagID;
if (DS.SetTypeSpecType(DeclSpec::TST_atomic, StartLoc, PrevSpec,
- DiagID, Result.release()))
+ DiagID, Result.get(),
+ Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
}
@@ -5774,6 +5836,7 @@ bool Parser::TryAltiVecVectorTokenOutOfLine() {
bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc,
const char *&PrevSpec, unsigned &DiagID,
bool &isInvalid) {
+ const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy();
if (Tok.getIdentifierInfo() == Ident_vector) {
Token Next = NextToken();
switch (Next.getKind()) {
@@ -5788,15 +5851,15 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc,
case tok::kw_double:
case tok::kw_bool:
case tok::kw___pixel:
- isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
+ isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID, Policy);
return true;
case tok::identifier:
if (Next.getIdentifierInfo() == Ident_pixel) {
- isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
+ isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID,Policy);
return true;
}
if (Next.getIdentifierInfo() == Ident_bool) {
- isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID);
+ isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID,Policy);
return true;
}
break;
@@ -5805,11 +5868,11 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc,
}
} else if ((Tok.getIdentifierInfo() == Ident_pixel) &&
DS.isTypeAltiVecVector()) {
- isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID);
+ isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID, Policy);
return true;
} else if ((Tok.getIdentifierInfo() == Ident_bool) &&
DS.isTypeAltiVecVector()) {
- isInvalid = DS.SetTypeAltiVecBool(true, Loc, PrevSpec, DiagID);
+ isInvalid = DS.SetTypeAltiVecBool(true, Loc, PrevSpec, DiagID, Policy);
return true;
}
return false;
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index dd29f99ffc71..6200363b3bc5 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -13,9 +13,12 @@
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/Basic/Attributes.h"
#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/OperatorKinds.h"
-#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
@@ -61,11 +64,11 @@ Decl *Parser::ParseNamespace(unsigned Context,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteNamespaceDecl(getCurScope());
cutOffParsing();
- return 0;
+ return nullptr;
}
SourceLocation IdentLoc;
- IdentifierInfo *Ident = 0;
+ IdentifierInfo *Ident = nullptr;
std::vector<SourceLocation> ExtraIdentLoc;
std::vector<IdentifierInfo*> ExtraIdent;
std::vector<SourceLocation> ExtraNamespaceLoc;
@@ -90,11 +93,11 @@ Decl *Parser::ParseNamespace(unsigned Context,
}
if (Tok.is(tok::equal)) {
- if (Ident == 0) {
- Diag(Tok, diag::err_expected_ident);
+ if (!Ident) {
+ Diag(Tok, diag::err_expected) << tok::identifier;
// Skip to end of the definition and eat the ';'.
SkipUntil(tok::semi);
- return 0;
+ return nullptr;
}
if (!attrs.empty())
Diag(attrTok, diag::err_unexpected_namespace_attributes_alias);
@@ -111,9 +114,13 @@ Decl *Parser::ParseNamespace(unsigned Context,
Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
<< SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
}
- Diag(Tok, Ident ? diag::err_expected_lbrace :
- diag::err_expected_ident_lbrace);
- return 0;
+
+ if (Ident)
+ Diag(Tok, diag::err_expected) << tok::l_brace;
+ else
+ Diag(Tok, diag::err_expected_either) << tok::identifier << tok::l_brace;
+
+ return nullptr;
}
if (getCurScope()->isClassScope() || getCurScope()->isTemplateParamScope() ||
@@ -125,7 +132,7 @@ Decl *Parser::ParseNamespace(unsigned Context,
}
Diag(T.getOpenLocation(), diag::err_namespace_nonnamespace_scope);
SkipUntil(tok::r_brace);
- return 0;
+ return nullptr;
}
if (!ExtraIdent.empty()) {
@@ -195,7 +202,7 @@ void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
ParsedAttributes& attrs,
BalancedDelimiterTracker &Tracker) {
if (index == Ident.size()) {
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX11Attributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
@@ -239,7 +246,7 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteNamespaceAliasDecl(getCurScope());
cutOffParsing();
- return 0;
+ return nullptr;
}
CXXScopeSpec SS;
@@ -250,7 +257,7 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
Diag(Tok, diag::err_expected_namespace_name);
// Skip to end of the definition and eat the ';'.
SkipUntil(tok::semi);
- return 0;
+ return nullptr;
}
// Parse identifier.
@@ -259,8 +266,8 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
// Eat the ';'.
DeclEnd = Tok.getLocation();
- ExpectAndConsume(tok::semi, diag::err_expected_semi_after_namespace_name,
- "", tok::semi);
+ if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after_namespace_name))
+ SkipUntil(tok::semi);
return Actions.ActOnNamespaceAliasDef(getCurScope(), NamespaceLoc, AliasLoc, Alias,
SS, IdentLoc, Ident);
@@ -274,27 +281,16 @@ Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc,
/// 'extern' string-literal declaration
///
Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
- assert(Tok.is(tok::string_literal) && "Not a string literal!");
- SmallString<8> LangBuffer;
- bool Invalid = false;
- StringRef Lang = PP.getSpelling(Tok, LangBuffer, &Invalid);
- if (Invalid)
- return 0;
-
- // FIXME: This is incorrect: linkage-specifiers are parsed in translation
- // phase 7, so string-literal concatenation is supposed to occur.
- // extern "" "C" "" "+" "+" { } is legal.
- if (Tok.hasUDSuffix())
- Diag(Tok, diag::err_invalid_string_udl);
- SourceLocation Loc = ConsumeStringToken();
+ assert(isTokenStringLiteral() && "Not a string literal!");
+ ExprResult Lang = ParseStringLiteralExpression(false);
ParseScope LinkageScope(this, Scope::DeclScope);
- Decl *LinkageSpec
- = Actions.ActOnStartLinkageSpecification(getCurScope(),
- DS.getSourceRange().getBegin(),
- Loc, Lang,
- Tok.is(tok::l_brace) ? Tok.getLocation()
- : SourceLocation());
+ Decl *LinkageSpec =
+ Lang.isInvalid()
+ ? nullptr
+ : Actions.ActOnStartLinkageSpecification(
+ getCurScope(), DS.getSourceRange().getBegin(), Lang.get(),
+ Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation());
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX11Attributes(attrs);
@@ -308,8 +304,9 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
// ... but anyway remember that such an "extern" was seen.
DS.setExternInLinkageSpec(true);
ParseExternalDeclaration(attrs, &DS);
- return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec,
- SourceLocation());
+ return LinkageSpec ? Actions.ActOnFinishLinkageSpecification(
+ getCurScope(), LinkageSpec, SourceLocation())
+ : nullptr;
}
DS.abort();
@@ -318,16 +315,48 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
BalancedDelimiterTracker T(*this, tok::l_brace);
T.consumeOpen();
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
- ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX11Attributes(attrs);
- MaybeParseMicrosoftAttributes(attrs);
- ParseExternalDeclaration(attrs);
+
+ unsigned NestedModules = 0;
+ while (true) {
+ switch (Tok.getKind()) {
+ case tok::annot_module_begin:
+ ++NestedModules;
+ ParseTopLevelDecl();
+ continue;
+
+ case tok::annot_module_end:
+ if (!NestedModules)
+ break;
+ --NestedModules;
+ ParseTopLevelDecl();
+ continue;
+
+ case tok::annot_module_include:
+ ParseTopLevelDecl();
+ continue;
+
+ case tok::eof:
+ break;
+
+ case tok::r_brace:
+ if (!NestedModules)
+ break;
+ // Fall through.
+ default:
+ ParsedAttributesWithRange attrs(AttrFactory);
+ MaybeParseCXX11Attributes(attrs);
+ MaybeParseMicrosoftAttributes(attrs);
+ ParseExternalDeclaration(attrs);
+ continue;
+ }
+
+ break;
}
T.consumeClose();
- return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec,
- T.getCloseLocation());
+ return LinkageSpec ? Actions.ActOnFinishLinkageSpecification(
+ getCurScope(), LinkageSpec, T.getCloseLocation())
+ : nullptr;
}
/// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or
@@ -346,7 +375,7 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteUsing(getCurScope());
cutOffParsing();
- return 0;
+ return nullptr;
}
// 'using namespace' means this is a using-directive.
@@ -392,14 +421,14 @@ Decl *Parser::ParseUsingDirective(unsigned Context,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteUsingDirective(getCurScope());
cutOffParsing();
- return 0;
+ return nullptr;
}
CXXScopeSpec SS;
// Parse (optional) nested-name-specifier.
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
- IdentifierInfo *NamespcName = 0;
+ IdentifierInfo *NamespcName = nullptr;
SourceLocation IdentLoc = SourceLocation();
// Parse namespace-name.
@@ -408,7 +437,7 @@ Decl *Parser::ParseUsingDirective(unsigned Context,
// If there was invalid namespace name, skip to end of decl, and eat ';'.
SkipUntil(tok::semi);
// FIXME: Are there cases, when we would like to call ActOnUsingDirective?
- return 0;
+ return nullptr;
}
// Parse identifier.
@@ -424,10 +453,10 @@ Decl *Parser::ParseUsingDirective(unsigned Context,
// Eat ';'.
DeclEnd = Tok.getLocation();
- ExpectAndConsume(tok::semi,
- GNUAttr ? diag::err_expected_semi_after_attribute_list
- : diag::err_expected_semi_after_namespace_name,
- "", tok::semi);
+ if (ExpectAndConsume(tok::semi,
+ GNUAttr ? diag::err_expected_semi_after_attribute_list
+ : diag::err_expected_semi_after_namespace_name))
+ SkipUntil(tok::semi);
return Actions.ActOnUsingDirective(getCurScope(), UsingLoc, NamespcLoc, SS,
IdentLoc, NamespcName, attrs.getList());
@@ -461,21 +490,20 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
// Ignore optional 'typename'.
// FIXME: This is wrong; we should parse this as a typename-specifier.
- if (Tok.is(tok::kw_typename)) {
- TypenameLoc = ConsumeToken();
+ if (TryConsumeToken(tok::kw_typename, TypenameLoc))
HasTypenameKeyword = true;
- }
// Parse nested-name-specifier.
- IdentifierInfo *LastII = 0;
+ IdentifierInfo *LastII = nullptr;
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false,
- /*MayBePseudoDtor=*/0, /*IsTypename=*/false,
+ /*MayBePseudoDtor=*/nullptr,
+ /*IsTypename=*/false,
/*LastII=*/&LastII);
// Check nested-name specifier.
if (SS.isInvalid()) {
SkipUntil(tok::semi);
- return 0;
+ return nullptr;
}
SourceLocation TemplateKWLoc;
@@ -504,7 +532,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
/*AllowConstructorName=*/ true, ParsedType(),
TemplateKWLoc, Name)) {
SkipUntil(tok::semi);
- return 0;
+ return nullptr;
}
ParsedAttributesWithRange Attrs(AttrFactory);
@@ -551,7 +579,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
Diag(Range.getBegin(), diag::err_alias_declaration_specialization)
<< SpecKind << Range;
SkipUntil(tok::semi);
- return 0;
+ return nullptr;
}
// Name must be an identifier.
@@ -559,7 +587,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
Diag(Name.StartLocation, diag::err_alias_declaration_not_identifier);
// No removal fixit: can't recover from this.
SkipUntil(tok::semi);
- return 0;
+ return nullptr;
} else if (HasTypenameKeyword)
Diag(TypenameLoc, diag::err_alias_declaration_not_identifier)
<< FixItHint::CreateRemoval(SourceRange(TypenameLoc,
@@ -568,7 +596,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier)
<< FixItHint::CreateRemoval(SS.getRange());
- TypeAlias = ParseTypeName(0, TemplateInfo.Kind ?
+ TypeAlias = ParseTypeName(nullptr, TemplateInfo.Kind ?
Declarator::AliasTemplateContext :
Declarator::AliasDeclContext, AS, OwnedType,
&Attrs);
@@ -584,10 +612,11 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
// Eat ';'.
DeclEnd = Tok.getLocation();
- ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
- !Attrs.empty() ? "attributes list" :
- IsAliasDecl ? "alias declaration" : "using declaration",
- tok::semi);
+ if (ExpectAndConsume(tok::semi, diag::err_expected_after,
+ !Attrs.empty() ? "attributes list"
+ : IsAliasDecl ? "alias declaration"
+ : "using declaration"))
+ SkipUntil(tok::semi);
// Diagnose an attempt to declare a templated using-declaration.
// In C++11, alias-declarations can be templates:
@@ -600,7 +629,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
// Unfortunately, we have to bail out instead of recovering by
// ignoring the parameters, just in case the nested name specifier
// depends on the parameters.
- return 0;
+ return nullptr;
}
// "typename" keyword is allowed for identifiers only,
@@ -615,7 +644,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
if (IsAliasDecl) {
TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
MultiTemplateParamsArg TemplateParamsArg(
- TemplateParams ? TemplateParams->data() : 0,
+ TemplateParams ? TemplateParams->data() : nullptr,
TemplateParams ? TemplateParams->size() : 0);
return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
UsingLoc, Name, Attrs.getList(),
@@ -649,31 +678,43 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.consumeOpen()) {
- Diag(Tok, diag::err_expected_lparen);
+ Diag(Tok, diag::err_expected) << tok::l_paren;
SkipMalformedDecl();
- return 0;
+ return nullptr;
}
ExprResult AssertExpr(ParseConstantExpression());
if (AssertExpr.isInvalid()) {
SkipMalformedDecl();
- return 0;
+ return nullptr;
}
- if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::semi))
- return 0;
+ ExprResult AssertMessage;
+ if (Tok.is(tok::r_paren)) {
+ Diag(Tok, getLangOpts().CPlusPlus1z
+ ? diag::warn_cxx1y_compat_static_assert_no_message
+ : diag::ext_static_assert_no_message)
+ << (getLangOpts().CPlusPlus1z
+ ? FixItHint()
+ : FixItHint::CreateInsertion(Tok.getLocation(), ", \"\""));
+ } else {
+ if (ExpectAndConsume(tok::comma)) {
+ SkipUntil(tok::semi);
+ return nullptr;
+ }
- if (!isTokenStringLiteral()) {
- Diag(Tok, diag::err_expected_string_literal)
- << /*Source='static_assert'*/1;
- SkipMalformedDecl();
- return 0;
- }
+ if (!isTokenStringLiteral()) {
+ Diag(Tok, diag::err_expected_string_literal)
+ << /*Source='static_assert'*/1;
+ SkipMalformedDecl();
+ return nullptr;
+ }
- ExprResult AssertMessage(ParseStringLiteralExpression());
- if (AssertMessage.isInvalid()) {
- SkipMalformedDecl();
- return 0;
+ AssertMessage = ParseStringLiteralExpression();
+ if (AssertMessage.isInvalid()) {
+ SkipMalformedDecl();
+ return nullptr;
+ }
}
T.consumeClose();
@@ -682,8 +723,8 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
ExpectAndConsumeSemi(diag::err_expected_semi_after_static_assert);
return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc,
- AssertExpr.take(),
- AssertMessage.take(),
+ AssertExpr.get(),
+ AssertMessage.get(),
T.getCloseLocation());
}
@@ -738,7 +779,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
// C++11 [dcl.type.simple]p4:
// The operand of the decltype specifier is an unevaluated operand.
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,
- 0, /*IsDecltype=*/true);
+ nullptr,/*IsDecltype=*/true);
Result = ParseExpression();
if (Result.isInvalid()) {
DS.SetTypeSpecError();
@@ -758,7 +799,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
return EndLoc;
}
- Result = Actions.ActOnDecltypeExpression(Result.take());
+ Result = Actions.ActOnDecltypeExpression(Result.get());
}
// Match the ')'
@@ -779,14 +820,15 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
}
assert(!Result.isInvalid());
- const char *PrevSpec = 0;
+ const char *PrevSpec = nullptr;
unsigned DiagID;
+ const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy();
// Check for duplicate type specifiers (e.g. "int decltype(a)").
if (Result.get()
? DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec,
- DiagID, Result.release())
+ DiagID, Result.get(), Policy)
: DS.SetTypeSpecType(DeclSpec::TST_decltype_auto, StartLoc, PrevSpec,
- DiagID)) {
+ DiagID, Policy)) {
Diag(StartLoc, DiagID) << PrevSpec;
DS.SetTypeSpecError();
}
@@ -834,10 +876,11 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
if (T.getCloseLocation().isInvalid())
return;
- const char *PrevSpec = 0;
+ const char *PrevSpec = nullptr;
unsigned DiagID;
if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec,
- DiagID, Result.release()))
+ DiagID, Result.get(),
+ Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
DS.setTypeofParensRange(T.getRange());
}
@@ -963,7 +1006,7 @@ Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
}
// We have an identifier; check whether it is actually a type.
- IdentifierInfo *CorrectedII = 0;
+ IdentifierInfo *CorrectedII = nullptr;
ParsedType Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, true,
false, ParsedType(),
/*IsCtorOrDtorName=*/false,
@@ -983,9 +1026,10 @@ Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
DS.SetRangeEnd(EndLocation);
DS.getTypeSpecScope() = SS;
- const char *PrevSpec = 0;
+ const char *PrevSpec = nullptr;
unsigned DiagID;
- DS.SetTypeSpecType(TST_typename, IdLoc, PrevSpec, DiagID, Type);
+ DS.SetTypeSpecType(TST_typename, IdLoc, PrevSpec, DiagID, Type,
+ Actions.getASTContext().getPrintingPolicy());
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
@@ -997,8 +1041,8 @@ void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) {
Tok.is(tok::kw___virtual_inheritance)) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
- attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0,
- AttributeList::AS_GNU);
+ attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
+ AttributeList::AS_Keyword);
}
}
@@ -1021,6 +1065,7 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
case tok::l_paren: // struct foo {...} ( x);
case tok::comma: // __builtin_offsetof(struct foo{...} ,
case tok::kw_operator: // struct foo operator ++() {...}
+ case tok::kw___declspec: // struct foo {...} __declspec(...)
return true;
case tok::colon:
return CouldBeBitfield; // enum E { ... } : 2;
@@ -1179,51 +1224,38 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// C++11 attributes
SourceLocation AttrFixitLoc = Tok.getLocation();
- if (TagType == DeclSpec::TST_struct &&
- !Tok.is(tok::identifier) &&
- Tok.getIdentifierInfo() &&
- (Tok.is(tok::kw___is_arithmetic) ||
- Tok.is(tok::kw___is_convertible) ||
- Tok.is(tok::kw___is_empty) ||
- Tok.is(tok::kw___is_floating_point) ||
- Tok.is(tok::kw___is_function) ||
- Tok.is(tok::kw___is_fundamental) ||
- Tok.is(tok::kw___is_integral) ||
- Tok.is(tok::kw___is_member_function_pointer) ||
- Tok.is(tok::kw___is_member_pointer) ||
- Tok.is(tok::kw___is_pod) ||
- Tok.is(tok::kw___is_pointer) ||
- Tok.is(tok::kw___is_same) ||
- Tok.is(tok::kw___is_scalar) ||
- Tok.is(tok::kw___is_signed) ||
- Tok.is(tok::kw___is_unsigned) ||
- Tok.is(tok::kw___is_void)))
- // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
- // name of struct templates, but some are keywords in GCC >= 4.3
- // and Clang. Therefore, when we see the token sequence "struct
- // X", make X into a normal identifier rather than a keyword, to
- // allow libstdc++ 4.2 and libc++ to work properly.
- TryKeywordIdentFallback(true);
+ // GNU libstdc++ and libc++ use certain intrinsic names as the
+ // name of struct templates, but some are keywords in GCC >= 4.3
+ // MSVC and Clang. For compatibility, convert the token to an identifier
+ // and issue a warning diagnostic.
+ if (TagType == DeclSpec::TST_struct && !Tok.is(tok::identifier) &&
+ !Tok.isAnnotation()) {
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ // We rarely end up here so the following check is efficient.
+ if (II && II->getName().startswith("__is_"))
+ TryKeywordIdentFallback(true);
+ }
// Parse the (optional) nested-name-specifier.
CXXScopeSpec &SS = DS.getTypeSpecScope();
if (getLangOpts().CPlusPlus) {
- // "FOO : BAR" is not a potential typo for "FOO::BAR".
+ // "FOO : BAR" is not a potential typo for "FOO::BAR". In this context it
+ // is a base-specifier-list.
ColonProtectionRAIIObject X(*this);
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
DS.SetTypeSpecError();
if (SS.isSet())
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
- Diag(Tok, diag::err_expected_ident);
+ Diag(Tok, diag::err_expected) << tok::identifier;
}
TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
// Parse the (optional) class name or simple-template-id.
- IdentifierInfo *Name = 0;
+ IdentifierInfo *Name = nullptr;
SourceLocation NameLoc;
- TemplateIdAnnotation *TemplateId = 0;
+ TemplateIdAnnotation *TemplateId = nullptr;
if (Tok.is(tok::identifier)) {
Name = Tok.getIdentifierInfo();
NameLoc = ConsumeToken();
@@ -1243,13 +1275,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
}
Diag(NameLoc, diag::err_explicit_spec_non_template)
- << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
- << (TagType == DeclSpec::TST_class? 0
- : TagType == DeclSpec::TST_struct? 1
- : TagType == DeclSpec::TST_union? 2
- : 3)
- << Name
- << SourceRange(LAngleLoc, RAngleLoc);
+ << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
+ << TagTokKind << Name << SourceRange(LAngleLoc, RAngleLoc);
// Strip off the last template parameter list if it was empty, since
// we've removed its template argument list.
@@ -1257,14 +1284,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (TemplateParams && TemplateParams->size() > 1) {
TemplateParams->pop_back();
} else {
- TemplateParams = 0;
+ TemplateParams = nullptr;
const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind
= ParsedTemplateInfo::NonTemplate;
}
} else if (TemplateInfo.Kind
== ParsedTemplateInfo::ExplicitInstantiation) {
// Pretend this is just a forward declaration.
- TemplateParams = 0;
+ TemplateParams = nullptr;
const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind
= ParsedTemplateInfo::NonTemplate;
const_cast<ParsedTemplateInfo&>(TemplateInfo).TemplateLoc
@@ -1286,6 +1313,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (SS.isNotEmpty())
Range.setBegin(SS.getBeginLoc());
+ // FIXME: Name may be null here.
Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template)
<< TemplateId->Name << static_cast<int>(TemplateId->Kind) << Range;
@@ -1318,11 +1346,12 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// new struct s;
// or
// &T::operator struct s;
- // For these, DSC is DSC_type_specifier.
+ // For these, DSC is DSC_type_specifier or DSC_alias_declaration.
// If there are attributes after class name, parse them.
MaybeParseCXX11Attributes(Attributes);
+ const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy();
Sema::TagUseKind TUK;
if (DSC == DSC_trailing)
TUK = Sema::TUK_Reference;
@@ -1375,14 +1404,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TUK = Sema::TUK_Reference;
PA.Revert();
- } else if (DSC != DSC_type_specifier &&
+ } else if (!isTypeSpecifier(DSC) &&
(Tok.is(tok::semi) ||
(Tok.isAtStartOfLine() && !isValidAfterTypeSpecifier(false)))) {
TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration;
if (Tok.isNot(tok::semi)) {
+ const PrintingPolicy &PPol = Actions.getASTContext().getPrintingPolicy();
// A semicolon was missing after this declaration. Diagnose and recover.
- ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
- DeclSpec::getSpecifierName(TagType));
+ ExpectAndConsume(tok::semi, diag::err_expected_after,
+ DeclSpec::getSpecifierName(TagType, PPol));
PP.EnterToken(Tok);
Tok.setKind(tok::semi);
}
@@ -1424,7 +1454,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (DS.getTypeSpecType() != DeclSpec::TST_error) {
// We have a declaration or reference to an anonymous class.
Diag(StartLoc, diag::err_anon_type_definition)
- << DeclSpec::getSpecifierName(TagType);
+ << DeclSpec::getSpecifierName(TagType, Policy);
}
// If we are parsing a definition and stop at a base-clause, continue on
@@ -1503,7 +1533,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (TUK == Sema::TUK_Friend) {
Diag(DS.getFriendSpecLoc(), diag::err_friend_explicit_instantiation);
- TemplateParams = 0;
+ TemplateParams = nullptr;
} else {
SourceLocation LAngleLoc =
PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
@@ -1516,25 +1546,19 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// "template<>", so that we treat this construct as a class
// template specialization.
FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
- 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0,
- LAngleLoc));
+ 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, nullptr,
+ 0, LAngleLoc));
TemplateParams = &FakedParamLists;
}
}
// Build the class template specialization.
- TagOrTempResult
- = Actions.ActOnClassTemplateSpecialization(getCurScope(), TagType, TUK,
- StartLoc, DS.getModulePrivateSpecLoc(), SS,
- TemplateId->Template,
- TemplateId->TemplateNameLoc,
- TemplateId->LAngleLoc,
- TemplateArgsPtr,
- TemplateId->RAngleLoc,
- attrs.getList(),
- MultiTemplateParamsArg(
- TemplateParams? &(*TemplateParams)[0] : 0,
- TemplateParams? TemplateParams->size() : 0));
+ TagOrTempResult = Actions.ActOnClassTemplateSpecialization(
+ getCurScope(), TagType, TUK, StartLoc, DS.getModulePrivateSpecLoc(),
+ *TemplateId, attrs.getList(),
+ MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0]
+ : nullptr,
+ TemplateParams ? TemplateParams->size() : 0));
}
} else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
TUK == Sema::TUK_Declaration) {
@@ -1560,7 +1584,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TagType, StartLoc, SS,
Name, NameLoc, attrs.getList(),
MultiTemplateParamsArg(
- TemplateParams? &(*TemplateParams)[0] : 0,
+ TemplateParams? &(*TemplateParams)[0]
+ : nullptr,
TemplateParams? TemplateParams->size() : 0));
} else {
if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition)
@@ -1572,7 +1597,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// recover by ignoring the 'template' keyword.
Diag(Tok, diag::err_template_defn_explicit_instantiation)
<< 1 << FixItHint::CreateRemoval(TemplateInfo.TemplateLoc);
- TemplateParams = 0;
+ TemplateParams = nullptr;
}
bool IsDependent = false;
@@ -1591,7 +1616,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
DS.getModulePrivateSpecLoc(),
TParams, Owned, IsDependent,
SourceLocation(), false,
- clang::TypeResult());
+ clang::TypeResult(),
+ DSC == DSC_type_specifier);
// If ActOnTag said the type was dependent, try again with the
// less common call.
@@ -1614,17 +1640,18 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get());
}
- const char *PrevSpec = 0;
+ const char *PrevSpec = nullptr;
unsigned DiagID;
bool Result;
if (!TypeResult.isInvalid()) {
Result = DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc,
NameLoc.isValid() ? NameLoc : StartLoc,
- PrevSpec, DiagID, TypeResult.get());
+ PrevSpec, DiagID, TypeResult.get(), Policy);
} else if (!TagOrTempResult.isInvalid()) {
Result = DS.SetTypeSpecType(TagType, StartLoc,
NameLoc.isValid() ? NameLoc : StartLoc,
- PrevSpec, DiagID, TagOrTempResult.get(), Owned);
+ PrevSpec, DiagID, TagOrTempResult.get(), Owned,
+ Policy);
} else {
DS.SetTypeSpecError();
return;
@@ -1645,8 +1672,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (TUK == Sema::TUK_Definition &&
(TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) {
if (Tok.isNot(tok::semi)) {
- ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
- DeclSpec::getSpecifierName(TagType));
+ const PrintingPolicy &PPol = Actions.getASTContext().getPrintingPolicy();
+ ExpectAndConsume(tok::semi, diag::err_expected_after,
+ DeclSpec::getSpecifierName(TagType, PPol));
// Push this token back into the preprocessor and change our current token
// to ';' so that the rest of the code recovers as though there were an
// ';' after the definition.
@@ -1684,10 +1712,8 @@ void Parser::ParseBaseClause(Decl *ClassDecl) {
// If the next token is a comma, consume it and keep reading
// base-specifiers.
- if (Tok.isNot(tok::comma)) break;
-
- // Consume the comma.
- ConsumeToken();
+ if (!TryConsumeToken(tok::comma))
+ break;
}
// Attach the base specifiers
@@ -1713,10 +1739,8 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
MaybeParseCXX11Attributes(Attributes);
// Parse the 'virtual' keyword.
- if (Tok.is(tok::kw_virtual)) {
- ConsumeToken();
+ if (TryConsumeToken(tok::kw_virtual))
IsVirtual = true;
- }
CheckMisplacedCXX11Attribute(Attributes, StartLoc);
@@ -1753,9 +1777,8 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
// actually part of the base-specifier-list grammar productions, but we
// parse it here for convenience.
SourceLocation EllipsisLoc;
- if (Tok.is(tok::ellipsis))
- EllipsisLoc = ConsumeToken();
-
+ TryConsumeToken(tok::ellipsis, EllipsisLoc);
+
// Find the complete source range for the base-specifier.
SourceRange Range(StartLoc, EndLocation);
@@ -1789,12 +1812,12 @@ void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
Decl *ThisDecl) {
// We just declared a member function. If this member function
// has any default arguments, we'll need to parse them later.
- LateParsedMethodDeclaration *LateMethod = 0;
+ LateParsedMethodDeclaration *LateMethod = nullptr;
DeclaratorChunk::FunctionTypeInfo &FTI
= DeclaratorInfo.getFunctionTypeInfo();
- for (unsigned ParamIdx = 0; ParamIdx < FTI.NumArgs; ++ParamIdx) {
- if (LateMethod || FTI.ArgInfo[ParamIdx].DefaultArgTokens) {
+ for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx) {
+ if (LateMethod || FTI.Params[ParamIdx].DefaultArgTokens) {
if (!LateMethod) {
// Push this method onto the stack of late-parsed method
// declarations.
@@ -1804,17 +1827,16 @@ void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
// Add all of the parameters prior to this one (they don't
// have default arguments).
- LateMethod->DefaultArgs.reserve(FTI.NumArgs);
+ LateMethod->DefaultArgs.reserve(FTI.NumParams);
for (unsigned I = 0; I < ParamIdx; ++I)
LateMethod->DefaultArgs.push_back(
- LateParsedDefaultArgument(FTI.ArgInfo[I].Param));
+ LateParsedDefaultArgument(FTI.Params[I].Param));
}
// Add this parameter to the list of parameters (it may or may
// not have a default argument).
- LateMethod->DefaultArgs.push_back(
- LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param,
- FTI.ArgInfo[ParamIdx].DefaultArgTokens));
+ LateMethod->DefaultArgs.push_back(LateParsedDefaultArgument(
+ FTI.Params[ParamIdx].Param, FTI.Params[ParamIdx].DefaultArgTokens));
}
}
}
@@ -1826,29 +1848,27 @@ void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
/// override
/// final
VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const {
- if (!getLangOpts().CPlusPlus)
+ if (!getLangOpts().CPlusPlus || Tok.isNot(tok::identifier))
return VirtSpecifiers::VS_None;
- if (Tok.is(tok::identifier)) {
- IdentifierInfo *II = Tok.getIdentifierInfo();
+ IdentifierInfo *II = Tok.getIdentifierInfo();
- // Initialize the contextual keywords.
- if (!Ident_final) {
- Ident_final = &PP.getIdentifierTable().get("final");
- if (getLangOpts().MicrosoftExt)
- Ident_sealed = &PP.getIdentifierTable().get("sealed");
- Ident_override = &PP.getIdentifierTable().get("override");
- }
+ // Initialize the contextual keywords.
+ if (!Ident_final) {
+ Ident_final = &PP.getIdentifierTable().get("final");
+ if (getLangOpts().MicrosoftExt)
+ Ident_sealed = &PP.getIdentifierTable().get("sealed");
+ Ident_override = &PP.getIdentifierTable().get("override");
+ }
- if (II == Ident_override)
- return VirtSpecifiers::VS_Override;
+ if (II == Ident_override)
+ return VirtSpecifiers::VS_Override;
- if (II == Ident_sealed)
- return VirtSpecifiers::VS_Sealed;
+ if (II == Ident_sealed)
+ return VirtSpecifiers::VS_Sealed;
- if (II == Ident_final)
- return VirtSpecifiers::VS_Final;
- }
+ if (II == Ident_final)
+ return VirtSpecifiers::VS_Final;
return VirtSpecifiers::VS_None;
}
@@ -1867,7 +1887,7 @@ void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS,
// C++ [class.mem]p8:
// A virt-specifier-seq shall contain at most one of each virt-specifier.
- const char *PrevSpec = 0;
+ const char *PrevSpec = nullptr;
if (VS.SetSpecifier(Specifier, Tok.getLocation(), PrevSpec))
Diag(Tok.getLocation(), diag::err_duplicate_virt_specifier)
<< PrevSpec
@@ -1891,24 +1911,52 @@ void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS,
}
/// isCXX11FinalKeyword - Determine whether the next token is a C++11
-/// contextual 'final' keyword.
+/// 'final' or Microsoft 'sealed' contextual keyword.
bool Parser::isCXX11FinalKeyword() const {
- if (!getLangOpts().CPlusPlus)
- return false;
+ VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier();
+ return Specifier == VirtSpecifiers::VS_Final ||
+ Specifier == VirtSpecifiers::VS_Sealed;
+}
- if (!Tok.is(tok::identifier))
- return false;
+/// \brief Parse a C++ member-declarator up to, but not including, the optional
+/// brace-or-equal-initializer or pure-specifier.
+void Parser::ParseCXXMemberDeclaratorBeforeInitializer(
+ Declarator &DeclaratorInfo, VirtSpecifiers &VS, ExprResult &BitfieldSize,
+ LateParsedAttrList &LateParsedAttrs) {
+ // member-declarator:
+ // declarator pure-specifier[opt]
+ // declarator brace-or-equal-initializer[opt]
+ // identifier[opt] ':' constant-expression
+ if (Tok.isNot(tok::colon))
+ ParseDeclarator(DeclaratorInfo);
- // Initialize the contextual keywords.
- if (!Ident_final) {
- Ident_final = &PP.getIdentifierTable().get("final");
- if (getLangOpts().MicrosoftExt)
- Ident_sealed = &PP.getIdentifierTable().get("sealed");
- Ident_override = &PP.getIdentifierTable().get("override");
+ if (!DeclaratorInfo.isFunctionDeclarator() && TryConsumeToken(tok::colon)) {
+ BitfieldSize = ParseConstantExpression();
+ if (BitfieldSize.isInvalid())
+ SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
+ } else
+ ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface);
+
+ // If a simple-asm-expr is present, parse it.
+ if (Tok.is(tok::kw_asm)) {
+ SourceLocation Loc;
+ ExprResult AsmLabel(ParseSimpleAsm(&Loc));
+ if (AsmLabel.isInvalid())
+ SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
+
+ DeclaratorInfo.setAsmLabel(AsmLabel.get());
+ DeclaratorInfo.SetRangeEnd(Loc);
}
- return Tok.getIdentifierInfo() == Ident_final ||
- Tok.getIdentifierInfo() == Ident_sealed;
+ // If attributes exist after the declarator, but before an '{', parse them.
+ MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
+
+ // For compatibility with code written to older Clang, also accept a
+ // virt-specifier *after* the GNU attributes.
+ // FIXME: If we saw any attributes that are known to GCC followed by a
+ // virt-specifier, issue a GCC-compat warning.
+ if (BitfieldSize.isUnset() && VS.isUnset())
+ ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface);
}
/// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration.
@@ -1962,6 +2010,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return;
}
+ // Turn on colon protection early, while parsing declspec, although there is
+ // nothing to protect there. It prevents from false errors if error recovery
+ // incorrectly determines where the declspec ends, as in the example:
+ // struct A { enum class B { C }; };
+ // const int C = 4;
+ // struct D { A::B : C; };
+ ColonProtectionRAIIObject X(*this);
+
// Access declarations.
bool MalformedTypeSpec = false;
if (!TemplateInfo.Kind &&
@@ -1993,17 +2049,17 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}
// TODO: recover from mistakenly-qualified operator declarations.
- if (ExpectAndConsume(tok::semi,
- diag::err_expected_semi_after,
- "access declaration",
- tok::semi))
+ if (ExpectAndConsume(tok::semi, diag::err_expected_after,
+ "access declaration")) {
+ SkipUntil(tok::semi);
return;
+ }
Actions.ActOnUsingDeclaration(getCurScope(), AS,
/* HasUsingKeyword */ false,
SourceLocation(),
SS, Name,
- /* AttrList */ 0,
+ /* AttrList */ nullptr,
/* HasTypenameKeyword */ false,
SourceLocation());
return;
@@ -2036,10 +2092,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
TemplateInfo, TemplateDiags);
}
- // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it
- // is a bitfield.
- ColonProtectionRAIIObject X(*this);
-
ParsedAttributesWithRange attrs(AttrFactory);
ParsedAttributesWithRange FnAttrs(AttrFactory);
// Optional C++11 attribute-specifier
@@ -2078,9 +2130,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
DS.takeAttributesFrom(attrs);
if (MalformedTypeSpec)
DS.SetTypeSpecError();
+
ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class,
&CommonLateParsedAttrs);
+ // Turn off colon protection that was set for declspec.
+ X.restore();
+
// If we had a free-standing type definition with a missing semicolon, we
// may get this far before the problem becomes obvious.
if (DS.hasTagDefinition() &&
@@ -2090,12 +2146,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return;
MultiTemplateParamsArg TemplateParams(
- TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0,
+ TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data()
+ : nullptr,
TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0);
- if (Tok.is(tok::semi)) {
- ConsumeToken();
-
+ if (TryConsumeToken(tok::semi)) {
if (DS.isFriendSpecified())
ProhibitAttributes(FnAttrs);
@@ -2114,30 +2169,30 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SourceLocation EqualLoc;
bool HasInitializer = false;
ExprResult Init;
- if (Tok.isNot(tok::colon)) {
- // Don't parse FOO:BAR as if it were a typo for FOO::BAR.
- ColonProtectionRAIIObject X(*this);
- // Parse the first declarator.
- ParseDeclarator(DeclaratorInfo);
- // Error parsing the declarator?
- if (!DeclaratorInfo.hasName()) {
- // If so, skip until the semi-colon or a }.
- SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
- if (Tok.is(tok::semi))
- ConsumeToken();
- return;
- }
+ SmallVector<Decl *, 8> DeclsInGroup;
+ ExprResult BitfieldSize;
+ bool ExpectSemi = true;
- ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface);
+ // Parse the first declarator.
+ ParseCXXMemberDeclaratorBeforeInitializer(DeclaratorInfo, VS, BitfieldSize,
+ LateParsedAttrs);
- // If attributes exist after the declarator, but before an '{', parse them.
- MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
+ // If this has neither a name nor a bit width, something has gone seriously
+ // wrong. Skip until the semi-colon or }.
+ if (!DeclaratorInfo.hasName() && BitfieldSize.isUnset()) {
+ // If so, skip until the semi-colon or a }.
+ SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
+ TryConsumeToken(tok::semi);
+ return;
+ }
- // MSVC permits pure specifier on inline functions declared at class scope.
+ // Check for a member function definition.
+ if (BitfieldSize.isUnset()) {
+ // MSVC permits pure specifier on inline functions defined at class scope.
// Hence check for =0 before checking for function definition.
if (getLangOpts().MicrosoftExt && Tok.is(tok::equal) &&
- DeclaratorInfo.isFunctionDeclarator() &&
+ DeclaratorInfo.isFunctionDeclarator() &&
NextToken().is(tok::numeric_constant)) {
EqualLoc = ConsumeToken();
Init = ParseInitializer();
@@ -2183,8 +2238,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SkipUntil(tok::r_brace);
// Consume the optional ';'
- if (Tok.is(tok::semi))
- ConsumeToken();
+ TryConsumeToken(tok::semi);
+
return;
}
@@ -2222,40 +2277,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// member-declarator
// member-declarator-list ',' member-declarator
- SmallVector<Decl *, 8> DeclsInGroup;
- ExprResult BitfieldSize;
- bool ExpectSemi = true;
-
while (1) {
- // member-declarator:
- // declarator pure-specifier[opt]
- // declarator brace-or-equal-initializer[opt]
- // identifier[opt] ':' constant-expression
- if (Tok.is(tok::colon)) {
- ConsumeToken();
- BitfieldSize = ParseConstantExpression();
- if (BitfieldSize.isInvalid())
- SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
- }
-
- // If a simple-asm-expr is present, parse it.
- if (Tok.is(tok::kw_asm)) {
- SourceLocation Loc;
- ExprResult AsmLabel(ParseSimpleAsm(&Loc));
- if (AsmLabel.isInvalid())
- SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
-
- DeclaratorInfo.setAsmLabel(AsmLabel.release());
- DeclaratorInfo.SetRangeEnd(Loc);
- }
-
- // If attributes exist after the declarator, parse them.
- MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
-
- // FIXME: When g++ adds support for this, we'll need to check whether it
- // goes before or after the GNU attributes and __asm__.
- ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface);
-
InClassInitStyle HasInClassInit = ICIS_NoInit;
if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) {
if (BitfieldSize.get()) {
@@ -2274,35 +2296,31 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// this call will *not* return the created decl; It will return null.
// See Sema::ActOnCXXMemberDeclarator for details.
- NamedDecl *ThisDecl = 0;
+ NamedDecl *ThisDecl = nullptr;
if (DS.isFriendSpecified()) {
- // C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains
+ // C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains
// to a friend declaration, that declaration shall be a definition.
//
- // Diagnose attributes appear after friend member function declarator:
- // foo [[]] ();
+ // Diagnose attributes that appear in a friend member function declarator:
+ // friend int foo [[]] ();
SmallVector<SourceRange, 4> Ranges;
DeclaratorInfo.getCXX11AttributeRanges(Ranges);
- if (!Ranges.empty()) {
- for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(),
- E = Ranges.end(); I != E; ++I) {
- Diag((*I).getBegin(), diag::err_attributes_not_allowed)
- << *I;
- }
- }
+ for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(),
+ E = Ranges.end(); I != E; ++I)
+ Diag((*I).getBegin(), diag::err_attributes_not_allowed) << *I;
- // TODO: handle initializers, bitfields, 'delete'
+ // TODO: handle initializers, VS, bitfields, 'delete'
ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
TemplateParams);
} else {
ThisDecl = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS,
DeclaratorInfo,
TemplateParams,
- BitfieldSize.release(),
+ BitfieldSize.get(),
VS, HasInClassInit);
if (VarTemplateDecl *VT =
- ThisDecl ? dyn_cast<VarTemplateDecl>(ThisDecl) : 0)
+ ThisDecl ? dyn_cast<VarTemplateDecl>(ThisDecl) : nullptr)
// Re-direct this decl to refer to the templated decl so that we can
// initialize it.
ThisDecl = VT->getTemplatedDecl();
@@ -2372,12 +2390,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// If we don't have a comma, it is either the end of the list (a ';')
// or an error, bail out.
- if (Tok.isNot(tok::comma))
+ SourceLocation CommaLoc;
+ if (!TryConsumeToken(tok::comma, CommaLoc))
break;
- // Consume the comma.
- SourceLocation CommaLoc = ConsumeToken();
-
if (Tok.isAtStartOfLine() &&
!MightBeDeclarator(Declarator::MemberContext)) {
// This comma was followed by a line-break and something which can't be
@@ -2397,11 +2413,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
HasInitializer = false;
DeclaratorInfo.setCommaLoc(CommaLoc);
- // Attributes are only allowed on the second declarator.
+ // GNU attributes are allowed before the second and subsequent declarator.
MaybeParseGNUAttributes(DeclaratorInfo);
- if (Tok.isNot(tok::colon))
- ParseDeclarator(DeclaratorInfo);
+ ParseCXXMemberDeclaratorBeforeInitializer(DeclaratorInfo, VS, BitfieldSize,
+ LateParsedAttrs);
}
if (ExpectSemi &&
@@ -2409,7 +2425,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// Skip to end of block or statement.
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
// If we stopped at a ';', eat it.
- if (Tok.is(tok::semi)) ConsumeToken();
+ TryConsumeToken(tok::semi);
return;
}
@@ -2446,8 +2462,7 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
EnterExpressionEvaluationContext Context(Actions,
Sema::PotentiallyEvaluated,
D);
- if (Tok.is(tok::equal)) {
- EqualLoc = ConsumeToken();
+ if (TryConsumeToken(tok::equal, EqualLoc)) {
if (Tok.is(tok::kw_delete)) {
// In principle, an initializer of '= delete p;' is legal, but it will
// never type-check. It's better to diagnose it as an ill-formed expression
@@ -2456,13 +2471,13 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
// a top-level comma always ends the initializer expression.
const Token &Next = NextToken();
if (IsFunction || Next.is(tok::semi) || Next.is(tok::comma) ||
- Next.is(tok::eof)) {
+ Next.is(tok::eof)) {
if (IsFunction)
Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
<< 1 /* delete */;
else
Diag(ConsumeToken(), diag::err_deleted_non_function);
- return ExprResult();
+ return ExprError();
}
} else if (Tok.is(tok::kw_default)) {
if (IsFunction)
@@ -2470,7 +2485,7 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
<< 0 /* default */;
else
Diag(ConsumeToken(), diag::err_default_special_members);
- return ExprResult();
+ return ExprError();
}
}
@@ -2510,7 +2525,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
<< /*ErrorType=*/6
<< (isa<NamedDecl>(TagDecl)
? cast<NamedDecl>(TagDecl)->getQualifiedNameAsString()
- : "<anonymous>");
+ : "(anonymous)");
}
break;
}
@@ -2601,7 +2616,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
if (TagDecl) {
// While we still have something to read, read the member-declarations.
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
// Each iteration of this loop reads one member-declaration.
if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) ||
@@ -2636,6 +2651,16 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
continue;
}
+ if (Tok.is(tok::annot_pragma_ms_pointers_to_members)) {
+ HandlePragmaMSPointersToMembers();
+ continue;
+ }
+
+ if (Tok.is(tok::annot_pragma_ms_pragma)) {
+ HandlePragmaMSPragma();
+ continue;
+ }
+
// If we see a namespace here, a close brace was missing somewhere.
if (Tok.is(tok::kw_namespace)) {
DiagnoseUnexpectedNamespace(cast<NamedDecl>(TagDecl));
@@ -2653,18 +2678,14 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
MaybeParseGNUAttributes(AccessAttrs);
SourceLocation EndLoc;
- if (Tok.is(tok::colon)) {
- EndLoc = Tok.getLocation();
- ConsumeToken();
- } else if (Tok.is(tok::semi)) {
- EndLoc = Tok.getLocation();
- ConsumeToken();
- Diag(EndLoc, diag::err_expected_colon)
- << FixItHint::CreateReplacement(EndLoc, ":");
+ if (TryConsumeToken(tok::colon, EndLoc)) {
+ } else if (TryConsumeToken(tok::semi, EndLoc)) {
+ Diag(EndLoc, diag::err_expected)
+ << tok::colon << FixItHint::CreateReplacement(EndLoc, ":");
} else {
EndLoc = ASLoc.getLocWithOffset(TokLength);
- Diag(EndLoc, diag::err_expected_colon)
- << FixItHint::CreateInsertion(EndLoc, ":");
+ Diag(EndLoc, diag::err_expected)
+ << tok::colon << FixItHint::CreateInsertion(EndLoc, ":");
}
// The Microsoft extension __interface does not permit non-public
@@ -2810,7 +2831,8 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
<< FixItHint::CreateInsertion(Loc, ", ");
} else {
// Skip over garbage, until we get to '{'. Don't eat the '{'.
- Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma);
+ Diag(Tok.getLocation(), diag::err_expected_either) << tok::l_brace
+ << tok::comma;
SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
break;
}
@@ -2854,7 +2876,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
return true;
}
- IdentifierInfo *II = 0;
+ IdentifierInfo *II = nullptr;
DeclSpec DS(AttrFactory);
SourceLocation IdLoc = Tok.getLocation();
if (Tok.is(tok::annot_decltype)) {
@@ -2878,12 +2900,11 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
return true;
SourceLocation EllipsisLoc;
- if (Tok.is(tok::ellipsis))
- EllipsisLoc = ConsumeToken();
+ TryConsumeToken(tok::ellipsis, EllipsisLoc);
return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
TemplateTypeTy, DS, IdLoc,
- InitList.take(), EllipsisLoc);
+ InitList.get(), EllipsisLoc);
} else if(Tok.is(tok::l_paren)) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
@@ -2899,8 +2920,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
T.consumeClose();
SourceLocation EllipsisLoc;
- if (Tok.is(tok::ellipsis))
- EllipsisLoc = ConsumeToken();
+ TryConsumeToken(tok::ellipsis, EllipsisLoc);
return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
TemplateTypeTy, DS, IdLoc,
@@ -2908,9 +2928,10 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
T.getCloseLocation(), EllipsisLoc);
}
- Diag(Tok, getLangOpts().CPlusPlus11 ? diag::err_expected_lparen_or_lbrace
- : diag::err_expected_lparen);
- return true;
+ if (getLangOpts().CPlusPlus11)
+ return Diag(Tok, diag::err_expected_either) << tok::l_paren << tok::l_brace;
+ else
+ return Diag(Tok, diag::err_expected) << tok::l_paren;
}
/// \brief Parse a C++ exception-specification if present (C++0x [except.spec]).
@@ -3054,10 +3075,8 @@ ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification(
Exceptions.push_back(Res.get());
Ranges.push_back(Range);
}
-
- if (Tok.is(tok::comma))
- ConsumeToken();
- else
+
+ if (!TryConsumeToken(tok::comma))
break;
}
@@ -3153,7 +3172,7 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) {
Loc = ConsumeToken();
return II;
}
- return 0;
+ return nullptr;
case tok::ampamp: // 'and'
case tok::pipe: // 'bitor'
@@ -3174,7 +3193,7 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) {
Loc = ConsumeToken();
return &PP.getIdentifierTable().get(Spelling);
}
- return 0;
+ return nullptr;
}
}
@@ -3183,6 +3202,7 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
switch (AttributeList::getKind(AttrName, ScopeName,
AttributeList::AS_CXX11)) {
case AttributeList::AT_CarriesDependency:
+ case AttributeList::AT_Deprecated:
case AttributeList::AT_FallThrough:
case AttributeList::AT_CXX11NoReturn: {
return true;
@@ -3193,8 +3213,75 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
}
}
-/// ParseCXX11AttributeSpecifier - Parse a C++11 attribute-specifier. Currently
-/// only parses standard attributes.
+/// ParseCXX11AttributeArgs -- Parse a C++11 attribute-argument-clause.
+///
+/// [C++11] attribute-argument-clause:
+/// '(' balanced-token-seq ')'
+///
+/// [C++11] balanced-token-seq:
+/// balanced-token
+/// balanced-token-seq balanced-token
+///
+/// [C++11] balanced-token:
+/// '(' balanced-token-seq ')'
+/// '[' balanced-token-seq ']'
+/// '{' balanced-token-seq '}'
+/// any token but '(', ')', '[', ']', '{', or '}'
+bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
+ SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs,
+ SourceLocation *EndLoc,
+ IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc) {
+ assert(Tok.is(tok::l_paren) && "Not a C++11 attribute argument list");
+ SourceLocation LParenLoc = Tok.getLocation();
+
+ // If the attribute isn't known, we will not attempt to parse any
+ // arguments.
+ if (!hasAttribute(AttrSyntax::CXX, ScopeName, AttrName,
+ getTargetInfo().getTriple(), getLangOpts())) {
+ // Eat the left paren, then skip to the ending right paren.
+ ConsumeParen();
+ SkipUntil(tok::r_paren);
+ return false;
+ }
+
+ if (ScopeName && ScopeName->getName() == "gnu")
+ // GNU-scoped attributes have some special cases to handle GNU-specific
+ // behaviors.
+ ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
+ ScopeLoc, AttributeList::AS_CXX11, nullptr);
+ else {
+ unsigned NumArgs =
+ ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc,
+ ScopeName, ScopeLoc, AttributeList::AS_CXX11);
+
+ const AttributeList *Attr = Attrs.getList();
+ if (Attr && IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName)) {
+ // If the attribute is a standard or built-in attribute and we are
+ // parsing an argument list, we need to determine whether this attribute
+ // was allowed to have an argument list (such as [[deprecated]]), and how
+ // many arguments were parsed (so we can diagnose on [[deprecated()]]).
+ if (Attr->getMaxArgs() && !NumArgs) {
+ // The attribute was allowed to have arguments, but none were provided
+ // even though the attribute parsed successfully. This is an error.
+ // FIXME: This is a good place for a fixit which removes the parens.
+ Diag(LParenLoc, diag::err_attribute_requires_arguments) << AttrName;
+ return false;
+ } else if (!Attr->getMaxArgs()) {
+ // The attribute parsed successfully, but was not allowed to have any
+ // arguments. It doesn't matter whether any were provided -- the
+ // presence of the argument list (even if empty) is diagnosed.
+ Diag(LParenLoc, diag::err_cxx11_attribute_forbids_arguments)
+ << AttrName;
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/// ParseCXX11AttributeSpecifier - Parse a C++11 attribute-specifier.
///
/// [C++11] attribute-specifier:
/// '[' '[' attribute-list ']' ']'
@@ -3218,19 +3305,6 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
///
/// [C++11] attribute-namespace:
/// identifier
-///
-/// [C++11] attribute-argument-clause:
-/// '(' balanced-token-seq ')'
-///
-/// [C++11] balanced-token-seq:
-/// balanced-token
-/// balanced-token-seq balanced-token
-///
-/// [C++11] balanced-token:
-/// '(' balanced-token-seq ')'
-/// '[' balanced-token-seq ']'
-/// '{' balanced-token-seq '}'
-/// any token but '(', ')', '[', ']', '{', or '}'
void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
SourceLocation *endLoc) {
if (Tok.is(tok::kw_alignas)) {
@@ -3251,13 +3325,11 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
while (Tok.isNot(tok::r_square)) {
// attribute not present
- if (Tok.is(tok::comma)) {
- ConsumeToken();
+ if (TryConsumeToken(tok::comma))
continue;
- }
SourceLocation ScopeLoc, AttrLoc;
- IdentifierInfo *ScopeName = 0, *AttrName = 0;
+ IdentifierInfo *ScopeName = nullptr, *AttrName = nullptr;
AttrName = TryParseCXX11AttributeIdentifier(AttrLoc);
if (!AttrName)
@@ -3265,64 +3337,47 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
break;
// scoped attribute
- if (Tok.is(tok::coloncolon)) {
- ConsumeToken();
-
+ if (TryConsumeToken(tok::coloncolon)) {
ScopeName = AttrName;
ScopeLoc = AttrLoc;
AttrName = TryParseCXX11AttributeIdentifier(AttrLoc);
if (!AttrName) {
- Diag(Tok.getLocation(), diag::err_expected_ident);
+ Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
SkipUntil(tok::r_square, tok::comma, StopAtSemi | StopBeforeMatch);
continue;
}
}
- bool StandardAttr = IsBuiltInOrStandardCXX11Attribute(AttrName,ScopeName);
+ bool StandardAttr = IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName);
bool AttrParsed = false;
if (StandardAttr &&
!SeenAttrs.insert(std::make_pair(AttrName, AttrLoc)).second)
Diag(AttrLoc, diag::err_cxx11_attribute_repeated)
- << AttrName << SourceRange(SeenAttrs[AttrName]);
+ << AttrName << SourceRange(SeenAttrs[AttrName]);
// Parse attribute arguments
- if (Tok.is(tok::l_paren)) {
- if (ScopeName && ScopeName->getName() == "gnu") {
- ParseGNUAttributeArgs(AttrName, AttrLoc, attrs, endLoc,
- ScopeName, ScopeLoc, AttributeList::AS_CXX11);
- AttrParsed = true;
- } else {
- if (StandardAttr)
- Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments)
- << AttrName->getName();
-
- // FIXME: handle other formats of c++11 attribute arguments
- ConsumeParen();
- SkipUntil(tok::r_paren);
- }
- }
+ if (Tok.is(tok::l_paren))
+ AttrParsed = ParseCXX11AttributeArgs(AttrName, AttrLoc, attrs, endLoc,
+ ScopeName, ScopeLoc);
if (!AttrParsed)
attrs.addNew(AttrName,
SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc,
AttrLoc),
- ScopeName, ScopeLoc, 0, 0, AttributeList::AS_CXX11);
-
- if (Tok.is(tok::ellipsis)) {
- ConsumeToken();
+ ScopeName, ScopeLoc, nullptr, 0, AttributeList::AS_CXX11);
+ if (TryConsumeToken(tok::ellipsis))
Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis)
<< AttrName->getName();
- }
}
- if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
+ if (ExpectAndConsume(tok::r_square))
SkipUntil(tok::r_square);
if (endLoc)
*endLoc = Tok.getLocation();
- if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
+ if (ExpectAndConsume(tok::r_square))
SkipUntil(tok::r_square);
}
@@ -3346,13 +3401,23 @@ void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs,
}
void Parser::DiagnoseAndSkipCXX11Attributes() {
- if (!isCXX11AttributeSpecifier())
- return;
-
// Start and end location of an attribute or an attribute list.
SourceLocation StartLoc = Tok.getLocation();
+ SourceLocation EndLoc = SkipCXX11Attributes();
+
+ if (EndLoc.isValid()) {
+ SourceRange Range(StartLoc, EndLoc);
+ Diag(StartLoc, diag::err_attributes_not_allowed)
+ << Range;
+ }
+}
+
+SourceLocation Parser::SkipCXX11Attributes() {
SourceLocation EndLoc;
+ if (!isCXX11AttributeSpecifier())
+ return EndLoc;
+
do {
if (Tok.is(tok::l_square)) {
BalancedDelimiterTracker T(*this, tok::l_square);
@@ -3369,11 +3434,7 @@ void Parser::DiagnoseAndSkipCXX11Attributes() {
}
} while (isCXX11AttributeSpecifier());
- if (EndLoc.isValid()) {
- SourceRange Range(StartLoc, EndLoc);
- Diag(StartLoc, diag::err_attributes_not_allowed)
- << Range;
- }
+ return EndLoc;
}
/// ParseMicrosoftAttributes - Parse a Microsoft attribute [Attr]
@@ -3393,7 +3454,7 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs,
ConsumeBracket();
SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch);
if (endLoc) *endLoc = Tok.getLocation();
- ExpectAndConsume(tok::r_square, diag::err_expected_rsquare);
+ ExpectAndConsume(tok::r_square);
}
}
@@ -3405,7 +3466,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType,
BalancedDelimiterTracker Braces(*this, tok::l_brace);
if (Braces.consumeOpen()) {
- Diag(Tok, diag::err_expected_lbrace);
+ Diag(Tok, diag::err_expected) << tok::l_brace;
return;
}
@@ -3424,7 +3485,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType,
return;
}
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
// __if_exists, __if_not_exists can nest.
if ((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) {
ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS);
@@ -3446,13 +3507,13 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType,
if (Tok.is(tok::colon))
Actions.ActOnAccessSpecifier(AS, ASLoc, Tok.getLocation());
else
- Diag(Tok, diag::err_expected_colon);
+ Diag(Tok, diag::err_expected) << tok::colon;
ConsumeToken();
continue;
}
// Parse all the comma separated declarators.
- ParseCXXClassMemberDeclaration(CurAS, 0);
+ ParseCXXClassMemberDeclaration(CurAS, nullptr);
}
Braces.consumeClose();
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 45f1b1da2e7f..0e4dfb91ad5d 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -23,6 +23,7 @@
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
+#include "clang/AST/ASTContext.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
@@ -147,7 +148,7 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
if (!LHS.isInvalid())
LHS = Actions.ActOnUnaryOp(getCurScope(), ExtLoc, tok::kw___extension__,
- LHS.take());
+ LHS.get());
return ParseRHSOfBinaryExpression(LHS, prec::Comma);
}
@@ -260,19 +261,16 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
TernaryMiddle = ParseExpression();
if (TernaryMiddle.isInvalid()) {
LHS = ExprError();
- TernaryMiddle = 0;
+ TernaryMiddle = nullptr;
}
} else {
// Special case handling of "X ? Y : Z" where Y is empty:
// logical-OR-expression '?' ':' conditional-expression [GNU]
- TernaryMiddle = 0;
+ TernaryMiddle = nullptr;
Diag(Tok, diag::ext_gnu_conditional_expr);
}
- if (Tok.is(tok::colon)) {
- // Eat the colon.
- ColonLoc = ConsumeToken();
- } else {
+ if (!TryConsumeToken(tok::colon, ColonLoc)) {
// Otherwise, we're missing a ':'. Assume that this was a typo that
// the user forgot. If we're not in a macro expansion, we can suggest
// a fixit hint. If there were two spaces before the current token,
@@ -294,10 +292,10 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
}
}
}
-
- Diag(Tok, diag::err_expected_colon)
- << FixItHint::CreateInsertion(FILoc, FIText);
- Diag(OpToken, diag::note_matching) << "?";
+
+ Diag(Tok, diag::err_expected)
+ << tok::colon << FixItHint::CreateInsertion(FILoc, FIText);
+ Diag(OpToken, diag::note_matching) << tok::question;
ColonLoc = Tok.getLocation();
}
}
@@ -394,11 +392,11 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
Actions.getExprRange(RHS.get()).getEnd()));
LHS = Actions.ActOnBinOp(getCurScope(), OpToken.getLocation(),
- OpToken.getKind(), LHS.take(), RHS.take());
+ OpToken.getKind(), LHS.get(), RHS.get());
} else
LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc,
- LHS.take(), TernaryMiddle.take(),
- RHS.take());
+ LHS.get(), TernaryMiddle.get(),
+ RHS.get());
}
}
}
@@ -430,14 +428,15 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback {
WantTypeSpecifiers = AllowTypes;
}
- virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ bool ValidateCandidate(const TypoCorrection &candidate) override {
NamedDecl *ND = candidate.getCorrectionDecl();
if (!ND)
return candidate.isKeyword();
if (isa<TypeDecl>(ND))
return WantTypeSpecifiers;
- return AllowNonTypes;
+ return AllowNonTypes &&
+ CorrectionCandidateCallback::ValidateCandidate(candidate);
}
private:
@@ -639,18 +638,12 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// If this expression is limited to being a unary-expression, the parent can
// not start a cast expression.
ParenParseOption ParenExprType =
- (isUnaryExpression && !getLangOpts().CPlusPlus)? CompoundLiteral : CastExpr;
+ (isUnaryExpression && !getLangOpts().CPlusPlus) ? CompoundLiteral
+ : CastExpr;
ParsedType CastTy;
SourceLocation RParenLoc;
-
- {
- // The inside of the parens don't need to be a colon protected scope, and
- // isn't immediately a message send.
- ColonProtectionRAIIObject X(*this, false);
-
- Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
- isTypeCast == IsTypeCast, CastTy, RParenLoc);
- }
+ Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
+ isTypeCast == IsTypeCast, CastTy, RParenLoc);
switch (ParenExprType) {
case SimpleExpr: break; // Nothing else to do.
@@ -690,7 +683,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
return Actions.ActOnCXXNullPtrLiteral(ConsumeToken());
case tok::annot_primary_expr:
- assert(Res.get() == 0 && "Stray primary-expression annotation?");
+ assert(Res.get() == nullptr && "Stray primary-expression annotation?");
Res = getExprAnnotation(Tok);
ConsumeToken();
break;
@@ -715,48 +708,11 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// If this identifier was reverted from a token ID, and the next token
// is a parenthesis, this is likely to be a use of a type trait. Check
// those tokens.
- if (Next.is(tok::l_paren) &&
- Tok.is(tok::identifier) &&
- Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier()) {
- IdentifierInfo *II = Tok.getIdentifierInfo();
- // Build up the mapping of revertable type traits, for future use.
- if (RevertableTypeTraits.empty()) {
-#define RTT_JOIN(X,Y) X##Y
-#define REVERTABLE_TYPE_TRAIT(Name) \
- RevertableTypeTraits[PP.getIdentifierInfo(#Name)] \
- = RTT_JOIN(tok::kw_,Name)
-
- REVERTABLE_TYPE_TRAIT(__is_arithmetic);
- REVERTABLE_TYPE_TRAIT(__is_convertible);
- REVERTABLE_TYPE_TRAIT(__is_empty);
- REVERTABLE_TYPE_TRAIT(__is_floating_point);
- REVERTABLE_TYPE_TRAIT(__is_function);
- REVERTABLE_TYPE_TRAIT(__is_fundamental);
- REVERTABLE_TYPE_TRAIT(__is_integral);
- REVERTABLE_TYPE_TRAIT(__is_member_function_pointer);
- REVERTABLE_TYPE_TRAIT(__is_member_pointer);
- REVERTABLE_TYPE_TRAIT(__is_pod);
- REVERTABLE_TYPE_TRAIT(__is_pointer);
- REVERTABLE_TYPE_TRAIT(__is_same);
- REVERTABLE_TYPE_TRAIT(__is_scalar);
- REVERTABLE_TYPE_TRAIT(__is_signed);
- REVERTABLE_TYPE_TRAIT(__is_unsigned);
- REVERTABLE_TYPE_TRAIT(__is_void);
-#undef REVERTABLE_TYPE_TRAIT
-#undef RTT_JOIN
- }
-
- // If we find that this is in fact the name of a type trait,
- // update the token kind in place and parse again to treat it as
- // the appropriate kind of type trait.
- llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind>::iterator Known
- = RevertableTypeTraits.find(II);
- if (Known != RevertableTypeTraits.end()) {
- Tok.setKind(Known->second);
- return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
- NotCastExpr, isTypeCast);
- }
- }
+ if (Next.is(tok::l_paren) && Tok.is(tok::identifier) &&
+ Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier() &&
+ TryIdentKeywordUpgrade())
+ return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
+ NotCastExpr, isTypeCast);
if (Next.is(tok::coloncolon) ||
(!ColonIsSacred && Next.is(tok::colon)) ||
@@ -806,8 +762,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
((Tok.is(tok::identifier) &&
(NextToken().is(tok::colon) || NextToken().is(tok::r_square))) ||
Tok.is(tok::code_completion))) {
- Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, ParsedType(),
- 0);
+ Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, ParsedType(),
+ nullptr);
break;
}
@@ -828,19 +784,20 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
DeclSpec DS(AttrFactory);
DS.SetRangeStart(ILoc);
DS.SetRangeEnd(ILoc);
- const char *PrevSpec = 0;
+ const char *PrevSpec = nullptr;
unsigned DiagID;
- DS.SetTypeSpecType(TST_typename, ILoc, PrevSpec, DiagID, Typ);
+ DS.SetTypeSpecType(TST_typename, ILoc, PrevSpec, DiagID, Typ,
+ Actions.getASTContext().getPrintingPolicy());
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
TypeResult Ty = Actions.ActOnTypeName(getCurScope(),
DeclaratorInfo);
if (Ty.isInvalid())
break;
-
+
Res = ParseObjCMessageExpressionBody(SourceLocation(),
SourceLocation(),
- Ty.get(), 0);
+ Ty.get(), nullptr);
break;
}
}
@@ -857,6 +814,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
SourceLocation TemplateKWLoc;
CastExpressionIdValidator Validator(isTypeCast != NotTypeCast,
isTypeCast != IsTypeCast);
+ Validator.IsAddressOfOperand = isAddressOfOperand;
Name.setIdentifier(&II, ILoc);
Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,
Name, Tok.is(tok::l_paren),
@@ -873,6 +831,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2]
case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU]
case tok::kw___FUNCDNAME__: // primary-expression: __FUNCDNAME__ [MS]
+ case tok::kw___FUNCSIG__: // primary-expression: __FUNCSIG__ [MS]
case tok::kw_L__FUNCTION__: // primary-expression: L__FUNCTION__ [MS]
case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU]
Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind);
@@ -904,7 +863,12 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
// ++ cast-expression
// -- cast-expression
SourceLocation SavedLoc = ConsumeToken();
- Res = ParseCastExpression(!getLangOpts().CPlusPlus);
+ // One special case is implicitly handled here: if the preceding tokens are
+ // an ambiguous cast expression, such as "(T())++", then we recurse to
+ // determine whether the '++' is prefix or postfix.
+ Res = ParseCastExpression(!getLangOpts().CPlusPlus,
+ /*isAddressOfOperand*/false, NotCastExpr,
+ NotTypeCast);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
return Res;
@@ -955,9 +919,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::ampamp: { // unary-expression: '&&' identifier
SourceLocation AmpAmpLoc = ConsumeToken();
if (Tok.isNot(tok::identifier))
- return ExprError(Diag(Tok, diag::err_expected_ident));
+ return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);
- if (getCurScope()->getFnParent() == 0)
+ if (getCurScope()->getFnParent() == nullptr)
return ExprError(Diag(Tok, diag::err_address_of_label_outside_fn));
Diag(AmpAmpLoc, diag::ext_gnu_address_of_label);
@@ -992,10 +956,11 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
DS.SetRangeStart(Tok.getLocation());
DS.SetRangeEnd(Tok.getLastLoc());
- const char *PrevSpec = 0;
+ const char *PrevSpec = nullptr;
unsigned DiagID;
DS.SetTypeSpecType(TST_typename, Tok.getAnnotationEndLoc(),
- PrevSpec, DiagID, Type);
+ PrevSpec, DiagID, Type,
+ Actions.getASTContext().getPrintingPolicy());
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
@@ -1004,7 +969,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
ConsumeToken();
Res = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(),
- Ty.get(), 0);
+ Ty.get(), nullptr);
break;
}
// Fall through
@@ -1028,15 +993,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw_void:
case tok::kw_typename:
case tok::kw_typeof:
- case tok::kw___vector:
- case tok::kw_image1d_t:
- case tok::kw_image1d_array_t:
- case tok::kw_image1d_buffer_t:
- case tok::kw_image2d_t:
- case tok::kw_image2d_array_t:
- case tok::kw_image3d_t:
- case tok::kw_sampler_t:
- case tok::kw_event_t: {
+ case tok::kw___vector: {
if (!getLangOpts().CPlusPlus) {
Diag(Tok, diag::err_expected_expression);
return ExprError();
@@ -1164,69 +1121,13 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
if (!Result.isInvalid())
Result = Actions.ActOnNoexceptExpr(KeyLoc, T.getOpenLocation(),
- Result.take(), T.getCloseLocation());
+ Result.get(), T.getCloseLocation());
return Result;
}
- case tok::kw___is_abstract: // [GNU] unary-type-trait
- case tok::kw___is_class:
- case tok::kw___is_empty:
- case tok::kw___is_enum:
- case tok::kw___is_interface_class:
- case tok::kw___is_literal:
- case tok::kw___is_arithmetic:
- case tok::kw___is_integral:
- case tok::kw___is_floating_point:
- case tok::kw___is_complete_type:
- case tok::kw___is_void:
- case tok::kw___is_array:
- case tok::kw___is_function:
- case tok::kw___is_reference:
- case tok::kw___is_lvalue_reference:
- case tok::kw___is_rvalue_reference:
- case tok::kw___is_fundamental:
- case tok::kw___is_object:
- case tok::kw___is_scalar:
- case tok::kw___is_compound:
- case tok::kw___is_pointer:
- case tok::kw___is_member_object_pointer:
- case tok::kw___is_member_function_pointer:
- case tok::kw___is_member_pointer:
- case tok::kw___is_const:
- case tok::kw___is_volatile:
- case tok::kw___is_standard_layout:
- case tok::kw___is_signed:
- case tok::kw___is_unsigned:
- case tok::kw___is_literal_type:
- case tok::kw___is_pod:
- case tok::kw___is_polymorphic:
- case tok::kw___is_trivial:
- case tok::kw___is_trivially_copyable:
- case tok::kw___is_union:
- case tok::kw___is_final:
- case tok::kw___is_sealed:
- case tok::kw___has_trivial_constructor:
- case tok::kw___has_trivial_move_constructor:
- case tok::kw___has_trivial_copy:
- case tok::kw___has_trivial_assign:
- case tok::kw___has_trivial_move_assign:
- case tok::kw___has_trivial_destructor:
- case tok::kw___has_nothrow_assign:
- case tok::kw___has_nothrow_move_assign:
- case tok::kw___has_nothrow_copy:
- case tok::kw___has_nothrow_constructor:
- case tok::kw___has_virtual_destructor:
- return ParseUnaryTypeTrait();
-
- case tok::kw___builtin_types_compatible_p:
- case tok::kw___is_base_of:
- case tok::kw___is_same:
- case tok::kw___is_convertible:
- case tok::kw___is_convertible_to:
- case tok::kw___is_trivially_assignable:
- return ParseBinaryTypeTrait();
-
- case tok::kw___is_trivially_constructible:
+#define TYPE_TRAIT(N,Spelling,K) \
+ case tok::kw_##Spelling:
+#include "clang/Basic/TokenKinds.def"
return ParseTypeTrait();
case tok::kw___array_rank:
@@ -1358,8 +1259,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
SourceLocation RLoc = Tok.getLocation();
if (!LHS.isInvalid() && !Idx.isInvalid() && Tok.is(tok::r_square)) {
- LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.take(), Loc,
- Idx.take(), RLoc);
+ LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.get(), Loc,
+ Idx.get(), RLoc);
} else
LHS = ExprError();
@@ -1373,8 +1274,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
// '(' argument-expression-list[opt] ')'
tok::TokenKind OpKind = Tok.getKind();
InMessageExpressionRAIIObject InMessage(*this, false);
-
- Expr *ExecConfig = 0;
+
+ Expr *ExecConfig = nullptr;
BalancedDelimiterTracker PT(*this, tok::l_paren);
@@ -1387,21 +1288,20 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
LHS = ExprError();
}
- SourceLocation CloseLoc = Tok.getLocation();
- if (Tok.is(tok::greatergreatergreater)) {
- ConsumeToken();
+ SourceLocation CloseLoc;
+ if (TryConsumeToken(tok::greatergreatergreater, CloseLoc)) {
} else if (LHS.isInvalid()) {
SkipUntil(tok::greatergreatergreater, StopAtSemi);
} else {
// There was an error closing the brackets
- Diag(Tok, diag::err_expected_ggg);
- Diag(OpenLoc, diag::note_matching) << "<<<";
+ Diag(Tok, diag::err_expected) << tok::greatergreatergreater;
+ Diag(OpenLoc, diag::note_matching) << tok::lesslessless;
SkipUntil(tok::greatergreatergreater, StopAtSemi);
LHS = ExprError();
}
if (!LHS.isInvalid()) {
- if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen, ""))
+ if (ExpectAndConsume(tok::l_paren))
LHS = ExprError();
else
Loc = PrevTokLocation;
@@ -1450,7 +1350,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
assert((ArgExprs.size() == 0 ||
ArgExprs.size()-1 == CommaLocs.size())&&
"Unexpected number of commas!");
- LHS = Actions.ActOnCallExpr(getCurScope(), LHS.take(), Loc,
+ LHS = Actions.ActOnCallExpr(getCurScope(), LHS.get(), Loc,
ArgExprs, Tok.getLocation(),
ExecConfig);
PT.consumeClose();
@@ -1469,14 +1369,14 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
ParsedType ObjectType;
bool MayBePseudoDestructor = false;
if (getLangOpts().CPlusPlus && !LHS.isInvalid()) {
- Expr *Base = LHS.take();
+ Expr *Base = LHS.get();
const Type* BaseType = Base->getType().getTypePtrOrNull();
if (BaseType && Tok.is(tok::l_paren) &&
(BaseType->isFunctionType() ||
BaseType->isSpecificPlaceholderType(BuiltinType::BoundMember))) {
Diag(OpLoc, diag::err_function_is_not_record)
- << (OpKind == tok::arrow) << Base->getSourceRange()
- << FixItHint::CreateRemoval(OpLoc);
+ << OpKind << Base->getSourceRange()
+ << FixItHint::CreateRemoval(OpLoc);
return ParsePostfixExpressionSuffix(Base);
}
@@ -1503,7 +1403,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
}
if (MayBePseudoDestructor && !LHS.isInvalid()) {
- LHS = ParseCXXPseudoDestructor(LHS.take(), OpLoc, OpKind, SS,
+ LHS = ParseCXXPseudoDestructor(LHS.get(), OpLoc, OpKind, SS,
ObjectType);
break;
}
@@ -1537,9 +1437,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
LHS = ExprError();
if (!LHS.isInvalid())
- LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.take(), OpLoc,
+ LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.get(), OpLoc,
OpKind, SS, TemplateKWLoc, Name,
- CurParsedObjCImpl ? CurParsedObjCImpl->Dcl : 0,
+ CurParsedObjCImpl ? CurParsedObjCImpl->Dcl
+ : nullptr,
Tok.is(tok::l_paren));
break;
}
@@ -1547,7 +1448,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
case tok::minusminus: // postfix-expression: postfix-expression '--'
if (!LHS.isInvalid()) {
LHS = Actions.ActOnPostfixUnaryOp(getCurScope(), Tok.getLocation(),
- Tok.getKind(), LHS.take());
+ Tok.getKind(), LHS.get());
}
ConsumeToken();
break;
@@ -1597,8 +1498,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
// pathenthesis around type name.
if (OpTok.is(tok::kw_sizeof) || OpTok.is(tok::kw___alignof) ||
OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw__Alignof)) {
- bool isAmbiguousTypeId;
- if (isTypeIdInParens(isAmbiguousTypeId)) {
+ if (isTypeIdUnambiguously()) {
DeclSpec DS(AttrFactory);
ParseSpecifierQualifierList(DS);
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
@@ -1617,7 +1517,8 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
isCastExpr = false;
if (OpTok.is(tok::kw_typeof) && !getLangOpts().CPlusPlus) {
- Diag(Tok,diag::err_expected_lparen_after_id) << OpTok.getIdentifierInfo();
+ Diag(Tok, diag::err_expected_after) << OpTok.getIdentifierInfo()
+ << tok::l_paren;
return ExprError();
}
@@ -1681,7 +1582,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
if (Tok.is(tok::ellipsis) && OpTok.is(tok::kw_sizeof)) {
SourceLocation EllipsisLoc = ConsumeToken();
SourceLocation LParenLoc, RParenLoc;
- IdentifierInfo *Name = 0;
+ IdentifierInfo *Name = nullptr;
SourceLocation NameLoc;
if (Tok.is(tok::l_paren)) {
BalancedDelimiterTracker T(*this, tok::l_paren);
@@ -1759,7 +1660,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(),
ExprKind,
/*isType=*/false,
- Operand.release(),
+ Operand.get(),
CastRange);
return Operand;
}
@@ -1789,8 +1690,8 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
// All of these start with an open paren.
if (Tok.isNot(tok::l_paren))
- return ExprError(Diag(Tok, diag::err_expected_lparen_after_id)
- << BuiltinII);
+ return ExprError(Diag(Tok, diag::err_expected_after) << BuiltinII
+ << tok::l_paren);
BalancedDelimiterTracker PT(*this, tok::l_paren);
PT.consumeOpen();
@@ -1802,20 +1703,22 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
case tok::kw___builtin_va_arg: {
ExprResult Expr(ParseAssignmentExpression());
- if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ if (ExpectAndConsume(tok::comma)) {
+ SkipUntil(tok::r_paren, StopAtSemi);
Expr = ExprError();
+ }
TypeResult Ty = ParseTypeName();
if (Tok.isNot(tok::r_paren)) {
- Diag(Tok, diag::err_expected_rparen);
+ Diag(Tok, diag::err_expected) << tok::r_paren;
Expr = ExprError();
}
if (Expr.isInvalid() || Ty.isInvalid())
Res = ExprError();
else
- Res = Actions.ActOnVAArg(StartLoc, Expr.take(), Ty.get(), ConsumeParen());
+ Res = Actions.ActOnVAArg(StartLoc, Expr.get(), Ty.get(), ConsumeParen());
break;
}
case tok::kw___builtin_offsetof: {
@@ -1826,12 +1729,14 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
return ExprError();
}
- if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ if (ExpectAndConsume(tok::comma)) {
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
+ }
// We must have at least one identifier here.
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
+ Diag(Tok, diag::err_expected) << tok::identifier;
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
@@ -1853,7 +1758,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
Comps.back().LocStart = ConsumeToken();
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
+ Diag(Tok, diag::err_expected) << tok::identifier;
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
@@ -1875,7 +1780,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
SkipUntil(tok::r_paren, StopAtSemi);
return Res;
}
- Comps.back().U.E = Res.release();
+ Comps.back().U.E = Res.get();
ST.consumeClose();
Comps.back().LocEnd = ST.getCloseLocation();
@@ -1902,16 +1807,20 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
SkipUntil(tok::r_paren, StopAtSemi);
return Cond;
}
- if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ if (ExpectAndConsume(tok::comma)) {
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
+ }
ExprResult Expr1(ParseAssignmentExpression());
if (Expr1.isInvalid()) {
SkipUntil(tok::r_paren, StopAtSemi);
return Expr1;
}
- if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
+ if (ExpectAndConsume(tok::comma)) {
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
+ }
ExprResult Expr2(ParseAssignmentExpression());
if (Expr2.isInvalid()) {
@@ -1919,11 +1828,11 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
return Expr2;
}
if (Tok.isNot(tok::r_paren)) {
- Diag(Tok, diag::err_expected_rparen);
+ Diag(Tok, diag::err_expected) << tok::r_paren;
return ExprError();
}
- Res = Actions.ActOnChooseExpr(StartLoc, Cond.take(), Expr1.take(),
- Expr2.take(), ConsumeParen());
+ Res = Actions.ActOnChooseExpr(StartLoc, Cond.get(), Expr1.get(),
+ Expr2.get(), ConsumeParen());
break;
}
case tok::kw___builtin_astype: {
@@ -1933,11 +1842,12 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
-
- if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",
- tok::r_paren))
+
+ if (ExpectAndConsume(tok::comma)) {
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
-
+ }
+
// Second argument is the type to bitcast to.
TypeResult DestTy = ParseTypeName();
if (DestTy.isInvalid())
@@ -1945,12 +1855,12 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
// Attempt to consume the r-paren.
if (Tok.isNot(tok::r_paren)) {
- Diag(Tok, diag::err_expected_rparen);
+ Diag(Tok, diag::err_expected) << tok::r_paren;
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
- Res = Actions.ActOnAsTypeExpr(Expr.take(), DestTy.get(), StartLoc,
+ Res = Actions.ActOnAsTypeExpr(Expr.get(), DestTy.get(), StartLoc,
ConsumeParen());
break;
}
@@ -1961,11 +1871,12 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
-
- if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",
- tok::r_paren))
+
+ if (ExpectAndConsume(tok::comma)) {
+ SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
-
+ }
+
// Second argument is the type to bitcast to.
TypeResult DestTy = ParseTypeName();
if (DestTy.isInvalid())
@@ -1973,12 +1884,12 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
// Attempt to consume the r-paren.
if (Tok.isNot(tok::r_paren)) {
- Diag(Tok, diag::err_expected_rparen);
+ Diag(Tok, diag::err_expected) << tok::r_paren;
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
- Res = Actions.ActOnConvertVectorExpr(Expr.take(), DestTy.get(), StartLoc,
+ Res = Actions.ActOnConvertVectorExpr(Expr.get(), DestTy.get(), StartLoc,
ConsumeParen());
break;
}
@@ -1989,7 +1900,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
// These can be followed by postfix-expr pieces because they are
// primary-expressions.
- return ParsePostfixExpressionSuffix(Res.take());
+ return ParsePostfixExpressionSuffix(Res.get());
}
/// ParseParenExpression - This parses the unit that starts with a '(' token,
@@ -2018,6 +1929,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
bool isTypeCast, ParsedType &CastTy,
SourceLocation &RParenLoc) {
assert(Tok.is(tok::l_paren) && "Not a paren expr!");
+ ColonProtectionRAIIObject ColonProtection(*this, false);
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.consumeOpen())
return ExprError();
@@ -2042,7 +1954,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
Tok.is(tok::kw___bridge_retained) ||
Tok.is(tok::kw___bridge_retain)));
if (BridgeCast && !getLangOpts().ObjCAutoRefCount) {
- if (Tok.isNot(tok::kw___bridge)) {
+ if (!TryConsumeToken(tok::kw___bridge)) {
StringRef BridgeCastName = Tok.getName();
SourceLocation BridgeKeywordLoc = ConsumeToken();
if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc))
@@ -2050,8 +1962,6 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
<< BridgeCastName
<< FixItHint::CreateReplacement(BridgeKeywordLoc, "");
}
- else
- ConsumeToken(); // consume __bridge
BridgeCast = false;
}
@@ -2066,7 +1976,7 @@ 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());
+ Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.get(), Tok.getLocation());
} else {
Actions.ActOnStmtExprError();
}
@@ -2095,6 +2005,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
TypeResult Ty = ParseTypeName();
T.consumeClose();
+ ColonProtection.restore();
RParenLoc = T.getCloseLocation();
ExprResult SubExpr = ParseCastExpression(/*isUnaryExpression=*/false);
@@ -2115,7 +2026,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// if stopIfCastExpr is false, we need to determine the context past the
// parens, so we defer to ParseCXXAmbiguousParenExpression for that.
if (isAmbiguousTypeId && !stopIfCastExpr) {
- ExprResult res = ParseCXXAmbiguousParenExpression(ExprType, CastTy, T);
+ ExprResult res = ParseCXXAmbiguousParenExpression(ExprType, CastTy, T,
+ ColonProtection);
RParenLoc = T.getCloseLocation();
return res;
}
@@ -2139,10 +2051,11 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
}
Result = ParseObjCMessageExpressionBody(SourceLocation(),
SourceLocation(),
- Ty.get(), 0);
+ Ty.get(), nullptr);
} else {
// Match the ')'.
T.consumeClose();
+ ColonProtection.restore();
RParenLoc = T.getCloseLocation();
if (Tok.is(tok::l_brace)) {
ExprType = CompoundLiteral;
@@ -2171,7 +2084,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
CastTy = Ty.get();
return ExprResult();
}
-
+
// Reject the cast of super idiom in ObjC.
if (Tok.is(tok::identifier) && getLangOpts().ObjC1 &&
Tok.getIdentifierInfo() == Ident_super &&
@@ -2190,7 +2103,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
if (!Result.isInvalid()) {
Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc,
DeclaratorInfo, CastTy,
- RParenLoc, Result.take());
+ RParenLoc, Result.get());
}
return Result;
}
@@ -2218,7 +2131,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// Don't build a paren expression unless we actually match a ')'.
if (!Result.isInvalid() && Tok.is(tok::r_paren))
- Result = Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), Result.take());
+ Result =
+ Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), Result.get());
}
// Match the ')'.
@@ -2249,7 +2163,7 @@ Parser::ParseCompoundLiteralExpression(ParsedType Ty,
Diag(LParenLoc, diag::ext_c99_compound_literal);
ExprResult Result = ParseInitializer();
if (!Result.isInvalid() && Ty)
- return Actions.ActOnCompoundLiteral(LParenLoc, Ty, RParenLoc, Result.take());
+ return Actions.ActOnCompoundLiteral(LParenLoc, Ty, RParenLoc, Result.get());
return Result;
}
@@ -2274,8 +2188,9 @@ ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) {
} while (isTokenStringLiteral());
// Pass the set of string tokens, ready for concatenation, to the actions.
- return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size(),
- AllowUserDefinedLiteral ? getCurScope() : 0);
+ return Actions.ActOnStringLiteral(StringToks,
+ AllowUserDefinedLiteral ? getCurScope()
+ : nullptr);
}
/// ParseGenericSelectionExpression - Parse a C11 generic-selection
@@ -2299,7 +2214,7 @@ ExprResult Parser::ParseGenericSelectionExpression() {
Diag(KeyLoc, diag::ext_c11_generic_selection);
BalancedDelimiterTracker T(*this, tok::l_paren);
- if (T.expectAndConsume(diag::err_expected_lparen))
+ if (T.expectAndConsume())
return ExprError();
ExprResult ControllingExpr;
@@ -2314,7 +2229,7 @@ ExprResult Parser::ParseGenericSelectionExpression() {
}
}
- if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "")) {
+ if (ExpectAndConsume(tok::comma)) {
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
@@ -2322,7 +2237,7 @@ ExprResult Parser::ParseGenericSelectionExpression() {
SourceLocation DefaultLoc;
TypeVector Types;
ExprVector Exprs;
- while (1) {
+ do {
ParsedType Ty;
if (Tok.is(tok::kw_default)) {
// C11 6.5.1.1p2 "A generic selection shall have no more than one default
@@ -2342,11 +2257,11 @@ ExprResult Parser::ParseGenericSelectionExpression() {
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
- Ty = TR.release();
+ Ty = TR.get();
}
Types.push_back(Ty);
- if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "")) {
+ if (ExpectAndConsume(tok::colon)) {
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
@@ -2358,12 +2273,8 @@ ExprResult Parser::ParseGenericSelectionExpression() {
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
- Exprs.push_back(ER.release());
-
- if (Tok.isNot(tok::comma))
- break;
- ConsumeToken();
- }
+ Exprs.push_back(ER.get());
+ } while (TryConsumeToken(tok::comma));
T.consumeClose();
if (T.getCloseLocation().isInvalid())
@@ -2371,7 +2282,7 @@ ExprResult Parser::ParseGenericSelectionExpression() {
return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc,
T.getCloseLocation(),
- ControllingExpr.release(),
+ ControllingExpr.get(),
Types, Exprs);
}
@@ -2403,6 +2314,7 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs,
Expr *Data,
ArrayRef<Expr *> Args),
Expr *Data) {
+ bool SawError = false;
while (1) {
if (Tok.is(tok::code_completion)) {
if (Completer)
@@ -2422,13 +2334,15 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs,
if (Tok.is(tok::ellipsis))
Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken());
- if (Expr.isInvalid())
- return true;
-
- Exprs.push_back(Expr.release());
+ if (Expr.isInvalid()) {
+ SkipUntil(tok::comma, tok::r_paren, StopBeforeMatch);
+ SawError = true;
+ } else {
+ Exprs.push_back(Expr.get());
+ }
if (Tok.isNot(tok::comma))
- return false;
+ return SawError;
// Move to the next argument, remember where the comma was.
CommaLocs.push_back(ConsumeToken());
}
@@ -2450,7 +2364,7 @@ Parser::ParseSimpleExpressionList(SmallVectorImpl<Expr*> &Exprs,
if (Expr.isInvalid())
return true;
- Exprs.push_back(Expr.release());
+ Exprs.push_back(Expr.get());
if (Tok.isNot(tok::comma))
return false;
@@ -2531,7 +2445,7 @@ ExprResult Parser::ParseBlockLiteralExpression() {
// SetIdentifier sets the source range end, but in this case we're past
// that location.
SourceLocation Tmp = ParamInfo.getSourceRange().getEnd();
- ParamInfo.SetIdentifier(0, CaretLoc);
+ ParamInfo.SetIdentifier(nullptr, CaretLoc);
ParamInfo.SetRangeEnd(Tmp);
if (ParamInfo.isInvalidType()) {
// If there was an error parsing the arguments, they may have
@@ -2554,7 +2468,7 @@ ExprResult Parser::ParseBlockLiteralExpression() {
ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(/*HasProto=*/true,
/*IsAmbiguous=*/false,
/*RParenLoc=*/NoLoc,
- /*ArgInfo=*/0,
+ /*ArgInfo=*/nullptr,
/*NumArgs=*/0,
/*EllipsisLoc=*/NoLoc,
/*RParenLoc=*/NoLoc,
@@ -2566,10 +2480,10 @@ ExprResult Parser::ParseBlockLiteralExpression() {
/*MutableLoc=*/NoLoc,
EST_None,
/*ESpecLoc=*/NoLoc,
- /*Exceptions=*/0,
- /*ExceptionRanges=*/0,
+ /*Exceptions=*/nullptr,
+ /*ExceptionRanges=*/nullptr,
/*NumExceptions=*/0,
- /*NoexceptExpr=*/0,
+ /*NoexceptExpr=*/nullptr,
CaretLoc, CaretLoc,
ParamInfo),
attrs, CaretLoc);
@@ -2592,7 +2506,7 @@ ExprResult Parser::ParseBlockLiteralExpression() {
StmtResult Stmt(ParseCompoundStatementBody());
BlockScope.Exit();
if (!Stmt.isInvalid())
- Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.take(), getCurScope());
+ Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.get(), getCurScope());
else
Actions.ActOnBlockError(CaretLoc, getCurScope());
return Result;
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 5fe47fc9711c..83121a8b1a2d 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -10,12 +10,13 @@
// This file implements the Expression parsing implementation for C++.
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/DeclTemplate.h"
-#include "clang/Parse/Parser.h"
+#include "clang/AST/ASTContext.h"
#include "RAIIObjectsForParser.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Parser.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
@@ -26,7 +27,9 @@ using namespace clang;
static int SelectDigraphErrorMessage(tok::TokenKind Kind) {
switch (Kind) {
- case tok::kw_template: return 0;
+ // template name
+ case tok::unknown: return 0;
+ // casts
case tok::kw_const_cast: return 1;
case tok::kw_dynamic_cast: return 2;
case tok::kw_reinterpret_cast: return 3;
@@ -93,7 +96,7 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType,
Template, MemberOfUnknownSpecialization))
return;
- FixDigraph(*this, PP, Next, SecondToken, tok::kw_template,
+ FixDigraph(*this, PP, Next, SecondToken, tok::unknown,
/*AtDigraph*/false);
}
@@ -204,7 +207,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
}
if (LastII)
- *LastII = 0;
+ *LastII = nullptr;
bool HasScopeSpecifier = false;
@@ -233,12 +236,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
DeclSpec DS(AttrFactory);
SourceLocation DeclLoc = Tok.getLocation();
SourceLocation EndLoc = ParseDecltypeSpecifier(DS);
- if (Tok.isNot(tok::coloncolon)) {
+
+ SourceLocation CCLoc;
+ if (!TryConsumeToken(tok::coloncolon, CCLoc)) {
AnnotateExistingDecltypeSpecifier(DS, DeclLoc, EndLoc);
return false;
}
-
- SourceLocation CCLoc = ConsumeToken();
+
if (Actions.ActOnCXXNestedNameSpecifierDecltype(SS, DS, CCLoc))
SS.SetInvalid(SourceRange(DeclLoc, CCLoc));
@@ -287,19 +291,23 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
TentativeParsingAction TPA(*this);
SourceLocation TemplateKWLoc = ConsumeToken();
-
+
UnqualifiedId TemplateName;
if (Tok.is(tok::identifier)) {
// Consume the identifier.
TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
ConsumeToken();
} else if (Tok.is(tok::kw_operator)) {
- if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType,
+ // We don't need to actually parse the unqualified-id in this case,
+ // because a simple-template-id cannot start with 'operator', but
+ // go ahead and parse it anyway for consistency with the case where
+ // we already annotated the template-id.
+ if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType,
TemplateName)) {
TPA.Commit();
break;
}
-
+
if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId &&
TemplateName.getKind() != UnqualifiedId::IK_LiteralOperatorId) {
Diag(TemplateName.getSourceRange().getBegin(),
@@ -341,10 +349,10 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) {
// We have
//
- // simple-template-id '::'
+ // template-id '::'
//
- // So we need to check whether the simple-template-id is of the
- // right kind (it should name a type or be dependent), and then
+ // So we need to check whether the template-id is a simple-template-id 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 = takeTemplateIdAnnotation(Tok);
if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
@@ -357,15 +365,15 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// Consume the template-id token.
ConsumeToken();
-
+
assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
SourceLocation CCLoc = ConsumeToken();
HasScopeSpecifier = true;
-
+
ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
-
+
if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(),
SS,
TemplateId->TemplateKWLoc,
@@ -385,7 +393,6 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
continue;
}
-
// The rest of the nested-name-specifier possibilities start with
// tok::identifier.
if (Tok.isNot(tok::identifier))
@@ -410,9 +417,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// error, but they probably meant something else strange so don't
// recover like this.
PP.LookAhead(1).is(tok::identifier)) {
- Diag(Next, diag::err_unexected_colon_in_nested_name_spec)
+ Diag(Next, diag::err_unexpected_colon_in_nested_name_spec)
<< FixItHint::CreateReplacement(Next.getLocation(), "::");
-
// Recover as if the user wrote '::'.
Next.setKind(tok::coloncolon);
}
@@ -426,23 +432,52 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
return false;
}
+ if (ColonIsSacred) {
+ const Token &Next2 = GetLookAheadToken(2);
+ if (Next2.is(tok::kw_private) || Next2.is(tok::kw_protected) ||
+ Next2.is(tok::kw_public) || Next2.is(tok::kw_virtual)) {
+ Diag(Next2, diag::err_unexpected_token_in_nested_name_spec)
+ << Next2.getName()
+ << FixItHint::CreateReplacement(Next.getLocation(), ":");
+ Token ColonColon;
+ PP.Lex(ColonColon);
+ ColonColon.setKind(tok::colon);
+ PP.EnterToken(ColonColon);
+ break;
+ }
+ }
+
if (LastII)
*LastII = &II;
// We have an identifier followed by a '::'. Lookup this name
// as the name in a nested-name-specifier.
+ Token Identifier = Tok;
SourceLocation IdLoc = ConsumeToken();
assert((Tok.is(tok::coloncolon) || Tok.is(tok::colon)) &&
"NextToken() not working properly!");
+ Token ColonColon = Tok;
SourceLocation CCLoc = ConsumeToken();
CheckForLParenAfterColonColon();
- HasScopeSpecifier = true;
+ bool IsCorrectedToColon = false;
+ bool *CorrectionFlagPtr = ColonIsSacred ? &IsCorrectedToColon : nullptr;
if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), II, IdLoc, CCLoc,
- ObjectType, EnteringContext, SS))
+ ObjectType, EnteringContext, SS,
+ false, CorrectionFlagPtr)) {
+ // Identifier is not recognized as a nested name, but we can have
+ // mistyped '::' instead of ':'.
+ if (CorrectionFlagPtr && IsCorrectedToColon) {
+ ColonColon.setKind(tok::colon);
+ PP.EnterToken(Tok);
+ PP.EnterToken(ColonColon);
+ Tok = Identifier;
+ break;
+ }
SS.SetInvalid(SourceRange(IdLoc, CCLoc));
-
+ }
+ HasScopeSpecifier = true;
continue;
}
@@ -732,7 +767,7 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
!Intro.Captures.empty())) {
Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
/*AfterAmpersand=*/false);
- ConsumeCodeCompletionToken();
+ cutOffParsing();
break;
}
@@ -749,7 +784,7 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
else
Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
/*AfterAmpersand=*/false);
- ConsumeCodeCompletionToken();
+ cutOffParsing();
break;
}
@@ -758,7 +793,7 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
// Parse capture.
LambdaCaptureKind Kind = LCK_ByCopy;
SourceLocation Loc;
- IdentifierInfo* Id = 0;
+ IdentifierInfo *Id = nullptr;
SourceLocation EllipsisLoc;
ExprResult Init;
@@ -773,7 +808,7 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro,
/*AfterAmpersand=*/true);
- ConsumeCodeCompletionToken();
+ cutOffParsing();
break;
}
}
@@ -814,8 +849,7 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
// to save the necessary state, and restore it later.
EnterExpressionEvaluationContext EC(Actions,
Sema::PotentiallyEvaluated);
- if (Tok.is(tok::equal))
- ConsumeToken();
+ TryConsumeToken(tok::equal);
if (!SkippedInits)
Init = ParseInitializer();
@@ -830,8 +864,8 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
// [..., x = expr
//
// We need to find the end of the following expression in order to
- // determine whether this is an Obj-C message send's receiver, or a
- // lambda init-capture.
+ // determine whether this is an Obj-C message send's receiver, a
+ // C99 designator, or a lambda init-capture.
//
// Parse the expression to find where it ends, and annotate it back
// onto the tokens. We would have parsed this expression the same way
@@ -864,8 +898,8 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
ConsumeToken();
}
}
- } else if (Tok.is(tok::ellipsis))
- EllipsisLoc = ConsumeToken();
+ } else
+ TryConsumeToken(tok::ellipsis, EllipsisLoc);
}
// If this is an init capture, process the initialization expression
// right away. For lambda init-captures such as the following:
@@ -988,7 +1022,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
ParsedAttributes Attr(AttrFactory);
SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
SourceLocation EllipsisLoc;
-
if (Tok.isNot(tok::r_paren)) {
Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth);
@@ -1002,12 +1035,14 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
SourceLocation RParenLoc = T.getCloseLocation();
DeclEndLoc = RParenLoc;
+ // GNU-style attributes must be parsed before the mutable specifier to be
+ // compatible with GCC.
+ MaybeParseGNUAttributes(Attr, &DeclEndLoc);
+
// Parse 'mutable'[opt].
SourceLocation MutableLoc;
- if (Tok.is(tok::kw_mutable)) {
- MutableLoc = ConsumeToken();
+ if (TryConsumeToken(tok::kw_mutable, MutableLoc))
DeclEndLoc = MutableLoc;
- }
// Parse exception-specification[opt].
ExceptionSpecificationType ESpecType = EST_None;
@@ -1057,26 +1092,45 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
DynamicExceptionRanges.data(),
DynamicExceptions.size(),
NoexceptExpr.isUsable() ?
- NoexceptExpr.get() : 0,
+ NoexceptExpr.get() : nullptr,
LParenLoc, FunLocalRangeEnd, D,
TrailingReturnType),
Attr, DeclEndLoc);
- } else if (Tok.is(tok::kw_mutable) || Tok.is(tok::arrow)) {
- // It's common to forget that one needs '()' before 'mutable' or the
- // result type. Deal with this.
+ } else if (Tok.is(tok::kw_mutable) || Tok.is(tok::arrow) ||
+ Tok.is(tok::kw___attribute) ||
+ (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) {
+ // It's common to forget that one needs '()' before 'mutable', an attribute
+ // specifier, or the result type. Deal with this.
+ unsigned TokKind = 0;
+ switch (Tok.getKind()) {
+ case tok::kw_mutable: TokKind = 0; break;
+ case tok::arrow: TokKind = 1; break;
+ case tok::kw___attribute:
+ case tok::l_square: TokKind = 2; break;
+ default: llvm_unreachable("Unknown token kind");
+ }
+
Diag(Tok, diag::err_lambda_missing_parens)
- << Tok.is(tok::arrow)
+ << TokKind
<< FixItHint::CreateInsertion(Tok.getLocation(), "() ");
SourceLocation DeclLoc = Tok.getLocation();
SourceLocation DeclEndLoc = DeclLoc;
-
+
+ // GNU-style attributes must be parsed before the mutable specifier to be
+ // compatible with GCC.
+ ParsedAttributes Attr(AttrFactory);
+ MaybeParseGNUAttributes(Attr, &DeclEndLoc);
+
// Parse 'mutable', if it's there.
SourceLocation MutableLoc;
if (Tok.is(tok::kw_mutable)) {
MutableLoc = ConsumeToken();
DeclEndLoc = MutableLoc;
}
-
+
+ // Parse attribute-specifier[opt].
+ MaybeParseCXX11Attributes(Attr, &DeclEndLoc);
+
// Parse the return type, if there is one.
TypeResult TrailingReturnType;
if (Tok.is(tok::arrow)) {
@@ -1086,12 +1140,11 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
DeclEndLoc = Range.getEnd();
}
- ParsedAttributes Attr(AttrFactory);
SourceLocation NoLoc;
D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true,
/*isAmbiguous=*/false,
/*LParenLoc=*/NoLoc,
- /*Params=*/0,
+ /*Params=*/nullptr,
/*NumParams=*/0,
/*EllipsisLoc=*/NoLoc,
/*RParenLoc=*/NoLoc,
@@ -1103,10 +1156,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
MutableLoc,
EST_None,
/*ESpecLoc=*/NoLoc,
- /*Exceptions=*/0,
- /*ExceptionRanges=*/0,
+ /*Exceptions=*/nullptr,
+ /*ExceptionRanges=*/nullptr,
/*NumExceptions=*/0,
- /*NoexceptExpr=*/0,
+ /*NoexceptExpr=*/nullptr,
DeclLoc, DeclEndLoc, D,
TrailingReturnType),
Attr, DeclEndLoc);
@@ -1131,7 +1184,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
BodyScope.Exit();
if (!Stmt.isInvalid())
- return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.take(), getCurScope());
+ return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get(), getCurScope());
Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
return ExprError();
@@ -1148,7 +1201,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
///
ExprResult Parser::ParseCXXCasts() {
tok::TokenKind Kind = Tok.getKind();
- const char *CastName = 0; // For error messages
+ const char *CastName = nullptr; // For error messages
switch (Kind) {
default: llvm_unreachable("Unknown C++ cast!");
@@ -1182,8 +1235,8 @@ ExprResult Parser::ParseCXXCasts() {
SourceLocation RAngleBracketLoc = Tok.getLocation();
- if (ExpectAndConsume(tok::greater, diag::err_expected_greater))
- return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << "<");
+ if (ExpectAndConsume(tok::greater))
+ return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << tok::less);
SourceLocation LParenLoc, RParenLoc;
BalancedDelimiterTracker T(*this, tok::l_paren);
@@ -1200,7 +1253,7 @@ ExprResult Parser::ParseCXXCasts() {
Result = Actions.ActOnCXXNamedCast(OpLoc, Kind,
LAngleBracketLoc, DeclaratorInfo,
RAngleBracketLoc,
- T.getOpenLocation(), Result.take(),
+ T.getOpenLocation(), Result.get(),
T.getCloseLocation());
return Result;
@@ -1266,7 +1319,7 @@ ExprResult Parser::ParseCXXTypeid() {
return ExprError();
Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false,
- Result.release(), RParenLoc);
+ Result.get(), RParenLoc);
}
}
@@ -1314,7 +1367,7 @@ ExprResult Parser::ParseCXXUuidof() {
Result = Actions.ActOnCXXUuidof(OpLoc, T.getOpenLocation(),
/*isType=*/false,
- Result.release(), T.getCloseLocation());
+ Result.get(), T.getCloseLocation());
}
}
@@ -1364,7 +1417,7 @@ Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc,
assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail");
CCLoc = ConsumeToken();
} else {
- FirstTypeName.setIdentifier(0, SourceLocation());
+ FirstTypeName.setIdentifier(nullptr, SourceLocation());
}
// Parse the tilde.
@@ -1436,12 +1489,12 @@ ExprResult Parser::ParseThrowExpression() {
case tok::r_brace:
case tok::colon:
case tok::comma:
- return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, 0);
+ return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, nullptr);
default:
ExprResult Expr(ParseAssignmentExpression());
if (Expr.isInvalid()) return Expr;
- return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, Expr.take());
+ return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, Expr.get());
}
}
@@ -1481,7 +1534,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
ExprResult Init = ParseBraceInitializer();
if (Init.isInvalid())
return Init;
- Expr *InitList = Init.take();
+ Expr *InitList = Init.get();
return Actions.ActOnCXXTypeConstructExpr(TypeRep, SourceLocation(),
MultiExprArg(&InitList, 1),
SourceLocation());
@@ -1555,7 +1608,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
// Parse the expression.
ExprOut = ParseExpression(); // expression
- DeclOut = 0;
+ DeclOut = nullptr;
if (ExprOut.isInvalid())
return true;
@@ -1583,7 +1636,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
SkipUntil(tok::semi, StopAtSemi);
return true;
}
- DeclaratorInfo.setAsmLabel(AsmLabel.release());
+ DeclaratorInfo.setAsmLabel(AsmLabel.get());
DeclaratorInfo.SetRangeEnd(Loc);
}
@@ -1623,7 +1676,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
}
if (!InitExpr.isInvalid())
- Actions.AddInitializerToDecl(DeclOut, InitExpr.take(), !CopyInitialization,
+ Actions.AddInitializerToDecl(DeclOut, InitExpr.get(), !CopyInitialization,
DS.containsPlaceholderType());
else
Actions.ActOnInitializerError(DeclOut);
@@ -1667,6 +1720,8 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
const char *PrevSpec;
unsigned DiagID;
SourceLocation Loc = Tok.getLocation();
+ const clang::PrintingPolicy &Policy =
+ Actions.getASTContext().getPrintingPolicy();
switch (Tok.getKind()) {
case tok::identifier: // foo::bar
@@ -1679,7 +1734,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
case tok::annot_typename: {
if (getTypeAnnotation(Tok))
DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID,
- getTypeAnnotation(Tok));
+ getTypeAnnotation(Tok), Policy);
else
DS.SetTypeSpecError();
@@ -1693,19 +1748,19 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
if (Tok.is(tok::less) && getLangOpts().ObjC1)
ParseObjCProtocolQualifiers(DS);
- DS.Finish(Diags, PP);
+ DS.Finish(Diags, PP, Policy);
return;
}
// builtin types
case tok::kw_short:
- DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, DiagID);
+ DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_long:
- DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, DiagID);
+ DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw___int64:
- DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, DiagID);
+ DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_signed:
DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID);
@@ -1714,47 +1769,47 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec, DiagID);
break;
case tok::kw_void:
- DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID);
+ DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_char:
- DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID);
+ DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_int:
- DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID);
+ DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw___int128:
- DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec, DiagID);
+ DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_half:
- DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID);
+ DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_float:
- DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID);
+ DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_double:
- DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID);
+ DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_wchar_t:
- DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID);
+ DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_char16_t:
- DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, DiagID);
+ DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_char32_t:
- DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, DiagID);
+ DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, DiagID, Policy);
break;
case tok::kw_bool:
- DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID);
+ DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID, Policy);
break;
case tok::annot_decltype:
case tok::kw_decltype:
DS.SetRangeEnd(ParseDecltypeSpecifier(DS));
- return DS.Finish(Diags, PP);
+ return DS.Finish(Diags, PP, Policy);
// GNU typeof support.
case tok::kw_typeof:
ParseTypeofSpecifier(DS);
- DS.Finish(Diags, PP);
+ DS.Finish(Diags, PP, Policy);
return;
}
if (Tok.is(tok::annot_typename))
@@ -1762,7 +1817,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
else
DS.SetRangeEnd(Tok.getLocation());
ConsumeToken();
- DS.Finish(Diags, PP);
+ DS.Finish(Diags, PP, Policy);
}
/// ParseCXXTypeSpecifierSeq - Parse a C++ type-specifier-seq (C++
@@ -1778,7 +1833,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
///
bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
ParseSpecifierQualifierList(DS, AS_none, DSC_type_specifier);
- DS.Finish(Diags, PP);
+ DS.Finish(Diags, PP, Actions.getASTContext().getPrintingPolicy());
return false;
}
@@ -1935,12 +1990,13 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
TemplateIdAnnotation *TemplateId
= TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds);
+ // FIXME: Store name for literal operator too.
if (Id.getKind() == UnqualifiedId::IK_Identifier) {
TemplateId->Name = Id.Identifier;
TemplateId->Operator = OO_None;
TemplateId->TemplateNameLoc = Id.StartLocation;
} else {
- TemplateId->Name = 0;
+ TemplateId->Name = nullptr;
TemplateId->Operator = Id.OperatorFunctionId.Operator;
TemplateId->TemplateNameLoc = Id.StartLocation;
}
@@ -2139,13 +2195,13 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
TokLocs.push_back(ConsumeStringToken());
}
- StringLiteralParser Literal(Toks.data(), Toks.size(), PP);
+ StringLiteralParser Literal(Toks, PP);
if (Literal.hadError)
return true;
// Grab the literal operator's suffix, which will be either the next token
// or a ud-suffix from the string literal.
- IdentifierInfo *II = 0;
+ IdentifierInfo *II = nullptr;
SourceLocation SuffixLoc;
if (!Literal.getUDSuffix().empty()) {
II = &PP.getIdentifierTable().get(Literal.getUDSuffix());
@@ -2158,7 +2214,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
SuffixLoc = ConsumeToken();
TokLocs.push_back(SuffixLoc);
} else {
- Diag(Tok.getLocation(), diag::err_expected_ident);
+ Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
return true;
}
@@ -2183,9 +2239,10 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
}
Result.setLiteralOperatorId(II, KeywordLoc, SuffixLoc);
- return false;
+
+ return Actions.checkLiteralOperatorId(SS, Result);
}
-
+
// Parse a conversion-function-id.
//
// conversion-function-id: [C++ 12.3.2]
@@ -2205,8 +2262,8 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
// Parse the conversion-declarator, which is merely a sequence of
// ptr-operators.
Declarator D(DS, Declarator::ConversionIdContext);
- ParseDeclaratorInternal(D, /*DirectDeclParser=*/0);
-
+ ParseDeclaratorInternal(D, /*DirectDeclParser=*/nullptr);
+
// Finish up the type.
TypeResult Ty = Actions.ActOnTypeName(getCurScope(), D);
if (Ty.isInvalid())
@@ -2362,10 +2419,10 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
Result.getKind() == UnqualifiedId::IK_LiteralOperatorId) &&
(TemplateSpecified || Tok.is(tok::less)))
return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc,
- 0, SourceLocation(),
+ nullptr, SourceLocation(),
EnteringContext, ObjectType,
Result, TemplateSpecified);
-
+
return false;
}
@@ -2560,7 +2617,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
PlacementArgs, PlacementRParen,
- TypeIdParens, DeclaratorInfo, Initializer.take());
+ TypeIdParens, DeclaratorInfo, Initializer.get());
}
/// ParseDirectNewDeclarator - Parses a direct-new-declarator. Intended to be
@@ -2598,7 +2655,7 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) {
D.AddTypeInfo(DeclaratorChunk::getArray(0,
/*static=*/false, /*star=*/false,
- Size.release(),
+ Size.get(),
T.getOpenLocation(),
T.getCloseLocation()),
Attrs, T.getCloseLocation());
@@ -2675,82 +2732,20 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
if (Operand.isInvalid())
return Operand;
- return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, Operand.take());
-}
-
-static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) {
- switch(kind) {
- default: llvm_unreachable("Not a known unary type trait.");
- case tok::kw___has_nothrow_assign: return UTT_HasNothrowAssign;
- case tok::kw___has_nothrow_move_assign: return UTT_HasNothrowMoveAssign;
- case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor;
- case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy;
- case tok::kw___has_trivial_assign: return UTT_HasTrivialAssign;
- case tok::kw___has_trivial_move_assign: return UTT_HasTrivialMoveAssign;
- case tok::kw___has_trivial_constructor:
- return UTT_HasTrivialDefaultConstructor;
- case tok::kw___has_trivial_move_constructor:
- return UTT_HasTrivialMoveConstructor;
- case tok::kw___has_trivial_copy: return UTT_HasTrivialCopy;
- case tok::kw___has_trivial_destructor: return UTT_HasTrivialDestructor;
- case tok::kw___has_virtual_destructor: return UTT_HasVirtualDestructor;
- case tok::kw___is_abstract: return UTT_IsAbstract;
- case tok::kw___is_arithmetic: return UTT_IsArithmetic;
- case tok::kw___is_array: return UTT_IsArray;
- case tok::kw___is_class: return UTT_IsClass;
- case tok::kw___is_complete_type: return UTT_IsCompleteType;
- case tok::kw___is_compound: return UTT_IsCompound;
- case tok::kw___is_const: return UTT_IsConst;
- case tok::kw___is_empty: return UTT_IsEmpty;
- case tok::kw___is_enum: return UTT_IsEnum;
- case tok::kw___is_final: return UTT_IsFinal;
- case tok::kw___is_floating_point: return UTT_IsFloatingPoint;
- case tok::kw___is_function: return UTT_IsFunction;
- case tok::kw___is_fundamental: return UTT_IsFundamental;
- case tok::kw___is_integral: return UTT_IsIntegral;
- case tok::kw___is_interface_class: return UTT_IsInterfaceClass;
- case tok::kw___is_lvalue_reference: return UTT_IsLvalueReference;
- case tok::kw___is_member_function_pointer: return UTT_IsMemberFunctionPointer;
- case tok::kw___is_member_object_pointer: return UTT_IsMemberObjectPointer;
- case tok::kw___is_member_pointer: return UTT_IsMemberPointer;
- case tok::kw___is_object: return UTT_IsObject;
- case tok::kw___is_literal: return UTT_IsLiteral;
- case tok::kw___is_literal_type: return UTT_IsLiteral;
- case tok::kw___is_pod: return UTT_IsPOD;
- case tok::kw___is_pointer: return UTT_IsPointer;
- case tok::kw___is_polymorphic: return UTT_IsPolymorphic;
- case tok::kw___is_reference: return UTT_IsReference;
- case tok::kw___is_rvalue_reference: return UTT_IsRvalueReference;
- case tok::kw___is_scalar: return UTT_IsScalar;
- case tok::kw___is_sealed: return UTT_IsSealed;
- case tok::kw___is_signed: return UTT_IsSigned;
- case tok::kw___is_standard_layout: return UTT_IsStandardLayout;
- case tok::kw___is_trivial: return UTT_IsTrivial;
- case tok::kw___is_trivially_copyable: return UTT_IsTriviallyCopyable;
- case tok::kw___is_union: return UTT_IsUnion;
- case tok::kw___is_unsigned: return UTT_IsUnsigned;
- case tok::kw___is_void: return UTT_IsVoid;
- case tok::kw___is_volatile: return UTT_IsVolatile;
- }
-}
-
-static BinaryTypeTrait BinaryTypeTraitFromTokKind(tok::TokenKind kind) {
- switch(kind) {
- default: llvm_unreachable("Not a known binary type trait");
- case tok::kw___is_base_of: return BTT_IsBaseOf;
- case tok::kw___is_convertible: return BTT_IsConvertible;
- case tok::kw___is_same: return BTT_IsSame;
- case tok::kw___builtin_types_compatible_p: return BTT_TypeCompatible;
- case tok::kw___is_convertible_to: return BTT_IsConvertibleTo;
- case tok::kw___is_trivially_assignable: return BTT_IsTriviallyAssignable;
- }
+ return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, Operand.get());
}
static TypeTrait TypeTraitFromTokKind(tok::TokenKind kind) {
switch (kind) {
default: llvm_unreachable("Not a known type trait");
- case tok::kw___is_trivially_constructible:
- return TT_IsTriviallyConstructible;
+#define TYPE_TRAIT_1(Spelling, Name, Key) \
+case tok::kw_ ## Spelling: return UTT_ ## Name;
+#define TYPE_TRAIT_2(Spelling, Name, Key) \
+case tok::kw_ ## Spelling: return BTT_ ## Name;
+#include "clang/Basic/TokenKinds.def"
+#define TYPE_TRAIT_N(Spelling, Name, Key) \
+ case tok::kw_ ## Spelling: return TT_ ## Name;
+#include "clang/Basic/TokenKinds.def"
}
}
@@ -2770,87 +2765,33 @@ static ExpressionTrait ExpressionTraitFromTokKind(tok::TokenKind kind) {
}
}
-/// ParseUnaryTypeTrait - Parse the built-in unary type-trait
-/// pseudo-functions that allow implementation of the TR1/C++0x type traits
-/// templates.
-///
-/// primary-expression:
-/// [GNU] unary-type-trait '(' type-id ')'
-///
-ExprResult Parser::ParseUnaryTypeTrait() {
- UnaryTypeTrait UTT = UnaryTypeTraitFromTokKind(Tok.getKind());
- SourceLocation Loc = ConsumeToken();
-
- BalancedDelimiterTracker T(*this, tok::l_paren);
- if (T.expectAndConsume(diag::err_expected_lparen))
- return ExprError();
-
- // FIXME: Error reporting absolutely sucks! If the this fails to parse a type
- // there will be cryptic errors about mismatched parentheses and missing
- // specifiers.
- TypeResult Ty = ParseTypeName();
-
- T.consumeClose();
-
- if (Ty.isInvalid())
- return ExprError();
-
- return Actions.ActOnUnaryTypeTrait(UTT, Loc, Ty.get(), T.getCloseLocation());
-}
-
-/// ParseBinaryTypeTrait - Parse the built-in binary type-trait
-/// pseudo-functions that allow implementation of the TR1/C++0x type traits
-/// templates.
-///
-/// primary-expression:
-/// [GNU] binary-type-trait '(' type-id ',' type-id ')'
-///
-ExprResult Parser::ParseBinaryTypeTrait() {
- BinaryTypeTrait BTT = BinaryTypeTraitFromTokKind(Tok.getKind());
- SourceLocation Loc = ConsumeToken();
-
- BalancedDelimiterTracker T(*this, tok::l_paren);
- if (T.expectAndConsume(diag::err_expected_lparen))
- return ExprError();
-
- TypeResult LhsTy = ParseTypeName();
- if (LhsTy.isInvalid()) {
- SkipUntil(tok::r_paren, StopAtSemi);
- return ExprError();
- }
-
- if (ExpectAndConsume(tok::comma, diag::err_expected_comma)) {
- SkipUntil(tok::r_paren, StopAtSemi);
- return ExprError();
- }
-
- TypeResult RhsTy = ParseTypeName();
- if (RhsTy.isInvalid()) {
- SkipUntil(tok::r_paren, StopAtSemi);
- return ExprError();
+static unsigned TypeTraitArity(tok::TokenKind kind) {
+ switch (kind) {
+ default: llvm_unreachable("Not a known type trait");
+#define TYPE_TRAIT(N,Spelling,K) case tok::kw_##Spelling: return N;
+#include "clang/Basic/TokenKinds.def"
}
-
- T.consumeClose();
-
- return Actions.ActOnBinaryTypeTrait(BTT, Loc, LhsTy.get(), RhsTy.get(),
- T.getCloseLocation());
}
/// \brief Parse the built-in type-trait pseudo-functions that allow
/// implementation of the TR1/C++11 type traits templates.
///
/// primary-expression:
+/// unary-type-trait '(' type-id ')'
+/// binary-type-trait '(' type-id ',' type-id ')'
/// type-trait '(' type-id-seq ')'
///
/// type-id-seq:
/// type-id ...[opt] type-id-seq[opt]
///
ExprResult Parser::ParseTypeTrait() {
- TypeTrait Kind = TypeTraitFromTokKind(Tok.getKind());
+ tok::TokenKind Kind = Tok.getKind();
+ unsigned Arity = TypeTraitArity(Kind);
+
SourceLocation Loc = ConsumeToken();
BalancedDelimiterTracker Parens(*this, tok::l_paren);
- if (Parens.expectAndConsume(diag::err_expected_lparen))
+ if (Parens.expectAndConsume())
return ExprError();
SmallVector<ParsedType, 2> Args;
@@ -2873,19 +2814,26 @@ ExprResult Parser::ParseTypeTrait() {
// Add this type to the list of arguments.
Args.push_back(Ty.get());
-
- if (Tok.is(tok::comma)) {
- ConsumeToken();
- continue;
- }
-
- break;
- } while (true);
-
+ } while (TryConsumeToken(tok::comma));
+
if (Parens.consumeClose())
return ExprError();
-
- return Actions.ActOnTypeTrait(Kind, Loc, Args, Parens.getCloseLocation());
+
+ SourceLocation EndLoc = Parens.getCloseLocation();
+
+ if (Arity && Args.size() != Arity) {
+ Diag(EndLoc, diag::err_type_trait_arity)
+ << Arity << 0 << (Arity > 1) << (int)Args.size() << SourceRange(Loc);
+ return ExprError();
+ }
+
+ if (!Arity && Args.empty()) {
+ Diag(EndLoc, diag::err_type_trait_arity)
+ << 1 << 1 << 1 << (int)Args.size() << SourceRange(Loc);
+ return ExprError();
+ }
+
+ return Actions.ActOnTypeTrait(TypeTraitFromTokKind(Kind), Loc, Args, EndLoc);
}
/// ParseArrayTypeTrait - Parse the built-in array type-trait
@@ -2900,7 +2848,7 @@ ExprResult Parser::ParseArrayTypeTrait() {
SourceLocation Loc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
- if (T.expectAndConsume(diag::err_expected_lparen))
+ if (T.expectAndConsume())
return ExprError();
TypeResult Ty = ParseTypeName();
@@ -2913,11 +2861,11 @@ ExprResult Parser::ParseArrayTypeTrait() {
switch (ATT) {
case ATT_ArrayRank: {
T.consumeClose();
- return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), NULL,
+ return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), nullptr,
T.getCloseLocation());
}
case ATT_ArrayExtent: {
- if (ExpectAndConsume(tok::comma, diag::err_expected_comma)) {
+ if (ExpectAndConsume(tok::comma)) {
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
@@ -2943,7 +2891,7 @@ ExprResult Parser::ParseExpressionTrait() {
SourceLocation Loc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
- if (T.expectAndConsume(diag::err_expected_lparen))
+ if (T.expectAndConsume())
return ExprError();
ExprResult Expr = ParseExpression();
@@ -2961,7 +2909,8 @@ ExprResult Parser::ParseExpressionTrait() {
ExprResult
Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
ParsedType &CastTy,
- BalancedDelimiterTracker &Tracker) {
+ BalancedDelimiterTracker &Tracker,
+ ColonProtectionRAIIObject &ColonProt) {
assert(getLangOpts().CPlusPlus && "Should only be called for C++!");
assert(ExprType == CastExpr && "Compound literals are not ambiguous!");
assert(isTypeIdInParens() && "Not a type-id!");
@@ -3003,13 +2952,13 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
ParseAs = CompoundLiteral;
} else {
bool NotCastExpr;
- // FIXME: Special-case ++ and --: "(S())++;" is not a cast-expression
if (Tok.is(tok::l_paren) && NextToken().is(tok::r_paren)) {
NotCastExpr = true;
} else {
// Try parsing the cast-expression that may follow.
// If it is not a cast-expression, NotCastExpr will be true and no token
// will be consumed.
+ ColonProt.restore();
Result = ParseCastExpression(false/*isUnaryExpression*/,
false/*isAddressofOperand*/,
NotCastExpr,
@@ -3035,17 +2984,24 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
if (ParseAs >= CompoundLiteral) {
// Parse the type declarator.
DeclSpec DS(AttrFactory);
- ParseSpecifierQualifierList(DS);
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
- ParseDeclarator(DeclaratorInfo);
+ {
+ ColonProtectionRAIIObject InnerColonProtection(*this);
+ ParseSpecifierQualifierList(DS);
+ ParseDeclarator(DeclaratorInfo);
+ }
// Match the ')'.
Tracker.consumeClose();
+ ColonProt.restore();
if (ParseAs == CompoundLiteral) {
ExprType = CompoundLiteral;
- TypeResult Ty = ParseTypeName();
- return ParseCompoundLiteralExpression(Ty.get(),
+ if (DeclaratorInfo.isInvalidType())
+ return ExprError();
+
+ TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
+ return ParseCompoundLiteralExpression(Ty.get(),
Tracker.getOpenLocation(),
Tracker.getCloseLocation());
}
@@ -3060,7 +3016,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
if (!Result.isInvalid())
Result = Actions.ActOnCastExpr(getCurScope(), Tracker.getOpenLocation(),
DeclaratorInfo, CastTy,
- Tracker.getCloseLocation(), Result.take());
+ Tracker.getCloseLocation(), Result.get());
return Result;
}
@@ -3071,7 +3027,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
Result = ParseExpression();
if (!Result.isInvalid() && Tok.is(tok::r_paren))
Result = Actions.ActOnParenExpr(Tracker.getOpenLocation(),
- Tok.getLocation(), Result.take());
+ Tok.getLocation(), Result.get());
// Match the ')'.
if (Result.isInvalid()) {
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index 37f74bbcd51b..8536420088f3 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -66,47 +66,29 @@ bool Parser::MayBeDesignationStart() {
}
// Parse up to (at most) the token after the closing ']' to determine
- // whether this is a C99 designator or a lambda.
+ // whether this is a C99 designator or a lambda.
TentativeParsingAction Tentative(*this);
- ConsumeBracket();
- while (true) {
- switch (Tok.getKind()) {
- case tok::equal:
- case tok::amp:
- case tok::identifier:
- case tok::kw_this:
- // These tokens can occur in a capture list or a constant-expression.
- // Keep looking.
- ConsumeToken();
- continue;
-
- case tok::comma:
- // Since a comma cannot occur in a constant-expression, this must
- // be a lambda.
- Tentative.Revert();
- return false;
-
- case tok::r_square: {
- // Once we hit the closing square bracket, we look at the next
- // token. If it's an '=', this is a designator. Otherwise, it's a
- // lambda expression. This decision favors lambdas over the older
- // GNU designator syntax, which allows one to omit the '=', but is
- // consistent with GCC.
- ConsumeBracket();
- tok::TokenKind Kind = Tok.getKind();
- Tentative.Revert();
- return Kind == tok::equal;
- }
-
- default:
- // Anything else cannot occur in a lambda capture list, so it
- // must be a designator.
- Tentative.Revert();
- return true;
- }
+
+ LambdaIntroducer Intro;
+ bool SkippedInits = false;
+ Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro, &SkippedInits));
+
+ if (DiagID) {
+ // If this can't be a lambda capture list, it's a designator.
+ Tentative.Revert();
+ return true;
}
-
- return true;
+
+ // Once we hit the closing square bracket, we look at the next
+ // token. If it's an '=', this is a designator. Otherwise, it's a
+ // lambda expression. This decision favors lambdas over the older
+ // GNU designator syntax, which allows one to omit the '=', but is
+ // consistent with GCC.
+ tok::TokenKind Kind = Tok.getKind();
+ // FIXME: If we didn't skip any inits, parse the lambda from here
+ // rather than throwing away then reparsing the LambdaIntroducer.
+ Tentative.Revert();
+ return Kind == tok::equal;
}
static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc,
@@ -237,7 +219,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
ConsumeToken(),
ParsedType(),
- 0);
+ nullptr);
}
// Parse the receiver, which is either a type or an expression.
@@ -255,7 +237,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
SourceLocation(),
ParsedType::getFromOpaquePtr(TypeOrExpr),
- 0);
+ nullptr);
}
// If the receiver was an expression, we still don't know
@@ -282,7 +264,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
ConsumeToken(),
ParsedType(),
- 0);
+ nullptr);
ConsumeToken(); // the identifier
if (!ReceiverType) {
SkipUntil(tok::r_square, StopAtSemi);
@@ -292,7 +274,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
SourceLocation(),
ReceiverType,
- 0);
+ nullptr);
case Sema::ObjCInstanceMessage:
// Fall through; we'll just parse the expression and
@@ -327,12 +309,12 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
SourceLocation(),
ParsedType(),
- Idx.take());
+ Idx.get());
}
// If this is a normal array designator, remember it.
if (Tok.isNot(tok::ellipsis)) {
- Desig.AddDesignator(Designator::getArray(Idx.release(), StartLoc));
+ Desig.AddDesignator(Designator::getArray(Idx.get(), StartLoc));
} else {
// Handle the gnu array range extension.
Diag(Tok, diag::ext_gnu_array_range);
@@ -343,8 +325,8 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
SkipUntil(tok::r_square, StopAtSemi);
return RHS;
}
- Desig.AddDesignator(Designator::getArrayRange(Idx.release(),
- RHS.release(),
+ Desig.AddDesignator(Designator::getArrayRange(Idx.get(),
+ RHS.get(),
StartLoc, EllipsisLoc));
}
@@ -444,7 +426,7 @@ ExprResult Parser::ParseBraceInitializer() {
// If we couldn't parse the subelement, bail out.
if (!SubElt.isInvalid()) {
- InitExprs.push_back(SubElt.release());
+ InitExprs.push_back(SubElt.get());
} else {
InitExprsOk = false;
@@ -493,7 +475,7 @@ bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs,
BalancedDelimiterTracker Braces(*this, tok::l_brace);
if (Braces.consumeOpen()) {
- Diag(Tok, diag::err_expected_lbrace);
+ Diag(Tok, diag::err_expected) << tok::l_brace;
return false;
}
@@ -512,7 +494,7 @@ bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs,
return false;
}
- while (Tok.isNot(tok::eof)) {
+ while (!isEofOrEom()) {
trailingComma = false;
// If we know that this cannot be a designation, just parse the nested
// initializer directly.
@@ -527,7 +509,7 @@ bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs,
// If we couldn't parse the subelement, bail out.
if (!SubElt.isInvalid())
- InitExprs.push_back(SubElt.release());
+ InitExprs.push_back(SubElt.get());
else
InitExprsOk = false;
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 86f38cfee37a..7fe72ec0c3b1 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -51,8 +51,8 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() {
cutOffParsing();
return DeclGroupPtrTy();
}
-
- Decl *SingleDecl = 0;
+
+ Decl *SingleDecl = nullptr;
switch (Tok.getObjCKeywordID()) {
case tok::objc_class:
return ParseObjCAtClassDeclaration(AtLoc);
@@ -81,13 +81,13 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() {
case tok::objc_import:
if (getLangOpts().Modules)
return ParseModuleImport(AtLoc);
-
- // Fall through
-
+ Diag(AtLoc, diag::err_atimport);
+ SkipUntil(tok::semi);
+ return Actions.ConvertDeclToDeclGroup(nullptr);
default:
Diag(AtLoc, diag::err_unexpected_at);
SkipUntil(tok::semi);
- SingleDecl = 0;
+ SingleDecl = nullptr;
break;
}
return Actions.ConvertDeclToDeclGroup(SingleDecl);
@@ -107,23 +107,21 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
while (1) {
MaybeSkipAttributes(tok::objc_class);
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
+ Diag(Tok, diag::err_expected) << tok::identifier;
SkipUntil(tok::semi);
- return Actions.ConvertDeclToDeclGroup(0);
+ return Actions.ConvertDeclToDeclGroup(nullptr);
}
ClassNames.push_back(Tok.getIdentifierInfo());
ClassLocs.push_back(Tok.getLocation());
ConsumeToken();
- if (Tok.isNot(tok::comma))
+ if (!TryConsumeToken(tok::comma))
break;
-
- ConsumeToken();
}
// Consume the ';'.
- if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class"))
- return Actions.ConvertDeclToDeclGroup(0);
+ if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@class"))
+ return Actions.ConvertDeclToDeclGroup(nullptr);
return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
ClassLocs.data(),
@@ -189,14 +187,15 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCInterfaceDecl(getCurScope());
cutOffParsing();
- return 0;
+ return nullptr;
}
MaybeSkipAttributes(tok::objc_interface);
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident); // missing class or category name.
- return 0;
+ Diag(Tok, diag::err_expected)
+ << tok::identifier; // missing class or category name.
+ return nullptr;
}
// We have a class or category name - consume it.
@@ -209,11 +208,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
T.consumeOpen();
SourceLocation categoryLoc;
- IdentifierInfo *categoryId = 0;
+ IdentifierInfo *categoryId = nullptr;
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCInterfaceCategory(getCurScope(), nameId, nameLoc);
cutOffParsing();
- return 0;
+ return nullptr;
}
// For ObjC2, the category name is optional (not an error).
@@ -222,14 +221,15 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
categoryLoc = ConsumeToken();
}
else if (!getLangOpts().ObjC2) {
- Diag(Tok, diag::err_expected_ident); // missing category name.
- return 0;
+ Diag(Tok, diag::err_expected)
+ << tok::identifier; // missing category name.
+ return nullptr;
}
T.consumeClose();
if (T.getCloseLocation().isInvalid())
- return 0;
-
+ return nullptr;
+
if (!attrs.empty()) { // categories don't support attributes.
Diag(nameLoc, diag::err_objc_no_attributes_on_category);
attrs.clear();
@@ -242,7 +242,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
LAngleLoc, EndProtoLoc))
- return 0;
+ return nullptr;
Decl *CategoryType =
Actions.ActOnStartCategoryInterface(AtLoc,
@@ -260,7 +260,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
return CategoryType;
}
// Parse a class interface.
- IdentifierInfo *superClassId = 0;
+ IdentifierInfo *superClassId = nullptr;
SourceLocation superClassLoc;
if (Tok.is(tok::colon)) { // a super class is specified.
@@ -270,12 +270,13 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCSuperclass(getCurScope(), nameId, nameLoc);
cutOffParsing();
- return 0;
+ return nullptr;
}
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident); // missing super class name.
- return 0;
+ Diag(Tok, diag::err_expected)
+ << tok::identifier; // missing super class name.
+ return nullptr;
}
superClassId = Tok.getIdentifierInfo();
superClassLoc = ConsumeToken();
@@ -287,7 +288,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true,
LAngleLoc, EndProtoLoc))
- return 0;
+ return nullptr;
if (Tok.isNot(tok::less))
Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc);
@@ -328,8 +329,8 @@ public:
MethodImplKind(MethodImplKind) {
}
- void invoke(ParsingFieldDeclarator &FD) {
- if (FD.D.getIdentifier() == 0) {
+ void invoke(ParsingFieldDeclarator &FD) override {
+ if (FD.D.getIdentifier() == nullptr) {
P.Diag(AtLoc, diag::err_objc_property_requires_field_name)
<< FD.D.getSourceRange();
return;
@@ -423,7 +424,7 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
}
// If we got to the end of the file, exit the loop.
- if (Tok.is(tok::eof))
+ if (isEofOrEom())
break;
// Code completion within an Objective-C interface.
@@ -576,7 +577,7 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
const IdentifierInfo *II = Tok.getIdentifierInfo();
// If this is not an identifier at all, bail out early.
- if (II == 0) {
+ if (!II) {
T.consumeClose();
return;
}
@@ -610,8 +611,10 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
unsigned DiagID = IsSetter ? diag::err_objc_expected_equal_for_setter :
diag::err_objc_expected_equal_for_getter;
- if (ExpectAndConsume(tok::equal, DiagID, "", tok::r_paren))
+ if (ExpectAndConsume(tok::equal, DiagID)) {
+ SkipUntil(tok::r_paren, StopAtSemi);
return;
+ }
if (Tok.is(tok::code_completion)) {
if (IsSetter)
@@ -636,10 +639,11 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_setter);
DS.setSetterName(SelIdent);
- if (ExpectAndConsume(tok::colon,
- diag::err_expected_colon_after_setter_name, "",
- tok::r_paren))
+ if (ExpectAndConsume(tok::colon,
+ diag::err_expected_colon_after_setter_name)) {
+ SkipUntil(tok::r_paren, StopAtSemi);
return;
+ }
} else {
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter);
DS.setGetterName(SelIdent);
@@ -694,7 +698,7 @@ IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {
switch (Tok.getKind()) {
default:
- return 0;
+ return nullptr;
case tok::ampamp:
case tok::ampequal:
case tok::amp:
@@ -713,7 +717,7 @@ IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {
SelectorLoc = ConsumeToken();
return II;
}
- return 0;
+ return nullptr;
}
case tok::identifier:
@@ -841,7 +845,7 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
}
DS.setObjCDeclQualifier(Qual);
ConsumeToken();
- II = 0;
+ II = nullptr;
break;
}
@@ -862,7 +866,7 @@ static void takeDeclAttributes(ParsedAttributes &attrs,
// Clear out the next pointer. We're really completely
// destroying the internal invariants of the declarator here,
// but it doesn't matter because we're done with it.
- cur->setNext(0);
+ cur->setNext(nullptr);
attrs.add(cur);
}
}
@@ -893,7 +897,8 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
ParsedAttributes *paramAttrs) {
assert(context == Declarator::ObjCParameterContext ||
context == Declarator::ObjCResultContext);
- assert((paramAttrs != 0) == (context == Declarator::ObjCParameterContext));
+ assert((paramAttrs != nullptr) ==
+ (context == Declarator::ObjCParameterContext));
assert(Tok.is(tok::l_paren) && "expected (");
@@ -990,14 +995,15 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
/*ReturnType=*/ ParsedType());
cutOffParsing();
- return 0;
+ return nullptr;
}
// Parse the return type if present.
ParsedType ReturnType;
ObjCDeclSpec DSRet;
if (Tok.is(tok::l_paren))
- ReturnType = ParseObjCTypeName(DSRet, Declarator::ObjCResultContext, 0);
+ ReturnType = ParseObjCTypeName(DSRet, Declarator::ObjCResultContext,
+ nullptr);
// If attributes exist before the method, parse them.
ParsedAttributes methodAttrs(AttrFactory);
@@ -1008,7 +1014,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
ReturnType);
cutOffParsing();
- return 0;
+ return nullptr;
}
// Now parse the selector.
@@ -1021,7 +1027,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
<< SourceRange(mLoc, Tok.getLocation());
// Skip until we get a ; or @.
SkipUntil(tok::at, StopAtSemi | StopBeforeMatch);
- return 0;
+ return nullptr;
}
SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo;
@@ -1034,7 +1040,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
Decl *Result
= Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(),
mType, DSRet, ReturnType,
- selLoc, Sel, 0,
+ selLoc, Sel, nullptr,
CParamInfo.data(), CParamInfo.size(),
methodAttrs.getList(), MethodImplKind,
false, MethodDefinition);
@@ -1054,11 +1060,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
Sema::ObjCArgInfo ArgInfo;
// Each iteration parses a single keyword argument.
- if (Tok.isNot(tok::colon)) {
- Diag(Tok, diag::err_expected_colon);
+ if (ExpectAndConsume(tok::colon))
break;
- }
- ConsumeToken(); // Eat the ':'.
ArgInfo.Type = ParsedType();
if (Tok.is(tok::l_paren)) // Parse the argument type if present.
@@ -1068,7 +1071,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
// If attributes exist before the argument name, parse them.
// Regardless, collect all the attributes we've parsed so far.
- ArgInfo.ArgAttrs = 0;
+ ArgInfo.ArgAttrs = nullptr;
if (getLangOpts().ObjC2) {
MaybeParseGNUAttributes(paramAttrs);
ArgInfo.ArgAttrs = paramAttrs.getList();
@@ -1082,11 +1085,12 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
/*AtParameterName=*/true,
ReturnType, KeyIdents);
cutOffParsing();
- return 0;
+ return nullptr;
}
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident); // missing argument name.
+ Diag(Tok, diag::err_expected)
+ << tok::identifier; // missing argument name.
break;
}
@@ -1108,7 +1112,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
/*AtParameterName=*/false,
ReturnType, KeyIdents);
cutOffParsing();
- return 0;
+ return nullptr;
}
// Check for another keyword selector.
@@ -1150,7 +1154,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
ParmDecl.getIdentifierLoc(),
Param,
- 0));
+ nullptr));
}
// FIXME: Add support for optional parameter list...
@@ -1159,8 +1163,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
MaybeParseGNUAttributes(methodAttrs);
if (KeyIdents.size() == 0)
- return 0;
-
+ return nullptr;
+
Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
&KeyIdents[0]);
Decl *Result
@@ -1198,7 +1202,7 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
}
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
+ Diag(Tok, diag::err_expected) << tok::identifier;
SkipUntil(tok::greater, StopAtSemi);
return true;
}
@@ -1207,9 +1211,8 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
ProtocolLocs.push_back(Tok.getLocation());
ConsumeToken();
- if (Tok.isNot(tok::comma))
+ if (!TryConsumeToken(tok::comma))
break;
- ConsumeToken();
}
// Consume the '>'.
@@ -1254,7 +1257,7 @@ void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocatio
// for code rewriting tools that need to be aware of the empty list.
Actions.ActOnFields(getCurScope(), atLoc, interfaceDecl,
AllIvarDecls,
- T.getOpenLocation(), T.getCloseLocation(), 0);
+ T.getOpenLocation(), T.getCloseLocation(), nullptr);
}
/// objc-class-instance-variables:
@@ -1289,7 +1292,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
BalancedDelimiterTracker T(*this, tok::l_brace);
T.consumeOpen();
// While we still have something to read, read the instance variables.
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
// Each iteration of this loop reads one objc-instance-variable-decl.
// Check for extraneous top-level semicolon.
@@ -1299,9 +1302,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
}
// Set the default visibility to private.
- if (Tok.is(tok::at)) { // parse objc-visibility-spec
- ConsumeToken(); // eat the @ sign
-
+ if (TryConsumeToken(tok::at)) { // parse objc-visibility-spec
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCAtVisibility(getCurScope());
return cutOffParsing();
@@ -1349,7 +1350,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
P(P), IDecl(IDecl), visibility(V), AllIvarDecls(AllIvarDecls) {
}
- void invoke(ParsingFieldDeclarator &FD) {
+ void invoke(ParsingFieldDeclarator &FD) override {
P.Actions.ActOnObjCContainerStartDefinition(IDecl);
// Install the declarator into the interface decl.
Decl *Field
@@ -1412,16 +1413,15 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
MaybeSkipAttributes(tok::objc_protocol);
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident); // missing protocol name.
+ Diag(Tok, diag::err_expected) << tok::identifier; // missing protocol name.
return DeclGroupPtrTy();
}
// Save the protocol name, then consume it.
IdentifierInfo *protocolName = Tok.getIdentifierInfo();
SourceLocation nameLoc = ConsumeToken();
- if (Tok.is(tok::semi)) { // forward declaration of one protocol.
+ if (TryConsumeToken(tok::semi)) { // forward declaration of one protocol.
IdentifierLocPair ProtoInfo(protocolName, nameLoc);
- ConsumeToken();
return Actions.ActOnForwardProtocolDeclaration(AtLoc, &ProtoInfo, 1,
attrs.getList());
}
@@ -1436,7 +1436,7 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
while (1) {
ConsumeToken(); // the ','
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
+ Diag(Tok, diag::err_expected) << tok::identifier;
SkipUntil(tok::semi);
return DeclGroupPtrTy();
}
@@ -1448,7 +1448,7 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
break;
}
// Consume the ';'.
- if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol"))
+ if (ExpectAndConsume(tok::semi, diag::err_expected_after, "@protocol"))
return DeclGroupPtrTy();
return Actions.ActOnForwardProtocolDeclaration(AtLoc,
@@ -1505,19 +1505,20 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
MaybeSkipAttributes(tok::objc_implementation);
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident); // missing class or category name.
+ Diag(Tok, diag::err_expected)
+ << tok::identifier; // missing class or category name.
return DeclGroupPtrTy();
}
// We have a class or category name - consume it.
IdentifierInfo *nameId = Tok.getIdentifierInfo();
SourceLocation nameLoc = ConsumeToken(); // consume class or category name
- Decl *ObjCImpDecl = 0;
+ Decl *ObjCImpDecl = nullptr;
if (Tok.is(tok::l_paren)) {
// we have a category implementation.
ConsumeParen();
SourceLocation categoryLoc, rparenLoc;
- IdentifierInfo *categoryId = 0;
+ IdentifierInfo *categoryId = nullptr;
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCImplementationCategory(getCurScope(), nameId, nameLoc);
@@ -1529,11 +1530,12 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
categoryId = Tok.getIdentifierInfo();
categoryLoc = ConsumeToken();
} else {
- Diag(Tok, diag::err_expected_ident); // missing category name.
+ Diag(Tok, diag::err_expected)
+ << tok::identifier; // missing category name.
return DeclGroupPtrTy();
}
if (Tok.isNot(tok::r_paren)) {
- Diag(Tok, diag::err_expected_rparen);
+ Diag(Tok, diag::err_expected) << tok::r_paren;
SkipUntil(tok::r_paren); // don't stop at ';'
return DeclGroupPtrTy();
}
@@ -1551,12 +1553,12 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
} else {
// We have a class implementation
SourceLocation superClassLoc;
- IdentifierInfo *superClassId = 0;
- if (Tok.is(tok::colon)) {
+ IdentifierInfo *superClassId = nullptr;
+ if (TryConsumeToken(tok::colon)) {
// We have a super class
- ConsumeToken();
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident); // missing super class name.
+ Diag(Tok, diag::err_expected)
+ << tok::identifier; // missing super class name.
return DeclGroupPtrTy();
}
superClassId = Tok.getIdentifierInfo();
@@ -1582,7 +1584,7 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
{
ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl);
- while (!ObjCImplParsing.isFinished() && Tok.isNot(tok::eof)) {
+ while (!ObjCImplParsing.isFinished() && !isEofOrEom()) {
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX11Attributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
@@ -1612,14 +1614,14 @@ Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() {
if (!Finished) {
finish(P.Tok.getLocation());
- if (P.Tok.is(tok::eof)) {
+ if (P.isEofOrEom()) {
P.Diag(P.Tok, diag::err_objc_missing_end)
<< FixItHint::CreateInsertion(P.Tok.getLocation(), "\n@end\n");
P.Diag(Dcl->getLocStart(), diag::note_objc_container_start)
<< Sema::OCK_Implementation;
}
}
- P.CurParsedObjCImpl = 0;
+ P.CurParsedObjCImpl = nullptr;
assert(LateParsedObjCMethods.empty());
}
@@ -1655,19 +1657,18 @@ Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) {
"ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");
ConsumeToken(); // consume compatibility_alias
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
- return 0;
+ Diag(Tok, diag::err_expected) << tok::identifier;
+ return nullptr;
}
IdentifierInfo *aliasId = Tok.getIdentifierInfo();
SourceLocation aliasLoc = ConsumeToken(); // consume alias-name
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
- return 0;
+ Diag(Tok, diag::err_expected) << tok::identifier;
+ return nullptr;
}
IdentifierInfo *classId = Tok.getIdentifierInfo();
SourceLocation classLoc = ConsumeToken(); // consume class-name;
- ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
- "@compatibility_alias");
+ ExpectAndConsume(tok::semi, diag::err_expected_after, "@compatibility_alias");
return Actions.ActOnCompatibilityAlias(atLoc, aliasId, aliasLoc,
classId, classLoc);
}
@@ -1692,31 +1693,29 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
cutOffParsing();
- return 0;
+ return nullptr;
}
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_synthesized_property_name);
SkipUntil(tok::semi);
- return 0;
+ return nullptr;
}
-
- IdentifierInfo *propertyIvar = 0;
+
+ IdentifierInfo *propertyIvar = nullptr;
IdentifierInfo *propertyId = Tok.getIdentifierInfo();
SourceLocation propertyLoc = ConsumeToken(); // consume property name
SourceLocation propertyIvarLoc;
- if (Tok.is(tok::equal)) {
+ if (TryConsumeToken(tok::equal)) {
// property '=' ivar-name
- ConsumeToken(); // consume '='
-
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCPropertySynthesizeIvar(getCurScope(), propertyId);
cutOffParsing();
- return 0;
+ return nullptr;
}
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
+ Diag(Tok, diag::err_expected) << tok::identifier;
break;
}
propertyIvar = Tok.getIdentifierInfo();
@@ -1728,8 +1727,8 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) {
break;
ConsumeToken(); // consume ','
}
- ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@synthesize");
- return 0;
+ ExpectAndConsume(tok::semi, diag::err_expected_after, "@synthesize");
+ return nullptr;
}
/// property-dynamic:
@@ -1747,26 +1746,26 @@ Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCPropertyDefinition(getCurScope());
cutOffParsing();
- return 0;
+ return nullptr;
}
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
+ Diag(Tok, diag::err_expected) << tok::identifier;
SkipUntil(tok::semi);
- return 0;
+ return nullptr;
}
IdentifierInfo *propertyId = Tok.getIdentifierInfo();
SourceLocation propertyLoc = ConsumeToken(); // consume property name
Actions.ActOnPropertyImplDecl(getCurScope(), atLoc, propertyLoc, false,
- propertyId, 0, SourceLocation());
+ propertyId, nullptr, SourceLocation());
if (Tok.isNot(tok::comma))
break;
ConsumeToken(); // consume ','
}
- ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@dynamic");
- return 0;
+ ExpectAndConsume(tok::semi, diag::err_expected_after, "@dynamic");
+ return nullptr;
}
/// objc-throw-statement:
@@ -1783,8 +1782,8 @@ StmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) {
}
}
// consume ';'
- ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@throw");
- return Actions.ActOnObjCAtThrowStmt(atLoc, Res.take(), getCurScope());
+ ExpectAndConsume(tok::semi, diag::err_expected_after, "@throw");
+ return Actions.ActOnObjCAtThrowStmt(atLoc, Res.get(), getCurScope());
}
/// objc-synchronized-statement:
@@ -1806,7 +1805,7 @@ Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
ConsumeParen(); // ')'
} else {
if (!operand.isInvalid())
- Diag(Tok, diag::err_expected_rparen);
+ Diag(Tok, diag::err_expected) << tok::r_paren;
// Skip forward until we see a left brace, but don't consume it.
SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch);
@@ -1815,13 +1814,13 @@ Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
// Require a compound statement.
if (Tok.isNot(tok::l_brace)) {
if (!operand.isInvalid())
- Diag(Tok, diag::err_expected_lbrace);
+ Diag(Tok, diag::err_expected) << tok::l_brace;
return StmtError();
}
// Check the @synchronized operand now.
if (!operand.isInvalid())
- operand = Actions.ActOnObjCAtSynchronizedOperand(atLoc, operand.take());
+ operand = Actions.ActOnObjCAtSynchronizedOperand(atLoc, operand.get());
// Parse the compound statement within a new scope.
ParseScope bodyScope(this, Scope::DeclScope);
@@ -1855,7 +1854,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
ConsumeToken(); // consume try
if (Tok.isNot(tok::l_brace)) {
- Diag(Tok, diag::err_expected_lbrace);
+ Diag(Tok, diag::err_expected) << tok::l_brace;
return StmtError();
}
StmtVector CatchStmts;
@@ -1877,7 +1876,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
SourceLocation AtCatchFinallyLoc = ConsumeToken();
if (Tok.isObjCAtKeyword(tok::objc_catch)) {
- Decl *FirstPart = 0;
+ Decl *FirstPart = nullptr;
ConsumeToken(); // consume catch
if (Tok.is(tok::l_paren)) {
ConsumeParen();
@@ -1905,16 +1904,16 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
if (Tok.is(tok::l_brace))
CatchBody = ParseCompoundStatementBody();
else
- Diag(Tok, diag::err_expected_lbrace);
+ Diag(Tok, diag::err_expected) << tok::l_brace;
if (CatchBody.isInvalid())
CatchBody = Actions.ActOnNullStmt(Tok.getLocation());
StmtResult Catch = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
RParenLoc,
FirstPart,
- CatchBody.take());
+ CatchBody.get());
if (!Catch.isInvalid())
- CatchStmts.push_back(Catch.release());
+ CatchStmts.push_back(Catch.get());
} else {
Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after)
@@ -1931,11 +1930,11 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
if (Tok.is(tok::l_brace))
FinallyBody = ParseCompoundStatementBody();
else
- Diag(Tok, diag::err_expected_lbrace);
+ Diag(Tok, diag::err_expected) << tok::l_brace;
if (FinallyBody.isInvalid())
FinallyBody = Actions.ActOnNullStmt(Tok.getLocation());
FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc,
- FinallyBody.take());
+ FinallyBody.get());
catch_or_finally_seen = true;
break;
}
@@ -1945,9 +1944,9 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
return StmtError();
}
- return Actions.ActOnObjCAtTryStmt(atLoc, TryBody.take(),
+ return Actions.ActOnObjCAtTryStmt(atLoc, TryBody.get(),
CatchStmts,
- FinallyStmt.take());
+ FinallyStmt.get());
}
/// objc-autoreleasepool-statement:
@@ -1957,7 +1956,7 @@ StmtResult
Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) {
ConsumeToken(); // consume autoreleasepool
if (Tok.isNot(tok::l_brace)) {
- Diag(Tok, diag::err_expected_lbrace);
+ Diag(Tok, diag::err_expected) << tok::l_brace;
return StmtError();
}
// Enter a scope to hold everything within the compound stmt. Compound
@@ -1970,7 +1969,7 @@ Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) {
if (AutoreleasePoolBody.isInvalid())
AutoreleasePoolBody = Actions.ActOnNullStmt(Tok.getLocation());
return Actions.ActOnObjCAutoreleasePoolStmt(atLoc,
- AutoreleasePoolBody.take());
+ AutoreleasePoolBody.get());
}
/// StashAwayMethodOrFunctionBodyTokens - Consume the tokens and store them
@@ -2036,13 +2035,13 @@ Decl *Parser::ParseObjCMethodDefinition() {
// If we didn't find the '{', bail out.
if (Tok.isNot(tok::l_brace))
- return 0;
+ return nullptr;
}
if (!MDecl) {
ConsumeBrace();
SkipUntil(tok::r_brace);
- return 0;
+ return nullptr;
}
// Allow the rest of sema to find private method decl implementations.
@@ -2100,7 +2099,7 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
SourceLocation OpLoc = ConsumeToken();
if (!Tok.is(tok::numeric_constant)) {
- const char *Symbol = 0;
+ const char *Symbol = nullptr;
switch (Kind) {
case tok::minus: Symbol = "-"; break;
case tok::plus: Symbol = "+"; break;
@@ -2117,12 +2116,12 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
}
ConsumeToken(); // Consume the literal token.
- Lit = Actions.ActOnUnaryOp(getCurScope(), OpLoc, Kind, Lit.take());
+ Lit = Actions.ActOnUnaryOp(getCurScope(), OpLoc, Kind, Lit.get());
if (Lit.isInvalid())
return Lit;
return ParsePostfixExpressionSuffix(
- Actions.BuildObjCNumericLiteral(AtLoc, Lit.take()));
+ Actions.BuildObjCNumericLiteral(AtLoc, Lit.get()));
}
case tok::string_literal: // primary-expression: string-literal
@@ -2155,7 +2154,7 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
return ParsePostfixExpressionSuffix(ParseObjCBoxedExpr(AtLoc));
default:
- if (Tok.getIdentifierInfo() == 0)
+ if (Tok.getIdentifierInfo() == nullptr)
return ExprError(Diag(AtLoc, diag::err_unexpected_at));
switch (Tok.getIdentifierInfo()->getObjCKeywordID()) {
@@ -2166,13 +2165,13 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
case tok::objc_selector:
return ParsePostfixExpressionSuffix(ParseObjCSelectorExpression(AtLoc));
default: {
- const char *str = 0;
+ const char *str = nullptr;
if (GetLookAheadToken(1).is(tok::l_brace)) {
char ch = Tok.getIdentifierInfo()->getNameStart()[0];
str =
ch == 't' ? "try"
: (ch == 'f' ? "finally"
- : (ch == 'a' ? "autoreleasepool" : 0));
+ : (ch == 'a' ? "autoreleasepool" : nullptr));
}
if (str) {
SourceLocation kwLoc = Tok.getLocation();
@@ -2223,7 +2222,7 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
return true;
IsExpr = true;
- TypeOrExpr = Receiver.take();
+ TypeOrExpr = Receiver.get();
return false;
}
@@ -2249,14 +2248,14 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
// instance method.
ExprResult Receiver = ParseCXXTypeConstructExpression(DS);
if (!Receiver.isInvalid())
- Receiver = ParsePostfixExpressionSuffix(Receiver.take());
+ Receiver = ParsePostfixExpressionSuffix(Receiver.get());
if (!Receiver.isInvalid())
- Receiver = ParseRHSOfBinaryExpression(Receiver.take(), prec::Comma);
+ Receiver = ParseRHSOfBinaryExpression(Receiver.get(), prec::Comma);
if (Receiver.isInvalid())
return true;
IsExpr = true;
- TypeOrExpr = Receiver.take();
+ TypeOrExpr = Receiver.get();
return false;
}
@@ -2345,11 +2344,11 @@ ExprResult Parser::ParseObjCMessageExpression() {
if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
NextToken().isNot(tok::period) && getCurScope()->isInObjcMethodScope())
return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(),
- ParsedType(), 0);
+ ParsedType(), nullptr);
// Parse the receiver, which is either a type or an expression.
bool IsExpr;
- void *TypeOrExpr = NULL;
+ void *TypeOrExpr = nullptr;
if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
SkipUntil(tok::r_square, StopAtSemi);
return ExprError();
@@ -2362,7 +2361,7 @@ ExprResult Parser::ParseObjCMessageExpression() {
return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
ParsedType::getFromOpaquePtr(TypeOrExpr),
- 0);
+ nullptr);
}
if (Tok.is(tok::identifier)) {
@@ -2375,7 +2374,7 @@ ExprResult Parser::ParseObjCMessageExpression() {
ReceiverType)) {
case Sema::ObjCSuperMessage:
return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(),
- ParsedType(), 0);
+ ParsedType(), nullptr);
case Sema::ObjCClassMessage:
if (!ReceiverType) {
@@ -2386,8 +2385,8 @@ ExprResult Parser::ParseObjCMessageExpression() {
ConsumeToken(); // the type name
return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
- ReceiverType, 0);
-
+ ReceiverType, nullptr);
+
case Sema::ObjCInstanceMessage:
// Fall through to parse an expression.
break;
@@ -2402,7 +2401,7 @@ ExprResult Parser::ParseObjCMessageExpression() {
}
return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
- ParsedType(), Res.take());
+ ParsedType(), Res.get());
}
/// \brief Parse the remainder of an Objective-C message following the
@@ -2478,8 +2477,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
KeyIdents.push_back(selIdent);
KeyLocs.push_back(Loc);
- if (Tok.isNot(tok::colon)) {
- Diag(Tok, diag::err_expected_colon);
+ if (ExpectAndConsume(tok::colon)) {
// We must manually skip to a ']', otherwise the expression skipper will
// stop at the ']' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
@@ -2487,7 +2485,6 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
return ExprError();
}
- ConsumeToken(); // Eat the ':'.
/// Parse the expression after ':'
if (Tok.is(tok::code_completion)) {
@@ -2525,7 +2522,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
}
// We have a valid expression.
- KeyExprs.push_back(Res.release());
+ KeyExprs.push_back(Res.get());
// Code completion after each argument.
if (Tok.is(tok::code_completion)) {
@@ -2569,10 +2566,10 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
}
// We have a valid expression.
- KeyExprs.push_back(Res.release());
+ KeyExprs.push_back(Res.get());
}
} else if (!selIdent) {
- Diag(Tok, diag::err_expected_ident); // missing selector name.
+ Diag(Tok, diag::err_expected) << tok::identifier; // missing selector name.
// We must manually skip to a ']', otherwise the expression skipper will
// stop at the ']' when it skips to the ';'. We want it to skip beyond
@@ -2582,10 +2579,8 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
}
if (Tok.isNot(tok::r_square)) {
- if (Tok.is(tok::identifier))
- Diag(Tok, diag::err_expected_colon);
- else
- Diag(Tok, diag::err_expected_rsquare);
+ Diag(Tok, diag::err_expected)
+ << (Tok.is(tok::identifier) ? tok::colon : tok::r_square);
// We must manually skip to a ']', otherwise the expression skipper will
// stop at the ']' when it skips to the ';'. We want it to skip beyond
// the enclosing expression.
@@ -2622,7 +2617,7 @@ ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
SmallVector<SourceLocation, 4> AtLocs;
ExprVector AtStrings;
AtLocs.push_back(AtLoc);
- AtStrings.push_back(Res.release());
+ AtStrings.push_back(Res.get());
while (Tok.is(tok::at)) {
AtLocs.push_back(ConsumeToken()); // eat the @.
@@ -2635,7 +2630,7 @@ ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
if (Lit.isInvalid())
return Lit;
- AtStrings.push_back(Lit.release());
+ AtStrings.push_back(Lit.get());
}
return Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.data(),
@@ -2662,7 +2657,7 @@ ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) {
return Lit;
}
ConsumeToken(); // Consume the literal token.
- return Actions.BuildObjCNumericLiteral(AtLoc, Lit.take());
+ return Actions.BuildObjCNumericLiteral(AtLoc, Lit.get());
}
/// ParseObjCNumericLiteral -
@@ -2676,7 +2671,7 @@ ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) {
return Lit;
}
ConsumeToken(); // Consume the literal token.
- return Actions.BuildObjCNumericLiteral(AtLoc, Lit.take());
+ return Actions.BuildObjCNumericLiteral(AtLoc, Lit.get());
}
/// ParseObjCBoxedExpr -
@@ -2699,9 +2694,9 @@ Parser::ParseObjCBoxedExpr(SourceLocation AtLoc) {
// Wrap the sub-expression in a parenthesized expression, to distinguish
// a boxed expression from a literal.
SourceLocation LPLoc = T.getOpenLocation(), RPLoc = T.getCloseLocation();
- ValueExpr = Actions.ActOnParenExpr(LPLoc, RPLoc, ValueExpr.take());
+ ValueExpr = Actions.ActOnParenExpr(LPLoc, RPLoc, ValueExpr.get());
return Actions.BuildObjCBoxedExpr(SourceRange(AtLoc, RPLoc),
- ValueExpr.take());
+ ValueExpr.get());
}
ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
@@ -2725,12 +2720,13 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
if (Res.isInvalid())
return true;
- ElementExprs.push_back(Res.release());
+ ElementExprs.push_back(Res.get());
if (Tok.is(tok::comma))
ConsumeToken(); // Eat the ','.
else if (Tok.isNot(tok::r_square))
- return ExprError(Diag(Tok, diag::err_expected_rsquare_or_comma));
+ return ExprError(Diag(Tok, diag::err_expected_either) << tok::r_square
+ << tok::comma);
}
SourceLocation EndLoc = ConsumeBracket(); // location of ']'
MultiExprArg Args(ElementExprs);
@@ -2755,10 +2751,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
}
}
- if (Tok.is(tok::colon)) {
- ConsumeToken();
- } else {
- Diag(Tok, diag::err_expected_colon);
+ if (ExpectAndConsume(tok::colon)) {
SkipUntil(tok::r_brace, StopAtSemi);
return ExprError();
}
@@ -2774,20 +2767,19 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
// Parse the ellipsis that designates this as a pack expansion.
SourceLocation EllipsisLoc;
- if (Tok.is(tok::ellipsis) && getLangOpts().CPlusPlus)
- EllipsisLoc = ConsumeToken();
-
+ if (getLangOpts().CPlusPlus)
+ TryConsumeToken(tok::ellipsis, EllipsisLoc);
+
// We have a valid expression. Collect it in a vector so we can
// build the argument list.
ObjCDictionaryElement Element = {
KeyExpr.get(), ValueExpr.get(), EllipsisLoc, None
};
Elements.push_back(Element);
-
- if (Tok.is(tok::comma))
- ConsumeToken(); // Eat the ','.
- else if (Tok.isNot(tok::r_brace))
- return ExprError(Diag(Tok, diag::err_expected_rbrace_or_comma));
+
+ if (!TryConsumeToken(tok::comma) && Tok.isNot(tok::r_brace))
+ return ExprError(Diag(Tok, diag::err_expected_either) << tok::r_brace
+ << tok::comma);
}
SourceLocation EndLoc = ConsumeBrace();
@@ -2834,7 +2826,7 @@ Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
T.consumeOpen();
if (Tok.isNot(tok::identifier))
- return ExprError(Diag(Tok, diag::err_expected_ident));
+ return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);
IdentifierInfo *protocolId = Tok.getIdentifierInfo();
SourceLocation ProtoIdLoc = ConsumeToken();
@@ -2847,7 +2839,7 @@ Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
}
/// objc-selector-expression
-/// @selector '(' objc-keyword-selector ')'
+/// @selector '(' '('[opt] objc-keyword-selector ')'[opt] ')'
ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
SourceLocation SelectorLoc = ConsumeToken();
@@ -2859,7 +2851,10 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
-
+ bool HasOptionalParen = Tok.is(tok::l_paren);
+ if (HasOptionalParen)
+ ConsumeParen();
+
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents);
cutOffParsing();
@@ -2869,20 +2864,20 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
IdentifierInfo *SelIdent = ParseObjCSelectorPiece(sLoc);
if (!SelIdent && // missing selector name.
Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon))
- return ExprError(Diag(Tok, diag::err_expected_ident));
+ return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);
KeyIdents.push_back(SelIdent);
+
unsigned nColons = 0;
if (Tok.isNot(tok::r_paren)) {
while (1) {
- if (Tok.is(tok::coloncolon)) { // Handle :: in C++.
+ if (TryConsumeToken(tok::coloncolon)) { // Handle :: in C++.
++nColons;
- KeyIdents.push_back(0);
- } else if (Tok.isNot(tok::colon))
- return ExprError(Diag(Tok, diag::err_expected_colon));
-
+ KeyIdents.push_back(nullptr);
+ } else if (ExpectAndConsume(tok::colon)) // Otherwise expect ':'.
+ return ExprError();
++nColons;
- ConsumeToken(); // Eat the ':' or '::'.
+
if (Tok.is(tok::r_paren))
break;
@@ -2900,11 +2895,14 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
break;
}
}
+ if (HasOptionalParen && Tok.is(tok::r_paren))
+ ConsumeParen(); // ')'
T.consumeClose();
Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);
return Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
T.getOpenLocation(),
- T.getCloseLocation());
+ T.getCloseLocation(),
+ !HasOptionalParen);
}
void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
@@ -2931,7 +2929,7 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
assert((Tok.is(tok::l_brace) || Tok.is(tok::kw_try) ||
Tok.is(tok::colon)) &&
"Inline objective-c method not starting with '{' or 'try' or ':'");
- // Enter a scope for the method or c-fucntion body.
+ // Enter a scope for the method or c-function body.
ParseScope BodyScope(this,
parseMethod
? Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope
@@ -2944,11 +2942,11 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
else
Actions.ActOnStartOfFunctionDef(getCurScope(), MCDecl);
if (Tok.is(tok::kw_try))
- MCDecl = ParseFunctionTryBlock(MCDecl, BodyScope);
+ ParseFunctionTryBlock(MCDecl, BodyScope);
else {
if (Tok.is(tok::colon))
ParseConstructorInitializer(MCDecl);
- MCDecl = ParseFunctionStatementBody(MCDecl, BodyScope);
+ ParseFunctionStatementBody(MCDecl, BodyScope);
}
if (Tok.getLocation() != OrigLoc) {
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index 89e4147e285c..d1544e6baa5b 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -11,19 +11,43 @@
///
//===----------------------------------------------------------------------===//
+#include "RAIIObjectsForParser.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Sema/Scope.h"
#include "llvm/ADT/PointerIntPair.h"
-#include "RAIIObjectsForParser.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// OpenMP declarative directives.
//===----------------------------------------------------------------------===//
+static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) {
+ auto Tok = P.getCurToken();
+ auto DKind =
+ Tok.isAnnotation()
+ ? OMPD_unknown
+ : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
+ if (DKind == OMPD_parallel) {
+ Tok = P.getPreprocessor().LookAhead(0);
+ auto SDKind =
+ Tok.isAnnotation()
+ ? OMPD_unknown
+ : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
+ if (SDKind == OMPD_for) {
+ P.ConsumeToken();
+ DKind = OMPD_parallel_for;
+ } else if (SDKind == OMPD_sections) {
+ P.ConsumeToken();
+ DKind = OMPD_parallel_sections;
+ }
+ }
+ return DKind;
+}
+
/// \brief Parsing of declarative OpenMP directives.
///
/// threadprivate-directive:
@@ -35,9 +59,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
SourceLocation Loc = ConsumeToken();
SmallVector<Expr *, 5> Identifiers;
- OpenMPDirectiveKind DKind = Tok.isAnnotation() ?
- OMPD_unknown :
- getOpenMPDirectiveKind(PP.getSpelling(Tok));
+ auto DKind = ParseOpenMPDirectiveKind(*this);
switch (DKind) {
case OMPD_threadprivate:
@@ -47,23 +69,34 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
// extra tokens.
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
- << getOpenMPDirectiveName(OMPD_threadprivate);
+ << getOpenMPDirectiveName(OMPD_threadprivate);
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
}
// Skip the last annot_pragma_openmp_end.
ConsumeToken();
- return Actions.ActOnOpenMPThreadprivateDirective(Loc,
- Identifiers);
+ return Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers);
}
break;
case OMPD_unknown:
Diag(Tok, diag::err_omp_unknown_directive);
break;
case OMPD_parallel:
+ case OMPD_simd:
case OMPD_task:
- case NUM_OPENMP_DIRECTIVES:
+ case OMPD_taskyield:
+ case OMPD_barrier:
+ case OMPD_taskwait:
+ case OMPD_flush:
+ case OMPD_for:
+ case OMPD_sections:
+ case OMPD_section:
+ case OMPD_single:
+ case OMPD_master:
+ case OMPD_critical:
+ case OMPD_parallel_for:
+ case OMPD_parallel_sections:
Diag(Tok, diag::err_omp_unexpected_directive)
- << getOpenMPDirectiveName(DKind);
+ << getOpenMPDirectiveName(DKind);
break;
}
SkipUntil(tok::annot_pragma_openmp_end);
@@ -76,25 +109,29 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
/// annot_pragma_openmp 'threadprivate' simple-variable-list
/// annot_pragma_openmp_end
///
-/// parallel-directive:
-/// annot_pragma_openmp 'parallel' {clause} annot_pragma_openmp_end
+/// executable-directive:
+/// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' |
+/// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] |
+/// 'parallel for' | 'parallel sections' | 'task' | 'taskyield' |
+/// 'barrier' | 'taskwait' | 'flush' {clause} annot_pragma_openmp_end
///
-StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() {
+StmtResult
+Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) {
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
ParenBraceBracketBalancer BalancerRAIIObj(*this);
SmallVector<Expr *, 5> Identifiers;
SmallVector<OMPClause *, 5> Clauses;
- SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, NUM_OPENMP_CLAUSES>
- FirstClauses(NUM_OPENMP_CLAUSES);
- const unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |
- Scope::OpenMPDirectiveScope;
+ SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1>
+ FirstClauses(OMPC_unknown + 1);
+ unsigned ScopeFlags =
+ Scope::FnScope | Scope::DeclScope | Scope::OpenMPDirectiveScope;
SourceLocation Loc = ConsumeToken(), EndLoc;
- OpenMPDirectiveKind DKind = Tok.isAnnotation() ?
- OMPD_unknown :
- getOpenMPDirectiveKind(PP.getSpelling(Tok));
+ auto DKind = ParseOpenMPDirectiveKind(*this);
// Name of critical directive.
DeclarationNameInfo DirName;
StmtResult Directive = StmtError();
+ bool HasAssociatedStatement = true;
+ bool FlushHasClause = false;
switch (DKind) {
case OMPD_threadprivate:
@@ -104,27 +141,75 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() {
// extra tokens.
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
- << getOpenMPDirectiveName(OMPD_threadprivate);
+ << getOpenMPDirectiveName(OMPD_threadprivate);
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
}
DeclGroupPtrTy Res =
- Actions.ActOnOpenMPThreadprivateDirective(Loc,
- Identifiers);
+ Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers);
Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
}
SkipUntil(tok::annot_pragma_openmp_end);
break;
- case OMPD_parallel: {
+ case OMPD_flush:
+ if (PP.LookAhead(0).is(tok::l_paren)) {
+ FlushHasClause = true;
+ // Push copy of the current token back to stream to properly parse
+ // pseudo-clause OMPFlushClause.
+ PP.EnterToken(Tok);
+ }
+ case OMPD_taskyield:
+ case OMPD_barrier:
+ case OMPD_taskwait:
+ if (!StandAloneAllowed) {
+ Diag(Tok, diag::err_omp_immediate_directive)
+ << getOpenMPDirectiveName(DKind);
+ }
+ HasAssociatedStatement = false;
+ // Fall through for further analysis.
+ case OMPD_parallel:
+ case OMPD_simd:
+ case OMPD_for:
+ case OMPD_sections:
+ case OMPD_single:
+ case OMPD_section:
+ case OMPD_master:
+ case OMPD_critical:
+ case OMPD_parallel_for:
+ case OMPD_parallel_sections:
+ case OMPD_task: {
ConsumeToken();
+ // Parse directive name of the 'critical' directive if any.
+ if (DKind == OMPD_critical) {
+ BalancedDelimiterTracker T(*this, tok::l_paren,
+ tok::annot_pragma_openmp_end);
+ if (!T.consumeOpen()) {
+ if (Tok.isAnyIdentifier()) {
+ DirName =
+ DeclarationNameInfo(Tok.getIdentifierInfo(), Tok.getLocation());
+ ConsumeAnyToken();
+ } else {
+ Diag(Tok, diag::err_omp_expected_identifier_for_critical);
+ }
+ T.consumeClose();
+ }
+ }
- Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope());
+ if (isOpenMPLoopDirective(DKind))
+ ScopeFlags |= Scope::OpenMPLoopDirectiveScope;
+ if (isOpenMPSimdDirective(DKind))
+ ScopeFlags |= Scope::OpenMPSimdDirectiveScope;
+ ParseScope OMPDirectiveScope(this, ScopeFlags);
+ Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), Loc);
while (Tok.isNot(tok::annot_pragma_openmp_end)) {
- OpenMPClauseKind CKind = Tok.isAnnotation() ?
- OMPC_unknown :
- getOpenMPClauseKind(PP.getSpelling(Tok));
- OMPClause *Clause = ParseOpenMPClause(DKind, CKind,
- !FirstClauses[CKind].getInt());
+ OpenMPClauseKind CKind =
+ Tok.isAnnotation()
+ ? OMPC_unknown
+ : FlushHasClause ? OMPC_flush
+ : getOpenMPClauseKind(PP.getSpelling(Tok));
+ FlushHasClause = false;
+ OMPClause *Clause =
+ ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt());
FirstClauses[CKind].setInt(true);
if (Clause) {
FirstClauses[CKind].setPointer(Clause);
@@ -142,11 +227,10 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() {
StmtResult AssociatedStmt;
bool CreateDirective = true;
- ParseScope OMPDirectiveScope(this, ScopeFlags);
- {
+ if (HasAssociatedStatement) {
// The body is a block scope like in Lambdas and Blocks.
Sema::CompoundScopeRAII CompoundScope(Actions);
- Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_OpenMP, 1);
+ Actions.ActOnOpenMPRegionStart(DKind, getCurScope());
Actions.ActOnStartOfCompoundStmt();
// Parse statement
AssociatedStmt = ParseStatement();
@@ -155,30 +239,23 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() {
Actions.ActOnCapturedRegionError();
CreateDirective = false;
} else {
- AssociatedStmt = Actions.ActOnCapturedRegionEnd(AssociatedStmt.take());
+ AssociatedStmt = Actions.ActOnCapturedRegionEnd(AssociatedStmt.get());
CreateDirective = AssociatedStmt.isUsable();
}
}
if (CreateDirective)
- Directive = Actions.ActOnOpenMPExecutableDirective(DKind, Clauses,
- AssociatedStmt.take(),
- Loc, EndLoc);
+ Directive = Actions.ActOnOpenMPExecutableDirective(
+ DKind, DirName, Clauses, AssociatedStmt.get(), Loc, EndLoc);
// Exit scope.
Actions.EndOpenMPDSABlock(Directive.get());
OMPDirectiveScope.Exit();
- }
break;
+ }
case OMPD_unknown:
Diag(Tok, diag::err_omp_unknown_directive);
SkipUntil(tok::annot_pragma_openmp_end);
break;
- case OMPD_task:
- case NUM_OPENMP_DIRECTIVES:
- Diag(Tok, diag::err_omp_unexpected_directive)
- << getOpenMPDirectiveName(DKind);
- SkipUntil(tok::annot_pragma_openmp_end);
- break;
}
return Directive;
}
@@ -225,14 +302,15 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
IsCorrect = false;
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
StopBeforeMatch);
- Diag(PrevTok.getLocation(), diag::err_expected_ident)
- << SourceRange(PrevTok.getLocation(), PrevTokLocation);
+ Diag(PrevTok.getLocation(), diag::err_expected)
+ << tok::identifier
+ << SourceRange(PrevTok.getLocation(), PrevTokLocation);
} else {
DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name);
- ExprResult Res = Actions.ActOnOpenMPIdExpression(getCurScope(), SS,
- NameInfo);
+ ExprResult Res =
+ Actions.ActOnOpenMPIdExpression(getCurScope(), SS, NameInfo);
if (Res.isUsable())
- VarList.push_back(Res.take());
+ VarList.push_back(Res.get());
}
// Consume ','.
if (Tok.is(tok::comma)) {
@@ -241,7 +319,7 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
}
if (NoIdentIsFound) {
- Diag(Tok, diag::err_expected_ident);
+ Diag(Tok, diag::err_expected) << tok::identifier;
IsCorrect = false;
}
@@ -254,56 +332,159 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
/// \brief Parsing of OpenMP clauses.
///
/// clause:
-/// default-clause|private-clause|firstprivate-clause|shared-clause
+/// if-clause | final-clause | num_threads-clause | safelen-clause |
+/// default-clause | private-clause | firstprivate-clause | shared-clause
+/// | linear-clause | aligned-clause | collapse-clause |
+/// lastprivate-clause | reduction-clause | proc_bind-clause |
+/// schedule-clause | copyin-clause | copyprivate-clause | untied-clause |
+/// mergeable-clause | flush-clause
///
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind, bool FirstClause) {
- OMPClause *Clause = 0;
+ OMPClause *Clause = nullptr;
bool ErrorFound = false;
// Check if clause is allowed for the given directive.
if (CKind != OMPC_unknown && !isAllowedClauseForDirective(DKind, CKind)) {
- Diag(Tok, diag::err_omp_unexpected_clause)
- << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
+ Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind)
+ << getOpenMPDirectiveName(DKind);
ErrorFound = true;
}
switch (CKind) {
+ case OMPC_if:
+ case OMPC_final:
+ case OMPC_num_threads:
+ case OMPC_safelen:
+ case OMPC_collapse:
+ // OpenMP [2.5, Restrictions]
+ // At most one if clause can appear on the directive.
+ // At most one num_threads clause can appear on the directive.
+ // OpenMP [2.8.1, simd construct, Restrictions]
+ // Only one safelen clause can appear on a simd directive.
+ // Only one collapse clause can appear on a simd directive.
+ // OpenMP [2.11.1, task Construct, Restrictions]
+ // At most one if clause can appear on the directive.
+ // At most one final clause can appear on the directive.
+ if (!FirstClause) {
+ Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
+ << getOpenMPClauseName(CKind);
+ }
+
+ Clause = ParseOpenMPSingleExprClause(CKind);
+ break;
case OMPC_default:
- // OpenMP [2.9.3.1, Restrictions]
- // Only a single default clause may be specified on a parallel or task
- // directive.
+ case OMPC_proc_bind:
+ // OpenMP [2.14.3.1, Restrictions]
+ // Only a single default clause may be specified on a parallel, task or
+ // teams directive.
+ // OpenMP [2.5, parallel Construct, Restrictions]
+ // At most one proc_bind clause can appear on the directive.
if (!FirstClause) {
- Diag(Tok, diag::err_omp_more_one_clause)
- << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind);
+ Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
+ << getOpenMPClauseName(CKind);
}
Clause = ParseOpenMPSimpleClause(CKind);
break;
+ case OMPC_schedule:
+ // OpenMP [2.7.1, Restrictions, p. 3]
+ // Only one schedule clause can appear on a loop directive.
+ if (!FirstClause) {
+ Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
+ << getOpenMPClauseName(CKind);
+ }
+
+ Clause = ParseOpenMPSingleExprWithArgClause(CKind);
+ break;
+ case OMPC_ordered:
+ case OMPC_nowait:
+ case OMPC_untied:
+ case OMPC_mergeable:
+ // OpenMP [2.7.1, Restrictions, p. 9]
+ // Only one ordered clause can appear on a loop directive.
+ // OpenMP [2.7.1, Restrictions, C/C++, p. 4]
+ // Only one nowait clause can appear on a for directive.
+ if (!FirstClause) {
+ Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
+ << getOpenMPClauseName(CKind);
+ }
+
+ Clause = ParseOpenMPClause(CKind);
+ break;
case OMPC_private:
case OMPC_firstprivate:
+ case OMPC_lastprivate:
case OMPC_shared:
+ case OMPC_reduction:
+ case OMPC_linear:
+ case OMPC_aligned:
+ case OMPC_copyin:
+ case OMPC_copyprivate:
+ case OMPC_flush:
Clause = ParseOpenMPVarListClause(CKind);
break;
case OMPC_unknown:
Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
- << getOpenMPDirectiveName(DKind);
+ << getOpenMPDirectiveName(DKind);
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
break;
case OMPC_threadprivate:
- case NUM_OPENMP_CLAUSES:
- Diag(Tok, diag::err_omp_unexpected_clause)
- << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
+ Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind)
+ << getOpenMPDirectiveName(DKind);
SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch);
break;
}
- return ErrorFound ? 0 : Clause;
+ return ErrorFound ? nullptr : Clause;
+}
+
+/// \brief Parsing of OpenMP clauses with single expressions like 'if',
+/// 'final', 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams' or
+/// 'thread_limit'.
+///
+/// if-clause:
+/// 'if' '(' expression ')'
+///
+/// final-clause:
+/// 'final' '(' expression ')'
+///
+/// num_threads-clause:
+/// 'num_threads' '(' expression ')'
+///
+/// safelen-clause:
+/// 'safelen' '(' expression ')'
+///
+/// collapse-clause:
+/// 'collapse' '(' expression ')'
+///
+OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind) {
+ SourceLocation Loc = ConsumeToken();
+
+ BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ getOpenMPClauseName(Kind)))
+ return nullptr;
+
+ ExprResult LHS(ParseCastExpression(false, false, NotTypeCast));
+ ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
+
+ // Parse ')'.
+ T.consumeClose();
+
+ if (Val.isInvalid())
+ return nullptr;
+
+ return Actions.ActOnOpenMPSingleExprClause(
+ Kind, Val.get(), Loc, T.getOpenLocation(), T.getCloseLocation());
}
-/// \brief Parsing of simple OpenMP clauses like 'default'.
+/// \brief Parsing of simple OpenMP clauses like 'default' or 'proc_bind'.
///
/// default-clause:
/// 'default' '(' 'none' | 'shared' ')
///
+/// proc_bind-clause:
+/// 'proc_bind' '(' 'master' | 'close' | 'spread' ')
+///
OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
SourceLocation Loc = Tok.getLocation();
SourceLocation LOpen = ConsumeToken();
@@ -311,11 +492,10 @@ OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
if (T.expectAndConsume(diag::err_expected_lparen_after,
getOpenMPClauseName(Kind)))
- return 0;
+ return nullptr;
- unsigned Type = Tok.isAnnotation() ?
- unsigned(OMPC_DEFAULT_unknown) :
- getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok));
+ unsigned Type = getOpenMPSimpleClauseType(
+ Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok));
SourceLocation TypeLoc = Tok.getLocation();
if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
Tok.isNot(tok::annot_pragma_openmp_end))
@@ -328,54 +508,221 @@ OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
Tok.getLocation());
}
-/// \brief Parsing of OpenMP clause 'private', 'firstprivate',
-/// 'shared', 'copyin', or 'reduction'.
+/// \brief Parsing of OpenMP clauses like 'ordered'.
+///
+/// ordered-clause:
+/// 'ordered'
+///
+/// nowait-clause:
+/// 'nowait'
+///
+/// untied-clause:
+/// 'untied'
+///
+/// mergeable-clause:
+/// 'mergeable'
+///
+OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind) {
+ SourceLocation Loc = Tok.getLocation();
+ ConsumeAnyToken();
+
+ return Actions.ActOnOpenMPClause(Kind, Loc, Tok.getLocation());
+}
+
+
+/// \brief Parsing of OpenMP clauses with single expressions and some additional
+/// argument like 'schedule' or 'dist_schedule'.
+///
+/// schedule-clause:
+/// 'schedule' '(' kind [',' expression ] ')'
+///
+OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind) {
+ SourceLocation Loc = ConsumeToken();
+ SourceLocation CommaLoc;
+ // Parse '('.
+ BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ getOpenMPClauseName(Kind)))
+ return nullptr;
+
+ ExprResult Val;
+ unsigned Type = getOpenMPSimpleClauseType(
+ Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok));
+ SourceLocation KLoc = Tok.getLocation();
+ if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
+ Tok.isNot(tok::annot_pragma_openmp_end))
+ ConsumeAnyToken();
+
+ if (Kind == OMPC_schedule &&
+ (Type == OMPC_SCHEDULE_static || Type == OMPC_SCHEDULE_dynamic ||
+ Type == OMPC_SCHEDULE_guided) &&
+ Tok.is(tok::comma)) {
+ CommaLoc = ConsumeAnyToken();
+ ExprResult LHS(ParseCastExpression(false, false, NotTypeCast));
+ Val = ParseRHSOfBinaryExpression(LHS, prec::Conditional);
+ if (Val.isInvalid())
+ return nullptr;
+ }
+
+ // Parse ')'.
+ T.consumeClose();
+
+ return Actions.ActOnOpenMPSingleExprWithArgClause(
+ Kind, Type, Val.get(), Loc, T.getOpenLocation(), KLoc, CommaLoc,
+ T.getCloseLocation());
+}
+
+static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,
+ UnqualifiedId &ReductionId) {
+ SourceLocation TemplateKWLoc;
+ if (ReductionIdScopeSpec.isEmpty()) {
+ auto OOK = OO_None;
+ switch (P.getCurToken().getKind()) {
+ case tok::plus:
+ OOK = OO_Plus;
+ break;
+ case tok::minus:
+ OOK = OO_Minus;
+ break;
+ case tok::star:
+ OOK = OO_Star;
+ break;
+ case tok::amp:
+ OOK = OO_Amp;
+ break;
+ case tok::pipe:
+ OOK = OO_Pipe;
+ break;
+ case tok::caret:
+ OOK = OO_Caret;
+ break;
+ case tok::ampamp:
+ OOK = OO_AmpAmp;
+ break;
+ case tok::pipepipe:
+ OOK = OO_PipePipe;
+ break;
+ default:
+ break;
+ }
+ if (OOK != OO_None) {
+ SourceLocation OpLoc = P.ConsumeToken();
+ SourceLocation SymbolLocations[] = {OpLoc, OpLoc, SourceLocation()};
+ ReductionId.setOperatorFunctionId(OpLoc, OOK, SymbolLocations);
+ return false;
+ }
+ }
+ return P.ParseUnqualifiedId(ReductionIdScopeSpec, /*EnteringContext*/ false,
+ /*AllowDestructorName*/ false,
+ /*AllowConstructorName*/ false, ParsedType(),
+ TemplateKWLoc, ReductionId);
+}
+
+/// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate',
+/// 'shared', 'copyin', 'copyprivate', 'flush' or 'reduction'.
///
/// private-clause:
/// 'private' '(' list ')'
/// firstprivate-clause:
/// 'firstprivate' '(' list ')'
+/// lastprivate-clause:
+/// 'lastprivate' '(' list ')'
/// shared-clause:
/// 'shared' '(' list ')'
+/// linear-clause:
+/// 'linear' '(' list [ ':' linear-step ] ')'
+/// aligned-clause:
+/// 'aligned' '(' list [ ':' alignment ] ')'
+/// reduction-clause:
+/// 'reduction' '(' reduction-identifier ':' list ')'
+/// copyprivate-clause:
+/// 'copyprivate' '(' list ')'
+/// flush-clause:
+/// 'flush' '(' list ')'
///
OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
SourceLocation Loc = Tok.getLocation();
SourceLocation LOpen = ConsumeToken();
+ SourceLocation ColonLoc = SourceLocation();
+ // Optional scope specifier and unqualified id for reduction identifier.
+ CXXScopeSpec ReductionIdScopeSpec;
+ UnqualifiedId ReductionId;
+ bool InvalidReductionId = false;
// Parse '('.
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
if (T.expectAndConsume(diag::err_expected_lparen_after,
getOpenMPClauseName(Kind)))
- return 0;
+ return nullptr;
+
+ // Handle reduction-identifier for reduction clause.
+ if (Kind == OMPC_reduction) {
+ ColonProtectionRAIIObject ColonRAII(*this);
+ if (getLangOpts().CPlusPlus) {
+ ParseOptionalCXXScopeSpecifier(ReductionIdScopeSpec, ParsedType(), false);
+ }
+ InvalidReductionId =
+ ParseReductionId(*this, ReductionIdScopeSpec, ReductionId);
+ if (InvalidReductionId) {
+ SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
+ }
+ if (Tok.is(tok::colon)) {
+ ColonLoc = ConsumeToken();
+ } else {
+ Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier";
+ }
+ }
SmallVector<Expr *, 5> Vars;
- bool IsComma = true;
- while (IsComma || (Tok.isNot(tok::r_paren) &&
+ bool IsComma = !InvalidReductionId;
+ const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned);
+ while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&
Tok.isNot(tok::annot_pragma_openmp_end))) {
+ ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);
// Parse variable
ExprResult VarExpr = ParseAssignmentExpression();
if (VarExpr.isUsable()) {
- Vars.push_back(VarExpr.take());
+ Vars.push_back(VarExpr.get());
} else {
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
StopBeforeMatch);
}
// Skip ',' if any
IsComma = Tok.is(tok::comma);
- if (IsComma) {
+ if (IsComma)
ConsumeToken();
- } else if (Tok.isNot(tok::r_paren) &&
- Tok.isNot(tok::annot_pragma_openmp_end)) {
+ else if (Tok.isNot(tok::r_paren) &&
+ Tok.isNot(tok::annot_pragma_openmp_end) &&
+ (!MayHaveTail || Tok.isNot(tok::colon)))
Diag(Tok, diag::err_omp_expected_punc)
- << 1 << getOpenMPClauseName(Kind);
- }
+ << ((Kind == OMPC_flush) ? getOpenMPDirectiveName(OMPD_flush)
+ : getOpenMPClauseName(Kind))
+ << (Kind == OMPC_flush);
+ }
+
+ // Parse ':' linear-step (or ':' alignment).
+ Expr *TailExpr = nullptr;
+ const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon);
+ if (MustHaveTail) {
+ ColonLoc = Tok.getLocation();
+ ConsumeToken();
+ ExprResult Tail = ParseAssignmentExpression();
+ if (Tail.isUsable())
+ TailExpr = Tail.get();
+ else
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
}
// Parse ')'.
T.consumeClose();
- if (Vars.empty())
- return 0;
+ if (Vars.empty() || (MustHaveTail && !TailExpr) || InvalidReductionId)
+ return nullptr;
- return Actions.ActOnOpenMPVarListClause(Kind, Vars, Loc, LOpen,
- Tok.getLocation());
+ return Actions.ActOnOpenMPVarListClause(
+ Kind, Vars, TailExpr, Loc, LOpen, ColonLoc, Tok.getLocation(),
+ ReductionIdScopeSpec,
+ ReductionId.isValid() ? Actions.GetNameFromUnqualifiedId(ReductionId)
+ : DeclarationNameInfo());
}
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 8a374e0fce61..d3777f3ea4a0 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -11,14 +11,288 @@
//
//===----------------------------------------------------------------------===//
-#include "ParsePragma.h"
+#include "RAIIObjectsForParser.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
+#include "clang/Sema/LoopHint.h"
#include "clang/Sema/Scope.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
+namespace {
+
+struct PragmaAlignHandler : public PragmaHandler {
+ explicit PragmaAlignHandler() : PragmaHandler("align") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
+struct PragmaGCCVisibilityHandler : public PragmaHandler {
+ explicit PragmaGCCVisibilityHandler() : PragmaHandler("visibility") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
+struct PragmaOptionsHandler : public PragmaHandler {
+ explicit PragmaOptionsHandler() : PragmaHandler("options") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
+struct PragmaPackHandler : public PragmaHandler {
+ explicit PragmaPackHandler() : PragmaHandler("pack") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
+struct PragmaMSStructHandler : public PragmaHandler {
+ explicit PragmaMSStructHandler() : PragmaHandler("ms_struct") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
+struct PragmaUnusedHandler : public PragmaHandler {
+ PragmaUnusedHandler() : PragmaHandler("unused") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
+struct PragmaWeakHandler : public PragmaHandler {
+ explicit PragmaWeakHandler() : PragmaHandler("weak") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
+struct PragmaRedefineExtnameHandler : public PragmaHandler {
+ explicit PragmaRedefineExtnameHandler() : PragmaHandler("redefine_extname") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
+struct PragmaOpenCLExtensionHandler : public PragmaHandler {
+ PragmaOpenCLExtensionHandler() : PragmaHandler("EXTENSION") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
+
+struct PragmaFPContractHandler : public PragmaHandler {
+ PragmaFPContractHandler() : PragmaHandler("FP_CONTRACT") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
+struct PragmaNoOpenMPHandler : public PragmaHandler {
+ PragmaNoOpenMPHandler() : PragmaHandler("omp") { }
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
+struct PragmaOpenMPHandler : public PragmaHandler {
+ PragmaOpenMPHandler() : PragmaHandler("omp") { }
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
+/// PragmaCommentHandler - "\#pragma comment ...".
+struct PragmaCommentHandler : public PragmaHandler {
+ PragmaCommentHandler(Sema &Actions)
+ : PragmaHandler("comment"), Actions(Actions) {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+private:
+ Sema &Actions;
+};
+
+struct PragmaDetectMismatchHandler : public PragmaHandler {
+ PragmaDetectMismatchHandler(Sema &Actions)
+ : PragmaHandler("detect_mismatch"), Actions(Actions) {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+private:
+ Sema &Actions;
+};
+
+struct PragmaMSPointersToMembers : public PragmaHandler {
+ explicit PragmaMSPointersToMembers() : PragmaHandler("pointers_to_members") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
+struct PragmaMSVtorDisp : public PragmaHandler {
+ explicit PragmaMSVtorDisp() : PragmaHandler("vtordisp") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
+struct PragmaMSPragma : public PragmaHandler {
+ explicit PragmaMSPragma(const char *name) : PragmaHandler(name) {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
+/// PragmaOptimizeHandler - "\#pragma clang optimize on/off".
+struct PragmaOptimizeHandler : public PragmaHandler {
+ PragmaOptimizeHandler(Sema &S)
+ : PragmaHandler("optimize"), Actions(S) {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+private:
+ Sema &Actions;
+};
+
+struct PragmaLoopHintHandler : public PragmaHandler {
+ PragmaLoopHintHandler() : PragmaHandler("loop") {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
+struct PragmaUnrollHintHandler : public PragmaHandler {
+ PragmaUnrollHintHandler(const char *name) : PragmaHandler(name) {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
+} // end namespace
+
+void Parser::initializePragmaHandlers() {
+ AlignHandler.reset(new PragmaAlignHandler());
+ PP.AddPragmaHandler(AlignHandler.get());
+
+ GCCVisibilityHandler.reset(new PragmaGCCVisibilityHandler());
+ PP.AddPragmaHandler("GCC", GCCVisibilityHandler.get());
+
+ OptionsHandler.reset(new PragmaOptionsHandler());
+ PP.AddPragmaHandler(OptionsHandler.get());
+
+ PackHandler.reset(new PragmaPackHandler());
+ PP.AddPragmaHandler(PackHandler.get());
+
+ MSStructHandler.reset(new PragmaMSStructHandler());
+ PP.AddPragmaHandler(MSStructHandler.get());
+
+ UnusedHandler.reset(new PragmaUnusedHandler());
+ PP.AddPragmaHandler(UnusedHandler.get());
+
+ WeakHandler.reset(new PragmaWeakHandler());
+ PP.AddPragmaHandler(WeakHandler.get());
+
+ RedefineExtnameHandler.reset(new PragmaRedefineExtnameHandler());
+ PP.AddPragmaHandler(RedefineExtnameHandler.get());
+
+ FPContractHandler.reset(new PragmaFPContractHandler());
+ PP.AddPragmaHandler("STDC", FPContractHandler.get());
+
+ if (getLangOpts().OpenCL) {
+ OpenCLExtensionHandler.reset(new PragmaOpenCLExtensionHandler());
+ PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get());
+
+ PP.AddPragmaHandler("OPENCL", FPContractHandler.get());
+ }
+ if (getLangOpts().OpenMP)
+ OpenMPHandler.reset(new PragmaOpenMPHandler());
+ else
+ OpenMPHandler.reset(new PragmaNoOpenMPHandler());
+ PP.AddPragmaHandler(OpenMPHandler.get());
+
+ if (getLangOpts().MicrosoftExt) {
+ MSCommentHandler.reset(new PragmaCommentHandler(Actions));
+ PP.AddPragmaHandler(MSCommentHandler.get());
+ MSDetectMismatchHandler.reset(new PragmaDetectMismatchHandler(Actions));
+ PP.AddPragmaHandler(MSDetectMismatchHandler.get());
+ MSPointersToMembers.reset(new PragmaMSPointersToMembers());
+ PP.AddPragmaHandler(MSPointersToMembers.get());
+ MSVtorDisp.reset(new PragmaMSVtorDisp());
+ PP.AddPragmaHandler(MSVtorDisp.get());
+ MSInitSeg.reset(new PragmaMSPragma("init_seg"));
+ PP.AddPragmaHandler(MSInitSeg.get());
+ MSDataSeg.reset(new PragmaMSPragma("data_seg"));
+ PP.AddPragmaHandler(MSDataSeg.get());
+ MSBSSSeg.reset(new PragmaMSPragma("bss_seg"));
+ PP.AddPragmaHandler(MSBSSSeg.get());
+ MSConstSeg.reset(new PragmaMSPragma("const_seg"));
+ PP.AddPragmaHandler(MSConstSeg.get());
+ MSCodeSeg.reset(new PragmaMSPragma("code_seg"));
+ PP.AddPragmaHandler(MSCodeSeg.get());
+ MSSection.reset(new PragmaMSPragma("section"));
+ PP.AddPragmaHandler(MSSection.get());
+ }
+
+ OptimizeHandler.reset(new PragmaOptimizeHandler(Actions));
+ PP.AddPragmaHandler("clang", OptimizeHandler.get());
+
+ LoopHintHandler.reset(new PragmaLoopHintHandler());
+ PP.AddPragmaHandler("clang", LoopHintHandler.get());
+
+ UnrollHintHandler.reset(new PragmaUnrollHintHandler("unroll"));
+ PP.AddPragmaHandler(UnrollHintHandler.get());
+}
+
+void Parser::resetPragmaHandlers() {
+ // Remove the pragma handlers we installed.
+ PP.RemovePragmaHandler(AlignHandler.get());
+ AlignHandler.reset();
+ PP.RemovePragmaHandler("GCC", GCCVisibilityHandler.get());
+ GCCVisibilityHandler.reset();
+ PP.RemovePragmaHandler(OptionsHandler.get());
+ OptionsHandler.reset();
+ PP.RemovePragmaHandler(PackHandler.get());
+ PackHandler.reset();
+ PP.RemovePragmaHandler(MSStructHandler.get());
+ MSStructHandler.reset();
+ PP.RemovePragmaHandler(UnusedHandler.get());
+ UnusedHandler.reset();
+ PP.RemovePragmaHandler(WeakHandler.get());
+ WeakHandler.reset();
+ PP.RemovePragmaHandler(RedefineExtnameHandler.get());
+ RedefineExtnameHandler.reset();
+
+ if (getLangOpts().OpenCL) {
+ PP.RemovePragmaHandler("OPENCL", OpenCLExtensionHandler.get());
+ OpenCLExtensionHandler.reset();
+ PP.RemovePragmaHandler("OPENCL", FPContractHandler.get());
+ }
+ PP.RemovePragmaHandler(OpenMPHandler.get());
+ OpenMPHandler.reset();
+
+ if (getLangOpts().MicrosoftExt) {
+ PP.RemovePragmaHandler(MSCommentHandler.get());
+ MSCommentHandler.reset();
+ PP.RemovePragmaHandler(MSDetectMismatchHandler.get());
+ MSDetectMismatchHandler.reset();
+ PP.RemovePragmaHandler(MSPointersToMembers.get());
+ MSPointersToMembers.reset();
+ PP.RemovePragmaHandler(MSVtorDisp.get());
+ MSVtorDisp.reset();
+ PP.RemovePragmaHandler(MSInitSeg.get());
+ MSInitSeg.reset();
+ PP.RemovePragmaHandler(MSDataSeg.get());
+ MSDataSeg.reset();
+ PP.RemovePragmaHandler(MSBSSSeg.get());
+ MSBSSSeg.reset();
+ PP.RemovePragmaHandler(MSConstSeg.get());
+ MSConstSeg.reset();
+ PP.RemovePragmaHandler(MSCodeSeg.get());
+ MSCodeSeg.reset();
+ PP.RemovePragmaHandler(MSSection.get());
+ MSSection.reset();
+ }
+
+ PP.RemovePragmaHandler("STDC", FPContractHandler.get());
+ FPContractHandler.reset();
+
+ PP.RemovePragmaHandler("clang", OptimizeHandler.get());
+ OptimizeHandler.reset();
+
+ PP.RemovePragmaHandler("clang", LoopHintHandler.get());
+ LoopHintHandler.reset();
+
+ PP.RemovePragmaHandler(UnrollHintHandler.get());
+ UnrollHintHandler.reset();
+}
+
/// \brief Handle the annotation token produced for #pragma unused(...)
///
/// Each annot_pragma_unused is followed by the argument token so e.g.
@@ -130,7 +404,7 @@ StmtResult Parser::HandlePragmaCaptured()
ConsumeToken();
if (Tok.isNot(tok::l_brace)) {
- PP.Diag(Tok, diag::err_expected_lbrace);
+ PP.Diag(Tok, diag::err_expected) << tok::l_brace;
return StmtError();
}
@@ -180,7 +454,307 @@ void Parser::HandlePragmaOpenCLExtension() {
}
}
+void Parser::HandlePragmaMSPointersToMembers() {
+ assert(Tok.is(tok::annot_pragma_ms_pointers_to_members));
+ LangOptions::PragmaMSPointersToMembersKind RepresentationMethod =
+ static_cast<LangOptions::PragmaMSPointersToMembersKind>(
+ reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
+ SourceLocation PragmaLoc = ConsumeToken(); // The annotation token.
+ Actions.ActOnPragmaMSPointersToMembers(RepresentationMethod, PragmaLoc);
+}
+
+void Parser::HandlePragmaMSVtorDisp() {
+ assert(Tok.is(tok::annot_pragma_ms_vtordisp));
+ uintptr_t Value = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue());
+ Sema::PragmaVtorDispKind Kind =
+ static_cast<Sema::PragmaVtorDispKind>((Value >> 16) & 0xFFFF);
+ MSVtorDispAttr::Mode Mode = MSVtorDispAttr::Mode(Value & 0xFFFF);
+ SourceLocation PragmaLoc = ConsumeToken(); // The annotation token.
+ Actions.ActOnPragmaMSVtorDisp(Kind, PragmaLoc, Mode);
+}
+void Parser::HandlePragmaMSPragma() {
+ assert(Tok.is(tok::annot_pragma_ms_pragma));
+ // Grab the tokens out of the annotation and enter them into the stream.
+ auto TheTokens = (std::pair<Token*, size_t> *)Tok.getAnnotationValue();
+ PP.EnterTokenStream(TheTokens->first, TheTokens->second, true, true);
+ SourceLocation PragmaLocation = ConsumeToken(); // The annotation token.
+ assert(Tok.isAnyIdentifier());
+ StringRef PragmaName = Tok.getIdentifierInfo()->getName();
+ PP.Lex(Tok); // pragma kind
+
+ // Figure out which #pragma we're dealing with. The switch has no default
+ // because lex shouldn't emit the annotation token for unrecognized pragmas.
+ typedef bool (Parser::*PragmaHandler)(StringRef, SourceLocation);
+ PragmaHandler Handler = llvm::StringSwitch<PragmaHandler>(PragmaName)
+ .Case("data_seg", &Parser::HandlePragmaMSSegment)
+ .Case("bss_seg", &Parser::HandlePragmaMSSegment)
+ .Case("const_seg", &Parser::HandlePragmaMSSegment)
+ .Case("code_seg", &Parser::HandlePragmaMSSegment)
+ .Case("section", &Parser::HandlePragmaMSSection)
+ .Case("init_seg", &Parser::HandlePragmaMSInitSeg);
+
+ if (!(this->*Handler)(PragmaName, PragmaLocation)) {
+ // Pragma handling failed, and has been diagnosed. Slurp up the tokens
+ // until eof (really end of line) to prevent follow-on errors.
+ while (Tok.isNot(tok::eof))
+ PP.Lex(Tok);
+ PP.Lex(Tok);
+ }
+}
+
+bool Parser::HandlePragmaMSSection(StringRef PragmaName,
+ SourceLocation PragmaLocation) {
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_lparen) << PragmaName;
+ return false;
+ }
+ PP.Lex(Tok); // (
+ // Parsing code for pragma section
+ if (Tok.isNot(tok::string_literal)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_section_name)
+ << PragmaName;
+ return false;
+ }
+ ExprResult StringResult = ParseStringLiteralExpression();
+ if (StringResult.isInvalid())
+ return false; // Already diagnosed.
+ StringLiteral *SegmentName = cast<StringLiteral>(StringResult.get());
+ if (SegmentName->getCharByteWidth() != 1) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string)
+ << PragmaName;
+ return false;
+ }
+ int SectionFlags = 0;
+ while (Tok.is(tok::comma)) {
+ PP.Lex(Tok); // ,
+ if (!Tok.isAnyIdentifier()) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_action_or_r_paren)
+ << PragmaName;
+ return false;
+ }
+ Sema::PragmaSectionFlag Flag =
+ llvm::StringSwitch<Sema::PragmaSectionFlag>(
+ Tok.getIdentifierInfo()->getName())
+ .Case("read", Sema::PSF_Read)
+ .Case("write", Sema::PSF_Write)
+ .Case("execute", Sema::PSF_Execute)
+ .Case("shared", Sema::PSF_Invalid)
+ .Case("nopage", Sema::PSF_Invalid)
+ .Case("nocache", Sema::PSF_Invalid)
+ .Case("discard", Sema::PSF_Invalid)
+ .Case("remove", Sema::PSF_Invalid)
+ .Default(Sema::PSF_None);
+ if (Flag == Sema::PSF_None || Flag == Sema::PSF_Invalid) {
+ PP.Diag(PragmaLocation, Flag == Sema::PSF_None
+ ? diag::warn_pragma_invalid_specific_action
+ : diag::warn_pragma_unsupported_action)
+ << PragmaName << Tok.getIdentifierInfo()->getName();
+ return false;
+ }
+ SectionFlags |= Flag;
+ PP.Lex(Tok); // Identifier
+ }
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_rparen) << PragmaName;
+ return false;
+ }
+ PP.Lex(Tok); // )
+ if (Tok.isNot(tok::eof)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_extra_tokens_at_eol)
+ << PragmaName;
+ return false;
+ }
+ PP.Lex(Tok); // eof
+ Actions.ActOnPragmaMSSection(PragmaLocation, SectionFlags, SegmentName);
+ return true;
+}
+
+bool Parser::HandlePragmaMSSegment(StringRef PragmaName,
+ SourceLocation PragmaLocation) {
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_lparen) << PragmaName;
+ return false;
+ }
+ PP.Lex(Tok); // (
+ Sema::PragmaMsStackAction Action = Sema::PSK_Reset;
+ StringRef SlotLabel;
+ if (Tok.isAnyIdentifier()) {
+ StringRef PushPop = Tok.getIdentifierInfo()->getName();
+ if (PushPop == "push")
+ Action = Sema::PSK_Push;
+ else if (PushPop == "pop")
+ Action = Sema::PSK_Pop;
+ else {
+ PP.Diag(PragmaLocation,
+ diag::warn_pragma_expected_section_push_pop_or_name)
+ << PragmaName;
+ return false;
+ }
+ if (Action != Sema::PSK_Reset) {
+ PP.Lex(Tok); // push | pop
+ if (Tok.is(tok::comma)) {
+ PP.Lex(Tok); // ,
+ // If we've got a comma, we either need a label or a string.
+ if (Tok.isAnyIdentifier()) {
+ SlotLabel = Tok.getIdentifierInfo()->getName();
+ PP.Lex(Tok); // identifier
+ if (Tok.is(tok::comma))
+ PP.Lex(Tok);
+ else if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_punc)
+ << PragmaName;
+ return false;
+ }
+ }
+ } else if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_punc) << PragmaName;
+ return false;
+ }
+ }
+ }
+ // Grab the string literal for our section name.
+ StringLiteral *SegmentName = nullptr;
+ if (Tok.isNot(tok::r_paren)) {
+ if (Tok.isNot(tok::string_literal)) {
+ unsigned DiagID = Action != Sema::PSK_Reset ? !SlotLabel.empty() ?
+ diag::warn_pragma_expected_section_name :
+ diag::warn_pragma_expected_section_label_or_name :
+ diag::warn_pragma_expected_section_push_pop_or_name;
+ PP.Diag(PragmaLocation, DiagID) << PragmaName;
+ return false;
+ }
+ ExprResult StringResult = ParseStringLiteralExpression();
+ if (StringResult.isInvalid())
+ return false; // Already diagnosed.
+ SegmentName = cast<StringLiteral>(StringResult.get());
+ if (SegmentName->getCharByteWidth() != 1) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string)
+ << PragmaName;
+ return false;
+ }
+ // Setting section "" has no effect
+ if (SegmentName->getLength())
+ Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set);
+ }
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_rparen) << PragmaName;
+ return false;
+ }
+ PP.Lex(Tok); // )
+ if (Tok.isNot(tok::eof)) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_extra_tokens_at_eol)
+ << PragmaName;
+ return false;
+ }
+ PP.Lex(Tok); // eof
+ Actions.ActOnPragmaMSSeg(PragmaLocation, Action, SlotLabel,
+ SegmentName, PragmaName);
+ return true;
+}
+
+// #pragma init_seg({ compiler | lib | user | "section-name" [, func-name]} )
+bool Parser::HandlePragmaMSInitSeg(StringRef PragmaName,
+ SourceLocation PragmaLocation) {
+ if (getTargetInfo().getTriple().getEnvironment() != llvm::Triple::MSVC) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_init_seg_unsupported_target);
+ return false;
+ }
+
+ if (ExpectAndConsume(tok::l_paren, diag::warn_pragma_expected_lparen,
+ PragmaName))
+ return false;
+
+ // Parse either the known section names or the string section name.
+ StringLiteral *SegmentName = nullptr;
+ if (Tok.isAnyIdentifier()) {
+ auto *II = Tok.getIdentifierInfo();
+ StringRef Section = llvm::StringSwitch<StringRef>(II->getName())
+ .Case("compiler", "\".CRT$XCC\"")
+ .Case("lib", "\".CRT$XCL\"")
+ .Case("user", "\".CRT$XCU\"")
+ .Default("");
+
+ if (!Section.empty()) {
+ // Pretend the user wrote the appropriate string literal here.
+ Token Toks[1];
+ Toks[0].startToken();
+ Toks[0].setKind(tok::string_literal);
+ Toks[0].setLocation(Tok.getLocation());
+ Toks[0].setLiteralData(Section.data());
+ Toks[0].setLength(Section.size());
+ SegmentName =
+ cast<StringLiteral>(Actions.ActOnStringLiteral(Toks, nullptr).get());
+ PP.Lex(Tok);
+ }
+ } else if (Tok.is(tok::string_literal)) {
+ ExprResult StringResult = ParseStringLiteralExpression();
+ if (StringResult.isInvalid())
+ return false;
+ SegmentName = cast<StringLiteral>(StringResult.get());
+ if (SegmentName->getCharByteWidth() != 1) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string)
+ << PragmaName;
+ return false;
+ }
+ // FIXME: Add support for the '[, func-name]' part of the pragma.
+ }
+
+ if (!SegmentName) {
+ PP.Diag(PragmaLocation, diag::warn_pragma_expected_init_seg) << PragmaName;
+ return false;
+ }
+
+ if (ExpectAndConsume(tok::r_paren, diag::warn_pragma_expected_rparen,
+ PragmaName) ||
+ ExpectAndConsume(tok::eof, diag::warn_pragma_extra_tokens_at_eol,
+ PragmaName))
+ return false;
+
+ Actions.ActOnPragmaMSInitSeg(PragmaLocation, SegmentName);
+ return true;
+}
+
+struct PragmaLoopHintInfo {
+ Token PragmaName;
+ Token Option;
+ Token Value;
+ bool HasValue;
+};
+
+LoopHint Parser::HandlePragmaLoopHint() {
+ assert(Tok.is(tok::annot_pragma_loop_hint));
+ PragmaLoopHintInfo *Info =
+ static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue());
+
+ LoopHint Hint;
+ Hint.PragmaNameLoc =
+ IdentifierLoc::create(Actions.Context, Info->PragmaName.getLocation(),
+ Info->PragmaName.getIdentifierInfo());
+ Hint.OptionLoc =
+ IdentifierLoc::create(Actions.Context, Info->Option.getLocation(),
+ Info->Option.getIdentifierInfo());
+ if (Info->HasValue) {
+ Hint.Range =
+ SourceRange(Info->Option.getLocation(), Info->Value.getLocation());
+ Hint.ValueLoc =
+ IdentifierLoc::create(Actions.Context, Info->Value.getLocation(),
+ Info->Value.getIdentifierInfo());
+
+ // FIXME: We should allow non-type template parameters for the loop hint
+ // value. See bug report #19610
+ if (Info->Value.is(tok::numeric_constant))
+ Hint.ValueExpr = Actions.ActOnNumericConstant(Info->Value).get();
+ else
+ Hint.ValueExpr = nullptr;
+ } else {
+ Hint.Range = SourceRange(Info->PragmaName.getLocation());
+ Hint.ValueLoc = nullptr;
+ Hint.ValueExpr = nullptr;
+ }
+
+ return Hint;
+}
// #pragma GCC visibility comes in two variants:
// 'push' '(' [visibility] ')'
@@ -197,7 +771,7 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP,
const IdentifierInfo *VisType;
if (PushPop && PushPop->isStr("pop")) {
- VisType = 0;
+ VisType = nullptr;
} else if (PushPop && PushPop->isStr("push")) {
PP.LexUnexpandedToken(Tok);
if (Tok.isNot(tok::l_paren)) {
@@ -257,7 +831,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
}
Sema::PragmaPackKind Kind = Sema::PPK_Default;
- IdentifierInfo *Name = 0;
+ IdentifierInfo *Name = nullptr;
Token Alignment;
Alignment.startToken();
SourceLocation LParenLoc = Tok.getLocation();
@@ -283,7 +857,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP,
} else if (II->isStr("pop")) {
Kind = Sema::PPK_Pop;
} else {
- PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_invalid_action);
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_action) << "pack";
return;
}
PP.Lex(Tok);
@@ -530,7 +1104,7 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP,
}
// Illegal token!
- PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_punc);
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_punc) << "unused";
return;
}
@@ -760,13 +1334,11 @@ void
PragmaNoOpenMPHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &FirstTok) {
- if (PP.getDiagnostics().getDiagnosticLevel(diag::warn_pragma_omp_ignored,
- FirstTok.getLocation()) !=
- DiagnosticsEngine::Ignored) {
+ if (!PP.getDiagnostics().isIgnored(diag::warn_pragma_omp_ignored,
+ FirstTok.getLocation())) {
PP.Diag(FirstTok, diag::warn_pragma_omp_ignored);
- PP.getDiagnostics().setDiagnosticMapping(diag::warn_pragma_omp_ignored,
- diag::MAP_IGNORE,
- SourceLocation());
+ PP.getDiagnostics().setSeverity(diag::warn_pragma_omp_ignored,
+ diag::Severity::Ignored, SourceLocation());
}
PP.DiscardUntilEndOfDirective();
}
@@ -799,6 +1371,220 @@ PragmaOpenMPHandler::HandlePragma(Preprocessor &PP,
/*DisableMacroExpansion=*/true, /*OwnsTokens=*/true);
}
+/// \brief Handle '#pragma pointers_to_members'
+// The grammar for this pragma is as follows:
+//
+// <inheritance model> ::= ('single' | 'multiple' | 'virtual') '_inheritance'
+//
+// #pragma pointers_to_members '(' 'best_case' ')'
+// #pragma pointers_to_members '(' 'full_generality' [',' inheritance-model] ')'
+// #pragma pointers_to_members '(' inheritance-model ')'
+void PragmaMSPointersToMembers::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &Tok) {
+ SourceLocation PointersToMembersLoc = Tok.getLocation();
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(PointersToMembersLoc, diag::warn_pragma_expected_lparen)
+ << "pointers_to_members";
+ return;
+ }
+ PP.Lex(Tok);
+ const IdentifierInfo *Arg = Tok.getIdentifierInfo();
+ if (!Arg) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
+ << "pointers_to_members";
+ return;
+ }
+ PP.Lex(Tok);
+
+ LangOptions::PragmaMSPointersToMembersKind RepresentationMethod;
+ if (Arg->isStr("best_case")) {
+ RepresentationMethod = LangOptions::PPTMK_BestCase;
+ } else {
+ if (Arg->isStr("full_generality")) {
+ if (Tok.is(tok::comma)) {
+ PP.Lex(Tok);
+
+ Arg = Tok.getIdentifierInfo();
+ if (!Arg) {
+ PP.Diag(Tok.getLocation(),
+ diag::err_pragma_pointers_to_members_unknown_kind)
+ << Tok.getKind() << /*OnlyInheritanceModels*/ 0;
+ return;
+ }
+ PP.Lex(Tok);
+ } else if (Tok.is(tok::r_paren)) {
+ // #pragma pointers_to_members(full_generality) implicitly specifies
+ // virtual_inheritance.
+ Arg = nullptr;
+ RepresentationMethod = LangOptions::PPTMK_FullGeneralityVirtualInheritance;
+ } else {
+ PP.Diag(Tok.getLocation(), diag::err_expected_punc)
+ << "full_generality";
+ return;
+ }
+ }
+
+ if (Arg) {
+ if (Arg->isStr("single_inheritance")) {
+ RepresentationMethod =
+ LangOptions::PPTMK_FullGeneralitySingleInheritance;
+ } else if (Arg->isStr("multiple_inheritance")) {
+ RepresentationMethod =
+ LangOptions::PPTMK_FullGeneralityMultipleInheritance;
+ } else if (Arg->isStr("virtual_inheritance")) {
+ RepresentationMethod =
+ LangOptions::PPTMK_FullGeneralityVirtualInheritance;
+ } else {
+ PP.Diag(Tok.getLocation(),
+ diag::err_pragma_pointers_to_members_unknown_kind)
+ << Arg << /*HasPointerDeclaration*/ 1;
+ return;
+ }
+ }
+ }
+
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected_rparen_after)
+ << (Arg ? Arg->getName() : "full_generality");
+ return;
+ }
+
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "pointers_to_members";
+ return;
+ }
+
+ Token AnnotTok;
+ AnnotTok.startToken();
+ AnnotTok.setKind(tok::annot_pragma_ms_pointers_to_members);
+ AnnotTok.setLocation(PointersToMembersLoc);
+ AnnotTok.setAnnotationValue(
+ reinterpret_cast<void *>(static_cast<uintptr_t>(RepresentationMethod)));
+ PP.EnterToken(AnnotTok);
+}
+
+/// \brief Handle '#pragma vtordisp'
+// The grammar for this pragma is as follows:
+//
+// <vtordisp-mode> ::= ('off' | 'on' | '0' | '1' | '2' )
+//
+// #pragma vtordisp '(' ['push' ','] vtordisp-mode ')'
+// #pragma vtordisp '(' 'pop' ')'
+// #pragma vtordisp '(' ')'
+void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &Tok) {
+ SourceLocation VtorDispLoc = Tok.getLocation();
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(VtorDispLoc, diag::warn_pragma_expected_lparen) << "vtordisp";
+ return;
+ }
+ PP.Lex(Tok);
+
+ Sema::PragmaVtorDispKind Kind = Sema::PVDK_Set;
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (II) {
+ if (II->isStr("push")) {
+ // #pragma vtordisp(push, mode)
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::comma)) {
+ PP.Diag(VtorDispLoc, diag::warn_pragma_expected_punc) << "vtordisp";
+ return;
+ }
+ PP.Lex(Tok);
+ Kind = Sema::PVDK_Push;
+ // not push, could be on/off
+ } else if (II->isStr("pop")) {
+ // #pragma vtordisp(pop)
+ PP.Lex(Tok);
+ Kind = Sema::PVDK_Pop;
+ }
+ // not push or pop, could be on/off
+ } else {
+ if (Tok.is(tok::r_paren)) {
+ // #pragma vtordisp()
+ Kind = Sema::PVDK_Reset;
+ }
+ }
+
+
+ uint64_t Value = 0;
+ if (Kind == Sema::PVDK_Push || Kind == Sema::PVDK_Set) {
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (II && II->isStr("off")) {
+ PP.Lex(Tok);
+ Value = 0;
+ } else if (II && II->isStr("on")) {
+ PP.Lex(Tok);
+ Value = 1;
+ } else if (Tok.is(tok::numeric_constant) &&
+ PP.parseSimpleIntegerLiteral(Tok, Value)) {
+ if (Value > 2) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_integer)
+ << 0 << 2 << "vtordisp";
+ return;
+ }
+ } else {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_action)
+ << "vtordisp";
+ return;
+ }
+ }
+
+ // Finish the pragma: ')' $
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(VtorDispLoc, diag::warn_pragma_expected_rparen) << "vtordisp";
+ return;
+ }
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "vtordisp";
+ return;
+ }
+
+ // Enter the annotation.
+ Token AnnotTok;
+ AnnotTok.startToken();
+ AnnotTok.setKind(tok::annot_pragma_ms_vtordisp);
+ AnnotTok.setLocation(VtorDispLoc);
+ AnnotTok.setAnnotationValue(reinterpret_cast<void *>(
+ static_cast<uintptr_t>((Kind << 16) | (Value & 0xFFFF))));
+ PP.EnterToken(AnnotTok);
+}
+
+/// \brief Handle all MS pragmas. Simply forwards the tokens after inserting
+/// an annotation token.
+void PragmaMSPragma::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &Tok) {
+ Token EoF, AnnotTok;
+ EoF.startToken();
+ EoF.setKind(tok::eof);
+ AnnotTok.startToken();
+ AnnotTok.setKind(tok::annot_pragma_ms_pragma);
+ AnnotTok.setLocation(Tok.getLocation());
+ SmallVector<Token, 8> TokenVector;
+ // Suck up all of the tokens before the eod.
+ for (; Tok.isNot(tok::eod); PP.Lex(Tok))
+ TokenVector.push_back(Tok);
+ // Add a sentinal EoF token to the end of the list.
+ TokenVector.push_back(EoF);
+ // We must allocate this array with new because EnterTokenStream is going to
+ // delete it later.
+ Token *TokenArray = new Token[TokenVector.size()];
+ std::copy(TokenVector.begin(), TokenVector.end(), TokenArray);
+ auto Value = new (PP.getPreprocessorAllocator())
+ std::pair<Token*, size_t>(std::make_pair(TokenArray, TokenVector.size()));
+ AnnotTok.setAnnotationValue(Value);
+ PP.EnterToken(AnnotTok);
+}
+
/// \brief Handle the Microsoft \#pragma detect_mismatch extension.
///
/// The syntax is:
@@ -815,7 +1601,7 @@ void PragmaDetectMismatchHandler::HandlePragma(Preprocessor &PP,
SourceLocation CommentLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::l_paren)) {
- PP.Diag(CommentLoc, diag::err_expected_lparen);
+ PP.Diag(CommentLoc, diag::err_expected) << tok::l_paren;
return;
}
@@ -838,7 +1624,7 @@ void PragmaDetectMismatchHandler::HandlePragma(Preprocessor &PP,
return;
if (Tok.isNot(tok::r_paren)) {
- PP.Diag(Tok.getLocation(), diag::err_expected_rparen);
+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
return;
}
PP.Lex(Tok); // Eat the r_paren.
@@ -929,3 +1715,251 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
Actions.ActOnPragmaMSComment(Kind, ArgumentString);
}
+
+// #pragma clang optimize off
+// #pragma clang optimize on
+void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &FirstToken) {
+ Token Tok;
+ PP.Lex(Tok);
+ if (Tok.is(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument)
+ << "clang optimize"
+ << "'on' or 'off'";
+ return;
+ }
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_invalid_argument)
+ << PP.getSpelling(Tok);
+ return;
+ }
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ // The only accepted values are 'on' or 'off'.
+ bool IsOn = false;
+ if (II->isStr("on")) {
+ IsOn = true;
+ } else if (!II->isStr("off")) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_invalid_argument)
+ << PP.getSpelling(Tok);
+ return;
+ }
+ PP.Lex(Tok);
+
+ if (Tok.isNot(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_extra_argument)
+ << PP.getSpelling(Tok);
+ return;
+ }
+
+ Actions.ActOnPragmaOptimize(IsOn, FirstToken.getLocation());
+}
+
+/// \brief Parses loop or unroll pragma hint value and fills in Info.
+static bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token &PragmaName,
+ Token &Option, bool &ValueInParens,
+ PragmaLoopHintInfo &Info) {
+ ValueInParens = Tok.is(tok::l_paren);
+ if (ValueInParens) {
+ PP.Lex(Tok);
+ if (Tok.is(tok::r_paren)) {
+ // Nothing between the parentheses.
+ std::string PragmaString;
+ if (PragmaName.getIdentifierInfo()->getName() == "loop") {
+ PragmaString = "clang loop ";
+ PragmaString += Option.getIdentifierInfo()->getName();
+ } else {
+ assert(PragmaName.getIdentifierInfo()->getName() == "unroll" &&
+ "Unexpected pragma name");
+ PragmaString = "unroll";
+ }
+ PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument)
+ << PragmaString << "a positive integer value";
+ return true;
+ }
+ }
+
+ // FIXME: Value should be stored and parsed as a constant expression.
+ Token Value = Tok;
+
+ if (ValueInParens) {
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
+ return true;
+ }
+ }
+
+ Info.PragmaName = PragmaName;
+ Info.Option = Option;
+ Info.Value = Value;
+ Info.HasValue = true;
+ return false;
+}
+
+/// \brief Handle the \#pragma clang loop directive.
+/// #pragma clang 'loop' loop-hints
+///
+/// loop-hints:
+/// loop-hint loop-hints[opt]
+///
+/// loop-hint:
+/// 'vectorize' '(' loop-hint-keyword ')'
+/// 'interleave' '(' loop-hint-keyword ')'
+/// 'unroll' '(' loop-hint-keyword ')'
+/// 'vectorize_width' '(' loop-hint-value ')'
+/// 'interleave_count' '(' loop-hint-value ')'
+/// 'unroll_count' '(' loop-hint-value ')'
+///
+/// loop-hint-keyword:
+/// 'enable'
+/// 'disable'
+///
+/// loop-hint-value:
+/// constant-expression
+///
+/// Specifying vectorize(enable) or vectorize_width(_value_) instructs llvm to
+/// try vectorizing the instructions of the loop it precedes. Specifying
+/// interleave(enable) or interleave_count(_value_) instructs llvm to try
+/// interleaving multiple iterations of the loop it precedes. The width of the
+/// vector instructions is specified by vectorize_width() and the number of
+/// interleaved loop iterations is specified by interleave_count(). Specifying a
+/// value of 1 effectively disables vectorization/interleaving, even if it is
+/// possible and profitable, and 0 is invalid. The loop vectorizer currently
+/// only works on inner loops.
+///
+/// The unroll and unroll_count directives control the concatenation
+/// unroller. Specifying unroll(enable) instructs llvm to try to
+/// unroll the loop completely, and unroll(disable) disables unrolling
+/// for the loop. Specifying unroll_count(_value_) instructs llvm to
+/// try to unroll the loop the number of times indicated by the value.
+/// If unroll(enable) and unroll_count are both specified only
+/// unroll_count takes effect.
+void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &Tok) {
+ // Incoming token is "loop" from "#pragma clang loop".
+ Token PragmaName = Tok;
+ SmallVector<Token, 1> TokenList;
+
+ // Lex the optimization option and verify it is an identifier.
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::identifier)) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option)
+ << /*MissingOption=*/true << "";
+ return;
+ }
+
+ while (Tok.is(tok::identifier)) {
+ Token Option = Tok;
+ IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
+
+ bool OptionValid = llvm::StringSwitch<bool>(OptionInfo->getName())
+ .Case("vectorize", true)
+ .Case("interleave", true)
+ .Case("unroll", true)
+ .Case("vectorize_width", true)
+ .Case("interleave_count", true)
+ .Case("unroll_count", true)
+ .Default(false);
+ if (!OptionValid) {
+ PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option)
+ << /*MissingOption=*/false << OptionInfo;
+ return;
+ }
+
+ auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
+ PP.Lex(Tok);
+ bool ValueInParens;
+ if (ParseLoopHintValue(PP, Tok, PragmaName, Option, ValueInParens, *Info))
+ return;
+
+ if (!ValueInParens) {
+ PP.Diag(Info->Value.getLocation(), diag::err_expected) << tok::l_paren;
+ return;
+ }
+
+ // Generate the loop hint token.
+ Token LoopHintTok;
+ LoopHintTok.startToken();
+ LoopHintTok.setKind(tok::annot_pragma_loop_hint);
+ LoopHintTok.setLocation(PragmaName.getLocation());
+ LoopHintTok.setAnnotationValue(static_cast<void *>(Info));
+ TokenList.push_back(LoopHintTok);
+
+ // Get next optimization option.
+ PP.Lex(Tok);
+ }
+
+ if (Tok.isNot(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "clang loop";
+ return;
+ }
+
+ Token *TokenArray = new Token[TokenList.size()];
+ std::copy(TokenList.begin(), TokenList.end(), TokenArray);
+
+ PP.EnterTokenStream(TokenArray, TokenList.size(),
+ /*DisableMacroExpansion=*/false,
+ /*OwnsTokens=*/true);
+}
+
+/// \brief Handle the loop unroll optimization pragmas.
+/// #pragma unroll
+/// #pragma unroll unroll-hint-value
+/// #pragma unroll '(' unroll-hint-value ')'
+///
+/// unroll-hint-value:
+/// constant-expression
+///
+/// Loop unrolling hints are specified with '#pragma unroll'. '#pragma unroll'
+/// can take a numeric argument optionally contained in parentheses. With no
+/// argument the directive instructs llvm to try to unroll the loop
+/// completely. A positive integer argument can be specified to indicate the
+/// number of times the loop should be unrolled. To maximize compatibility with
+/// other compilers the unroll count argument can be specified with or without
+/// parentheses.
+void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &Tok) {
+ // Incoming token is "unroll" of "#pragma unroll".
+ Token PragmaName = Tok;
+ PP.Lex(Tok);
+ auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
+ if (Tok.is(tok::eod)) {
+ // Unroll pragma without an argument.
+ Info->PragmaName = PragmaName;
+ Info->Option = PragmaName;
+ Info->HasValue = false;
+ } else {
+ // Unroll pragma with an argument: "#pragma unroll N" or
+ // "#pragma unroll(N)".
+ bool ValueInParens;
+ if (ParseLoopHintValue(PP, Tok, PragmaName, PragmaName, ValueInParens,
+ *Info))
+ return;
+
+ // In CUDA, the argument to '#pragma unroll' should not be contained in
+ // parentheses.
+ if (PP.getLangOpts().CUDA && ValueInParens)
+ PP.Diag(Info->Value.getLocation(),
+ diag::warn_pragma_unroll_cuda_value_in_parens);
+
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "unroll";
+ return;
+ }
+ }
+
+ // Generate the hint token.
+ Token *TokenArray = new Token[1];
+ TokenArray[0].startToken();
+ TokenArray[0].setKind(tok::annot_pragma_loop_hint);
+ TokenArray[0].setLocation(PragmaName.getLocation());
+ TokenArray[0].setAnnotationValue(static_cast<void *>(Info));
+ PP.EnterTokenStream(TokenArray, 1, /*DisableMacroExpansion=*/false,
+ /*OwnsTokens=*/true);
+}
diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h
deleted file mode 100644
index b41450f4eadf..000000000000
--- a/lib/Parse/ParsePragma.h
+++ /dev/null
@@ -1,139 +0,0 @@
-//===---- ParserPragmas.h - Language specific pragmas -----------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines #pragma handlers for language specific pragmas.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_PARSE_PARSEPRAGMA_H
-#define LLVM_CLANG_PARSE_PARSEPRAGMA_H
-
-#include "clang/Lex/Pragma.h"
-
-namespace clang {
- class Sema;
- class Parser;
-
-class PragmaAlignHandler : public PragmaHandler {
-public:
- explicit PragmaAlignHandler() : PragmaHandler("align") {}
-
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &FirstToken);
-};
-
-class PragmaGCCVisibilityHandler : public PragmaHandler {
-public:
- explicit PragmaGCCVisibilityHandler() : PragmaHandler("visibility") {}
-
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &FirstToken);
-};
-
-class PragmaOptionsHandler : public PragmaHandler {
-public:
- explicit PragmaOptionsHandler() : PragmaHandler("options") {}
-
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &FirstToken);
-};
-
-class PragmaPackHandler : public PragmaHandler {
-public:
- explicit PragmaPackHandler() : PragmaHandler("pack") {}
-
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &FirstToken);
-};
-
-class PragmaMSStructHandler : public PragmaHandler {
-public:
- explicit PragmaMSStructHandler() : PragmaHandler("ms_struct") {}
-
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &FirstToken);
-};
-
-class PragmaUnusedHandler : public PragmaHandler {
-public:
- PragmaUnusedHandler() : PragmaHandler("unused") {}
-
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &FirstToken);
-};
-
-class PragmaWeakHandler : public PragmaHandler {
-public:
- explicit PragmaWeakHandler() : PragmaHandler("weak") {}
-
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &FirstToken);
-};
-
-class PragmaRedefineExtnameHandler : public PragmaHandler {
-public:
- explicit PragmaRedefineExtnameHandler() : PragmaHandler("redefine_extname") {}
-
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &FirstToken);
-};
-
-class PragmaOpenCLExtensionHandler : public PragmaHandler {
-public:
- PragmaOpenCLExtensionHandler() : PragmaHandler("EXTENSION") {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &FirstToken);
-};
-
-
-class PragmaFPContractHandler : public PragmaHandler {
-public:
- PragmaFPContractHandler() : PragmaHandler("FP_CONTRACT") {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &FirstToken);
-};
-
-class PragmaNoOpenMPHandler : public PragmaHandler {
-public:
- PragmaNoOpenMPHandler() : PragmaHandler("omp") { }
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &FirstToken);
-};
-
-class PragmaOpenMPHandler : public PragmaHandler {
-public:
- PragmaOpenMPHandler() : PragmaHandler("omp") { }
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &FirstToken);
-};
-
-/// PragmaCommentHandler - "\#pragma comment ...".
-class PragmaCommentHandler : public PragmaHandler {
-public:
- PragmaCommentHandler(Sema &Actions)
- : PragmaHandler("comment"), Actions(Actions) {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &FirstToken);
-private:
- Sema &Actions;
-};
-
-class PragmaDetectMismatchHandler : public PragmaHandler {
-public:
- PragmaDetectMismatchHandler(Sema &Actions)
- : PragmaHandler("detect_mismatch"), Actions(Actions) {}
- virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
- Token &FirstToken);
-private:
- Sema &Actions;
-};
-
-} // end namespace clang
-
-#endif
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index d1f2138db48f..ec0ca6b1fdd6 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -15,25 +15,14 @@
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
#include "clang/AST/ASTContext.h"
+#include "clang/Basic/Attributes.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/PrettyStackTrace.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/LoopHint.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/TypoCorrection.h"
-#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCObjectFileInfo.h"
-#include "llvm/MC/MCParser/MCAsmParser.h"
-#include "llvm/MC/MCRegisterInfo.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCTargetAsmParser.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/TargetSelect.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -112,7 +101,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement,
ParenBraceBracketBalancer BalancerRAIIObj(*this);
ParsedAttributesWithRange Attrs(AttrFactory);
- MaybeParseCXX11Attributes(Attrs, 0, /*MightBeObjCMessageSend*/ true);
+ MaybeParseCXX11Attributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true);
StmtResult Res = ParseStatementOrDeclarationAfterAttributes(Stmts,
OnlyStatement, TrailingElseLoc, Attrs);
@@ -142,7 +131,7 @@ public:
WantCXXNamedCasts = false;
}
- virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ bool ValidateCandidate(const TypoCorrection &candidate) override {
if (FieldDecl *FD = candidate.getCorrectionDeclAs<FieldDecl>())
return !candidate.getCorrectionSpecifier() || isa<ObjCIvarDecl>(FD);
if (NextToken.is(tok::equal))
@@ -162,7 +151,7 @@ StmtResult
Parser::ParseStatementOrDeclarationAfterAttributes(StmtVector &Stmts,
bool OnlyStatement, SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs) {
- const char *SemiError = 0;
+ const char *SemiError = nullptr;
StmtResult Res;
// Cases in this switch statement should fall through if the parser expects
@@ -284,6 +273,14 @@ Retry:
break;
}
+ case tok::kw___if_exists:
+ case tok::kw___if_not_exists:
+ ProhibitAttributes(Attrs);
+ ParseMicrosoftIfExistsStatement(Stmts);
+ // An __if_exists block is like a compound statement, but it doesn't create
+ // a new scope.
+ return StmtEmpty();
+
case tok::kw_try: // C++ 15: try-block
return ParseCXXTryBlock();
@@ -291,6 +288,11 @@ Retry:
ProhibitAttributes(Attrs); // TODO: is it correct?
return ParseSEHTryBlock();
+ case tok::kw___leave:
+ Res = ParseSEHLeaveStatement();
+ SemiError = "__leave";
+ break;
+
case tok::annot_pragma_vis:
ProhibitAttributes(Attrs);
HandlePragmaVisibility();
@@ -343,14 +345,25 @@ Retry:
case tok::annot_pragma_openmp:
ProhibitAttributes(Attrs);
- return ParseOpenMPDeclarativeOrExecutableDirective();
+ return ParseOpenMPDeclarativeOrExecutableDirective(!OnlyStatement);
+
+ case tok::annot_pragma_ms_pointers_to_members:
+ ProhibitAttributes(Attrs);
+ HandlePragmaMSPointersToMembers();
+ return StmtEmpty();
+ case tok::annot_pragma_ms_pragma:
+ ProhibitAttributes(Attrs);
+ HandlePragmaMSPragma();
+ return StmtEmpty();
+
+ case tok::annot_pragma_loop_hint:
+ ProhibitAttributes(Attrs);
+ return ParsePragmaLoopHint(Stmts, OnlyStatement, TrailingElseLoc, Attrs);
}
// If we reached this code, the statement must end in a semicolon.
- if (Tok.is(tok::semi)) {
- ConsumeToken();
- } else if (!Res.isInvalid()) {
+ if (!TryConsumeToken(tok::semi) && !Res.isInvalid()) {
// If the result was valid, then we do want to diagnose this. Use
// ExpectAndConsume to emit the diagnostic, even though we know it won't
// succeed.
@@ -411,10 +424,27 @@ StmtResult Parser::ParseSEHTryBlock() {
/// seh-finally-block
///
StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) {
- if(Tok.isNot(tok::l_brace))
- return StmtError(Diag(Tok,diag::err_expected_lbrace));
+ if (Tok.isNot(tok::l_brace))
+ return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
+
+ int SEHTryIndex, SEHTryParentIndex;
+ StmtResult TryBlock;
+ {
+ 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 | Scope::SEHTryScope);
+ SEHTryIndex = getCurScope()->getSEHTryIndex();
+ SEHTryParentIndex = getCurScope()->getSEHTryParentIndex();
+
+ // Parse the statements in the body.
+ TryBlock = ParseCompoundStatementBody();
+ }
+
+ //StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false,
+ // Scope::DeclScope | Scope::SEHTryScope));
- StmtResult TryBlock(ParseCompoundStatement());
if(TryBlock.isInvalid())
return TryBlock;
@@ -435,8 +465,10 @@ StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) {
return Actions.ActOnSEHTryBlock(false /* IsCXXTry */,
TryLoc,
- TryBlock.take(),
- Handler.take());
+ TryBlock.get(),
+ Handler.get(),
+ SEHTryIndex,
+ SEHTryParentIndex);
}
/// ParseSEHExceptBlock - Handle __except
@@ -449,7 +481,7 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) {
raii2(Ident___exception_code, false),
raii3(Ident_GetExceptionCode, false);
- if(ExpectAndConsume(tok::l_paren,diag::err_expected_lparen))
+ if (ExpectAndConsume(tok::l_paren))
return StmtError();
ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope);
@@ -470,7 +502,7 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) {
if(FilterExpr.isInvalid())
return StmtError();
- if(ExpectAndConsume(tok::r_paren,diag::err_expected_rparen))
+ if (ExpectAndConsume(tok::r_paren))
return StmtError();
StmtResult Block(ParseCompoundStatement());
@@ -478,7 +510,7 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) {
if(Block.isInvalid())
return Block;
- return Actions.ActOnSEHExceptBlock(ExceptLoc, FilterExpr.take(), Block.take());
+ return Actions.ActOnSEHExceptBlock(ExceptLoc, FilterExpr.get(), Block.get());
}
/// ParseSEHFinallyBlock - Handle __finally
@@ -495,7 +527,17 @@ StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyBlock) {
if(Block.isInvalid())
return Block;
- return Actions.ActOnSEHFinallyBlock(FinallyBlock,Block.take());
+ return Actions.ActOnSEHFinallyBlock(FinallyBlock,Block.get());
+}
+
+/// Handle __leave
+///
+/// seh-leave-statement:
+/// '__leave' ';'
+///
+StmtResult Parser::ParseSEHLeaveStatement() {
+ SourceLocation LeaveLoc = ConsumeToken(); // eat the '__leave'.
+ return Actions.ActOnSEHLeaveStmt(LeaveLoc, getCurScope());
}
/// ParseLabeledStatement - We have an identifier and a ':' after it.
@@ -538,12 +580,12 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs) {
// can't handle GNU attributes), so only call it in the one case where
// GNU attributes are allowed.
SubStmt = ParseStatementOrDeclarationAfterAttributes(
- Stmts, /*OnlyStmts*/ true, 0, TempAttrs);
+ Stmts, /*OnlyStmts*/ true, nullptr, TempAttrs);
if (!TempAttrs.empty() && !SubStmt.isInvalid())
SubStmt = Actions.ProcessStmtAttributes(
SubStmt.get(), TempAttrs.getList(), TempAttrs.Range);
} else {
- Diag(Tok, diag::err_expected_semi_after) << "__attribute__";
+ Diag(Tok, diag::err_expected_after) << "__attribute__" << tok::semi;
}
}
@@ -595,13 +637,14 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
// DeepestParsedCaseStmt - This is the deepest statement we have parsed, which
// gets updated each time a new case is parsed, and whose body is unset so
// far. When parsing 'case 4', this is the 'case 3' node.
- Stmt *DeepestParsedCaseStmt = 0;
+ Stmt *DeepestParsedCaseStmt = nullptr;
// While we have case statements, eat and stack them.
SourceLocation ColonLoc;
do {
SourceLocation CaseLoc = MissingCase ? Expr.get()->getExprLoc() :
ConsumeToken(); // eat the 'case'.
+ ColonLoc = SourceLocation();
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteCase(getCurScope());
@@ -614,41 +657,52 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
/// expression.
ColonProtectionRAIIObject ColonProtection(*this);
- ExprResult LHS(MissingCase ? Expr : ParseConstantExpression());
- MissingCase = false;
- if (LHS.isInvalid()) {
- SkipUntil(tok::colon, StopAtSemi);
- return StmtError();
+ ExprResult LHS;
+ if (!MissingCase) {
+ LHS = ParseConstantExpression();
+ if (LHS.isInvalid()) {
+ // If constant-expression is parsed unsuccessfully, recover by skipping
+ // current case statement (moving to the colon that ends it).
+ if (SkipUntil(tok::colon, tok::r_brace, StopAtSemi | StopBeforeMatch)) {
+ TryConsumeToken(tok::colon, ColonLoc);
+ continue;
+ }
+ return StmtError();
+ }
+ } else {
+ LHS = Expr;
+ MissingCase = false;
}
// GNU case range extension.
SourceLocation DotDotDotLoc;
ExprResult RHS;
- if (Tok.is(tok::ellipsis)) {
- Diag(Tok, diag::ext_gnu_case_range);
- DotDotDotLoc = ConsumeToken();
-
+ if (TryConsumeToken(tok::ellipsis, DotDotDotLoc)) {
+ Diag(DotDotDotLoc, diag::ext_gnu_case_range);
RHS = ParseConstantExpression();
if (RHS.isInvalid()) {
- SkipUntil(tok::colon, StopAtSemi);
+ if (SkipUntil(tok::colon, tok::r_brace, StopAtSemi | StopBeforeMatch)) {
+ TryConsumeToken(tok::colon, ColonLoc);
+ continue;
+ }
return StmtError();
}
}
ColonProtection.restore();
- if (Tok.is(tok::colon)) {
- ColonLoc = ConsumeToken();
-
- // Treat "case blah;" as a typo for "case blah:".
- } else if (Tok.is(tok::semi)) {
- ColonLoc = ConsumeToken();
- Diag(ColonLoc, diag::err_expected_colon_after) << "'case'"
- << FixItHint::CreateReplacement(ColonLoc, ":");
+ if (TryConsumeToken(tok::colon, ColonLoc)) {
+ } else if (TryConsumeToken(tok::semi, ColonLoc) ||
+ TryConsumeToken(tok::coloncolon, ColonLoc)) {
+ // Treat "case blah;" or "case blah::" as a typo for "case blah:".
+ Diag(ColonLoc, diag::err_expected_after)
+ << "'case'" << tok::colon
+ << FixItHint::CreateReplacement(ColonLoc, ":");
} else {
SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation);
- Diag(ExpectedLoc, diag::err_expected_colon_after) << "'case'"
- << FixItHint::CreateInsertion(ExpectedLoc, ":");
+ Diag(ExpectedLoc, diag::err_expected_after)
+ << "'case'" << tok::colon
+ << FixItHint::CreateInsertion(ExpectedLoc, ":");
ColonLoc = ExpectedLoc;
}
@@ -676,8 +730,6 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
// Handle all case statements.
} while (Tok.is(tok::kw_case));
- assert(!TopLevelCase.isInvalid() && "Should have parsed at least one case!");
-
// If we found a non-case statement, start by parsing it.
StmtResult SubStmt;
@@ -685,19 +737,23 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
SubStmt = ParseStatement();
} else {
// Nicely diagnose the common error "switch (X) { case 4: }", which is
- // not valid.
- SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
- Diag(AfterColonLoc, diag::err_label_end_of_compound_statement)
- << FixItHint::CreateInsertion(AfterColonLoc, " ;");
- SubStmt = true;
+ // not valid. If ColonLoc doesn't point to a valid text location, there was
+ // another parsing error, so avoid producing extra diagnostics.
+ if (ColonLoc.isValid()) {
+ SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
+ Diag(AfterColonLoc, diag::err_label_end_of_compound_statement)
+ << FixItHint::CreateInsertion(AfterColonLoc, " ;");
+ }
+ SubStmt = StmtError();
}
- // Broken sub-stmt shouldn't prevent forming the case statement properly.
- if (SubStmt.isInvalid())
- SubStmt = Actions.ActOnNullStmt(SourceLocation());
-
// Install the body into the most deeply-nested case.
- Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, SubStmt.get());
+ if (DeepestParsedCaseStmt) {
+ // Broken sub-stmt shouldn't prevent forming the case statement properly.
+ if (SubStmt.isInvalid())
+ SubStmt = Actions.ActOnNullStmt(SourceLocation());
+ Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, SubStmt.get());
+ }
// Return the top level parsed statement tree.
return TopLevelCase;
@@ -713,18 +769,17 @@ StmtResult Parser::ParseDefaultStatement() {
SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'.
SourceLocation ColonLoc;
- if (Tok.is(tok::colon)) {
- ColonLoc = ConsumeToken();
-
- // Treat "default;" as a typo for "default:".
- } else if (Tok.is(tok::semi)) {
- ColonLoc = ConsumeToken();
- Diag(ColonLoc, diag::err_expected_colon_after) << "'default'"
- << FixItHint::CreateReplacement(ColonLoc, ":");
+ if (TryConsumeToken(tok::colon, ColonLoc)) {
+ } else if (TryConsumeToken(tok::semi, ColonLoc)) {
+ // Treat "default;" as a typo for "default:".
+ Diag(ColonLoc, diag::err_expected_after)
+ << "'default'" << tok::colon
+ << FixItHint::CreateReplacement(ColonLoc, ":");
} else {
SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation);
- Diag(ExpectedLoc, diag::err_expected_colon_after) << "'default'"
- << FixItHint::CreateInsertion(ExpectedLoc, ":");
+ Diag(ExpectedLoc, diag::err_expected_after)
+ << "'default'" << tok::colon
+ << FixItHint::CreateInsertion(ExpectedLoc, ":");
ColonLoc = ExpectedLoc;
}
@@ -767,7 +822,6 @@ StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) {
/// declaration
/// [GNU] '__extension__' declaration
/// statement
-/// [OMP] openmp-directive [TODO]
///
/// [GNU] label-declarations:
/// [GNU] label-declaration
@@ -776,10 +830,6 @@ StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) {
/// [GNU] label-declaration:
/// [GNU] '__label__' identifier-list ';'
///
-/// [OMP] openmp-directive: [TODO]
-/// [OMP] barrier-directive
-/// [OMP] flush-directive
-///
StmtResult Parser::ParseCompoundStatement(bool isStmtExpr,
unsigned ScopeFlags) {
assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
@@ -826,6 +876,12 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
case tok::annot_pragma_fp_contract:
HandlePragmaFPContract();
break;
+ case tok::annot_pragma_ms_pointers_to_members:
+ HandlePragmaMSPointersToMembers();
+ break;
+ case tok::annot_pragma_ms_pragma:
+ HandlePragmaMSPragma();
+ break;
default:
checkForPragmas = false;
break;
@@ -867,7 +923,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
SmallVector<Decl *, 8> DeclsInGroup;
while (1) {
if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
+ Diag(Tok, diag::err_expected) << tok::identifier;
break;
}
@@ -875,9 +931,8 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
SourceLocation IdLoc = ConsumeToken();
DeclsInGroup.push_back(Actions.LookupOrCreateLabel(II, IdLoc, LabelLoc));
- if (!Tok.is(tok::comma))
+ if (!TryConsumeToken(tok::comma))
break;
- ConsumeToken();
}
DeclSpec DS(AttrFactory);
@@ -887,21 +942,15 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
ExpectAndConsumeSemi(diag::err_expected_semi_declaration);
if (R.isUsable())
- Stmts.push_back(R.release());
+ Stmts.push_back(R.get());
}
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
if (Tok.is(tok::annot_pragma_unused)) {
HandlePragmaUnused();
continue;
}
- if (getLangOpts().MicrosoftExt && (Tok.is(tok::kw___if_exists) ||
- Tok.is(tok::kw___if_not_exists))) {
- ParseMicrosoftIfExistsStatement(Stmts);
- continue;
- }
-
StmtResult R;
if (Tok.isNot(tok::kw___extension__)) {
R = ParseStatementOrDeclaration(Stmts, false);
@@ -915,7 +964,8 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
ConsumeToken();
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX11Attributes(attrs, 0, /*MightBeObjCMessageSend*/ true);
+ MaybeParseCXX11Attributes(attrs, nullptr,
+ /*MightBeObjCMessageSend*/ true);
// If this is the start of a declaration, parse it as such.
if (isDeclarationStatement()) {
@@ -946,7 +996,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
}
if (R.isUsable())
- Stmts.push_back(R.release());
+ Stmts.push_back(R.get());
}
SourceLocation CloseLoc = Tok.getLocation();
@@ -983,7 +1033,7 @@ bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult,
ParseCXXCondition(ExprResult, DeclResult, Loc, ConvertToBoolean);
else {
ExprResult = ParseExpression();
- DeclResult = 0;
+ DeclResult = nullptr;
// If required, convert to a boolean value.
if (!ExprResult.isInvalid() && ConvertToBoolean)
@@ -1053,7 +1103,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
// Parse the condition.
ExprResult CondExp;
- Decl *CondVar = 0;
+ Decl *CondVar = nullptr;
if (ParseParenExprOrCondition(CondExp, CondVar, IfLoc, true))
return StmtError();
@@ -1077,8 +1127,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
// would have to notify ParseStatement not to create a new scope. It's
// simpler to let it create a new scope.
//
- ParseScope InnerScope(this, Scope::DeclScope,
- C99orCXX && Tok.isNot(tok::l_brace));
+ ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
// Read the 'then' stmt.
SourceLocation ThenStmtLoc = Tok.getLocation();
@@ -1110,8 +1159,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
// The substatement in a selection-statement (each substatement, in the else
// form of the if statement) implicitly defines a local scope.
//
- ParseScope InnerScope(this, Scope::DeclScope,
- C99orCXX && Tok.isNot(tok::l_brace));
+ ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
ElseStmt = ParseStatement();
@@ -1131,8 +1179,8 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
// make turn the invalid one into a null stmt to avoid dropping the other
// part. If both are invalid, return error.
if ((ThenStmt.isInvalid() && ElseStmt.isInvalid()) ||
- (ThenStmt.isInvalid() && ElseStmt.get() == 0) ||
- (ThenStmt.get() == 0 && ElseStmt.isInvalid())) {
+ (ThenStmt.isInvalid() && ElseStmt.get() == nullptr) ||
+ (ThenStmt.get() == nullptr && ElseStmt.isInvalid())) {
// Both invalid, or one is invalid and other is non-present: return error.
return StmtError();
}
@@ -1175,14 +1223,14 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) {
// while, for, and switch statements are local to the if, while, for, or
// switch statement (including the controlled statement).
//
- unsigned ScopeFlags = Scope::BreakScope | Scope::SwitchScope;
+ unsigned ScopeFlags = Scope::SwitchScope;
if (C99orCXX)
ScopeFlags |= Scope::DeclScope | Scope::ControlScope;
ParseScope SwitchScope(this, ScopeFlags);
// Parse the condition.
ExprResult Cond;
- Decl *CondVar = 0;
+ Decl *CondVar = nullptr;
if (ParseParenExprOrCondition(Cond, CondVar, SwitchLoc, false))
return StmtError();
@@ -1213,8 +1261,13 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) {
// See comments in ParseIfStatement for why we create a scope for the
// condition and a new scope for substatement in C++.
//
- ParseScope InnerScope(this, Scope::DeclScope,
- C99orCXX && Tok.isNot(tok::l_brace));
+ getCurScope()->AddFlags(Scope::BreakScope);
+ ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
+
+ // We have incremented the mangling number for the SwitchScope and the
+ // InnerScope, which is one too many.
+ if (C99orCXX)
+ getCurScope()->decrementMSLocalManglingNumber();
// Read the body statement.
StmtResult Body(ParseStatement(TrailingElseLoc));
@@ -1223,15 +1276,6 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) {
InnerScope.Exit();
SwitchScope.Exit();
- if (Body.isInvalid()) {
- // FIXME: Remove the case statement list from the Switch statement.
-
- // Put the synthesized null statement on the same line as the end of switch
- // condition.
- SourceLocation SynthesizedNullStmtLocation = Cond.get()->getLocEnd();
- Body = Actions.ActOnNullStmt(SynthesizedNullStmtLocation);
- }
-
return Actions.ActOnFinishSwitchStmt(SwitchLoc, Switch.get(), Body.get());
}
@@ -1274,13 +1318,13 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) {
// Parse the condition.
ExprResult Cond;
- Decl *CondVar = 0;
+ Decl *CondVar = nullptr;
if (ParseParenExprOrCondition(Cond, CondVar, WhileLoc, true))
return StmtError();
FullExprArg FullCond(Actions.MakeFullExpr(Cond.get(), WhileLoc));
- // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
+ // C99 6.8.5p5 - In C99, the body of the while statement is a scope, even if
// there is no compound stmt. C90 does not have this clause. We only do this
// if the body isn't a compound statement to avoid push/pop in common cases.
//
@@ -1291,8 +1335,7 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) {
// See comments in ParseIfStatement for why we create a scope for the
// condition and a new scope for substatement in C++.
//
- ParseScope InnerScope(this, Scope::DeclScope,
- C99orCXX && Tok.isNot(tok::l_brace));
+ ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
// Read the body statement.
StmtResult Body(ParseStatement(TrailingElseLoc));
@@ -1325,7 +1368,7 @@ StmtResult Parser::ParseDoStatement() {
ParseScope DoScope(this, ScopeFlags);
- // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
+ // C99 6.8.5p5 - In C99, the body of the do statement is a scope, even if
// there is no compound stmt. C90 does not have this clause. We only do this
// if the body isn't a compound statement to avoid push/pop in common cases.
//
@@ -1333,9 +1376,8 @@ StmtResult Parser::ParseDoStatement() {
// The substatement in an iteration-statement implicitly defines a local scope
// which is entered and exited each time through the loop.
//
- ParseScope InnerScope(this, Scope::DeclScope,
- (getLangOpts().C99 || getLangOpts().CPlusPlus) &&
- Tok.isNot(tok::l_brace));
+ bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus;
+ ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
// Read the body statement.
StmtResult Body(ParseStatement());
@@ -1346,7 +1388,7 @@ StmtResult Parser::ParseDoStatement() {
if (Tok.isNot(tok::kw_while)) {
if (!Body.isInvalid()) {
Diag(Tok, diag::err_expected_while);
- Diag(DoLoc, diag::note_matching) << "do";
+ Diag(DoLoc, diag::note_matching) << "'do'";
SkipUntil(tok::semi, StopBeforeMatch);
}
return StmtError();
@@ -1377,6 +1419,25 @@ StmtResult Parser::ParseDoStatement() {
Cond.get(), T.getCloseLocation());
}
+bool Parser::isForRangeIdentifier() {
+ assert(Tok.is(tok::identifier));
+
+ const Token &Next = NextToken();
+ if (Next.is(tok::colon))
+ return true;
+
+ if (Next.is(tok::l_square) || Next.is(tok::kw_alignas)) {
+ TentativeParsingAction PA(*this);
+ ConsumeToken();
+ SkipCXX11Attributes();
+ bool Result = Tok.is(tok::colon);
+ PA.Revert();
+ return Result;
+ }
+
+ return false;
+}
+
/// ParseForStatement
/// for-statement: [C99 6.8.5.3]
/// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement
@@ -1424,12 +1485,9 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
// Names declared in the for-init-statement are in the same declarative-region
// as those declared in the condition.
//
- unsigned ScopeFlags;
+ unsigned ScopeFlags = 0;
if (C99orCXXorObjC)
- ScopeFlags = Scope::BreakScope | Scope::ContinueScope |
- Scope::DeclScope | Scope::ControlScope;
- else
- ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
+ ScopeFlags = Scope::DeclScope | Scope::ControlScope;
ParseScope ForScope(this, ScopeFlags);
@@ -1445,7 +1503,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
ExprResult Collection;
ForRangeInit ForRangeInit;
FullExprArg ThirdPart(Actions);
- Decl *SecondVar = 0;
+ Decl *SecondVar = nullptr;
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteOrdinaryName(getCurScope(),
@@ -1463,6 +1521,29 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
ProhibitAttributes(attrs);
// no first part, eat the ';'.
ConsumeToken();
+ } else if (getLangOpts().CPlusPlus && Tok.is(tok::identifier) &&
+ isForRangeIdentifier()) {
+ ProhibitAttributes(attrs);
+ IdentifierInfo *Name = Tok.getIdentifierInfo();
+ SourceLocation Loc = ConsumeToken();
+ MaybeParseCXX11Attributes(attrs);
+
+ ForRangeInit.ColonLoc = ConsumeToken();
+ if (Tok.is(tok::l_brace))
+ ForRangeInit.RangeExpr = ParseBraceInitializer();
+ else
+ ForRangeInit.RangeExpr = ParseExpression();
+
+ Diag(Loc, getLangOpts().CPlusPlus1z
+ ? diag::warn_cxx1y_compat_for_range_identifier
+ : diag::ext_for_range_identifier)
+ << ((getLangOpts().CPlusPlus11 && !getLangOpts().CPlusPlus1z)
+ ? FixItHint::CreateInsertion(Loc, "auto &&")
+ : FixItHint());
+
+ FirstPart = Actions.ActOnCXXForRangeIdentifier(getCurScope(), Loc, Name,
+ attrs, attrs.Range.getEnd());
+ ForRange = true;
} else if (isForInitDeclaration()) { // for (int X = 4;
// Parse declaration, which eats the ';'.
if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode?
@@ -1474,12 +1555,10 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
StmtVector Stmts;
- DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext,
- DeclEnd, attrs, false,
- MightBeForRangeStmt ?
- &ForRangeInit : 0);
+ DeclGroupPtrTy DG = ParseSimpleDeclaration(
+ Stmts, Declarator::ForContext, DeclEnd, attrs, false,
+ MightBeForRangeStmt ? &ForRangeInit : nullptr);
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
-
if (ForRangeInit.ParsedForRangeDecl()) {
Diag(ForRangeInit.ColonLoc, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_for_range : diag::ext_for_range);
@@ -1544,6 +1623,9 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
}
}
}
+
+ // Parse the second part of the for specifier.
+ getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope);
if (!ForEach && !ForRange) {
assert(!SecondPart.get() && "Shouldn't have a second expression yet.");
// Parse the second part of the for specifier.
@@ -1582,7 +1664,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
ExprResult Third = ParseExpression();
// FIXME: The C++11 standard doesn't actually say that this is a
// discarded-value expression, but it clearly should be.
- ThirdPart = Actions.MakeFullDiscardedValueExpr(Third.take());
+ ThirdPart = Actions.MakeFullDiscardedValueExpr(Third.get());
}
}
// Match the ')'.
@@ -1595,7 +1677,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
StmtResult ForEachStmt;
if (ForRange) {
- ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, FirstPart.take(),
+ ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, FirstPart.get(),
ForRangeInit.ColonLoc,
ForRangeInit.RangeExpr.get(),
T.getCloseLocation(),
@@ -1606,12 +1688,12 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
// statement immediately in order to close over temporaries correctly.
} else if (ForEach) {
ForEachStmt = Actions.ActOnObjCForCollectionStmt(ForLoc,
- FirstPart.take(),
- Collection.take(),
+ FirstPart.get(),
+ Collection.get(),
T.getCloseLocation());
}
- // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
+ // C99 6.8.5p5 - In C99, the body of the for statement is a scope, even if
// there is no compound stmt. C90 does not have this clause. We only do this
// if the body isn't a compound statement to avoid push/pop in common cases.
//
@@ -1622,8 +1704,15 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
// See comments in ParseIfStatement for why we create a scope for
// for-init-statement/condition and a new scope for substatement in C++.
//
- ParseScope InnerScope(this, Scope::DeclScope,
- C99orCXXorObjC && Tok.isNot(tok::l_brace));
+ ParseScope InnerScope(this, Scope::DeclScope, C99orCXXorObjC,
+ Tok.is(tok::l_brace));
+
+ // The body of the for loop has the same local mangling number as the
+ // for-init-statement.
+ // It will only be incremented if the body contains other things that would
+ // normally increment the mangling number (like a compound statement).
+ if (C99orCXXorObjC)
+ getCurScope()->decrementMSLocalManglingNumber();
// Read the body statement.
StmtResult Body(ParseStatement(TrailingElseLoc));
@@ -1638,15 +1727,15 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
return StmtError();
if (ForEach)
- return Actions.FinishObjCForCollectionStmt(ForEachStmt.take(),
- Body.take());
+ return Actions.FinishObjCForCollectionStmt(ForEachStmt.get(),
+ Body.get());
if (ForRange)
- return Actions.FinishCXXForRangeStmt(ForRangeStmt.take(), Body.take());
+ return Actions.FinishCXXForRangeStmt(ForRangeStmt.get(), Body.get());
- return Actions.ActOnForStmt(ForLoc, T.getOpenLocation(), FirstPart.take(),
+ return Actions.ActOnForStmt(ForLoc, T.getOpenLocation(), FirstPart.get(),
SecondPart, SecondVar, ThirdPart,
- T.getCloseLocation(), Body.take());
+ T.getCloseLocation(), Body.get());
}
/// ParseGotoStatement
@@ -1675,9 +1764,9 @@ StmtResult Parser::ParseGotoStatement() {
SkipUntil(tok::semi, StopBeforeMatch);
return StmtError();
}
- Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, R.take());
+ Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, R.get());
} else {
- Diag(Tok, diag::err_expected_ident);
+ Diag(Tok, diag::err_expected) << tok::identifier;
return StmtError();
}
@@ -1730,713 +1819,40 @@ StmtResult Parser::ParseReturnStatement() {
<< R.get()->getSourceRange();
} else
R = ParseExpression();
- if (R.isInvalid()) { // Skip to the semicolon, but don't consume it.
- SkipUntil(tok::semi, StopBeforeMatch);
+ if (R.isInvalid()) {
+ SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
return StmtError();
}
}
- return Actions.ActOnReturnStmt(ReturnLoc, R.take());
-}
-
-namespace {
- class ClangAsmParserCallback : public llvm::MCAsmParserSemaCallback {
- Parser &TheParser;
- SourceLocation AsmLoc;
- StringRef AsmString;
-
- /// The tokens we streamed into AsmString and handed off to MC.
- ArrayRef<Token> AsmToks;
-
- /// The offset of each token in AsmToks within AsmString.
- ArrayRef<unsigned> AsmTokOffsets;
-
- public:
- ClangAsmParserCallback(Parser &P, SourceLocation Loc,
- StringRef AsmString,
- ArrayRef<Token> Toks,
- ArrayRef<unsigned> Offsets)
- : TheParser(P), AsmLoc(Loc), AsmString(AsmString),
- AsmToks(Toks), AsmTokOffsets(Offsets) {
- assert(AsmToks.size() == AsmTokOffsets.size());
- }
-
- void *LookupInlineAsmIdentifier(StringRef &LineBuf,
- InlineAsmIdentifierInfo &Info,
- bool IsUnevaluatedContext) {
- // Collect the desired tokens.
- SmallVector<Token, 16> LineToks;
- const Token *FirstOrigToken = 0;
- findTokensForString(LineBuf, LineToks, FirstOrigToken);
-
- unsigned NumConsumedToks;
- ExprResult Result =
- TheParser.ParseMSAsmIdentifier(LineToks, NumConsumedToks, &Info,
- IsUnevaluatedContext);
-
- // If we consumed the entire line, tell MC that.
- // Also do this if we consumed nothing as a way of reporting failure.
- if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) {
- // By not modifying LineBuf, we're implicitly consuming it all.
-
- // Otherwise, consume up to the original tokens.
- } else {
- assert(FirstOrigToken && "not using original tokens?");
-
- // Since we're using original tokens, apply that offset.
- assert(FirstOrigToken[NumConsumedToks].getLocation()
- == LineToks[NumConsumedToks].getLocation());
- unsigned FirstIndex = FirstOrigToken - AsmToks.begin();
- unsigned LastIndex = FirstIndex + NumConsumedToks - 1;
-
- // The total length we've consumed is the relative offset
- // of the last token we consumed plus its length.
- unsigned TotalOffset = (AsmTokOffsets[LastIndex]
- + AsmToks[LastIndex].getLength()
- - AsmTokOffsets[FirstIndex]);
- LineBuf = LineBuf.substr(0, TotalOffset);
- }
-
- // Initialize the "decl" with the lookup result.
- Info.OpDecl = static_cast<void*>(Result.take());
- return Info.OpDecl;
- }
-
- bool LookupInlineAsmField(StringRef Base, StringRef Member,
- unsigned &Offset) {
- return TheParser.getActions().LookupInlineAsmField(Base, Member,
- Offset, AsmLoc);
- }
-
- static void DiagHandlerCallback(const llvm::SMDiagnostic &D,
- void *Context) {
- ((ClangAsmParserCallback*) Context)->handleDiagnostic(D);
- }
-
- private:
- /// Collect the appropriate tokens for the given string.
- void findTokensForString(StringRef Str, SmallVectorImpl<Token> &TempToks,
- const Token *&FirstOrigToken) const {
- // For now, assert that the string we're working with is a substring
- // of what we gave to MC. This lets us use the original tokens.
- assert(!std::less<const char*>()(Str.begin(), AsmString.begin()) &&
- !std::less<const char*>()(AsmString.end(), Str.end()));
-
- // Try to find a token whose offset matches the first token.
- unsigned FirstCharOffset = Str.begin() - AsmString.begin();
- const unsigned *FirstTokOffset
- = std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(),
- FirstCharOffset);
-
- // For now, assert that the start of the string exactly
- // corresponds to the start of a token.
- assert(*FirstTokOffset == FirstCharOffset);
-
- // Use all the original tokens for this line. (We assume the
- // end of the line corresponds cleanly to a token break.)
- unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin();
- FirstOrigToken = &AsmToks[FirstTokIndex];
- unsigned LastCharOffset = Str.end() - AsmString.begin();
- for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) {
- if (AsmTokOffsets[i] >= LastCharOffset) break;
- TempToks.push_back(AsmToks[i]);
- }
- }
-
- void handleDiagnostic(const llvm::SMDiagnostic &D) {
- // Compute an offset into the inline asm buffer.
- // FIXME: This isn't right if .macro is involved (but hopefully, no
- // real-world code does that).
- const llvm::SourceMgr &LSM = *D.getSourceMgr();
- const llvm::MemoryBuffer *LBuf =
- LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
- unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
-
- // Figure out which token that offset points into.
- const unsigned *TokOffsetPtr =
- std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset);
- unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin();
- unsigned TokOffset = *TokOffsetPtr;
-
- // If we come up with an answer which seems sane, use it; otherwise,
- // just point at the __asm keyword.
- // FIXME: Assert the answer is sane once we handle .macro correctly.
- SourceLocation Loc = AsmLoc;
- if (TokIndex < AsmToks.size()) {
- const Token &Tok = AsmToks[TokIndex];
- Loc = Tok.getLocation();
- Loc = Loc.getLocWithOffset(Offset - TokOffset);
- }
- TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing)
- << D.getMessage();
- }
- };
-}
-
-/// Parse an identifier in an MS-style inline assembly block.
-///
-/// \param CastInfo - a void* so that we don't have to teach Parser.h
-/// about the actual type.
-ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
- unsigned &NumLineToksConsumed,
- void *CastInfo,
- bool IsUnevaluatedContext) {
- llvm::InlineAsmIdentifierInfo &Info =
- *(llvm::InlineAsmIdentifierInfo *) CastInfo;
-
- // Push a fake token on the end so that we don't overrun the token
- // stream. We use ';' because it expression-parsing should never
- // overrun it.
- const tok::TokenKind EndOfStream = tok::semi;
- Token EndOfStreamTok;
- EndOfStreamTok.startToken();
- EndOfStreamTok.setKind(EndOfStream);
- LineToks.push_back(EndOfStreamTok);
-
- // Also copy the current token over.
- LineToks.push_back(Tok);
-
- PP.EnterTokenStream(LineToks.begin(),
- LineToks.size(),
- /*disable macros*/ true,
- /*owns tokens*/ false);
-
- // Clear the current token and advance to the first token in LineToks.
- ConsumeAnyToken();
-
- // Parse an optional scope-specifier if we're in C++.
- CXXScopeSpec SS;
- if (getLangOpts().CPlusPlus) {
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
- }
-
- // Require an identifier here.
- SourceLocation TemplateKWLoc;
- UnqualifiedId Id;
- bool Invalid = ParseUnqualifiedId(SS,
- /*EnteringContext=*/false,
- /*AllowDestructorName=*/false,
- /*AllowConstructorName=*/false,
- /*ObjectType=*/ ParsedType(),
- TemplateKWLoc,
- Id);
-
- // If we've run into the poison token we inserted before, or there
- // was a parsing error, then claim the entire line.
- if (Invalid || Tok.is(EndOfStream)) {
- NumLineToksConsumed = LineToks.size() - 2;
-
- // Otherwise, claim up to the start of the next token.
- } else {
- // Figure out how many tokens we are into LineToks.
- unsigned LineIndex = 0;
- while (LineToks[LineIndex].getLocation() != Tok.getLocation()) {
- LineIndex++;
- assert(LineIndex < LineToks.size() - 2); // we added two extra tokens
- }
-
- NumLineToksConsumed = LineIndex;
- }
-
- // Finally, restore the old parsing state by consuming all the
- // tokens we staged before, implicitly killing off the
- // token-lexer we pushed.
- for (unsigned n = LineToks.size() - 2 - NumLineToksConsumed; n != 0; --n) {
- ConsumeAnyToken();
- }
- ConsumeToken(EndOfStream);
-
- // Leave LineToks in its original state.
- LineToks.pop_back();
- LineToks.pop_back();
-
- // Perform the lookup.
- return Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info,
- IsUnevaluatedContext);
+ return Actions.ActOnReturnStmt(ReturnLoc, R.get(), getCurScope());
}
-/// Turn a sequence of our tokens back into a string that we can hand
-/// to the MC asm parser.
-static bool buildMSAsmString(Preprocessor &PP,
- SourceLocation AsmLoc,
- ArrayRef<Token> AsmToks,
- SmallVectorImpl<unsigned> &TokOffsets,
- SmallString<512> &Asm) {
- assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
-
- // Is this the start of a new assembly statement?
- bool isNewStatement = true;
-
- for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
- const Token &Tok = AsmToks[i];
-
- // Start each new statement with a newline and a tab.
- if (!isNewStatement &&
- (Tok.is(tok::kw_asm) || Tok.isAtStartOfLine())) {
- Asm += "\n\t";
- isNewStatement = true;
- }
-
- // Preserve the existence of leading whitespace except at the
- // start of a statement.
- if (!isNewStatement && Tok.hasLeadingSpace())
- Asm += ' ';
+StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, bool OnlyStatement,
+ SourceLocation *TrailingElseLoc,
+ ParsedAttributesWithRange &Attrs) {
+ // Create temporary attribute list.
+ ParsedAttributesWithRange TempAttrs(AttrFactory);
- // Remember the offset of this token.
- TokOffsets.push_back(Asm.size());
-
- // Don't actually write '__asm' into the assembly stream.
- if (Tok.is(tok::kw_asm)) {
- // Complain about __asm at the end of the stream.
- if (i + 1 == e) {
- PP.Diag(AsmLoc, diag::err_asm_empty);
- return true;
- }
-
- continue;
- }
-
- // Append the spelling of the token.
- SmallString<32> SpellingBuffer;
- bool SpellingInvalid = false;
- Asm += PP.getSpelling(Tok, SpellingBuffer, &SpellingInvalid);
- assert(!SpellingInvalid && "spelling was invalid after correct parse?");
-
- // We are no longer at the start of a statement.
- isNewStatement = false;
- }
-
- // Ensure that the buffer is null-terminated.
- Asm.push_back('\0');
- Asm.pop_back();
-
- assert(TokOffsets.size() == AsmToks.size());
- return false;
-}
-
-/// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled,
-/// this routine is called to collect the tokens for an MS asm statement.
-///
-/// [MS] ms-asm-statement:
-/// ms-asm-block
-/// ms-asm-block ms-asm-statement
-///
-/// [MS] ms-asm-block:
-/// '__asm' ms-asm-line '\n'
-/// '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt]
-///
-/// [MS] ms-asm-instruction-block
-/// ms-asm-line
-/// ms-asm-line '\n' ms-asm-instruction-block
-///
-StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
- SourceManager &SrcMgr = PP.getSourceManager();
- SourceLocation EndLoc = AsmLoc;
- SmallVector<Token, 4> AsmToks;
-
- bool InBraces = false;
- unsigned short savedBraceCount = 0;
- bool InAsmComment = false;
- FileID FID;
- unsigned LineNo = 0;
- unsigned NumTokensRead = 0;
- SourceLocation LBraceLoc;
-
- if (Tok.is(tok::l_brace)) {
- // Braced inline asm: consume the opening brace.
- InBraces = true;
- savedBraceCount = BraceCount;
- EndLoc = LBraceLoc = ConsumeBrace();
- ++NumTokensRead;
- } else {
- // Single-line inline asm; compute which line it is on.
- std::pair<FileID, unsigned> ExpAsmLoc =
- SrcMgr.getDecomposedExpansionLoc(EndLoc);
- FID = ExpAsmLoc.first;
- LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second);
- }
-
- SourceLocation TokLoc = Tok.getLocation();
- do {
- // If we hit EOF, we're done, period.
- if (Tok.is(tok::eof))
- break;
-
- if (!InAsmComment && Tok.is(tok::semi)) {
- // A semicolon in an asm is the start of a comment.
- InAsmComment = true;
- if (InBraces) {
- // Compute which line the comment is on.
- std::pair<FileID, unsigned> ExpSemiLoc =
- SrcMgr.getDecomposedExpansionLoc(TokLoc);
- FID = ExpSemiLoc.first;
- LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second);
- }
- } else if (!InBraces || InAsmComment) {
- // If end-of-line is significant, check whether this token is on a
- // new line.
- std::pair<FileID, unsigned> ExpLoc =
- SrcMgr.getDecomposedExpansionLoc(TokLoc);
- if (ExpLoc.first != FID ||
- SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) {
- // If this is a single-line __asm, we're done.
- if (!InBraces)
- break;
- // We're no longer in a comment.
- InAsmComment = false;
- } else if (!InAsmComment && Tok.is(tok::r_brace)) {
- // Single-line asm always ends when a closing brace is seen.
- // FIXME: This is compatible with Apple gcc's -fasm-blocks; what
- // does MSVC do here?
- break;
- }
- }
- if (!InAsmComment && InBraces && Tok.is(tok::r_brace) &&
- BraceCount == (savedBraceCount + 1)) {
- // Consume the closing brace, and finish
- EndLoc = ConsumeBrace();
- break;
- }
-
- // Consume the next token; make sure we don't modify the brace count etc.
- // if we are in a comment.
- EndLoc = TokLoc;
- if (InAsmComment)
- PP.Lex(Tok);
- else {
- AsmToks.push_back(Tok);
- ConsumeAnyToken();
- }
- TokLoc = Tok.getLocation();
- ++NumTokensRead;
- } while (1);
-
- if (InBraces && BraceCount != savedBraceCount) {
- // __asm without closing brace (this can happen at EOF).
- Diag(Tok, diag::err_expected_rbrace);
- Diag(LBraceLoc, diag::note_matching) << "{";
- return StmtError();
- } else if (NumTokensRead == 0) {
- // Empty __asm.
- Diag(Tok, diag::err_expected_lbrace);
- return StmtError();
- }
-
- // Okay, prepare to use MC to parse the assembly.
- SmallVector<StringRef, 4> ConstraintRefs;
- SmallVector<Expr*, 4> Exprs;
- SmallVector<StringRef, 4> ClobberRefs;
-
- // We need an actual supported target.
- llvm::Triple TheTriple = Actions.Context.getTargetInfo().getTriple();
- llvm::Triple::ArchType ArchTy = TheTriple.getArch();
- const std::string &TT = TheTriple.getTriple();
- const llvm::Target *TheTarget = 0;
- bool UnsupportedArch = (ArchTy != llvm::Triple::x86 &&
- ArchTy != llvm::Triple::x86_64);
- if (UnsupportedArch) {
- Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();
- } else {
- std::string Error;
- TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error);
- if (!TheTarget)
- Diag(AsmLoc, diag::err_msasm_unable_to_create_target) << Error;
- }
-
- // If we don't support assembly, or the assembly is empty, we don't
- // need to instantiate the AsmParser, etc.
- if (!TheTarget || AsmToks.empty()) {
- return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, StringRef(),
- /*NumOutputs*/ 0, /*NumInputs*/ 0,
- ConstraintRefs, ClobberRefs, Exprs, EndLoc);
- }
-
- // Expand the tokens into a string buffer.
- SmallString<512> AsmString;
- SmallVector<unsigned, 8> TokOffsets;
- if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString))
- return StmtError();
-
- OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
- OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT));
- // Get the instruction descriptor.
- const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo();
- OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
- OwningPtr<llvm::MCSubtargetInfo>
- STI(TheTarget->createMCSubtargetInfo(TT, "", ""));
-
- llvm::SourceMgr TempSrcMgr;
- llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr);
- llvm::MemoryBuffer *Buffer =
- llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>");
-
- // Tell SrcMgr about this buffer, which is what the parser will pick up.
- TempSrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
-
- OwningPtr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
- OwningPtr<llvm::MCAsmParser>
- Parser(createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI));
- OwningPtr<llvm::MCTargetAsmParser>
- TargetParser(TheTarget->createMCAsmParser(*STI, *Parser, *MII));
-
- llvm::MCInstPrinter *IP =
- TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI);
-
- // Change to the Intel dialect.
- Parser->setAssemblerDialect(1);
- Parser->setTargetParser(*TargetParser.get());
- Parser->setParsingInlineAsm(true);
- TargetParser->setParsingInlineAsm(true);
-
- ClangAsmParserCallback Callback(*this, AsmLoc, AsmString,
- AsmToks, TokOffsets);
- TargetParser->setSemaCallback(&Callback);
- TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback,
- &Callback);
-
- unsigned NumOutputs;
- unsigned NumInputs;
- std::string AsmStringIR;
- SmallVector<std::pair<void *, bool>, 4> OpExprs;
- SmallVector<std::string, 4> Constraints;
- SmallVector<std::string, 4> Clobbers;
- if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR,
- NumOutputs, NumInputs, OpExprs, Constraints,
- Clobbers, MII, IP, Callback))
- return StmtError();
-
- // Build the vector of clobber StringRefs.
- unsigned NumClobbers = Clobbers.size();
- ClobberRefs.resize(NumClobbers);
- for (unsigned i = 0; i != NumClobbers; ++i)
- ClobberRefs[i] = StringRef(Clobbers[i]);
-
- // Recast the void pointers and build the vector of constraint StringRefs.
- unsigned NumExprs = NumOutputs + NumInputs;
- ConstraintRefs.resize(NumExprs);
- Exprs.resize(NumExprs);
- for (unsigned i = 0, e = NumExprs; i != e; ++i) {
- Expr *OpExpr = static_cast<Expr *>(OpExprs[i].first);
- if (!OpExpr)
- return StmtError();
-
- // Need address of variable.
- if (OpExprs[i].second)
- OpExpr = Actions.BuildUnaryOp(getCurScope(), AsmLoc, UO_AddrOf, OpExpr)
- .take();
-
- ConstraintRefs[i] = StringRef(Constraints[i]);
- Exprs[i] = OpExpr;
- }
-
- // FIXME: We should be passing source locations for better diagnostics.
- return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, AsmStringIR,
- NumOutputs, NumInputs,
- ConstraintRefs, ClobberRefs, Exprs, EndLoc);
-}
-
-/// ParseAsmStatement - Parse a GNU extended asm statement.
-/// asm-statement:
-/// gnu-asm-statement
-/// ms-asm-statement
-///
-/// [GNU] gnu-asm-statement:
-/// 'asm' type-qualifier[opt] '(' asm-argument ')' ';'
-///
-/// [GNU] asm-argument:
-/// asm-string-literal
-/// asm-string-literal ':' asm-operands[opt]
-/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
-/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
-/// ':' asm-clobbers
-///
-/// [GNU] asm-clobbers:
-/// asm-string-literal
-/// asm-clobbers ',' asm-string-literal
-///
-StmtResult Parser::ParseAsmStatement(bool &msAsm) {
- assert(Tok.is(tok::kw_asm) && "Not an asm stmt");
- SourceLocation AsmLoc = ConsumeToken();
-
- if (getLangOpts().AsmBlocks && Tok.isNot(tok::l_paren) &&
- !isTypeQualifier()) {
- msAsm = true;
- return ParseMicrosoftAsmStatement(AsmLoc);
- }
- DeclSpec DS(AttrFactory);
- SourceLocation Loc = Tok.getLocation();
- ParseTypeQualifierListOpt(DS, true, false);
-
- // GNU asms accept, but warn, about type-qualifiers other than volatile.
- if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
- Diag(Loc, diag::w_asm_qualifier_ignored) << "const";
- if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
- Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict";
- // FIXME: Once GCC supports _Atomic, check whether it permits it here.
- if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
- Diag(Loc, diag::w_asm_qualifier_ignored) << "_Atomic";
-
- // Remember if this was a volatile asm.
- bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile;
- if (Tok.isNot(tok::l_paren)) {
- Diag(Tok, diag::err_expected_lparen_after) << "asm";
- SkipUntil(tok::r_paren, StopAtSemi);
- return StmtError();
- }
- BalancedDelimiterTracker T(*this, tok::l_paren);
- T.consumeOpen();
-
- ExprResult AsmString(ParseAsmStringLiteral());
- if (AsmString.isInvalid()) {
- // Consume up to and including the closing paren.
- T.skipToEnd();
- return StmtError();
- }
-
- SmallVector<IdentifierInfo *, 4> Names;
- ExprVector Constraints;
- ExprVector Exprs;
- ExprVector Clobbers;
-
- if (Tok.is(tok::r_paren)) {
- // We have a simple asm expression like 'asm("foo")'.
- T.consumeClose();
- return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,
- /*NumOutputs*/ 0, /*NumInputs*/ 0, 0,
- Constraints, Exprs, AsmString.take(),
- Clobbers, T.getCloseLocation());
- }
-
- // Parse Outputs, if present.
- bool AteExtraColon = false;
- if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
- // In C++ mode, parse "::" like ": :".
- AteExtraColon = Tok.is(tok::coloncolon);
+ // Get loop hints and consume annotated token.
+ while (Tok.is(tok::annot_pragma_loop_hint)) {
+ LoopHint Hint = HandlePragmaLoopHint();
ConsumeToken();
- if (!AteExtraColon &&
- ParseAsmOperandsOpt(Names, Constraints, Exprs))
- return StmtError();
+ ArgsUnion ArgHints[] = {Hint.PragmaNameLoc, Hint.OptionLoc, Hint.ValueLoc,
+ ArgsUnion(Hint.ValueExpr)};
+ TempAttrs.addNew(Hint.PragmaNameLoc->Ident, Hint.Range, nullptr,
+ Hint.PragmaNameLoc->Loc, ArgHints, 4,
+ AttributeList::AS_Pragma);
}
- unsigned NumOutputs = Names.size();
-
- // Parse Inputs, if present.
- if (AteExtraColon ||
- Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
- // In C++ mode, parse "::" like ": :".
- if (AteExtraColon)
- AteExtraColon = false;
- else {
- AteExtraColon = Tok.is(tok::coloncolon);
- ConsumeToken();
- }
+ // Get the next statement.
+ MaybeParseCXX11Attributes(Attrs);
- if (!AteExtraColon &&
- ParseAsmOperandsOpt(Names, Constraints, Exprs))
- return StmtError();
- }
-
- assert(Names.size() == Constraints.size() &&
- Constraints.size() == Exprs.size() &&
- "Input operand size mismatch!");
-
- unsigned NumInputs = Names.size() - NumOutputs;
-
- // Parse the clobbers, if present.
- if (AteExtraColon || Tok.is(tok::colon)) {
- if (!AteExtraColon)
- ConsumeToken();
-
- // Parse the asm-string list for clobbers if present.
- if (Tok.isNot(tok::r_paren)) {
- while (1) {
- ExprResult Clobber(ParseAsmStringLiteral());
-
- if (Clobber.isInvalid())
- break;
-
- Clobbers.push_back(Clobber.release());
-
- if (Tok.isNot(tok::comma)) break;
- ConsumeToken();
- }
- }
- }
+ StmtResult S = ParseStatementOrDeclarationAfterAttributes(
+ Stmts, OnlyStatement, TrailingElseLoc, Attrs);
- T.consumeClose();
- return Actions.ActOnGCCAsmStmt(AsmLoc, false, isVolatile, NumOutputs,
- NumInputs, Names.data(), Constraints, Exprs,
- AsmString.take(), Clobbers,
- T.getCloseLocation());
-}
-
-/// ParseAsmOperands - Parse the asm-operands production as used by
-/// asm-statement, assuming the leading ':' token was eaten.
-///
-/// [GNU] asm-operands:
-/// asm-operand
-/// asm-operands ',' asm-operand
-///
-/// [GNU] asm-operand:
-/// asm-string-literal '(' expression ')'
-/// '[' identifier ']' asm-string-literal '(' expression ')'
-///
-//
-// FIXME: Avoid unnecessary std::string trashing.
-bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
- SmallVectorImpl<Expr *> &Constraints,
- SmallVectorImpl<Expr *> &Exprs) {
- // 'asm-operands' isn't present?
- if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))
- return false;
-
- while (1) {
- // Read the [id] if present.
- if (Tok.is(tok::l_square)) {
- BalancedDelimiterTracker T(*this, tok::l_square);
- T.consumeOpen();
-
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected_ident);
- SkipUntil(tok::r_paren, StopAtSemi);
- return true;
- }
-
- IdentifierInfo *II = Tok.getIdentifierInfo();
- ConsumeToken();
-
- Names.push_back(II);
- T.consumeClose();
- } else
- Names.push_back(0);
-
- ExprResult Constraint(ParseAsmStringLiteral());
- if (Constraint.isInvalid()) {
- SkipUntil(tok::r_paren, StopAtSemi);
- return true;
- }
- Constraints.push_back(Constraint.release());
-
- if (Tok.isNot(tok::l_paren)) {
- Diag(Tok, diag::err_expected_lparen_after) << "asm operand";
- SkipUntil(tok::r_paren, StopAtSemi);
- return true;
- }
-
- // Read the parenthesized expression.
- BalancedDelimiterTracker T(*this, tok::l_paren);
- T.consumeOpen();
- ExprResult Res(ParseExpression());
- T.consumeClose();
- if (Res.isInvalid()) {
- SkipUntil(tok::r_paren, StopAtSemi);
- return true;
- }
- Exprs.push_back(Res.release());
- // Eat the comma and continue parsing if it exists.
- if (Tok.isNot(tok::comma)) return false;
- ConsumeToken();
- }
+ Attrs.takeAllFrom(TempAttrs);
+ return S;
}
Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
@@ -2464,7 +1880,7 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
}
BodyScope.Exit();
- return Actions.ActOnFinishFunctionBody(Decl, FnBody.take());
+ return Actions.ActOnFinishFunctionBody(Decl, FnBody.get());
}
/// ParseFunctionTryBlock - Parse a C++ function-try-block.
@@ -2501,7 +1917,7 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) {
}
BodyScope.Exit();
- return Actions.ActOnFinishFunctionBody(Decl, FnBody.take());
+ return Actions.ActOnFinishFunctionBody(Decl, FnBody.get());
}
bool Parser::trySkippingFunctionBody() {
@@ -2554,16 +1970,28 @@ StmtResult Parser::ParseCXXTryBlock() {
///
/// [Borland] try-block:
/// 'try' compound-statement seh-except-block
-/// 'try' compound-statment seh-finally-block
+/// 'try' compound-statement seh-finally-block
///
StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
if (Tok.isNot(tok::l_brace))
- return StmtError(Diag(Tok, diag::err_expected_lbrace));
+ return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
// FIXME: Possible draft standard bug: attribute-specifier should be allowed?
- StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false,
- Scope::DeclScope | Scope::TryScope |
- (FnTry ? Scope::FnTryCatchScope : 0)));
+ int SEHTryIndex, SEHTryParentIndex;
+ StmtResult TryBlock;
+ {
+ 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 | Scope::TryScope |
+ (FnTry ? Scope::FnTryCatchScope : 0));
+ SEHTryIndex = getCurScope()->getSEHTryIndex();
+ SEHTryParentIndex = getCurScope()->getSEHTryParentIndex();
+
+ // Parse the statements in the body.
+ TryBlock = ParseCompoundStatementBody();
+ }
if (TryBlock.isInvalid())
return TryBlock;
@@ -2587,8 +2015,10 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
return Actions.ActOnSEHTryBlock(true /* IsCXXTry */,
TryLoc,
- TryBlock.take(),
- Handler.take());
+ TryBlock.get(),
+ Handler.get(),
+ SEHTryIndex,
+ SEHTryParentIndex);
}
else {
StmtVector Handlers;
@@ -2602,14 +2032,14 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
while (Tok.is(tok::kw_catch)) {
StmtResult Handler(ParseCXXCatchBlock(FnTry));
if (!Handler.isInvalid())
- Handlers.push_back(Handler.release());
+ Handlers.push_back(Handler.get());
}
// Don't bother creating the full statement if we don't have any usable
// handlers.
if (Handlers.empty())
return StmtError();
- return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(), Handlers);
+ return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.get(), Handlers);
}
}
@@ -2629,7 +2059,7 @@ StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
SourceLocation CatchLoc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
- if (T.expectAndConsume(diag::err_expected_lparen))
+ if (T.expectAndConsume())
return StmtError();
// C++ 3.3.2p3:
@@ -2640,7 +2070,7 @@ StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
// exception-declaration is equivalent to '...' or a parameter-declaration
// without default arguments.
- Decl *ExceptionDecl = 0;
+ Decl *ExceptionDecl = nullptr;
if (Tok.isNot(tok::ellipsis)) {
ParsedAttributesWithRange Attributes(AttrFactory);
MaybeParseCXX11Attributes(Attributes);
@@ -2662,14 +2092,14 @@ StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
return StmtError();
if (Tok.isNot(tok::l_brace))
- return StmtError(Diag(Tok, diag::err_expected_lbrace));
+ return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
// FIXME: Possible draft standard bug: attribute-specifier should be allowed?
StmtResult Block(ParseCompoundStatement());
if (Block.isInvalid())
return Block;
- return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, Block.take());
+ return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, Block.get());
}
void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) {
@@ -2683,7 +2113,7 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) {
// inside these braces escaping to the surrounding code.
if (Result.Behavior == IEB_Dependent) {
if (!Tok.is(tok::l_brace)) {
- Diag(Tok, diag::err_expected_lbrace);
+ Diag(Tok, diag::err_expected) << tok::l_brace;
return;
}
@@ -2703,7 +2133,7 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) {
BalancedDelimiterTracker Braces(*this, tok::l_brace);
if (Braces.consumeOpen()) {
- Diag(Tok, diag::err_expected_lbrace);
+ Diag(Tok, diag::err_expected) << tok::l_brace;
return;
}
@@ -2724,7 +2154,7 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) {
while (Tok.isNot(tok::r_brace)) {
StmtResult R = ParseStatementOrDeclaration(Stmts, false);
if (R.isUsable())
- Stmts.push_back(R.release());
+ Stmts.push_back(R.get());
}
Braces.consumeClose();
}
diff --git a/lib/Parse/ParseStmtAsm.cpp b/lib/Parse/ParseStmtAsm.cpp
new file mode 100644
index 000000000000..f7e8307883de
--- /dev/null
+++ b/lib/Parse/ParseStmtAsm.cpp
@@ -0,0 +1,761 @@
+//===---- ParseStmtAsm.cpp - Assembly Statement Parser --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements parsing for GCC and Microsoft inline assembly.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Parse/Parser.h"
+#include "RAIIObjectsForParser.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetAsmParser.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+using namespace clang;
+
+namespace {
+class ClangAsmParserCallback : public llvm::MCAsmParserSemaCallback {
+ Parser &TheParser;
+ SourceLocation AsmLoc;
+ StringRef AsmString;
+
+ /// The tokens we streamed into AsmString and handed off to MC.
+ ArrayRef<Token> AsmToks;
+
+ /// The offset of each token in AsmToks within AsmString.
+ ArrayRef<unsigned> AsmTokOffsets;
+
+public:
+ ClangAsmParserCallback(Parser &P, SourceLocation Loc, StringRef AsmString,
+ ArrayRef<Token> Toks, ArrayRef<unsigned> Offsets)
+ : TheParser(P), AsmLoc(Loc), AsmString(AsmString), AsmToks(Toks),
+ AsmTokOffsets(Offsets) {
+ assert(AsmToks.size() == AsmTokOffsets.size());
+ }
+
+ void *LookupInlineAsmIdentifier(StringRef &LineBuf,
+ llvm::InlineAsmIdentifierInfo &Info,
+ bool IsUnevaluatedContext) override {
+ // Collect the desired tokens.
+ SmallVector<Token, 16> LineToks;
+ const Token *FirstOrigToken = nullptr;
+ findTokensForString(LineBuf, LineToks, FirstOrigToken);
+
+ unsigned NumConsumedToks;
+ ExprResult Result = TheParser.ParseMSAsmIdentifier(
+ LineToks, NumConsumedToks, &Info, IsUnevaluatedContext);
+
+ // If we consumed the entire line, tell MC that.
+ // Also do this if we consumed nothing as a way of reporting failure.
+ if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) {
+ // By not modifying LineBuf, we're implicitly consuming it all.
+
+ // Otherwise, consume up to the original tokens.
+ } else {
+ assert(FirstOrigToken && "not using original tokens?");
+
+ // Since we're using original tokens, apply that offset.
+ assert(FirstOrigToken[NumConsumedToks].getLocation() ==
+ LineToks[NumConsumedToks].getLocation());
+ unsigned FirstIndex = FirstOrigToken - AsmToks.begin();
+ unsigned LastIndex = FirstIndex + NumConsumedToks - 1;
+
+ // The total length we've consumed is the relative offset
+ // of the last token we consumed plus its length.
+ unsigned TotalOffset =
+ (AsmTokOffsets[LastIndex] + AsmToks[LastIndex].getLength() -
+ AsmTokOffsets[FirstIndex]);
+ LineBuf = LineBuf.substr(0, TotalOffset);
+ }
+
+ // Initialize the "decl" with the lookup result.
+ Info.OpDecl = static_cast<void *>(Result.get());
+ return Info.OpDecl;
+ }
+
+ bool LookupInlineAsmField(StringRef Base, StringRef Member,
+ unsigned &Offset) override {
+ return TheParser.getActions().LookupInlineAsmField(Base, Member, Offset,
+ AsmLoc);
+ }
+
+ static void DiagHandlerCallback(const llvm::SMDiagnostic &D, void *Context) {
+ ((ClangAsmParserCallback *)Context)->handleDiagnostic(D);
+ }
+
+private:
+ /// Collect the appropriate tokens for the given string.
+ void findTokensForString(StringRef Str, SmallVectorImpl<Token> &TempToks,
+ const Token *&FirstOrigToken) const {
+ // For now, assert that the string we're working with is a substring
+ // of what we gave to MC. This lets us use the original tokens.
+ assert(!std::less<const char *>()(Str.begin(), AsmString.begin()) &&
+ !std::less<const char *>()(AsmString.end(), Str.end()));
+
+ // Try to find a token whose offset matches the first token.
+ unsigned FirstCharOffset = Str.begin() - AsmString.begin();
+ const unsigned *FirstTokOffset = std::lower_bound(
+ AsmTokOffsets.begin(), AsmTokOffsets.end(), FirstCharOffset);
+
+ // For now, assert that the start of the string exactly
+ // corresponds to the start of a token.
+ assert(*FirstTokOffset == FirstCharOffset);
+
+ // Use all the original tokens for this line. (We assume the
+ // end of the line corresponds cleanly to a token break.)
+ unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin();
+ FirstOrigToken = &AsmToks[FirstTokIndex];
+ unsigned LastCharOffset = Str.end() - AsmString.begin();
+ for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) {
+ if (AsmTokOffsets[i] >= LastCharOffset)
+ break;
+ TempToks.push_back(AsmToks[i]);
+ }
+ }
+
+ void handleDiagnostic(const llvm::SMDiagnostic &D) {
+ // Compute an offset into the inline asm buffer.
+ // FIXME: This isn't right if .macro is involved (but hopefully, no
+ // real-world code does that).
+ const llvm::SourceMgr &LSM = *D.getSourceMgr();
+ const llvm::MemoryBuffer *LBuf =
+ LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
+ unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
+
+ // Figure out which token that offset points into.
+ const unsigned *TokOffsetPtr =
+ std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset);
+ unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin();
+ unsigned TokOffset = *TokOffsetPtr;
+
+ // If we come up with an answer which seems sane, use it; otherwise,
+ // just point at the __asm keyword.
+ // FIXME: Assert the answer is sane once we handle .macro correctly.
+ SourceLocation Loc = AsmLoc;
+ if (TokIndex < AsmToks.size()) {
+ const Token &Tok = AsmToks[TokIndex];
+ Loc = Tok.getLocation();
+ Loc = Loc.getLocWithOffset(Offset - TokOffset);
+ }
+ TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
+ }
+};
+}
+
+/// Parse an identifier in an MS-style inline assembly block.
+///
+/// \param CastInfo - a void* so that we don't have to teach Parser.h
+/// about the actual type.
+ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
+ unsigned &NumLineToksConsumed,
+ void *CastInfo,
+ bool IsUnevaluatedContext) {
+ llvm::InlineAsmIdentifierInfo &Info =
+ *(llvm::InlineAsmIdentifierInfo *)CastInfo;
+
+ // Push a fake token on the end so that we don't overrun the token
+ // stream. We use ';' because it expression-parsing should never
+ // overrun it.
+ const tok::TokenKind EndOfStream = tok::semi;
+ Token EndOfStreamTok;
+ EndOfStreamTok.startToken();
+ EndOfStreamTok.setKind(EndOfStream);
+ LineToks.push_back(EndOfStreamTok);
+
+ // Also copy the current token over.
+ LineToks.push_back(Tok);
+
+ PP.EnterTokenStream(LineToks.begin(), LineToks.size(),
+ /*disable macros*/ true,
+ /*owns tokens*/ false);
+
+ // Clear the current token and advance to the first token in LineToks.
+ ConsumeAnyToken();
+
+ // Parse an optional scope-specifier if we're in C++.
+ CXXScopeSpec SS;
+ if (getLangOpts().CPlusPlus) {
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
+ }
+
+ // Require an identifier here.
+ SourceLocation TemplateKWLoc;
+ UnqualifiedId Id;
+ bool Invalid =
+ ParseUnqualifiedId(SS,
+ /*EnteringContext=*/false,
+ /*AllowDestructorName=*/false,
+ /*AllowConstructorName=*/false,
+ /*ObjectType=*/ParsedType(), TemplateKWLoc, Id);
+
+ // Figure out how many tokens we are into LineToks.
+ unsigned LineIndex = 0;
+ if (Tok.is(EndOfStream)) {
+ LineIndex = LineToks.size() - 2;
+ } else {
+ while (LineToks[LineIndex].getLocation() != Tok.getLocation()) {
+ LineIndex++;
+ assert(LineIndex < LineToks.size() - 2); // we added two extra tokens
+ }
+ }
+
+ // If we've run into the poison token we inserted before, or there
+ // was a parsing error, then claim the entire line.
+ if (Invalid || Tok.is(EndOfStream)) {
+ NumLineToksConsumed = LineToks.size() - 2;
+ } else {
+ // Otherwise, claim up to the start of the next token.
+ NumLineToksConsumed = LineIndex;
+ }
+
+ // Finally, restore the old parsing state by consuming all the tokens we
+ // staged before, implicitly killing off the token-lexer we pushed.
+ for (unsigned i = 0, e = LineToks.size() - LineIndex - 2; i != e; ++i) {
+ ConsumeAnyToken();
+ }
+ assert(Tok.is(EndOfStream));
+ ConsumeToken();
+
+ // Leave LineToks in its original state.
+ LineToks.pop_back();
+ LineToks.pop_back();
+
+ // Perform the lookup.
+ return Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info,
+ IsUnevaluatedContext);
+}
+
+/// Turn a sequence of our tokens back into a string that we can hand
+/// to the MC asm parser.
+static bool buildMSAsmString(Preprocessor &PP, SourceLocation AsmLoc,
+ ArrayRef<Token> AsmToks,
+ SmallVectorImpl<unsigned> &TokOffsets,
+ SmallString<512> &Asm) {
+ assert(!AsmToks.empty() && "Didn't expect an empty AsmToks!");
+
+ // Is this the start of a new assembly statement?
+ bool isNewStatement = true;
+
+ for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
+ const Token &Tok = AsmToks[i];
+
+ // Start each new statement with a newline and a tab.
+ if (!isNewStatement && (Tok.is(tok::kw_asm) || Tok.isAtStartOfLine())) {
+ Asm += "\n\t";
+ isNewStatement = true;
+ }
+
+ // Preserve the existence of leading whitespace except at the
+ // start of a statement.
+ if (!isNewStatement && Tok.hasLeadingSpace())
+ Asm += ' ';
+
+ // Remember the offset of this token.
+ TokOffsets.push_back(Asm.size());
+
+ // Don't actually write '__asm' into the assembly stream.
+ if (Tok.is(tok::kw_asm)) {
+ // Complain about __asm at the end of the stream.
+ if (i + 1 == e) {
+ PP.Diag(AsmLoc, diag::err_asm_empty);
+ return true;
+ }
+
+ continue;
+ }
+
+ // Append the spelling of the token.
+ SmallString<32> SpellingBuffer;
+ bool SpellingInvalid = false;
+ Asm += PP.getSpelling(Tok, SpellingBuffer, &SpellingInvalid);
+ assert(!SpellingInvalid && "spelling was invalid after correct parse?");
+
+ // We are no longer at the start of a statement.
+ isNewStatement = false;
+ }
+
+ // Ensure that the buffer is null-terminated.
+ Asm.push_back('\0');
+ Asm.pop_back();
+
+ assert(TokOffsets.size() == AsmToks.size());
+ return false;
+}
+
+/// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled,
+/// this routine is called to collect the tokens for an MS asm statement.
+///
+/// [MS] ms-asm-statement:
+/// ms-asm-block
+/// ms-asm-block ms-asm-statement
+///
+/// [MS] ms-asm-block:
+/// '__asm' ms-asm-line '\n'
+/// '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt]
+///
+/// [MS] ms-asm-instruction-block
+/// ms-asm-line
+/// ms-asm-line '\n' ms-asm-instruction-block
+///
+StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
+ SourceManager &SrcMgr = PP.getSourceManager();
+ SourceLocation EndLoc = AsmLoc;
+ SmallVector<Token, 4> AsmToks;
+
+ unsigned BraceNesting = 0;
+ unsigned short savedBraceCount = BraceCount;
+ bool InAsmComment = false;
+ FileID FID;
+ unsigned LineNo = 0;
+ unsigned NumTokensRead = 0;
+ SmallVector<SourceLocation, 4> LBraceLocs;
+ bool SkippedStartOfLine = false;
+
+ if (Tok.is(tok::l_brace)) {
+ // Braced inline asm: consume the opening brace.
+ BraceNesting = 1;
+ EndLoc = ConsumeBrace();
+ LBraceLocs.push_back(EndLoc);
+ ++NumTokensRead;
+ } else {
+ // Single-line inline asm; compute which line it is on.
+ std::pair<FileID, unsigned> ExpAsmLoc =
+ SrcMgr.getDecomposedExpansionLoc(EndLoc);
+ FID = ExpAsmLoc.first;
+ LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second);
+ LBraceLocs.push_back(SourceLocation());
+ }
+
+ SourceLocation TokLoc = Tok.getLocation();
+ do {
+ // If we hit EOF, we're done, period.
+ if (isEofOrEom())
+ break;
+
+ if (!InAsmComment && Tok.is(tok::l_brace)) {
+ // Consume the opening brace.
+ SkippedStartOfLine = Tok.isAtStartOfLine();
+ EndLoc = ConsumeBrace();
+ BraceNesting++;
+ LBraceLocs.push_back(EndLoc);
+ TokLoc = Tok.getLocation();
+ ++NumTokensRead;
+ continue;
+ } else if (!InAsmComment && Tok.is(tok::semi)) {
+ // A semicolon in an asm is the start of a comment.
+ InAsmComment = true;
+ if (BraceNesting) {
+ // Compute which line the comment is on.
+ std::pair<FileID, unsigned> ExpSemiLoc =
+ SrcMgr.getDecomposedExpansionLoc(TokLoc);
+ FID = ExpSemiLoc.first;
+ LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second);
+ }
+ } else if (!BraceNesting || InAsmComment) {
+ // If end-of-line is significant, check whether this token is on a
+ // new line.
+ std::pair<FileID, unsigned> ExpLoc =
+ SrcMgr.getDecomposedExpansionLoc(TokLoc);
+ if (ExpLoc.first != FID ||
+ SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) {
+ // If this is a single-line __asm, we're done.
+ if (!BraceNesting)
+ break;
+ // We're no longer in a comment.
+ InAsmComment = false;
+ } else if (!InAsmComment && Tok.is(tok::r_brace)) {
+ // Single-line asm always ends when a closing brace is seen.
+ // FIXME: This is compatible with Apple gcc's -fasm-blocks; what
+ // does MSVC do here?
+ break;
+ }
+ }
+ if (!InAsmComment && BraceNesting && Tok.is(tok::r_brace) &&
+ BraceCount == (savedBraceCount + BraceNesting)) {
+ // Consume the closing brace.
+ SkippedStartOfLine = Tok.isAtStartOfLine();
+ EndLoc = ConsumeBrace();
+ BraceNesting--;
+ // Finish if all of the opened braces in the inline asm section were
+ // consumed.
+ if (BraceNesting == 0)
+ break;
+ else {
+ LBraceLocs.pop_back();
+ TokLoc = Tok.getLocation();
+ ++NumTokensRead;
+ continue;
+ }
+ }
+
+ // Consume the next token; make sure we don't modify the brace count etc.
+ // if we are in a comment.
+ EndLoc = TokLoc;
+ if (InAsmComment)
+ PP.Lex(Tok);
+ else {
+ // Set the token as the start of line if we skipped the original start
+ // of line token in case it was a nested brace.
+ if (SkippedStartOfLine)
+ Tok.setFlag(Token::StartOfLine);
+ AsmToks.push_back(Tok);
+ ConsumeAnyToken();
+ }
+ TokLoc = Tok.getLocation();
+ ++NumTokensRead;
+ SkippedStartOfLine = false;
+ } while (1);
+
+ if (BraceNesting && BraceCount != savedBraceCount) {
+ // __asm without closing brace (this can happen at EOF).
+ for (unsigned i = 0; i < BraceNesting; ++i) {
+ Diag(Tok, diag::err_expected) << tok::r_brace;
+ Diag(LBraceLocs.back(), diag::note_matching) << tok::l_brace;
+ LBraceLocs.pop_back();
+ }
+ return StmtError();
+ } else if (NumTokensRead == 0) {
+ // Empty __asm.
+ Diag(Tok, diag::err_expected) << tok::l_brace;
+ return StmtError();
+ }
+
+ // Okay, prepare to use MC to parse the assembly.
+ SmallVector<StringRef, 4> ConstraintRefs;
+ SmallVector<Expr *, 4> Exprs;
+ SmallVector<StringRef, 4> ClobberRefs;
+
+ // We need an actual supported target.
+ const llvm::Triple &TheTriple = Actions.Context.getTargetInfo().getTriple();
+ llvm::Triple::ArchType ArchTy = TheTriple.getArch();
+ const std::string &TT = TheTriple.getTriple();
+ const llvm::Target *TheTarget = nullptr;
+ bool UnsupportedArch =
+ (ArchTy != llvm::Triple::x86 && ArchTy != llvm::Triple::x86_64);
+ if (UnsupportedArch) {
+ Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();
+ } else {
+ std::string Error;
+ TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error);
+ if (!TheTarget)
+ Diag(AsmLoc, diag::err_msasm_unable_to_create_target) << Error;
+ }
+
+ assert(!LBraceLocs.empty() && "Should have at least one location here");
+
+ // If we don't support assembly, or the assembly is empty, we don't
+ // need to instantiate the AsmParser, etc.
+ if (!TheTarget || AsmToks.empty()) {
+ return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, StringRef(),
+ /*NumOutputs*/ 0, /*NumInputs*/ 0,
+ ConstraintRefs, ClobberRefs, Exprs, EndLoc);
+ }
+
+ // Expand the tokens into a string buffer.
+ SmallString<512> AsmString;
+ SmallVector<unsigned, 8> TokOffsets;
+ if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString))
+ return StmtError();
+
+ std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
+ std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT));
+ // Get the instruction descriptor.
+ std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo());
+ std::unique_ptr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
+ std::unique_ptr<llvm::MCSubtargetInfo> STI(
+ TheTarget->createMCSubtargetInfo(TT, "", ""));
+
+ llvm::SourceMgr TempSrcMgr;
+ llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr);
+ llvm::MemoryBuffer *Buffer =
+ llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>");
+
+ // Tell SrcMgr about this buffer, which is what the parser will pick up.
+ TempSrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
+
+ std::unique_ptr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
+ std::unique_ptr<llvm::MCAsmParser> Parser(
+ createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI));
+
+ // FIXME: init MCOptions from sanitizer flags here.
+ llvm::MCTargetOptions MCOptions;
+ std::unique_ptr<llvm::MCTargetAsmParser> TargetParser(
+ TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions));
+
+ std::unique_ptr<llvm::MCInstPrinter> IP(
+ TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI));
+
+ // Change to the Intel dialect.
+ Parser->setAssemblerDialect(1);
+ Parser->setTargetParser(*TargetParser.get());
+ Parser->setParsingInlineAsm(true);
+ TargetParser->setParsingInlineAsm(true);
+
+ ClangAsmParserCallback Callback(*this, AsmLoc, AsmString, AsmToks,
+ TokOffsets);
+ TargetParser->setSemaCallback(&Callback);
+ TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback,
+ &Callback);
+
+ unsigned NumOutputs;
+ unsigned NumInputs;
+ std::string AsmStringIR;
+ SmallVector<std::pair<void *, bool>, 4> OpExprs;
+ SmallVector<std::string, 4> Constraints;
+ SmallVector<std::string, 4> Clobbers;
+ if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR, NumOutputs,
+ NumInputs, OpExprs, Constraints, Clobbers,
+ MII.get(), IP.get(), Callback))
+ return StmtError();
+
+ // Filter out "fpsw". Clang doesn't accept it, and it always lists flags and
+ // fpsr as clobbers.
+ auto End = std::remove(Clobbers.begin(), Clobbers.end(), "fpsw");
+ Clobbers.erase(End, Clobbers.end());
+
+ // Build the vector of clobber StringRefs.
+ ClobberRefs.insert(ClobberRefs.end(), Clobbers.begin(), Clobbers.end());
+
+ // Recast the void pointers and build the vector of constraint StringRefs.
+ unsigned NumExprs = NumOutputs + NumInputs;
+ ConstraintRefs.resize(NumExprs);
+ Exprs.resize(NumExprs);
+ for (unsigned i = 0, e = NumExprs; i != e; ++i) {
+ Expr *OpExpr = static_cast<Expr *>(OpExprs[i].first);
+ if (!OpExpr)
+ return StmtError();
+
+ // Need address of variable.
+ if (OpExprs[i].second)
+ OpExpr =
+ Actions.BuildUnaryOp(getCurScope(), AsmLoc, UO_AddrOf, OpExpr).get();
+
+ ConstraintRefs[i] = StringRef(Constraints[i]);
+ Exprs[i] = OpExpr;
+ }
+
+ // FIXME: We should be passing source locations for better diagnostics.
+ return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, AsmStringIR,
+ NumOutputs, NumInputs, ConstraintRefs,
+ ClobberRefs, Exprs, EndLoc);
+}
+
+/// ParseAsmStatement - Parse a GNU extended asm statement.
+/// asm-statement:
+/// gnu-asm-statement
+/// ms-asm-statement
+///
+/// [GNU] gnu-asm-statement:
+/// 'asm' type-qualifier[opt] '(' asm-argument ')' ';'
+///
+/// [GNU] asm-argument:
+/// asm-string-literal
+/// asm-string-literal ':' asm-operands[opt]
+/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
+/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
+/// ':' asm-clobbers
+///
+/// [GNU] asm-clobbers:
+/// asm-string-literal
+/// asm-clobbers ',' asm-string-literal
+///
+StmtResult Parser::ParseAsmStatement(bool &msAsm) {
+ assert(Tok.is(tok::kw_asm) && "Not an asm stmt");
+ SourceLocation AsmLoc = ConsumeToken();
+
+ if (getLangOpts().AsmBlocks && Tok.isNot(tok::l_paren) &&
+ !isTypeQualifier()) {
+ msAsm = true;
+ return ParseMicrosoftAsmStatement(AsmLoc);
+ }
+ DeclSpec DS(AttrFactory);
+ SourceLocation Loc = Tok.getLocation();
+ ParseTypeQualifierListOpt(DS, true, false);
+
+ // GNU asms accept, but warn, about type-qualifiers other than volatile.
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
+ Diag(Loc, diag::w_asm_qualifier_ignored) << "const";
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
+ Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict";
+ // FIXME: Once GCC supports _Atomic, check whether it permits it here.
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
+ Diag(Loc, diag::w_asm_qualifier_ignored) << "_Atomic";
+
+ // Remember if this was a volatile asm.
+ bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile;
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "asm";
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return StmtError();
+ }
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+
+ ExprResult AsmString(ParseAsmStringLiteral());
+ if (AsmString.isInvalid()) {
+ // Consume up to and including the closing paren.
+ T.skipToEnd();
+ return StmtError();
+ }
+
+ SmallVector<IdentifierInfo *, 4> Names;
+ ExprVector Constraints;
+ ExprVector Exprs;
+ ExprVector Clobbers;
+
+ if (Tok.is(tok::r_paren)) {
+ // We have a simple asm expression like 'asm("foo")'.
+ T.consumeClose();
+ return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,
+ /*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr,
+ Constraints, Exprs, AsmString.get(),
+ Clobbers, T.getCloseLocation());
+ }
+
+ // Parse Outputs, if present.
+ bool AteExtraColon = false;
+ if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
+ // In C++ mode, parse "::" like ": :".
+ AteExtraColon = Tok.is(tok::coloncolon);
+ ConsumeToken();
+
+ if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
+ return StmtError();
+ }
+
+ unsigned NumOutputs = Names.size();
+
+ // Parse Inputs, if present.
+ if (AteExtraColon || Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
+ // In C++ mode, parse "::" like ": :".
+ if (AteExtraColon)
+ AteExtraColon = false;
+ else {
+ AteExtraColon = Tok.is(tok::coloncolon);
+ ConsumeToken();
+ }
+
+ if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
+ return StmtError();
+ }
+
+ assert(Names.size() == Constraints.size() &&
+ Constraints.size() == Exprs.size() && "Input operand size mismatch!");
+
+ unsigned NumInputs = Names.size() - NumOutputs;
+
+ // Parse the clobbers, if present.
+ if (AteExtraColon || Tok.is(tok::colon)) {
+ if (!AteExtraColon)
+ ConsumeToken();
+
+ // Parse the asm-string list for clobbers if present.
+ if (Tok.isNot(tok::r_paren)) {
+ while (1) {
+ ExprResult Clobber(ParseAsmStringLiteral());
+
+ if (Clobber.isInvalid())
+ break;
+
+ Clobbers.push_back(Clobber.get());
+
+ if (!TryConsumeToken(tok::comma))
+ break;
+ }
+ }
+ }
+
+ T.consumeClose();
+ return Actions.ActOnGCCAsmStmt(
+ AsmLoc, false, isVolatile, NumOutputs, NumInputs, Names.data(),
+ Constraints, Exprs, AsmString.get(), Clobbers, T.getCloseLocation());
+}
+
+/// ParseAsmOperands - Parse the asm-operands production as used by
+/// asm-statement, assuming the leading ':' token was eaten.
+///
+/// [GNU] asm-operands:
+/// asm-operand
+/// asm-operands ',' asm-operand
+///
+/// [GNU] asm-operand:
+/// asm-string-literal '(' expression ')'
+/// '[' identifier ']' asm-string-literal '(' expression ')'
+///
+//
+// FIXME: Avoid unnecessary std::string trashing.
+bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
+ SmallVectorImpl<Expr *> &Constraints,
+ SmallVectorImpl<Expr *> &Exprs) {
+ // 'asm-operands' isn't present?
+ if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))
+ return false;
+
+ while (1) {
+ // Read the [id] if present.
+ if (Tok.is(tok::l_square)) {
+ BalancedDelimiterTracker T(*this, tok::l_square);
+ T.consumeOpen();
+
+ if (Tok.isNot(tok::identifier)) {
+ Diag(Tok, diag::err_expected) << tok::identifier;
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return true;
+ }
+
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ ConsumeToken();
+
+ Names.push_back(II);
+ T.consumeClose();
+ } else
+ Names.push_back(nullptr);
+
+ ExprResult Constraint(ParseAsmStringLiteral());
+ if (Constraint.isInvalid()) {
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return true;
+ }
+ Constraints.push_back(Constraint.get());
+
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << "asm operand";
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return true;
+ }
+
+ // Read the parenthesized expression.
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ T.consumeOpen();
+ ExprResult Res(ParseExpression());
+ T.consumeClose();
+ if (Res.isInvalid()) {
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return true;
+ }
+ Exprs.push_back(Res.get());
+ // Eat the comma and continue parsing if it exists.
+ if (!TryConsumeToken(tok::comma))
+ return false;
+ }
+}
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 076edb93fa11..fa6401f083a6 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -101,17 +101,13 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
do {
// Consume the 'export', if any.
SourceLocation ExportLoc;
- if (Tok.is(tok::kw_export)) {
- ExportLoc = ConsumeToken();
- }
+ TryConsumeToken(tok::kw_export, ExportLoc);
// Consume the 'template', which should be here.
SourceLocation TemplateLoc;
- if (Tok.is(tok::kw_template)) {
- TemplateLoc = ConsumeToken();
- } else {
+ if (!TryConsumeToken(tok::kw_template, TemplateLoc)) {
Diag(Tok.getLocation(), diag::err_expected_template);
- return 0;
+ return nullptr;
}
// Parse the '<' template-parameter-list '>'
@@ -121,9 +117,8 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
TemplateParams, LAngleLoc, RAngleLoc)) {
// Skip until the semi-colon or a }.
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
- if (Tok.is(tok::semi))
- ConsumeToken();
- return 0;
+ TryConsumeToken(tok::semi);
+ return nullptr;
}
ParamLists.push_back(
@@ -175,7 +170,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
// We are parsing a member template.
ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo,
&DiagsFromTParams);
- return 0;
+ return nullptr;
}
ParsedAttributesWithRange prefixAttrs(AttrFactory);
@@ -219,7 +214,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
if (Tok.is(tok::semi))
ConsumeToken();
- return 0;
+ return nullptr;
}
LateParsedAttrList LateParsedAttrs(true);
@@ -255,8 +250,8 @@ Parser::ParseSingleDeclarationAfterTemplate(
// Recover as if it were an explicit specialization.
TemplateParameterLists FakedParamLists;
FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
- 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0,
- LAngleLoc));
+ 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, nullptr,
+ 0, LAngleLoc));
return ParseFunctionDefinition(
DeclaratorInfo, ParsedTemplateInfo(&FakedParamLists,
@@ -302,11 +297,10 @@ bool Parser::ParseTemplateParameters(unsigned Depth,
SourceLocation &LAngleLoc,
SourceLocation &RAngleLoc) {
// Get the template parameter list.
- if (!Tok.is(tok::less)) {
+ if (!TryConsumeToken(tok::less, LAngleLoc)) {
Diag(Tok.getLocation(), diag::err_expected_less_after) << "template";
return true;
}
- LAngleLoc = ConsumeToken();
// Try to parse the template parameter list.
bool Failed = false;
@@ -322,10 +316,8 @@ bool Parser::ParseTemplateParameters(unsigned Depth,
Tok.setKind(tok::greater);
RAngleLoc = Tok.getLocation();
Tok.setLocation(Tok.getLocation().getLocWithOffset(1));
- } else if (Tok.is(tok::greater))
- RAngleLoc = ConsumeToken();
- else if (Failed) {
- Diag(Tok.getLocation(), diag::err_expected_greater);
+ } else if (!TryConsumeToken(tok::greater, RAngleLoc) && Failed) {
+ Diag(Tok.getLocation(), diag::err_expected) << tok::greater;
return true;
}
return false;
@@ -481,12 +473,8 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
SourceLocation KeyLoc = ConsumeToken();
// Grab the ellipsis (if given).
- bool Ellipsis = false;
SourceLocation EllipsisLoc;
- if (Tok.is(tok::ellipsis)) {
- Ellipsis = true;
- EllipsisLoc = ConsumeToken();
-
+ if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) {
Diag(EllipsisLoc,
getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_variadic_templates
@@ -495,7 +483,7 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
// Grab the template parameter name (if given)
SourceLocation NameLoc;
- IdentifierInfo* ParamName = 0;
+ IdentifierInfo *ParamName = nullptr;
if (Tok.is(tok::identifier)) {
ParamName = Tok.getIdentifierInfo();
NameLoc = ConsumeToken();
@@ -504,34 +492,40 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
// Unnamed template parameter. Don't have to do anything here, just
// don't consume this token.
} else {
- Diag(Tok.getLocation(), diag::err_expected_ident);
- return 0;
+ Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
+ return nullptr;
}
+ // Recover from misplaced ellipsis.
+ bool AlreadyHasEllipsis = EllipsisLoc.isValid();
+ if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
+ DiagnoseMisplacedEllipsis(EllipsisLoc, NameLoc, AlreadyHasEllipsis, true);
+
// Grab a default argument (if available).
// Per C++0x [basic.scope.pdecl]p9, we parse the default argument before
// we introduce the type parameter into the local scope.
SourceLocation EqualLoc;
ParsedType DefaultArg;
- if (Tok.is(tok::equal)) {
- EqualLoc = ConsumeToken();
- DefaultArg = ParseTypeName(/*Range=*/0,
+ if (TryConsumeToken(tok::equal, EqualLoc))
+ DefaultArg = ParseTypeName(/*Range=*/nullptr,
Declarator::TemplateTypeArgContext).get();
- }
- return Actions.ActOnTypeParameter(getCurScope(), TypenameKeyword, Ellipsis,
- EllipsisLoc, KeyLoc, ParamName, NameLoc,
- Depth, Position, EqualLoc, DefaultArg);
+ return Actions.ActOnTypeParameter(getCurScope(), TypenameKeyword, EllipsisLoc,
+ KeyLoc, ParamName, NameLoc, Depth, Position,
+ EqualLoc, DefaultArg);
}
/// ParseTemplateTemplateParameter - Handle the parsing of template
/// template parameters.
///
/// type-parameter: [C++ temp.param]
-/// 'template' '<' template-parameter-list '>' 'class'
+/// 'template' '<' template-parameter-list '>' type-parameter-key
/// ...[opt] identifier[opt]
-/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
-/// = id-expression
+/// 'template' '<' template-parameter-list '>' type-parameter-key
+/// identifier[opt] = id-expression
+/// type-parameter-key:
+/// 'class'
+/// 'typename' [C++1z]
Decl *
Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
assert(Tok.is(tok::kw_template) && "Expected 'template' keyword");
@@ -544,45 +538,50 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
if (ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc,
RAngleLoc)) {
- return 0;
+ return nullptr;
}
}
+ // Provide an ExtWarn if the C++1z feature of using 'typename' here is used.
// Generate a meaningful error if the user forgot to put class before the
// identifier, comma, or greater. Provide a fixit if the identifier, comma,
- // or greater appear immediately or after 'typename' or 'struct'. In the
- // latter case, replace the keyword with 'class'.
- if (!Tok.is(tok::kw_class)) {
+ // or greater appear immediately or after 'struct'. In the latter case,
+ // replace the keyword with 'class'.
+ if (!TryConsumeToken(tok::kw_class)) {
bool Replace = Tok.is(tok::kw_typename) || Tok.is(tok::kw_struct);
- const Token& Next = Replace ? NextToken() : Tok;
- if (Next.is(tok::identifier) || Next.is(tok::comma) ||
- Next.is(tok::greater) || Next.is(tok::greatergreater) ||
- Next.is(tok::ellipsis))
+ const Token &Next = Tok.is(tok::kw_struct) ? NextToken() : Tok;
+ if (Tok.is(tok::kw_typename)) {
+ Diag(Tok.getLocation(),
+ getLangOpts().CPlusPlus1z
+ ? diag::warn_cxx1y_compat_template_template_param_typename
+ : diag::ext_template_template_param_typename)
+ << (!getLangOpts().CPlusPlus1z
+ ? FixItHint::CreateReplacement(Tok.getLocation(), "class")
+ : FixItHint());
+ } else if (Next.is(tok::identifier) || Next.is(tok::comma) ||
+ Next.is(tok::greater) || Next.is(tok::greatergreater) ||
+ Next.is(tok::ellipsis)) {
Diag(Tok.getLocation(), diag::err_class_on_template_template_param)
<< (Replace ? FixItHint::CreateReplacement(Tok.getLocation(), "class")
: FixItHint::CreateInsertion(Tok.getLocation(), "class "));
- else
+ } else
Diag(Tok.getLocation(), diag::err_class_on_template_template_param);
if (Replace)
ConsumeToken();
- } else
- ConsumeToken();
+ }
// Parse the ellipsis, if given.
SourceLocation EllipsisLoc;
- if (Tok.is(tok::ellipsis)) {
- EllipsisLoc = ConsumeToken();
-
+ if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
Diag(EllipsisLoc,
getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_variadic_templates
: diag::ext_variadic_templates);
- }
// Get the identifier, if given.
SourceLocation NameLoc;
- IdentifierInfo* ParamName = 0;
+ IdentifierInfo *ParamName = nullptr;
if (Tok.is(tok::identifier)) {
ParamName = Tok.getIdentifierInfo();
NameLoc = ConsumeToken();
@@ -591,10 +590,15 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
// Unnamed template parameter. Don't have to do anything here, just
// don't consume this token.
} else {
- Diag(Tok.getLocation(), diag::err_expected_ident);
- return 0;
+ Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
+ return nullptr;
}
+ // Recover from misplaced ellipsis.
+ bool AlreadyHasEllipsis = EllipsisLoc.isValid();
+ if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
+ DiagnoseMisplacedEllipsis(EllipsisLoc, NameLoc, AlreadyHasEllipsis, true);
+
TemplateParameterList *ParamList =
Actions.ActOnTemplateParameterList(Depth, SourceLocation(),
TemplateLoc, LAngleLoc,
@@ -607,8 +611,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
// we introduce the template parameter into the local scope.
SourceLocation EqualLoc;
ParsedTemplateArgument DefaultArg;
- if (Tok.is(tok::equal)) {
- EqualLoc = ConsumeToken();
+ if (TryConsumeToken(tok::equal, EqualLoc)) {
DefaultArg = ParseTemplateTemplateArgument();
if (DefaultArg.isInvalid()) {
Diag(Tok.getLocation(),
@@ -643,17 +646,20 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
ParseDeclarator(ParamDecl);
if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) {
Diag(Tok.getLocation(), diag::err_expected_template_parameter);
- return 0;
+ return nullptr;
}
+ // Recover from misplaced ellipsis.
+ SourceLocation EllipsisLoc;
+ if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
+ DiagnoseMisplacedEllipsisInDeclarator(EllipsisLoc, ParamDecl);
+
// If there is a default value, parse it.
// Per C++0x [basic.scope.pdecl]p9, we parse the default argument before
// we introduce the template parameter into the local scope.
SourceLocation EqualLoc;
ExprResult DefaultArg;
- if (Tok.is(tok::equal)) {
- EqualLoc = ConsumeToken();
-
+ if (TryConsumeToken(tok::equal, EqualLoc)) {
// C++ [temp.param]p15:
// When parsing a default template-argument for a non-type
// template-parameter, the first non-nested > is taken as the
@@ -670,7 +676,29 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
// Create the parameter.
return Actions.ActOnNonTypeTemplateParameter(getCurScope(), ParamDecl,
Depth, Position, EqualLoc,
- DefaultArg.take());
+ DefaultArg.get());
+}
+
+void Parser::DiagnoseMisplacedEllipsis(SourceLocation EllipsisLoc,
+ SourceLocation CorrectLoc,
+ bool AlreadyHasEllipsis,
+ bool IdentifierHasName) {
+ FixItHint Insertion;
+ if (!AlreadyHasEllipsis)
+ Insertion = FixItHint::CreateInsertion(CorrectLoc, "...");
+ Diag(EllipsisLoc, diag::err_misplaced_ellipsis_in_declaration)
+ << FixItHint::CreateRemoval(EllipsisLoc) << Insertion
+ << !IdentifierHasName;
+}
+
+void Parser::DiagnoseMisplacedEllipsisInDeclarator(SourceLocation EllipsisLoc,
+ Declarator &D) {
+ assert(EllipsisLoc.isValid());
+ bool AlreadyHasEllipsis = D.getEllipsisLoc().isValid();
+ if (!AlreadyHasEllipsis)
+ D.setEllipsisLoc(EllipsisLoc);
+ DiagnoseMisplacedEllipsis(EllipsisLoc, D.getIdentifierLoc(),
+ AlreadyHasEllipsis, D.hasName());
}
/// \brief Parses a '>' at the end of a template list.
@@ -692,7 +720,7 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
switch (Tok.getKind()) {
default:
- Diag(Tok.getLocation(), diag::err_expected_greater);
+ Diag(Tok.getLocation(), diag::err_expected) << tok::greater;
return true;
case tok::greater:
@@ -723,7 +751,9 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
// This template-id is terminated by a token which starts with a '>'. Outside
// C++11, this is now error recovery, and in C++11, this is error recovery if
- // the token isn't '>>'.
+ // the token isn't '>>' or '>>>'.
+ // '>>>' is for CUDA, where this sequence of characters is parsed into
+ // tok::greatergreatergreater, rather than two separate tokens.
RAngleLoc = Tok.getLocation();
@@ -753,7 +783,8 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " ");
unsigned DiagId = diag::err_two_right_angle_brackets_need_space;
- if (getLangOpts().CPlusPlus11 && Tok.is(tok::greatergreater))
+ if (getLangOpts().CPlusPlus11 &&
+ (Tok.is(tok::greatergreater) || Tok.is(tok::greatergreatergreater)))
DiagId = diag::warn_cxx98_compat_two_right_angle_brackets;
else if (Tok.is(tok::greaterequal))
DiagId = diag::err_right_angle_bracket_equal_needs_space;
@@ -900,8 +931,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
if (Invalid) {
// If we failed to parse the template ID but skipped ahead to a >, we're not
// going to be able to form a token annotation. Eat the '>' if present.
- if (Tok.is(tok::greater))
- ConsumeToken();
+ TryConsumeToken(tok::greater);
return true;
}
@@ -916,8 +946,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
if (Type.isInvalid()) {
// If we failed to parse the template ID but skipped ahead to a >, we're not
// going to be able to form a token annotation. Eat the '>' if present.
- if (Tok.is(tok::greater))
- ConsumeToken();
+ TryConsumeToken(tok::greater);
return true;
}
@@ -940,7 +969,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
TemplateId->Name = TemplateName.Identifier;
TemplateId->Operator = OO_None;
} else {
- TemplateId->Name = 0;
+ TemplateId->Name = nullptr;
TemplateId->Operator = TemplateName.OperatorFunctionId.Operator;
}
TemplateId->SS = SS;
@@ -1044,11 +1073,9 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
UnqualifiedId Name;
Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
ConsumeToken(); // the identifier
-
- // Parse the ellipsis.
- if (Tok.is(tok::ellipsis))
- EllipsisLoc = ConsumeToken();
-
+
+ TryConsumeToken(tok::ellipsis, EllipsisLoc);
+
// If the next token signals the end of a template argument,
// then we have a dependent template name that could be a template
// template argument.
@@ -1067,10 +1094,8 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
UnqualifiedId Name;
Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
ConsumeToken(); // the identifier
-
- // Parse the ellipsis.
- if (Tok.is(tok::ellipsis))
- EllipsisLoc = ConsumeToken();
+
+ TryConsumeToken(tok::ellipsis, EllipsisLoc);
if (isEndOfTemplateArgument(Tok)) {
bool MemberOfUnknownSpecialization;
@@ -1111,7 +1136,7 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() {
// Therefore, we initially try to parse a type-id.
if (isCXXTypeId(TypeIdAsTemplateArgument)) {
SourceLocation Loc = Tok.getLocation();
- TypeResult TypeArg = ParseTypeName(/*Range=*/0,
+ TypeResult TypeArg = ParseTypeName(/*Range=*/nullptr,
Declarator::TemplateTypeArgContext);
if (TypeArg.isInvalid())
return ParsedTemplateArgument();
@@ -1143,7 +1168,7 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() {
return ParsedTemplateArgument();
return ParsedTemplateArgument(ParsedTemplateArgument::NonType,
- ExprArg.release(), Loc);
+ ExprArg.get(), Loc);
}
/// \brief Determine whether the current tokens can only be parsed as a
@@ -1161,16 +1186,15 @@ bool Parser::IsTemplateArgumentList(unsigned Skip) {
}
// '<'
- if (!Tok.is(tok::less))
+ if (!TryConsumeToken(tok::less))
return false;
- ConsumeToken();
// An empty template argument list.
if (Tok.is(tok::greater))
return true;
// See whether we have declaration specifiers, which indicate a type.
- while (isCXXDeclarationSpecifier() == TPResult::True())
+ while (isCXXDeclarationSpecifier() == TPResult::True)
ConsumeToken();
// If we have a '>' or a ',' then this is a template argument list.
@@ -1187,13 +1211,13 @@ bool
Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
// Template argument lists are constant-evaluation contexts.
EnterExpressionEvaluationContext EvalContext(Actions,Sema::ConstantEvaluated);
+ ColonProtectionRAIIObject ColonProtection(*this, false);
- while (true) {
+ do {
ParsedTemplateArgument Arg = ParseTemplateArgument();
- if (Tok.is(tok::ellipsis)) {
- SourceLocation EllipsisLoc = ConsumeToken();
+ SourceLocation EllipsisLoc;
+ if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
Arg = Actions.ActOnPackExpansion(Arg, EllipsisLoc);
- }
if (Arg.isInvalid()) {
SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch);
@@ -1205,11 +1229,7 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
// If the next token is a comma, consume it and keep reading
// arguments.
- if (Tok.isNot(tok::comma)) break;
-
- // Consume the comma.
- ConsumeToken();
- }
+ } while (TryConsumeToken(tok::comma));
return false;
}
@@ -1258,9 +1278,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
return;
// Get the FunctionDecl.
- FunctionTemplateDecl *FunTmplD = dyn_cast<FunctionTemplateDecl>(LPT.D);
- FunctionDecl *FunD =
- FunTmplD ? FunTmplD->getTemplatedDecl() : cast<FunctionDecl>(LPT.D);
+ FunctionDecl *FunD = LPT.D->getAsFunction();
// Track template parameter depth.
TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
@@ -1271,7 +1289,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
// Get the list of DeclContexts to reenter.
SmallVector<DeclContext*, 4> DeclContextsToReenter;
- DeclContext *DD = FunD->getLexicalParent();
+ DeclContext *DD = FunD;
while (DD && !DD->isTranslationUnit()) {
DeclContextsToReenter.push_back(DD);
DD = DD->getLexicalParent();
@@ -1281,35 +1299,16 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
SmallVectorImpl<DeclContext *>::reverse_iterator II =
DeclContextsToReenter.rbegin();
for (; II != DeclContextsToReenter.rend(); ++II) {
- if (ClassTemplatePartialSpecializationDecl *MD =
- dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(*II)) {
- TemplateParamScopeStack.push_back(
- new ParseScope(this, Scope::TemplateParamScope));
- Actions.ActOnReenterTemplateScope(getCurScope(), MD);
- ++CurTemplateDepthTracker;
- } else if (CXXRecordDecl *MD = dyn_cast_or_null<CXXRecordDecl>(*II)) {
- bool IsClassTemplate = MD->getDescribedClassTemplate() != 0;
- TemplateParamScopeStack.push_back(
- new ParseScope(this, Scope::TemplateParamScope,
- /*ManageScope*/IsClassTemplate));
- Actions.ActOnReenterTemplateScope(getCurScope(),
- MD->getDescribedClassTemplate());
- if (IsClassTemplate)
- ++CurTemplateDepthTracker;
+ TemplateParamScopeStack.push_back(new ParseScope(this,
+ Scope::TemplateParamScope));
+ unsigned NumParamLists =
+ Actions.ActOnReenterTemplateScope(getCurScope(), cast<Decl>(*II));
+ CurTemplateDepthTracker.addDepth(NumParamLists);
+ if (*II != FunD) {
+ TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope));
+ Actions.PushDeclContext(Actions.getCurScope(), *II);
}
- TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope));
- Actions.PushDeclContext(Actions.getCurScope(), *II);
- }
- TemplateParamScopeStack.push_back(
- new ParseScope(this, Scope::TemplateParamScope));
-
- DeclaratorDecl *Declarator = dyn_cast<DeclaratorDecl>(FunD);
- if (Declarator && Declarator->getNumTemplateParameterLists() != 0) {
- Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator);
- ++CurTemplateDepthTracker;
}
- Actions.ActOnReenterTemplateScope(getCurScope(), LPT.D);
- ++CurTemplateDepthTracker;
assert(!LPT.Toks.empty() && "Empty body!");
@@ -1341,14 +1340,16 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
Actions.ActOnDefaultCtorInitializers(LPT.D);
if (Tok.is(tok::l_brace)) {
- assert((!FunTmplD || FunTmplD->getTemplateParameters()->getDepth() <
- TemplateParameterDepth) &&
+ assert((!isa<FunctionTemplateDecl>(LPT.D) ||
+ cast<FunctionTemplateDecl>(LPT.D)
+ ->getTemplateParameters()
+ ->getDepth() == TemplateParameterDepth - 1) &&
"TemplateParameterDepth should be greater than the depth of "
"current template being instantiated!");
ParseFunctionStatementBody(LPT.D, FnScope);
Actions.UnmarkAsLateParsedTemplate(FunD);
} else
- Actions.ActOnFinishFunctionBody(LPT.D, 0);
+ Actions.ActOnFinishFunctionBody(LPT.D, nullptr);
}
// Exit scopes.
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index a1d6b13fdab8..8514af2a8c89 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -101,15 +101,15 @@ bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) {
// an ambiguity if the first decl-specifier is
// simple-type-specifier/typename-specifier followed by a '(', which may
// indicate a function-style cast expression.
- // isCXXDeclarationSpecifier will return TPResult::Ambiguous() only in such
+ // isCXXDeclarationSpecifier will return TPResult::Ambiguous only in such
// a case.
bool InvalidAsDeclaration = false;
- TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(),
+ TPResult TPR = isCXXDeclarationSpecifier(TPResult::False,
&InvalidAsDeclaration);
- if (TPR != TPResult::Ambiguous())
- return TPR != TPResult::False(); // Returns true for TPResult::True() or
- // TPResult::Error().
+ if (TPR != TPResult::Ambiguous)
+ return TPR != TPResult::False; // Returns true for TPResult::True or
+ // TPResult::Error.
// FIXME: TryParseSimpleDeclaration doesn't look past the first initializer,
// and so gets some cases wrong. We can't carry on if we've already seen
@@ -131,15 +131,15 @@ bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) {
PA.Revert();
// In case of an error, let the declaration parsing code handle it.
- if (TPR == TPResult::Error())
+ if (TPR == TPResult::Error)
return true;
// Declarations take precedence over expressions.
- if (TPR == TPResult::Ambiguous())
- TPR = TPResult::True();
+ if (TPR == TPResult::Ambiguous)
+ TPR = TPResult::True;
- assert(TPR == TPResult::True() || TPR == TPResult::False());
- return TPR == TPResult::True();
+ assert(TPR == TPResult::True || TPR == TPResult::False);
+ return TPR == TPResult::True;
}
/// Try to consume a token sequence that we've already identified as
@@ -157,10 +157,10 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() {
case tok::kw___underlying_type: {
ConsumeToken();
if (Tok.isNot(tok::l_paren))
- return TPResult::Error();
+ return TPResult::Error;
ConsumeParen();
if (!SkipUntil(tok::r_paren))
- return TPResult::Error();
+ return TPResult::Error;
break;
}
@@ -184,23 +184,23 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() {
if (Tok.is(tok::l_square)) {
ConsumeBracket();
if (!SkipUntil(tok::r_square))
- return TPResult::Error();
+ return TPResult::Error;
} else {
ConsumeToken();
if (Tok.isNot(tok::l_paren))
- return TPResult::Error();
+ return TPResult::Error;
ConsumeParen();
if (!SkipUntil(tok::r_paren))
- return TPResult::Error();
+ return TPResult::Error;
}
}
if (TryAnnotateCXXScopeToken())
- return TPResult::Error();
+ return TPResult::Error;
if (Tok.is(tok::annot_cxxscope))
ConsumeToken();
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
- return TPResult::Error();
+ return TPResult::Error;
ConsumeToken();
break;
@@ -215,7 +215,7 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() {
break;
}
- return TPResult::Ambiguous();
+ return TPResult::Ambiguous;
}
/// simple-declaration:
@@ -227,29 +227,29 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() {
/// attribute-specifier-seqopt type-specifier-seq declarator
///
Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) {
- if (TryConsumeDeclarationSpecifier() == TPResult::Error())
- return TPResult::Error();
+ if (TryConsumeDeclarationSpecifier() == TPResult::Error)
+ return TPResult::Error;
// Two decl-specifiers in a row conclusively disambiguate this as being a
// simple-declaration. Don't bother calling isCXXDeclarationSpecifier in the
// overwhelmingly common case that the next token is a '('.
if (Tok.isNot(tok::l_paren)) {
TPResult TPR = isCXXDeclarationSpecifier();
- if (TPR == TPResult::Ambiguous())
- return TPResult::True();
- if (TPR == TPResult::True() || TPR == TPResult::Error())
+ if (TPR == TPResult::Ambiguous)
+ return TPResult::True;
+ if (TPR == TPResult::True || TPR == TPResult::Error)
return TPR;
- assert(TPR == TPResult::False());
+ assert(TPR == TPResult::False);
}
TPResult TPR = TryParseInitDeclaratorList();
- if (TPR != TPResult::Ambiguous())
+ if (TPR != TPResult::Ambiguous)
return TPR;
if (Tok.isNot(tok::semi) && (!AllowForRangeDecl || Tok.isNot(tok::colon)))
- return TPResult::False();
+ return TPResult::False;
- return TPResult::Ambiguous();
+ return TPResult::Ambiguous;
}
/// Tentatively parse an init-declarator-list in order to disambiguate it from
@@ -283,23 +283,23 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() {
while (1) {
// declarator
TPResult TPR = TryParseDeclarator(false/*mayBeAbstract*/);
- if (TPR != TPResult::Ambiguous())
+ if (TPR != TPResult::Ambiguous)
return TPR;
// [GNU] simple-asm-expr[opt] attributes[opt]
if (Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
- return TPResult::True();
+ return TPResult::True;
// initializer[opt]
if (Tok.is(tok::l_paren)) {
// Parse through the parens.
ConsumeParen();
if (!SkipUntil(tok::r_paren, StopAtSemi))
- return TPResult::Error();
+ return TPResult::Error;
} else if (Tok.is(tok::l_brace)) {
// A left-brace here is sufficient to disambiguate the parse; an
// expression can never be followed directly by a braced-init-list.
- return TPResult::True();
+ return TPResult::True;
} else if (Tok.is(tok::equal) || isTokIdentifier_in()) {
// MSVC and g++ won't examine the rest of declarators if '=' is
// encountered; they just conclude that we have a declaration.
@@ -317,15 +317,14 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() {
// in any other context 'in' is invalid after a declaration and parser
// issues the error regardless of outcome of this decision.
// FIXME: Change if above assumption does not hold.
- return TPResult::True();
+ return TPResult::True;
}
- if (Tok.isNot(tok::comma))
+ if (!TryConsumeToken(tok::comma))
break;
- ConsumeToken(); // the comma.
}
- return TPResult::Ambiguous();
+ return TPResult::Ambiguous;
}
/// isCXXConditionDeclaration - Disambiguates between a declaration or an
@@ -343,9 +342,9 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() {
///
bool Parser::isCXXConditionDeclaration() {
TPResult TPR = isCXXDeclarationSpecifier();
- if (TPR != TPResult::Ambiguous())
- return TPR != TPResult::False(); // Returns true for TPResult::True() or
- // TPResult::Error().
+ if (TPR != TPResult::Ambiguous)
+ return TPR != TPResult::False; // Returns true for TPResult::True or
+ // TPResult::Error.
// FIXME: Add statistics about the number of ambiguous statements encountered
// and how they were resolved (number of declarations+number of expressions).
@@ -363,25 +362,25 @@ bool Parser::isCXXConditionDeclaration() {
TPR = TryParseDeclarator(false/*mayBeAbstract*/);
// In case of an error, let the declaration parsing code handle it.
- if (TPR == TPResult::Error())
- TPR = TPResult::True();
+ if (TPR == TPResult::Error)
+ TPR = TPResult::True;
- if (TPR == TPResult::Ambiguous()) {
+ if (TPR == TPResult::Ambiguous) {
// '='
// [GNU] simple-asm-expr[opt] attributes[opt]
if (Tok.is(tok::equal) ||
Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
- TPR = TPResult::True();
+ TPR = TPResult::True;
else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace))
- TPR = TPResult::True();
+ TPR = TPResult::True;
else
- TPR = TPResult::False();
+ TPR = TPResult::False;
}
PA.Revert();
- assert(TPR == TPResult::True() || TPR == TPResult::False());
- return TPR == TPResult::True();
+ assert(TPR == TPResult::True || TPR == TPResult::False);
+ return TPR == TPResult::True;
}
/// \brief Determine whether the next set of tokens contains a type-id.
@@ -413,9 +412,9 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
// in its syntactic context shall be considered a type-id.
TPResult TPR = isCXXDeclarationSpecifier();
- if (TPR != TPResult::Ambiguous())
- return TPR != TPResult::False(); // Returns true for TPResult::True() or
- // TPResult::Error().
+ if (TPR != TPResult::Ambiguous)
+ return TPR != TPResult::False; // Returns true for TPResult::True or
+ // TPResult::Error.
// FIXME: Add statistics about the number of ambiguous statements encountered
// and how they were resolved (number of declarations+number of expressions).
@@ -433,14 +432,14 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
TPR = TryParseDeclarator(true/*mayBeAbstract*/, false/*mayHaveIdentifier*/);
// In case of an error, let the declaration parsing code handle it.
- if (TPR == TPResult::Error())
- TPR = TPResult::True();
+ if (TPR == TPResult::Error)
+ TPR = TPResult::True;
- if (TPR == TPResult::Ambiguous()) {
+ if (TPR == TPResult::Ambiguous) {
// We are supposed to be inside parens, so if after the abstract declarator
// we encounter a ')' this is a type-id, otherwise it's an expression.
if (Context == TypeIdInParens && Tok.is(tok::r_paren)) {
- TPR = TPResult::True();
+ TPR = TPResult::True;
isAmbiguous = true;
// We are supposed to be inside a template argument, so if after
@@ -449,17 +448,17 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
} else if (Context == TypeIdAsTemplateArgument &&
(Tok.is(tok::greater) || Tok.is(tok::comma) ||
(getLangOpts().CPlusPlus11 && Tok.is(tok::greatergreater)))) {
- TPR = TPResult::True();
+ TPR = TPResult::True;
isAmbiguous = true;
} else
- TPR = TPResult::False();
+ TPR = TPResult::False;
}
PA.Revert();
- assert(TPR == TPResult::True() || TPR == TPResult::False());
- return TPR == TPResult::True();
+ assert(TPR == TPResult::True || TPR == TPResult::False);
+ return TPR == TPResult::True;
}
/// \brief Returns true if this is a C++11 attribute-specifier. Per
@@ -595,13 +594,10 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate,
}
}
- if (Tok.is(tok::ellipsis))
- ConsumeToken();
+ TryConsumeToken(tok::ellipsis);
- if (Tok.isNot(tok::comma))
+ if (!TryConsumeToken(tok::comma))
break;
-
- ConsumeToken();
}
// An attribute must end ']]'.
@@ -628,7 +624,7 @@ Parser::TPResult Parser::TryParsePtrOperatorSeq() {
while (true) {
if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier))
if (TryAnnotateCXXScopeToken(true))
- return TPResult::Error();
+ return TPResult::Error;
if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) ||
Tok.is(tok::ampamp) ||
@@ -640,7 +636,7 @@ Parser::TPResult Parser::TryParsePtrOperatorSeq() {
Tok.is(tok::kw_restrict))
ConsumeToken();
} else {
- return TPResult::True();
+ return TPResult::True;
}
}
}
@@ -675,20 +671,20 @@ Parser::TPResult Parser::TryParseOperatorId() {
ConsumeBracket();
ConsumeBracket();
}
- return TPResult::True();
+ return TPResult::True;
#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemOnly) \
case tok::Token:
#define OVERLOADED_OPERATOR_MULTI(Name, Spelling, Unary, Binary, MemOnly)
#include "clang/Basic/OperatorKinds.def"
ConsumeToken();
- return TPResult::True();
+ return TPResult::True;
case tok::l_square:
if (NextToken().is(tok::r_square)) {
ConsumeBracket();
ConsumeBracket();
- return TPResult::True();
+ return TPResult::True;
}
break;
@@ -696,7 +692,7 @@ Parser::TPResult Parser::TryParseOperatorId() {
if (NextToken().is(tok::r_paren)) {
ConsumeParen();
ConsumeParen();
- return TPResult::True();
+ return TPResult::True;
}
break;
@@ -716,24 +712,24 @@ Parser::TPResult Parser::TryParseOperatorId() {
if (Tok.is(tok::identifier))
ConsumeToken();
else
- return TPResult::Error();
+ return TPResult::Error;
}
- return TPResult::True();
+ return TPResult::True;
}
// Maybe this is a conversion-function-id.
bool AnyDeclSpecifiers = false;
while (true) {
TPResult TPR = isCXXDeclarationSpecifier();
- if (TPR == TPResult::Error())
+ if (TPR == TPResult::Error)
return TPR;
- if (TPR == TPResult::False()) {
+ if (TPR == TPResult::False) {
if (!AnyDeclSpecifiers)
- return TPResult::Error();
+ return TPResult::Error;
break;
}
- if (TryConsumeDeclarationSpecifier() == TPResult::Error())
- return TPResult::Error();
+ if (TryConsumeDeclarationSpecifier() == TPResult::Error)
+ return TPResult::Error;
AnyDeclSpecifiers = true;
}
return TryParsePtrOperatorSeq();
@@ -797,8 +793,8 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
// declarator:
// direct-declarator
// ptr-operator declarator
- if (TryParsePtrOperatorSeq() == TPResult::Error())
- return TPResult::Error();
+ if (TryParsePtrOperatorSeq() == TPResult::Error)
+ return TPResult::Error;
// direct-declarator:
// direct-abstract-declarator:
@@ -815,8 +811,8 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
else if (Tok.is(tok::identifier))
TentativelyDeclaredIdentifiers.push_back(Tok.getIdentifierInfo());
if (Tok.is(tok::kw_operator)) {
- if (TryParseOperatorId() == TPResult::Error())
- return TPResult::Error();
+ if (TryParseOperatorId() == TPResult::Error)
+ return TPResult::Error;
} else
ConsumeToken();
} else if (Tok.is(tok::l_paren)) {
@@ -829,7 +825,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
// exception-specification[opt]
TPResult TPR = TryParseFunctionDeclarator();
- if (TPR != TPResult::Ambiguous())
+ if (TPR != TPResult::Ambiguous)
return TPR;
} else {
// '(' declarator ')'
@@ -842,20 +838,20 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
Tok.is(tok::kw___fastcall) ||
Tok.is(tok::kw___thiscall) ||
Tok.is(tok::kw___unaligned))
- return TPResult::True(); // attributes indicate declaration
+ return TPResult::True; // attributes indicate declaration
TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier);
- if (TPR != TPResult::Ambiguous())
+ if (TPR != TPResult::Ambiguous)
return TPR;
if (Tok.isNot(tok::r_paren))
- return TPResult::False();
+ return TPResult::False;
ConsumeParen();
}
} else if (!mayBeAbstract) {
- return TPResult::False();
+ return TPResult::False;
}
while (1) {
- TPResult TPR(TPResult::Ambiguous());
+ TPResult TPR(TPResult::Ambiguous);
// abstract-declarator: ...
if (Tok.is(tok::ellipsis))
@@ -881,11 +877,11 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
break;
}
- if (TPR != TPResult::Ambiguous())
+ if (TPR != TPResult::Ambiguous)
return TPR;
}
- return TPResult::Ambiguous();
+ return TPResult::Ambiguous;
}
Parser::TPResult
@@ -935,42 +931,19 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw___alignof:
case tok::kw___builtin_choose_expr:
case tok::kw___builtin_offsetof:
- case tok::kw___builtin_types_compatible_p:
case tok::kw___builtin_va_arg:
case tok::kw___imag:
case tok::kw___real:
case tok::kw___FUNCTION__:
case tok::kw___FUNCDNAME__:
+ case tok::kw___FUNCSIG__:
case tok::kw_L__FUNCTION__:
case tok::kw___PRETTY_FUNCTION__:
- case tok::kw___has_nothrow_assign:
- case tok::kw___has_nothrow_copy:
- case tok::kw___has_nothrow_constructor:
- case tok::kw___has_trivial_assign:
- case tok::kw___has_trivial_copy:
- case tok::kw___has_trivial_constructor:
- case tok::kw___has_trivial_destructor:
- case tok::kw___has_virtual_destructor:
- case tok::kw___is_abstract:
- case tok::kw___is_base_of:
- case tok::kw___is_class:
- case tok::kw___is_convertible_to:
- case tok::kw___is_empty:
- case tok::kw___is_enum:
- case tok::kw___is_interface_class:
- case tok::kw___is_final:
- case tok::kw___is_literal:
- case tok::kw___is_literal_type:
- case tok::kw___is_pod:
- case tok::kw___is_polymorphic:
- case tok::kw___is_sealed:
- case tok::kw___is_trivial:
- case tok::kw___is_trivially_assignable:
- case tok::kw___is_trivially_constructible:
- case tok::kw___is_trivially_copyable:
- case tok::kw___is_union:
case tok::kw___uuidof:
- return TPResult::True();
+#define TYPE_TRAIT(N,Spelling,K) \
+ case tok::kw_##Spelling:
+#include "clang/Basic/TokenKinds.def"
+ return TPResult::True;
// Obviously starts a type-specifier-seq:
case tok::kw_char:
@@ -1015,22 +988,14 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw___vector:
case tok::kw___pixel:
case tok::kw__Atomic:
- case tok::kw_image1d_t:
- case tok::kw_image1d_array_t:
- case tok::kw_image1d_buffer_t:
- case tok::kw_image2d_t:
- case tok::kw_image2d_array_t:
- case tok::kw_image3d_t:
- case tok::kw_sampler_t:
- case tok::kw_event_t:
case tok::kw___unknown_anytype:
- return TPResult::False();
+ return TPResult::False;
default:
break;
}
- return TPResult::Ambiguous();
+ return TPResult::Ambiguous;
}
bool Parser::isTentativelyDeclared(IdentifierInfo *II) {
@@ -1039,16 +1004,16 @@ bool Parser::isTentativelyDeclared(IdentifierInfo *II) {
!= TentativelyDeclaredIdentifiers.end();
}
-/// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration
-/// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could
-/// be either a decl-specifier or a function-style cast, and TPResult::Error()
+/// isCXXDeclarationSpecifier - Returns TPResult::True if it is a declaration
+/// specifier, TPResult::False if it is not, TPResult::Ambiguous if it could
+/// be either a decl-specifier or a function-style cast, and TPResult::Error
/// if a parsing error was found and reported.
///
/// If HasMissingTypename is provided, a name with a dependent scope specifier
/// will be treated as ambiguous if the 'typename' keyword is missing. If this
/// happens, *HasMissingTypename will be set to 'true'. This will also be used
/// as an indicator that undeclared identifiers (which will trigger a later
-/// parse error) should be treated as types. Returns TPResult::Ambiguous() in
+/// parse error) should be treated as types. Returns TPResult::Ambiguous in
/// such cases.
///
/// decl-specifier:
@@ -1152,12 +1117,12 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
// Check for need to substitute AltiVec __vector keyword
// for "vector" identifier.
if (TryAltiVecVectorToken())
- return TPResult::True();
+ return TPResult::True;
const Token &Next = NextToken();
// In 'foo bar', 'foo' is always a type name outside of Objective-C.
if (!getLangOpts().ObjC1 && Next.is(tok::identifier))
- return TPResult::True();
+ return TPResult::True;
if (Next.isNot(tok::coloncolon) && Next.isNot(tok::less)) {
// Determine whether this is a valid expression. If not, we will hit
@@ -1170,15 +1135,15 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
switch (TryAnnotateName(false /* no nested name specifier */,
&TypoCorrection)) {
case ANK_Error:
- return TPResult::Error();
+ return TPResult::Error;
case ANK_TentativeDecl:
- return TPResult::False();
+ return TPResult::False;
case ANK_TemplateName:
// A bare type template-name which can't be a template template
// argument is an error, and was probably intended to be a type.
- return GreaterThanIsOperator ? TPResult::True() : TPResult::False();
+ return GreaterThanIsOperator ? TPResult::True : TPResult::False;
case ANK_Unresolved:
- return HasMissingTypename ? TPResult::Ambiguous() : TPResult::False();
+ return HasMissingTypename ? TPResult::Ambiguous : TPResult::False;
case ANK_Success:
break;
}
@@ -1190,12 +1155,12 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
// since it will annotate as a primary expression, and we want to use the
// "missing 'typename'" logic.
if (TryAnnotateTypeOrScopeToken())
- return TPResult::Error();
+ return TPResult::Error;
// If annotation failed, assume it's a non-type.
// FIXME: If this happens due to an undeclared identifier, treat it as
// ambiguous.
if (Tok.is(tok::identifier))
- return TPResult::False();
+ return TPResult::False;
}
// We annotated this token as something. Recurse to handle whatever we got.
@@ -1206,21 +1171,21 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
if (TryAnnotateTypeOrScopeToken())
- return TPResult::Error();
+ return TPResult::Error;
return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);
case tok::coloncolon: { // ::foo::bar
const Token &Next = NextToken();
if (Next.is(tok::kw_new) || // ::new
Next.is(tok::kw_delete)) // ::delete
- return TPResult::False();
+ return TPResult::False;
}
// Fall through.
case tok::kw_decltype:
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
if (TryAnnotateTypeOrScopeToken())
- return TPResult::Error();
+ return TPResult::Error;
return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);
// decl-specifier:
@@ -1277,7 +1242,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
case tok::kw_restrict:
case tok::kw__Complex:
case tok::kw___attribute:
- return TPResult::True();
+ return TPResult::True;
// Microsoft
case tok::kw___declspec:
@@ -1292,20 +1257,20 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
case tok::kw___ptr32:
case tok::kw___forceinline:
case tok::kw___unaligned:
- return TPResult::True();
+ return TPResult::True;
// Borland
case tok::kw___pascal:
- return TPResult::True();
+ return TPResult::True;
// AltiVec
case tok::kw___vector:
- return TPResult::True();
+ return TPResult::True;
case tok::annot_template_id: {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (TemplateId->Kind != TNK_Type_template)
- return TPResult::False();
+ return TPResult::False;
CXXScopeSpec SS;
AnnotateTemplateIdTokenAsType();
assert(Tok.is(tok::annot_typename));
@@ -1315,7 +1280,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed
// We've already annotated a scope; try to annotate a type.
if (TryAnnotateTypeOrScopeToken())
- return TPResult::Error();
+ return TPResult::Error;
if (!Tok.is(tok::annot_typename)) {
// If the next token is an identifier or a type qualifier, then this
// can't possibly be a valid expression either.
@@ -1329,37 +1294,37 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
ConsumeToken();
ConsumeToken();
bool isIdentifier = Tok.is(tok::identifier);
- TPResult TPR = TPResult::False();
+ TPResult TPR = TPResult::False;
if (!isIdentifier)
TPR = isCXXDeclarationSpecifier(BracedCastResult,
HasMissingTypename);
PA.Revert();
if (isIdentifier ||
- TPR == TPResult::True() || TPR == TPResult::Error())
- return TPResult::Error();
+ TPR == TPResult::True || TPR == TPResult::Error)
+ return TPResult::Error;
if (HasMissingTypename) {
// We can't tell whether this is a missing 'typename' or a valid
// expression.
*HasMissingTypename = true;
- return TPResult::Ambiguous();
+ return TPResult::Ambiguous;
}
} else {
// Try to resolve the name. If it doesn't exist, assume it was
// intended to name a type and keep disambiguating.
switch (TryAnnotateName(false /* SS is not dependent */)) {
case ANK_Error:
- return TPResult::Error();
+ return TPResult::Error;
case ANK_TentativeDecl:
- return TPResult::False();
+ return TPResult::False;
case ANK_TemplateName:
// A bare type template-name which can't be a template template
// argument is an error, and was probably intended to be a type.
- return GreaterThanIsOperator ? TPResult::True() : TPResult::False();
+ return GreaterThanIsOperator ? TPResult::True : TPResult::False;
case ANK_Unresolved:
- return HasMissingTypename ? TPResult::Ambiguous()
- : TPResult::False();
+ return HasMissingTypename ? TPResult::Ambiguous
+ : TPResult::False;
case ANK_Success:
// Annotated it, check again.
assert(Tok.isNot(tok::annot_cxxscope) ||
@@ -1369,7 +1334,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
}
}
}
- return TPResult::False();
+ return TPResult::False;
}
// If that succeeded, fallthrough into the generic simple-type-id case.
@@ -1405,16 +1370,16 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
PA.Revert();
- if (TPR == TPResult::Error())
- return TPResult::Error();
+ if (TPR == TPResult::Error)
+ return TPResult::Error;
if (isFollowedByParen)
- return TPResult::Ambiguous();
+ return TPResult::Ambiguous;
if (getLangOpts().CPlusPlus11 && isFollowedByBrace)
return BracedCastResult;
- return TPResult::True();
+ return TPResult::True;
}
case tok::kw_char:
@@ -1435,7 +1400,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
case tok::kw_void:
case tok::annot_decltype:
if (NextToken().is(tok::l_paren))
- return TPResult::Ambiguous();
+ return TPResult::Ambiguous;
// This is a function-style cast in all cases we disambiguate other than
// one:
@@ -1447,14 +1412,14 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
return BracedCastResult;
if (isStartOfObjCClassMessageMissingOpenBracket())
- return TPResult::False();
+ return TPResult::False;
- return TPResult::True();
+ return TPResult::True;
// GNU typeof support.
case tok::kw_typeof: {
if (NextToken().isNot(tok::l_paren))
- return TPResult::True();
+ return TPResult::True;
TentativeParsingAction PA(*this);
@@ -1464,28 +1429,28 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
PA.Revert();
- if (TPR == TPResult::Error())
- return TPResult::Error();
+ if (TPR == TPResult::Error)
+ return TPResult::Error;
if (isFollowedByParen)
- return TPResult::Ambiguous();
+ return TPResult::Ambiguous;
if (getLangOpts().CPlusPlus11 && isFollowedByBrace)
return BracedCastResult;
- return TPResult::True();
+ return TPResult::True;
}
// C++0x type traits support
case tok::kw___underlying_type:
- return TPResult::True();
+ return TPResult::True;
// C11 _Atomic
case tok::kw__Atomic:
- return TPResult::True();
+ return TPResult::True;
default:
- return TPResult::False();
+ return TPResult::False;
}
}
@@ -1551,9 +1516,9 @@ Parser::TPResult Parser::TryParseTypeofSpecifier() {
// Parse through the parens after 'typeof'.
ConsumeParen();
if (!SkipUntil(tok::r_paren, StopAtSemi))
- return TPResult::Error();
+ return TPResult::Error;
- return TPResult::Ambiguous();
+ return TPResult::Ambiguous;
}
/// [ObjC] protocol-qualifiers:
@@ -1563,7 +1528,7 @@ Parser::TPResult Parser::TryParseProtocolQualifiers() {
ConsumeToken();
do {
if (Tok.isNot(tok::identifier))
- return TPResult::Error();
+ return TPResult::Error;
ConsumeToken();
if (Tok.is(tok::comma)) {
@@ -1573,11 +1538,11 @@ Parser::TPResult Parser::TryParseProtocolQualifiers() {
if (Tok.is(tok::greater)) {
ConsumeToken();
- return TPResult::Ambiguous();
+ return TPResult::Ambiguous;
}
} while (false);
- return TPResult::Error();
+ return TPResult::Error;
}
/// isCXXFunctionDeclarator - Disambiguates between a function declarator or
@@ -1606,9 +1571,9 @@ bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) {
ConsumeParen();
bool InvalidAsDeclaration = false;
TPResult TPR = TryParseParameterDeclarationClause(&InvalidAsDeclaration);
- if (TPR == TPResult::Ambiguous()) {
+ if (TPR == TPResult::Ambiguous) {
if (Tok.isNot(tok::r_paren))
- TPR = TPResult::False();
+ TPR = TPResult::False;
else {
const Token &Next = NextToken();
if (Next.is(tok::amp) || Next.is(tok::ampamp) ||
@@ -1620,20 +1585,20 @@ bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) {
// The next token cannot appear after a constructor-style initializer,
// and can appear next in a function definition. This must be a function
// declarator.
- TPR = TPResult::True();
+ TPR = TPResult::True;
else if (InvalidAsDeclaration)
// Use the absence of 'typename' as a tie-breaker.
- TPR = TPResult::False();
+ TPR = TPResult::False;
}
}
PA.Revert();
- if (IsAmbiguous && TPR == TPResult::Ambiguous())
+ if (IsAmbiguous && TPR == TPResult::Ambiguous)
*IsAmbiguous = true;
// In case of an error, let the declaration parsing code handle it.
- return TPR != TPResult::False();
+ return TPR != TPResult::False;
}
/// parameter-declaration-clause:
@@ -1658,7 +1623,7 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration,
bool VersusTemplateArgument) {
if (Tok.is(tok::r_paren))
- return TPResult::Ambiguous();
+ return TPResult::Ambiguous;
// parameter-declaration-list[opt] '...'[opt]
// parameter-declaration-list ',' '...'
@@ -1672,15 +1637,15 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration,
if (Tok.is(tok::ellipsis)) {
ConsumeToken();
if (Tok.is(tok::r_paren))
- return TPResult::True(); // '...)' is a sign of a function declarator.
+ return TPResult::True; // '...)' is a sign of a function declarator.
else
- return TPResult::False();
+ return TPResult::False;
}
// An attribute-specifier-seq here is a sign of a function declarator.
if (isCXX11AttributeSpecifier(/*Disambiguate*/false,
/*OuterMightBeMessageSend*/true))
- return TPResult::True();
+ return TPResult::True;
ParsedAttributes attrs(AttrFactory);
MaybeParseMicrosoftAttributes(attrs);
@@ -1688,43 +1653,43 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration,
// decl-specifier-seq
// A parameter-declaration's initializer must be preceded by an '=', so
// decl-specifier-seq '{' is not a parameter in C++11.
- TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(),
+ TPResult TPR = isCXXDeclarationSpecifier(TPResult::False,
InvalidAsDeclaration);
- if (VersusTemplateArgument && TPR == TPResult::True()) {
+ if (VersusTemplateArgument && TPR == TPResult::True) {
// Consume the decl-specifier-seq. We have to look past it, since a
// type-id might appear here in a template argument.
bool SeenType = false;
do {
SeenType |= isCXXDeclarationSpecifierAType();
- if (TryConsumeDeclarationSpecifier() == TPResult::Error())
- return TPResult::Error();
+ if (TryConsumeDeclarationSpecifier() == TPResult::Error)
+ return TPResult::Error;
// If we see a parameter name, this can't be a template argument.
if (SeenType && Tok.is(tok::identifier))
- return TPResult::True();
+ return TPResult::True;
- TPR = isCXXDeclarationSpecifier(TPResult::False(),
+ TPR = isCXXDeclarationSpecifier(TPResult::False,
InvalidAsDeclaration);
- if (TPR == TPResult::Error())
+ if (TPR == TPResult::Error)
return TPR;
- } while (TPR != TPResult::False());
- } else if (TPR == TPResult::Ambiguous()) {
+ } while (TPR != TPResult::False);
+ } else if (TPR == TPResult::Ambiguous) {
// Disambiguate what follows the decl-specifier.
- if (TryConsumeDeclarationSpecifier() == TPResult::Error())
- return TPResult::Error();
+ if (TryConsumeDeclarationSpecifier() == TPResult::Error)
+ return TPResult::Error;
} else
return TPR;
// declarator
// abstract-declarator[opt]
TPR = TryParseDeclarator(true/*mayBeAbstract*/);
- if (TPR != TPResult::Ambiguous())
+ if (TPR != TPResult::Ambiguous)
return TPR;
// [GNU] attributes[opt]
if (Tok.is(tok::kw___attribute))
- return TPResult::True();
+ return TPResult::True;
// If we're disambiguating a template argument in a default argument in
// a class definition versus a parameter declaration, an '=' here
@@ -1737,37 +1702,36 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration,
// parameter-declaration-clause, and the last param is missing its default
// argument.
if (VersusTemplateArgument)
- return (Tok.is(tok::equal) || Tok.is(tok::r_paren)) ? TPResult::True()
- : TPResult::False();
+ return (Tok.is(tok::equal) || Tok.is(tok::r_paren)) ? TPResult::True
+ : TPResult::False;
if (Tok.is(tok::equal)) {
// '=' assignment-expression
// Parse through assignment-expression.
// FIXME: assignment-expression may contain an unparenthesized comma.
if (!SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch))
- return TPResult::Error();
+ return TPResult::Error;
}
if (Tok.is(tok::ellipsis)) {
ConsumeToken();
if (Tok.is(tok::r_paren))
- return TPResult::True(); // '...)' is a sign of a function declarator.
+ return TPResult::True; // '...)' is a sign of a function declarator.
else
- return TPResult::False();
+ return TPResult::False;
}
- if (Tok.isNot(tok::comma))
+ if (!TryConsumeToken(tok::comma))
break;
- ConsumeToken(); // the comma.
}
- return TPResult::Ambiguous();
+ return TPResult::Ambiguous;
}
/// TryParseFunctionDeclarator - We parsed a '(' and we want to try to continue
/// parsing as a function declarator.
/// If TryParseFunctionDeclarator fully parsed the function declarator, it will
-/// return TPResult::Ambiguous(), otherwise it will return either False() or
+/// return TPResult::Ambiguous, otherwise it will return either False() or
/// Error().
///
/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
@@ -1781,15 +1745,15 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() {
// The '(' is already parsed.
TPResult TPR = TryParseParameterDeclarationClause();
- if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren))
- TPR = TPResult::False();
+ if (TPR == TPResult::Ambiguous && Tok.isNot(tok::r_paren))
+ TPR = TPResult::False;
- if (TPR == TPResult::False() || TPR == TPResult::Error())
+ if (TPR == TPResult::False || TPR == TPResult::Error)
return TPR;
// Parse through the parens.
if (!SkipUntil(tok::r_paren, StopAtSemi))
- return TPResult::Error();
+ return TPResult::Error;
// cv-qualifier-seq
while (Tok.is(tok::kw_const) ||
@@ -1805,12 +1769,12 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() {
if (Tok.is(tok::kw_throw)) {
ConsumeToken();
if (Tok.isNot(tok::l_paren))
- return TPResult::Error();
+ return TPResult::Error;
// Parse through the parens after 'throw'.
ConsumeParen();
if (!SkipUntil(tok::r_paren, StopAtSemi))
- return TPResult::Error();
+ return TPResult::Error;
}
if (Tok.is(tok::kw_noexcept)) {
ConsumeToken();
@@ -1819,11 +1783,11 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() {
// Find the matching rparen.
ConsumeParen();
if (!SkipUntil(tok::r_paren, StopAtSemi))
- return TPResult::Error();
+ return TPResult::Error;
}
}
- return TPResult::Ambiguous();
+ return TPResult::Ambiguous;
}
/// '[' constant-expression[opt] ']'
@@ -1831,7 +1795,7 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() {
Parser::TPResult Parser::TryParseBracketDeclarator() {
ConsumeBracket();
if (!SkipUntil(tok::r_square, StopAtSemi))
- return TPResult::Error();
+ return TPResult::Error;
- return TPResult::Ambiguous();
+ return TPResult::Ambiguous;
}
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 457dd36cbe9b..37ce157e0812 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -12,9 +12,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
-#include "ParsePragma.h"
#include "RAIIObjectsForParser.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
@@ -33,7 +33,7 @@ class ActionCommentHandler : public CommentHandler {
public:
explicit ActionCommentHandler(Sema &S) : S(S) { }
- virtual bool HandleComment(Preprocessor &PP, SourceRange Comment) {
+ bool HandleComment(Preprocessor &PP, SourceRange Comment) override {
S.ActOnComment(Comment);
return false;
}
@@ -56,58 +56,14 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
SkipFunctionBodies = pp.isCodeCompletionEnabled() || skipFunctionBodies;
Tok.startToken();
Tok.setKind(tok::eof);
- Actions.CurScope = 0;
+ Actions.CurScope = nullptr;
NumCachedScopes = 0;
ParenCount = BracketCount = BraceCount = 0;
- CurParsedObjCImpl = 0;
+ CurParsedObjCImpl = nullptr;
// Add #pragma handlers. These are removed and destroyed in the
// destructor.
- AlignHandler.reset(new PragmaAlignHandler());
- PP.AddPragmaHandler(AlignHandler.get());
-
- GCCVisibilityHandler.reset(new PragmaGCCVisibilityHandler());
- PP.AddPragmaHandler("GCC", GCCVisibilityHandler.get());
-
- OptionsHandler.reset(new PragmaOptionsHandler());
- PP.AddPragmaHandler(OptionsHandler.get());
-
- PackHandler.reset(new PragmaPackHandler());
- PP.AddPragmaHandler(PackHandler.get());
-
- MSStructHandler.reset(new PragmaMSStructHandler());
- PP.AddPragmaHandler(MSStructHandler.get());
-
- UnusedHandler.reset(new PragmaUnusedHandler());
- PP.AddPragmaHandler(UnusedHandler.get());
-
- WeakHandler.reset(new PragmaWeakHandler());
- PP.AddPragmaHandler(WeakHandler.get());
-
- RedefineExtnameHandler.reset(new PragmaRedefineExtnameHandler());
- PP.AddPragmaHandler(RedefineExtnameHandler.get());
-
- FPContractHandler.reset(new PragmaFPContractHandler());
- PP.AddPragmaHandler("STDC", FPContractHandler.get());
-
- if (getLangOpts().OpenCL) {
- OpenCLExtensionHandler.reset(new PragmaOpenCLExtensionHandler());
- PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get());
-
- PP.AddPragmaHandler("OPENCL", FPContractHandler.get());
- }
- if (getLangOpts().OpenMP)
- OpenMPHandler.reset(new PragmaOpenMPHandler());
- else
- OpenMPHandler.reset(new PragmaNoOpenMPHandler());
- PP.AddPragmaHandler(OpenMPHandler.get());
-
- if (getLangOpts().MicrosoftExt) {
- MSCommentHandler.reset(new PragmaCommentHandler(actions));
- PP.AddPragmaHandler(MSCommentHandler.get());
- MSDetectMismatchHandler.reset(new PragmaDetectMismatchHandler(actions));
- PP.AddPragmaHandler(MSDetectMismatchHandler.get());
- }
+ initializePragmaHandlers();
CommentSemaHandler.reset(new ActionCommentHandler(actions));
PP.addCommentHandler(CommentSemaHandler.get());
@@ -152,14 +108,8 @@ static bool IsCommonTypo(tok::TokenKind ExpectedTok, const Token &Tok) {
}
}
-/// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the
-/// input. If so, it is consumed and false is returned.
-///
-/// If the input is malformed, this emits the specified diagnostic. Next, if
-/// SkipToTok is specified, it calls SkipUntil(SkipToTok). Finally, true is
-/// returned.
bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
- const char *Msg, tok::TokenKind SkipToTok) {
+ StringRef Msg) {
if (Tok.is(ExpectedTok) || Tok.is(tok::code_completion)) {
ConsumeAnyToken();
return false;
@@ -168,35 +118,48 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
// Detect common single-character typos and resume.
if (IsCommonTypo(ExpectedTok, Tok)) {
SourceLocation Loc = Tok.getLocation();
- Diag(Loc, DiagID)
- << Msg
- << FixItHint::CreateReplacement(SourceRange(Loc),
- getTokenSimpleSpelling(ExpectedTok));
- ConsumeAnyToken();
+ {
+ DiagnosticBuilder DB = Diag(Loc, DiagID);
+ DB << FixItHint::CreateReplacement(
+ SourceRange(Loc), tok::getPunctuatorSpelling(ExpectedTok));
+ if (DiagID == diag::err_expected)
+ DB << ExpectedTok;
+ else if (DiagID == diag::err_expected_after)
+ DB << Msg << ExpectedTok;
+ else
+ DB << Msg;
+ }
// Pretend there wasn't a problem.
+ ConsumeAnyToken();
return false;
}
- const char *Spelling = 0;
SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation);
- if (EndLoc.isValid() &&
- (Spelling = tok::getTokenSimpleSpelling(ExpectedTok))) {
- // Show what code to insert to fix this problem.
- Diag(EndLoc, DiagID)
- << Msg
- << FixItHint::CreateInsertion(EndLoc, Spelling);
- } else
- Diag(Tok, DiagID) << Msg;
+ const char *Spelling = nullptr;
+ if (EndLoc.isValid())
+ Spelling = tok::getPunctuatorSpelling(ExpectedTok);
+
+ DiagnosticBuilder DB =
+ Spelling
+ ? Diag(EndLoc, DiagID) << FixItHint::CreateInsertion(EndLoc, Spelling)
+ : Diag(Tok, DiagID);
+ if (DiagID == diag::err_expected)
+ DB << ExpectedTok;
+ else if (DiagID == diag::err_expected_after)
+ DB << Msg << ExpectedTok;
+ else
+ DB << Msg;
- if (SkipToTok != tok::unknown)
- SkipUntil(SkipToTok, StopAtSemi);
return true;
}
bool Parser::ExpectAndConsumeSemi(unsigned DiagID) {
- if (Tok.is(tok::semi) || Tok.is(tok::code_completion)) {
- ConsumeToken();
+ if (TryConsumeToken(tok::semi))
+ return false;
+
+ if (Tok.is(tok::code_completion)) {
+ handleUnexpectedCodeCompletionToken();
return false;
}
@@ -241,7 +204,8 @@ void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST) {
if (Kind != AfterMemberFunctionDefinition || HadMultipleSemis)
Diag(StartLoc, diag::ext_extra_semi)
- << Kind << DeclSpec::getSpecifierName((DeclSpec::TST)TST)
+ << Kind << DeclSpec::getSpecifierName((DeclSpec::TST)TST,
+ Actions.getASTContext().getPrintingPolicy())
<< FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));
else
// A single semicolon is valid after a member function definition.
@@ -288,7 +252,7 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
if (Toks.size() == 1 && Toks[0] == tok::eof &&
!HasFlagsSet(Flags, StopAtSemi) &&
!HasFlagsSet(Flags, StopAtCodeCompletion)) {
- while (Tok.getKind() != tok::eof)
+ while (Tok.isNot(tok::eof))
ConsumeAnyToken();
return true;
}
@@ -297,10 +261,20 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
case tok::eof:
// Ran out of tokens.
return false;
-
+
+ case tok::annot_pragma_openmp_end:
+ // Stop before an OpenMP pragma boundary.
+ case tok::annot_module_begin:
+ case tok::annot_module_end:
+ case tok::annot_module_include:
+ // Stop before we change submodules. They generally indicate a "good"
+ // place to pick up parsing again (except in the special case where
+ // we're trying to skip to EOF).
+ return false;
+
case tok::code_completion:
if (!HasFlagsSet(Flags, StopAtCodeCompletion))
- ConsumeToken();
+ handleUnexpectedCodeCompletionToken();
return false;
case tok::l_paren:
@@ -391,8 +365,7 @@ void Parser::ExitScope() {
// Inform the actions module that this scope is going away if there are any
// decls in it.
- if (!getCurScope()->decl_empty())
- Actions.ActOnPopScope(Tok.getLocation(), getCurScope());
+ Actions.ActOnPopScope(Tok.getLocation(), getCurScope());
Scope *OldScope = getCurScope();
Actions.CurScope = OldScope->getParent();
@@ -407,7 +380,7 @@ void Parser::ExitScope() {
/// this object does nothing.
Parser::ParseScopeFlags::ParseScopeFlags(Parser *Self, unsigned ScopeFlags,
bool ManageFlags)
- : CurScope(ManageFlags ? Self->getCurScope() : 0) {
+ : CurScope(ManageFlags ? Self->getCurScope() : nullptr) {
if (CurScope) {
OldFlags = CurScope->getFlags();
CurScope->setFlags(ScopeFlags);
@@ -429,47 +402,13 @@ Parser::ParseScopeFlags::~ParseScopeFlags() {
Parser::~Parser() {
// If we still have scopes active, delete the scope tree.
delete getCurScope();
- Actions.CurScope = 0;
-
+ Actions.CurScope = nullptr;
+
// Free the scope cache.
for (unsigned i = 0, e = NumCachedScopes; i != e; ++i)
delete ScopeCache[i];
- // Remove the pragma handlers we installed.
- PP.RemovePragmaHandler(AlignHandler.get());
- AlignHandler.reset();
- PP.RemovePragmaHandler("GCC", GCCVisibilityHandler.get());
- GCCVisibilityHandler.reset();
- PP.RemovePragmaHandler(OptionsHandler.get());
- OptionsHandler.reset();
- PP.RemovePragmaHandler(PackHandler.get());
- PackHandler.reset();
- PP.RemovePragmaHandler(MSStructHandler.get());
- MSStructHandler.reset();
- PP.RemovePragmaHandler(UnusedHandler.get());
- UnusedHandler.reset();
- PP.RemovePragmaHandler(WeakHandler.get());
- WeakHandler.reset();
- PP.RemovePragmaHandler(RedefineExtnameHandler.get());
- RedefineExtnameHandler.reset();
-
- if (getLangOpts().OpenCL) {
- PP.RemovePragmaHandler("OPENCL", OpenCLExtensionHandler.get());
- OpenCLExtensionHandler.reset();
- PP.RemovePragmaHandler("OPENCL", FPContractHandler.get());
- }
- PP.RemovePragmaHandler(OpenMPHandler.get());
- OpenMPHandler.reset();
-
- if (getLangOpts().MicrosoftExt) {
- PP.RemovePragmaHandler(MSCommentHandler.get());
- MSCommentHandler.reset();
- PP.RemovePragmaHandler(MSDetectMismatchHandler.get());
- MSDetectMismatchHandler.reset();
- }
-
- PP.RemovePragmaHandler("STDC", FPContractHandler.get());
- FPContractHandler.reset();
+ resetPragmaHandlers();
PP.removeCommentHandler(CommentSemaHandler.get());
@@ -482,7 +421,7 @@ Parser::~Parser() {
///
void Parser::Initialize() {
// Create the translation unit scope. Install it as the current scope.
- assert(getCurScope() == 0 && "A scope is already active?");
+ assert(getCurScope() == nullptr && "A scope is already active?");
EnterScope(Scope::DeclScope);
Actions.ActOnTranslationUnitScope(getCurScope());
@@ -497,10 +436,10 @@ void Parser::Initialize() {
ObjCTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref");
}
- Ident_instancetype = 0;
- Ident_final = 0;
- Ident_sealed = 0;
- Ident_override = 0;
+ Ident_instancetype = nullptr;
+ Ident_final = nullptr;
+ Ident_sealed = nullptr;
+ Ident_override = nullptr;
Ident_super = &PP.getIdentifierTable().get("super");
@@ -510,16 +449,18 @@ void Parser::Initialize() {
Ident_bool = &PP.getIdentifierTable().get("bool");
}
- Ident_introduced = 0;
- Ident_deprecated = 0;
- Ident_obsoleted = 0;
- Ident_unavailable = 0;
+ Ident_introduced = nullptr;
+ Ident_deprecated = nullptr;
+ Ident_obsoleted = nullptr;
+ Ident_unavailable = nullptr;
- Ident__except = 0;
-
- Ident__exception_code = Ident__exception_info = Ident__abnormal_termination = 0;
- Ident___exception_code = Ident___exception_info = Ident___abnormal_termination = 0;
- Ident_GetExceptionCode = Ident_GetExceptionInfo = Ident_AbnormalTermination = 0;
+ Ident__except = nullptr;
+
+ Ident__exception_code = Ident__exception_info = nullptr;
+ Ident__abnormal_termination = Ident___exception_code = nullptr;
+ Ident___exception_info = Ident___abnormal_termination = nullptr;
+ Ident_GetExceptionCode = Ident_GetExceptionInfo = nullptr;
+ Ident_AbnormalTermination = nullptr;
if(getLangOpts().Borland) {
Ident__exception_info = PP.getIdentifierInfo("_exception_info");
@@ -574,7 +515,7 @@ namespace {
bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(TemplateIds);
- // Skip over the EOF token, flagging end of previous input for incremental
+ // Skip over the EOF token, flagging end of previous input for incremental
// processing
if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::eof))
ConsumeToken();
@@ -592,6 +533,12 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
ConsumeToken();
return false;
+ case tok::annot_module_begin:
+ case tok::annot_module_end:
+ // FIXME: Update visibility based on the submodule we're in.
+ ConsumeToken();
+ return false;
+
case tok::eof:
// Late template parsing can begin.
if (getLangOpts().DelayedTemplateParsing)
@@ -647,7 +594,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
return DeclGroupPtrTy();
}
- Decl *SingleDecl = 0;
+ Decl *SingleDecl = nullptr;
switch (Tok.getKind()) {
case tok::annot_pragma_vis:
HandlePragmaVisibility();
@@ -679,6 +626,15 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::annot_pragma_openmp:
ParseOpenMPDeclarativeDirective();
return DeclGroupPtrTy();
+ case tok::annot_pragma_ms_pointers_to_members:
+ HandlePragmaMSPointersToMembers();
+ return DeclGroupPtrTy();
+ case tok::annot_pragma_ms_vtordisp:
+ HandlePragmaMSVtorDisp();
+ return DeclGroupPtrTy();
+ case tok::annot_pragma_ms_pragma:
+ HandlePragmaMSPragma();
+ return DeclGroupPtrTy();
case tok::semi:
// Either a C++11 empty-declaration or attribute-declaration.
SingleDecl = Actions.ActOnEmptyDeclaration(getCurScope(),
@@ -706,7 +662,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
SourceLocation EndLoc;
ExprResult Result(ParseSimpleAsm(&EndLoc));
- ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
+ ExpectAndConsume(tok::semi, diag::err_expected_after,
"top-level asm block");
if (Result.isInvalid())
@@ -793,7 +749,6 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
ParseExplicitInstantiation(Declarator::FileContext,
ExternLoc, TemplateLoc, DeclEnd));
}
- // FIXME: Detect C++ linkage specifications here?
goto dont_know;
case tok::kw___if_exists:
@@ -907,9 +862,10 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
DS.abort();
- const char *PrevSpec = 0;
+ const char *PrevSpec = nullptr;
unsigned DiagID;
- if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec, DiagID))
+ if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec, DiagID,
+ Actions.getASTContext().getPrintingPolicy()))
Diag(AtLoc, DiagID) << PrevSpec;
if (Tok.isObjCAtKeyword(tok::objc_protocol))
@@ -922,7 +878,7 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
// If the declspec consisted only of 'extern' and we have a string
// literal following it, this must be a C++ linkage specifier like
// 'extern "C"'.
- if (Tok.is(tok::string_literal) && getLangOpts().CPlusPlus &&
+ if (getLangOpts().CPlusPlus && isTokenStringLiteral() &&
DS.getStorageClassSpec() == DeclSpec::SCS_extern &&
DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) {
Decl *TheDecl = ParseLinkage(DS, Declarator::FileContext);
@@ -949,26 +905,6 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributesWithRange &attrs,
}
}
-
-static inline bool isFunctionDeclaratorRequiringReturnTypeDeduction(
- const Declarator &D) {
- if (!D.isFunctionDeclarator() || !D.getDeclSpec().containsPlaceholderType())
- return false;
- for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) {
- unsigned chunkIndex = E - I - 1;
- const DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex);
- if (DeclType.Kind == DeclaratorChunk::Function) {
- const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
- if (!FTI.hasTrailingReturnType())
- return true;
- QualType TrailingRetType = FTI.getTrailingReturnType().get();
- return TrailingRetType->getCanonicalTypeInternal()
- ->getContainedAutoType();
- }
- }
- return false;
-}
-
/// ParseFunctionDefinition - We parsed and verified that the specified
/// Declarator is well formed. If this is a K&R-style function, read the
/// parameters declaration-list, then start the compound-statement.
@@ -996,9 +932,11 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (getLangOpts().ImplicitInt && D.getDeclSpec().isEmpty()) {
const char *PrevSpec;
unsigned DiagID;
+ const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy();
D.getMutableDeclSpec().SetTypeSpecType(DeclSpec::TST_int,
D.getIdentifierLoc(),
- PrevSpec, DiagID);
+ PrevSpec, DiagID,
+ Policy);
D.SetRangeBegin(D.getDeclSpec().getSourceRange().getBegin());
}
@@ -1021,7 +959,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// If we didn't find the '{', bail out.
if (Tok.isNot(tok::l_brace))
- return 0;
+ return nullptr;
}
// Check to make sure that any normal attributes are allowed to be on
@@ -1029,10 +967,10 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (Tok.isNot(tok::equal)) {
AttributeList *DtorAttrs = D.getAttributes();
while (DtorAttrs) {
- if (!IsThreadSafetyAttribute(DtorAttrs->getName()->getName()) &&
+ if (DtorAttrs->isKnownToGCC() &&
!DtorAttrs->isCXX11Attribute()) {
Diag(DtorAttrs->getLoc(), diag::warn_attribute_on_function_definition)
- << DtorAttrs->getName()->getName();
+ << DtorAttrs->getName();
}
DtorAttrs = DtorAttrs->getNext();
}
@@ -1042,8 +980,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// tokens and store them for late parsing at the end of the translation unit.
if (getLangOpts().DelayedTemplateParsing && Tok.isNot(tok::equal) &&
TemplateInfo.Kind == ParsedTemplateInfo::Template &&
- !D.getDeclSpec().isConstexprSpecified() &&
- !isFunctionDeclaratorRequiringReturnTypeDeduction(D)) {
+ Actions.canDelayFunctionBody(D)) {
MultiTemplateParamsArg TemplateParameterLists(*TemplateInfo.TemplateParams);
ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
@@ -1059,12 +996,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
LexTemplateFunctionForLateParsing(Toks);
if (DP) {
- FunctionDecl *FnD = 0;
- if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(DP))
- FnD = FunTmpl->getTemplatedDecl();
- else
- FnD = cast<FunctionDecl>(DP);
-
+ FunctionDecl *FnD = DP->getAsFunction();
Actions.CheckForFunctionRedefinition(FnD);
Actions.MarkAsLateParsedTemplate(FnD, DP, Toks);
}
@@ -1077,7 +1009,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
Actions.CurContext->isTranslationUnit()) {
ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
Scope *ParentScope = getCurScope()->getParent();
-
+
D.setFunctionDefinitionKind(FDK_Definition);
Decl *FuncDecl = Actions.HandleDeclarator(ParentScope, D,
MultiTemplateParamsArg());
@@ -1089,8 +1021,9 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
CurParsedObjCImpl->HasCFunction = true;
return FuncDecl;
}
+ // FIXME: Should we really fall through here?
}
-
+
// Enter a scope for the function body.
ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
@@ -1108,28 +1041,22 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// safe because we're always the sole owner.
D.getMutableDeclSpec().abort();
- if (Tok.is(tok::equal)) {
+ if (TryConsumeToken(tok::equal)) {
assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='");
- ConsumeToken();
+ Actions.ActOnFinishFunctionBody(Res, nullptr, false);
- Actions.ActOnFinishFunctionBody(Res, 0, false);
-
bool Delete = false;
SourceLocation KWLoc;
- if (Tok.is(tok::kw_delete)) {
- Diag(Tok, getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_deleted_function :
- diag::ext_deleted_function);
-
- KWLoc = ConsumeToken();
+ if (TryConsumeToken(tok::kw_delete, KWLoc)) {
+ Diag(KWLoc, getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_deleted_function
+ : diag::ext_deleted_function);
Actions.SetDeclDeleted(Res, KWLoc);
Delete = true;
- } else if (Tok.is(tok::kw_default)) {
- Diag(Tok, getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_defaulted_function :
- diag::ext_defaulted_function);
-
- KWLoc = ConsumeToken();
+ } else if (TryConsumeToken(tok::kw_default, KWLoc)) {
+ Diag(KWLoc, getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_defaulted_function
+ : diag::ext_defaulted_function);
Actions.SetDeclDefaulted(Res, KWLoc);
} else {
llvm_unreachable("function definition after = not 'delete' or 'default'");
@@ -1139,9 +1066,9 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
Diag(KWLoc, diag::err_default_delete_in_multiple_declaration)
<< Delete;
SkipUntil(tok::semi);
- } else {
- ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
- Delete ? "delete" : "default", tok::semi);
+ } else if (ExpectAndConsume(tok::semi, diag::err_expected_after,
+ Delete ? "delete" : "default")) {
+ SkipUntil(tok::semi);
}
return Res;
@@ -1158,7 +1085,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// Recover from error.
if (!Tok.is(tok::l_brace)) {
BodyScope.Exit();
- Actions.ActOnFinishFunctionBody(Res, 0);
+ Actions.ActOnFinishFunctionBody(Res, nullptr);
return Res;
}
} else
@@ -1195,9 +1122,8 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
// NOTE: GCC just makes this an ext-warn. It's not clear what it does with
// the declarations though. It's trivial to ignore them, really hard to do
// anything else with them.
- if (Tok.is(tok::semi)) {
+ if (TryConsumeToken(tok::semi)) {
Diag(DSStart, diag::err_declaration_does_not_declare_param);
- ConsumeToken();
continue;
}
@@ -1237,20 +1163,20 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
for (unsigned i = 0; ; ++i) {
// C99 6.9.1p6: those declarators shall declare only identifiers from
// the identifier list.
- if (i == FTI.NumArgs) {
+ if (i == FTI.NumParams) {
Diag(ParmDeclarator.getIdentifierLoc(), diag::err_no_matching_param)
<< ParmDeclarator.getIdentifier();
break;
}
- if (FTI.ArgInfo[i].Ident == ParmDeclarator.getIdentifier()) {
+ if (FTI.Params[i].Ident == ParmDeclarator.getIdentifier()) {
// Reject redefinitions of parameters.
- if (FTI.ArgInfo[i].Param) {
+ if (FTI.Params[i].Param) {
Diag(ParmDeclarator.getIdentifierLoc(),
diag::err_param_redefinition)
<< ParmDeclarator.getIdentifier();
} else {
- FTI.ArgInfo[i].Param = Param;
+ FTI.Params[i].Param = Param;
}
break;
}
@@ -1271,12 +1197,14 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
ParseDeclarator(ParmDeclarator);
}
- if (ExpectAndConsumeSemi(diag::err_expected_semi_declaration)) {
- // Skip to end of block or statement
- SkipUntil(tok::semi);
- if (Tok.is(tok::semi))
- ConsumeToken();
- }
+ // Consume ';' and continue parsing.
+ if (!ExpectAndConsumeSemi(diag::err_expected_semi_declaration))
+ continue;
+
+ // Otherwise recover by skipping to next semi or mandatory function body.
+ if (SkipUntil(tok::l_brace, StopAtSemi | StopBeforeMatch))
+ break;
+ TryConsumeToken(tok::semi);
}
// The actions module must verify that all arguments were declared.
@@ -1340,16 +1268,15 @@ Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) {
ExprResult Result(ParseAsmStringLiteral());
- if (Result.isInvalid()) {
- SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch);
- if (EndLoc)
- *EndLoc = Tok.getLocation();
- ConsumeAnyToken();
- } else {
+ if (!Result.isInvalid()) {
// Close the paren and get the location of the end bracket
T.consumeClose();
if (EndLoc)
*EndLoc = T.getCloseLocation();
+ } else if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) {
+ if (EndLoc)
+ *EndLoc = Tok.getLocation();
+ ConsumeParen();
}
return Result;
@@ -1430,11 +1357,11 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
// Look up and classify the identifier. We don't perform any typo-correction
// after a scope specifier, because in general we can't recover from typos
- // there (eg, after correcting 'A::tempalte B<X>::C', we would need to jump
- // back into scope specifier parsing).
+ // there (eg, after correcting 'A::tempalte B<X>::C' [sic], we would need to
+ // jump back into scope specifier parsing).
Sema::NameClassification Classification
= Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next,
- IsAddressOfOperand, SS.isEmpty() ? CCC : 0);
+ IsAddressOfOperand, SS.isEmpty() ? CCC : nullptr);
switch (Classification.getKind()) {
case Sema::NC_Error:
@@ -1504,16 +1431,34 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
}
bool Parser::TryKeywordIdentFallback(bool DisableKeyword) {
- assert(Tok.isNot(tok::identifier));
+ assert(!Tok.is(tok::identifier) && !Tok.isAnnotation());
Diag(Tok, diag::ext_keyword_as_ident)
<< PP.getSpelling(Tok)
<< DisableKeyword;
- if (DisableKeyword)
- Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
+ if (DisableKeyword) {
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ ContextualKeywords[II] = Tok.getKind();
+ II->RevertTokenIDToIdentifier();
+ }
Tok.setKind(tok::identifier);
return true;
}
+bool Parser::TryIdentKeywordUpgrade() {
+ assert(Tok.is(tok::identifier));
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ assert(II->hasRevertedTokenIDToIdentifier());
+ // If we find that this is in fact the name of a type trait,
+ // update the token kind in place and parse again to treat it as
+ // the appropriate kind of type trait.
+ llvm::SmallDenseMap<const IdentifierInfo *, tok::TokenKind>::iterator Known =
+ ContextualKeywords.find(II);
+ if (Known == ContextualKeywords.end())
+ return false;
+ Tok.setKind(Known->second);
+ return true;
+}
+
/// 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
@@ -1549,7 +1494,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
// We will consume the typedef token here and put it back after we have
// parsed the first identifier, transforming it into something more like:
// typename T_::D typedef D;
- if (getLangOpts().MicrosoftMode && NextToken().is(tok::kw_typedef)) {
+ if (getLangOpts().MSVCCompat && NextToken().is(tok::kw_typedef)) {
Token TypedefToken;
PP.Lex(TypedefToken);
bool Result = TryAnnotateTypeOrScopeToken(EnteringContext, NeedType);
@@ -1570,7 +1515,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
CXXScopeSpec SS;
if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ParsedType(),
/*EnteringContext=*/false,
- 0, /*IsTypename*/true))
+ nullptr, /*IsTypename*/ true))
return true;
if (!SS.isSet()) {
if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id) ||
@@ -1601,7 +1546,8 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
Tok.getLocation());
} else if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
- if (TemplateId->Kind == TNK_Function_template) {
+ if (TemplateId->Kind != TNK_Type_template &&
+ TemplateId->Kind != TNK_Dependent_template_name) {
Diag(Tok, diag::err_typename_refers_to_non_type_template)
<< Tok.getAnnotationRange();
return true;
@@ -1652,7 +1598,7 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext,
CXXScopeSpec &SS,
bool IsNewScope) {
if (Tok.is(tok::identifier)) {
- IdentifierInfo *CorrectedII = 0;
+ IdentifierInfo *CorrectedII = nullptr;
// Determine whether the identifier is a type name.
if (ParsedType Ty = Actions.getTypeName(*Tok.getIdentifierInfo(),
Tok.getLocation(), getCurScope(),
@@ -1660,8 +1606,9 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext,
NextToken().is(tok::period),
ParsedType(),
/*IsCtorOrDtorName=*/false,
- /*NonTrivialTypeSourceInfo*/true,
- NeedType ? &CorrectedII : NULL)) {
+ /*NonTrivialTypeSourceInfo*/ true,
+ NeedType ? &CorrectedII
+ : nullptr)) {
// A FixIt was applied as a result of typo correction
if (CorrectedII)
Tok.setIdentifierInfo(CorrectedII);
@@ -1725,8 +1672,7 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext,
// annotation token to a type annotation token now.
AnnotateTemplateIdTokenAsType();
return false;
- } else if (TemplateId->Kind == TNK_Var_template)
- return false;
+ }
}
if (SS.isEmpty())
@@ -1780,8 +1726,8 @@ bool Parser::isTokenEqualOrEqualTypo() {
case tok::pipeequal: // |=
case tok::equalequal: // ==
Diag(Tok, diag::err_invalid_token_after_declarator_suggest_equal)
- << getTokenSimpleSpelling(Kind)
- << FixItHint::CreateReplacement(SourceRange(Tok.getLocation()), "=");
+ << Kind
+ << FixItHint::CreateReplacement(SourceRange(Tok.getLocation()), "=");
case tok::equal:
return true;
}
@@ -1910,7 +1856,7 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
BalancedDelimiterTracker Braces(*this, tok::l_brace);
if (Braces.consumeOpen()) {
- Diag(Tok, diag::err_expected_lbrace);
+ Diag(Tok, diag::err_expected) << tok::l_brace;
return;
}
@@ -1928,14 +1874,15 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
}
// Parse the declarations.
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ // FIXME: Support module import within __if_exists?
+ while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX11Attributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
DeclGroupPtrTy Result = ParseExternalDeclaration(attrs);
if (Result && !getCurScope()->getParent())
Actions.getASTConsumer().HandleTopLevelDecl(Result.get());
- }
+ }
Braces.consumeClose();
}
@@ -1951,8 +1898,7 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) {
if (!Tok.is(tok::identifier)) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteModuleImport(ImportLoc, Path);
- ConsumeCodeCompletionToken();
- SkipUntil(tok::semi);
+ cutOffParsing();
return DeclGroupPtrTy();
}
@@ -1991,17 +1937,20 @@ bool BalancedDelimiterTracker::diagnoseOverflow() {
P.Diag(P.Tok, diag::err_bracket_depth_exceeded)
<< P.getLangOpts().BracketDepth;
P.Diag(P.Tok, diag::note_bracket_depth);
- P.SkipUntil(tok::eof);
- return true;
+ P.cutOffParsing();
+ return true;
}
bool BalancedDelimiterTracker::expectAndConsume(unsigned DiagID,
- const char *Msg,
- tok::TokenKind SkipToToc ) {
+ const char *Msg,
+ tok::TokenKind SkipToTok) {
LOpen = P.Tok.getLocation();
- if (P.ExpectAndConsume(Kind, DiagID, Msg, SkipToToc))
+ if (P.ExpectAndConsume(Kind, DiagID, Msg)) {
+ if (SkipToTok != tok::unknown)
+ P.SkipUntil(SkipToTok, Parser::StopAtSemi);
return true;
-
+ }
+
if (getDepth() < MaxDepth)
return false;
@@ -2010,17 +1959,9 @@ bool BalancedDelimiterTracker::expectAndConsume(unsigned DiagID,
bool BalancedDelimiterTracker::diagnoseMissingClose() {
assert(!P.Tok.is(Close) && "Should have consumed closing delimiter");
-
- const char *LHSName = "unknown";
- diag::kind DID;
- switch (Close) {
- default: llvm_unreachable("Unexpected balanced token");
- case tok::r_paren : LHSName = "("; DID = diag::err_expected_rparen; break;
- case tok::r_brace : LHSName = "{"; DID = diag::err_expected_rbrace; break;
- case tok::r_square: LHSName = "["; DID = diag::err_expected_rsquare; break;
- }
- P.Diag(P.Tok, DID);
- P.Diag(LOpen, diag::note_matching) << LHSName;
+
+ P.Diag(P.Tok, diag::err_expected) << Close;
+ P.Diag(LOpen, diag::note_matching) << Kind;
// If we're not already at some kind of closing bracket, skip to our closing
// token.
diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h
index f68a2e09fe91..4f5f3ab81036 100644
--- a/lib/Parse/RAIIObjectsForParser.h
+++ b/lib/Parse/RAIIObjectsForParser.h
@@ -50,7 +50,7 @@ namespace clang {
public:
/// Begin suppressing access-like checks
SuppressAccessChecks(Parser &P, bool activate = true)
- : S(P.getActions()), DiagnosticPool(NULL) {
+ : S(P.getActions()), DiagnosticPool(nullptr) {
if (activate) {
State = S.PushParsingDeclaration(DiagnosticPool);
Active = true;
@@ -61,7 +61,7 @@ namespace clang {
void done() {
assert(Active && "trying to end an inactive suppression");
- S.PopParsingDeclaration(State, NULL);
+ S.PopParsingDeclaration(State, nullptr);
Active = false;
}
@@ -93,7 +93,7 @@ namespace clang {
public:
enum NoParent_t { NoParent };
ParsingDeclRAIIObject(Parser &P, NoParent_t _)
- : Actions(P.getActions()), DiagnosticPool(NULL) {
+ : Actions(P.getActions()), DiagnosticPool(nullptr) {
push();
}
@@ -109,7 +109,7 @@ namespace clang {
/// RAII object (which is assumed to be the current top pool).
ParsingDeclRAIIObject(Parser &P, ParsingDeclRAIIObject *other)
: Actions(P.getActions()),
- DiagnosticPool(other ? other->DiagnosticPool.getParent() : NULL) {
+ DiagnosticPool(other ? other->DiagnosticPool.getParent() : nullptr) {
if (other) {
DiagnosticPool.steal(other->DiagnosticPool);
other->abort();
@@ -137,7 +137,7 @@ namespace clang {
/// Signals that the context was completed without an appropriate
/// declaration being parsed.
void abort() {
- pop(0);
+ pop(nullptr);
}
void complete(Decl *D) {
@@ -148,7 +148,7 @@ namespace clang {
/// Unregister this object from Sema, but remember all the
/// diagnostics that were emitted into it.
void abortAndRemember() {
- pop(0);
+ pop(nullptr);
}
private:
@@ -415,8 +415,8 @@ namespace clang {
return diagnoseOverflow();
}
-
- bool expectAndConsume(unsigned DiagID,
+
+ bool expectAndConsume(unsigned DiagID = diag::err_expected,
const char *Msg = "",
tok::TokenKind SkipToTok = tok::unknown);
bool consumeClose() {
diff --git a/lib/Rewrite/CMakeLists.txt b/lib/Rewrite/CMakeLists.txt
index d3d75430233f..0c77536012aa 100644
--- a/lib/Rewrite/CMakeLists.txt
+++ b/lib/Rewrite/CMakeLists.txt
@@ -1,2 +1,16 @@
-add_subdirectory(Core)
-add_subdirectory(Frontend)
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_clang_library(clangRewrite
+ DeltaTree.cpp
+ HTMLRewrite.cpp
+ RewriteRope.cpp
+ Rewriter.cpp
+ TokenRewriter.cpp
+
+ LINK_LIBS
+ clangAST
+ clangBasic
+ clangLex
+ )
diff --git a/lib/Rewrite/Core/CMakeLists.txt b/lib/Rewrite/Core/CMakeLists.txt
deleted file mode 100644
index 07978187ff19..000000000000
--- a/lib/Rewrite/Core/CMakeLists.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-add_clang_library(clangRewriteCore
- DeltaTree.cpp
- HTMLRewrite.cpp
- RewriteRope.cpp
- Rewriter.cpp
- TokenRewriter.cpp
- )
-
-add_dependencies(clangRewriteCore
- ClangAttrClasses
- ClangAttrList
- ClangAttrParsedAttrList
- ClangCommentNodes
- ClangDeclNodes
- ClangDiagnosticCommon
- ClangDiagnosticFrontend
- ClangStmtNodes
- )
-
-target_link_libraries(clangRewriteCore
- clangBasic
- clangAST
- clangParse
- )
diff --git a/lib/Rewrite/Core/Makefile b/lib/Rewrite/Core/Makefile
deleted file mode 100644
index 8c8d2e478135..000000000000
--- a/lib/Rewrite/Core/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-##===- clang/lib/Rewrite/Makefile --------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-#
-# This implements code transformation / rewriting facilities.
-#
-##===----------------------------------------------------------------------===##
-
-CLANG_LEVEL := ../../..
-LIBRARYNAME := clangRewriteCore
-
-include $(CLANG_LEVEL)/Makefile
-
diff --git a/lib/Rewrite/Core/DeltaTree.cpp b/lib/Rewrite/DeltaTree.cpp
index 7a7f15b7d336..352fab077a2e 100644
--- a/lib/Rewrite/Core/DeltaTree.cpp
+++ b/lib/Rewrite/DeltaTree.cpp
@@ -216,9 +216,9 @@ bool DeltaTreeNode::DoInsertion(unsigned FileIndex, int Delta,
DoSplit(*InsertRes);
if (InsertRes->Split.FileLoc > FileIndex)
- InsertRes->LHS->DoInsertion(FileIndex, Delta, 0 /*can't fail*/);
+ InsertRes->LHS->DoInsertion(FileIndex, Delta, nullptr /*can't fail*/);
else
- InsertRes->RHS->DoInsertion(FileIndex, Delta, 0 /*can't fail*/);
+ InsertRes->RHS->DoInsertion(FileIndex, Delta, nullptr /*can't fail*/);
return true;
}
diff --git a/lib/Rewrite/Frontend/CMakeLists.txt b/lib/Rewrite/Frontend/CMakeLists.txt
deleted file mode 100644
index 903a3ef8d50d..000000000000
--- a/lib/Rewrite/Frontend/CMakeLists.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-add_clang_library(clangRewriteFrontend
- FixItRewriter.cpp
- FrontendActions.cpp
- HTMLPrint.cpp
- InclusionRewriter.cpp
- RewriteMacros.cpp
- RewriteModernObjC.cpp
- RewriteObjC.cpp
- RewriteTest.cpp
- )
-
-add_dependencies(clangRewriteFrontend
- ClangAttrClasses
- ClangAttrList
- ClangAttrParsedAttrList
- ClangCommentNodes
- ClangDeclNodes
- ClangDiagnosticCommon
- ClangDiagnosticFrontend
- ClangStmtNodes
- )
-
-target_link_libraries(clangRewriteFrontend
- clangBasic
- clangAST
- clangParse
- clangFrontend
- clangRewriteCore
- )
diff --git a/lib/Rewrite/Core/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp
index 4da00a8cc97b..275fbd0ebca2 100644
--- a/lib/Rewrite/Core/HTMLRewrite.cpp
+++ b/lib/Rewrite/HTMLRewrite.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines the HTMLRewriter clas, which is used to translate the
+// This file defines the HTMLRewriter class, which is used to translate the
// text of a source file into prettified HTML.
//
//===----------------------------------------------------------------------===//
@@ -17,11 +17,11 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/TokenConcatenation.h"
#include "clang/Rewrite/Core/Rewriter.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
+#include <memory>
using namespace clang;
diff --git a/lib/Rewrite/Makefile b/lib/Rewrite/Makefile
index 0be84d406405..5fef9b2c0d38 100644
--- a/lib/Rewrite/Makefile
+++ b/lib/Rewrite/Makefile
@@ -1,4 +1,4 @@
-##===- clang/lib/StaticAnalyzer/Makefile -------------------*- Makefile -*-===##
+##===- clang/lib/Rewrite/Makefile --------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
@@ -6,9 +6,13 @@
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
+#
+# This implements code transformation / rewriting facilities.
+#
+##===----------------------------------------------------------------------===##
CLANG_LEVEL := ../..
-DIRS := Frontend
-PARALLEL_DIRS := Core
+LIBRARYNAME := clangRewrite
include $(CLANG_LEVEL)/Makefile
+
diff --git a/lib/Rewrite/Core/RewriteRope.cpp b/lib/Rewrite/RewriteRope.cpp
index fe7aa2d6477d..ef8abfcadc03 100644
--- a/lib/Rewrite/Core/RewriteRope.cpp
+++ b/lib/Rewrite/RewriteRope.cpp
@@ -146,7 +146,7 @@ namespace {
RopePieceBTreeLeaf **PrevLeaf, *NextLeaf;
public:
RopePieceBTreeLeaf() : RopePieceBTreeNode(true), NumPieces(0),
- PrevLeaf(0), NextLeaf(0) {}
+ PrevLeaf(nullptr), NextLeaf(nullptr) {}
~RopePieceBTreeLeaf() {
if (PrevLeaf || NextLeaf)
removeFromLeafInOrder();
@@ -171,7 +171,7 @@ namespace {
const RopePieceBTreeLeaf *getNextLeafInOrder() const { return NextLeaf; }
void insertAfterLeafInOrder(RopePieceBTreeLeaf *Node) {
- assert(PrevLeaf == 0 && NextLeaf == 0 && "Already in ordering");
+ assert(!PrevLeaf && !NextLeaf && "Already in ordering");
NextLeaf = Node->NextLeaf;
if (NextLeaf)
@@ -186,7 +186,7 @@ namespace {
if (NextLeaf)
NextLeaf->PrevLeaf = PrevLeaf;
} else if (NextLeaf) {
- NextLeaf->PrevLeaf = 0;
+ NextLeaf->PrevLeaf = nullptr;
}
}
@@ -236,7 +236,7 @@ RopePieceBTreeNode *RopePieceBTreeLeaf::split(unsigned Offset) {
// specified offset so find it.
if (Offset == 0 || Offset == size()) {
// Fastpath for a common case. There is already a splitpoint at the end.
- return 0;
+ return nullptr;
}
// Find the piece that this offset lands in.
@@ -250,7 +250,7 @@ RopePieceBTreeNode *RopePieceBTreeLeaf::split(unsigned Offset) {
// If there is already a split point at the specified offset, just return
// success.
if (PieceOffs == Offset)
- return 0;
+ return nullptr;
// Otherwise, we need to split piece 'i' at Offset-PieceOffs. Convert Offset
// to being Piece relative.
@@ -296,7 +296,7 @@ RopePieceBTreeNode *RopePieceBTreeLeaf::insert(unsigned Offset,
Pieces[i] = R;
++NumPieces;
Size += R.size();
- return 0;
+ return nullptr;
}
// Otherwise, if this is leaf is full, split it in two halves. Since this
@@ -470,7 +470,7 @@ namespace {
RopePieceBTreeNode *RopePieceBTreeInterior::split(unsigned Offset) {
// Figure out which child to split.
if (Offset == 0 || Offset == size())
- return 0; // If we have an exact offset, we're already split.
+ return nullptr; // If we have an exact offset, we're already split.
unsigned ChildOffset = 0;
unsigned i = 0;
@@ -479,12 +479,12 @@ RopePieceBTreeNode *RopePieceBTreeInterior::split(unsigned Offset) {
// If already split there, we're done.
if (ChildOffset == Offset)
- return 0;
+ return nullptr;
// Otherwise, recursively split the child.
if (RopePieceBTreeNode *RHS = getChild(i)->split(Offset-ChildOffset))
return HandleChildPiece(i, RHS);
- return 0; // Done!
+ return nullptr; // Done!
}
/// insert - Insert the specified ropepiece into this tree node at the
@@ -515,7 +515,7 @@ RopePieceBTreeNode *RopePieceBTreeInterior::insert(unsigned Offset,
if (RopePieceBTreeNode *RHS = getChild(i)->insert(Offset-ChildOffs, R))
return HandleChildPiece(i, RHS);
- return 0;
+ return nullptr;
}
/// HandleChildPiece - A child propagated an insertion result up to us.
@@ -531,7 +531,7 @@ RopePieceBTreeInterior::HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS) {
(getNumChildren()-i-1)*sizeof(Children[0]));
Children[i+1] = RHS;
++NumChildren;
- return 0;
+ return nullptr;
}
// Okay, this node is full. Split it in half, moving WidthFactor children to
@@ -678,10 +678,10 @@ RopePieceBTreeIterator::RopePieceBTreeIterator(const void *n) {
while (CurNode && getCN(CurNode)->getNumPieces() == 0)
CurNode = getCN(CurNode)->getNextLeafInOrder();
- if (CurNode != 0)
+ if (CurNode)
CurPiece = &getCN(CurNode)->getPiece(0);
else // Empty tree, this is an end() iterator.
- CurPiece = 0;
+ CurPiece = nullptr;
CurChar = 0;
}
@@ -697,10 +697,10 @@ void RopePieceBTreeIterator::MoveToNextPiece() {
CurNode = getCN(CurNode)->getNextLeafInOrder();
while (CurNode && getCN(CurNode)->getNumPieces() == 0);
- if (CurNode != 0)
+ if (CurNode)
CurPiece = &getCN(CurNode)->getPiece(0);
else // Hit end().
- CurPiece = 0;
+ CurPiece = nullptr;
CurChar = 0;
}
@@ -788,9 +788,8 @@ RopePiece RewriteRope::MakeRopeString(const char *Start, const char *End) {
// Otherwise, this was a small request but we just don't have space for it
// Make a new chunk and share it with later allocations.
- // If we had an old allocation, drop our reference to it.
- if (AllocBuffer && --AllocBuffer->RefCount == 0)
- delete [] (char*)AllocBuffer;
+ if (AllocBuffer)
+ AllocBuffer->dropRef();
unsigned AllocSize = offsetof(RopeRefCountString, Data) + AllocChunkSize;
AllocBuffer = reinterpret_cast<RopeRefCountString *>(new char[AllocSize]);
diff --git a/lib/Rewrite/Core/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp
index afb1080c66a1..eab4ccfeadc3 100644
--- a/lib/Rewrite/Core/Rewriter.cpp
+++ b/lib/Rewrite/Rewriter.cpp
@@ -21,13 +21,17 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
raw_ostream &RewriteBuffer::write(raw_ostream &os) const {
- // FIXME: eliminate the copy by writing out each chunk at a time
- os << std::string(begin(), end());
+ // Walk RewriteRope chunks efficiently using MoveToNextPiece() instead of the
+ // character iterator.
+ for (RopePieceBTreeIterator I = begin(), E = end(); I != E;
+ I.MoveToNextPiece())
+ os << I.piece();
return os;
}
@@ -328,6 +332,8 @@ bool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) {
/// printer to generate the replacement code. This returns true if the input
/// could not be rewritten, or false if successful.
bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) {
+ assert(From != nullptr && To != nullptr && "Expected non-null Stmt's");
+
// Measaure the old text.
int Size = getRangeSize(From->getSourceRange());
if (Size == -1)
@@ -336,7 +342,7 @@ bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) {
// Get the new text.
std::string SStr;
llvm::raw_string_ostream S(SStr);
- To->printPretty(S, 0, PrintingPolicy(*LangOpts));
+ To->printPretty(S, nullptr, PrintingPolicy(*LangOpts));
const std::string &Str = S.str();
ReplaceText(From->getLocStart(), Size, Str);
@@ -344,9 +350,10 @@ bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) {
}
std::string Rewriter::ConvertToString(Stmt *From) {
+ assert(From != nullptr && "Expected non-null Stmt");
std::string SStr;
llvm::raw_string_ostream S(SStr);
- From->printPretty(S, 0, PrintingPolicy(*LangOpts));
+ From->printPretty(S, nullptr, PrintingPolicy(*LangOpts));
return S.str();
}
@@ -446,30 +453,29 @@ public:
if (!ok()) return;
FileStream->flush();
-#ifdef _WIN32
+#ifdef LLVM_ON_WIN32
// Win32 does not allow rename/removing opened files.
FileStream.reset();
#endif
- if (llvm::error_code ec =
- llvm::sys::fs::rename(TempFilename.str(), Filename)) {
+ if (std::error_code ec =
+ llvm::sys::fs::rename(TempFilename.str(), Filename)) {
AllWritten = false;
Diagnostics.Report(clang::diag::err_unable_to_rename_temp)
<< TempFilename << Filename << ec.message();
- bool existed;
// If the remove fails, there's not a lot we can do - this is already an
// error.
- llvm::sys::fs::remove(TempFilename.str(), existed);
+ llvm::sys::fs::remove(TempFilename.str());
}
}
- bool ok() { return FileStream.isValid(); }
+ bool ok() { return (bool)FileStream; }
raw_ostream &getStream() { return *FileStream; }
private:
DiagnosticsEngine &Diagnostics;
StringRef Filename;
SmallString<128> TempFilename;
- OwningPtr<llvm::raw_fd_ostream> FileStream;
+ std::unique_ptr<llvm::raw_fd_ostream> FileStream;
bool &AllWritten;
};
} // end anonymous namespace
diff --git a/lib/Rewrite/Core/TokenRewriter.cpp b/lib/Rewrite/TokenRewriter.cpp
index 494defdedaa9..494defdedaa9 100644
--- a/lib/Rewrite/Core/TokenRewriter.cpp
+++ b/lib/Rewrite/TokenRewriter.cpp
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 93e3ecfb2947..213d6fbffffc 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -65,16 +65,198 @@ namespace {
public:
UnreachableCodeHandler(Sema &s) : S(s) {}
- void HandleUnreachable(SourceLocation L, SourceRange R1, SourceRange R2) {
- S.Diag(L, diag::warn_unreachable) << R1 << R2;
+ void HandleUnreachable(reachable_code::UnreachableKind UK,
+ SourceLocation L,
+ SourceRange SilenceableCondVal,
+ SourceRange R1,
+ SourceRange R2) override {
+ unsigned diag = diag::warn_unreachable;
+ switch (UK) {
+ case reachable_code::UK_Break:
+ diag = diag::warn_unreachable_break;
+ break;
+ case reachable_code::UK_Return:
+ diag = diag::warn_unreachable_return;
+ break;
+ case reachable_code::UK_Loop_Increment:
+ diag = diag::warn_unreachable_loop_increment;
+ break;
+ case reachable_code::UK_Other:
+ break;
+ }
+
+ S.Diag(L, diag) << R1 << R2;
+
+ SourceLocation Open = SilenceableCondVal.getBegin();
+ if (Open.isValid()) {
+ SourceLocation Close = SilenceableCondVal.getEnd();
+ Close = S.getLocForEndOfToken(Close);
+ if (Close.isValid()) {
+ S.Diag(Open, diag::note_unreachable_silence)
+ << FixItHint::CreateInsertion(Open, "/* DISABLES CODE */ (")
+ << FixItHint::CreateInsertion(Close, ")");
+ }
+ }
}
};
}
/// CheckUnreachable - Check for unreachable code.
static void CheckUnreachable(Sema &S, AnalysisDeclContext &AC) {
+ // As a heuristic prune all diagnostics not in the main file. Currently
+ // the majority of warnings in headers are false positives. These
+ // are largely caused by configuration state, e.g. preprocessor
+ // defined code, etc.
+ //
+ // Note that this is also a performance optimization. Analyzing
+ // headers many times can be expensive.
+ if (!S.getSourceManager().isInMainFile(AC.getDecl()->getLocStart()))
+ return;
+
UnreachableCodeHandler UC(S);
- reachable_code::FindUnreachableCode(AC, UC);
+ reachable_code::FindUnreachableCode(AC, S.getPreprocessor(), UC);
+}
+
+/// \brief Warn on logical operator errors in CFGBuilder
+class LogicalErrorHandler : public CFGCallback {
+ Sema &S;
+
+public:
+ LogicalErrorHandler(Sema &S) : CFGCallback(), S(S) {}
+
+ static bool HasMacroID(const Expr *E) {
+ if (E->getExprLoc().isMacroID())
+ return true;
+
+ // Recurse to children.
+ for (ConstStmtRange SubStmts = E->children(); SubStmts; ++SubStmts)
+ if (*SubStmts)
+ if (const Expr *SubExpr = dyn_cast<Expr>(*SubStmts))
+ if (HasMacroID(SubExpr))
+ return true;
+
+ return false;
+ }
+
+ void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) {
+ if (HasMacroID(B))
+ return;
+
+ SourceRange DiagRange = B->getSourceRange();
+ S.Diag(B->getExprLoc(), diag::warn_tautological_overlap_comparison)
+ << DiagRange << isAlwaysTrue;
+ }
+
+ void compareBitwiseEquality(const BinaryOperator *B, bool isAlwaysTrue) {
+ if (HasMacroID(B))
+ return;
+
+ SourceRange DiagRange = B->getSourceRange();
+ S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_always)
+ << DiagRange << isAlwaysTrue;
+ }
+};
+
+
+//===----------------------------------------------------------------------===//
+// Check for infinite self-recursion in functions
+//===----------------------------------------------------------------------===//
+
+// All blocks are in one of three states. States are ordered so that blocks
+// can only move to higher states.
+enum RecursiveState {
+ FoundNoPath,
+ FoundPath,
+ FoundPathWithNoRecursiveCall
+};
+
+static void checkForFunctionCall(Sema &S, const FunctionDecl *FD,
+ CFGBlock &Block, unsigned ExitID,
+ llvm::SmallVectorImpl<RecursiveState> &States,
+ RecursiveState State) {
+ unsigned ID = Block.getBlockID();
+
+ // A block's state can only move to a higher state.
+ if (States[ID] >= State)
+ return;
+
+ States[ID] = State;
+
+ // Found a path to the exit node without a recursive call.
+ if (ID == ExitID && State == FoundPathWithNoRecursiveCall)
+ return;
+
+ if (State == FoundPathWithNoRecursiveCall) {
+ // If the current state is FoundPathWithNoRecursiveCall, the successors
+ // will be either FoundPathWithNoRecursiveCall or FoundPath. To determine
+ // which, process all the Stmt's in this block to find any recursive calls.
+ for (const auto &B : Block) {
+ if (B.getKind() != CFGElement::Statement)
+ continue;
+
+ const CallExpr *CE = dyn_cast<CallExpr>(B.getAs<CFGStmt>()->getStmt());
+ if (CE && CE->getCalleeDecl() &&
+ CE->getCalleeDecl()->getCanonicalDecl() == FD) {
+
+ // Skip function calls which are qualified with a templated class.
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(
+ CE->getCallee()->IgnoreParenImpCasts())) {
+ if (NestedNameSpecifier *NNS = DRE->getQualifier()) {
+ if (NNS->getKind() == NestedNameSpecifier::TypeSpec &&
+ isa<TemplateSpecializationType>(NNS->getAsType())) {
+ continue;
+ }
+ }
+ }
+
+ if (const CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(CE)) {
+ if (isa<CXXThisExpr>(MCE->getImplicitObjectArgument()) ||
+ !MCE->getMethodDecl()->isVirtual()) {
+ State = FoundPath;
+ break;
+ }
+ } else {
+ State = FoundPath;
+ break;
+ }
+ }
+ }
+ }
+
+ for (CFGBlock::succ_iterator I = Block.succ_begin(), E = Block.succ_end();
+ I != E; ++I)
+ if (*I)
+ checkForFunctionCall(S, FD, **I, ExitID, States, State);
+}
+
+static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD,
+ const Stmt *Body,
+ AnalysisDeclContext &AC) {
+ FD = FD->getCanonicalDecl();
+
+ // Only run on non-templated functions and non-templated members of
+ // templated classes.
+ if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate &&
+ FD->getTemplatedKind() != FunctionDecl::TK_MemberSpecialization)
+ return;
+
+ CFG *cfg = AC.getCFG();
+ if (!cfg) return;
+
+ // If the exit block is unreachable, skip processing the function.
+ if (cfg->getExit().pred_empty())
+ return;
+
+ // Mark all nodes as FoundNoPath, then begin processing the entry block.
+ llvm::SmallVector<RecursiveState, 16> states(cfg->getNumBlockIDs(),
+ FoundNoPath);
+ checkForFunctionCall(S, FD, cfg->getEntry(), cfg->getExit().getBlockID(),
+ states, FoundPathWithNoRecursiveCall);
+
+ // Check that the exit block is reachable. This prevents triggering the
+ // warning on functions that do not terminate.
+ if (states[cfg->getExit().getBlockID()] == FoundPath)
+ S.Diag(Body->getLocStart(), diag::warn_infinite_recursive_function);
}
//===----------------------------------------------------------------------===//
@@ -100,7 +282,7 @@ enum ControlFlowKind {
/// will return.
static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
CFG *cfg = AC.getCFG();
- if (cfg == 0) return UnknownFallThrough;
+ if (!cfg) return UnknownFallThrough;
// The CFG leaves in dead things, and we don't want the dead code paths to
// confuse us, so we mark all live things first.
@@ -113,14 +295,13 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
// When there are things remaining dead, and we didn't add EH edges
// from CallExprs to the catch clauses, we have to go back and
// mark them as live.
- for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
- CFGBlock &b = **I;
- if (!live[b.getBlockID()]) {
- if (b.pred_begin() == b.pred_end()) {
- if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator()))
+ for (const auto *B : *cfg) {
+ if (!live[B->getBlockID()]) {
+ if (B->pred_begin() == B->pred_end()) {
+ if (B->getTerminator() && isa<CXXTryStmt>(B->getTerminator()))
// When not adding EH edges from calls, catch clauses
// can otherwise seem dead. Avoid noting them as dead.
- count += reachable_code::ScanReachableFromBlock(&b, live);
+ count += reachable_code::ScanReachableFromBlock(B, live);
continue;
}
}
@@ -272,8 +453,7 @@ struct CheckFallThroughDiagnostics {
diag::err_noreturn_block_has_return_expr;
D.diag_AlwaysFallThrough_ReturnsNonVoid =
diag::err_falloff_nonvoid_block;
- D.diag_NeverFallThroughOrReturn =
- diag::warn_suggest_noreturn_block;
+ D.diag_NeverFallThroughOrReturn = 0;
D.funMode = Block;
return D;
}
@@ -297,21 +477,17 @@ struct CheckFallThroughDiagnostics {
bool HasNoReturn) const {
if (funMode == Function) {
return (ReturnsVoid ||
- D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function,
- FuncLoc) == DiagnosticsEngine::Ignored)
- && (!HasNoReturn ||
- D.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr,
- FuncLoc) == DiagnosticsEngine::Ignored)
- && (!ReturnsVoid ||
- D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc)
- == DiagnosticsEngine::Ignored);
+ D.isIgnored(diag::warn_maybe_falloff_nonvoid_function,
+ FuncLoc)) &&
+ (!HasNoReturn ||
+ D.isIgnored(diag::warn_noreturn_function_has_return_expr,
+ FuncLoc)) &&
+ (!ReturnsVoid ||
+ D.isIgnored(diag::warn_suggest_noreturn_block, FuncLoc));
}
// For blocks / lambdas.
- return ReturnsVoid && !HasNoReturn
- && ((funMode == Lambda) ||
- D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc)
- == DiagnosticsEngine::Ignored);
+ return ReturnsVoid && !HasNoReturn;
}
};
@@ -330,18 +506,18 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
bool HasNoReturn = false;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- ReturnsVoid = FD->getResultType()->isVoidType();
+ ReturnsVoid = FD->getReturnType()->isVoidType();
HasNoReturn = FD->isNoReturn();
}
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- ReturnsVoid = MD->getResultType()->isVoidType();
+ ReturnsVoid = MD->getReturnType()->isVoidType();
HasNoReturn = MD->hasAttr<NoReturnAttr>();
}
else if (isa<BlockDecl>(D)) {
QualType BlockTy = blkExpr->getType();
if (const FunctionType *FT =
BlockTy->getPointeeType()->getAs<FunctionType>()) {
- if (FT->getResultType()->isVoidType())
+ if (FT->getReturnType()->isVoidType())
ReturnsVoid = true;
if (FT->getNoReturnAttr())
HasNoReturn = true;
@@ -435,8 +611,9 @@ static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
QualType VariableTy = VD->getType().getCanonicalType();
if (VariableTy->isBlockPointerType() &&
!VD->hasAttr<BlocksAttr>()) {
- S.Diag(VD->getLocation(), diag::note_block_var_fixit_add_initialization) << VD->getDeclName()
- << FixItHint::CreateInsertion(VD->getLocation(), "__block ");
+ S.Diag(VD->getLocation(), diag::note_block_var_fixit_add_initialization)
+ << VD->getDeclName()
+ << FixItHint::CreateInsertion(VD->getLocation(), "__block ");
return true;
}
@@ -448,7 +625,7 @@ static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
if (VD->getLocEnd().isMacroID())
return false;
- SourceLocation Loc = S.PP.getLocForEndOfToken(VD->getLocEnd());
+ SourceLocation Loc = S.getLocForEndOfToken(VD->getLocEnd());
// Suggest possible initialization (if any).
std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc);
@@ -744,8 +921,7 @@ namespace {
// constants, covered enums, etc.
// These blocks can contain fall-through annotations, and we don't want to
// issue a warn_fallthrough_attr_unreachable for them.
- for (CFG::iterator I = Cfg->begin(), E = Cfg->end(); I != E; ++I) {
- const CFGBlock *B = *I;
+ for (const auto *B : *Cfg) {
const Stmt *L = B->getLabel();
if (L && isa<SwitchCase>(L) && ReachableBlocks.insert(B))
BlockQueue.push_back(B);
@@ -769,13 +945,11 @@ namespace {
int UnannotatedCnt = 0;
AnnotatedCnt = 0;
- std::deque<const CFGBlock*> BlockQueue;
-
- std::copy(B.pred_begin(), B.pred_end(), std::back_inserter(BlockQueue));
-
+ std::deque<const CFGBlock*> BlockQueue(B.pred_begin(), B.pred_end());
while (!BlockQueue.empty()) {
const CFGBlock *P = BlockQueue.front();
BlockQueue.pop_front();
+ if (!P) continue;
const Stmt *Term = P->getTerminator();
if (Term && isa<SwitchStmt>(Term))
@@ -852,6 +1026,9 @@ namespace {
// methods separately.
bool TraverseDecl(Decl *D) { return true; }
+ // We analyze lambda bodies separately. Skip them here.
+ bool TraverseLambdaBody(LambdaExpr *LE) { return true; }
+
private:
static const AttributedStmt *asFallThroughAttr(const Stmt *S) {
@@ -859,7 +1036,7 @@ namespace {
if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs()))
return AS;
}
- return 0;
+ return nullptr;
}
static const Stmt *getLastStmt(const CFGBlock &B) {
@@ -878,7 +1055,7 @@ namespace {
if (!isa<SwitchCase>(SW->getSubStmt()))
return SW->getSubStmt();
- return 0;
+ return nullptr;
}
bool FoundSwitchStatements;
@@ -968,31 +1145,8 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
}
}
- const FallthroughMapper::AttrStmts &Fallthroughs = FM.getFallthroughStmts();
- for (FallthroughMapper::AttrStmts::const_iterator I = Fallthroughs.begin(),
- E = Fallthroughs.end();
- I != E; ++I) {
- S.Diag((*I)->getLocStart(), diag::warn_fallthrough_attr_invalid_placement);
- }
-
-}
-
-namespace {
-typedef std::pair<const Stmt *,
- sema::FunctionScopeInfo::WeakObjectUseMap::const_iterator>
- StmtUsesPair;
-
-class StmtUseSorter {
- const SourceManager &SM;
-
-public:
- explicit StmtUseSorter(const SourceManager &SM) : SM(SM) { }
-
- bool operator()(const StmtUsesPair &LHS, const StmtUsesPair &RHS) {
- return SM.isBeforeInTranslationUnit(LHS.first->getLocStart(),
- RHS.first->getLocStart());
- }
-};
+ for (const auto *F : FM.getFallthroughStmts())
+ S.Diag(F->getLocStart(), diag::warn_fallthrough_attr_invalid_placement);
}
static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM,
@@ -1029,6 +1183,8 @@ static void diagnoseRepeatedUseOfWeak(Sema &S,
typedef sema::FunctionScopeInfo::WeakObjectProfileTy WeakObjectProfileTy;
typedef sema::FunctionScopeInfo::WeakObjectUseMap WeakObjectUseMap;
typedef sema::FunctionScopeInfo::WeakUseVector WeakUseVector;
+ typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator>
+ StmtUsesPair;
ASTContext &Ctx = S.getASTContext();
@@ -1087,8 +1243,12 @@ static void diagnoseRepeatedUseOfWeak(Sema &S,
return;
// Sort by first use so that we emit the warnings in a deterministic order.
+ SourceManager &SM = S.getSourceManager();
std::sort(UsesByStmt.begin(), UsesByStmt.end(),
- StmtUseSorter(S.getSourceManager()));
+ [&SM](const StmtUsesPair &LHS, const StmtUsesPair &RHS) {
+ return SM.isBeforeInTranslationUnit(LHS.first->getLocStart(),
+ RHS.first->getLocStart());
+ });
// Classify the current code body for better warning text.
// This enum should stay in sync with the cases in
@@ -1112,12 +1272,10 @@ static void diagnoseRepeatedUseOfWeak(Sema &S,
FunctionKind = Function;
// Iterate through the sorted problems and emit warnings for each.
- for (SmallVectorImpl<StmtUsesPair>::const_iterator I = UsesByStmt.begin(),
- E = UsesByStmt.end();
- I != E; ++I) {
- const Stmt *FirstRead = I->first;
- const WeakObjectProfileTy &Key = I->second->first;
- const WeakUseVector &Uses = I->second->second;
+ for (const auto &P : UsesByStmt) {
+ const Stmt *FirstRead = P.first;
+ const WeakObjectProfileTy &Key = P.second->first;
+ const WeakUseVector &Uses = P.second->second;
// For complicated expressions like 'a.b.c' and 'x.b.c', WeakObjectProfileTy
// may not contain enough information to determine that these are different
@@ -1158,30 +1316,17 @@ static void diagnoseRepeatedUseOfWeak(Sema &S,
<< FirstRead->getSourceRange();
// Print all the other accesses as notes.
- for (WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
- UI != UE; ++UI) {
- if (UI->getUseExpr() == FirstRead)
+ for (const auto &Use : Uses) {
+ if (Use.getUseExpr() == FirstRead)
continue;
- S.Diag(UI->getUseExpr()->getLocStart(),
+ S.Diag(Use.getUseExpr()->getLocStart(),
diag::note_arc_weak_also_accessed_here)
- << UI->getUseExpr()->getSourceRange();
+ << Use.getUseExpr()->getSourceRange();
}
}
}
-
namespace {
-struct SLocSort {
- bool operator()(const UninitUse &a, const UninitUse &b) {
- // Prefer a more confident report over a less confident one.
- if (a.getKind() != b.getKind())
- return a.getKind() > b.getKind();
- SourceLocation aLoc = a.getUser()->getLocStart();
- SourceLocation bLoc = b.getUser()->getLocStart();
- return aLoc.getRawEncoding() < bLoc.getRawEncoding();
- }
-};
-
class UninitValsDiagReporter : public UninitVariablesHandler {
Sema &S;
typedef SmallVector<UninitUse, 2> UsesVec;
@@ -1193,7 +1338,7 @@ class UninitValsDiagReporter : public UninitVariablesHandler {
UsesMap *uses;
public:
- UninitValsDiagReporter(Sema &S) : S(S), uses(0) {}
+ UninitValsDiagReporter(Sema &S) : S(S), uses(nullptr) {}
~UninitValsDiagReporter() {
flushDiagnostics();
}
@@ -1208,12 +1353,13 @@ public:
return V;
}
-
- void handleUseOfUninitVariable(const VarDecl *vd, const UninitUse &use) {
+
+ void handleUseOfUninitVariable(const VarDecl *vd,
+ const UninitUse &use) override {
getUses(vd).getPointer()->push_back(use);
}
- void handleSelfInit(const VarDecl *vd) {
+ void handleSelfInit(const VarDecl *vd) override {
getUses(vd).setInt(true);
}
@@ -1221,9 +1367,9 @@ public:
if (!uses)
return;
- for (UsesMap::iterator i = uses->begin(), e = uses->end(); i != e; ++i) {
- const VarDecl *vd = i->first;
- const MappedType &V = i->second;
+ for (const auto &P : *uses) {
+ const VarDecl *vd = P.first;
+ const MappedType &V = P.second;
UsesVec *vec = V.getPointer();
bool hasSelfInit = V.getInt();
@@ -1240,12 +1386,17 @@ public:
// Sort the uses by their SourceLocations. While not strictly
// guaranteed to produce them in line/column order, this will provide
// a stable ordering.
- std::sort(vec->begin(), vec->end(), SLocSort());
-
- for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve;
- ++vi) {
+ std::sort(vec->begin(), vec->end(),
+ [](const UninitUse &a, const UninitUse &b) {
+ // Prefer a more confident report over a less confident one.
+ if (a.getKind() != b.getKind())
+ return a.getKind() > b.getKind();
+ return a.getUser()->getLocStart() < b.getUser()->getLocStart();
+ });
+
+ for (const auto &U : *vec) {
// If we have self-init, downgrade all uses to 'may be uninitialized'.
- UninitUse Use = hasSelfInit ? UninitUse(vi->getUser(), false) : *vi;
+ UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false) : U;
if (DiagnoseUninitializedUse(S, vd, Use))
// Skip further diagnostics for this variable. We try to warn only
@@ -1262,15 +1413,12 @@ public:
private:
static bool hasAlwaysUninitializedUse(const UsesVec* vec) {
- for (UsesVec::const_iterator i = vec->begin(), e = vec->end(); i != e; ++i) {
- if (i->getKind() == UninitUse::Always ||
- i->getKind() == UninitUse::AfterCall ||
- i->getKind() == UninitUse::AfterDecl) {
- return true;
- }
+ return std::any_of(vec->begin(), vec->end(), [](const UninitUse &U) {
+ return U.getKind() == UninitUse::Always ||
+ U.getKind() == UninitUse::AfterCall ||
+ U.getKind() == UninitUse::AfterDecl;
+ });
}
- return false;
-}
};
}
@@ -1304,12 +1452,13 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
SourceLocation FunLocation, FunEndLocation;
// Helper functions
- void warnLockMismatch(unsigned DiagID, Name LockName, SourceLocation Loc) {
+ void warnLockMismatch(unsigned DiagID, StringRef Kind, Name LockName,
+ SourceLocation Loc) {
// Gracefully handle rare cases when the analysis can't get a more
// precise source location.
if (!Loc.isValid())
Loc = FunLocation;
- PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << LockName);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind << LockName);
Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
@@ -1323,31 +1472,40 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
/// and outputs them.
void emitDiagnostics() {
Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
- for (DiagList::iterator I = Warnings.begin(), E = Warnings.end();
- I != E; ++I) {
- S.Diag(I->first.first, I->first.second);
- const OptionalNotes &Notes = I->second;
- for (unsigned NoteI = 0, NoteN = Notes.size(); NoteI != NoteN; ++NoteI)
- S.Diag(Notes[NoteI].first, Notes[NoteI].second);
+ for (const auto &Diag : Warnings) {
+ S.Diag(Diag.first.first, Diag.first.second);
+ for (const auto &Note : Diag.second)
+ S.Diag(Note.first, Note.second);
}
}
- void handleInvalidLockExp(SourceLocation Loc) {
- PartialDiagnosticAt Warning(Loc,
- S.PDiag(diag::warn_cannot_resolve_lock) << Loc);
+ void handleInvalidLockExp(StringRef Kind, SourceLocation Loc) override {
+ PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_cannot_resolve_lock)
+ << Loc);
Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
- void handleUnmatchedUnlock(Name LockName, SourceLocation Loc) {
- warnLockMismatch(diag::warn_unlock_but_no_lock, LockName, Loc);
+ void handleUnmatchedUnlock(StringRef Kind, Name LockName,
+ SourceLocation Loc) override {
+ warnLockMismatch(diag::warn_unlock_but_no_lock, Kind, LockName, Loc);
}
-
- void handleDoubleLock(Name LockName, SourceLocation Loc) {
- warnLockMismatch(diag::warn_double_lock, LockName, Loc);
+ void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
+ LockKind Expected, LockKind Received,
+ SourceLocation Loc) override {
+ if (Loc.isInvalid())
+ Loc = FunLocation;
+ PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_kind_mismatch)
+ << Kind << LockName << Received
+ << Expected);
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ }
+ void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation Loc) override {
+ warnLockMismatch(diag::warn_double_lock, Kind, LockName, Loc);
}
- void handleMutexHeldEndOfScope(Name LockName, SourceLocation LocLocked,
+ void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,
+ SourceLocation LocLocked,
SourceLocation LocEndOfScope,
- LockErrorKind LEK){
+ LockErrorKind LEK) override {
unsigned DiagID = 0;
switch (LEK) {
case LEK_LockedSomePredecessors:
@@ -1366,29 +1524,33 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
if (LocEndOfScope.isInvalid())
LocEndOfScope = FunEndLocation;
- PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID) << LockName);
+ PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID) << Kind
+ << LockName);
if (LocLocked.isValid()) {
- PartialDiagnosticAt Note(LocLocked, S.PDiag(diag::note_locked_here));
+ PartialDiagnosticAt Note(LocLocked, S.PDiag(diag::note_locked_here)
+ << Kind);
Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note)));
return;
}
Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
-
- void handleExclusiveAndShared(Name LockName, SourceLocation Loc1,
- SourceLocation Loc2) {
- PartialDiagnosticAt Warning(
- Loc1, S.PDiag(diag::warn_lock_exclusive_and_shared) << LockName);
- PartialDiagnosticAt Note(
- Loc2, S.PDiag(diag::note_lock_exclusive_and_shared) << LockName);
+ void handleExclusiveAndShared(StringRef Kind, Name LockName,
+ SourceLocation Loc1,
+ SourceLocation Loc2) override {
+ PartialDiagnosticAt Warning(Loc1,
+ S.PDiag(diag::warn_lock_exclusive_and_shared)
+ << Kind << LockName);
+ PartialDiagnosticAt Note(Loc2, S.PDiag(diag::note_lock_exclusive_and_shared)
+ << Kind << LockName);
Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note)));
}
- void handleNoMutexHeld(const NamedDecl *D, ProtectedOperationKind POK,
- AccessKind AK, SourceLocation Loc) {
- assert((POK == POK_VarAccess || POK == POK_VarDereference)
- && "Only works for variables");
+ void handleNoMutexHeld(StringRef Kind, const NamedDecl *D,
+ ProtectedOperationKind POK, AccessKind AK,
+ SourceLocation Loc) override {
+ assert((POK == POK_VarAccess || POK == POK_VarDereference) &&
+ "Only works for variables");
unsigned DiagID = POK == POK_VarAccess?
diag::warn_variable_requires_any_lock:
diag::warn_var_deref_requires_any_lock;
@@ -1397,9 +1559,10 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
- void handleMutexNotHeld(const NamedDecl *D, ProtectedOperationKind POK,
- Name LockName, LockKind LK, SourceLocation Loc,
- Name *PossibleMatch) {
+ void handleMutexNotHeld(StringRef Kind, const NamedDecl *D,
+ ProtectedOperationKind POK, Name LockName,
+ LockKind LK, SourceLocation Loc,
+ Name *PossibleMatch) override {
unsigned DiagID = 0;
if (PossibleMatch) {
switch (POK) {
@@ -1413,10 +1576,11 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
DiagID = diag::warn_fun_requires_lock_precise;
break;
}
- PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
- << D->getNameAsString() << LockName << LK);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind
+ << D->getNameAsString()
+ << LockName << LK);
PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match)
- << *PossibleMatch);
+ << *PossibleMatch);
Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note)));
} else {
switch (POK) {
@@ -1430,15 +1594,17 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
DiagID = diag::warn_fun_requires_lock;
break;
}
- PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID)
- << D->getNameAsString() << LockName << LK);
+ PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind
+ << D->getNameAsString()
+ << LockName << LK);
Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
}
- void handleFunExcludesLock(Name FunName, Name LockName, SourceLocation Loc) {
- PartialDiagnosticAt Warning(Loc,
- S.PDiag(diag::warn_fun_excludes_mutex) << FunName << LockName);
+ void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName,
+ SourceLocation Loc) override {
+ PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_fun_excludes_mutex)
+ << Kind << FunName << LockName);
Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
}
};
@@ -1461,23 +1627,18 @@ class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
public:
ConsumedWarningsHandler(Sema &S) : S(S) {}
-
- void emitDiagnostics() {
+
+ void emitDiagnostics() override {
Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
-
- for (DiagList::iterator I = Warnings.begin(), E = Warnings.end();
- I != E; ++I) {
-
- const OptionalNotes &Notes = I->second;
- S.Diag(I->first.first, I->first.second);
-
- for (unsigned NoteI = 0, NoteN = Notes.size(); NoteI != NoteN; ++NoteI) {
- S.Diag(Notes[NoteI].first, Notes[NoteI].second);
- }
+ for (const auto &Diag : Warnings) {
+ S.Diag(Diag.first.first, Diag.first.second);
+ for (const auto &Note : Diag.second)
+ S.Diag(Note.first, Note.second);
}
}
-
- void warnLoopStateMismatch(SourceLocation Loc, StringRef VariableName) {
+
+ void warnLoopStateMismatch(SourceLocation Loc,
+ StringRef VariableName) override {
PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_loop_state_mismatch) <<
VariableName);
@@ -1487,7 +1648,7 @@ public:
void warnParamReturnTypestateMismatch(SourceLocation Loc,
StringRef VariableName,
StringRef ExpectedState,
- StringRef ObservedState) {
+ StringRef ObservedState) override {
PartialDiagnosticAt Warning(Loc, S.PDiag(
diag::warn_param_return_typestate_mismatch) << VariableName <<
@@ -1497,7 +1658,7 @@ public:
}
void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
- StringRef ObservedState) {
+ StringRef ObservedState) override {
PartialDiagnosticAt Warning(Loc, S.PDiag(
diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
@@ -1506,7 +1667,7 @@ public:
}
void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
- StringRef TypeName) {
+ StringRef TypeName) override {
PartialDiagnosticAt Warning(Loc, S.PDiag(
diag::warn_return_typestate_for_unconsumable_type) << TypeName);
@@ -1514,7 +1675,7 @@ public:
}
void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
- StringRef ObservedState) {
+ StringRef ObservedState) override {
PartialDiagnosticAt Warning(Loc, S.PDiag(
diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
@@ -1523,7 +1684,7 @@ public:
}
void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,
- SourceLocation Loc) {
+ SourceLocation Loc) override {
PartialDiagnosticAt Warning(Loc, S.PDiag(
diag::warn_use_of_temp_in_invalid_state) << MethodName << State);
@@ -1532,7 +1693,7 @@ public:
}
void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
- StringRef State, SourceLocation Loc) {
+ StringRef State, SourceLocation Loc) override {
PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_invalid_state) <<
MethodName << VariableName << State);
@@ -1554,6 +1715,10 @@ clang::sema::AnalysisBasedWarnings::Policy::Policy() {
enableConsumedAnalysis = 0;
}
+static unsigned isEnabled(DiagnosticsEngine &D, unsigned diag) {
+ return (unsigned)!D.isIgnored(diag, SourceLocation());
+}
+
clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
: S(s),
NumFunctionsAnalyzed(0),
@@ -1565,26 +1730,26 @@ clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
MaxUninitAnalysisVariablesPerFunction(0),
NumUninitAnalysisBlockVisits(0),
MaxUninitAnalysisBlockVisitsPerFunction(0) {
+
+ using namespace diag;
DiagnosticsEngine &D = S.getDiagnostics();
- DefaultPolicy.enableCheckUnreachable = (unsigned)
- (D.getDiagnosticLevel(diag::warn_unreachable, SourceLocation()) !=
- DiagnosticsEngine::Ignored);
- DefaultPolicy.enableThreadSafetyAnalysis = (unsigned)
- (D.getDiagnosticLevel(diag::warn_double_lock, SourceLocation()) !=
- DiagnosticsEngine::Ignored);
- DefaultPolicy.enableConsumedAnalysis = (unsigned)
- (D.getDiagnosticLevel(diag::warn_use_in_invalid_state, SourceLocation()) !=
- DiagnosticsEngine::Ignored);
+
+ DefaultPolicy.enableCheckUnreachable =
+ isEnabled(D, warn_unreachable) ||
+ isEnabled(D, warn_unreachable_break) ||
+ isEnabled(D, warn_unreachable_return) ||
+ isEnabled(D, warn_unreachable_loop_increment);
+
+ DefaultPolicy.enableThreadSafetyAnalysis =
+ isEnabled(D, warn_double_lock);
+
+ DefaultPolicy.enableConsumedAnalysis =
+ isEnabled(D, warn_use_in_invalid_state);
}
-static void flushDiagnostics(Sema &S, sema::FunctionScopeInfo *fscope) {
- for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
- i = fscope->PossiblyUnreachableDiags.begin(),
- e = fscope->PossiblyUnreachableDiags.end();
- i != e; ++i) {
- const sema::PossiblyUnreachableDiag &D = *i;
+static void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope) {
+ for (const auto &D : fscope->PossiblyUnreachableDiags)
S.Diag(D.Loc, D.PD);
- }
}
void clang::sema::
@@ -1620,7 +1785,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
assert(Body);
// Construct the analysis context with the specified CFG build options.
- AnalysisDeclContext AC(/* AnalysisDeclContextManager */ 0, D);
+ AnalysisDeclContext AC(/* AnalysisDeclContextManager */ nullptr, D);
// Don't generate EH edges for CallExprs as we'd like to avoid the n^2
// explosion for destructors that can result and the compile time hit.
@@ -1629,6 +1794,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
AC.getCFGBuildOptions().AddInitializers = true;
AC.getCFGBuildOptions().AddImplicitDtors = true;
AC.getCFGBuildOptions().AddTemporaryDtors = true;
+ AC.getCFGBuildOptions().AddCXXNewAllocator = false;
// Force that certain expressions appear as CFGElements in the CFG. This
// is used to speed up various analyses.
@@ -1653,31 +1819,30 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
.setAlwaysAdd(Stmt::AttributedStmtClass);
}
+ // Install the logical handler for -Wtautological-overlap-compare
+ std::unique_ptr<LogicalErrorHandler> LEH;
+ if (!Diags.isIgnored(diag::warn_tautological_overlap_comparison,
+ D->getLocStart())) {
+ LEH.reset(new LogicalErrorHandler(S));
+ AC.getCFGBuildOptions().Observer = LEH.get();
+ }
// Emit delayed diagnostics.
if (!fscope->PossiblyUnreachableDiags.empty()) {
bool analyzed = false;
// Register the expressions with the CFGBuilder.
- for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
- i = fscope->PossiblyUnreachableDiags.begin(),
- e = fscope->PossiblyUnreachableDiags.end();
- i != e; ++i) {
- if (const Stmt *stmt = i->stmt)
- AC.registerForcedBlockExpression(stmt);
+ for (const auto &D : fscope->PossiblyUnreachableDiags) {
+ if (D.stmt)
+ AC.registerForcedBlockExpression(D.stmt);
}
if (AC.getCFG()) {
analyzed = true;
- for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
- i = fscope->PossiblyUnreachableDiags.begin(),
- e = fscope->PossiblyUnreachableDiags.end();
- i != e; ++i)
- {
- const sema::PossiblyUnreachableDiag &D = *i;
+ for (const auto &D : fscope->PossiblyUnreachableDiags) {
bool processed = false;
- if (const Stmt *stmt = i->stmt) {
- const CFGBlock *block = AC.getBlockForRegisteredExpression(stmt);
+ if (D.stmt) {
+ const CFGBlock *block = AC.getBlockForRegisteredExpression(D.stmt);
CFGReverseBlockReachabilityAnalysis *cra =
AC.getCFGReachablityAnalysis();
// FIXME: We should be able to assert that block is non-null, but
@@ -1732,8 +1897,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
SourceLocation FL = AC.getDecl()->getLocation();
SourceLocation FEL = AC.getDecl()->getLocEnd();
thread_safety::ThreadSafetyReporter Reporter(S, FL, FEL);
- if (Diags.getDiagnosticLevel(diag::warn_thread_safety_beta,D->getLocStart())
- != DiagnosticsEngine::Ignored)
+ if (!Diags.isIgnored(diag::warn_thread_safety_beta, D->getLocStart()))
Reporter.setIssueBetaWarnings(true);
thread_safety::runThreadSafetyAnalysis(AC, Reporter);
@@ -1747,12 +1911,9 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
Analyzer.run(AC);
}
- if (Diags.getDiagnosticLevel(diag::warn_uninit_var, D->getLocStart())
- != DiagnosticsEngine::Ignored ||
- Diags.getDiagnosticLevel(diag::warn_sometimes_uninit_var,D->getLocStart())
- != DiagnosticsEngine::Ignored ||
- Diags.getDiagnosticLevel(diag::warn_maybe_uninit_var, D->getLocStart())
- != DiagnosticsEngine::Ignored) {
+ if (!Diags.isIgnored(diag::warn_uninit_var, D->getLocStart()) ||
+ !Diags.isIgnored(diag::warn_sometimes_uninit_var, D->getLocStart()) ||
+ !Diags.isIgnored(diag::warn_maybe_uninit_var, D->getLocStart())) {
if (CFG *cfg = AC.getCFG()) {
UninitValsDiagReporter reporter(S);
UninitVariablesAnalysisStats stats;
@@ -1775,20 +1936,33 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
}
bool FallThroughDiagFull =
- Diags.getDiagnosticLevel(diag::warn_unannotated_fallthrough,
- D->getLocStart()) != DiagnosticsEngine::Ignored;
- bool FallThroughDiagPerFunction =
- Diags.getDiagnosticLevel(diag::warn_unannotated_fallthrough_per_function,
- D->getLocStart()) != DiagnosticsEngine::Ignored;
+ !Diags.isIgnored(diag::warn_unannotated_fallthrough, D->getLocStart());
+ bool FallThroughDiagPerFunction = !Diags.isIgnored(
+ diag::warn_unannotated_fallthrough_per_function, D->getLocStart());
if (FallThroughDiagFull || FallThroughDiagPerFunction) {
DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull);
}
if (S.getLangOpts().ObjCARCWeak &&
- Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
- D->getLocStart()) != DiagnosticsEngine::Ignored)
+ !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, D->getLocStart()))
diagnoseRepeatedUseOfWeak(S, fscope, D, AC.getParentMap());
+
+ // Check for infinite self-recursion in functions
+ if (!Diags.isIgnored(diag::warn_infinite_recursive_function,
+ D->getLocStart())) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ checkRecursiveFunction(S, FD, Body, AC);
+ }
+ }
+
+ // If none of the previous checks caused a CFG build, trigger one here
+ // for -Wtautological-overlap-compare
+ if (!Diags.isIgnored(diag::warn_tautological_overlap_comparison,
+ D->getLocStart())) {
+ AC.getCFG();
+ }
+
// Collect statistics about the CFG if it was built.
if (S.CollectStats && AC.isCFGBuilt()) {
++NumFunctionsAnalyzed;
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index c9807723f064..476a22b628ad 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -13,8 +13,11 @@
#include "clang/Sema/AttributeList.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/IdentifierTable.h"
+#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
@@ -103,14 +106,6 @@ void AttributePool::takePool(AttributeList *pool) {
} while (pool);
}
-AttributeList *
-AttributePool::createIntegerAttribute(ASTContext &C, IdentifierInfo *Name,
- SourceLocation TokLoc, int Arg) {
- ArgsUnion IArg = IntegerLiteral::Create(C, llvm::APInt(32, (uint64_t) Arg),
- C.IntTy, TokLoc);
- return create(Name, TokLoc, 0, TokLoc, &IArg, 1, AttributeList::AS_GNU);
-}
-
#include "clang/Sema/AttrParsedAttrKinds.inc"
AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name,
@@ -118,21 +113,25 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name,
Syntax SyntaxUsed) {
StringRef AttrName = Name->getName();
- // Normalize the attribute name, __foo__ becomes foo.
- if (AttrName.startswith("__") && AttrName.endswith("__") &&
- AttrName.size() >= 4)
- AttrName = AttrName.substr(2, AttrName.size() - 4);
-
- SmallString<64> Buf;
+ SmallString<64> FullName;
if (ScopeName)
- Buf += ScopeName->getName();
+ FullName += ScopeName->getName();
+
+ // Normalize the attribute name, __foo__ becomes foo. This is only allowable
+ // for GNU attributes.
+ bool IsGNU = SyntaxUsed == AS_GNU || (SyntaxUsed == AS_CXX11 &&
+ FullName == "gnu");
+ if (IsGNU && AttrName.size() >= 4 && AttrName.startswith("__") &&
+ AttrName.endswith("__"))
+ AttrName = AttrName.slice(2, AttrName.size() - 2);
+
// Ensure that in the case of C++11 attributes, we look for '::foo' if it is
// unscoped.
if (ScopeName || SyntaxUsed == AS_CXX11)
- Buf += "::";
- Buf += AttrName;
+ FullName += "::";
+ FullName += AttrName;
- return ::getAttrKind(Buf);
+ return ::getAttrKind(FullName, SyntaxUsed);
}
unsigned AttributeList::getAttributeSpellingListIndex() const {
@@ -149,6 +148,15 @@ struct ParsedAttrInfo {
unsigned NumArgs : 4;
unsigned OptArgs : 4;
unsigned HasCustomParsing : 1;
+ unsigned IsTargetSpecific : 1;
+ unsigned IsType : 1;
+ unsigned IsKnownToGCC : 1;
+
+ bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr,
+ const Decl *);
+ bool (*DiagLangOpts)(Sema &S, const AttributeList &Attr);
+ bool (*ExistsInTarget)(const llvm::Triple &T);
+ unsigned (*SpellingIndexToSemanticSpelling)(const AttributeList &Attr);
};
namespace {
@@ -170,3 +178,31 @@ unsigned AttributeList::getMaxArgs() const {
bool AttributeList::hasCustomParsing() const {
return getInfo(*this).HasCustomParsing;
}
+
+bool AttributeList::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
+ return getInfo(*this).DiagAppertainsToDecl(S, *this, D);
+}
+
+bool AttributeList::diagnoseLangOpts(Sema &S) const {
+ return getInfo(*this).DiagLangOpts(S, *this);
+}
+
+bool AttributeList::isTargetSpecificAttr() const {
+ return getInfo(*this).IsTargetSpecific;
+}
+
+bool AttributeList::isTypeAttr() const {
+ return getInfo(*this).IsType;
+}
+
+bool AttributeList::existsInTarget(const llvm::Triple &T) const {
+ return getInfo(*this).ExistsInTarget(T);
+}
+
+bool AttributeList::isKnownToGCC() const {
+ return getInfo(*this).IsKnownToGCC;
+}
+
+unsigned AttributeList::getSemanticSpelling() const {
+ return getInfo(*this).SpellingIndexToSemanticSpelling(*this);
+}
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 5e0914086c28..7847d2c36e5b 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -1,8 +1,5 @@
set(LLVM_LINK_COMPONENTS
- ${LLVM_TARGETS_TO_BUILD}
- asmparser
- support
- mc
+ Support
)
add_clang_library(clangSema
@@ -50,30 +47,9 @@ add_clang_library(clangSema
SemaTemplateInstantiateDecl.cpp
SemaTemplateVariadic.cpp
SemaType.cpp
- TargetAttributesSema.cpp
TypeLocBuilder.cpp
- )
-
-add_dependencies(clangSema
- ClangARMNeon
- ClangAttrClasses
- ClangAttrList
- ClangAttrParsedAttrList
- ClangAttrParsedAttrKinds
- ClangAttrParsedAttrImpl
- ClangAttrSpellingListIndex
- ClangAttrTemplateInstantiate
- ClangCommentNodes
- ClangDeclNodes
- ClangDiagnosticAST
- ClangDiagnosticComment
- ClangDiagnosticCommon
- ClangDiagnosticParse
- ClangDiagnosticSema
- ClangStmtNodes
- )
-target_link_libraries(clangSema
+ LINK_LIBS
clangAST
clangAnalysis
clangBasic
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index 19be1cb42fe7..b2dc2d79616b 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -15,7 +15,6 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/Sema.h"
#include "llvm/ADT/STLExtras.h"
@@ -219,7 +218,7 @@ const char *CodeCompletionString::getAnnotation(unsigned AnnotationNr) const {
if (AnnotationNr < NumAnnotations)
return reinterpret_cast<const char * const*>(end())[AnnotationNr];
else
- return 0;
+ return nullptr;
}
@@ -248,8 +247,8 @@ const char *CodeCompletionString::getTypedText() const {
for (iterator C = begin(), CEnd = end(); C != CEnd; ++C)
if (C->Kind == CK_TypedText)
return C->Text;
-
- return 0;
+
+ return nullptr;
}
const char *CodeCompletionAllocator::CopyString(StringRef String) {
@@ -279,7 +278,7 @@ StringRef CodeCompletionTUInfo::getParentName(const DeclContext *DC) {
// If we already processed this DeclContext and assigned empty to it, the
// data pointer will be non-null.
- if (CachedParentName.data() != 0)
+ if (CachedParentName.data() != nullptr)
return StringRef();
// Find the interesting names.
@@ -406,7 +405,7 @@ CodeCompleteConsumer::OverloadCandidate::getFunction() const {
else if (getKind() == CK_FunctionTemplate)
return FunctionTemplate->getTemplatedDecl();
else
- return 0;
+ return nullptr;
}
const FunctionType *
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index c2f16157b8eb..d7372b7a2768 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -149,8 +149,8 @@ CXXScopeSpec::getWithLocInContext(ASTContext &Context) const {
DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
bool isAmbiguous,
SourceLocation LParenLoc,
- ParamInfo *ArgInfo,
- unsigned NumArgs,
+ ParamInfo *Params,
+ unsigned NumParams,
SourceLocation EllipsisLoc,
SourceLocation RParenLoc,
unsigned TypeQuals,
@@ -178,17 +178,17 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
I.Kind = Function;
I.Loc = LocalRangeBegin;
I.EndLoc = LocalRangeEnd;
- I.Fun.AttrList = 0;
+ I.Fun.AttrList = nullptr;
I.Fun.hasPrototype = hasProto;
I.Fun.isVariadic = EllipsisLoc.isValid();
I.Fun.isAmbiguous = isAmbiguous;
I.Fun.LParenLoc = LParenLoc.getRawEncoding();
I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding();
I.Fun.RParenLoc = RParenLoc.getRawEncoding();
- I.Fun.DeleteArgInfo = false;
+ I.Fun.DeleteParams = false;
I.Fun.TypeQuals = TypeQuals;
- I.Fun.NumArgs = NumArgs;
- I.Fun.ArgInfo = 0;
+ I.Fun.NumParams = NumParams;
+ I.Fun.Params = nullptr;
I.Fun.RefQualifierIsLValueRef = RefQualifierIsLvalueRef;
I.Fun.RefQualifierLoc = RefQualifierLoc.getRawEncoding();
I.Fun.ConstQualifierLoc = ConstQualifierLoc.getRawEncoding();
@@ -197,28 +197,28 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
I.Fun.ExceptionSpecType = ESpecType;
I.Fun.ExceptionSpecLoc = ESpecLoc.getRawEncoding();
I.Fun.NumExceptions = 0;
- I.Fun.Exceptions = 0;
- I.Fun.NoexceptExpr = 0;
+ I.Fun.Exceptions = nullptr;
+ I.Fun.NoexceptExpr = nullptr;
I.Fun.HasTrailingReturnType = TrailingReturnType.isUsable() ||
TrailingReturnType.isInvalid();
I.Fun.TrailingReturnType = TrailingReturnType.get();
- // new[] an argument array if needed.
- if (NumArgs) {
+ // new[] a parameter array if needed.
+ if (NumParams) {
// If the 'InlineParams' in Declarator is unused and big enough, put our
// parameter list there (in an effort to avoid new/delete traffic). If it
// is already used (consider a function returning a function pointer) or too
- // small (function taking too many arguments), go to the heap.
+ // small (function with too many parameters), go to the heap.
if (!TheDeclarator.InlineParamsUsed &&
- NumArgs <= llvm::array_lengthof(TheDeclarator.InlineParams)) {
- I.Fun.ArgInfo = TheDeclarator.InlineParams;
- I.Fun.DeleteArgInfo = false;
+ NumParams <= llvm::array_lengthof(TheDeclarator.InlineParams)) {
+ I.Fun.Params = TheDeclarator.InlineParams;
+ I.Fun.DeleteParams = false;
TheDeclarator.InlineParamsUsed = true;
} else {
- I.Fun.ArgInfo = new DeclaratorChunk::ParamInfo[NumArgs];
- I.Fun.DeleteArgInfo = true;
+ I.Fun.Params = new DeclaratorChunk::ParamInfo[NumParams];
+ I.Fun.DeleteParams = true;
}
- memcpy(I.Fun.ArgInfo, ArgInfo, sizeof(ArgInfo[0])*NumArgs);
+ memcpy(I.Fun.Params, Params, sizeof(Params[0]) * NumParams);
}
// Check what exception specification information we should actually store.
@@ -285,14 +285,6 @@ bool Declarator::isDeclarationOfFunction() const {
case TST_unspecified:
case TST_void:
case TST_wchar:
- case TST_image1d_t:
- case TST_image1d_array_t:
- case TST_image1d_buffer_t:
- case TST_image2d_t:
- case TST_image2d_array_t:
- case TST_image3d_t:
- case TST_sampler_t:
- case TST_event_t:
return false;
case TST_decltype_auto:
@@ -426,12 +418,13 @@ const char *DeclSpec::getSpecifierName(TSS S) {
llvm_unreachable("Unknown typespec!");
}
-const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
+const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
+ const PrintingPolicy &Policy) {
switch (T) {
case DeclSpec::TST_unspecified: return "unspecified";
case DeclSpec::TST_void: return "void";
case DeclSpec::TST_char: return "char";
- case DeclSpec::TST_wchar: return "wchar_t";
+ case DeclSpec::TST_wchar: return Policy.MSWChar ? "__wchar_t" : "wchar_t";
case DeclSpec::TST_char16: return "char16_t";
case DeclSpec::TST_char32: return "char32_t";
case DeclSpec::TST_int: return "int";
@@ -439,7 +432,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
case DeclSpec::TST_half: return "half";
case DeclSpec::TST_float: return "float";
case DeclSpec::TST_double: return "double";
- case DeclSpec::TST_bool: return "_Bool";
+ case DeclSpec::TST_bool: return Policy.Bool ? "bool" : "_Bool";
case DeclSpec::TST_decimal32: return "_Decimal32";
case DeclSpec::TST_decimal64: return "_Decimal64";
case DeclSpec::TST_decimal128: return "_Decimal128";
@@ -457,14 +450,6 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
case DeclSpec::TST_underlyingType: return "__underlying_type";
case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
case DeclSpec::TST_atomic: return "_Atomic";
- case DeclSpec::TST_image1d_t: return "image1d_t";
- case DeclSpec::TST_image1d_array_t: return "image1d_array_t";
- case DeclSpec::TST_image1d_buffer_t: return "image1d_buffer_t";
- case DeclSpec::TST_image2d_t: return "image2d_t";
- case DeclSpec::TST_image2d_array_t: return "image2d_array_t";
- case DeclSpec::TST_image3d_t: return "image3d_t";
- case DeclSpec::TST_sampler_t: return "sampler_t";
- case DeclSpec::TST_event_t: return "event_t";
case DeclSpec::TST_error: return "(error)";
}
llvm_unreachable("Unknown typespec!");
@@ -483,7 +468,8 @@ const char *DeclSpec::getSpecifierName(TQ T) {
bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc,
const char *&PrevSpec,
- unsigned &DiagID) {
+ unsigned &DiagID,
+ const PrintingPolicy &Policy) {
// OpenCL v1.1 s6.8g: "The extern, static, auto and register storage-class
// specifiers are not supported.
// It seems sensible to prohibit private_extern too
@@ -518,10 +504,10 @@ bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc,
bool isInvalid = true;
if (TypeSpecType == TST_unspecified && S.getLangOpts().CPlusPlus) {
if (SC == SCS_auto)
- return SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID);
+ return SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID, Policy);
if (StorageClassSpec == SCS_auto) {
isInvalid = SetTypeSpecType(TST_auto, StorageClassSpecLoc,
- PrevSpec, DiagID);
+ PrevSpec, DiagID, Policy);
assert(!isInvalid && "auto SCS -> TST recovery failed");
}
}
@@ -557,7 +543,8 @@ bool DeclSpec::SetStorageClassSpecThread(TSCS TSC, SourceLocation Loc,
/// specified).
bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc,
const char *&PrevSpec,
- unsigned &DiagID) {
+ unsigned &DiagID,
+ const PrintingPolicy &Policy) {
// Overwrite TSWLoc only if TypeSpecWidth was unspecified, so that
// for 'long long' we will keep the source location of the first 'long'.
if (TypeSpecWidth == TSW_unspecified)
@@ -568,7 +555,7 @@ bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc,
TypeSpecWidth = W;
if (TypeAltiVecVector && !TypeAltiVecBool &&
((TypeSpecWidth == TSW_long) || (TypeSpecWidth == TSW_longlong))) {
- PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
DiagID = diag::warn_vector_long_decl_spec_combination;
return true;
}
@@ -598,19 +585,21 @@ bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc,
bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
const char *&PrevSpec,
unsigned &DiagID,
- ParsedType Rep) {
- return SetTypeSpecType(T, Loc, Loc, PrevSpec, DiagID, Rep);
+ ParsedType Rep,
+ const PrintingPolicy &Policy) {
+ return SetTypeSpecType(T, Loc, Loc, PrevSpec, DiagID, Rep, Policy);
}
bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,
SourceLocation TagNameLoc,
const char *&PrevSpec,
unsigned &DiagID,
- ParsedType Rep) {
+ ParsedType Rep,
+ const PrintingPolicy &Policy) {
assert(isTypeRep(T) && "T does not store a type");
assert(Rep && "no type provided!");
if (TypeSpecType != TST_unspecified) {
- PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
DiagID = diag::err_invalid_decl_spec_combination;
return true;
}
@@ -625,11 +614,12 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,
bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
const char *&PrevSpec,
unsigned &DiagID,
- Expr *Rep) {
+ Expr *Rep,
+ const PrintingPolicy &Policy) {
assert(isExprRep(T) && "T does not store an expr");
assert(Rep && "no expression provided!");
if (TypeSpecType != TST_unspecified) {
- PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
DiagID = diag::err_invalid_decl_spec_combination;
return true;
}
@@ -644,20 +634,22 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
const char *&PrevSpec,
unsigned &DiagID,
- Decl *Rep, bool Owned) {
- return SetTypeSpecType(T, Loc, Loc, PrevSpec, DiagID, Rep, Owned);
+ Decl *Rep, bool Owned,
+ const PrintingPolicy &Policy) {
+ return SetTypeSpecType(T, Loc, Loc, PrevSpec, DiagID, Rep, Owned, Policy);
}
bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,
SourceLocation TagNameLoc,
const char *&PrevSpec,
unsigned &DiagID,
- Decl *Rep, bool Owned) {
+ Decl *Rep, bool Owned,
+ const PrintingPolicy &Policy) {
assert(isDeclRep(T) && "T does not store a decl");
// Unlike the other cases, we don't assert that we actually get a decl.
if (TypeSpecType != TST_unspecified) {
- PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
DiagID = diag::err_invalid_decl_spec_combination;
return true;
}
@@ -665,17 +657,18 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,
DeclRep = Rep;
TSTLoc = TagKwLoc;
TSTNameLoc = TagNameLoc;
- TypeSpecOwned = Owned && Rep != 0;
+ TypeSpecOwned = Owned && Rep != nullptr;
return false;
}
bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
const char *&PrevSpec,
- unsigned &DiagID) {
+ unsigned &DiagID,
+ const PrintingPolicy &Policy) {
assert(!isDeclRep(T) && !isTypeRep(T) && !isExprRep(T) &&
"rep required for these type-spec kinds!");
if (TypeSpecType != TST_unspecified) {
- PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
DiagID = diag::err_invalid_decl_spec_combination;
return true;
}
@@ -688,7 +681,7 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
TypeSpecType = T;
TypeSpecOwned = false;
if (TypeAltiVecVector && !TypeAltiVecBool && (TypeSpecType == TST_double)) {
- PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
DiagID = diag::err_invalid_vector_decl_spec;
return true;
}
@@ -696,9 +689,10 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
}
bool DeclSpec::SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc,
- const char *&PrevSpec, unsigned &DiagID) {
+ const char *&PrevSpec, unsigned &DiagID,
+ const PrintingPolicy &Policy) {
if (TypeSpecType != TST_unspecified) {
- PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
DiagID = diag::err_invalid_vector_decl_spec_combination;
return true;
}
@@ -708,10 +702,11 @@ bool DeclSpec::SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc,
}
bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc,
- const char *&PrevSpec, unsigned &DiagID) {
+ const char *&PrevSpec, unsigned &DiagID,
+ const PrintingPolicy &Policy) {
if (!TypeAltiVecVector || TypeAltiVecPixel ||
(TypeSpecType != TST_unspecified)) {
- PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
DiagID = diag::err_invalid_pixel_decl_spec_combination;
return true;
}
@@ -722,10 +717,11 @@ bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc,
}
bool DeclSpec::SetTypeAltiVecBool(bool isAltiVecBool, SourceLocation Loc,
- const char *&PrevSpec, unsigned &DiagID) {
+ const char *&PrevSpec, unsigned &DiagID,
+ const PrintingPolicy &Policy) {
if (!TypeAltiVecVector || TypeAltiVecBool ||
(TypeSpecType != TST_unspecified)) {
- PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType);
+ PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy);
DiagID = diag::err_invalid_vector_bool_decl_spec;
return true;
}
@@ -843,7 +839,12 @@ bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID) {
if (Friend_specified) {
PrevSpec = "friend";
- DiagID = diag::ext_duplicate_declspec;
+ // Keep the later location, so that we can later diagnose ill-formed
+ // declarations like 'friend class X friend;'. Per [class.friend]p3,
+ // 'friend' must be the first token in a friend declaration that is
+ // not a function declaration.
+ FriendLoc = Loc;
+ DiagID = diag::warn_duplicate_declspec;
return true;
}
@@ -866,7 +867,13 @@ bool DeclSpec::setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec,
bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID) {
- // 'constexpr constexpr' is ok.
+ // 'constexpr constexpr' is ok, but warn as this is likely not what the user
+ // intended.
+ if (Constexpr_specified) {
+ DiagID = diag::warn_duplicate_declspec;
+ PrevSpec = "constexpr";
+ return true;
+ }
Constexpr_specified = true;
ConstexprLoc = Loc;
return false;
@@ -906,7 +913,7 @@ void DeclSpec::SaveWrittenBuiltinSpecs() {
/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or
/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
-void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
+void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP, const PrintingPolicy &Policy) {
// Before possibly changing their values, save specs as written.
SaveWrittenBuiltinSpecs();
@@ -959,7 +966,7 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
(TypeSpecType != TST_int)) || TypeAltiVecPixel) {
Diag(D, TSTLoc, diag::err_invalid_vector_bool_decl_spec)
<< (TypeAltiVecPixel ? "__pixel" :
- getSpecifierName((TST)TypeSpecType));
+ getSpecifierName((TST)TypeSpecType, Policy));
}
// Only 'short' is valid with vector bool. (PIM 2.1)
@@ -989,7 +996,7 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
else if (TypeSpecType != TST_int && TypeSpecType != TST_int128 &&
TypeSpecType != TST_char && TypeSpecType != TST_wchar) {
Diag(D, TSSLoc, diag::err_invalid_sign_spec)
- << getSpecifierName((TST)TypeSpecType);
+ << getSpecifierName((TST)TypeSpecType, Policy);
// signed double -> double.
TypeSpecSign = TSS_unspecified;
}
@@ -1006,7 +1013,7 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
Diag(D, TSWLoc,
TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec
: diag::err_invalid_longlong_spec)
- << getSpecifierName((TST)TypeSpecType);
+ << getSpecifierName((TST)TypeSpecType, Policy);
TypeSpecType = TST_int;
TypeSpecOwned = false;
}
@@ -1016,7 +1023,7 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
TypeSpecType = TST_int; // long -> long int.
else if (TypeSpecType != TST_int && TypeSpecType != TST_double) {
Diag(D, TSWLoc, diag::err_invalid_long_spec)
- << getSpecifierName((TST)TypeSpecType);
+ << getSpecifierName((TST)TypeSpecType, Policy);
TypeSpecType = TST_int;
TypeSpecOwned = false;
}
@@ -1038,7 +1045,7 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
Diag(D, TSTLoc, diag::ext_integer_complex);
} else if (TypeSpecType != TST_float && TypeSpecType != TST_double) {
Diag(D, TSCLoc, diag::err_invalid_complex_spec)
- << getSpecifierName((TST)TypeSpecType);
+ << getSpecifierName((TST)TypeSpecType, Policy);
TypeSpecComplex = TSC_unspecified;
}
}
@@ -1118,14 +1125,41 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
ThreadHint = FixItHint::CreateRemoval(SCLoc);
}
- Diag(D, SCLoc, diag::err_friend_storage_spec)
+ Diag(D, SCLoc, diag::err_friend_decl_spec)
<< SpecName << StorageHint << ThreadHint;
ClearStorageClassSpecs();
}
+ // C++11 [dcl.fct.spec]p5:
+ // The virtual specifier shall be used only in the initial
+ // declaration of a non-static class member function;
+ // C++11 [dcl.fct.spec]p6:
+ // The explicit specifier shall be used only in the declaration of
+ // a constructor or conversion function within its class
+ // definition;
+ if (isFriendSpecified() && (isVirtualSpecified() || isExplicitSpecified())) {
+ StringRef Keyword;
+ SourceLocation SCLoc;
+
+ if (isVirtualSpecified()) {
+ Keyword = "virtual";
+ SCLoc = getVirtualSpecLoc();
+ } else {
+ Keyword = "explicit";
+ SCLoc = getExplicitSpecLoc();
+ }
+
+ FixItHint Hint = FixItHint::CreateRemoval(SCLoc);
+ Diag(D, SCLoc, diag::err_friend_decl_spec)
+ << Keyword << Hint;
+
+ FS_virtual_specified = FS_explicit_specified = false;
+ FS_virtualLoc = FS_explicitLoc = SourceLocation();
+ }
+
assert(!TypeSpecOwned || isDeclRep((TST) TypeSpecType));
-
+
// Okay, now we can infer the real type.
// TODO: return "auto function" and other bad things based on the real type.
@@ -1135,7 +1169,7 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
bool DeclSpec::isMissingDeclaratorOk() {
TST tst = getTypeSpecType();
- return isDeclRep(tst) && getRepAsDecl() != 0 &&
+ return isDeclRep(tst) && getRepAsDecl() != nullptr &&
StorageClassSpec != DeclSpec::SCS_typedef;
}
diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp
index 310043288554..664a6b1a8998 100644
--- a/lib/Sema/DelayedDiagnostic.cpp
+++ b/lib/Sema/DelayedDiagnostic.cpp
@@ -19,19 +19,29 @@
using namespace clang;
using namespace sema;
-DelayedDiagnostic DelayedDiagnostic::makeDeprecation(SourceLocation Loc,
+DelayedDiagnostic
+DelayedDiagnostic::makeAvailability(Sema::AvailabilityDiagnostic AD,
+ SourceLocation Loc,
const NamedDecl *D,
const ObjCInterfaceDecl *UnknownObjCClass,
const ObjCPropertyDecl *ObjCProperty,
- StringRef Msg) {
+ StringRef Msg,
+ bool ObjCPropertyAccess) {
DelayedDiagnostic DD;
- DD.Kind = Deprecation;
+ switch (AD) {
+ case Sema::AD_Deprecation:
+ DD.Kind = Deprecation;
+ break;
+ case Sema::AD_Unavailable:
+ DD.Kind = Unavailable;
+ break;
+ }
DD.Triggered = false;
DD.Loc = Loc;
DD.DeprecationData.Decl = D;
DD.DeprecationData.UnknownObjCClass = UnknownObjCClass;
DD.DeprecationData.ObjCProperty = ObjCProperty;
- char *MessageData = 0;
+ char *MessageData = nullptr;
if (Msg.size()) {
MessageData = new char [Msg.size()];
memcpy(MessageData, Msg.data(), Msg.size());
@@ -39,16 +49,18 @@ DelayedDiagnostic DelayedDiagnostic::makeDeprecation(SourceLocation Loc,
DD.DeprecationData.Message = MessageData;
DD.DeprecationData.MessageLen = Msg.size();
+ DD.DeprecationData.ObjCPropertyAccess = ObjCPropertyAccess;
return DD;
}
void DelayedDiagnostic::Destroy() {
- switch (Kind) {
+ switch (static_cast<DDKind>(Kind)) {
case Access:
getAccessData().~AccessedEntity();
break;
- case Deprecation:
+ case Deprecation:
+ case Unavailable:
delete [] DeprecationData.Message;
break;
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index 6e354b9060e3..2a5bacff0d93 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -45,7 +45,7 @@ class IdentifierResolver::IdDeclInfoMap {
unsigned int CurIndex;
public:
- IdDeclInfoMap() : CurPool(0), CurIndex(POOL_SIZE) {}
+ IdDeclInfoMap() : CurPool(nullptr), CurIndex(POOL_SIZE) {}
~IdDeclInfoMap() {
IdDeclInfoPool *Cur = CurPool;
@@ -95,7 +95,7 @@ IdentifierResolver::~IdentifierResolver() {
/// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
/// true if 'D' belongs to the given declaration context.
bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S,
- bool ExplicitInstantiationOrSpecialization) const {
+ bool AllowInlineNamespace) const {
Ctx = Ctx->getRedeclContext();
if (Ctx->isFunctionOrMethod() || S->isFunctionPrototypeScope()) {
@@ -131,9 +131,8 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S,
}
DeclContext *DCtx = D->getDeclContext()->getRedeclContext();
- return ExplicitInstantiationOrSpecialization
- ? Ctx->InEnclosingNamespaceSetOf(DCtx)
- : Ctx->Equals(DCtx);
+ return AllowInlineNamespace ? Ctx->InEnclosingNamespaceSetOf(DCtx)
+ : Ctx->Equals(DCtx);
}
/// AddDecl - Link the decl to its shadowed decl chain.
@@ -152,7 +151,7 @@ void IdentifierResolver::AddDecl(NamedDecl *D) {
IdDeclInfo *IDI;
if (isDeclPtr(Ptr)) {
- Name.setFETokenInfo(NULL);
+ Name.setFETokenInfo(nullptr);
IDI = &(*IdDeclInfos)[Name];
NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr);
IDI->AddDecl(PrevD);
@@ -214,7 +213,7 @@ void IdentifierResolver::RemoveDecl(NamedDecl *D) {
if (isDeclPtr(Ptr)) {
assert(D == Ptr && "Didn't find this decl on its identifier's chain!");
- Name.setFETokenInfo(NULL);
+ Name.setFETokenInfo(nullptr);
return;
}
@@ -274,10 +273,8 @@ static DeclMatchKind compareDeclarations(NamedDecl *Existing, NamedDecl *New) {
// If the existing declaration is somewhere in the previous declaration
// chain of the new declaration, then prefer the new declaration.
- for (Decl::redecl_iterator RD = New->redecls_begin(),
- RDEnd = New->redecls_end();
- RD != RDEnd; ++RD) {
- if (*RD == Existing)
+ for (auto RD : New->redecls()) {
+ if (RD == Existing)
return DMK_Replace;
if (RD->isCanonicalDecl())
@@ -317,8 +314,8 @@ bool IdentifierResolver::tryAddTopLevelDecl(NamedDecl *D, DeclarationName Name){
Name.setFETokenInfo(D);
return true;
}
-
- Name.setFETokenInfo(NULL);
+
+ Name.setFETokenInfo(nullptr);
IDI = &(*IdDeclInfos)[Name];
// If the existing declaration is not visible in translation unit scope,
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index d3de1732766e..255845282dfa 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -32,6 +32,10 @@ namespace {
class JumpScopeChecker {
Sema &S;
+ /// Permissive - True when recovering from errors, in which case precautions
+ /// are taken to handle incomplete scope information.
+ const bool Permissive;
+
/// GotoScope - This is a record that we use to keep track of all of the
/// scopes that are introduced by VLAs and other things that scope jumps like
/// gotos. This scope tree has nothing to do with the source scope tree,
@@ -85,8 +89,10 @@ private:
};
} // end anonymous namespace
+#define CHECK_PERMISSIVE(x) (assert(Permissive || !(x)), (Permissive && (x)))
-JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) {
+JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s)
+ : S(s), Permissive(s.hasAnyUnrecoverableErrorsInThisFunction()) {
// Add a scope entry for function scope.
Scopes.push_back(GotoScope(~0U, ~0U, ~0U, SourceLocation()));
@@ -121,9 +127,11 @@ 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 ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
+static ScopePair GetDiagForGotoScopeDecl(Sema &S, const Decl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
unsigned InDiag = 0;
+ unsigned OutDiag = 0;
+
if (VD->getType()->isVariablyModifiedType())
InDiag = diag::note_protected_by_vla;
@@ -135,21 +143,24 @@ static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
return ScopePair(diag::note_protected_by_cleanup,
diag::note_exits_cleanup);
- if (Context.getLangOpts().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:
+ if (VD->hasLocalStorage()) {
+ switch (VD->getType().isDestructedType()) {
+ case QualType::DK_objc_strong_lifetime:
+ case QualType::DK_objc_weak_lifetime:
return ScopePair(diag::note_protected_by_objc_ownership,
diag::note_exits_objc_ownership);
+
+ case QualType::DK_cxx_destructor:
+ OutDiag = diag::note_exits_dtor;
+ break;
+
+ case QualType::DK_none:
+ break;
}
}
- if (Context.getLangOpts().CPlusPlus && VD->hasLocalStorage()) {
+ const Expr *Init = VD->getInit();
+ if (S.Context.getLangOpts().CPlusPlus && VD->hasLocalStorage() && Init) {
// C++11 [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
@@ -164,68 +175,34 @@ static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
// where it is in scope is ill-formed unless the variable has
// POD type and is declared without an initializer.
- const Expr *Init = VD->getInit();
- if (!Init)
- return ScopePair(InDiag, 0);
-
- const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init);
- if (EWC)
- Init = EWC->getSubExpr();
-
- const MaterializeTemporaryExpr *M = NULL;
- Init = Init->findMaterializedTemporary(M);
-
- SmallVector<const Expr *, 2> CommaLHSs;
- SmallVector<SubobjectAdjustment, 2> Adjustments;
- Init = Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
-
- QualType QT = Init->getType();
- if (QT.isNull())
- return ScopePair(diag::note_protected_by_variable_init, 0);
-
- const Type *T = QT.getTypePtr();
- if (T->isArrayType())
- T = T->getBaseElementTypeUnsafe();
-
- const CXXRecordDecl *Record = T->getAsCXXRecordDecl();
- if (!Record)
- return ScopePair(diag::note_protected_by_variable_init, 0);
+ InDiag = diag::note_protected_by_variable_init;
- // If we need to call a non trivial destructor for this variable,
- // record an out diagnostic.
- unsigned OutDiag = 0;
- if (!Init->isGLValue() && !Record->hasTrivialDestructor())
- OutDiag = diag::note_exits_dtor;
-
- if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(Init)) {
- const CXXConstructorDecl *ctor = cce->getConstructor();
- // For a variable declared without an initializer, we will have
- // call-style initialization and the initializer will be the
- // CXXConstructExpr with no intervening nodes.
- if (ctor->isTrivial() && ctor->isDefaultConstructor() &&
- VD->getInit() == Init && VD->getInitStyle() == VarDecl::CallInit) {
+ // For a variable of (array of) class type declared without an
+ // initializer, we will have call-style initialization and the initializer
+ // will be the CXXConstructExpr with no intervening nodes.
+ if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) {
+ const CXXConstructorDecl *Ctor = CCE->getConstructor();
+ if (Ctor->isTrivial() && Ctor->isDefaultConstructor() &&
+ VD->getInitStyle() == VarDecl::CallInit) {
if (OutDiag)
InDiag = diag::note_protected_by_variable_nontriv_destructor;
- else if (!Record->isPOD())
+ else if (!Ctor->getParent()->isPOD())
InDiag = diag::note_protected_by_variable_non_pod;
- return ScopePair(InDiag, OutDiag);
+ else
+ InDiag = 0;
}
}
-
- return ScopePair(diag::note_protected_by_variable_init, OutDiag);
}
- return ScopePair(InDiag, 0);
- }
-
- if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
- if (TD->getUnderlyingType()->isVariablyModifiedType())
- return ScopePair(diag::note_protected_by_vla_typedef, 0);
+ return ScopePair(InDiag, OutDiag);
}
- if (const TypeAliasDecl *TD = dyn_cast<TypeAliasDecl>(D)) {
+ if (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
if (TD->getUnderlyingType()->isVariablyModifiedType())
- return ScopePair(diag::note_protected_by_vla_type_alias, 0);
+ return ScopePair(isa<TypedefDecl>(TD)
+ ? diag::note_protected_by_vla_typedef
+ : diag::note_protected_by_vla_type_alias,
+ 0);
}
return ScopePair(0U, 0U);
@@ -234,7 +211,7 @@ static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
/// \brief Build scope information for a declaration that is part of a DeclStmt.
void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) {
// If this decl causes a new scope, push and switch to it.
- std::pair<unsigned,unsigned> Diags = GetDiagForGotoScopeDecl(S.Context, D);
+ std::pair<unsigned,unsigned> Diags = GetDiagForGotoScopeDecl(S, D);
if (Diags.first || Diags.second) {
Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second,
D->getLocation()));
@@ -371,7 +348,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
}
Stmt *SubStmt = *CI;
- if (SubStmt == 0) continue;
+ if (!SubStmt) continue;
// Cases, labels, and defaults aren't "scope parents". It's also
// important to handle these iteratively instead of recursively in
@@ -396,9 +373,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
if (DeclStmt *DS = dyn_cast<DeclStmt>(SubStmt)) {
// The decl statement creates a scope if any of the decls in it are VLAs
// or have the cleanup attribute.
- for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end();
- I != E; ++I)
- BuildScopeInformation(*I, ParentScope);
+ for (auto *I : DS->decls())
+ BuildScopeInformation(I, ParentScope);
continue;
}
// Disallow jumps into any part of an @try statement by pushing a scope and
@@ -474,14 +450,32 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(SubStmt)) {
for (unsigned i = 0, e = EWC->getNumObjects(); i != e; ++i) {
const BlockDecl *BDecl = EWC->getObject(i);
- for (BlockDecl::capture_const_iterator ci = BDecl->capture_begin(),
- ce = BDecl->capture_end(); ci != ce; ++ci) {
- VarDecl *variable = ci->getVariable();
+ for (const auto &CI : BDecl->captures()) {
+ VarDecl *variable = CI.getVariable();
BuildScopeInformation(variable, BDecl, ParentScope);
}
}
}
-
+
+ // Disallow jumps out of scopes containing temporaries lifetime-extended to
+ // automatic storage duration.
+ if (MaterializeTemporaryExpr *MTE =
+ dyn_cast<MaterializeTemporaryExpr>(SubStmt)) {
+ if (MTE->getStorageDuration() == SD_Automatic) {
+ SmallVector<const Expr *, 4> CommaLHS;
+ SmallVector<SubobjectAdjustment, 4> Adjustments;
+ const Expr *ExtendedObject =
+ MTE->GetTemporaryExpr()->skipRValueSubobjectAdjustments(
+ CommaLHS, Adjustments);
+ if (ExtendedObject->getType().isDestructedType()) {
+ Scopes.push_back(GotoScope(ParentScope, 0,
+ diag::note_exits_temporary_dtor,
+ ExtendedObject->getExprLoc()));
+ ParentScope = Scopes.size()-1;
+ }
+ }
+ }
+
// Recursively walk the AST.
BuildScopeInformation(SubStmt, ParentScope);
}
@@ -497,7 +491,7 @@ void JumpScopeChecker::VerifyJumps() {
if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) {
CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(),
diag::err_goto_into_protected_scope,
- diag::warn_goto_into_protected_scope,
+ diag::ext_goto_into_protected_scope,
diag::warn_cxx98_compat_goto_into_protected_scope);
continue;
}
@@ -507,7 +501,7 @@ void JumpScopeChecker::VerifyJumps() {
LabelDecl *Target = IGS->getConstantTarget();
CheckJump(IGS, Target->getStmt(), IGS->getGotoLoc(),
diag::err_goto_into_protected_scope,
- diag::warn_goto_into_protected_scope,
+ diag::ext_goto_into_protected_scope,
diag::warn_cxx98_compat_goto_into_protected_scope);
continue;
}
@@ -515,7 +509,8 @@ void JumpScopeChecker::VerifyJumps() {
SwitchStmt *SS = cast<SwitchStmt>(Jump);
for (SwitchCase *SC = SS->getSwitchCaseList(); SC;
SC = SC->getNextSwitchCase()) {
- assert(LabelAndGotoScopes.count(SC) && "Case not visited?");
+ if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(SC)))
+ continue;
SourceLocation Loc;
if (CaseStmt *CS = dyn_cast<CaseStmt>(SC))
Loc = CS->getLocStart();
@@ -569,8 +564,8 @@ void JumpScopeChecker::VerifyIndirectJumps() {
for (SmallVectorImpl<IndirectGotoStmt*>::iterator
I = IndirectJumps.begin(), E = IndirectJumps.end(); I != E; ++I) {
IndirectGotoStmt *IG = *I;
- assert(LabelAndGotoScopes.count(IG) &&
- "indirect jump didn't get added to scopes?");
+ if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(IG)))
+ continue;
unsigned IGScope = LabelAndGotoScopes[IG];
IndirectGotoStmt *&Entry = JumpScopesMap[IGScope];
if (!Entry) Entry = IG;
@@ -589,8 +584,8 @@ void JumpScopeChecker::VerifyIndirectJumps() {
I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end();
I != E; ++I) {
LabelDecl *TheLabel = *I;
- assert(LabelAndGotoScopes.count(TheLabel->getStmt()) &&
- "Referenced label didn't get added to scopes?");
+ if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(TheLabel->getStmt())))
+ continue;
unsigned LabelScope = LabelAndGotoScopes[TheLabel->getStmt()];
LabelDecl *&Target = TargetScopes[LabelScope];
if (!Target) Target = TheLabel;
@@ -695,7 +690,8 @@ static void DiagnoseIndirectJumpStmt(Sema &S, IndirectGotoStmt *Jump,
/// Produce note diagnostics for a jump into a protected scope.
void JumpScopeChecker::NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes) {
- assert(!ToScopes.empty());
+ if (CHECK_PERMISSIVE(ToScopes.empty()))
+ return;
for (unsigned I = 0, E = ToScopes.size(); I != E; ++I)
if (Scopes[ToScopes[I]].InDiag)
S.Diag(Scopes[ToScopes[I]].Loc, Scopes[ToScopes[I]].InDiag);
@@ -706,7 +702,8 @@ void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
unsigned JumpScope,
LabelDecl *Target,
unsigned TargetScope) {
- assert(JumpScope != TargetScope);
+ if (CHECK_PERMISSIVE(JumpScope == TargetScope))
+ return;
unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope);
bool Diagnosed = false;
@@ -743,10 +740,12 @@ void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
unsigned JumpDiagError, unsigned JumpDiagWarning,
unsigned JumpDiagCXX98Compat) {
- assert(LabelAndGotoScopes.count(From) && "Jump didn't get added to scopes?");
- unsigned FromScope = LabelAndGotoScopes[From];
+ if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(From)))
+ return;
+ if (CHECK_PERMISSIVE(!LabelAndGotoScopes.count(To)))
+ return;
- assert(LabelAndGotoScopes.count(To) && "Jump didn't get added to scopes?");
+ unsigned FromScope = LabelAndGotoScopes[From];
unsigned ToScope = LabelAndGotoScopes[To];
// Common case: exactly the same scope, which is fine.
@@ -762,7 +761,7 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, SourceLocation DiagLoc,
SmallVector<unsigned, 10> ToScopesError;
SmallVector<unsigned, 10> ToScopesWarning;
for (unsigned I = ToScope; I != CommonScope; I = Scopes[I].ParentScope) {
- if (S.getLangOpts().MicrosoftMode && JumpDiagWarning != 0 &&
+ if (S.getLangOpts().MSVCCompat && JumpDiagWarning != 0 &&
IsMicrosoftJumpWarning(JumpDiagError, Scopes[I].InDiag))
ToScopesWarning.push_back(I);
else if (IsCXX98CompatWarning(S, Scopes[I].InDiag))
diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp
index ad7627a45715..97237dbf097d 100644
--- a/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -46,7 +46,12 @@ Decl *MultiplexExternalSemaSource::GetExternalDecl(uint32_t ID) {
for(size_t i = 0; i < Sources.size(); ++i)
if (Decl *Result = Sources[i]->GetExternalDecl(ID))
return Result;
- return 0;
+ return nullptr;
+}
+
+void MultiplexExternalSemaSource::CompleteRedeclChain(const Decl *D) {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->CompleteRedeclChain(D);
}
Selector MultiplexExternalSemaSource::GetExternalSelector(uint32_t ID) {
@@ -70,7 +75,7 @@ Stmt *MultiplexExternalSemaSource::GetExternalDeclStmt(uint64_t Offset) {
for(size_t i = 0; i < Sources.size(); ++i)
if (Stmt *Result = Sources[i]->GetExternalDeclStmt(Offset))
return Result;
- return 0;
+ return nullptr;
}
CXXBaseSpecifier *MultiplexExternalSemaSource::GetExternalCXXBaseSpecifiers(
@@ -78,7 +83,7 @@ CXXBaseSpecifier *MultiplexExternalSemaSource::GetExternalCXXBaseSpecifiers(
for(size_t i = 0; i < Sources.size(); ++i)
if (CXXBaseSpecifier *R = Sources[i]->GetExternalCXXBaseSpecifiers(Offset))
return R;
- return 0;
+ return nullptr;
}
bool MultiplexExternalSemaSource::
diff --git a/lib/Sema/Scope.cpp b/lib/Sema/Scope.cpp
index 10f12ce844f8..35e2075b3826 100644
--- a/lib/Sema/Scope.cpp
+++ b/lib/Sema/Scope.cpp
@@ -13,6 +13,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/Scope.h"
+#include "clang/AST/Decl.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -26,7 +28,7 @@ void Scope::Init(Scope *parent, unsigned flags) {
} else {
// Control scopes do not contain the contents of nested function scopes for
// control flow purposes.
- BreakParent = ContinueParent = 0;
+ BreakParent = ContinueParent = nullptr;
}
if (parent) {
@@ -36,16 +38,35 @@ void Scope::Init(Scope *parent, unsigned flags) {
FnParent = parent->FnParent;
BlockParent = parent->BlockParent;
TemplateParamParent = parent->TemplateParamParent;
+ MSLocalManglingParent = parent->MSLocalManglingParent;
+ SEHTryParent = parent->SEHTryParent;
+ if (parent->Flags & SEHTryScope)
+ SEHTryParent = parent;
+ if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |
+ FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==
+ 0)
+ Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;
} else {
Depth = 0;
PrototypeDepth = 0;
PrototypeIndex = 0;
- FnParent = BlockParent = 0;
- TemplateParamParent = 0;
+ SEHTryParent = MSLocalManglingParent = FnParent = BlockParent = nullptr;
+ TemplateParamParent = nullptr;
+ MSLocalManglingNumber = 1;
}
// If this scope is a function or contains breaks/continues, remember it.
if (flags & FnScope) FnParent = this;
+ SEHTryIndexPool = 0;
+ SEHTryIndex = -1;
+ if (flags & SEHTryScope)
+ SEHTryIndex = FnParent ? FnParent->SEHTryIndexPool++ : -1;
+ // The MS mangler uses the number of scopes that can hold declarations as
+ // part of an external name.
+ if (Flags & (ClassScope | FnScope)) {
+ MSLocalManglingNumber = getMSLocalManglingNumber();
+ MSLocalManglingParent = this;
+ }
if (flags & BreakScope) BreakParent = this;
if (flags & ContinueScope) ContinueParent = this;
if (flags & BlockScope) BlockParent = this;
@@ -54,10 +75,24 @@ void Scope::Init(Scope *parent, unsigned flags) {
// If this is a prototype scope, record that.
if (flags & FunctionPrototypeScope) PrototypeDepth++;
+ if (flags & DeclScope) {
+ if (flags & FunctionPrototypeScope)
+ ; // Prototype scopes are uninteresting.
+ else if ((flags & ClassScope) && getParent()->isClassScope())
+ ; // Nested class scopes aren't ambiguous.
+ else if ((flags & ClassScope) && getParent()->getFlags() == DeclScope)
+ ; // Classes inside of namespaces aren't ambiguous.
+ else if ((flags & EnumScope))
+ ; // Don't increment for enum scopes.
+ else
+ incrementMSLocalManglingNumber();
+ }
+
DeclsInScope.clear();
UsingDirectives.clear();
- Entity = 0;
+ Entity = nullptr;
ErrorTrap.reset();
+ NRVO.setPointerAndInt(nullptr, 0);
}
bool Scope::containedInPrototypeScope() const {
@@ -69,3 +104,121 @@ bool Scope::containedInPrototypeScope() const {
}
return false;
}
+
+void Scope::AddFlags(unsigned FlagsToSet) {
+ assert((FlagsToSet & ~(BreakScope | ContinueScope)) == 0 &&
+ "Unsupported scope flags");
+ if (FlagsToSet & BreakScope) {
+ assert((Flags & BreakScope) == 0 && "Already set");
+ BreakParent = this;
+ }
+ if (FlagsToSet & ContinueScope) {
+ assert((Flags & ContinueScope) == 0 && "Already set");
+ ContinueParent = this;
+ }
+ Flags |= FlagsToSet;
+}
+
+void Scope::mergeNRVOIntoParent() {
+ if (VarDecl *Candidate = NRVO.getPointer()) {
+ if (isDeclScope(Candidate))
+ Candidate->setNRVOVariable(true);
+ }
+
+ if (getEntity())
+ return;
+
+ if (NRVO.getInt())
+ getParent()->setNoNRVO();
+ else if (NRVO.getPointer())
+ getParent()->addNRVOCandidate(NRVO.getPointer());
+}
+
+void Scope::dump() const { dumpImpl(llvm::errs()); }
+
+void Scope::dumpImpl(raw_ostream &OS) const {
+ unsigned Flags = getFlags();
+ bool HasFlags = Flags != 0;
+
+ if (HasFlags)
+ OS << "Flags: ";
+
+ while (Flags) {
+ if (Flags & FnScope) {
+ OS << "FnScope";
+ Flags &= ~FnScope;
+ } else if (Flags & BreakScope) {
+ OS << "BreakScope";
+ Flags &= ~BreakScope;
+ } else if (Flags & ContinueScope) {
+ OS << "ContinueScope";
+ Flags &= ~ContinueScope;
+ } else if (Flags & DeclScope) {
+ OS << "DeclScope";
+ Flags &= ~DeclScope;
+ } else if (Flags & ControlScope) {
+ OS << "ControlScope";
+ Flags &= ~ControlScope;
+ } else if (Flags & ClassScope) {
+ OS << "ClassScope";
+ Flags &= ~ClassScope;
+ } else if (Flags & BlockScope) {
+ OS << "BlockScope";
+ Flags &= ~BlockScope;
+ } else if (Flags & TemplateParamScope) {
+ OS << "TemplateParamScope";
+ Flags &= ~TemplateParamScope;
+ } else if (Flags & FunctionPrototypeScope) {
+ OS << "FunctionPrototypeScope";
+ Flags &= ~FunctionPrototypeScope;
+ } else if (Flags & FunctionDeclarationScope) {
+ OS << "FunctionDeclarationScope";
+ Flags &= ~FunctionDeclarationScope;
+ } else if (Flags & AtCatchScope) {
+ OS << "AtCatchScope";
+ Flags &= ~AtCatchScope;
+ } else if (Flags & ObjCMethodScope) {
+ OS << "ObjCMethodScope";
+ Flags &= ~ObjCMethodScope;
+ } else if (Flags & SwitchScope) {
+ OS << "SwitchScope";
+ Flags &= ~SwitchScope;
+ } else if (Flags & TryScope) {
+ OS << "TryScope";
+ Flags &= ~TryScope;
+ } else if (Flags & FnTryCatchScope) {
+ OS << "FnTryCatchScope";
+ Flags &= ~FnTryCatchScope;
+ } else if (Flags & SEHTryScope) {
+ OS << "SEHTryScope";
+ Flags &= ~SEHTryScope;
+ } else if (Flags & OpenMPDirectiveScope) {
+ OS << "OpenMPDirectiveScope";
+ Flags &= ~OpenMPDirectiveScope;
+ } else if (Flags & OpenMPLoopDirectiveScope) {
+ OS << "OpenMPLoopDirectiveScope";
+ Flags &= ~OpenMPLoopDirectiveScope;
+ } else if (Flags & OpenMPSimdDirectiveScope) {
+ OS << "OpenMPSimdDirectiveScope";
+ Flags &= ~OpenMPSimdDirectiveScope;
+ }
+
+ if (Flags)
+ OS << " | ";
+ }
+ if (HasFlags)
+ OS << '\n';
+
+ if (const Scope *Parent = getParent())
+ OS << "Parent: (clang::Scope*)" << Parent << '\n';
+
+ OS << "Depth: " << Depth << '\n';
+ OS << "MSLocalManglingNumber: " << getMSLocalManglingNumber() << '\n';
+ if (const DeclContext *DC = getEntity())
+ OS << "Entity : (clang::DeclContext*)" << DC << '\n';
+
+ if (NRVO.getInt())
+ OS << "NRVO not allowed";
+ else if (NRVO.getPointer())
+ OS << "NRVO candidate : (clang::VarDecl*)" << NRVO.getPointer() << '\n';
+}
diff --git a/lib/Sema/ScopeInfo.cpp b/lib/Sema/ScopeInfo.cpp
index 8b3493ebfef8..4d079e705f62 100644
--- a/lib/Sema/ScopeInfo.cpp
+++ b/lib/Sema/ScopeInfo.cpp
@@ -26,6 +26,12 @@ void FunctionScopeInfo::Clear() {
HasBranchProtectedScope = false;
HasBranchIntoScope = false;
HasIndirectGoto = false;
+ HasDroppedStmt = false;
+ ObjCShouldCallSuper = false;
+ ObjCIsDesignatedInit = false;
+ ObjCWarnForNoDesignatedInitChain = false;
+ ObjCIsSecondaryInit = false;
+ ObjCWarnForNoInitDelegation = false;
SwitchStack.clear();
Returns.clear();
@@ -45,7 +51,7 @@ FunctionScopeInfo::WeakObjectProfileTy::BaseInfoTy
FunctionScopeInfo::WeakObjectProfileTy::getBaseInfo(const Expr *E) {
E = E->IgnoreParenCasts();
- const NamedDecl *D = 0;
+ const NamedDecl *D = nullptr;
bool IsExact = false;
switch (E->getStmtClass()) {
@@ -87,10 +93,9 @@ FunctionScopeInfo::WeakObjectProfileTy::getBaseInfo(const Expr *E) {
return BaseInfoTy(D, IsExact);
}
-
FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(
const ObjCPropertyRefExpr *PropE)
- : Base(0, true), Property(getBestPropertyDecl(PropE)) {
+ : Base(nullptr, true), Property(getBestPropertyDecl(PropE)) {
if (PropE->isObjectReceiver()) {
const OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(PropE->getBase());
@@ -105,7 +110,7 @@ FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(
FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(const Expr *BaseE,
const ObjCPropertyDecl *Prop)
- : Base(0, true), Property(Prop) {
+ : Base(nullptr, true), Property(Prop) {
if (BaseE)
Base = getBaseInfo(BaseE);
// else, this is a message accessing a property on super.
@@ -113,7 +118,7 @@ FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(const Expr *BaseE,
FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(
const DeclRefExpr *DRE)
- : Base(0, true), Property(DRE->getDecl()) {
+ : Base(nullptr, true), Property(DRE->getDecl()) {
assert(isa<VarDecl>(Property));
}
@@ -153,8 +158,14 @@ void FunctionScopeInfo::markSafeWeakUse(const Expr *E) {
// Has this weak object been seen before?
FunctionScopeInfo::WeakObjectUseMap::iterator Uses;
- if (const ObjCPropertyRefExpr *RefExpr = dyn_cast<ObjCPropertyRefExpr>(E))
- Uses = WeakObjectUses.find(WeakObjectProfileTy(RefExpr));
+ if (const ObjCPropertyRefExpr *RefExpr = dyn_cast<ObjCPropertyRefExpr>(E)) {
+ if (isa<OpaqueValueExpr>(RefExpr->getBase()))
+ Uses = WeakObjectUses.find(WeakObjectProfileTy(RefExpr));
+ else {
+ markSafeWeakUse(RefExpr->getBase());
+ return;
+ }
+ }
else if (const ObjCIvarRefExpr *IvarE = dyn_cast<ObjCIvarRefExpr>(E))
Uses = WeakObjectUses.find(WeakObjectProfileTy(IvarE));
else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
@@ -184,10 +195,11 @@ void FunctionScopeInfo::markSafeWeakUse(const Expr *E) {
ThisUse->markSafe();
}
-void LambdaScopeInfo::getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E) {
+void LambdaScopeInfo::getPotentialVariableCapture(unsigned Idx, VarDecl *&VD,
+ Expr *&E) const {
assert(Idx < getNumPotentialVariableCaptures() &&
- "Index of potential capture must be within 0 to less than the "
- "number of captures!");
+ "Index of potential capture must be within 0 to less than the "
+ "number of captures!");
E = PotentiallyCapturingExprs[Idx];
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
VD = dyn_cast<VarDecl>(DRE->getFoundDecl());
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 4d01fb0a6be6..2c653325b37b 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -13,7 +13,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "TargetAttributesSema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/DeclCXX.h"
@@ -22,6 +21,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
@@ -44,6 +44,12 @@
using namespace clang;
using namespace sema;
+SourceLocation Sema::getLocForEndOfToken(SourceLocation Loc, unsigned Offset) {
+ return Lexer::getLocForEndOfToken(Loc, Offset, SourceMgr, LangOpts);
+}
+
+ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); }
+
PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context,
const Preprocessor &PP) {
PrintingPolicy Policy = Context.getPrintingPolicy();
@@ -70,35 +76,41 @@ void Sema::ActOnTranslationUnitScope(Scope *S) {
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TranslationUnitKind TUKind,
CodeCompleteConsumer *CodeCompleter)
- : TheTargetAttributesSema(0), ExternalSource(0),
+ : ExternalSource(nullptr),
isMultiplexExternalSource(false), FPFeatures(pp.getLangOpts()),
LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
CollectStats(false), CodeCompleter(CodeCompleter),
- CurContext(0), OriginalLexicalContext(0),
- PackContext(0), MSStructPragmaOn(false), VisContext(0),
+ CurContext(nullptr), OriginalLexicalContext(nullptr),
+ PackContext(nullptr), MSStructPragmaOn(false),
+ MSPointerToMemberRepresentationMethod(
+ LangOpts.getMSPointerToMemberRepresentationMethod()),
+ VtorDispModeStack(1, MSVtorDispAttr::Mode(LangOpts.VtorDispMode)),
+ DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
+ CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr),
IsBuildingRecoveryCallExpr(false),
- ExprNeedsCleanups(false), LateTemplateParser(0), OpaqueParser(0),
- IdResolver(pp), StdInitializerList(0), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
- NSNumberDecl(0),
- NSStringDecl(0), StringWithUTF8StringMethod(0),
- NSArrayDecl(0), ArrayWithObjectsMethod(0),
- NSDictionaryDecl(0), DictionaryWithObjectsMethod(0),
+ ExprNeedsCleanups(false), LateTemplateParser(nullptr),
+ OpaqueParser(nullptr), IdResolver(pp), StdInitializerList(nullptr),
+ CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr),
+ NSNumberDecl(nullptr),
+ NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr),
+ NSArrayDecl(nullptr), ArrayWithObjectsMethod(nullptr),
+ NSDictionaryDecl(nullptr), DictionaryWithObjectsMethod(nullptr),
GlobalNewDeleteDeclared(false),
TUKind(TUKind),
- NumSFINAEErrors(0), InFunctionDeclarator(0),
+ NumSFINAEErrors(0),
AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
- CurrentInstantiationScope(0), DisableTypoCorrection(false),
+ CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),
TyposCorrected(0), AnalysisWarnings(*this),
- VarDataSharingAttributesStack(0), CurScope(0),
- Ident_super(0), Ident___float128(0)
+ VarDataSharingAttributesStack(nullptr), CurScope(nullptr),
+ Ident_super(nullptr), Ident___float128(nullptr)
{
- TUScope = 0;
+ TUScope = nullptr;
LoadedExternalKnownNamespaces = false;
for (unsigned I = 0; I != NSAPI::NumNSNumberLiteralMethods; ++I)
- NSNumberLiteralMethods[I] = 0;
+ NSNumberLiteralMethods[I] = nullptr;
if (getLangOpts().ObjC1)
NSAPIObj.reset(new NSAPI(Context));
@@ -112,7 +124,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
ExprEvalContexts.push_back(
ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0,
- false, 0, false));
+ false, nullptr, false));
FunctionScopes.push_back(new FunctionScopeInfo(Diags));
@@ -120,6 +132,12 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
InitDataSharingAttributesStack();
}
+void Sema::addImplicitTypedef(StringRef Name, QualType T) {
+ DeclarationName DN = &Context.Idents.get(Name);
+ if (IdResolver.begin(DN) == IdResolver.end())
+ PushOnScopeChains(Context.buildImplicitTypedef(T, Name), TUScope);
+}
+
void Sema::Initialize() {
// Tell the AST consumer about this Sema object.
Consumer.Initialize(Context);
@@ -134,7 +152,7 @@ void Sema::Initialize() {
ExternalSema->InitializeSema(*this);
// Initialize predefined 128-bit integer types, if needed.
- if (PP.getTargetInfo().hasInt128Type()) {
+ if (Context.getTargetInfo().hasInt128Type()) {
// If either of the 128-bit integer types are unavailable to name lookup,
// define them now.
DeclarationName Int128 = &Context.Idents.get("__int128_t");
@@ -172,20 +190,36 @@ void Sema::Initialize() {
PushOnScopeChains(Context.getObjCProtocolDecl(), TUScope);
}
+ // Initialize Microsoft "predefined C++ types".
+ if (PP.getLangOpts().MSVCCompat && PP.getLangOpts().CPlusPlus) {
+ if (IdResolver.begin(&Context.Idents.get("type_info")) == IdResolver.end())
+ PushOnScopeChains(Context.buildImplicitRecord("type_info", TTK_Class),
+ TUScope);
+
+ addImplicitTypedef("size_t", Context.getSizeType());
+ }
+
+ // Initialize predefined OpenCL types.
+ if (PP.getLangOpts().OpenCL) {
+ addImplicitTypedef("image1d_t", Context.OCLImage1dTy);
+ addImplicitTypedef("image1d_array_t", Context.OCLImage1dArrayTy);
+ addImplicitTypedef("image1d_buffer_t", Context.OCLImage1dBufferTy);
+ addImplicitTypedef("image2d_t", Context.OCLImage2dTy);
+ addImplicitTypedef("image2d_array_t", Context.OCLImage2dArrayTy);
+ addImplicitTypedef("image3d_t", Context.OCLImage3dTy);
+ addImplicitTypedef("sampler_t", Context.OCLSamplerTy);
+ addImplicitTypedef("event_t", Context.OCLEventTy);
+ }
+
DeclarationName BuiltinVaList = &Context.Idents.get("__builtin_va_list");
if (IdResolver.begin(BuiltinVaList) == IdResolver.end())
PushOnScopeChains(Context.getBuiltinVaListDecl(), TUScope);
}
Sema::~Sema() {
- for (LateParsedTemplateMapT::iterator I = LateParsedTemplateMap.begin(),
- E = LateParsedTemplateMap.end();
- I != E; ++I)
- delete I->second;
+ llvm::DeleteContainerSeconds(LateParsedTemplateMap);
if (PackContext) FreePackedContext();
if (VisContext) FreeVisContext();
- delete TheTargetAttributesSema;
- MSStructPragmaOn = false;
// Kill all the active scopes.
for (unsigned I = 1, E = FunctionScopes.size(); I != E; ++I)
delete FunctionScopes[I];
@@ -230,7 +264,7 @@ bool Sema::makeUnavailableInSystemHeader(SourceLocation loc,
// 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));
+ fn->addAttr(UnavailableAttr::CreateImplicit(Context, msg, loc));
return true;
}
@@ -279,7 +313,8 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
if (VK == VK_RValue && !E->isRValue()) {
switch (Kind) {
default:
- assert(0 && "can't implicitly cast lvalue to rvalue with this cast kind");
+ llvm_unreachable("can't implicitly cast lvalue to rvalue with this cast "
+ "kind");
case CK_LValueToRValue:
case CK_ArrayToPointerDecay:
case CK_FunctionToPointerDecay:
@@ -294,7 +329,7 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
QualType TypeTy = Context.getCanonicalType(Ty);
if (ExprTy == TypeTy)
- return Owned(E);
+ return E;
// If this is a derived-to-base cast to a through a virtual base, we
// need a vtable.
@@ -312,11 +347,11 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
if (ImpCast->getCastKind() == Kind && (!BasePath || BasePath->empty())) {
ImpCast->setType(Ty);
ImpCast->setValueKind(VK);
- return Owned(E);
+ return E;
}
}
- return Owned(ImplicitCastExpr::Create(Context, Ty, Kind, E, BasePath, VK));
+ return ImplicitCastExpr::Create(Context, Ty, Kind, E, BasePath, VK);
}
/// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding
@@ -384,25 +419,6 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
return false;
}
-namespace {
- struct SortUndefinedButUsed {
- const SourceManager &SM;
- explicit SortUndefinedButUsed(SourceManager &SM) : SM(SM) {}
-
- bool operator()(const std::pair<NamedDecl *, SourceLocation> &l,
- const std::pair<NamedDecl *, SourceLocation> &r) const {
- if (l.second.isValid() && !r.second.isValid())
- return true;
- if (!l.second.isValid() && r.second.isValid())
- return false;
- if (l.second != r.second)
- return SM.isBeforeInTranslationUnit(l.second, r.second);
- return SM.isBeforeInTranslationUnit(l.first->getLocation(),
- r.first->getLocation());
- }
- };
-}
-
/// Obtains a sorted list of functions that are undefined but ODR-used.
void Sema::getUndefinedButUsed(
SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> > &Undefined) {
@@ -435,8 +451,19 @@ void Sema::getUndefinedButUsed(
// Sort (in order of use site) so that we're not dependent on the iteration
// order through an llvm::DenseMap.
+ SourceManager &SM = Context.getSourceManager();
std::sort(Undefined.begin(), Undefined.end(),
- SortUndefinedButUsed(Context.getSourceManager()));
+ [&SM](const std::pair<NamedDecl *, SourceLocation> &l,
+ const std::pair<NamedDecl *, SourceLocation> &r) {
+ if (l.second.isValid() && !r.second.isValid())
+ return true;
+ if (!l.second.isValid() && r.second.isValid())
+ return false;
+ if (l.second != r.second)
+ return SM.isBeforeInTranslationUnit(l.second, r.second);
+ return SM.isBeforeInTranslationUnit(l.first->getLocation(),
+ r.first->getLocation());
+ });
}
/// checkUndefinedButUsed - Check for undefined objects with internal linkage
@@ -453,6 +480,13 @@ static void checkUndefinedButUsed(Sema &S) {
I = Undefined.begin(), E = Undefined.end(); I != E; ++I) {
NamedDecl *ND = I->first;
+ if (ND->hasAttr<DLLImportAttr>() || ND->hasAttr<DLLExportAttr>()) {
+ // An exported function will always be emitted when defined, so even if
+ // the function is inline, it doesn't have to be emitted in this TU. An
+ // imported function implies that it has been exported somewhere else.
+ continue;
+ }
+
if (!ND->isExternallyVisible()) {
S.Diag(ND->getLocation(), diag::warn_undefined_internal)
<< isa<VarDecl>(ND) << ND;
@@ -561,7 +595,7 @@ static bool IsRecordFullyDefined(const CXXRecordDecl *RD,
/// translation unit when EOF is reached and all but the top-level scope is
/// popped.
void Sema::ActOnEndOfTranslationUnit() {
- assert(DelayedDiagnostics.getCurrentPool() == NULL
+ assert(DelayedDiagnostics.getCurrentPool() == nullptr
&& "reached end of translation unit with a pool attached?");
// If code completion is enabled, don't perform any end-of-translation-unit
@@ -582,8 +616,9 @@ void Sema::ActOnEndOfTranslationUnit() {
I != E; ++I) {
assert(!(*I)->isDependentType() &&
"Should not see dependent types here!");
- if (const CXXMethodDecl *KeyFunction = Context.getCurrentKeyFunction(*I)) {
- const FunctionDecl *Definition = 0;
+ if (const CXXMethodDecl *KeyFunction =
+ Context.getCurrentKeyFunction(*I)) {
+ const FunctionDecl *Definition = nullptr;
if (KeyFunction->hasBody(Definition))
MarkVTableUsed(Definition->getLocation(), *I, true);
}
@@ -603,7 +638,15 @@ void Sema::ActOnEndOfTranslationUnit() {
// so it will find some names that are not required to be found. This is
// valid, but we could do better by diagnosing if an instantiation uses a
// name that was not visible at its first point of instantiation.
+ if (ExternalSource) {
+ // Load pending instantiations from the external source.
+ SmallVector<PendingImplicitInstantiation, 4> Pending;
+ ExternalSource->ReadPendingInstantiations(Pending);
+ PendingInstantiations.insert(PendingInstantiations.begin(),
+ Pending.begin(), Pending.end());
+ }
PerformPendingInstantiations();
+
CheckDelayedMemberExceptionSpecs();
}
@@ -614,14 +657,14 @@ void Sema::ActOnEndOfTranslationUnit() {
// Remove file scoped decls that turned out to be used.
UnusedFileScopedDecls.erase(
- std::remove_if(UnusedFileScopedDecls.begin(0, true),
+ std::remove_if(UnusedFileScopedDecls.begin(nullptr, true),
UnusedFileScopedDecls.end(),
std::bind1st(std::ptr_fun(ShouldRemoveFromUnused), this)),
UnusedFileScopedDecls.end());
if (TUKind == TU_Prefix) {
// Translation unit prefixes don't need any of the checking below.
- TUScope = 0;
+ TUScope = nullptr;
return;
}
@@ -639,9 +682,7 @@ void Sema::ActOnEndOfTranslationUnit() {
}
if (LangOpts.CPlusPlus11 &&
- Diags.getDiagnosticLevel(diag::warn_delegating_ctor_cycle,
- SourceLocation())
- != DiagnosticsEngine::Ignored)
+ !Diags.isIgnored(diag::warn_delegating_ctor_cycle, SourceLocation()))
CheckDelegatingCtorCycles();
if (TUKind == TU_Module) {
@@ -673,7 +714,7 @@ void Sema::ActOnEndOfTranslationUnit() {
}
// Modules don't need any of the checking below.
- TUScope = 0;
+ TUScope = nullptr;
return;
}
@@ -699,7 +740,7 @@ void Sema::ActOnEndOfTranslationUnit() {
// If the tentative definition was completed, getActingDefinition() returns
// null. If we've already seen this variable before, insert()'s second
// return value is false.
- if (VD == 0 || VD->isInvalidDecl() || !Seen.insert(VD))
+ if (!VD || VD->isInvalidDecl() || !Seen.insert(VD))
continue;
if (const IncompleteArrayType *ArrayT
@@ -781,9 +822,7 @@ void Sema::ActOnEndOfTranslationUnit() {
checkUndefinedButUsed(*this);
}
- if (Diags.getDiagnosticLevel(diag::warn_unused_private_field,
- SourceLocation())
- != DiagnosticsEngine::Ignored) {
+ if (!Diags.isIgnored(diag::warn_unused_private_field, SourceLocation())) {
RecordCompleteMap RecordsComplete;
RecordCompleteMap MNCComplete;
for (NamedDeclSetType::iterator I = UnusedPrivateFields.begin(),
@@ -804,7 +843,7 @@ void Sema::ActOnEndOfTranslationUnit() {
assert(ParsingInitForAutoVars.empty() &&
"Didn't unmark var as having its initializer parsed");
- TUScope = 0;
+ TUScope = nullptr;
}
@@ -848,7 +887,7 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() {
DeclContext *DC = getFunctionLevelDeclContext();
if (isa<ObjCMethodDecl>(DC) || isa<FunctionDecl>(DC))
return cast<NamedDecl>(DC);
- return 0;
+ return nullptr;
}
void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
@@ -996,7 +1035,7 @@ bool Sema::findMacroSpelling(SourceLocation &locref, StringRef name) {
Scope *Sema::getScopeForContext(DeclContext *Ctx) {
if (!Ctx)
- return 0;
+ return nullptr;
Ctx = Ctx->getPrimaryContext();
for (Scope *S = getCurScope(); S; S = S->getParent()) {
@@ -1008,7 +1047,7 @@ Scope *Sema::getScopeForContext(DeclContext *Ctx) {
return S;
}
- return 0;
+ return nullptr;
}
/// \brief Enter a new function scope
@@ -1052,19 +1091,12 @@ void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
// Issue any analysis-based warnings.
if (WP && D)
AnalysisWarnings.IssueWarnings(*WP, Scope, D, blkExpr);
- else {
- for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator
- i = Scope->PossiblyUnreachableDiags.begin(),
- e = Scope->PossiblyUnreachableDiags.end();
- i != e; ++i) {
- const sema::PossiblyUnreachableDiag &D = *i;
- Diag(D.Loc, D.PD);
- }
- }
+ else
+ for (const auto &PUD : Scope->PossiblyUnreachableDiags)
+ Diag(PUD.Loc, PUD.PD);
- if (FunctionScopes.back() != Scope) {
+ if (FunctionScopes.back() != Scope)
delete Scope;
- }
}
void Sema::PushCompoundScope() {
@@ -1086,25 +1118,41 @@ bool Sema::hasAnyUnrecoverableErrorsInThisFunction() const {
BlockScopeInfo *Sema::getCurBlock() {
if (FunctionScopes.empty())
- return 0;
+ return nullptr;
+
+ auto CurBSI = dyn_cast<BlockScopeInfo>(FunctionScopes.back());
+ if (CurBSI && CurBSI->TheDecl &&
+ !CurBSI->TheDecl->Encloses(CurContext)) {
+ // We have switched contexts due to template instantiation.
+ assert(!ActiveTemplateInstantiations.empty());
+ return nullptr;
+ }
- return dyn_cast<BlockScopeInfo>(FunctionScopes.back());
+ return CurBSI;
}
LambdaScopeInfo *Sema::getCurLambda() {
if (FunctionScopes.empty())
- return 0;
+ return nullptr;
+
+ auto CurLSI = dyn_cast<LambdaScopeInfo>(FunctionScopes.back());
+ if (CurLSI && CurLSI->Lambda &&
+ !CurLSI->Lambda->Encloses(CurContext)) {
+ // We have switched contexts due to template instantiation.
+ assert(!ActiveTemplateInstantiations.empty());
+ return nullptr;
+ }
- return dyn_cast<LambdaScopeInfo>(FunctionScopes.back());
+ return CurLSI;
}
// We have a generic lambda if we parsed auto parameters, or we have
// an associated template parameter list.
LambdaScopeInfo *Sema::getCurGenericLambda() {
if (LambdaScopeInfo *LSI = getCurLambda()) {
return (LSI->AutoTemplateParams.size() ||
- LSI->GLTemplateParameterList) ? LSI : 0;
+ LSI->GLTemplateParameterList) ? LSI : nullptr;
}
- return 0;
+ return nullptr;
}
@@ -1182,7 +1230,7 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy,
ZeroArgCallReturnTy = QualType();
OverloadSet.clear();
- const OverloadExpr *Overloads = NULL;
+ const OverloadExpr *Overloads = nullptr;
bool IsMemExpr = false;
if (E.getType() == Context.OverloadTy) {
OverloadExpr::FindResult FR = OverloadExpr::find(const_cast<Expr*>(&E));
@@ -1215,7 +1263,7 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy,
ZeroArgCallReturnTy = QualType();
Ambiguous = true;
} else
- ZeroArgCallReturnTy = OverloadDecl->getResultType();
+ ZeroArgCallReturnTy = OverloadDecl->getReturnType();
}
}
}
@@ -1231,8 +1279,8 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy,
if (IsMemExpr && !E.isTypeDependent()) {
bool Suppress = getDiagnostics().getSuppressAllDiagnostics();
getDiagnostics().setSuppressAllDiagnostics(true);
- ExprResult R = BuildCallToMemberFunction(NULL, &E, SourceLocation(), None,
- SourceLocation());
+ ExprResult R = BuildCallToMemberFunction(nullptr, &E, SourceLocation(),
+ None, SourceLocation());
getDiagnostics().setSuppressAllDiagnostics(Suppress);
if (R.isUsable()) {
ZeroArgCallReturnTy = R.get()->getType();
@@ -1244,7 +1292,7 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy,
if (const DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E.IgnoreParens())) {
if (const FunctionDecl *Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) {
if (Fun->getMinRequiredArguments() == 0)
- ZeroArgCallReturnTy = Fun->getResultType();
+ ZeroArgCallReturnTy = Fun->getReturnType();
return true;
}
}
@@ -1252,7 +1300,7 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy,
// We don't have an expression that's convenient to get a FunctionDecl from,
// but we can at least check if the type is "function of 0 arguments".
QualType ExprTy = E.getType();
- const FunctionType *FunTy = NULL;
+ const FunctionType *FunTy = nullptr;
QualType PointeeTy = ExprTy->getPointeeType();
if (!PointeeTy.isNull())
FunTy = PointeeTy->getAs<FunctionType>();
@@ -1261,8 +1309,8 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy,
if (const FunctionProtoType *FPT =
dyn_cast_or_null<FunctionProtoType>(FunTy)) {
- if (FPT->getNumArgs() == 0)
- ZeroArgCallReturnTy = FunTy->getResultType();
+ if (FPT->getNumParams() == 0)
+ ZeroArgCallReturnTy = FunTy->getReturnType();
return true;
}
return false;
@@ -1313,7 +1361,7 @@ static void notePlausibleOverloads(Sema &S, SourceLocation Loc,
for (OverloadExpr::decls_iterator It = Overloads.begin(),
DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It);
- QualType OverloadResultTy = OverloadDecl->getResultType();
+ QualType OverloadResultTy = OverloadDecl->getReturnType();
if (IsPlausibleResult(OverloadResultTy))
PlausibleOverloads.addDecl(It.getDecl());
}
@@ -1357,7 +1405,7 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD,
// FIXME: Try this before emitting the fixit, and suppress diagnostics
// while doing so.
- E = ActOnCallExpr(0, E.take(), Range.getEnd(), None,
+ E = ActOnCallExpr(nullptr, E.get(), Range.getEnd(), None,
Range.getEnd().getLocWithOffset(1));
return true;
}
@@ -1392,7 +1440,7 @@ void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD,
CapturedRegionScopeInfo *Sema::getCurCapturedRegion() {
if (FunctionScopes.empty())
- return 0;
+ return nullptr;
return dyn_cast<CapturedRegionScopeInfo>(FunctionScopes.back());
}
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 61dc157f8589..ffdb0aa27a6b 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -78,7 +78,7 @@ static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
namespace {
struct EffectiveContext {
- EffectiveContext() : Inner(0), Dependent(false) {}
+ EffectiveContext() : Inner(nullptr), Dependent(false) {}
explicit EffectiveContext(DeclContext *DC)
: Inner(DC),
@@ -209,7 +209,8 @@ struct AccessTarget : public AccessedEntity {
CalculatedInstanceContext = true;
DeclContext *IC = S.computeDeclContext(getBaseObjectType());
- InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl() : 0);
+ InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl()
+ : nullptr);
return InstanceContext;
}
@@ -232,7 +233,7 @@ private:
!getBaseObjectType().isNull() &&
getTargetDecl()->isCXXInstanceMember());
CalculatedInstanceContext = false;
- InstanceContext = 0;
+ InstanceContext = nullptr;
if (isMemberAccess())
DeclaringClass = FindDeclaringClass(getTargetDecl());
@@ -288,12 +289,10 @@ static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,
if (Derived->isDependentContext() && !Derived->hasDefinition())
return AR_dependent;
- for (CXXRecordDecl::base_class_const_iterator
- I = Derived->bases_begin(), E = Derived->bases_end(); I != E; ++I) {
-
+ for (const auto &I : Derived->bases()) {
const CXXRecordDecl *RD;
- QualType T = I->getType();
+ QualType T = I.getType();
if (const RecordType *RT = T->getAs<RecordType>()) {
RD = cast<CXXRecordDecl>(RT->getDecl());
} else if (const InjectedClassNameType *IT
@@ -376,18 +375,16 @@ static bool MightInstantiateTo(Sema &S,
if (FriendTy.getQualifiers() != ContextTy.getQualifiers())
return false;
- if (FriendTy->getNumArgs() != ContextTy->getNumArgs())
+ if (FriendTy->getNumParams() != ContextTy->getNumParams())
return false;
- if (!MightInstantiateTo(S,
- ContextTy->getResultType(),
- FriendTy->getResultType()))
+ if (!MightInstantiateTo(S, ContextTy->getReturnType(),
+ FriendTy->getReturnType()))
return false;
- for (unsigned I = 0, E = FriendTy->getNumArgs(); I != E; ++I)
- if (!MightInstantiateTo(S,
- ContextTy->getArgType(I),
- FriendTy->getArgType(I)))
+ for (unsigned I = 0, E = FriendTy->getNumParams(); I != E; ++I)
+ if (!MightInstantiateTo(S, ContextTy->getParamType(I),
+ FriendTy->getParamType(I)))
return false;
return true;
@@ -575,10 +572,7 @@ static AccessResult GetFriendKind(Sema &S,
AccessResult OnFailure = AR_inaccessible;
// Okay, check friends.
- for (CXXRecordDecl::friend_iterator I = Class->friend_begin(),
- E = Class->friend_end(); I != E; ++I) {
- FriendDecl *Friend = *I;
-
+ for (auto *Friend : Class->friends()) {
switch (MatchesFriend(S, EC, Friend)) {
case AR_accessible:
return AR_accessible;
@@ -648,18 +642,16 @@ struct ProtectedFriendContext {
EverDependent = true;
// Recurse into the base classes.
- for (CXXRecordDecl::base_class_const_iterator
- I = Cur->bases_begin(), E = Cur->bases_end(); I != E; ++I) {
-
+ for (const auto &I : Cur->bases()) {
// If this is private inheritance, then a public member of the
// base will not have any access in classes derived from Cur.
unsigned BasePrivateDepth = PrivateDepth;
- if (I->getAccessSpecifier() == AS_private)
+ if (I.getAccessSpecifier() == AS_private)
BasePrivateDepth = CurPath.size() - 1;
const CXXRecordDecl *RD;
- QualType T = I->getType();
+ QualType T = I.getType();
if (const RecordType *RT = T->getAs<RecordType>()) {
RD = cast<CXXRecordDecl>(RT->getDecl());
} else if (const InjectedClassNameType *IT
@@ -718,7 +710,7 @@ struct ProtectedFriendContext {
static AccessResult GetProtectedFriendKind(Sema &S, const EffectiveContext &EC,
const CXXRecordDecl *InstanceContext,
const CXXRecordDecl *NamingClass) {
- assert(InstanceContext == 0 ||
+ assert(InstanceContext == nullptr ||
InstanceContext->getCanonicalDecl() == InstanceContext);
assert(NamingClass->getCanonicalDecl() == NamingClass);
@@ -797,7 +789,7 @@ static AccessResult HasAccess(Sema &S,
// Emulate a MSVC bug where the creation of pointer-to-member
// to protected member of base class is allowed but only from
// static member functions.
- if (S.getLangOpts().MicrosoftMode && !EC.Functions.empty())
+ if (S.getLangOpts().MSVCCompat && !EC.Functions.empty())
if (CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(EC.Functions.front()))
if (MD->isStatic()) return AR_accessible;
@@ -851,7 +843,7 @@ static AccessResult HasAccess(Sema &S,
// and instead rely on whether any potential P is a friend.
if (Access == AS_protected && Target.isInstanceMember()) {
// Compute the instance context if possible.
- const CXXRecordDecl *InstanceContext = 0;
+ const CXXRecordDecl *InstanceContext = nullptr;
if (Target.hasInstanceContext()) {
InstanceContext = Target.resolveInstanceContext(S);
if (!InstanceContext) return AR_dependent;
@@ -946,7 +938,7 @@ static CXXBasePath *FindBestPath(Sema &S,
assert(isDerived && "derived class not actually derived from base");
(void) isDerived;
- CXXBasePath *BestPath = 0;
+ CXXBasePath *BestPath = nullptr;
assert(FinalAccess != AS_none && "forbidden access after declaring class");
@@ -995,7 +987,7 @@ static CXXBasePath *FindBestPath(Sema &S,
// Note that we modify the path's Access field to the
// friend-modified access.
- if (BestPath == 0 || PathAccess < BestPath->Access) {
+ if (BestPath == nullptr || PathAccess < BestPath->Access) {
BestPath = &*PI;
BestPath->Access = PathAccess;
@@ -1013,7 +1005,7 @@ static CXXBasePath *FindBestPath(Sema &S,
// We didn't find a public path, but at least one path was subject
// to dependent friendship, so delay the check.
if (AnyDependent)
- return 0;
+ return nullptr;
return BestPath;
}
@@ -1082,15 +1074,15 @@ static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC,
(isa<FunctionTemplateDecl>(D) &&
isa<CXXConstructorDecl>(
cast<FunctionTemplateDecl>(D)->getTemplatedDecl()))) {
- S.Diag(D->getLocation(), diag::note_access_protected_restricted_ctordtor)
- << isa<CXXDestructorDecl>(D);
- return true;
+ return S.Diag(D->getLocation(),
+ diag::note_access_protected_restricted_ctordtor)
+ << isa<CXXDestructorDecl>(D->getAsFunction());
}
// Otherwise, use the generic diagnostic.
- S.Diag(D->getLocation(), diag::note_access_protected_restricted_object)
- << S.Context.getTypeDeclType(ECRecord);
- return true;
+ return S.Diag(D->getLocation(),
+ diag::note_access_protected_restricted_object)
+ << S.Context.getTypeDeclType(ECRecord);
}
return false;
@@ -1110,7 +1102,7 @@ static void diagnoseBadDirectAccess(Sema &S,
// Find an original declaration.
while (D->isOutOfLine()) {
- NamedDecl *PrevDecl = 0;
+ NamedDecl *PrevDecl = nullptr;
if (VarDecl *VD = dyn_cast<VarDecl>(D))
PrevDecl = VD->getPreviousDecl();
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
@@ -1140,11 +1132,9 @@ static void diagnoseBadDirectAccess(Sema &S,
// Check whether there's an AccessSpecDecl preceding this in the
// chain of the DeclContext.
bool isImplicit = true;
- for (CXXRecordDecl::decl_iterator
- I = DeclaringClass->decls_begin(), E = DeclaringClass->decls_end();
- I != E; ++I) {
- if (*I == ImmediateChild) break;
- if (isa<AccessSpecDecl>(*I)) {
+ for (const auto *I : DeclaringClass->decls()) {
+ if (I == ImmediateChild) break;
+ if (isa<AccessSpecDecl>(I)) {
isImplicit = false;
break;
}
@@ -1223,7 +1213,7 @@ static void DiagnoseAccessPath(Sema &S,
case AR_accessible:
accessSoFar = AS_public;
entity.suppressInstanceContext();
- constrainingBase = 0;
+ constrainingBase = nullptr;
break;
case AR_dependent:
llvm_unreachable("cannot diagnose dependent access");
@@ -1262,7 +1252,8 @@ static void DiagnoseAccessPath(Sema &S,
<< (base->getAccessSpecifierAsWritten() == AS_none);
if (entity.isMemberAccess())
- S.Diag(entity.getTargetDecl()->getLocation(), diag::note_field_decl);
+ S.Diag(entity.getTargetDecl()->getLocation(),
+ diag::note_member_declared_at);
}
static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
@@ -1270,7 +1261,7 @@ static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
AccessTarget &Entity) {
const CXXRecordDecl *NamingClass = Entity.getNamingClass();
const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
- NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0);
+ NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : nullptr);
S.Diag(Loc, Entity.getDiag())
<< (Entity.getAccess() == AS_protected)
@@ -1422,16 +1413,15 @@ static AccessResult CheckEffectiveAccess(Sema &S,
AccessTarget &Entity) {
assert(Entity.getAccess() != AS_public && "called for public access!");
- if (S.getLangOpts().MicrosoftMode &&
- IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity))
- return AR_accessible;
-
switch (IsAccessible(S, EC, Entity)) {
case AR_dependent:
DelayDependentAccess(S, EC, Loc, Entity);
return AR_dependent;
case AR_inaccessible:
+ if (S.getLangOpts().MSVCCompat &&
+ IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity))
+ return AR_accessible;
if (!Entity.isQuiet())
DiagnoseBadAccess(S, Loc, EC, Entity);
return AR_inaccessible;
@@ -1482,11 +1472,10 @@ void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) {
// However, this does not apply to local extern declarations.
DeclContext *DC = D->getDeclContext();
- if (FunctionDecl *FN = dyn_cast<FunctionDecl>(D)) {
- if (D->getLexicalDeclContext()->isFunctionOrMethod())
- DC = D->getLexicalDeclContext();
- else
- DC = FN;
+ if (D->isLocalExternDecl()) {
+ DC = D->getLexicalDeclContext();
+ } else if (FunctionDecl *FN = dyn_cast<FunctionDecl>(D)) {
+ DC = FN;
} else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) {
DC = cast<DeclContext>(TD->getTemplatedDecl());
}
@@ -1750,10 +1739,7 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
/// Checks access to the target of a friend declaration.
Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) {
- assert(isa<CXXMethodDecl>(target) ||
- (isa<FunctionTemplateDecl>(target) &&
- isa<CXXMethodDecl>(cast<FunctionTemplateDecl>(target)
- ->getTemplatedDecl())));
+ assert(isa<CXXMethodDecl>(target->getAsFunction()));
// Friendship lookup is a redeclaration lookup, so there's never an
// inheritance path modifying access.
@@ -1762,10 +1748,7 @@ Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) {
if (!getLangOpts().AccessControl || access == AS_public)
return AR_accessible;
- CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(target);
- if (!method)
- method = cast<CXXMethodDecl>(
- cast<FunctionTemplateDecl>(target)->getTemplatedDecl());
+ CXXMethodDecl *method = cast<CXXMethodDecl>(target->getAsFunction());
assert(method->getQualifier());
AccessTarget entity(Context, AccessTarget::Member,
@@ -1891,7 +1874,7 @@ bool Sema::IsSimplyAccessible(NamedDecl *Decl, DeclContext *Ctx) {
// If we are inside a class or category implementation, determine the
// interface we're in.
- ObjCInterfaceDecl *ClassOfMethodDecl = 0;
+ ObjCInterfaceDecl *ClassOfMethodDecl = nullptr;
if (ObjCMethodDecl *MD = getCurMethodDecl())
ClassOfMethodDecl = MD->getClassInterface();
else if (FunctionDecl *FD = getCurFunctionDecl()) {
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 8f9ab32517d6..a7d606d545ca 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -109,7 +109,7 @@ bool PragmaPackStack::pop(IdentifierInfo *Name, bool IsReset) {
/// FreePackedContext - Deallocate and null out PackContext.
void Sema::FreePackedContext() {
delete static_cast<PragmaPackStack*>(PackContext);
- PackContext = 0;
+ PackContext = nullptr;
}
void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) {
@@ -122,23 +122,28 @@ void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) {
// Otherwise, check to see if we need a max field alignment attribute.
if (unsigned Alignment = Stack->getAlignment()) {
if (Alignment == PackStackEntry::kMac68kAlignmentSentinel)
- RD->addAttr(::new (Context) AlignMac68kAttr(SourceLocation(), Context));
+ RD->addAttr(AlignMac68kAttr::CreateImplicit(Context));
else
- RD->addAttr(::new (Context) MaxFieldAlignmentAttr(SourceLocation(),
- Context,
+ RD->addAttr(MaxFieldAlignmentAttr::CreateImplicit(Context,
Alignment * 8));
}
}
void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) {
- if (!MSStructPragmaOn)
- return;
- RD->addAttr(::new (Context) MsStructAttr(SourceLocation(), Context));
+ if (MSStructPragmaOn)
+ RD->addAttr(MsStructAttr::CreateImplicit(Context));
+
+ // FIXME: We should merge AddAlignmentAttributesForRecord with
+ // AddMsStructLayoutForRecord into AddPragmaAttributesForRecord, which takes
+ // all active pragmas and applies them as attributes to class definitions.
+ if (VtorDispModeStack.back() != getLangOpts().VtorDispMode)
+ RD->addAttr(
+ MSVtorDispAttr::CreateImplicit(Context, VtorDispModeStack.back()));
}
void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
SourceLocation PragmaLoc) {
- if (PackContext == 0)
+ if (!PackContext)
PackContext = new PragmaPackStack();
PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext);
@@ -150,31 +155,31 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
case POAK_Native:
case POAK_Power:
case POAK_Natural:
- Context->push(0);
+ Context->push(nullptr);
Context->setAlignment(0);
break;
// Note that '#pragma options align=packed' is not equivalent to attribute
// packed, it has a different precedence relative to attribute aligned.
case POAK_Packed:
- Context->push(0);
+ Context->push(nullptr);
Context->setAlignment(1);
break;
case POAK_Mac68k:
// Check if the target supports this.
- if (!PP.getTargetInfo().hasAlignMac68kSupport()) {
+ if (!this->Context.getTargetInfo().hasAlignMac68kSupport()) {
Diag(PragmaLoc, diag::err_pragma_options_align_mac68k_target_unsupported);
return;
}
- Context->push(0);
+ Context->push(nullptr);
Context->setAlignment(PackStackEntry::kMac68kAlignmentSentinel);
break;
case POAK_Reset:
// Reset just pops the top of the stack, or resets the current alignment to
// default.
- if (!Context->pop(0, /*IsReset=*/true)) {
+ if (!Context->pop(nullptr, /*IsReset=*/true)) {
Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed)
<< "stack empty";
}
@@ -206,7 +211,7 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
AlignmentVal = (unsigned) Val.getZExtValue();
}
- if (PackContext == 0)
+ if (!PackContext)
PackContext = new PragmaPackStack();
PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext);
@@ -247,8 +252,8 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
// If a name was specified then failure indicates the name
// wasn't found. Otherwise failure indicates the stack was
// empty.
- Diag(PragmaLoc, diag::warn_pragma_pack_pop_failed)
- << (Name ? "no record matching name" : "stack empty");
+ Diag(PragmaLoc, diag::warn_pragma_pop_failed)
+ << "pack" << (Name ? "no record matching name" : "stack empty");
// FIXME: Warn about popping named records as MSVC does.
} else {
@@ -288,12 +293,159 @@ void Sema::ActOnPragmaDetectMismatch(StringRef Name, StringRef Value) {
Consumer.HandleDetectMismatch(Name, Value);
}
+void Sema::ActOnPragmaMSPointersToMembers(
+ LangOptions::PragmaMSPointersToMembersKind RepresentationMethod,
+ SourceLocation PragmaLoc) {
+ MSPointerToMemberRepresentationMethod = RepresentationMethod;
+ ImplicitMSInheritanceAttrLoc = PragmaLoc;
+}
+
+void Sema::ActOnPragmaMSVtorDisp(PragmaVtorDispKind Kind,
+ SourceLocation PragmaLoc,
+ MSVtorDispAttr::Mode Mode) {
+ switch (Kind) {
+ case PVDK_Set:
+ VtorDispModeStack.back() = Mode;
+ break;
+ case PVDK_Push:
+ VtorDispModeStack.push_back(Mode);
+ break;
+ case PVDK_Reset:
+ VtorDispModeStack.clear();
+ VtorDispModeStack.push_back(MSVtorDispAttr::Mode(LangOpts.VtorDispMode));
+ break;
+ case PVDK_Pop:
+ VtorDispModeStack.pop_back();
+ if (VtorDispModeStack.empty()) {
+ Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "vtordisp"
+ << "stack empty";
+ VtorDispModeStack.push_back(MSVtorDispAttr::Mode(LangOpts.VtorDispMode));
+ }
+ break;
+ }
+}
+
+template<typename ValueType>
+void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation,
+ PragmaMsStackAction Action,
+ llvm::StringRef StackSlotLabel,
+ ValueType Value) {
+ if (Action == PSK_Reset) {
+ CurrentValue = nullptr;
+ return;
+ }
+ if (Action & PSK_Push)
+ Stack.push_back(Slot(StackSlotLabel, CurrentValue, CurrentPragmaLocation));
+ else if (Action & PSK_Pop) {
+ if (!StackSlotLabel.empty()) {
+ // If we've got a label, try to find it and jump there.
+ auto I = std::find_if(Stack.rbegin(), Stack.rend(),
+ [&](const Slot &x) { return x.StackSlotLabel == StackSlotLabel; });
+ // If we found the label so pop from there.
+ if (I != Stack.rend()) {
+ CurrentValue = I->Value;
+ CurrentPragmaLocation = I->PragmaLocation;
+ Stack.erase(std::prev(I.base()), Stack.end());
+ }
+ } else if (!Stack.empty()) {
+ // We don't have a label, just pop the last entry.
+ CurrentValue = Stack.back().Value;
+ CurrentPragmaLocation = Stack.back().PragmaLocation;
+ Stack.pop_back();
+ }
+ }
+ if (Action & PSK_Set) {
+ CurrentValue = Value;
+ CurrentPragmaLocation = PragmaLocation;
+ }
+}
+
+bool Sema::UnifySection(const StringRef &SectionName,
+ int SectionFlags,
+ DeclaratorDecl *Decl) {
+ auto Section = SectionInfos.find(SectionName);
+ if (Section == SectionInfos.end()) {
+ SectionInfos[SectionName] =
+ SectionInfo(Decl, SourceLocation(), SectionFlags);
+ return false;
+ }
+ // A pre-declared section takes precedence w/o diagnostic.
+ if (Section->second.SectionFlags == SectionFlags ||
+ !(Section->second.SectionFlags & PSF_Implicit))
+ return false;
+ auto OtherDecl = Section->second.Decl;
+ Diag(Decl->getLocation(), diag::err_section_conflict)
+ << Decl << OtherDecl;
+ Diag(OtherDecl->getLocation(), diag::note_declared_at)
+ << OtherDecl->getName();
+ if (auto A = Decl->getAttr<SectionAttr>())
+ if (A->isImplicit())
+ Diag(A->getLocation(), diag::note_pragma_entered_here);
+ if (auto A = OtherDecl->getAttr<SectionAttr>())
+ if (A->isImplicit())
+ Diag(A->getLocation(), diag::note_pragma_entered_here);
+ return false;
+}
+
+bool Sema::UnifySection(const StringRef &SectionName,
+ int SectionFlags,
+ SourceLocation PragmaSectionLocation) {
+ auto Section = SectionInfos.find(SectionName);
+ if (Section != SectionInfos.end()) {
+ if (Section->second.SectionFlags == SectionFlags)
+ return false;
+ if (!(Section->second.SectionFlags & PSF_Implicit)) {
+ Diag(PragmaSectionLocation, diag::err_section_conflict)
+ << "this" << "a prior #pragma section";
+ Diag(Section->second.PragmaSectionLocation,
+ diag::note_pragma_entered_here);
+ return true;
+ }
+ }
+ SectionInfos[SectionName] =
+ SectionInfo(nullptr, PragmaSectionLocation, SectionFlags);
+ return false;
+}
+
+/// \brief Called on well formed \#pragma bss_seg().
+void Sema::ActOnPragmaMSSeg(SourceLocation PragmaLocation,
+ PragmaMsStackAction Action,
+ llvm::StringRef StackSlotLabel,
+ StringLiteral *SegmentName,
+ llvm::StringRef PragmaName) {
+ PragmaStack<StringLiteral *> *Stack =
+ llvm::StringSwitch<PragmaStack<StringLiteral *> *>(PragmaName)
+ .Case("data_seg", &DataSegStack)
+ .Case("bss_seg", &BSSSegStack)
+ .Case("const_seg", &ConstSegStack)
+ .Case("code_seg", &CodeSegStack);
+ if (Action & PSK_Pop && Stack->Stack.empty())
+ Diag(PragmaLocation, diag::warn_pragma_pop_failed) << PragmaName
+ << "stack empty";
+ Stack->Act(PragmaLocation, Action, StackSlotLabel, SegmentName);
+}
+
+/// \brief Called on well formed \#pragma bss_seg().
+void Sema::ActOnPragmaMSSection(SourceLocation PragmaLocation,
+ int SectionFlags, StringLiteral *SegmentName) {
+ UnifySection(SegmentName->getString(), SectionFlags, PragmaLocation);
+}
+
+void Sema::ActOnPragmaMSInitSeg(SourceLocation PragmaLocation,
+ StringLiteral *SegmentName) {
+ // There's no stack to maintain, so we just have a current section. When we
+ // see the default section, reset our current section back to null so we stop
+ // tacking on unnecessary attributes.
+ CurInitSeg = SegmentName->getString() == ".CRT$XCU" ? nullptr : SegmentName;
+ CurInitSegLoc = PragmaLocation;
+}
+
void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
SourceLocation PragmaLoc) {
IdentifierInfo *Name = IdTok.getIdentifierInfo();
LookupResult Lookup(*this, Name, IdTok.getLocation(), LookupOrdinaryName);
- LookupParsedName(Lookup, curScope, NULL, true);
+ LookupParsedName(Lookup, curScope, nullptr, true);
if (Lookup.empty()) {
Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
@@ -312,7 +464,7 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
if (VD->isUsed())
Diag(PragmaLoc, diag::warn_used_but_marked_unused) << Name;
- VD->addAttr(::new (Context) UnusedAttr(IdTok.getLocation(), Context));
+ VD->addAttr(UnusedAttr::CreateImplicit(Context, IdTok.getLocation()));
}
void Sema::AddCFAuditedAttribute(Decl *D) {
@@ -324,11 +476,39 @@ void Sema::AddCFAuditedAttribute(Decl *D) {
D->hasAttr<CFUnknownTransferAttr>())
return;
- D->addAttr(::new (Context) CFAuditedTransferAttr(Loc, Context));
+ D->addAttr(CFAuditedTransferAttr::CreateImplicit(Context, Loc));
+}
+
+void Sema::ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc) {
+ if(On)
+ OptimizeOffPragmaLocation = SourceLocation();
+ else
+ OptimizeOffPragmaLocation = PragmaLoc;
+}
+
+void Sema::AddRangeBasedOptnone(FunctionDecl *FD) {
+ // In the future, check other pragmas if they're implemented (e.g. pragma
+ // optimize 0 will probably map to this functionality too).
+ if(OptimizeOffPragmaLocation.isValid())
+ AddOptnoneAttributeIfNoConflicts(FD, OptimizeOffPragmaLocation);
+}
+
+void Sema::AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD,
+ SourceLocation Loc) {
+ // Don't add a conflicting attribute. No diagnostic is needed.
+ if (FD->hasAttr<MinSizeAttr>() || FD->hasAttr<AlwaysInlineAttr>())
+ return;
+
+ // Add attributes only if required. Optnone requires noinline as well, but if
+ // either is already present then don't bother adding them.
+ if (!FD->hasAttr<OptimizeNoneAttr>())
+ FD->addAttr(OptimizeNoneAttr::CreateImplicit(Context, Loc));
+ if (!FD->hasAttr<NoInlineAttr>())
+ FD->addAttr(NoInlineAttr::CreateImplicit(Context, Loc));
}
typedef std::vector<std::pair<unsigned, SourceLocation> > VisStack;
-enum { NoVisibility = (unsigned) -1 };
+enum : unsigned { NoVisibility = ~0U };
void Sema::AddPushedVisibilityAttribute(Decl *D) {
if (!VisContext)
@@ -346,13 +526,13 @@ void Sema::AddPushedVisibilityAttribute(Decl *D) {
= (VisibilityAttr::VisibilityType) rawType;
SourceLocation loc = Stack->back().second;
- D->addAttr(::new (Context) VisibilityAttr(loc, Context, type));
+ D->addAttr(VisibilityAttr::CreateImplicit(Context, type, loc));
}
/// FreeVisContext - Deallocate and null out VisContext.
void Sema::FreeVisContext() {
delete static_cast<VisStack*>(VisContext);
- VisContext = 0;
+ VisContext = nullptr;
}
static void PushPragmaVisibility(Sema &S, unsigned type, SourceLocation loc) {
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 554a114bae60..a70aca2ad86a 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -29,7 +29,7 @@ using namespace clang;
static CXXRecordDecl *getCurrentInstantiationOf(QualType T,
DeclContext *CurContext) {
if (T.isNull())
- return 0;
+ return nullptr;
const Type *Ty = T->getCanonicalTypeInternal().getTypePtr();
if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
@@ -38,11 +38,11 @@ static CXXRecordDecl *getCurrentInstantiationOf(QualType T,
Record->isCurrentInstantiation(CurContext))
return Record;
- return 0;
+ return nullptr;
} else if (isa<InjectedClassNameType>(Ty))
return cast<InjectedClassNameType>(Ty)->getDecl();
else
- return 0;
+ return nullptr;
}
/// \brief Compute the DeclContext that is associated with the given type.
@@ -76,7 +76,7 @@ DeclContext *Sema::computeDeclContext(QualType T) {
DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
bool EnteringContext) {
if (!SS.isSet() || SS.isInvalid())
- return 0;
+ return nullptr;
NestedNameSpecifier *NNS = SS.getScopeRep();
if (NNS->isDependent()) {
@@ -88,7 +88,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
if (EnteringContext) {
const Type *NNSType = NNS->getAsType();
if (!NNSType) {
- return 0;
+ return nullptr;
}
// Look through type alias templates, per C++0x [temp.dep.type]p1.
@@ -126,7 +126,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
}
}
- return 0;
+ return nullptr;
}
switch (NNS->getKind()) {
@@ -170,7 +170,7 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
assert(NNS->isDependent() && "Only dependent nested-name-specifier allowed");
if (!NNS->getAsType())
- return 0;
+ return nullptr;
QualType T = QualType(NNS->getAsType(), 0);
return ::getCurrentInstantiationOf(T, CurContext);
@@ -187,7 +187,7 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
/// will attempt to instantiate that class template.
bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
DeclContext *DC) {
- assert(DC != 0 && "given null context");
+ assert(DC && "given null context");
TagDecl *tag = dyn_cast<TagDecl>(DC);
@@ -282,13 +282,13 @@ bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD) {
/// name lookup.
NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
if (!S || !NNS)
- return 0;
+ return nullptr;
while (NNS->getPrefix())
NNS = NNS->getPrefix();
if (NNS->getKind() != NestedNameSpecifier::Identifier)
- return 0;
+ return nullptr;
LookupResult Found(*this, NNS->getAsIdentifier(), SourceLocation(),
LookupNestedNameSpecifierName);
@@ -296,13 +296,13 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet");
if (!Found.isSingleResult())
- return 0;
+ return nullptr;
NamedDecl *Result = Found.getFoundDecl();
if (isAcceptableNestedNameSpecifier(Result))
return Result;
- return 0;
+ return nullptr;
}
bool Sema::isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS,
@@ -313,7 +313,7 @@ bool Sema::isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS,
LookupResult Found(*this, &II, IdLoc, LookupNestedNameSpecifierName);
// Determine where to perform name lookup
- DeclContext *LookupCtx = 0;
+ DeclContext *LookupCtx = nullptr;
bool isDependent = false;
if (!ObjectType.isNull()) {
// This nested-name-specifier occurs in a member access expression, e.g.,
@@ -363,7 +363,7 @@ class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback {
explicit NestedNameSpecifierValidatorCCC(Sema &SRef)
: SRef(SRef) {}
- virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ bool ValidateCandidate(const TypoCorrection &candidate) override {
return SRef.isAcceptableNestedNameSpecifier(candidate.getCorrectionDecl());
}
@@ -377,6 +377,28 @@ class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback {
/// by ActOnCXXNestedNameSpecifier.
///
/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
+/// that it contains an extra parameter \p ScopeLookupResult.
+///
+/// \param S Scope in which the nested-name-specifier occurs.
+/// \param Identifier Identifier in the sequence "identifier" "::".
+/// \param IdentifierLoc Location of the \p Identifier.
+/// \param CCLoc Location of "::" following Identifier.
+/// \param ObjectType Type of postfix expression if the nested-name-specifier
+/// occurs in construct like: <tt>ptr->nns::f</tt>.
+/// \param EnteringContext If true, enter the context specified by the
+/// nested-name-specifier.
+/// \param SS Optional nested name specifier preceding the identifier.
+/// \param ScopeLookupResult Provides the result of name lookup within the
+/// scope of the nested-name-specifier that was computed at template
+/// definition time.
+/// \param ErrorRecoveryLookup Specifies if the method is called to improve
+/// error recovery and what kind of recovery is performed.
+/// \param IsCorrectedToColon If not null, suggestion of replace '::' -> ':'
+/// are allowed. The bool value pointed by this parameter is set to
+/// 'true' if the identifier is treated as if it was followed by ':',
+/// not '::'.
+///
+/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
/// that it contains an extra parameter \p ScopeLookupResult, which provides
/// the result of name lookup within the scope of the nested-name-specifier
/// that was computed at template definition time.
@@ -395,13 +417,16 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
bool EnteringContext,
CXXScopeSpec &SS,
NamedDecl *ScopeLookupResult,
- bool ErrorRecoveryLookup) {
+ bool ErrorRecoveryLookup,
+ bool *IsCorrectedToColon) {
LookupResult Found(*this, &Identifier, IdentifierLoc,
LookupNestedNameSpecifierName);
// Determine where to perform name lookup
- DeclContext *LookupCtx = 0;
+ DeclContext *LookupCtx = nullptr;
bool isDependent = false;
+ if (IsCorrectedToColon)
+ *IsCorrectedToColon = false;
if (!ObjectType.isNull()) {
// This nested-name-specifier occurs in a member access expression, e.g.,
// x->B::f, and we are looking into the type of the object.
@@ -416,7 +441,6 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
Found.setContextRange(SS.getRange());
}
-
bool ObjectTypeSearchedInScope = false;
if (LookupCtx) {
// Perform "qualified" name lookup into the declaration context we
@@ -473,18 +497,47 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
// Don't speculate if we're just trying to improve error recovery.
if (ErrorRecoveryLookup)
return true;
-
+
// We were not able to compute the declaration context for a dependent
// base object type or prior nested-name-specifier, so this
// nested-name-specifier refers to an unknown specialization. Just build
// a dependent nested-name-specifier.
SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc);
return false;
- }
-
+ }
+
// FIXME: Deal with ambiguities cleanly.
- if (Found.empty() && !ErrorRecoveryLookup && !getLangOpts().MicrosoftMode) {
+ if (Found.empty() && !ErrorRecoveryLookup) {
+ // If identifier is not found as class-name-or-namespace-name, but is found
+ // as other entity, don't look for typos.
+ LookupResult R(*this, Found.getLookupNameInfo(), LookupOrdinaryName);
+ if (LookupCtx)
+ LookupQualifiedName(R, LookupCtx);
+ else if (S && !isDependent)
+ LookupName(R, S);
+ if (!R.empty()) {
+ // The identifier is found in ordinary lookup. If correction to colon is
+ // allowed, suggest replacement to ':'.
+ if (IsCorrectedToColon) {
+ *IsCorrectedToColon = true;
+ Diag(CCLoc, diag::err_nested_name_spec_is_not_class)
+ << &Identifier << getLangOpts().CPlusPlus
+ << FixItHint::CreateReplacement(CCLoc, ":");
+ if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
+ Diag(ND->getLocation(), diag::note_declared_at);
+ return true;
+ }
+ // Replacement '::' -> ':' is not allowed, just issue respective error.
+ Diag(R.getNameLoc(), diag::err_expected_class_or_namespace)
+ << &Identifier << getLangOpts().CPlusPlus;
+ if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
+ Diag(ND->getLocation(), diag::note_entity_declared_at) << &Identifier;
+ return true;
+ }
+ }
+
+ if (Found.empty() && !ErrorRecoveryLookup && !getLangOpts().MSVCCompat) {
// We haven't found anything, and we're not recovering from a
// different kind of error, so look for typos.
DeclarationName Name = Found.getLookupName();
@@ -492,7 +545,8 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
Found.clear();
if (TypoCorrection Corrected =
CorrectTypo(Found.getLookupNameInfo(), Found.getLookupKind(), S,
- &SS, Validator, LookupCtx, EnteringContext)) {
+ &SS, Validator, CTK_ErrorRecovery, LookupCtx,
+ EnteringContext)) {
if (LookupCtx) {
bool DroppedSpecifier =
Corrected.WillReplaceSpecifier() &&
@@ -543,8 +597,8 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
!Context.hasSameType(
Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)),
Context.getTypeDeclType(cast<TypeDecl>(SD))))) {
- if (ErrorRecoveryLookup)
- return true;
+ if (ErrorRecoveryLookup)
+ return true;
Diag(IdentifierLoc,
diag::err_nested_name_member_ref_lookup_ambiguous)
@@ -558,7 +612,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
}
}
- // If we're just performing this lookup for error-recovery purposes,
+ // If we're just performing this lookup for error-recovery purposes,
// don't extend the nested-name-specifier. Just return now.
if (ErrorRecoveryLookup)
return false;
@@ -646,7 +700,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
// public:
// void foo() { D::foo2(); }
// };
- if (getLangOpts().MicrosoftMode) {
+ if (getLangOpts().MSVCCompat) {
DeclContext *DC = LookupCtx ? LookupCtx : CurContext;
if (DC->isDependentContext() && DC->isFunctionOrMethod()) {
SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc);
@@ -654,20 +708,21 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
}
}
- unsigned DiagID;
- if (!Found.empty())
- DiagID = diag::err_expected_class_or_namespace;
- else if (SS.isSet()) {
- Diag(IdentifierLoc, diag::err_no_member)
- << &Identifier << LookupCtx << SS.getRange();
- return true;
- } else
- DiagID = diag::err_undeclared_var_use;
-
- if (SS.isSet())
- Diag(IdentifierLoc, DiagID) << &Identifier << SS.getRange();
+ if (!Found.empty()) {
+ if (TypeDecl *TD = Found.getAsSingle<TypeDecl>())
+ Diag(IdentifierLoc, diag::err_expected_class_or_namespace)
+ << QualType(TD->getTypeForDecl(), 0) << getLangOpts().CPlusPlus;
+ else {
+ Diag(IdentifierLoc, diag::err_expected_class_or_namespace)
+ << &Identifier << getLangOpts().CPlusPlus;
+ if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
+ Diag(ND->getLocation(), diag::note_entity_declared_at) << &Identifier;
+ }
+ } else if (SS.isSet())
+ Diag(IdentifierLoc, diag::err_no_member) << &Identifier << LookupCtx
+ << SS.getRange();
else
- Diag(IdentifierLoc, DiagID) << &Identifier;
+ Diag(IdentifierLoc, diag::err_undeclared_var_use) << &Identifier;
return true;
}
@@ -678,14 +733,17 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
SourceLocation CCLoc,
ParsedType ObjectType,
bool EnteringContext,
- CXXScopeSpec &SS) {
+ CXXScopeSpec &SS,
+ bool ErrorRecoveryLookup,
+ bool *IsCorrectedToColon) {
if (SS.isInvalid())
return true;
-
+
return BuildCXXNestedNameSpecifier(S, Identifier, IdentifierLoc, CCLoc,
GetTypeFromParser(ObjectType),
EnteringContext, SS,
- /*ScopeLookupResult=*/0, false);
+ /*ScopeLookupResult=*/nullptr, false,
+ IsCorrectedToColon);
}
bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
@@ -698,7 +756,7 @@ bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
if (!T->isDependentType() && !T->getAs<TagType>()) {
- Diag(DS.getTypeSpecTypeLoc(), diag::err_expected_class)
+ Diag(DS.getTypeSpecTypeLoc(), diag::err_expected_class_or_namespace)
<< T << getLangOpts().CPlusPlus;
return true;
}
@@ -725,11 +783,11 @@ bool Sema::IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS,
bool EnteringContext) {
if (SS.isInvalid())
return false;
-
+
return !BuildCXXNestedNameSpecifier(S, Identifier, IdentifierLoc, ColonLoc,
GetTypeFromParser(ObjectType),
EnteringContext, SS,
- /*ScopeLookupResult=*/0, true);
+ /*ScopeLookupResult=*/nullptr, true);
}
bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
@@ -749,7 +807,8 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
translateTemplateArguments(TemplateArgsIn, TemplateArgs);
- if (DependentTemplateName *DTN = Template.get().getAsDependentTemplateName()){
+ DependentTemplateName *DTN = Template.get().getAsDependentTemplateName();
+ if (DTN && DTN->isIdentifier()) {
// Handle a dependent template specialization for which we cannot resolve
// the template name.
assert(DTN->getQualifier() == SS.getScopeRep());
@@ -775,20 +834,20 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
CCLoc);
return false;
}
-
-
- if (Template.get().getAsOverloadedTemplate() ||
- isa<FunctionTemplateDecl>(Template.get().getAsTemplateDecl())) {
+
+ TemplateDecl *TD = Template.get().getAsTemplateDecl();
+ if (Template.get().getAsOverloadedTemplate() || DTN ||
+ isa<FunctionTemplateDecl>(TD) || isa<VarTemplateDecl>(TD)) {
SourceRange R(TemplateNameLoc, RAngleLoc);
if (SS.getRange().isValid())
R.setBegin(SS.getRange().getBegin());
-
+
Diag(CCLoc, diag::err_non_type_template_in_nested_name_specifier)
- << Template.get() << R;
+ << (TD && isa<VarTemplateDecl>(TD)) << Template.get() << R;
NoteAllFoundTemplates(Template.get());
return true;
}
-
+
// We were able to resolve the template name to an actual template.
// Build an appropriate nested-name-specifier.
QualType T = CheckTemplateIdType(Template.get(), TemplateNameLoc,
@@ -831,8 +890,8 @@ namespace {
void *Sema::SaveNestedNameSpecifierAnnotation(CXXScopeSpec &SS) {
if (SS.isEmpty() || SS.isInvalid())
- return 0;
-
+ return nullptr;
+
void *Mem = Context.Allocate((sizeof(NestedNameSpecifierAnnotation) +
SS.location_size()),
llvm::alignOf<NestedNameSpecifierAnnotation>());
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index ba00b712aad5..ae5436cf415c 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/Initialization.h"
#include "llvm/ADT/SmallVector.h"
#include <set>
@@ -89,10 +90,10 @@ namespace {
if (IsARCUnbridgedCast) {
castExpr = ImplicitCastExpr::Create(Self.Context,
Self.Context.ARCUnbridgedCastTy,
- CK_Dependent, castExpr, 0,
+ CK_Dependent, castExpr, nullptr,
castExpr->getValueKind());
}
- return Self.Owned(castExpr);
+ return castExpr;
}
// Internal convenience methods.
@@ -133,7 +134,7 @@ namespace {
if (!isPlaceholder() || isPlaceholder(BuiltinType::Overload))
return;
- SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.take());
+ SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.get());
if (SrcExpr.isInvalid())
return;
PlaceholderKind = (BuiltinType::Kind) 0;
@@ -238,7 +239,7 @@ ExprResult
Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
TypeSourceInfo *DestTInfo, Expr *E,
SourceRange AngleBrackets, SourceRange Parens) {
- ExprResult Ex = Owned(E);
+ ExprResult Ex = E;
QualType DestType = DestTInfo->getType();
// If the type is dependent, we won't do the semantic analysis now.
@@ -261,7 +262,7 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
return ExprError();
}
return Op.complete(CXXConstCastExpr::Create(Context, Op.ResultType,
- Op.ValueKind, Op.SrcExpr.take(), DestTInfo,
+ Op.ValueKind, Op.SrcExpr.get(), DestTInfo,
OpLoc, Parens.getEnd(),
AngleBrackets));
@@ -272,7 +273,7 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
return ExprError();
}
return Op.complete(CXXDynamicCastExpr::Create(Context, Op.ResultType,
- Op.ValueKind, Op.Kind, Op.SrcExpr.take(),
+ Op.ValueKind, Op.Kind, Op.SrcExpr.get(),
&Op.BasePath, DestTInfo,
OpLoc, Parens.getEnd(),
AngleBrackets));
@@ -284,8 +285,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
return ExprError();
}
return Op.complete(CXXReinterpretCastExpr::Create(Context, Op.ResultType,
- Op.ValueKind, Op.Kind, Op.SrcExpr.take(),
- 0, DestTInfo, OpLoc,
+ Op.ValueKind, Op.Kind, Op.SrcExpr.get(),
+ nullptr, DestTInfo, OpLoc,
Parens.getEnd(),
AngleBrackets));
}
@@ -297,7 +298,7 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
}
return Op.complete(CXXStaticCastExpr::Create(Context, Op.ResultType,
- Op.ValueKind, Op.Kind, Op.SrcExpr.take(),
+ Op.ValueKind, Op.Kind, Op.SrcExpr.get(),
&Op.BasePath, DestTInfo,
OpLoc, Parens.getEnd(),
AngleBrackets));
@@ -534,9 +535,9 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
/// checked downcasts in class hierarchies.
void CastOperation::CheckDynamicCast() {
if (ValueKind == VK_RValue)
- SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
+ SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
else if (isPlaceholder())
- SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.take());
+ SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.get());
if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
return;
@@ -548,7 +549,7 @@ void CastOperation::CheckDynamicCast() {
QualType DestPointee;
const PointerType *DestPointer = DestType->getAs<PointerType>();
- const ReferenceType *DestReference = 0;
+ const ReferenceType *DestReference = nullptr;
if (DestPointer) {
DestPointee = DestPointer->getPointeeType();
} else if ((DestReference = DestType->getAs<ReferenceType>())) {
@@ -599,6 +600,11 @@ void CastOperation::CheckDynamicCast() {
}
SrcPointee = SrcType;
} else {
+ // If we're dynamic_casting from a prvalue to an rvalue reference, we need
+ // to materialize the prvalue before we bind the reference to it.
+ if (SrcExpr.get()->isRValue())
+ SrcExpr = new (Self.Context) MaterializeTemporaryExpr(
+ SrcType, SrcExpr.get(), /*IsLValueReference*/false);
SrcPointee = SrcType;
}
@@ -647,7 +653,7 @@ void CastOperation::CheckDynamicCast() {
SrcExpr = ExprError();
return;
}
-
+
Kind = CK_DerivedToBase;
// If we are casting to or through a virtual base class, we need a
@@ -689,9 +695,9 @@ void CastOperation::CheckDynamicCast() {
/// legacy_function(const_cast\<char*\>(str));
void CastOperation::CheckConstCast() {
if (ValueKind == VK_RValue)
- SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
+ SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
else if (isPlaceholder())
- SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.take());
+ SrcExpr = Self.CheckPlaceholderExpr(SrcExpr.get());
if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
return;
@@ -804,7 +810,7 @@ static void DiagnoseReinterpretUpDownCast(Sema &Self, const Expr *SrcExpr,
/// char *bytes = reinterpret_cast\<char*\>(int_ptr);
void CastOperation::CheckReinterpretCast() {
if (ValueKind == VK_RValue && !isPlaceholder(BuiltinType::Overload))
- SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
+ SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
else
checkNonOverloadPlaceholders();
if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
@@ -863,13 +869,13 @@ void CastOperation::CheckStaticCast() {
return;
}
- SrcExpr = Self.IgnoredValueConversions(SrcExpr.take());
+ SrcExpr = Self.IgnoredValueConversions(SrcExpr.get());
return;
}
if (ValueKind == VK_RValue && !DestType->isRecordType() &&
!isPlaceholder(BuiltinType::Overload)) {
- SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
+ SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
return;
}
@@ -1066,6 +1072,11 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
Kind = CK_BitCast;
return TC_Success;
}
+ // Allow ns-pointer to cf-pointer conversion in either direction
+ // with static casts.
+ if (!CStyle &&
+ Self.CheckTollFreeBridgeStaticCast(DestType, SrcExpr.get(), Kind))
+ return TC_Success;
// We tried everything. Everything! Nothing works! :-(
return TC_NotApplicable;
@@ -1150,6 +1161,9 @@ TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType,
QualType DestPointee = DestReference->getPointeeType();
+ // FIXME: If the source is a prvalue, we should issue a warning (because the
+ // cast always has undefined behavior), and for AST consistency, we should
+ // materialize a temporary.
return TryStaticDowncast(Self,
Self.Context.getCanonicalType(SrcExpr->getType()),
Self.Context.getCanonicalType(DestPointee), CStyle,
@@ -1271,7 +1285,7 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
return TC_Failed;
}
- if (Paths.getDetectedVirtual() != 0) {
+ if (Paths.getDetectedVirtual() != nullptr) {
QualType VirtualBase(Paths.getDetectedVirtual(), 0);
Self.Diag(OpRange.getBegin(), diag::err_static_downcast_via_virtual)
<< OrigSrcType << OrigDestType << VirtualBase << OpRange;
@@ -1346,7 +1360,8 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
QualType DestClass(DestMemPtr->getClass(), 0);
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/true);
- if (!Self.IsDerivedFrom(SrcClass, DestClass, Paths)) {
+ if (Self.RequireCompleteType(OpRange.getBegin(), SrcClass, 0) ||
+ !Self.IsDerivedFrom(SrcClass, DestClass, Paths)) {
return TC_NotApplicable;
}
@@ -1431,6 +1446,10 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
msg = 0;
return TC_Failed;
}
+ } else if (DestType->isMemberPointerType()) {
+ if (Self.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ Self.RequireCompleteType(OpRange.getBegin(), DestType, 0);
+ }
}
InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
@@ -1578,8 +1597,7 @@ static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr,
// This is a const_cast from a class prvalue to an rvalue reference type.
// Materialize a temporary to store the result of the conversion.
SrcExpr = new (Self.Context) MaterializeTemporaryExpr(
- SrcType, SrcExpr.take(), /*IsLValueReference*/ false,
- /*ExtendingDecl*/ 0);
+ SrcType, SrcExpr.get(), /*IsLValueReference*/ false);
return TC_Success;
}
@@ -1596,10 +1614,8 @@ void Sema::CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType,
diag::warn_pointer_indirection_from_incompatible_type :
diag::warn_undefined_reinterpret_cast;
- if (Diags.getDiagnosticLevel(DiagID, Range.getBegin()) ==
- DiagnosticsEngine::Ignored) {
+ if (Diags.isIgnored(DiagID, Range.getBegin()))
return;
- }
QualType SrcTy, DestTy;
if (IsDereference) {
@@ -1729,7 +1745,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// same effect as the conversion *reinterpret_cast<T*>(&x) with the
// built-in & and * operators.
- const char *inappropriate = 0;
+ const char *inappropriate = nullptr;
switch (SrcExpr.get()->getObjectKind()) {
case OK_Ordinary:
break;
@@ -1778,6 +1794,13 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
return TC_Failed;
}
+ if (Self.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ // We need to determine the inheritance model that the class will use if
+ // haven't yet.
+ Self.RequireCompleteType(OpRange.getBegin(), SrcType, 0);
+ Self.RequireCompleteType(OpRange.getBegin(), DestType, 0);
+ }
+
// Don't allow casting between member pointers of different sizes.
if (Self.Context.getTypeSize(DestMemPtr) !=
Self.Context.getTypeSize(SrcMemPtr)) {
@@ -2007,7 +2030,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
return;
}
- SrcExpr = Self.IgnoredValueConversions(SrcExpr.take());
+ SrcExpr = Self.IgnoredValueConversions(SrcExpr.get());
return;
}
@@ -2020,7 +2043,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
if (ValueKind == VK_RValue && !DestType->isRecordType() &&
!isPlaceholder(BuiltinType::Overload)) {
- SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
+ SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
if (SrcExpr.isInvalid())
return;
}
@@ -2082,10 +2105,16 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
DestType,
/*Complain*/ true,
Found);
-
- assert(!Fn && "cast failed but able to resolve overload expression!!");
- (void)Fn;
-
+ if (Fn) {
+ // If DestType is a function type (not to be confused with the function
+ // pointer type), it will be possible to resolve the function address,
+ // but the type cast should be considered as failure.
+ OverloadExpr *OE = OverloadExpr::find(SrcExpr.get()).Expression;
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cstyle_cast_overload)
+ << OE->getName() << DestType << OpRange
+ << OE->getQualifierLoc().getSourceRange();
+ Self.NoteAllOverloadCandidates(SrcExpr.get());
+ }
} else {
diagnoseBadCast(Self, msg, (FunctionalStyle ? CT_Functional : CT_CStyle),
OpRange, SrcExpr.get(), DestType, ListInitialization);
@@ -2104,9 +2133,8 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
/// pointer; etc. Cast to 'void' is an exception.
static void DiagnoseBadFunctionCast(Sema &Self, const ExprResult &SrcExpr,
QualType DestType) {
- if (Self.Diags.getDiagnosticLevel(diag::warn_bad_function_cast,
- SrcExpr.get()->getExprLoc())
- == DiagnosticsEngine::Ignored)
+ if (Self.Diags.isIgnored(diag::warn_bad_function_cast,
+ SrcExpr.get()->getExprLoc()))
return;
if (!isa<CallExpr>(SrcExpr.get()))
@@ -2152,7 +2180,7 @@ void CastOperation::CheckCStyleCast() {
// type needs to be scalar.
if (DestType->isVoidType()) {
// We don't necessarily do lvalue-to-rvalue conversions on this.
- SrcExpr = Self.IgnoredValueConversions(SrcExpr.take());
+ SrcExpr = Self.IgnoredValueConversions(SrcExpr.get());
if (SrcExpr.isInvalid())
return;
@@ -2161,13 +2189,28 @@ void CastOperation::CheckCStyleCast() {
return;
}
- SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take());
+ SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get());
if (SrcExpr.isInvalid())
return;
QualType SrcType = SrcExpr.get()->getType();
assert(!SrcType->isPlaceholderType());
+ // OpenCL v1 s6.5: Casting a pointer to address space A to a pointer to
+ // address space B is illegal.
+ if (Self.getLangOpts().OpenCL && DestType->isPointerType() &&
+ SrcType->isPointerType()) {
+ if (DestType->getPointeeType().getAddressSpace() !=
+ SrcType->getPointeeType().getAddressSpace()) {
+ Self.Diag(OpRange.getBegin(),
+ diag::err_typecheck_incompatible_address_space)
+ << SrcType << DestType << Sema::AA_Casting
+ << SrcExpr.get()->getSourceRange();
+ SrcExpr = ExprError();
+ return;
+ }
+ }
+
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
diag::err_typecheck_cast_to_incomplete)) {
SrcExpr = ExprError();
@@ -2227,7 +2270,7 @@ void CastOperation::CheckCStyleCast() {
}
if (DestType->isExtVectorType()) {
- SrcExpr = Self.CheckExtVectorCast(OpRange, DestType, SrcExpr.take(), Kind);
+ SrcExpr = Self.CheckExtVectorCast(OpRange, DestType, SrcExpr.get(), Kind);
return;
}
@@ -2319,6 +2362,7 @@ void CastOperation::CheckCStyleCast() {
return;
}
}
+
DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType);
DiagnoseBadFunctionCast(Self, SrcExpr, DestType);
Kind = Self.PrepareScalarCast(SrcExpr, DestType);
@@ -2348,7 +2392,7 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc,
return ExprError();
return Op.complete(CStyleCastExpr::Create(Context, Op.ResultType,
- Op.ValueKind, Op.Kind, Op.SrcExpr.take(),
+ Op.ValueKind, Op.Kind, Op.SrcExpr.get(),
&Op.BasePath, CastTypeInfo, LPLoc, RPLoc));
}
@@ -2370,5 +2414,5 @@ ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo,
return Op.complete(CXXFunctionalCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, CastTypeInfo, Op.Kind,
- Op.SrcExpr.take(), &Op.BasePath, LPLoc, RPLoc));
+ Op.SrcExpr.get(), &Op.BasePath, LPLoc, RPLoc));
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 0b95c48d4f8e..66be962fcf33 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -27,14 +27,14 @@
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/Lexer.h" // TODO: Extract static functions to fix layering.
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Sema.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/raw_ostream.h"
#include <limits>
@@ -43,8 +43,8 @@ using namespace sema;
SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
unsigned ByteNo) const {
- return SL->getLocationOfByte(ByteNo, PP.getSourceManager(),
- PP.getLangOpts(), PP.getTargetInfo());
+ return SL->getLocationOfByte(ByteNo, getSourceManager(), LangOpts,
+ Context.getTargetInfo());
}
/// Checks that a call expression's argument count is the desired number.
@@ -101,19 +101,19 @@ static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) {
if (checkArgCount(S, TheCall, 1))
return true;
- ExprResult Arg(S.Owned(TheCall->getArg(0)));
+ ExprResult Arg(TheCall->getArg(0));
QualType ResultType = S.CheckAddressOfOperand(Arg, TheCall->getLocStart());
if (ResultType.isNull())
return true;
- TheCall->setArg(0, Arg.take());
+ TheCall->setArg(0, Arg.get());
TheCall->setType(ResultType);
return false;
}
ExprResult
Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
- ExprResult TheCallResult(Owned(TheCall));
+ ExprResult TheCallResult(TheCall);
// Find out if any arguments are required to be integer constant expressions.
unsigned ICEArguments = 0;
@@ -145,6 +145,20 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (SemaBuiltinVAStart(TheCall))
return ExprError();
break;
+ case Builtin::BI__va_start: {
+ switch (Context.getTargetInfo().getTriple().getArch()) {
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ if (SemaBuiltinVAStartARM(TheCall))
+ return ExprError();
+ break;
+ default:
+ if (SemaBuiltinVAStart(TheCall))
+ return ExprError();
+ break;
+ }
+ break;
+ }
case Builtin::BI__builtin_isgreater:
case Builtin::BI__builtin_isgreaterequal:
case Builtin::BI__builtin_isless:
@@ -174,8 +188,12 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (SemaBuiltinPrefetch(TheCall))
return ExprError();
break;
+ case Builtin::BI__assume:
+ if (SemaBuiltinAssume(TheCall))
+ return ExprError();
+ break;
case Builtin::BI__builtin_object_size:
- if (SemaBuiltinObjectSize(TheCall))
+ if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3))
return ExprError();
break;
case Builtin::BI__builtin_longjmp:
@@ -295,18 +313,37 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (SemaBuiltinAddressof(*this, TheCall))
return ExprError();
break;
+ case Builtin::BI__builtin_operator_new:
+ case Builtin::BI__builtin_operator_delete:
+ if (!getLangOpts().CPlusPlus) {
+ Diag(TheCall->getExprLoc(), diag::err_builtin_requires_language)
+ << (BuiltinID == Builtin::BI__builtin_operator_new
+ ? "__builtin_operator_new"
+ : "__builtin_operator_delete")
+ << "C++";
+ return ExprError();
+ }
+ // CodeGen assumes it can find the global new and delete to call,
+ // so ensure that they are declared.
+ DeclareGlobalNewDelete();
+ break;
}
-
+
// Since the target specific builtins for each arch overlap, only check those
// of the arch we are compiling for.
if (BuiltinID >= Builtin::FirstTSBuiltin) {
switch (Context.getTargetInfo().getTriple().getArch()) {
case llvm::Triple::arm:
+ case llvm::Triple::armeb:
case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
if (CheckARMBuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
break;
case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm64:
+ case llvm::Triple::arm64_be:
if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
break;
@@ -317,6 +354,11 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (CheckMipsBuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
break;
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (CheckX86BuiltinFunctionCall(BuiltinID, TheCall))
+ return ExprError();
+ break;
default:
break;
}
@@ -326,9 +368,9 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
}
// Get the valid immediate range for the specified NEON type code.
-static unsigned RFT(unsigned t, bool shift = false) {
+static unsigned RFT(unsigned t, bool shift = false, bool ForceQuad = false) {
NeonTypeFlags Type(t);
- int IsQuad = Type.isQuad();
+ int IsQuad = ForceQuad ? true : Type.isQuad();
switch (Type.getEltType()) {
case NeonTypeFlags::Int8:
case NeonTypeFlags::Poly8:
@@ -341,6 +383,8 @@ static unsigned RFT(unsigned t, bool shift = false) {
case NeonTypeFlags::Int64:
case NeonTypeFlags::Poly64:
return shift ? 63 : (1 << IsQuad) - 1;
+ case NeonTypeFlags::Poly128:
+ return shift ? 127 : (1 << IsQuad) - 1;
case NeonTypeFlags::Float16:
assert(!shift && "cannot shift float types!");
return (4 << IsQuad) - 1;
@@ -358,7 +402,7 @@ static unsigned RFT(unsigned t, bool shift = false) {
/// the vector type specified by the NeonTypeFlags. This is used to check
/// the pointer arguments for Neon load/store intrinsics.
static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context,
- bool IsAArch64) {
+ bool IsPolyUnsigned, bool IsInt64Long) {
switch (Flags.getEltType()) {
case NeonTypeFlags::Int8:
return Flags.isUnsigned() ? Context.UnsignedCharTy : Context.SignedCharTy;
@@ -367,13 +411,19 @@ static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context,
case NeonTypeFlags::Int32:
return Flags.isUnsigned() ? Context.UnsignedIntTy : Context.IntTy;
case NeonTypeFlags::Int64:
- return Flags.isUnsigned() ? Context.UnsignedLongLongTy : Context.LongLongTy;
+ if (IsInt64Long)
+ return Flags.isUnsigned() ? Context.UnsignedLongTy : Context.LongTy;
+ else
+ return Flags.isUnsigned() ? Context.UnsignedLongLongTy
+ : Context.LongLongTy;
case NeonTypeFlags::Poly8:
- return IsAArch64 ? Context.UnsignedCharTy : Context.SignedCharTy;
+ return IsPolyUnsigned ? Context.UnsignedCharTy : Context.SignedCharTy;
case NeonTypeFlags::Poly16:
- return IsAArch64 ? Context.UnsignedShortTy : Context.ShortTy;
+ return IsPolyUnsigned ? Context.UnsignedShortTy : Context.ShortTy;
case NeonTypeFlags::Poly64:
- return Context.UnsignedLongLongTy;
+ return Context.UnsignedLongTy;
+ case NeonTypeFlags::Poly128:
+ break;
case NeonTypeFlags::Float16:
return Context.HalfTy;
case NeonTypeFlags::Float32:
@@ -384,24 +434,21 @@ static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context,
llvm_unreachable("Invalid NeonTypeFlag!");
}
-bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
- CallExpr *TheCall) {
-
+bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
llvm::APSInt Result;
-
uint64_t mask = 0;
unsigned TV = 0;
int PtrArgNum = -1;
bool HasConstPtr = false;
switch (BuiltinID) {
-#define GET_NEON_AARCH64_OVERLOAD_CHECK
+#define GET_NEON_OVERLOAD_CHECK
#include "clang/Basic/arm_neon.inc"
-#undef GET_NEON_AARCH64_OVERLOAD_CHECK
+#undef GET_NEON_OVERLOAD_CHECK
}
// For NEON intrinsics which are overloaded on vector element type, validate
// the immediate which specifies which variant to emit.
- unsigned ImmArg = TheCall->getNumArgs() - 1;
+ unsigned ImmArg = TheCall->getNumArgs()-1;
if (mask) {
if (SemaBuiltinConstantArg(TheCall, ImmArg, Result))
return true;
@@ -409,7 +456,7 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
TV = Result.getLimitedValue(64);
if ((TV > 63) || (mask & (1ULL << TV)) == 0)
return Diag(TheCall->getLocStart(), diag::err_invalid_neon_type_code)
- << TheCall->getArg(ImmArg)->getSourceRange();
+ << TheCall->getArg(ImmArg)->getSourceRange();
}
if (PtrArgNum >= 0) {
@@ -419,7 +466,14 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
Arg = ICE->getSubExpr();
ExprResult RHS = DefaultFunctionArrayLvalueConversion(Arg);
QualType RHSTy = RHS.get()->getType();
- QualType EltTy = getNeonEltType(NeonTypeFlags(TV), Context, true);
+
+ llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch();
+ bool IsPolyUnsigned =
+ Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::arm64;
+ bool IsInt64Long =
+ Context.getTargetInfo().getInt64Type() == TargetInfo::SignedLong;
+ QualType EltTy =
+ getNeonEltType(NeonTypeFlags(TV), Context, IsPolyUnsigned, IsInt64Long);
if (HasConstPtr)
EltTy = EltTy.withConst();
QualType LHSTy = Context.getPointerType(EltTy);
@@ -438,35 +492,29 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
switch (BuiltinID) {
default:
return false;
-#define GET_NEON_AARCH64_IMMEDIATE_CHECK
+#define GET_NEON_IMMEDIATE_CHECK
#include "clang/Basic/arm_neon.inc"
-#undef GET_NEON_AARCH64_IMMEDIATE_CHECK
+#undef GET_NEON_IMMEDIATE_CHECK
}
- ;
- // We can't check the value of a dependent argument.
- if (TheCall->getArg(i)->isTypeDependent() ||
- TheCall->getArg(i)->isValueDependent())
- return false;
-
- // Check that the immediate argument is actually a constant.
- if (SemaBuiltinConstantArg(TheCall, i, Result))
- return true;
-
- // Range check against the upper/lower values for this isntruction.
- unsigned Val = Result.getZExtValue();
- if (Val < l || Val > (u + l))
- return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
- << l << u + l << TheCall->getArg(i)->getSourceRange();
-
- return false;
+ return SemaBuiltinConstantArgRange(TheCall, i, l, u + l);
}
-bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall) {
+bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall,
+ unsigned MaxWidth) {
assert((BuiltinID == ARM::BI__builtin_arm_ldrex ||
- BuiltinID == ARM::BI__builtin_arm_strex) &&
+ BuiltinID == ARM::BI__builtin_arm_ldaex ||
+ BuiltinID == ARM::BI__builtin_arm_strex ||
+ BuiltinID == ARM::BI__builtin_arm_stlex ||
+ BuiltinID == AArch64::BI__builtin_arm_ldrex ||
+ BuiltinID == AArch64::BI__builtin_arm_ldaex ||
+ BuiltinID == AArch64::BI__builtin_arm_strex ||
+ BuiltinID == AArch64::BI__builtin_arm_stlex) &&
"unexpected ARM builtin");
- bool IsLdrex = BuiltinID == ARM::BI__builtin_arm_ldrex;
+ bool IsLdrex = BuiltinID == ARM::BI__builtin_arm_ldrex ||
+ BuiltinID == ARM::BI__builtin_arm_ldaex ||
+ BuiltinID == AArch64::BI__builtin_arm_ldrex ||
+ BuiltinID == AArch64::BI__builtin_arm_ldaex;
DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
@@ -482,7 +530,7 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall) {
ExprResult PointerArgRes = DefaultFunctionArrayLvalueConversion(PointerArg);
if (PointerArgRes.isInvalid())
return true;
- PointerArg = PointerArgRes.take();
+ PointerArg = PointerArgRes.get();
const PointerType *pointerType = PointerArg->getType()->getAs<PointerType>();
if (!pointerType) {
@@ -514,7 +562,7 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall) {
PointerArgRes = ImpCastExprToType(PointerArg, AddrType, CastNeeded);
if (PointerArgRes.isInvalid())
return true;
- PointerArg = PointerArgRes.take();
+ PointerArg = PointerArgRes.get();
TheCall->setArg(IsLdrex ? 0 : 1, PointerArg);
@@ -527,7 +575,8 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall) {
}
// But ARM doesn't have instructions to deal with 128-bit versions.
- if (Context.getTypeSize(ValType) > 64) {
+ if (Context.getTypeSize(ValType) > MaxWidth) {
+ assert(MaxWidth == 64 && "Diagnostic unexpectedly inaccurate");
Diag(DRE->getLocStart(), diag::err_atomic_exclusive_builtin_pointer_size)
<< PointerArg->getType() << PointerArg->getSourceRange();
return true;
@@ -572,55 +621,17 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
llvm::APSInt Result;
if (BuiltinID == ARM::BI__builtin_arm_ldrex ||
- BuiltinID == ARM::BI__builtin_arm_strex) {
- return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall);
+ BuiltinID == ARM::BI__builtin_arm_ldaex ||
+ BuiltinID == ARM::BI__builtin_arm_strex ||
+ BuiltinID == ARM::BI__builtin_arm_stlex) {
+ return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 64);
}
- uint64_t mask = 0;
- unsigned TV = 0;
- int PtrArgNum = -1;
- bool HasConstPtr = false;
- switch (BuiltinID) {
-#define GET_NEON_OVERLOAD_CHECK
-#include "clang/Basic/arm_neon.inc"
-#undef GET_NEON_OVERLOAD_CHECK
- }
-
- // For NEON intrinsics which are overloaded on vector element type, validate
- // the immediate which specifies which variant to emit.
- unsigned ImmArg = TheCall->getNumArgs()-1;
- if (mask) {
- if (SemaBuiltinConstantArg(TheCall, ImmArg, Result))
- return true;
-
- TV = Result.getLimitedValue(64);
- if ((TV > 63) || (mask & (1ULL << TV)) == 0)
- return Diag(TheCall->getLocStart(), diag::err_invalid_neon_type_code)
- << TheCall->getArg(ImmArg)->getSourceRange();
- }
+ if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall))
+ return true;
- if (PtrArgNum >= 0) {
- // Check that pointer arguments have the specified type.
- Expr *Arg = TheCall->getArg(PtrArgNum);
- if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg))
- Arg = ICE->getSubExpr();
- ExprResult RHS = DefaultFunctionArrayLvalueConversion(Arg);
- QualType RHSTy = RHS.get()->getType();
- QualType EltTy = getNeonEltType(NeonTypeFlags(TV), Context, false);
- if (HasConstPtr)
- EltTy = EltTy.withConst();
- QualType LHSTy = Context.getPointerType(EltTy);
- AssignConvertType ConvTy;
- ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS);
- if (RHS.isInvalid())
- return true;
- if (DiagnoseAssignmentResult(ConvTy, Arg->getLocStart(), LHSTy, RHSTy,
- RHS.get(), AA_Assigning))
- return true;
- }
-
- // For NEON intrinsics which take an immediate value as part of the
- // instruction, range check them here.
+ // For intrinsics which take an immediate value as part of the instruction,
+ // range check them here.
unsigned i = 0, l = 0, u = 0;
switch (BuiltinID) {
default: return false;
@@ -629,29 +640,40 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case ARM::BI__builtin_arm_vcvtr_f:
case ARM::BI__builtin_arm_vcvtr_d: i = 1; u = 1; break;
case ARM::BI__builtin_arm_dmb:
- case ARM::BI__builtin_arm_dsb: l = 0; u = 15; break;
-#define GET_NEON_IMMEDIATE_CHECK
-#include "clang/Basic/arm_neon.inc"
-#undef GET_NEON_IMMEDIATE_CHECK
- };
+ case ARM::BI__builtin_arm_dsb:
+ case ARM::BI__builtin_arm_isb: l = 0; u = 15; break;
+ }
- // We can't check the value of a dependent argument.
- if (TheCall->getArg(i)->isTypeDependent() ||
- TheCall->getArg(i)->isValueDependent())
- return false;
+ // FIXME: VFP Intrinsics should error if VFP not present.
+ return SemaBuiltinConstantArgRange(TheCall, i, l, u + l);
+}
+
+bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
+ CallExpr *TheCall) {
+ llvm::APSInt Result;
+
+ if (BuiltinID == AArch64::BI__builtin_arm_ldrex ||
+ BuiltinID == AArch64::BI__builtin_arm_ldaex ||
+ BuiltinID == AArch64::BI__builtin_arm_strex ||
+ BuiltinID == AArch64::BI__builtin_arm_stlex) {
+ return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 128);
+ }
- // Check that the immediate argument is actually a constant.
- if (SemaBuiltinConstantArg(TheCall, i, Result))
+ if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall))
return true;
- // Range check against the upper/lower values for this isntruction.
- unsigned Val = Result.getZExtValue();
- if (Val < l || Val > (u + l))
- return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
- << l << u+l << TheCall->getArg(i)->getSourceRange();
+ // For intrinsics which take an immediate value as part of the instruction,
+ // range check them here.
+ unsigned i = 0, l = 0, u = 0;
+ switch (BuiltinID) {
+ default: return false;
+ case AArch64::BI__builtin_arm_dmb:
+ case AArch64::BI__builtin_arm_dsb:
+ case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break;
+ }
// FIXME: VFP Intrinsics should error if VFP not present.
- return false;
+ return SemaBuiltinConstantArgRange(TheCall, i, l, u + l);
}
bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
@@ -665,24 +687,17 @@ bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case Mips::BI__builtin_mips_precr_sra_ph_w: i = 2; l = 0; u = 31; break;
case Mips::BI__builtin_mips_precr_sra_r_ph_w: i = 2; l = 0; u = 31; break;
case Mips::BI__builtin_mips_prepend: i = 2; l = 0; u = 31; break;
- };
-
- // We can't check the value of a dependent argument.
- if (TheCall->getArg(i)->isTypeDependent() ||
- TheCall->getArg(i)->isValueDependent())
- return false;
-
- // Check that the immediate argument is actually a constant.
- llvm::APSInt Result;
- if (SemaBuiltinConstantArg(TheCall, i, Result))
- return true;
+ }
- // Range check against the upper/lower values for this instruction.
- unsigned Val = Result.getZExtValue();
- if (Val < l || Val > u)
- return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
- << l << u << TheCall->getArg(i)->getSourceRange();
+ return SemaBuiltinConstantArgRange(TheCall, i, l, u);
+}
+bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
+ switch (BuiltinID) {
+ case X86::BI_mm_prefetch:
+ // This is declared to take (const char*, int)
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3);
+ }
return false;
}
@@ -709,14 +724,66 @@ bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
return true;
}
+/// Checks if a the given expression evaluates to null.
+///
+/// \brief Returns true if the value evaluates to null.
+static bool CheckNonNullExpr(Sema &S,
+ const Expr *Expr) {
+ // As a special case, transparent unions initialized with zero are
+ // considered null for the purposes of the nonnull attribute.
+ if (const RecordType *UT = Expr->getType()->getAsUnionType()) {
+ if (UT->getDecl()->hasAttr<TransparentUnionAttr>())
+ if (const CompoundLiteralExpr *CLE =
+ dyn_cast<CompoundLiteralExpr>(Expr))
+ if (const InitListExpr *ILE =
+ dyn_cast<InitListExpr>(CLE->getInitializer()))
+ Expr = ILE->getInit(0);
+ }
+
+ bool Result;
+ return (!Expr->isValueDependent() &&
+ Expr->EvaluateAsBooleanCondition(Result, S.Context) &&
+ !Result);
+}
+
+static void CheckNonNullArgument(Sema &S,
+ const Expr *ArgExpr,
+ SourceLocation CallSiteLoc) {
+ if (CheckNonNullExpr(S, ArgExpr))
+ S.Diag(CallSiteLoc, diag::warn_null_arg) << ArgExpr->getSourceRange();
+}
+
+static void CheckNonNullArguments(Sema &S,
+ const NamedDecl *FDecl,
+ const Expr * const *ExprArgs,
+ SourceLocation CallSiteLoc) {
+ // Check the attributes attached to the method/function itself.
+ for (const auto *NonNull : FDecl->specific_attrs<NonNullAttr>()) {
+ for (const auto &Val : NonNull->args())
+ CheckNonNullArgument(S, ExprArgs[Val], CallSiteLoc);
+ }
+
+ // Check the attributes on the parameters.
+ ArrayRef<ParmVarDecl*> parms;
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(FDecl))
+ parms = FD->parameters();
+ else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(FDecl))
+ parms = MD->parameters();
+
+ unsigned argIndex = 0;
+ for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end();
+ I != E; ++I, ++argIndex) {
+ const ParmVarDecl *PVD = *I;
+ if (PVD->hasAttr<NonNullAttr>())
+ CheckNonNullArgument(S, ExprArgs[argIndex], CallSiteLoc);
+ }
+}
+
/// Handles the checks for format strings, non-POD arguments to vararg
/// functions, and NULL arguments passed to non-NULL parameters.
-void Sema::checkCall(NamedDecl *FDecl,
- ArrayRef<const Expr *> Args,
- unsigned NumProtoArgs,
- bool IsMemberFunction,
- SourceLocation Loc,
- SourceRange Range,
+void Sema::checkCall(NamedDecl *FDecl, ArrayRef<const Expr *> Args,
+ unsigned NumParams, bool IsMemberFunction,
+ SourceLocation Loc, SourceRange Range,
VariadicCallType CallType) {
// FIXME: We should check as much as we can in the template definition.
if (CurContext->isDependentContext())
@@ -725,14 +792,11 @@ void Sema::checkCall(NamedDecl *FDecl,
// Printf and scanf checking.
llvm::SmallBitVector CheckedVarArgs;
if (FDecl) {
- for (specific_attr_iterator<FormatAttr>
- I = FDecl->specific_attr_begin<FormatAttr>(),
- E = FDecl->specific_attr_end<FormatAttr>();
- I != E; ++I) {
+ for (const auto *I : FDecl->specific_attrs<FormatAttr>()) {
// Only create vector if there are format attributes.
CheckedVarArgs.resize(Args.size());
- CheckFormatArguments(*I, Args, IsMemberFunction, CallType, Loc, Range,
+ CheckFormatArguments(I, Args, IsMemberFunction, CallType, Loc, Range,
CheckedVarArgs);
}
}
@@ -740,7 +804,7 @@ void Sema::checkCall(NamedDecl *FDecl,
// Refuse POD arguments that weren't caught by the format string
// checks above.
if (CallType != VariadicDoesNotApply) {
- for (unsigned ArgIdx = NumProtoArgs; ArgIdx < Args.size(); ++ArgIdx) {
+ for (unsigned ArgIdx = NumParams; ArgIdx < Args.size(); ++ArgIdx) {
// Args[ArgIdx] can be null in malformed code.
if (const Expr *Arg = Args[ArgIdx]) {
if (CheckedVarArgs.empty() || !CheckedVarArgs[ArgIdx])
@@ -750,18 +814,11 @@ void Sema::checkCall(NamedDecl *FDecl,
}
if (FDecl) {
- for (specific_attr_iterator<NonNullAttr>
- I = FDecl->specific_attr_begin<NonNullAttr>(),
- E = FDecl->specific_attr_end<NonNullAttr>(); I != E; ++I)
- CheckNonNullArguments(*I, Args.data(), Loc);
+ CheckNonNullArguments(*this, FDecl, Args.data(), Loc);
// Type safety checking.
- for (specific_attr_iterator<ArgumentWithTypeTagAttr>
- i = FDecl->specific_attr_begin<ArgumentWithTypeTagAttr>(),
- e = FDecl->specific_attr_end<ArgumentWithTypeTagAttr>();
- i != e; ++i) {
- CheckArgumentWithTypeTag(*i, Args.data());
- }
+ for (const auto *I : FDecl->specific_attrs<ArgumentWithTypeTagAttr>())
+ CheckArgumentWithTypeTag(I, Args.data());
}
}
@@ -773,7 +830,7 @@ void Sema::CheckConstructorCall(FunctionDecl *FDecl,
SourceLocation Loc) {
VariadicCallType CallType =
Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
- checkCall(FDecl, Args, Proto->getNumArgs(),
+ checkCall(FDecl, Args, Proto->getNumParams(),
/*IsMemberFunction=*/true, Loc, SourceRange(), CallType);
}
@@ -787,7 +844,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
IsMemberOperatorCall;
VariadicCallType CallType = getVariadicCallType(FDecl, Proto,
TheCall->getCallee());
- unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
+ unsigned NumParams = Proto ? Proto->getNumParams() : 0;
Expr** Args = TheCall->getArgs();
unsigned NumArgs = TheCall->getNumArgs();
if (IsMemberOperatorCall) {
@@ -797,8 +854,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
++Args;
--NumArgs;
}
- checkCall(FDecl, llvm::makeArrayRef<const Expr *>(Args, NumArgs),
- NumProtoArgs,
+ checkCall(FDecl, llvm::makeArrayRef<const Expr *>(Args, NumArgs), NumParams,
IsMemberFunction, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -808,6 +864,8 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
if (!FnInfo)
return false;
+ CheckAbsoluteValueFunction(TheCall, FDecl, FnInfo);
+
unsigned CMId = FDecl->getMemoryFunctionKind();
if (CMId == 0)
return false;
@@ -853,35 +911,59 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall,
} else { // Ty->isFunctionPointerType()
CallType = VariadicFunction;
}
- unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
+ unsigned NumParams = Proto ? Proto->getNumParams() : 0;
- checkCall(NDecl,
- llvm::makeArrayRef<const Expr *>(TheCall->getArgs(),
- TheCall->getNumArgs()),
- NumProtoArgs, /*IsMemberFunction=*/false,
- TheCall->getRParenLoc(),
+ checkCall(NDecl, llvm::makeArrayRef<const Expr *>(TheCall->getArgs(),
+ TheCall->getNumArgs()),
+ NumParams, /*IsMemberFunction=*/false, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
-
+
return false;
}
/// Checks function calls when a FunctionDecl or a NamedDecl is not available,
/// such as function pointers returned from functions.
bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) {
- VariadicCallType CallType = getVariadicCallType(/*FDecl=*/0, Proto,
+ VariadicCallType CallType = getVariadicCallType(/*FDecl=*/nullptr, Proto,
TheCall->getCallee());
- unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
+ unsigned NumParams = Proto ? Proto->getNumParams() : 0;
- checkCall(/*FDecl=*/0,
+ checkCall(/*FDecl=*/nullptr,
llvm::makeArrayRef<const Expr *>(TheCall->getArgs(),
TheCall->getNumArgs()),
- NumProtoArgs, /*IsMemberFunction=*/false,
- TheCall->getRParenLoc(),
+ NumParams, /*IsMemberFunction=*/false, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
return false;
}
+static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) {
+ if (Ordering < AtomicExpr::AO_ABI_memory_order_relaxed ||
+ Ordering > AtomicExpr::AO_ABI_memory_order_seq_cst)
+ return false;
+
+ switch (Op) {
+ case AtomicExpr::AO__c11_atomic_init:
+ llvm_unreachable("There is no ordering argument for an init");
+
+ case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__atomic_load_n:
+ case AtomicExpr::AO__atomic_load:
+ return Ordering != AtomicExpr::AO_ABI_memory_order_release &&
+ Ordering != AtomicExpr::AO_ABI_memory_order_acq_rel;
+
+ case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__atomic_store:
+ case AtomicExpr::AO__atomic_store_n:
+ return Ordering != AtomicExpr::AO_ABI_memory_order_consume &&
+ Ordering != AtomicExpr::AO_ABI_memory_order_acquire &&
+ Ordering != AtomicExpr::AO_ABI_memory_order_acq_rel;
+
+ default:
+ return true;
+ }
+}
+
ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
AtomicExpr::AtomicOp Op) {
CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
@@ -1170,7 +1252,16 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
SubExprs.push_back(TheCall->getArg(3)); // Weak
break;
}
-
+
+ if (SubExprs.size() >= 2 && Form != Init) {
+ llvm::APSInt Result(32);
+ if (SubExprs[1]->isIntegerConstantExpr(Result, Context) &&
+ !isValidOrderingForOp(Result.getSExtValue(), Op))
+ Diag(SubExprs[1]->getLocStart(),
+ diag::warn_atomic_op_has_invalid_memory_order)
+ << SubExprs[1]->getSourceRange();
+ }
+
AtomicExpr *AE = new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(),
SubExprs, ResultType, Op,
TheCall->getRParenLoc());
@@ -1181,7 +1272,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
Diag(AE->getLocStart(), diag::err_atomic_load_store_uses_lib) <<
((Op == AtomicExpr::AO__c11_atomic_load) ? 0 : 1);
- return Owned(AE);
+ return AE;
}
@@ -1205,7 +1296,7 @@ static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) {
if (Arg.isInvalid())
return true;
- E->setArg(ArgIndex, Arg.take());
+ E->setArg(ArgIndex, Arg.get());
return false;
}
@@ -1240,7 +1331,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
ExprResult FirstArgResult = DefaultFunctionArrayLvalueConversion(FirstArg);
if (FirstArgResult.isInvalid())
return ExprError();
- FirstArg = FirstArgResult.take();
+ FirstArg = FirstArgResult.get();
TheCall->setArg(0, FirstArg);
const PointerType *pointerType = FirstArg->getType()->getAs<PointerType>();
@@ -1493,7 +1584,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
LookupName(Res, TUScope, /*AllowBuiltinCreation=*/true);
assert(Res.getFoundDecl());
NewBuiltinDecl = dyn_cast<FunctionDecl>(Res.getFoundDecl());
- if (NewBuiltinDecl == 0)
+ if (!NewBuiltinDecl)
return ExprError();
}
@@ -1518,7 +1609,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// pass in 42. The 42 gets converted to char. This is even more strange
// for things like 45.123 -> char, etc.
// FIXME: Do this check.
- TheCall->setArg(i+1, Arg.take());
+ TheCall->setArg(i+1, Arg.get());
}
ASTContext& Context = this->getASTContext();
@@ -1539,7 +1630,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
QualType CalleePtrTy = Context.getPointerType(NewBuiltinDecl->getType());
ExprResult PromotedCall = ImpCastExprToType(NewDRE, CalleePtrTy,
CK_BuiltinFnToFnPtr);
- TheCall->setCallee(PromotedCall.take());
+ TheCall->setCallee(PromotedCall.get());
// Change the result type of the call to match the original value type. This
// is arbitrary, but the codegen for these builtins ins design to handle it
@@ -1661,6 +1752,58 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
return false;
}
+bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) {
+ // void __va_start(va_list *ap, const char *named_addr, size_t slot_size,
+ // const char *named_addr);
+
+ Expr *Func = Call->getCallee();
+
+ if (Call->getNumArgs() < 3)
+ return Diag(Call->getLocEnd(),
+ diag::err_typecheck_call_too_few_args_at_least)
+ << 0 /*function call*/ << 3 << Call->getNumArgs();
+
+ // Determine whether the current function is variadic or not.
+ bool IsVariadic;
+ if (BlockScopeInfo *CurBlock = getCurBlock())
+ IsVariadic = CurBlock->TheDecl->isVariadic();
+ else if (FunctionDecl *FD = getCurFunctionDecl())
+ IsVariadic = FD->isVariadic();
+ else if (ObjCMethodDecl *MD = getCurMethodDecl())
+ IsVariadic = MD->isVariadic();
+ else
+ llvm_unreachable("unexpected statement type");
+
+ if (!IsVariadic) {
+ Diag(Func->getLocStart(), diag::err_va_start_used_in_non_variadic_function);
+ return true;
+ }
+
+ // Type-check the first argument normally.
+ if (checkBuiltinArgument(*this, Call, 0))
+ return true;
+
+ static const struct {
+ unsigned ArgNo;
+ QualType Type;
+ } ArgumentTypes[] = {
+ { 1, Context.getPointerType(Context.CharTy.withConst()) },
+ { 2, Context.getSizeType() },
+ };
+
+ for (const auto &AT : ArgumentTypes) {
+ const Expr *Arg = Call->getArg(AT.ArgNo)->IgnoreParens();
+ if (Arg->getType().getCanonicalType() == AT.Type.getCanonicalType())
+ continue;
+ Diag(Arg->getLocStart(), diag::err_typecheck_convert_incompatible)
+ << Arg->getType() << AT.Type << 1 /* different class */
+ << 0 /* qualifier difference */ << 3 /* parameter mismatch */
+ << AT.ArgNo + 1 << Arg->getType() << AT.Type;
+ }
+
+ return false;
+}
+
/// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isgreater and
/// friends. This is declared to take (...), so we have to check everything.
bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
@@ -1735,7 +1878,7 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) {
if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) {
assert(Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) &&
"promotion from float to double is the only expected cast here");
- Cast->setSubExpr(0);
+ Cast->setSubExpr(nullptr);
TheCall->setArg(NumArgs-1, CastArg);
}
}
@@ -1820,12 +1963,12 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
for (unsigned i = 0, e = TheCall->getNumArgs(); i != e; i++) {
exprs.push_back(TheCall->getArg(i));
- TheCall->setArg(i, 0);
+ TheCall->setArg(i, nullptr);
}
- return Owned(new (Context) ShuffleVectorExpr(Context, exprs, resType,
- TheCall->getCallee()->getLocStart(),
- TheCall->getRParenLoc()));
+ return new (Context) ShuffleVectorExpr(Context, exprs, resType,
+ TheCall->getCallee()->getLocStart(),
+ TheCall->getRParenLoc());
}
/// SemaConvertVectorExpr - Handle __builtin_convertvector
@@ -1854,9 +1997,8 @@ ExprResult Sema::SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,
<< E->getSourceRange());
}
- return Owned(new (Context) ConvertVectorExpr(E, TInfo, DstTy, VK, OK,
- BuiltinLoc, RParenLoc));
-
+ return new (Context)
+ ConvertVectorExpr(E, TInfo, DstTy, VK, OK, BuiltinLoc, RParenLoc);
}
/// SemaBuiltinPrefetch - Handle __builtin_prefetch.
@@ -1873,30 +2015,23 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) {
// Argument 0 is checked for us and the remaining arguments must be
// constant integers.
- for (unsigned i = 1; i != NumArgs; ++i) {
- Expr *Arg = TheCall->getArg(i);
+ for (unsigned i = 1; i != NumArgs; ++i)
+ if (SemaBuiltinConstantArgRange(TheCall, i, 0, i == 1 ? 1 : 3))
+ return true;
- // We can't check the value of a dependent argument.
- if (Arg->isTypeDependent() || Arg->isValueDependent())
- continue;
+ return false;
+}
- llvm::APSInt Result;
- if (SemaBuiltinConstantArg(TheCall, i, Result))
- return true;
+/// SemaBuiltinAssume - Handle __assume (MS Extension).
+// __assume does not evaluate its arguments, and should warn if its argument
+// has side effects.
+bool Sema::SemaBuiltinAssume(CallExpr *TheCall) {
+ Expr *Arg = TheCall->getArg(0);
+ if (Arg->isInstantiationDependent()) return false;
- // FIXME: gcc issues a warning and rewrites these to 0. These
- // seems especially odd for the third argument since the default
- // is 3.
- if (i == 1) {
- if (Result.getLimitedValue() > 1)
- return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
- << "0" << "1" << Arg->getSourceRange();
- } else {
- if (Result.getLimitedValue() > 3)
- return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
- << "0" << "3" << Arg->getSourceRange();
- }
- }
+ if (Arg->HasSideEffects(Context))
+ return Diag(Arg->getLocStart(), diag::warn_assume_side_effects)
+ << Arg->getSourceRange();
return false;
}
@@ -1918,27 +2053,24 @@ bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
return false;
}
-/// SemaBuiltinObjectSize - Handle __builtin_object_size(void *ptr,
-/// int type). This simply type checks that type is one of the defined
-/// constants (0-3).
-// For compatibility check 0-3, llvm only handles 0 and 2.
-bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
+/// SemaBuiltinConstantArgRange - Handle a check if argument ArgNum of CallExpr
+/// TheCall is a constant expression in the range [Low, High].
+bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum,
+ int Low, int High) {
llvm::APSInt Result;
// We can't check the value of a dependent argument.
- if (TheCall->getArg(1)->isTypeDependent() ||
- TheCall->getArg(1)->isValueDependent())
+ Expr *Arg = TheCall->getArg(ArgNum);
+ if (Arg->isTypeDependent() || Arg->isValueDependent())
return false;
// Check constant-ness first.
- if (SemaBuiltinConstantArg(TheCall, 1, Result))
+ if (SemaBuiltinConstantArg(TheCall, ArgNum, Result))
return true;
- Expr *Arg = TheCall->getArg(1);
- if (Result.getSExtValue() < 0 || Result.getSExtValue() > 3) {
+ if (Result.getSExtValue() < Low || Result.getSExtValue() > High)
return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
- << "0" << "3" << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
- }
+ << Low << High << Arg->getSourceRange();
return false;
}
@@ -2081,10 +2213,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(VD)) {
if (const NamedDecl *ND = dyn_cast<NamedDecl>(PV->getDeclContext())) {
int PVIndex = PV->getFunctionScopeIndex() + 1;
- for (specific_attr_iterator<FormatAttr>
- i = ND->specific_attr_begin<FormatAttr>(),
- e = ND->specific_attr_end<FormatAttr>(); i != e ; ++i) {
- FormatAttr *PVFormat = *i;
+ for (const auto *PVFormat : ND->specific_attrs<FormatAttr>()) {
// adjust for implicit parameter
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND))
if (MD->isInstance())
@@ -2133,30 +2262,9 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
return SLCT_NotALiteral;
}
-
- case Stmt::ObjCMessageExprClass: {
- const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(E);
- if (const ObjCMethodDecl *MDecl = ME->getMethodDecl()) {
- if (const NamedDecl *ND = dyn_cast<NamedDecl>(MDecl)) {
- if (const FormatArgAttr *FA = ND->getAttr<FormatArgAttr>()) {
- unsigned ArgIndex = FA->getFormatIdx();
- if (ArgIndex <= ME->getNumArgs()) {
- const Expr *Arg = ME->getArg(ArgIndex-1);
- return checkFormatStringExpr(S, Arg, Args,
- HasVAListArg, format_idx,
- firstDataArg, Type, CallType,
- InFunctionCall, CheckedVarArgs);
- }
- }
- }
- }
-
- return SLCT_NotALiteral;
- }
-
case Stmt::ObjCStringLiteralClass:
case Stmt::StringLiteralClass: {
- const StringLiteral *StrE = NULL;
+ const StringLiteral *StrE = nullptr;
if (const ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(E))
StrE = ObjCFExpr->getString();
@@ -2177,32 +2285,6 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
}
}
-void
-Sema::CheckNonNullArguments(const NonNullAttr *NonNull,
- const Expr * const *ExprArgs,
- SourceLocation CallSiteLoc) {
- for (NonNullAttr::args_iterator i = NonNull->args_begin(),
- e = NonNull->args_end();
- i != e; ++i) {
- const Expr *ArgExpr = ExprArgs[*i];
-
- // As a special case, transparent unions initialized with zero are
- // considered null for the purposes of the nonnull attribute.
- if (const RecordType *UT = ArgExpr->getType()->getAsUnionType()) {
- if (UT->getDecl()->hasAttr<TransparentUnionAttr>())
- if (const CompoundLiteralExpr *CLE =
- dyn_cast<CompoundLiteralExpr>(ArgExpr))
- if (const InitListExpr *ILE =
- dyn_cast<InitListExpr>(CLE->getInitializer()))
- ArgExpr = ILE->getInit(0);
- }
-
- bool Result;
- if (ArgExpr->EvaluateAsBooleanCondition(Result, Context) && !Result)
- Diag(CallSiteLoc, diag::warn_null_arg) << ArgExpr->getSourceRange();
- }
-}
-
Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
return llvm::StringSwitch<FormatStringType>(Format->getType()->getName())
.Case("scanf", FST_Scanf)
@@ -2331,30 +2413,31 @@ public:
void DoneProcessing();
void HandleIncompleteSpecifier(const char *startSpecifier,
- unsigned specifierLen);
+ unsigned specifierLen) override;
void HandleInvalidLengthModifier(
- const analyze_format_string::FormatSpecifier &FS,
- const analyze_format_string::ConversionSpecifier &CS,
- const char *startSpecifier, unsigned specifierLen, unsigned DiagID);
+ const analyze_format_string::FormatSpecifier &FS,
+ const analyze_format_string::ConversionSpecifier &CS,
+ const char *startSpecifier, unsigned specifierLen,
+ unsigned DiagID);
void HandleNonStandardLengthModifier(
- const analyze_format_string::FormatSpecifier &FS,
- const char *startSpecifier, unsigned specifierLen);
+ const analyze_format_string::FormatSpecifier &FS,
+ const char *startSpecifier, unsigned specifierLen);
void HandleNonStandardConversionSpecifier(
- const analyze_format_string::ConversionSpecifier &CS,
- const char *startSpecifier, unsigned specifierLen);
+ const analyze_format_string::ConversionSpecifier &CS,
+ const char *startSpecifier, unsigned specifierLen);
- virtual void HandlePosition(const char *startPos, unsigned posLen);
+ void HandlePosition(const char *startPos, unsigned posLen) override;
- virtual void HandleInvalidPosition(const char *startSpecifier,
- unsigned specifierLen,
- analyze_format_string::PositionContext p);
+ void HandleInvalidPosition(const char *startSpecifier,
+ unsigned specifierLen,
+ analyze_format_string::PositionContext p) override;
- virtual void HandleZeroPosition(const char *startPos, unsigned posLen);
+ void HandleZeroPosition(const char *startPos, unsigned posLen) override;
- void HandleNullChar(const char *nullCharacter);
+ void HandleNullChar(const char *nullCharacter) override;
template <typename Range>
static void EmitFormatDiagnostic(Sema &S, bool inFunctionCall,
@@ -2390,9 +2473,6 @@ protected:
void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc,
bool IsStringLocation, Range StringRange,
ArrayRef<FixItHint> Fixit = None);
-
- void CheckPositionalAndNonpositionalArgs(
- const analyze_format_string::FormatSpecifier *FS);
};
}
@@ -2723,15 +2803,15 @@ public:
ObjCContext(isObjC)
{}
-
+
bool HandleInvalidPrintfConversionSpecifier(
const analyze_printf::PrintfSpecifier &FS,
const char *startSpecifier,
- unsigned specifierLen);
-
+ unsigned specifierLen) override;
+
bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
const char *startSpecifier,
- unsigned specifierLen);
+ unsigned specifierLen) override;
bool checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
const char *StartSpecifier,
unsigned SpecifierLen,
@@ -2751,7 +2831,7 @@ public:
const analyze_printf::OptionalFlag &flag,
const char *startSpecifier, unsigned specifierLen);
bool checkForCStrMembers(const analyze_printf::ArgType &AT,
- const Expr *E, const CharSourceRange &CSR);
+ const Expr *E);
};
}
@@ -2885,11 +2965,12 @@ CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) {
if (!RT)
return Results;
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
- if (!RD)
+ if (!RD || !RD->getDefinition())
return Results;
- LookupResult R(S, &S.PP.getIdentifierTable().get(Name), SourceLocation(),
+ LookupResult R(S, &S.Context.Idents.get(Name), SourceLocation(),
Sema::LookupMemberName);
+ R.suppressDiagnostics();
// We just need to include all members of the right kind turned up by the
// filter, at this point.
@@ -2902,12 +2983,26 @@ CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) {
return Results;
}
+/// Check if we could call '.c_str()' on an object.
+///
+/// FIXME: This returns the wrong results in some cases (if cv-qualifiers don't
+/// allow the call, or if it would be ambiguous).
+bool Sema::hasCStrMethod(const Expr *E) {
+ typedef llvm::SmallPtrSet<CXXMethodDecl*, 1> MethodSet;
+ MethodSet Results =
+ CXXRecordMembersNamed<CXXMethodDecl>("c_str", *this, E->getType());
+ for (MethodSet::iterator MI = Results.begin(), ME = Results.end();
+ MI != ME; ++MI)
+ if ((*MI)->getMinRequiredArguments() == 0)
+ return true;
+ return false;
+}
+
// Check if a (w)string was passed when a (w)char* was needed, and offer a
// better diagnostic if so. AT is assumed to be valid.
// Returns true when a c_str() conversion method is found.
bool CheckPrintfHandler::checkForCStrMembers(
- const analyze_printf::ArgType &AT, const Expr *E,
- const CharSourceRange &CSR) {
+ const analyze_printf::ArgType &AT, const Expr *E) {
typedef llvm::SmallPtrSet<CXXMethodDecl*, 1> MethodSet;
MethodSet Results =
@@ -2916,11 +3011,10 @@ bool CheckPrintfHandler::checkForCStrMembers(
for (MethodSet::iterator MI = Results.begin(), ME = Results.end();
MI != ME; ++MI) {
const CXXMethodDecl *Method = *MI;
- if (Method->getNumParams() == 0 &&
- AT.matchesType(S.Context, Method->getResultType())) {
+ if (Method->getMinRequiredArguments() == 0 &&
+ AT.matchesType(S.Context, Method->getReturnType())) {
// FIXME: Suggest parens if the expression needs them.
- SourceLocation EndLoc =
- S.getPreprocessor().getLocForEndOfToken(E->getLocEnd());
+ SourceLocation EndLoc = S.getLocForEndOfToken(E->getLocEnd());
S.Diag(E->getLocStart(), diag::note_printf_c_str)
<< "c_str()"
<< FixItHint::CreateInsertion(EndLoc, ".c_str()");
@@ -3135,6 +3229,13 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
ExprTy = S.Context.CharTy;
}
+ // Look through enums to their underlying type.
+ bool IsEnum = false;
+ if (auto EnumTy = ExprTy->getAs<EnumType>()) {
+ ExprTy = EnumTy->getDecl()->getIntegerType();
+ IsEnum = true;
+ }
+
// %C in an Objective-C context prints a unichar, not a wchar_t.
// If the argument is an integer of some kind, believe the %C and suggest
// a cast instead of changing the conversion specifier.
@@ -3207,8 +3308,8 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// In this case, the specifier is wrong and should be changed to match
// the argument.
EmitFormatDiagnostic(
- S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << IntendedTy
+ S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
+ << AT.getRepresentativeTypeName(S.Context) << IntendedTy << IsEnum
<< E->getSourceRange(),
E->getLocStart(),
/*IsStringLocation*/false,
@@ -3249,7 +3350,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
Hints.push_back(FixItHint::CreateInsertion(E->getLocStart(),
CastFix.str()));
- SourceLocation After = S.PP.getLocForEndOfToken(E->getLocEnd());
+ SourceLocation After = S.getLocForEndOfToken(E->getLocEnd());
Hints.push_back(FixItHint::CreateInsertion(After, ")"));
}
@@ -3260,7 +3361,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
StringRef Name = cast<TypedefType>(ExprTy)->getDecl()->getName();
EmitFormatDiagnostic(S.PDiag(diag::warn_format_argument_needs_cast)
- << Name << IntendedTy
+ << Name << IntendedTy << IsEnum
<< E->getSourceRange(),
E->getLocStart(), /*IsStringLocation=*/false,
SpecRange, Hints);
@@ -3269,8 +3370,8 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// specifier, but we've decided that the specifier is probably correct
// and we should cast instead. Just use the normal warning message.
EmitFormatDiagnostic(
- S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << ExprTy
+ S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
+ << AT.getRepresentativeTypeName(S.Context) << ExprTy << IsEnum
<< E->getSourceRange(),
E->getLocStart(), /*IsStringLocation*/false,
SpecRange, Hints);
@@ -3286,8 +3387,8 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
case Sema::VAK_Valid:
case Sema::VAK_ValidInCXX11:
EmitFormatDiagnostic(
- S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << ExprTy
+ S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
+ << AT.getRepresentativeTypeName(S.Context) << ExprTy << IsEnum
<< CSR
<< E->getSourceRange(),
E->getLocStart(), /*IsStringLocation*/false, CSR);
@@ -3303,7 +3404,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
<< CSR
<< E->getSourceRange(),
E->getLocStart(), /*IsStringLocation*/false, CSR);
- checkForCStrMembers(AT, E, CSR);
+ checkForCStrMembers(AT, E);
break;
case Sema::VAK_Invalid:
@@ -3355,14 +3456,14 @@ public:
bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
const char *startSpecifier,
- unsigned specifierLen);
+ unsigned specifierLen) override;
bool HandleInvalidScanfConversionSpecifier(
const analyze_scanf::ScanfSpecifier &FS,
const char *startSpecifier,
- unsigned specifierLen);
+ unsigned specifierLen) override;
- void HandleIncompleteScanList(const char *start, const char *end);
+ void HandleIncompleteScanList(const char *start, const char *end) override;
};
}
@@ -3467,8 +3568,9 @@ bool CheckScanfHandler::HandleScanfSpecifier(
const analyze_format_string::ArgType &AT = FS.getArgType(S.Context);
if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType())) {
ScanfSpecifier fixedFS = FS;
- bool success = fixedFS.fixType(Ex->getType(), S.getLangOpts(),
- S.Context);
+ bool success = fixedFS.fixType(Ex->getType(),
+ Ex->IgnoreImpCasts()->getType(),
+ S.getLangOpts(), S.Context);
if (success) {
// Get the fix string from the fixed format specifier.
@@ -3477,8 +3579,8 @@ bool CheckScanfHandler::HandleScanfSpecifier(
fixedFS.toString(os);
EmitFormatDiagnostic(
- S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << Ex->getType()
+ S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
+ << AT.getRepresentativeTypeName(S.Context) << Ex->getType() << false
<< Ex->getSourceRange(),
Ex->getLocStart(),
/*IsStringLocation*/false,
@@ -3488,8 +3590,8 @@ bool CheckScanfHandler::HandleScanfSpecifier(
os.str()));
} else {
EmitFormatDiagnostic(
- S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << Ex->getType()
+ S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
+ << AT.getRepresentativeTypeName(S.Context) << Ex->getType() << false
<< Ex->getSourceRange(),
Ex->getLocStart(),
/*IsStringLocation*/false,
@@ -3520,9 +3622,25 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
// Str - The format string. NOTE: this is NOT null-terminated!
StringRef StrRef = FExpr->getString();
const char *Str = StrRef.data();
- unsigned StrLen = StrRef.size();
+ // Account for cases where the string literal is truncated in a declaration.
+ const ConstantArrayType *T = Context.getAsConstantArrayType(FExpr->getType());
+ assert(T && "String literal not of constant array type!");
+ size_t TypeSize = T->getSize().getZExtValue();
+ size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size());
const unsigned numDataArgs = Args.size() - firstDataArg;
-
+
+ // Emit a warning if the string literal is truncated and does not contain an
+ // embedded null character.
+ if (TypeSize <= StrRef.size() &&
+ StrRef.substr(0, TypeSize).find('\0') == StringRef::npos) {
+ CheckFormatHandler::EmitFormatDiagnostic(
+ *this, inFunctionCall, Args[format_idx],
+ PDiag(diag::warn_printf_format_string_not_null_terminated),
+ FExpr->getLocStart(),
+ /*IsStringLocation=*/true, OrigFormatExpr->getSourceRange());
+ return;
+ }
+
// CHECK: empty format string?
if (StrLen == 0 && numDataArgs > 0) {
CheckFormatHandler::EmitFormatDiagnostic(
@@ -3554,17 +3672,452 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
} // TODO: handle other formats
}
+//===--- CHECK: Warn on use of wrong absolute value function. -------------===//
+
+// Returns the related absolute value function that is larger, of 0 if one
+// does not exist.
+static unsigned getLargerAbsoluteValueFunction(unsigned AbsFunction) {
+ switch (AbsFunction) {
+ default:
+ return 0;
+
+ case Builtin::BI__builtin_abs:
+ return Builtin::BI__builtin_labs;
+ case Builtin::BI__builtin_labs:
+ return Builtin::BI__builtin_llabs;
+ case Builtin::BI__builtin_llabs:
+ return 0;
+
+ case Builtin::BI__builtin_fabsf:
+ return Builtin::BI__builtin_fabs;
+ case Builtin::BI__builtin_fabs:
+ return Builtin::BI__builtin_fabsl;
+ case Builtin::BI__builtin_fabsl:
+ return 0;
+
+ case Builtin::BI__builtin_cabsf:
+ return Builtin::BI__builtin_cabs;
+ case Builtin::BI__builtin_cabs:
+ return Builtin::BI__builtin_cabsl;
+ case Builtin::BI__builtin_cabsl:
+ return 0;
+
+ case Builtin::BIabs:
+ return Builtin::BIlabs;
+ case Builtin::BIlabs:
+ return Builtin::BIllabs;
+ case Builtin::BIllabs:
+ return 0;
+
+ case Builtin::BIfabsf:
+ return Builtin::BIfabs;
+ case Builtin::BIfabs:
+ return Builtin::BIfabsl;
+ case Builtin::BIfabsl:
+ return 0;
+
+ case Builtin::BIcabsf:
+ return Builtin::BIcabs;
+ case Builtin::BIcabs:
+ return Builtin::BIcabsl;
+ case Builtin::BIcabsl:
+ return 0;
+ }
+}
+
+// Returns the argument type of the absolute value function.
+static QualType getAbsoluteValueArgumentType(ASTContext &Context,
+ unsigned AbsType) {
+ if (AbsType == 0)
+ return QualType();
+
+ ASTContext::GetBuiltinTypeError Error = ASTContext::GE_None;
+ QualType BuiltinType = Context.GetBuiltinType(AbsType, Error);
+ if (Error != ASTContext::GE_None)
+ return QualType();
+
+ const FunctionProtoType *FT = BuiltinType->getAs<FunctionProtoType>();
+ if (!FT)
+ return QualType();
+
+ if (FT->getNumParams() != 1)
+ return QualType();
+
+ return FT->getParamType(0);
+}
+
+// Returns the best absolute value function, or zero, based on type and
+// current absolute value function.
+static unsigned getBestAbsFunction(ASTContext &Context, QualType ArgType,
+ unsigned AbsFunctionKind) {
+ unsigned BestKind = 0;
+ uint64_t ArgSize = Context.getTypeSize(ArgType);
+ for (unsigned Kind = AbsFunctionKind; Kind != 0;
+ Kind = getLargerAbsoluteValueFunction(Kind)) {
+ QualType ParamType = getAbsoluteValueArgumentType(Context, Kind);
+ if (Context.getTypeSize(ParamType) >= ArgSize) {
+ if (BestKind == 0)
+ BestKind = Kind;
+ else if (Context.hasSameType(ParamType, ArgType)) {
+ BestKind = Kind;
+ break;
+ }
+ }
+ }
+ return BestKind;
+}
+
+enum AbsoluteValueKind {
+ AVK_Integer,
+ AVK_Floating,
+ AVK_Complex
+};
+
+static AbsoluteValueKind getAbsoluteValueKind(QualType T) {
+ if (T->isIntegralOrEnumerationType())
+ return AVK_Integer;
+ if (T->isRealFloatingType())
+ return AVK_Floating;
+ if (T->isAnyComplexType())
+ return AVK_Complex;
+
+ llvm_unreachable("Type not integer, floating, or complex");
+}
+
+// Changes the absolute value function to a different type. Preserves whether
+// the function is a builtin.
+static unsigned changeAbsFunction(unsigned AbsKind,
+ AbsoluteValueKind ValueKind) {
+ switch (ValueKind) {
+ case AVK_Integer:
+ switch (AbsKind) {
+ default:
+ return 0;
+ case Builtin::BI__builtin_fabsf:
+ case Builtin::BI__builtin_fabs:
+ case Builtin::BI__builtin_fabsl:
+ case Builtin::BI__builtin_cabsf:
+ case Builtin::BI__builtin_cabs:
+ case Builtin::BI__builtin_cabsl:
+ return Builtin::BI__builtin_abs;
+ case Builtin::BIfabsf:
+ case Builtin::BIfabs:
+ case Builtin::BIfabsl:
+ case Builtin::BIcabsf:
+ case Builtin::BIcabs:
+ case Builtin::BIcabsl:
+ return Builtin::BIabs;
+ }
+ case AVK_Floating:
+ switch (AbsKind) {
+ default:
+ return 0;
+ case Builtin::BI__builtin_abs:
+ case Builtin::BI__builtin_labs:
+ case Builtin::BI__builtin_llabs:
+ case Builtin::BI__builtin_cabsf:
+ case Builtin::BI__builtin_cabs:
+ case Builtin::BI__builtin_cabsl:
+ return Builtin::BI__builtin_fabsf;
+ case Builtin::BIabs:
+ case Builtin::BIlabs:
+ case Builtin::BIllabs:
+ case Builtin::BIcabsf:
+ case Builtin::BIcabs:
+ case Builtin::BIcabsl:
+ return Builtin::BIfabsf;
+ }
+ case AVK_Complex:
+ switch (AbsKind) {
+ default:
+ return 0;
+ case Builtin::BI__builtin_abs:
+ case Builtin::BI__builtin_labs:
+ case Builtin::BI__builtin_llabs:
+ case Builtin::BI__builtin_fabsf:
+ case Builtin::BI__builtin_fabs:
+ case Builtin::BI__builtin_fabsl:
+ return Builtin::BI__builtin_cabsf;
+ case Builtin::BIabs:
+ case Builtin::BIlabs:
+ case Builtin::BIllabs:
+ case Builtin::BIfabsf:
+ case Builtin::BIfabs:
+ case Builtin::BIfabsl:
+ return Builtin::BIcabsf;
+ }
+ }
+ llvm_unreachable("Unable to convert function");
+}
+
+static unsigned getAbsoluteValueFunctionKind(const FunctionDecl *FDecl) {
+ const IdentifierInfo *FnInfo = FDecl->getIdentifier();
+ if (!FnInfo)
+ return 0;
+
+ switch (FDecl->getBuiltinID()) {
+ default:
+ return 0;
+ case Builtin::BI__builtin_abs:
+ case Builtin::BI__builtin_fabs:
+ case Builtin::BI__builtin_fabsf:
+ case Builtin::BI__builtin_fabsl:
+ case Builtin::BI__builtin_labs:
+ case Builtin::BI__builtin_llabs:
+ case Builtin::BI__builtin_cabs:
+ case Builtin::BI__builtin_cabsf:
+ case Builtin::BI__builtin_cabsl:
+ case Builtin::BIabs:
+ case Builtin::BIlabs:
+ case Builtin::BIllabs:
+ case Builtin::BIfabs:
+ case Builtin::BIfabsf:
+ case Builtin::BIfabsl:
+ case Builtin::BIcabs:
+ case Builtin::BIcabsf:
+ case Builtin::BIcabsl:
+ return FDecl->getBuiltinID();
+ }
+ llvm_unreachable("Unknown Builtin type");
+}
+
+// If the replacement is valid, emit a note with replacement function.
+// Additionally, suggest including the proper header if not already included.
+static void emitReplacement(Sema &S, SourceLocation Loc, SourceRange Range,
+ unsigned AbsKind, QualType ArgType) {
+ bool EmitHeaderHint = true;
+ const char *HeaderName = nullptr;
+ const char *FunctionName = nullptr;
+ if (S.getLangOpts().CPlusPlus && !ArgType->isAnyComplexType()) {
+ FunctionName = "std::abs";
+ if (ArgType->isIntegralOrEnumerationType()) {
+ HeaderName = "cstdlib";
+ } else if (ArgType->isRealFloatingType()) {
+ HeaderName = "cmath";
+ } else {
+ llvm_unreachable("Invalid Type");
+ }
+
+ // Lookup all std::abs
+ if (NamespaceDecl *Std = S.getStdNamespace()) {
+ LookupResult R(S, &S.Context.Idents.get("abs"), Loc, Sema::LookupAnyName);
+ R.suppressDiagnostics();
+ S.LookupQualifiedName(R, Std);
+
+ for (const auto *I : R) {
+ const FunctionDecl *FDecl = nullptr;
+ if (const UsingShadowDecl *UsingD = dyn_cast<UsingShadowDecl>(I)) {
+ FDecl = dyn_cast<FunctionDecl>(UsingD->getTargetDecl());
+ } else {
+ FDecl = dyn_cast<FunctionDecl>(I);
+ }
+ if (!FDecl)
+ continue;
+
+ // Found std::abs(), check that they are the right ones.
+ if (FDecl->getNumParams() != 1)
+ continue;
+
+ // Check that the parameter type can handle the argument.
+ QualType ParamType = FDecl->getParamDecl(0)->getType();
+ if (getAbsoluteValueKind(ArgType) == getAbsoluteValueKind(ParamType) &&
+ S.Context.getTypeSize(ArgType) <=
+ S.Context.getTypeSize(ParamType)) {
+ // Found a function, don't need the header hint.
+ EmitHeaderHint = false;
+ break;
+ }
+ }
+ }
+ } else {
+ FunctionName = S.Context.BuiltinInfo.GetName(AbsKind);
+ HeaderName = S.Context.BuiltinInfo.getHeaderName(AbsKind);
+
+ if (HeaderName) {
+ DeclarationName DN(&S.Context.Idents.get(FunctionName));
+ LookupResult R(S, DN, Loc, Sema::LookupAnyName);
+ R.suppressDiagnostics();
+ S.LookupName(R, S.getCurScope());
+
+ if (R.isSingleResult()) {
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(R.getFoundDecl());
+ if (FD && FD->getBuiltinID() == AbsKind) {
+ EmitHeaderHint = false;
+ } else {
+ return;
+ }
+ } else if (!R.empty()) {
+ return;
+ }
+ }
+ }
+
+ S.Diag(Loc, diag::note_replace_abs_function)
+ << FunctionName << FixItHint::CreateReplacement(Range, FunctionName);
+
+ if (!HeaderName)
+ return;
+
+ if (!EmitHeaderHint)
+ return;
+
+ S.Diag(Loc, diag::note_include_header_or_declare) << HeaderName
+ << FunctionName;
+}
+
+static bool IsFunctionStdAbs(const FunctionDecl *FDecl) {
+ if (!FDecl)
+ return false;
+
+ if (!FDecl->getIdentifier() || !FDecl->getIdentifier()->isStr("abs"))
+ return false;
+
+ const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(FDecl->getDeclContext());
+
+ while (ND && ND->isInlineNamespace()) {
+ ND = dyn_cast<NamespaceDecl>(ND->getDeclContext());
+ }
+
+ if (!ND || !ND->getIdentifier() || !ND->getIdentifier()->isStr("std"))
+ return false;
+
+ if (!isa<TranslationUnitDecl>(ND->getDeclContext()))
+ return false;
+
+ return true;
+}
+
+// Warn when using the wrong abs() function.
+void Sema::CheckAbsoluteValueFunction(const CallExpr *Call,
+ const FunctionDecl *FDecl,
+ IdentifierInfo *FnInfo) {
+ if (Call->getNumArgs() != 1)
+ return;
+
+ unsigned AbsKind = getAbsoluteValueFunctionKind(FDecl);
+ bool IsStdAbs = IsFunctionStdAbs(FDecl);
+ if (AbsKind == 0 && !IsStdAbs)
+ return;
+
+ QualType ArgType = Call->getArg(0)->IgnoreParenImpCasts()->getType();
+ QualType ParamType = Call->getArg(0)->getType();
+
+ // Unsigned types cannot be negative. Suggest removing the absolute value
+ // function call.
+ if (ArgType->isUnsignedIntegerType()) {
+ const char *FunctionName =
+ IsStdAbs ? "std::abs" : Context.BuiltinInfo.GetName(AbsKind);
+ Diag(Call->getExprLoc(), diag::warn_unsigned_abs) << ArgType << ParamType;
+ Diag(Call->getExprLoc(), diag::note_remove_abs)
+ << FunctionName
+ << FixItHint::CreateRemoval(Call->getCallee()->getSourceRange());
+ return;
+ }
+
+ // std::abs has overloads which prevent most of the absolute value problems
+ // from occurring.
+ if (IsStdAbs)
+ return;
+
+ AbsoluteValueKind ArgValueKind = getAbsoluteValueKind(ArgType);
+ AbsoluteValueKind ParamValueKind = getAbsoluteValueKind(ParamType);
+
+ // The argument and parameter are the same kind. Check if they are the right
+ // size.
+ if (ArgValueKind == ParamValueKind) {
+ if (Context.getTypeSize(ArgType) <= Context.getTypeSize(ParamType))
+ return;
+
+ unsigned NewAbsKind = getBestAbsFunction(Context, ArgType, AbsKind);
+ Diag(Call->getExprLoc(), diag::warn_abs_too_small)
+ << FDecl << ArgType << ParamType;
+
+ if (NewAbsKind == 0)
+ return;
+
+ emitReplacement(*this, Call->getExprLoc(),
+ Call->getCallee()->getSourceRange(), NewAbsKind, ArgType);
+ return;
+ }
+
+ // ArgValueKind != ParamValueKind
+ // The wrong type of absolute value function was used. Attempt to find the
+ // proper one.
+ unsigned NewAbsKind = changeAbsFunction(AbsKind, ArgValueKind);
+ NewAbsKind = getBestAbsFunction(Context, ArgType, NewAbsKind);
+ if (NewAbsKind == 0)
+ return;
+
+ Diag(Call->getExprLoc(), diag::warn_wrong_absolute_value_type)
+ << FDecl << ParamValueKind << ArgValueKind;
+
+ emitReplacement(*this, Call->getExprLoc(),
+ Call->getCallee()->getSourceRange(), NewAbsKind, ArgType);
+ return;
+}
+
//===--- CHECK: Standard memory functions ---------------------------------===//
-/// \brief Determine whether the given type is a dynamic class type (e.g.,
-/// whether it has a vtable).
-static bool isDynamicClassType(QualType T) {
- if (CXXRecordDecl *Record = T->getAsCXXRecordDecl())
- if (CXXRecordDecl *Definition = Record->getDefinition())
- if (Definition->isDynamicClass())
- return true;
-
- return false;
+/// \brief Takes the expression passed to the size_t parameter of functions
+/// such as memcmp, strncat, etc and warns if it's a comparison.
+///
+/// This is to catch typos like `if (memcmp(&a, &b, sizeof(a) > 0))`.
+static bool CheckMemorySizeofForComparison(Sema &S, const Expr *E,
+ IdentifierInfo *FnName,
+ SourceLocation FnLoc,
+ SourceLocation RParenLoc) {
+ const BinaryOperator *Size = dyn_cast<BinaryOperator>(E);
+ if (!Size)
+ return false;
+
+ // if E is binop and op is >, <, >=, <=, ==, &&, ||:
+ if (!Size->isComparisonOp() && !Size->isEqualityOp() && !Size->isLogicalOp())
+ return false;
+
+ SourceRange SizeRange = Size->getSourceRange();
+ S.Diag(Size->getOperatorLoc(), diag::warn_memsize_comparison)
+ << SizeRange << FnName;
+ S.Diag(FnLoc, diag::note_memsize_comparison_paren)
+ << FnName << FixItHint::CreateInsertion(
+ S.getLocForEndOfToken(Size->getLHS()->getLocEnd()), ")")
+ << FixItHint::CreateRemoval(RParenLoc);
+ S.Diag(SizeRange.getBegin(), diag::note_memsize_comparison_cast_silence)
+ << FixItHint::CreateInsertion(SizeRange.getBegin(), "(size_t)(")
+ << FixItHint::CreateInsertion(S.getLocForEndOfToken(SizeRange.getEnd()),
+ ")");
+
+ return true;
+}
+
+/// \brief Determine whether the given type is or contains a dynamic class type
+/// (e.g., whether it has a vtable).
+static const CXXRecordDecl *getContainedDynamicClass(QualType T,
+ bool &IsContained) {
+ // Look through array types while ignoring qualifiers.
+ const Type *Ty = T->getBaseElementTypeUnsafe();
+ IsContained = false;
+
+ const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ RD = RD ? RD->getDefinition() : nullptr;
+ if (!RD)
+ return nullptr;
+
+ if (RD->isDynamicClass())
+ return RD;
+
+ // Check all the fields. If any bases were dynamic, the class is dynamic.
+ // It's impossible for a class to transitively contain itself by value, so
+ // infinite recursion is impossible.
+ for (auto *FD : RD->fields()) {
+ bool SubContained;
+ if (const CXXRecordDecl *ContainedRD =
+ getContainedDynamicClass(FD->getType(), SubContained)) {
+ IsContained = true;
+ return ContainedRD;
+ }
+ }
+
+ return nullptr;
}
/// \brief If E is a sizeof expression, returns its argument expression,
@@ -3575,7 +4128,7 @@ static const Expr *getSizeOfExprArg(const Expr* E) {
if (SizeOf->getKind() == clang::UETT_SizeOf && !SizeOf->isArgumentType())
return SizeOf->getArgumentExpr()->IgnoreParenImpCasts();
- return 0;
+ return nullptr;
}
/// \brief If E is a sizeof expression, returns its argument type.
@@ -3611,6 +4164,10 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
unsigned LenArg = (BId == Builtin::BIstrndup ? 1 : 2);
const Expr *LenExpr = Call->getArg(LenArg)->IgnoreParenImpCasts();
+ if (CheckMemorySizeofForComparison(*this, LenExpr, FnName,
+ Call->getLocStart(), Call->getRParenLoc()))
+ return;
+
// We have special checking when the length is a sizeof expression.
QualType SizeOfArgTy = getSizeOfArgType(LenExpr);
const Expr *SizeOfArg = getSizeOfExprArg(LenExpr);
@@ -3634,8 +4191,8 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
// 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())) {
+ !Diags.isIgnored(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())
@@ -3661,7 +4218,7 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
SourceLocation SL = SizeOfArg->getExprLoc();
SourceRange DSR = Dest->getSourceRange();
SourceRange SSR = SizeOfArg->getSourceRange();
- SourceManager &SM = PP.getSourceManager();
+ SourceManager &SM = getSourceManager();
if (SM.isMacroArgExpansion(SL)) {
ReadableName = Lexer::getImmediateMacroName(SL, SM, LangOpts);
@@ -3704,7 +4261,9 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
}
// Always complain about dynamic classes.
- if (isDynamicClassType(PointeeTy)) {
+ bool IsContained;
+ if (const CXXRecordDecl *ContainedRD =
+ getContainedDynamicClass(PointeeTy, IsContained)) {
unsigned OperationType = 0;
// "overwritten" if we're warning about the destination for any call
@@ -3722,8 +4281,7 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
Dest->getExprLoc(), Dest,
PDiag(diag::warn_dyn_class_memaccess)
<< (BId == Builtin::BImemcmp ? ArgIdx + 2 : ArgIdx)
- << FnName << PointeeTy
- << OperationType
+ << FnName << IsContained << ContainedRD << OperationType
<< Call->getCallee()->getSourceRange());
} else if (PointeeTy.hasNonTrivialObjCLifetime() &&
BId != Builtin::BImemset)
@@ -3793,7 +4351,11 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call,
const Expr *SrcArg = ignoreLiteralAdditions(Call->getArg(1), Context);
const Expr *SizeArg = ignoreLiteralAdditions(Call->getArg(2), Context);
- const Expr *CompareWithSrc = NULL;
+ const Expr *CompareWithSrc = nullptr;
+
+ if (CheckMemorySizeofForComparison(*this, SizeArg, FnName,
+ Call->getLocStart(), Call->getRParenLoc()))
+ return;
// Look for 'strlcpy(dst, x, sizeof(x))'
if (const Expr *Ex = getSizeOfExprArg(SizeArg))
@@ -3801,8 +4363,8 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call,
else {
// Look for 'strlcpy(dst, x, strlen(x))'
if (const CallExpr *SizeCall = dyn_cast<CallExpr>(SizeArg)) {
- if (SizeCall->isBuiltinCall() == Builtin::BIstrlen
- && SizeCall->getNumArgs() == 1)
+ if (SizeCall->getBuiltinCallee() == Builtin::BIstrlen &&
+ SizeCall->getNumArgs() == 1)
CompareWithSrc = ignoreLiteralAdditions(SizeCall->getArg(0), Context);
}
}
@@ -3838,7 +4400,7 @@ void Sema::CheckStrlcpycatArguments(const CallExpr *Call,
SmallString<128> sizeString;
llvm::raw_svector_ostream OS(sizeString);
OS << "sizeof(";
- DstArg->printPretty(OS, 0, getPrintingPolicy());
+ DstArg->printPretty(OS, nullptr, getPrintingPolicy());
OS << ")";
Diag(OriginalSizeArg->getLocStart(), diag::note_strlcpycat_wrong_size)
@@ -3858,10 +4420,10 @@ static const Expr *getStrlenExprArg(const Expr *E) {
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
const FunctionDecl *FD = CE->getDirectCallee();
if (!FD || FD->getMemoryFunctionKind() != Builtin::BIstrlen)
- return 0;
+ return nullptr;
return CE->getArg(0)->IgnoreParenCasts();
}
- return 0;
+ return nullptr;
}
// Warn on anti-patterns as the 'size' argument to strncat.
@@ -3876,6 +4438,10 @@ void Sema::CheckStrncatArguments(const CallExpr *CE,
const Expr *SrcArg = CE->getArg(1)->IgnoreParenCasts();
const Expr *LenArg = CE->getArg(2)->IgnoreParenCasts();
+ if (CheckMemorySizeofForComparison(*this, LenArg, FnName, CE->getLocStart(),
+ CE->getRParenLoc()))
+ return;
+
// Identify common expressions, which are wrongly used as the size argument
// to strncat and may lead to buffer overflows.
unsigned PatternType = 0;
@@ -3906,7 +4472,7 @@ void Sema::CheckStrncatArguments(const CallExpr *CE,
// Generate the diagnostic.
SourceLocation SL = LenArg->getLocStart();
SourceRange SR = LenArg->getSourceRange();
- SourceManager &SM = PP.getSourceManager();
+ SourceManager &SM = getSourceManager();
// If the function is defined as a builtin macro, do not show macro expansion.
if (SM.isMacroArgExpansion(SL)) {
@@ -3935,10 +4501,10 @@ void Sema::CheckStrncatArguments(const CallExpr *CE,
SmallString<128> sizeString;
llvm::raw_svector_ostream OS(sizeString);
OS << "sizeof(";
- DstArg->printPretty(OS, 0, getPrintingPolicy());
+ DstArg->printPretty(OS, nullptr, getPrintingPolicy());
OS << ") - ";
OS << "strlen(";
- DstArg->printPretty(OS, 0, getPrintingPolicy());
+ DstArg->printPretty(OS, nullptr, getPrintingPolicy());
OS << ") - 1";
Diag(SL, diag::note_strncat_wrong_size)
@@ -3954,23 +4520,23 @@ static Expr *EvalAddr(Expr* E, SmallVectorImpl<DeclRefExpr *> &refVars,
/// CheckReturnStackAddr - Check if a return statement returns the address
/// of a stack variable.
-void
-Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
- SourceLocation ReturnLoc) {
+static void
+CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType,
+ SourceLocation ReturnLoc) {
- Expr *stackE = 0;
+ Expr *stackE = nullptr;
SmallVector<DeclRefExpr *, 8> refVars;
// Perform checking for returned stack addresses, local blocks,
// label addresses or references to temporaries.
if (lhsType->isPointerType() ||
- (!getLangOpts().ObjCAutoRefCount && lhsType->isBlockPointerType())) {
- stackE = EvalAddr(RetValExp, refVars, /*ParentDecl=*/0);
+ (!S.getLangOpts().ObjCAutoRefCount && lhsType->isBlockPointerType())) {
+ stackE = EvalAddr(RetValExp, refVars, /*ParentDecl=*/nullptr);
} else if (lhsType->isReferenceType()) {
- stackE = EvalVal(RetValExp, refVars, /*ParentDecl=*/0);
+ stackE = EvalVal(RetValExp, refVars, /*ParentDecl=*/nullptr);
}
- if (stackE == 0)
+ if (!stackE)
return; // Nothing suspicious was found.
SourceLocation diagLoc;
@@ -3988,16 +4554,16 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
}
if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(stackE)) { //address of local var.
- Diag(diagLoc, lhsType->isReferenceType() ? diag::warn_ret_stack_ref
+ S.Diag(diagLoc, lhsType->isReferenceType() ? diag::warn_ret_stack_ref
: diag::warn_ret_stack_addr)
<< DR->getDecl()->getDeclName() << diagRange;
} else if (isa<BlockExpr>(stackE)) { // local block.
- Diag(diagLoc, diag::err_ret_local_block) << diagRange;
+ S.Diag(diagLoc, diag::err_ret_local_block) << diagRange;
} else if (isa<AddrLabelExpr>(stackE)) { // address of label.
- Diag(diagLoc, diag::warn_ret_addr_label) << diagRange;
+ S.Diag(diagLoc, diag::warn_ret_addr_label) << diagRange;
} else { // local temporary.
- Diag(diagLoc, lhsType->isReferenceType() ? diag::warn_ret_local_temp_ref
- : diag::warn_ret_local_temp_addr)
+ S.Diag(diagLoc, lhsType->isReferenceType() ? diag::warn_ret_local_temp_ref
+ : diag::warn_ret_local_temp_addr)
<< diagRange;
}
@@ -4010,8 +4576,8 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
// show the range of the expression.
SourceRange range = (i < e-1) ? refVars[i+1]->getSourceRange()
: stackE->getSourceRange();
- Diag(VD->getLocation(), diag::note_ref_var_local_bind)
- << VD->getDeclName() << range;
+ S.Diag(VD->getLocation(), diag::note_ref_var_local_bind)
+ << VD->getDeclName() << range;
}
}
@@ -4044,7 +4610,7 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
Decl *ParentDecl) {
if (E->isTypeDependent())
- return NULL;
+ return nullptr;
// We should only be called for evaluating pointer expressions.
assert((E->getType()->isAnyPointerType() ||
@@ -4061,6 +4627,10 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
case Stmt::DeclRefExprClass: {
DeclRefExpr *DR = cast<DeclRefExpr>(E);
+ // If we leave the immediate function, the lifetime isn't about to end.
+ if (DR->refersToEnclosingLocal())
+ return nullptr;
+
if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl()))
// If this is a reference variable, follow through to the expression that
// it points to.
@@ -4071,7 +4641,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
return EvalAddr(V->getInit(), refVars, ParentDecl);
}
- return NULL;
+ return nullptr;
}
case Stmt::UnaryOperatorClass: {
@@ -4082,7 +4652,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
if (U->getOpcode() == UO_AddrOf)
return EvalVal(U->getSubExpr(), refVars, ParentDecl);
else
- return NULL;
+ return nullptr;
}
case Stmt::BinaryOperatorClass: {
@@ -4092,7 +4662,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
BinaryOperatorKind op = B->getOpcode();
if (op != BO_Add && op != BO_Sub)
- return NULL;
+ return nullptr;
Expr *Base = B->getLHS();
@@ -4110,24 +4680,25 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
ConditionalOperator *C = cast<ConditionalOperator>(E);
// Handle the GNU extension for missing LHS.
- if (Expr *lhsExpr = C->getLHS()) {
- // In C++, we can have a throw-expression, which has 'void' type.
- if (!lhsExpr->getType()->isVoidType())
- if (Expr* LHS = EvalAddr(lhsExpr, refVars, ParentDecl))
+ // FIXME: That isn't a ConditionalOperator, so doesn't get here.
+ if (Expr *LHSExpr = C->getLHS()) {
+ // In C++, we can have a throw-expression, which has 'void' type.
+ if (!LHSExpr->getType()->isVoidType())
+ if (Expr *LHS = EvalAddr(LHSExpr, refVars, ParentDecl))
return LHS;
}
// In C++, we can have a throw-expression, which has 'void' type.
if (C->getRHS()->getType()->isVoidType())
- return NULL;
+ return nullptr;
return EvalAddr(C->getRHS(), refVars, ParentDecl);
}
-
+
case Stmt::BlockExprClass:
if (cast<BlockExpr>(E)->getBlockDecl()->hasCaptures())
return E; // local block.
- return NULL;
+ return nullptr;
case Stmt::AddrLabelExprClass:
return E; // address of label.
@@ -4148,7 +4719,6 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
case Stmt::CXXReinterpretCastExprClass: {
Expr* SubExpr = cast<CastExpr>(E)->getSubExpr();
switch (cast<CastExpr>(E)->getCastKind()) {
- case CK_BitCast:
case CK_LValueToRValue:
case CK_NoOp:
case CK_BaseToDerived:
@@ -4163,8 +4733,16 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
case CK_ArrayToPointerDecay:
return EvalVal(SubExpr, refVars, ParentDecl);
+ case CK_BitCast:
+ if (SubExpr->getType()->isAnyPointerType() ||
+ SubExpr->getType()->isBlockPointerType() ||
+ SubExpr->getType()->isObjCQualifiedIdType())
+ return EvalAddr(SubExpr, refVars, ParentDecl);
+ else
+ return nullptr;
+
default:
- return 0;
+ return nullptr;
}
}
@@ -4178,7 +4756,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
// Everything else: we simply don't reason about them.
default:
- return NULL;
+ return nullptr;
}
}
@@ -4204,7 +4782,7 @@ do {
E = IE->getSubExpr();
continue;
}
- return NULL;
+ return nullptr;
}
case Stmt::ExprWithCleanupsClass:
@@ -4216,6 +4794,10 @@ do {
// local storage within the function, and if so, return the expression.
DeclRefExpr *DR = cast<DeclRefExpr>(E);
+ // If we leave the immediate function, the lifetime isn't about to end.
+ if (DR->refersToEnclosingLocal())
+ return nullptr;
+
if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) {
// Check if it refers to itself, e.g. "int& i = i;".
if (V == ParentDecl)
@@ -4235,7 +4817,7 @@ do {
}
}
- return NULL;
+ return nullptr;
}
case Stmt::UnaryOperatorClass: {
@@ -4247,7 +4829,7 @@ do {
if (U->getOpcode() == UO_Deref)
return EvalAddr(U->getSubExpr(), refVars, ParentDecl);
- return NULL;
+ return nullptr;
}
case Stmt::ArraySubscriptExprClass: {
@@ -4263,9 +4845,16 @@ do {
ConditionalOperator *C = cast<ConditionalOperator>(E);
// Handle the GNU extension for missing LHS.
- if (Expr *lhsExpr = C->getLHS())
- if (Expr *LHS = EvalVal(lhsExpr, refVars, ParentDecl))
- return LHS;
+ if (Expr *LHSExpr = C->getLHS()) {
+ // In C++, we can have a throw-expression, which has 'void' type.
+ if (!LHSExpr->getType()->isVoidType())
+ if (Expr *LHS = EvalVal(LHSExpr, refVars, ParentDecl))
+ return LHS;
+ }
+
+ // In C++, we can have a throw-expression, which has 'void' type.
+ if (C->getRHS()->getType()->isVoidType())
+ return nullptr;
return EvalVal(C->getRHS(), refVars, ParentDecl);
}
@@ -4276,12 +4865,12 @@ do {
// Check for indirect access. We only want direct field accesses.
if (M->isArrow())
- return NULL;
+ return nullptr;
// Check whether the member type is itself a reference, in which case
// we're not going to refer to the member, but to what the member refers to.
if (M->getMemberDecl()->getType()->isReferenceType())
- return NULL;
+ return nullptr;
return EvalVal(M->getBase(), refVars, ParentDecl);
}
@@ -4301,11 +4890,43 @@ do {
return E;
// Everything else: we simply don't reason about them.
- return NULL;
+ return nullptr;
}
} while (true);
}
+void
+Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType,
+ SourceLocation ReturnLoc,
+ bool isObjCMethod,
+ const AttrVec *Attrs,
+ const FunctionDecl *FD) {
+ CheckReturnStackAddr(*this, RetValExp, lhsType, ReturnLoc);
+
+ // Check if the return value is null but should not be.
+ if (Attrs && hasSpecificAttr<ReturnsNonNullAttr>(*Attrs) &&
+ CheckNonNullExpr(*this, RetValExp))
+ Diag(ReturnLoc, diag::warn_null_ret)
+ << (isObjCMethod ? 1 : 0) << RetValExp->getSourceRange();
+
+ // C++11 [basic.stc.dynamic.allocation]p4:
+ // If an allocation function declared with a non-throwing
+ // exception-specification fails to allocate storage, it shall return
+ // a null pointer. Any other allocation function that fails to allocate
+ // storage shall indicate failure only by throwing an exception [...]
+ if (FD) {
+ OverloadedOperatorKind Op = FD->getOverloadedOperator();
+ if (Op == OO_New || Op == OO_Array_New) {
+ const FunctionProtoType *Proto
+ = FD->getType()->castAs<FunctionProtoType>();
+ if (!Proto->isNothrow(Context, /*ResultIfDependent*/true) &&
+ CheckNonNullExpr(*this, RetValExp))
+ Diag(ReturnLoc, diag::warn_operator_new_returns_null)
+ << FD << getLangOpts().CPlusPlus11;
+ }
+ }
+}
+
//===--- CHECK: Floating-Point comparisons (-Wfloat-equal) ---------------===//
/// Check for comparisons of floating point operands using != and ==.
@@ -4338,11 +4959,11 @@ void Sema::CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr *RHS) {
// Check for comparisons with builtin types.
if (CallExpr* CL = dyn_cast<CallExpr>(LeftExprSansParen))
- if (CL->isBuiltinCall())
+ if (CL->getBuiltinCallee())
return;
if (CallExpr* CR = dyn_cast<CallExpr>(RightExprSansParen))
- if (CR->isBuiltinCall())
+ if (CR->getBuiltinCallee())
return;
// Emit the diagnostic.
@@ -4387,6 +5008,8 @@ struct IntRange {
T = VT->getElementType().getTypePtr();
if (const ComplexType *CT = dyn_cast<ComplexType>(T))
T = CT->getElementType().getTypePtr();
+ if (const AtomicType *AT = dyn_cast<AtomicType>(T))
+ T = AT->getValueType().getTypePtr();
// For enum types, use the known bit width of the enumerators.
if (const EnumType *ET = dyn_cast<EnumType>(T)) {
@@ -4422,6 +5045,8 @@ struct IntRange {
T = VT->getElementType().getTypePtr();
if (const ComplexType *CT = dyn_cast<ComplexType>(T))
T = CT->getElementType().getTypePtr();
+ if (const AtomicType *AT = dyn_cast<AtomicType>(T))
+ T = AT->getValueType().getTypePtr();
if (const EnumType *ET = dyn_cast<EnumType>(T))
T = C.getCanonicalType(ET->getDecl()->getIntegerType()).getTypePtr();
@@ -4821,95 +5446,189 @@ static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E,
if (!S.ActiveTemplateInstantiations.empty())
return;
+ // TODO: Investigate using GetExprRange() to get tighter bounds
+ // on the bit ranges.
+ QualType OtherT = Other->getType();
+ if (const AtomicType *AT = dyn_cast<AtomicType>(OtherT))
+ OtherT = AT->getValueType();
+ IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
+ unsigned OtherWidth = OtherRange.Width;
+
+ bool OtherIsBooleanType = Other->isKnownToHaveBooleanValue();
+
// 0 values are handled later by CheckTrivialUnsignedComparison().
- if (Value == 0)
+ if ((Value == 0) && (!OtherIsBooleanType))
return;
BinaryOperatorKind op = E->getOpcode();
- QualType OtherT = Other->getType();
- QualType ConstantT = Constant->getType();
- QualType CommonT = E->getLHS()->getType();
- if (S.Context.hasSameUnqualifiedType(OtherT, ConstantT))
- return;
- assert((OtherT->isIntegerType() && ConstantT->isIntegerType())
- && "comparison with non-integer type");
+ bool IsTrue = true;
+
+ // Used for diagnostic printout.
+ enum {
+ LiteralConstant = 0,
+ CXXBoolLiteralTrue,
+ CXXBoolLiteralFalse
+ } LiteralOrBoolConstant = LiteralConstant;
- bool ConstantSigned = ConstantT->isSignedIntegerType();
- bool CommonSigned = CommonT->isSignedIntegerType();
+ if (!OtherIsBooleanType) {
+ QualType ConstantT = Constant->getType();
+ QualType CommonT = E->getLHS()->getType();
- bool EqualityOnly = false;
+ if (S.Context.hasSameUnqualifiedType(OtherT, ConstantT))
+ return;
+ assert((OtherT->isIntegerType() && ConstantT->isIntegerType()) &&
+ "comparison with non-integer type");
- // TODO: Investigate using GetExprRange() to get tighter bounds on
- // on the bit ranges.
- IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
- unsigned OtherWidth = OtherRange.Width;
-
- if (CommonSigned) {
- // The common type is signed, therefore no signed to unsigned conversion.
- if (!OtherRange.NonNegative) {
- // Check that the constant is representable in type OtherT.
- if (ConstantSigned) {
- if (OtherWidth >= Value.getMinSignedBits())
- return;
- } else { // !ConstantSigned
- if (OtherWidth >= Value.getActiveBits() + 1)
- return;
+ bool ConstantSigned = ConstantT->isSignedIntegerType();
+ bool CommonSigned = CommonT->isSignedIntegerType();
+
+ bool EqualityOnly = false;
+
+ if (CommonSigned) {
+ // The common type is signed, therefore no signed to unsigned conversion.
+ if (!OtherRange.NonNegative) {
+ // Check that the constant is representable in type OtherT.
+ if (ConstantSigned) {
+ if (OtherWidth >= Value.getMinSignedBits())
+ return;
+ } else { // !ConstantSigned
+ if (OtherWidth >= Value.getActiveBits() + 1)
+ return;
+ }
+ } else { // !OtherSigned
+ // Check that the constant is representable in type OtherT.
+ // Negative values are out of range.
+ if (ConstantSigned) {
+ if (Value.isNonNegative() && OtherWidth >= Value.getActiveBits())
+ return;
+ } else { // !ConstantSigned
+ if (OtherWidth >= Value.getActiveBits())
+ return;
+ }
}
- } else { // !OtherSigned
- // Check that the constant is representable in type OtherT.
- // Negative values are out of range.
- if (ConstantSigned) {
- if (Value.isNonNegative() && OtherWidth >= Value.getActiveBits())
- return;
- } else { // !ConstantSigned
+ } else { // !CommonSigned
+ if (OtherRange.NonNegative) {
if (OtherWidth >= Value.getActiveBits())
return;
+ } else { // OtherSigned
+ assert(!ConstantSigned &&
+ "Two signed types converted to unsigned types.");
+ // Check to see if the constant is representable in OtherT.
+ if (OtherWidth > Value.getActiveBits())
+ return;
+ // Check to see if the constant is equivalent to a negative value
+ // cast to CommonT.
+ if (S.Context.getIntWidth(ConstantT) ==
+ S.Context.getIntWidth(CommonT) &&
+ Value.isNegative() && Value.getMinSignedBits() <= OtherWidth)
+ return;
+ // The constant value rests between values that OtherT can represent
+ // after conversion. Relational comparison still works, but equality
+ // comparisons will be tautological.
+ EqualityOnly = true;
}
}
- } else { // !CommonSigned
- if (OtherRange.NonNegative) {
- if (OtherWidth >= Value.getActiveBits())
- return;
- } else if (!OtherRange.NonNegative && !ConstantSigned) {
- // Check to see if the constant is representable in OtherT.
- if (OtherWidth > Value.getActiveBits())
- return;
- // Check to see if the constant is equivalent to a negative value
- // cast to CommonT.
- if (S.Context.getIntWidth(ConstantT) == S.Context.getIntWidth(CommonT) &&
- Value.isNegative() && Value.getMinSignedBits() <= OtherWidth)
- return;
- // The constant value rests between values that OtherT can represent after
- // conversion. Relational comparison still works, but equality
- // comparisons will be tautological.
- EqualityOnly = true;
- } else { // OtherSigned && ConstantSigned
- assert(0 && "Two signed types converted to unsigned types.");
- }
- }
- bool PositiveConstant = !ConstantSigned || Value.isNonNegative();
+ bool PositiveConstant = !ConstantSigned || Value.isNonNegative();
- bool IsTrue = true;
- if (op == BO_EQ || op == BO_NE) {
- IsTrue = op == BO_NE;
- } else if (EqualityOnly) {
- return;
- } else if (RhsConstant) {
- if (op == BO_GT || op == BO_GE)
- IsTrue = !PositiveConstant;
- else // op == BO_LT || op == BO_LE
- IsTrue = PositiveConstant;
+ if (op == BO_EQ || op == BO_NE) {
+ IsTrue = op == BO_NE;
+ } else if (EqualityOnly) {
+ return;
+ } else if (RhsConstant) {
+ if (op == BO_GT || op == BO_GE)
+ IsTrue = !PositiveConstant;
+ else // op == BO_LT || op == BO_LE
+ IsTrue = PositiveConstant;
+ } else {
+ if (op == BO_LT || op == BO_LE)
+ IsTrue = !PositiveConstant;
+ else // op == BO_GT || op == BO_GE
+ IsTrue = PositiveConstant;
+ }
} else {
- if (op == BO_LT || op == BO_LE)
- IsTrue = !PositiveConstant;
- else // op == BO_GT || op == BO_GE
- IsTrue = PositiveConstant;
+ // Other isKnownToHaveBooleanValue
+ enum CompareBoolWithConstantResult { AFals, ATrue, Unkwn };
+ enum ConstantValue { LT_Zero, Zero, One, GT_One, SizeOfConstVal };
+ enum ConstantSide { Lhs, Rhs, SizeOfConstSides };
+
+ static const struct LinkedConditions {
+ CompareBoolWithConstantResult BO_LT_OP[SizeOfConstSides][SizeOfConstVal];
+ CompareBoolWithConstantResult BO_GT_OP[SizeOfConstSides][SizeOfConstVal];
+ CompareBoolWithConstantResult BO_LE_OP[SizeOfConstSides][SizeOfConstVal];
+ CompareBoolWithConstantResult BO_GE_OP[SizeOfConstSides][SizeOfConstVal];
+ CompareBoolWithConstantResult BO_EQ_OP[SizeOfConstSides][SizeOfConstVal];
+ CompareBoolWithConstantResult BO_NE_OP[SizeOfConstSides][SizeOfConstVal];
+
+ } TruthTable = {
+ // Constant on LHS. | Constant on RHS. |
+ // LT_Zero| Zero | One |GT_One| LT_Zero| Zero | One |GT_One|
+ { { ATrue, Unkwn, AFals, AFals }, { AFals, AFals, Unkwn, ATrue } },
+ { { AFals, AFals, Unkwn, ATrue }, { ATrue, Unkwn, AFals, AFals } },
+ { { ATrue, ATrue, Unkwn, AFals }, { AFals, Unkwn, ATrue, ATrue } },
+ { { AFals, Unkwn, ATrue, ATrue }, { ATrue, ATrue, Unkwn, AFals } },
+ { { AFals, Unkwn, Unkwn, AFals }, { AFals, Unkwn, Unkwn, AFals } },
+ { { ATrue, Unkwn, Unkwn, ATrue }, { ATrue, Unkwn, Unkwn, ATrue } }
+ };
+
+ bool ConstantIsBoolLiteral = isa<CXXBoolLiteralExpr>(Constant);
+
+ enum ConstantValue ConstVal = Zero;
+ if (Value.isUnsigned() || Value.isNonNegative()) {
+ if (Value == 0) {
+ LiteralOrBoolConstant =
+ ConstantIsBoolLiteral ? CXXBoolLiteralFalse : LiteralConstant;
+ ConstVal = Zero;
+ } else if (Value == 1) {
+ LiteralOrBoolConstant =
+ ConstantIsBoolLiteral ? CXXBoolLiteralTrue : LiteralConstant;
+ ConstVal = One;
+ } else {
+ LiteralOrBoolConstant = LiteralConstant;
+ ConstVal = GT_One;
+ }
+ } else {
+ ConstVal = LT_Zero;
+ }
+
+ CompareBoolWithConstantResult CmpRes;
+
+ switch (op) {
+ case BO_LT:
+ CmpRes = TruthTable.BO_LT_OP[RhsConstant][ConstVal];
+ break;
+ case BO_GT:
+ CmpRes = TruthTable.BO_GT_OP[RhsConstant][ConstVal];
+ break;
+ case BO_LE:
+ CmpRes = TruthTable.BO_LE_OP[RhsConstant][ConstVal];
+ break;
+ case BO_GE:
+ CmpRes = TruthTable.BO_GE_OP[RhsConstant][ConstVal];
+ break;
+ case BO_EQ:
+ CmpRes = TruthTable.BO_EQ_OP[RhsConstant][ConstVal];
+ break;
+ case BO_NE:
+ CmpRes = TruthTable.BO_NE_OP[RhsConstant][ConstVal];
+ break;
+ default:
+ CmpRes = Unkwn;
+ break;
+ }
+
+ if (CmpRes == AFals) {
+ IsTrue = false;
+ } else if (CmpRes == ATrue) {
+ IsTrue = true;
+ } else {
+ return;
+ }
}
// If this is a comparison to an enum constant, include that
// constant in the diagnostic.
- const EnumConstantDecl *ED = 0;
+ const EnumConstantDecl *ED = nullptr;
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Constant))
ED = dyn_cast<EnumConstantDecl>(DR->getDecl());
@@ -4920,9 +5639,12 @@ static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E,
else
OS << Value;
- S.Diag(E->getOperatorLoc(), diag::warn_out_of_range_compare)
- << OS.str() << OtherT << IsTrue
- << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+ S.DiagRuntimeBehavior(
+ E->getOperatorLoc(), E,
+ S.PDiag(diag::warn_out_of_range_compare)
+ << OS.str() << LiteralOrBoolConstant
+ << OtherT << (OtherIsBooleanType && !OtherT->isBooleanType()) << IsTrue
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange());
}
/// Analyze the operands of the given comparison. Implements the
@@ -5211,7 +5933,7 @@ void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall,
}
void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
- SourceLocation CC, bool *ICContext = 0) {
+ SourceLocation CC, bool *ICContext = nullptr) {
if (E->isTypeDependent() || E->isValueDependent()) return;
const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr();
@@ -5231,39 +5953,21 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if (Target->isSpecificBuiltinType(BuiltinType::Bool)) {
if (isa<StringLiteral>(E))
// Warn on string literal to bool. Checks for string literals in logical
- // expressions, for instances, assert(0 && "error here"), is prevented
- // by a check in AnalyzeImplicitConversions().
+ // and expressions, for instance, assert(0 && "error here"), are
+ // prevented by a check in AnalyzeImplicitConversions().
return DiagnoseImpCast(S, E, T, CC,
diag::warn_impcast_string_literal_to_bool);
- if (Source->isFunctionType()) {
- // Warn on function to bool. Checks free functions and static member
- // functions. Weakly imported functions are excluded from the check,
- // since it's common to test their value to check whether the linker
- // found a definition for them.
- ValueDecl *D = 0;
- if (DeclRefExpr* R = dyn_cast<DeclRefExpr>(E)) {
- D = R->getDecl();
- } else if (MemberExpr *M = dyn_cast<MemberExpr>(E)) {
- D = M->getMemberDecl();
- }
-
- if (D && !D->isWeak()) {
- if (FunctionDecl* F = dyn_cast<FunctionDecl>(D)) {
- S.Diag(E->getExprLoc(), diag::warn_impcast_function_to_bool)
- << F << E->getSourceRange() << SourceRange(CC);
- S.Diag(E->getExprLoc(), diag::note_function_to_bool_silence)
- << FixItHint::CreateInsertion(E->getExprLoc(), "&");
- QualType ReturnType;
- UnresolvedSet<4> NonTemplateOverloads;
- S.tryExprAsCall(*E, ReturnType, NonTemplateOverloads);
- if (!ReturnType.isNull()
- && ReturnType->isSpecificBuiltinType(BuiltinType::Bool))
- S.Diag(E->getExprLoc(), diag::note_function_to_bool_call)
- << FixItHint::CreateInsertion(
- S.getPreprocessor().getLocForEndOfToken(E->getLocEnd()), "()");
- return;
- }
- }
+ if (isa<ObjCStringLiteral>(E) || isa<ObjCArrayLiteral>(E) ||
+ isa<ObjCDictionaryLiteral>(E) || isa<ObjCBoxedExpr>(E)) {
+ // This covers the literal expressions that evaluate to Objective-C
+ // objects.
+ return DiagnoseImpCast(S, E, T, CC,
+ diag::warn_impcast_objective_c_literal_to_bool);
+ }
+ if (Source->isPointerType() || Source->canDecayToPointerType()) {
+ // Warn on pointer to bool conversion that is always true.
+ S.DiagnoseAlwaysNonNullPointer(E, Expr::NPCK_NotNull, /*IsEqual*/ false,
+ SourceRange(CC));
}
}
@@ -5283,6 +5987,8 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
Source = cast<VectorType>(Source)->getElementType().getTypePtr();
Target = cast<VectorType>(Target)->getElementType().getTypePtr();
}
+ if (auto VecTy = dyn_cast<VectorType>(Target))
+ Target = VecTy->getElementType().getTypePtr();
// Strip complex types.
if (isa<ComplexType>(Source)) {
@@ -5501,8 +6207,7 @@ void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
if (!Suspicious) return;
// ...but it's currently ignored...
- if (S.Diags.getDiagnosticLevel(diag::warn_impcast_integer_sign_conditional,
- CC))
+ if (!S.Diags.isIgnored(diag::warn_impcast_integer_sign_conditional, CC))
return;
// ...then check whether it would have warned about either of the
@@ -5526,7 +6231,7 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
if (E->isTypeDependent() || E->isValueDependent())
return;
-
+
// For conditional operators, we analyze the arguments as if they
// were being fed directly into the output.
if (isa<ConditionalOperator>(E)) {
@@ -5583,15 +6288,16 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
// Now just recurse over the expression's children.
CC = E->getExprLoc();
BinaryOperator *BO = dyn_cast<BinaryOperator>(E);
- bool IsLogicalOperator = BO && BO->isLogicalOp();
+ bool IsLogicalAndOperator = BO && BO->getOpcode() == BO_LAnd;
for (Stmt::child_range I = E->children(); I; ++I) {
Expr *ChildExpr = dyn_cast_or_null<Expr>(*I);
if (!ChildExpr)
continue;
- if (IsLogicalOperator &&
+ if (IsLogicalAndOperator &&
isa<StringLiteral>(ChildExpr->IgnoreParenImpCasts()))
- // Ignore checking string literals that are in logical operators.
+ // Ignore checking string literals that are in logical and operators.
+ // This is a common pattern for asserts.
continue;
AnalyzeImplicitConversions(S, ChildExpr, CC);
}
@@ -5599,6 +6305,172 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
} // end anonymous namespace
+enum {
+ AddressOf,
+ FunctionPointer,
+ ArrayPointer
+};
+
+// Helper function for Sema::DiagnoseAlwaysNonNullPointer.
+// Returns true when emitting a warning about taking the address of a reference.
+static bool CheckForReference(Sema &SemaRef, const Expr *E,
+ PartialDiagnostic PD) {
+ E = E->IgnoreParenImpCasts();
+
+ const FunctionDecl *FD = nullptr;
+
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (!DRE->getDecl()->getType()->isReferenceType())
+ return false;
+ } else if (const MemberExpr *M = dyn_cast<MemberExpr>(E)) {
+ if (!M->getMemberDecl()->getType()->isReferenceType())
+ return false;
+ } else if (const CallExpr *Call = dyn_cast<CallExpr>(E)) {
+ if (!Call->getCallReturnType()->isReferenceType())
+ return false;
+ FD = Call->getDirectCallee();
+ } else {
+ return false;
+ }
+
+ SemaRef.Diag(E->getExprLoc(), PD);
+
+ // If possible, point to location of function.
+ if (FD) {
+ SemaRef.Diag(FD->getLocation(), diag::note_reference_is_return_value) << FD;
+ }
+
+ return true;
+}
+
+/// \brief Diagnose pointers that are always non-null.
+/// \param E the expression containing the pointer
+/// \param NullKind NPCK_NotNull if E is a cast to bool, otherwise, E is
+/// compared to a null pointer
+/// \param IsEqual True when the comparison is equal to a null pointer
+/// \param Range Extra SourceRange to highlight in the diagnostic
+void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
+ Expr::NullPointerConstantKind NullKind,
+ bool IsEqual, SourceRange Range) {
+ if (!E)
+ return;
+
+ // Don't warn inside macros.
+ if (E->getExprLoc().isMacroID())
+ return;
+ E = E->IgnoreImpCasts();
+
+ const bool IsCompare = NullKind != Expr::NPCK_NotNull;
+
+ if (isa<CXXThisExpr>(E)) {
+ unsigned DiagID = IsCompare ? diag::warn_this_null_compare
+ : diag::warn_this_bool_conversion;
+ Diag(E->getExprLoc(), DiagID) << E->getSourceRange() << Range << IsEqual;
+ return;
+ }
+
+ bool IsAddressOf = false;
+
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ if (UO->getOpcode() != UO_AddrOf)
+ return;
+ IsAddressOf = true;
+ E = UO->getSubExpr();
+ }
+
+ if (IsAddressOf) {
+ unsigned DiagID = IsCompare
+ ? diag::warn_address_of_reference_null_compare
+ : diag::warn_address_of_reference_bool_conversion;
+ PartialDiagnostic PD = PDiag(DiagID) << E->getSourceRange() << Range
+ << IsEqual;
+ if (CheckForReference(*this, E, PD)) {
+ return;
+ }
+ }
+
+ // Expect to find a single Decl. Skip anything more complicated.
+ ValueDecl *D = nullptr;
+ if (DeclRefExpr *R = dyn_cast<DeclRefExpr>(E)) {
+ D = R->getDecl();
+ } else if (MemberExpr *M = dyn_cast<MemberExpr>(E)) {
+ D = M->getMemberDecl();
+ }
+
+ // Weak Decls can be null.
+ if (!D || D->isWeak())
+ return;
+
+ QualType T = D->getType();
+ const bool IsArray = T->isArrayType();
+ const bool IsFunction = T->isFunctionType();
+
+ // Address of function is used to silence the function warning.
+ if (IsAddressOf && IsFunction) {
+ return;
+ }
+
+ // Found nothing.
+ if (!IsAddressOf && !IsFunction && !IsArray)
+ return;
+
+ // Pretty print the expression for the diagnostic.
+ std::string Str;
+ llvm::raw_string_ostream S(Str);
+ E->printPretty(S, nullptr, getPrintingPolicy());
+
+ unsigned DiagID = IsCompare ? diag::warn_null_pointer_compare
+ : diag::warn_impcast_pointer_to_bool;
+ unsigned DiagType;
+ if (IsAddressOf)
+ DiagType = AddressOf;
+ else if (IsFunction)
+ DiagType = FunctionPointer;
+ else if (IsArray)
+ DiagType = ArrayPointer;
+ else
+ llvm_unreachable("Could not determine diagnostic.");
+ Diag(E->getExprLoc(), DiagID) << DiagType << S.str() << E->getSourceRange()
+ << Range << IsEqual;
+
+ if (!IsFunction)
+ return;
+
+ // Suggest '&' to silence the function warning.
+ Diag(E->getExprLoc(), diag::note_function_warning_silence)
+ << FixItHint::CreateInsertion(E->getLocStart(), "&");
+
+ // Check to see if '()' fixit should be emitted.
+ QualType ReturnType;
+ UnresolvedSet<4> NonTemplateOverloads;
+ tryExprAsCall(*E, ReturnType, NonTemplateOverloads);
+ if (ReturnType.isNull())
+ return;
+
+ if (IsCompare) {
+ // There are two cases here. If there is null constant, the only suggest
+ // for a pointer return type. If the null is 0, then suggest if the return
+ // type is a pointer or an integer type.
+ if (!ReturnType->isPointerType()) {
+ if (NullKind == Expr::NPCK_ZeroExpression ||
+ NullKind == Expr::NPCK_ZeroLiteral) {
+ if (!ReturnType->isIntegerType())
+ return;
+ } else {
+ return;
+ }
+ }
+ } else { // !IsCompare
+ // For function to bool, only suggest if the function pointer has bool
+ // return type.
+ if (!ReturnType->isSpecificBuiltinType(BuiltinType::Bool))
+ return;
+ }
+ Diag(E->getExprLoc(), diag::note_function_to_function_call)
+ << FixItHint::CreateInsertion(getLocForEndOfToken(E->getLocEnd()), "()");
+}
+
+
/// Diagnoses "dangerous" implicit conversions within the given
/// expression (which is a full expression). Implements -Wconversion
/// and -Wsign-compare.
@@ -5720,7 +6592,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
};
struct Usage {
- Usage() : Use(0), Seq() {}
+ Usage() : Use(nullptr), Seq() {}
Expr *Use;
SequenceTree::Seq Seq;
};
@@ -5820,7 +6692,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
} else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
// FIXME: If this is a reference, map through to its value.
return DRE->getDecl();
- return 0;
+ return nullptr;
}
/// \brief Note that an object was modified or used by an expression.
@@ -5880,8 +6752,8 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
public:
SequenceChecker(Sema &S, Expr *E, SmallVectorImpl<Expr *> &WorkList)
- : Base(S.Context), SemaRef(S), Region(Tree.root()), ModAsSideEffect(0),
- WorkList(WorkList), EvalTracker(0) {
+ : Base(S.Context), SemaRef(S), Region(Tree.root()),
+ ModAsSideEffect(nullptr), WorkList(WorkList), EvalTracker(nullptr) {
Visit(E);
}
@@ -6166,7 +7038,7 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl *const *P,
// C99 6.9.1p5: If the declarator includes a parameter type list, the
// declaration of each parameter shall include an identifier.
if (CheckParameterNames &&
- Param->getIdentifier() == 0 &&
+ Param->getIdentifier() == nullptr &&
!Param->isImplicit() &&
!getLangOpts().CPlusPlus)
Diag(Param->getLocation(), diag::err_parameter_name_omitted);
@@ -6189,11 +7061,23 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl *const *P,
// MSVC destroys objects passed by value in the callee. Therefore a
// function definition which takes such a parameter must be able to call the
- // object's destructor.
- if (getLangOpts().CPlusPlus &&
- Context.getTargetInfo().getCXXABI().isArgumentDestroyedByCallee()) {
- if (const RecordType *RT = Param->getType()->getAs<RecordType>())
- FinalizeVarWithDestructor(Param, RT);
+ // object's destructor. However, we don't perform any direct access check
+ // on the dtor.
+ if (getLangOpts().CPlusPlus && Context.getTargetInfo()
+ .getCXXABI()
+ .areArgsDestroyedLeftToRightInCallee()) {
+ if (!Param->isInvalidDecl()) {
+ if (const RecordType *RT = Param->getType()->getAs<RecordType>()) {
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (!ClassDecl->isInvalidDecl() &&
+ !ClassDecl->hasIrrelevantDestructor() &&
+ !ClassDecl->isDependentContext()) {
+ CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl);
+ MarkFunctionReferenced(Param->getLocation(), Destructor);
+ DiagnoseUseOfDecl(Destructor, Param->getLocation());
+ }
+ }
+ }
}
}
@@ -6205,9 +7089,7 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl *const *P,
void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) {
// This is actually a lot of work to potentially be doing on every
// cast; don't do it if we're ignoring -Wcast_align (as is the default).
- if (getDiagnostics().getDiagnosticLevel(diag::warn_cast_align,
- TRange.getBegin())
- == DiagnosticsEngine::Ignored)
+ if (getDiagnostics().isIgnored(diag::warn_cast_align, TRange.getBegin()))
return;
// Ignore dependent types.
@@ -6321,7 +7203,7 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
if (IndexNegated)
index = -index;
- const NamedDecl *ND = NULL;
+ const NamedDecl *ND = nullptr;
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
ND = dyn_cast<NamedDecl>(DRE->getDecl());
if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr))
@@ -6464,7 +7346,7 @@ void Sema::CheckArrayAccess(const Expr *expr) {
namespace {
struct RetainCycleOwner {
- RetainCycleOwner() : Variable(0), Indirect(false) {}
+ RetainCycleOwner() : Variable(nullptr), Indirect(false) {}
VarDecl *Variable;
SourceRange Range;
SourceLocation Loc;
@@ -6575,10 +7457,12 @@ namespace {
struct FindCaptureVisitor : EvaluatedExprVisitor<FindCaptureVisitor> {
FindCaptureVisitor(ASTContext &Context, VarDecl *variable)
: EvaluatedExprVisitor<FindCaptureVisitor>(Context),
- Variable(variable), Capturer(0) {}
-
+ Context(Context), Variable(variable), Capturer(nullptr),
+ VarWillBeReased(false) {}
+ ASTContext &Context;
VarDecl *Variable;
Expr *Capturer;
+ bool VarWillBeReased;
void VisitDeclRefExpr(DeclRefExpr *ref) {
if (ref->getDecl() == Variable && !Capturer)
@@ -6603,6 +7487,21 @@ namespace {
if (OVE->getSourceExpr())
Visit(OVE->getSourceExpr());
}
+ void VisitBinaryOperator(BinaryOperator *BinOp) {
+ if (!Variable || VarWillBeReased || BinOp->getOpcode() != BO_Assign)
+ return;
+ Expr *LHS = BinOp->getLHS();
+ if (const DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(LHS)) {
+ if (DRE->getDecl() != Variable)
+ return;
+ if (Expr *RHS = BinOp->getRHS()) {
+ RHS = RHS->IgnoreParenCasts();
+ llvm::APSInt Value;
+ VarWillBeReased =
+ (RHS && RHS->isIntegerConstantExpr(Value, Context) && Value == 0);
+ }
+ }
+ }
};
}
@@ -6619,7 +7518,7 @@ static Expr *findCapturingExpr(Sema &S, Expr *e, RetainCycleOwner &owner) {
if (Cmd.isUnarySelector() && Cmd.getNameForSlot(0) == "copy") {
e = ME->getInstanceReceiver();
if (!e)
- return 0;
+ return nullptr;
e = e->IgnoreParenCasts();
}
} else if (CallExpr *CE = dyn_cast<CallExpr>(e)) {
@@ -6636,11 +7535,11 @@ static Expr *findCapturingExpr(Sema &S, Expr *e, RetainCycleOwner &owner) {
BlockExpr *block = dyn_cast<BlockExpr>(e);
if (!block || !block->getBlockDecl()->capturesVariable(owner.Variable))
- return 0;
+ return nullptr;
FindCaptureVisitor visitor(S.Context, owner.Variable);
visitor.Visit(block->getBlockDecl()->getBody());
- return visitor.Capturer;
+ return visitor.VarWillBeReased ? nullptr : visitor.Capturer;
}
static void diagnoseRetainCycle(Sema &S, Expr *capturer,
@@ -6712,7 +7611,7 @@ void Sema::checkRetainCycles(Expr *receiver, Expr *argument) {
void Sema::checkRetainCycles(VarDecl *Var, Expr *Init) {
RetainCycleOwner Owner;
- if (!considerVariable(Var, /*DeclRefExpr=*/0, Owner))
+ if (!considerVariable(Var, /*DeclRefExpr=*/nullptr, Owner))
return;
// Because we don't have an expression for the variable, we have to set the
@@ -6784,7 +7683,7 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
Expr *LHS, Expr *RHS) {
QualType LHSType;
// PropertyRef on LHS type need be directly obtained from
- // its declaration as it has a PsuedoType.
+ // its declaration as it has a PseudoType.
ObjCPropertyRefExpr *PRE
= dyn_cast<ObjCPropertyRefExpr>(LHS->IgnoreParens());
if (PRE && !PRE->isImplicitProperty()) {
@@ -6799,9 +7698,7 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime();
if (LT == Qualifiers::OCL_Weak) {
- DiagnosticsEngine::Level Level =
- Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, Loc);
- if (Level != DiagnosticsEngine::Ignored)
+ if (!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
getCurFunction()->markSafeWeakUse(LHS);
}
@@ -6926,8 +7823,7 @@ void Sema::DiagnoseEmptyLoopBody(const Stmt *S,
return;
// Skip expensive checks if diagnostic is disabled.
- if (Diags.getDiagnosticLevel(DiagID, NBody->getSemiLoc()) ==
- DiagnosticsEngine::Ignored)
+ if (Diags.isIgnored(DiagID, NBody->getSemiLoc()))
return;
// Do the usual checks.
@@ -7057,21 +7953,16 @@ bool isLayoutCompatibleUnion(ASTContext &C,
RecordDecl *RD1,
RecordDecl *RD2) {
llvm::SmallPtrSet<FieldDecl *, 8> UnmatchedFields;
- for (RecordDecl::field_iterator Field2 = RD2->field_begin(),
- Field2End = RD2->field_end();
- Field2 != Field2End; ++Field2) {
- UnmatchedFields.insert(*Field2);
- }
+ for (auto *Field2 : RD2->fields())
+ UnmatchedFields.insert(Field2);
- for (RecordDecl::field_iterator Field1 = RD1->field_begin(),
- Field1End = RD1->field_end();
- Field1 != Field1End; ++Field1) {
+ for (auto *Field1 : RD1->fields()) {
llvm::SmallPtrSet<FieldDecl *, 8>::iterator
I = UnmatchedFields.begin(),
E = UnmatchedFields.end();
for ( ; I != E; ++I) {
- if (isLayoutCompatible(C, *Field1, *I)) {
+ if (isLayoutCompatible(C, Field1, *I)) {
bool Result = UnmatchedFields.erase(*I);
(void) Result;
assert(Result);
@@ -7228,7 +8119,7 @@ bool GetMatchingCType(
FoundWrongKind = false;
// Variable declaration that has type_tag_for_datatype attribute.
- const ValueDecl *VD = NULL;
+ const ValueDecl *VD = nullptr;
uint64_t MagicValue;
@@ -7236,10 +8127,7 @@ bool GetMatchingCType(
return false;
if (VD) {
- for (specific_attr_iterator<TypeTagForDatatypeAttr>
- I = VD->specific_attr_begin<TypeTagForDatatypeAttr>(),
- E = VD->specific_attr_end<TypeTagForDatatypeAttr>();
- I != E; ++I) {
+ if (TypeTagForDatatypeAttr *I = VD->getAttr<TypeTagForDatatypeAttr>()) {
if (I->getArgumentKind() != ArgumentKind) {
FoundWrongKind = true;
return false;
@@ -7372,8 +8260,9 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
if (mismatch)
Diag(ArgumentExpr->getExprLoc(), diag::warn_type_safety_type_mismatch)
- << ArgumentType << ArgumentKind->getName()
+ << ArgumentType << ArgumentKind
<< TypeInfo.LayoutCompatible << RequiredType
<< ArgumentExpr->getSourceRange()
<< TypeTagExpr->getSourceRange();
}
+
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 7a1b36b2d7ee..3d250e3bef11 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -104,7 +104,7 @@ namespace {
if (DeclIndexPairVector *Vec
= DeclOrVector.dyn_cast<DeclIndexPairVector *>()) {
delete Vec;
- DeclOrVector = ((NamedDecl *)0);
+ DeclOrVector = ((NamedDecl *)nullptr);
}
}
@@ -172,12 +172,12 @@ namespace {
explicit ResultBuilder(Sema &SemaRef, CodeCompletionAllocator &Allocator,
CodeCompletionTUInfo &CCTUInfo,
const CodeCompletionContext &CompletionContext,
- LookupFilter Filter = 0)
+ LookupFilter Filter = nullptr)
: SemaRef(SemaRef), Allocator(Allocator), CCTUInfo(CCTUInfo),
Filter(Filter),
AllowNestedNameSpecifiers(false), HasObjectTypeQualifiers(false),
CompletionContext(CompletionContext),
- ObjCImplementation(0)
+ ObjCImplementation(nullptr)
{
// If this is an Objective-C instance method definition, dig out the
// corresponding implementation.
@@ -212,8 +212,8 @@ namespace {
void setFilter(LookupFilter Filter) {
this->Filter = Filter;
}
-
- Result *data() { return Results.empty()? 0 : &Results.front(); }
+
+ Result *data() { return Results.empty()? nullptr : &Results.front(); }
unsigned size() const { return Results.size(); }
bool empty() const { return Results.empty(); }
@@ -289,8 +289,8 @@ namespace {
/// \param R the result to add (if it is unique).
///
/// \param CurContext the context in which this result will be named.
- void MaybeAddResult(Result R, DeclContext *CurContext = 0);
-
+ void MaybeAddResult(Result R, DeclContext *CurContext = nullptr);
+
/// \brief Add a new result to this result set, where we already know
/// the hiding declation (if any).
///
@@ -364,8 +364,8 @@ public:
return &Value;
}
};
-
- iterator() : DeclOrIterator((NamedDecl *)0), SingleDeclIndex(0) { }
+
+ iterator() : DeclOrIterator((NamedDecl *)nullptr), SingleDeclIndex(0) {}
iterator(const NamedDecl *SingleDecl, unsigned Index)
: DeclOrIterator(SingleDecl), SingleDeclIndex(Index) { }
@@ -375,7 +375,7 @@ public:
iterator &operator++() {
if (DeclOrIterator.is<const NamedDecl *>()) {
- DeclOrIterator = (NamedDecl *)0;
+ DeclOrIterator = (NamedDecl *)nullptr;
SingleDeclIndex = 0;
return *this;
}
@@ -461,8 +461,8 @@ getRequiredQualification(ASTContext &Context,
TargetParents.push_back(CommonAncestor);
}
-
- NestedNameSpecifier *Result = 0;
+
+ NestedNameSpecifier *Result = nullptr;
while (!TargetParents.empty()) {
const DeclContext *Parent = TargetParents.pop_back_val();
@@ -480,6 +480,16 @@ getRequiredQualification(ASTContext &Context,
return Result;
}
+/// Determine whether \p Id is a name reserved for the implementation (C99
+/// 7.1.3, C++ [lib.global.names]).
+static bool isReservedName(const IdentifierInfo *Id) {
+ if (Id->getLength() < 2)
+ return false;
+ const char *Name = Id->getNameStart();
+ return Name[0] == '_' &&
+ (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z'));
+}
+
bool ResultBuilder::isInterestingDecl(const NamedDecl *ND,
bool &AsNestedNameSpecifier) const {
AsNestedNameSpecifier = false;
@@ -506,31 +516,21 @@ bool ResultBuilder::isInterestingDecl(const NamedDecl *ND,
return false;
// Some declarations have reserved names that we don't want to ever show.
- if (const IdentifierInfo *Id = ND->getIdentifier()) {
- // __va_list_tag is a freak of nature. Find it and skip it.
- if (Id->isStr("__va_list_tag") || Id->isStr("__builtin_va_list"))
- return false;
-
- // Filter out names reserved for the implementation (C99 7.1.3,
- // C++ [lib.global.names]) if they come from a system header.
- //
- // FIXME: Add predicate for this.
- if (Id->getLength() >= 2) {
- const char *Name = Id->getNameStart();
- if (Name[0] == '_' &&
- (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z')) &&
- (ND->getLocation().isInvalid() ||
- SemaRef.SourceMgr.isInSystemHeader(
- SemaRef.SourceMgr.getSpellingLoc(ND->getLocation()))))
+ // Filter out names reserved for the implementation if they come from a
+ // system header.
+ // TODO: Add a predicate for this.
+ if (const IdentifierInfo *Id = ND->getIdentifier())
+ if (isReservedName(Id) &&
+ (ND->getLocation().isInvalid() ||
+ SemaRef.SourceMgr.isInSystemHeader(
+ SemaRef.SourceMgr.getSpellingLoc(ND->getLocation()))))
return false;
- }
- }
if (Filter == &ResultBuilder::IsNestedNameSpecifier ||
((isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND)) &&
Filter != &ResultBuilder::IsNamespace &&
Filter != &ResultBuilder::IsNamespaceOrAlias &&
- Filter != 0))
+ Filter != nullptr))
AsNestedNameSpecifier = true;
// Filter out any unwanted results.
@@ -660,13 +660,10 @@ QualType clang::getDeclUsageType(ASTContext &C, const NamedDecl *ND) {
return C.getObjCInterfaceType(Iface);
QualType T;
- if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(ND))
+ if (const FunctionDecl *Function = ND->getAsFunction())
T = Function->getCallResultType();
else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
T = Method->getSendResultType();
- else if (const FunctionTemplateDecl *FunTmpl =
- dyn_cast<FunctionTemplateDecl>(ND))
- T = FunTmpl->getTemplatedDecl()->getCallResultType();
else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND))
T = C.getTypeDeclType(cast<EnumDecl>(Enumerator->getDeclContext()));
else if (const ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
@@ -700,7 +697,7 @@ QualType clang::getDeclUsageType(ASTContext &C, const NamedDecl *ND) {
}
if (const FunctionType *Function = T->getAs<FunctionType>()) {
- T = Function->getResultType();
+ T = Function->getReturnType();
continue;
}
@@ -782,7 +779,7 @@ void ResultBuilder::MaybeAddConstructorResults(Result R) {
ASTContext &Context = SemaRef.Context;
const NamedDecl *D = R.Declaration;
- const CXXRecordDecl *Record = 0;
+ const CXXRecordDecl *Record = nullptr;
if (const ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(D))
Record = ClassTemplate->getTemplatedDecl();
else if ((Record = dyn_cast<CXXRecordDecl>(D))) {
@@ -913,10 +910,11 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
!R.StartsNestedNameSpecifier) {
const DeclContext *Ctx = R.Declaration->getDeclContext();
if (const NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx))
- R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, Namespace);
+ R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, nullptr,
+ Namespace);
else if (const TagDecl *Tag = dyn_cast<TagDecl>(Ctx))
- R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, false,
- SemaRef.Context.getTypeDeclType(Tag).getTypePtr());
+ R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, nullptr,
+ false, SemaRef.Context.getTypeDeclType(Tag).getTypePtr());
else
R.QualifierIsInformative = false;
}
@@ -978,9 +976,10 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
!R.StartsNestedNameSpecifier) {
const DeclContext *Ctx = R.Declaration->getDeclContext();
if (const NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx))
- R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, Namespace);
+ R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, nullptr,
+ Namespace);
else if (const TagDecl *Tag = dyn_cast<TagDecl>(Ctx))
- R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, false,
+ R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, nullptr, false,
SemaRef.Context.getTypeDeclType(Tag).getTypePtr());
else
R.QualifierIsInformative = false;
@@ -1256,15 +1255,15 @@ namespace {
public:
CodeCompletionDeclConsumer(ResultBuilder &Results, DeclContext *CurContext)
: Results(Results), CurContext(CurContext) { }
-
- virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
- bool InBaseClass) {
+
+ void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
+ bool InBaseClass) override {
bool Accessible = true;
if (Ctx)
Accessible = Results.getSema().IsSimplyAccessible(ND, Ctx);
-
- ResultBuilder::Result Result(ND, Results.getBasePriority(ND), 0, false,
- Accessible);
+
+ ResultBuilder::Result Result(ND, Results.getBasePriority(ND), nullptr,
+ false, Accessible);
Results.AddResult(Result, CurContext, Hiding, InBaseClass);
}
};
@@ -1784,10 +1783,10 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
// know the function is void or not.
bool isVoid = false;
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(SemaRef.CurContext))
- isVoid = Function->getResultType()->isVoidType();
+ isVoid = Function->getReturnType()->isVoidType();
else if (ObjCMethodDecl *Method
= dyn_cast<ObjCMethodDecl>(SemaRef.CurContext))
- isVoid = Method->getResultType()->isVoidType();
+ isVoid = Method->getReturnType()->isVoidType();
else if (SemaRef.getCurBlock() &&
!SemaRef.getCurBlock()->ReturnType.isNull())
isVoid = SemaRef.getCurBlock()->ReturnType->isVoidType();
@@ -2066,14 +2065,11 @@ static void AddResultTypeChunk(ASTContext &Context,
return;
// Determine the type of the declaration (if it has a type).
- QualType T;
- if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(ND))
- T = Function->getResultType();
+ QualType T;
+ if (const FunctionDecl *Function = ND->getAsFunction())
+ T = Function->getReturnType();
else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
- T = Method->getResultType();
- else if (const FunctionTemplateDecl *FunTmpl =
- dyn_cast<FunctionTemplateDecl>(ND))
- T = FunTmpl->getTemplatedDecl()->getResultType();
+ T = Method->getReturnType();
else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND))
T = Context.getTypeDeclType(cast<TypeDecl>(Enumerator->getDeclContext()));
else if (isa<UnresolvedUsingValueDecl>(ND)) {
@@ -2206,26 +2202,26 @@ static std::string FormatFunctionParameter(ASTContext &Context,
// We have the function prototype behind the block pointer type, as it was
// written in the source.
std::string Result;
- QualType ResultType = Block.getTypePtr()->getResultType();
+ QualType ResultType = Block.getTypePtr()->getReturnType();
if (!ResultType->isVoidType() || SuppressBlock)
ResultType.getAsStringInternal(Result, Policy);
// Format the parameter list.
std::string Params;
- if (!BlockProto || Block.getNumArgs() == 0) {
+ if (!BlockProto || Block.getNumParams() == 0) {
if (BlockProto && BlockProto.getTypePtr()->isVariadic())
Params = "(...)";
else
Params = "(void)";
} else {
Params += "(";
- for (unsigned I = 0, N = Block.getNumArgs(); I != N; ++I) {
+ for (unsigned I = 0, N = Block.getNumParams(); I != N; ++I) {
if (I)
Params += ", ";
- Params += FormatFunctionParameter(Context, Policy, Block.getArg(I),
- /*SuppressName=*/false,
+ Params += FormatFunctionParameter(Context, Policy, Block.getParam(I),
+ /*SuppressName=*/false,
/*SuppressBlock=*/true);
-
+
if (I == N - 1 && BlockProto.getTypePtr()->isVariadic())
Params += ", ...";
}
@@ -2297,7 +2293,7 @@ static void AddFunctionParameterChunks(ASTContext &Context,
if (const FunctionProtoType *Proto
= Function->getType()->getAs<FunctionProtoType>())
if (Proto->isVariadic()) {
- if (Proto->getNumArgs() == 0)
+ if (Proto->getNumParams() == 0)
Result.AddPlaceholderChunk("...");
MaybeAddSentinel(Context, Function, Result);
@@ -2450,7 +2446,7 @@ static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy,
switch (Name.getNameKind()) {
case DeclarationName::CXXOperatorName: {
- const char *OperatorName = 0;
+ const char *OperatorName = nullptr;
switch (Name.getCXXOverloadedOperator()) {
case OO_None:
case OO_Conditional:
@@ -2489,7 +2485,7 @@ static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy,
break;
case DeclarationName::CXXConstructorName: {
- CXXRecordDecl *Record = 0;
+ CXXRecordDecl *Record = nullptr;
QualType Ty = Name.getCXXNameType();
if (const RecordType *RecordTy = Ty->getAs<RecordType>())
Record = cast<CXXRecordDecl>(RecordTy->getDecl());
@@ -2644,12 +2640,9 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
return Result.TakeString();
}
- for (Decl::attr_iterator i = ND->attr_begin(); i != ND->attr_end(); ++i) {
- if (AnnotateAttr *Attr = dyn_cast_or_null<AnnotateAttr>(*i)) {
- Result.AddAnnotation(Result.getAllocator().CopyString(Attr->getAnnotation()));
- }
- }
-
+ for (const auto *I : ND->specific_attrs<AnnotateAttr>())
+ Result.AddAnnotation(Result.getAllocator().CopyString(I->getAnnotation()));
+
AddResultTypeChunk(Ctx, Policy, ND, Result);
if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
@@ -2836,9 +2829,8 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
// Function without a prototype. Just give the return type and a
// highlighted ellipsis.
const FunctionType *FT = getFunctionType();
- Result.AddTextChunk(GetCompletionTypeString(FT->getResultType(),
- S.Context, Policy,
- Result.getAllocator()));
+ Result.AddTextChunk(GetCompletionTypeString(FT->getReturnType(), S.Context,
+ Policy, Result.getAllocator()));
Result.AddChunk(CodeCompletionString::CK_LeftParen);
Result.AddChunk(CodeCompletionString::CK_CurrentParameter, "...");
Result.AddChunk(CodeCompletionString::CK_RightParen);
@@ -2849,12 +2841,11 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
Result.AddTextChunk(
Result.getAllocator().CopyString(FDecl->getNameAsString()));
else
- Result.AddTextChunk(
- Result.getAllocator().CopyString(
- Proto->getResultType().getAsString(Policy)));
-
+ Result.AddTextChunk(Result.getAllocator().CopyString(
+ Proto->getReturnType().getAsString(Policy)));
+
Result.AddChunk(CodeCompletionString::CK_LeftParen);
- unsigned NumParams = FDecl? FDecl->getNumParams() : Proto->getNumArgs();
+ unsigned NumParams = FDecl ? FDecl->getNumParams() : Proto->getNumParams();
for (unsigned I = 0; I != NumParams; ++I) {
if (I)
Result.AddChunk(CodeCompletionString::CK_Comma);
@@ -2866,7 +2857,7 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
ArgString = FDecl->getParamDecl(I)->getNameAsString();
ArgType = FDecl->getParamDecl(I)->getOriginalType();
} else {
- ArgType = Proto->getArgType(I);
+ ArgType = Proto->getParamType(I);
}
ArgType.getAsStringInternal(ArgString, Policy);
@@ -2998,11 +2989,16 @@ static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results,
for (Preprocessor::macro_iterator M = PP.macro_begin(),
MEnd = PP.macro_end();
M != MEnd; ++M) {
- if (IncludeUndefined || M->first->hasMacroDefinition())
+ if (IncludeUndefined || M->first->hasMacroDefinition()) {
+ if (MacroInfo *MI = M->second->getMacroInfo())
+ if (MI->isUsedForHeaderGuard())
+ continue;
+
Results.AddResult(Result(M->first,
getMacroUsagePriority(M->first->getName(),
PP.getLangOpts(),
TargetTypeIsPointer)));
+ }
}
Results.ExitScope();
@@ -3109,13 +3105,9 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
// We need to have names for all of the parameters, if we're going to
// generate a forwarding call.
- for (CXXMethodDecl::param_iterator P = Method->param_begin(),
- PEnd = Method->param_end();
- P != PEnd;
- ++P) {
- if (!(*P)->getDeclName())
+ for (auto P : Method->params())
+ if (!P->getDeclName())
return;
- }
PrintingPolicy Policy = getCompletionPrintingPolicy(S);
for (CXXMethodDecl::method_iterator M = Method->begin_overridden_methods(),
@@ -3145,16 +3137,14 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
Overridden->getNameAsString()));
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
bool FirstParam = true;
- for (CXXMethodDecl::param_iterator P = Method->param_begin(),
- PEnd = Method->param_end();
- P != PEnd; ++P) {
+ for (auto P : Method->params()) {
if (FirstParam)
FirstParam = false;
else
Builder.AddChunk(CodeCompletionString::CK_Comma);
- Builder.AddPlaceholderChunk(Results.getAllocator().CopyString(
- (*P)->getIdentifier()->getName()));
+ Builder.AddPlaceholderChunk(
+ Results.getAllocator().CopyString(P->getIdentifier()->getName()));
}
Builder.AddChunk(CodeCompletionString::CK_RightParen);
Results.AddResult(CodeCompletionResult(Builder.TakeString(),
@@ -3252,7 +3242,7 @@ void Sema::CodeCompleteOrdinaryName(Scope *S,
Results.setFilter(&ResultBuilder::IsOrdinaryNonTypeName);
if (getLangOpts().CPlusPlus)
- MaybeAddOverrideCalls(*this, /*InContext=*/0, Results);
+ MaybeAddOverrideCalls(*this, /*InContext=*/nullptr, Results);
break;
case PCC_RecoveryInFunction:
@@ -3340,7 +3330,7 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS,
CodeCompletionDeclConsumer Consumer(Results, CurContext);
LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer,
CodeCompleter->includeGlobals());
- Results.setFilter(0);
+ Results.setFilter(nullptr);
}
}
Results.ExitScope();
@@ -3438,7 +3428,7 @@ void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E) {
if (E.isInvalid())
CodeCompleteOrdinaryName(S, PCC_RecoveryInFunction);
else if (getLangOpts().ObjC1)
- CodeCompleteObjCInstanceMessage(S, E.take(), None, false);
+ CodeCompleteObjCInstanceMessage(S, E.get(), None, false);
}
/// \brief The set of properties that have already been added, referenced by
@@ -3475,32 +3465,26 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
Container = getContainerDef(Container);
// Add properties in this container.
- for (ObjCContainerDecl::prop_iterator P = Container->prop_begin(),
- PEnd = Container->prop_end();
- P != PEnd;
- ++P) {
+ for (const auto *P : Container->properties())
if (AddedProperties.insert(P->getIdentifier()))
- Results.MaybeAddResult(Result(*P, Results.getBasePriority(*P), 0),
+ Results.MaybeAddResult(Result(P, Results.getBasePriority(P), nullptr),
CurContext);
- }
-
+
// Add nullary methods
if (AllowNullaryMethods) {
ASTContext &Context = Container->getASTContext();
PrintingPolicy Policy = getCompletionPrintingPolicy(Results.getSema());
- for (ObjCContainerDecl::method_iterator M = Container->meth_begin(),
- MEnd = Container->meth_end();
- M != MEnd; ++M) {
+ for (auto *M : Container->methods()) {
if (M->getSelector().isUnarySelector())
if (IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0))
if (AddedProperties.insert(Name)) {
CodeCompletionBuilder Builder(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
- AddResultTypeChunk(Context, Policy, *M, Builder);
+ AddResultTypeChunk(Context, Policy, M, Builder);
Builder.AddTypedTextChunk(
Results.getAllocator().CopyString(Name->getName()));
- Results.MaybeAddResult(Result(Builder.TakeString(), *M,
+ Results.MaybeAddResult(Result(Builder.TakeString(), M,
CCP_MemberDeclaration + CCD_MethodAsProperty),
CurContext);
}
@@ -3510,27 +3494,20 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
// Add properties in referenced protocols.
if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
- for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(),
- PEnd = Protocol->protocol_end();
- P != PEnd; ++P)
- AddObjCProperties(*P, AllowCategories, AllowNullaryMethods, CurContext,
+ for (auto *P : Protocol->protocols())
+ AddObjCProperties(P, AllowCategories, AllowNullaryMethods, CurContext,
AddedProperties, Results);
} else if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)){
if (AllowCategories) {
// Look through categories.
- for (ObjCInterfaceDecl::known_categories_iterator
- Cat = IFace->known_categories_begin(),
- CatEnd = IFace->known_categories_end();
- Cat != CatEnd; ++Cat)
- AddObjCProperties(*Cat, AllowCategories, AllowNullaryMethods,
- CurContext, AddedProperties, Results);
+ for (auto *Cat : IFace->known_categories())
+ AddObjCProperties(Cat, AllowCategories, AllowNullaryMethods, CurContext,
+ AddedProperties, Results);
}
-
+
// Look through protocols.
- for (ObjCInterfaceDecl::all_protocol_iterator
- I = IFace->all_referenced_protocol_begin(),
- E = IFace->all_referenced_protocol_end(); I != E; ++I)
- AddObjCProperties(*I, AllowCategories, AllowNullaryMethods, CurContext,
+ for (auto *I : IFace->all_referenced_protocols())
+ AddObjCProperties(I, AllowCategories, AllowNullaryMethods, CurContext,
AddedProperties, Results);
// Look in the superclass.
@@ -3541,10 +3518,8 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
} else if (const ObjCCategoryDecl *Category
= dyn_cast<ObjCCategoryDecl>(Container)) {
// Look through protocols.
- for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
- PEnd = Category->protocol_end();
- P != PEnd; ++P)
- AddObjCProperties(*P, AllowCategories, AllowNullaryMethods, CurContext,
+ for (auto *P : Category->protocols())
+ AddObjCProperties(P, AllowCategories, AllowNullaryMethods, CurContext,
AddedProperties, Results);
}
}
@@ -3636,15 +3611,13 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
AddedProperties, Results);
// Add properties from the protocols in a qualified interface.
- for (ObjCObjectPointerType::qual_iterator I = ObjCPtr->qual_begin(),
- E = ObjCPtr->qual_end();
- I != E; ++I)
- AddObjCProperties(*I, true, /*AllowNullaryMethods=*/true, CurContext,
+ for (auto *I : ObjCPtr->quals())
+ AddObjCProperties(I, true, /*AllowNullaryMethods=*/true, CurContext,
AddedProperties, Results);
} else if ((IsArrow && BaseType->isObjCObjectPointerType()) ||
(!IsArrow && BaseType->isObjCObjectType())) {
// Objective-C instance variable access.
- ObjCInterfaceDecl *Class = 0;
+ ObjCInterfaceDecl *Class = nullptr;
if (const ObjCObjectPointerType *ObjCPtr
= BaseType->getAs<ObjCObjectPointerType>())
Class = ObjCPtr->getInterfaceDecl();
@@ -3673,8 +3646,8 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) {
if (!CodeCompleter)
return;
-
- ResultBuilder::LookupFilter Filter = 0;
+
+ ResultBuilder::LookupFilter Filter = nullptr;
enum CodeCompletionContext::Kind ContextKind
= CodeCompletionContext::CCC_Other;
switch ((DeclSpec::TST)TagSpec) {
@@ -3763,7 +3736,7 @@ void Sema::CodeCompleteCase(Scope *S) {
// token, in case we are code-completing in the middle of the switch and not
// at the end. However, we aren't able to do so at the moment.
llvm::SmallPtrSet<EnumConstantDecl *, 8> EnumeratorsSeen;
- NestedNameSpecifier *Qualifier = 0;
+ NestedNameSpecifier *Qualifier = nullptr;
for (SwitchCase *SC = Switch->getSwitchCaseList(); SC;
SC = SC->getNextSwitchCase()) {
CaseStmt *Case = dyn_cast<CaseStmt>(SC);
@@ -3809,14 +3782,12 @@ void Sema::CodeCompleteCase(Scope *S) {
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_Expression);
Results.EnterNewScope();
- for (EnumDecl::enumerator_iterator E = Enum->enumerator_begin(),
- EEnd = Enum->enumerator_end();
- E != EEnd; ++E) {
- if (EnumeratorsSeen.count(*E))
+ for (auto *E : Enum->enumerators()) {
+ if (EnumeratorsSeen.count(E))
continue;
- CodeCompletionResult R(*E, CCP_EnumInCase, Qualifier);
- Results.AddResult(R, CurContext, 0, false);
+ CodeCompletionResult R(E, CCP_EnumInCase, Qualifier);
+ Results.AddResult(R, CurContext, nullptr, false);
}
Results.ExitScope();
@@ -3833,22 +3804,6 @@ void Sema::CodeCompleteCase(Scope *S) {
Results.data(),Results.size());
}
-namespace {
- struct IsBetterOverloadCandidate {
- Sema &S;
- SourceLocation Loc;
-
- public:
- explicit IsBetterOverloadCandidate(Sema &S, SourceLocation Loc)
- : S(S), Loc(Loc) { }
-
- bool
- operator()(const OverloadCandidate &X, const OverloadCandidate &Y) const {
- return isBetterOverloadCandidate(S, X, Y, Loc);
- }
- };
-}
-
static bool anyNullArguments(ArrayRef<Expr *> Args) {
if (Args.size() && !Args.data())
return true;
@@ -3880,7 +3835,7 @@ void Sema::CodeCompleteCall(Scope *S, Expr *FnIn, ArrayRef<Expr *> Args) {
// Build an overload candidate set based on the functions we find.
SourceLocation Loc = Fn->getExprLoc();
- OverloadCandidateSet CandidateSet(Loc);
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
// FIXME: What if we're calling something that isn't a function declaration?
// FIXME: What if we're calling a pseudo-destructor?
@@ -3910,9 +3865,12 @@ void Sema::CodeCompleteCall(Scope *S, Expr *FnIn, ArrayRef<Expr *> Args) {
if (!CandidateSet.empty()) {
// Sort the overload candidate set by placing the best overloads first.
- std::stable_sort(CandidateSet.begin(), CandidateSet.end(),
- IsBetterOverloadCandidate(*this, Loc));
-
+ std::stable_sort(
+ CandidateSet.begin(), CandidateSet.end(),
+ [&](const OverloadCandidate &X, const OverloadCandidate &Y) {
+ return isBetterOverloadCandidate(*this, X, Y, Loc);
+ });
+
// Add the remaining viable overload candidates as code-completion reslults.
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
CandEnd = CandidateSet.end();
@@ -3925,12 +3883,13 @@ void Sema::CodeCompleteCall(Scope *S, Expr *FnIn, ArrayRef<Expr *> Args) {
for (unsigned I = 0, N = Results.size(); I != N; ++I) {
if (const FunctionType *FType = Results[I].getFunctionType())
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FType))
- if (Args.size() < Proto->getNumArgs()) {
+ if (Args.size() < Proto->getNumParams()) {
if (ParamType.isNull())
- ParamType = Proto->getArgType(Args.size());
+ ParamType = Proto->getParamType(Args.size());
else if (!Context.hasSameUnqualifiedType(
- ParamType.getNonReferenceType(),
- Proto->getArgType(Args.size()).getNonReferenceType())) {
+ ParamType.getNonReferenceType(),
+ Proto->getParamType(Args.size())
+ .getNonReferenceType())) {
ParamType = QualType();
break;
}
@@ -3951,8 +3910,8 @@ void Sema::CodeCompleteCall(Scope *S, Expr *FnIn, ArrayRef<Expr *> Args) {
if (const FunctionProtoType *Proto
= FunctionType->getAs<FunctionProtoType>()) {
- if (Args.size() < Proto->getNumArgs())
- ParamType = Proto->getArgType(Args.size());
+ if (Args.size() < Proto->getNumParams())
+ ParamType = Proto->getParamType(Args.size());
}
}
@@ -3982,10 +3941,10 @@ void Sema::CodeCompleteReturn(Scope *S) {
if (BlockScopeInfo *BSI = getCurBlock())
ResultType = BSI->ReturnType;
} else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(CurContext))
- ResultType = Function->getResultType();
+ ResultType = Function->getReturnType();
else if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(CurContext))
- ResultType = Method->getResultType();
-
+ ResultType = Method->getReturnType();
+
if (ResultType.isNull())
CodeCompleteOrdinaryName(S, PCC_Expression);
else
@@ -4080,7 +4039,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
// The "template" keyword can follow "::" in the grammar, but only
// put it into the grammar if the nested-name-specifier is dependent.
- NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
+ NestedNameSpecifier *NNS = SS.getScopeRep();
if (!Results.empty() && NNS->isDependent())
Results.AddResult("template");
@@ -4184,8 +4143,9 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) {
NSEnd = OrigToLatest.end();
NS != NSEnd; ++NS)
Results.AddResult(CodeCompletionResult(
- NS->second, Results.getBasePriority(NS->second), 0),
- CurContext, 0, false);
+ NS->second, Results.getBasePriority(NS->second),
+ nullptr),
+ CurContext, nullptr, false);
Results.ExitScope();
}
@@ -4274,21 +4234,19 @@ void Sema::CodeCompleteConstructorInitializer(
Results.getCodeCompletionTUInfo());
bool SawLastInitializer = Initializers.empty();
CXXRecordDecl *ClassDecl = Constructor->getParent();
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
- BaseEnd = ClassDecl->bases_end();
- Base != BaseEnd; ++Base) {
- if (!InitializedBases.insert(Context.getCanonicalType(Base->getType()))) {
+ for (const auto &Base : ClassDecl->bases()) {
+ if (!InitializedBases.insert(Context.getCanonicalType(Base.getType()))) {
SawLastInitializer
= !Initializers.empty() &&
Initializers.back()->isBaseInitializer() &&
- Context.hasSameUnqualifiedType(Base->getType(),
+ Context.hasSameUnqualifiedType(Base.getType(),
QualType(Initializers.back()->getBaseClass(), 0));
continue;
}
Builder.AddTypedTextChunk(
Results.getAllocator().CopyString(
- Base->getType().getAsString(Policy)));
+ Base.getType().getAsString(Policy)));
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("args");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
@@ -4299,21 +4257,19 @@ void Sema::CodeCompleteConstructorInitializer(
}
// Add completions for virtual base classes.
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
- BaseEnd = ClassDecl->vbases_end();
- Base != BaseEnd; ++Base) {
- if (!InitializedBases.insert(Context.getCanonicalType(Base->getType()))) {
+ for (const auto &Base : ClassDecl->vbases()) {
+ if (!InitializedBases.insert(Context.getCanonicalType(Base.getType()))) {
SawLastInitializer
= !Initializers.empty() &&
Initializers.back()->isBaseInitializer() &&
- Context.hasSameUnqualifiedType(Base->getType(),
+ Context.hasSameUnqualifiedType(Base.getType(),
QualType(Initializers.back()->getBaseClass(), 0));
continue;
}
Builder.AddTypedTextChunk(
Builder.getAllocator().CopyString(
- Base->getType().getAsString(Policy)));
+ Base.getType().getAsString(Policy)));
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("args");
Builder.AddChunk(CodeCompletionString::CK_RightParen);
@@ -4324,14 +4280,12 @@ void Sema::CodeCompleteConstructorInitializer(
}
// Add completions for members.
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
+ for (auto *Field : ClassDecl->fields()) {
if (!InitializedFields.insert(cast<FieldDecl>(Field->getCanonicalDecl()))) {
SawLastInitializer
= !Initializers.empty() &&
Initializers.back()->isAnyMemberInitializer() &&
- Initializers.back()->getAnyMember() == *Field;
+ Initializers.back()->getAnyMember() == Field;
continue;
}
@@ -4348,7 +4302,7 @@ void Sema::CodeCompleteConstructorInitializer(
: CCP_MemberDeclaration,
CXCursor_MemberRef,
CXAvailability_Available,
- *Field));
+ Field));
SawLastInitializer = false;
}
Results.ExitScope();
@@ -4376,22 +4330,19 @@ void Sema::CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro,
// Note what has already been captured.
llvm::SmallPtrSet<IdentifierInfo *, 4> Known;
bool IncludedThis = false;
- for (SmallVectorImpl<LambdaCapture>::iterator C = Intro.Captures.begin(),
- CEnd = Intro.Captures.end();
- C != CEnd; ++C) {
- if (C->Kind == LCK_This) {
+ for (const auto &C : Intro.Captures) {
+ if (C.Kind == LCK_This) {
IncludedThis = true;
continue;
}
- Known.insert(C->Id);
+ Known.insert(C.Id);
}
// Look for other capturable variables.
for (; S && !isNamespaceScope(S); S = S->getParent()) {
- for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
- D != DEnd; ++D) {
- VarDecl *Var = dyn_cast<VarDecl>(*D);
+ for (const auto *D : S->decls()) {
+ const auto *Var = dyn_cast<VarDecl>(D);
if (!Var ||
!Var->hasLocalStorage() ||
Var->hasAttr<BlocksAttr>())
@@ -4399,7 +4350,7 @@ void Sema::CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro,
if (Known.insert(Var->getIdentifier()))
Results.AddResult(CodeCompletionResult(Var, CCP_LocalDeclaration),
- CurContext, 0, false);
+ CurContext, nullptr, false);
}
}
@@ -4759,7 +4710,7 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
CodeCompletionBuilder Setter(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
Setter.AddTypedTextChunk("setter");
- Setter.AddTextChunk(" = ");
+ Setter.AddTextChunk("=");
Setter.AddPlaceholderChunk("method");
Results.AddResult(CodeCompletionResult(Setter.TakeString()));
}
@@ -4767,7 +4718,7 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
CodeCompletionBuilder Getter(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
Getter.AddTypedTextChunk("getter");
- Getter.AddTextChunk(" = ");
+ Getter.AddTextChunk("=");
Getter.AddPlaceholderChunk("method");
Results.AddResult(CodeCompletionResult(Getter.TakeString()));
}
@@ -4856,22 +4807,20 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
Container = getContainerDef(Container);
ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container);
bool isRootClass = IFace && !IFace->getSuperClass();
- for (ObjCContainerDecl::method_iterator M = Container->meth_begin(),
- MEnd = Container->meth_end();
- M != MEnd; ++M) {
+ for (auto *M : Container->methods()) {
// The instance methods on the root class can be messaged via the
// metaclass.
if (M->isInstanceMethod() == WantInstanceMethods ||
(isRootClass && !WantInstanceMethods)) {
// Check whether the selector identifiers we've been given are a
// subset of the identifiers for this particular method.
- if (!isAcceptableObjCMethod(*M, WantKind, SelIdents, AllowSameLength))
+ if (!isAcceptableObjCMethod(M, WantKind, SelIdents, AllowSameLength))
continue;
if (!Selectors.insert(M->getSelector()))
continue;
-
- Result R = Result(*M, Results.getBasePriority(*M), 0);
+
+ Result R = Result(M, Results.getBasePriority(M), nullptr);
R.StartParameter = SelIdents.size();
R.AllParametersAreInformative = (WantKind != MK_Any);
if (!InOriginalClass)
@@ -4897,19 +4846,12 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
return;
// Add methods in protocols.
- for (ObjCInterfaceDecl::protocol_iterator I = IFace->protocol_begin(),
- E = IFace->protocol_end();
- I != E; ++I)
- AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents,
+ for (auto *I : IFace->protocols())
+ AddObjCMethods(I, WantInstanceMethods, WantKind, SelIdents,
CurContext, Selectors, AllowSameLength, Results, false);
// Add methods in categories.
- for (ObjCInterfaceDecl::known_categories_iterator
- Cat = IFace->known_categories_begin(),
- CatEnd = IFace->known_categories_end();
- Cat != CatEnd; ++Cat) {
- ObjCCategoryDecl *CatDecl = *Cat;
-
+ for (auto *CatDecl : IFace->known_categories()) {
AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents,
CurContext, Selectors, AllowSameLength,
Results, InOriginalClass);
@@ -5080,22 +5022,22 @@ void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS,
static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {
ObjCMessageExpr *Msg = dyn_cast_or_null<ObjCMessageExpr>(E);
if (!Msg)
- return 0;
+ return nullptr;
Selector Sel = Msg->getSelector();
if (Sel.isNull())
- return 0;
+ return nullptr;
IdentifierInfo *Id = Sel.getIdentifierInfoForSlot(0);
if (!Id)
- return 0;
+ return nullptr;
ObjCMethodDecl *Method = Msg->getMethodDecl();
if (!Method)
- return 0;
+ return nullptr;
// Determine the class that we're sending the message to.
- ObjCInterfaceDecl *IFace = 0;
+ ObjCInterfaceDecl *IFace = nullptr;
switch (Msg->getReceiverKind()) {
case ObjCMessageExpr::Class:
if (const ObjCObjectType *ObjType
@@ -5116,7 +5058,7 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {
}
if (!IFace)
- return 0;
+ return nullptr;
ObjCInterfaceDecl *Super = IFace->getSuperClass();
if (Method->isInstanceMethod())
@@ -5133,7 +5075,7 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {
.Case("class", IFace)
.Case("classForCoder", IFace)
.Case("superclass", Super)
- .Default(0);
+ .Default(nullptr);
return llvm::StringSwitch<ObjCInterfaceDecl *>(Id->getName())
.Case("new", IFace)
@@ -5141,7 +5083,7 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) {
.Case("allocWithZone", IFace)
.Case("class", IFace)
.Case("superclass", Super)
- .Default(0);
+ .Default(nullptr);
}
// Add a special completion for a message send to "super", which fills in the
@@ -5166,14 +5108,14 @@ static ObjCMethodDecl *AddSuperSendCompletion(
ResultBuilder &Results) {
ObjCMethodDecl *CurMethod = S.getCurMethodDecl();
if (!CurMethod)
- return 0;
-
+ return nullptr;
+
ObjCInterfaceDecl *Class = CurMethod->getClassInterface();
if (!Class)
- return 0;
-
+ return nullptr;
+
// Try to find a superclass method with the same selector.
- ObjCMethodDecl *SuperMethod = 0;
+ ObjCMethodDecl *SuperMethod = nullptr;
while ((Class = Class->getSuperClass()) && !SuperMethod) {
// Check in the class
SuperMethod = Class->getMethod(CurMethod->getSelector(),
@@ -5181,10 +5123,7 @@ static ObjCMethodDecl *AddSuperSendCompletion(
// Check in categories or class extensions.
if (!SuperMethod) {
- for (ObjCInterfaceDecl::known_categories_iterator
- Cat = Class->known_categories_begin(),
- CatEnd = Class->known_categories_end();
- Cat != CatEnd; ++Cat) {
+ for (const auto *Cat : Class->known_categories()) {
if ((SuperMethod = Cat->getMethod(CurMethod->getSelector(),
CurMethod->isInstanceMethod())))
break;
@@ -5193,13 +5132,13 @@ static ObjCMethodDecl *AddSuperSendCompletion(
}
if (!SuperMethod)
- return 0;
-
+ return nullptr;
+
// Check whether the superclass method has the same signature.
if (CurMethod->param_size() != SuperMethod->param_size() ||
CurMethod->isVariadic() != SuperMethod->isVariadic())
- return 0;
-
+ return nullptr;
+
for (ObjCMethodDecl::param_iterator CurP = CurMethod->param_begin(),
CurPEnd = CurMethod->param_end(),
SuperP = SuperMethod->param_begin();
@@ -5207,11 +5146,11 @@ static ObjCMethodDecl *AddSuperSendCompletion(
// Make sure the parameter types are compatible.
if (!S.Context.hasSameUnqualifiedType((*CurP)->getType(),
(*SuperP)->getType()))
- return 0;
-
+ return nullptr;
+
// Make sure we have a parameter name to forward!
if (!(*CurP)->getIdentifier())
- return 0;
+ return nullptr;
}
// We have a superclass method. Now, form the send-to-super completion.
@@ -5306,7 +5245,7 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) {
void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
ArrayRef<IdentifierInfo *> SelIdents,
bool AtArgumentExpression) {
- ObjCInterfaceDecl *CDecl = 0;
+ ObjCInterfaceDecl *CDecl = nullptr;
if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) {
// Figure out which interface we're in.
CDecl = CurMethod->getClassInterface();
@@ -5322,7 +5261,7 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
// We are inside an instance method, which means that the message
// send [super ...] is actually calling an instance method on the
// current object.
- return CodeCompleteObjCInstanceMessage(S, 0, SelIdents,
+ return CodeCompleteObjCInstanceMessage(S, nullptr, SelIdents,
AtArgumentExpression,
CDecl);
}
@@ -5383,7 +5322,7 @@ static QualType getPreferredArgumentTypeForMessageSend(ResultBuilder &Results,
if (R.Priority <= BestPriority) {
const ObjCMethodDecl *Method = cast<ObjCMethodDecl>(R.Declaration);
if (NumSelIdents <= Method->param_size()) {
- QualType MyPreferredType = Method->param_begin()[NumSelIdents - 1]
+ QualType MyPreferredType = Method->parameters()[NumSelIdents - 1]
->getType();
if (R.Priority < BestPriority || PreferredType.isNull()) {
BestPriority = R.Priority;
@@ -5407,12 +5346,12 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S,
bool IsSuper,
ResultBuilder &Results) {
typedef CodeCompletionResult Result;
- ObjCInterfaceDecl *CDecl = 0;
-
+ ObjCInterfaceDecl *CDecl = nullptr;
+
// If the given name refers to an interface type, retrieve the
// corresponding declaration.
if (Receiver) {
- QualType T = SemaRef.GetTypeFromParser(Receiver, 0);
+ QualType T = SemaRef.GetTypeFromParser(Receiver, nullptr);
if (!T.isNull())
if (const ObjCObjectType *Interface = T->getAs<ObjCObjectType>())
CDecl = Interface->getInterface();
@@ -5465,8 +5404,9 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S,
MethList = MethList->getNext()) {
if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents))
continue;
-
- Result R(MethList->Method, Results.getBasePriority(MethList->Method),0);
+
+ Result R(MethList->Method, Results.getBasePriority(MethList->Method),
+ nullptr);
R.StartParameter = SelIdents.size();
R.AllParametersAreInformative = false;
Results.MaybeAddResult(R, SemaRef.CurContext);
@@ -5526,7 +5466,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
ExprResult Conv = DefaultFunctionArrayLvalueConversion(RecExpr);
if (Conv.isInvalid()) // conversion failed. bail.
return;
- RecExpr = Conv.take();
+ RecExpr = Conv.get();
}
QualType ReceiverType = RecExpr? RecExpr->getType()
: Super? Context.getObjCObjectPointerType(
@@ -5536,7 +5476,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
// If we're messaging an expression with type "id" or "Class", check
// whether we know something special about the receiver that allows
// us to assume a more-specific receiver type.
- if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType())
+ if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType()) {
if (ObjCInterfaceDecl *IFace = GetAssumedMessageSendExprType(RecExpr)) {
if (ReceiverType->isObjCClassType())
return CodeCompleteObjCClassMessage(S,
@@ -5547,6 +5487,13 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
ReceiverType = Context.getObjCObjectPointerType(
Context.getObjCInterfaceType(IFace));
}
+ } else if (RecExpr && getLangOpts().CPlusPlus) {
+ ExprResult Conv = PerformContextuallyConvertToObjCPointer(RecExpr);
+ if (Conv.isUsable()) {
+ RecExpr = Conv.get();
+ ReceiverType = RecExpr->getType();
+ }
+ }
// Build the set of methods we can see.
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
@@ -5587,10 +5534,8 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
else if (const ObjCObjectPointerType *QualID
= ReceiverType->getAsObjCQualifiedIdType()) {
// Search protocols for instance methods.
- for (ObjCObjectPointerType::qual_iterator I = QualID->qual_begin(),
- E = QualID->qual_end();
- I != E; ++I)
- AddObjCMethods(*I, true, MK_Any, SelIdents, CurContext,
+ for (auto *I : QualID->quals())
+ AddObjCMethods(I, true, MK_Any, SelIdents, CurContext,
Selectors, AtArgumentExpression, Results);
}
// Handle messages to a pointer to interface type.
@@ -5602,10 +5547,8 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
Results);
// Search protocols for instance methods.
- for (ObjCObjectPointerType::qual_iterator I = IFacePtr->qual_begin(),
- E = IFacePtr->qual_end();
- I != E; ++I)
- AddObjCMethods(*I, true, MK_Any, SelIdents, CurContext,
+ for (auto *I : IFacePtr->quals())
+ AddObjCMethods(I, true, MK_Any, SelIdents, CurContext,
Selectors, AtArgumentExpression, Results);
}
// Handle messages to "id".
@@ -5637,8 +5580,9 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
if (!Selectors.insert(MethList->Method->getSelector()))
continue;
-
- Result R(MethList->Method, Results.getBasePriority(MethList->Method),0);
+
+ Result R(MethList->Method, Results.getBasePriority(MethList->Method),
+ nullptr);
R.StartParameter = SelIdents.size();
R.AllParametersAreInformative = false;
Results.MaybeAddResult(R, CurContext);
@@ -5750,14 +5694,12 @@ static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext,
ResultBuilder &Results) {
typedef CodeCompletionResult Result;
- for (DeclContext::decl_iterator D = Ctx->decls_begin(),
- DEnd = Ctx->decls_end();
- D != DEnd; ++D) {
+ for (const auto *D : Ctx->decls()) {
// Record any protocols we find.
- if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(*D))
+ if (const auto *Proto = dyn_cast<ObjCProtocolDecl>(D))
if (!OnlyForwardDeclarations || !Proto->hasDefinition())
- Results.AddResult(Result(Proto, Results.getBasePriority(Proto), 0),
- CurContext, 0, false);
+ Results.AddResult(Result(Proto, Results.getBasePriority(Proto),nullptr),
+ CurContext, nullptr, false);
}
}
@@ -5818,15 +5760,13 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext,
ResultBuilder &Results) {
typedef CodeCompletionResult Result;
- for (DeclContext::decl_iterator D = Ctx->decls_begin(),
- DEnd = Ctx->decls_end();
- D != DEnd; ++D) {
+ for (const auto *D : Ctx->decls()) {
// Record any interfaces we find.
- if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*D))
+ if (const auto *Class = dyn_cast<ObjCInterfaceDecl>(D))
if ((!OnlyForwardDeclarations || !Class->hasDefinition()) &&
(!OnlyUnimplemented || !Class->getImplementation()))
- Results.AddResult(Result(Class, Results.getBasePriority(Class), 0),
- CurContext, 0, false);
+ Results.AddResult(Result(Class, Results.getBasePriority(Class),nullptr),
+ CurContext, nullptr, false);
}
}
@@ -5909,24 +5849,19 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
NamedDecl *CurClass
= LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName);
if (ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass)){
- for (ObjCInterfaceDecl::visible_categories_iterator
- Cat = Class->visible_categories_begin(),
- CatEnd = Class->visible_categories_end();
- Cat != CatEnd; ++Cat) {
+ for (const auto *Cat : Class->visible_categories())
CategoryNames.insert(Cat->getIdentifier());
- }
}
// Add all of the categories we know about.
Results.EnterNewScope();
TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
- for (DeclContext::decl_iterator D = TU->decls_begin(),
- DEnd = TU->decls_end();
- D != DEnd; ++D)
- if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(*D))
+ for (const auto *D : TU->decls())
+ if (const auto *Category = dyn_cast<ObjCCategoryDecl>(D))
if (CategoryNames.insert(Category->getIdentifier()))
- Results.AddResult(Result(Category, Results.getBasePriority(Category),0),
- CurContext, 0, false);
+ Results.AddResult(Result(Category, Results.getBasePriority(Category),
+ nullptr),
+ CurContext, nullptr, false);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
@@ -5959,14 +5894,11 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
Results.EnterNewScope();
bool IgnoreImplemented = true;
while (Class) {
- for (ObjCInterfaceDecl::visible_categories_iterator
- Cat = Class->visible_categories_begin(),
- CatEnd = Class->visible_categories_end();
- Cat != CatEnd; ++Cat) {
+ for (const auto *Cat : Class->visible_categories()) {
if ((!IgnoreImplemented || !Cat->getImplementation()) &&
CategoryNames.insert(Cat->getIdentifier()))
- Results.AddResult(Result(*Cat, Results.getBasePriority(*Cat), 0),
- CurContext, 0, false);
+ Results.AddResult(Result(Cat, Results.getBasePriority(Cat), nullptr),
+ CurContext, nullptr, false);
}
Class = Class->getSuperClass();
@@ -5994,10 +5926,8 @@ void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) {
// Ignore any properties that have already been implemented.
Container = getContainerDef(Container);
- for (DeclContext::decl_iterator D = Container->decls_begin(),
- DEnd = Container->decls_end();
- D != DEnd; ++D)
- if (ObjCPropertyImplDecl *PropertyImpl = dyn_cast<ObjCPropertyImplDecl>(*D))
+ for (const auto *D : Container->decls())
+ if (const auto *PropertyImpl = dyn_cast<ObjCPropertyImplDecl>(D))
Results.Ignore(PropertyImpl->getPropertyDecl());
// Add any properties that we find.
@@ -6035,7 +5965,7 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
return;
// Figure out which interface we're looking into.
- ObjCInterfaceDecl *Class = 0;
+ ObjCInterfaceDecl *Class = nullptr;
if (ObjCImplementationDecl *ClassImpl
= dyn_cast<ObjCImplementationDecl>(Container))
Class = ClassImpl->getClassInterface();
@@ -6067,9 +5997,9 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
for(; Class; Class = Class->getSuperClass()) {
for (ObjCIvarDecl *Ivar = Class->all_declared_ivar_begin(); Ivar;
Ivar = Ivar->getNextIvar()) {
- Results.AddResult(Result(Ivar, Results.getBasePriority(Ivar), 0),
- CurContext, 0, false);
-
+ Results.AddResult(Result(Ivar, Results.getBasePriority(Ivar), nullptr),
+ CurContext, nullptr, false);
+
// Determine whether we've seen an ivar with a name similar to the
// property.
if ((PropertyName == Ivar->getIdentifier() ||
@@ -6144,11 +6074,8 @@ static void FindImplementableMethods(ASTContext &Context,
KnownMethods, InOriginalClass);
// Add methods from any class extensions and categories.
- for (ObjCInterfaceDecl::visible_categories_iterator
- Cat = IFace->visible_categories_begin(),
- CatEnd = IFace->visible_categories_end();
- Cat != CatEnd; ++Cat) {
- FindImplementableMethods(Context, *Cat, WantInstanceMethods, ReturnType,
+ for (auto *Cat : IFace->visible_categories()) {
+ FindImplementableMethods(Context, Cat, WantInstanceMethods, ReturnType,
KnownMethods, false);
}
@@ -6196,16 +6123,14 @@ static void FindImplementableMethods(ASTContext &Context,
// Add methods in this container. This operation occurs last because
// we want the methods from this container to override any methods
// we've previously seen with the same selector.
- for (ObjCContainerDecl::method_iterator M = Container->meth_begin(),
- MEnd = Container->meth_end();
- M != MEnd; ++M) {
+ for (auto *M : Container->methods()) {
if (M->isInstanceMethod() == WantInstanceMethods) {
if (!ReturnType.isNull() &&
- !Context.hasSameUnqualifiedType(ReturnType, M->getResultType()))
+ !Context.hasSameUnqualifiedType(ReturnType, M->getReturnType()))
continue;
KnownMethods[M->getSelector()] =
- KnownMethodsMap::mapped_type(*M, InOriginalClass);
+ KnownMethodsMap::mapped_type(M, InOriginalClass);
}
}
}
@@ -6267,10 +6192,10 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
CodeCompletionAllocator &Allocator;
StringRef Key;
const char *CopiedKey;
-
+
KeyHolder(CodeCompletionAllocator &Allocator, StringRef Key)
- : Allocator(Allocator), Key(Key), CopiedKey(0) { }
-
+ : Allocator(Allocator), Key(Key), CopiedKey(nullptr) {}
+
operator const char *() {
if (CopiedKey)
return CopiedKey;
@@ -6872,13 +6797,13 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
// Determine the return type of the method we're declaring, if
// provided.
QualType ReturnType = GetTypeFromParser(ReturnTy);
- Decl *IDecl = 0;
+ Decl *IDecl = nullptr;
if (CurContext->isObjCContainer()) {
ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext);
IDecl = cast<Decl>(OCD);
}
// Determine where we should start searching for methods.
- ObjCContainerDecl *SearchDecl = 0;
+ ObjCContainerDecl *SearchDecl = nullptr;
bool IsInImplementation = false;
if (Decl *D = IDecl) {
if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(D)) {
@@ -6900,7 +6825,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
if (!SearchDecl) {
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext::CCC_Other,
- 0, 0);
+ nullptr, 0);
return;
}
@@ -6926,10 +6851,9 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
// If the result type was not already provided, add it to the
// pattern as (type).
if (ReturnType.isNull())
- AddObjCPassingTypeChunk(Method->getResultType(),
- Method->getObjCDeclQualifier(),
- Context, Policy,
- Builder);
+ AddObjCPassingTypeChunk(Method->getReturnType(),
+ Method->getObjCDeclQualifier(), Context, Policy,
+ Builder);
Selector Sel = Method->getSelector();
@@ -6973,7 +6897,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddChunk(CodeCompletionString::CK_LeftBrace);
Builder.AddChunk(CodeCompletionString::CK_VerticalSpace);
- if (!Method->getResultType()->isVoidType()) {
+ if (!Method->getReturnType()->isVoidType()) {
// If the result type is not void, add a return clause.
Builder.AddTextChunk("return");
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
@@ -7011,23 +6935,14 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(SearchDecl))
IFace = Category->getClassInterface();
- if (IFace) {
- for (ObjCInterfaceDecl::visible_categories_iterator
- Cat = IFace->visible_categories_begin(),
- CatEnd = IFace->visible_categories_end();
- Cat != CatEnd; ++Cat) {
- Containers.push_back(*Cat);
- }
- }
+ if (IFace)
+ for (auto *Cat : IFace->visible_categories())
+ Containers.push_back(Cat);
- for (unsigned I = 0, N = Containers.size(); I != N; ++I) {
- for (ObjCContainerDecl::prop_iterator P = Containers[I]->prop_begin(),
- PEnd = Containers[I]->prop_end();
- P != PEnd; ++P) {
- AddObjCKeyValueCompletions(*P, IsInstanceMethod, ReturnType, Context,
+ for (unsigned I = 0, N = Containers.size(); I != N; ++I)
+ for (auto *P : Containers[I]->properties())
+ AddObjCKeyValueCompletions(P, IsInstanceMethod, ReturnType, Context,
KnownSelectors, Results);
- }
- }
}
Results.ExitScope();
@@ -7079,7 +6994,7 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S,
// Suggest parameter names we've seen before.
unsigned NumSelIdents = SelIdents.size();
if (NumSelIdents && NumSelIdents <= MethList->Method->param_size()) {
- ParmVarDecl *Param = MethList->Method->param_begin()[NumSelIdents-1];
+ ParmVarDecl *Param = MethList->Method->parameters()[NumSelIdents-1];
if (Param->getIdentifier()) {
CodeCompletionBuilder Builder(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
@@ -7091,8 +7006,9 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S,
continue;
}
-
- Result R(MethList->Method, Results.getBasePriority(MethList->Method), 0);
+
+ Result R(MethList->Method, Results.getBasePriority(MethList->Method),
+ nullptr);
R.StartParameter = SelIdents.size();
R.AllParametersAreInformative = false;
R.DeclaringEntity = true;
@@ -7338,7 +7254,7 @@ void Sema::CodeCompletePreprocessorMacroArgument(Scope *S,
void Sema::CodeCompleteNaturalLanguage() {
HandleCodeCompleteResults(this, CodeCompleter,
CodeCompletionContext::CCC_NaturalLanguage,
- 0, 0);
+ nullptr, 0);
}
void Sema::GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 328ce7059631..bbe69306b645 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -25,12 +25,14 @@
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Lex/HeaderSearch.h" // FIXME: Sema shouldn't depend on Lex
-#include "clang/Lex/ModuleLoader.h" // FIXME: Sema shouldn't depend on Lex
-#include "clang/Lex/Preprocessor.h" // FIXME: Sema shouldn't depend on Lex
+#include "clang/Lex/HeaderSearch.h" // TODO: Sema shouldn't depend on Lex
+#include "clang/Lex/Lexer.h" // TODO: Extract static functions to fix layering.
+#include "clang/Lex/ModuleLoader.h" // TODO: Sema shouldn't depend on Lex
+#include "clang/Lex/Preprocessor.h" // Included for isCodeCompletionEnabled()
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/CXXFieldCollector.h"
#include "clang/Sema/DeclSpec.h"
@@ -62,24 +64,29 @@ namespace {
class TypeNameValidatorCCC : public CorrectionCandidateCallback {
public:
- TypeNameValidatorCCC(bool AllowInvalid, bool WantClass=false)
- : AllowInvalidDecl(AllowInvalid), WantClassName(WantClass) {
+ TypeNameValidatorCCC(bool AllowInvalid, bool WantClass=false,
+ bool AllowTemplates=false)
+ : AllowInvalidDecl(AllowInvalid), WantClassName(WantClass),
+ AllowClassTemplates(AllowTemplates) {
WantExpressionKeywords = false;
WantCXXNamedCasts = false;
WantRemainingKeywords = false;
}
- virtual bool ValidateCandidate(const TypoCorrection &candidate) {
- if (NamedDecl *ND = candidate.getCorrectionDecl())
- return (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) &&
- (AllowInvalidDecl || !ND->isInvalidDecl());
- else
- return !WantClassName && candidate.isKeyword();
+ bool ValidateCandidate(const TypoCorrection &candidate) override {
+ if (NamedDecl *ND = candidate.getCorrectionDecl()) {
+ bool IsType = isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND);
+ bool AllowedTemplate = AllowClassTemplates && isa<ClassTemplateDecl>(ND);
+ return (IsType || AllowedTemplate) &&
+ (AllowInvalidDecl || !ND->isInvalidDecl());
+ }
+ return !WantClassName && candidate.isKeyword();
}
private:
bool AllowInvalidDecl;
bool WantClassName;
+ bool AllowClassTemplates;
};
}
@@ -121,6 +128,65 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
return false;
}
+static ParsedType recoverFromTypeInKnownDependentBase(Sema &S,
+ const IdentifierInfo &II,
+ SourceLocation NameLoc) {
+ // Find the first parent class template context, if any.
+ // FIXME: Perform the lookup in all enclosing class templates.
+ const CXXRecordDecl *RD = nullptr;
+ for (DeclContext *DC = S.CurContext; DC; DC = DC->getParent()) {
+ RD = dyn_cast<CXXRecordDecl>(DC);
+ if (RD && RD->getDescribedClassTemplate())
+ break;
+ }
+ if (!RD)
+ return ParsedType();
+
+ // Look for type decls in dependent base classes that have known primary
+ // templates.
+ bool FoundTypeDecl = false;
+ for (const auto &Base : RD->bases()) {
+ auto *TST = Base.getType()->getAs<TemplateSpecializationType>();
+ if (!TST || !TST->isDependentType())
+ continue;
+ auto *TD = TST->getTemplateName().getAsTemplateDecl();
+ if (!TD)
+ continue;
+ auto *BasePrimaryTemplate = cast<CXXRecordDecl>(TD->getTemplatedDecl());
+ // FIXME: Allow lookup into non-dependent bases of dependent bases, possibly
+ // by calling or integrating with the main LookupQualifiedName mechanism.
+ for (NamedDecl *ND : BasePrimaryTemplate->lookup(&II)) {
+ if (FoundTypeDecl)
+ return ParsedType();
+ FoundTypeDecl = isa<TypeDecl>(ND);
+ if (!FoundTypeDecl)
+ return ParsedType();
+ }
+ }
+ if (!FoundTypeDecl)
+ return ParsedType();
+
+ // We found some types in dependent base classes. Recover as if the user
+ // wrote 'typename MyClass::II' instead of 'II'. We'll fully resolve the
+ // lookup during template instantiation.
+ S.Diag(NameLoc, diag::ext_found_via_dependent_bases_lookup) << &II;
+
+ ASTContext &Context = S.Context;
+ auto *NNS = NestedNameSpecifier::Create(Context, nullptr, false,
+ cast<Type>(Context.getRecordType(RD)));
+ QualType T = Context.getDependentNameType(ETK_Typename, NNS, &II);
+
+ CXXScopeSpec SS;
+ SS.MakeTrivial(Context, NNS, SourceRange(NameLoc));
+
+ TypeLocBuilder Builder;
+ DependentNameTypeLoc DepTL = Builder.push<DependentNameTypeLoc>(T);
+ DepTL.setNameLoc(NameLoc);
+ DepTL.setElaboratedKeywordLoc(SourceLocation());
+ DepTL.setQualifierLoc(SS.getWithLocInContext(Context));
+ return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
+}
+
/// \brief If the identifier refers to a type name within this scope,
/// return the declaration of that type.
///
@@ -137,7 +203,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
bool WantNontrivialTypeSourceInfo,
IdentifierInfo **CorrectedII) {
// Determine where we will perform name lookup.
- DeclContext *LookupCtx = 0;
+ DeclContext *LookupCtx = nullptr;
if (ObjectTypePtr) {
QualType ObjectType = ObjectTypePtr.get();
if (ObjectType->isRecordType())
@@ -165,11 +231,9 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc).get();
NestedNameSpecifierLoc QualifierLoc = SS->getWithLocInContext(Context);
- QualType T =
- CheckTypenameType(ETK_None, SourceLocation(), QualifierLoc,
- II, NameLoc);
-
- return ParsedType::make(T);
+ QualType T = CheckTypenameType(ETK_None, SourceLocation(), QualifierLoc,
+ II, NameLoc);
+ return ParsedType::make(T);
}
return ParsedType();
@@ -204,16 +268,25 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
} else {
// Perform unqualified name lookup.
LookupName(Result, S);
+
+ // For unqualified lookup in a class template in MSVC mode, look into
+ // dependent base classes where the primary class template is known.
+ if (Result.empty() && getLangOpts().MSVCCompat && (!SS || SS->isEmpty())) {
+ if (ParsedType TypeInBase =
+ recoverFromTypeInKnownDependentBase(*this, II, NameLoc))
+ return TypeInBase;
+ }
}
-
- NamedDecl *IIDecl = 0;
+
+ NamedDecl *IIDecl = nullptr;
switch (Result.getResultKind()) {
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
if (CorrectedII) {
TypeNameValidatorCCC Validator(true, isClassName);
TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(),
- Kind, S, SS, Validator);
+ Kind, S, SS, Validator,
+ CTK_ErrorRecovery);
IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo();
TemplateTy Template;
bool MemberOfUnknownSpecialization;
@@ -303,8 +376,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) {
DiagnoseUseOfDecl(IIDecl, NameLoc);
- if (T.isNull())
- T = Context.getTypeDeclType(TD);
+ T = Context.getTypeDeclType(TD);
// NOTE: avoid constructing an ElaboratedType(Loc) if this is a
// constructor or destructor name (in such a case, the scope specifier
@@ -338,6 +410,50 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
return ParsedType::make(T);
}
+// Builds a fake NNS for the given decl context.
+static NestedNameSpecifier *
+synthesizeCurrentNestedNameSpecifier(ASTContext &Context, DeclContext *DC) {
+ for (;; DC = DC->getLookupParent()) {
+ DC = DC->getPrimaryContext();
+ auto *ND = dyn_cast<NamespaceDecl>(DC);
+ if (ND && !ND->isInline() && !ND->isAnonymousNamespace())
+ return NestedNameSpecifier::Create(Context, nullptr, ND);
+ else if (auto *RD = dyn_cast<CXXRecordDecl>(DC))
+ return NestedNameSpecifier::Create(Context, nullptr, RD->isTemplateDecl(),
+ RD->getTypeForDecl());
+ else if (isa<TranslationUnitDecl>(DC))
+ return NestedNameSpecifier::GlobalSpecifier(Context);
+ }
+ llvm_unreachable("something isn't in TU scope?");
+}
+
+ParsedType Sema::ActOnDelayedDefaultTemplateArg(const IdentifierInfo &II,
+ SourceLocation NameLoc) {
+ // Accepting an undeclared identifier as a default argument for a template
+ // type parameter is a Microsoft extension.
+ Diag(NameLoc, diag::ext_ms_delayed_template_argument) << &II;
+
+ // Build a fake DependentNameType that will perform lookup into CurContext at
+ // instantiation time. The name specifier isn't dependent, so template
+ // instantiation won't transform it. It will retry the lookup, however.
+ NestedNameSpecifier *NNS =
+ synthesizeCurrentNestedNameSpecifier(Context, CurContext);
+ QualType T = Context.getDependentNameType(ETK_None, NNS, &II);
+
+ // Build type location information. We synthesized the qualifier, so we have
+ // to build a fake NestedNameSpecifierLoc.
+ NestedNameSpecifierLocBuilder NNSLocBuilder;
+ NNSLocBuilder.MakeTrivial(Context, NNS, SourceRange(NameLoc));
+ NestedNameSpecifierLoc QualifierLoc = NNSLocBuilder.getWithLocInContext(Context);
+
+ TypeLocBuilder Builder;
+ DependentNameTypeLoc DepTL = Builder.push<DependentNameTypeLoc>(T);
+ DepTL.setNameLoc(NameLoc);
+ DepTL.setElaboratedKeywordLoc(SourceLocation());
+ DepTL.setQualifierLoc(QualifierLoc);
+ return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
+}
+
/// isTagName() - This method is called *for error recovery purposes only*
/// to determine if the specified name is a valid tag name ("struct foo"). If
/// so, this returns the TST for the tag corresponding to it (TST_enum,
@@ -381,29 +497,29 @@ bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) {
const Type *Ty = SS->getScopeRep()->getAsType();
CXXRecordDecl *RD = cast<CXXRecordDecl>(CurContext);
- for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(),
- BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base)
- if (Context.hasSameUnqualifiedType(QualType(Ty, 1), Base->getType()))
+ for (const auto &Base : RD->bases())
+ if (Context.hasSameUnqualifiedType(QualType(Ty, 1), Base.getType()))
return true;
return S->isFunctionPrototypeScope();
}
return CurContext->isFunctionOrMethod() || S->isFunctionPrototypeScope();
}
-bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
+void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
SourceLocation IILoc,
Scope *S,
CXXScopeSpec *SS,
- ParsedType &SuggestedType) {
+ ParsedType &SuggestedType,
+ bool AllowClassTemplates) {
// We don't have anything to suggest (yet).
SuggestedType = ParsedType();
// 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.
- TypeNameValidatorCCC Validator(false);
+ TypeNameValidatorCCC Validator(false, false, AllowClassTemplates);
if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(II, IILoc),
LookupOrdinaryName, S, SS,
- Validator)) {
+ Validator, CTK_ErrorRecovery)) {
if (Corrected.isKeyword()) {
// We corrected to a keyword.
diagnoseTypo(Corrected, PDiag(diag::err_unknown_typename_suggest) << II);
@@ -434,7 +550,7 @@ bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
/*IsCtorOrDtorName=*/false,
/*NonTrivialTypeSourceInfo=*/true);
}
- return true;
+ return;
}
if (getLangOpts().CPlusPlus) {
@@ -453,7 +569,7 @@ bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
Diag(TplDecl->getLocation(), diag::note_template_decl_here)
<< TplDecl->getTemplateParameters()->getSourceRange();
}
- return true;
+ return;
}
}
@@ -467,11 +583,11 @@ bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
<< II << DC << SS->getRange();
else if (isDependentScopeSpecifier(*SS)) {
unsigned DiagID = diag::err_typename_missing;
- if (getLangOpts().MicrosoftMode && isMicrosoftMissingTypename(SS, S))
- DiagID = diag::warn_typename_missing;
+ if (getLangOpts().MSVCCompat && isMicrosoftMissingTypename(SS, S))
+ DiagID = diag::ext_typename_missing;
Diag(SS->getRange().getBegin(), DiagID)
- << (NestedNameSpecifier *)SS->getScopeRep() << II->getName()
+ << SS->getScopeRep() << II->getName()
<< SourceRange(SS->getRange().getBegin(), IILoc)
<< FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename ");
SuggestedType = ActOnTypenameType(S, SourceLocation(),
@@ -480,8 +596,6 @@ bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
assert(SS && SS->isInvalid() &&
"Invalid scope specifier has already been diagnosed");
}
-
- return true;
}
/// \brief Determine whether the given result set contains either a type name
@@ -508,35 +622,30 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result,
LookupResult R(SemaRef, Name, NameLoc, Sema::LookupTagName);
SemaRef.LookupParsedName(R, S, &SS);
if (TagDecl *Tag = R.getAsSingle<TagDecl>()) {
- const char *TagName = 0;
- const char *FixItTagName = 0;
+ StringRef FixItTagName;
switch (Tag->getTagKind()) {
case TTK_Class:
- TagName = "class";
FixItTagName = "class ";
break;
case TTK_Enum:
- TagName = "enum";
FixItTagName = "enum ";
break;
case TTK_Struct:
- TagName = "struct";
FixItTagName = "struct ";
break;
case TTK_Interface:
- TagName = "__interface";
FixItTagName = "__interface ";
break;
case TTK_Union:
- TagName = "union";
FixItTagName = "union ";
break;
}
+ StringRef TagName = FixItTagName.drop_back();
SemaRef.Diag(NameLoc, diag::err_use_of_tag_name_without_tag)
<< Name << TagName << SemaRef.getLangOpts().CPlusPlus
<< FixItHint::CreateInsertion(NameLoc, FixItTagName);
@@ -579,16 +688,23 @@ Sema::NameClassification Sema::ClassifyName(Scope *S,
CorrectionCandidateCallback *CCC) {
DeclarationNameInfo NameInfo(Name, NameLoc);
ObjCMethodDecl *CurMethod = getCurMethodDecl();
-
+
if (NextToken.is(tok::coloncolon)) {
BuildCXXNestedNameSpecifier(S, *Name, NameLoc, NextToken.getLocation(),
- QualType(), false, SS, 0, false);
-
+ QualType(), false, SS, nullptr, false);
}
-
+
LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
LookupParsedName(Result, S, &SS, !CurMethod);
-
+
+ // For unqualified lookup in a class template in MSVC mode, look into
+ // dependent base classes where the primary class template is known.
+ if (Result.empty() && SS.isEmpty() && getLangOpts().MSVCCompat) {
+ if (ParsedType TypeInBase =
+ recoverFromTypeInKnownDependentBase(*this, *Name, NameLoc))
+ return TypeInBase;
+ }
+
// Perform lookup for Objective-C instance variables (including automatically
// synthesized instance variables), if we're in an Objective-C method.
// FIXME: This lookup really, really needs to be folded in to the normal
@@ -646,13 +762,14 @@ Corrected:
SecondTry = true;
if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
Result.getLookupKind(), S,
- &SS, *CCC)) {
+ &SS, *CCC,
+ CTK_ErrorRecovery)) {
unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest;
unsigned QualifiedDiag = diag::err_no_member_suggest;
NamedDecl *FirstDecl = Corrected.getCorrectionDecl();
NamedDecl *UnderlyingFirstDecl
- = FirstDecl? FirstDecl->getUnderlyingDecl() : 0;
+ = FirstDecl? FirstDecl->getUnderlyingDecl() : nullptr;
if (getLangOpts().CPlusPlus && NextToken.is(tok::less) &&
UnderlyingFirstDecl && isa<TemplateDecl>(UnderlyingFirstDecl)) {
UnqualifiedDiag = diag::err_no_template_suggest;
@@ -725,7 +842,7 @@ Corrected:
// keyword here.
return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(),
NameInfo, IsAddressOfOperand,
- /*TemplateArgs=*/0);
+ /*TemplateArgs=*/nullptr);
}
case LookupResult::Found:
@@ -817,8 +934,8 @@ Corrected:
ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(FirstDecl);
if (!Class) {
// FIXME: It's unfortunate that we don't have a Type node for handling this.
- if (ObjCCompatibleAliasDecl *Alias
- = dyn_cast<ObjCCompatibleAliasDecl>(FirstDecl))
+ if (ObjCCompatibleAliasDecl *Alias =
+ dyn_cast<ObjCCompatibleAliasDecl>(FirstDecl))
Class = Alias->getClassInterface();
}
@@ -845,7 +962,8 @@ Corrected:
// seems likely a type is wanted instead of the non-type that was found.
bool NextIsOp = NextToken.is(tok::amp) || NextToken.is(tok::star);
if ((NextToken.is(tok::identifier) ||
- (NextIsOp && FirstDecl->isFunctionOrFunctionTemplate())) &&
+ (NextIsOp &&
+ FirstDecl->getUnderlyingDecl()->isFunctionOrFunctionTemplate())) &&
isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) {
TypeDecl *Type = Result.getAsSingle<TypeDecl>();
DiagnoseUseOfDecl(Type, NameLoc);
@@ -856,7 +974,8 @@ Corrected:
}
if (FirstDecl->isCXXClassMember())
- return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, 0);
+ return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result,
+ nullptr);
bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
return BuildDeclarationNameExpr(SS, Result, ADL);
@@ -962,12 +1081,9 @@ void Sema::ExitDeclaratorContext(Scope *S) {
void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) {
- FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (FunctionTemplateDecl *TFD = dyn_cast_or_null<FunctionTemplateDecl>(D)) {
- // We assume that the caller has already called
- // ActOnReenterTemplateScope
- FD = TFD->getTemplatedDecl();
- }
+ // We assume that the caller has already called
+ // ActOnReenterTemplateScope so getTemplatedDecl() works.
+ FunctionDecl *FD = D->getAsFunction();
if (!FD)
return;
@@ -1086,9 +1202,8 @@ void Sema::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) {
}
bool Sema::isDeclInScope(NamedDecl *D, DeclContext *Ctx, Scope *S,
- bool ExplicitInstantiationOrSpecialization) {
- return IdResolver.isDeclInScope(D, Ctx, S,
- ExplicitInstantiationOrSpecialization);
+ bool AllowInlineNamespace) {
+ return IdResolver.isDeclInScope(D, Ctx, S, AllowInlineNamespace);
}
Scope *Sema::getScopeForDeclContext(Scope *S, DeclContext *DC) {
@@ -1099,7 +1214,7 @@ Scope *Sema::getScopeForDeclContext(Scope *S, DeclContext *DC) {
return S;
} while ((S = S->getParent()));
- return 0;
+ return nullptr;
}
static bool isOutOfScopePreviousDeclaration(NamedDecl *,
@@ -1108,21 +1223,19 @@ static bool isOutOfScopePreviousDeclaration(NamedDecl *,
/// Filters out lookup results that don't fall within the given scope
/// as determined by isDeclInScope.
-void Sema::FilterLookupForScope(LookupResult &R,
- DeclContext *Ctx, Scope *S,
+void Sema::FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S,
bool ConsiderLinkage,
- bool ExplicitInstantiationOrSpecialization) {
+ bool AllowInlineNamespace) {
LookupResult::Filter F = R.makeFilter();
while (F.hasNext()) {
NamedDecl *D = F.next();
- if (isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization))
+ if (isDeclInScope(D, Ctx, S, AllowInlineNamespace))
continue;
- if (ConsiderLinkage &&
- isOutOfScopePreviousDeclaration(D, Ctx, Context))
+ if (ConsiderLinkage && isOutOfScopePreviousDeclaration(D, Ctx, Context))
continue;
-
+
F.erase();
}
@@ -1173,8 +1286,8 @@ static bool IsDisallowedCopyOrAssign(const CXXMethodDecl *D) {
//
// When we see foo we don't know if after the typedef we will get 'A' or '*A'
// for example. If 'A', foo will have external linkage. If we have '*A',
-// foo will have no linkage. Since we can't know untill we get to the end
-// of the typedef, this function finds out if D might have non external linkage.
+// foo will have no linkage. Since we can't know until we get to the end
+// of the typedef, this function finds out if D might have non-external linkage.
// Callers should verify at the end of the TU if it D has external linkage or
// not.
bool Sema::mightHaveNonExternalLinkage(const DeclaratorDecl *D) {
@@ -1204,7 +1317,8 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
if (D->isInvalidDecl() || D->isUsed() || D->hasAttr<UnusedAttr>())
return false;
- // Ignore class templates.
+ // Ignore all entities declared within templates, and out-of-line definitions
+ // of members of class templates.
if (D->getDeclContext()->isDependentContext() ||
D->getLexicalDeclContext()->isDependentContext())
return false;
@@ -1218,8 +1332,7 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
return false;
} else {
// 'static inline' functions are defined in headers; don't warn.
- if (FD->isInlineSpecified() &&
- !isMainFileLoc(*this, FD->getLocation()))
+ if (FD->isInlined() && !isMainFileLoc(*this, FD->getLocation()))
return false;
}
@@ -1244,6 +1357,8 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
}
// Only warn for unused decls internal to the translation unit.
+ // FIXME: This seems like a bogus check; it suppresses -Wunused-function
+ // for inline functions defined in the main source file, for instance.
return mightHaveNonExternalLinkage(D);
}
@@ -1271,7 +1386,8 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
if (D->isInvalidDecl())
return false;
- if (D->isReferenced() || D->isUsed() || D->hasAttr<UnusedAttr>())
+ if (D->isReferenced() || D->isUsed() || D->hasAttr<UnusedAttr>() ||
+ D->hasAttr<ObjCPreciseLifetimeAttr>())
return false;
if (isa<LabelDecl>(D))
@@ -1309,7 +1425,8 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return false;
if (const Expr *Init = VD->getInit()) {
- if (const ExprWithCleanups *Cleanups = dyn_cast<ExprWithCleanups>(Init))
+ if (const ExprWithCleanups *Cleanups =
+ dyn_cast<ExprWithCleanups>(Init))
Init = Cleanups->getSubExpr();
const CXXConstructExpr *Construct =
dyn_cast<CXXConstructExpr>(Init);
@@ -1344,10 +1461,10 @@ static void GenerateFixForUnusedDecl(const NamedDecl *D, ASTContext &Ctx,
/// DiagnoseUnusedDecl - Emit warnings about declarations that are not used
/// unless they are marked attr(unused).
void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
- FixItHint Hint;
if (!ShouldDiagnoseUnusedDecl(D))
return;
+ FixItHint Hint;
GenerateFixForUnusedDecl(D, Context, Hint);
unsigned DiagID;
@@ -1365,18 +1482,18 @@ static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
// Verify that we have no forward references left. If so, there was a goto
// or address of a label taken, but no definition of it. Label fwd
// definitions are indicated with a null substmt.
- if (L->getStmt() == 0)
+ if (L->getStmt() == nullptr)
S.Diag(L->getLocation(), diag::err_undeclared_label_use) <<L->getDeclName();
}
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
+ S->mergeNRVOIntoParent();
+
if (S->decl_empty()) return;
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
"Scope shouldn't contain decls!");
- for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end();
- I != E; ++I) {
- Decl *TmpD = (*I);
+ for (auto *TmpD : S->decls()) {
assert(TmpD && "This decl didn't get pushed??");
assert(isa<NamedDecl>(TmpD) && "Decl isn't NamedDecl?");
@@ -1395,16 +1512,6 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
// Remove this name from our lexical scope.
IdResolver.RemoveDecl(D);
}
- DiagnoseUnusedBackingIvarInAccessor(S);
-}
-
-void Sema::ActOnStartFunctionDeclarator() {
- ++InFunctionDeclarator;
-}
-
-void Sema::ActOnEndFunctionDeclarator() {
- assert(InFunctionDeclarator);
- --InFunctionDeclarator;
}
/// \brief Look for an Objective-C class in the translation unit.
@@ -1432,8 +1539,8 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
// find an Objective-C class name.
DeclFilterCCC<ObjCInterfaceDecl> Validator;
if (TypoCorrection C = CorrectTypo(DeclarationNameInfo(Id, IdLoc),
- LookupOrdinaryName, TUScope, NULL,
- Validator)) {
+ LookupOrdinaryName, TUScope, nullptr,
+ Validator, CTK_ErrorRecovery)) {
diagnoseTypo(C, PDiag(diag::err_undef_interface_suggest) << Id);
IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>();
Id = IDecl->getIdentifier();
@@ -1495,6 +1602,20 @@ static void LookupPredefedObjCSuperType(Sema &ThisSema, Scope *S,
Context.setObjCSuperType(Context.getTagDeclType(TD));
}
+static StringRef getHeaderName(ASTContext::GetBuiltinTypeError Error) {
+ switch (Error) {
+ case ASTContext::GE_None:
+ return "";
+ case ASTContext::GE_Missing_stdio:
+ return "stdio.h";
+ case ASTContext::GE_Missing_setjmp:
+ return "setjmp.h";
+ case ASTContext::GE_Missing_ucontext:
+ return "ucontext.h";
+ }
+ llvm_unreachable("unhandled error kind");
+}
+
/// LazilyCreateBuiltin - The specified Builtin-ID was first used at
/// file scope. lazily create a decl for it. ForRedeclaration is true
/// if we're creating this built-in in anticipation of redeclaring the
@@ -1508,28 +1629,12 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
ASTContext::GetBuiltinTypeError Error;
QualType R = Context.GetBuiltinType(BID, Error);
- switch (Error) {
- case ASTContext::GE_None:
- // Okay
- break;
-
- case ASTContext::GE_Missing_stdio:
+ if (Error) {
if (ForRedeclaration)
- Diag(Loc, diag::warn_implicit_decl_requires_stdio)
- << Context.BuiltinInfo.GetName(BID);
- return 0;
-
- case ASTContext::GE_Missing_setjmp:
- if (ForRedeclaration)
- Diag(Loc, diag::warn_implicit_decl_requires_setjmp)
- << Context.BuiltinInfo.GetName(BID);
- return 0;
-
- case ASTContext::GE_Missing_ucontext:
- if (ForRedeclaration)
- Diag(Loc, diag::warn_implicit_decl_requires_ucontext)
- << Context.BuiltinInfo.GetName(BID);
- return 0;
+ Diag(Loc, diag::warn_implicit_decl_requires_sysheader)
+ << getHeaderName(Error)
+ << Context.BuiltinInfo.GetName(BID);
+ return nullptr;
}
if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(BID)) {
@@ -1537,11 +1642,10 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
<< Context.BuiltinInfo.GetName(BID)
<< R;
if (Context.BuiltinInfo.getHeaderName(BID) &&
- Diags.getDiagnosticLevel(diag::ext_implicit_lib_function_decl, Loc)
- != DiagnosticsEngine::Ignored)
- Diag(Loc, diag::note_please_include_header)
- << Context.BuiltinInfo.getHeaderName(BID)
- << Context.BuiltinInfo.GetName(BID);
+ !Diags.isIgnored(diag::ext_implicit_lib_function_decl, Loc))
+ Diag(Loc, diag::note_include_header_or_declare)
+ << Context.BuiltinInfo.getHeaderName(BID)
+ << Context.BuiltinInfo.GetName(BID);
}
DeclContext *Parent = Context.getTranslationUnitDecl();
@@ -1549,13 +1653,14 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
LinkageSpecDecl *CLinkageDecl =
LinkageSpecDecl::Create(Context, Parent, Loc, Loc,
LinkageSpecDecl::lang_c, false);
+ CLinkageDecl->setImplicit();
Parent->addDecl(CLinkageDecl);
Parent = CLinkageDecl;
}
FunctionDecl *New = FunctionDecl::Create(Context,
Parent,
- Loc, Loc, II, R, /*TInfo=*/0,
+ Loc, Loc, II, R, /*TInfo=*/nullptr,
SC_Extern,
false,
/*hasPrototype=*/true);
@@ -1565,12 +1670,11 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
// FunctionDecl.
if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) {
SmallVector<ParmVarDecl*, 16> Params;
- for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) {
+ for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) {
ParmVarDecl *parm =
- ParmVarDecl::Create(Context, New, SourceLocation(),
- SourceLocation(), 0,
- FT->getArgType(i), /*TInfo=*/0,
- SC_None, 0);
+ ParmVarDecl::Create(Context, New, SourceLocation(), SourceLocation(),
+ nullptr, FT->getParamType(i), /*TInfo=*/nullptr,
+ SC_None, nullptr);
parm->setScopeInfo(0, i);
Params.push_back(parm);
}
@@ -1789,7 +1893,7 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
Context.getSourceManager().isInSystemHeader(New->getLocation())))
return;
- Diag(New->getLocation(), diag::warn_redefinition_of_typedef)
+ Diag(New->getLocation(), diag::ext_redefinition_of_typedef)
<< New->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
return;
@@ -1797,46 +1901,19 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
/// DeclhasAttr - returns true if decl Declaration already has the target
/// attribute.
-static bool
-DeclHasAttr(const Decl *D, const Attr *A) {
- // There can be multiple AvailabilityAttr in a Decl. Make sure we copy
- // all of them. It is mergeAvailabilityAttr in SemaDeclAttr.cpp that is
- // responsible for making sure they are consistent.
- const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(A);
- if (AA)
- return false;
-
- // The following thread safety attributes can also be duplicated.
- switch (A->getKind()) {
- case attr::ExclusiveLocksRequired:
- case attr::SharedLocksRequired:
- case attr::LocksExcluded:
- case attr::ExclusiveLockFunction:
- case attr::SharedLockFunction:
- case attr::UnlockFunction:
- case attr::ExclusiveTrylockFunction:
- case attr::SharedTrylockFunction:
- case attr::GuardedBy:
- case attr::PtGuardedBy:
- case attr::AcquiredBefore:
- case attr::AcquiredAfter:
- return false;
- default:
- ;
- }
-
+static bool DeclHasAttr(const Decl *D, const Attr *A) {
const OwnershipAttr *OA = dyn_cast<OwnershipAttr>(A);
const AnnotateAttr *Ann = dyn_cast<AnnotateAttr>(A);
- for (Decl::attr_iterator i = D->attr_begin(), e = D->attr_end(); i != e; ++i)
- if ((*i)->getKind() == A->getKind()) {
+ for (const auto *i : D->attrs())
+ if (i->getKind() == A->getKind()) {
if (Ann) {
- if (Ann->getAnnotation() == cast<AnnotateAttr>(*i)->getAnnotation())
+ if (Ann->getAnnotation() == cast<AnnotateAttr>(i)->getAnnotation())
return true;
continue;
}
// FIXME: Don't hardcode this check
- if (OA && isa<OwnershipAttr>(*i))
- return OA->getOwnKind() == cast<OwnershipAttr>(*i)->getOwnKind();
+ if (OA && isa<OwnershipAttr>(i))
+ return OA->getOwnKind() == cast<OwnershipAttr>(i)->getOwnKind();
return true;
}
@@ -1858,12 +1935,10 @@ static bool isAttributeTargetADefinition(Decl *D) {
static bool mergeAlignedAttrs(Sema &S, NamedDecl *New, Decl *Old) {
// Look for alignas attributes on Old, and pick out whichever attribute
// specifies the strictest alignment requirement.
- AlignedAttr *OldAlignasAttr = 0;
- AlignedAttr *OldStrictestAlignAttr = 0;
+ AlignedAttr *OldAlignasAttr = nullptr;
+ AlignedAttr *OldStrictestAlignAttr = nullptr;
unsigned OldAlign = 0;
- for (specific_attr_iterator<AlignedAttr>
- I = Old->specific_attr_begin<AlignedAttr>(),
- E = Old->specific_attr_end<AlignedAttr>(); I != E; ++I) {
+ for (auto *I : Old->specific_attrs<AlignedAttr>()) {
// FIXME: We have no way of representing inherited dependent alignments
// in a case like:
// template<int A, int B> struct alignas(A) X;
@@ -1874,26 +1949,24 @@ static bool mergeAlignedAttrs(Sema &S, NamedDecl *New, Decl *Old) {
return false;
if (I->isAlignas())
- OldAlignasAttr = *I;
+ OldAlignasAttr = I;
unsigned Align = I->getAlignment(S.Context);
if (Align > OldAlign) {
OldAlign = Align;
- OldStrictestAlignAttr = *I;
+ OldStrictestAlignAttr = I;
}
}
// Look for alignas attributes on New.
- AlignedAttr *NewAlignasAttr = 0;
+ AlignedAttr *NewAlignasAttr = nullptr;
unsigned NewAlign = 0;
- for (specific_attr_iterator<AlignedAttr>
- I = New->specific_attr_begin<AlignedAttr>(),
- E = New->specific_attr_end<AlignedAttr>(); I != E; ++I) {
+ for (auto *I : New->specific_attrs<AlignedAttr>()) {
if (I->isAlignmentDependent())
return false;
if (I->isAlignas())
- NewAlignasAttr = *I;
+ NewAlignasAttr = I;
unsigned Align = I->getAlignment(S.Context);
if (Align > NewAlign)
@@ -1939,9 +2012,9 @@ static bool mergeAlignedAttrs(Sema &S, NamedDecl *New, Decl *Old) {
// specifier, any other declaration of that object shall also
// have no alignment specifier.
S.Diag(New->getLocation(), diag::err_alignas_missing_on_definition)
- << OldAlignasAttr->isC11();
+ << OldAlignasAttr;
S.Diag(OldAlignasAttr->getLocation(), diag::note_alignas_on_declaration)
- << OldAlignasAttr->isC11();
+ << OldAlignasAttr;
}
bool AnyAdded = false;
@@ -1966,40 +2039,46 @@ static bool mergeAlignedAttrs(Sema &S, NamedDecl *New, Decl *Old) {
return AnyAdded;
}
-static bool mergeDeclAttribute(Sema &S, NamedDecl *D, InheritableAttr *Attr,
- bool Override) {
- InheritableAttr *NewAttr = NULL;
+static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
+ const InheritableAttr *Attr, bool Override) {
+ InheritableAttr *NewAttr = nullptr;
unsigned AttrSpellingListIndex = Attr->getSpellingListIndex();
- if (AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attr))
+ if (const auto *AA = dyn_cast<AvailabilityAttr>(Attr))
NewAttr = S.mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(),
AA->getIntroduced(), AA->getDeprecated(),
AA->getObsoleted(), AA->getUnavailable(),
AA->getMessage(), Override,
AttrSpellingListIndex);
- else if (VisibilityAttr *VA = dyn_cast<VisibilityAttr>(Attr))
+ else if (const auto *VA = dyn_cast<VisibilityAttr>(Attr))
NewAttr = S.mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
AttrSpellingListIndex);
- else if (TypeVisibilityAttr *VA = dyn_cast<TypeVisibilityAttr>(Attr))
+ else if (const auto *VA = dyn_cast<TypeVisibilityAttr>(Attr))
NewAttr = S.mergeTypeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
AttrSpellingListIndex);
- else if (DLLImportAttr *ImportA = dyn_cast<DLLImportAttr>(Attr))
+ else if (const auto *ImportA = dyn_cast<DLLImportAttr>(Attr))
NewAttr = S.mergeDLLImportAttr(D, ImportA->getRange(),
AttrSpellingListIndex);
- else if (DLLExportAttr *ExportA = dyn_cast<DLLExportAttr>(Attr))
+ else if (const auto *ExportA = dyn_cast<DLLExportAttr>(Attr))
NewAttr = S.mergeDLLExportAttr(D, ExportA->getRange(),
AttrSpellingListIndex);
- else if (FormatAttr *FA = dyn_cast<FormatAttr>(Attr))
+ else if (const auto *FA = dyn_cast<FormatAttr>(Attr))
NewAttr = S.mergeFormatAttr(D, FA->getRange(), FA->getType(),
FA->getFormatIdx(), FA->getFirstArg(),
AttrSpellingListIndex);
- else if (SectionAttr *SA = dyn_cast<SectionAttr>(Attr))
+ else if (const auto *SA = dyn_cast<SectionAttr>(Attr))
NewAttr = S.mergeSectionAttr(D, SA->getRange(), SA->getName(),
AttrSpellingListIndex);
+ else if (const auto *IA = dyn_cast<MSInheritanceAttr>(Attr))
+ NewAttr = S.mergeMSInheritanceAttr(D, IA->getRange(), IA->getBestCase(),
+ AttrSpellingListIndex,
+ IA->getSemanticSpelling());
else if (isa<AlignedAttr>(Attr))
// AlignedAttrs are handled separately, because we need to handle all
// such attributes on a declaration at the same time.
- NewAttr = 0;
- else if (!DeclHasAttr(D, Attr))
+ NewAttr = nullptr;
+ else if (isa<DeprecatedAttr>(Attr) && Override)
+ NewAttr = nullptr;
+ else if (Attr->duplicatesAllowed() || !DeclHasAttr(D, Attr))
NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
if (NewAttr) {
@@ -2025,16 +2104,13 @@ static const Decl *getDefinition(const Decl *D) {
if (FD->isDefined(Def))
return Def;
}
- return NULL;
+ return nullptr;
}
static bool hasAttribute(const Decl *D, attr::Kind Kind) {
- for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end();
- I != E; ++I) {
- Attr *Attribute = *I;
+ for (const auto *Attribute : D->attrs())
if (Attribute->getKind() == Kind)
return true;
- }
return false;
}
@@ -2097,9 +2173,9 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
// specifier, any other declaration of that object shall also
// have no alignment specifier.
S.Diag(Def->getLocation(), diag::err_alignas_missing_on_definition)
- << AA->isC11();
+ << AA;
S.Diag(NewAttribute->getLocation(), diag::note_alignas_on_declaration)
- << AA->isC11();
+ << AA;
NewAttributes.erase(NewAttributes.begin() + I);
--E;
continue;
@@ -2138,15 +2214,12 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
// we process them.
if (!foundAny) New->setAttrs(AttrVec());
- for (specific_attr_iterator<InheritableAttr>
- i = Old->specific_attr_begin<InheritableAttr>(),
- e = Old->specific_attr_end<InheritableAttr>();
- i != e; ++i) {
+ for (auto *I : Old->specific_attrs<InheritableAttr>()) {
bool Override = false;
// Ignore deprecated/unavailable/availability attributes if requested.
- if (isa<DeprecatedAttr>(*i) ||
- isa<UnavailableAttr>(*i) ||
- isa<AvailabilityAttr>(*i)) {
+ if (isa<DeprecatedAttr>(I) ||
+ isa<UnavailableAttr>(I) ||
+ isa<AvailabilityAttr>(I)) {
switch (AMK) {
case AMK_None:
continue;
@@ -2161,10 +2234,10 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
}
// Already handled.
- if (isa<UsedAttr>(*i))
+ if (isa<UsedAttr>(I))
continue;
- if (mergeDeclAttribute(*this, New, *i, Override))
+ if (mergeDeclAttribute(*this, New, I, Override))
foundAny = true;
}
@@ -2183,9 +2256,9 @@ static void mergeParamDeclAttributes(ParmVarDecl *newDecl,
// The first declaration of a function shall specify the
// carries_dependency attribute for its declarator-id if any declaration
// of the function specifies the carries_dependency attribute.
- if (newDecl->hasAttr<CarriesDependencyAttr>() &&
- !oldDecl->hasAttr<CarriesDependencyAttr>()) {
- S.Diag(newDecl->getAttr<CarriesDependencyAttr>()->getLocation(),
+ const CarriesDependencyAttr *CDA = newDecl->getAttr<CarriesDependencyAttr>();
+ if (CDA && !oldDecl->hasAttr<CarriesDependencyAttr>()) {
+ S.Diag(CDA->getLocation(),
diag::err_carries_dependency_missing_on_first_decl) << 1/*Param*/;
// Find the first declaration of the parameter.
// FIXME: Should we build redeclaration chains for function parameters?
@@ -2206,12 +2279,10 @@ static void mergeParamDeclAttributes(ParmVarDecl *newDecl,
// done before we process them.
if (!foundAny) newDecl->setAttrs(AttrVec());
- for (specific_attr_iterator<InheritableParamAttr>
- i = oldDecl->specific_attr_begin<InheritableParamAttr>(),
- e = oldDecl->specific_attr_end<InheritableParamAttr>(); i != e; ++i) {
- if (!DeclHasAttr(newDecl, *i)) {
+ for (const auto *I : oldDecl->specific_attrs<InheritableParamAttr>()) {
+ if (!DeclHasAttr(newDecl, I)) {
InheritableAttr *newAttr =
- cast<InheritableParamAttr>((*i)->clone(S.Context));
+ cast<InheritableParamAttr>(I->clone(S.Context));
newAttr->setInherited(true);
newDecl->addAttr(newAttr);
foundAny = true;
@@ -2255,6 +2326,24 @@ Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) {
return Sema::CXXInvalid;
}
+// Determine whether the previous declaration was a definition, implicit
+// declaration, or a declaration.
+template <typename T>
+static std::pair<diag::kind, SourceLocation>
+getNoteDiagForInvalidRedeclaration(const T *Old, const T *New) {
+ diag::kind PrevDiag;
+ SourceLocation OldLocation = Old->getLocation();
+ if (Old->isThisDeclarationADefinition())
+ PrevDiag = diag::note_previous_definition;
+ else if (Old->isImplicit()) {
+ PrevDiag = diag::note_previous_implicit_declaration;
+ if (OldLocation.isInvalid())
+ OldLocation = New->getLocation();
+ } else
+ PrevDiag = diag::note_previous_declaration;
+ return std::make_pair(PrevDiag, OldLocation);
+}
+
/// canRedefineFunction - checks if a function can be redefined. Currently,
/// only extern inline functions can be redefined, and even then only in
/// GNU89 mode.
@@ -2298,15 +2387,10 @@ static bool haveIncompatibleLanguageLinkages(const T *Old, const T *New) {
/// merged with.
///
/// Returns true if there was an error, false otherwise.
-bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
- bool MergeTypeWithOld) {
+bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
+ Scope *S, bool MergeTypeWithOld) {
// Verify the old decl was also a function.
- FunctionDecl *Old = 0;
- if (FunctionTemplateDecl *OldFunctionTemplate
- = dyn_cast<FunctionTemplateDecl>(OldD))
- Old = OldFunctionTemplate->getTemplatedDecl();
- else
- Old = dyn_cast<FunctionDecl>(OldD);
+ FunctionDecl *Old = OldD->getAsFunction();
if (!Old) {
if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(OldD)) {
if (New->getFriendObjectKind()) {
@@ -2318,33 +2402,44 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
return true;
}
- Diag(New->getLocation(), diag::err_using_decl_conflict_reverse);
- Diag(Shadow->getTargetDecl()->getLocation(),
- diag::note_using_decl_target);
- Diag(Shadow->getUsingDecl()->getLocation(),
- diag::note_using_decl) << 0;
+ // C++11 [namespace.udecl]p14:
+ // If a function declaration in namespace scope or block scope has the
+ // same name and the same parameter-type-list as a function introduced
+ // by a using-declaration, and the declarations do not declare the same
+ // function, the program is ill-formed.
+
+ // Check whether the two declarations might declare the same function.
+ Old = dyn_cast<FunctionDecl>(Shadow->getTargetDecl());
+ if (Old &&
+ !Old->getDeclContext()->getRedeclContext()->Equals(
+ New->getDeclContext()->getRedeclContext()) &&
+ !(Old->isExternC() && New->isExternC()))
+ Old = nullptr;
+
+ if (!Old) {
+ Diag(New->getLocation(), diag::err_using_decl_conflict_reverse);
+ Diag(Shadow->getTargetDecl()->getLocation(),
+ diag::note_using_decl_target);
+ Diag(Shadow->getUsingDecl()->getLocation(), diag::note_using_decl) << 0;
+ return true;
+ }
+ OldD = Old;
+ } else {
+ Diag(New->getLocation(), diag::err_redefinition_different_kind)
+ << New->getDeclName();
+ Diag(OldD->getLocation(), diag::note_previous_definition);
return true;
}
-
- Diag(New->getLocation(), diag::err_redefinition_different_kind)
- << New->getDeclName();
- Diag(OldD->getLocation(), diag::note_previous_definition);
- return true;
}
// If the old declaration is invalid, just give up here.
if (Old->isInvalidDecl())
return true;
- // Determine whether the previous declaration was a definition,
- // implicit declaration, or a declaration.
diag::kind PrevDiag;
- if (Old->isThisDeclarationADefinition())
- PrevDiag = diag::note_previous_definition;
- else if (Old->isImplicit())
- PrevDiag = diag::note_previous_implicit_declaration;
- else
- PrevDiag = diag::note_previous_declaration;
+ SourceLocation OldLocation;
+ std::tie(PrevDiag, OldLocation) =
+ getNoteDiagForInvalidRedeclaration(Old, New);
// Don't complain about this if we're in GNU89 mode and the old function
// is an extern inline function.
@@ -2356,11 +2451,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
!New->getTemplateSpecializationInfo() &&
!canRedefineFunction(Old, getLangOpts())) {
if (getLangOpts().MicrosoftExt) {
- Diag(New->getLocation(), diag::warn_static_non_static) << New;
- Diag(Old->getLocation(), PrevDiag);
+ Diag(New->getLocation(), diag::ext_static_non_static) << New;
+ Diag(OldLocation, PrevDiag);
} else {
Diag(New->getLocation(), diag::err_static_non_static) << New;
- Diag(Old->getLocation(), PrevDiag);
+ Diag(OldLocation, PrevDiag);
return true;
}
}
@@ -2426,7 +2521,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
Diag(New->getLocation(), diag::err_regparm_mismatch)
<< NewType->getRegParmType()
<< OldType->getRegParmType();
- Diag(Old->getLocation(), diag::note_previous_declaration);
+ Diag(OldLocation, diag::note_previous_declaration);
return true;
}
@@ -2438,7 +2533,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
if (OldTypeInfo.getProducesResult() != NewTypeInfo.getProducesResult()) {
if (NewTypeInfo.getProducesResult()) {
Diag(New->getLocation(), diag::err_returns_retained_mismatch);
- Diag(Old->getLocation(), diag::note_previous_declaration);
+ Diag(OldLocation, diag::note_previous_declaration);
return true;
}
@@ -2482,12 +2577,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
// Redeclarations or specializations of a function or function template
// with a declared return type that uses a placeholder type shall also
// use that placeholder, not a deduced type.
- QualType OldDeclaredReturnType = (Old->getTypeSourceInfo()
- ? Old->getTypeSourceInfo()->getType()->castAs<FunctionType>()
- : OldType)->getResultType();
- QualType NewDeclaredReturnType = (New->getTypeSourceInfo()
- ? New->getTypeSourceInfo()->getType()->castAs<FunctionType>()
- : NewType)->getResultType();
+ QualType OldDeclaredReturnType =
+ (Old->getTypeSourceInfo()
+ ? Old->getTypeSourceInfo()->getType()->castAs<FunctionType>()
+ : OldType)->getReturnType();
+ QualType NewDeclaredReturnType =
+ (New->getTypeSourceInfo()
+ ? New->getTypeSourceInfo()->getType()->castAs<FunctionType>()
+ : NewType)->getReturnType();
QualType ResQT;
if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType) &&
!((NewQType->isDependentType() || OldQType->isDependentType()) &&
@@ -2497,23 +2594,25 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType);
if (ResQT.isNull()) {
if (New->isCXXClassMember() && New->isOutOfLine())
- Diag(New->getLocation(),
- diag::err_member_def_does_not_match_ret_type) << New;
+ Diag(New->getLocation(), diag::err_member_def_does_not_match_ret_type)
+ << New << New->getReturnTypeSourceRange();
else
- Diag(New->getLocation(), diag::err_ovl_diff_return_type);
- Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
+ Diag(New->getLocation(), diag::err_ovl_diff_return_type)
+ << New->getReturnTypeSourceRange();
+ Diag(OldLocation, PrevDiag) << Old << Old->getType()
+ << Old->getReturnTypeSourceRange();
return true;
}
else
NewQType = ResQT;
}
- QualType OldReturnType = OldType->getResultType();
- QualType NewReturnType = cast<FunctionType>(NewQType)->getResultType();
+ QualType OldReturnType = OldType->getReturnType();
+ QualType NewReturnType = cast<FunctionType>(NewQType)->getReturnType();
if (OldReturnType != NewReturnType) {
// If this function has a deduced return type and has already been
// defined, copy the deduced value from the old declaration.
- AutoType *OldAT = Old->getResultType()->getContainedAutoType();
+ AutoType *OldAT = Old->getReturnType()->getContainedAutoType();
if (OldAT && OldAT->isDeduced()) {
New->setType(
SubstAutoType(New->getType(),
@@ -2533,8 +2632,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
NewMethod->setTrivial(OldMethod->isTrivial());
// MSVC allows explicit template specialization at class scope:
- // 2 CXMethodDecls referring to the same function will be injected.
- // We don't want a redeclartion error.
+ // 2 CXXMethodDecls referring to the same function will be injected.
+ // We don't want a redeclaration error.
bool IsClassScopeExplicitSpecialization =
OldMethod->isFunctionTemplateSpecialization() &&
NewMethod->isFunctionTemplateSpecialization();
@@ -2547,7 +2646,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
// is a static member function declaration.
if (OldMethod->isStatic() != NewMethod->isStatic()) {
Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member);
- Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
+ Diag(OldLocation, PrevDiag) << Old << Old->getType();
return true;
}
@@ -2571,7 +2670,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
Diag(New->getLocation(), diag::err_member_redeclared_in_instantiation)
<< New << New->getType();
}
- Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
+ Diag(OldLocation, PrevDiag) << Old << Old->getType();
// Complain if this is an explicit declaration of a special
// member that was initially declared implicitly.
@@ -2599,10 +2698,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
// The first declaration of a function shall specify the noreturn
// attribute if any declaration of that function specifies the noreturn
// attribute.
- if (New->hasAttr<CXX11NoReturnAttr>() &&
- !Old->hasAttr<CXX11NoReturnAttr>()) {
- Diag(New->getAttr<CXX11NoReturnAttr>()->getLocation(),
- diag::err_noreturn_missing_on_first_decl);
+ const CXX11NoReturnAttr *NRA = New->getAttr<CXX11NoReturnAttr>();
+ if (NRA && !Old->hasAttr<CXX11NoReturnAttr>()) {
+ Diag(NRA->getLocation(), diag::err_noreturn_missing_on_first_decl);
Diag(Old->getFirstDecl()->getLocation(),
diag::note_noreturn_missing_first_decl);
}
@@ -2611,9 +2709,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
// The first declaration of a function shall specify the
// carries_dependency attribute for its declarator-id if any declaration
// of the function specifies the carries_dependency attribute.
- if (New->hasAttr<CarriesDependencyAttr>() &&
- !Old->hasAttr<CarriesDependencyAttr>()) {
- Diag(New->getAttr<CarriesDependencyAttr>()->getLocation(),
+ const CarriesDependencyAttr *CDA = New->getAttr<CarriesDependencyAttr>();
+ if (CDA && !Old->hasAttr<CarriesDependencyAttr>()) {
+ Diag(CDA->getLocation(),
diag::err_carries_dependency_missing_on_first_decl) << 0/*Function*/;
Diag(Old->getFirstDecl()->getLocation(),
diag::note_carries_dependency_missing_first_decl) << 0/*Function*/;
@@ -2645,10 +2743,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
// Check cautiously as the friend object kind isn't yet complete.
if (New->getFriendObjectKind() != Decl::FOK_None) {
Diag(New->getLocation(), diag::ext_retained_language_linkage) << New;
- Diag(Old->getLocation(), PrevDiag);
+ Diag(OldLocation, PrevDiag);
} else {
Diag(New->getLocation(), diag::err_different_language_linkage) << New;
- Diag(Old->getLocation(), PrevDiag);
+ Diag(OldLocation, PrevDiag);
return true;
}
}
@@ -2673,32 +2771,26 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
Context.typesAreCompatible(OldQType, NewQType)) {
const FunctionType *OldFuncType = OldQType->getAs<FunctionType>();
const FunctionType *NewFuncType = NewQType->getAs<FunctionType>();
- const FunctionProtoType *OldProto = 0;
+ const FunctionProtoType *OldProto = nullptr;
if (MergeTypeWithOld && isa<FunctionNoProtoType>(NewFuncType) &&
(OldProto = dyn_cast<FunctionProtoType>(OldFuncType))) {
// The old declaration provided a function prototype, but the
// new declaration does not. Merge in the prototype.
assert(!OldProto->hasExceptionSpec() && "Exception spec in C");
- SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(),
- OldProto->arg_type_end());
- NewQType = Context.getFunctionType(NewFuncType->getResultType(),
- ParamTypes,
- OldProto->getExtProtoInfo());
+ SmallVector<QualType, 16> ParamTypes(OldProto->param_types());
+ NewQType =
+ Context.getFunctionType(NewFuncType->getReturnType(), ParamTypes,
+ OldProto->getExtProtoInfo());
New->setType(NewQType);
New->setHasInheritedPrototype();
- // Synthesize a parameter for each argument type.
+ // Synthesize parameters with the same types.
SmallVector<ParmVarDecl*, 16> Params;
- for (FunctionProtoType::arg_type_iterator
- ParamType = OldProto->arg_type_begin(),
- ParamEnd = OldProto->arg_type_end();
- ParamType != ParamEnd; ++ParamType) {
- ParmVarDecl *Param = ParmVarDecl::Create(Context, New,
- SourceLocation(),
- SourceLocation(), 0,
- *ParamType, /*TInfo=*/0,
- SC_None,
- 0);
+ for (const auto &ParamType : OldProto->param_types()) {
+ ParmVarDecl *Param = ParmVarDecl::Create(Context, New, SourceLocation(),
+ SourceLocation(), nullptr,
+ ParamType, /*TInfo=*/nullptr,
+ SC_None, nullptr);
Param->setScopeInfo(0, Params.size());
Param->setImplicit();
Params.push_back(Param);
@@ -2733,21 +2825,21 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
= New->getType()->getAs<FunctionProtoType>();
// Determine whether this is the GNU C extension.
- QualType MergedReturn = Context.mergeTypes(OldProto->getResultType(),
- NewProto->getResultType());
+ QualType MergedReturn = Context.mergeTypes(OldProto->getReturnType(),
+ NewProto->getReturnType());
bool LooseCompatible = !MergedReturn.isNull();
for (unsigned Idx = 0, End = Old->getNumParams();
LooseCompatible && Idx != End; ++Idx) {
ParmVarDecl *OldParm = Old->getParamDecl(Idx);
ParmVarDecl *NewParm = New->getParamDecl(Idx);
if (Context.typesAreCompatible(OldParm->getType(),
- NewProto->getArgType(Idx))) {
+ NewProto->getParamType(Idx))) {
ArgTypes.push_back(NewParm->getType());
} else if (Context.typesAreCompatible(OldParm->getType(),
NewParm->getType(),
/*CompareUnqualified=*/true)) {
- GNUCompatibleParamWarning Warn
- = { OldParm, NewParm, NewProto->getArgType(Idx) };
+ GNUCompatibleParamWarning Warn = { OldParm, NewParm,
+ NewProto->getParamType(Idx) };
Warnings.push_back(Warn);
ArgTypes.push_back(NewParm->getType());
} else
@@ -2785,7 +2877,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
// or 'printf', just warn about the incompatible redeclaration.
if (Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) {
Diag(New->getLocation(), diag::warn_redecl_library_builtin) << New;
- Diag(Old->getLocation(), diag::note_previous_builtin_declaration)
+ Diag(OldLocation, diag::note_previous_builtin_declaration)
<< Old << Old->getType();
// If this is a global redeclaration, just forget hereafter
@@ -2806,7 +2898,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
}
Diag(New->getLocation(), diag::err_conflicting_types) << New->getDeclName();
- Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
+ Diag(OldLocation, PrevDiag) << Old << Old->getType();
return true;
}
@@ -3003,14 +3095,17 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
if (New->isInvalidDecl())
return;
+ VarTemplateDecl *NewTemplate = New->getDescribedVarTemplate();
+
// Verify the old decl was also a variable or variable template.
- VarDecl *Old = 0;
- if (Previous.isSingleResult() &&
- (Old = dyn_cast<VarDecl>(Previous.getFoundDecl()))) {
- if (New->getDescribedVarTemplate())
- Old = Old->getDescribedVarTemplate() ? Old : 0;
- else
- Old = Old->getDescribedVarTemplate() ? 0 : Old;
+ VarDecl *Old = nullptr;
+ VarTemplateDecl *OldTemplate = nullptr;
+ if (Previous.isSingleResult()) {
+ if (NewTemplate) {
+ OldTemplate = dyn_cast<VarTemplateDecl>(Previous.getFoundDecl());
+ Old = OldTemplate ? OldTemplate->getTemplatedDecl() : nullptr;
+ } else
+ Old = dyn_cast<VarDecl>(Previous.getFoundDecl());
}
if (!Old) {
Diag(New->getLocation(), diag::err_redefinition_different_kind)
@@ -3023,6 +3118,13 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
if (!shouldLinkPossiblyHiddenDecl(Old, New))
return;
+ // Ensure the template parameters are compatible.
+ if (NewTemplate &&
+ !TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
+ OldTemplate->getTemplateParameters(),
+ /*Complain=*/true, TPL_TemplateMatch))
+ return;
+
// C++ [class.mem]p1:
// A member shall not be declared twice in the member-specification [...]
//
@@ -3037,9 +3139,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
mergeDeclAttributes(New, Old);
// Warn if an already-declared variable is made a weak_import in a subsequent
// declaration
- if (New->getAttr<WeakImportAttr>() &&
+ if (New->hasAttr<WeakImportAttr>() &&
Old->getStorageClass() == SC_None &&
- !Old->getAttr<WeakImportAttr>()) {
+ !Old->hasAttr<WeakImportAttr>()) {
Diag(New->getLocation(), diag::warn_weak_import) << New->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
// Remove weak_import attribute on new declaration.
@@ -3052,13 +3154,25 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
if (New->isInvalidDecl())
return;
+ diag::kind PrevDiag;
+ SourceLocation OldLocation;
+ std::tie(PrevDiag, OldLocation) =
+ getNoteDiagForInvalidRedeclaration(Old, New);
+
// [dcl.stc]p8: Check if we have a non-static decl followed by a static.
if (New->getStorageClass() == SC_Static &&
!New->isStaticDataMember() &&
Old->hasExternalFormalLinkage()) {
- Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
- return New->setInvalidDecl();
+ if (getLangOpts().MicrosoftExt) {
+ Diag(New->getLocation(), diag::ext_static_non_static)
+ << New->getDeclName();
+ Diag(OldLocation, PrevDiag);
+ } else {
+ Diag(New->getLocation(), diag::err_static_non_static)
+ << New->getDeclName();
+ Diag(OldLocation, PrevDiag);
+ return New->setInvalidDecl();
+ }
}
// C99 6.2.2p4:
// For an identifier declared with the storage-class specifier
@@ -3075,7 +3189,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
!New->isStaticDataMember() &&
Old->getCanonicalDecl()->getStorageClass() == SC_Static) {
Diag(New->getLocation(), diag::err_non_static_static) << New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ Diag(OldLocation, PrevDiag);
return New->setInvalidDecl();
}
@@ -3083,13 +3197,13 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
if (New->hasExternalStorage() &&
!Old->hasLinkage() && Old->isLocalVarDecl()) {
Diag(New->getLocation(), diag::err_extern_non_extern) << New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ Diag(OldLocation, PrevDiag);
return New->setInvalidDecl();
}
if (Old->hasLinkage() && New->isLocalVarDecl() &&
!New->hasExternalStorage()) {
Diag(New->getLocation(), diag::err_non_extern_extern) << New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ Diag(OldLocation, PrevDiag);
return New->setInvalidDecl();
}
@@ -3102,17 +3216,17 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
!(Old->getLexicalDeclContext()->isRecord() &&
!New->getLexicalDeclContext()->isRecord())) {
Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ Diag(OldLocation, PrevDiag);
return New->setInvalidDecl();
}
if (New->getTLSKind() != Old->getTLSKind()) {
if (!Old->getTLSKind()) {
Diag(New->getLocation(), diag::err_thread_non_thread) << New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_declaration);
+ Diag(OldLocation, PrevDiag);
} else if (!New->getTLSKind()) {
Diag(New->getLocation(), diag::err_non_thread_thread) << New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_declaration);
+ Diag(OldLocation, PrevDiag);
} else {
// Do not allow redeclaration to change the variable between requiring
// static and dynamic initialization.
@@ -3120,7 +3234,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
// declaration to determine the kind. Do we need to be compatible here?
Diag(New->getLocation(), diag::err_thread_thread_different_kind)
<< New->getDeclName() << (New->getTLSKind() == VarDecl::TLS_Dynamic);
- Diag(Old->getLocation(), diag::note_previous_declaration);
+ Diag(OldLocation, PrevDiag);
}
}
@@ -3137,7 +3251,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
if (haveIncompatibleLanguageLinkages(Old, New)) {
Diag(New->getLocation(), diag::err_different_language_linkage) << New;
- Diag(Old->getLocation(), diag::note_previous_definition);
+ Diag(OldLocation, PrevDiag);
New->setInvalidDecl();
return;
}
@@ -3148,14 +3262,13 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
// Keep a chain of previous declarations.
New->setPreviousDecl(Old);
+ if (NewTemplate)
+ NewTemplate->setPreviousDecl(OldTemplate);
// Inherit access appropriately.
New->setAccess(Old->getAccess());
-
- if (VarTemplateDecl *VTD = New->getDescribedVarTemplate()) {
- if (New->isStaticDataMember() && New->isOutOfLine())
- VTD->setAccess(New->getAccess());
- }
+ if (NewTemplate)
+ NewTemplate->setAccess(New->getAccess());
}
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
@@ -3165,7 +3278,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg());
}
-static void HandleTagNumbering(Sema &S, const TagDecl *Tag) {
+static void HandleTagNumbering(Sema &S, const TagDecl *Tag, Scope *TagScope) {
if (!S.Context.getLangOpts().CPlusPlus)
return;
@@ -3176,7 +3289,8 @@ static void HandleTagNumbering(Sema &S, const TagDecl *Tag) {
return;
MangleNumberingContext &MCtx =
S.Context.getManglingNumberContext(Tag->getParent());
- S.Context.setManglingNumber(Tag, MCtx.getManglingNumber(Tag));
+ S.Context.setManglingNumber(
+ Tag, MCtx.getManglingNumber(Tag, TagScope->getMSLocalManglingNumber()));
return;
}
@@ -3185,7 +3299,9 @@ static void HandleTagNumbering(Sema &S, const TagDecl *Tag) {
if (MangleNumberingContext *MCtx =
S.getCurrentMangleNumberContext(Tag->getDeclContext(),
ManglingContextDecl)) {
- S.Context.setManglingNumber(Tag, MCtx->getManglingNumber(Tag));
+ S.Context.setManglingNumber(
+ Tag,
+ MCtx->getManglingNumber(Tag, TagScope->getMSLocalManglingNumber()));
}
}
@@ -3196,8 +3312,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
DeclSpec &DS,
MultiTemplateParamsArg TemplateParams,
bool IsExplicitInstantiation) {
- Decl *TagD = 0;
- TagDecl *Tag = 0;
+ Decl *TagD = nullptr;
+ TagDecl *Tag = nullptr;
if (DS.getTypeSpecType() == DeclSpec::TST_class ||
DS.getTypeSpecType() == DeclSpec::TST_struct ||
DS.getTypeSpecType() == DeclSpec::TST_interface ||
@@ -3206,7 +3322,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
TagD = DS.getRepAsDecl();
if (!TagD) // We probably had an error
- return 0;
+ return nullptr;
// Note that the above type specs guarantee that the
// type rep is a Decl, whereas in many of the others
@@ -3218,7 +3334,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
}
if (Tag) {
- HandleTagNumbering(*this, Tag);
+ HandleTagNumbering(*this, Tag, S);
Tag->setFreeStanding();
if (Tag->isInvalidDecl())
return Tag;
@@ -3254,7 +3370,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
// If we're dealing with a decl but not a TagDecl, assume that
// whatever routines created it handled the friendship aspect.
if (TagD && !Tag)
- return 0;
+ return nullptr;
return ActOnFriendTypeDecl(S, DS, TemplateParams);
}
@@ -3273,7 +3389,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
DS.getTypeSpecType() == DeclSpec::TST_interface ? 2 :
DS.getTypeSpecType() == DeclSpec::TST_union ? 3 : 4)
<< SS.getRange();
- return 0;
+ return nullptr;
}
// Track whether this decl-specifier declares anything.
@@ -3285,7 +3401,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
if (getLangOpts().CPlusPlus ||
Record->getDeclContext()->isRecord())
- return BuildAnonymousStructOrUnion(S, DS, AS, Record);
+ return BuildAnonymousStructOrUnion(S, DS, AS, Record, Context.getPrintingPolicy());
DeclaresAnything = false;
}
@@ -3368,10 +3484,15 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
// Note that a linkage-specification sets a storage class, but
// 'extern "C" struct foo;' is actually valid and not theoretically
// useless.
- if (DeclSpec::SCS SCS = DS.getStorageClassSpec())
- if (!DS.isExternInLinkageSpec() && SCS != DeclSpec::SCS_typedef)
+ if (DeclSpec::SCS SCS = DS.getStorageClassSpec()) {
+ if (SCS == DeclSpec::SCS_mutable)
+ // Since mutable is not a viable storage class specifier in C, there is
+ // no reason to treat it as an extension. Instead, diagnose as an error.
+ Diag(DS.getStorageClassSpecLoc(), diag::err_mutable_nonmember);
+ else if (!DS.isExternInLinkageSpec() && SCS != DeclSpec::SCS_typedef)
Diag(DS.getStorageClassSpecLoc(), DiagID)
<< DeclSpec::getSpecifierName(SCS);
+ }
if (DeclSpec::TSCS TSCS = DS.getThreadStorageClassSpec())
Diag(DS.getThreadStorageClassSpecLoc(), DiagID)
@@ -3471,12 +3592,10 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S,
bool Invalid = false;
// Look every FieldDecl and IndirectFieldDecl with a name.
- for (RecordDecl::decl_iterator D = AnonRecord->decls_begin(),
- DEnd = AnonRecord->decls_end();
- D != DEnd; ++D) {
- if ((isa<FieldDecl>(*D) || isa<IndirectFieldDecl>(*D)) &&
- cast<NamedDecl>(*D)->getDeclName()) {
- ValueDecl *VD = cast<ValueDecl>(*D);
+ for (auto *D : AnonRecord->decls()) {
+ if ((isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) &&
+ cast<NamedDecl>(D)->getDeclName()) {
+ ValueDecl *VD = cast<ValueDecl>(D);
if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, VD->getDeclName(),
VD->getLocation(), diagKind)) {
// C++ [class.union]p2:
@@ -3492,9 +3611,8 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S,
// anonymous union is declared.
unsigned OldChainingSize = Chaining.size();
if (IndirectFieldDecl *IF = dyn_cast<IndirectFieldDecl>(VD))
- for (IndirectFieldDecl::chain_iterator PI = IF->chain_begin(),
- PE = IF->chain_end(); PI != PE; ++PI)
- Chaining.push_back(*PI);
+ for (auto *PI : IF->chain())
+ Chaining.push_back(PI);
else
Chaining.push_back(VD);
@@ -3549,13 +3667,45 @@ StorageClassSpecToVarDeclStorageClass(const DeclSpec &DS) {
llvm_unreachable("unknown storage class specifier");
}
+static SourceLocation findDefaultInitializer(const CXXRecordDecl *Record) {
+ assert(Record->hasInClassInitializer());
+
+ for (const auto *I : Record->decls()) {
+ const auto *FD = dyn_cast<FieldDecl>(I);
+ if (const auto *IFD = dyn_cast<IndirectFieldDecl>(I))
+ FD = IFD->getAnonField();
+ if (FD && FD->hasInClassInitializer())
+ return FD->getLocation();
+ }
+
+ llvm_unreachable("couldn't find in-class initializer");
+}
+
+static void checkDuplicateDefaultInit(Sema &S, CXXRecordDecl *Parent,
+ SourceLocation DefaultInitLoc) {
+ if (!Parent->isUnion() || !Parent->hasInClassInitializer())
+ return;
+
+ S.Diag(DefaultInitLoc, diag::err_multiple_mem_union_initialization);
+ S.Diag(findDefaultInitializer(Parent), diag::note_previous_initializer) << 0;
+}
+
+static void checkDuplicateDefaultInit(Sema &S, CXXRecordDecl *Parent,
+ CXXRecordDecl *AnonUnion) {
+ if (!Parent->isUnion() || !Parent->hasInClassInitializer())
+ return;
+
+ checkDuplicateDefaultInit(S, Parent, findDefaultInitializer(AnonUnion));
+}
+
/// BuildAnonymousStructOrUnion - Handle the declaration of an
/// anonymous structure or union. Anonymous unions are a C++ feature
/// (C++ [class.union]) and a C11 feature; anonymous structures
/// are a C11 feature and GNU C++ extension.
Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
- AccessSpecifier AS,
- RecordDecl *Record) {
+ AccessSpecifier AS,
+ RecordDecl *Record,
+ const PrintingPolicy &Policy) {
DeclContext *Owner = Record->getDeclContext();
// Diagnose whether this anonymous struct/union is an extension.
@@ -3570,7 +3720,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// structs/unions.
bool Invalid = false;
if (getLangOpts().CPlusPlus) {
- const char* PrevSpec = 0;
+ const char *PrevSpec = nullptr;
unsigned DiagID;
if (Record->isUnion()) {
// C++ [class.union]p6:
@@ -3585,7 +3735,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// Recover by adding 'static'.
DS.SetStorageClassSpec(*this, DeclSpec::SCS_static, SourceLocation(),
- PrevSpec, DiagID);
+ PrevSpec, DiagID, Policy);
}
// C++ [class.union]p6:
// A storage class is not allowed in a declaration of an
@@ -3599,7 +3749,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// Recover by removing the storage specifier.
DS.SetStorageClassSpec(*this, DeclSpec::SCS_unspecified,
SourceLocation(),
- PrevSpec, DiagID);
+ PrevSpec, DiagID, Context.getPrintingPolicy());
}
}
@@ -3632,10 +3782,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// The member-specification of an anonymous union shall only
// define non-static data members. [Note: nested types and
// functions cannot be declared within an anonymous union. ]
- for (DeclContext::decl_iterator Mem = Record->decls_begin(),
- MemEnd = Record->decls_end();
- Mem != MemEnd; ++Mem) {
- if (FieldDecl *FD = dyn_cast<FieldDecl>(*Mem)) {
+ for (auto *Mem : Record->decls()) {
+ if (auto *FD = dyn_cast<FieldDecl>(Mem)) {
// C++ [class.union]p3:
// An anonymous union shall not have private or protected
// members (clause 11).
@@ -3653,14 +3801,14 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// array of such objects.
if (CheckNontrivialField(FD))
Invalid = true;
- } else if ((*Mem)->isImplicit()) {
+ } else if (Mem->isImplicit()) {
// Any implicit members are fine.
- } else if (isa<TagDecl>(*Mem) && (*Mem)->getDeclContext() != Record) {
+ } else if (isa<TagDecl>(Mem) && Mem->getDeclContext() != Record) {
// This is a type that showed up in an
// elaborated-type-specifier inside the anonymous struct or
// union, but which actually declares a type outside of the
// anonymous struct or union. It's okay.
- } else if (RecordDecl *MemRecord = dyn_cast<RecordDecl>(*Mem)) {
+ } else if (auto *MemRecord = dyn_cast<RecordDecl>(Mem)) {
if (!MemRecord->isAnonymousStructOrUnion() &&
MemRecord->getDeclName()) {
// Visual C++ allows type definition in anonymous struct or union.
@@ -3681,31 +3829,41 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
diag::ext_anonymous_record_with_anonymous_type)
<< (int)Record->isUnion();
}
- } else if (isa<AccessSpecDecl>(*Mem)) {
+ } else if (isa<AccessSpecDecl>(Mem)) {
// Any access specifier is fine.
+ } else if (isa<StaticAssertDecl>(Mem)) {
+ // In C++1z, static_assert declarations are also fine.
} else {
// We have something that isn't a non-static data
// member. Complain about it.
unsigned DK = diag::err_anonymous_record_bad_member;
- if (isa<TypeDecl>(*Mem))
+ if (isa<TypeDecl>(Mem))
DK = diag::err_anonymous_record_with_type;
- else if (isa<FunctionDecl>(*Mem))
+ else if (isa<FunctionDecl>(Mem))
DK = diag::err_anonymous_record_with_function;
- else if (isa<VarDecl>(*Mem))
+ else if (isa<VarDecl>(Mem))
DK = diag::err_anonymous_record_with_static;
// Visual C++ allows type definition in anonymous struct or union.
if (getLangOpts().MicrosoftExt &&
DK == diag::err_anonymous_record_with_type)
- Diag((*Mem)->getLocation(), diag::ext_anonymous_record_with_type)
+ Diag(Mem->getLocation(), diag::ext_anonymous_record_with_type)
<< (int)Record->isUnion();
else {
- Diag((*Mem)->getLocation(), DK)
+ Diag(Mem->getLocation(), DK)
<< (int)Record->isUnion();
Invalid = true;
}
}
}
+
+ // C++11 [class.union]p8 (DR1460):
+ // At most one variant member of a union may have a
+ // brace-or-equal-initializer.
+ if (cast<CXXRecordDecl>(Record)->hasInClassInitializer() &&
+ Owner->isRecord())
+ checkDuplicateDefaultInit(*this, cast<CXXRecordDecl>(Owner),
+ cast<CXXRecordDecl>(Record));
}
if (!Record->isUnion() && !Owner->isRecord()) {
@@ -3720,15 +3878,15 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
assert(TInfo && "couldn't build declarator info for anonymous struct/union");
// Create a declaration for this anonymous struct/union.
- NamedDecl *Anon = 0;
+ NamedDecl *Anon = nullptr;
if (RecordDecl *OwningClass = dyn_cast<RecordDecl>(Owner)) {
Anon = FieldDecl::Create(Context, OwningClass,
DS.getLocStart(),
Record->getLocation(),
- /*IdentifierInfo=*/0,
+ /*IdentifierInfo=*/nullptr,
Context.getTypeDeclType(Record),
TInfo,
- /*BitWidth=*/0, /*Mutable=*/false,
+ /*BitWidth=*/nullptr, /*Mutable=*/false,
/*InitStyle=*/ICIS_NoInit);
Anon->setAccess(AS);
if (getLangOpts().CPlusPlus)
@@ -3746,7 +3904,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Anon = VarDecl::Create(Context, Owner,
DS.getLocStart(),
- Record->getLocation(), /*IdentifierInfo=*/0,
+ Record->getLocation(), /*IdentifierInfo=*/nullptr,
Context.getTypeDeclType(Record),
TInfo, SC);
@@ -3758,11 +3916,14 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
}
Anon->setImplicit();
+ // Mark this as an anonymous struct/union type.
+ Record->setAnonymousStructOrUnion(true);
+
// Add the anonymous struct/union object to the current
// context. We'll be referencing this object when we refer to one of
// its members.
Owner->addDecl(Anon);
-
+
// Inject the members of the anonymous struct/union into the owning
// context and into the identifier resolver chain for name lookup
// purposes.
@@ -3773,13 +3934,17 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Chain, false))
Invalid = true;
- // Mark this as an anonymous struct/union type. Note that we do not
- // do this until after we have already checked and injected the
- // members of this anonymous struct/union type, because otherwise
- // the members could be injected twice: once by DeclContext when it
- // builds its lookup table, and once by
- // InjectAnonymousStructOrUnionMembers.
- Record->setAnonymousStructOrUnion(true);
+ if (VarDecl *NewVD = dyn_cast<VarDecl>(Anon)) {
+ if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) {
+ Decl *ManglingContextDecl;
+ if (MangleNumberingContext *MCtx =
+ getCurrentMangleNumberContext(NewVD->getDeclContext(),
+ ManglingContextDecl)) {
+ Context.setManglingNumber(NewVD, MCtx->getManglingNumber(NewVD, S->getMSLocalManglingNumber()));
+ Context.setStaticLocalNumber(NewVD, MCtx->getStaticLocalNumber(NewVD));
+ }
+ }
+ }
if (Invalid)
Anon->setInvalidDecl();
@@ -3813,14 +3978,14 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
assert(TInfo && "couldn't build declarator info for anonymous struct");
// Create a declaration for this anonymous struct.
- NamedDecl* Anon = FieldDecl::Create(Context,
+ NamedDecl *Anon = FieldDecl::Create(Context,
cast<RecordDecl>(CurContext),
DS.getLocStart(),
DS.getLocStart(),
- /*IdentifierInfo=*/0,
+ /*IdentifierInfo=*/nullptr,
Context.getTypeDeclType(Record),
TInfo,
- /*BitWidth=*/0, /*Mutable=*/false,
+ /*BitWidth=*/nullptr, /*Mutable=*/false,
/*InitStyle=*/ICIS_NoInit);
Anon->setImplicit();
@@ -3922,7 +4087,7 @@ Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) {
Context.getCanonicalType(CurClassType)));
NameInfo.setLoc(Name.StartLocation);
// FIXME: should we retrieve TypeSourceInfo?
- NameInfo.setNamedTypeInfo(0);
+ NameInfo.setNamedTypeInfo(nullptr);
return NameInfo;
}
@@ -4018,7 +4183,7 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
case DeclSpec::TST_underlyingType:
case DeclSpec::TST_atomic: {
// Grab the type from the parser.
- TypeSourceInfo *TSI = 0;
+ TypeSourceInfo *TSI = nullptr;
QualType T = S.GetTypeFromParser(DS.getRepAsType(), &TSI);
if (T.isNull() || !T->isDependentType()) break;
@@ -4117,33 +4282,31 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC,
/// \returns true if we cannot safely recover from this error, false otherwise.
bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
DeclarationName Name,
- SourceLocation Loc) {
+ SourceLocation Loc) {
DeclContext *Cur = CurContext;
while (isa<LinkageSpecDecl>(Cur) || isa<CapturedDecl>(Cur))
Cur = Cur->getParent();
-
- // C++ [dcl.meaning]p1:
- // A declarator-id shall not be qualified except for the definition
- // of a member function (9.3) or static data member (9.4) outside of
- // its class, the definition or explicit instantiation of a function
- // or variable member of a namespace outside of its namespace, or the
- // definition of an explicit specialization outside of its namespace,
- // or the declaration of a friend function that is a member of
- // another class or namespace (11.3). [...]
-
- // The user provided a superfluous scope specifier that refers back to the
- // class or namespaces in which the entity is already declared.
+
+ // If the user provided a superfluous scope specifier that refers back to the
+ // class in which the entity is already declared, diagnose and ignore it.
//
// class X {
// void X::f();
// };
+ //
+ // Note, it was once ill-formed to give redundant qualification in all
+ // contexts, but that rule was removed by DR482.
if (Cur->Equals(DC)) {
- Diag(Loc, LangOpts.MicrosoftExt? diag::warn_member_extra_qualification
- : diag::err_member_extra_qualification)
- << Name << FixItHint::CreateRemoval(SS.getRange());
- SS.clear();
+ if (Cur->isRecord()) {
+ Diag(Loc, LangOpts.MicrosoftExt ? diag::warn_member_extra_qualification
+ : diag::err_member_extra_qualification)
+ << Name << FixItHint::CreateRemoval(SS.getRange());
+ SS.clear();
+ } else {
+ Diag(Loc, diag::warn_namespace_member_extra_qualification) << Name;
+ }
return false;
- }
+ }
// Check whether the qualifying scope encloses the scope of the original
// declaration.
@@ -4212,9 +4375,9 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
Diag(D.getDeclSpec().getLocStart(),
diag::err_declarator_need_ident)
<< D.getDeclSpec().getSourceRange() << D.getSourceRange();
- return 0;
+ return nullptr;
} else if (DiagnoseUnexpandedParameterPack(NameInfo, UPPC_DeclarationType))
- return 0;
+ return nullptr;
// The scope passed in may not be a decl scope. Zip up the scope tree until
// we find one that is.
@@ -4228,7 +4391,7 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
else if (D.getCXXScopeSpec().isSet()) {
if (DiagnoseUnexpandedParameterPack(D.getCXXScopeSpec(),
UPPC_DeclarationQualifier))
- return 0;
+ return nullptr;
bool EnteringContext = !D.getDeclSpec().isFriendSpecified();
DC = computeDeclContext(D.getCXXScopeSpec(), EnteringContext);
@@ -4239,15 +4402,15 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
// and return early, to avoid the coming semantic disaster.
Diag(D.getIdentifierLoc(),
diag::err_template_qualified_declarator_no_match)
- << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep()
+ << D.getCXXScopeSpec().getScopeRep()
<< D.getCXXScopeSpec().getRange();
- return 0;
+ return nullptr;
}
bool IsDependentContext = DC->isDependentContext();
if (!IsDependentContext &&
RequireCompleteDeclContext(D.getCXXScopeSpec(), DC))
- return 0;
+ return nullptr;
if (isa<CXXRecordDecl>(DC) && !cast<CXXRecordDecl>(DC)->hasDefinition()) {
Diag(D.getIdentifierLoc(),
@@ -4258,8 +4421,8 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
if (diagnoseQualifiedDeclaration(D.getCXXScopeSpec(), DC,
Name, D.getIdentifierLoc())) {
if (DC->isRecord())
- return 0;
-
+ return nullptr;
+
D.setInvalidType();
}
}
@@ -4278,8 +4441,8 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
// If this is a typedef, we'll end up spewing multiple diagnostics.
// Just return early; it's safer.
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
- return 0;
-
+ return nullptr;
+
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType R = TInfo->getType();
@@ -4380,7 +4543,7 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
if (TemplateParamLists.size()) {
Diag(D.getIdentifierLoc(), diag::err_template_typedef);
- return 0;
+ return nullptr;
}
New = ActOnTypedefDeclarator(S, D, DC, TInfo, Previous);
@@ -4393,8 +4556,8 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
AddToScope);
}
- if (New == 0)
- return 0;
+ if (!New)
+ return nullptr;
// If this has an identifier and is not an invalid redeclaration or
// function template specialization, add it to the scope stack.
@@ -4521,7 +4684,7 @@ TryToFixInvalidVariablyModifiedTypeSourceInfo(TypeSourceInfo *TInfo,
= TryToFixInvalidVariablyModifiedType(TInfo->getType(), Context,
SizeIsNegative, Oversized);
if (FixedTy.isNull())
- return 0;
+ return nullptr;
TypeSourceInfo *FixedTInfo = Context.getTrivialTypeSourceInfo(FixedTy);
FixInvalidVariablyModifiedTypeLoc(TInfo->getTypeLoc(),
FixedTInfo->getTypeLoc());
@@ -4560,7 +4723,7 @@ NamedDecl *Sema::findLocallyScopedExternCDecl(DeclarationName Name) {
}
NamedDecl *D = LocallyScopedExternCDecls.lookup(Name);
- return D ? D->getMostRecentDecl() : 0;
+ return D ? D->getMostRecentDecl() : nullptr;
}
/// \brief Diagnose function specifiers on a declaration of an identifier that
@@ -4607,11 +4770,11 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (D.getName().Kind != UnqualifiedId::IK_Identifier) {
Diag(D.getName().StartLocation, diag::err_typedef_not_identifier)
<< D.getName().getSourceRange();
- return 0;
+ return nullptr;
}
TypedefDecl *NewTD = ParseTypedefDecl(S, D, TInfo->getType(), TInfo);
- if (!NewTD) return 0;
+ if (!NewTD) return nullptr;
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewTD, D);
@@ -4635,7 +4798,7 @@ Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) {
if (T->isVariablyModifiedType()) {
getCurFunction()->setHasBranchProtectedScope();
- if (S->getFnParent() == 0) {
+ if (S->getFnParent() == nullptr) {
bool SizeIsNegative;
llvm::APSInt Oversized;
TypeSourceInfo *FixedTInfo =
@@ -4670,8 +4833,8 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
LookupResult &Previous, bool &Redeclaration) {
// Merge the decl with the existing one if appropriate. If the decl is
// in an outer scope, it isn't the same thing.
- FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/ false,
- /*ExplicitInstantiationOrSpecialization=*/false);
+ FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/false,
+ /*AllowInlineNamespace*/false);
filterNonConflictingPreviousDecls(Context, NewTD, Previous);
if (!Previous.empty()) {
Redeclaration = true;
@@ -4804,6 +4967,10 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) {
}
static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
+ // Ensure that an auto decl is deduced otherwise the checks below might cache
+ // the wrong linkage.
+ assert(S.ParsingInitForAutoVars.count(&ND) == 0);
+
// 'weak' only applies to declarations with external linkage.
if (WeakAttr *Attr = ND.getAttr<WeakAttr>()) {
if (!ND.isExternallyVisible()) {
@@ -4826,6 +4993,79 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
ND.dropAttr<SelectAnyAttr>();
}
}
+
+ // dll attributes require external linkage.
+ if (const DLLImportAttr *Attr = ND.getAttr<DLLImportAttr>()) {
+ if (!ND.isExternallyVisible()) {
+ S.Diag(ND.getLocation(), diag::err_attribute_dll_not_extern)
+ << &ND << Attr;
+ ND.setInvalidDecl();
+ }
+ }
+ if (const DLLExportAttr *Attr = ND.getAttr<DLLExportAttr>()) {
+ if (!ND.isExternallyVisible()) {
+ S.Diag(ND.getLocation(), diag::err_attribute_dll_not_extern)
+ << &ND << Attr;
+ ND.setInvalidDecl();
+ }
+ }
+}
+
+static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
+ NamedDecl *NewDecl,
+ bool IsSpecialization) {
+ if (TemplateDecl *OldTD = dyn_cast<TemplateDecl>(OldDecl))
+ OldDecl = OldTD->getTemplatedDecl();
+ if (TemplateDecl *NewTD = dyn_cast<TemplateDecl>(NewDecl))
+ NewDecl = NewTD->getTemplatedDecl();
+
+ if (!OldDecl || !NewDecl)
+ return;
+
+ const DLLImportAttr *OldImportAttr = OldDecl->getAttr<DLLImportAttr>();
+ const DLLExportAttr *OldExportAttr = OldDecl->getAttr<DLLExportAttr>();
+ const DLLImportAttr *NewImportAttr = NewDecl->getAttr<DLLImportAttr>();
+ const DLLExportAttr *NewExportAttr = NewDecl->getAttr<DLLExportAttr>();
+
+ // dllimport and dllexport are inheritable attributes so we have to exclude
+ // inherited attribute instances.
+ bool HasNewAttr = (NewImportAttr && !NewImportAttr->isInherited()) ||
+ (NewExportAttr && !NewExportAttr->isInherited());
+
+ // A redeclaration is not allowed to add a dllimport or dllexport attribute,
+ // the only exception being explicit specializations.
+ // Implicitly generated declarations are also excluded for now because there
+ // is no other way to switch these to use dllimport or dllexport.
+ bool AddsAttr = !(OldImportAttr || OldExportAttr) && HasNewAttr;
+ if (AddsAttr && !IsSpecialization && !OldDecl->isImplicit()) {
+ S.Diag(NewDecl->getLocation(), diag::err_attribute_dll_redeclaration)
+ << NewDecl
+ << (NewImportAttr ? (const Attr *)NewImportAttr : NewExportAttr);
+ S.Diag(OldDecl->getLocation(), diag::note_previous_declaration);
+ NewDecl->setInvalidDecl();
+ return;
+ }
+
+ // A redeclaration is not allowed to drop a dllimport attribute, the only
+ // exception being inline function definitions.
+ // NB: MSVC converts such a declaration to dllexport.
+ bool IsInline = false, IsStaticDataMember = false;
+ if (const auto *VD = dyn_cast<VarDecl>(NewDecl))
+ // Ignore static data because out-of-line definitions are diagnosed
+ // separately.
+ IsStaticDataMember = VD->isStaticDataMember();
+ else if (const auto *FD = dyn_cast<FunctionDecl>(NewDecl))
+ IsInline = FD->isInlined();
+
+ if (OldImportAttr && !HasNewAttr && !IsInline && !IsStaticDataMember) {
+ S.Diag(NewDecl->getLocation(),
+ diag::warn_redeclaration_without_attribute_prev_attribute_ignored)
+ << NewDecl << OldImportAttr;
+ S.Diag(OldDecl->getLocation(), diag::note_previous_declaration);
+ S.Diag(OldImportAttr->getLocation(), diag::note_previous_attribute);
+ OldDecl->dropAttr<DLLImportAttr>();
+ NewDecl->dropAttr<DLLImportAttr>();
+ }
}
/// Given that we are within the definition of the given function,
@@ -4851,7 +5091,8 @@ static bool isFunctionDefinitionDiscarded(Sema &S, FunctionDecl *FD) {
FD->setLazyBody(1);
#endif
- bool isC99Inline = (S.Context.GetGVALinkageForFunction(FD) == GVA_C99Inline);
+ bool isC99Inline =
+ S.Context.GetGVALinkageForFunction(FD) == GVA_AvailableExternally;
#ifndef NDEBUG
FD->setLazyBody(0);
@@ -4906,6 +5147,31 @@ static bool shouldConsiderLinkage(const FunctionDecl *FD) {
llvm_unreachable("Unexpected context");
}
+static bool hasParsedAttr(Scope *S, const AttributeList *AttrList,
+ AttributeList::Kind Kind) {
+ for (const AttributeList *L = AttrList; L; L = L->getNext())
+ if (L->getKind() == Kind)
+ return true;
+ return false;
+}
+
+static bool hasParsedAttr(Scope *S, const Declarator &PD,
+ AttributeList::Kind Kind) {
+ // Check decl attributes on the DeclSpec.
+ if (hasParsedAttr(S, PD.getDeclSpec().getAttributes().getList(), Kind))
+ return true;
+
+ // Walk the declarator structure, checking decl attributes that were in a type
+ // position to the decl itself.
+ for (unsigned I = 0, E = PD.getNumTypeObjects(); I != E; ++I) {
+ if (hasParsedAttr(S, PD.getTypeObject(I).getAttrs(), Kind))
+ return true;
+ }
+
+ // Finally, check attributes on the decl itself.
+ return hasParsedAttr(S, PD.getAttributes(), Kind);
+}
+
/// Adjust the \c DeclContext for a function or variable that might be a
/// function-local external declaration.
bool Sema::adjustContextForLocalExternDecl(DeclContext *&DC) {
@@ -4942,16 +5208,36 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
VarDecl::StorageClass SC =
StorageClassSpecToVarDeclStorageClass(D.getDeclSpec());
+ // dllimport globals without explicit storage class are treated as extern. We
+ // have to change the storage class this early to get the right DeclContext.
+ if (SC == SC_None && !DC->isRecord() &&
+ hasParsedAttr(S, D, AttributeList::AT_DLLImport) &&
+ !hasParsedAttr(S, D, AttributeList::AT_DLLExport))
+ SC = SC_Extern;
+
DeclContext *OriginalDC = DC;
bool IsLocalExternDecl = SC == SC_Extern &&
adjustContextForLocalExternDecl(DC);
- if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp16) {
- // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and
- // half array type (unless the cl_khr_fp16 extension is enabled).
- if (Context.getBaseElementType(R)->isHalfType()) {
- Diag(D.getIdentifierLoc(), diag::err_opencl_half_declaration) << R;
- D.setInvalidType();
+ if (getLangOpts().OpenCL) {
+ // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed.
+ QualType NR = R;
+ while (NR->isPointerType()) {
+ if (NR->isFunctionPointerType()) {
+ Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer_variable);
+ D.setInvalidType();
+ break;
+ }
+ NR = NR->getPointeeType();
+ }
+
+ if (!getOpenCLOptions().cl_khr_fp16) {
+ // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and
+ // half array type (unless the cl_khr_fp16 extension is enabled).
+ if (Context.getBaseElementType(R)->isHalfType()) {
+ Diag(D.getIdentifierLoc(), diag::err_opencl_half_declaration) << R;
+ D.setInvalidType();
+ }
}
}
@@ -4978,21 +5264,17 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (!II) {
Diag(D.getIdentifierLoc(), diag::err_bad_variable_name)
<< Name;
- return 0;
+ return nullptr;
}
DiagnoseFunctionSpecifiers(D.getDeclSpec());
- if (!DC->isRecord() && S->getFnParent() == 0) {
+ if (!DC->isRecord() && S->getFnParent() == nullptr) {
// C99 6.9p2: The storage-class specifiers auto and register shall not
// appear in the declaration specifiers in an external declaration.
- if (SC == SC_Auto || SC == SC_Register) {
- // If this is a register variable with an asm label specified, then this
- // is a GNU extension.
- if (SC == SC_Register && D.getAsmLabel())
- Diag(D.getIdentifierLoc(), diag::err_unsupported_global_register);
- else
- Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope);
+ // Global Register+Asm is a GNU extension we support.
+ if (SC == SC_Auto || (SC == SC_Register && !D.getAsmLabel())) {
+ Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope);
D.setInvalidType();
}
}
@@ -5017,7 +5299,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// The event type cannot be used with the __local, __constant and __global
// address space qualifiers.
if (R->isEventT()) {
- if (S->getParent() == 0) {
+ if (S->getParent() == nullptr) {
Diag(D.getLocStart(), diag::err_event_t_global_var);
D.setInvalidType();
}
@@ -5033,9 +5315,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool IsVariableTemplateSpecialization = false;
bool IsPartialSpecialization = false;
bool IsVariableTemplate = false;
- VarTemplateDecl *PrevVarTemplate = 0;
- VarDecl *NewVD = 0;
- VarTemplateDecl *NewTemplate = 0;
+ VarDecl *NewVD = nullptr;
+ VarTemplateDecl *NewTemplate = nullptr;
+ TemplateParameterList *TemplateParams = nullptr;
if (!getLangOpts().CPlusPlus) {
NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
D.getIdentifierLoc(), II,
@@ -5097,18 +5379,17 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
- NamedDecl *PrevDecl = 0;
- if (Previous.begin() != Previous.end())
- PrevDecl = (*Previous.begin())->getUnderlyingDecl();
- PrevVarTemplate = dyn_cast_or_null<VarTemplateDecl>(PrevDecl);
-
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
- TemplateParameterList *TemplateParams =
- MatchTemplateParametersToScopeSpecifier(
- D.getDeclSpec().getLocStart(), D.getIdentifierLoc(),
- D.getCXXScopeSpec(), TemplateParamLists,
- /*never a friend*/ false, IsExplicitSpecialization, Invalid);
+ TemplateParams = MatchTemplateParametersToScopeSpecifier(
+ D.getDeclSpec().getLocStart(), D.getIdentifierLoc(),
+ D.getCXXScopeSpec(),
+ D.getName().getKind() == UnqualifiedId::IK_TemplateId
+ ? D.getName().TemplateId
+ : nullptr,
+ TemplateParamLists,
+ /*never a friend*/ false, IsExplicitSpecialization, Invalid);
+
if (TemplateParams) {
if (!TemplateParams->size() &&
D.getName().getKind() != UnqualifiedId::IK_TemplateId) {
@@ -5119,113 +5400,43 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< II
<< SourceRange(TemplateParams->getTemplateLoc(),
TemplateParams->getRAngleLoc());
+ TemplateParams = nullptr;
} else {
- // Only C++1y supports variable templates (N3651).
- Diag(D.getIdentifierLoc(),
- getLangOpts().CPlusPlus1y
- ? diag::warn_cxx11_compat_variable_template
- : diag::ext_variable_template);
-
if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) {
// This is an explicit specialization or a partial specialization.
- // Check that we can declare a specialization here
-
+ // FIXME: Check that we can declare a specialization here.
IsVariableTemplateSpecialization = true;
IsPartialSpecialization = TemplateParams->size() > 0;
-
} else { // if (TemplateParams->size() > 0)
// This is a template declaration.
IsVariableTemplate = true;
// Check that we can declare a template here.
if (CheckTemplateDeclScope(S, TemplateParams))
- return 0;
-
- // If there is a previous declaration with the same name, check
- // whether this is a valid redeclaration.
- if (PrevDecl && !isDeclInScope(PrevDecl, DC, S))
- PrevDecl = PrevVarTemplate = 0;
-
- if (PrevVarTemplate) {
- // Ensure that the template parameter lists are compatible.
- if (!TemplateParameterListsAreEqual(
- TemplateParams, PrevVarTemplate->getTemplateParameters(),
- /*Complain=*/true, TPL_TemplateMatch))
- return 0;
- } else if (PrevDecl && PrevDecl->isTemplateParameter()) {
- // Maybe we will complain about the shadowed template parameter.
- DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
-
- // Just pretend that we didn't see the previous declaration.
- PrevDecl = 0;
- } else if (PrevDecl) {
- // C++ [temp]p5:
- // ... a template name declared in namespace scope or in class
- // scope shall be unique in that scope.
- Diag(D.getIdentifierLoc(), diag::err_redefinition_different_kind)
- << Name;
- Diag(PrevDecl->getLocation(), diag::note_previous_definition);
- return 0;
- }
+ return nullptr;
- // Check the template parameter list of this declaration, possibly
- // merging in the template parameter list from the previous variable
- // template declaration.
- if (CheckTemplateParameterList(
- TemplateParams,
- PrevVarTemplate ? PrevVarTemplate->getTemplateParameters()
- : 0,
- (D.getCXXScopeSpec().isSet() && DC && DC->isRecord() &&
- DC->isDependentContext())
- ? TPC_ClassTemplateMember
- : TPC_VarTemplate))
- Invalid = true;
-
- if (D.getCXXScopeSpec().isSet()) {
- // If the name of the template was qualified, we must be defining
- // the template out-of-line.
- if (!D.getCXXScopeSpec().isInvalid() && !Invalid &&
- !PrevVarTemplate) {
- Diag(D.getIdentifierLoc(), diag::err_member_decl_does_not_match)
- << Name << DC << /*IsDefinition*/true
- << D.getCXXScopeSpec().getRange();
- Invalid = true;
- }
- }
+ // Only C++1y supports variable templates (N3651).
+ Diag(D.getIdentifierLoc(),
+ getLangOpts().CPlusPlus1y
+ ? diag::warn_cxx11_compat_variable_template
+ : diag::ext_variable_template);
}
}
- } else if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) {
- TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
-
- // We have encountered something that the user meant to be a
- // specialization (because it has explicitly-specified template
- // arguments) but that was not introduced with a "template<>" (or had
- // too few of them).
- // FIXME: Differentiate between attempts for explicit instantiations
- // (starting with "template") and the rest.
- Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header)
- << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)
- << FixItHint::CreateInsertion(D.getDeclSpec().getLocStart(),
- "template<> ");
- IsVariableTemplateSpecialization = true;
+ } else {
+ assert(D.getName().getKind() != UnqualifiedId::IK_TemplateId &&
+ "should have a 'template<>' for this decl");
}
if (IsVariableTemplateSpecialization) {
- if (!PrevVarTemplate) {
- Diag(D.getIdentifierLoc(), diag::err_var_spec_no_template)
- << IsPartialSpecialization;
- return 0;
- }
-
SourceLocation TemplateKWLoc =
TemplateParamLists.size() > 0
? TemplateParamLists[0]->getTemplateLoc()
: SourceLocation();
DeclResult Res = ActOnVarTemplateSpecialization(
- S, PrevVarTemplate, D, TInfo, TemplateKWLoc, TemplateParams, SC,
+ S, D, TInfo, TemplateKWLoc, TemplateParams, SC,
IsPartialSpecialization);
if (Res.isInvalid())
- return 0;
+ return nullptr;
NewVD = cast<VarDecl>(Res.get());
AddToScope = false;
} else
@@ -5236,7 +5447,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (IsVariableTemplate) {
NewTemplate =
VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name,
- TemplateParams, NewVD, PrevVarTemplate);
+ TemplateParams, NewVD);
NewVD->setDescribedVarTemplate(NewTemplate);
}
@@ -5253,18 +5464,13 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
SetNestedNameSpecifier(NewVD, D);
- // FIXME: Do we need D.getCXXScopeSpec().isSet()?
- if (TemplateParams && TemplateParamLists.size() > 1 &&
- (!IsVariableTemplateSpecialization || D.getCXXScopeSpec().isSet())) {
+ // If we have any template parameter lists that don't directly belong to
+ // the variable (matching the scope specifier), store them.
+ unsigned VDTemplateParamLists = TemplateParams ? 1 : 0;
+ if (TemplateParamLists.size() > VDTemplateParamLists)
NewVD->setTemplateParameterListsInfo(
- Context, TemplateParamLists.size() - 1, TemplateParamLists.data());
- } else if (IsVariableTemplateSpecialization ||
- (!TemplateParams && TemplateParamLists.size() > 0 &&
- (D.getCXXScopeSpec().isSet()))) {
- NewVD->setTemplateParameterListsInfo(Context,
- TemplateParamLists.size(),
- TemplateParamLists.data());
- }
+ Context, TemplateParamLists.size() - VDTemplateParamLists,
+ TemplateParamLists.data());
if (D.getDeclSpec().isConstexprSpecified())
NewVD->setConstexpr(true);
@@ -5311,7 +5517,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// that a local variable with thread storage duration still has to
// be marked 'static'. Also note that it's possible to get these
// semantics in C++ using __attribute__((gnu_inline)).
- if (SC == SC_Static && S->getFnParent() != 0 &&
+ if (SC == SC_Static && S->getFnParent() != nullptr &&
!NewVD->getType().isConstQualified()) {
FunctionDecl *CurFD = getCurFunctionDecl();
if (CurFD && isFunctionDefinitionDiscarded(*this, CurFD)) {
@@ -5346,19 +5552,23 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewVD, D);
- if (NewVD->hasAttrs())
- CheckAlignasUnderalignment(NewVD);
-
if (getLangOpts().CUDA) {
// CUDA B.2.5: "__shared__ and __constant__ variables have implied static
// storage [duration]."
- if (SC == SC_None && S->getFnParent() != 0 &&
+ if (SC == SC_None && S->getFnParent() != nullptr &&
(NewVD->hasAttr<CUDASharedAttr>() ||
NewVD->hasAttr<CUDAConstantAttr>())) {
NewVD->setStorageClass(SC_Static);
}
}
+ // Ensure that dllimport globals without explicit storage class are treated as
+ // extern. The storage class is set above using parsed attributes. Now we can
+ // check the VarDecl itself.
+ assert(!NewVD->hasAttr<DLLImportAttr>() ||
+ NewVD->getAttr<DLLImportAttr>()->isInherited() ||
+ NewVD->isStaticDataMember() || NewVD->getStorageClass() != SC_None);
+
// In auto-retain/release, infer strong retension for variables of
// retainable type.
if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(NewVD))
@@ -5369,13 +5579,14 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
StringRef Label = SE->getString();
- if (S->getFnParent() != 0) {
+ if (S->getFnParent() != nullptr) {
switch (SC) {
case SC_None:
case SC_Auto:
Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label;
break;
case SC_Register:
+ // Local Named register
if (!Context.getTargetInfo().isValidGCCRegisterName(Label))
Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label;
break;
@@ -5385,10 +5596,18 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
case SC_OpenCLWorkGroupLocal:
break;
}
+ } else if (SC == SC_Register) {
+ // Global Named register
+ if (!Context.getTargetInfo().isValidGCCRegisterName(Label))
+ Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label;
+ if (!R->isIntegralType(Context) && !R->isPointerType()) {
+ Diag(D.getLocStart(), diag::err_asm_bad_register_type);
+ NewVD->setInvalidDecl(true);
+ }
}
NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0),
- Context, Label));
+ Context, Label, 0));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier());
@@ -5399,15 +5618,16 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
// Diagnose shadowed variables before filtering for scope.
- if (!D.getCXXScopeSpec().isSet())
+ if (D.getCXXScopeSpec().isEmpty())
CheckShadow(S, NewVD, Previous);
// Don't consider existing declarations that are in a different
// scope and are out-of-semantic-context declarations (if the new
// declaration has linkage).
- FilterLookupForScope(
- Previous, OriginalDC, S, shouldConsiderLinkage(NewVD),
- IsExplicitSpecialization || IsVariableTemplateSpecialization);
+ FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewVD),
+ D.getCXXScopeSpec().isNotEmpty() ||
+ IsExplicitSpecialization ||
+ IsVariableTemplateSpecialization);
// Check whether the previous declaration is in the same block scope. This
// affects whether we merge types with it, per C++11 [dcl.array]p3.
@@ -5420,6 +5640,11 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (!getLangOpts().CPlusPlus) {
D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
} else {
+ // If this is an explicit specialization of a static data member, check it.
+ if (IsExplicitSpecialization && !NewVD->isInvalidDecl() &&
+ CheckMemberSpecialization(NewVD, Previous))
+ NewVD->setInvalidDecl();
+
// Merge the decl with the existing one if appropriate.
if (!Previous.empty()) {
if (Previous.isSingleResult() &&
@@ -5440,24 +5665,37 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD->setInvalidDecl();
}
- if (!IsVariableTemplateSpecialization) {
- if (PrevVarTemplate) {
- LookupResult PrevDecl(*this, GetNameForDeclarator(D),
- LookupOrdinaryName, ForRedeclaration);
- PrevDecl.addDecl(PrevVarTemplate->getTemplatedDecl());
- D.setRedeclaration(CheckVariableDeclaration(NewVD, PrevDecl));
- } else
- D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
- }
+ if (!IsVariableTemplateSpecialization)
+ D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
+
+ if (NewTemplate) {
+ VarTemplateDecl *PrevVarTemplate =
+ NewVD->getPreviousDecl()
+ ? NewVD->getPreviousDecl()->getDescribedVarTemplate()
+ : nullptr;
+
+ // Check the template parameter list of this declaration, possibly
+ // merging in the template parameter list from the previous variable
+ // template declaration.
+ if (CheckTemplateParameterList(
+ TemplateParams,
+ PrevVarTemplate ? PrevVarTemplate->getTemplateParameters()
+ : nullptr,
+ (D.getCXXScopeSpec().isSet() && DC && DC->isRecord() &&
+ DC->isDependentContext())
+ ? TPC_ClassTemplateMember
+ : TPC_VarTemplate))
+ NewVD->setInvalidDecl();
- // This is an explicit specialization of a static data member. Check it.
- if (IsExplicitSpecialization && !NewVD->isInvalidDecl() &&
- CheckMemberSpecialization(NewVD, Previous))
- NewVD->setInvalidDecl();
+ // If we are providing an explicit specialization of a static variable
+ // template, make a note of that.
+ if (PrevVarTemplate &&
+ PrevVarTemplate->getInstantiatedFromMemberTemplate())
+ PrevVarTemplate->setMemberSpecialization();
+ }
}
ProcessPragmaWeak(S, NewVD);
- checkAttributesAfterMerging(*this, *NewVD);
// If this is the first declaration of an extern C variable, update
// the map of such variables.
@@ -5470,16 +5708,21 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (MangleNumberingContext *MCtx =
getCurrentMangleNumberContext(NewVD->getDeclContext(),
ManglingContextDecl)) {
- Context.setManglingNumber(NewVD, MCtx->getManglingNumber(NewVD));
+ Context.setManglingNumber(
+ NewVD, MCtx->getManglingNumber(NewVD, S->getMSLocalManglingNumber()));
+ Context.setStaticLocalNumber(NewVD, MCtx->getStaticLocalNumber(NewVD));
}
}
- // If we are providing an explicit specialization of a static variable
- // template, make a note of that.
- if (PrevVarTemplate && PrevVarTemplate->getInstantiatedFromMemberTemplate())
- PrevVarTemplate->setMemberSpecialization();
+ if (D.isRedeclaration() && !Previous.empty()) {
+ checkDLLAttributeRedeclaration(
+ *this, dyn_cast<NamedDecl>(Previous.getRepresentativeDecl()), NewVD,
+ IsExplicitSpecialization);
+ }
if (NewTemplate) {
+ if (NewVD->isInvalidDecl())
+ NewTemplate->setInvalidDecl();
ActOnDocumentableDecl(NewTemplate);
return NewTemplate;
}
@@ -5498,8 +5741,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
///
void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) {
// Return if warning is ignored.
- if (Diags.getDiagnosticLevel(diag::warn_decl_shadow, R.getNameLoc()) ==
- DiagnosticsEngine::Ignored)
+ if (Diags.isIgnored(diag::warn_decl_shadow, R.getNameLoc()))
return;
// Don't diagnose declarations at file scope.
@@ -5526,11 +5768,9 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) {
if (shadowedVar->isExternC()) {
// For shadowing external vars, make sure that we point to the global
// declaration, not a locally scoped extern declaration.
- for (VarDecl::redecl_iterator
- I = shadowedVar->redecls_begin(), E = shadowedVar->redecls_end();
- I != E; ++I)
+ for (auto I : shadowedVar->redecls())
if (I->isFileVarDecl()) {
- ShadowedDecl = *I;
+ ShadowedDecl = I;
break;
}
}
@@ -5566,14 +5806,15 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) {
DeclarationName Name = R.getLookupName();
// Emit warning and note.
+ if (getSourceManager().isInSystemMacro(R.getNameLoc()))
+ return;
Diag(R.getNameLoc(), diag::warn_decl_shadow) << Name << Kind << OldDC;
Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
}
/// \brief Check -Wshadow without the advantage of a previous lookup.
void Sema::CheckShadow(Scope *S, VarDecl *D) {
- if (Diags.getDiagnosticLevel(diag::warn_decl_shadow, D->getLocation()) ==
- DiagnosticsEngine::Ignored)
+ if (Diags.isIgnored(diag::warn_decl_shadow, D->getLocation()))
return;
LookupResult R(*this, D->getDeclName(), D->getLocation(),
@@ -5711,6 +5952,9 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
if (T->isUndeducedType())
return;
+ if (NewVD->hasAttrs())
+ CheckAlignasUnderalignment(NewVD);
+
if (T->isObjCObjectType()) {
Diag(NewVD->getLocation(), diag::err_statically_allocated_object)
<< FixItHint::CreateInsertion(NewVD->getLocation(), "*");
@@ -5769,7 +6013,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
TypeSourceInfo *FixedTInfo =
TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context,
SizeIsNegative, Oversized);
- if (FixedTInfo == 0 && T->isVariableArrayType()) {
+ if (!FixedTInfo && T->isVariableArrayType()) {
const VariableArrayType *VAT = Context.getAsVariableArrayType(T);
// FIXME: This won't give the correct result for
// int a[10][n];
@@ -5788,7 +6032,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
return;
}
- if (FixedTInfo == 0) {
+ if (!FixedTInfo) {
if (NewVD->isFileVarDecl())
Diag(NewVD->getLocation(), diag::err_vm_decl_in_file_scope);
else
@@ -5828,7 +6072,6 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
if (NewVD->isConstexpr() && !T->isDependentType() &&
RequireLiteralType(NewVD->getLocation(), T,
diag::err_constexpr_var_non_literal)) {
- // Can't perform this check until the type is deduced.
NewVD->setInvalidDecl();
return;
}
@@ -5947,9 +6190,8 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
bool hasNonDeletedOverridenMethods = false;
bool AddedAny = false;
if (DC->lookupInBases(&FindOverriddenMethod, &Data, Paths)) {
- for (CXXBasePaths::decl_iterator I = Paths.found_decls_begin(),
- E = Paths.found_decls_end(); I != E; ++I) {
- if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) {
+ for (auto *I : Paths.found_decls()) {
+ if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(I)) {
MD->addOverriddenMethod(OldMD->getCanonicalDecl());
if (!CheckOverridingFunctionReturnType(MD, OldMD) &&
!CheckOverridingFunctionAttributes(MD, OldMD) &&
@@ -5993,9 +6235,9 @@ class DifferentNameValidatorCCC : public CorrectionCandidateCallback {
DifferentNameValidatorCCC(ASTContext &Context, FunctionDecl *TypoFD,
CXXRecordDecl *Parent)
: Context(Context), OriginalFD(TypoFD),
- ExpectedParent(Parent ? Parent->getCanonicalDecl() : 0) {}
+ ExpectedParent(Parent ? Parent->getCanonicalDecl() : nullptr) {}
- virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ bool ValidateCandidate(const TypoCorrection &candidate) override {
if (candidate.getEditDistance() == 0)
return false;
@@ -6062,7 +6304,7 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
"Cannot have an ambiguity in previous-declaration lookup");
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
DifferentNameValidatorCCC Validator(SemaRef.Context, NewFD,
- MD ? MD->getParent() : 0);
+ MD ? MD->getParent() : nullptr);
if (!Prev.empty()) {
for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
Func != FuncEnd; ++Func) {
@@ -6080,7 +6322,7 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
} else if ((Correction = SemaRef.CorrectTypo(
Prev.getLookupNameInfo(), Prev.getLookupKind(), S,
&ExtraArgs.D.getCXXScopeSpec(), Validator,
- IsLocalFriend ? 0 : NewDC))) {
+ Sema::CTK_ErrorRecovery, IsLocalFriend ? nullptr : NewDC))) {
// Set up everything for the call to ActOnFunctionDeclarator
ExtraArgs.D.SetIdentifier(Correction.getCorrectionAsIdentifierInfo(),
ExtraArgs.D.getIdentifierLoc());
@@ -6114,7 +6356,7 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
ExtraArgs.AddToScope);
if (Trap.hasErrorOccurred())
- Result = 0;
+ Result = nullptr;
}
if (Result) {
@@ -6174,7 +6416,7 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
IsMember ? diag::note_member_def_close_match
: diag::note_local_decl_close_match);
}
- return 0;
+ return nullptr;
}
static FunctionDecl::StorageClass getFunctionStorageClass(Sema &SemaRef,
@@ -6221,7 +6463,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
DeclarationNameInfo NameInfo = SemaRef.GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName();
- FunctionDecl *NewFD = 0;
+ FunctionDecl *NewFD = nullptr;
bool isInline = D.getDeclSpec().isInlineSpecified();
if (!SemaRef.getLangOpts().CPlusPlus) {
@@ -6254,10 +6496,9 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
// For record types, this is done by the AbstractClassUsageDiagnoser once
// the class has been completely parsed.
if (!DC->isRecord() &&
- SemaRef.RequireNonAbstractType(D.getIdentifierLoc(),
- R->getAs<FunctionType>()->getResultType(),
- diag::err_abstract_type_in_decl,
- SemaRef.AbstractReturnType))
+ SemaRef.RequireNonAbstractType(
+ D.getIdentifierLoc(), R->getAs<FunctionType>()->getReturnType(),
+ diag::err_abstract_type_in_decl, SemaRef.AbstractReturnType))
D.setInvalidType();
if (Name.getNameKind() == DeclarationName::CXXConstructorName) {
@@ -6292,15 +6533,6 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
SemaRef.AdjustDestructorExceptionSpec(Record, NewDD);
}
- // The Microsoft ABI requires that we perform the destructor body
- // checks (i.e. operator delete() lookup) at every declaration, as
- // any translation unit may need to emit a deleting destructor.
- if (SemaRef.Context.getTargetInfo().getCXXABI().isMicrosoft() &&
- !Record->isDependentType() && Record->getDefinition() &&
- !Record->isBeingDefined()) {
- SemaRef.CheckDestructor(NewDD);
- }
-
IsVirtualOkay = true;
return NewDD;
@@ -6321,7 +6553,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
if (!DC->isRecord()) {
SemaRef.Diag(D.getIdentifierLoc(),
diag::err_conv_function_not_member);
- return 0;
+ return nullptr;
}
SemaRef.CheckConversionDeclarator(D, R, SC);
@@ -6341,7 +6573,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
SemaRef.Diag(D.getIdentifierLoc(), diag::err_constructor_return_type)
<< SourceRange(D.getDeclSpec().getTypeSpecTypeLoc())
<< SourceRange(D.getIdentifierLoc());
- return 0;
+ return nullptr;
}
// This is a C++ method declaration.
@@ -6363,26 +6595,11 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
}
}
-void Sema::checkVoidParamDecl(ParmVarDecl *Param) {
- // In C++, the empty parameter-type-list must be spelled "void"; a
- // typedef of void is not permitted.
- if (getLangOpts().CPlusPlus &&
- Param->getType().getUnqualifiedType() != Context.VoidTy) {
- bool IsTypeAlias = false;
- if (const TypedefType *TT = Param->getType()->getAs<TypedefType>())
- IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl());
- else if (const TemplateSpecializationType *TST =
- Param->getType()->getAs<TemplateSpecializationType>())
- IsTypeAlias = TST->isTypeAlias();
- Diag(Param->getLocation(), diag::err_param_typedef_of_void)
- << IsTypeAlias;
- }
-}
-
enum OpenCLParamType {
ValidKernelParam,
PtrPtrKernelParam,
PtrKernelParam,
+ PrivatePtrKernelParam,
InvalidKernelParam,
RecordKernelParam
};
@@ -6390,7 +6607,10 @@ enum OpenCLParamType {
static OpenCLParamType getOpenCLKernelParameterType(QualType PT) {
if (PT->isPointerType()) {
QualType PointeeType = PT->getPointeeType();
- return PointeeType->isPointerType() ? PtrPtrKernelParam : PtrKernelParam;
+ if (PointeeType->isPointerType())
+ return PtrPtrKernelParam;
+ return PointeeType.getAddressSpace() == 0 ? PrivatePtrKernelParam
+ : PtrKernelParam;
}
// TODO: Forbid the other integer types (size_t, ptrdiff_t...) when they can
@@ -6435,6 +6655,14 @@ static void checkIsValidOpenCLKernelParameter(
D.setInvalidType();
return;
+ case PrivatePtrKernelParam:
+ // OpenCL v1.2 s6.9.a:
+ // A kernel function argument cannot be declared as a
+ // pointer to the private address space.
+ S.Diag(Param->getLocation(), diag::err_opencl_private_ptr_kernel_param);
+ D.setInvalidType();
+ return;
+
// OpenCL v1.2 s6.9.k:
// Arguments to kernel functions in a program cannot be declared with the
// built-in scalar types bool, half, size_t, ptrdiff_t, intptr_t, and
@@ -6464,7 +6692,7 @@ static void checkIsValidOpenCLKernelParameter(
// Track where we are in the nested structs. Items will migrate from
// VisitStack to HistoryStack as we do the DFS for bad field.
SmallVector<const FieldDecl *, 4> HistoryStack;
- HistoryStack.push_back((const FieldDecl *) 0);
+ HistoryStack.push_back(nullptr);
const RecordDecl *PD = PT->castAs<RecordType>()->getDecl();
VisitStack.push_back(PD);
@@ -6493,11 +6721,9 @@ static void checkIsValidOpenCLKernelParameter(
}
// Add a null marker so we know when we've gone back up a level
- VisitStack.push_back((const Decl *) 0);
+ VisitStack.push_back(nullptr);
- for (RecordDecl::field_iterator I = RD->field_begin(),
- E = RD->field_end(); I != E; ++I) {
- const FieldDecl *FD = *I;
+ for (const auto *FD : RD->fields()) {
QualType QT = FD->getType();
if (ValidTypes.count(QT.getTypePtr()))
@@ -6516,7 +6742,8 @@ static void checkIsValidOpenCLKernelParameter(
// Arguments to kernel functions that are declared to be a struct or union
// do not allow OpenCL objects to be passed as elements of the struct or
// union.
- if (ParamType == PtrKernelParam || ParamType == PtrPtrKernelParam) {
+ if (ParamType == PtrKernelParam || ParamType == PtrPtrKernelParam ||
+ ParamType == PrivatePtrKernelParam) {
S.Diag(Param->getLocation(),
diag::err_record_with_pointers_kernel_param)
<< PT->isUnionType()
@@ -6569,7 +6796,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
adjustMemberFunctionCC(R, D.isStaticMember());
bool isFriend = false;
- FunctionTemplateDecl *FunctionTemplate = 0;
+ FunctionTemplateDecl *FunctionTemplate = nullptr;
bool isExplicitSpecialization = false;
bool isFunctionTemplateSpecialization = false;
@@ -6584,7 +6811,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
FunctionDecl *NewFD = CreateNewFunctionDecl(*this, D, DC, R, TInfo, SC,
isVirtualOkay);
- if (!NewFD) return 0;
+ if (!NewFD) return nullptr;
if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer())
NewFD->setTopLevelDeclInObjCContainer();
@@ -6631,19 +6858,23 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (TemplateParameterList *TemplateParams =
MatchTemplateParametersToScopeSpecifier(
D.getDeclSpec().getLocStart(), D.getIdentifierLoc(),
- D.getCXXScopeSpec(), TemplateParamLists, isFriend,
- isExplicitSpecialization, Invalid)) {
+ D.getCXXScopeSpec(),
+ D.getName().getKind() == UnqualifiedId::IK_TemplateId
+ ? D.getName().TemplateId
+ : nullptr,
+ TemplateParamLists, isFriend, isExplicitSpecialization,
+ Invalid)) {
if (TemplateParams->size() > 0) {
// This is a function template
// Check that we can declare a template here.
if (CheckTemplateDeclScope(S, TemplateParams))
- return 0;
+ return nullptr;
// A destructor cannot be a template.
if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
Diag(NewFD->getLocation(), diag::err_destructor_template);
- return 0;
+ return nullptr;
}
// If we're adding a template to a dependent context, we may need to
@@ -6673,9 +6904,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// This is a function template specialization.
isFunctionTemplateSpecialization = true;
// For source fidelity, store all the template param lists.
- NewFD->setTemplateParameterListsInfo(Context,
- TemplateParamLists.size(),
- TemplateParamLists.data());
+ if (TemplateParamLists.size() > 0)
+ NewFD->setTemplateParameterListsInfo(Context,
+ TemplateParamLists.size(),
+ TemplateParamLists.data());
// C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);".
if (isFriend) {
@@ -6690,7 +6922,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
SourceLocation InsertLoc;
if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) {
InsertLoc = D.getName().getSourceRange().getEnd();
- InsertLoc = PP.getLocForEndOfToken(InsertLoc);
+ InsertLoc = getLocForEndOfToken(InsertLoc);
}
Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend)
@@ -6742,14 +6974,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
if (getLangOpts().CPlusPlus1y &&
- NewFD->getResultType()->isUndeducedType())
+ NewFD->getReturnType()->isUndeducedType())
Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_auto_fn_virtual);
}
if (getLangOpts().CPlusPlus1y &&
(NewFD->isDependentContext() ||
(isFriend && CurContext->isDependentContext())) &&
- NewFD->getResultType()->isUndeducedType()) {
+ NewFD->getReturnType()->isUndeducedType()) {
// If the function template is referenced directly (for instance, as a
// member of the current instantiation), pretend it has a dependent type.
// This is not really justified by the standard, but is the only sane
@@ -6758,9 +6990,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// a friend yet, so 'isDependentContext' on the FD doesn't work.
const FunctionProtoType *FPT =
NewFD->getType()->castAs<FunctionProtoType>();
- QualType Result = SubstAutoType(FPT->getResultType(),
- Context.DependentTy);
- NewFD->setType(Context.getFunctionType(Result, FPT->getArgTypes(),
+ QualType Result =
+ SubstAutoType(FPT->getReturnType(), Context.DependentTy);
+ NewFD->setType(Context.getFunctionType(Result, FPT->getParamTypes(),
FPT->getExtProtoInfo()));
}
@@ -6833,6 +7065,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
// If a function is defined as defaulted or deleted, mark it as such now.
+ // FIXME: Does this ever happen? ActOnStartOfFunctionDef forces the function
+ // definition kind to FDK_Definition.
switch (D.getFunctionDefinitionKind()) {
case FDK_Declaration:
case FDK_Definition:
@@ -6878,13 +7112,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
getLangOpts().CPlusPlus11 && FPT && !FPT->hasExceptionSpec()) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExceptionSpecType = EST_BasicNoexcept;
- NewFD->setType(Context.getFunctionType(FPT->getResultType(),
- FPT->getArgTypes(), EPI));
+ NewFD->setType(Context.getFunctionType(FPT->getReturnType(),
+ FPT->getParamTypes(), EPI));
}
}
// Filter out previous declarations that don't match the scope.
FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewFD),
+ D.getCXXScopeSpec().isNotEmpty() ||
isExplicitSpecialization ||
isFunctionTemplateSpecialization);
@@ -6893,7 +7128,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
NewFD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), Context,
- SE->getString()));
+ SE->getString(), 0));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewFD->getIdentifier());
@@ -6914,14 +7149,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// single void argument.
// We let through "const void" here because Sema::GetTypeForDeclarator
// already checks for that case.
- if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
- FTI.ArgInfo[0].Param &&
- cast<ParmVarDecl>(FTI.ArgInfo[0].Param)->getType()->isVoidType()) {
- // Empty arg list, don't push any params.
- checkVoidParamDecl(cast<ParmVarDecl>(FTI.ArgInfo[0].Param));
- } else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) {
- for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
- ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param);
+ if (FTIHasNonVoidParameters(FTI) && FTI.Params[0].Param) {
+ for (unsigned i = 0, e = FTI.NumParams; i != e; ++i) {
+ ParmVarDecl *Param = cast<ParmVarDecl>(FTI.Params[i].Param);
assert(Param->getDeclContext() != NewFD && "Was set before ?");
Param->setDeclContext(NewFD);
Params.push_back(Param);
@@ -6942,10 +7172,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// @endcode
// Synthesize a parameter for each argument type.
- for (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(),
- AE = FT->arg_type_end(); AI != AE; ++AI) {
+ for (const auto &AI : FT->param_types()) {
ParmVarDecl *Param =
- BuildParmVarDeclForTypedef(NewFD, D.getIdentifierLoc(), *AI);
+ BuildParmVarDeclForTypedef(NewFD, D.getIdentifierLoc(), AI);
Param->setScopeInfo(0, Params.size());
Params.push_back(Param);
}
@@ -6969,30 +7198,53 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (D.getDeclSpec().isNoreturnSpecified())
NewFD->addAttr(
::new(Context) C11NoReturnAttr(D.getDeclSpec().getNoreturnSpecLoc(),
- Context));
+ Context, 0));
// Functions returning a variably modified type violate C99 6.7.5.2p2
// because all functions have linkage.
if (!NewFD->isInvalidDecl() &&
- NewFD->getResultType()->isVariablyModifiedType()) {
+ NewFD->getReturnType()->isVariablyModifiedType()) {
Diag(NewFD->getLocation(), diag::err_vm_func_decl);
NewFD->setInvalidDecl();
}
+ if (D.isFunctionDefinition() && CodeSegStack.CurrentValue &&
+ !NewFD->hasAttr<SectionAttr>()) {
+ NewFD->addAttr(
+ SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate,
+ CodeSegStack.CurrentValue->getString(),
+ CodeSegStack.CurrentPragmaLocation));
+ if (UnifySection(CodeSegStack.CurrentValue->getString(),
+ PSF_Implicit | PSF_Execute | PSF_Read, NewFD))
+ NewFD->dropAttr<SectionAttr>();
+ }
+
// Handle attributes.
ProcessDeclAttributes(S, NewFD, D);
- QualType RetType = NewFD->getResultType();
+ QualType RetType = NewFD->getReturnType();
const CXXRecordDecl *Ret = RetType->isRecordType() ?
RetType->getAsCXXRecordDecl() : RetType->getPointeeCXXRecordDecl();
if (!NewFD->isInvalidDecl() && !NewFD->hasAttr<WarnUnusedResultAttr>() &&
Ret && Ret->hasAttr<WarnUnusedResultAttr>()) {
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
- // Attach the attribute to the new decl. Don't apply the attribute if it
- // returns an instance of the class (e.g. assignment operators).
- if (!MD || MD->getParent() != Ret) {
- NewFD->addAttr(new (Context) WarnUnusedResultAttr(SourceRange(),
- Context));
+ // Attach WarnUnusedResult to functions returning types with that attribute.
+ // Don't apply the attribute to that type's own non-static member functions
+ // (to avoid warning on things like assignment operators)
+ if (!MD || MD->getParent() != Ret)
+ NewFD->addAttr(WarnUnusedResultAttr::CreateImplicit(Context));
+ }
+
+ if (getLangOpts().OpenCL) {
+ // OpenCL v1.1 s6.5: Using an address space qualifier in a function return
+ // type declaration will generate a compilation error.
+ unsigned AddressSpace = RetType.getAddressSpace();
+ if (AddressSpace == LangAS::opencl_local ||
+ AddressSpace == LangAS::opencl_global ||
+ AddressSpace == LangAS::opencl_constant) {
+ Diag(NewFD->getLocation(),
+ diag::err_opencl_return_value_with_address_space);
+ NewFD->setInvalidDecl();
}
}
@@ -7050,21 +7302,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc);
HasExplicitTemplateArgs = false;
- } else if (!isFunctionTemplateSpecialization &&
- !D.getDeclSpec().isFriendSpecified()) {
- // We have encountered something that the user meant to be a
- // specialization (because it has explicitly-specified template
- // arguments) but that was not introduced with a "template<>" (or had
- // too few of them).
- // FIXME: Differentiate between attempts for explicit instantiations
- // (starting with "template") and the rest.
- Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header)
- << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)
- << FixItHint::CreateInsertion(
- D.getDeclSpec().getLocStart(),
- "template<> ");
- isFunctionTemplateSpecialization = true;
} else {
+ assert((isFunctionTemplateSpecialization ||
+ D.getDeclSpec().isFriendSpecified()) &&
+ "should have a 'template<>' for this decl");
// "friend void foo<>(int);" is an implicit specialization decl.
isFunctionTemplateSpecialization = true;
}
@@ -7076,7 +7317,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// friend void foo<>(int);
// Go ahead and fake up a template id.
HasExplicitTemplateArgs = true;
- TemplateArgs.setLAngleLoc(D.getIdentifierLoc());
+ TemplateArgs.setLAngleLoc(D.getIdentifierLoc());
TemplateArgs.setRAngleLoc(D.getIdentifierLoc());
}
@@ -7104,7 +7345,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
diag::err_function_specialization_in_class)
<< NewFD->getDeclName();
} else if (CheckFunctionTemplateSpecialization(NewFD,
- (HasExplicitTemplateArgs ? &TemplateArgs : 0),
+ (HasExplicitTemplateArgs ? &TemplateArgs
+ : nullptr),
Previous))
NewFD->setInvalidDecl();
@@ -7141,12 +7383,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint())
CheckMSVCRTEntryPoint(NewFD);
- if (NewFD->isInvalidDecl()) {
- // If this is a class member, mark the class invalid immediately.
- // This avoids some consistency errors later.
- if (CXXMethodDecl* methodDecl = dyn_cast<CXXMethodDecl>(NewFD))
- methodDecl->getParent()->setInvalidDecl();
- } else
+ if (!NewFD->isInvalidDecl())
D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
isExplicitSpecialization));
}
@@ -7178,7 +7415,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
FunctionTemplateDecl *PrevTemplate =
FunctionTemplate->getPreviousDecl();
CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(),
- PrevTemplate ? PrevTemplate->getTemplateParameters() : 0,
+ PrevTemplate ? PrevTemplate->getTemplateParameters()
+ : nullptr,
D.getDeclSpec().isFriendSpecified()
? (D.isFunctionDefinition()
? TPC_FriendFunctionTemplateDefinition
@@ -7232,7 +7470,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// whether the parameter types are references).
if (NamedDecl *Result = DiagnoseInvalidRedeclaration(
- *this, Previous, NewFD, ExtraArgs, false, 0)) {
+ *this, Previous, NewFD, ExtraArgs, false, nullptr)) {
AddToScope = ExtraArgs.AddToScope;
return Result;
}
@@ -7248,11 +7486,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
- } else if (!D.isFunctionDefinition() && D.getCXXScopeSpec().isSet() &&
+ } else if (!D.isFunctionDefinition() &&
+ isa<CXXMethodDecl>(NewFD) && NewFD->isOutOfLine() &&
!isFriend && !isFunctionTemplateSpecialization &&
!isExplicitSpecialization) {
// An out-of-line member function declaration must also be a
- // definition (C++ [dcl.meaning]p1).
+ // definition (C++ [class.mfct]p2).
// Note that this is not the case for explicit specializations of
// function templates or member functions of class templates, per
// C++ [temp.expl.spec]p2. We also allow these declarations as an
@@ -7281,7 +7520,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
EPI.Variadic = true;
EPI.ExtInfo = FT->getExtInfo();
- QualType R = Context.getFunctionType(FT->getResultType(), None, EPI);
+ QualType R = Context.getFunctionType(FT->getReturnType(), None, EPI);
NewFD->setType(R);
}
@@ -7294,6 +7533,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// marking the function.
AddCFAuditedAttribute(NewFD);
+ // If this is a function definition, check if we have to apply optnone due to
+ // a pragma.
+ if(D.isFunctionDefinition())
+ AddRangeBasedOptnone(NewFD);
+
// If this is the first declaration of an extern C variable, update
// the map of such variables.
if (NewFD->isFirstDecl() && !NewFD->isInvalidDecl() &&
@@ -7303,6 +7547,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Set this FunctionDecl's range up to the right paren.
NewFD->setRangeEnd(D.getSourceRange().getEnd());
+ if (D.isRedeclaration() && !Previous.empty()) {
+ checkDLLAttributeRedeclaration(
+ *this, dyn_cast<NamedDecl>(Previous.getRepresentativeDecl()), NewFD,
+ isExplicitSpecialization || isFunctionTemplateSpecialization);
+ }
+
if (getLangOpts().CPlusPlus) {
if (FunctionTemplate) {
if (NewFD->isInvalidDecl())
@@ -7320,18 +7570,17 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
// OpenCL v1.2, s6.9 -- Kernels can only have return type void.
- if (!NewFD->getResultType()->isVoidType()) {
- Diag(D.getIdentifierLoc(),
- diag::err_expected_kernel_void_return_type);
+ if (!NewFD->getReturnType()->isVoidType()) {
+ SourceRange RTRange = NewFD->getReturnTypeSourceRange();
+ Diag(D.getIdentifierLoc(), diag::err_expected_kernel_void_return_type)
+ << (RTRange.isValid() ? FixItHint::CreateReplacement(RTRange, "void")
+ : FixItHint());
D.setInvalidType();
}
llvm::SmallPtrSet<const Type *, 16> ValidTypes;
- for (FunctionDecl::param_iterator PI = NewFD->param_begin(),
- PE = NewFD->param_end(); PI != PE; ++PI) {
- ParmVarDecl *Param = *PI;
+ for (auto Param : NewFD->params())
checkIsValidOpenCLKernelParameter(*this, D, Param, ValidTypes);
- }
}
MarkUnusedFileScopedDecl(NewFD);
@@ -7341,7 +7590,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (!NewFD->isInvalidDecl() &&
NewFD->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
if (II->isStr("cudaConfigureCall")) {
- if (!R->getAs<FunctionType>()->getResultType()->isScalarType())
+ if (!R->getAs<FunctionType>()->getReturnType()->isScalarType())
Diag(NewFD->getLocation(), diag::err_config_scalar_return);
Context.setcudaConfigureCallDecl(NewFD);
@@ -7383,8 +7632,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
LookupResult &Previous,
bool IsExplicitSpecialization) {
- assert(!NewFD->getResultType()->isVariablyModifiedType()
- && "Variably modified return types are not handled here");
+ assert(!NewFD->getReturnType()->isVariablyModifiedType() &&
+ "Variably modified return types are not handled here");
// Determine whether the type of this function should be merged with
// a previous visible declaration. This never happens for functions in C++,
@@ -7396,7 +7645,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
filterNonConflictingPreviousDecls(Context, NewFD, Previous);
bool Redeclaration = false;
- NamedDecl *OldDecl = 0;
+ NamedDecl *OldDecl = nullptr;
// Merge or overload the declaration with an existing declaration of
// the same name, if appropriate.
@@ -7432,7 +7681,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// with that name must be marked "overloadable".
Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
<< Redeclaration << NewFD;
- NamedDecl *OverloadedDecl = 0;
+ NamedDecl *OverloadedDecl = nullptr;
if (Redeclaration)
OverloadedDecl = OldDecl;
else if (!Previous.empty())
@@ -7440,8 +7689,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (OverloadedDecl)
Diag(OverloadedDecl->getLocation(),
diag::note_attribute_overloadable_prev_overload);
- NewFD->addAttr(::new (Context) OverloadableAttr(SourceLocation(),
- Context));
+ NewFD->addAttr(OverloadableAttr::CreateImplicit(Context));
}
}
}
@@ -7464,12 +7712,11 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
<< Redeclaration << NewFD;
Diag(Previous.getFoundDecl()->getLocation(),
diag::note_attribute_overloadable_prev_overload);
- NewFD->addAttr(::new (Context) OverloadableAttr(SourceLocation(),
- Context));
+ NewFD->addAttr(OverloadableAttr::CreateImplicit(Context));
}
if (IsOverload(NewFD, cast<FunctionDecl>(OldDecl), false)) {
Redeclaration = false;
- OldDecl = 0;
+ OldDecl = nullptr;
}
}
}
@@ -7488,17 +7735,16 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (!getLangOpts().CPlusPlus1y && MD && MD->isConstexpr() &&
!MD->isStatic() && !isa<CXXConstructorDecl>(MD) &&
(MD->getTypeQualifiers() & Qualifiers::Const) == 0) {
- CXXMethodDecl *OldMD = dyn_cast_or_null<CXXMethodDecl>(OldDecl);
- if (FunctionTemplateDecl *OldTD =
- dyn_cast_or_null<FunctionTemplateDecl>(OldDecl))
- OldMD = dyn_cast<CXXMethodDecl>(OldTD->getTemplatedDecl());
+ CXXMethodDecl *OldMD = nullptr;
+ if (OldDecl)
+ OldMD = dyn_cast<CXXMethodDecl>(OldDecl->getAsFunction());
if (!OldMD || !OldMD->isStatic()) {
const FunctionProtoType *FPT =
MD->getType()->castAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.TypeQuals |= Qualifiers::Const;
- MD->setType(Context.getFunctionType(FPT->getResultType(),
- FPT->getArgTypes(), EPI));
+ MD->setType(Context.getFunctionType(FPT->getReturnType(),
+ FPT->getParamTypes(), EPI));
// Warn that we did this, if we're not performing template instantiation.
// In that case, we'll have warned already when the template was defined.
@@ -7506,7 +7752,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
SourceLocation AddConstLoc;
if (FunctionTypeLoc FTL = MD->getTypeSourceInfo()->getTypeLoc()
.IgnoreParens().getAs<FunctionTypeLoc>())
- AddConstLoc = PP.getLocForEndOfToken(FTL.getRParenLoc());
+ AddConstLoc = getLocForEndOfToken(FTL.getRParenLoc());
Diag(MD->getLocation(), diag::warn_cxx1y_compat_constexpr_not_const)
<< FixItHint::CreateInsertion(AddConstLoc, " const");
@@ -7656,7 +7902,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// compatible, and if it does, warn the user.
// But, issue any diagnostic on the first declaration only.
if (NewFD->isExternC() && Previous.empty()) {
- QualType R = NewFD->getResultType();
+ QualType R = NewFD->getReturnType();
if (R->isIncompleteType() && !R->isVoidType())
Diag(NewFD->getLocation(), diag::warn_return_value_udt_incomplete)
<< NewFD << R;
@@ -7668,26 +7914,10 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
return Redeclaration;
}
-static SourceRange getResultSourceRange(const FunctionDecl *FD) {
- const TypeSourceInfo *TSI = FD->getTypeSourceInfo();
- if (!TSI)
- return SourceRange();
-
- TypeLoc TL = TSI->getTypeLoc();
- FunctionTypeLoc FunctionTL = TL.getAs<FunctionTypeLoc>();
- if (!FunctionTL)
- return SourceRange();
-
- TypeLoc ResultTL = FunctionTL.getResultLoc();
- if (ResultTL.getUnqualifiedLoc().getAs<BuiltinTypeLoc>())
- return ResultTL.getSourceRange();
-
- return SourceRange();
-}
-
void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
- // C++11 [basic.start.main]p3: A program that declares main to be inline,
- // static or constexpr is ill-formed.
+ // C++11 [basic.start.main]p3:
+ // A program that [...] declares main to be inline, static or
+ // constexpr is ill-formed.
// C11 6.7.4p4: In a hosted environment, no function specifier(s) shall
// appear in a declaration of main.
// static main is not an error under C99, but we should warn about it.
@@ -7701,8 +7931,7 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
<< FixItHint::CreateRemoval(DS.getInlineSpecLoc());
if (DS.isNoreturnSpecified()) {
SourceLocation NoreturnLoc = DS.getNoreturnSpecLoc();
- SourceRange NoreturnRange(NoreturnLoc,
- PP.getLocForEndOfToken(NoreturnLoc));
+ SourceRange NoreturnRange(NoreturnLoc, getLocForEndOfToken(NoreturnLoc));
Diag(NoreturnLoc, diag::ext_noreturn_main);
Diag(NoreturnLoc, diag::note_main_remove_noreturn)
<< FixItHint::CreateRemoval(NoreturnRange);
@@ -7724,41 +7953,44 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
assert(T->isFunctionType() && "function decl is not of function type");
const FunctionType* FT = T->castAs<FunctionType>();
- // All the standards say that main() should should return 'int'.
- if (Context.hasSameUnqualifiedType(FT->getResultType(), Context.IntTy)) {
+ if (getLangOpts().GNUMode && !getLangOpts().CPlusPlus) {
+ // In C with GNU extensions we allow main() to have non-integer return
+ // type, but we should warn about the extension, and we disable the
+ // implicit-return-zero rule.
+
+ // GCC in C mode accepts qualified 'int'.
+ if (Context.hasSameUnqualifiedType(FT->getReturnType(), Context.IntTy))
+ FD->setHasImplicitReturnZero(true);
+ else {
+ Diag(FD->getTypeSpecStartLoc(), diag::ext_main_returns_nonint);
+ SourceRange RTRange = FD->getReturnTypeSourceRange();
+ if (RTRange.isValid())
+ Diag(RTRange.getBegin(), diag::note_main_change_return_type)
+ << FixItHint::CreateReplacement(RTRange, "int");
+ }
+ } else {
// In C and C++, main magically returns 0 if you fall off the end;
// set the flag which tells us that.
// This is C++ [basic.start.main]p5 and C99 5.1.2.2.3.
- FD->setHasImplicitReturnZero(true);
- // In C with GNU extensions we allow main() to have non-integer return
- // type, but we should warn about the extension, and we disable the
- // implicit-return-zero rule.
- } else if (getLangOpts().GNUMode && !getLangOpts().CPlusPlus) {
- Diag(FD->getTypeSpecStartLoc(), diag::ext_main_returns_nonint);
-
- SourceRange ResultRange = getResultSourceRange(FD);
- if (ResultRange.isValid())
- Diag(ResultRange.getBegin(), diag::note_main_change_return_type)
- << FixItHint::CreateReplacement(ResultRange, "int");
-
- // Otherwise, this is just a flat-out error.
- } else {
- SourceRange ResultRange = getResultSourceRange(FD);
- if (ResultRange.isValid())
+ // All the standards say that main() should return 'int'.
+ if (Context.hasSameType(FT->getReturnType(), Context.IntTy))
+ FD->setHasImplicitReturnZero(true);
+ else {
+ // Otherwise, this is just a flat-out error.
+ SourceRange RTRange = FD->getReturnTypeSourceRange();
Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint)
- << FixItHint::CreateReplacement(ResultRange, "int");
- else
- Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint);
-
- FD->setInvalidDecl(true);
+ << (RTRange.isValid() ? FixItHint::CreateReplacement(RTRange, "int")
+ : FixItHint());
+ FD->setInvalidDecl(true);
+ }
}
// Treat protoless main() as nullary.
if (isa<FunctionNoProtoType>(FT)) return;
const FunctionProtoType* FTP = cast<const FunctionProtoType>(FT);
- unsigned nparams = FTP->getNumArgs();
+ unsigned nparams = FTP->getNumParams();
assert(FD->getNumParams() == nparams);
bool HasExtraParameters = (nparams > 3);
@@ -7783,7 +8015,7 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
QualType Expected[] = { Context.IntTy, CharPP, CharPP, CharPP };
for (unsigned i = 0; i < nparams; ++i) {
- QualType AT = FTP->getArgType(i);
+ QualType AT = FTP->getParamType(i);
bool mismatch = true;
@@ -7818,7 +8050,7 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
}
if (!FD->isInvalidDecl() && FD->getDescribedFunctionTemplate()) {
- Diag(FD->getLocation(), diag::err_mainlike_template_decl) << FD->getName();
+ Diag(FD->getLocation(), diag::err_mainlike_template_decl) << FD;
FD->setInvalidDecl();
}
}
@@ -7830,15 +8062,15 @@ void Sema::CheckMSVCRTEntryPoint(FunctionDecl *FD) {
// Set an implicit return of 'zero' if the function can return some integral,
// enumeration, pointer or nullptr type.
- if (FT->getResultType()->isIntegralOrEnumerationType() ||
- FT->getResultType()->isAnyPointerType() ||
- FT->getResultType()->isNullPtrType())
+ if (FT->getReturnType()->isIntegralOrEnumerationType() ||
+ FT->getReturnType()->isAnyPointerType() ||
+ FT->getReturnType()->isNullPtrType())
// DllMain is exempt because a return value of zero means it failed.
if (FD->getName() != "DllMain")
FD->setHasImplicitReturnZero(true);
if (!FD->isInvalidDecl() && FD->getDescribedFunctionTemplate()) {
- Diag(FD->getLocation(), diag::err_mainlike_template_decl) << FD->getName();
+ Diag(FD->getLocation(), diag::err_mainlike_template_decl) << FD;
FD->setInvalidDecl();
}
}
@@ -7852,10 +8084,11 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
// "may accept other forms of constant expressions" exception.
// (We never end up here for C++, so the constant expression
// rules there don't matter.)
- if (Init->isConstantInitializer(Context, false))
+ const Expr *Culprit;
+ if (Init->isConstantInitializer(Context, false, &Culprit))
return false;
- Diag(Init->getExprLoc(), diag::err_init_element_not_constant)
- << Init->getSourceRange();
+ Diag(Culprit->getExprLoc(), diag::err_init_element_not_constant)
+ << Culprit->getSourceRange();
return true;
}
@@ -8029,7 +8262,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
bool DirectInit, bool TypeMayContainAuto) {
// If there is no declaration, there was an error parsing it. Just ignore
// the initializer.
- if (RealDecl == 0 || RealDecl->isInvalidDecl())
+ if (!RealDecl || RealDecl->isInvalidDecl())
return;
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
@@ -8084,6 +8317,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
return;
} else {
DeduceInit = CXXDirectInit->getExpr(0);
+ if (isa<InitListExpr>(DeduceInit))
+ Diag(CXXDirectInit->getLocStart(),
+ diag::err_auto_var_init_paren_braces)
+ << VDecl->getDeclName() << VDecl->getType()
+ << VDecl->getSourceRange();
}
}
@@ -8096,7 +8334,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
VDecl->setInvalidDecl();
return;
}
- Init = Result.take();
+ Init = Result.get();
DefaultedToAuto = true;
}
@@ -8141,6 +8379,13 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
return;
}
+ // dllimport cannot be used on variable definitions.
+ if (VDecl->hasAttr<DLLImportAttr>() && !VDecl->isStaticDataMember()) {
+ Diag(VDecl->getLocation(), diag::err_attribute_dllimport_data_definition);
+ VDecl->setInvalidDecl();
+ return;
+ }
+
if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) {
// C99 6.7.8p5. C++ has no such restriction, but that is a defect.
Diag(VDecl->getLocation(), diag::err_block_extern_cant_init);
@@ -8176,8 +8421,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
VDecl->setInvalidDecl();
return;
}
-
- const VarDecl* PrevInit = 0;
+
+ const VarDecl *PrevInit = nullptr;
if (getLangOpts().CPlusPlus) {
// C++ [class.static.data]p4
// If a static data member is of const integral or const
@@ -8192,9 +8437,9 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// data members we also need to check whether there was an in-class
// declaration with an initializer.
if (VDecl->isStaticDataMember() && VDecl->getAnyInitializer(PrevInit)) {
- Diag(VDecl->getLocation(), diag::err_redefinition)
- << VDecl->getDeclName();
- Diag(PrevInit->getLocation(), diag::note_previous_definition);
+ Diag(Init->getExprLoc(), diag::err_static_data_member_reinitialization)
+ << VDecl->getDeclName();
+ Diag(PrevInit->getInit()->getExprLoc(), diag::note_previous_initializer) << 0;
return;
}
@@ -8228,7 +8473,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
VDecl->setInvalidDecl();
return;
}
- Init = Result.take();
+ Init = Result.get();
}
// Perform the initialization.
@@ -8256,7 +8501,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
return;
}
- Init = Result.takeAs<Expr>();
+ Init = Result.getAs<Expr>();
}
// Check for self-references within variable initializers.
@@ -8287,13 +8532,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// we do not warn to warn spuriously when 'x' and 'y' are on separate
// paths through the function. This should be revisited if
// -Wrepeated-use-of-weak is made flow-sensitive.
- if (VDecl->getType().getObjCLifetime() == Qualifiers::OCL_Strong) {
- DiagnosticsEngine::Level Level =
- Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
- Init->getLocStart());
- if (Level != DiagnosticsEngine::Ignored)
+ if (VDecl->getType().getObjCLifetime() == Qualifiers::OCL_Strong &&
+ !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak,
+ Init->getLocStart()))
getCurFunction()->markSafeWeakUse(Init);
- }
}
// The initialization is usually a full-expression.
@@ -8314,7 +8556,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
VDecl->setInvalidDecl();
return;
}
- Init = Result.take();
+ Init = Result.get();
// Attach the initializer to the decl.
VDecl->setInit(Init);
@@ -8324,6 +8566,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// static storage duration shall be constant expressions or string literals.
// C++ does not have this restriction.
if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl()) {
+ const Expr *Culprit;
if (VDecl->getStorageClass() == SC_Static)
CheckForConstantInitializer(Init, DclT);
// C89 is stricter than C99 for non-static aggregate types.
@@ -8332,10 +8575,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// constant expressions.
else if (!getLangOpts().C99 && VDecl->getType()->isAggregateType() &&
isa<InitListExpr>(Init) &&
- !Init->isConstantInitializer(Context, false))
- Diag(Init->getExprLoc(),
+ !Init->isConstantInitializer(Context, false, &Culprit))
+ Diag(Culprit->getExprLoc(),
diag::ext_aggregate_init_not_constant)
- << Init->getSourceRange();
+ << Culprit->getSourceRange();
}
} else if (VDecl->isStaticDataMember() &&
VDecl->getLexicalDeclContext()->isRecord()) {
@@ -8444,19 +8687,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// C99 6.7.8p4. All file scoped initializers need to be constant.
if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl())
CheckForConstantInitializer(Init, DclT);
- else if (VDecl->getTLSKind() == VarDecl::TLS_Static &&
- !VDecl->isInvalidDecl() && !DclT->isDependentType() &&
- !Init->isValueDependent() && !VDecl->isConstexpr() &&
- !Init->isConstantInitializer(
- Context, VDecl->getType()->isReferenceType())) {
- // GNU C++98 edits for __thread, [basic.start.init]p4:
- // An object of thread storage duration shall not require dynamic
- // initialization.
- // FIXME: Need strict checking here.
- Diag(VDecl->getLocation(), diag::err_thread_dynamic_init);
- if (getLangOpts().CPlusPlus11)
- Diag(VDecl->getLocation(), diag::note_use_thread_local);
- }
}
// We will represent direct-initialization similarly to copy-initialization:
@@ -8512,7 +8742,7 @@ void Sema::ActOnInitializerError(Decl *D) {
return;
}
- // Require an abstract type.
+ // Require a non-abstract type.
if (RequireNonAbstractType(VD->getLocation(), Ty,
diag::err_abstract_type_in_decl,
AbstractVariableType)) {
@@ -8527,7 +8757,7 @@ void Sema::ActOnInitializerError(Decl *D) {
void Sema::ActOnUninitializedDecl(Decl *RealDecl,
bool TypeMayContainAuto) {
// If there is no declaration, there was an error parsing it. Just ignore it.
- if (RealDecl == 0)
+ if (!RealDecl)
return;
if (VarDecl *Var = dyn_cast<VarDecl>(RealDecl)) {
@@ -8558,6 +8788,16 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
return;
}
+ // OpenCL v1.1 s6.5.3: variables declared in the constant address space must
+ // be initialized.
+ if (!Var->isInvalidDecl() &&
+ Var->getType().getAddressSpace() == LangAS::opencl_constant &&
+ Var->getStorageClass() != SC_Extern && !Var->getInit()) {
+ Diag(Var->getLocation(), diag::err_opencl_constant_no_init);
+ Var->setInvalidDecl();
+ return;
+ }
+
switch (Var->isThisDeclarationADefinition()) {
case VarDecl::Definition:
if (!Var->isStaticDataMember() || !Var->getAnyInitializer())
@@ -8657,11 +8897,13 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
if (Var->isInvalidDecl())
return;
- if (RequireCompleteType(Var->getLocation(),
- Context.getBaseElementType(Type),
- diag::err_typecheck_decl_incomplete_type)) {
- Var->setInvalidDecl();
- return;
+ if (!Var->hasAttr<AliasAttr>()) {
+ if (RequireCompleteType(Var->getLocation(),
+ Context.getBaseElementType(Type),
+ diag::err_typecheck_decl_incomplete_type)) {
+ Var->setInvalidDecl();
+ return;
+ }
}
// The variable can not have an abstract class type.
@@ -8768,6 +9010,37 @@ void Sema::ActOnCXXForRangeDecl(Decl *D) {
}
}
+StmtResult
+Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
+ IdentifierInfo *Ident,
+ ParsedAttributes &Attrs,
+ SourceLocation AttrEnd) {
+ // C++1y [stmt.iter]p1:
+ // A range-based for statement of the form
+ // for ( for-range-identifier : for-range-initializer ) statement
+ // is equivalent to
+ // for ( auto&& for-range-identifier : for-range-initializer ) statement
+ DeclSpec DS(Attrs.getPool().getFactory());
+
+ const char *PrevSpec;
+ unsigned DiagID;
+ DS.SetTypeSpecType(DeclSpec::TST_auto, IdentLoc, PrevSpec, DiagID,
+ getPrintingPolicy());
+
+ Declarator D(DS, Declarator::ForContext);
+ D.SetIdentifier(Ident, IdentLoc);
+ D.takeAttributes(Attrs, AttrEnd);
+
+ ParsedAttributes EmptyAttrs(Attrs.getPool().getFactory());
+ D.AddTypeInfo(DeclaratorChunk::getReference(0, IdentLoc, /*lvalue*/false),
+ EmptyAttrs, IdentLoc);
+ Decl *Var = ActOnDeclarator(S, D);
+ cast<VarDecl>(Var)->setCXXForRangeDecl(true);
+ FinalizeDeclaration(Var);
+ return ActOnDeclStmt(FinalizeDeclaratorGroup(S, DS, Var), IdentLoc,
+ AttrEnd.isValid() ? AttrEnd : IdentLoc);
+}
+
void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (var->isInvalidDecl()) return;
@@ -8788,11 +9061,16 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
}
}
+ // Warn about externally-visible variables being defined without a
+ // prior declaration. We only want to do this for global
+ // declarations, but we also specifically need to avoid doing it for
+ // class members because the linkage of an anonymous class can
+ // change if it's later given a typedef name.
if (var->isThisDeclarationADefinition() &&
+ var->getDeclContext()->getRedeclContext()->isFileContext() &&
var->isExternallyVisible() && var->hasLinkage() &&
- getDiagnostics().getDiagnosticLevel(
- diag::warn_missing_variable_declarations,
- var->getLocation())) {
+ !getDiagnostics().isIgnored(diag::warn_missing_variable_declarations,
+ var->getLocation())) {
// Find a previous declaration that's not a definition.
VarDecl *prev = var->getPreviousDecl();
while (prev && prev->isThisDeclarationADefinition())
@@ -8802,14 +9080,58 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
Diag(var->getLocation(), diag::warn_missing_variable_declarations) << var;
}
- if (var->getTLSKind() == VarDecl::TLS_Static &&
- var->getType().isDestructedType()) {
- // GNU C++98 edits for __thread, [basic.start.term]p3:
- // The type of an object with thread storage duration shall not
- // have a non-trivial destructor.
- Diag(var->getLocation(), diag::err_thread_nontrivial_dtor);
- if (getLangOpts().CPlusPlus11)
- Diag(var->getLocation(), diag::note_use_thread_local);
+ if (var->getTLSKind() == VarDecl::TLS_Static) {
+ const Expr *Culprit;
+ if (var->getType().isDestructedType()) {
+ // GNU C++98 edits for __thread, [basic.start.term]p3:
+ // The type of an object with thread storage duration shall not
+ // have a non-trivial destructor.
+ Diag(var->getLocation(), diag::err_thread_nontrivial_dtor);
+ if (getLangOpts().CPlusPlus11)
+ Diag(var->getLocation(), diag::note_use_thread_local);
+ } else if (getLangOpts().CPlusPlus && var->hasInit() &&
+ !var->getInit()->isConstantInitializer(
+ Context, var->getType()->isReferenceType(), &Culprit)) {
+ // GNU C++98 edits for __thread, [basic.start.init]p4:
+ // An object of thread storage duration shall not require dynamic
+ // initialization.
+ // FIXME: Need strict checking here.
+ Diag(Culprit->getExprLoc(), diag::err_thread_dynamic_init)
+ << Culprit->getSourceRange();
+ if (getLangOpts().CPlusPlus11)
+ Diag(var->getLocation(), diag::note_use_thread_local);
+ }
+
+ }
+
+ if (var->isThisDeclarationADefinition() &&
+ ActiveTemplateInstantiations.empty()) {
+ PragmaStack<StringLiteral *> *Stack = nullptr;
+ int SectionFlags = PSF_Implicit | PSF_Read;
+ if (var->getType().isConstQualified())
+ Stack = &ConstSegStack;
+ else if (!var->getInit()) {
+ Stack = &BSSSegStack;
+ SectionFlags |= PSF_Write;
+ } else {
+ Stack = &DataSegStack;
+ SectionFlags |= PSF_Write;
+ }
+ if (!var->hasAttr<SectionAttr>() && Stack->CurrentValue)
+ var->addAttr(
+ SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate,
+ Stack->CurrentValue->getString(),
+ Stack->CurrentPragmaLocation));
+ if (const SectionAttr *SA = var->getAttr<SectionAttr>())
+ if (UnifySection(SA->getName(), SectionFlags, var))
+ var->dropAttr<SectionAttr>();
+
+ // Apply the init_seg attribute if this has an initializer. If the
+ // initializer turns out to not be dynamic, we'll end up ignoring this
+ // attribute.
+ if (CurInitSeg && var->getInit())
+ var->addAttr(InitSegAttr::CreateImplicit(Context, CurInitSeg->getString(),
+ CurInitSegLoc));
}
// All the following checks are C++ only.
@@ -8835,7 +9157,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
var, var->getType(), varRef, /*AllowNRVO=*/true);
if (!result.isInvalid()) {
result = MaybeCreateExprWithCleanups(result);
- Expr *init = result.takeAs<Expr>();
+ Expr *init = result.getAs<Expr>();
Context.setBlockVarCopyInits(var, init);
}
}
@@ -8848,9 +9170,8 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (!var->getDeclContext()->isDependentContext() &&
Init && !Init->isValueDependent()) {
if (IsGlobal && !var->isConstexpr() &&
- getDiagnostics().getDiagnosticLevel(diag::warn_global_constructor,
- var->getLocation())
- != DiagnosticsEngine::Ignored) {
+ !getDiagnostics().isIgnored(diag::warn_global_constructor,
+ var->getLocation())) {
// Warn about globals which don't have a constant initializer. Don't
// warn about globals with a non-trivial destructor because we already
// warned about them.
@@ -8901,9 +9222,45 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
if (!VD)
return;
+ checkAttributesAfterMerging(*this, *VD);
+
+ // Static locals inherit dll attributes from their function.
+ if (VD->isStaticLocal()) {
+ if (FunctionDecl *FD =
+ dyn_cast<FunctionDecl>(VD->getParentFunctionOrMethod())) {
+ if (Attr *A = getDLLAttr(FD)) {
+ auto *NewAttr = cast<InheritableAttr>(A->clone(getASTContext()));
+ NewAttr->setInherited(true);
+ VD->addAttr(NewAttr);
+ }
+ }
+ }
+
+ // Imported static data members cannot be defined out-of-line.
+ if (const DLLImportAttr *IA = VD->getAttr<DLLImportAttr>()) {
+ if (VD->isStaticDataMember() && VD->isOutOfLine() &&
+ VD->isThisDeclarationADefinition()) {
+ // We allow definitions of dllimport class template static data members
+ // with a warning.
+ CXXRecordDecl *Context =
+ cast<CXXRecordDecl>(VD->getFirstDecl()->getDeclContext());
+ bool IsClassTemplateMember =
+ isa<ClassTemplatePartialSpecializationDecl>(Context) ||
+ Context->getDescribedClassTemplate();
+
+ Diag(VD->getLocation(),
+ IsClassTemplateMember
+ ? diag::warn_attribute_dllimport_static_field_definition
+ : diag::err_attribute_dllimport_static_field_definition);
+ Diag(IA->getLocation(), diag::note_attribute);
+ if (!IsClassTemplateMember)
+ VD->setInvalidDecl();
+ }
+ }
+
if (UsedAttr *Attr = VD->getAttr<UsedAttr>()) {
if (!Attr->isInherited() && !VD->isThisDeclarationADefinition()) {
- Diag(Attr->getLocation(), diag::warn_attribute_ignored) << "used";
+ Diag(Attr->getLocation(), diag::warn_attribute_ignored) << Attr;
VD->dropAttr<UsedAttr>();
}
}
@@ -8923,10 +9280,12 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
const DeclContext *DC = VD->getDeclContext();
// If there's a #pragma GCC visibility in scope, and this isn't a class
// member, set the visibility of this variable.
- if (!DC->isRecord() && VD->isExternallyVisible())
+ if (DC->getRedeclContext()->isFileContext() && VD->isExternallyVisible())
AddPushedVisibilityAttribute(VD);
- if (VD->isFileVarDecl())
+ // FIXME: Warn on unused templates.
+ if (VD->isFileVarDecl() && !VD->getDescribedVarTemplate() &&
+ !isa<VarTemplatePartialSpecializationDecl>(VD))
MarkUnusedFileScopedDecl(VD);
// Now we have parsed the initializer and can update the table of magic
@@ -8935,10 +9294,7 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
!VD->getType()->isIntegralOrEnumerationType())
return;
- for (specific_attr_iterator<TypeTagForDatatypeAttr>
- I = ThisDecl->specific_attr_begin<TypeTagForDatatypeAttr>(),
- E = ThisDecl->specific_attr_end<TypeTagForDatatypeAttr>();
- I != E; ++I) {
+ for (const auto *I : ThisDecl->specific_attrs<TypeTagForDatatypeAttr>()) {
const Expr *MagicValueExpr = VD->getInit();
if (!MagicValueExpr) {
continue;
@@ -8972,7 +9328,7 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
if (DS.isTypeSpecOwned())
Decls.push_back(DS.getRepAsDecl());
- DeclaratorDecl *FirstDeclaratorInGroup = 0;
+ DeclaratorDecl *FirstDeclaratorInGroup = nullptr;
for (unsigned i = 0, e = Group.size(); i != e; ++i)
if (Decl *D = Group[i]) {
if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D))
@@ -8983,7 +9339,7 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
if (DeclSpec::isDeclRep(DS.getTypeSpecType())) {
if (TagDecl *Tag = dyn_cast_or_null<TagDecl>(DS.getRepAsDecl())) {
- HandleTagNumbering(*this, Tag);
+ HandleTagNumbering(*this, Tag, S);
if (!Tag->hasNameForLinkage() && !Tag->hasDeclaratorForAnonDecl())
Tag->setDeclaratorForAnonDecl(FirstDeclaratorInGroup);
}
@@ -8995,7 +9351,7 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
/// BuildDeclaratorGroup - convert a list of declarations into a declaration
/// group, performing any necessary semantic checking.
Sema::DeclGroupPtrTy
-Sema::BuildDeclaratorGroup(llvm::MutableArrayRef<Decl *> Group,
+Sema::BuildDeclaratorGroup(MutableArrayRef<Decl *> Group,
bool TypeMayContainAuto) {
// C++0x [dcl.spec.auto]p7:
// If the type deduced for the template parameter U is not the same in each
@@ -9007,7 +9363,7 @@ Sema::BuildDeclaratorGroup(llvm::MutableArrayRef<Decl *> Group,
if (TypeMayContainAuto && Group.size() > 1) {
QualType Deduced;
CanQualType DeducedCanon;
- VarDecl *DeducedDecl = 0;
+ VarDecl *DeducedDecl = nullptr;
for (unsigned i = 0, e = Group.size(); i != e; ++i) {
if (VarDecl *D = dyn_cast<VarDecl>(Group[i])) {
AutoType *AT = D->getType()->getContainedAutoType();
@@ -9052,9 +9408,7 @@ void Sema::ActOnDocumentableDecls(ArrayRef<Decl *> Group) {
if (Group.empty() || !Group[0])
return;
- if (Diags.getDiagnosticLevel(diag::warn_doc_param_not_found,
- Group[0]->getLocation())
- == DiagnosticsEngine::Ignored)
+ if (Diags.isIgnored(diag::warn_doc_param_not_found, Group[0]->getLocation()))
return;
if (Group.size() >= 2) {
@@ -9133,12 +9487,12 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
}
// Ensure we have a valid name
- IdentifierInfo *II = 0;
+ IdentifierInfo *II = nullptr;
if (D.hasName()) {
II = D.getIdentifier();
if (!II) {
Diag(D.getIdentifierLoc(), diag::err_bad_parameter_name)
- << GetNameForDeclarator(D).getName().getAsString();
+ << GetNameForDeclarator(D).getName();
D.setInvalidType(true);
}
}
@@ -9154,14 +9508,14 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
// Just pretend that we didn't see the previous declaration.
- PrevDecl = 0;
+ PrevDecl = nullptr;
} else if (S->isDeclScope(PrevDecl)) {
Diag(D.getIdentifierLoc(), diag::err_param_redefinition) << II;
Diag(PrevDecl->getLocation(), diag::note_previous_declaration);
// Recover by removing the name
- II = 0;
- D.SetIdentifier(0, D.getIdentifierLoc());
+ II = nullptr;
+ D.SetIdentifier(nullptr, D.getIdentifierLoc());
D.setInvalidType(true);
}
}
@@ -9211,9 +9565,9 @@ ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC,
/* FIXME: setting StartLoc == Loc.
Would it be worth to modify callers so as to provide proper source
location for the unnamed parameters, embedding the parameter's type? */
- ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, Loc, Loc, 0,
+ ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, Loc, Loc, nullptr,
T, Context.getTrivialTypeSourceInfo(T, Loc),
- SC_None, 0);
+ SC_None, nullptr);
Param->setImplicit();
return Param;
}
@@ -9293,7 +9647,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name,
Context.getAdjustedParameterType(T),
TSInfo,
- StorageClass, 0);
+ StorageClass, nullptr);
// Parameters can not be abstract class types.
// For record types, this is done by the AbstractClassUsageDiagnoser once
@@ -9319,8 +9673,12 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
// Since all parameters have automatic store duration, they can not have
// an address space.
if (T.getAddressSpace() != 0) {
- Diag(NameLoc, diag::err_arg_with_address_space);
- New->setInvalidDecl();
+ // OpenCL allows function arguments declared to be an array of a type
+ // to be qualified with an address space.
+ if (!(getLangOpts().OpenCL && T->isArrayType())) {
+ Diag(NameLoc, diag::err_arg_with_address_space);
+ New->setInvalidDecl();
+ }
}
return New;
@@ -9333,16 +9691,15 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
// Verify 6.9.1p6: 'every identifier in the identifier list shall be declared'
// for a K&R function.
if (!FTI.hasPrototype) {
- for (int i = FTI.NumArgs; i != 0; /* decrement in loop */) {
+ for (int i = FTI.NumParams; i != 0; /* decrement in loop */) {
--i;
- if (FTI.ArgInfo[i].Param == 0) {
+ if (FTI.Params[i].Param == nullptr) {
SmallString<256> Code;
- llvm::raw_svector_ostream(Code) << " int "
- << FTI.ArgInfo[i].Ident->getName()
- << ";\n";
- Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared)
- << FTI.ArgInfo[i].Ident
- << FixItHint::CreateInsertion(LocAfterDecls, Code.str());
+ llvm::raw_svector_ostream(Code)
+ << " int " << FTI.Params[i].Ident->getName() << ";\n";
+ Diag(FTI.Params[i].IdentLoc, diag::ext_param_not_declared)
+ << FTI.Params[i].Ident
+ << FixItHint::CreateInsertion(LocAfterDecls, Code.str());
// Implicitly declare the argument as type 'int' for lack of a better
// type.
@@ -9350,21 +9707,21 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
DeclSpec DS(attrs);
const char* PrevSpec; // unused
unsigned DiagID; // unused
- DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc,
- PrevSpec, DiagID);
+ DS.SetTypeSpecType(DeclSpec::TST_int, FTI.Params[i].IdentLoc, PrevSpec,
+ DiagID, Context.getPrintingPolicy());
// Use the identifier location for the type source range.
- DS.SetRangeStart(FTI.ArgInfo[i].IdentLoc);
- DS.SetRangeEnd(FTI.ArgInfo[i].IdentLoc);
+ DS.SetRangeStart(FTI.Params[i].IdentLoc);
+ DS.SetRangeEnd(FTI.Params[i].IdentLoc);
Declarator ParamD(DS, Declarator::KNRTypeListContext);
- ParamD.SetIdentifier(FTI.ArgInfo[i].Ident, FTI.ArgInfo[i].IdentLoc);
- FTI.ArgInfo[i].Param = ActOnParamDeclarator(S, ParamD);
+ ParamD.SetIdentifier(FTI.Params[i].Ident, FTI.Params[i].IdentLoc);
+ FTI.Params[i].Param = ActOnParamDeclarator(S, ParamD);
}
}
}
}
Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
- assert(getCurFunctionDecl() == 0 && "Function parsing confused");
+ assert(getCurFunctionDecl() == nullptr && "Function parsing confused");
assert(D.isFunctionDeclarator() && "Not a function declarator!");
Scope *ParentScope = FnBodyScope->getParent();
@@ -9373,6 +9730,10 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
return ActOnStartOfFunctionDef(FnBodyScope, DP);
}
+void Sema::ActOnFinishInlineMethodDef(CXXMethodDecl *D) {
+ Consumer.HandleInlineMethodDefinition(D);
+}
+
static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
const FunctionDecl*& PossibleZeroParamPrototype) {
// Don't warn about invalid declarations.
@@ -9456,7 +9817,7 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
LambdaScopeInfo *LSI = S.PushLambdaScope();
LSI->CallOperator = CallOperator;
LSI->Lambda = LambdaClass;
- LSI->ReturnType = CallOperator->getResultType();
+ LSI->ReturnType = CallOperator->getReturnType();
const LambdaCaptureDefault LCD = LambdaClass->getLambdaCaptureDefault();
if (LCD == LCD_None)
@@ -9472,23 +9833,22 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
// Add the captures to the LSI so they can be noted as already
// captured within tryCaptureVar.
- for (LambdaExpr::capture_iterator C = LambdaClass->captures_begin(),
- CEnd = LambdaClass->captures_end(); C != CEnd; ++C) {
- if (C->capturesVariable()) {
- VarDecl *VD = C->getCapturedVar();
+ for (const auto &C : LambdaClass->captures()) {
+ if (C.capturesVariable()) {
+ VarDecl *VD = C.getCapturedVar();
if (VD->isInitCapture())
S.CurrentInstantiationScope->InstantiatedLocal(VD, VD);
QualType CaptureType = VD->getType();
- const bool ByRef = C->getCaptureKind() == LCK_ByRef;
+ const bool ByRef = C.getCaptureKind() == LCK_ByRef;
LSI->addCapture(VD, /*IsBlock*/false, ByRef,
- /*RefersToEnclosingLocal*/true, C->getLocation(),
- /*EllipsisLoc*/C->isPackExpansion()
- ? C->getEllipsisLoc() : SourceLocation(),
- CaptureType, /*Expr*/ 0);
-
- } else if (C->capturesThis()) {
- LSI->addThisCapture(/*Nested*/ false, C->getLocation(),
- S.getCurrentThisType(), /*Expr*/ 0);
+ /*RefersToEnclosingLocal*/true, C.getLocation(),
+ /*EllipsisLoc*/C.isPackExpansion()
+ ? C.getEllipsisLoc() : SourceLocation(),
+ CaptureType, /*Expr*/ nullptr);
+
+ } else if (C.capturesThis()) {
+ LSI->addThisCapture(/*Nested*/ false, C.getLocation(),
+ S.getCurrentThisType(), /*Expr*/ nullptr);
}
}
}
@@ -9499,7 +9859,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
if (!D)
return D;
- FunctionDecl *FD = 0;
+ FunctionDecl *FD = nullptr;
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D))
FD = FunTmpl->getTemplatedDecl();
@@ -9539,7 +9899,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
// The return type of a function definition must be complete
// (C99 6.9.1p3, C++ [dcl.fct]p6).
- QualType ResultType = FD->getResultType();
+ QualType ResultType = FD->getReturnType();
if (!ResultType->isDependentType() && !ResultType->isVoidType() &&
!FD->isInvalidDecl() &&
RequireCompleteType(FD->getLocation(), ResultType,
@@ -9551,7 +9911,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
// prototype declaration. This warning is issued even if the
// definition itself provides a prototype. The aim is to detect
// global functions that fail to be declared in header files.
- const FunctionDecl *PossibleZeroParamPrototype = 0;
+ const FunctionDecl *PossibleZeroParamPrototype = nullptr;
if (ShouldWarnAboutMissingPrototype(FD, PossibleZeroParamPrototype)) {
Diag(FD->getLocation(), diag::warn_missing_prototype) << FD;
@@ -9578,8 +9938,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
/*CheckParameterNames=*/true);
// Introduce our parameters into the function scope
- for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) {
- ParmVarDecl *Param = FD->getParamDecl(p);
+ for (auto Param : FD->params()) {
Param->setOwningFunction(FD);
// If this has an identifier, add it to the scope stack.
@@ -9604,9 +9963,8 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
// and reattach to the current context.
if (D->getLexicalDeclContext() == Context.getTranslationUnitDecl()) {
// Is the decl actually in the context?
- for (DeclContext::decl_iterator DI = Context.getTranslationUnitDecl()->decls_begin(),
- DE = Context.getTranslationUnitDecl()->decls_end(); DI != DE; ++DI) {
- if (*DI == D) {
+ for (const auto *DI : Context.getTranslationUnitDecl()->decls()) {
+ if (DI == D) {
Context.getTranslationUnitDecl()->removeDecl(D);
break;
}
@@ -9621,10 +9979,9 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
// Similarly, dive into enums and fish their constants out, making them
// accessible in this scope.
- if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
- for (EnumDecl::enumerator_iterator EI = ED->enumerator_begin(),
- EE = ED->enumerator_end(); EI != EE; ++EI)
- PushOnScopeChains(*EI, FnBodyScope, /*AddToContext=*/false);
+ if (auto *ED = dyn_cast<EnumDecl>(D)) {
+ for (auto *EI : ED->enumerators())
+ PushOnScopeChains(EI, FnBodyScope, /*AddToContext=*/false);
}
}
}
@@ -9633,35 +9990,22 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
if (const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>())
ResolveExceptionSpec(D->getLocation(), FPT);
- // Checking attributes of current function definition
- // dllimport attribute.
- DLLImportAttr *DA = FD->getAttr<DLLImportAttr>();
- if (DA && (!FD->getAttr<DLLExportAttr>())) {
- // dllimport attribute cannot be directly applied to definition.
- // Microsoft accepts dllimport for functions defined within class scope.
- if (!DA->isInherited() &&
- !(LangOpts.MicrosoftExt && FD->getLexicalDeclContext()->isRecord())) {
- Diag(FD->getLocation(),
- diag::err_attribute_can_be_applied_only_to_symbol_declaration)
- << "dllimport";
- FD->setInvalidDecl();
- return D;
- }
-
- // Visual C++ appears to not think this is an issue, so only issue
- // a warning when Microsoft extensions are disabled.
- if (!LangOpts.MicrosoftExt) {
- // If a symbol previously declared dllimport is later defined, the
- // attribute is ignored in subsequent references, and a warning is
- // emitted.
- Diag(FD->getLocation(),
- diag::warn_redeclaration_without_attribute_prev_attribute_ignored)
- << FD->getName() << "dllimport";
- }
+ // dllimport cannot be applied to non-inline function definitions.
+ if (FD->hasAttr<DLLImportAttr>() && !FD->isInlined() &&
+ !FD->isTemplateInstantiation()) {
+ assert(!FD->hasAttr<DLLExportAttr>());
+ Diag(FD->getLocation(), diag::err_attribute_dllimport_function_definition);
+ FD->setInvalidDecl();
+ return D;
}
// We want to attach documentation to original Decl (which might be
// a function template).
ActOnDocumentableDecl(D);
+ if (getCurLexicalContext()->isObjCContainer() &&
+ getCurLexicalContext()->getDeclKind() != Decl::ObjCCategoryImpl &&
+ getCurLexicalContext()->getDeclKind() != Decl::ObjCImplementation)
+ Diag(FD->getLocation(), diag::warn_function_def_in_objc_container);
+
return D;
}
@@ -9675,49 +10019,53 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
/// use the named return value optimization.
///
/// This function applies a very simplistic algorithm for NRVO: if every return
-/// statement in the function has the same NRVO candidate, that candidate is
-/// the NRVO variable.
-///
-/// FIXME: Employ a smarter algorithm that accounts for multiple return
-/// statements and the lifetimes of the NRVO candidates. We should be able to
-/// find a maximal set of NRVO variables.
+/// statement in the scope of a variable has the same NRVO candidate, that
+/// candidate is an NRVO variable.
void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) {
ReturnStmt **Returns = Scope->Returns.data();
- const VarDecl *NRVOCandidate = 0;
for (unsigned I = 0, E = Scope->Returns.size(); I != E; ++I) {
- if (!Returns[I]->getNRVOCandidate())
- return;
-
- if (!NRVOCandidate)
- NRVOCandidate = Returns[I]->getNRVOCandidate();
- else if (NRVOCandidate != Returns[I]->getNRVOCandidate())
- return;
+ if (const VarDecl *NRVOCandidate = Returns[I]->getNRVOCandidate()) {
+ if (!NRVOCandidate->isNRVOVariable())
+ Returns[I]->setNRVOCandidate(nullptr);
+ }
}
-
- if (NRVOCandidate)
- const_cast<VarDecl*>(NRVOCandidate)->setNRVOVariable(true);
}
-bool Sema::canSkipFunctionBody(Decl *D) {
- if (!Consumer.shouldSkipFunctionBody(D))
+bool Sema::canDelayFunctionBody(const Declarator &D) {
+ // We can't delay parsing the body of a constexpr function template (yet).
+ if (D.getDeclSpec().isConstexprSpecified())
return false;
- if (isa<ObjCMethodDecl>(D))
- return true;
+ // We can't delay parsing the body of a function template with a deduced
+ // return type (yet).
+ if (D.getDeclSpec().containsPlaceholderType()) {
+ // If the placeholder introduces a non-deduced trailing return type,
+ // we can still delay parsing it.
+ if (D.getNumTypeObjects()) {
+ const auto &Outer = D.getTypeObject(D.getNumTypeObjects() - 1);
+ if (Outer.Kind == DeclaratorChunk::Function &&
+ Outer.Fun.hasTrailingReturnType()) {
+ QualType Ty = GetTypeFromParser(Outer.Fun.getTrailingReturnType());
+ return Ty.isNull() || !Ty->isUndeducedType();
+ }
+ }
+ return false;
+ }
- FunctionDecl *FD = 0;
- if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
- FD = FTD->getTemplatedDecl();
- else
- FD = cast<FunctionDecl>(D);
+ return true;
+}
+bool Sema::canSkipFunctionBody(Decl *D) {
// We cannot skip the body of a function (or function template) which is
// constexpr, since we may need to evaluate its body in order to parse the
// rest of the file.
// We cannot skip the body of a function with an undeduced return type,
// because any callers of that function need to know the type.
- return !FD->isConstexpr() && !FD->getResultType()->isUndeducedType();
+ if (const FunctionDecl *FD = D->getAsFunction())
+ if (FD->isConstexpr() || FD->getReturnType()->isUndeducedType())
+ return false;
+ return Consumer.shouldSkipFunctionBody(D);
}
Decl *Sema::ActOnSkippedFunctionBody(Decl *Decl) {
@@ -9725,7 +10073,7 @@ Decl *Sema::ActOnSkippedFunctionBody(Decl *Decl) {
FD->setHasSkippedBody();
else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(Decl))
MD->setHasSkippedBody();
- return ActOnFinishFunctionBody(Decl, 0);
+ return ActOnFinishFunctionBody(Decl, nullptr);
}
Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) {
@@ -9734,32 +10082,27 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) {
Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
bool IsInstantiation) {
- FunctionDecl *FD = 0;
- FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl);
- if (FunTmpl)
- FD = FunTmpl->getTemplatedDecl();
- else
- FD = dyn_cast_or_null<FunctionDecl>(dcl);
+ FunctionDecl *FD = dcl ? dcl->getAsFunction() : nullptr;
sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
- sema::AnalysisBasedWarnings::Policy *ActivePolicy = 0;
+ sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr;
if (FD) {
FD->setBody(Body);
if (getLangOpts().CPlusPlus1y && !FD->isInvalidDecl() && Body &&
- !FD->isDependentContext() && FD->getResultType()->isUndeducedType()) {
+ !FD->isDependentContext() && FD->getReturnType()->isUndeducedType()) {
// If the function has a deduced result type but contains no 'return'
// statements, the result type as written must be exactly 'auto', and
// the deduced result type is 'void'.
- if (!FD->getResultType()->getAs<AutoType>()) {
+ if (!FD->getReturnType()->getAs<AutoType>()) {
Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto)
- << FD->getResultType();
+ << FD->getReturnType();
FD->setInvalidDecl();
} else {
// Substitute 'void' for the 'auto' in the type.
TypeLoc ResultType = FD->getTypeSourceInfo()->getTypeLoc().
- IgnoreParens().castAs<FunctionProtoTypeLoc>().getResultLoc();
+ IgnoreParens().castAs<FunctionProtoTypeLoc>().getReturnLoc();
Context.adjustDeducedFunctionResultType(
FD, SubstAutoType(ResultType.getType(), Context.VoidTy));
}
@@ -9783,15 +10126,17 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
WP.disableCheckFallThrough();
// MSVC permits the use of pure specifier (=0) on function definition,
- // defined at class scope, warn about this non standard construct.
+ // defined at class scope, warn about this non-standard construct.
if (getLangOpts().MicrosoftExt && FD->isPure() && FD->isCanonicalDecl())
- Diag(FD->getLocation(), diag::warn_pure_function_definition);
+ Diag(FD->getLocation(), diag::ext_pure_function_definition);
if (!FD->isInvalidDecl()) {
- DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
+ // Don't diagnose unused parameters of defaulted or deleted functions.
+ if (Body)
+ DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(),
- FD->getResultType(), FD);
-
+ FD->getReturnType(), FD);
+
// If this is a constructor, we need a vtable.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(FD))
MarkVTableUsed(FD->getLocation(), Constructor->getParent());
@@ -9799,7 +10144,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// Try to apply the named return value optimization. We have to check
// if we can do this here because lambdas keep return statements around
// to deduce an implicit return type.
- if (getLangOpts().CPlusPlus && FD->getResultType()->isRecordType() &&
+ if (getLangOpts().CPlusPlus && FD->getReturnType()->isRecordType() &&
!FD->isDependentContext())
computeNRVO(Body, getCurFunction());
}
@@ -9812,8 +10157,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (!MD->isInvalidDecl()) {
DiagnoseUnusedParameters(MD->param_begin(), MD->param_end());
DiagnoseSizeOfParametersAndReturnValue(MD->param_begin(), MD->param_end(),
- MD->getResultType(), MD);
-
+ MD->getReturnType(), MD);
+
if (Body)
computeNRVO(Body, getCurFunction());
}
@@ -9822,8 +10167,41 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
<< MD->getSelector().getAsString();
getCurFunction()->ObjCShouldCallSuper = false;
}
+ if (getCurFunction()->ObjCWarnForNoDesignatedInitChain) {
+ const ObjCMethodDecl *InitMethod = nullptr;
+ bool isDesignated =
+ MD->isDesignatedInitializerForTheInterface(&InitMethod);
+ assert(isDesignated && InitMethod);
+ (void)isDesignated;
+
+ auto superIsNSObject = [&](const ObjCMethodDecl *MD) {
+ auto IFace = MD->getClassInterface();
+ if (!IFace)
+ return false;
+ auto SuperD = IFace->getSuperClass();
+ if (!SuperD)
+ return false;
+ return SuperD->getIdentifier() ==
+ NSAPIObj->getNSClassId(NSAPI::ClassId_NSObject);
+ };
+ // Don't issue this warning for unavailable inits or direct subclasses
+ // of NSObject.
+ if (!MD->isUnavailable() && !superIsNSObject(MD)) {
+ Diag(MD->getLocation(),
+ diag::warn_objc_designated_init_missing_super_call);
+ Diag(InitMethod->getLocation(),
+ diag::note_objc_designated_init_marked_here);
+ }
+ getCurFunction()->ObjCWarnForNoDesignatedInitChain = false;
+ }
+ if (getCurFunction()->ObjCWarnForNoInitDelegation) {
+ // Don't issue this warning for unavaialable inits.
+ if (!MD->isUnavailable())
+ Diag(MD->getLocation(), diag::warn_objc_secondary_init_missing_init_call);
+ getCurFunction()->ObjCWarnForNoInitDelegation = false;
+ }
} else {
- return 0;
+ return nullptr;
}
assert(!getCurFunction()->ObjCShouldCallSuper &&
@@ -9840,8 +10218,6 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// Verify that gotos and switch cases don't jump into scopes illegally.
if (getCurFunction()->NeedsScopeChecking() &&
- !dcl->isInvalidDecl() &&
- !hasAnyUnrecoverableErrorsInThisFunction() &&
!PP.isCodeCompletionEnabled())
DiagnoseInvalidJumps(Body);
@@ -9856,11 +10232,11 @@ 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 (PP.getDiagnostics().hasErrorOccurred() ||
- PP.getDiagnostics().getSuppressAllDiagnostics()) {
+ if (getDiagnostics().hasErrorOccurred() ||
+ getDiagnostics().getSuppressAllDiagnostics()) {
DiscardCleanupsInEvaluationContext();
}
- if (!PP.getDiagnostics().hasUncompilableErrorOccurred() &&
+ if (!getDiagnostics().hasUncompilableErrorOccurred() &&
!isa<FunctionTemplateDecl>(dcl)) {
// Since the body is valid, issue any analysis-based warnings that are
// enabled.
@@ -9938,7 +10314,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
TypoCorrection Corrected;
DeclFilterCCC<FunctionDecl> Validator;
if (S && (Corrected = CorrectTypo(DeclarationNameInfo(&II, Loc),
- LookupOrdinaryName, S, 0, Validator)))
+ LookupOrdinaryName, S, nullptr, Validator,
+ CTK_NonError)))
diagnoseTypo(Corrected, PDiag(diag::note_function_suggestion),
/*ErrorRecovery*/false);
}
@@ -9948,16 +10325,17 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
AttributeFactory attrFactory;
DeclSpec DS(attrFactory);
unsigned DiagID;
- bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy, DiagID);
+ bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy, DiagID,
+ Context.getPrintingPolicy());
(void)Error; // Silence warning.
assert(!Error && "Error setting up implicit decl!");
SourceLocation NoLoc;
Declarator D(DS, Declarator::BlockContext);
D.AddTypeInfo(DeclaratorChunk::getFunction(/*HasProto=*/false,
/*IsAmbiguous=*/false,
- /*RParenLoc=*/NoLoc,
- /*ArgInfo=*/0,
- /*NumArgs=*/0,
+ /*LParenLoc=*/NoLoc,
+ /*Params=*/nullptr,
+ /*NumParams=*/0,
/*EllipsisLoc=*/NoLoc,
/*RParenLoc=*/NoLoc,
/*TypeQuals=*/0,
@@ -9968,10 +10346,10 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
/*MutableLoc=*/NoLoc,
EST_None,
/*ESpecLoc=*/NoLoc,
- /*Exceptions=*/0,
- /*ExceptionRanges=*/0,
+ /*Exceptions=*/nullptr,
+ /*ExceptionRanges=*/nullptr,
/*NumExceptions=*/0,
- /*NoexceptExpr=*/0,
+ /*NoexceptExpr=*/nullptr,
Loc, Loc, D),
DS.getAttributes(),
SourceLocation());
@@ -10012,25 +10390,27 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
unsigned FormatIdx;
bool HasVAListArg;
if (Context.BuiltinInfo.isPrintfLike(BuiltinID, FormatIdx, HasVAListArg)) {
- if (!FD->getAttr<FormatAttr>()) {
+ if (!FD->hasAttr<FormatAttr>()) {
const char *fmt = "printf";
unsigned int NumParams = FD->getNumParams();
if (FormatIdx < NumParams && // NumParams may be 0 (e.g. vfprintf)
FD->getParamDecl(FormatIdx)->getType()->isObjCObjectPointerType())
fmt = "NSString";
- FD->addAttr(::new (Context) FormatAttr(FD->getLocation(), Context,
+ FD->addAttr(FormatAttr::CreateImplicit(Context,
&Context.Idents.get(fmt),
FormatIdx+1,
- HasVAListArg ? 0 : FormatIdx+2));
+ HasVAListArg ? 0 : FormatIdx+2,
+ FD->getLocation()));
}
}
if (Context.BuiltinInfo.isScanfLike(BuiltinID, FormatIdx,
HasVAListArg)) {
- if (!FD->getAttr<FormatAttr>())
- FD->addAttr(::new (Context) FormatAttr(FD->getLocation(), Context,
+ if (!FD->hasAttr<FormatAttr>())
+ FD->addAttr(FormatAttr::CreateImplicit(Context,
&Context.Idents.get("scanf"),
FormatIdx+1,
- HasVAListArg ? 0 : FormatIdx+2));
+ HasVAListArg ? 0 : FormatIdx+2,
+ FD->getLocation()));
}
// Mark const if we don't care about errno and that is the only
@@ -10038,17 +10418,18 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
// IRgen to use LLVM intrinsics for such functions.
if (!getLangOpts().MathErrno &&
Context.BuiltinInfo.isConstWithoutErrno(BuiltinID)) {
- if (!FD->getAttr<ConstAttr>())
- FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context));
+ if (!FD->hasAttr<ConstAttr>())
+ FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation()));
}
if (Context.BuiltinInfo.isReturnsTwice(BuiltinID) &&
- !FD->getAttr<ReturnsTwiceAttr>())
- FD->addAttr(::new (Context) ReturnsTwiceAttr(FD->getLocation(), Context));
- if (Context.BuiltinInfo.isNoThrow(BuiltinID) && !FD->getAttr<NoThrowAttr>())
- FD->addAttr(::new (Context) NoThrowAttr(FD->getLocation(), Context));
- if (Context.BuiltinInfo.isConst(BuiltinID) && !FD->getAttr<ConstAttr>())
- FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context));
+ !FD->hasAttr<ReturnsTwiceAttr>())
+ FD->addAttr(ReturnsTwiceAttr::CreateImplicit(Context,
+ FD->getLocation()));
+ if (Context.BuiltinInfo.isNoThrow(BuiltinID) && !FD->hasAttr<NoThrowAttr>())
+ FD->addAttr(NoThrowAttr::CreateImplicit(Context, FD->getLocation()));
+ if (Context.BuiltinInfo.isConst(BuiltinID) && !FD->hasAttr<ConstAttr>())
+ FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation()));
}
IdentifierInfo *Name = FD->getIdentifier();
@@ -10067,17 +10448,19 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
if (Name->isStr("asprintf") || Name->isStr("vasprintf")) {
// FIXME: asprintf and vasprintf aren't C99 functions. Should they be
// target-specific builtins, perhaps?
- if (!FD->getAttr<FormatAttr>())
- FD->addAttr(::new (Context) FormatAttr(FD->getLocation(), Context,
+ if (!FD->hasAttr<FormatAttr>())
+ FD->addAttr(FormatAttr::CreateImplicit(Context,
&Context.Idents.get("printf"), 2,
- Name->isStr("vasprintf") ? 0 : 3));
+ Name->isStr("vasprintf") ? 0 : 3,
+ FD->getLocation()));
}
if (Name->isStr("__CFStringMakeConstantString")) {
// We already have a __builtin___CFStringMakeConstantString,
// but builds that use -fno-constant-cfstrings don't go through that.
- if (!FD->getAttr<FormatArgAttr>())
- FD->addAttr(::new (Context) FormatArgAttr(FD->getLocation(), Context, 1));
+ if (!FD->hasAttr<FormatArgAttr>())
+ FD->addAttr(FormatArgAttr::CreateImplicit(Context, 1,
+ FD->getLocation()));
}
}
@@ -10140,6 +10523,26 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
if (!Context.hasSameType(T, Context.getTagDeclType(tagFromDeclSpec)))
break;
+ // If we've already computed linkage for the anonymous tag, then
+ // adding a typedef name for the anonymous decl can change that
+ // linkage, which might be a serious problem. Diagnose this as
+ // unsupported and ignore the typedef name. TODO: we should
+ // pursue this as a language defect and establish a formal rule
+ // for how to handle it.
+ if (tagFromDeclSpec->hasLinkageBeenComputed()) {
+ Diag(D.getIdentifierLoc(), diag::err_typedef_changes_linkage);
+
+ SourceLocation tagLoc = D.getDeclSpec().getTypeSpecTypeLoc();
+ tagLoc = getLocForEndOfToken(tagLoc);
+
+ llvm::SmallString<40> textToInsert;
+ textToInsert += ' ';
+ textToInsert += D.getIdentifier()->getName();
+ Diag(tagLoc, diag::note_typedef_changes_linkage)
+ << FixItHint::CreateInsertion(tagLoc, textToInsert);
+ break;
+ }
+
// Otherwise, set this is the anon-decl typedef for the tag.
tagFromDeclSpec->setTypedefNameForAnonDecl(NewTD);
break;
@@ -10179,7 +10582,7 @@ bool Sema::CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped,
if (IsScoped != Prev->isScoped()) {
Diag(EnumLoc, diag::err_enum_redeclare_scoped_mismatch)
<< Prev->isScoped();
- Diag(Prev->getLocation(), diag::note_previous_use);
+ Diag(Prev->getLocation(), diag::note_previous_declaration);
return true;
}
@@ -10188,15 +10591,17 @@ bool Sema::CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped,
!Prev->getIntegerType()->isDependentType() &&
!Context.hasSameUnqualifiedType(EnumUnderlyingTy,
Prev->getIntegerType())) {
+ // TODO: Highlight the underlying type of the redeclaration.
Diag(EnumLoc, diag::err_enum_redeclare_type_mismatch)
<< EnumUnderlyingTy << Prev->getIntegerType();
- Diag(Prev->getLocation(), diag::note_previous_use);
+ Diag(Prev->getLocation(), diag::note_previous_declaration)
+ << Prev->getIntegerTypeRange();
return true;
}
} else if (IsFixed != Prev->isFixed()) {
Diag(EnumLoc, diag::err_enum_redeclare_fixed_mismatch)
<< Prev->isFixed();
- Diag(Prev->getLocation(), diag::note_previous_use);
+ Diag(Prev->getLocation(), diag::note_previous_declaration);
return true;
}
@@ -10276,8 +10681,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
}
bool previousMismatch = false;
- for (TagDecl::redecl_iterator I(Previous->redecls_begin()),
- E(Previous->redecls_end()); I != E; ++I) {
+ for (auto I : Previous->redecls()) {
if (I->getTagKind() != NewTag) {
if (!previousMismatch) {
previousMismatch = true;
@@ -10308,7 +10712,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
<< getRedeclDiagFromTagKind(OldTag);
Diag(Redecl->getLocation(), diag::note_previous_use);
- // If there is a previous defintion, suggest a fix-it.
+ // If there is a previous definition, suggest a fix-it.
if (Previous->getDefinition()) {
Diag(NewTagLoc, diag::note_struct_class_suggestion)
<< getRedeclDiagFromTagKind(Redecl->getTagKind())
@@ -10321,10 +10725,56 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
return false;
}
+/// Add a minimal nested name specifier fixit hint to allow lookup of a tag name
+/// from an outer enclosing namespace or file scope inside a friend declaration.
+/// This should provide the commented out code in the following snippet:
+/// namespace N {
+/// struct X;
+/// namespace M {
+/// struct Y { friend struct /*N::*/ X; };
+/// }
+/// }
+static FixItHint createFriendTagNNSFixIt(Sema &SemaRef, NamedDecl *ND, Scope *S,
+ SourceLocation NameLoc) {
+ // While the decl is in a namespace, do repeated lookup of that name and see
+ // if we get the same namespace back. If we do not, continue until
+ // translation unit scope, at which point we have a fully qualified NNS.
+ SmallVector<IdentifierInfo *, 4> Namespaces;
+ DeclContext *DC = ND->getDeclContext()->getRedeclContext();
+ for (; !DC->isTranslationUnit(); DC = DC->getParent()) {
+ // This tag should be declared in a namespace, which can only be enclosed by
+ // other namespaces. Bail if there's an anonymous namespace in the chain.
+ NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(DC);
+ if (!Namespace || Namespace->isAnonymousNamespace())
+ return FixItHint();
+ IdentifierInfo *II = Namespace->getIdentifier();
+ Namespaces.push_back(II);
+ NamedDecl *Lookup = SemaRef.LookupSingleName(
+ S, II, NameLoc, Sema::LookupNestedNameSpecifierName);
+ if (Lookup == Namespace)
+ break;
+ }
+
+ // Once we have all the namespaces, reverse them to go outermost first, and
+ // build an NNS.
+ SmallString<64> Insertion;
+ llvm::raw_svector_ostream OS(Insertion);
+ if (DC->isTranslationUnit())
+ OS << "::";
+ std::reverse(Namespaces.begin(), Namespaces.end());
+ for (auto *II : Namespaces)
+ OS << II->getName() << "::";
+ OS.flush();
+ return FixItHint::CreateInsertion(NameLoc, Insertion);
+}
+
/// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'. In the
/// former case, Name will be non-null. In the later case, Name will be null.
/// TagSpec indicates what kind of tag this is. TUK indicates whether this is a
/// reference/declaration/definition of a tag.
+///
+/// IsTypeSpecifier is true if this is a type-specifier (or
+/// trailing-type-specifier) other than one in an alias-declaration.
Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
@@ -10334,10 +10784,11 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
bool &OwnedDecl, bool &IsDependent,
SourceLocation ScopedEnumKWLoc,
bool ScopedEnumUsesClassTag,
- TypeResult UnderlyingType) {
+ TypeResult UnderlyingType,
+ bool IsTypeSpecifier) {
// If this is not a definition, it must have a name.
IdentifierInfo *OrigName = Name;
- assert((Name != 0 || TUK == TUK_Definition) &&
+ assert((Name != nullptr || TUK == TUK_Definition) &&
"Nameless record must be a definition!");
assert(TemplateParameterLists.size() == 0 || TUK != TUK_Reference);
@@ -10356,11 +10807,11 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
(SS.isNotEmpty() && TUK != TUK_Reference)) {
if (TemplateParameterList *TemplateParams =
MatchTemplateParametersToScopeSpecifier(
- KWLoc, NameLoc, SS, TemplateParameterLists, TUK == TUK_Friend,
- isExplicitSpecialization, Invalid)) {
+ KWLoc, NameLoc, SS, nullptr, TemplateParameterLists,
+ TUK == TUK_Friend, isExplicitSpecialization, Invalid)) {
if (Kind == TTK_Enum) {
Diag(KWLoc, diag::err_enum_template);
- return 0;
+ return nullptr;
}
if (TemplateParams->size() > 0) {
@@ -10368,13 +10819,14 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// be a member of another template).
if (Invalid)
- return 0;
+ return nullptr;
OwnedDecl = false;
DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc,
SS, Name, NameLoc, Attr,
TemplateParams, AS,
ModulePrivateLoc,
+ /*FriendLoc*/SourceLocation(),
TemplateParameterLists.size()-1,
TemplateParameterLists.data());
return Result.get();
@@ -10400,7 +10852,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
else if (UnderlyingType.get()) {
// C++0x 7.2p2: The type-specifier-seq of an enum-base shall name an
// integral type; any cv-qualification is ignored.
- TypeSourceInfo *TI = 0;
+ TypeSourceInfo *TI = nullptr;
GetTypeFromParser(UnderlyingType.get(), &TI);
EnumUnderlying = TI;
@@ -10412,7 +10864,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
UPPC_FixedUnderlyingType))
EnumUnderlying = Context.IntTy.getTypePtr();
- } else if (getLangOpts().MicrosoftMode)
+ } else if (getLangOpts().MSVCCompat)
// Microsoft enums are always of int type.
EnumUnderlying = Context.IntTy.getTypePtr();
}
@@ -10426,13 +10878,12 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
Redecl = NotForRedeclaration;
LookupResult Previous(*this, Name, NameLoc, LookupTagName, Redecl);
- bool FriendSawTagOutsideEnclosingNamespace = false;
if (Name && SS.isNotEmpty()) {
// We have a nested-name tag ('struct foo::bar').
// Check for invalid 'foo::'.
if (SS.isInvalid()) {
- Name = 0;
+ Name = nullptr;
goto CreateNewDecl;
}
@@ -10442,26 +10893,26 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
DC = computeDeclContext(SS, false);
if (!DC) {
IsDependent = true;
- return 0;
+ return nullptr;
}
} else {
DC = computeDeclContext(SS, true);
if (!DC) {
Diag(SS.getRange().getBegin(), diag::err_dependent_nested_name_spec)
<< SS.getRange();
- return 0;
+ return nullptr;
}
}
if (RequireCompleteDeclContext(SS, DC))
- return 0;
+ return nullptr;
SearchDC = DC;
// Look-up name inside 'foo::'.
LookupQualifiedName(Previous, DC);
if (Previous.isAmbiguous())
- return 0;
+ return nullptr;
if (Previous.empty()) {
// Name lookup did not find anything. However, if the
@@ -10473,13 +10924,13 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (Previous.wasNotFoundInCurrentInstantiation() &&
(TUK == TUK_Reference || TUK == TUK_Friend)) {
IsDependent = true;
- return 0;
+ return nullptr;
}
// A tag 'foo::bar' must already exist.
Diag(NameLoc, diag::err_not_tag_in_scope)
<< Kind << Name << DC << SS.getRange();
- Name = 0;
+ Name = nullptr;
Invalid = true;
goto CreateNewDecl;
}
@@ -10511,26 +10962,41 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// the entity has been previously declared shall not consider
// any scopes outside the innermost enclosing namespace.
//
+ // MSVC doesn't implement the above rule for types, so a friend tag
+ // declaration may be a redeclaration of a type declared in an enclosing
+ // scope. They do implement this rule for friend functions.
+ //
// Does it matter that this should be by scope instead of by
// semantic context?
if (!Previous.empty() && TUK == TUK_Friend) {
DeclContext *EnclosingNS = SearchDC->getEnclosingNamespaceContext();
LookupResult::Filter F = Previous.makeFilter();
+ bool FriendSawTagOutsideEnclosingNamespace = false;
while (F.hasNext()) {
NamedDecl *ND = F.next();
DeclContext *DC = ND->getDeclContext()->getRedeclContext();
if (DC->isFileContext() &&
!EnclosingNS->Encloses(ND->getDeclContext())) {
- F.erase();
- FriendSawTagOutsideEnclosingNamespace = true;
+ if (getLangOpts().MSVCCompat)
+ FriendSawTagOutsideEnclosingNamespace = true;
+ else
+ F.erase();
}
}
F.done();
+
+ // Diagnose this MSVC extension in the easy case where lookup would have
+ // unambiguously found something outside the enclosing namespace.
+ if (Previous.isSingleResult() && FriendSawTagOutsideEnclosingNamespace) {
+ NamedDecl *ND = Previous.getFoundDecl();
+ Diag(NameLoc, diag::ext_friend_tag_redecl_outside_namespace)
+ << createFriendTagNNSFixIt(*this, ND, S, NameLoc);
+ }
}
-
+
// Note: there used to be some attempt at recovery here.
if (Previous.isAmbiguous())
- return 0;
+ return nullptr;
if (!getLangOpts().CPlusPlus && TUK != TUK_Reference) {
// FIXME: This makes sure that we ignore the contexts associated
@@ -10540,11 +11006,6 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
while (isa<RecordDecl>(SearchDC) || isa<EnumDecl>(SearchDC))
SearchDC = SearchDC->getParent();
}
- } else if (S->isFunctionPrototypeScope()) {
- // If this is an enum declaration in function prototype scope, set its
- // initial context to the translation unit.
- // FIXME: [citation needed]
- SearchDC = Context.getTranslationUnitDecl();
}
if (Previous.isSingleResult() &&
@@ -10634,7 +11095,9 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
if (!Previous.empty()) {
- NamedDecl *PrevDecl = (*Previous.begin())->getUnderlyingDecl();
+ NamedDecl *PrevDecl = Previous.getFoundDecl();
+ NamedDecl *DirectPrevDecl =
+ getLangOpts().MSVCCompat ? *Previous.begin() : PrevDecl;
// It's okay to have a tag decl in the same scope as a typedef
// which hides a tag decl in the same scope. Finding this
@@ -10666,7 +11129,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// in the same scope (so that the definition/declaration completes or
// rementions the tag), reuse the decl.
if (TUK == TUK_Reference || TUK == TUK_Friend ||
- isDeclInScope(PrevDecl, SearchDC, S, isExplicitSpecialization)) {
+ isDeclInScope(DirectPrevDecl, SearchDC, S,
+ SS.isNotEmpty() || isExplicitSpecialization)) {
// Make sure that this wasn't declared as an enum and now used as a
// struct or something similar.
if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind,
@@ -10688,7 +11152,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
Kind = PrevTagDecl->getTagKind();
else {
// Recover by making this an anonymous redefinition.
- Name = 0;
+ Name = nullptr;
Previous.clear();
Invalid = true;
}
@@ -10709,7 +11173,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
QualType EnumUnderlyingTy;
if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo*>())
- EnumUnderlyingTy = TI->getType();
+ EnumUnderlyingTy = TI->getType().getUnqualifiedType();
else if (const Type *T = EnumUnderlying.dyn_cast<const Type*>())
EnumUnderlyingTy = QualType(T, 0);
@@ -10718,7 +11182,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// in which case we want the caller to bail out.
if (CheckEnumRedeclaration(NameLoc.isValid() ? NameLoc : KWLoc,
ScopedEnum, EnumUnderlyingTy, PrevEnum))
- return TUK == TUK_Declaration ? PrevTagDecl : 0;
+ return TUK == TUK_Declaration ? PrevTagDecl : nullptr;
}
// C++11 [class.mem]p1:
@@ -10732,14 +11196,17 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
if (!Invalid) {
- // If this is a use, just return the declaration we found.
+ // If this is a use, just return the declaration we found, unless
+ // we have attributes.
// FIXME: In the future, return a variant or some other clue
// for the consumer of this Decl to know it doesn't own it.
// For our current ASTs this shouldn't be a problem, but will
// need to be changed with DeclGroups.
- if ((TUK == TUK_Reference && (!PrevTagDecl->getFriendObjectKind() ||
- getLangOpts().MicrosoftExt)) || TUK == TUK_Friend)
+ if (!Attr &&
+ ((TUK == TUK_Reference &&
+ (!PrevTagDecl->getFriendObjectKind() || getLangOpts().MicrosoftExt))
+ || TUK == TUK_Friend))
return PrevTagDecl;
// Diagnose attempts to redefine a tag.
@@ -10771,7 +11238,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// If this is a redefinition, recover by making this
// struct be anonymous, which will make any later
// references get the previous definition.
- Name = 0;
+ Name = nullptr;
Previous.clear();
Invalid = true;
}
@@ -10784,14 +11251,22 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
Diag(NameLoc, diag::err_nested_redefinition) << Name;
Diag(PrevTagDecl->getLocation(),
diag::note_previous_definition);
- Name = 0;
+ Name = nullptr;
Previous.clear();
Invalid = true;
}
}
// Okay, this is definition of a previously declared or referenced
- // tag PrevDecl. We're going to create a new Decl for it.
+ // tag. We're going to create a new Decl for it.
+ }
+
+ // Okay, we're going to make a redeclaration. If this is some kind
+ // of reference, make sure we build the redeclaration in the same DC
+ // as the original, and ignore the current access specifier.
+ if (TUK == TUK_Friend || TUK == TUK_Reference) {
+ SearchDC = PrevTagDecl->getDeclContext();
+ AS = AS_none;
}
}
// If we get here we have (another) forward declaration or we
@@ -10827,8 +11302,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
Invalid = true;
// Otherwise, only diagnose if the declaration is in scope.
- } else if (!isDeclInScope(PrevDecl, SearchDC, S,
- isExplicitSpecialization)) {
+ } else if (!isDeclInScope(PrevDecl, SearchDC, S,
+ SS.isNotEmpty() || isExplicitSpecialization)) {
// do nothing
// Diagnose implicit declarations introduced by elaborated types.
@@ -10857,7 +11332,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// issue an error and recover by making this tag be anonymous.
Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
- Name = 0;
+ Name = nullptr;
Invalid = true;
}
@@ -10869,7 +11344,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
CreateNewDecl:
- TagDecl *PrevDecl = 0;
+ TagDecl *PrevDecl = nullptr;
if (Previous.isSingleResult())
PrevDecl = cast<TagDecl>(Previous.getFoundDecl());
@@ -10904,7 +11379,7 @@ CreateNewDecl:
Diag(Def->getLocation(), diag::note_previous_definition);
} else {
unsigned DiagID = diag::ext_forward_ref_enum;
- if (getLangOpts().MicrosoftMode)
+ if (getLangOpts().MSVCCompat)
DiagID = diag::ext_ms_forward_ref_enum;
else if (getLangOpts().CPlusPlus)
DiagID = diag::err_forward_ref_enum;
@@ -10944,6 +11419,14 @@ CreateNewDecl:
cast_or_null<RecordDecl>(PrevDecl));
}
+ // C++11 [dcl.type]p3:
+ // A type-specifier-seq shall not define a class or enumeration [...].
+ if (getLangOpts().CPlusPlus && IsTypeSpecifier && TUK == TUK_Definition) {
+ Diag(New->getLocation(), diag::err_type_defined_in_type_specifier)
+ << Context.getTagDeclType(New);
+ Invalid = true;
+ }
+
// Maybe add qualifier info.
if (SS.isNotEmpty()) {
if (SS.isSet()) {
@@ -10995,23 +11478,37 @@ CreateNewDecl:
else if (!SearchDC->isFunctionOrMethod())
New->setModulePrivate();
}
-
+
// If this is a specialization of a member class (of a class template),
// check the specialization.
if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous))
Invalid = true;
-
+
+ // If we're declaring or defining a tag in function prototype scope in C,
+ // note that this type can only be used within the function and add it to
+ // the list of decls to inject into the function definition scope.
+ if ((Name || Kind == TTK_Enum) &&
+ getNonFieldDeclScope(S)->isFunctionPrototypeScope()) {
+ if (getLangOpts().CPlusPlus) {
+ // C++ [dcl.fct]p6:
+ // Types shall not be defined in return or parameter types.
+ if (TUK == TUK_Definition && !IsTypeSpecifier) {
+ Diag(Loc, diag::err_type_defined_in_param_type)
+ << Name;
+ Invalid = true;
+ }
+ } else {
+ Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New);
+ }
+ DeclsInPrototypeScope.push_back(New);
+ }
+
if (Invalid)
New->setInvalidDecl();
if (Attr)
ProcessDeclAttributeList(S, New, Attr);
- // If we're declaring or defining a tag in function prototype scope
- // in C, note that this type can only be used within the function.
- if (Name && S->isFunctionPrototypeScope() && !getLangOpts().CPlusPlus)
- Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New);
-
// Set the lexical context. If the tag has a C++ scope specifier, the
// lexical context will be different from the semantic context.
New->setLexicalDeclContext(CurContext);
@@ -11021,8 +11518,7 @@ CreateNewDecl:
// declaration so we always pass true to setObjectOfFriendDecl to make
// the tag name visible.
if (TUK == TUK_Friend)
- New->setObjectOfFriendDecl(!FriendSawTagOutsideEnclosingNamespace &&
- getLangOpts().MicrosoftExt);
+ New->setObjectOfFriendDecl(getLangOpts().MSVCCompat);
// Set the access specifier.
if (!Invalid && SearchDC->isRecord())
@@ -11060,12 +11556,6 @@ CreateNewDecl:
II->isStr("FILE"))
Context.setFILEDecl(New);
- // If we were in function prototype scope (and not in C++ mode), add this
- // tag to the list of decls to inject into the function definition scope.
- if (S->isFunctionPrototypeScope() && !getLangOpts().CPlusPlus &&
- InFunctionDeclarator && Name)
- DeclsInPrototypeScope.push_back(New);
-
if (PrevDecl)
mergeDeclAttributes(New, PrevDecl);
@@ -11076,7 +11566,7 @@ CreateNewDecl:
OwnedDecl = true;
// In C++, don't return an invalid declaration. We can't recover well from
// the cases where we make the type anonymous.
- return (Invalid && getLangOpts().CPlusPlus) ? 0 : New;
+ return (Invalid && getLangOpts().CPlusPlus) ? nullptr : New;
}
void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) {
@@ -11128,7 +11618,7 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD,
= CXXRecordDecl::Create(Context, Record->getTagKind(), CurContext,
Record->getLocStart(), Record->getLocation(),
Record->getIdentifier(),
- /*PrevDecl=*/0,
+ /*PrevDecl=*/nullptr,
/*DelayTypeCreation=*/true);
Context.getTypeDeclType(InjectedClassName, Record);
InjectedClassName->setImplicit();
@@ -11181,7 +11671,7 @@ void Sema::ActOnObjCTemporaryExitContainerContext(DeclContext *DC) {
void Sema::ActOnObjCReenterContainerContext(DeclContext *DC) {
ActOnObjCContainerStartDefinition(cast<Decl>(DC));
- OriginalLexicalContext = 0;
+ OriginalLexicalContext = nullptr;
}
void Sema::ActOnTagDefinitionError(Scope *S, Decl *TagD) {
@@ -11229,13 +11719,13 @@ ExprResult Sema::VerifyBitField(SourceLocation FieldLoc,
// If the bit-width is type- or value-dependent, don't try to check
// it now.
if (BitWidth->isValueDependent() || BitWidth->isTypeDependent())
- return Owned(BitWidth);
+ return BitWidth;
llvm::APSInt Value;
ExprResult ICE = VerifyIntegerConstantExpression(BitWidth, &Value);
if (ICE.isInvalid())
return ICE;
- BitWidth = ICE.take();
+ BitWidth = ICE.get();
if (Value != 0 && ZeroWidth)
*ZeroWidth = false;
@@ -11255,7 +11745,8 @@ ExprResult Sema::VerifyBitField(SourceLocation FieldLoc,
if (!FieldTy->isDependentType()) {
uint64_t TypeSize = Context.getTypeSize(FieldTy);
if (Value.getZExtValue() > TypeSize) {
- if (!getLangOpts().CPlusPlus || IsMsStruct) {
+ if (!getLangOpts().CPlusPlus || IsMsStruct ||
+ Context.getTargetInfo().getCXXABI().isMicrosoft()) {
if (FieldName)
return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size)
<< FieldName << (unsigned)Value.getZExtValue()
@@ -11275,7 +11766,7 @@ ExprResult Sema::VerifyBitField(SourceLocation FieldLoc,
}
}
- return Owned(BitWidth);
+ return BitWidth;
}
/// ActOnField - Each field of a C struct/union is passed into this in order
@@ -11333,7 +11824,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
<< DeclSpec::getSpecifierName(TSCS);
// Check to see if this name was declared as a member previously
- NamedDecl *PrevDecl = 0;
+ NamedDecl *PrevDecl = nullptr;
LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration);
LookupName(Previous, S);
switch (Previous.getResultKind()) {
@@ -11357,11 +11848,11 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
// Just pretend that we didn't see the previous declaration.
- PrevDecl = 0;
+ PrevDecl = nullptr;
}
if (PrevDecl && !isDeclInScope(PrevDecl, Record, S))
- PrevDecl = 0;
+ PrevDecl = nullptr;
bool Mutable
= (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable);
@@ -11474,10 +11965,10 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
// If this is declared as a bit-field, check the bit-field.
if (!InvalidDecl && BitWidth) {
BitWidth = VerifyBitField(Loc, II, T, Record->isMsStruct(Context), BitWidth,
- &ZeroWidth).take();
+ &ZeroWidth).get();
if (!BitWidth) {
InvalidDecl = true;
- BitWidth = 0;
+ BitWidth = nullptr;
ZeroWidth = false;
}
}
@@ -11500,6 +11991,12 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
}
}
+ // C++11 [class.union]p8 (DR1460):
+ // At most one variant member of a union may have a
+ // brace-or-equal-initializer.
+ if (InitStyle != ICIS_NoInit)
+ checkDuplicateDefaultInit(*this, cast<CXXRecordDecl>(Record), Loc);
+
FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo,
BitWidth, Mutable, InitStyle);
if (InvalidDecl)
@@ -11603,8 +12100,9 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
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"));
+ FD->addAttr(UnavailableAttr::CreateImplicit(Context,
+ "this system field has retaining ownership",
+ Loc));
return false;
}
}
@@ -11655,7 +12153,7 @@ Decl *Sema::ActOnIvar(Scope *S,
if (BitWidth) {
// 6.7.2.1p3, 6.7.2.1p4
- BitWidth = VerifyBitField(Loc, II, T, /*IsMsStruct*/false, BitWidth).take();
+ BitWidth = VerifyBitField(Loc, II, T, /*IsMsStruct*/false, BitWidth).get();
if (!BitWidth)
D.setInvalidType();
} else {
@@ -11682,7 +12180,7 @@ Decl *Sema::ActOnIvar(Scope *S,
// Must set ivar's DeclContext to its enclosing interface.
ObjCContainerDecl *EnclosingDecl = cast<ObjCContainerDecl>(CurContext);
if (!EnclosingDecl || EnclosingDecl->isInvalidDecl())
- return 0;
+ return nullptr;
ObjCContainerDecl *EnclosingContext;
if (ObjCImplementationDecl *IMPDecl =
dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) {
@@ -11698,7 +12196,7 @@ Decl *Sema::ActOnIvar(Scope *S,
dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) {
if (LangOpts.ObjCRuntime.isFragile() || !CDecl->IsClassExtension()) {
Diag(Loc, diag::err_misplaced_ivar) << CDecl->IsClassExtension();
- return 0;
+ return nullptr;
}
}
EnclosingContext = EnclosingDecl;
@@ -11776,7 +12274,7 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc,
Expr * BW = IntegerLiteral::Create(Context, Zero, Context.IntTy, DeclLoc);
Ivar = ObjCIvarDecl::Create(Context, cast<ObjCContainerDecl>(CurContext),
- DeclLoc, DeclLoc, 0,
+ DeclLoc, DeclLoc, nullptr,
Context.CharTy,
Context.getTrivialTypeSourceInfo(Context.CharTy,
DeclLoc),
@@ -11813,9 +12311,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
// members of anonymous structs and unions in the total.
unsigned NumNamedMembers = 0;
if (Record) {
- for (RecordDecl::decl_iterator i = Record->decls_begin(),
- e = Record->decls_end(); i != e; i++) {
- if (IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(*i))
+ for (const auto *I : Record->decls()) {
+ if (const auto *IFD = dyn_cast<IndirectFieldDecl>(I))
if (IFD->getDeclName())
++NumNamedMembers;
}
@@ -11902,9 +12399,14 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
Diag(FD->getLocation(), diag::ext_c99_flexible_array_member)
<< FD->getDeclName() << Record->getTagKind();
- if (!FD->getType()->isDependentType() &&
- !Context.getBaseElementType(FD->getType()).isPODType(Context)) {
- Diag(FD->getLocation(), diag::err_flexible_array_has_nonpod_type)
+ // If the element type has a non-trivial destructor, we would not
+ // implicitly destroy the elements, so disallow it for now.
+ //
+ // FIXME: GCC allows this. We should probably either implicitly delete
+ // the destructor of the containing class, or just allow this.
+ QualType BaseElem = Context.getBaseElementType(FD->getType());
+ if (!BaseElem->isDependentType() && BaseElem.isDestructedType()) {
+ Diag(FD->getLocation(), diag::err_flexible_array_has_nontrivial_dtor)
<< FD->getDeclName() << FD->getType();
FD->setInvalidDecl();
EnclosingDecl->setInvalidDecl();
@@ -11972,8 +12474,9 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
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"));
+ FD->addAttr(UnavailableAttr::CreateImplicit(Context,
+ "this system field has retaining ownership",
+ loc));
}
} else {
Diag(FD->getLocation(), diag::err_arc_objc_object_in_tag)
@@ -12021,12 +12524,6 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
if (getLangOpts().CPlusPlus11)
AdjustDestructorExceptionSpec(CXXRecord,
CXXRecord->getDestructor());
-
- // The Microsoft ABI requires that we perform the destructor body
- // checks (i.e. operator delete() lookup) at every declaration, as
- // any translation unit may need to emit a deleting destructor.
- if (Context.getTargetInfo().getCXXABI().isMicrosoft())
- CheckDestructor(CXXRecord->getDestructor());
}
// Add any implicitly-declared members to this class.
@@ -12078,9 +12575,15 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
if (!Completed)
Record->completeDefinition();
- if (Record->hasAttrs())
+ if (Record->hasAttrs()) {
CheckAlignasUnderalignment(Record);
+ if (const MSInheritanceAttr *IA = Record->getAttr<MSInheritanceAttr>())
+ checkMSInheritanceAttrOnDefinition(cast<CXXRecordDecl>(Record),
+ IA->getRange(), IA->getBestCase(),
+ IA->getSemanticSpelling());
+ }
+
// Check if the structure/union declaration is a type that can have zero
// size in C. For C this is a language extension, for C++ it may cause
// compatibility problems.
@@ -12175,10 +12678,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
Diag(ClsIvar->getLocation(), diag::note_previous_definition);
continue;
}
- for (ObjCInterfaceDecl::known_extensions_iterator
- Ext = IDecl->known_extensions_begin(),
- ExtEnd = IDecl->known_extensions_end();
- Ext != ExtEnd; ++Ext) {
+ for (const auto *Ext : IDecl->known_extensions()) {
if (const ObjCIvarDecl *ClsExtIvar
= Ext->getIvarDecl(ClsFields[i]->getIdentifier())) {
Diag(ClsFields[i]->getLocation(),
@@ -12251,10 +12751,10 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
QualType EltTy;
if (Val && DiagnoseUnexpandedParameterPack(Val, UPPC_EnumeratorValue))
- Val = 0;
+ Val = nullptr;
if (Val)
- Val = DefaultLvalueConversion(Val).take();
+ Val = DefaultLvalueConversion(Val).get();
if (Val) {
if (Enum->isDependentType() || Val->isTypeDependent())
@@ -12262,7 +12762,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
else {
SourceLocation ExpLoc;
if (getLangOpts().CPlusPlus11 && Enum->isFixed() &&
- !getLangOpts().MicrosoftMode) {
+ !getLangOpts().MSVCCompat) {
// C++11 [dcl.enum]p5: If the underlying type is fixed, [...] the
// constant-expression in the enumerator-definition shall be a converted
// constant expression of the underlying type.
@@ -12271,12 +12771,12 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
CheckConvertedConstantExpression(Val, EltTy, EnumVal,
CCEK_Enumerator);
if (Converted.isInvalid())
- Val = 0;
+ Val = nullptr;
else
- Val = Converted.take();
+ Val = Converted.get();
} else if (!Val->isValueDependent() &&
!(Val = VerifyIntegerConstantExpression(Val,
- &EnumVal).take())) {
+ &EnumVal).get())) {
// C99 6.7.2.2p2: Make sure we have an integer constant expression.
} else {
if (Enum->isFixed()) {
@@ -12287,13 +12787,13 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// we perform a non-narrowing conversion as part of converted constant
// expression checking.
if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
- if (getLangOpts().MicrosoftMode) {
+ if (getLangOpts().MSVCCompat) {
Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy;
- Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).take();
+ Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).get();
} else
Diag(IdLoc, diag::err_enumerator_too_large) << EltTy;
} else
- Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).take();
+ Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).get();
} else if (getLangOpts().CPlusPlus) {
// C++11 [dcl.enum]p5:
// If the underlying type is not fixed, the type of each enumerator
@@ -12314,7 +12814,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
<< (EnumVal.isUnsigned() || EnumVal.isNonNegative());
else if (!Context.hasSameType(Val->getType(), Context.IntTy)) {
// Force the type of the expression to 'int'.
- Val = ImpCastExprToType(Val, Context.IntTy, CK_IntegralCast).take();
+ Val = ImpCastExprToType(Val, Context.IntTy, CK_IntegralCast).get();
}
EltTy = Val->getType();
}
@@ -12371,7 +12871,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
<< EnumVal.toString(10)
<< EltTy;
else
- Diag(IdLoc, diag::warn_enumerator_too_large)
+ Diag(IdLoc, diag::ext_enumerator_increment_too_large)
<< EnumVal.toString(10);
} else {
EltTy = T;
@@ -12433,7 +12933,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(IdLoc, PrevDecl);
// Just pretend that we didn't see the previous declaration.
- PrevDecl = 0;
+ PrevDecl = nullptr;
}
if (PrevDecl) {
@@ -12447,7 +12947,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
else
Diag(IdLoc, diag::err_redefinition) << Id;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
- return 0;
+ return nullptr;
}
}
@@ -12549,9 +13049,7 @@ struct DenseMapInfoDupKey {
static void CheckForDuplicateEnumValues(Sema &S, ArrayRef<Decl *> Elements,
EnumDecl *Enum,
QualType EnumType) {
- if (S.Diags.getDiagnosticLevel(diag::warn_duplicate_enum_values,
- Enum->getLocation()) ==
- DiagnosticsEngine::Ignored)
+ if (S.Diags.isIgnored(diag::warn_duplicate_enum_values, Enum->getLocation()))
return;
// Avoid anonymous enums
if (!Enum->getIdentifier())
@@ -12729,7 +13227,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
// The C99 rule is modified by a gcc extension
QualType BestPromotionType;
- bool Packed = Enum->getAttr<PackedAttr>() ? true : false;
+ bool Packed = Enum->hasAttr<PackedAttr>();
// -fshort-enums is the equivalent to specifying the packed attribute on all
// enum definitions.
if (LangOpts.ShortEnums)
@@ -12769,7 +13267,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
BestWidth = Context.getTargetInfo().getLongLongWidth();
if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth)
- Diag(Enum->getLocation(), diag::warn_enum_too_large);
+ Diag(Enum->getLocation(), diag::ext_enum_too_large);
BestType = Context.LongLongTy;
}
}
@@ -12860,7 +13358,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
ECD->setInitExpr(ImplicitCastExpr::Create(Context, NewTy,
CK_IntegralCast,
ECD->getInitExpr(),
- /*base paths*/ 0,
+ /*base paths*/ nullptr,
VK_RValue));
if (getLangOpts().CPlusPlus)
// C++ [dcl.enum]p4: Following the closing brace of an
@@ -12874,11 +13372,6 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
Enum->completeDefinition(BestType, BestPromotionType,
NumPositiveBits, NumNegativeBits);
- // If we're declaring a function, ensure this decl isn't forgotten about -
- // it needs to go into the function scope.
- if (InFunctionDeclarator)
- DeclsInPrototypeScope.push_back(Enum);
-
CheckForDuplicateEnumValues(*this, Elements, Enum, EnumType);
// Now that the enum type is defined, ensure it's not been underaligned.
@@ -12898,15 +13391,54 @@ Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
return New;
}
+static void checkModuleImportContext(Sema &S, Module *M,
+ SourceLocation ImportLoc,
+ DeclContext *DC) {
+ if (auto *LSD = dyn_cast<LinkageSpecDecl>(DC)) {
+ switch (LSD->getLanguage()) {
+ case LinkageSpecDecl::lang_c:
+ if (!M->IsExternC) {
+ S.Diag(ImportLoc, diag::err_module_import_in_extern_c)
+ << M->getFullModuleName();
+ S.Diag(LSD->getLocStart(), diag::note_module_import_in_extern_c);
+ return;
+ }
+ break;
+ case LinkageSpecDecl::lang_cxx:
+ break;
+ }
+ DC = LSD->getParent();
+ }
+
+ while (isa<LinkageSpecDecl>(DC))
+ DC = DC->getParent();
+ if (!isa<TranslationUnitDecl>(DC)) {
+ S.Diag(ImportLoc, diag::err_module_import_not_at_top_level)
+ << M->getFullModuleName() << DC;
+ S.Diag(cast<Decl>(DC)->getLocStart(),
+ diag::note_module_import_not_at_top_level)
+ << DC;
+ }
+}
+
DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
SourceLocation ImportLoc,
ModuleIdPath Path) {
- Module *Mod = PP.getModuleLoader().loadModule(ImportLoc, Path,
- Module::AllVisible,
- /*IsIncludeDirective=*/false);
+ Module *Mod =
+ getModuleLoader().loadModule(ImportLoc, Path, Module::AllVisible,
+ /*IsIncludeDirective=*/false);
if (!Mod)
return true;
-
+
+ checkModuleImportContext(*this, Mod, ImportLoc, CurContext);
+
+ // FIXME: we should support importing a submodule within a different submodule
+ // of the same top-level module. Until we do, make it an error rather than
+ // silently ignoring the import.
+ if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule)
+ Diag(ImportLoc, diag::err_module_self_import)
+ << Mod->getFullModuleName() << getLangOpts().CurrentModule;
+
SmallVector<SourceLocation, 2> IdentifierLocs;
Module *ModCheck = Mod;
for (unsigned I = 0, N = Path.size(); I != N; ++I) {
@@ -12928,12 +13460,19 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
}
void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
+ checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext);
+
// FIXME: Should we synthesize an ImportDecl here?
- PP.getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, DirectiveLoc,
- /*Complain=*/true);
+ getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, DirectiveLoc,
+ /*Complain=*/true);
}
-void Sema::createImplicitModuleImport(SourceLocation Loc, Module *Mod) {
+void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc,
+ Module *Mod) {
+ // Bail if we're not allowed to implicitly import a module here.
+ if (isSFINAEContext() || !getLangOpts().ModulesErrorRecovery)
+ return;
+
// Create the implicit import declaration.
TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU,
@@ -12942,8 +13481,8 @@ void Sema::createImplicitModuleImport(SourceLocation Loc, Module *Mod) {
Consumer.HandleImplicitImportDecl(ImportD);
// Make the module visible.
- PP.getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, Loc,
- /*Complain=*/false);
+ getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, Loc,
+ /*Complain=*/false);
}
void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
@@ -12953,8 +13492,8 @@ void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
SourceLocation AliasNameLoc) {
Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc,
LookupOrdinaryName);
- AsmLabelAttr *Attr =
- ::new (Context) AsmLabelAttr(AliasNameLoc, Context, AliasName->getName());
+ AsmLabelAttr *Attr = ::new (Context) AsmLabelAttr(AliasNameLoc, Context,
+ AliasName->getName(), 0);
if (PrevDecl)
PrevDecl->addAttr(Attr);
@@ -12969,11 +13508,11 @@ void Sema::ActOnPragmaWeakID(IdentifierInfo* Name,
Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName);
if (PrevDecl) {
- PrevDecl->addAttr(::new (Context) WeakAttr(PragmaLoc, Context));
+ PrevDecl->addAttr(WeakAttr::CreateImplicit(Context, PragmaLoc));
} else {
(void)WeakUndeclaredIdentifiers.insert(
std::pair<IdentifierInfo*,WeakInfo>
- (Name, WeakInfo((IdentifierInfo*)0, NameLoc)));
+ (Name, WeakInfo((IdentifierInfo*)nullptr, NameLoc)));
}
}
@@ -13002,5 +13541,22 @@ Decl *Sema::getObjCDeclContext() const {
AvailabilityResult Sema::getCurContextAvailability() const {
const Decl *D = cast<Decl>(getCurObjCLexicalContext());
+ // If we are within an Objective-C method, we should consult
+ // both the availability of the method as well as the
+ // enclosing class. If the class is (say) deprecated,
+ // the entire method is considered deprecated from the
+ // purpose of checking if the current context is deprecated.
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ AvailabilityResult R = MD->getAvailability();
+ if (R != AR_Available)
+ return R;
+ D = MD->getClassInterface();
+ }
+ // If we are within an Objective-c @implementation, it
+ // gets the same availability context as the @interface.
+ else if (const ObjCImplementationDecl *ID =
+ dyn_cast<ObjCImplementationDecl>(D)) {
+ D = ID->getClassInterface();
+ }
return D->getAvailability();
}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 3e583862092c..61683cd87579 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -12,13 +12,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "TargetAttributesSema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/Mangle.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
@@ -32,86 +32,23 @@
using namespace clang;
using namespace sema;
-/// These constants match the enumerated choices of
-/// warn_attribute_wrong_decl_type and err_attribute_wrong_decl_type.
-enum AttributeDeclKind {
- ExpectedFunction,
- ExpectedUnion,
- ExpectedVariableOrFunction,
- ExpectedFunctionOrMethod,
- ExpectedParameter,
- ExpectedFunctionMethodOrBlock,
- ExpectedFunctionMethodOrClass,
- ExpectedFunctionMethodOrParameter,
- ExpectedClass,
- ExpectedVariable,
- ExpectedMethod,
- ExpectedVariableFunctionOrLabel,
- ExpectedFieldOrGlobalVar,
- ExpectedStruct,
- ExpectedVariableFunctionOrTag,
- ExpectedTLSVar,
- ExpectedVariableOrField,
- ExpectedVariableFieldOrTag,
- ExpectedTypeOrNamespace,
- ExpectedObjectiveCInterface,
- ExpectedMethodOrProperty,
- ExpectedStructOrUnion,
- ExpectedStructOrUnionOrClass
-};
+namespace AttributeLangSupport {
+ enum LANG {
+ C,
+ Cpp,
+ ObjC
+ };
+}
//===----------------------------------------------------------------------===//
// Helper functions
//===----------------------------------------------------------------------===//
-static const FunctionType *getFunctionType(const Decl *D,
- bool blocksToo = true) {
- QualType Ty;
- if (const ValueDecl *decl = dyn_cast<ValueDecl>(D))
- Ty = decl->getType();
- else if (const FieldDecl *decl = dyn_cast<FieldDecl>(D))
- Ty = decl->getType();
- else if (const TypedefNameDecl* decl = dyn_cast<TypedefNameDecl>(D))
- Ty = decl->getUnderlyingType();
- else
- return 0;
-
- if (Ty->isFunctionPointerType())
- Ty = Ty->getAs<PointerType>()->getPointeeType();
- else if (blocksToo && Ty->isBlockPointerType())
- Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
-
- return Ty->getAs<FunctionType>();
-}
-
-// FIXME: We should provide an abstraction around a method or function
-// to provide the following bits of information.
-
-/// 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;
-}
-
/// 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);
-}
-
-/// 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))
- return true;
- // check for block is more involved.
- if (const VarDecl *V = dyn_cast<VarDecl>(D)) {
- QualType Ty = V->getType();
- return Ty->isBlockPointerType();
- }
- return isa<BlockDecl>(D);
+ return (D->getFunctionType() != nullptr) || isa<ObjCMethodDecl>(D);
}
/// Return true if the given decl has a declarator that should have
@@ -126,42 +63,39 @@ static bool hasDeclarator(const Decl *D) {
/// information. This decl should have already passed
/// isFunctionOrMethod or isFunctionOrMethodOrBlock.
static bool hasFunctionProto(const Decl *D) {
- if (const FunctionType *FnTy = getFunctionType(D))
+ if (const FunctionType *FnTy = D->getFunctionType())
return isa<FunctionProtoType>(FnTy);
- else {
- assert(isa<ObjCMethodDecl>(D) || isa<BlockDecl>(D));
- return true;
- }
+ return isa<ObjCMethodDecl>(D) || isa<BlockDecl>(D);
}
-/// getFunctionOrMethodNumArgs - Return number of function or method
-/// arguments. It is an error to call this on a K&R function (use
+/// getFunctionOrMethodNumParams - Return number of function or method
+/// parameters. 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))
- return cast<FunctionProtoType>(FnTy)->getNumArgs();
+static unsigned getFunctionOrMethodNumParams(const Decl *D) {
+ if (const FunctionType *FnTy = D->getFunctionType())
+ return cast<FunctionProtoType>(FnTy)->getNumParams();
if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
return BD->getNumParams();
return cast<ObjCMethodDecl>(D)->param_size();
}
-static QualType getFunctionOrMethodArgType(const Decl *D, unsigned Idx) {
- if (const FunctionType *FnTy = getFunctionType(D))
- return cast<FunctionProtoType>(FnTy)->getArgType(Idx);
+static QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) {
+ if (const FunctionType *FnTy = D->getFunctionType())
+ return cast<FunctionProtoType>(FnTy)->getParamType(Idx);
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)->parameters()[Idx]->getType();
}
static QualType getFunctionOrMethodResultType(const Decl *D) {
- if (const FunctionType *FnTy = getFunctionType(D))
- return cast<FunctionProtoType>(FnTy)->getResultType();
- return cast<ObjCMethodDecl>(D)->getResultType();
+ if (const FunctionType *FnTy = D->getFunctionType())
+ return cast<FunctionType>(FnTy)->getReturnType();
+ return cast<ObjCMethodDecl>(D)->getReturnType();
}
static bool isFunctionOrMethodVariadic(const Decl *D) {
- if (const FunctionType *FnTy = getFunctionType(D)) {
+ if (const FunctionType *FnTy = D->getFunctionType()) {
const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy);
return proto->isVariadic();
} else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
@@ -227,30 +161,63 @@ static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr,
return true;
}
-
/// \brief Check if the attribute has at least as many args as Num. May
/// output an error.
static bool checkAttributeAtLeastNumArgs(Sema &S, const AttributeList &Attr,
unsigned Num) {
if (getNumAttributeArgs(Attr) < Num) {
- S.Diag(Attr.getLoc(), diag::err_attribute_too_few_arguments) << Num;
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_few_arguments)
+ << Attr.getName() << Num;
return false;
}
return true;
}
-/// \brief Check if IdxExpr is a valid argument index for a function or
+/// \brief If Expr is a valid integer constant, get the value of the integer
+/// expression and return success or failure. May output an error.
+static bool checkUInt32Argument(Sema &S, const AttributeList &Attr,
+ const Expr *Expr, uint32_t &Val,
+ unsigned Idx = UINT_MAX) {
+ llvm::APSInt I(32);
+ if (Expr->isTypeDependent() || Expr->isValueDependent() ||
+ !Expr->isIntegerConstantExpr(I, S.Context)) {
+ if (Idx != UINT_MAX)
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+ << Attr.getName() << Idx << AANT_ArgumentIntegerConstant
+ << Expr->getSourceRange();
+ else
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
+ << Attr.getName() << AANT_ArgumentIntegerConstant
+ << Expr->getSourceRange();
+ return false;
+ }
+ Val = (uint32_t)I.getZExtValue();
+ return true;
+}
+
+/// \brief Diagnose mutually exclusive attributes when present on a given
+/// declaration. Returns true if diagnosed.
+template <typename AttrTy>
+static bool checkAttrMutualExclusion(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (AttrTy *A = D->getAttr<AttrTy>()) {
+ S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
+ << Attr.getName() << A;
+ return true;
+ }
+ return false;
+}
+
+/// \brief Check if IdxExpr is a valid parameter index for a function or
/// instance method D. May output an error.
///
/// \returns true if IdxExpr is a valid index.
-static bool checkFunctionOrMethodArgumentIndex(Sema &S, const Decl *D,
- StringRef AttrName,
- SourceLocation AttrLoc,
- unsigned AttrArgNum,
- const Expr *IdxExpr,
- uint64_t &Idx)
-{
+static bool checkFunctionOrMethodParameterIndex(Sema &S, const Decl *D,
+ const AttributeList &Attr,
+ unsigned AttrArgNum,
+ const Expr *IdxExpr,
+ uint64_t &Idx) {
assert(isFunctionOrMethod(D));
// In C++ the implicit 'this' function parameter also counts.
@@ -258,30 +225,30 @@ static bool checkFunctionOrMethodArgumentIndex(Sema &S, const Decl *D,
bool HP = hasFunctionProto(D);
bool HasImplicitThisParam = isInstanceMethod(D);
bool IV = HP && isFunctionOrMethodVariadic(D);
- unsigned NumArgs = (HP ? getFunctionOrMethodNumArgs(D) : 0) +
- HasImplicitThisParam;
+ unsigned NumParams =
+ (HP ? getFunctionOrMethodNumParams(D) : 0) + HasImplicitThisParam;
llvm::APSInt IdxInt;
if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
!IdxExpr->isIntegerConstantExpr(IdxInt, S.Context)) {
- std::string Name = std::string("'") + AttrName.str() + std::string("'");
- S.Diag(AttrLoc, diag::err_attribute_argument_n_type) << Name.c_str()
- << AttrArgNum << AANT_ArgumentIntegerConstant << IdxExpr->getSourceRange();
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
+ << Attr.getName() << AttrArgNum << AANT_ArgumentIntegerConstant
+ << IdxExpr->getSourceRange();
return false;
}
Idx = IdxInt.getLimitedValue();
- if (Idx < 1 || (!IV && Idx > NumArgs)) {
- S.Diag(AttrLoc, diag::err_attribute_argument_out_of_bounds)
- << AttrName << AttrArgNum << IdxExpr->getSourceRange();
+ if (Idx < 1 || (!IV && Idx > NumParams)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << Attr.getName() << AttrArgNum << IdxExpr->getSourceRange();
return false;
}
Idx--; // Convert to zero-based.
if (HasImplicitThisParam) {
if (Idx == 0) {
- S.Diag(AttrLoc,
+ S.Diag(Attr.getLoc(),
diag::err_attribute_invalid_implicit_this_argument)
- << AttrName << IdxExpr->getSourceRange();
+ << Attr.getName() << IdxExpr->getSourceRange();
return false;
}
--Idx;
@@ -326,17 +293,13 @@ bool Sema::checkStringLiteralArgumentAttr(const AttributeList &Attr,
return true;
}
-///
-/// \brief Check if passed in Decl is a field or potentially shared global var
-/// \return true if the Decl is a field or potentially shared global variable
-///
-static bool mayBeSharedVariable(const Decl *D) {
- if (isa<FieldDecl>(D))
- return true;
- if (const VarDecl *vd = dyn_cast<VarDecl>(D))
- return vd->hasGlobalStorage() && !vd->getTLSKind();
-
- return false;
+/// \brief Applies the given attribute to the Decl without performing any
+/// additional semantic checking.
+template <typename AttrType>
+static void handleSimpleAttribute(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ D->addAttr(::new (S.Context) AttrType(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
/// \brief Check if the passed-in expression is of type int or bool.
@@ -367,28 +330,24 @@ static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) {
/// \return true if the Decl is a pointer type; false otherwise
static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D,
const AttributeList &Attr) {
- if (const ValueDecl *vd = dyn_cast<ValueDecl>(D)) {
- QualType QT = vd->getType();
- if (QT->isAnyPointerType())
- return true;
-
- if (const RecordType *RT = QT->getAs<RecordType>()) {
- // If it's an incomplete type, it could be a smart pointer; skip it.
- // (We don't want to force template instantiation if we can avoid it,
- // since that would alter the order in which templates are instantiated.)
- if (RT->isIncompleteType())
- return true;
+ const ValueDecl *vd = cast<ValueDecl>(D);
+ QualType QT = vd->getType();
+ if (QT->isAnyPointerType())
+ return true;
- if (threadSafetyCheckIsSmartPointer(S, RT))
- return true;
- }
+ if (const RecordType *RT = QT->getAs<RecordType>()) {
+ // If it's an incomplete type, it could be a smart pointer; skip it.
+ // (We don't want to force template instantiation if we can avoid it,
+ // since that would alter the order in which templates are instantiated.)
+ if (RT->isIncompleteType())
+ return true;
- S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_pointer)
- << Attr.getName()->getName() << QT;
- } else {
- S.Diag(Attr.getLoc(), diag::err_attribute_can_be_applied_only_to_value_decl)
- << Attr.getName();
+ if (threadSafetyCheckIsSmartPointer(S, RT))
+ return true;
}
+
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_pointer)
+ << Attr.getName() << QT;
return false;
}
@@ -402,68 +361,101 @@ static const RecordType *getRecordType(QualType QT) {
if (const PointerType *PT = QT->getAs<PointerType>())
return PT->getPointeeType()->getAs<RecordType>();
- return 0;
-}
-
-
-static bool checkBaseClassIsLockableCallback(const CXXBaseSpecifier *Specifier,
- CXXBasePath &Path, void *Unused) {
- const RecordType *RT = Specifier->getType()->getAs<RecordType>();
- if (RT->getDecl()->getAttr<LockableAttr>())
- return true;
- return false;
+ return nullptr;
}
-
-/// \brief Thread Safety Analysis: Checks that the passed in RecordType
-/// resolves to a lockable object.
-static void checkForLockableRecord(Sema &S, Decl *D, const AttributeList &Attr,
- QualType Ty) {
+static bool checkRecordTypeForCapability(Sema &S, QualType Ty) {
const RecordType *RT = getRecordType(Ty);
- // Warn if could not get record type for this argument.
- if (!RT) {
- S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_class)
- << Attr.getName() << Ty.getAsString();
- return;
- }
+ if (!RT)
+ return false;
- // Don't check for lockable if the class hasn't been defined yet.
+ // Don't check for the capability if the class hasn't been defined yet.
if (RT->isIncompleteType())
- return;
+ return true;
- // Allow smart pointers to be used as lockable objects.
+ // Allow smart pointers to be used as capability objects.
// FIXME -- Check the type that the smart pointer points to.
if (threadSafetyCheckIsSmartPointer(S, RT))
- return;
+ return true;
- // Check if the type is lockable.
+ // Check if the record itself has a capability.
RecordDecl *RD = RT->getDecl();
- if (RD->getAttr<LockableAttr>())
- return;
+ if (RD->hasAttr<CapabilityAttr>())
+ return true;
- // Else check if any base classes are lockable.
+ // Else check if any base classes have a capability.
if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
CXXBasePaths BPaths(false, false);
- if (CRD->lookupInBases(checkBaseClassIsLockableCallback, 0, BPaths))
- return;
+ if (CRD->lookupInBases([](const CXXBaseSpecifier *BS, CXXBasePath &P,
+ void *) {
+ return BS->getType()->getAs<RecordType>()
+ ->getDecl()->hasAttr<CapabilityAttr>();
+ }, nullptr, BPaths))
+ return true;
+ }
+ return false;
+}
+
+static bool checkTypedefTypeForCapability(QualType Ty) {
+ const auto *TD = Ty->getAs<TypedefType>();
+ if (!TD)
+ return false;
+
+ TypedefNameDecl *TN = TD->getDecl();
+ if (!TN)
+ return false;
+
+ return TN->hasAttr<CapabilityAttr>();
+}
+
+static bool typeHasCapability(Sema &S, QualType Ty) {
+ if (checkTypedefTypeForCapability(Ty))
+ return true;
+
+ if (checkRecordTypeForCapability(S, Ty))
+ return true;
+
+ return false;
+}
+
+static bool isCapabilityExpr(Sema &S, const Expr *Ex) {
+ // Capability expressions are simple expressions involving the boolean logic
+ // operators &&, || or !, a simple DeclRefExpr, CastExpr or a ParenExpr. Once
+ // a DeclRefExpr is found, its type should be checked to determine whether it
+ // is a capability or not.
+
+ if (const auto *E = dyn_cast<DeclRefExpr>(Ex))
+ return typeHasCapability(S, E->getType());
+ else if (const auto *E = dyn_cast<CastExpr>(Ex))
+ return isCapabilityExpr(S, E->getSubExpr());
+ else if (const auto *E = dyn_cast<ParenExpr>(Ex))
+ return isCapabilityExpr(S, E->getSubExpr());
+ else if (const auto *E = dyn_cast<UnaryOperator>(Ex)) {
+ if (E->getOpcode() == UO_LNot)
+ return isCapabilityExpr(S, E->getSubExpr());
+ return false;
+ } else if (const auto *E = dyn_cast<BinaryOperator>(Ex)) {
+ if (E->getOpcode() == BO_LAnd || E->getOpcode() == BO_LOr)
+ return isCapabilityExpr(S, E->getLHS()) &&
+ isCapabilityExpr(S, E->getRHS());
+ return false;
}
- S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable)
- << Attr.getName() << Ty.getAsString();
+ return false;
}
-/// \brief Thread Safety Analysis: Checks that all attribute arguments, starting
-/// from Sidx, resolve to a lockable object.
+/// \brief Checks that all attribute arguments, starting from Sidx, resolve to
+/// a capability object.
/// \param Sidx The attribute argument index to start checking with.
/// \param ParamIdxOk Whether an argument can be indexing into a function
/// parameter list.
-static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
- const AttributeList &Attr,
- SmallVectorImpl<Expr*> &Args,
- int Sidx = 0,
- bool ParamIdxOk = false) {
- for(unsigned Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) {
+static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D,
+ const AttributeList &Attr,
+ SmallVectorImpl<Expr *> &Args,
+ int Sidx = 0,
+ bool ParamIdxOk = false) {
+ for (unsigned Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) {
Expr *ArgExp = Attr.getArgAsExpr(Idx);
if (ArgExp->isTypeDependent()) {
@@ -499,7 +491,7 @@ static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
if (DRE->getDecl()->isCXXInstanceMember())
ArgTy = DRE->getDecl()->getType();
- // First see if we can just cast to record type, or point to record type.
+ // First see if we can just cast to record type, or pointer to record type.
const RecordType *RT = getRecordType(ArgTy);
// Now check if we index into a record type function param.
@@ -520,7 +512,13 @@ static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
}
}
- checkForLockableRecord(S, D, Attr, ArgTy);
+ // If the type does not have a capability, see if the components of the
+ // expression have capabilities. This allows for writing C code where the
+ // capability may be on the type, and the expression is a capability
+ // boolean logic expression. Eg) requires_capability(A || B && !C)
+ if (!typeHasCapability(S, ArgTy) && !isCapabilityExpr(S, ArgExp))
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable)
+ << Attr.getName() << ArgTy;
Args.push_back(ArgExp);
}
@@ -534,38 +532,8 @@ static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
// least add some helper functions to check most argument patterns (#
// and types of args).
-enum ThreadAttributeDeclKind {
- ThreadExpectedFieldOrGlobalVar,
- ThreadExpectedFunctionOrMethod,
- ThreadExpectedClassOrStruct
-};
-
-static bool checkGuardedVarAttrCommon(Sema &S, Decl *D,
- const AttributeList &Attr) {
- // D must be either a member field or global (potentially shared) variable.
- if (!mayBeSharedVariable(D)) {
- S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
- << Attr.getName() << ThreadExpectedFieldOrGlobalVar;
- return false;
- }
-
- return true;
-}
-
-static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!checkGuardedVarAttrCommon(S, D, Attr))
- return;
-
- D->addAttr(::new (S.Context)
- GuardedVarAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
static void handlePtGuardedVarAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!checkGuardedVarAttrCommon(S, D, Attr))
- return;
-
if (!threadSafetyCheckIsPointer(S, D, Attr))
return;
@@ -577,16 +545,9 @@ static void handlePtGuardedVarAttr(Sema &S, Decl *D,
static bool checkGuardedByAttrCommon(Sema &S, Decl *D,
const AttributeList &Attr,
Expr* &Arg) {
- // D must be either a member field or global (potentially shared) variable.
- if (!mayBeSharedVariable(D)) {
- S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
- << Attr.getName() << ThreadExpectedFieldOrGlobalVar;
- return false;
- }
-
SmallVector<Expr*, 1> Args;
// check that all arguments are lockable objects
- checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ checkAttrArgsAreCapabilityObjs(S, D, Attr, Args);
unsigned Size = Args.size();
if (Size != 1)
return false;
@@ -597,16 +558,17 @@ static bool checkGuardedByAttrCommon(Sema &S, Decl *D,
}
static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- Expr *Arg = 0;
+ Expr *Arg = nullptr;
if (!checkGuardedByAttrCommon(S, D, Attr, Arg))
return;
- D->addAttr(::new (S.Context) GuardedByAttr(Attr.getRange(), S.Context, Arg));
+ D->addAttr(::new (S.Context) GuardedByAttr(Attr.getRange(), S.Context, Arg,
+ Attr.getAttributeSpellingListIndex()));
}
static void handlePtGuardedByAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- Expr *Arg = 0;
+ Expr *Arg = nullptr;
if (!checkGuardedByAttrCommon(S, D, Attr, Arg))
return;
@@ -614,85 +576,8 @@ static void handlePtGuardedByAttr(Sema &S, Decl *D,
return;
D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getRange(),
- S.Context, Arg));
-}
-
-static bool checkLockableAttrCommon(Sema &S, Decl *D,
- const AttributeList &Attr) {
- // FIXME: Lockable structs for C code.
- if (!isa<RecordDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
- << Attr.getName() << ThreadExpectedClassOrStruct;
- return false;
- }
-
- return true;
-}
-
-static void handleLockableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!checkLockableAttrCommon(S, D, Attr))
- return;
-
- D->addAttr(::new (S.Context) LockableAttr(Attr.getRange(), S.Context));
-}
-
-static void handleScopedLockableAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- if (!checkLockableAttrCommon(S, D, Attr))
- return;
-
- D->addAttr(::new (S.Context)
- ScopedLockableAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
-static void handleNoThreadSafetyAnalysis(Sema &S, Decl *D,
- const AttributeList &Attr) {
- if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
- << Attr.getName() << ThreadExpectedFunctionOrMethod;
- return;
- }
-
- D->addAttr(::new (S.Context) NoThreadSafetyAnalysisAttr(Attr.getRange(),
- S.Context));
-}
-
-static void handleNoSanitizeAddressAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
- return;
- }
-
- D->addAttr(::new (S.Context)
- NoSanitizeAddressAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
-static void handleNoSanitizeMemory(Sema &S, Decl *D,
- const AttributeList &Attr) {
- if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
- return;
- }
-
- D->addAttr(::new (S.Context) NoSanitizeMemoryAttr(Attr.getRange(),
- S.Context));
-}
-
-static void handleNoSanitizeThread(Sema &S, Decl *D,
- const AttributeList &Attr) {
- if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
- return;
- }
-
- D->addAttr(::new (S.Context) NoSanitizeThreadAttr(Attr.getRange(),
- S.Context));
+ S.Context, Arg,
+ Attr.getAttributeSpellingListIndex()));
}
static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D,
@@ -701,19 +586,11 @@ static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D,
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
return false;
- // D must be either a member field or global (potentially shared) variable.
- ValueDecl *VD = dyn_cast<ValueDecl>(D);
- if (!VD || !mayBeSharedVariable(D)) {
- S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
- << Attr.getName() << ThreadExpectedFieldOrGlobalVar;
- return false;
- }
-
// Check that this attribute only applies to lockable types.
- QualType QT = VD->getType();
+ QualType QT = cast<ValueDecl>(D)->getType();
if (!QT->isDependentType()) {
const RecordType *RT = getRecordType(QT);
- if (!RT || !RT->getDecl()->getAttr<LockableAttr>()) {
+ if (!RT || !RT->getDecl()->hasAttr<CapabilityAttr>()) {
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_lockable)
<< Attr.getName();
return false;
@@ -721,7 +598,7 @@ static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D,
}
// Check that all arguments are lockable objects.
- checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ checkAttrArgsAreCapabilityObjs(S, D, Attr, Args);
if (Args.empty())
return false;
@@ -758,47 +635,12 @@ static bool checkLockFunAttrCommon(Sema &S, Decl *D,
const AttributeList &Attr,
SmallVectorImpl<Expr *> &Args) {
// zero or more arguments ok
-
- // check that the attribute is applied to a function
- if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
- << Attr.getName() << ThreadExpectedFunctionOrMethod;
- return false;
- }
-
// check that all arguments are lockable objects
- checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true);
+ checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true);
return true;
}
-static void handleSharedLockFunctionAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- SmallVector<Expr*, 1> Args;
- if (!checkLockFunAttrCommon(S, D, Attr, Args))
- return;
-
- unsigned Size = Args.size();
- Expr **StartArg = Size == 0 ? 0 : &Args[0];
- D->addAttr(::new (S.Context)
- SharedLockFunctionAttr(Attr.getRange(), S.Context, StartArg, Size,
- Attr.getAttributeSpellingListIndex()));
-}
-
-static void handleExclusiveLockFunctionAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- SmallVector<Expr*, 1> Args;
- if (!checkLockFunAttrCommon(S, D, Attr, Args))
- return;
-
- unsigned Size = Args.size();
- Expr **StartArg = Size == 0 ? 0 : &Args[0];
- D->addAttr(::new (S.Context)
- ExclusiveLockFunctionAttr(Attr.getRange(), S.Context,
- StartArg, Size,
- Attr.getAttributeSpellingListIndex()));
-}
-
static void handleAssertSharedLockAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
SmallVector<Expr*, 1> Args;
@@ -806,7 +648,7 @@ static void handleAssertSharedLockAttr(Sema &S, Decl *D,
return;
unsigned Size = Args.size();
- Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ Expr **StartArg = Size == 0 ? nullptr : &Args[0];
D->addAttr(::new (S.Context)
AssertSharedLockAttr(Attr.getRange(), S.Context, StartArg, Size,
Attr.getAttributeSpellingListIndex()));
@@ -819,7 +661,7 @@ static void handleAssertExclusiveLockAttr(Sema &S, Decl *D,
return;
unsigned Size = Args.size();
- Expr **StartArg = Size == 0 ? 0 : &Args[0];
+ Expr **StartArg = Size == 0 ? nullptr : &Args[0];
D->addAttr(::new (S.Context)
AssertExclusiveLockAttr(Attr.getRange(), S.Context,
StartArg, Size,
@@ -833,12 +675,6 @@ static bool checkTryLockFunAttrCommon(Sema &S, Decl *D,
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
return false;
- if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
- << Attr.getName() << ThreadExpectedFunctionOrMethod;
- return false;
- }
-
if (!isIntOrBool(Attr.getArgAsExpr(0))) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
<< Attr.getName() << 1 << AANT_ArgumentIntOrBool;
@@ -846,7 +682,7 @@ static bool checkTryLockFunAttrCommon(Sema &S, Decl *D,
}
// check that all arguments are lockable objects
- checkAttrArgsAreLockableObjs(S, D, Attr, Args, 1);
+ checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 1);
return true;
}
@@ -877,84 +713,11 @@ static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
-static bool checkLocksRequiredCommon(Sema &S, Decl *D,
- const AttributeList &Attr,
- SmallVectorImpl<Expr *> &Args) {
- if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
- return false;
-
- if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
- << Attr.getName() << ThreadExpectedFunctionOrMethod;
- return false;
- }
-
- // check that all arguments are lockable objects
- checkAttrArgsAreLockableObjs(S, D, Attr, Args);
- if (Args.empty())
- return false;
-
- return true;
-}
-
-static void handleExclusiveLocksRequiredAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- SmallVector<Expr*, 1> Args;
- if (!checkLocksRequiredCommon(S, D, Attr, Args))
- return;
-
- Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context)
- ExclusiveLocksRequiredAttr(Attr.getRange(), S.Context,
- StartArg, Args.size(),
- Attr.getAttributeSpellingListIndex()));
-}
-
-static void handleSharedLocksRequiredAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- SmallVector<Expr*, 1> Args;
- if (!checkLocksRequiredCommon(S, D, Attr, Args))
- return;
-
- Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context)
- SharedLocksRequiredAttr(Attr.getRange(), S.Context,
- StartArg, Args.size(),
- Attr.getAttributeSpellingListIndex()));
-}
-
-static void handleUnlockFunAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- // zero or more arguments ok
-
- if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
- << Attr.getName() << ThreadExpectedFunctionOrMethod;
- return;
- }
-
- // check that all arguments are lockable objects
- SmallVector<Expr*, 1> Args;
- checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true);
- unsigned Size = Args.size();
- Expr **StartArg = Size == 0 ? 0 : &Args[0];
-
- D->addAttr(::new (S.Context)
- UnlockFunctionAttr(Attr.getRange(), S.Context, StartArg, Size,
- Attr.getAttributeSpellingListIndex()));
-}
-
static void handleLockReturnedAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
- << Attr.getName() << ThreadExpectedFunctionOrMethod;
- return;
- }
-
// check that the argument is lockable object
SmallVector<Expr*, 1> Args;
- checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ checkAttrArgsAreCapabilityObjs(S, D, Attr, Args);
unsigned Size = Args.size();
if (Size == 0)
return;
@@ -969,15 +732,9 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D,
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
return;
- if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type)
- << Attr.getName() << ThreadExpectedFunctionOrMethod;
- return;
- }
-
// check that all arguments are lockable objects
SmallVector<Expr*, 1> Args;
- checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+ checkAttrArgsAreCapabilityObjs(S, D, Attr, Args);
unsigned Size = Args.size();
if (Size == 0)
return;
@@ -988,6 +745,34 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
+static void handleEnableIfAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ Expr *Cond = Attr.getArgAsExpr(0);
+ if (!Cond->isTypeDependent()) {
+ ExprResult Converted = S.PerformContextuallyConvertToBool(Cond);
+ if (Converted.isInvalid())
+ return;
+ Cond = Converted.get();
+ }
+
+ StringRef Msg;
+ if (!S.checkStringLiteralArgumentAttr(Attr, 1, Msg))
+ return;
+
+ SmallVector<PartialDiagnosticAt, 8> Diags;
+ if (!Cond->isValueDependent() &&
+ !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(D),
+ Diags)) {
+ S.Diag(Attr.getLoc(), diag::err_enable_if_never_constant_expr);
+ for (int I = 0, N = Diags.size(); I != N; ++I)
+ S.Diag(Diags[I].first, Diags[I].second);
+ return;
+ }
+
+ D->addAttr(::new (S.Context)
+ EnableIfAttr(Attr.getRange(), S.Context, Cond, Msg,
+ Attr.getAttributeSpellingListIndex()));
+}
+
static void handleConsumableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
ConsumableAttr::ConsumedState DefaultState;
@@ -1004,18 +789,13 @@ static void handleConsumableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
<< Attr.getName() << AANT_ArgumentIdentifier;
return;
}
-
- if (!isa<CXXRecordDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
- Attr.getName() << ExpectedClass;
- return;
- }
D->addAttr(::new (S.Context)
ConsumableAttr(Attr.getRange(), S.Context, DefaultState,
Attr.getAttributeSpellingListIndex()));
}
+
static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD,
const AttributeList &Attr) {
ASTContext &CurrContext = S.getASTContext();
@@ -1038,12 +818,6 @@ static void handleCallableWhenAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
return;
-
- if (!isa<CXXMethodDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
- Attr.getName() << ExpectedMethod;
- return;
- }
if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr))
return;
@@ -1076,13 +850,7 @@ static void handleCallableWhenAttr(Sema &S, Decl *D,
static void handleParamTypestateAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (!checkAttributeNumArgs(S, Attr, 1)) return;
-
- if (!isa<ParmVarDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
- Attr.getName() << ExpectedParameter;
- return;
- }
-
+
ParamTypestateAttr::ConsumedState ParamState;
if (Attr.isArgIdent(0)) {
@@ -1123,12 +891,6 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (!checkAttributeNumArgs(S, Attr, 1)) return;
- if (!(isa<FunctionDecl>(D) || isa<ParmVarDecl>(D))) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
- Attr.getName() << ExpectedFunctionMethodOrParameter;
- return;
- }
-
ReturnTypestateAttr::ConsumedState ReturnState;
if (Attr.isArgIdent(0)) {
@@ -1179,12 +941,6 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D,
static void handleSetTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkAttributeNumArgs(S, Attr, 1))
return;
-
- if (!isa<CXXMethodDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
- Attr.getName() << ExpectedMethod;
- return;
- }
if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr))
return;
@@ -1214,12 +970,6 @@ static void handleTestTypestateAttr(Sema &S, Decl *D,
if (!checkAttributeNumArgs(S, Attr, 1))
return;
- if (!isa<CXXMethodDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
- Attr.getName() << ExpectedMethod;
- return;
- }
-
if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr))
return;
@@ -1245,21 +995,14 @@ static void handleTestTypestateAttr(Sema &S, Decl *D,
static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr) {
- TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
- if (TD == 0) {
- // __attribute__((ext_vector_type(N))) can only be applied to typedefs
- // and type-ids.
- S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef);
- return;
- }
-
// Remember this typedef decl, we will need it later for diagnostics.
- S.ExtVectorDecls.push_back(TD);
+ S.ExtVectorDecls.push_back(cast<TypedefNameDecl>(D));
}
static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (TagDecl *TD = dyn_cast<TagDecl>(D))
- TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context));
+ TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
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.
@@ -1276,28 +1019,6 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
-static void handleMsStructAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (RecordDecl *RD = dyn_cast<RecordDecl>(D))
- RD->addAttr(::new (S.Context)
- MsStructAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
- else
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
-}
-
-static void handleIBAction(Sema &S, Decl *D, const AttributeList &Attr) {
- // The IBAction attributes only apply to instance methods.
- if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
- if (MD->isInstanceMethod()) {
- D->addAttr(::new (S.Context)
- IBActionAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
- return;
- }
-
- S.Diag(Attr.getLoc(), diag::warn_attribute_ibaction) << Attr.getName();
-}
-
static bool checkIBOutletCommon(Sema &S, Decl *D, const AttributeList &Attr) {
// The IBOutlet/IBOutletCollection attributes only apply to instance
// variables or properties of Objective-C classes. The outlet must also
@@ -1359,7 +1080,7 @@ static void handleIBOutletCollection(Sema &S, Decl *D,
}
}
- TypeSourceInfo *QTLoc = 0;
+ TypeSourceInfo *QTLoc = nullptr;
QualType QT = S.GetTypeFromParser(PT, &QTLoc);
if (!QTLoc)
QTLoc = S.Context.getTrivialTypeSourceInfo(QT, Attr.getLoc());
@@ -1384,9 +1105,8 @@ 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();
+ for (const auto *I : UD->fields()) {
+ QualType QT = I->getType();
if (QT->isAnyPointerType() || QT->isBlockPointerType()) {
T = QT;
return;
@@ -1395,74 +1115,34 @@ static void possibleTransparentUnionPointerType(QualType &T) {
}
}
-static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!isFunctionOrMethod(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
- return;
- }
+static bool attrNonNullArgCheck(Sema &S, QualType T, const AttributeList &Attr,
+ SourceRange R, bool isReturnValue = false) {
+ T = T.getNonReferenceType();
+ possibleTransparentUnionPointerType(T);
- if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
- return;
-
- SmallVector<unsigned, 8> SizeArgs;
- for (unsigned i = 0; i < Attr.getNumArgs(); ++i) {
- Expr *Ex = Attr.getArgAsExpr(i);
- uint64_t Idx;
- if (!checkFunctionOrMethodArgumentIndex(S, D, Attr.getName()->getName(),
- Attr.getLoc(), i + 1, Ex, Idx))
- return;
-
- // check if the function argument is of an integer type
- QualType T = getFunctionOrMethodArgType(D, Idx).getNonReferenceType();
- if (!T->isIntegerType()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
- << Attr.getName() << AANT_ArgumentIntegerConstant
- << Ex->getSourceRange();
- return;
- }
- SizeArgs.push_back(Idx);
- }
-
- // check if the function returns a pointer
- if (!getFunctionType(D)->getResultType()->isAnyPointerType()) {
- S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type)
- << Attr.getName() << 0 /*function*/<< 1 /*pointer*/ << D->getSourceRange();
+ if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
+ S.Diag(Attr.getLoc(),
+ isReturnValue ? diag::warn_attribute_return_pointers_only
+ : diag::warn_attribute_pointers_only)
+ << Attr.getName() << R;
+ return false;
}
-
- D->addAttr(::new (S.Context)
- AllocSizeAttr(Attr.getRange(), S.Context,
- SizeArgs.data(), SizeArgs.size(),
- Attr.getAttributeSpellingListIndex()));
+ return true;
}
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)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunction;
- return;
- }
-
SmallVector<unsigned, 8> NonNullArgs;
for (unsigned i = 0; i < Attr.getNumArgs(); ++i) {
Expr *Ex = Attr.getArgAsExpr(i);
uint64_t Idx;
- if (!checkFunctionOrMethodArgumentIndex(S, D, Attr.getName()->getName(),
- Attr.getLoc(), i + 1, Ex, Idx))
+ if (!checkFunctionOrMethodParameterIndex(S, D, Attr, i + 1, Ex, Idx))
return;
// Is the function argument a pointer type?
- QualType T = getFunctionOrMethodArgType(D, Idx).getNonReferenceType();
- possibleTransparentUnionPointerType(T);
-
- if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
- // FIXME: Should also highlight argument in decl.
- S.Diag(Attr.getLoc(), diag::warn_nonnull_pointers_only)
- << "nonnull" << Ex->getSourceRange();
+ // FIXME: Should also highlight argument in decl in the diagnostic.
+ if (!attrNonNullArgCheck(S, getFunctionOrMethodParamType(D, Idx), Attr,
+ Ex->getSourceRange()))
continue;
- }
NonNullArgs.push_back(Idx);
}
@@ -1470,8 +1150,8 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// 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 = getFunctionOrMethodNumParams(D); i != e; ++i) {
+ QualType T = getFunctionOrMethodParamType(D, i).getNonReferenceType();
possibleTransparentUnionPointerType(T);
if (T->isAnyPointerType() || T->isBlockPointerType())
NonNullArgs.push_back(i);
@@ -1495,13 +1175,37 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
-static const char *ownershipKindToDiagName(OwnershipAttr::OwnershipKind K) {
- switch (K) {
- case OwnershipAttr::Holds: return "'ownership_holds'";
- case OwnershipAttr::Takes: return "'ownership_takes'";
- case OwnershipAttr::Returns: return "'ownership_returns'";
+static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D,
+ const AttributeList &Attr) {
+ if (Attr.getNumArgs() > 0) {
+ if (D->getFunctionType()) {
+ handleNonNullAttr(S, D, Attr);
+ } else {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_parm_no_args)
+ << D->getSourceRange();
+ }
+ return;
}
- llvm_unreachable("unknown ownership");
+
+ // Is the argument a pointer type?
+ if (!attrNonNullArgCheck(S, D->getType(), Attr, D->getSourceRange()))
+ return;
+
+ D->addAttr(::new (S.Context)
+ NonNullAttr(Attr.getRange(), S.Context, nullptr, 0,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleReturnsNonNullAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ QualType ResultType = getFunctionOrMethodResultType(D);
+ if (!attrNonNullArgCheck(S, ResultType, Attr, Attr.getRange(),
+ /* isReturnValue */ true))
+ return;
+
+ D->addAttr(::new (S.Context)
+ ReturnsNonNullAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
@@ -1519,58 +1223,49 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
return;
}
- // Figure out our Kind, and check arguments while we're at it.
- OwnershipAttr::OwnershipKind K;
- switch (AL.getKind()) {
- case AttributeList::AT_ownership_takes:
- K = OwnershipAttr::Takes;
- if (AL.getNumArgs() < 2) {
- S.Diag(AL.getLoc(), diag::err_attribute_too_few_arguments) << 2;
- return;
- }
- break;
- case AttributeList::AT_ownership_holds:
- K = OwnershipAttr::Holds;
+ // Figure out our Kind.
+ OwnershipAttr::OwnershipKind K =
+ OwnershipAttr(AL.getLoc(), S.Context, nullptr, nullptr, 0,
+ AL.getAttributeSpellingListIndex()).getOwnKind();
+
+ // Check arguments.
+ switch (K) {
+ case OwnershipAttr::Takes:
+ case OwnershipAttr::Holds:
if (AL.getNumArgs() < 2) {
- S.Diag(AL.getLoc(), diag::err_attribute_too_few_arguments) << 2;
+ S.Diag(AL.getLoc(), diag::err_attribute_too_few_arguments)
+ << AL.getName() << 2;
return;
}
break;
- case AttributeList::AT_ownership_returns:
- K = OwnershipAttr::Returns;
-
+ case OwnershipAttr::Returns:
if (AL.getNumArgs() > 2) {
- S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << 1;
+ S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments)
+ << AL.getName() << 1;
return;
}
break;
- default:
- // This should never happen given how we are called.
- llvm_unreachable("Unknown ownership attribute");
}
- if (!isFunction(D) || !hasFunctionProto(D)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
- << AL.getName() << ExpectedFunction;
- return;
- }
-
- StringRef Module = AL.getArgAsIdent(0)->Ident->getName();
+ IdentifierInfo *Module = AL.getArgAsIdent(0)->Ident;
// Normalize the argument, __foo__ becomes foo.
- if (Module.startswith("__") && Module.endswith("__"))
- Module = Module.substr(2, Module.size() - 4);
+ StringRef ModuleName = Module->getName();
+ if (ModuleName.startswith("__") && ModuleName.endswith("__") &&
+ ModuleName.size() > 4) {
+ ModuleName = ModuleName.drop_front(2).drop_back(2);
+ Module = &S.PP.getIdentifierTable().get(ModuleName);
+ }
SmallVector<unsigned, 8> OwnershipArgs;
for (unsigned i = 1; i < AL.getNumArgs(); ++i) {
Expr *Ex = AL.getArgAsExpr(i);
uint64_t Idx;
- if (!checkFunctionOrMethodArgumentIndex(S, D, AL.getName()->getName(),
- AL.getLoc(), i, Ex, Idx))
+ if (!checkFunctionOrMethodParameterIndex(S, D, AL, i, Ex, Idx))
return;
// Is the function argument a pointer type?
- QualType T = getFunctionOrMethodArgType(D, Idx);
+ QualType T = getFunctionOrMethodParamType(D, Idx);
int Err = -1; // No error
switch (K) {
case OwnershipAttr::Takes:
@@ -1590,13 +1285,13 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
}
// 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 != e; ++i) {
- if ((*i)->getOwnKind() != K && (*i)->args_end() !=
- std::find((*i)->args_begin(), (*i)->args_end(), Idx)) {
+ for (const auto *I : D->specific_attrs<OwnershipAttr>()) {
+ // FIXME: A returns attribute should conflict with any returns attribute
+ // with a different index too.
+ if (I->getOwnKind() != K && I->args_end() !=
+ std::find(I->args_begin(), I->args_end(), Idx)) {
S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
- << AL.getName() << ownershipKindToDiagName((*i)->getOwnKind());
+ << AL.getName() << I;
return;
}
}
@@ -1608,7 +1303,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
llvm::array_pod_sort(start, start + size);
D->addAttr(::new (S.Context)
- OwnershipAttr(AL.getLoc(), S.Context, K, Module, start, size,
+ OwnershipAttr(AL.getLoc(), S.Context, Module, start, size,
AL.getAttributeSpellingListIndex()));
}
@@ -1620,12 +1315,6 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- 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);
// gcc rejects
@@ -1640,8 +1329,8 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// we reject them
const DeclContext *Ctx = D->getDeclContext()->getRedeclContext();
if (!Ctx->isFileContext()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context) <<
- nd->getNameAsString();
+ S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context)
+ << nd;
return;
}
@@ -1698,77 +1387,22 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
-static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!isa<FunctionDecl>(D) && !isa<ObjCMethodDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
- return;
- }
-
- D->addAttr(::new (S.Context)
- MinSizeAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!isa<FunctionDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunction;
+ if (checkAttrMutualExclusion<HotAttr>(S, D, Attr))
return;
- }
-
- if (D->hasAttr<HotAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
- << Attr.getName() << "hot";
- return;
- }
D->addAttr(::new (S.Context) ColdAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
}
static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!isa<FunctionDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunction;
- return;
- }
-
- if (D->hasAttr<ColdAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
- << Attr.getName() << "cold";
+ if (checkAttrMutualExclusion<ColdAttr>(S, D, Attr))
return;
- }
D->addAttr(::new (S.Context) HotAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
}
-static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- 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.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
-static void handleAlwaysInlineAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- 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.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
static void handleTLSModelAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
StringRef Model;
@@ -1777,12 +1411,6 @@ static void handleTLSModelAttr(Sema &S, Decl *D,
if (!S.checkStringLiteralArgumentAttr(Attr, 0, Model, &LiteralLoc))
return;
- if (!isa<VarDecl>(D) || !cast<VarDecl>(D)->getTLSKind()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedTLSVar;
- return;
- }
-
// Check that the value.
if (Model != "global-dynamic" && Model != "local-dynamic"
&& Model != "initial-exec" && Model != "local-exec") {
@@ -1797,7 +1425,7 @@ static void handleTLSModelAttr(Sema &S, Decl *D,
static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- QualType RetTy = FD->getResultType();
+ QualType RetTy = FD->getReturnType();
if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) {
D->addAttr(::new (S.Context)
MallocAttr(Attr.getRange(), S.Context,
@@ -1809,35 +1437,15 @@ static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
S.Diag(Attr.getLoc(), diag::warn_attribute_malloc_pointer_only);
}
-static void handleMayAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- D->addAttr(::new (S.Context)
- MayAliasAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
-static void handleNoCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (isa<VarDecl>(D))
- D->addAttr(::new (S.Context)
- NoCommonAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
- else
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedVariable;
-}
-
static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.CPlusPlus) {
- S.Diag(Attr.getLoc(), diag::err_common_not_supported_cplusplus);
+ S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang)
+ << Attr.getName() << AttributeLangSupport::Cpp;
return;
}
- if (isa<VarDecl>(D))
- D->addAttr(::new (S.Context)
- CommonAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
- else
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedVariable;
+ D->addAttr(::new (S.Context) CommonAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) {
@@ -1872,8 +1480,8 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D,
// because 'analyzer_noreturn' does not impact the type.
if (!isFunctionOrMethod(D) && !isa<BlockDecl>(D)) {
ValueDecl *VD = dyn_cast<ValueDecl>(D);
- if (VD == 0 || (!VD->getType()->isBlockPointerType()
- && !VD->getType()->isFunctionPointerType())) {
+ if (!VD || (!VD->getType()->isBlockPointerType() &&
+ !VD->getType()->isFunctionPointerType())) {
S.Diag(Attr.getLoc(),
Attr.isCXX11Attribute() ? diag::err_attribute_wrong_decl_type
: diag::warn_attribute_wrong_decl_type)
@@ -1887,23 +1495,6 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
-static void handleCXX11NoReturnAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- // C++11 [dcl.attr.noreturn]p1:
- // The attribute may be applied to the declarator-id in a function
- // declaration.
- FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (!FD) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
- return;
- }
-
- D->addAttr(::new (S.Context)
- CXX11NoReturnAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
// PS3 PPU-specific.
static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) {
/*
@@ -1929,14 +1520,8 @@ static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return result; // This will be returned in a register
}
*/
- if (!isa<RecordDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedClass;
- return;
- }
-
- if (D->getAttr<VecReturnAttr>()) {
- S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "vecreturn";
+ if (VecReturnAttr *A = D->getAttr<VecReturnAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << A;
return;
}
@@ -1953,9 +1538,8 @@ static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- for (RecordDecl::field_iterator iter = record->field_begin();
- iter != record->field_end(); iter++) {
- if ((count == 1) || !iter->getType()->isVectorType()) {
+ for (const auto *I : record->fields()) {
+ if ((count == 1) || !I->getType()->isVectorType()) {
S.Diag(Attr.getLoc(), diag::err_attribute_vecreturn_only_vector_member);
return;
}
@@ -1977,10 +1561,6 @@ static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D,
diag::err_carries_dependency_param_not_function_decl);
return;
}
- } else if (!isa<FunctionDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionMethodOrParameter;
- return;
}
D->addAttr(::new (S.Context) CarriesDependencyAttr(
@@ -1988,36 +1568,10 @@ static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
-static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!isa<VarDecl>(D) && !isa<ObjCIvarDecl>(D) && !isFunctionOrMethod(D) &&
- !isa<TypeDecl>(D) && !isa<LabelDecl>(D) && !isa<FieldDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedVariableFunctionOrLabel;
- return;
- }
-
- D->addAttr(::new (S.Context)
- UnusedAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
-static void handleReturnsTwiceAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- if (!isa<FunctionDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunction;
- return;
- }
-
- D->addAttr(::new (S.Context)
- ReturnsTwiceAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (VD->hasLocalStorage()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "used";
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
return;
}
} else if (!isFunctionOrMethod(D)) {
@@ -2034,29 +1588,15 @@ static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
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;
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments)
+ << Attr.getName() << 1;
return;
}
- int priority = 65535; // FIXME: Do not hardcode such constants.
- if (Attr.getNumArgs() > 0) {
- Expr *E = Attr.getArgAsExpr(0);
- llvm::APSInt Idx(32);
- if (E->isTypeDependent() || E->isValueDependent() ||
- !E->isIntegerConstantExpr(Idx, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
- << Attr.getName() << 1 << AANT_ArgumentIntegerConstant
- << E->getSourceRange();
- return;
- }
- priority = Idx.getZExtValue();
- }
-
- if (!isa<FunctionDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunction;
+ uint32_t priority = ConstructorAttr::DefaultPriority;
+ if (Attr.getNumArgs() > 0 &&
+ !checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), priority))
return;
- }
D->addAttr(::new (S.Context)
ConstructorAttr(Attr.getRange(), S.Context, priority,
@@ -2066,29 +1606,15 @@ static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
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;
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments)
+ << Attr.getName() << 1;
return;
}
- int priority = 65535; // FIXME: Do not hardcode such constants.
- if (Attr.getNumArgs() > 0) {
- Expr *E = Attr.getArgAsExpr(0);
- llvm::APSInt Idx(32);
- if (E->isTypeDependent() || E->isValueDependent() ||
- !E->isIntegerConstantExpr(Idx, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
- << Attr.getName() << 1 << AANT_ArgumentIntegerConstant
- << E->getSourceRange();
- return;
- }
- priority = Idx.getZExtValue();
- }
-
- if (!isa<FunctionDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunction;
+ uint32_t priority = DestructorAttr::DefaultPriority;
+ if (Attr.getNumArgs() > 0 &&
+ !checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), priority))
return;
- }
D->addAttr(::new (S.Context)
DestructorAttr(Attr.getRange(), S.Context, priority,
@@ -2100,7 +1626,8 @@ static void handleAttrWithMessage(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;
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments)
+ << Attr.getName() << 1;
return;
}
@@ -2113,36 +1640,17 @@ static void handleAttrWithMessage(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
-static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- D->addAttr(::new (S.Context)
- ArcWeakrefUnavailableAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
-static void handleObjCRootClassAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- if (!isa<ObjCInterfaceDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedObjectiveCInterface;
+static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!cast<ObjCProtocolDecl>(D)->isThisDeclarationADefinition()) {
+ S.Diag(Attr.getLoc(), diag::err_objc_attr_protocol_requires_definition)
+ << Attr.getName() << Attr.getRange();
return;
}
-
- D->addAttr(::new (S.Context)
- ObjCRootClassAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-static void handleObjCRequiresPropertyDefsAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- if (!isa<ObjCInterfaceDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::err_suppress_autosynthesis);
- return;
- }
-
D->addAttr(::new (S.Context)
- ObjCRequiresPropertyDefsAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ ObjCExplicitProtocolImplAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static bool checkAvailabilityAttr(Sema &S, SourceRange Range,
@@ -2312,7 +1820,7 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
MergedIntroduced == Introduced &&
MergedDeprecated == Deprecated &&
MergedObsoleted == Obsoleted)
- return NULL;
+ return nullptr;
// Only create a new attribute if !Override, but we want to do
// the checking.
@@ -2324,7 +1832,7 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
Obsoleted, IsUnavailable, Message,
AttrSpellingListIndex);
}
- return NULL;
+ return nullptr;
}
static void handleAvailabilityAttr(Sema &S, Decl *D,
@@ -2373,7 +1881,7 @@ static T *mergeVisibilityAttr(Sema &S, Decl *D, SourceRange range,
if (existingAttr) {
typename T::VisibilityType existingValue = existingAttr->getVisibility();
if (existingValue == value)
- return NULL;
+ return nullptr;
S.Diag(existingAttr->getLocation(), diag::err_mismatched_visibility);
S.Diag(range.getBegin(), diag::note_previous_attribute);
D->dropAttr<T>();
@@ -2450,13 +1958,7 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr,
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)
- << ExpectedMethod;
- return;
- }
-
+ ObjCMethodDecl *method = cast<ObjCMethodDecl>(decl);
if (!Attr.isArgIdent(0)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
<< Attr.getName() << 1 << AANT_ArgumentIdentifier;
@@ -2471,30 +1973,17 @@ static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl,
return;
}
- if (F == ObjCMethodFamilyAttr::OMF_init &&
- !method->getResultType()->isObjCObjectPointerType()) {
+ if (F == ObjCMethodFamilyAttr::OMF_init &&
+ !method->getReturnType()->isObjCObjectPointerType()) {
S.Diag(method->getLocation(), diag::err_init_method_bad_return_type)
- << method->getResultType();
+ << method->getReturnType();
// Ignore the attribute.
return;
}
method->addAttr(new (S.Context) ObjCMethodFamilyAttr(Attr.getRange(),
- S.Context, F));
-}
-
-static void handleObjCExceptionAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- ObjCInterfaceDecl *OCI = dyn_cast<ObjCInterfaceDecl>(D);
- if (OCI == 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedObjectiveCInterface;
- return;
- }
-
- D->addAttr(::new (S.Context)
- ObjCExceptionAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ S.Context, F,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2526,18 +2015,6 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
-static void
-handleOverloadableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!isa<FunctionDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_overloadable_not_function);
- return;
- }
-
- D->addAttr(::new (S.Context)
- OverloadableAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!Attr.isArgIdent(0)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
@@ -2561,11 +2038,12 @@ static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) {
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;
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments)
+ << Attr.getName() << 2;
return;
}
- unsigned sentinel = 0;
+ unsigned sentinel = (unsigned)SentinelAttr::DefaultSentinel;
if (Attr.getNumArgs() > 0) {
Expr *E = Attr.getArgAsExpr(0);
llvm::APSInt Idx(32);
@@ -2586,7 +2064,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
sentinel = Idx.getZExtValue();
}
- unsigned nullPos = 0;
+ unsigned nullPos = (unsigned)SentinelAttr::DefaultNullPos;
if (Attr.getNumArgs() > 1) {
Expr *E = Attr.getArgAsExpr(1);
llvm::APSInt Idx(32);
@@ -2632,7 +2110,8 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
} 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()
+ ? D->getFunctionType()
: Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
if (!cast<FunctionProtoType>(FT)->isVariadic()) {
int m = Ty->isFunctionPointerType() ? 0 : 1;
@@ -2654,27 +2133,15 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
-static void handleWarnUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (RecordDecl *RD = dyn_cast<RecordDecl>(D))
- RD->addAttr(::new (S.Context) WarnUnusedAttr(Attr.getRange(), S.Context));
- else
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
-}
-
static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!isFunction(D) && !isa<ObjCMethodDecl>(D) && !isa<CXXRecordDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionMethodOrClass;
- return;
- }
-
- if (isFunction(D) && getFunctionType(D)->getResultType()->isVoidType()) {
+ if (D->getFunctionType() &&
+ D->getFunctionType()->getReturnType()->isVoidType()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method)
<< Attr.getName() << 0;
return;
}
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
- if (MD->getResultType()->isVoidType()) {
+ if (MD->getReturnType()->isVoidType()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method)
<< Attr.getName() << 1;
return;
@@ -2685,24 +2152,6 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr)
Attr.getAttributeSpellingListIndex()));
}
-static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D)) {
- if (isa<CXXRecordDecl>(D)) {
- D->addAttr(::new (S.Context) WeakAttr(Attr.getRange(), S.Context));
- return;
- }
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedVariableOrFunction;
- return;
- }
-
- NamedDecl *nd = cast<NamedDecl>(D);
-
- nd->addAttr(::new (S.Context)
- WeakAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// weak_import only applies to variable & function declarations.
bool isDef = false;
@@ -2727,66 +2176,40 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
// Handles reqd_work_group_size and work_group_size_hint.
+template <typename WorkGroupAttr>
static void handleWorkGroupSize(Sema &S, Decl *D,
const AttributeList &Attr) {
- unsigned WGSize[3];
+ uint32_t WGSize[3];
for (unsigned i = 0; i < 3; ++i) {
- Expr *E = Attr.getArgAsExpr(i);
- llvm::APSInt ArgNum(32);
- if (E->isTypeDependent() || E->isValueDependent() ||
- !E->isIntegerConstantExpr(ArgNum, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
- << Attr.getName() << AANT_ArgumentIntegerConstant
- << E->getSourceRange();
+ const Expr *E = Attr.getArgAsExpr(i);
+ if (!checkUInt32Argument(S, Attr, E, WGSize[i], i))
+ return;
+ if (WGSize[i] == 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_is_zero)
+ << Attr.getName() << E->getSourceRange();
return;
}
- WGSize[i] = (unsigned) ArgNum.getZExtValue();
- }
-
- if (Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize
- && D->hasAttr<ReqdWorkGroupSizeAttr>()) {
- ReqdWorkGroupSizeAttr *A = D->getAttr<ReqdWorkGroupSizeAttr>();
- if (!(A->getXDim() == WGSize[0] &&
- A->getYDim() == WGSize[1] &&
- A->getZDim() == WGSize[2])) {
- S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) <<
- Attr.getName();
- }
}
- if (Attr.getKind() == AttributeList::AT_WorkGroupSizeHint
- && D->hasAttr<WorkGroupSizeHintAttr>()) {
- WorkGroupSizeHintAttr *A = D->getAttr<WorkGroupSizeHintAttr>();
- if (!(A->getXDim() == WGSize[0] &&
- A->getYDim() == WGSize[1] &&
- A->getZDim() == WGSize[2])) {
- S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) <<
- Attr.getName();
- }
- }
+ WorkGroupAttr *Existing = D->getAttr<WorkGroupAttr>();
+ if (Existing && !(Existing->getXDim() == WGSize[0] &&
+ Existing->getYDim() == WGSize[1] &&
+ Existing->getZDim() == WGSize[2]))
+ S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName();
- if (Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize)
- D->addAttr(::new (S.Context)
- ReqdWorkGroupSizeAttr(Attr.getRange(), S.Context,
- WGSize[0], WGSize[1], WGSize[2],
- Attr.getAttributeSpellingListIndex()));
- else
- D->addAttr(::new (S.Context)
- WorkGroupSizeHintAttr(Attr.getRange(), S.Context,
- WGSize[0], WGSize[1], WGSize[2],
+ D->addAttr(::new (S.Context) WorkGroupAttr(Attr.getRange(), S.Context,
+ WGSize[0], WGSize[1], WGSize[2],
Attr.getAttributeSpellingListIndex()));
}
static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) {
- assert(Attr.getKind() == AttributeList::AT_VecTypeHint);
-
if (!Attr.hasParsedType()) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
<< Attr.getName() << 1;
return;
}
- TypeSourceInfo *ParmTSI = 0;
+ TypeSourceInfo *ParmTSI = nullptr;
QualType ParmType = S.GetTypeFromParser(Attr.getTypeArg(), &ParmTSI);
assert(ParmTSI && "no type source info for attribute argument");
@@ -2798,9 +2221,7 @@ static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- if (Attr.getKind() == AttributeList::AT_VecTypeHint &&
- D->hasAttr<VecTypeHintAttr>()) {
- VecTypeHintAttr *A = D->getAttr<VecTypeHintAttr>();
+ if (VecTypeHintAttr *A = D->getAttr<VecTypeHintAttr>()) {
if (!S.Context.hasSameType(A->getTypeHint(), ParmType)) {
S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName();
return;
@@ -2808,7 +2229,8 @@ static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) {
}
D->addAttr(::new (S.Context) VecTypeHintAttr(Attr.getLoc(), S.Context,
- ParmTSI));
+ ParmTSI,
+ Attr.getAttributeSpellingListIndex()));
}
SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
@@ -2816,10 +2238,10 @@ SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
unsigned AttrSpellingListIndex) {
if (SectionAttr *ExistingAttr = D->getAttr<SectionAttr>()) {
if (ExistingAttr->getName() == Name)
- return NULL;
+ return nullptr;
Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section);
Diag(Range.getBegin(), diag::note_previous_attribute);
- return NULL;
+ return nullptr;
}
return ::new (Context) SectionAttr(Range, Context, Name,
AttrSpellingListIndex);
@@ -2841,12 +2263,6 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- // This attribute cannot be applied to local variables.
- if (isa<VarDecl>(D) && cast<VarDecl>(D)->hasLocalStorage()) {
- S.Diag(LiteralLoc, diag::err_attribute_section_local_variable);
- return;
- }
-
unsigned Index = Attr.getAttributeSpellingListIndex();
SectionAttr *NewAttr = S.mergeSectionAttr(D, Attr.getRange(), Str, Index);
if (NewAttr)
@@ -2854,44 +2270,16 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
-static void handleNothrowAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (NoThrowAttr *Existing = D->getAttr<NoThrowAttr>()) {
- if (Existing->getLocation().isInvalid())
- Existing->setRange(Attr.getRange());
- } else {
- D->addAttr(::new (S.Context)
- NoThrowAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
- }
-}
-
-static void handleConstAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (ConstAttr *Existing = D->getAttr<ConstAttr>()) {
- if (Existing->getLocation().isInvalid())
- Existing->setRange(Attr.getRange());
- } else {
- D->addAttr(::new (S.Context)
- ConstAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex() ));
- }
-}
-
-static void handlePureAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- D->addAttr(::new (S.Context)
- PureAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- VarDecl *VD = dyn_cast<VarDecl>(D);
- if (!VD || !VD->hasLocalStorage()) {
+ VarDecl *VD = cast<VarDecl>(D);
+ if (!VD->hasLocalStorage()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
return;
}
Expr *E = Attr.getArgAsExpr(0);
SourceLocation Loc = E->getExprLoc();
- FunctionDecl *FD = 0;
+ FunctionDecl *FD = nullptr;
DeclarationNameInfo NI;
// gcc only allows for simple identifiers. Since we support more than gcc, we
@@ -2948,20 +2336,13 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
/// Handle __attribute__((format_arg((idx)))) attribute based on
/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunction;
- return;
- }
-
Expr *IdxExpr = Attr.getArgAsExpr(0);
- uint64_t ArgIdx;
- if (!checkFunctionOrMethodArgumentIndex(S, D, Attr.getName()->getName(),
- Attr.getLoc(), 1, IdxExpr, ArgIdx))
+ uint64_t Idx;
+ if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 1, IdxExpr, Idx))
return;
// make sure the format string is really a string
- QualType Ty = getFunctionOrMethodArgType(D, ArgIdx);
+ QualType Ty = getFunctionOrMethodParamType(D, Idx);
bool not_nsstring_type = !isNSStringType(Ty, S.Context);
if (not_nsstring_type &&
@@ -2986,7 +2367,7 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- // We cannot use the ArgIdx returned from checkFunctionOrMethodArgumentIndex
+ // We cannot use the Idx returned from checkFunctionOrMethodParameterIndex
// because that has corrected for the implicit this parameter, and is zero-
// based. The attribute expects what the user wrote explicitly.
llvm::APSInt Val;
@@ -3033,12 +2414,12 @@ static void handleInitPriorityAttr(Sema &S, Decl *D,
return;
}
- if (!isa<VarDecl>(D) || S.getCurFunctionOrMethodDecl()) {
+ if (S.getCurFunctionOrMethodDecl()) {
S.Diag(Attr.getLoc(), diag::err_init_priority_object_attr);
Attr.setInvalid();
return;
}
- QualType T = dyn_cast<VarDecl>(D)->getType();
+ QualType T = cast<VarDecl>(D)->getType();
if (S.Context.getAsArrayType(T))
T = S.Context.getBaseElementType(T);
if (!T->getAs<RecordType>()) {
@@ -3046,22 +2427,17 @@ static void handleInitPriorityAttr(Sema &S, Decl *D,
Attr.setInvalid();
return;
}
-
- Expr *priorityExpr = Attr.getArgAsExpr(0);
-
- llvm::APSInt priority(32);
- if (priorityExpr->isTypeDependent() || priorityExpr->isValueDependent() ||
- !priorityExpr->isIntegerConstantExpr(priority, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
- << Attr.getName() << AANT_ArgumentIntegerConstant
- << priorityExpr->getSourceRange();
+
+ Expr *E = Attr.getArgAsExpr(0);
+ uint32_t prioritynum;
+ if (!checkUInt32Argument(S, Attr, E, prioritynum)) {
Attr.setInvalid();
return;
}
- unsigned prioritynum = priority.getZExtValue();
+
if (prioritynum < 101 || prioritynum > 65535) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_outof_range)
- << priorityExpr->getSourceRange();
+ << E->getSourceRange();
Attr.setInvalid();
return;
}
@@ -3075,19 +2451,15 @@ FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range,
int FirstArg,
unsigned AttrSpellingListIndex) {
// 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() == FormatIdx &&
- f->getFirstArg() == FirstArg) {
+ for (auto *F : D->specific_attrs<FormatAttr>()) {
+ if (F->getType() == Format &&
+ F->getFormatIdx() == FormatIdx &&
+ F->getFirstArg() == FirstArg) {
// If we don't have a valid location for this attribute, adopt the
// location.
- if (f->getLocation().isInvalid())
- f->setRange(Range);
- return NULL;
+ if (F->getLocation().isInvalid())
+ F->setRange(Range);
+ return nullptr;
}
}
@@ -3104,17 +2476,10 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- if (!isFunctionOrMethodOrBlock(D) || !hasFunctionProto(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunction;
- return;
- }
-
// In C++ the implicit 'this' function parameter also counts, and they are
// counted from one.
bool HasImplicitThisParam = isInstanceMethod(D);
- unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
- unsigned FirstIdx = 1;
+ unsigned NumArgs = getFunctionOrMethodNumParams(D) + HasImplicitThisParam;
IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident;
StringRef Format = II->getName();
@@ -3134,29 +2499,24 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (Kind == InvalidFormat) {
S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
- << "format" << II->getName();
+ << Attr.getName() << II->getName();
return;
}
// checks for the 2nd argument
Expr *IdxExpr = Attr.getArgAsExpr(1);
- llvm::APSInt Idx(32);
- if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
- !IdxExpr->isIntegerConstantExpr(Idx, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
- << Attr.getName() << 2 << AANT_ArgumentIntegerConstant
- << IdxExpr->getSourceRange();
+ uint32_t Idx;
+ if (!checkUInt32Argument(S, Attr, IdxExpr, Idx, 2))
return;
- }
- if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) {
+ if (Idx < 1 || Idx > NumArgs) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << "format" << 2 << IdxExpr->getSourceRange();
+ << Attr.getName() << 2 << IdxExpr->getSourceRange();
return;
}
// FIXME: Do we need to bounds check?
- unsigned ArgIdx = Idx.getZExtValue() - 1;
+ unsigned ArgIdx = Idx - 1;
if (HasImplicitThisParam) {
if (ArgIdx == 0) {
@@ -3169,7 +2529,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
// make sure the format string is really a string
- QualType Ty = getFunctionOrMethodArgType(D, ArgIdx);
+ QualType Ty = getFunctionOrMethodParamType(D, ArgIdx);
if (Kind == CFStringFormat) {
if (!isCFStringType(Ty, S.Context)) {
@@ -3196,14 +2556,9 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the 3rd argument
Expr *FirstArgExpr = Attr.getArgAsExpr(2);
- llvm::APSInt FirstArg(32);
- if (FirstArgExpr->isTypeDependent() || FirstArgExpr->isValueDependent() ||
- !FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
- << Attr.getName() << 3 << AANT_ArgumentIntegerConstant
- << FirstArgExpr->getSourceRange();
+ uint32_t FirstArg;
+ if (!checkUInt32Argument(S, Attr, FirstArgExpr, FirstArg, 3))
return;
- }
// check if the function is variadic if the 3rd argument non-zero
if (FirstArg != 0) {
@@ -3226,13 +2581,12 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// if 0 it disables parameter checking (to use with e.g. va_list)
} else if (FirstArg != 0 && FirstArg != NumArgs) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << "format" << 3 << FirstArgExpr->getSourceRange();
+ << Attr.getName() << 3 << FirstArgExpr->getSourceRange();
return;
}
FormatAttr *NewAttr = S.mergeFormatAttr(D, Attr.getRange(), II,
- Idx.getZExtValue(),
- FirstArg.getZExtValue(),
+ Idx, FirstArg,
Attr.getAttributeSpellingListIndex());
if (NewAttr)
D->addAttr(NewAttr);
@@ -3241,7 +2595,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static void handleTransparentUnionAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
// Try to find the underlying union declaration.
- RecordDecl *RD = 0;
+ RecordDecl *RD = nullptr;
TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
if (TD && TD->getUnderlyingType()->isUnionType())
RD = TD->getUnderlyingType()->getAsUnionType()->getDecl();
@@ -3280,8 +2634,13 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D,
uint64_t FirstAlign = S.Context.getTypeAlign(FirstType);
for (; Field != FieldEnd; ++Field) {
QualType FieldType = Field->getType();
+ // FIXME: this isn't fully correct; we also need to test whether the
+ // members of the union would all have the same calling convention as the
+ // first member of the union. Checking just the size and alignment isn't
+ // sufficient (consider structs passed on the stack instead of in registers
+ // as an example).
if (S.Context.getTypeSize(FieldType) != FirstSize ||
- S.Context.getTypeAlign(FieldType) != FirstAlign) {
+ S.Context.getTypeAlign(FieldType) > FirstAlign) {
// Warn if we drop the attribute.
bool isSize = S.Context.getTypeSize(FieldType) != FirstSize;
unsigned FieldBits = isSize? S.Context.getTypeSize(FieldType)
@@ -3310,10 +2669,8 @@ static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
// Don't duplicate annotations that are already set.
- for (specific_attr_iterator<AnnotateAttr>
- i = D->specific_attr_begin<AnnotateAttr>(),
- e = D->specific_attr_end<AnnotateAttr>(); i != e; ++i) {
- if ((*i)->getAnnotation() == Str)
+ for (const auto *I : D->specific_attrs<AnnotateAttr>()) {
+ if (I->getAnnotation() == Str)
return;
}
@@ -3332,7 +2689,7 @@ static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (Attr.getNumArgs() == 0) {
D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context,
- true, 0, Attr.getAttributeSpellingListIndex()));
+ true, nullptr, Attr.getAttributeSpellingListIndex()));
return;
}
@@ -3380,15 +2737,14 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
if (FD->isBitField())
DiagKind = 3;
} else if (!isa<TagDecl>(D)) {
- Diag(AttrLoc, diag::err_attribute_wrong_decl_type)
- << (TmpAttr.isC11() ? "'_Alignas'" : "'alignas'")
+ Diag(AttrLoc, diag::err_attribute_wrong_decl_type) << &TmpAttr
<< (TmpAttr.isC11() ? ExpectedVariableOrField
: ExpectedVariableFieldOrTag);
return;
}
if (DiagKind != -1) {
Diag(AttrLoc, diag::err_alignas_attribute_wrong_decl_type)
- << TmpAttr.isC11() << DiagKind;
+ << &TmpAttr << DiagKind;
return;
}
}
@@ -3422,18 +2778,16 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
return;
}
- if (TmpAttr.isDeclspec()) {
- // We've already verified it's a power of 2, now let's make sure it's
- // 8192 or less.
- if (Alignment.getZExtValue() > 8192) {
- Diag(AttrLoc, diag::err_attribute_aligned_greater_than_8192)
- << E->getSourceRange();
- return;
- }
+ // Alignment calculations can wrap around if it's greater than 2**28.
+ unsigned MaxValidAlignment = TmpAttr.isDeclspec() ? 8192 : 268435456;
+ if (Alignment.getZExtValue() > MaxValidAlignment) {
+ Diag(AttrLoc, diag::err_attribute_aligned_too_great) << MaxValidAlignment
+ << E->getSourceRange();
+ return;
}
AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, true,
- ICE.take(), SpellingListIndex);
+ ICE.get(), SpellingListIndex);
AA->setPackExpansion(IsPackExpansion);
D->addAttr(AA);
}
@@ -3463,15 +2817,13 @@ void Sema::CheckAlignasUnderalignment(Decl *D) {
// The combined effect of all alignment attributes in a declaration shall
// not specify an alignment that is less strict than the alignment that
// would otherwise be required for the entity being declared.
- AlignedAttr *AlignasAttr = 0;
+ AlignedAttr *AlignasAttr = nullptr;
unsigned Align = 0;
- for (specific_attr_iterator<AlignedAttr>
- I = D->specific_attr_begin<AlignedAttr>(),
- E = D->specific_attr_end<AlignedAttr>(); I != E; ++I) {
+ for (auto *I : D->specific_attrs<AlignedAttr>()) {
if (I->isAlignmentDependent())
return;
if (I->isAlignas())
- AlignasAttr = *I;
+ AlignasAttr = I;
Align = std::max(Align, I->getAlignment(Context));
}
@@ -3484,6 +2836,35 @@ void Sema::CheckAlignasUnderalignment(Decl *D) {
}
}
+bool Sema::checkMSInheritanceAttrOnDefinition(
+ CXXRecordDecl *RD, SourceRange Range, bool BestCase,
+ MSInheritanceAttr::Spelling SemanticSpelling) {
+ assert(RD->hasDefinition() && "RD has no definition!");
+
+ // We may not have seen base specifiers or any virtual methods yet. We will
+ // have to wait until the record is defined to catch any mismatches.
+ if (!RD->getDefinition()->isCompleteDefinition())
+ return false;
+
+ // The unspecified model never matches what a definition could need.
+ if (SemanticSpelling == MSInheritanceAttr::Keyword_unspecified_inheritance)
+ return false;
+
+ if (BestCase) {
+ if (RD->calculateInheritanceModel() == SemanticSpelling)
+ return false;
+ } else {
+ if (RD->calculateInheritanceModel() <= SemanticSpelling)
+ return false;
+ }
+
+ Diag(Range.getBegin(), diag::err_mismatched_ms_inheritance)
+ << 0 /*definition*/;
+ Diag(RD->getDefinition()->getLocation(), diag::note_defined_here)
+ << RD->getNameAsString();
+ return true;
+}
+
/// handleModeAttr - This attribute modifies the width of a decl with primitive
/// type.
///
@@ -3553,7 +2934,7 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
OldTy = VD->getType();
else {
S.Diag(D->getLocation(), diag::err_attr_wrong_decl)
- << "mode" << Attr.getRange();
+ << Attr.getName() << Attr.getRange();
return;
}
@@ -3575,7 +2956,7 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// FIXME: Make sure floating-point mappings are accurate
// FIXME: Support XF and TF types
if (!DestWidth) {
- S.Diag(Attr.getLoc(), diag::err_unknown_machine_mode) << Name;
+ S.Diag(Attr.getLoc(), diag::err_machine_mode) << 0 /*Unknown*/ << Name;
return;
}
@@ -3588,7 +2969,7 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
NewTy = S.Context.getRealTypeForBitwidth(DestWidth);
if (NewTy.isNull()) {
- S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name;
+ S.Diag(Attr.getLoc(), diag::err_machine_mode) << 1 /*Unsupported*/ << Name;
return;
}
@@ -3625,141 +3006,44 @@ static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
-static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!isa<FunctionDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunction;
+static void handleAlwaysInlineAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (checkAttrMutualExclusion<OptimizeNoneAttr>(S, D, Attr))
return;
- }
D->addAttr(::new (S.Context)
- NoInlineAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ AlwaysInlineAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
-static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- if (!isa<FunctionDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunction;
+static void handleOptimizeNoneAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (checkAttrMutualExclusion<AlwaysInlineAttr>(S, D, Attr))
return;
- }
D->addAttr(::new (S.Context)
- NoInstrumentFunctionAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
-static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (S.LangOpts.CUDA) {
- 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.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
- } else {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "constant";
- }
-}
-
-static void handleDeviceAttr(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)
- << Attr.getName() << 0;
- return;
- }
-
- 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.getRange(), S.Context,
+ OptimizeNoneAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
- } else {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "device";
- }
}
static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (S.LangOpts.CUDA) {
- if (!isa<FunctionDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunction;
- return;
- }
-
- FunctionDecl *FD = cast<FunctionDecl>(D);
- if (!FD->getResultType()->isVoidType()) {
- TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens();
- if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
- S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return)
- << FD->getType()
- << FixItHint::CreateReplacement(FTL.getResultLoc().getSourceRange(),
- "void");
- } else {
- S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return)
- << FD->getType();
- }
- return;
- }
-
- D->addAttr(::new (S.Context)
- CUDAGlobalAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
- } else {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "global";
+ FunctionDecl *FD = cast<FunctionDecl>(D);
+ if (!FD->getReturnType()->isVoidType()) {
+ SourceRange RTRange = FD->getReturnTypeSourceRange();
+ S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return)
+ << FD->getType()
+ << (RTRange.isValid() ? FixItHint::CreateReplacement(RTRange, "void")
+ : FixItHint());
+ return;
}
-}
-static void handleHostAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (S.LangOpts.CUDA) {
- 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.getRange(), S.Context,
+ D->addAttr(::new (S.Context)
+ CUDAGlobalAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
- } else {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "host";
- }
-}
-
-static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (S.LangOpts.CUDA) {
- 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.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
- } else {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "shared";
- }
}
static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- FunctionDecl *Fn = dyn_cast<FunctionDecl>(D);
- if (Fn == 0) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunction;
- return;
- }
-
+ FunctionDecl *Fn = cast<FunctionDecl>(D);
if (!Fn->isInlineSpecified()) {
S.Diag(Attr.getLoc(), diag::warn_gnu_inline_attribute_requires_inline);
return;
@@ -3856,25 +3140,6 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
}
-static void handleOpenCLKernelAttr(Sema &S, Decl *D, const AttributeList &Attr){
- D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getRange(), S.Context));
-}
-
-static void handleOpenCLImageAccessAttr(Sema &S, Decl *D, const AttributeList &Attr){
- Expr *E = Attr.getArgAsExpr(0);
- llvm::APSInt ArgNum(32);
- if (E->isTypeDependent() || E->isValueDependent() ||
- !E->isIntegerConstantExpr(ArgNum, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
- << Attr.getName() << AANT_ArgumentIntegerConstant
- << E->getSourceRange();
- return;
- }
-
- D->addAttr(::new (S.Context) OpenCLImageAccessAttr(
- Attr.getRange(), S.Context, ArgNum.getZExtValue()));
-}
-
bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
const FunctionDecl *FD) {
if (attr.isInvalid())
@@ -3886,8 +3151,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
return true;
}
- // TODO: diagnose uses of these conventions on the wrong target. Or, better
- // move to TargetAttributesSema one day.
+ // TODO: diagnose uses of these conventions on the wrong target.
switch (attr.getKind()) {
case AttributeList::AT_CDecl: CC = CC_C; break;
case AttributeList::AT_FastCall: CC = CC_X86FastCall; break;
@@ -3940,24 +3204,6 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
return false;
}
-static void handleRegparmAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (hasDeclarator(D)) return;
-
- unsigned numParams;
- if (S.CheckRegparmAttr(Attr, numParams))
- return;
-
- 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.getRange(), S.Context, numParams,
- Attr.getAttributeSpellingListIndex()));
-}
-
/// 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) {
@@ -3969,13 +3215,9 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) {
return true;
}
+ uint32_t NP;
Expr *NumParamsExpr = Attr.getArgAsExpr(0);
- llvm::APSInt NumParams(32);
- if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() ||
- !NumParamsExpr->isIntegerConstantExpr(NumParams, Context)) {
- Diag(Attr.getLoc(), diag::err_attribute_argument_type)
- << Attr.getName() << AANT_ArgumentIntegerConstant
- << NumParamsExpr->getSourceRange();
+ if (!checkUInt32Argument(*this, Attr, NumParamsExpr, NP)) {
Attr.setInvalid();
return true;
}
@@ -3987,7 +3229,7 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) {
return true;
}
- numParams = NumParams.getZExtValue();
+ numParams = NP;
if (numParams > Context.getTargetInfo().getRegParmMax()) {
Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number)
<< Context.getTargetInfo().getRegParmMax() << NumParamsExpr->getSourceRange();
@@ -3998,53 +3240,28 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) {
return false;
}
-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) {
- // FIXME: 0 is not okay.
- S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 2;
- return;
- }
-
- if (!isFunctionOrMethod(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
- return;
- }
-
- Expr *MaxThreadsExpr = Attr.getArgAsExpr(0);
- llvm::APSInt MaxThreads(32);
- if (MaxThreadsExpr->isTypeDependent() ||
- MaxThreadsExpr->isValueDependent() ||
- !MaxThreadsExpr->isIntegerConstantExpr(MaxThreads, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
- << Attr.getName() << 1 << AANT_ArgumentIntegerConstant
- << MaxThreadsExpr->getSourceRange();
- return;
- }
+static void handleLaunchBoundsAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() != 1 && Attr.getNumArgs() != 2) {
+ // FIXME: 0 is not okay.
+ S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments)
+ << Attr.getName() << 2;
+ return;
+ }
- llvm::APSInt MinBlocks(32);
- if (Attr.getNumArgs() > 1) {
- Expr *MinBlocksExpr = Attr.getArgAsExpr(1);
- if (MinBlocksExpr->isTypeDependent() ||
- MinBlocksExpr->isValueDependent() ||
- !MinBlocksExpr->isIntegerConstantExpr(MinBlocks, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type)
- << Attr.getName() << 2 << AANT_ArgumentIntegerConstant
- << MinBlocksExpr->getSourceRange();
- return;
- }
- }
+ uint32_t MaxThreads, MinBlocks = 0;
+ if (!checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), MaxThreads, 1))
+ return;
+ if (Attr.getNumArgs() > 1 && !checkUInt32Argument(S, Attr,
+ Attr.getArgAsExpr(1),
+ MinBlocks, 2))
+ return;
- D->addAttr(::new (S.Context)
- CUDALaunchBoundsAttr(Attr.getRange(), S.Context,
- MaxThreads.getZExtValue(),
- MinBlocks.getZExtValue(),
- Attr.getAttributeSpellingListIndex()));
- } else {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "launch_bounds";
- }
+ D->addAttr(::new (S.Context)
+ CUDALaunchBoundsAttr(Attr.getRange(), S.Context,
+ MaxThreads, MinBlocks,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
@@ -4058,7 +3275,6 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
if (!checkAttributeNumArgs(S, Attr, 3))
return;
- StringRef AttrName = Attr.getName()->getName();
IdentifierInfo *ArgumentKind = Attr.getArgAsIdent(0)->Ident;
if (!isFunctionOrMethod(D) || !hasFunctionProto(D)) {
@@ -4068,21 +3284,19 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
}
uint64_t ArgumentIdx;
- if (!checkFunctionOrMethodArgumentIndex(S, D, AttrName,
- Attr.getLoc(), 2,
- Attr.getArgAsExpr(1), ArgumentIdx))
+ if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 2, Attr.getArgAsExpr(1),
+ ArgumentIdx))
return;
uint64_t TypeTagIdx;
- if (!checkFunctionOrMethodArgumentIndex(S, D, AttrName,
- Attr.getLoc(), 3,
- Attr.getArgAsExpr(2), TypeTagIdx))
+ if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 3, Attr.getArgAsExpr(2),
+ TypeTagIdx))
return;
- bool IsPointer = (AttrName == "pointer_with_type_tag");
+ bool IsPointer = (Attr.getName()->getName() == "pointer_with_type_tag");
if (IsPointer) {
// Ensure that buffer has a pointer type.
- QualType BufferTy = getFunctionOrMethodArgType(D, ArgumentIdx);
+ QualType BufferTy = getFunctionOrMethodParamType(D, ArgumentIdx);
if (!BufferTy->isPointerType()) {
S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only)
<< Attr.getName();
@@ -4106,8 +3320,14 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
if (!checkAttributeNumArgs(S, Attr, 1))
return;
+ if (!isa<VarDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedVariable;
+ return;
+ }
+
IdentifierInfo *PointerKind = Attr.getArgAsIdent(0)->Ident;
- TypeSourceInfo *MatchingCTypeLoc = 0;
+ TypeSourceInfo *MatchingCTypeLoc = nullptr;
S.GetTypeFromParser(Attr.getMatchingCType(), &MatchingCTypeLoc);
assert(MatchingCTypeLoc && "no type source info for attribute argument");
@@ -4123,6 +3343,11 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
// Checker-specific attribute handlers.
//===----------------------------------------------------------------------===//
+static bool isValidSubjectOfNSReturnsRetainedAttribute(QualType type) {
+ return type->isDependentType() ||
+ type->isObjCRetainableType();
+}
+
static bool isValidSubjectOfNSAttribute(Sema &S, QualType type) {
return type->isDependentType() ||
type->isObjCObjectPointerType() ||
@@ -4135,14 +3360,9 @@ static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) {
}
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)
- << Attr.getRange() << Attr.getName() << ExpectedParameter;
- return;
- }
-
+ ParmVarDecl *param = cast<ParmVarDecl>(D);
bool typeOK, cf;
+
if (Attr.getKind() == AttributeList::AT_NSConsumed) {
typeOK = isValidSubjectOfNSAttribute(S, param->getType());
cf = false;
@@ -4167,33 +3387,20 @@ static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
-static void handleNSConsumesSelfAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- if (!isa<ObjCMethodDecl>(D)) {
- S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type)
- << Attr.getRange() << Attr.getName() << ExpectedMethod;
- return;
- }
-
- D->addAttr(::new (S.Context)
- NSConsumesSelfAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
QualType returnType;
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
- returnType = MD->getResultType();
+ returnType = MD->getReturnType();
else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) &&
(Attr.getKind() == AttributeList::AT_NSReturnsRetained))
return; // ignore: was handled as a type attribute
else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
returnType = PD->getType();
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- returnType = FD->getResultType();
+ returnType = FD->getReturnType();
else {
S.Diag(D->getLocStart(), diag::warn_attribute_wrong_decl_type)
<< Attr.getRange() << Attr.getName()
@@ -4205,8 +3412,12 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
bool cf;
switch (Attr.getKind()) {
default: llvm_unreachable("invalid ownership attribute");
- case AttributeList::AT_NSReturnsAutoreleased:
case AttributeList::AT_NSReturnsRetained:
+ typeOK = isValidSubjectOfNSReturnsRetainedAttribute(returnType);
+ cf = false;
+ break;
+
+ case AttributeList::AT_NSReturnsAutoreleased:
case AttributeList::AT_NSReturnsNotRetained:
typeOK = isValidSubjectOfNSAttribute(S, returnType);
cf = false;
@@ -4263,27 +3474,17 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
SourceLocation loc = attr.getLoc();
QualType resultType;
-
- ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(D);
-
- if (!method) {
- ObjCPropertyDecl *property = dyn_cast<ObjCPropertyDecl>(D);
- if (!property) {
- S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
- << SourceRange(loc, loc) << attr.getName() << ExpectedMethodOrProperty;
- return;
- }
- resultType = property->getType();
- }
+ if (isa<ObjCMethodDecl>(D))
+ resultType = cast<ObjCMethodDecl>(D)->getReturnType();
else
- // Check that the method returns a normal pointer.
- resultType = method->getResultType();
+ resultType = cast<ObjCPropertyDecl>(D)->getType();
if (!resultType->isReferenceType() &&
(!resultType->isPointerType() || resultType->isObjCRetainableType())) {
S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
<< SourceRange(loc)
- << attr.getName() << (method ? EP_ObjCMethod : EP_ObjCProperty)
+ << attr.getName()
+ << (isa<ObjCMethodDecl>(D) ? EP_ObjCMethod : EP_ObjCProperty)
<< /*non-retainable pointer*/ 2;
// Drop the attribute.
@@ -4297,14 +3498,8 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
const AttributeList &attr) {
- SourceLocation loc = attr.getLoc();
- ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(D);
+ ObjCMethodDecl *method = cast<ObjCMethodDecl>(D);
- if (!method) {
- S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
- << SourceRange(loc, loc) << attr.getName() << ExpectedMethod;
- return;
- }
DeclContext *DC = method->getDeclContext();
if (const ObjCProtocolDecl *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) {
S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol)
@@ -4323,97 +3518,94 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
attr.getAttributeSpellingListIndex()));
}
-/// Handle cf_audited_transfer and cf_unknown_transfer.
-static void handleCFTransferAttr(Sema &S, Decl *D, const AttributeList &A) {
- if (!isa<FunctionDecl>(D)) {
- S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
- << A.getRange() << A.getName() << ExpectedFunction;
+static void handleCFAuditedTransferAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (checkAttrMutualExclusion<CFUnknownTransferAttr>(S, D, Attr))
return;
- }
- bool IsAudited = (A.getKind() == AttributeList::AT_CFAuditedTransfer);
+ D->addAttr(::new (S.Context)
+ CFAuditedTransferAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
+}
- // Check whether there's a conflicting attribute already present.
- Attr *Existing;
- if (IsAudited) {
- Existing = D->getAttr<CFUnknownTransferAttr>();
- } else {
- Existing = D->getAttr<CFAuditedTransferAttr>();
- }
- if (Existing) {
- S.Diag(D->getLocStart(), diag::err_attributes_are_not_compatible)
- << A.getName()
- << (IsAudited ? "cf_unknown_transfer" : "cf_audited_transfer")
- << A.getRange() << Existing->getRange();
+static void handleCFUnknownTransferAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (checkAttrMutualExclusion<CFAuditedTransferAttr>(S, D, Attr))
return;
- }
- // All clear; add the attribute.
- if (IsAudited) {
- D->addAttr(::new (S.Context)
- CFAuditedTransferAttr(A.getRange(), S.Context,
- A.getAttributeSpellingListIndex()));
- } else {
- D->addAttr(::new (S.Context)
- CFUnknownTransferAttr(A.getRange(), S.Context,
- A.getAttributeSpellingListIndex()));
- }
+ D->addAttr(::new (S.Context)
+ CFUnknownTransferAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
-static void handleNSBridgedAttr(Sema &S, Scope *Sc, Decl *D,
+static void handleObjCBridgeAttr(Sema &S, Scope *Sc, Decl *D,
const AttributeList &Attr) {
- RecordDecl *RD = dyn_cast<RecordDecl>(D);
- if (!RD || RD->isUnion()) {
- S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
- << Attr.getRange() << Attr.getName() << ExpectedStruct;
- }
-
- IdentifierLoc *Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : 0;
-
- // In Objective-C, verify that the type names an Objective-C type.
- // We don't want to check this outside of ObjC because people sometimes
- // do crazy C declarations of Objective-C types.
- if (Parm && S.getLangOpts().ObjC1) {
- // Check for an existing type with this name.
- LookupResult R(S, DeclarationName(Parm->Ident), Parm->Loc,
- Sema::LookupOrdinaryName);
- if (S.LookupName(R, Sc)) {
- NamedDecl *Target = R.getFoundDecl();
- if (Target && !isa<ObjCInterfaceDecl>(Target)) {
- S.Diag(D->getLocStart(), diag::err_ns_bridged_not_interface);
- S.Diag(Target->getLocStart(), diag::note_declared_at);
- }
- }
- }
+ IdentifierLoc * Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr;
+ if (!Parm) {
+ S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0;
+ return;
+ }
+
D->addAttr(::new (S.Context)
- NSBridgedAttr(Attr.getRange(), S.Context, Parm ? Parm->Ident : 0,
+ ObjCBridgeAttr(Attr.getRange(), S.Context, Parm->Ident,
Attr.getAttributeSpellingListIndex()));
}
-static void handleObjCBridgeAttr(Sema &S, Scope *Sc, Decl *D,
- const AttributeList &Attr) {
- if (!isa<RecordDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName()
- << (S.getLangOpts().CPlusPlus ? ExpectedStructOrUnionOrClass
- : ExpectedStructOrUnion);
+static void handleObjCBridgeMutableAttr(Sema &S, Scope *Sc, Decl *D,
+ const AttributeList &Attr) {
+ IdentifierLoc * Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr;
+
+ if (!Parm) {
+ S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0;
return;
}
- if (Attr.getNumArgs() != 1) {
- S.Diag(D->getLocStart(), diag::err_objc_bridge_not_id);
+ D->addAttr(::new (S.Context)
+ ObjCBridgeMutableAttr(Attr.getRange(), S.Context, Parm->Ident,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleObjCBridgeRelatedAttr(Sema &S, Scope *Sc, Decl *D,
+ const AttributeList &Attr) {
+ IdentifierInfo *RelatedClass =
+ Attr.isArgIdent(0) ? Attr.getArgAsIdent(0)->Ident : nullptr;
+ if (!RelatedClass) {
+ S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0;
return;
}
- IdentifierLoc *Parm = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : 0;
- if (!Parm) {
- S.Diag(D->getLocStart(), diag::err_objc_bridge_not_id);
+ IdentifierInfo *ClassMethod =
+ Attr.getArgAsIdent(1) ? Attr.getArgAsIdent(1)->Ident : nullptr;
+ IdentifierInfo *InstanceMethod =
+ Attr.getArgAsIdent(2) ? Attr.getArgAsIdent(2)->Ident : nullptr;
+ D->addAttr(::new (S.Context)
+ ObjCBridgeRelatedAttr(Attr.getRange(), S.Context, RelatedClass,
+ ClassMethod, InstanceMethod,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleObjCDesignatedInitializer(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ ObjCInterfaceDecl *IFace;
+ if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(D->getDeclContext()))
+ IFace = CatDecl->getClassInterface();
+ else
+ IFace = cast<ObjCInterfaceDecl>(D->getDeclContext());
+ IFace->setHasDesignatedInitializers();
+ D->addAttr(::new (S.Context)
+ ObjCDesignatedInitializerAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleObjCRuntimeName(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ StringRef MetaDataName;
+ if (!S.checkStringLiteralArgumentAttr(Attr, 0, MetaDataName))
return;
- }
-
D->addAttr(::new (S.Context)
- ObjCBridgeAttr(Attr.getRange(), S.Context, Parm ? Parm->Ident : 0,
- Attr.getAttributeSpellingListIndex()));
+ ObjCRuntimeNameAttr(Attr.getRange(), S.Context,
+ MetaDataName,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleObjCOwnershipAttr(Sema &S, Decl *D,
@@ -4426,12 +3618,6 @@ static void handleObjCOwnershipAttr(Sema &S, Decl *D,
static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (!isa<VarDecl>(D) && !isa<FieldDecl>(D)) {
- S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type)
- << Attr.getRange() << Attr.getName() << ExpectedVariable;
- return;
- }
-
ValueDecl *vd = cast<ValueDecl>(D);
QualType type = vd->getType();
@@ -4475,19 +3661,18 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
// Microsoft specific attribute handlers.
//===----------------------------------------------------------------------===//
-// Check if MS extensions or some other language extensions are enabled. If
-// not, issue a diagnostic that the given attribute is unused.
-static bool checkMicrosoftExt(Sema &S, const AttributeList &Attr,
- bool OtherExtension = false) {
- if (S.LangOpts.MicrosoftExt || OtherExtension)
- return true;
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
- return false;
-}
-
static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!checkMicrosoftExt(S, Attr, S.LangOpts.Borland))
+ if (!S.LangOpts.CPlusPlus) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang)
+ << Attr.getName() << AttributeLangSupport::C;
+ return;
+ }
+
+ if (!isa<CXXRecordDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedClass;
return;
+ }
StringRef StrRef;
SourceLocation LiteralLoc;
@@ -4521,55 +3706,299 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
-static void handleInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!checkMicrosoftExt(S, Attr))
+static void handleMSInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!S.LangOpts.CPlusPlus) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang)
+ << Attr.getName() << AttributeLangSupport::C;
return;
+ }
+ MSInheritanceAttr *IA = S.mergeMSInheritanceAttr(
+ D, Attr.getRange(), /*BestCase=*/true,
+ Attr.getAttributeSpellingListIndex(),
+ (MSInheritanceAttr::Spelling)Attr.getSemanticSpelling());
+ if (IA)
+ D->addAttr(IA);
+}
- AttributeList::Kind Kind = Attr.getKind();
- if (Kind == AttributeList::AT_SingleInheritance)
- D->addAttr(
- ::new (S.Context)
- SingleInheritanceAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
- else if (Kind == AttributeList::AT_MultipleInheritance)
- D->addAttr(
- ::new (S.Context)
- MultipleInheritanceAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
- else if (Kind == AttributeList::AT_VirtualInheritance)
- D->addAttr(
- ::new (S.Context)
- VirtualInheritanceAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+static void handleDeclspecThreadAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ VarDecl *VD = cast<VarDecl>(D);
+ if (!S.Context.getTargetInfo().isTLSSupported()) {
+ S.Diag(Attr.getLoc(), diag::err_thread_unsupported);
+ return;
+ }
+ if (VD->getTSCSpec() != TSCS_unspecified) {
+ S.Diag(Attr.getLoc(), diag::err_declspec_thread_on_thread_variable);
+ return;
+ }
+ if (VD->hasLocalStorage()) {
+ S.Diag(Attr.getLoc(), diag::err_thread_non_global) << "__declspec(thread)";
+ return;
+ }
+ VD->addAttr(::new (S.Context) ThreadAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
}
-static void handlePortabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!checkMicrosoftExt(S, Attr))
+static void handleARMInterruptAttr(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)
+ << Attr.getName() << 1;
+ return;
+ }
+
+ StringRef Str;
+ SourceLocation ArgLoc;
+
+ if (Attr.getNumArgs() == 0)
+ Str = "";
+ else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc))
return;
- AttributeList::Kind Kind = Attr.getKind();
- if (Kind == AttributeList::AT_Win64)
- D->addAttr(
- ::new (S.Context) Win64Attr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ ARMInterruptAttr::InterruptType Kind;
+ if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
+ << Attr.getName() << Str << ArgLoc;
+ return;
+ }
+
+ unsigned Index = Attr.getAttributeSpellingListIndex();
+ D->addAttr(::new (S.Context)
+ ARMInterruptAttr(Attr.getLoc(), S.Context, Kind, Index));
}
-static void handleForceInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!checkMicrosoftExt(S, Attr))
+static void handleMSP430InterruptAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!checkAttributeNumArgs(S, Attr, 1))
+ return;
+
+ if (!Attr.isArgExpr(0)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName()
+ << AANT_ArgumentIntegerConstant;
+ return;
+ }
+
+ // FIXME: Check for decl - it should be void ()(void).
+
+ Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
+ llvm::APSInt NumParams(32);
+ if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
+ << Attr.getName() << AANT_ArgumentIntegerConstant
+ << NumParamsExpr->getSourceRange();
+ return;
+ }
+
+ unsigned Num = NumParams.getLimitedValue(255);
+ if ((Num & 1) || Num > 30) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << Attr.getName() << (int)NumParams.getSExtValue()
+ << NumParamsExpr->getSourceRange();
return;
+ }
+
D->addAttr(::new (S.Context)
- ForceInlineAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ MSP430InterruptAttr(Attr.getLoc(), S.Context, Num,
+ Attr.getAttributeSpellingListIndex()));
+ D->addAttr(UsedAttr::CreateImplicit(S.Context));
}
-static void handleSelectAnyAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!checkMicrosoftExt(S, Attr))
+static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ // Dispatch the interrupt attribute based on the current target.
+ if (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::msp430)
+ handleMSP430InterruptAttr(S, D, Attr);
+ else
+ handleARMInterruptAttr(S, D, Attr);
+}
+
+static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D,
+ const AttributeList& Attr) {
+ // If we try to apply it to a function pointer, don't warn, but don't
+ // do anything, either. It doesn't matter anyway, because there's nothing
+ // special about calling a force_align_arg_pointer function.
+ ValueDecl *VD = dyn_cast<ValueDecl>(D);
+ if (VD && VD->getType()->isFunctionPointerType())
+ return;
+ // Also don't warn on function pointer typedefs.
+ TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
+ if (TD && (TD->getUnderlyingType()->isFunctionPointerType() ||
+ TD->getUnderlyingType()->isFunctionType()))
+ return;
+ // Attribute can only be applied to function types.
+ if (!isa<FunctionDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << /* function */0;
return;
- // Check linkage after possibly merging declaratinos. See
- // checkAttributesAfterMerging().
+ }
+
D->addAttr(::new (S.Context)
- SelectAnyAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ X86ForceAlignArgPointerAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range,
+ unsigned AttrSpellingListIndex) {
+ if (D->hasAttr<DLLExportAttr>()) {
+ Diag(Range.getBegin(), diag::warn_attribute_ignored) << "'dllimport'";
+ return nullptr;
+ }
+
+ if (D->hasAttr<DLLImportAttr>())
+ return nullptr;
+
+ return ::new (Context) DLLImportAttr(Range, Context, AttrSpellingListIndex);
+}
+
+DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range,
+ unsigned AttrSpellingListIndex) {
+ if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) {
+ Diag(Import->getLocation(), diag::warn_attribute_ignored) << Import;
+ D->dropAttr<DLLImportAttr>();
+ }
+
+ if (D->hasAttr<DLLExportAttr>())
+ return nullptr;
+
+ return ::new (Context) DLLExportAttr(Range, Context, AttrSpellingListIndex);
+}
+
+static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) {
+ if (isa<ClassTemplatePartialSpecializationDecl>(D) &&
+ S.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored)
+ << A.getName();
+ return;
+ }
+
+ unsigned Index = A.getAttributeSpellingListIndex();
+ Attr *NewAttr = A.getKind() == AttributeList::AT_DLLExport
+ ? (Attr *)S.mergeDLLExportAttr(D, A.getRange(), Index)
+ : (Attr *)S.mergeDLLImportAttr(D, A.getRange(), Index);
+ if (NewAttr)
+ D->addAttr(NewAttr);
+}
+
+MSInheritanceAttr *
+Sema::mergeMSInheritanceAttr(Decl *D, SourceRange Range, bool BestCase,
+ unsigned AttrSpellingListIndex,
+ MSInheritanceAttr::Spelling SemanticSpelling) {
+ if (MSInheritanceAttr *IA = D->getAttr<MSInheritanceAttr>()) {
+ if (IA->getSemanticSpelling() == SemanticSpelling)
+ return nullptr;
+ Diag(IA->getLocation(), diag::err_mismatched_ms_inheritance)
+ << 1 /*previous declaration*/;
+ Diag(Range.getBegin(), diag::note_previous_ms_inheritance);
+ D->dropAttr<MSInheritanceAttr>();
+ }
+
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(D);
+ if (RD->hasDefinition()) {
+ if (checkMSInheritanceAttrOnDefinition(RD, Range, BestCase,
+ SemanticSpelling)) {
+ return nullptr;
+ }
+ } else {
+ if (isa<ClassTemplatePartialSpecializationDecl>(RD)) {
+ Diag(Range.getBegin(), diag::warn_ignored_ms_inheritance)
+ << 1 /*partial specialization*/;
+ return nullptr;
+ }
+ if (RD->getDescribedClassTemplate()) {
+ Diag(Range.getBegin(), diag::warn_ignored_ms_inheritance)
+ << 0 /*primary template*/;
+ return nullptr;
+ }
+ }
+
+ return ::new (Context)
+ MSInheritanceAttr(Range, Context, BestCase, AttrSpellingListIndex);
+}
+
+static void handleCapabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ // The capability attributes take a single string parameter for the name of
+ // the capability they represent. The lockable attribute does not take any
+ // parameters. However, semantically, both attributes represent the same
+ // concept, and so they use the same semantic attribute. Eventually, the
+ // lockable attribute will be removed.
+ //
+ // For backward compatibility, any capability which has no specified string
+ // literal will be considered a "mutex."
+ StringRef N("mutex");
+ SourceLocation LiteralLoc;
+ if (Attr.getKind() == AttributeList::AT_Capability &&
+ !S.checkStringLiteralArgumentAttr(Attr, 0, N, &LiteralLoc))
+ return;
+
+ // Currently, there are only two names allowed for a capability: role and
+ // mutex (case insensitive). Diagnose other capability names.
+ if (!N.equals_lower("mutex") && !N.equals_lower("role"))
+ S.Diag(LiteralLoc, diag::warn_invalid_capability_name) << N;
+
+ D->addAttr(::new (S.Context) CapabilityAttr(Attr.getRange(), S.Context, N,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleAssertCapabilityAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ D->addAttr(::new (S.Context) AssertCapabilityAttr(Attr.getRange(), S.Context,
+ Attr.getArgAsExpr(0),
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleAcquireCapabilityAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ SmallVector<Expr*, 1> Args;
+ if (!checkLockFunAttrCommon(S, D, Attr, Args))
+ return;
+
+ D->addAttr(::new (S.Context) AcquireCapabilityAttr(Attr.getRange(),
+ S.Context,
+ Args.data(), Args.size(),
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleTryAcquireCapabilityAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ SmallVector<Expr*, 2> Args;
+ if (!checkTryLockFunAttrCommon(S, D, Attr, Args))
+ return;
+
+ D->addAttr(::new (S.Context) TryAcquireCapabilityAttr(Attr.getRange(),
+ S.Context,
+ Attr.getArgAsExpr(0),
+ Args.data(),
+ Args.size(),
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleReleaseCapabilityAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ // Check that all arguments are lockable objects.
+ SmallVector<Expr *, 1> Args;
+ checkAttrArgsAreCapabilityObjs(S, D, Attr, Args, 0, true);
+
+ D->addAttr(::new (S.Context) ReleaseCapabilityAttr(
+ Attr.getRange(), S.Context, Args.data(), Args.size(),
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleRequiresCapabilityAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
+ return;
+
+ // check that all arguments are lockable objects
+ SmallVector<Expr*, 1> Args;
+ checkAttrArgsAreCapabilityObjs(S, D, Attr, Args);
+ if (Args.empty())
+ return;
+
+ RequiresCapabilityAttr *RCA = ::new (S.Context)
+ RequiresCapabilityAttr(Attr.getRange(), S.Context, Args.data(),
+ Args.size(), Attr.getAttributeSpellingListIndex());
+
+ D->addAttr(RCA);
}
/// Handles semantic checking for features that are common to all attributes,
@@ -4583,15 +4012,24 @@ static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D,
// We also bail on unknown and ignored attributes because those are handled
// as part of the target-specific handling logic.
if (Attr.hasCustomParsing() ||
- Attr.getKind() == AttributeList::UnknownAttribute ||
- Attr.getKind() == AttributeList::IgnoredAttribute)
+ Attr.getKind() == AttributeList::UnknownAttribute)
return false;
+ // Check whether the attribute requires specific language extensions to be
+ // enabled.
+ if (!Attr.diagnoseLangOpts(S))
+ return true;
+
// If there are no optional arguments, then checking for the argument count
// is trivial.
if (Attr.getMinArgs() == Attr.getMaxArgs() &&
!checkAttributeNumArgs(S, Attr, Attr.getMinArgs()))
return true;
+
+ // Check whether the attribute appertains to the given subject.
+ if (!Attr.diagnoseAppertainsTo(S, D))
+ return true;
+
return false;
}
@@ -4605,7 +4043,7 @@ static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D,
static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr,
bool IncludeCXX11Attributes) {
- if (Attr.isInvalid())
+ if (Attr.isInvalid() || Attr.getKind() == AttributeList::IgnoredAttribute)
return;
// Ignore C++11 attributes on declarator chunks: they appertain to the type
@@ -4613,145 +4051,282 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
if (Attr.isCXX11Attribute() && !IncludeCXX11Attributes)
return;
+ // Unknown attributes are automatically warned on. Target-specific attributes
+ // which do not apply to the current target architecture are treated as
+ // though they were unknown attributes.
+ if (Attr.getKind() == AttributeList::UnknownAttribute ||
+ !Attr.existsInTarget(S.Context.getTargetInfo().getTriple())) {
+ S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute()
+ ? diag::warn_unhandled_ms_attribute_ignored
+ : diag::warn_unknown_attribute_ignored)
+ << Attr.getName();
+ return;
+ }
+
if (handleCommonAttributeFeatures(S, scope, D, Attr))
return;
switch (Attr.getKind()) {
- case AttributeList::AT_IBAction: handleIBAction(S, D, Attr); break;
- case AttributeList::AT_IBOutlet: handleIBOutlet(S, D, Attr); break;
+ default:
+ // Type attributes are handled elsewhere; silently move on.
+ assert(Attr.isTypeAttr() && "Non-type attribute not handled");
+ break;
+ case AttributeList::AT_Interrupt:
+ handleInterruptAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_X86ForceAlignArgPointer:
+ handleX86ForceAlignArgPointerAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_DLLExport:
+ case AttributeList::AT_DLLImport:
+ handleDLLAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_Mips16:
+ handleSimpleAttribute<Mips16Attr>(S, D, Attr);
+ break;
+ case AttributeList::AT_NoMips16:
+ handleSimpleAttribute<NoMips16Attr>(S, D, Attr);
+ break;
+ case AttributeList::AT_IBAction:
+ handleSimpleAttribute<IBActionAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_IBOutlet:
+ handleIBOutlet(S, D, Attr);
+ break;
case AttributeList::AT_IBOutletCollection:
- handleIBOutletCollection(S, D, Attr); break;
- case AttributeList::AT_AddressSpace:
- case AttributeList::AT_ObjCGC:
- case AttributeList::AT_VectorSize:
- case AttributeList::AT_NeonVectorType:
- case AttributeList::AT_NeonPolyVectorType:
- case AttributeList::AT_Ptr32:
- case AttributeList::AT_Ptr64:
- case AttributeList::AT_SPtr:
- case AttributeList::AT_UPtr:
- // Ignore these, these are type attributes, handled by
- // ProcessTypeAttributes.
- break;
- case AttributeList::AT_Alias: handleAliasAttr (S, D, Attr); break;
- case AttributeList::AT_Aligned: handleAlignedAttr (S, D, Attr); break;
- case AttributeList::AT_AllocSize: handleAllocSizeAttr (S, D, Attr); break;
+ handleIBOutletCollection(S, D, Attr);
+ break;
+ case AttributeList::AT_Alias:
+ handleAliasAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_Aligned:
+ handleAlignedAttr(S, D, Attr);
+ break;
case AttributeList::AT_AlwaysInline:
- handleAlwaysInlineAttr (S, D, Attr); break;
+ handleAlwaysInlineAttr(S, D, Attr);
+ break;
case AttributeList::AT_AnalyzerNoReturn:
- handleAnalyzerNoReturnAttr (S, D, Attr); break;
- case AttributeList::AT_TLSModel: handleTLSModelAttr (S, D, Attr); break;
- case AttributeList::AT_Annotate: handleAnnotateAttr (S, D, Attr); break;
- case AttributeList::AT_Availability:handleAvailabilityAttr(S, D, Attr); break;
+ handleAnalyzerNoReturnAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_TLSModel:
+ handleTLSModelAttr(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_CarriesDependency:
handleDependencyAttr(S, scope, D, Attr);
break;
- case AttributeList::AT_Common: handleCommonAttr (S, D, Attr); break;
- case AttributeList::AT_CUDAConstant:handleConstantAttr (S, D, Attr); break;
- case AttributeList::AT_Constructor: handleConstructorAttr (S, D, Attr); break;
+ case AttributeList::AT_Common:
+ handleCommonAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_CUDAConstant:
+ handleSimpleAttribute<CUDAConstantAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_Constructor:
+ handleConstructorAttr(S, D, Attr);
+ break;
case AttributeList::AT_CXX11NoReturn:
- handleCXX11NoReturnAttr(S, D, Attr);
+ handleSimpleAttribute<CXX11NoReturnAttr>(S, D, Attr);
break;
case AttributeList::AT_Deprecated:
handleAttrWithMessage<DeprecatedAttr>(S, D, Attr);
break;
- case AttributeList::AT_Destructor: handleDestructorAttr (S, D, Attr); break;
+ case AttributeList::AT_Destructor:
+ handleDestructorAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_EnableIf:
+ handleEnableIfAttr(S, D, Attr);
+ break;
case AttributeList::AT_ExtVectorType:
handleExtVectorTypeAttr(S, scope, D, Attr);
break;
case AttributeList::AT_MinSize:
- handleMinSizeAttr(S, D, Attr);
- break;
- case AttributeList::AT_Format: handleFormatAttr (S, D, Attr); break;
- case AttributeList::AT_FormatArg: handleFormatArgAttr (S, D, Attr); break;
- case AttributeList::AT_CUDAGlobal: handleGlobalAttr (S, D, Attr); break;
- case AttributeList::AT_CUDADevice: handleDeviceAttr (S, D, Attr); break;
- case AttributeList::AT_CUDAHost: handleHostAttr (S, D, Attr); break;
- case AttributeList::AT_GNUInline: handleGNUInlineAttr (S, D, Attr); break;
+ handleSimpleAttribute<MinSizeAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_OptimizeNone:
+ handleOptimizeNoneAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_Flatten:
+ handleSimpleAttribute<FlattenAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_Format:
+ handleFormatAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_FormatArg:
+ handleFormatArgAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_CUDAGlobal:
+ handleGlobalAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_CUDADevice:
+ handleSimpleAttribute<CUDADeviceAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_CUDAHost:
+ handleSimpleAttribute<CUDAHostAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_GNUInline:
+ handleGNUInlineAttr(S, D, Attr);
+ break;
case AttributeList::AT_CUDALaunchBounds:
handleLaunchBoundsAttr(S, D, Attr);
break;
- case AttributeList::AT_Malloc: handleMallocAttr (S, D, Attr); break;
- case AttributeList::AT_MayAlias: handleMayAliasAttr (S, D, Attr); break;
- case AttributeList::AT_Mode: handleModeAttr (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_Overloadable:handleOverloadableAttr(S, D, Attr); break;
- case AttributeList::AT_ownership_returns:
- case AttributeList::AT_ownership_takes:
- case AttributeList::AT_ownership_holds:
- handleOwnershipAttr (S, D, Attr); break;
- case AttributeList::AT_Cold: handleColdAttr (S, D, Attr); break;
- case AttributeList::AT_Hot: handleHotAttr (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_CUDAShared: handleSharedAttr (S, D, Attr); break;
- case AttributeList::AT_VecReturn: handleVecReturnAttr (S, D, Attr); break;
+ case AttributeList::AT_Malloc:
+ handleMallocAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_MayAlias:
+ handleSimpleAttribute<MayAliasAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_Mode:
+ handleModeAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_NoCommon:
+ handleSimpleAttribute<NoCommonAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_NoSplitStack:
+ handleSimpleAttribute<NoSplitStackAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_NonNull:
+ if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(D))
+ handleNonNullAttrParameter(S, PVD, Attr);
+ else
+ handleNonNullAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_ReturnsNonNull:
+ handleReturnsNonNullAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_Overloadable:
+ handleSimpleAttribute<OverloadableAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_Ownership:
+ handleOwnershipAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_Cold:
+ handleColdAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_Hot:
+ handleHotAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_Naked:
+ handleSimpleAttribute<NakedAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_NoReturn:
+ handleNoReturnAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_NoThrow:
+ handleSimpleAttribute<NoThrowAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_CUDAShared:
+ handleSimpleAttribute<CUDASharedAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_VecReturn:
+ handleVecReturnAttr(S, D, Attr);
+ break;
case AttributeList::AT_ObjCOwnership:
- handleObjCOwnershipAttr(S, D, Attr); break;
+ handleObjCOwnershipAttr(S, D, Attr);
+ break;
case AttributeList::AT_ObjCPreciseLifetime:
- handleObjCPreciseLifetimeAttr(S, D, Attr); break;
+ handleObjCPreciseLifetimeAttr(S, D, Attr);
+ break;
case AttributeList::AT_ObjCReturnsInnerPointer:
- handleObjCReturnsInnerPointerAttr(S, D, Attr); break;
+ handleObjCReturnsInnerPointerAttr(S, D, Attr);
+ break;
case AttributeList::AT_ObjCRequiresSuper:
- handleObjCRequiresSuperAttr(S, D, Attr); break;
-
- case AttributeList::AT_NSBridged:
- handleNSBridgedAttr(S, scope, D, Attr); break;
-
+ handleObjCRequiresSuperAttr(S, D, Attr);
+ break;
+
case AttributeList::AT_ObjCBridge:
- handleObjCBridgeAttr(S, scope, D, Attr); break;
+ handleObjCBridgeAttr(S, scope, D, Attr);
+ break;
+
+ case AttributeList::AT_ObjCBridgeMutable:
+ handleObjCBridgeMutableAttr(S, scope, D, Attr);
+ break;
+
+ case AttributeList::AT_ObjCBridgeRelated:
+ handleObjCBridgeRelatedAttr(S, scope, D, Attr);
+ break;
+ case AttributeList::AT_ObjCDesignatedInitializer:
+ handleObjCDesignatedInitializer(S, D, Attr);
+ break;
+
+ case AttributeList::AT_ObjCRuntimeName:
+ handleObjCRuntimeName(S, D, Attr);
+ break;
+
case AttributeList::AT_CFAuditedTransfer:
+ handleCFAuditedTransferAttr(S, D, Attr);
+ break;
case AttributeList::AT_CFUnknownTransfer:
- handleCFTransferAttr(S, D, Attr); break;
+ handleCFUnknownTransferAttr(S, D, Attr);
+ break;
- // Checker-specific.
case AttributeList::AT_CFConsumed:
- case AttributeList::AT_NSConsumed: handleNSConsumedAttr (S, D, Attr); break;
+ case AttributeList::AT_NSConsumed:
+ handleNSConsumedAttr(S, D, Attr);
+ break;
case AttributeList::AT_NSConsumesSelf:
- handleNSConsumesSelfAttr(S, D, Attr); break;
+ handleSimpleAttribute<NSConsumesSelfAttr>(S, D, Attr);
+ break;
case AttributeList::AT_NSReturnsAutoreleased:
case AttributeList::AT_NSReturnsNotRetained:
case AttributeList::AT_CFReturnsNotRetained:
case AttributeList::AT_NSReturnsRetained:
case AttributeList::AT_CFReturnsRetained:
- handleNSReturnsRetainedAttr(S, D, Attr); break;
-
+ handleNSReturnsRetainedAttr(S, D, Attr);
+ break;
case AttributeList::AT_WorkGroupSizeHint:
+ handleWorkGroupSize<WorkGroupSizeHintAttr>(S, D, Attr);
+ break;
case AttributeList::AT_ReqdWorkGroupSize:
- handleWorkGroupSize(S, D, Attr); break;
-
+ handleWorkGroupSize<ReqdWorkGroupSizeAttr>(S, D, Attr);
+ break;
case AttributeList::AT_VecTypeHint:
- handleVecTypeHint(S, D, Attr); break;
+ handleVecTypeHint(S, D, Attr);
+ break;
- case AttributeList::AT_InitPriority:
- handleInitPriorityAttr(S, D, Attr); break;
-
- case AttributeList::AT_Packed: handlePackedAttr (S, D, Attr); break;
- case AttributeList::AT_Section: handleSectionAttr (S, D, Attr); break;
+ case AttributeList::AT_InitPriority:
+ handleInitPriorityAttr(S, D, Attr);
+ break;
+
+ case AttributeList::AT_Packed:
+ handlePackedAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_Section:
+ handleSectionAttr(S, D, Attr);
+ break;
case AttributeList::AT_Unavailable:
handleAttrWithMessage<UnavailableAttr>(S, D, Attr);
break;
- case AttributeList::AT_ArcWeakrefUnavailable:
- handleArcWeakrefUnavailableAttr (S, D, Attr);
+ case AttributeList::AT_ArcWeakrefUnavailable:
+ handleSimpleAttribute<ArcWeakrefUnavailableAttr>(S, D, Attr);
break;
case AttributeList::AT_ObjCRootClass:
- handleObjCRootClassAttr(S, D, Attr);
+ handleSimpleAttribute<ObjCRootClassAttr>(S, D, Attr);
break;
- case AttributeList::AT_ObjCRequiresPropertyDefs:
- handleObjCRequiresPropertyDefsAttr (S, D, Attr);
+ case AttributeList::AT_ObjCExplicitProtocolImpl:
+ handleObjCSuppresProtocolAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_ObjCRequiresPropertyDefs:
+ handleSimpleAttribute<ObjCRequiresPropertyDefsAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_Unused:
+ handleSimpleAttribute<UnusedAttr>(S, D, Attr);
break;
- case AttributeList::AT_Unused: handleUnusedAttr (S, D, Attr); break;
case AttributeList::AT_ReturnsTwice:
- handleReturnsTwiceAttr(S, D, Attr);
+ handleSimpleAttribute<ReturnsTwiceAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_Used:
+ handleUsedAttr(S, D, Attr);
break;
- case AttributeList::AT_Used: handleUsedAttr (S, D, Attr); break;
case AttributeList::AT_Visibility:
handleVisibilityAttr(S, D, Attr, false);
break;
@@ -4759,36 +4334,58 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleVisibilityAttr(S, D, Attr, true);
break;
case AttributeList::AT_WarnUnused:
- handleWarnUnusedAttr(S, D, Attr);
+ handleSimpleAttribute<WarnUnusedAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_WarnUnusedResult:
+ handleWarnUnusedResult(S, D, Attr);
+ break;
+ case AttributeList::AT_Weak:
+ handleSimpleAttribute<WeakAttr>(S, D, Attr);
break;
- case AttributeList::AT_WarnUnusedResult: handleWarnUnusedResult(S, D, Attr);
+ case AttributeList::AT_WeakRef:
+ handleWeakRefAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_WeakImport:
+ handleWeakImportAttr(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_WeakImport: handleWeakImportAttr (S, D, Attr); break;
case AttributeList::AT_TransparentUnion:
handleTransparentUnionAttr(S, D, Attr);
break;
case AttributeList::AT_ObjCException:
- handleObjCExceptionAttr(S, D, Attr);
+ handleSimpleAttribute<ObjCExceptionAttr>(S, D, Attr);
break;
case AttributeList::AT_ObjCMethodFamily:
handleObjCMethodFamilyAttr(S, D, Attr);
break;
- case AttributeList::AT_ObjCNSObject: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_NoInstrumentFunction: // Interacts with -pg.
- handleNoInstrumentFunctionAttr(S, D, Attr);
+ case AttributeList::AT_ObjCNSObject:
+ 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:
+ handleSimpleAttribute<ConstAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_Pure:
+ handleSimpleAttribute<PureAttr>(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_NoDuplicate:
+ handleSimpleAttribute<NoDuplicateAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_NoInline:
+ handleSimpleAttribute<NoInlineAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_NoInstrumentFunction: // Interacts with -pg.
+ handleSimpleAttribute<NoInstrumentFunctionAttr>(S, D, Attr);
break;
case AttributeList::AT_StdCall:
case AttributeList::AT_CDecl:
@@ -4803,32 +4400,27 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleCallConvAttr(S, D, Attr);
break;
case AttributeList::AT_OpenCLKernel:
- handleOpenCLKernelAttr(S, D, Attr);
+ handleSimpleAttribute<OpenCLKernelAttr>(S, D, Attr);
break;
case AttributeList::AT_OpenCLImageAccess:
- handleOpenCLImageAccessAttr(S, D, Attr);
+ handleSimpleAttribute<OpenCLImageAccessAttr>(S, D, Attr);
break;
// Microsoft attributes:
case AttributeList::AT_MsStruct:
- handleMsStructAttr(S, D, Attr);
+ handleSimpleAttribute<MsStructAttr>(S, D, Attr);
break;
case AttributeList::AT_Uuid:
handleUuidAttr(S, D, Attr);
break;
- case AttributeList::AT_SingleInheritance:
- case AttributeList::AT_MultipleInheritance:
- case AttributeList::AT_VirtualInheritance:
- handleInheritanceAttr(S, D, Attr);
- break;
- case AttributeList::AT_Win64:
- handlePortabilityAttr(S, D, Attr);
- break;
- case AttributeList::AT_ForceInline:
- handleForceInlineAttr(S, D, Attr);
+ case AttributeList::AT_MSInheritance:
+ handleMSInheritanceAttr(S, D, Attr);
break;
case AttributeList::AT_SelectAny:
- handleSelectAnyAttr(S, D, Attr);
+ handleSimpleAttribute<SelectAnyAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_Thread:
+ handleDeclspecThreadAttr(S, D, Attr);
break;
// Thread safety attributes:
@@ -4839,28 +4431,25 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleAssertSharedLockAttr(S, D, Attr);
break;
case AttributeList::AT_GuardedVar:
- handleGuardedVarAttr(S, D, Attr);
+ handleSimpleAttribute<GuardedVarAttr>(S, D, Attr);
break;
case AttributeList::AT_PtGuardedVar:
handlePtGuardedVarAttr(S, D, Attr);
break;
case AttributeList::AT_ScopedLockable:
- handleScopedLockableAttr(S, D, Attr);
+ handleSimpleAttribute<ScopedLockableAttr>(S, D, Attr);
break;
case AttributeList::AT_NoSanitizeAddress:
- handleNoSanitizeAddressAttr(S, D, Attr);
+ handleSimpleAttribute<NoSanitizeAddressAttr>(S, D, Attr);
break;
case AttributeList::AT_NoThreadSafetyAnalysis:
- handleNoThreadSafetyAnalysis(S, D, Attr);
+ handleSimpleAttribute<NoThreadSafetyAnalysisAttr>(S, D, Attr);
break;
case AttributeList::AT_NoSanitizeThread:
- handleNoSanitizeThread(S, D, Attr);
+ handleSimpleAttribute<NoSanitizeThreadAttr>(S, D, Attr);
break;
case AttributeList::AT_NoSanitizeMemory:
- handleNoSanitizeMemory(S, D, Attr);
- break;
- case AttributeList::AT_Lockable:
- handleLockableAttr(S, D, Attr);
+ handleSimpleAttribute<NoSanitizeMemoryAttr>(S, D, Attr);
break;
case AttributeList::AT_GuardedBy:
handleGuardedByAttr(S, D, Attr);
@@ -4868,12 +4457,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_PtGuardedBy:
handlePtGuardedByAttr(S, D, Attr);
break;
- case AttributeList::AT_ExclusiveLockFunction:
- handleExclusiveLockFunctionAttr(S, D, Attr);
- break;
- case AttributeList::AT_ExclusiveLocksRequired:
- handleExclusiveLocksRequiredAttr(S, D, Attr);
- break;
case AttributeList::AT_ExclusiveTrylockFunction:
handleExclusiveTrylockFunctionAttr(S, D, Attr);
break;
@@ -4883,18 +4466,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_LocksExcluded:
handleLocksExcludedAttr(S, D, Attr);
break;
- case AttributeList::AT_SharedLockFunction:
- handleSharedLockFunctionAttr(S, D, Attr);
- break;
- case AttributeList::AT_SharedLocksRequired:
- handleSharedLocksRequiredAttr(S, D, Attr);
- break;
case AttributeList::AT_SharedTrylockFunction:
handleSharedTrylockFunctionAttr(S, D, Attr);
break;
- case AttributeList::AT_UnlockFunction:
- handleUnlockFunAttr(S, D, Attr);
- break;
case AttributeList::AT_AcquiredBefore:
handleAcquiredBeforeAttr(S, D, Attr);
break;
@@ -4902,10 +4476,38 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleAcquiredAfterAttr(S, D, Attr);
break;
+ // Capability analysis attributes.
+ case AttributeList::AT_Capability:
+ case AttributeList::AT_Lockable:
+ handleCapabilityAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_RequiresCapability:
+ handleRequiresCapabilityAttr(S, D, Attr);
+ break;
+
+ case AttributeList::AT_AssertCapability:
+ handleAssertCapabilityAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_AcquireCapability:
+ handleAcquireCapabilityAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_ReleaseCapability:
+ handleReleaseCapabilityAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_TryAcquireCapability:
+ handleTryAcquireCapabilityAttr(S, D, Attr);
+ break;
+
// Consumed analysis attributes.
case AttributeList::AT_Consumable:
handleConsumableAttr(S, D, Attr);
break;
+ case AttributeList::AT_ConsumableAutoCast:
+ handleSimpleAttribute<ConsumableAutoCastAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_ConsumableSetOnRead:
+ handleSimpleAttribute<ConsumableSetOnReadAttr>(S, D, Attr);
+ break;
case AttributeList::AT_CallableWhen:
handleCallableWhenAttr(S, D, Attr);
break;
@@ -4929,15 +4531,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_TypeTagForDatatype:
handleTypeTagForDatatypeAttr(S, D, Attr);
break;
-
- default:
- // Ask target about the attribute.
- const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema();
- if (!TargetAttrs.ProcessDeclAttribute(scope, D, Attr, S))
- S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute() ?
- diag::warn_unhandled_ms_attribute_ignored :
- diag::warn_unknown_attribute_ignored) << Attr.getName();
- break;
}
}
@@ -4949,15 +4542,32 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
for (const AttributeList* l = AttrList; l; l = l->getNext())
ProcessDeclAttribute(*this, S, D, *l, IncludeCXX11Attributes);
+ // FIXME: We should be able to handle these cases in TableGen.
// GCC accepts
// static int a9 __attribute__((weakref));
// but that looks really pointless. We reject it.
if (D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) {
- Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias) <<
- cast<NamedDecl>(D)->getNameAsString();
+ Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias)
+ << cast<NamedDecl>(D);
D->dropAttr<WeakRefAttr>();
return;
}
+
+ if (!D->hasAttr<OpenCLKernelAttr>()) {
+ // These attributes cannot be applied to a non-kernel function.
+ if (Attr *A = D->getAttr<ReqdWorkGroupSizeAttr>()) {
+ Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
+ D->setInvalidDecl();
+ }
+ if (Attr *A = D->getAttr<WorkGroupSizeHintAttr>()) {
+ Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
+ D->setInvalidDecl();
+ }
+ if (Attr *A = D->getAttr<VecTypeHintAttr>()) {
+ Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
+ D->setInvalidDecl();
+ }
+ }
}
// Annotation attributes are the only attributes allowed after an access
@@ -5009,7 +4619,7 @@ void Sema::checkUnusedDeclAttributes(Declarator &D) {
NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
SourceLocation Loc) {
assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND));
- NamedDecl *NewD = 0;
+ NamedDecl *NewD = nullptr;
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
FunctionDecl *NewFD;
// FIXME: Missing call to CheckFunctionDeclaration().
@@ -5032,9 +4642,8 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
QualType FDTy = FD->getType();
if (const FunctionProtoType *FT = FDTy->getAs<FunctionProtoType>()) {
SmallVector<ParmVarDecl*, 16> Params;
- for (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(),
- AE = FT->arg_type_end(); AI != AE; ++AI) {
- ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, Loc, *AI);
+ for (const auto &AI : FT->param_types()) {
+ ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, Loc, AI);
Param->setScopeInfo(0, Params.size());
Params.push_back(Param);
}
@@ -5061,18 +4670,20 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
IdentifierInfo *NDId = ND->getIdentifier();
NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias(), W.getLocation());
- NewD->addAttr(::new (Context) AliasAttr(W.getLocation(), Context,
- NDId->getName()));
- NewD->addAttr(::new (Context) WeakAttr(W.getLocation(), Context));
+ NewD->addAttr(AliasAttr::CreateImplicit(Context, NDId->getName(),
+ W.getLocation()));
+ NewD->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation()));
WeakTopLevelDecl.push_back(NewD);
// FIXME: "hideous" code from Sema::LazilyCreateBuiltin
// to insert Decl at TU scope, sorry.
DeclContext *SavedContext = CurContext;
CurContext = Context.getTranslationUnitDecl();
+ NewD->setDeclContext(CurContext);
+ NewD->setLexicalDeclContext(CurContext);
PushOnScopeChains(NewD, S);
CurContext = SavedContext;
} else { // just add weak to existing
- ND->addAttr(::new (Context) WeakAttr(W.getLocation(), Context));
+ ND->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation()));
}
}
@@ -5081,7 +4692,7 @@ void Sema::ProcessPragmaWeak(Scope *S, Decl *D) {
// have to do this.
LoadExternalWeakUndeclaredIdentifiers();
if (!WeakUndeclaredIdentifiers.empty()) {
- NamedDecl *ND = NULL;
+ NamedDecl *ND = nullptr;
if (VarDecl *VD = dyn_cast<VarDecl>(D))
if (VD->isExternC())
ND = VD;
@@ -5141,8 +4752,9 @@ static bool isForbiddenTypeAllowed(Sema &S, Decl *decl) {
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"));
+ decl->addAttr(UnavailableAttr::CreateImplicit(S.Context,
+ "this system declaration uses an unsupported type",
+ diag.Loc));
return;
}
if (S.getLangOpts().ObjCAutoRefCount)
@@ -5190,9 +4802,11 @@ void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
switch (diag.Kind) {
case DelayedDiagnostic::Deprecation:
- // Don't bother giving deprecation diagnostics if the decl is invalid.
+ case DelayedDiagnostic::Unavailable:
+ // Don't bother giving deprecation/unavailable diagnostics if
+ // the decl is invalid.
if (!decl->isInvalidDecl())
- HandleDelayedDeprecationCheck(diag, decl);
+ HandleDelayedAvailabilityCheck(diag, decl);
break;
case DelayedDiagnostic::Access:
@@ -5227,61 +4841,125 @@ static bool isDeclDeprecated(Decl *D) {
return false;
}
+static bool isDeclUnavailable(Decl *D) {
+ do {
+ if (D->isUnavailable())
+ return true;
+ // A category implicitly has the availability of the interface.
+ if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D))
+ return CatD->getClassInterface()->isUnavailable();
+ } while ((D = cast_or_null<Decl>(D->getDeclContext())));
+ return false;
+}
+
static void
-DoEmitDeprecationWarning(Sema &S, const NamedDecl *D, StringRef Message,
- SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass,
- const ObjCPropertyDecl *ObjCPropery) {
+DoEmitAvailabilityWarning(Sema &S,
+ DelayedDiagnostic::DDKind K,
+ Decl *Ctx,
+ const NamedDecl *D,
+ StringRef Message,
+ SourceLocation Loc,
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ const ObjCPropertyDecl *ObjCProperty,
+ bool ObjCPropertyAccess) {
+
+ // Diagnostics for deprecated or unavailable.
+ unsigned diag, diag_message, diag_fwdclass_message;
+
+ // Matches 'diag::note_property_attribute' options.
+ unsigned property_note_select;
+
+ // Matches diag::note_availability_specified_here.
+ unsigned available_here_select_kind;
+
+ // Don't warn if our current context is deprecated or unavailable.
+ switch (K) {
+ case DelayedDiagnostic::Deprecation:
+ if (isDeclDeprecated(Ctx))
+ return;
+ diag = !ObjCPropertyAccess ? diag::warn_deprecated
+ : diag::warn_property_method_deprecated;
+ diag_message = diag::warn_deprecated_message;
+ diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
+ property_note_select = /* deprecated */ 0;
+ available_here_select_kind = /* deprecated */ 2;
+ break;
+
+ case DelayedDiagnostic::Unavailable:
+ if (isDeclUnavailable(Ctx))
+ return;
+ diag = !ObjCPropertyAccess ? diag::err_unavailable
+ : diag::err_property_method_unavailable;
+ diag_message = diag::err_unavailable_message;
+ diag_fwdclass_message = diag::warn_unavailable_fwdclass_message;
+ property_note_select = /* unavailable */ 1;
+ available_here_select_kind = /* unavailable */ 0;
+ break;
+
+ default:
+ llvm_unreachable("Neither a deprecation or unavailable kind");
+ }
+
DeclarationName Name = D->getDeclName();
if (!Message.empty()) {
- S.Diag(Loc, diag::warn_deprecated_message) << Name << Message;
- S.Diag(D->getLocation(),
- isa<ObjCMethodDecl>(D) ? diag::note_method_declared_at
- : diag::note_previous_decl) << Name;
- if (ObjCPropery)
- S.Diag(ObjCPropery->getLocation(), diag::note_property_attribute)
- << ObjCPropery->getDeclName() << 0;
+ S.Diag(Loc, diag_message) << Name << Message;
+ if (ObjCProperty)
+ S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
+ << ObjCProperty->getDeclName() << property_note_select;
} else if (!UnknownObjCClass) {
- S.Diag(Loc, diag::warn_deprecated) << D->getDeclName();
- S.Diag(D->getLocation(),
- isa<ObjCMethodDecl>(D) ? diag::note_method_declared_at
- : diag::note_previous_decl) << Name;
- if (ObjCPropery)
- S.Diag(ObjCPropery->getLocation(), diag::note_property_attribute)
- << ObjCPropery->getDeclName() << 0;
+ S.Diag(Loc, diag) << Name;
+ if (ObjCProperty)
+ S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
+ << ObjCProperty->getDeclName() << property_note_select;
} else {
- S.Diag(Loc, diag::warn_deprecated_fwdclass_message) << Name;
+ S.Diag(Loc, diag_fwdclass_message) << Name;
S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
}
-}
-void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD,
- Decl *Ctx) {
- if (isDeclDeprecated(Ctx))
- return;
-
- DD.Triggered = true;
- DoEmitDeprecationWarning(*this, DD.getDeprecationDecl(),
- DD.getDeprecationMessage(), DD.Loc,
- DD.getUnknownObjCClass(),
- DD.getObjCProperty());
+ S.Diag(D->getLocation(), diag::note_availability_specified_here)
+ << D << available_here_select_kind;
}
-void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message,
- SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass,
- const ObjCPropertyDecl *ObjCProperty) {
+void Sema::HandleDelayedAvailabilityCheck(DelayedDiagnostic &DD,
+ Decl *Ctx) {
+ DD.Triggered = true;
+ DoEmitAvailabilityWarning(*this,
+ (DelayedDiagnostic::DDKind) DD.Kind,
+ Ctx,
+ DD.getDeprecationDecl(),
+ DD.getDeprecationMessage(),
+ DD.Loc,
+ DD.getUnknownObjCClass(),
+ DD.getObjCProperty(), false);
+}
+
+void Sema::EmitAvailabilityWarning(AvailabilityDiagnostic AD,
+ NamedDecl *D, StringRef Message,
+ SourceLocation Loc,
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ const ObjCPropertyDecl *ObjCProperty,
+ bool ObjCPropertyAccess) {
// Delay if we're currently parsing a declaration.
if (DelayedDiagnostics.shouldDelayDiagnostics()) {
- DelayedDiagnostics.add(DelayedDiagnostic::makeDeprecation(Loc, D,
- UnknownObjCClass,
- ObjCProperty,
- Message));
+ DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability(AD, Loc, D,
+ UnknownObjCClass,
+ ObjCProperty,
+ Message,
+ ObjCPropertyAccess));
return;
}
- // Otherwise, don't warn if our current context is deprecated.
- if (isDeclDeprecated(cast<Decl>(getCurLexicalContext())))
- return;
- DoEmitDeprecationWarning(*this, D, Message, Loc, UnknownObjCClass, ObjCProperty);
+ Decl *Ctx = cast<Decl>(getCurLexicalContext());
+ DelayedDiagnostic::DDKind K;
+ switch (AD) {
+ case AD_Deprecation:
+ K = DelayedDiagnostic::Deprecation;
+ break;
+ case AD_Unavailable:
+ K = DelayedDiagnostic::Unavailable;
+ break;
+ }
+
+ DoEmitAvailabilityWarning(*this, K, Ctx, D, Message, Loc,
+ UnknownObjCClass, ObjCProperty, ObjCPropertyAccess);
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 6b3400adac6e..c5cd83da59d6 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -18,7 +18,6 @@
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
-#include "clang/AST/DeclVisitor.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecordLayout.h"
@@ -212,11 +211,9 @@ Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,
"Shouldn't collect exceptions when throw-all is guaranteed.");
ComputedEST = EST_Dynamic;
// Record the exceptions in this function's exception specification.
- for (FunctionProtoType::exception_iterator E = Proto->exception_begin(),
- EEnd = Proto->exception_end();
- E != EEnd; ++E)
- if (ExceptionsSeen.insert(Self->Context.getCanonicalType(*E)))
- Exceptions.push_back(*E);
+ for (const auto &E : Proto->exceptions())
+ if (ExceptionsSeen.insert(Self->Context.getCanonicalType(E)))
+ Exceptions.push_back(E);
}
void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) {
@@ -271,7 +268,7 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg,
ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Arg);
if (Result.isInvalid())
return true;
- Arg = Result.takeAs<Expr>();
+ Arg = Result.getAs<Expr>();
CheckCompletedExpr(Arg, EqualLoc);
Arg = MaybeCreateExprWithCleanups(Arg);
@@ -347,13 +344,16 @@ void Sema::ActOnParamUnparsedDefaultArgument(Decl *param,
/// ActOnParamDefaultArgumentError - Parsing or semantic analysis of
/// the default argument for the parameter param failed.
-void Sema::ActOnParamDefaultArgumentError(Decl *param) {
+void Sema::ActOnParamDefaultArgumentError(Decl *param,
+ SourceLocation EqualLoc) {
if (!param)
return;
ParmVarDecl *Param = cast<ParmVarDecl>(param);
Param->setInvalidDecl();
UnparsedDefaultArgLocs.erase(Param);
+ Param->setDefaultArg(new(Context)
+ OpaqueValueExpr(EqualLoc, Param->getType(), VK_RValue));
}
/// CheckExtraCXXDefaultArguments - Check for any extra default
@@ -380,20 +380,20 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
MightBeFunction = false;
continue;
}
- for (unsigned argIdx = 0, e = chunk.Fun.NumArgs; argIdx != e; ++argIdx) {
- ParmVarDecl *Param =
- cast<ParmVarDecl>(chunk.Fun.ArgInfo[argIdx].Param);
+ for (unsigned argIdx = 0, e = chunk.Fun.NumParams; argIdx != e;
+ ++argIdx) {
+ ParmVarDecl *Param = cast<ParmVarDecl>(chunk.Fun.Params[argIdx].Param);
if (Param->hasUnparsedDefaultArg()) {
- CachedTokens *Toks = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens;
+ CachedTokens *Toks = chunk.Fun.Params[argIdx].DefaultArgTokens;
Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)
<< SourceRange((*Toks)[1].getLocation(),
Toks->back().getLocation());
delete Toks;
- chunk.Fun.ArgInfo[argIdx].DefaultArgTokens = 0;
+ chunk.Fun.Params[argIdx].DefaultArgTokens = nullptr;
} else if (Param->getDefaultArg()) {
Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)
<< Param->getDefaultArg()->getSourceRange();
- Param->setDefaultArg(0);
+ Param->setDefaultArg(nullptr);
}
}
} else if (chunk.Kind != DeclaratorChunk::Paren) {
@@ -479,7 +479,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
OldParam->getUninstantiatedDefaultArg());
else
NewParam->setDefaultArg(OldParam->getInit());
- DiagDefaultParamID = diag::warn_param_default_argument_redefinition;
+ DiagDefaultParamID = diag::ext_param_default_argument_redefinition;
Invalid = false;
}
}
@@ -586,6 +586,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
}
}
+ const FunctionDecl *Def;
// C++11 [dcl.constexpr]p1: If any declaration of a function or function
// template has a constexpr specifier then all its declarations shall
// contain the constexpr specifier.
@@ -594,6 +595,13 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
<< New << New->isConstexpr();
Diag(Old->getLocation(), diag::note_previous_declaration);
Invalid = true;
+ } else if (!Old->isInlined() && New->isInlined() && Old->isDefined(Def)) {
+ // C++11 [dcl.fcn.spec]p4:
+ // If the definition of a function appears in a translation unit before its
+ // first declaration as inline, the program is ill-formed.
+ Diag(New->getLocation(), diag::err_inline_decl_follows_def) << New;
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ Invalid = true;
}
// C++11 [dcl.fct.default]p4: If a friend declaration specifies a default
@@ -701,7 +709,7 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
for (p = 0; p <= LastMissingDefaultArg; ++p) {
ParmVarDecl *Param = FD->getParamDecl(p);
if (Param->hasDefaultArg()) {
- Param->setDefaultArg(0);
+ Param->setDefaultArg(nullptr);
}
}
}
@@ -714,8 +722,9 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef,
const FunctionDecl *FD) {
unsigned ArgIndex = 0;
const FunctionProtoType *FT = FD->getType()->getAs<FunctionProtoType>();
- for (FunctionProtoType::arg_type_iterator i = FT->arg_type_begin(),
- e = FT->arg_type_end(); i != e; ++i, ++ArgIndex) {
+ for (FunctionProtoType::param_type_iterator i = FT->param_type_begin(),
+ e = FT->param_type_end();
+ i != e; ++i, ++ArgIndex) {
const ParmVarDecl *PD = FD->getParamDecl(ArgIndex);
SourceLocation ParamLoc = PD->getLocation();
if (!(*i)->isDependentType() &&
@@ -760,10 +769,9 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base)
<< isa<CXXConstructorDecl>(NewFD)
<< getRecordDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases();
- for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
- E = RD->vbases_end(); I != E; ++I)
- Diag(I->getLocStart(),
- diag::note_constexpr_virtual_base_here) << I->getSourceRange();
+ for (const auto &I : RD->vbases())
+ Diag(I.getLocStart(),
+ diag::note_constexpr_virtual_base_here) << I.getSourceRange();
return false;
}
}
@@ -789,7 +797,7 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
}
// - its return type shall be a literal type;
- QualType RT = NewFD->getResultType();
+ QualType RT = NewFD->getReturnType();
if (!RT->isDependentType() &&
RequireLiteralType(NewFD->getLocation(), RT,
diag::err_constexpr_non_literal_return))
@@ -813,9 +821,8 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
// C++11 [dcl.constexpr]p3 and p4:
// The definition of a constexpr function(p3) or constructor(p4) [...] shall
// contain only
- for (DeclStmt::decl_iterator DclIt = DS->decl_begin(),
- DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) {
- switch ((*DclIt)->getKind()) {
+ for (const auto *DclIt : DS->decls()) {
+ switch (DclIt->getKind()) {
case Decl::StaticAssert:
case Decl::Using:
case Decl::UsingShadow:
@@ -831,7 +838,7 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
case Decl::TypeAlias: {
// - typedef declarations and alias-declarations that do not define
// classes or enumerations,
- TypedefNameDecl *TN = cast<TypedefNameDecl>(*DclIt);
+ const auto *TN = cast<TypedefNameDecl>(DclIt);
if (TN->getUnderlyingType()->isVariablyModifiedType()) {
// Don't allow variably-modified types in constexpr functions.
TypeLoc TL = TN->getTypeSourceInfo()->getTypeLoc();
@@ -846,7 +853,7 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
case Decl::Enum:
case Decl::CXXRecord:
// C++1y allows types to be defined, not just declared.
- if (cast<TagDecl>(*DclIt)->isThisDeclarationADefinition())
+ if (cast<TagDecl>(DclIt)->isThisDeclarationADefinition())
SemaRef.Diag(DS->getLocStart(),
SemaRef.getLangOpts().CPlusPlus1y
? diag::warn_cxx11_compat_constexpr_type_definition
@@ -865,7 +872,7 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
// C++1y [dcl.constexpr]p3 allows anything except:
// a definition of a variable of non-literal type or of static or
// thread storage duration or for which no initialization is performed.
- VarDecl *VD = cast<VarDecl>(*DclIt);
+ const auto *VD = cast<VarDecl>(DclIt);
if (VD->isThisDeclarationADefinition()) {
if (VD->isStaticLocal()) {
SemaRef.Diag(VD->getLocation(),
@@ -880,7 +887,8 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
diag::err_constexpr_local_var_non_literal_type,
isa<CXXConstructorDecl>(Dcl)))
return false;
- if (!VD->hasInit() && !VD->isCXXForRangeDecl()) {
+ if (!VD->getType()->isDependentType() &&
+ !VD->hasInit() && !VD->isCXXForRangeDecl()) {
SemaRef.Diag(VD->getLocation(),
diag::err_constexpr_local_var_no_init)
<< isa<CXXConstructorDecl>(Dcl);
@@ -932,8 +940,13 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef,
if (Field->isUnnamedBitfield())
return;
+ // Anonymous unions with no variant members and empty anonymous structs do not
+ // need to be explicitly initialized. FIXME: Anonymous structs that contain no
+ // indirect fields don't need initializing.
if (Field->isAnonymousStructOrUnion() &&
- Field->getType()->getAsCXXRecordDecl()->isEmpty())
+ (Field->getType()->isUnionType()
+ ? !Field->getType()->getAsCXXRecordDecl()->hasVariantMembers()
+ : Field->getType()->getAsCXXRecordDecl()->isEmpty()))
return;
if (!Inits.count(Field)) {
@@ -944,12 +957,11 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef,
SemaRef.Diag(Field->getLocation(), diag::note_constexpr_ctor_missing_init);
} else if (Field->isAnonymousStructOrUnion()) {
const RecordDecl *RD = Field->getType()->castAs<RecordType>()->getDecl();
- for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
- I != E; ++I)
+ for (auto *I : RD->fields())
// If an anonymous union contains an anonymous struct of which any member
// is initialized, all members must be initialized.
- if (!RD->isUnion() || Inits.count(*I))
- CheckConstexprCtorInitializer(SemaRef, Dcl, *I, Inits, Diagnosed);
+ if (!RD->isUnion() || Inits.count(I))
+ CheckConstexprCtorInitializer(SemaRef, Dcl, I, Inits, Diagnosed);
}
}
@@ -993,9 +1005,8 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
Cxx1yLoc = S->getLocStart();
CompoundStmt *CompStmt = cast<CompoundStmt>(S);
- for (CompoundStmt::body_iterator BodyIt = CompStmt->body_begin(),
- BodyEnd = CompStmt->body_end(); BodyIt != BodyEnd; ++BodyIt) {
- if (!CheckConstexprFunctionStmt(SemaRef, Dcl, *BodyIt, ReturnStmts,
+ for (auto *BodyIt : CompStmt->body()) {
+ if (!CheckConstexprFunctionStmt(SemaRef, Dcl, BodyIt, ReturnStmts,
Cxx1yLoc))
return false;
}
@@ -1097,9 +1108,8 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
// [... list of cases ...]
CompoundStmt *CompBody = cast<CompoundStmt>(Body);
SourceLocation Cxx1yLoc;
- for (CompoundStmt::body_iterator BodyIt = CompBody->body_begin(),
- BodyEnd = CompBody->body_end(); BodyIt != BodyEnd; ++BodyIt) {
- if (!CheckConstexprFunctionStmt(*this, Dcl, *BodyIt, ReturnStmts, Cxx1yLoc))
+ for (auto *BodyIt : CompBody->body()) {
+ if (!CheckConstexprFunctionStmt(*this, Dcl, BodyIt, ReturnStmts, Cxx1yLoc))
return false;
}
@@ -1116,11 +1126,12 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
// DR1359:
// - every non-variant non-static data member and base class sub-object
// shall be initialized;
- // - if the class is a non-empty union, or for each non-empty anonymous
- // union member of a non-union class, exactly one non-static data member
+ // DR1460:
+ // - if the class is a union having variant members, exactly one of them
// shall be initialized;
if (RD->isUnion()) {
- if (Constructor->getNumCtorInitializers() == 0 && !RD->isEmpty()) {
+ if (Constructor->getNumCtorInitializers() == 0 &&
+ RD->hasVariantMembers()) {
Diag(Dcl->getLocation(), diag::err_constexpr_union_ctor_no_init);
return false;
}
@@ -1139,25 +1150,26 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
break;
}
}
+ // DR1460:
+ // - if the class is a union-like class, but is not a union, for each of
+ // its anonymous union members having variant members, exactly one of
+ // them shall be initialized;
if (AnyAnonStructUnionMembers ||
Constructor->getNumCtorInitializers() != RD->getNumBases() + Fields) {
// Check initialization of non-static data members. Base classes are
// always initialized so do not need to be checked. Dependent bases
// might not have initializers in the member initializer list.
llvm::SmallSet<Decl*, 16> Inits;
- for (CXXConstructorDecl::init_const_iterator
- I = Constructor->init_begin(), E = Constructor->init_end();
- I != E; ++I) {
- if (FieldDecl *FD = (*I)->getMember())
+ for (const auto *I: Constructor->inits()) {
+ if (FieldDecl *FD = I->getMember())
Inits.insert(FD);
- else if (IndirectFieldDecl *ID = (*I)->getIndirectMember())
+ else if (IndirectFieldDecl *ID = I->getIndirectMember())
Inits.insert(ID->chain_begin(), ID->chain_end());
}
bool Diagnosed = false;
- for (CXXRecordDecl::field_iterator I = RD->field_begin(),
- E = RD->field_end(); I != E; ++I)
- CheckConstexprCtorInitializer(*this, Dcl, *I, Inits, Diagnosed);
+ for (auto *I : RD->fields())
+ CheckConstexprCtorInitializer(*this, Dcl, I, Inits, Diagnosed);
if (Diagnosed)
return false;
}
@@ -1165,10 +1177,12 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
} else {
if (ReturnStmts.empty()) {
// C++1y doesn't require constexpr functions to contain a 'return'
- // statement. We still do, unless the return type is void, because
+ // statement. We still do, unless the return type might be void, because
// otherwise if there's no return statement, the function cannot
// be used in a core constant expression.
- bool OK = getLangOpts().CPlusPlus1y && Dcl->getResultType()->isVoidType();
+ bool OK = getLangOpts().CPlusPlus1y &&
+ (Dcl->getReturnType()->isVoidType() ||
+ Dcl->getReturnType()->isDependentType());
Diag(Dcl->getLocation(),
OK ? diag::warn_cxx11_compat_constexpr_body_no_return
: diag::err_constexpr_body_no_return);
@@ -1261,10 +1275,8 @@ static bool findCircularInheritance(const CXXRecordDecl *Class,
Class = Class->getCanonicalDecl();
while (true) {
- for (CXXRecordDecl::base_class_const_iterator I = Current->bases_begin(),
- E = Current->bases_end();
- I != E; ++I) {
- CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();
+ for (const auto &I : Current->bases()) {
+ CXXRecordDecl *Base = I.getType()->getAsCXXRecordDecl();
if (!Base)
continue;
@@ -1287,6 +1299,57 @@ static bool findCircularInheritance(const CXXRecordDecl *Class,
return false;
}
+/// \brief Perform propagation of DLL attributes from a derived class to a
+/// templated base class for MS compatibility.
+static void propagateDLLAttrToBaseClassTemplate(
+ Sema &S, CXXRecordDecl *Class, Attr *ClassAttr,
+ ClassTemplateSpecializationDecl *BaseTemplateSpec, SourceLocation BaseLoc) {
+ if (getDLLAttr(
+ BaseTemplateSpec->getSpecializedTemplate()->getTemplatedDecl())) {
+ // If the base class template has a DLL attribute, don't try to change it.
+ return;
+ }
+
+ if (BaseTemplateSpec->getSpecializationKind() == TSK_Undeclared) {
+ // If the base class is not already specialized, we can do the propagation.
+ auto *NewAttr = cast<InheritableAttr>(ClassAttr->clone(S.getASTContext()));
+ NewAttr->setInherited(true);
+ BaseTemplateSpec->addAttr(NewAttr);
+ return;
+ }
+
+ bool DifferentAttribute = false;
+ if (Attr *SpecializationAttr = getDLLAttr(BaseTemplateSpec)) {
+ if (!SpecializationAttr->isInherited()) {
+ // The template has previously been specialized or instantiated with an
+ // explicit attribute. We should not try to change it.
+ return;
+ }
+ if (SpecializationAttr->getKind() == ClassAttr->getKind()) {
+ // The specialization already has the right attribute.
+ return;
+ }
+ DifferentAttribute = true;
+ }
+
+ // The template was previously instantiated or explicitly specialized without
+ // a dll attribute, or the template was previously instantiated with a
+ // different inherited attribute. It's too late for us to change the
+ // attribute, so warn that this is unsupported.
+ S.Diag(BaseLoc, diag::warn_attribute_dll_instantiated_base_class)
+ << BaseTemplateSpec->isExplicitSpecialization() << DifferentAttribute;
+ S.Diag(ClassAttr->getLocation(), diag::note_attribute);
+ if (BaseTemplateSpec->isExplicitSpecialization()) {
+ S.Diag(BaseTemplateSpec->getLocation(),
+ diag::note_template_class_explicit_specialization_was_here)
+ << BaseTemplateSpec;
+ } else {
+ S.Diag(BaseTemplateSpec->getPointOfInstantiation(),
+ diag::note_template_class_instantiation_was_here)
+ << BaseTemplateSpec;
+ }
+}
+
/// \brief Check the validity of a C++ base class specifier.
///
/// \returns a new CXXBaseSpecifier if well-formed, emits diagnostics
@@ -1304,7 +1367,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
if (Class->isUnion()) {
Diag(Class->getLocation(), diag::err_base_clause_on_union)
<< SpecifierRange;
- return 0;
+ return nullptr;
}
if (EllipsisLoc.isValid() &&
@@ -1330,8 +1393,8 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
if (BaseDecl->getCanonicalDecl() != Class->getCanonicalDecl())
Diag(BaseDecl->getLocation(), diag::note_previous_decl)
<< BaseType;
-
- return 0;
+
+ return nullptr;
}
}
@@ -1343,14 +1406,25 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
// Base specifiers must be record types.
if (!BaseType->isRecordType()) {
Diag(BaseLoc, diag::err_base_must_be_class) << SpecifierRange;
- return 0;
+ return nullptr;
}
// C++ [class.union]p1:
// A union shall not be used as a base class.
if (BaseType->isUnionType()) {
Diag(BaseLoc, diag::err_union_as_base_class) << SpecifierRange;
- return 0;
+ return nullptr;
+ }
+
+ // For the MS ABI, propagate DLL attributes to base class templates.
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ if (Attr *ClassAttr = getDLLAttr(Class)) {
+ if (auto *BaseTemplate = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
+ BaseType->getAsCXXRecordDecl())) {
+ propagateDLLAttrToBaseClassTemplate(*this, Class, ClassAttr,
+ BaseTemplate, BaseLoc);
+ }
+ }
}
// C++ [class.derived]p2:
@@ -1359,7 +1433,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
if (RequireCompleteType(BaseLoc, BaseType,
diag::err_incomplete_base_class, SpecifierRange)) {
Class->setInvalidDecl();
- return 0;
+ return nullptr;
}
// If the base class is polymorphic or isn't empty, the new one is/isn't, too.
@@ -1379,7 +1453,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
if (CXXBaseDecl->hasFlexibleArrayMember()) {
Diag(BaseLoc, diag::err_base_class_has_flexible_array_member)
<< CXXBaseDecl->getDeclName();
- return 0;
+ return nullptr;
}
// C++ [class]p3:
@@ -1389,9 +1463,9 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
Diag(BaseLoc, diag::err_class_marked_final_used_as_base)
<< CXXBaseDecl->getDeclName()
<< FA->isSpelledAsSealed();
- Diag(CXXBaseDecl->getLocation(), diag::note_previous_decl)
- << CXXBaseDecl->getDeclName();
- return 0;
+ Diag(CXXBaseDecl->getLocation(), diag::note_entity_declared_at)
+ << CXXBaseDecl->getDeclName() << FA->getRange();
+ return nullptr;
}
if (BaseDecl->isInvalidDecl())
@@ -1422,6 +1496,9 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
if (!Class)
return true;
+ // We haven't yet attached the base specifiers.
+ Class->setIsParsingBaseSpecifiers();
+
// We do not support any C++11 attributes on base-specifiers yet.
// Diagnose any attributes we see.
if (!Attributes.empty()) {
@@ -1438,7 +1515,7 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
}
}
- TypeSourceInfo *TInfo = 0;
+ TypeSourceInfo *TInfo = nullptr;
GetTypeFromParser(basetype, &TInfo);
if (EllipsisLoc.isInvalid() &&
@@ -1509,7 +1586,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases,
Invalid = true;
}
if (RD->hasAttr<WeakAttr>())
- Class->addAttr(::new (Context) WeakAttr(SourceRange(), Context));
+ Class->addAttr(WeakAttr::CreateImplicit(Context));
}
}
}
@@ -1841,10 +1918,10 @@ static bool InitializationHasSideEffects(const FieldDecl &FD) {
}
static AttributeList *getMSPropertyAttr(AttributeList *list) {
- for (AttributeList* it = list; it != 0; it = it->getNext())
+ for (AttributeList *it = list; it != nullptr; it = it->getNext())
if (it->isDeclspecPropertyAttribute())
return it;
- return 0;
+ return nullptr;
}
/// ActOnCXXMemberDeclarator - This is invoked when a C++ class member
@@ -1913,7 +1990,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
else
Diag(Loc, diag::err_invalid_member_in_interface)
<< (InvalidDecl-1) << "";
- return 0;
+ return nullptr;
}
}
@@ -1952,20 +2029,26 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr_member);
SourceLocation ConstexprLoc = DS.getConstexprSpecLoc();
if (InitStyle == ICIS_NoInit) {
- B << 0 << 0 << FixItHint::CreateReplacement(ConstexprLoc, "const");
- D.getMutableDeclSpec().ClearConstexprSpec();
- const char *PrevSpec;
- unsigned DiagID;
- bool Failed = D.getMutableDeclSpec().SetTypeQual(DeclSpec::TQ_const, ConstexprLoc,
- PrevSpec, DiagID, getLangOpts());
- (void)Failed;
- assert(!Failed && "Making a constexpr member const shouldn't fail");
+ B << 0 << 0;
+ if (D.getDeclSpec().getTypeQualifiers() & DeclSpec::TQ_const)
+ B << FixItHint::CreateRemoval(ConstexprLoc);
+ else {
+ B << FixItHint::CreateReplacement(ConstexprLoc, "const");
+ D.getMutableDeclSpec().ClearConstexprSpec();
+ const char *PrevSpec;
+ unsigned DiagID;
+ bool Failed = D.getMutableDeclSpec().SetTypeQual(
+ DeclSpec::TQ_const, ConstexprLoc, PrevSpec, DiagID, getLangOpts());
+ (void)Failed;
+ assert(!Failed && "Making a constexpr member const shouldn't fail");
+ }
} else {
B << 1;
const char *PrevSpec;
unsigned DiagID;
if (D.getMutableDeclSpec().SetStorageClassSpec(
- *this, DeclSpec::SCS_static, ConstexprLoc, PrevSpec, DiagID)) {
+ *this, DeclSpec::SCS_static, ConstexprLoc, PrevSpec, DiagID,
+ Context.getPrintingPolicy())) {
assert(DS.getStorageClassSpec() == DeclSpec::SCS_mutable &&
"This is the only DeclSpec that should fail to be applied");
B << 1;
@@ -1984,7 +2067,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
if (!Name.isIdentifier()) {
Diag(Loc, diag::err_bad_variable_name)
<< Name;
- return 0;
+ return nullptr;
}
IdentifierInfo *II = Name.getAsIdentifierInfo();
@@ -2007,7 +2090,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
<< SourceRange(TemplateParams->getTemplateLoc(),
TemplateParams->getRAngleLoc());
}
- return 0;
+ return nullptr;
}
if (SS.isSet() && !SS.isInvalid()) {
@@ -2032,7 +2115,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
Member = HandleMSProperty(S, cast<CXXRecordDecl>(CurContext), Loc, D,
BitWidth, InitStyle, AS, MSPropertyAttr);
if (!Member)
- return 0;
+ return nullptr;
isInstField = false;
} else {
Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D,
@@ -2044,7 +2127,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
Member = HandleDeclarator(S, D, TemplateParameterLists);
if (!Member)
- return 0;
+ return nullptr;
// Non-instance-fields can't have a bitfield.
if (BitWidth) {
@@ -2067,7 +2150,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
<< BitWidth->getSourceRange();
}
- BitWidth = 0;
+ BitWidth = nullptr;
Member->setInvalidDecl();
}
@@ -2082,7 +2165,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
}
if (VS.isOverrideSpecified())
- Member->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context));
+ Member->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context, 0));
if (VS.isFinalSpecified())
Member->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context,
VS.isFinalSpelledSealed()));
@@ -2101,9 +2184,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
FieldDecl *FD = cast<FieldDecl>(Member);
FieldCollector->Add(FD);
- if (Diags.getDiagnosticLevel(diag::warn_unused_private_field,
- FD->getLocation())
- != DiagnosticsEngine::Ignored) {
+ if (!Diags.isIgnored(diag::warn_unused_private_field, FD->getLocation())) {
// Remember all explicit private FieldDecls that have a name, no side
// effects and are not part of a dependent type declaration.
if (!FD->isImplicit() && FD->getDeclName() &&
@@ -2278,7 +2359,7 @@ namespace {
// In class initializers will point to the constructor.
UninitializedFieldVisitor(S, Decls, Constructor).Visit(E);
} else {
- UninitializedFieldVisitor(S, Decls, 0).Visit(E);
+ UninitializedFieldVisitor(S, Decls, nullptr).Visit(E);
}
}
@@ -2291,9 +2372,8 @@ namespace {
static void DiagnoseUninitializedFields(
Sema &SemaRef, const CXXConstructorDecl *Constructor) {
- if (SemaRef.getDiagnostics().getDiagnosticLevel(diag::warn_field_is_uninit,
- Constructor->getLocation())
- == DiagnosticsEngine::Ignored) {
+ if (SemaRef.getDiagnostics().isIgnored(diag::warn_field_is_uninit,
+ Constructor->getLocation())) {
return;
}
@@ -2306,38 +2386,44 @@ namespace {
llvm::SmallPtrSet<ValueDecl*, 4> UninitializedFields;
// At the beginning, all fields are uninitialized.
- for (DeclContext::decl_iterator I = RD->decls_begin(), E = RD->decls_end();
- I != E; ++I) {
- if (FieldDecl *FD = dyn_cast<FieldDecl>(*I)) {
+ for (auto *I : RD->decls()) {
+ if (auto *FD = dyn_cast<FieldDecl>(I)) {
UninitializedFields.insert(FD);
- } else if (IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(*I)) {
+ } else if (auto *IFD = dyn_cast<IndirectFieldDecl>(I)) {
UninitializedFields.insert(IFD->getAnonField());
}
}
- for (CXXConstructorDecl::init_const_iterator FieldInit =
- Constructor->init_begin(),
- FieldInitEnd = Constructor->init_end();
- FieldInit != FieldInitEnd; ++FieldInit) {
-
- Expr *InitExpr = (*FieldInit)->getInit();
+ for (const auto *FieldInit : Constructor->inits()) {
+ Expr *InitExpr = FieldInit->getInit();
CheckInitExprContainsUninitializedFields(
SemaRef, InitExpr, UninitializedFields, Constructor);
- if (FieldDecl *Field = (*FieldInit)->getAnyMember())
+ if (FieldDecl *Field = FieldInit->getAnyMember())
UninitializedFields.erase(Field);
}
}
} // namespace
-/// ActOnCXXInClassMemberInitializer - This is invoked after parsing an
-/// in-class initializer for a non-static C++ class member, and after
-/// instantiating an in-class initializer in a class template. Such actions
-/// are deferred until the class is complete.
-void
-Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc,
- Expr *InitExpr) {
+/// \brief Enter a new C++ default initializer scope. After calling this, the
+/// caller must call \ref ActOnFinishCXXInClassMemberInitializer, even if
+/// parsing or instantiating the initializer failed.
+void Sema::ActOnStartCXXInClassMemberInitializer() {
+ // Create a synthetic function scope to represent the call to the constructor
+ // that notionally surrounds a use of this initializer.
+ PushFunctionScope();
+}
+
+/// \brief This is invoked after parsing an in-class initializer for a
+/// non-static C++ class member, and after instantiating an in-class initializer
+/// in a class template. Such actions are deferred until the class is complete.
+void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D,
+ SourceLocation InitLoc,
+ Expr *InitExpr) {
+ // Pop the notional constructor scope we created earlier.
+ PopFunctionScopeInfo(nullptr, D);
+
FieldDecl *FD = cast<FieldDecl>(D);
assert(FD->getInClassInitStyle() != ICIS_NoInit &&
"must set init style when field is created");
@@ -2371,13 +2457,13 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc,
// C++11 [class.base.init]p7:
// The initialization of each base and member constitutes a
// full-expression.
- Init = ActOnFinishFullExpr(Init.take(), InitLoc);
+ Init = ActOnFinishFullExpr(Init.get(), InitLoc);
if (Init.isInvalid()) {
FD->setInvalidDecl();
return;
}
- InitExpr = Init.release();
+ InitExpr = Init.get();
FD->setInClassInitializer(InitExpr);
}
@@ -2391,14 +2477,12 @@ static bool FindBaseInitializer(Sema &SemaRef,
const CXXBaseSpecifier *&DirectBaseSpec,
const CXXBaseSpecifier *&VirtualBaseSpec) {
// First, check for a direct base class.
- DirectBaseSpec = 0;
- for (CXXRecordDecl::base_class_const_iterator Base
- = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- if (SemaRef.Context.hasSameUnqualifiedType(BaseType, Base->getType())) {
+ DirectBaseSpec = nullptr;
+ for (const auto &Base : ClassDecl->bases()) {
+ if (SemaRef.Context.hasSameUnqualifiedType(BaseType, Base.getType())) {
// We found a direct base of this type. That's what we're
// initializing.
- DirectBaseSpec = &*Base;
+ DirectBaseSpec = &Base;
break;
}
}
@@ -2406,7 +2490,7 @@ static bool FindBaseInitializer(Sema &SemaRef,
// Check for a virtual base class.
// FIXME: We might be able to short-circuit this if we know in advance that
// there are no virtual bases.
- VirtualBaseSpec = 0;
+ VirtualBaseSpec = nullptr;
if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) {
// We haven't found a base yet; search the class hierarchy for a
// virtual base class.
@@ -2471,7 +2555,7 @@ public:
explicit MemInitializerValidatorCCC(CXXRecordDecl *ClassDecl)
: ClassDecl(ClassDecl) {}
- bool ValidateCandidate(const TypoCorrection &candidate) LLVM_OVERRIDE {
+ bool ValidateCandidate(const TypoCorrection &candidate) override {
if (NamedDecl *ND = candidate.getCorrectionDecl()) {
if (FieldDecl *Member = dyn_cast<FieldDecl>(ND))
return Member->getDeclContext()->getRedeclContext()->Equals(ClassDecl);
@@ -2543,7 +2627,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
}
// It didn't name a member, so see if it names a class.
QualType BaseType;
- TypeSourceInfo *TInfo = 0;
+ TypeSourceInfo *TInfo = nullptr;
if (TemplateTypeTy) {
BaseType = GetTypeFromParser(TemplateTypeTy, &TInfo);
@@ -2585,7 +2669,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
MemInitializerValidatorCCC Validator(ClassDecl);
if (R.empty() && BaseType.isNull() &&
(Corr = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
- Validator, ClassDecl))) {
+ Validator, CTK_ErrorRecovery, ClassDecl))) {
if (FieldDecl *Member = Corr.getCorrectionDeclAs<FieldDecl>()) {
// We have found a non-static data member with a similar
// name to what was typed; complain and initialize that
@@ -2629,13 +2713,10 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
if (BaseType.isNull()) {
BaseType = Context.getTypeDeclType(TyD);
- if (SS.isSet()) {
- NestedNameSpecifier *Qualifier =
- static_cast<NestedNameSpecifier*>(SS.getScopeRep());
-
+ if (SS.isSet())
// FIXME: preserve source range information
- BaseType = Context.getElaboratedType(ETK_None, Qualifier, BaseType);
- }
+ BaseType = Context.getElaboratedType(ETK_None, SS.getScopeRep(),
+ BaseType);
}
}
@@ -2731,15 +2812,17 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
// Initialize the member.
InitializedEntity MemberEntity =
- DirectMember ? InitializedEntity::InitializeMember(DirectMember, 0)
- : InitializedEntity::InitializeMember(IndirectMember, 0);
+ DirectMember ? InitializedEntity::InitializeMember(DirectMember, nullptr)
+ : InitializedEntity::InitializeMember(IndirectMember,
+ nullptr);
InitializationKind Kind =
InitList ? InitializationKind::CreateDirectList(IdLoc)
: InitializationKind::CreateDirect(IdLoc, InitRange.getBegin(),
InitRange.getEnd());
InitializationSequence InitSeq(*this, MemberEntity, Kind, Args);
- ExprResult MemberInit = InitSeq.Perform(*this, MemberEntity, Kind, Args, 0);
+ ExprResult MemberInit = InitSeq.Perform(*this, MemberEntity, Kind, Args,
+ nullptr);
if (MemberInit.isInvalid())
return true;
@@ -2792,7 +2875,7 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init,
InitRange.getEnd());
InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args);
ExprResult DelegationInit = InitSeq.Perform(*this, DelegationEntity, Kind,
- Args, 0);
+ Args, nullptr);
if (DelegationInit.isInvalid())
return true;
@@ -2815,10 +2898,10 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init,
// 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())
- DelegationInit = Owned(Init);
+ DelegationInit = Init;
return new (Context) CXXCtorInitializer(Context, TInfo, InitRange.getBegin(),
- DelegationInit.takeAs<Expr>(),
+ DelegationInit.getAs<Expr>(),
InitRange.getEnd());
}
@@ -2860,8 +2943,8 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
}
// Check for direct and virtual base classes.
- const CXXBaseSpecifier *DirectBaseSpec = 0;
- const CXXBaseSpecifier *VirtualBaseSpec = 0;
+ const CXXBaseSpecifier *DirectBaseSpec = nullptr;
+ const CXXBaseSpecifier *VirtualBaseSpec = nullptr;
if (!Dependent) {
if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0),
BaseType))
@@ -2925,7 +3008,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
: InitializationKind::CreateDirect(BaseLoc, InitRange.getBegin(),
InitRange.getEnd());
InitializationSequence InitSeq(*this, BaseEntity, Kind, Args);
- ExprResult BaseInit = InitSeq.Perform(*this, BaseEntity, Kind, Args, 0);
+ ExprResult BaseInit = InitSeq.Perform(*this, BaseEntity, Kind, Args, nullptr);
if (BaseInit.isInvalid())
return true;
@@ -2944,12 +3027,12 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// 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())
- BaseInit = Owned(Init);
+ BaseInit = Init;
return new (Context) CXXCtorInitializer(Context, BaseTInfo,
BaseSpec->isVirtual(),
InitRange.getBegin(),
- BaseInit.takeAs<Expr>(),
+ BaseInit.getAs<Expr>(),
InitRange.getEnd(), EllipsisLoc);
}
@@ -2964,7 +3047,7 @@ static Expr *CastForMoving(Sema &SemaRef, Expr *E, QualType T = QualType()) {
return SemaRef.BuildCXXNamedCast(ExprLoc, tok::kw_static_cast, TargetLoc, E,
SourceRange(ExprLoc, ExprLoc),
- E->getSourceRange()).take();
+ E->getSourceRange()).get();
}
/// ImplicitInitializerKind - How an implicit base or member initializer should
@@ -3006,7 +3089,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
VK_LValue, SourceLocation());
if (ArgExpr.isInvalid())
return true;
- Args.push_back(CastForMoving(SemaRef, ArgExpr.take(), PD->getType()));
+ Args.push_back(CastForMoving(SemaRef, ArgExpr.get(), PD->getType()));
}
InitializationKind InitKind = InitializationKind::CreateDirect(
@@ -3035,7 +3118,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(),
SourceLocation(), Param, false,
Constructor->getLocation(), ParamType,
- VK_LValue, 0);
+ VK_LValue, nullptr);
SemaRef.MarkDeclRefReferenced(cast<DeclRefExpr>(CopyCtorArg));
@@ -3053,7 +3136,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
CopyCtorArg = SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy,
CK_UncheckedDerivedToBase,
Moving ? VK_XValue : VK_LValue,
- &BasePath).take();
+ &BasePath).get();
InitializationKind InitKind
= InitializationKind::CreateDirect(Constructor->getLocation(),
@@ -3074,7 +3157,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
SourceLocation()),
BaseSpec->isVirtual(),
SourceLocation(),
- BaseInit.takeAs<Expr>(),
+ BaseInit.getAs<Expr>(),
SourceLocation(),
SourceLocation());
@@ -3108,7 +3191,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
Expr *MemberExprBase =
DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(),
SourceLocation(), Param, false,
- Loc, ParamType, VK_LValue, 0);
+ Loc, ParamType, VK_LValue, nullptr);
SemaRef.MarkDeclRefReferenced(cast<DeclRefExpr>(MemberExprBase));
@@ -3129,9 +3212,9 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
/*IsArrow=*/false,
SS,
/*TemplateKWLoc=*/SourceLocation(),
- /*FirstQualifierInScope=*/0,
+ /*FirstQualifierInScope=*/nullptr,
MemberLookup,
- /*TemplateArgs=*/0);
+ /*TemplateArgs=*/nullptr);
if (CtorArg.isInvalid())
return true;
@@ -3139,7 +3222,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
// - if a member m has rvalue reference type T&&, it is direct-initialized
// with static_cast<T&&>(x.m);
if (RefersToRValueRef(CtorArg.get())) {
- CtorArg = CastForMoving(SemaRef, CtorArg.take());
+ CtorArg = CastForMoving(SemaRef, CtorArg.get());
}
// When the field we are copying is an array, create index variables for
@@ -3154,7 +3237,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
= SemaRef.Context.getAsConstantArrayType(BaseType)) {
InitializingArray = true;
// Create the iteration variable for this array index.
- IdentifierInfo *IterationVarName = 0;
+ IdentifierInfo *IterationVarName = nullptr;
{
SmallString<8> Str;
llvm::raw_svector_ostream OS(Str);
@@ -3173,13 +3256,13 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
= SemaRef.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc);
assert(!IterationVarRef.isInvalid() &&
"Reference to invented variable cannot fail!");
- IterationVarRef = SemaRef.DefaultLvalueConversion(IterationVarRef.take());
+ IterationVarRef = SemaRef.DefaultLvalueConversion(IterationVarRef.get());
assert(!IterationVarRef.isInvalid() &&
"Conversion of invented variable cannot fail!");
// Subscript the array with this iteration variable.
- CtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(CtorArg.take(), Loc,
- IterationVarRef.take(),
+ CtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(CtorArg.get(), Loc,
+ IterationVarRef.get(),
Loc);
if (CtorArg.isInvalid())
return true;
@@ -3189,7 +3272,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
// The array subscript expression is an lvalue, which is wrong for moving.
if (Moving && InitializingArray)
- CtorArg = CastForMoving(SemaRef, CtorArg.take());
+ CtorArg = CastForMoving(SemaRef, CtorArg.get());
// Construct the entity that we will be initializing. For an array, this
// will be first element in the array, which may require several levels
@@ -3209,7 +3292,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
InitializationKind InitKind =
InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation());
- Expr *CtorArgE = CtorArg.takeAs<Expr>();
+ Expr *CtorArgE = CtorArg.getAs<Expr>();
InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind, CtorArgE);
ExprResult MemberInit
@@ -3225,11 +3308,11 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
CXXMemberInit
= new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect,
Loc, Loc,
- MemberInit.takeAs<Expr>(),
+ MemberInit.getAs<Expr>(),
Loc);
} else
CXXMemberInit = CXXCtorInitializer::Create(SemaRef.Context, Field, Loc,
- Loc, MemberInit.takeAs<Expr>(),
+ Loc, MemberInit.getAs<Expr>(),
Loc,
IndexVariables.data(),
IndexVariables.size());
@@ -3308,7 +3391,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
}
// Nothing to initialize.
- CXXMemberInit = 0;
+ CXXMemberInit = nullptr;
return false;
}
@@ -3320,6 +3403,7 @@ struct BaseAndFieldInfo {
ImplicitInitializerKind IIK;
llvm::DenseMap<const void *, CXXCtorInitializer*> AllBaseFields;
SmallVector<CXXCtorInitializer*, 8> AllToInit;
+ llvm::DenseMap<TagDecl*, FieldDecl*> ActiveUnionMember;
BaseAndFieldInfo(Sema &S, CXXConstructorDecl *Ctor, bool ErrorsInInits)
: S(S), Ctor(Ctor), AnyErrorsInInits(ErrorsInInits) {
@@ -3357,20 +3441,48 @@ struct BaseAndFieldInfo {
return false;
}
-};
-}
-/// \brief Determine whether the given indirect field declaration is somewhere
-/// within an anonymous union.
-static bool isWithinAnonymousUnion(IndirectFieldDecl *F) {
- for (IndirectFieldDecl::chain_iterator C = F->chain_begin(),
- CEnd = F->chain_end();
- C != CEnd; ++C)
- if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>((*C)->getDeclContext()))
- if (Record->isUnion())
+ bool isInactiveUnionMember(FieldDecl *Field) {
+ RecordDecl *Record = Field->getParent();
+ if (!Record->isUnion())
+ return false;
+
+ if (FieldDecl *Active =
+ ActiveUnionMember.lookup(Record->getCanonicalDecl()))
+ return Active != Field->getCanonicalDecl();
+
+ // In an implicit copy or move constructor, ignore any in-class initializer.
+ if (isImplicitCopyOrMove())
+ return true;
+
+ // If there's no explicit initialization, the field is active only if it
+ // has an in-class initializer...
+ if (Field->hasInClassInitializer())
+ return false;
+ // ... or it's an anonymous struct or union whose class has an in-class
+ // initializer.
+ if (!Field->isAnonymousStructOrUnion())
+ return true;
+ CXXRecordDecl *FieldRD = Field->getType()->getAsCXXRecordDecl();
+ return !FieldRD->hasInClassInitializer();
+ }
+
+ /// \brief Determine whether the given field is, or is within, a union member
+ /// that is inactive (because there was an initializer given for a different
+ /// member of the union, or because the union was not initialized at all).
+ bool isWithinInactiveUnionMember(FieldDecl *Field,
+ IndirectFieldDecl *Indirect) {
+ if (!Indirect)
+ return isInactiveUnionMember(Field);
+
+ for (auto *C : Indirect->chain()) {
+ FieldDecl *Field = dyn_cast<FieldDecl>(C);
+ if (Field && isInactiveUnionMember(Field))
return true;
-
- return false;
+ }
+ return false;
+ }
+};
}
/// \brief Determine whether the given type is an incomplete or zero-lenfgth
@@ -3391,17 +3503,30 @@ static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) {
static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
FieldDecl *Field,
- IndirectFieldDecl *Indirect = 0) {
+ IndirectFieldDecl *Indirect = nullptr) {
if (Field->isInvalidDecl())
return false;
// Overwhelmingly common case: we have a direct initializer for this field.
- if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(Field))
+ if (CXXCtorInitializer *Init =
+ Info.AllBaseFields.lookup(Field->getCanonicalDecl()))
return Info.addFieldInitializer(Init);
- // C++11 [class.base.init]p8: if the entity is a non-static data member that
- // has a brace-or-equal-initializer, the entity is initialized as specified
- // in [dcl.init].
+ // C++11 [class.base.init]p8:
+ // if the entity is a non-static data member that has a
+ // brace-or-equal-initializer and either
+ // -- the constructor's class is a union and no other variant member of that
+ // union is designated by a mem-initializer-id or
+ // -- the constructor's class is not a union, and, if the entity is a member
+ // of an anonymous union, no other member of that union is designated by
+ // a mem-initializer-id,
+ // the entity is initialized as specified in [dcl.init].
+ //
+ // We also apply the same rules to handle anonymous structs within anonymous
+ // unions.
+ if (Info.isWithinInactiveUnionMember(Field, Indirect))
+ return false;
+
if (Field->hasInClassInitializer() && !Info.isImplicitCopyOrMove()) {
Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context,
Info.Ctor->getLocation(), Field);
@@ -3419,12 +3544,6 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
return Info.addFieldInitializer(Init);
}
- // Don't build an implicit initializer for union members if none was
- // explicitly specified.
- if (Field->getParent()->isUnion() ||
- (Indirect && isWithinAnonymousUnion(Indirect)))
- return false;
-
// Don't initialize incomplete or zero-length arrays.
if (isIncompleteOrZeroLengthArrayType(SemaRef.Context, Field->getType()))
return false;
@@ -3435,7 +3554,7 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
if (Info.AnyErrorsInInits)
return false;
- CXXCtorInitializer *Init = 0;
+ CXXCtorInitializer *Init = nullptr;
if (BuildImplicitMemberInitializer(Info.S, Info.Ctor, Info.IIK, Field,
Indirect, Init))
return true;
@@ -3502,24 +3621,35 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
if (Member->isBaseInitializer())
Info.AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
- else
- Info.AllBaseFields[Member->getAnyMember()] = Member;
+ else {
+ Info.AllBaseFields[Member->getAnyMember()->getCanonicalDecl()] = Member;
+
+ if (IndirectFieldDecl *F = Member->getIndirectMember()) {
+ for (auto *C : F->chain()) {
+ FieldDecl *FD = dyn_cast<FieldDecl>(C);
+ if (FD && FD->getParent()->isUnion())
+ Info.ActiveUnionMember.insert(std::make_pair(
+ FD->getParent()->getCanonicalDecl(), FD->getCanonicalDecl()));
+ }
+ } else if (FieldDecl *FD = Member->getMember()) {
+ if (FD->getParent()->isUnion())
+ Info.ActiveUnionMember.insert(std::make_pair(
+ FD->getParent()->getCanonicalDecl(), FD->getCanonicalDecl()));
+ }
+ }
}
// Keep track of the direct virtual bases.
llvm::SmallPtrSet<CXXBaseSpecifier *, 16> DirectVBases;
- for (CXXRecordDecl::base_class_iterator I = ClassDecl->bases_begin(),
- E = ClassDecl->bases_end(); I != E; ++I) {
- if (I->isVirtual())
- DirectVBases.insert(I);
+ for (auto &I : ClassDecl->bases()) {
+ if (I.isVirtual())
+ DirectVBases.insert(&I);
}
// Push virtual bases before others.
- for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(),
- E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
-
+ for (auto &VBase : ClassDecl->vbases()) {
if (CXXCtorInitializer *Value
- = Info.AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) {
+ = Info.AllBaseFields.lookup(VBase.getType()->getAs<RecordType>())) {
// [class.base.init]p7, per DR257:
// A mem-initializer where the mem-initializer-id names a virtual base
// class is ignored during execution of a constructor of any class that
@@ -3528,7 +3658,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
// FIXME: Provide a fixit to remove the base specifier. This requires
// tracking the location of the associated comma for a base specifier.
Diag(Value->getSourceLocation(), diag::warn_abstract_vbase_init_ignored)
- << VBase->getType() << ClassDecl;
+ << VBase.getType() << ClassDecl;
DiagnoseAbstractType(ClassDecl);
}
@@ -3538,10 +3668,10 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
// If a given [...] base class is not named by a mem-initializer-id
// [...] and the entity is not a virtual base class of an abstract
// class, then [...] the entity is default-initialized.
- bool IsInheritedVirtualBase = !DirectVBases.count(VBase);
+ bool IsInheritedVirtualBase = !DirectVBases.count(&VBase);
CXXCtorInitializer *CXXBaseInit;
if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK,
- VBase, IsInheritedVirtualBase,
+ &VBase, IsInheritedVirtualBase,
CXXBaseInit)) {
HadError = true;
continue;
@@ -3552,19 +3682,18 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
}
// Non-virtual bases.
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
- E = ClassDecl->bases_end(); Base != E; ++Base) {
+ for (auto &Base : ClassDecl->bases()) {
// Virtuals are in the virtual base list and already constructed.
- if (Base->isVirtual())
+ if (Base.isVirtual())
continue;
if (CXXCtorInitializer *Value
- = Info.AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) {
+ = Info.AllBaseFields.lookup(Base.getType()->getAs<RecordType>())) {
Info.AllToInit.push_back(Value);
} else if (!AnyErrors) {
CXXCtorInitializer *CXXBaseInit;
if (BuildImplicitBaseInitializer(*this, Constructor, Info.IIK,
- Base, /*IsInheritedVirtualBase=*/false,
+ &Base, /*IsInheritedVirtualBase=*/false,
CXXBaseInit)) {
HadError = true;
continue;
@@ -3575,10 +3704,8 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
}
// Fields.
- for (DeclContext::decl_iterator Mem = ClassDecl->decls_begin(),
- MemEnd = ClassDecl->decls_end();
- Mem != MemEnd; ++Mem) {
- if (FieldDecl *F = dyn_cast<FieldDecl>(*Mem)) {
+ for (auto *Mem : ClassDecl->decls()) {
+ if (auto *F = dyn_cast<FieldDecl>(Mem)) {
// C++ [class.bit]p2:
// A declaration for a bit-field that omits the identifier declares an
// unnamed bit-field. Unnamed bit-fields are not members and cannot be
@@ -3601,7 +3728,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
if (Info.isImplicitCopyOrMove())
continue;
- if (IndirectFieldDecl *F = dyn_cast<IndirectFieldDecl>(*Mem)) {
+ if (auto *F = dyn_cast<IndirectFieldDecl>(Mem)) {
if (F->getType()->isIncompleteArrayType()) {
assert(ClassDecl->hasFlexibleArrayMember() &&
"Incomplete array type is not valid");
@@ -3638,13 +3765,12 @@ static void PopulateKeysForFields(FieldDecl *Field, SmallVectorImpl<const void*>
if (const RecordType *RT = Field->getType()->getAs<RecordType>()) {
const RecordDecl *RD = RT->getDecl();
if (RD->isAnonymousStructOrUnion()) {
- for (RecordDecl::field_iterator Field = RD->field_begin(),
- E = RD->field_end(); Field != E; ++Field)
- PopulateKeysForFields(*Field, IdealInits);
+ for (auto *Field : RD->fields())
+ PopulateKeysForFields(Field, IdealInits);
return;
}
}
- IdealInits.push_back(Field);
+ IdealInits.push_back(Field->getCanonicalDecl());
}
static const void *GetKeyForBase(ASTContext &Context, QualType BaseType) {
@@ -3656,7 +3782,7 @@ static const void *GetKeyForMember(ASTContext &Context,
if (!Member->isAnyMemberInitializer())
return GetKeyForBase(Context, QualType(Member->getBaseClass(), 0));
- return Member->getAnyMember();
+ return Member->getAnyMember()->getCanonicalDecl();
}
static void DiagnoseBaseOrMemInitializerOrder(
@@ -3670,9 +3796,8 @@ static void DiagnoseBaseOrMemInitializerOrder(
bool ShouldCheckOrder = false;
for (unsigned InitIndex = 0; InitIndex != Inits.size(); ++InitIndex) {
CXXCtorInitializer *Init = Inits[InitIndex];
- if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order,
- Init->getSourceLocation())
- != DiagnosticsEngine::Ignored) {
+ if (!SemaRef.Diags.isIgnored(diag::warn_initializer_out_of_order,
+ Init->getSourceLocation())) {
ShouldCheckOrder = true;
break;
}
@@ -3688,32 +3813,28 @@ static void DiagnoseBaseOrMemInitializerOrder(
const CXXRecordDecl *ClassDecl = Constructor->getParent();
// 1. Virtual bases.
- for (CXXRecordDecl::base_class_const_iterator VBase =
- ClassDecl->vbases_begin(),
- E = ClassDecl->vbases_end(); VBase != E; ++VBase)
- IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, VBase->getType()));
+ for (const auto &VBase : ClassDecl->vbases())
+ IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, VBase.getType()));
// 2. Non-virtual bases.
- for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(),
- E = ClassDecl->bases_end(); Base != E; ++Base) {
- if (Base->isVirtual())
+ for (const auto &Base : ClassDecl->bases()) {
+ if (Base.isVirtual())
continue;
- IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, Base->getType()));
+ IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, Base.getType()));
}
// 3. Direct fields.
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- E = ClassDecl->field_end(); Field != E; ++Field) {
+ for (auto *Field : ClassDecl->fields()) {
if (Field->isUnnamedBitfield())
continue;
- PopulateKeysForFields(*Field, IdealInitKeys);
+ PopulateKeysForFields(Field, IdealInitKeys);
}
unsigned NumIdealInits = IdealInitKeys.size();
unsigned IdealIndex = 0;
- CXXCtorInitializer *PrevInit = 0;
+ CXXCtorInitializer *PrevInit = nullptr;
for (unsigned InitIndex = 0; InitIndex != Inits.size(); ++InitIndex) {
CXXCtorInitializer *Init = Inits[InitIndex];
const void *InitKey = GetKeyForMember(SemaRef.Context, Init);
@@ -3855,13 +3976,12 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
Init->setSourceOrder(i);
if (Init->isAnyMemberInitializer()) {
- FieldDecl *Field = Init->getAnyMember();
- if (CheckRedundantInit(*this, Init, Members[Field]) ||
+ const void *Key = GetKeyForMember(Context, Init);
+ if (CheckRedundantInit(*this, Init, Members[Key]) ||
CheckRedundantUnionInit(*this, Init, MemberUnions))
HadError = true;
} else if (Init->isBaseInitializer()) {
- const void *Key =
- GetKeyForBase(Context, QualType(Init->getBaseClass(), 0));
+ const void *Key = GetKeyForMember(Context, Init);
if (CheckRedundantInit(*this, Init, Members[Key]))
HadError = true;
} else {
@@ -3903,9 +4023,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
// emitted, and we currently don't say.
// Non-static data members.
- for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
- E = ClassDecl->field_end(); I != E; ++I) {
- FieldDecl *Field = *I;
+ for (auto *Field : ClassDecl->fields()) {
if (Field->isInvalidDecl())
continue;
@@ -3942,13 +4060,12 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases;
// Bases.
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
- E = ClassDecl->bases_end(); Base != E; ++Base) {
+ for (const auto &Base : ClassDecl->bases()) {
// Bases are always records in a well-formed non-dependent class.
- const RecordType *RT = Base->getType()->getAs<RecordType>();
+ const RecordType *RT = Base.getType()->getAs<RecordType>();
// Remember direct virtual bases.
- if (Base->isVirtual())
+ if (Base.isVirtual())
DirectVirtualBases.insert(RT);
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
@@ -3962,10 +4079,10 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
assert(Dtor && "No dtor found for BaseClassDecl!");
// FIXME: caret should be on the start of the class name
- CheckDestructorAccess(Base->getLocStart(), Dtor,
+ CheckDestructorAccess(Base.getLocStart(), Dtor,
PDiag(diag::err_access_dtor_base)
- << Base->getType()
- << Base->getSourceRange(),
+ << Base.getType()
+ << Base.getSourceRange(),
Context.getTypeDeclType(ClassDecl));
MarkFunctionReferenced(Location, Dtor);
@@ -3973,11 +4090,9 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
}
// Virtual bases.
- for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(),
- E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
-
+ for (const auto &VBase : ClassDecl->vbases()) {
// Bases are always records in a well-formed non-dependent class.
- const RecordType *RT = VBase->getType()->castAs<RecordType>();
+ const RecordType *RT = VBase.getType()->castAs<RecordType>();
// Ignore direct virtual bases.
if (DirectVirtualBases.count(RT))
@@ -3995,13 +4110,13 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
if (CheckDestructorAccess(
ClassDecl->getLocation(), Dtor,
PDiag(diag::err_access_dtor_vbase)
- << Context.getTypeDeclType(ClassDecl) << VBase->getType(),
+ << Context.getTypeDeclType(ClassDecl) << VBase.getType(),
Context.getTypeDeclType(ClassDecl)) ==
AR_accessible) {
CheckDerivedToBaseConversion(
- Context.getTypeDeclType(ClassDecl), VBase->getType(),
+ Context.getTypeDeclType(ClassDecl), VBase.getType(),
diag::err_access_dtor_vbase, 0, ClassDecl->getLocation(),
- SourceRange(), DeclarationName(), 0);
+ SourceRange(), DeclarationName(), nullptr);
}
MarkFunctionReferenced(Location, Dtor);
@@ -4030,7 +4145,7 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
NonAbstractTypeDiagnoser(unsigned DiagID, AbstractDiagSelID SelID)
: TypeDiagnoser(DiagID == 0), DiagID(DiagID), SelID(SelID) { }
- void diagnose(Sema &S, SourceLocation Loc, QualType T) LLVM_OVERRIDE {
+ void diagnose(Sema &S, SourceLocation Loc, QualType T) override {
if (Suppressed) return;
if (SelID == -1)
S.Diag(Loc, DiagID) << T;
@@ -4172,12 +4287,12 @@ struct CheckAbstractUsage {
}
void Check(FunctionProtoTypeLoc TL, Sema::AbstractDiagSelID Sel) {
- Visit(TL.getResultLoc(), Sema::AbstractReturnType);
- for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
- if (!TL.getArg(I))
+ Visit(TL.getReturnLoc(), Sema::AbstractReturnType);
+ for (unsigned I = 0, E = TL.getNumParams(); I != E; ++I) {
+ if (!TL.getParam(I))
continue;
-
- TypeSourceInfo *TSI = TL.getArg(I)->getTypeSourceInfo();
+
+ TypeSourceInfo *TSI = TL.getParam(I)->getTypeSourceInfo();
if (TSI) Visit(TSI->getTypeLoc(), Sema::AbstractParamType);
}
}
@@ -4267,9 +4382,7 @@ static void CheckAbstractClassUsage(AbstractUsageInfo &Info,
/// Check for invalid uses of an abstract type within a class definition.
static void CheckAbstractClassUsage(AbstractUsageInfo &Info,
CXXRecordDecl *RD) {
- for (CXXRecordDecl::decl_iterator
- I = RD->decls_begin(), E = RD->decls_end(); I != E; ++I) {
- Decl *D = *I;
+ for (auto *D : RD->decls()) {
if (D->isImplicit()) continue;
// Methods and method templates.
@@ -4299,6 +4412,77 @@ static void CheckAbstractClassUsage(AbstractUsageInfo &Info,
}
}
+/// \brief Check class-level dllimport/dllexport attribute.
+static void checkDLLAttribute(Sema &S, CXXRecordDecl *Class) {
+ Attr *ClassAttr = getDLLAttr(Class);
+ if (!ClassAttr)
+ return;
+
+ bool ClassExported = ClassAttr->getKind() == attr::DLLExport;
+
+ // Force declaration of implicit members so they can inherit the attribute.
+ S.ForceDeclarationOfImplicitMembers(Class);
+
+ // FIXME: MSVC's docs say all bases must be exportable, but this doesn't
+ // seem to be true in practice?
+
+ for (Decl *Member : Class->decls()) {
+ VarDecl *VD = dyn_cast<VarDecl>(Member);
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member);
+
+ // Only methods and static fields inherit the attributes.
+ if (!VD && !MD)
+ continue;
+
+ // Don't process deleted methods.
+ if (MD && MD->isDeleted())
+ continue;
+
+ if (MD && MD->isMoveAssignmentOperator() && !ClassExported &&
+ MD->isInlined()) {
+ // Current MSVC versions don't export the move assignment operators, so
+ // don't attempt to import them if we have a definition.
+ continue;
+ }
+
+ if (InheritableAttr *MemberAttr = getDLLAttr(Member)) {
+ if (S.Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+ !MemberAttr->isInherited() && !ClassAttr->isInherited()) {
+ S.Diag(MemberAttr->getLocation(),
+ diag::err_attribute_dll_member_of_dll_class)
+ << MemberAttr << ClassAttr;
+ S.Diag(ClassAttr->getLocation(), diag::note_previous_attribute);
+ Member->setInvalidDecl();
+ continue;
+ }
+ } else {
+ auto *NewAttr =
+ cast<InheritableAttr>(ClassAttr->clone(S.getASTContext()));
+ NewAttr->setInherited(true);
+ Member->addAttr(NewAttr);
+ }
+
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) {
+ if (ClassExported) {
+ if (MD->isUserProvided()) {
+ // Instantiate non-default methods.
+ S.MarkFunctionReferenced(Class->getLocation(), MD);
+ } else if (!MD->isTrivial() || MD->isExplicitlyDefaulted() ||
+ MD->isCopyAssignmentOperator() ||
+ MD->isMoveAssignmentOperator()) {
+ // Instantiate non-trivial or explicitly defaulted methods, and the
+ // copy assignment / move assignment operators.
+ S.MarkFunctionReferenced(Class->getLocation(), MD);
+ // Resolve its exception specification; CodeGen needs it.
+ auto *FPT = MD->getType()->getAs<FunctionProtoType>();
+ S.ResolveExceptionSpec(Class->getLocation(), FPT);
+ S.ActOnFinishInlineMethodDef(MD);
+ }
+ }
+ }
+ }
+}
+
/// \brief Perform semantic checks on a class definition that has been
/// completing, introducing implicitly-declared members, checking for
/// abstract types, etc.
@@ -4318,9 +4502,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
!Record->isAggregate() && !Record->hasUserDeclaredConstructor() &&
!Record->isLambda()) {
bool Complained = false;
- for (RecordDecl::field_iterator F = Record->field_begin(),
- FEnd = Record->field_end();
- F != FEnd; ++F) {
+ for (const auto *F : Record->fields()) {
if (F->hasInClassInitializer() || F->isUnnamedBitfield())
continue;
@@ -4367,7 +4549,8 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
// Warn if the class has virtual methods but non-virtual public destructor.
if (Record->isPolymorphic() && !Record->isDependentType()) {
CXXDestructorDecl *dtor = Record->getDestructor();
- if (!dtor || (!dtor->isVirtual() && dtor->getAccess() == AS_public))
+ if ((!dtor || (!dtor->isVirtual() && dtor->getAccess() == AS_public)) &&
+ !Record->hasAttr<FinalAttr>())
Diag(dtor ? dtor->getLocation() : Record->getLocation(),
diag::warn_non_virtual_dtor) << Context.getRecordType(Record);
}
@@ -4381,27 +4564,25 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}
if (!Record->isDependentType()) {
- for (CXXRecordDecl::method_iterator M = Record->method_begin(),
- MEnd = Record->method_end();
- M != MEnd; ++M) {
+ for (auto *M : Record->methods()) {
// See if a method overloads virtual methods in a base
// class without overriding any.
if (!M->isStatic())
- DiagnoseHiddenVirtualMethods(*M);
+ DiagnoseHiddenVirtualMethods(M);
// Check whether the explicitly-defaulted special members are valid.
if (!M->isInvalidDecl() && M->isExplicitlyDefaulted())
- CheckExplicitlyDefaultedSpecialMember(*M);
+ CheckExplicitlyDefaultedSpecialMember(M);
// For an explicitly defaulted or deleted special member, we defer
// determining triviality until the class is complete. That time is now!
if (!M->isImplicit() && !M->isUserProvided()) {
- CXXSpecialMember CSM = getSpecialMember(*M);
+ CXXSpecialMember CSM = getSpecialMember(M);
if (CSM != CXXInvalid) {
- M->setTrivial(SpecialMemberIsTrivial(*M, CSM));
+ M->setTrivial(SpecialMemberIsTrivial(M, CSM));
// Inform the class that we've finished declaring this member.
- Record->finishedDefaultedOrDeletedMember(*M);
+ Record->finishedDefaultedOrDeletedMember(M);
}
}
}
@@ -4420,10 +4601,8 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
// destructor for the class is trivial.
if (LangOpts.CPlusPlus11 && !Record->isDependentType() &&
!Record->isLiteral() && !Record->getNumVBases()) {
- for (CXXRecordDecl::method_iterator M = Record->method_begin(),
- MEnd = Record->method_end();
- M != MEnd; ++M) {
- if (M->isConstexpr() && M->isInstance() && !isa<CXXConstructorDecl>(*M)) {
+ for (const auto *M : Record->methods()) {
+ if (M->isConstexpr() && M->isInstance() && !isa<CXXConstructorDecl>(M)) {
switch (Record->getTemplateSpecializationKind()) {
case TSK_ImplicitInstantiation:
case TSK_ExplicitInstantiationDeclaration:
@@ -4446,11 +4625,18 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}
}
- // Check to see if we're trying to lay out a struct using the ms_struct
- // attribute that is dynamic.
- if (Record->isMsStruct(Context) && Record->isDynamicClass()) {
- Diag(Record->getLocation(), diag::warn_pragma_ms_struct_failed);
- Record->dropAttr<MsStructAttr>();
+ // ms_struct is a request to use the same ABI rules as MSVC. Check
+ // whether this class uses any C++ features that are implemented
+ // completely differently in MSVC, and if so, emit a diagnostic.
+ // That diagnostic defaults to an error, but we allow projects to
+ // map it down to a warning (or ignore it). It's a fairly common
+ // practice among users of the ms_struct pragma to mass-annotate
+ // headers, sweeping up a bunch of types that the project doesn't
+ // really rely on MSVC-compatible layout for. We must therefore
+ // support "ms_struct except for C++ stuff" as a secondary ABI.
+ if (Record->isMsStruct(Context) &&
+ (Record->isPolymorphic() || Record->getNumBases())) {
+ Diag(Record->getLocation(), diag::warn_cxx_ms_struct);
}
// Declare inheriting constructors. We do this eagerly here because:
@@ -4461,16 +4647,47 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
// instantiated (e.g. meta-functions). This doesn't apply to classes that
// have inheriting constructors.
DeclareInheritingConstructors(Record);
+
+ checkDLLAttribute(*this, Record);
+}
+
+/// Look up the special member function that would be called by a special
+/// member function for a subobject of class type.
+///
+/// \param Class The class type of the subobject.
+/// \param CSM The kind of special member function.
+/// \param FieldQuals If the subobject is a field, its cv-qualifiers.
+/// \param ConstRHS True if this is a copy operation with a const object
+/// on its RHS, that is, if the argument to the outer special member
+/// function is 'const' and this is not a field marked 'mutable'.
+static Sema::SpecialMemberOverloadResult *lookupCallFromSpecialMember(
+ Sema &S, CXXRecordDecl *Class, Sema::CXXSpecialMember CSM,
+ unsigned FieldQuals, bool ConstRHS) {
+ unsigned LHSQuals = 0;
+ if (CSM == Sema::CXXCopyAssignment || CSM == Sema::CXXMoveAssignment)
+ LHSQuals = FieldQuals;
+
+ unsigned RHSQuals = FieldQuals;
+ if (CSM == Sema::CXXDefaultConstructor || CSM == Sema::CXXDestructor)
+ RHSQuals = 0;
+ else if (ConstRHS)
+ RHSQuals |= Qualifiers::Const;
+
+ return S.LookupSpecialMember(Class, CSM,
+ RHSQuals & Qualifiers::Const,
+ RHSQuals & Qualifiers::Volatile,
+ false,
+ LHSQuals & Qualifiers::Const,
+ LHSQuals & Qualifiers::Volatile);
}
/// Is the special member function which would be selected to perform the
/// specified operation on the specified class type a constexpr constructor?
static bool specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
Sema::CXXSpecialMember CSM,
- bool ConstArg) {
+ unsigned Quals, bool ConstRHS) {
Sema::SpecialMemberOverloadResult *SMOR =
- S.LookupSpecialMember(ClassDecl, CSM, ConstArg,
- false, false, false, false);
+ lookupCallFromSpecialMember(S, ClassDecl, CSM, Quals, ConstRHS);
if (!SMOR || !SMOR->getMethod())
// A constructor we wouldn't select can't be "involved in initializing"
// anything.
@@ -4540,14 +4757,12 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
// sub-objects shall be a constexpr constructor;
// -- the assignment operator selected to copy/move each direct base
// class is a constexpr function, and
- for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
- BEnd = ClassDecl->bases_end();
- B != BEnd; ++B) {
- const RecordType *BaseType = B->getType()->getAs<RecordType>();
+ for (const auto &B : ClassDecl->bases()) {
+ const RecordType *BaseType = B.getType()->getAs<RecordType>();
if (!BaseType) continue;
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, ConstArg))
+ if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg))
return false;
}
@@ -4555,18 +4770,18 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
// [...] shall be a constexpr constructor;
// -- every non-static data member and base class sub-object shall be
// initialized
- // -- for each non-stastic data member of X that is of class type (or array
+ // -- for each non-static data member of X that is of class type (or array
// thereof), the assignment operator selected to copy/move that member is
// a constexpr function
- for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
- FEnd = ClassDecl->field_end();
- F != FEnd; ++F) {
+ for (const auto *F : ClassDecl->fields()) {
if (F->isInvalidDecl())
continue;
- if (const RecordType *RecordTy =
- S.Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
+ QualType BaseType = S.Context.getBaseElementType(F->getType());
+ if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) {
CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
- if (!specialMemberIsConstexpr(S, FieldRecDecl, CSM, ConstArg))
+ if (!specialMemberIsConstexpr(S, FieldRecDecl, CSM,
+ BaseType.getCVRQualifiers(),
+ ConstArg && !F->isMutable()))
return false;
}
}
@@ -4598,15 +4813,6 @@ computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) {
return S.ComputeInheritingCtorExceptionSpec(cast<CXXConstructorDecl>(MD));
}
-static void
-updateExceptionSpec(Sema &S, FunctionDecl *FD, const FunctionProtoType *FPT,
- const Sema::ImplicitExceptionSpecification &ExceptSpec) {
- FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
- ExceptSpec.getEPI(EPI);
- FD->setType(S.Context.getFunctionType(FPT->getResultType(),
- FPT->getArgTypes(), EPI));
-}
-
static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S,
CXXMethodDecl *MD) {
FunctionProtoType::ExtProtoInfo EPI;
@@ -4631,8 +4837,11 @@ void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD)
ImplicitExceptionSpecification ExceptSpec =
computeImplicitExceptionSpec(*this, Loc, MD);
+ FunctionProtoType::ExtProtoInfo EPI;
+ ExceptSpec.getEPI(EPI);
+
// Update the type of the special member to use it.
- updateExceptionSpec(*this, MD, FPT, ExceptSpec);
+ UpdateExceptionSpec(MD, EPI);
// A user-provided destructor can be defined outside the class. When that
// happens, be sure to update the exception specification on both
@@ -4640,8 +4849,7 @@ void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD)
const FunctionProtoType *CanonicalFPT =
MD->getCanonicalDecl()->getType()->castAs<FunctionProtoType>();
if (CanonicalFPT->getExceptionSpecType() == EST_Unevaluated)
- updateExceptionSpec(*this, MD->getCanonicalDecl(),
- CanonicalFPT, ExceptSpec);
+ UpdateExceptionSpec(MD->getCanonicalDecl(), EPI);
}
void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
@@ -4691,7 +4899,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
QualType ReturnType = Context.VoidTy;
if (CSM == CXXCopyAssignment || CSM == CXXMoveAssignment) {
// Check for return type matching.
- ReturnType = Type->getResultType();
+ ReturnType = Type->getReturnType();
QualType ExpectedReturnType =
Context.getLValueReferenceType(Context.getTypeDeclType(RD));
if (!Context.hasSameType(ReturnType, ExpectedReturnType)) {
@@ -4709,7 +4917,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
}
// Check for parameter type matching.
- QualType ArgType = ExpectedParams ? Type->getArgType(0) : QualType();
+ QualType ArgType = ExpectedParams ? Type->getParamType(0) : QualType();
bool HasConstParam = false;
if (ExpectedParams && ArgType->isReferenceType()) {
// Argument must be reference to possibly-const T.
@@ -4803,6 +5011,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// [For a] user-provided explicitly-defaulted function [...] if such a
// function is implicitly defined as deleted, the program is ill-formed.
Diag(MD->getLocation(), diag::err_out_of_line_default_deletes) << CSM;
+ ShouldDeleteSpecialMember(MD, CSM, /*Diagnose*/true);
HadError = true;
}
}
@@ -4865,7 +5074,7 @@ struct SpecialMemberDeletionInfo {
bool Diagnose;
// Properties of the special member, computed for convenience.
- bool IsConstructor, IsAssignment, IsMove, ConstArg, VolatileArg;
+ bool IsConstructor, IsAssignment, IsMove, ConstArg;
SourceLocation Loc;
bool AllFieldsAreConst;
@@ -4874,7 +5083,7 @@ struct SpecialMemberDeletionInfo {
Sema::CXXSpecialMember CSM, bool Diagnose)
: S(S), MD(MD), CSM(CSM), Diagnose(Diagnose),
IsConstructor(false), IsAssignment(false), IsMove(false),
- ConstArg(false), VolatileArg(false), Loc(MD->getLocation()),
+ ConstArg(false), Loc(MD->getLocation()),
AllFieldsAreConst(true) {
switch (CSM) {
case Sema::CXXDefaultConstructor:
@@ -4899,8 +5108,9 @@ struct SpecialMemberDeletionInfo {
}
if (MD->getNumParams()) {
- ConstArg = MD->getParamDecl(0)->getType().isConstQualified();
- VolatileArg = MD->getParamDecl(0)->getType().isVolatileQualified();
+ if (const ReferenceType *RT =
+ MD->getParamDecl(0)->getType()->getAs<ReferenceType>())
+ ConstArg = RT->getPointeeType().isConstQualified();
}
}
@@ -4908,21 +5118,9 @@ struct SpecialMemberDeletionInfo {
/// Look up the corresponding special member in the given class.
Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class,
- unsigned Quals) {
- unsigned TQ = MD->getTypeQualifiers();
- // cv-qualifiers on class members don't affect default ctor / dtor calls.
- if (CSM == Sema::CXXDefaultConstructor || CSM == Sema::CXXDestructor)
- Quals = 0;
- // cv-qualifiers on class members affect the type of both '*this' and the
- // argument for an assignment.
- if (IsAssignment)
- TQ |= Quals;
- return S.LookupSpecialMember(Class, CSM,
- ConstArg || (Quals & Qualifiers::Const),
- VolatileArg || (Quals & Qualifiers::Volatile),
- MD->getRefQualifier() == RQ_RValue,
- TQ & Qualifiers::Const,
- TQ & Qualifiers::Volatile);
+ unsigned Quals, bool IsMutable) {
+ return lookupCallFromSpecialMember(S, Class, CSM, Quals,
+ ConstArg && !IsMutable);
}
typedef llvm::PointerUnion<CXXBaseSpecifier*, FieldDecl*> Subobject;
@@ -5017,6 +5215,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject(
CXXRecordDecl *Class, Subobject Subobj, unsigned Quals) {
FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>();
+ bool IsMutable = Field && Field->isMutable();
// C++11 [class.ctor]p5:
// -- any direct or virtual base class, or non-static data member with no
@@ -5034,7 +5233,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject(
// that is deleted or inaccessible
if (!(CSM == Sema::CXXDefaultConstructor &&
Field && Field->hasInClassInitializer()) &&
- shouldDeleteForSubobjectCall(Subobj, lookupIn(Class, Quals), false))
+ shouldDeleteForSubobjectCall(Subobj, lookupIn(Class, Quals, IsMutable),
+ false))
return true;
// C++11 [class.ctor]p5, C++11 [class.copy]p11:
@@ -5122,9 +5322,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
bool AllVariantFieldsAreConst = true;
// FIXME: Handle anonymous unions declared within anonymous unions.
- for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(),
- UE = FieldRecord->field_end();
- UI != UE; ++UI) {
+ for (auto *UI : FieldRecord->fields()) {
QualType UnionFieldType = S.Context.getBaseElementType(UI->getType());
if (!UnionFieldType.isConstQualified())
@@ -5132,14 +5330,14 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
CXXRecordDecl *UnionFieldRecord = UnionFieldType->getAsCXXRecordDecl();
if (UnionFieldRecord &&
- shouldDeleteForClassSubobject(UnionFieldRecord, *UI,
+ shouldDeleteForClassSubobject(UnionFieldRecord, UI,
UnionFieldType.getCVRQualifiers()))
return true;
}
// At least one member in each anonymous union must be non-const
if (CSM == Sema::CXXDefaultConstructor && AllVariantFieldsAreConst &&
- FieldRecord->field_begin() != FieldRecord->field_end()) {
+ !FieldRecord->field_empty()) {
if (Diagnose)
S.Diag(FieldRecord->getLocation(),
diag::note_deleted_default_ctor_all_const)
@@ -5167,7 +5365,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
// This is a silly definition, because it gives an empty union a deleted
// default constructor. Don't do that.
if (CSM == Sema::CXXDefaultConstructor && inUnion() && AllFieldsAreConst &&
- (MD->getParent()->field_begin() != MD->getParent()->field_end())) {
+ !MD->getParent()->field_empty()) {
if (Diagnose)
S.Diag(MD->getParent()->getLocation(),
diag::note_deleted_default_ctor_all_const)
@@ -5213,32 +5411,30 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
// operator is defined as deleted.
if (MD->isImplicit() &&
(CSM == CXXCopyConstructor || CSM == CXXCopyAssignment)) {
- CXXMethodDecl *UserDeclaredMove = 0;
+ CXXMethodDecl *UserDeclaredMove = nullptr;
// In Microsoft mode, a user-declared move only causes the deletion of the
// corresponding copy operation, not both copy operations.
if (RD->hasUserDeclaredMoveConstructor() &&
- (!getLangOpts().MicrosoftMode || CSM == CXXCopyConstructor)) {
+ (!getLangOpts().MSVCCompat || CSM == CXXCopyConstructor)) {
if (!Diagnose) return true;
// Find any user-declared move constructor.
- for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(),
- E = RD->ctor_end(); I != E; ++I) {
+ for (auto *I : RD->ctors()) {
if (I->isMoveConstructor()) {
- UserDeclaredMove = *I;
+ UserDeclaredMove = I;
break;
}
}
assert(UserDeclaredMove);
} else if (RD->hasUserDeclaredMoveAssignment() &&
- (!getLangOpts().MicrosoftMode || CSM == CXXCopyAssignment)) {
+ (!getLangOpts().MSVCCompat || CSM == CXXCopyAssignment)) {
if (!Diagnose) return true;
// Find any user-declared move assignment operator.
- for (CXXRecordDecl::method_iterator I = RD->method_begin(),
- E = RD->method_end(); I != E; ++I) {
+ for (auto *I : RD->methods()) {
if (I->isMoveAssignmentOperator()) {
- UserDeclaredMove = *I;
+ UserDeclaredMove = I;
break;
}
}
@@ -5261,7 +5457,7 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
// -- for a virtual destructor, lookup of the non-array deallocation function
// results in an ambiguity or in a function that is deleted or inaccessible
if (CSM == CXXDestructor && MD->isVirtual()) {
- FunctionDecl *OperatorDelete = 0;
+ FunctionDecl *OperatorDelete = nullptr;
DeclarationName Name =
Context.DeclarationNames.getCXXOperatorName(OO_Delete);
if (FindDeallocationFunction(MD->getLocation(), MD->getParent(), Name,
@@ -5274,26 +5470,22 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
SpecialMemberDeletionInfo SMI(*this, MD, CSM, Diagnose);
- for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
- BE = RD->bases_end(); BI != BE; ++BI)
- if (!BI->isVirtual() &&
- SMI.shouldDeleteForBase(BI))
+ for (auto &BI : RD->bases())
+ if (!BI.isVirtual() &&
+ SMI.shouldDeleteForBase(&BI))
return true;
// Per DR1611, do not consider virtual bases of constructors of abstract
// classes, since we are not going to construct them.
if (!RD->isAbstract() || !SMI.IsConstructor) {
- for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
- BE = RD->vbases_end();
- BI != BE; ++BI)
- if (SMI.shouldDeleteForBase(BI))
+ for (auto &BI : RD->vbases())
+ if (SMI.shouldDeleteForBase(&BI))
return true;
}
- for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
- FE = RD->field_end(); FI != FE; ++FI)
+ for (auto *FI : RD->fields())
if (!FI->isInvalidDecl() && !FI->isUnnamedBitfield() &&
- SMI.shouldDeleteForField(*FI))
+ SMI.shouldDeleteForField(FI))
return true;
if (SMI.shouldDeleteForAllConstMembers())
@@ -5312,9 +5504,9 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
/// member that was most likely to be intended to be trivial, if any.
static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD,
Sema::CXXSpecialMember CSM, unsigned Quals,
- CXXMethodDecl **Selected) {
+ bool ConstRHS, CXXMethodDecl **Selected) {
if (Selected)
- *Selected = 0;
+ *Selected = nullptr;
switch (CSM) {
case Sema::CXXInvalid:
@@ -5333,14 +5525,13 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD,
// If there's a default constructor which could have been trivial, dig it
// out. Otherwise, if there's any user-provided default constructor, point
// to that as an example of why there's not a trivial one.
- CXXConstructorDecl *DefCtor = 0;
+ CXXConstructorDecl *DefCtor = nullptr;
if (RD->needsImplicitDefaultConstructor())
S.DeclareImplicitDefaultConstructor(RD);
- for (CXXRecordDecl::ctor_iterator CI = RD->ctor_begin(),
- CE = RD->ctor_end(); CI != CE; ++CI) {
+ for (auto *CI : RD->ctors()) {
if (!CI->isDefaultConstructor())
continue;
- DefCtor = *CI;
+ DefCtor = CI;
if (!DefCtor->isUserProvided())
break;
}
@@ -5403,11 +5594,7 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD,
case Sema::CXXMoveAssignment:
NeedOverloadResolution:
Sema::SpecialMemberOverloadResult *SMOR =
- S.LookupSpecialMember(RD, CSM,
- Quals & Qualifiers::Const,
- Quals & Qualifiers::Volatile,
- /*RValueThis*/false, /*ConstThis*/false,
- /*VolatileThis*/false);
+ lookupCallFromSpecialMember(S, RD, CSM, Quals, ConstRHS);
// The standard doesn't describe how to behave if the lookup is ambiguous.
// We treat it as not making the member non-trivial, just like the standard
@@ -5433,10 +5620,9 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD,
}
static CXXConstructorDecl *findUserDeclaredCtor(CXXRecordDecl *RD) {
- for (CXXRecordDecl::ctor_iterator CI = RD->ctor_begin(), CE = RD->ctor_end();
- CI != CE; ++CI)
+ for (auto *CI : RD->ctors())
if (!CI->isImplicit())
- return *CI;
+ return CI;
// Look for constructor templates.
typedef CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl> tmpl_iter;
@@ -5446,7 +5632,7 @@ static CXXConstructorDecl *findUserDeclaredCtor(CXXRecordDecl *RD) {
return CD;
}
- return 0;
+ return nullptr;
}
/// The kind of subobject we are checking for triviality. The values of this
@@ -5462,7 +5648,7 @@ enum TrivialSubobjectKind {
/// Check whether the special member selected for a given type would be trivial.
static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc,
- QualType SubType,
+ QualType SubType, bool ConstRHS,
Sema::CXXSpecialMember CSM,
TrivialSubobjectKind Kind,
bool Diagnose) {
@@ -5472,10 +5658,13 @@ static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc,
CXXMethodDecl *Selected;
if (findTrivialSpecialMember(S, SubRD, CSM, SubType.getCVRQualifiers(),
- Diagnose ? &Selected : 0))
+ ConstRHS, Diagnose ? &Selected : nullptr))
return true;
if (Diagnose) {
+ if (ConstRHS)
+ SubType.addConst();
+
if (!Selected && CSM == Sema::CXXDefaultConstructor) {
S.Diag(SubobjLoc, diag::note_nontrivial_no_def_ctor)
<< Kind << SubType.getUnqualifiedType();
@@ -5511,8 +5700,7 @@ static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc,
static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD,
Sema::CXXSpecialMember CSM,
bool ConstArg, bool Diagnose) {
- for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
- FE = RD->field_end(); FI != FE; ++FI) {
+ for (const auto *FI : RD->fields()) {
if (FI->isInvalidDecl() || FI->isUnnamedBitfield())
continue;
@@ -5532,7 +5720,7 @@ static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD,
// brace-or-equal-initializer
if (CSM == Sema::CXXDefaultConstructor && FI->hasInClassInitializer()) {
if (Diagnose)
- S.Diag(FI->getLocation(), diag::note_nontrivial_in_class_init) << *FI;
+ S.Diag(FI->getLocation(), diag::note_nontrivial_in_class_init) << FI;
return false;
}
@@ -5548,10 +5736,9 @@ static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD,
return false;
}
- if (ConstArg && !FI->isMutable())
- FieldType.addConst();
- if (!checkTrivialSubobjectCall(S, FI->getLocation(), FieldType, CSM,
- TSK_Field, Diagnose))
+ bool ConstRHS = ConstArg && !FI->isMutable();
+ if (!checkTrivialSubobjectCall(S, FI->getLocation(), FieldType, ConstRHS,
+ CSM, TSK_Field, Diagnose))
return false;
}
@@ -5562,10 +5749,9 @@ static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD,
/// the given kind.
void Sema::DiagnoseNontrivial(const CXXRecordDecl *RD, CXXSpecialMember CSM) {
QualType Ty = Context.getRecordType(RD);
- if (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment)
- Ty.addConst();
- checkTrivialSubobjectCall(*this, RD->getLocation(), Ty, CSM,
+ bool ConstArg = (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment);
+ checkTrivialSubobjectCall(*this, RD->getLocation(), Ty, ConstArg, CSM,
TSK_CompleteObject, /*Diagnose*/true);
}
@@ -5648,12 +5834,9 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
// A [default constructor or destructor] is trivial if
// -- all the direct base classes have trivial [default constructors or
// destructors]
- for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
- BE = RD->bases_end(); BI != BE; ++BI)
- if (!checkTrivialSubobjectCall(*this, BI->getLocStart(),
- ConstArg ? BI->getType().withConst()
- : BI->getType(),
- CSM, TSK_BaseClass, Diagnose))
+ for (const auto &BI : RD->bases())
+ if (!checkTrivialSubobjectCall(*this, BI.getLocStart(), BI.getType(),
+ ConstArg, CSM, TSK_BaseClass, Diagnose))
return false;
// C++11 [class.ctor]p5, C++11 [class.dtor]p5:
@@ -5697,8 +5880,7 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
}
// Must have a virtual method.
- for (CXXRecordDecl::method_iterator MI = RD->method_begin(),
- ME = RD->method_end(); MI != ME; ++MI) {
+ for (const auto *MI : RD->methods()) {
if (MI->isVirtual()) {
SourceLocation MLoc = MI->getLocStart();
Diag(MLoc, diag::note_nontrivial_has_virtual) << RD << 0;
@@ -5836,8 +6018,7 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD) {
if (MD->isInvalidDecl())
return;
- if (Diags.getDiagnosticLevel(diag::warn_overloaded_virtual,
- MD->getLocation()) == DiagnosticsEngine::Ignored)
+ if (Diags.isIgnored(diag::warn_overloaded_virtual, MD->getLocation()))
return;
SmallVector<CXXMethodDecl *, 8> OverloadedMethods;
@@ -5937,47 +6118,55 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
}
}
-void Sema::ActOnReenterDeclaratorTemplateScope(Scope *S, DeclaratorDecl *D) {
+unsigned Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) {
if (!D)
- return;
+ return 0;
- int NumParamList = D->getNumTemplateParameterLists();
- for (int i = 0; i < NumParamList; i++) {
- TemplateParameterList* Params = D->getTemplateParameterList(i);
- for (TemplateParameterList::iterator Param = Params->begin(),
- ParamEnd = Params->end();
- Param != ParamEnd; ++Param) {
- NamedDecl *Named = cast<NamedDecl>(*Param);
- if (Named->getDeclName()) {
- S->AddDecl(Named);
- IdResolver.AddDecl(Named);
- }
+ // The order of template parameters is not important here. All names
+ // get added to the same scope.
+ SmallVector<TemplateParameterList *, 4> ParameterLists;
+
+ if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
+ D = TD->getTemplatedDecl();
+
+ if (auto *PSD = dyn_cast<ClassTemplatePartialSpecializationDecl>(D))
+ ParameterLists.push_back(PSD->getTemplateParameters());
+
+ if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
+ for (unsigned i = 0; i < DD->getNumTemplateParameterLists(); ++i)
+ ParameterLists.push_back(DD->getTemplateParameterList(i));
+
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate())
+ ParameterLists.push_back(FTD->getTemplateParameters());
}
}
-}
-void Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) {
- if (!D)
- return;
-
- TemplateParameterList *Params = 0;
- if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
- Params = Template->getTemplateParameters();
- else if (ClassTemplatePartialSpecializationDecl *PartialSpec
- = dyn_cast<ClassTemplatePartialSpecializationDecl>(D))
- Params = PartialSpec->getTemplateParameters();
- else
- return;
+ if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ for (unsigned i = 0; i < TD->getNumTemplateParameterLists(); ++i)
+ ParameterLists.push_back(TD->getTemplateParameterList(i));
- for (TemplateParameterList::iterator Param = Params->begin(),
- ParamEnd = Params->end();
- Param != ParamEnd; ++Param) {
- NamedDecl *Named = cast<NamedDecl>(*Param);
- if (Named->getDeclName()) {
- S->AddDecl(Named);
- IdResolver.AddDecl(Named);
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) {
+ if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate())
+ ParameterLists.push_back(CTD->getTemplateParameters());
}
}
+
+ unsigned Count = 0;
+ for (TemplateParameterList *Params : ParameterLists) {
+ if (Params->size() > 0)
+ // Ignore explicit specializations; they don't contribute to the template
+ // depth.
+ ++Count;
+ for (NamedDecl *Param : *Params) {
+ if (Param->getDeclName()) {
+ S->AddDecl(Param);
+ IdResolver.AddDecl(Param);
+ }
+ }
+ }
+
+ return Count;
}
void Sema::ActOnStartDelayedMemberDeclarations(Scope *S, Decl *RecordD) {
@@ -5992,6 +6181,18 @@ void Sema::ActOnFinishDelayedMemberDeclarations(Scope *S, Decl *RecordD) {
PopDeclContext();
}
+/// This is used to implement the constant expression evaluation part of the
+/// attribute enable_if extension. There is nothing in standard C++ which would
+/// require reentering parameters.
+void Sema::ActOnReenterCXXMethodParameter(Scope *S, ParmVarDecl *Param) {
+ if (!Param)
+ return;
+
+ S->AddDecl(Param);
+ if (Param->getDeclName())
+ IdResolver.AddDecl(Param);
+}
+
/// ActOnStartDelayedCXXMethodDeclaration - We have completed
/// parsing a top-level (non-nested) C++ class, and we are now
/// parsing those parts of the given Method declaration that could
@@ -6017,7 +6218,7 @@ void Sema::ActOnDelayedCXXMethodParameter(Scope *S, Decl *ParamD) {
// If this parameter has an unparsed default argument, clear it out
// to make way for the parsed default argument.
if (Param->hasUnparsedDefaultArg())
- Param->setDefaultArg(0);
+ Param->setDefaultArg(nullptr);
S->AddDecl(Param);
if (Param->getDeclName())
@@ -6081,6 +6282,15 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
SC = SC_None;
}
+ if (unsigned TypeQuals = D.getDeclSpec().getTypeQualifiers()) {
+ diagnoseIgnoredQualifiers(
+ diag::err_constructor_return_type, TypeQuals, SourceLocation(),
+ D.getDeclSpec().getConstSpecLoc(), D.getDeclSpec().getVolatileSpecLoc(),
+ D.getDeclSpec().getRestrictSpecLoc(),
+ D.getDeclSpec().getAtomicSpecLoc());
+ D.setInvalidType();
+ }
+
DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
if (FTI.TypeQuals != 0) {
if (FTI.TypeQuals & Qualifiers::Const)
@@ -6108,14 +6318,14 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
// case any of the errors above fired) and with "void" as the
// return type, since constructors don't have return types.
const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
- if (Proto->getResultType() == Context.VoidTy && !D.isInvalidType())
+ if (Proto->getReturnType() == Context.VoidTy && !D.isInvalidType())
return R;
FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
EPI.TypeQuals = 0;
EPI.RefQualifier = RQ_None;
-
- return Context.getFunctionType(Context.VoidTy, Proto->getArgTypes(), EPI);
+
+ return Context.getFunctionType(Context.VoidTy, Proto->getParamTypes(), EPI);
}
/// CheckConstructor - Checks a fully-formed constructor for
@@ -6170,7 +6380,7 @@ bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
Loc = RD->getLocation();
// If we have a virtual destructor, look up the deallocation function
- FunctionDecl *OperatorDelete = 0;
+ FunctionDecl *OperatorDelete = nullptr;
DeclarationName Name =
Context.DeclarationNames.getCXXOperatorName(OO_Delete);
if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete))
@@ -6188,13 +6398,6 @@ bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
return false;
}
-static inline bool
-FTIHasSingleVoidArgument(DeclaratorChunk::FunctionTypeInfo &FTI) {
- return (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
- FTI.ArgInfo[0].Param &&
- cast<ParmVarDecl>(FTI.ArgInfo[0].Param)->getType()->isVoidType());
-}
-
/// CheckDestructorDeclarator - Called by ActOnDeclarator to check
/// the well-formednes of the destructor declarator @p D with type @p
/// R. If there are any errors in the declarator, this routine will
@@ -6235,7 +6438,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
SC = SC_None;
}
- if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) {
+ if (!D.isInvalidType()) {
// Destructors don't have return types, but the parser will
// happily parse something like:
//
@@ -6244,9 +6447,19 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
// };
//
// The return type will be eliminated later.
- Diag(D.getIdentifierLoc(), diag::err_destructor_return_type)
- << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc())
- << SourceRange(D.getIdentifierLoc());
+ if (D.getDeclSpec().hasTypeSpecifier())
+ Diag(D.getIdentifierLoc(), diag::err_destructor_return_type)
+ << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc())
+ << SourceRange(D.getIdentifierLoc());
+ else if (unsigned TypeQuals = D.getDeclSpec().getTypeQualifiers()) {
+ diagnoseIgnoredQualifiers(diag::err_destructor_return_type, TypeQuals,
+ SourceLocation(),
+ D.getDeclSpec().getConstSpecLoc(),
+ D.getDeclSpec().getVolatileSpecLoc(),
+ D.getDeclSpec().getRestrictSpecLoc(),
+ D.getDeclSpec().getAtomicSpecLoc());
+ D.setInvalidType();
+ }
}
DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
@@ -6273,11 +6486,11 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
}
// Make sure we don't have any parameters.
- if (FTI.NumArgs > 0 && !FTIHasSingleVoidArgument(FTI)) {
+ if (FTIHasNonVoidParameters(FTI)) {
Diag(D.getIdentifierLoc(), diag::err_destructor_with_params);
// Delete the parameters.
- FTI.freeArgs();
+ FTI.freeParams();
D.setInvalidType();
}
@@ -6343,11 +6556,11 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
// Make sure we don't have any parameters.
- if (Proto->getNumArgs() > 0) {
+ if (Proto->getNumParams() > 0) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params);
// Delete the parameters.
- D.getFunctionTypeInfo().freeArgs();
+ D.getFunctionTypeInfo().freeParams();
D.setInvalidType();
} else if (Proto->isVariadic()) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic);
@@ -6356,11 +6569,11 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
// Diagnose "&operator bool()" and other such nonsense. This
// is actually a gcc extension which we don't support.
- if (Proto->getResultType() != ConvType) {
+ if (Proto->getReturnType() != ConvType) {
Diag(D.getIdentifierLoc(), diag::err_conv_function_with_complex_decl)
- << Proto->getResultType();
+ << Proto->getReturnType();
D.setInvalidType();
- ConvType = Proto->getResultType();
+ ConvType = Proto->getReturnType();
}
// C++ [class.conv.fct]p4:
@@ -6464,9 +6677,8 @@ static void DiagnoseNamespaceInlineMismatch(Sema &S, SourceLocation KeywordLoc,
NS->setInline(*IsInline);
// Patch up the lookup table for the containing namespace. This isn't really
// correct, but it's good enough for this particular case.
- for (DeclContext::decl_iterator I = PrevNS->decls_begin(),
- E = PrevNS->decls_end(); I != E; ++I)
- if (NamedDecl *ND = dyn_cast<NamedDecl>(*I))
+ for (auto *I : PrevNS->decls())
+ if (auto *ND = dyn_cast<NamedDecl>(I))
PrevNS->getParent()->makeDeclVisibleInContext(ND);
return;
}
@@ -6477,8 +6689,7 @@ static void DiagnoseNamespaceInlineMismatch(Sema &S, SourceLocation KeywordLoc,
S.Diag(Loc, diag::warn_inline_namespace_reopened_noninline)
<< FixItHint::CreateInsertion(KeywordLoc, "inline ");
else
- S.Diag(Loc, diag::err_inline_namespace_mismatch)
- << IsInline;
+ S.Diag(Loc, diag::err_inline_namespace_mismatch) << *IsInline;
S.Diag(PrevNS->getLocation(), diag::note_previous_definition);
*IsInline = PrevNS->isInline();
@@ -6502,7 +6713,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
bool AddToKnown = false;
Scope *DeclRegionScope = NamespcScope->getParent();
- NamespaceDecl *PrevNS = 0;
+ NamespaceDecl *PrevNS = nullptr;
if (II) {
// C++ [namespace.def]p2:
// The identifier in an original-namespace-definition shall not
@@ -6518,7 +6729,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
const unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Member |
Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag |
Decl::IDNS_Namespace;
- NamedDecl *PrevDecl = 0;
+ NamedDecl *PrevDecl = nullptr;
DeclContext::lookup_result R = CurContext->getRedeclContext()->lookup(II);
for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
++I) {
@@ -6679,7 +6890,7 @@ NamespaceDecl *Sema::getOrCreateStdNamespace() {
/*Inline=*/false,
SourceLocation(), SourceLocation(),
&PP.getIdentifierTable().get("std"),
- /*PrevDecl=*/0);
+ /*PrevDecl=*/nullptr);
getStdNamespace()->setImplicit(true);
}
@@ -6696,8 +6907,8 @@ bool Sema::isStdInitializerList(QualType Ty, QualType *Element) {
if (!StdNamespace) // If we haven't seen namespace std yet, this can't be it.
return false;
- ClassTemplateDecl *Template = 0;
- const TemplateArgument *Arguments = 0;
+ ClassTemplateDecl *Template = nullptr;
+ const TemplateArgument *Arguments = nullptr;
if (const RecordType *RT = Ty->getAs<RecordType>()) {
@@ -6750,14 +6961,14 @@ static ClassTemplateDecl *LookupStdInitializerList(Sema &S, SourceLocation Loc){
NamespaceDecl *Std = S.getStdNamespace();
if (!Std) {
S.Diag(Loc, diag::err_implied_std_initializer_list_not_found);
- return 0;
+ return nullptr;
}
LookupResult Result(S, &S.PP.getIdentifierTable().get("initializer_list"),
Loc, Sema::LookupOrdinaryName);
if (!S.LookupQualifiedName(Result, Std)) {
S.Diag(Loc, diag::err_implied_std_initializer_list_not_found);
- return 0;
+ return nullptr;
}
ClassTemplateDecl *Template = Result.getAsSingle<ClassTemplateDecl>();
if (!Template) {
@@ -6765,7 +6976,7 @@ static ClassTemplateDecl *LookupStdInitializerList(Sema &S, SourceLocation Loc){
// We found something weird. Complain about the first thing we found.
NamedDecl *Found = *Result.begin();
S.Diag(Found->getLocation(), diag::err_malformed_std_initializer_list);
- return 0;
+ return nullptr;
}
// We found some template called std::initializer_list. Now verify that it's
@@ -6774,7 +6985,7 @@ static ClassTemplateDecl *LookupStdInitializerList(Sema &S, SourceLocation Loc){
if (Params->getMinRequiredArguments() != 1 ||
!isa<TemplateTypeParmDecl>(Params->getParam(0))) {
S.Diag(Template->getLocation(), diag::err_malformed_std_initializer_list);
- return 0;
+ return nullptr;
}
return Template;
@@ -6809,7 +7020,7 @@ bool Sema::isInitListConstructor(const CXXConstructorDecl* Ctor) {
if (const ReferenceType *RT = ArgType->getAs<ReferenceType>())
ArgType = RT->getPointeeType().getUnqualifiedType();
- return isStdInitializerList(ArgType, 0);
+ return isStdInitializerList(ArgType, nullptr);
}
/// \brief Determine whether a using statement is in a context where it will be
@@ -6830,7 +7041,7 @@ namespace {
// Callback to only accept typo corrections that are namespaces.
class NamespaceValidatorCCC : public CorrectionCandidateCallback {
public:
- bool ValidateCandidate(const TypoCorrection &candidate) LLVM_OVERRIDE {
+ bool ValidateCandidate(const TypoCorrection &candidate) override {
if (NamedDecl *ND = candidate.getCorrectionDecl())
return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
return false;
@@ -6847,7 +7058,8 @@ static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
R.clear();
if (TypoCorrection Corrected = S.CorrectTypo(R.getLookupNameInfo(),
R.getLookupKind(), Sc, &SS,
- Validator)) {
+ Validator,
+ Sema::CTK_ErrorRecovery)) {
if (DeclContext *DC = S.computeDeclContext(SS, false)) {
std::string CorrectedStr(Corrected.getAsString(S.getLangOpts()));
bool DroppedSpecifier = Corrected.WillReplaceSpecifier() &&
@@ -6883,16 +7095,16 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
S = S->getParent();
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
- UsingDirectiveDecl *UDir = 0;
- NestedNameSpecifier *Qualifier = 0;
+ UsingDirectiveDecl *UDir = nullptr;
+ NestedNameSpecifier *Qualifier = nullptr;
if (SS.isSet())
- Qualifier = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ Qualifier = SS.getScopeRep();
// Lookup namespace name.
LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName);
LookupParsedName(R, S, &SS);
if (R.isAmbiguous())
- return 0;
+ return nullptr;
if (R.empty()) {
R.clear();
@@ -6957,7 +7169,7 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) {
if (Ctx && !Ctx->isFunctionOrMethod())
Ctx->addDecl(UDir);
else
- // Otherwise, it is at block sope. The using-directives will affect lookup
+ // Otherwise, it is at block scope. The using-directives will affect lookup
// only to the end of the scope.
S->PushUsingDirective(UDir);
}
@@ -6993,23 +7205,23 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
if (getLangOpts().CPlusPlus11) break;
- return 0;
-
+ return nullptr;
+
case UnqualifiedId::IK_DestructorName:
Diag(Name.getLocStart(), diag::err_using_decl_destructor)
<< SS.getRange();
- return 0;
-
+ return nullptr;
+
case UnqualifiedId::IK_TemplateId:
Diag(Name.getLocStart(), diag::err_using_decl_template_id)
<< SourceRange(Name.TemplateId->LAngleLoc, Name.TemplateId->RAngleLoc);
- return 0;
+ return nullptr;
}
DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name);
DeclarationName TargetName = TargetNameInfo.getName();
if (!TargetName)
- return 0;
+ return nullptr;
// Warn about access declarations.
if (!HasUsingKeyword) {
@@ -7021,7 +7233,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
if (DiagnoseUnexpandedParameterPack(SS, UPPC_UsingDeclaration) ||
DiagnoseUnexpandedParameterPack(TargetNameInfo, UPPC_UsingDeclaration))
- return 0;
+ return nullptr;
NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS,
TargetNameInfo, AttrList,
@@ -7113,7 +7325,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
//
// FIXME: but we might be increasing its access, in which case we
// should redeclare it.
- NamedDecl *NonTag = 0, *Tag = 0;
+ NamedDecl *NonTag = nullptr, *Tag = nullptr;
bool FoundEquivalentDecl = false;
for (LookupResult::iterator I = Previous.begin(), E = Previous.end();
I != E; ++I) {
@@ -7130,22 +7342,17 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
if (FoundEquivalentDecl)
return false;
- if (Target->isFunctionOrFunctionTemplate()) {
- FunctionDecl *FD;
- if (isa<FunctionTemplateDecl>(Target))
- FD = cast<FunctionTemplateDecl>(Target)->getTemplatedDecl();
- else
- FD = cast<FunctionDecl>(Target);
-
- NamedDecl *OldDecl = 0;
- switch (CheckOverload(0, FD, Previous, OldDecl, /*IsForUsingDecl*/ true)) {
+ if (FunctionDecl *FD = Target->getAsFunction()) {
+ NamedDecl *OldDecl = nullptr;
+ switch (CheckOverload(nullptr, FD, Previous, OldDecl,
+ /*IsForUsingDecl*/ true)) {
case Ovl_Overload:
return false;
case Ovl_NonFunction:
Diag(Using->getLocation(), diag::err_using_decl_conflict);
break;
-
+
// We found a decl with the exact signature.
case Ovl_Match:
// If we're in a record, we want to hide the target, so we
@@ -7266,29 +7473,80 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) {
// be possible for this to happen, because...?
}
+/// Find the base specifier for a base class with the given type.
+static CXXBaseSpecifier *findDirectBaseWithType(CXXRecordDecl *Derived,
+ QualType DesiredBase,
+ bool &AnyDependentBases) {
+ // Check whether the named type is a direct base class.
+ CanQualType CanonicalDesiredBase = DesiredBase->getCanonicalTypeUnqualified();
+ for (auto &Base : Derived->bases()) {
+ CanQualType BaseType = Base.getType()->getCanonicalTypeUnqualified();
+ if (CanonicalDesiredBase == BaseType)
+ return &Base;
+ if (BaseType->isDependentType())
+ AnyDependentBases = true;
+ }
+ return nullptr;
+}
+
namespace {
class UsingValidatorCCC : public CorrectionCandidateCallback {
public:
UsingValidatorCCC(bool HasTypenameKeyword, bool IsInstantiation,
- bool RequireMember)
+ NestedNameSpecifier *NNS, CXXRecordDecl *RequireMemberOf)
: HasTypenameKeyword(HasTypenameKeyword),
- IsInstantiation(IsInstantiation), RequireMember(RequireMember) {}
+ IsInstantiation(IsInstantiation), OldNNS(NNS),
+ RequireMemberOf(RequireMemberOf) {}
- bool ValidateCandidate(const TypoCorrection &Candidate) LLVM_OVERRIDE {
+ bool ValidateCandidate(const TypoCorrection &Candidate) override {
NamedDecl *ND = Candidate.getCorrectionDecl();
// Keywords are not valid here.
if (!ND || isa<NamespaceDecl>(ND))
return false;
- if (RequireMember && !isa<FieldDecl>(ND) && !isa<CXXMethodDecl>(ND) &&
- !isa<TypeDecl>(ND))
- return false;
-
// Completely unqualified names are invalid for a 'using' declaration.
if (Candidate.WillReplaceSpecifier() && !Candidate.getCorrectionSpecifier())
return false;
+ if (RequireMemberOf) {
+ auto *FoundRecord = dyn_cast<CXXRecordDecl>(ND);
+ if (FoundRecord && FoundRecord->isInjectedClassName()) {
+ // No-one ever wants a using-declaration to name an injected-class-name
+ // of a base class, unless they're declaring an inheriting constructor.
+ ASTContext &Ctx = ND->getASTContext();
+ if (!Ctx.getLangOpts().CPlusPlus11)
+ return false;
+ QualType FoundType = Ctx.getRecordType(FoundRecord);
+
+ // Check that the injected-class-name is named as a member of its own
+ // type; we don't want to suggest 'using Derived::Base;', since that
+ // means something else.
+ NestedNameSpecifier *Specifier =
+ Candidate.WillReplaceSpecifier()
+ ? Candidate.getCorrectionSpecifier()
+ : OldNNS;
+ if (!Specifier->getAsType() ||
+ !Ctx.hasSameType(QualType(Specifier->getAsType(), 0), FoundType))
+ return false;
+
+ // Check that this inheriting constructor declaration actually names a
+ // direct base class of the current class.
+ bool AnyDependentBases = false;
+ if (!findDirectBaseWithType(RequireMemberOf,
+ Ctx.getRecordType(FoundRecord),
+ AnyDependentBases) &&
+ !AnyDependentBases)
+ return false;
+ } else {
+ auto *RD = dyn_cast<CXXRecordDecl>(ND->getDeclContext());
+ if (!RD || RequireMemberOf->isProvablyNotDerivedFrom(RD))
+ return false;
+
+ // FIXME: Check that the base class member is accessible?
+ }
+ }
+
if (isa<TypeDecl>(ND))
return HasTypenameKeyword || !IsInstantiation;
@@ -7298,7 +7556,8 @@ public:
private:
bool HasTypenameKeyword;
bool IsInstantiation;
- bool RequireMember;
+ NestedNameSpecifier *OldNNS;
+ CXXRecordDecl *RequireMemberOf;
};
} // end anonymous namespace
@@ -7310,7 +7569,7 @@ private:
NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
CXXScopeSpec &SS,
- const DeclarationNameInfo &NameInfo,
+ DeclarationNameInfo NameInfo,
AttributeList *AttrList,
bool IsInstantiation,
bool HasTypenameKeyword,
@@ -7323,7 +7582,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
if (SS.isEmpty()) {
Diag(IdentLoc, diag::err_using_requires_qualname);
- return 0;
+ return nullptr;
}
// Do the redeclaration lookup in the current scope.
@@ -7339,6 +7598,13 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
NamedDecl *D = F.next();
if (!isDeclInScope(D, CurContext, S))
F.erase();
+ // If we found a local extern declaration that's not ordinarily visible,
+ // and this declaration is being added to a non-block scope, ignore it.
+ // We're only checking for scope conflicts here, not also for violations
+ // of the linkage rules.
+ else if (!CurContext->isFunctionOrMethod() && D->isLocalExternDecl() &&
+ !(D->getIdentifierNamespace() & Decl::IDNS_Ordinary))
+ F.erase();
}
F.done();
} else {
@@ -7350,11 +7616,11 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
// Check for invalid redeclarations.
if (CheckUsingDeclRedeclaration(UsingLoc, HasTypenameKeyword,
SS, IdentLoc, Previous))
- return 0;
+ return nullptr;
// Check for bad qualifiers.
- if (CheckUsingDeclQualifier(UsingLoc, SS, IdentLoc))
- return 0;
+ if (CheckUsingDeclQualifier(UsingLoc, SS, NameInfo, IdentLoc))
+ return nullptr;
DeclContext *LookupContext = computeDeclContext(SS);
NamedDecl *D;
@@ -7370,25 +7636,30 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
D = UnresolvedUsingValueDecl::Create(Context, CurContext, UsingLoc,
QualifierLoc, NameInfo);
}
- } else {
- D = UsingDecl::Create(Context, CurContext, UsingLoc, QualifierLoc,
- NameInfo, HasTypenameKeyword);
+ D->setAccess(AS);
+ CurContext->addDecl(D);
+ return D;
}
- D->setAccess(AS);
- CurContext->addDecl(D);
- if (!LookupContext) return D;
- UsingDecl *UD = cast<UsingDecl>(D);
-
- if (RequireCompleteDeclContext(SS, LookupContext)) {
- UD->setInvalidDecl();
+ auto Build = [&](bool Invalid) {
+ UsingDecl *UD =
+ UsingDecl::Create(Context, CurContext, UsingLoc, QualifierLoc, NameInfo,
+ HasTypenameKeyword);
+ UD->setAccess(AS);
+ CurContext->addDecl(UD);
+ UD->setInvalidDecl(Invalid);
return UD;
- }
+ };
+ auto BuildInvalid = [&]{ return Build(true); };
+ auto BuildValid = [&]{ return Build(false); };
+
+ if (RequireCompleteDeclContext(SS, LookupContext))
+ return BuildInvalid();
// The normal rules do not apply to inheriting constructor declarations.
if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) {
- if (CheckInheritingConstructorUsingDecl(UD))
- UD->setInvalidDecl();
+ UsingDecl *UD = BuildValid();
+ CheckInheritingConstructorUsingDecl(UD);
return UD;
}
@@ -7414,31 +7685,53 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
// Try to correct typos if possible.
if (R.empty()) {
- UsingValidatorCCC CCC(HasTypenameKeyword, IsInstantiation,
- CurContext->isRecord());
+ UsingValidatorCCC CCC(HasTypenameKeyword, IsInstantiation, SS.getScopeRep(),
+ dyn_cast<CXXRecordDecl>(CurContext));
if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
- R.getLookupKind(), S, &SS, CCC)){
+ R.getLookupKind(), S, &SS, CCC,
+ CTK_ErrorRecovery)){
// We reject any correction for which ND would be NULL.
NamedDecl *ND = Corrected.getCorrectionDecl();
- R.setLookupName(Corrected.getCorrection());
- R.addDecl(ND);
+
// We reject candidates where DroppedSpecifier == true, hence the
// literal '0' below.
diagnoseTypo(Corrected, PDiag(diag::err_no_member_suggest)
<< NameInfo.getName() << LookupContext << 0
<< SS.getRange());
+
+ // If we corrected to an inheriting constructor, handle it as one.
+ auto *RD = dyn_cast<CXXRecordDecl>(ND);
+ if (RD && RD->isInjectedClassName()) {
+ // Fix up the information we'll use to build the using declaration.
+ if (Corrected.WillReplaceSpecifier()) {
+ NestedNameSpecifierLocBuilder Builder;
+ Builder.MakeTrivial(Context, Corrected.getCorrectionSpecifier(),
+ QualifierLoc.getSourceRange());
+ QualifierLoc = Builder.getWithLocInContext(Context);
+ }
+
+ NameInfo.setName(Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(Context.getRecordType(RD))));
+ NameInfo.setNamedTypeInfo(nullptr);
+
+ // Build it and process it as an inheriting constructor.
+ UsingDecl *UD = BuildValid();
+ CheckInheritingConstructorUsingDecl(UD);
+ return UD;
+ }
+
+ // FIXME: Pick up all the declarations if we found an overloaded function.
+ R.setLookupName(Corrected.getCorrection());
+ R.addDecl(ND);
} else {
Diag(IdentLoc, diag::err_no_member)
<< NameInfo.getName() << LookupContext << SS.getRange();
- UD->setInvalidDecl();
- return UD;
+ return BuildInvalid();
}
}
- if (R.isAmbiguous()) {
- UD->setInvalidDecl();
- return UD;
- }
+ if (R.isAmbiguous())
+ return BuildInvalid();
if (HasTypenameKeyword) {
// If we asked for a typename and got a non-type decl, error out.
@@ -7447,8 +7740,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
Diag((*I)->getUnderlyingDecl()->getLocation(),
diag::note_using_decl_target);
- UD->setInvalidDecl();
- return UD;
+ return BuildInvalid();
}
} else {
// If we asked for a non-typename and we got a type, error out,
@@ -7457,8 +7749,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
if (IsInstantiation && R.getAsSingle<TypeDecl>()) {
Diag(IdentLoc, diag::err_using_dependent_value_is_type);
Diag(R.getFoundDecl()->getLocation(), diag::note_using_decl_target);
- UD->setInvalidDecl();
- return UD;
+ return BuildInvalid();
}
}
@@ -7467,12 +7758,12 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
if (R.getAsSingle<NamespaceDecl>()) {
Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_namespace)
<< SS.getRange();
- UD->setInvalidDecl();
- return UD;
+ return BuildInvalid();
}
+ UsingDecl *UD = BuildValid();
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- UsingShadowDecl *PrevDecl = 0;
+ UsingShadowDecl *PrevDecl = nullptr;
if (!CheckUsingShadowDecl(UD, *I, Previous, PrevDecl))
BuildUsingShadowDecl(S, UD, *I, PrevDecl);
}
@@ -7490,28 +7781,20 @@ bool Sema::CheckInheritingConstructorUsingDecl(UsingDecl *UD) {
CXXRecordDecl *TargetClass = cast<CXXRecordDecl>(CurContext);
// Check whether the named type is a direct base class.
- CanQualType CanonicalSourceType = SourceType->getCanonicalTypeUnqualified();
- CXXRecordDecl::base_class_iterator BaseIt, BaseE;
- for (BaseIt = TargetClass->bases_begin(), BaseE = TargetClass->bases_end();
- BaseIt != BaseE; ++BaseIt) {
- CanQualType BaseType = BaseIt->getType()->getCanonicalTypeUnqualified();
- if (CanonicalSourceType == BaseType)
- break;
- if (BaseIt->getType()->isDependentType())
- break;
- }
-
- if (BaseIt == BaseE) {
- // Did not find SourceType in the bases.
+ bool AnyDependentBases = false;
+ auto *Base = findDirectBaseWithType(TargetClass, QualType(SourceType, 0),
+ AnyDependentBases);
+ if (!Base && !AnyDependentBases) {
Diag(UD->getUsingLoc(),
diag::err_using_decl_constructor_not_in_direct_base)
<< UD->getNameInfo().getSourceRange()
<< QualType(SourceType, 0) << TargetClass;
+ UD->setInvalidDecl();
return true;
}
- if (!CurContext->isDependentContext())
- BaseIt->setInheritConstructors();
+ if (Base)
+ Base->setInheritConstructors();
return false;
}
@@ -7534,8 +7817,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
if (!CurContext->getRedeclContext()->isRecord())
return false;
- NestedNameSpecifier *Qual
- = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+ NestedNameSpecifier *Qual = SS.getScopeRep();
for (LookupResult::iterator I = Prev.begin(), E = Prev.end(); I != E; ++I) {
NamedDecl *D = *I;
@@ -7580,6 +7862,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
/// scope. If an error is found, diagnoses it and returns true.
bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
const CXXScopeSpec &SS,
+ const DeclarationNameInfo &NameInfo,
SourceLocation NameLoc) {
DeclContext *NamedContext = computeDeclContext(SS);
@@ -7591,8 +7874,56 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
// If we weren't able to compute a valid scope, it must be a
// dependent class scope.
if (!NamedContext || NamedContext->isRecord()) {
+ auto *RD = dyn_cast<CXXRecordDecl>(NamedContext);
+ if (RD && RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(SS), RD))
+ RD = nullptr;
+
Diag(NameLoc, diag::err_using_decl_can_not_refer_to_class_member)
<< SS.getRange();
+
+ // If we have a complete, non-dependent source type, try to suggest a
+ // way to get the same effect.
+ if (!RD)
+ return true;
+
+ // Find what this using-declaration was referring to.
+ LookupResult R(*this, NameInfo, LookupOrdinaryName);
+ R.setHideTags(false);
+ R.suppressDiagnostics();
+ LookupQualifiedName(R, RD);
+
+ if (R.getAsSingle<TypeDecl>()) {
+ if (getLangOpts().CPlusPlus11) {
+ // Convert 'using X::Y;' to 'using Y = X::Y;'.
+ Diag(SS.getBeginLoc(), diag::note_using_decl_class_member_workaround)
+ << 0 // alias declaration
+ << FixItHint::CreateInsertion(SS.getBeginLoc(),
+ NameInfo.getName().getAsString() +
+ " = ");
+ } else {
+ // Convert 'using X::Y;' to 'typedef X::Y Y;'.
+ SourceLocation InsertLoc =
+ PP.getLocForEndOfToken(NameInfo.getLocEnd());
+ Diag(InsertLoc, diag::note_using_decl_class_member_workaround)
+ << 1 // typedef declaration
+ << FixItHint::CreateReplacement(UsingLoc, "typedef")
+ << FixItHint::CreateInsertion(
+ InsertLoc, " " + NameInfo.getName().getAsString());
+ }
+ } else if (R.getAsSingle<VarDecl>()) {
+ // Don't provide a fixit outside C++11 mode; we don't want to suggest
+ // repeating the type of the static data member here.
+ FixItHint FixIt;
+ if (getLangOpts().CPlusPlus11) {
+ // Convert 'using X::Y;' to 'auto &Y = X::Y;'.
+ FixIt = FixItHint::CreateReplacement(
+ UsingLoc, "auto &" + NameInfo.getName().getAsString() + " = ");
+ }
+
+ Diag(UsingLoc, diag::note_using_decl_class_member_workaround)
+ << 2 // reference declaration
+ << FixIt;
+ }
return true;
}
@@ -7618,7 +7949,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
// but we don't have that level of source info.
Diag(SS.getRange().getBegin(),
diag::err_using_decl_nested_name_specifier_is_not_class)
- << (NestedNameSpecifier*) SS.getScopeRep() << SS.getRange();
+ << SS.getScopeRep() << SS.getRange();
return true;
}
@@ -7643,7 +7974,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
Diag(SS.getRange().getBegin(),
diag::err_using_decl_nested_name_specifier_is_not_base_class)
- << (NestedNameSpecifier*) SS.getScopeRep()
+ << SS.getScopeRep()
<< cast<CXXRecordDecl>(CurContext)
<< SS.getRange();
return true;
@@ -7703,7 +8034,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
Diag(SS.getRange().getBegin(),
diag::err_using_decl_nested_name_specifier_is_not_base_class)
- << (NestedNameSpecifier*) SS.getScopeRep()
+ << SS.getScopeRep()
<< cast<CXXRecordDecl>(CurContext)
<< SS.getRange();
@@ -7724,15 +8055,15 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
"got alias-declaration outside of declaration scope");
if (Type.isInvalid())
- return 0;
+ return nullptr;
bool Invalid = false;
DeclarationNameInfo NameInfo = GetNameFromUnqualifiedId(Name);
- TypeSourceInfo *TInfo = 0;
+ TypeSourceInfo *TInfo = nullptr;
GetTypeFromParser(Type.get(), &TInfo);
if (DiagnoseClassNameShadow(CurContext, NameInfo))
- return 0;
+ return nullptr;
if (DiagnoseUnexpandedParameterPack(Name.StartLocation, TInfo,
UPPC_DeclarationType)) {
@@ -7771,8 +8102,8 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
NamedDecl *NewND;
if (TemplateParamLists.size()) {
- TypeAliasTemplateDecl *OldDecl = 0;
- TemplateParameterList *OldTemplateParams = 0;
+ TypeAliasTemplateDecl *OldDecl = nullptr;
+ TemplateParameterList *OldTemplateParams = nullptr;
if (TemplateParamLists.size() != 1) {
Diag(UsingLoc, diag::err_alias_template_extra_headers)
@@ -7827,7 +8158,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
// and check the parameter list.
if (CheckTemplateParameterList(TemplateParams, OldTemplateParams,
TPC_TypeAliasTemplate))
- return 0;
+ return nullptr;
TypeAliasTemplateDecl *NewDecl =
TypeAliasTemplateDecl::Create(Context, CurContext, UsingLoc,
@@ -7871,7 +8202,7 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S,
= LookupSingleName(S, Alias, AliasLoc, LookupOrdinaryName,
ForRedeclaration);
if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S))
- PrevDecl = 0;
+ PrevDecl = nullptr;
if (PrevDecl) {
if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) {
@@ -7881,23 +8212,23 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S,
// declaration to maintain better source information.
if (!R.isAmbiguous() && !R.empty() &&
AD->getNamespace()->Equals(getNamespaceDecl(R.getFoundDecl())))
- return 0;
+ return nullptr;
}
unsigned DiagID = isa<NamespaceDecl>(PrevDecl) ? diag::err_redefinition :
diag::err_redefinition_different_kind;
Diag(AliasLoc, DiagID) << Alias;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
- return 0;
+ return nullptr;
}
if (R.isAmbiguous())
- return 0;
+ return nullptr;
if (R.empty()) {
if (!TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, Ident)) {
Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
- return 0;
+ return nullptr;
}
}
@@ -7923,40 +8254,34 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc,
return ExceptSpec;
// Direct base-class constructors.
- for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
- BEnd = ClassDecl->bases_end();
- B != BEnd; ++B) {
- if (B->isVirtual()) // Handled below.
+ for (const auto &B : ClassDecl->bases()) {
+ if (B.isVirtual()) // Handled below.
continue;
- if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
+ if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
// If this is a deleted function, add it anyway. This might be conformant
// with the standard. This might not. I'm not sure. It might not matter.
if (Constructor)
- ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
+ ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
}
}
// Virtual base-class constructors.
- for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(),
- BEnd = ClassDecl->vbases_end();
- B != BEnd; ++B) {
- if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
+ for (const auto &B : ClassDecl->vbases()) {
+ if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
// If this is a deleted function, add it anyway. This might be conformant
// with the standard. This might not. I'm not sure. It might not matter.
if (Constructor)
- ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
+ ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
}
}
// Field constructors.
- for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
- FEnd = ClassDecl->field_end();
- F != FEnd; ++F) {
+ for (const auto *F : ClassDecl->fields()) {
if (F->hasInClassInitializer()) {
if (Expr *E = F->getInClassInitializer())
ExceptSpec.CalledExpr(E);
@@ -8012,40 +8337,34 @@ Sema::ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD) {
ExceptSpec.CalledDecl(CD->getLocStart(), InheritedCD);
// Direct base-class constructors.
- for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
- BEnd = ClassDecl->bases_end();
- B != BEnd; ++B) {
- if (B->isVirtual()) // Handled below.
+ for (const auto &B : ClassDecl->bases()) {
+ if (B.isVirtual()) // Handled below.
continue;
- if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
+ if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
if (BaseClassDecl == InheritedDecl)
continue;
CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
if (Constructor)
- ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
+ ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
}
}
// Virtual base-class constructors.
- for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(),
- BEnd = ClassDecl->vbases_end();
- B != BEnd; ++B) {
- if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
+ for (const auto &B : ClassDecl->vbases()) {
+ if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
if (BaseClassDecl == InheritedDecl)
continue;
CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
if (Constructor)
- ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
+ ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
}
}
// Field constructors.
- for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
- FEnd = ClassDecl->field_end();
- F != FEnd; ++F) {
+ for (const auto *F : ClassDecl->fields()) {
if (F->hasInClassInitializer()) {
if (Expr *E = F->getInClassInitializer())
ExceptSpec.CalledExpr(E);
@@ -8107,7 +8426,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
DeclaringSpecialMember DSM(*this, ClassDecl, CXXDefaultConstructor);
if (DSM.isAlreadyBeingDeclared())
- return 0;
+ return nullptr;
bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,
CXXDefaultConstructor,
@@ -8121,9 +8440,9 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
= Context.DeclarationNames.getCXXConstructorName(ClassType);
DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create(
- Context, ClassDecl, ClassLoc, NameInfo, /*Type*/QualType(), /*TInfo=*/0,
- /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
- Constexpr);
+ Context, ClassDecl, ClassLoc, NameInfo, /*Type*/QualType(),
+ /*TInfo=*/nullptr, /*isExplicit=*/false, /*isInline=*/true,
+ /*isImplicitlyDeclared=*/true, Constexpr);
DefaultCon->setAccess(AS_public);
DefaultCon->setDefaulted();
DefaultCon->setImplicit();
@@ -8169,7 +8488,9 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
return;
}
- SourceLocation Loc = Constructor->getLocation();
+ SourceLocation Loc = Constructor->getLocEnd().isValid()
+ ? Constructor->getLocEnd()
+ : Constructor->getLocation();
Constructor->setBody(new (Context) CompoundStmt(Loc));
Constructor->markUsed(Context);
@@ -8209,7 +8530,7 @@ private:
/// Information about an inheriting constructor.
struct InheritingConstructor {
InheritingConstructor()
- : DeclaredInDerived(false), BaseCtor(0), DerivedCtor(0) {}
+ : DeclaredInDerived(false), BaseCtor(nullptr), DerivedCtor(nullptr) {}
/// If \c true, a constructor with this signature is already declared
/// in the derived class.
@@ -8256,10 +8577,8 @@ private:
/// Process all constructors for a class.
void visitAll(const CXXRecordDecl *RD, VisitFn Callback) {
- for (CXXRecordDecl::ctor_iterator CtorIt = RD->ctor_begin(),
- CtorE = RD->ctor_end();
- CtorIt != CtorE; ++CtorIt)
- (this->*Callback)(*CtorIt);
+ for (const auto *Ctor : RD->ctors())
+ (this->*Callback)(Ctor);
for (CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl>
I(RD->decls_begin()), E(RD->decls_end());
I != E; ++I) {
@@ -8278,7 +8597,7 @@ private:
void inherit(const CXXConstructorDecl *Ctor) {
const FunctionProtoType *CtorType =
Ctor->getType()->castAs<FunctionProtoType>();
- ArrayRef<QualType> ArgTypes(CtorType->getArgTypes());
+ ArrayRef<QualType> ArgTypes(CtorType->getParamTypes());
FunctionProtoType::ExtProtoInfo EPI = CtorType->getExtProtoInfo();
SourceLocation UsingLoc = getUsingLoc(Ctor->getParent());
@@ -8306,7 +8625,7 @@ private:
do
declareCtor(UsingLoc, Ctor,
SemaRef.Context.getFunctionType(
- Ctor->getResultType(), ArgTypes.slice(0, Params), EPI));
+ Ctor->getReturnType(), ArgTypes.slice(0, Params), EPI));
while (Params > MinParams &&
Ctor->getParamDecl(--Params)->hasDefaultArg());
}
@@ -8392,7 +8711,7 @@ private:
Context.getCanonicalType(Context.getRecordType(Derived)));
DeclarationNameInfo NameInfo(Name, UsingLoc);
- TemplateParameterList *TemplateParams = 0;
+ TemplateParameterList *TemplateParams = nullptr;
if (const FunctionTemplateDecl *FTD =
BaseCtor->getDescribedFunctionTemplate()) {
TemplateParams = FTD->getTemplateParameters();
@@ -8420,21 +8739,21 @@ private:
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = DerivedCtor;
- DerivedCtor->setType(Context.getFunctionType(FPT->getResultType(),
- FPT->getArgTypes(), EPI));
+ DerivedCtor->setType(Context.getFunctionType(FPT->getReturnType(),
+ FPT->getParamTypes(), EPI));
// Build the parameter declarations.
SmallVector<ParmVarDecl *, 16> ParamDecls;
- for (unsigned I = 0, N = FPT->getNumArgs(); I != N; ++I) {
+ for (unsigned I = 0, N = FPT->getNumParams(); I != N; ++I) {
TypeSourceInfo *TInfo =
- Context.getTrivialTypeSourceInfo(FPT->getArgType(I), UsingLoc);
+ Context.getTrivialTypeSourceInfo(FPT->getParamType(I), UsingLoc);
ParmVarDecl *PD = ParmVarDecl::Create(
- Context, DerivedCtor, UsingLoc, UsingLoc, /*IdentifierInfo=*/0,
- FPT->getArgType(I), TInfo, SC_None, /*DefaultArg=*/0);
+ Context, DerivedCtor, UsingLoc, UsingLoc, /*IdentifierInfo=*/nullptr,
+ FPT->getParamType(I), TInfo, SC_None, /*DefaultArg=*/nullptr);
PD->setScopeInfo(0, I);
PD->setImplicit();
ParamDecls.push_back(PD);
- ProtoLoc.setArg(I, PD);
+ ProtoLoc.setParam(I, PD);
}
// Set up the new constructor.
@@ -8475,11 +8794,9 @@ void Sema::DeclareInheritingConstructors(CXXRecordDecl *ClassDecl) {
// Find base classes from which we might inherit constructors.
SmallVector<CXXRecordDecl*, 4> InheritedBases;
- for (CXXRecordDecl::base_class_iterator BaseIt = ClassDecl->bases_begin(),
- BaseE = ClassDecl->bases_end();
- BaseIt != BaseE; ++BaseIt)
- if (BaseIt->getInheritConstructors())
- InheritedBases.push_back(BaseIt->getType()->getAsCXXRecordDecl());
+ for (const auto &BaseIt : ClassDecl->bases())
+ if (BaseIt.getInheritConstructors())
+ InheritedBases.push_back(BaseIt.getType()->getAsCXXRecordDecl());
// Go no further if we're not inheriting any constructors.
if (InheritedBases.empty())
@@ -8532,30 +8849,24 @@ Sema::ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD) {
return ExceptSpec;
// Direct base-class destructors.
- for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
- BEnd = ClassDecl->bases_end();
- B != BEnd; ++B) {
- if (B->isVirtual()) // Handled below.
+ for (const auto &B : ClassDecl->bases()) {
+ if (B.isVirtual()) // Handled below.
continue;
- if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
- ExceptSpec.CalledDecl(B->getLocStart(),
+ if (const RecordType *BaseType = B.getType()->getAs<RecordType>())
+ ExceptSpec.CalledDecl(B.getLocStart(),
LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
}
// Virtual base-class destructors.
- for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(),
- BEnd = ClassDecl->vbases_end();
- B != BEnd; ++B) {
- if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
- ExceptSpec.CalledDecl(B->getLocStart(),
+ for (const auto &B : ClassDecl->vbases()) {
+ if (const RecordType *BaseType = B.getType()->getAs<RecordType>())
+ ExceptSpec.CalledDecl(B.getLocStart(),
LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
}
// Field destructors.
- for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
- FEnd = ClassDecl->field_end();
- F != FEnd; ++F) {
+ for (const auto *F : ClassDecl->fields()) {
if (const RecordType *RecordTy
= Context.getBaseElementType(F->getType())->getAs<RecordType>())
ExceptSpec.CalledDecl(F->getLocation(),
@@ -8574,7 +8885,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
DeclaringSpecialMember DSM(*this, ClassDecl, CXXDestructor);
if (DSM.isAlreadyBeingDeclared())
- return 0;
+ return nullptr;
// Create the actual destructor declaration.
CanQualType ClassType
@@ -8585,7 +8896,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXDestructorDecl *Destructor
= CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
- QualType(), 0, /*isInline=*/true,
+ QualType(), nullptr, /*isInline=*/true,
/*isImplicitlyDeclared=*/true);
Destructor->setAccess(AS_public);
Destructor->setDefaulted();
@@ -8641,7 +8952,9 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
return;
}
- SourceLocation Loc = Destructor->getLocation();
+ SourceLocation Loc = Destructor->getLocEnd().isValid()
+ ? Destructor->getLocEnd()
+ : Destructor->getLocation();
Destructor->setBody(new (Context) CompoundStmt(Loc));
Destructor->markUsed(Context);
MarkVTableUsed(CurrentLocation, ClassDecl);
@@ -8719,8 +9032,8 @@ class RefBuilder: public ExprBuilder {
QualType VarType;
public:
- virtual Expr *build(Sema &S, SourceLocation Loc) const LLVM_OVERRIDE {
- return assertNotNull(S.BuildDeclRefExpr(Var, VarType, VK_LValue, Loc).take());
+ virtual Expr *build(Sema &S, SourceLocation Loc) const override {
+ return assertNotNull(S.BuildDeclRefExpr(Var, VarType, VK_LValue, Loc).get());
}
RefBuilder(VarDecl *Var, QualType VarType)
@@ -8729,8 +9042,8 @@ public:
class ThisBuilder: public ExprBuilder {
public:
- virtual Expr *build(Sema &S, SourceLocation Loc) const LLVM_OVERRIDE {
- return assertNotNull(S.ActOnCXXThis(Loc).takeAs<Expr>());
+ virtual Expr *build(Sema &S, SourceLocation Loc) const override {
+ return assertNotNull(S.ActOnCXXThis(Loc).getAs<Expr>());
}
};
@@ -8741,10 +9054,10 @@ class CastBuilder: public ExprBuilder {
const CXXCastPath &Path;
public:
- virtual Expr *build(Sema &S, SourceLocation Loc) const LLVM_OVERRIDE {
+ virtual Expr *build(Sema &S, SourceLocation Loc) const override {
return assertNotNull(S.ImpCastExprToType(Builder.build(S, Loc), Type,
CK_UncheckedDerivedToBase, Kind,
- &Path).take());
+ &Path).get());
}
CastBuilder(const ExprBuilder &Builder, QualType Type, ExprValueKind Kind,
@@ -8756,9 +9069,9 @@ class DerefBuilder: public ExprBuilder {
const ExprBuilder &Builder;
public:
- virtual Expr *build(Sema &S, SourceLocation Loc) const LLVM_OVERRIDE {
+ virtual Expr *build(Sema &S, SourceLocation Loc) const override {
return assertNotNull(
- S.CreateBuiltinUnaryOp(Loc, UO_Deref, Builder.build(S, Loc)).take());
+ S.CreateBuiltinUnaryOp(Loc, UO_Deref, Builder.build(S, Loc)).get());
}
DerefBuilder(const ExprBuilder &Builder) : Builder(Builder) {}
@@ -8772,10 +9085,10 @@ class MemberBuilder: public ExprBuilder {
LookupResult &MemberLookup;
public:
- virtual Expr *build(Sema &S, SourceLocation Loc) const LLVM_OVERRIDE {
+ virtual Expr *build(Sema &S, SourceLocation Loc) const override {
return assertNotNull(S.BuildMemberReferenceExpr(
- Builder.build(S, Loc), Type, Loc, IsArrow, SS, SourceLocation(), 0,
- MemberLookup, 0).take());
+ Builder.build(S, Loc), Type, Loc, IsArrow, SS, SourceLocation(),
+ nullptr, MemberLookup, nullptr).get());
}
MemberBuilder(const ExprBuilder &Builder, QualType Type, bool IsArrow,
@@ -8788,7 +9101,7 @@ class MoveCastBuilder: public ExprBuilder {
const ExprBuilder &Builder;
public:
- virtual Expr *build(Sema &S, SourceLocation Loc) const LLVM_OVERRIDE {
+ virtual Expr *build(Sema &S, SourceLocation Loc) const override {
return assertNotNull(CastForMoving(S, Builder.build(S, Loc)));
}
@@ -8799,9 +9112,9 @@ class LvalueConvBuilder: public ExprBuilder {
const ExprBuilder &Builder;
public:
- virtual Expr *build(Sema &S, SourceLocation Loc) const LLVM_OVERRIDE {
+ virtual Expr *build(Sema &S, SourceLocation Loc) const override {
return assertNotNull(
- S.DefaultLvalueConversion(Builder.build(S, Loc)).take());
+ S.DefaultLvalueConversion(Builder.build(S, Loc)).get());
}
LvalueConvBuilder(const ExprBuilder &Builder) : Builder(Builder) {}
@@ -8812,10 +9125,9 @@ class SubscriptBuilder: public ExprBuilder {
const ExprBuilder &Index;
public:
- virtual Expr *build(Sema &S, SourceLocation Loc) const
- LLVM_OVERRIDE {
+ virtual Expr *build(Sema &S, SourceLocation Loc) const override {
return assertNotNull(S.CreateBuiltinArraySubscriptExpr(
- Base.build(S, Loc), Loc, Index.build(S, Loc), Loc).take());
+ Base.build(S, Loc), Loc, Index.build(S, Loc), Loc).get());
}
SubscriptBuilder(const ExprBuilder &Base, const ExprBuilder &Index)
@@ -8867,17 +9179,17 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T,
return StmtError();
ExprResult MemCpyRef = S.BuildDeclRefExpr(MemCpy, S.Context.BuiltinFnTy,
- VK_RValue, Loc, 0);
+ VK_RValue, Loc, nullptr);
assert(MemCpyRef.isUsable() && "Builtin reference cannot fail");
Expr *CallArgs[] = {
To, From, IntegerLiteral::Create(S.Context, Size, SizeType, Loc)
};
- ExprResult Call = S.ActOnCallExpr(/*Scope=*/0, MemCpyRef.take(),
+ ExprResult Call = S.ActOnCallExpr(/*Scope=*/nullptr, MemCpyRef.get(),
Loc, CallArgs, Loc);
assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!");
- return S.Owned(Call.takeAs<Stmt>());
+ return Call.getAs<Stmt>();
}
/// \brief Builds a statement that copies/moves the given entity from \p From to
@@ -8976,7 +9288,7 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
CXXScopeSpec SS;
const Type *CanonicalT = S.Context.getCanonicalType(T.getTypePtr());
SS.MakeTrivial(S.Context,
- NestedNameSpecifier::Create(S.Context, 0, false,
+ NestedNameSpecifier::Create(S.Context, nullptr, false,
CanonicalT),
Loc);
@@ -8984,9 +9296,9 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
ExprResult OpEqualRef
= S.BuildMemberReferenceExpr(To.build(S, Loc), T, Loc, /*isArrow=*/false,
SS, /*TemplateKWLoc=*/SourceLocation(),
- /*FirstQualifierInScope=*/0,
+ /*FirstQualifierInScope=*/nullptr,
OpLookup,
- /*TemplateArgs=*/0,
+ /*TemplateArgs=*/nullptr,
/*SuppressQualifierCheck=*/true);
if (OpEqualRef.isInvalid())
return StmtError();
@@ -8994,8 +9306,8 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
// Build the call to the assignment operator.
Expr *FromInst = From.build(S, Loc);
- ExprResult Call = S.BuildCallToMemberFunction(/*Scope=*/0,
- OpEqualRef.takeAs<Expr>(),
+ ExprResult Call = S.BuildCallToMemberFunction(/*Scope=*/nullptr,
+ OpEqualRef.getAs<Expr>(),
Loc, FromInst, Loc);
if (Call.isInvalid())
return StmtError();
@@ -9004,7 +9316,7 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
// bail out. We'll replace the whole shebang with a memcpy.
CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(Call.get());
if (CE && CE->getMethodDecl()->isTrivial() && Depth)
- return StmtResult((Stmt*)0);
+ return StmtResult((Stmt*)nullptr);
// Convert to an expression-statement, and clean up any produced
// temporaries.
@@ -9033,7 +9345,7 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
QualType SizeType = S.Context.getSizeType();
// Create the iteration variable.
- IdentifierInfo *IterationVarName = 0;
+ IdentifierInfo *IterationVarName = nullptr;
{
SmallString<8> Str;
llvm::raw_svector_ostream OS(Str);
@@ -9093,8 +9405,8 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
// Construct the loop that copies all elements of this array.
return S.ActOnForStmt(Loc, Loc, InitStmt,
S.MakeFullExpr(Comparison),
- 0, S.MakeFullDiscardedValueExpr(Increment),
- Loc, Copy.take());
+ nullptr, S.MakeFullDiscardedValueExpr(Increment),
+ Loc, Copy.get());
}
static StmtResult
@@ -9127,8 +9439,9 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD) {
return ExceptSpec;
const FunctionProtoType *T = MD->getType()->castAs<FunctionProtoType>();
- assert(T->getNumArgs() == 1 && "not a copy assignment op");
- unsigned ArgQuals = T->getArgType(0).getNonReferenceType().getCVRQualifiers();
+ assert(T->getNumParams() == 1 && "not a copy assignment op");
+ unsigned ArgQuals =
+ T->getParamType(0).getNonReferenceType().getCVRQualifiers();
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have an
@@ -9140,33 +9453,26 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD) {
// 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.
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
- BaseEnd = ClassDecl->bases_end();
- Base != BaseEnd; ++Base) {
- if (Base->isVirtual())
+ for (const auto &Base : ClassDecl->bases()) {
+ if (Base.isVirtual())
continue;
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,
ArgQuals, false, 0))
- ExceptSpec.CalledDecl(Base->getLocStart(), CopyAssign);
+ ExceptSpec.CalledDecl(Base.getLocStart(), CopyAssign);
}
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
- BaseEnd = ClassDecl->vbases_end();
- Base != BaseEnd; ++Base) {
+ for (const auto &Base : ClassDecl->vbases()) {
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,
ArgQuals, false, 0))
- ExceptSpec.CalledDecl(Base->getLocStart(), CopyAssign);
+ ExceptSpec.CalledDecl(Base.getLocStart(), CopyAssign);
}
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd;
- ++Field) {
+ for (const auto *Field : ClassDecl->fields()) {
QualType FieldType = Context.getBaseElementType(Field->getType());
if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
if (CXXMethodDecl *CopyAssign =
@@ -9189,7 +9495,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
DeclaringSpecialMember DSM(*this, ClassDecl, CXXCopyAssignment);
if (DSM.isAlreadyBeingDeclared())
- return 0;
+ return nullptr;
QualType ArgType = Context.getTypeDeclType(ClassDecl);
QualType RetType = Context.getLValueReferenceType(ArgType);
@@ -9209,8 +9515,8 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXMethodDecl *CopyAssignment =
CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
- /*TInfo=*/ 0, /*StorageClass=*/ SC_None,
- /*isInline=*/ true, Constexpr, SourceLocation());
+ /*TInfo=*/nullptr, /*StorageClass=*/SC_None,
+ /*isInline=*/true, Constexpr, SourceLocation());
CopyAssignment->setAccess(AS_public);
CopyAssignment->setDefaulted();
CopyAssignment->setImplicit();
@@ -9222,9 +9528,10 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
- ClassLoc, ClassLoc, /*Id=*/0,
- ArgType, /*TInfo=*/0,
- SC_None, 0);
+ ClassLoc, ClassLoc,
+ /*Id=*/nullptr, ArgType,
+ /*TInfo=*/nullptr, SC_None,
+ nullptr);
CopyAssignment->setParams(FromParam);
AddOverriddenMethods(ClassDecl, CopyAssignment);
@@ -9255,7 +9562,7 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp,
assert(CopyOp->isImplicit());
CXXRecordDecl *RD = CopyOp->getParent();
- CXXMethodDecl *UserDeclaredOperation = 0;
+ CXXMethodDecl *UserDeclaredOperation = nullptr;
// In Microsoft mode, assignment operations don't affect constructors and
// vice versa.
@@ -9263,24 +9570,22 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp,
UserDeclaredOperation = RD->getDestructor();
} else if (!isa<CXXConstructorDecl>(CopyOp) &&
RD->hasUserDeclaredCopyConstructor() &&
- !S.getLangOpts().MicrosoftMode) {
+ !S.getLangOpts().MSVCCompat) {
// Find any user-declared copy constructor.
- for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(),
- E = RD->ctor_end(); I != E; ++I) {
+ for (auto *I : RD->ctors()) {
if (I->isCopyConstructor()) {
- UserDeclaredOperation = *I;
+ UserDeclaredOperation = I;
break;
}
}
assert(UserDeclaredOperation);
} else if (isa<CXXConstructorDecl>(CopyOp) &&
RD->hasUserDeclaredCopyAssignment() &&
- !S.getLangOpts().MicrosoftMode) {
+ !S.getLangOpts().MSVCCompat) {
// Find any user-declared move assignment operator.
- for (CXXRecordDecl::method_iterator I = RD->method_begin(),
- E = RD->method_end(); I != E; ++I) {
+ for (auto *I : RD->methods()) {
if (I->isCopyAssignmentOperator()) {
- UserDeclaredOperation = *I;
+ UserDeclaredOperation = I;
break;
}
}
@@ -9349,8 +9654,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
}
// Our location for everything implicitly-generated.
- SourceLocation Loc = CopyAssignOperator->getLocation();
-
+ SourceLocation Loc = CopyAssignOperator->getLocEnd().isValid()
+ ? CopyAssignOperator->getLocEnd()
+ : CopyAssignOperator->getLocation();
+
// Builds a DeclRefExpr for the "other" object.
RefBuilder OtherRef(Other, OtherRefType);
@@ -9359,18 +9666,17 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// Assign base classes.
bool Invalid = false;
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
- E = ClassDecl->bases_end(); Base != E; ++Base) {
+ for (auto &Base : ClassDecl->bases()) {
// Form the assignment:
// static_cast<Base*>(this)->Base::operator=(static_cast<Base&>(other));
- QualType BaseType = Base->getType().getUnqualifiedType();
+ QualType BaseType = Base.getType().getUnqualifiedType();
if (!BaseType->isRecordType()) {
Invalid = true;
continue;
}
CXXCastPath BasePath;
- BasePath.push_back(Base);
+ BasePath.push_back(&Base);
// Construct the "from" expression, which is an implicit cast to the
// appropriately-qualified base type.
@@ -9397,13 +9703,11 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
}
// Success! Record the copy.
- Statements.push_back(Copy.takeAs<Expr>());
+ Statements.push_back(Copy.getAs<Expr>());
}
// Assign non-static members.
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
+ for (auto *Field : ClassDecl->fields()) {
if (Field->isUnnamedBitfield())
continue;
@@ -9450,7 +9754,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
CXXScopeSpec SS; // Intentionally empty
LookupResult MemberLookup(*this, Field->getDeclName(), Loc,
LookupMemberName);
- MemberLookup.addDecl(*Field);
+ MemberLookup.addDecl(Field);
MemberLookup.resolveKind();
MemberBuilder From(OtherRef, OtherRefType, /*IsArrow=*/false, MemberLookup);
@@ -9470,18 +9774,18 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
}
// Success! Record the copy.
- Statements.push_back(Copy.takeAs<Stmt>());
+ Statements.push_back(Copy.getAs<Stmt>());
}
if (!Invalid) {
// Add a "return *this;"
ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc));
- StmtResult Return = ActOnReturnStmt(Loc, ThisObj.get());
+ StmtResult Return = BuildReturnStmt(Loc, ThisObj.get());
if (Return.isInvalid())
Invalid = true;
else {
- Statements.push_back(Return.takeAs<Stmt>());
+ Statements.push_back(Return.getAs<Stmt>());
if (Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
@@ -9503,7 +9807,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
/*isStmtExpr=*/false);
assert(!Body.isInvalid() && "Compound statement creation cannot fail");
}
- CopyAssignOperator->setBody(Body.takeAs<Stmt>());
+ CopyAssignOperator->setBody(Body.getAs<Stmt>());
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(CopyAssignOperator);
@@ -9530,33 +9834,26 @@ Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD) {
// actually happen.
// Note that a move constructor is not implicitly declared when there are
// virtual bases, but it can still be user-declared and explicitly defaulted.
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
- BaseEnd = ClassDecl->bases_end();
- Base != BaseEnd; ++Base) {
- if (Base->isVirtual())
+ for (const auto &Base : ClassDecl->bases()) {
+ if (Base.isVirtual())
continue;
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
0, false, 0))
- ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign);
+ ExceptSpec.CalledDecl(Base.getLocStart(), MoveAssign);
}
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
- BaseEnd = ClassDecl->vbases_end();
- Base != BaseEnd; ++Base) {
+ for (const auto &Base : ClassDecl->vbases()) {
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
0, false, 0))
- ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign);
+ ExceptSpec.CalledDecl(Base.getLocStart(), MoveAssign);
}
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd;
- ++Field) {
+ for (const auto *Field : ClassDecl->fields()) {
QualType FieldType = Context.getBaseElementType(Field->getType());
if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
if (CXXMethodDecl *MoveAssign =
@@ -9575,7 +9872,7 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
DeclaringSpecialMember DSM(*this, ClassDecl, CXXMoveAssignment);
if (DSM.isAlreadyBeingDeclared())
- return 0;
+ return nullptr;
// Note: The following rules are largely analoguous to the move
// constructor rules.
@@ -9595,7 +9892,7 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXMethodDecl *MoveAssignment =
CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
- /*TInfo=*/0, /*StorageClass=*/SC_None,
+ /*TInfo=*/nullptr, /*StorageClass=*/SC_None,
/*isInline=*/true, Constexpr, SourceLocation());
MoveAssignment->setAccess(AS_public);
MoveAssignment->setDefaulted();
@@ -9608,9 +9905,10 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveAssignment,
- ClassLoc, ClassLoc, /*Id=*/0,
- ArgType, /*TInfo=*/0,
- SC_None, 0);
+ ClassLoc, ClassLoc,
+ /*Id=*/nullptr, ArgType,
+ /*TInfo=*/nullptr, SC_None,
+ nullptr);
MoveAssignment->setParams(FromParam);
AddOverriddenMethods(ClassDecl, MoveAssignment);
@@ -9654,10 +9952,8 @@ static void checkMoveAssignmentForRepeatedMove(Sema &S, CXXRecordDecl *Class,
typedef llvm::DenseMap<CXXRecordDecl*, CXXBaseSpecifier*> VBaseMap;
VBaseMap VBases;
- for (CXXRecordDecl::base_class_iterator BI = Class->bases_begin(),
- BE = Class->bases_end();
- BI != BE; ++BI) {
- Worklist.push_back(&*BI);
+ for (auto &BI : Class->bases()) {
+ Worklist.push_back(&BI);
while (!Worklist.empty()) {
CXXBaseSpecifier *BaseSpec = Worklist.pop_back_val();
CXXRecordDecl *Base = BaseSpec->getType()->getAsCXXRecordDecl();
@@ -9689,22 +9985,22 @@ static void checkMoveAssignmentForRepeatedMove(Sema &S, CXXRecordDecl *Class,
// only happens in one base, we'll diagnose it when synthesizing
// that base class's move assignment operator.)
CXXBaseSpecifier *&Existing =
- VBases.insert(std::make_pair(Base->getCanonicalDecl(), BI))
+ VBases.insert(std::make_pair(Base->getCanonicalDecl(), &BI))
.first->second;
- if (Existing && Existing != BI) {
+ if (Existing && Existing != &BI) {
S.Diag(CurrentLocation, diag::warn_vbase_moved_multiple_times)
<< Class << Base;
S.Diag(Existing->getLocStart(), diag::note_vbase_moved_here)
<< (Base->getCanonicalDecl() ==
Existing->getType()->getAsCXXRecordDecl()->getCanonicalDecl())
<< Base << Existing->getType() << Existing->getSourceRange();
- S.Diag(BI->getLocStart(), diag::note_vbase_moved_here)
+ S.Diag(BI.getLocStart(), diag::note_vbase_moved_here)
<< (Base->getCanonicalDecl() ==
- BI->getType()->getAsCXXRecordDecl()->getCanonicalDecl())
- << Base << BI->getType() << BaseSpec->getSourceRange();
+ BI.getType()->getAsCXXRecordDecl()->getCanonicalDecl())
+ << Base << BI.getType() << BaseSpec->getSourceRange();
// Only diagnose each vbase once.
- Existing = 0;
+ Existing = nullptr;
}
} else {
// Only walk over bases that have defaulted move assignment operators.
@@ -9714,10 +10010,8 @@ static void checkMoveAssignmentForRepeatedMove(Sema &S, CXXRecordDecl *Class,
continue;
// We're going to move the base classes of Base. Add them to the list.
- for (CXXRecordDecl::base_class_iterator BI = Base->bases_begin(),
- BE = Base->bases_end();
- BI != BE; ++BI)
- Worklist.push_back(&*BI);
+ for (auto &BI : Base->bases())
+ Worklist.push_back(&BI);
}
}
}
@@ -9767,7 +10061,9 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
"Bad argument type of defaulted move assignment");
// Our location for everything implicitly-generated.
- SourceLocation Loc = MoveAssignOperator->getLocation();
+ SourceLocation Loc = MoveAssignOperator->getLocEnd().isValid()
+ ? MoveAssignOperator->getLocEnd()
+ : MoveAssignOperator->getLocation();
// Builds a reference to the "other" object.
RefBuilder OtherRef(Other, OtherRefType);
@@ -9779,8 +10075,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// Assign base classes.
bool Invalid = false;
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
- E = ClassDecl->bases_end(); Base != E; ++Base) {
+ for (auto &Base : ClassDecl->bases()) {
// C++11 [class.copy]p28:
// It is unspecified whether subobjects representing virtual base classes
// are assigned more than once by the implicitly-defined copy assignment
@@ -9791,14 +10086,14 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// Form the assignment:
// static_cast<Base*>(this)->Base::operator=(static_cast<Base&&>(other));
- QualType BaseType = Base->getType().getUnqualifiedType();
+ QualType BaseType = Base.getType().getUnqualifiedType();
if (!BaseType->isRecordType()) {
Invalid = true;
continue;
}
CXXCastPath BasePath;
- BasePath.push_back(Base);
+ BasePath.push_back(&Base);
// Construct the "from" expression, which is an implicit cast to the
// appropriately-qualified base type.
@@ -9826,13 +10121,11 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
}
// Success! Record the move.
- Statements.push_back(Move.takeAs<Expr>());
+ Statements.push_back(Move.getAs<Expr>());
}
// Assign non-static members.
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
+ for (auto *Field : ClassDecl->fields()) {
if (Field->isUnnamedBitfield())
continue;
@@ -9878,7 +10171,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// Build references to the field in the object we're copying from and to.
LookupResult MemberLookup(*this, Field->getDeclName(), Loc,
LookupMemberName);
- MemberLookup.addDecl(*Field);
+ MemberLookup.addDecl(Field);
MemberLookup.resolveKind();
MemberBuilder From(MoveOther, OtherRefType,
/*IsArrow=*/false, MemberLookup);
@@ -9902,18 +10195,19 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
}
// Success! Record the copy.
- Statements.push_back(Move.takeAs<Stmt>());
+ Statements.push_back(Move.getAs<Stmt>());
}
if (!Invalid) {
// Add a "return *this;"
- ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc));
-
- StmtResult Return = ActOnReturnStmt(Loc, ThisObj.get());
+ ExprResult ThisObj =
+ CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc));
+
+ StmtResult Return = BuildReturnStmt(Loc, ThisObj.get());
if (Return.isInvalid())
Invalid = true;
else {
- Statements.push_back(Return.takeAs<Stmt>());
+ Statements.push_back(Return.getAs<Stmt>());
if (Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
@@ -9935,7 +10229,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
/*isStmtExpr=*/false);
assert(!Body.isInvalid() && "Compound statement creation cannot fail");
}
- MoveAssignOperator->setBody(Body.takeAs<Stmt>());
+ MoveAssignOperator->setBody(Body.getAs<Stmt>());
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(MoveAssignOperator);
@@ -9951,40 +10245,31 @@ Sema::ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD) {
return ExceptSpec;
const FunctionProtoType *T = MD->getType()->castAs<FunctionProtoType>();
- assert(T->getNumArgs() >= 1 && "not a copy ctor");
- unsigned Quals = T->getArgType(0).getNonReferenceType().getCVRQualifiers();
+ assert(T->getNumParams() >= 1 && "not a copy ctor");
+ unsigned Quals = T->getParamType(0).getNonReferenceType().getCVRQualifiers();
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have an
// exception-specification. [...]
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
- BaseEnd = ClassDecl->bases_end();
- Base != BaseEnd;
- ++Base) {
+ for (const auto &Base : ClassDecl->bases()) {
// Virtual bases are handled below.
- if (Base->isVirtual())
+ if (Base.isVirtual())
continue;
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
if (CXXConstructorDecl *CopyConstructor =
LookupCopyingConstructor(BaseClassDecl, Quals))
- ExceptSpec.CalledDecl(Base->getLocStart(), CopyConstructor);
+ ExceptSpec.CalledDecl(Base.getLocStart(), CopyConstructor);
}
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
- BaseEnd = ClassDecl->vbases_end();
- Base != BaseEnd;
- ++Base) {
+ for (const auto &Base : ClassDecl->vbases()) {
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
if (CXXConstructorDecl *CopyConstructor =
LookupCopyingConstructor(BaseClassDecl, Quals))
- ExceptSpec.CalledDecl(Base->getLocStart(), CopyConstructor);
+ ExceptSpec.CalledDecl(Base.getLocStart(), CopyConstructor);
}
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd;
- ++Field) {
+ for (const auto *Field : ClassDecl->fields()) {
QualType FieldType = Context.getBaseElementType(Field->getType());
if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
if (CXXConstructorDecl *CopyConstructor =
@@ -10006,7 +10291,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
DeclaringSpecialMember DSM(*this, ClassDecl, CXXCopyConstructor);
if (DSM.isAlreadyBeingDeclared())
- return 0;
+ return nullptr;
QualType ClassType = Context.getTypeDeclType(ClassDecl);
QualType ArgType = ClassType;
@@ -10028,7 +10313,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
// An implicitly-declared copy constructor is an inline public
// member of its class.
CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(
- Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/0,
+ Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
/*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
Constexpr);
CopyConstructor->setAccess(AS_public);
@@ -10043,9 +10328,9 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor,
ClassLoc, ClassLoc,
- /*IdentifierInfo=*/0,
- ArgType, /*TInfo=*/0,
- SC_None, 0);
+ /*IdentifierInfo=*/nullptr,
+ ArgType, /*TInfo=*/nullptr,
+ SC_None, nullptr);
CopyConstructor->setParams(FromParam);
CopyConstructor->setTrivial(
@@ -10093,13 +10378,17 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
<< CXXCopyConstructor << Context.getTagDeclType(ClassDecl);
CopyConstructor->setInvalidDecl();
} else {
+ SourceLocation Loc = CopyConstructor->getLocEnd().isValid()
+ ? CopyConstructor->getLocEnd()
+ : CopyConstructor->getLocation();
Sema::CompoundScopeRAII CompoundScope(*this);
- CopyConstructor->setBody(ActOnCompoundStmt(
- CopyConstructor->getLocation(), CopyConstructor->getLocation(), None,
- /*isStmtExpr=*/ false).takeAs<Stmt>());
+ CopyConstructor->setBody(
+ ActOnCompoundStmt(Loc, Loc, None, /*isStmtExpr=*/false).getAs<Stmt>());
}
CopyConstructor->markUsed(Context);
+ MarkVTableUsed(CurrentLocation, ClassDecl);
+
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(CopyConstructor);
}
@@ -10117,42 +10406,36 @@ Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD) {
return ExceptSpec;
// Direct base-class constructors.
- for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
- BEnd = ClassDecl->bases_end();
- B != BEnd; ++B) {
- if (B->isVirtual()) // Handled below.
+ for (const auto &B : ClassDecl->bases()) {
+ if (B.isVirtual()) // Handled below.
continue;
- if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
+ if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
CXXConstructorDecl *Constructor =
LookupMovingConstructor(BaseClassDecl, 0);
// If this is a deleted function, add it anyway. This might be conformant
// with the standard. This might not. I'm not sure. It might not matter.
if (Constructor)
- ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
+ ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
}
}
// Virtual base-class constructors.
- for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(),
- BEnd = ClassDecl->vbases_end();
- B != BEnd; ++B) {
- if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
+ for (const auto &B : ClassDecl->vbases()) {
+ if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
CXXConstructorDecl *Constructor =
LookupMovingConstructor(BaseClassDecl, 0);
// If this is a deleted function, add it anyway. This might be conformant
// with the standard. This might not. I'm not sure. It might not matter.
if (Constructor)
- ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
+ ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
}
}
// Field constructors.
- for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
- FEnd = ClassDecl->field_end();
- F != FEnd; ++F) {
+ for (const auto *F : ClassDecl->fields()) {
QualType FieldType = Context.getBaseElementType(F->getType());
if (CXXRecordDecl *FieldRecDecl = FieldType->getAsCXXRecordDecl()) {
CXXConstructorDecl *Constructor =
@@ -10176,7 +10459,7 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
DeclaringSpecialMember DSM(*this, ClassDecl, CXXMoveConstructor);
if (DSM.isAlreadyBeingDeclared())
- return 0;
+ return nullptr;
QualType ClassType = Context.getTypeDeclType(ClassDecl);
QualType ArgType = Context.getRValueReferenceType(ClassType);
@@ -10195,7 +10478,7 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
// An implicitly-declared copy/move constructor is an inline public
// member of its class.
CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create(
- Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/0,
+ Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
/*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
Constexpr);
MoveConstructor->setAccess(AS_public);
@@ -10210,9 +10493,9 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor,
ClassLoc, ClassLoc,
- /*IdentifierInfo=*/0,
- ArgType, /*TInfo=*/0,
- SC_None, 0);
+ /*IdentifierInfo=*/nullptr,
+ ArgType, /*TInfo=*/nullptr,
+ SC_None, nullptr);
MoveConstructor->setParams(FromParam);
MoveConstructor->setTrivial(
@@ -10255,13 +10538,16 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
<< CXXMoveConstructor << Context.getTagDeclType(ClassDecl);
MoveConstructor->setInvalidDecl();
} else {
+ SourceLocation Loc = MoveConstructor->getLocEnd().isValid()
+ ? MoveConstructor->getLocEnd()
+ : MoveConstructor->getLocation();
Sema::CompoundScopeRAII CompoundScope(*this);
MoveConstructor->setBody(ActOnCompoundStmt(
- MoveConstructor->getLocation(), MoveConstructor->getLocation(), None,
- /*isStmtExpr=*/ false).takeAs<Stmt>());
+ Loc, Loc, None, /*isStmtExpr=*/ false).getAs<Stmt>());
}
MoveConstructor->markUsed(Context);
+ MarkVTableUsed(CurrentLocation, ClassDecl);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(MoveConstructor);
@@ -10281,19 +10567,17 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
// cache the deduced template arguments for this specialization
// so that we can use them to retrieve the corresponding call-operator
// and static-invoker.
- const TemplateArgumentList *DeducedTemplateArgs = 0;
-
-
+ const TemplateArgumentList *DeducedTemplateArgs = nullptr;
+
// Retrieve the corresponding call-operator specialization.
if (Lambda->isGenericLambda()) {
assert(Conv->isFunctionTemplateSpecialization());
FunctionTemplateDecl *CallOpTemplate =
CallOp->getDescribedFunctionTemplate();
DeducedTemplateArgs = Conv->getTemplateSpecializationArgs();
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
FunctionDecl *CallOpSpec = CallOpTemplate->findSpecialization(
- DeducedTemplateArgs->data(),
- DeducedTemplateArgs->size(),
+ DeducedTemplateArgs->asArray(),
InsertPos);
assert(CallOpSpec &&
"Conversion operator must have a corresponding call operator");
@@ -10309,7 +10593,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
SynthesizedFunctionScope Scope(*this, Conv);
DiagnosticErrorTrap Trap(Diags);
- // Retreive the static invoker...
+ // Retrieve the static invoker...
CXXMethodDecl *Invoker = Lambda->getLambdaStaticInvoker();
// ... and get the corresponding specialization for a generic lambda.
if (Lambda->isGenericLambda()) {
@@ -10317,10 +10601,9 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
"Must have deduced template arguments from Conversion Operator");
FunctionTemplateDecl *InvokeTemplate =
Invoker->getDescribedFunctionTemplate();
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
FunctionDecl *InvokeSpec = InvokeTemplate->findSpecialization(
- DeducedTemplateArgs->data(),
- DeducedTemplateArgs->size(),
+ DeducedTemplateArgs->asArray(),
InsertPos);
assert(InvokeSpec &&
"Must have a corresponding static invoker specialization");
@@ -10328,9 +10611,9 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
}
// Construct the body of the conversion function { return __invoke; }.
Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(),
- VK_LValue, Conv->getLocation()).take();
+ VK_LValue, Conv->getLocation()).get();
assert(FunctionRef && "Can't refer to __invoke function?");
- Stmt *Return = ActOnReturnStmt(Conv->getLocation(), FunctionRef).take();
+ Stmt *Return = BuildReturnStmt(Conv->getLocation(), FunctionRef).get();
Conv->setBody(new (Context) CompoundStmt(Context, Return,
Conv->getLocation(),
Conv->getLocation()));
@@ -10364,8 +10647,8 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
DiagnosticErrorTrap Trap(Diags);
// Copy-initialize the lambda object as needed to capture it.
- Expr *This = ActOnCXXThis(CurrentLocation).take();
- Expr *DerefThis =CreateBuiltinUnaryOp(CurrentLocation, UO_Deref, This).take();
+ Expr *This = ActOnCXXThis(CurrentLocation).get();
+ Expr *DerefThis =CreateBuiltinUnaryOp(CurrentLocation, UO_Deref, This).get();
ExprResult BuildBlock = BuildBlockForLambdaConversion(CurrentLocation,
Conv->getLocation(),
@@ -10378,7 +10661,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
if (!BuildBlock.isInvalid() && !getLangOpts().ObjCAutoRefCount)
BuildBlock = ImplicitCastExpr::Create(Context, BuildBlock.get()->getType(),
CK_CopyAndAutoreleaseBlockObject,
- BuildBlock.get(), 0, VK_RValue);
+ BuildBlock.get(), nullptr, VK_RValue);
if (BuildBlock.isInvalid()) {
Diag(CurrentLocation, diag::note_lambda_to_block_conv);
@@ -10388,7 +10671,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
// Create the return statement that returns the block from the conversion
// function.
- StmtResult Return = ActOnReturnStmt(Conv->getLocation(), BuildBlock.get());
+ StmtResult Return = BuildReturnStmt(Conv->getLocation(), BuildBlock.get());
if (Return.isInvalid()) {
Diag(CurrentLocation, diag::note_lambda_to_block_conv);
Conv->setInvalidDecl();
@@ -10396,7 +10679,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
}
// Set the body of the conversion function.
- Stmt *ReturnS = Return.take();
+ Stmt *ReturnS = Return.get();
Conv->setBody(new (Context) CompoundStmt(Context, ReturnS,
Conv->getLocation(),
Conv->getLocation()));
@@ -10432,6 +10715,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
MultiExprArg ExprArgs,
bool HadMultipleCandidates,
bool IsListInitialization,
+ bool IsStdInitListInitialization,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
@@ -10455,7 +10739,8 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
Elidable, ExprArgs, HadMultipleCandidates,
- IsListInitialization, RequiresZeroInit,
+ IsListInitialization,
+ IsStdInitListInitialization, RequiresZeroInit,
ConstructKind, ParenRange);
}
@@ -10467,16 +10752,17 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
MultiExprArg ExprArgs,
bool HadMultipleCandidates,
bool IsListInitialization,
+ bool IsStdInitListInitialization,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
MarkFunctionReferenced(ConstructLoc, Constructor);
- return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
- Constructor, Elidable, ExprArgs,
- HadMultipleCandidates,
- IsListInitialization, RequiresZeroInit,
- static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind),
- ParenRange));
+ return CXXConstructExpr::Create(
+ Context, DeclInitType, ConstructLoc, Constructor, Elidable, ExprArgs,
+ HadMultipleCandidates, IsListInitialization, IsStdInitListInitialization,
+ RequiresZeroInit,
+ static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind),
+ ParenRange);
}
void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
@@ -10495,6 +10781,7 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
<< VD->getType());
DiagnoseUseOfDecl(Destructor, VD->getLocation());
+ if (Destructor->isTrivial()) return;
if (!VD->hasGlobalStorage()) return;
// Emit warning for non-trivial dtor in global scope (a real global,
@@ -10525,11 +10812,11 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
const FunctionProtoType *Proto
= Constructor->getType()->getAs<FunctionProtoType>();
assert(Proto && "Constructor without a prototype?");
- unsigned NumArgsInProto = Proto->getNumArgs();
-
+ unsigned NumParams = Proto->getNumParams();
+
// If too few arguments are available, we'll fill in the rest with defaults.
- if (NumArgs < NumArgsInProto)
- ConvertedArgs.reserve(NumArgsInProto);
+ if (NumArgs < NumParams)
+ ConvertedArgs.reserve(NumParams);
else
ConvertedArgs.reserve(NumArgs);
@@ -10580,8 +10867,8 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
CanQualType ExpectedFirstParamType,
unsigned DependentParamTypeDiag,
unsigned InvalidParamTypeDiag) {
- QualType ResultType =
- FnDecl->getType()->getAs<FunctionType>()->getResultType();
+ QualType ResultType =
+ FnDecl->getType()->getAs<FunctionType>()->getReturnType();
// Check that the result type is not dependent.
if (ResultType->isDependentType())
@@ -10706,10 +10993,8 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
diag::err_operator_overload_static) << FnDecl->getDeclName();
} else {
bool ClassOrEnumParam = false;
- for (FunctionDecl::param_iterator Param = FnDecl->param_begin(),
- ParamEnd = FnDecl->param_end();
- Param != ParamEnd; ++Param) {
- QualType ParamType = (*Param)->getType().getNonReferenceType();
+ for (auto Param : FnDecl->params()) {
+ QualType ParamType = Param->getType().getNonReferenceType();
if (ParamType->isDependentType() || ParamType->isRecordType() ||
ParamType->isEnumeralType()) {
ClassOrEnumParam = true;
@@ -10730,12 +11015,11 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// Only the function-call operator allows default arguments
// (C++ [over.call]p1).
if (Op != OO_Call) {
- for (FunctionDecl::param_iterator Param = FnDecl->param_begin();
- Param != FnDecl->param_end(); ++Param) {
- if ((*Param)->hasDefaultArg())
- return Diag((*Param)->getLocation(),
+ for (auto Param : FnDecl->params()) {
+ if (Param->hasDefaultArg())
+ return Diag(Param->getLocation(),
diag::err_operator_overload_default_arg)
- << FnDecl->getDeclName() << (*Param)->getDefaultArgRange();
+ << FnDecl->getDeclName() << Param->getDefaultArgRange();
}
}
@@ -10802,11 +11086,10 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// increment operator ++ for objects of that type.
if ((Op == OO_PlusPlus || Op == OO_MinusMinus) && NumParams == 2) {
ParmVarDecl *LastParam = FnDecl->getParamDecl(FnDecl->getNumParams() - 1);
- bool ParamIsInt = false;
- if (const BuiltinType *BT = LastParam->getType()->getAs<BuiltinType>())
- ParamIsInt = BT->getKind() == BuiltinType::Int;
+ QualType ParamType = LastParam->getType();
- if (!ParamIsInt)
+ if (!ParamType->isSpecificBuiltinType(BuiltinType::Int) &&
+ !ParamType->isDependentType())
return Diag(LastParam->getLocation(),
diag::err_operator_overload_post_incdec_must_be_int)
<< LastParam->getType() << (Op == OO_MinusMinus);
@@ -10939,13 +11222,11 @@ FinishedParams:
// A parameter-declaration-clause containing a default argument is not
// equivalent to any of the permitted forms.
- for (FunctionDecl::param_iterator Param = FnDecl->param_begin(),
- ParamEnd = FnDecl->param_end();
- Param != ParamEnd; ++Param) {
- if ((*Param)->hasDefaultArg()) {
- Diag((*Param)->getDefaultArgRange().getBegin(),
+ for (auto Param : FnDecl->params()) {
+ if (Param->hasDefaultArg()) {
+ Diag(Param->getDefaultArgRange().getBegin(),
diag::err_literal_operator_default_argument)
- << (*Param)->getDefaultArgRange();
+ << Param->getDefaultArgRange();
break;
}
}
@@ -10965,29 +11246,36 @@ FinishedParams:
/// ActOnStartLinkageSpecification - Parsed the beginning of a C++
/// linkage specification, including the language and (if present)
-/// the '{'. ExternLoc is the location of the 'extern', LangLoc is
-/// the location of the language string literal, which is provided
-/// by Lang/StrSize. LBraceLoc, if valid, provides the location of
+/// the '{'. ExternLoc is the location of the 'extern', Lang is the
+/// language string literal. LBraceLoc, if valid, provides the location of
/// the '{' brace. Otherwise, this linkage specification does not
/// have any braces.
Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc,
- SourceLocation LangLoc,
- StringRef Lang,
+ Expr *LangStr,
SourceLocation LBraceLoc) {
+ StringLiteral *Lit = cast<StringLiteral>(LangStr);
+ if (!Lit->isAscii()) {
+ Diag(LangStr->getExprLoc(), diag::err_language_linkage_spec_not_ascii)
+ << LangStr->getSourceRange();
+ return nullptr;
+ }
+
+ StringRef Lang = Lit->getString();
LinkageSpecDecl::LanguageIDs Language;
- if (Lang == "\"C\"")
+ if (Lang == "C")
Language = LinkageSpecDecl::lang_c;
- else if (Lang == "\"C++\"")
+ else if (Lang == "C++")
Language = LinkageSpecDecl::lang_cxx;
else {
- Diag(LangLoc, diag::err_bad_language);
- return 0;
+ Diag(LangStr->getExprLoc(), diag::err_language_linkage_spec_unknown)
+ << LangStr->getSourceRange();
+ return nullptr;
}
// FIXME: Add all the various semantics of linkage specifications
- LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext,
- ExternLoc, LangLoc, Language,
+ LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext, ExternLoc,
+ LangStr->getExprLoc(), Language,
LBraceLoc.isValid());
CurContext->addDecl(D);
PushDeclContext(S, D);
@@ -11001,13 +11289,11 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc,
Decl *Sema::ActOnFinishLinkageSpecification(Scope *S,
Decl *LinkageSpec,
SourceLocation RBraceLoc) {
- if (LinkageSpec) {
- if (RBraceLoc.isValid()) {
- LinkageSpecDecl* LSDecl = cast<LinkageSpecDecl>(LinkageSpec);
- LSDecl->setRBraceLoc(RBraceLoc);
- }
- PopDeclContext();
+ if (RBraceLoc.isValid()) {
+ LinkageSpecDecl* LSDecl = cast<LinkageSpecDecl>(LinkageSpec);
+ LSDecl->setRBraceLoc(RBraceLoc);
}
+ PopDeclContext();
return LinkageSpec;
}
@@ -11128,7 +11414,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
else {
// If the constructor used was non-trivial, set this as the
// "initializer".
- CXXConstructExpr *construct = result.takeAs<CXXConstructExpr>();
+ CXXConstructExpr *construct = result.getAs<CXXConstructExpr>();
if (!construct->getConstructor()->isTrivial()) {
Expr *init = MaybeCreateExprWithCleanups(construct);
ExDecl->setInit(init);
@@ -11165,13 +11451,17 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
LookupOrdinaryName,
ForRedeclaration)) {
// The scope should be freshly made just for us. There is just no way
- // it contains any previous declaration.
+ // it contains any previous declaration, except for function parameters in
+ // a function-try-block's catch statement.
assert(!S->isDeclScope(PrevDecl));
- if (PrevDecl->isTemplateParameter()) {
+ if (isDeclInScope(PrevDecl, CurContext, S)) {
+ Diag(D.getIdentifierLoc(), diag::err_redefinition)
+ << D.getIdentifier();
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ Invalid = true;
+ } else if (PrevDecl->isTemplateParameter())
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
- PrevDecl = 0;
- }
}
if (D.getCXXScopeSpec().isSet() && !Invalid) {
@@ -11201,10 +11491,11 @@ Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc,
Expr *AssertExpr,
Expr *AssertMessageExpr,
SourceLocation RParenLoc) {
- StringLiteral *AssertMessage = cast<StringLiteral>(AssertMessageExpr);
+ StringLiteral *AssertMessage =
+ AssertMessageExpr ? cast<StringLiteral>(AssertMessageExpr) : nullptr;
if (DiagnoseUnexpandedParameterPack(AssertExpr, UPPC_StaticAssertExpression))
- return 0;
+ return nullptr;
return BuildStaticAssertDeclaration(StaticAssertLoc, AssertExpr,
AssertMessage, RParenLoc, false);
@@ -11215,6 +11506,7 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
StringLiteral *AssertMessage,
SourceLocation RParenLoc,
bool Failed) {
+ assert(AssertExpr != nullptr && "Expected non-null condition");
if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent() &&
!Failed) {
// In a static_assert-declaration, the constant-expression shall be a
@@ -11232,9 +11524,10 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
if (!Failed && !Cond) {
SmallString<256> MsgBuffer;
llvm::raw_svector_ostream Msg(MsgBuffer);
- AssertMessage->printPretty(Msg, 0, getPrintingPolicy());
+ if (AssertMessage)
+ AssertMessage->printPretty(Msg, nullptr, getPrintingPolicy());
Diag(StaticAssertLoc, diag::err_static_assert_failed)
- << Msg.str() << AssertExpr->getSourceRange();
+ << !AssertMessage << Msg.str() << AssertExpr->getSourceRange();
Failed = true;
}
}
@@ -11273,9 +11566,10 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
// a tag in front.
if (const RecordType *RT = T->getAs<RecordType>()) {
RecordDecl *RD = RT->getDecl();
-
- std::string InsertionText = std::string(" ") + RD->getKindName();
-
+
+ SmallString<16> InsertionText(" ");
+ InsertionText += RD->getKindName();
+
Diag(TypeRange.getBegin(),
getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_unelaborated_friend_type :
@@ -11314,7 +11608,9 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
// If the type specifier in a friend declaration designates a (possibly
// cv-qualified) class type, that class is declared as a friend; otherwise,
// the friend declaration is ignored.
- return FriendDecl::Create(Context, CurContext, LocStart, TSInfo, FriendLoc);
+ return FriendDecl::Create(Context, CurContext,
+ TSInfo->getTypeLoc().getLocStart(), TSInfo,
+ FriendLoc);
}
/// Handle a friend tag declaration where the scope specifier was
@@ -11333,19 +11629,18 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
if (TemplateParameterList *TemplateParams =
MatchTemplateParametersToScopeSpecifier(
- TagLoc, NameLoc, SS, TempParamLists, /*friend*/ true,
+ TagLoc, NameLoc, SS, nullptr, TempParamLists, /*friend*/ true,
isExplicitSpecialization, Invalid)) {
if (TemplateParams->size() > 0) {
// This is a declaration of a class template.
if (Invalid)
- return 0;
+ return nullptr;
- return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc,
- SS, Name, NameLoc, Attr,
- TemplateParams, AS_public,
+ return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc, SS, Name,
+ NameLoc, Attr, TemplateParams, AS_public,
/*ModulePrivateLoc=*/SourceLocation(),
- TempParamLists.size() - 1,
- TempParamLists.data()).take();
+ FriendLoc, TempParamLists.size() - 1,
+ TempParamLists.data()).get();
} else {
// The "template<>" header is extraneous.
Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams)
@@ -11354,7 +11649,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
}
}
- if (Invalid) return 0;
+ if (Invalid) return nullptr;
bool isAllExplicitSpecializations = true;
for (unsigned I = TempParamLists.size(); I-- > 0; ) {
@@ -11374,21 +11669,22 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
bool Owned = false;
bool IsDependent = false;
return ActOnTag(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc,
- Attr, AS_public,
+ Attr, AS_public,
/*ModulePrivateLoc=*/SourceLocation(),
- MultiTemplateParamsArg(), Owned, IsDependent,
+ MultiTemplateParamsArg(), Owned, IsDependent,
/*ScopedEnumKWLoc=*/SourceLocation(),
/*ScopedEnumUsesClassTag=*/false,
- /*UnderlyingType=*/TypeResult());
+ /*UnderlyingType=*/TypeResult(),
+ /*IsTypeSpecifier=*/false);
}
-
+
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
ElaboratedTypeKeyword Keyword
= TypeWithKeyword::getKeywordForTagTypeKind(Kind);
QualType T = CheckTypenameType(Keyword, TagLoc, QualifierLoc,
*Name, NameLoc);
if (T.isNull())
- return 0;
+ return nullptr;
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
if (isa<DependentNameType>(T)) {
@@ -11468,10 +11764,10 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
TypeSourceInfo *TSI = GetTypeForDeclarator(TheDeclarator, S);
QualType T = TSI->getType();
if (TheDeclarator.isInvalidType())
- return 0;
+ return nullptr;
if (DiagnoseUnexpandedParameterPack(Loc, TSI, UPPC_FriendDeclaration))
- return 0;
+ return nullptr;
// This is definitely an error in C++98. It's probably meant to
// be forbidden in C++0x, too, but the specification is just
@@ -11490,7 +11786,7 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
if (TempParams.size() && !T->isElaboratedTypeSpecifier()) {
Diag(Loc, diag::err_tagless_friend_type_template)
<< DS.getSourceRange();
- return 0;
+ return nullptr;
}
// C++98 [class.friend]p1: A friend of a class is a function
@@ -11515,8 +11811,8 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
D = CheckFriendTypeDecl(Loc, DS.getFriendSpecLoc(), TSI);
if (!D)
- return 0;
-
+ return nullptr;
+
D->setAccess(AS_public);
CurContext->addDecl(D);
@@ -11548,7 +11844,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
// It might be worthwhile to try to recover by creating an
// appropriate declaration.
- return 0;
+ return nullptr;
}
// C++ [namespace.memdef]p3
@@ -11575,7 +11871,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
if (DiagnoseUnexpandedParameterPack(Loc, TInfo, UPPC_FriendDeclaration) ||
DiagnoseUnexpandedParameterPack(NameInfo, UPPC_FriendDeclaration) ||
DiagnoseUnexpandedParameterPack(SS, UPPC_FriendDeclaration))
- return 0;
+ return nullptr;
// The context we found the declaration in, or in which we should
// create the declaration.
@@ -11588,7 +11884,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
// - There's no scope specifier and we're in a local class. Only look
// for functions declared in the immediately-enclosing block scope.
// We recover from invalid scope qualifiers as if they just weren't there.
- FunctionDecl *FunctionContainingLocalClass = 0;
+ FunctionDecl *FunctionContainingLocalClass = nullptr;
if ((SS.isInvalid() || !SS.isSet()) &&
(FunctionContainingLocalClass =
cast<CXXRecordDecl>(CurContext)->isLocalClass())) {
@@ -11681,9 +11977,9 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
// or function template.
} else if (!SS.getScopeRep()->isDependent()) {
DC = computeDeclContext(SS);
- if (!DC) return 0;
+ if (!DC) return nullptr;
- if (RequireCompleteDeclContext(SS, DC)) return 0;
+ if (RequireCompleteDeclContext(SS, DC)) return nullptr;
LookupQualifiedName(Previous, DC);
@@ -11703,7 +11999,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
D.setInvalidType();
Diag(Loc, diag::err_qualified_friend_not_found)
<< Name << TInfo->getType();
- return 0;
+ return nullptr;
}
// C++ [class.friend]p1: A friend of a class is a function or
@@ -11755,7 +12051,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
Diag(Loc, diag::err_introducing_special_friend) <<
(D.getName().getKind() == UnqualifiedId::IK_ConstructorName ? 0 :
D.getName().getKind() == UnqualifiedId::IK_DestructorName ? 1 : 2);
- return 0;
+ return nullptr;
}
}
@@ -11771,7 +12067,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
bool AddToScope = true;
NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, TInfo, Previous,
TemplateParams, AddToScope);
- if (!ND) return 0;
+ if (!ND) return nullptr;
assert(ND->getLexicalDeclContext() == CurContext);
@@ -11841,16 +12137,25 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
if (const FunctionDecl *Prev = Fn->getPreviousDecl()) {
// Don't consider the implicit declaration we generate for explicit
// specializations. FIXME: Do not generate these implicit declarations.
- if ((Prev->getTemplateSpecializationKind() != TSK_ExplicitSpecialization
- || Prev->getPreviousDecl()) && !Prev->isDefined()) {
+ if ((Prev->getTemplateSpecializationKind() != TSK_ExplicitSpecialization ||
+ Prev->getPreviousDecl()) &&
+ !Prev->isDefined()) {
Diag(DelLoc, diag::err_deleted_decl_not_first);
- Diag(Prev->getLocation(), diag::note_previous_declaration);
+ Diag(Prev->getLocation().isInvalid() ? DelLoc : Prev->getLocation(),
+ Prev->isImplicit() ? diag::note_previous_implicit_declaration
+ : diag::note_previous_declaration);
}
// If the declaration wasn't the first, we delete the function anyway for
// recovery.
Fn = Fn->getCanonicalDecl();
}
+ // dllimport/dllexport cannot be deleted.
+ if (const InheritableAttr *DLLAttr = getDLLAttr(Fn)) {
+ Diag(Fn->getLocation(), diag::err_attribute_dll_deleted) << DLLAttr;
+ Fn->setInvalidDecl();
+ }
+
if (Fn->isDeleted())
return;
@@ -11871,6 +12176,11 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
}
}
+ // C++11 [basic.start.main]p3:
+ // A program that defines main as deleted [...] is ill-formed.
+ if (Fn->isMain())
+ Diag(DelLoc, diag::err_deleted_main);
+
Fn->setDeletedAsWritten();
}
@@ -11977,6 +12287,13 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
if (NewCC == OldCC)
return false;
+ // If the calling conventions mismatch because the new function is static,
+ // suppress the calling convention mismatch error; the error about static
+ // function override (err_static_overrides_virtual from
+ // Sema::CheckFunctionDeclaration) is more clear.
+ if (New->getStorageClass() == SC_Static)
+ return false;
+
Diag(New->getLocation(),
diag::err_conflicting_overriding_cc_attributes)
<< New->getDeclName() << New->getType() << Old->getType();
@@ -11986,8 +12303,8 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
- QualType NewTy = New->getType()->getAs<FunctionType>()->getResultType();
- QualType OldTy = Old->getType()->getAs<FunctionType>()->getResultType();
+ QualType NewTy = New->getType()->getAs<FunctionType>()->getReturnType();
+ QualType OldTy = Old->getType()->getAs<FunctionType>()->getReturnType();
if (Context.hasSameType(NewTy, OldTy) ||
NewTy->isDependentType() || OldTy->isDependentType())
@@ -12015,8 +12332,10 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
if (NewClassTy.isNull()) {
Diag(New->getLocation(),
diag::err_different_return_type_for_overriding_virtual_function)
- << New->getDeclName() << NewTy << OldTy;
- Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ << New->getDeclName() << NewTy << OldTy
+ << New->getReturnTypeSourceRange();
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function)
+ << Old->getReturnTypeSourceRange();
return true;
}
@@ -12036,24 +12355,27 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
if (!Context.hasSameUnqualifiedType(NewClassTy, OldClassTy)) {
// Check if the new class derives from the old class.
if (!IsDerivedFrom(NewClassTy, OldClassTy)) {
- Diag(New->getLocation(),
- diag::err_covariant_return_not_derived)
- << New->getDeclName() << NewTy << OldTy;
- Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ Diag(New->getLocation(), diag::err_covariant_return_not_derived)
+ << New->getDeclName() << NewTy << OldTy
+ << New->getReturnTypeSourceRange();
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function)
+ << Old->getReturnTypeSourceRange();
return true;
}
// Check if we the conversion from derived to base is valid.
- if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy,
- diag::err_covariant_return_inaccessible_base,
- diag::err_covariant_return_ambiguous_derived_to_base_conv,
- // FIXME: Should this point to the return type?
- New->getLocation(), SourceRange(), New->getDeclName(), 0)) {
+ if (CheckDerivedToBaseConversion(
+ NewClassTy, OldClassTy,
+ diag::err_covariant_return_inaccessible_base,
+ diag::err_covariant_return_ambiguous_derived_to_base_conv,
+ New->getLocation(), New->getReturnTypeSourceRange(),
+ New->getDeclName(), nullptr)) {
// FIXME: this note won't trigger for delayed access control
// diagnostics, and it's impossible to get an undelayed error
// here from access control during the original parse because
// the ParsingDeclSpec/ParsingDeclarator are still in scope.
- Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function)
+ << Old->getReturnTypeSourceRange();
return true;
}
}
@@ -12062,8 +12384,10 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
if (NewTy.getLocalCVRQualifiers() != OldTy.getLocalCVRQualifiers()) {
Diag(New->getLocation(),
diag::err_covariant_return_type_different_qualifications)
- << New->getDeclName() << NewTy << OldTy;
- Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ << New->getDeclName() << NewTy << OldTy
+ << New->getReturnTypeSourceRange();
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function)
+ << Old->getReturnTypeSourceRange();
return true;
};
@@ -12072,8 +12396,10 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
if (NewClassTy.isMoreQualifiedThan(OldClassTy)) {
Diag(New->getLocation(),
diag::err_covariant_return_type_class_type_more_qualified)
- << New->getDeclName() << NewTy << OldTy;
- Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ << New->getDeclName() << NewTy << OldTy
+ << New->getReturnTypeSourceRange();
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function)
+ << Old->getReturnTypeSourceRange();
return true;
};
@@ -12118,13 +12444,16 @@ static bool isStaticDataMember(const Decl *D) {
/// class X.
void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
// If there is no declaration, there was an error parsing it.
- if (D == 0 || D->isInvalidDecl()) return;
+ if (!D || D->isInvalidDecl())
+ return;
+
+ // We will always have a nested name specifier here, but this declaration
+ // might not be out of line if the specifier names the current namespace:
+ // extern int n;
+ // int ::n = 0;
+ if (D->isOutOfLine())
+ EnterDeclaratorContext(S, D->getDeclContext());
- // We should only get called for declarations with scope specifiers, like:
- // int foo::bar;
- assert(D->isOutOfLine());
- EnterDeclaratorContext(S, D->getDeclContext());
-
// If we are parsing the initializer for a static data member, push a
// new expression evaluation context that is associated with this static
// data member.
@@ -12136,13 +12465,14 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
/// initializer for the out-of-line declaration 'D'.
void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) {
// If there is no declaration, there was an error parsing it.
- if (D == 0 || D->isInvalidDecl()) return;
+ if (!D || D->isInvalidDecl())
+ return;
if (isStaticDataMember(D))
- PopExpressionEvaluationContext();
+ PopExpressionEvaluationContext();
- assert(D->isOutOfLine());
- ExitDeclaratorContext(S);
+ if (D->isOutOfLine())
+ ExitDeclaratorContext(S);
}
/// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
@@ -12216,6 +12546,20 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
// Otherwise, we can early exit.
return;
}
+ } else {
+ // The Microsoft ABI requires that we perform the destructor body
+ // checks (i.e. operator delete() lookup) when the vtable is marked used, as
+ // the deleting destructor is emitted with the vtable, not with the
+ // destructor definition as in the Itanium ABI.
+ // If it has a definition, we do the check at that point instead.
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+ Class->hasUserDeclaredDestructor() &&
+ !Class->getDestructor()->isDefined() &&
+ !Class->getDestructor()->isDeleted()) {
+ CXXDestructorDecl *DD = Class->getDestructor();
+ ContextRAII SavedContext(*this, DD);
+ CheckDestructor(DD);
+ }
}
// Local classes need to have their virtual members marked
@@ -12267,11 +12611,9 @@ bool Sema::DefineUsedVTables() {
bool IsExplicitInstantiationDeclaration
= Class->getTemplateSpecializationKind()
== TSK_ExplicitInstantiationDeclaration;
- for (TagDecl::redecl_iterator R = Class->redecls_begin(),
- REnd = Class->redecls_end();
- R != REnd; ++R) {
+ for (auto R : Class->redecls()) {
TemplateSpecializationKind TSK
- = cast<CXXRecordDecl>(*R)->getTemplateSpecializationKind();
+ = cast<CXXRecordDecl>(R)->getTemplateSpecializationKind();
if (TSK == TSK_ExplicitInstantiationDeclaration)
IsExplicitInstantiationDeclaration = true;
else if (TSK == TSK_ExplicitInstantiationDefinition) {
@@ -12303,7 +12645,7 @@ bool Sema::DefineUsedVTables() {
// Optionally warn if we're emitting a weak vtable.
if (Class->isExternallyVisible() &&
Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) {
- const FunctionDecl *KeyFunctionDef = 0;
+ const FunctionDecl *KeyFunctionDef = nullptr;
if (!KeyFunction ||
(KeyFunction->hasBody(KeyFunctionDef) &&
KeyFunctionDef->isInlined()))
@@ -12320,10 +12662,9 @@ bool Sema::DefineUsedVTables() {
void Sema::MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc,
const CXXRecordDecl *RD) {
- for (CXXRecordDecl::method_iterator I = RD->method_begin(),
- E = RD->method_end(); I != E; ++I)
- if ((*I)->isVirtual() && !(*I)->isPure())
- ResolveExceptionSpec(Loc, (*I)->getType()->castAs<FunctionProtoType>());
+ for (const auto *I : RD->methods())
+ if (I->isVirtual() && !I->isPure())
+ ResolveExceptionSpec(Loc, I->getType()->castAs<FunctionProtoType>());
}
void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
@@ -12351,10 +12692,9 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
if (RD->getNumVBases() == 0)
return;
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
+ for (const auto &I : RD->bases()) {
const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
if (Base->getNumVBases() == 0)
continue;
MarkVirtualMembersReferenced(Loc, Base);
@@ -12394,7 +12734,7 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
Member =
new (Context) CXXCtorInitializer(Context, Field, SourceLocation(),
SourceLocation(),
- MemberInit.takeAs<Expr>(),
+ MemberInit.getAs<Expr>(),
SourceLocation());
AllToInit.push_back(Member);
@@ -12430,7 +12770,7 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
// Target may not be determinable yet, for instance if this is a dependent
// call in an uninstantiated template.
if (Target) {
- const FunctionDecl *FNTarget = 0;
+ const FunctionDecl *FNTarget = nullptr;
(void)Target->hasBody(FNTarget);
Target = const_cast<CXXConstructorDecl*>(
cast_or_null<CXXConstructorDecl>(FNTarget));
@@ -12438,7 +12778,7 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
CXXConstructorDecl *Canonical = Ctor->getCanonicalDecl(),
// Avoid dereferencing a null pointer here.
- *TCanonical = Target ? Target->getCanonicalDecl() : 0;
+ *TCanonical = Target? Target->getCanonicalDecl() : nullptr;
if (!Current.insert(Canonical))
return;
@@ -12463,7 +12803,7 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
CXXConstructorDecl *C = Target;
while (C->getCanonicalDecl() != Canonical) {
- const FunctionDecl *FNTarget = 0;
+ const FunctionDecl *FNTarget = nullptr;
(void)C->getTargetConstructor()->hasBody(FNTarget);
assert(FNTarget && "Ctor cycle through bodiless function");
@@ -12534,7 +12874,7 @@ bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) {
// If the return type came after the cv-qualifier-seq, check it now.
if (Proto->hasTrailingReturn() &&
- !Finder.TraverseTypeLoc(ProtoTL.getResultLoc()))
+ !Finder.TraverseTypeLoc(ProtoTL.getReturnLoc()))
return true;
// Check the exception specification.
@@ -12571,10 +12911,8 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) {
return true;
case EST_Dynamic:
- for (FunctionProtoType::exception_iterator E = Proto->exception_begin(),
- EEnd = Proto->exception_end();
- E != EEnd; ++E) {
- if (!Finder.TraverseType(*E))
+ for (const auto &E : Proto->exceptions()) {
+ if (!Finder.TraverseType(E))
return true;
}
break;
@@ -12587,45 +12925,36 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) {
FindCXXThisExpr Finder(*this);
// Check attributes.
- for (Decl::attr_iterator A = Method->attr_begin(), AEnd = Method->attr_end();
- A != AEnd; ++A) {
+ for (const auto *A : Method->attrs()) {
// FIXME: This should be emitted by tblgen.
- Expr *Arg = 0;
+ Expr *Arg = nullptr;
ArrayRef<Expr *> Args;
- if (GuardedByAttr *G = dyn_cast<GuardedByAttr>(*A))
+ if (const auto *G = dyn_cast<GuardedByAttr>(A))
Arg = G->getArg();
- else if (PtGuardedByAttr *G = dyn_cast<PtGuardedByAttr>(*A))
+ else if (const auto *G = dyn_cast<PtGuardedByAttr>(A))
Arg = G->getArg();
- else if (AcquiredAfterAttr *AA = dyn_cast<AcquiredAfterAttr>(*A))
+ else if (const auto *AA = dyn_cast<AcquiredAfterAttr>(A))
Args = ArrayRef<Expr *>(AA->args_begin(), AA->args_size());
- else if (AcquiredBeforeAttr *AB = dyn_cast<AcquiredBeforeAttr>(*A))
+ else if (const auto *AB = dyn_cast<AcquiredBeforeAttr>(A))
Args = ArrayRef<Expr *>(AB->args_begin(), AB->args_size());
- else if (ExclusiveLockFunctionAttr *ELF
- = dyn_cast<ExclusiveLockFunctionAttr>(*A))
- Args = ArrayRef<Expr *>(ELF->args_begin(), ELF->args_size());
- else if (SharedLockFunctionAttr *SLF
- = dyn_cast<SharedLockFunctionAttr>(*A))
- Args = ArrayRef<Expr *>(SLF->args_begin(), SLF->args_size());
- else if (ExclusiveTrylockFunctionAttr *ETLF
- = dyn_cast<ExclusiveTrylockFunctionAttr>(*A)) {
+ else if (const auto *ETLF = dyn_cast<ExclusiveTrylockFunctionAttr>(A)) {
Arg = ETLF->getSuccessValue();
Args = ArrayRef<Expr *>(ETLF->args_begin(), ETLF->args_size());
- } else if (SharedTrylockFunctionAttr *STLF
- = dyn_cast<SharedTrylockFunctionAttr>(*A)) {
+ } else if (const auto *STLF = dyn_cast<SharedTrylockFunctionAttr>(A)) {
Arg = STLF->getSuccessValue();
Args = ArrayRef<Expr *>(STLF->args_begin(), STLF->args_size());
- } else if (UnlockFunctionAttr *UF = dyn_cast<UnlockFunctionAttr>(*A))
- Args = ArrayRef<Expr *>(UF->args_begin(), UF->args_size());
- else if (LockReturnedAttr *LR = dyn_cast<LockReturnedAttr>(*A))
+ } else if (const auto *LR = dyn_cast<LockReturnedAttr>(A))
Arg = LR->getArg();
- else if (LocksExcludedAttr *LE = dyn_cast<LocksExcludedAttr>(*A))
+ else if (const auto *LE = dyn_cast<LocksExcludedAttr>(A))
Args = ArrayRef<Expr *>(LE->args_begin(), LE->args_size());
- else if (ExclusiveLocksRequiredAttr *ELR
- = dyn_cast<ExclusiveLocksRequiredAttr>(*A))
- Args = ArrayRef<Expr *>(ELR->args_begin(), ELR->args_size());
- else if (SharedLocksRequiredAttr *SLR
- = dyn_cast<SharedLocksRequiredAttr>(*A))
- Args = ArrayRef<Expr *>(SLR->args_begin(), SLR->args_size());
+ else if (const auto *RC = dyn_cast<RequiresCapabilityAttr>(A))
+ Args = ArrayRef<Expr *>(RC->args_begin(), RC->args_size());
+ else if (const auto *AC = dyn_cast<AcquireCapabilityAttr>(A))
+ Args = ArrayRef<Expr *>(AC->args_begin(), AC->args_size());
+ else if (const auto *AC = dyn_cast<TryAcquireCapabilityAttr>(A))
+ Args = ArrayRef<Expr *>(AC->args_begin(), AC->args_size());
+ else if (const auto *RC = dyn_cast<ReleaseCapabilityAttr>(A))
+ Args = ArrayRef<Expr *>(RC->args_begin(), RC->args_size());
if (Arg && !Finder.TraverseStmt(Arg))
return true;
@@ -12686,9 +13015,9 @@ Sema::checkExceptionSpecification(ExceptionSpecificationType EST,
}
if (!NoexceptExpr->isValueDependent())
- NoexceptExpr = VerifyIntegerConstantExpression(NoexceptExpr, 0,
+ NoexceptExpr = VerifyIntegerConstantExpression(NoexceptExpr, nullptr,
diag::err_noexcept_needs_constant_expression,
- /*AllowFold*/ false).take();
+ /*AllowFold*/ false).get();
EPI.NoexceptExpr = NoexceptExpr;
}
return;
@@ -12746,7 +13075,7 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record,
IdentifierInfo *II = D.getIdentifier();
if (!II) {
Diag(DeclStart, diag::err_anonymous_property);
- return NULL;
+ return nullptr;
}
SourceLocation Loc = D.getIdentifierLoc();
@@ -12771,7 +13100,7 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record,
<< DeclSpec::getSpecifierName(TSCS);
// Check to see if this name was declared as a member previously
- NamedDecl *PrevDecl = 0;
+ NamedDecl *PrevDecl = nullptr;
LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration);
LookupName(Previous, S);
switch (Previous.getResultKind()) {
@@ -12794,18 +13123,16 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record,
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
// Just pretend that we didn't see the previous declaration.
- PrevDecl = 0;
+ PrevDecl = nullptr;
}
if (PrevDecl && !isDeclInScope(PrevDecl, Record, S))
- PrevDecl = 0;
+ PrevDecl = nullptr;
SourceLocation TSSL = D.getLocStart();
- MSPropertyDecl *NewPD;
const AttributeList::PropertyData &Data = MSPropertyAttr->getPropertyData();
- NewPD = new (Context) MSPropertyDecl(Record, Loc,
- II, T, TInfo, TSSL,
- Data.GetterId, Data.SetterId);
+ MSPropertyDecl *NewPD = MSPropertyDecl::Create(
+ Context, Record, Loc, II, T, TInfo, TSSL, Data.GetterId, Data.SetterId);
ProcessDeclAttributes(TUScope, NewPD, D);
NewPD->setAccess(AS);
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index f44fb3251141..b5205b3e6238 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -15,11 +15,11 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/DataRecursiveASTVisitor.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/Lookup.h"
@@ -48,8 +48,8 @@ bool Sema::checkInitMethod(ObjCMethodDecl *method,
// We ignore protocols here. Should we? What about Class?
- const ObjCObjectType *result = method->getResultType()
- ->castAs<ObjCObjectPointerType>()->getObjectType();
+ const ObjCObjectType *result =
+ method->getReturnType()->castAs<ObjCObjectPointerType>()->getObjectType();
if (result->isObjCId()) {
return false;
@@ -70,7 +70,7 @@ bool Sema::checkInitMethod(ObjCMethodDecl *method,
} 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;
+ const ObjCInterfaceDecl *receiverClass = nullptr;
if (isa<ObjCProtocolDecl>(method->getDeclContext())) {
if (receiverTypeIfCall.isNull())
return false;
@@ -97,8 +97,9 @@ bool Sema::checkInitMethod(ObjCMethodDecl *method,
// 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"));
+ method->addAttr(UnavailableAttr::CreateImplicit(Context,
+ "init method returns a type unrelated to its receiver type",
+ loc));
return true;
}
@@ -116,10 +117,10 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
// implies a related result type, and the original (overridden) method has
// a suitable return type, but the new (overriding) method does not have
// a suitable return type.
- QualType ResultType = NewMethod->getResultType();
+ QualType ResultType = NewMethod->getReturnType();
SourceRange ResultTypeRange;
- if (const TypeSourceInfo *ResultTypeInfo
- = NewMethod->getResultTypeSourceInfo())
+ if (const TypeSourceInfo *ResultTypeInfo =
+ NewMethod->getReturnTypeSourceInfo())
ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
// Figure out which class this method is part of, if any.
@@ -207,19 +208,19 @@ bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) {
return false;
case OMF_dealloc:
- if (!Context.hasSameType(method->getResultType(), Context.VoidTy)) {
+ if (!Context.hasSameType(method->getReturnType(), Context.VoidTy)) {
SourceRange ResultTypeRange;
- if (const TypeSourceInfo *ResultTypeInfo
- = method->getResultTypeSourceInfo())
+ if (const TypeSourceInfo *ResultTypeInfo =
+ method->getReturnTypeSourceInfo())
ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
if (ResultTypeRange.isInvalid())
- Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
- << method->getResultType()
- << FixItHint::CreateInsertion(method->getSelectorLoc(0), "(void)");
+ Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
+ << method->getReturnType()
+ << FixItHint::CreateInsertion(method->getSelectorLoc(0), "(void)");
else
- Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
- << method->getResultType()
- << FixItHint::CreateReplacement(ResultTypeRange, "void");
+ Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
+ << method->getReturnType()
+ << FixItHint::CreateReplacement(ResultTypeRange, "void");
return true;
}
return false;
@@ -229,8 +230,7 @@ bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) {
if (checkInitMethod(method, QualType()))
return true;
- method->addAttr(new (Context) NSConsumesSelfAttr(SourceLocation(),
- Context));
+ method->addAttr(NSConsumesSelfAttr::CreateImplicit(Context));
// Don't add a second copy of this attribute, but otherwise don't
// let it be suppressed.
@@ -249,8 +249,7 @@ bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) {
break;
}
- method->addAttr(new (Context) NSReturnsRetainedAttr(SourceLocation(),
- Context));
+ method->addAttr(NSReturnsRetainedAttr::CreateImplicit(Context));
return false;
}
@@ -304,7 +303,7 @@ HasExplicitOwnershipAttr(Sema &S, ParmVarDecl *Param) {
/// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible
/// and user declared, in the method definition's AST.
void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
- assert((getCurMethodDecl() == 0) && "Methodparsing confused");
+ assert((getCurMethodDecl() == nullptr) && "Methodparsing confused");
ObjCMethodDecl *MDecl = dyn_cast_or_null<ObjCMethodDecl>(D);
// If we don't have a valid method decl, simply return.
@@ -329,17 +328,15 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
/*CheckParameterNames=*/false);
// Introduce all of the other parameters into this scope.
- for (ObjCMethodDecl::param_iterator PI = MDecl->param_begin(),
- E = MDecl->param_end(); PI != E; ++PI) {
- ParmVarDecl *Param = (*PI);
+ for (auto *Param : MDecl->params()) {
if (!Param->isInvalidDecl() &&
getLangOpts().ObjCAutoRefCount &&
!HasExplicitOwnershipAttr(*this, Param))
Diag(Param->getLocation(), diag::warn_arc_strong_pointer_objc_pointer) <<
Param->getType();
- if ((*PI)->getIdentifier())
- PushOnScopeChains(*PI, FnBodyScope);
+ if (Param->getIdentifier())
+ PushOnScopeChains(Param, FnBodyScope);
}
// In ARC, disallow definition of retain/release/autorelease/retainCount
@@ -378,11 +375,16 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
dyn_cast<ObjCImplDecl>(MDecl->getDeclContext());
ObjCContainerDecl *ContDeclOfMethodDecl =
dyn_cast<ObjCContainerDecl>(IMD->getDeclContext());
- ObjCImplDecl *ImplDeclOfMethodDecl = 0;
+ ObjCImplDecl *ImplDeclOfMethodDecl = nullptr;
if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ContDeclOfMethodDecl))
ImplDeclOfMethodDecl = OID->getImplementation();
- else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContDeclOfMethodDecl))
- ImplDeclOfMethodDecl = CD->getImplementation();
+ else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContDeclOfMethodDecl)) {
+ if (CD->IsClassExtension()) {
+ if (ObjCInterfaceDecl *OID = CD->getClassInterface())
+ ImplDeclOfMethodDecl = OID->getImplementation();
+ } else
+ ImplDeclOfMethodDecl = CD->getImplementation();
+ }
// No need to issue deprecated warning if deprecated mehod in class/category
// is being implemented in its own implementation (no overriding is involved).
if (!ImplDeclOfMethodDecl || ImplDeclOfMethodDecl != ImplDeclOfMethodDef)
@@ -391,6 +393,17 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
MDecl->getLocation(), 0);
}
+ if (MDecl->getMethodFamily() == OMF_init) {
+ if (MDecl->isDesignatedInitializerForTheInterface()) {
+ getCurFunction()->ObjCIsDesignatedInit = true;
+ getCurFunction()->ObjCWarnForNoDesignatedInitChain =
+ IC->getSuperClass() != nullptr;
+ } else if (IC->hasDesignatedInitializers()) {
+ getCurFunction()->ObjCIsSecondaryInit = true;
+ getCurFunction()->ObjCWarnForNoInitDelegation = true;
+ }
+ }
+
// If this is "dealloc" or "finalize", set some bit here.
// Then in ActOnSuperMessage() (SemaExprObjC), set it back to false.
// Finally, in ActOnFinishFunctionBody() (SemaDecl), warn if flag is set.
@@ -424,11 +437,11 @@ namespace {
// function will reject corrections to that class.
class ObjCInterfaceValidatorCCC : public CorrectionCandidateCallback {
public:
- ObjCInterfaceValidatorCCC() : CurrentIDecl(0) {}
+ ObjCInterfaceValidatorCCC() : CurrentIDecl(nullptr) {}
explicit ObjCInterfaceValidatorCCC(ObjCInterfaceDecl *IDecl)
: CurrentIDecl(IDecl) {}
- virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ bool ValidateCandidate(const TypoCorrection &candidate) override {
ObjCInterfaceDecl *ID = candidate.getCorrectionDeclAs<ObjCInterfaceDecl>();
return ID && !declaresSameEntity(ID, CurrentIDecl);
}
@@ -510,7 +523,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
ObjCInterfaceValidatorCCC Validator(IDecl);
if (TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope,
- NULL, Validator)) {
+ nullptr, Validator, CTK_ErrorRecovery)) {
diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest)
<< SuperName << ClassName);
PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
@@ -529,7 +542,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
if (SuperClassDecl)
(void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc);
- if (PrevDecl && SuperClassDecl == 0) {
+ if (PrevDecl && !SuperClassDecl) {
// The previous declaration was not a class decl. Check if we have a
// typedef. If we do, get the underlying class type.
if (const TypedefNameDecl *TDecl =
@@ -568,7 +581,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
SuperClassDecl->getDeclName(),
ClassName,
SourceRange(AtInterfaceLoc, ClassLoc))) {
- SuperClassDecl = 0;
+ SuperClassDecl = nullptr;
}
}
IDecl->setSuperClass(SuperClassDecl);
@@ -607,9 +620,8 @@ void Sema::ActOnTypedefedProtocols(SmallVectorImpl<Decl *> &ProtocolRefs,
QualType T = TDecl->getUnderlyingType();
if (T->isObjCObjectType())
if (const ObjCObjectType *OPT = T->getAs<ObjCObjectType>())
- for (ObjCObjectType::qual_iterator I = OPT->qual_begin(),
- E = OPT->qual_end(); I != E; ++I)
- ProtocolRefs.push_back(*I);
+ for (auto *I : OPT->quals())
+ ProtocolRefs.push_back(I);
}
}
@@ -626,7 +638,7 @@ Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc,
if (ADecl) {
Diag(AliasLocation, diag::err_conflicting_aliasing_type) << AliasName;
Diag(ADecl->getLocation(), diag::note_previous_declaration);
- return 0;
+ return nullptr;
}
// Check for class declaration
NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation,
@@ -643,11 +655,11 @@ Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc,
}
}
ObjCInterfaceDecl *CDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDeclU);
- if (CDecl == 0) {
+ if (!CDecl) {
Diag(ClassLocation, diag::warn_undef_interface) << ClassName;
if (CDeclU)
Diag(CDeclU->getLocation(), diag::note_previous_declaration);
- return 0;
+ return nullptr;
}
// Everything checked out, instantiate a new alias declaration AST.
@@ -701,8 +713,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
assert(ProtocolName && "Missing protocol identifier");
ObjCProtocolDecl *PrevDecl = LookupProtocol(ProtocolName, ProtocolLoc,
ForRedeclaration);
- ObjCProtocolDecl *PDecl = 0;
- if (ObjCProtocolDecl *Def = PrevDecl? PrevDecl->getDefinition() : 0) {
+ ObjCProtocolDecl *PDecl = nullptr;
+ if (ObjCProtocolDecl *Def = PrevDecl? PrevDecl->getDefinition() : nullptr) {
// If we already have a definition, complain.
Diag(ProtocolLoc, diag::warn_duplicate_protocol_def) << ProtocolName;
Diag(Def->getLocation(), diag::note_previous_definition);
@@ -713,7 +725,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
// FIXME: Can we turn this into an error?
PDecl = ObjCProtocolDecl::Create(Context, CurContext, ProtocolName,
ProtocolLoc, AtProtoInterfaceLoc,
- /*PrevDecl=*/0);
+ /*PrevDecl=*/nullptr);
PDecl->startDefinition();
} else {
if (PrevDecl) {
@@ -751,6 +763,21 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
return ActOnObjCContainerStartDefinition(PDecl);
}
+static bool NestedProtocolHasNoDefinition(ObjCProtocolDecl *PDecl,
+ ObjCProtocolDecl *&UndefinedProtocol) {
+ if (!PDecl->hasDefinition() || PDecl->getDefinition()->isHidden()) {
+ UndefinedProtocol = PDecl;
+ return true;
+ }
+
+ for (auto *PI : PDecl->protocols())
+ if (NestedProtocolHasNoDefinition(PI, UndefinedProtocol)) {
+ UndefinedProtocol = PI;
+ return true;
+ }
+ return false;
+}
+
/// FindProtocolDeclaration - This routine looks up protocols and
/// issues an error if they are not declared. It returns list of
/// protocol declarations in its 'Protocols' argument.
@@ -766,7 +793,8 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
DeclFilterCCC<ObjCProtocolDecl> Validator;
TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second),
- LookupObjCProtocolName, TUScope, NULL, Validator);
+ LookupObjCProtocolName, TUScope, nullptr, Validator,
+ CTK_ErrorRecovery);
if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>()))
diagnoseTypo(Corrected, PDiag(diag::err_undeclared_protocol_suggest)
<< ProtocolId[i].first);
@@ -786,10 +814,15 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
// If this is a forward declaration and we are supposed to warn in this
// case, do it.
// FIXME: Recover nicely in the hidden case.
+ ObjCProtocolDecl *UndefinedProtocol;
+
if (WarnOnDeclarations &&
- (!PDecl->hasDefinition() || PDecl->getDefinition()->isHidden()))
+ NestedProtocolHasNoDefinition(PDecl, UndefinedProtocol)) {
Diag(ProtocolId[i].second, diag::warn_undef_protocolref)
<< ProtocolId[i].first;
+ Diag(UndefinedProtocol->getLocation(), diag::note_protocol_decl_undefined)
+ << UndefinedProtocol;
+ }
Protocols.push_back(PDecl);
}
}
@@ -803,19 +836,16 @@ void Sema::DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT,
return; // Possibly due to previous error
llvm::DenseMap<Selector, const ObjCMethodDecl*> MethodMap;
- for (ObjCInterfaceDecl::method_iterator i = ID->meth_begin(),
- e = ID->meth_end(); i != e; ++i) {
- ObjCMethodDecl *MD = *i;
+ for (auto *MD : ID->methods())
MethodMap[MD->getSelector()] = MD;
- }
if (MethodMap.empty())
return;
- for (ObjCCategoryDecl::method_iterator i = CAT->meth_begin(),
- e = CAT->meth_end(); i != e; ++i) {
- ObjCMethodDecl *Method = *i;
+ for (const auto *Method : CAT->methods()) {
const ObjCMethodDecl *&PrevMethod = MethodMap[Method->getSelector()];
- if (PrevMethod && !MatchTwoMethodDeclarations(Method, PrevMethod)) {
+ if (PrevMethod &&
+ (PrevMethod->isInstanceMethod() == Method->isInstanceMethod()) &&
+ !MatchTwoMethodDeclarations(Method, PrevMethod)) {
Diag(Method->getLocation(), diag::err_duplicate_method_decl)
<< Method->getDeclName();
Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
@@ -871,7 +901,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
if (!IDecl
|| RequireCompleteType(ClassLoc, Context.getObjCInterfaceType(IDecl),
diag::err_category_forward_interface,
- CategoryName == 0)) {
+ CategoryName == nullptr)) {
// Create an invalid ObjCCategoryDecl to serve as context for
// the enclosing method declarations. We mark the decl invalid
// to make it clear that this isn't a valid AST.
@@ -928,7 +958,7 @@ Decl *Sema::ActOnStartCategoryImplementation(
IdentifierInfo *ClassName, SourceLocation ClassLoc,
IdentifierInfo *CatName, SourceLocation CatLoc) {
ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true);
- ObjCCategoryDecl *CatIDecl = 0;
+ ObjCCategoryDecl *CatIDecl = nullptr;
if (IDecl && IDecl->hasDefinition()) {
CatIDecl = IDecl->FindCategoryDeclaration(CatName);
if (!CatIDecl) {
@@ -987,7 +1017,7 @@ Decl *Sema::ActOnStartClassImplementation(
IdentifierInfo *ClassName, SourceLocation ClassLoc,
IdentifierInfo *SuperClassname,
SourceLocation SuperClassLoc) {
- ObjCInterfaceDecl *IDecl = 0;
+ ObjCInterfaceDecl *IDecl = nullptr;
// Check for another declaration kind with the same name.
NamedDecl *PrevDecl
= LookupSingleName(TUScope, ClassName, ClassLoc, LookupOrdinaryName,
@@ -1004,7 +1034,8 @@ Decl *Sema::ActOnStartClassImplementation(
ObjCInterfaceValidatorCCC Validator;
TypoCorrection Corrected =
CorrectTypo(DeclarationNameInfo(ClassName, ClassLoc),
- LookupOrdinaryName, TUScope, NULL, Validator);
+ LookupOrdinaryName, TUScope, nullptr, Validator,
+ CTK_NonError);
if (Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) {
// Suggest the (potentially) correct interface name. Don't provide a
// code-modification hint or use the typo name for recovery, because
@@ -1018,7 +1049,7 @@ Decl *Sema::ActOnStartClassImplementation(
}
// Check that super class name is valid class name
- ObjCInterfaceDecl* SDecl = 0;
+ ObjCInterfaceDecl *SDecl = nullptr;
if (SuperClassname) {
// Check if a different kind of symbol declared in this scope.
PrevDecl = LookupSingleName(TUScope, SuperClassname, SuperClassLoc,
@@ -1030,7 +1061,7 @@ Decl *Sema::ActOnStartClassImplementation(
} else {
SDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
if (SDecl && !SDecl->hasDefinition())
- SDecl = 0;
+ SDecl = nullptr;
if (!SDecl)
Diag(SuperClassLoc, diag::err_undef_superclass)
<< SuperClassname << ClassName;
@@ -1051,7 +1082,7 @@ Decl *Sema::ActOnStartClassImplementation(
// FIXME: Do we support attributes on the @implementation? If so we should
// copy them over.
IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc,
- ClassName, /*PrevDecl=*/0, ClassLoc,
+ ClassName, /*PrevDecl=*/nullptr, ClassLoc,
true);
IDecl->startDefinition();
if (SDecl) {
@@ -1154,11 +1185,7 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
continue;
}
// Check class extensions (unnamed categories) for duplicate ivars.
- for (ObjCInterfaceDecl::visible_extensions_iterator
- Ext = IDecl->visible_extensions_begin(),
- ExtEnd = IDecl->visible_extensions_end();
- Ext != ExtEnd; ++Ext) {
- ObjCCategoryDecl *CDecl = *Ext;
+ for (const auto *CDecl : IDecl->visible_extensions()) {
if (const ObjCIvarDecl *ClsExtIvar =
CDecl->getIvarDecl(ImplIvar->getIdentifier())) {
Diag(ImplIvar->getLocation(), diag::err_duplicate_ivar_declaration);
@@ -1209,13 +1236,16 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
}
if (numIvars > 0)
- Diag(ivars[j]->getLocation(), diag::err_inconsistant_ivar_count);
+ Diag(ivars[j]->getLocation(), diag::err_inconsistent_ivar_count);
else if (IVI != IVE)
- Diag(IVI->getLocation(), diag::err_inconsistant_ivar_count);
+ Diag(IVI->getLocation(), diag::err_inconsistent_ivar_count);
}
-void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
- bool &IncompleteImpl, unsigned DiagID) {
+static void WarnUndefinedMethod(Sema &S, SourceLocation ImpLoc,
+ ObjCMethodDecl *method,
+ bool &IncompleteImpl,
+ unsigned DiagID,
+ NamedDecl *NeededFor = nullptr) {
// No point warning no definition of method which is 'unavailable'.
switch (method->getAvailability()) {
case AR_Available:
@@ -1233,13 +1263,17 @@ void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
// warning, but some users strongly voiced that they would prefer
// separate warnings. We will give that approach a try, as that
// matches what we do with protocols.
-
- Diag(ImpLoc, DiagID) << method->getDeclName();
+ {
+ const Sema::SemaDiagnosticBuilder &B = S.Diag(ImpLoc, DiagID);
+ B << method;
+ if (NeededFor)
+ B << NeededFor;
+ }
// Issue a note to the original declaration.
SourceLocation MethodLoc = method->getLocStart();
if (MethodLoc.isValid())
- Diag(MethodLoc, diag::note_method_declared_at) << method;
+ S.Diag(MethodLoc, diag::note_method_declared_at) << method;
}
/// Determines if type B can be substituted for type A. Returns true if we can
@@ -1323,21 +1357,21 @@ static bool CheckMethodOverrideReturn(Sema &S,
(MethodDecl->getObjCDeclQualifier() !=
MethodImpl->getObjCDeclQualifier())) {
if (Warn) {
- S.Diag(MethodImpl->getLocation(),
- (IsOverridingMode ?
- diag::warn_conflicting_overriding_ret_type_modifiers
- : diag::warn_conflicting_ret_type_modifiers))
+ S.Diag(MethodImpl->getLocation(),
+ (IsOverridingMode
+ ? diag::warn_conflicting_overriding_ret_type_modifiers
+ : diag::warn_conflicting_ret_type_modifiers))
<< MethodImpl->getDeclName()
- << getTypeRange(MethodImpl->getResultTypeSourceInfo());
- S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration)
- << getTypeRange(MethodDecl->getResultTypeSourceInfo());
+ << getTypeRange(MethodImpl->getReturnTypeSourceInfo());
+ S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration)
+ << getTypeRange(MethodDecl->getReturnTypeSourceInfo());
}
else
return false;
}
-
- if (S.Context.hasSameUnqualifiedType(MethodImpl->getResultType(),
- MethodDecl->getResultType()))
+
+ if (S.Context.hasSameUnqualifiedType(MethodImpl->getReturnType(),
+ MethodDecl->getReturnType()))
return true;
if (!Warn)
return false;
@@ -1349,9 +1383,9 @@ static bool CheckMethodOverrideReturn(Sema &S,
// Mismatches between ObjC pointers go into a different warning
// category, and sometimes they're even completely whitelisted.
if (const ObjCObjectPointerType *ImplPtrTy =
- MethodImpl->getResultType()->getAs<ObjCObjectPointerType>()) {
+ MethodImpl->getReturnType()->getAs<ObjCObjectPointerType>()) {
if (const ObjCObjectPointerType *IfacePtrTy =
- MethodDecl->getResultType()->getAs<ObjCObjectPointerType>()) {
+ MethodDecl->getReturnType()->getAs<ObjCObjectPointerType>()) {
// Allow non-matching return types as long as they don't violate
// the principle of substitutability. Specifically, we permit
// return types that are subclasses of the declared return type,
@@ -1366,14 +1400,13 @@ static bool CheckMethodOverrideReturn(Sema &S,
}
S.Diag(MethodImpl->getLocation(), DiagID)
- << MethodImpl->getDeclName()
- << MethodDecl->getResultType()
- << MethodImpl->getResultType()
- << getTypeRange(MethodImpl->getResultTypeSourceInfo());
- S.Diag(MethodDecl->getLocation(),
- IsOverridingMode ? diag::note_previous_declaration
- : diag::note_previous_definition)
- << getTypeRange(MethodDecl->getResultTypeSourceInfo());
+ << MethodImpl->getDeclName() << MethodDecl->getReturnType()
+ << MethodImpl->getReturnType()
+ << getTypeRange(MethodImpl->getReturnTypeSourceInfo());
+ S.Diag(MethodDecl->getLocation(), IsOverridingMode
+ ? diag::note_previous_declaration
+ : diag::note_previous_definition)
+ << getTypeRange(MethodDecl->getReturnTypeSourceInfo());
return false;
}
@@ -1505,7 +1538,7 @@ static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl,
// The only reason these methods don't fall within their families is
// due to unusual result types.
- if (unmatched->getResultType()->isObjCObjectPointerType()) {
+ if (unmatched->getReturnType()->isObjCObjectPointerType()) {
reasonSelector = R_UnrelatedReturn;
} else {
reasonSelector = R_NonObjectReturn;
@@ -1615,22 +1648,75 @@ void Sema::WarnExactTypedMethods(ObjCMethodDecl *ImpMethodDecl,
/// we used an immutable set to keep the table then it wouldn't add significant
/// memory cost and it would be handy for lookups.
+typedef llvm::DenseSet<IdentifierInfo*> ProtocolNameSet;
+typedef std::unique_ptr<ProtocolNameSet> LazyProtocolNameSet;
+
+static void findProtocolsWithExplicitImpls(const ObjCProtocolDecl *PDecl,
+ ProtocolNameSet &PNS) {
+ if (PDecl->hasAttr<ObjCExplicitProtocolImplAttr>())
+ PNS.insert(PDecl->getIdentifier());
+ for (const auto *PI : PDecl->protocols())
+ findProtocolsWithExplicitImpls(PI, PNS);
+}
+
+/// Recursively populates a set with all conformed protocols in a class
+/// hierarchy that have the 'objc_protocol_requires_explicit_implementation'
+/// attribute.
+static void findProtocolsWithExplicitImpls(const ObjCInterfaceDecl *Super,
+ ProtocolNameSet &PNS) {
+ if (!Super)
+ return;
+
+ for (const auto *I : Super->all_referenced_protocols())
+ findProtocolsWithExplicitImpls(I, PNS);
+
+ findProtocolsWithExplicitImpls(Super->getSuperClass(), PNS);
+}
+
/// CheckProtocolMethodDefs - This routine checks unimplemented methods
/// Declared in protocol, and those referenced by it.
-void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
- ObjCProtocolDecl *PDecl,
- bool& IncompleteImpl,
- const SelectorSet &InsMap,
- const SelectorSet &ClsMap,
- ObjCContainerDecl *CDecl) {
+static void CheckProtocolMethodDefs(Sema &S,
+ SourceLocation ImpLoc,
+ ObjCProtocolDecl *PDecl,
+ bool& IncompleteImpl,
+ const Sema::SelectorSet &InsMap,
+ const Sema::SelectorSet &ClsMap,
+ ObjCContainerDecl *CDecl,
+ LazyProtocolNameSet &ProtocolsExplictImpl) {
ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl);
ObjCInterfaceDecl *IDecl = C ? C->getClassInterface()
: dyn_cast<ObjCInterfaceDecl>(CDecl);
assert (IDecl && "CheckProtocolMethodDefs - IDecl is null");
ObjCInterfaceDecl *Super = IDecl->getSuperClass();
- ObjCInterfaceDecl *NSIDecl = 0;
- if (getLangOpts().ObjCRuntime.isNeXTFamily()) {
+ ObjCInterfaceDecl *NSIDecl = nullptr;
+
+ // If this protocol is marked 'objc_protocol_requires_explicit_implementation'
+ // then we should check if any class in the super class hierarchy also
+ // conforms to this protocol, either directly or via protocol inheritance.
+ // If so, we can skip checking this protocol completely because we
+ // know that a parent class already satisfies this protocol.
+ //
+ // Note: we could generalize this logic for all protocols, and merely
+ // add the limit on looking at the super class chain for just
+ // specially marked protocols. This may be a good optimization. This
+ // change is restricted to 'objc_protocol_requires_explicit_implementation'
+ // protocols for now for controlled evaluation.
+ if (PDecl->hasAttr<ObjCExplicitProtocolImplAttr>()) {
+ if (!ProtocolsExplictImpl) {
+ ProtocolsExplictImpl.reset(new ProtocolNameSet);
+ findProtocolsWithExplicitImpls(Super, *ProtocolsExplictImpl);
+ }
+ if (ProtocolsExplictImpl->find(PDecl->getIdentifier()) !=
+ ProtocolsExplictImpl->end())
+ return;
+
+ // If no super class conforms to the protocol, we should not search
+ // for methods in the super class to implicitly satisfy the protocol.
+ Super = nullptr;
+ }
+
+ if (S.getLangOpts().ObjCRuntime.isNeXTFamily()) {
// check to see if class implements forwardInvocation method and objects
// of this class are derived from 'NSProxy' so that to forward requests
// from one object to another.
@@ -1638,12 +1724,12 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
// implemented in the class, we should not issue "Method definition not
// found" warnings.
// FIXME: Use a general GetUnarySelector method for this.
- IdentifierInfo* II = &Context.Idents.get("forwardInvocation");
- Selector fISelector = Context.Selectors.getSelector(1, &II);
+ IdentifierInfo* II = &S.Context.Idents.get("forwardInvocation");
+ Selector fISelector = S.Context.Selectors.getSelector(1, &II);
if (InsMap.count(fISelector))
// Is IDecl derived from 'NSProxy'? If so, no instance methods
// need be implemented in the implementation.
- NSIDecl = IDecl->lookupInheritedClass(&Context.Idents.get("NSProxy"));
+ NSIDecl = IDecl->lookupInheritedClass(&S.Context.Idents.get("NSProxy"));
}
// If this is a forward protocol declaration, get its definition.
@@ -1658,13 +1744,15 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
// check unimplemented instance methods.
if (!NSIDecl)
- for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
- E = PDecl->instmeth_end(); I != E; ++I) {
- ObjCMethodDecl *method = *I;
+ for (auto *method : PDecl->instance_methods()) {
if (method->getImplementationControl() != ObjCMethodDecl::Optional &&
!method->isPropertyAccessor() &&
!InsMap.count(method->getSelector()) &&
- (!Super || !Super->lookupInstanceMethod(method->getSelector()))) {
+ (!Super || !Super->lookupMethod(method->getSelector(),
+ true /* instance */,
+ false /* shallowCategory */,
+ true /* followsSuper */,
+ nullptr /* category */))) {
// If a method is not implemented in the category implementation but
// has been declared in its primary class, superclass,
// or in one of their protocols, no need to issue the warning.
@@ -1675,44 +1763,45 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
// have been synthesized due to a property declared in the class which
// uses the protocol.
if (ObjCMethodDecl *MethodInClass =
- IDecl->lookupInstanceMethod(method->getSelector(),
- true /*shallowCategoryLookup*/))
+ IDecl->lookupMethod(method->getSelector(),
+ true /* instance */,
+ true /* shallowCategoryLookup */,
+ false /* followSuper */))
if (C || MethodInClass->isPropertyAccessor())
continue;
unsigned DIAG = diag::warn_unimplemented_protocol_method;
- if (Diags.getDiagnosticLevel(DIAG, ImpLoc)
- != DiagnosticsEngine::Ignored) {
- WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
- Diag(CDecl->getLocation(), diag::note_required_for_protocol_at)
- << PDecl->getDeclName();
+ if (!S.Diags.isIgnored(DIAG, ImpLoc)) {
+ WarnUndefinedMethod(S, ImpLoc, method, IncompleteImpl, DIAG,
+ PDecl);
}
}
}
// check unimplemented class methods
- for (ObjCProtocolDecl::classmeth_iterator
- I = PDecl->classmeth_begin(), E = PDecl->classmeth_end();
- I != E; ++I) {
- ObjCMethodDecl *method = *I;
+ for (auto *method : PDecl->class_methods()) {
if (method->getImplementationControl() != ObjCMethodDecl::Optional &&
!ClsMap.count(method->getSelector()) &&
- (!Super || !Super->lookupClassMethod(method->getSelector()))) {
+ (!Super || !Super->lookupMethod(method->getSelector(),
+ false /* class method */,
+ false /* shallowCategoryLookup */,
+ true /* followSuper */,
+ nullptr /* category */))) {
// See above comment for instance method lookups.
- if (C && IDecl->lookupClassMethod(method->getSelector(),
- true /*shallowCategoryLookup*/))
+ if (C && IDecl->lookupMethod(method->getSelector(),
+ false /* class */,
+ true /* shallowCategoryLookup */,
+ false /* followSuper */))
continue;
+
unsigned DIAG = diag::warn_unimplemented_protocol_method;
- if (Diags.getDiagnosticLevel(DIAG, ImpLoc) !=
- DiagnosticsEngine::Ignored) {
- WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
- Diag(IDecl->getLocation(), diag::note_required_for_protocol_at) <<
- PDecl->getDeclName();
+ if (!S.Diags.isIgnored(DIAG, ImpLoc)) {
+ WarnUndefinedMethod(S, ImpLoc, method, IncompleteImpl, DIAG, PDecl);
}
}
}
// Check on this protocols's referenced protocols, recursively.
- for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
- E = PDecl->protocol_end(); PI != E; ++PI)
- CheckProtocolMethodDefs(ImpLoc, *PI, IncompleteImpl, InsMap, ClsMap, CDecl);
+ for (auto *PI : PDecl->protocols())
+ CheckProtocolMethodDefs(S, ImpLoc, PI, IncompleteImpl, InsMap, ClsMap,
+ CDecl, ProtocolsExplictImpl);
}
/// MatchAllMethodDeclarations - Check methods declared in interface
@@ -1729,56 +1818,50 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
bool WarnCategoryMethodImpl) {
// Check and see if instance methods in class interface have been
// implemented in the implementation class. If so, their types match.
- for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(),
- E = CDecl->instmeth_end(); I != E; ++I) {
- if (!InsMapSeen.insert((*I)->getSelector()))
+ for (auto *I : CDecl->instance_methods()) {
+ if (!InsMapSeen.insert(I->getSelector()))
continue;
- if (!(*I)->isPropertyAccessor() &&
- !InsMap.count((*I)->getSelector())) {
+ if (!I->isPropertyAccessor() &&
+ !InsMap.count(I->getSelector())) {
if (ImmediateClass)
- WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl,
+ WarnUndefinedMethod(*this, IMPDecl->getLocation(), I, IncompleteImpl,
diag::warn_undef_method_impl);
continue;
} else {
ObjCMethodDecl *ImpMethodDecl =
- IMPDecl->getInstanceMethod((*I)->getSelector());
- assert(CDecl->getInstanceMethod((*I)->getSelector()) &&
+ IMPDecl->getInstanceMethod(I->getSelector());
+ assert(CDecl->getInstanceMethod(I->getSelector()) &&
"Expected to find the method through lookup as well");
- ObjCMethodDecl *MethodDecl = *I;
// ImpMethodDecl may be null as in a @dynamic property.
if (ImpMethodDecl) {
if (!WarnCategoryMethodImpl)
- WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl,
+ WarnConflictingTypedMethods(ImpMethodDecl, I,
isa<ObjCProtocolDecl>(CDecl));
- else if (!MethodDecl->isPropertyAccessor())
- WarnExactTypedMethods(ImpMethodDecl, MethodDecl,
- isa<ObjCProtocolDecl>(CDecl));
+ else if (!I->isPropertyAccessor())
+ WarnExactTypedMethods(ImpMethodDecl, I, isa<ObjCProtocolDecl>(CDecl));
}
}
}
// Check and see if class methods in class interface have been
// implemented in the implementation class. If so, their types match.
- for (ObjCInterfaceDecl::classmeth_iterator I = CDecl->classmeth_begin(),
- E = CDecl->classmeth_end();
- I != E; ++I) {
- if (!ClsMapSeen.insert((*I)->getSelector()))
+ for (auto *I : CDecl->class_methods()) {
+ if (!ClsMapSeen.insert(I->getSelector()))
continue;
- if (!ClsMap.count((*I)->getSelector())) {
+ if (!ClsMap.count(I->getSelector())) {
if (ImmediateClass)
- WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl,
+ WarnUndefinedMethod(*this, IMPDecl->getLocation(), I, IncompleteImpl,
diag::warn_undef_method_impl);
} else {
ObjCMethodDecl *ImpMethodDecl =
- IMPDecl->getClassMethod((*I)->getSelector());
- assert(CDecl->getClassMethod((*I)->getSelector()) &&
+ IMPDecl->getClassMethod(I->getSelector());
+ assert(CDecl->getClassMethod(I->getSelector()) &&
"Expected to find the method through lookup as well");
- ObjCMethodDecl *MethodDecl = *I;
if (!WarnCategoryMethodImpl)
- WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl,
+ WarnConflictingTypedMethods(ImpMethodDecl, I,
isa<ObjCProtocolDecl>(CDecl));
else
- WarnExactTypedMethods(ImpMethodDecl, MethodDecl,
+ WarnExactTypedMethods(ImpMethodDecl, I,
isa<ObjCProtocolDecl>(CDecl));
}
}
@@ -1786,10 +1869,9 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl> (CDecl)) {
// Also, check for methods declared in protocols inherited by
// this protocol.
- for (ObjCProtocolDecl::protocol_iterator
- PI = PD->protocol_begin(), E = PD->protocol_end(); PI != E; ++PI)
+ for (auto *PI : PD->protocols())
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
- IMPDecl, (*PI), IncompleteImpl, false,
+ IMPDecl, PI, IncompleteImpl, false,
WarnCategoryMethodImpl);
}
@@ -1798,35 +1880,24 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
// i.e. when WarnCategoryMethodImpl is false, check declarations in class
// extension; as well as those in categories.
if (!WarnCategoryMethodImpl) {
- for (ObjCInterfaceDecl::visible_categories_iterator
- Cat = I->visible_categories_begin(),
- CatEnd = I->visible_categories_end();
- Cat != CatEnd; ++Cat) {
+ for (auto *Cat : I->visible_categories())
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
- IMPDecl, *Cat, IncompleteImpl, false,
+ IMPDecl, Cat, IncompleteImpl, false,
WarnCategoryMethodImpl);
- }
} else {
// Also methods in class extensions need be looked at next.
- for (ObjCInterfaceDecl::visible_extensions_iterator
- Ext = I->visible_extensions_begin(),
- ExtEnd = I->visible_extensions_end();
- Ext != ExtEnd; ++Ext) {
+ for (auto *Ext : I->visible_extensions())
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
- IMPDecl, *Ext, IncompleteImpl, false,
+ IMPDecl, Ext, IncompleteImpl, false,
WarnCategoryMethodImpl);
- }
}
// Check for any implementation of a methods declared in protocol.
- for (ObjCInterfaceDecl::all_protocol_iterator
- PI = I->all_referenced_protocol_begin(),
- E = I->all_referenced_protocol_end(); PI != E; ++PI)
+ for (auto *PI : I->all_referenced_protocols())
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
- IMPDecl,
- (*PI), IncompleteImpl, false,
+ IMPDecl, PI, IncompleteImpl, false,
WarnCategoryMethodImpl);
-
+
// FIXME. For now, we are not checking for extact match of methods
// in category implementation and its primary class's super class.
if (!WarnCategoryMethodImpl && I->getSuperClass())
@@ -1841,20 +1912,6 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
/// warns each time an exact match is found.
void Sema::CheckCategoryVsClassMethodMatches(
ObjCCategoryImplDecl *CatIMPDecl) {
- SelectorSet InsMap, ClsMap;
-
- for (ObjCImplementationDecl::instmeth_iterator
- I = CatIMPDecl->instmeth_begin(),
- E = CatIMPDecl->instmeth_end(); I!=E; ++I)
- InsMap.insert((*I)->getSelector());
-
- for (ObjCImplementationDecl::classmeth_iterator
- I = CatIMPDecl->classmeth_begin(),
- E = CatIMPDecl->classmeth_end(); I != E; ++I)
- ClsMap.insert((*I)->getSelector());
- if (InsMap.empty() && ClsMap.empty())
- return;
-
// Get category's primary class.
ObjCCategoryDecl *CatDecl = CatIMPDecl->getCategoryDecl();
if (!CatDecl)
@@ -1862,6 +1919,28 @@ void Sema::CheckCategoryVsClassMethodMatches(
ObjCInterfaceDecl *IDecl = CatDecl->getClassInterface();
if (!IDecl)
return;
+ ObjCInterfaceDecl *SuperIDecl = IDecl->getSuperClass();
+ SelectorSet InsMap, ClsMap;
+
+ for (const auto *I : CatIMPDecl->instance_methods()) {
+ Selector Sel = I->getSelector();
+ // When checking for methods implemented in the category, skip over
+ // those declared in category class's super class. This is because
+ // the super class must implement the method.
+ if (SuperIDecl && SuperIDecl->lookupMethod(Sel, true))
+ continue;
+ InsMap.insert(Sel);
+ }
+
+ for (const auto *I : CatIMPDecl->class_methods()) {
+ Selector Sel = I->getSelector();
+ if (SuperIDecl && SuperIDecl->lookupMethod(Sel, false))
+ continue;
+ ClsMap.insert(Sel);
+ }
+ if (InsMap.empty() && ClsMap.empty())
+ return;
+
SelectorSet InsMapSeen, ClsMapSeen;
bool IncompleteImpl = false;
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
@@ -1876,24 +1955,22 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
SelectorSet InsMap;
// Check and see if instance methods in class interface have been
// implemented in the implementation class.
- for (ObjCImplementationDecl::instmeth_iterator
- I = IMPDecl->instmeth_begin(), E = IMPDecl->instmeth_end(); I!=E; ++I)
- InsMap.insert((*I)->getSelector());
+ for (const auto *I : IMPDecl->instance_methods())
+ InsMap.insert(I->getSelector());
// Check and see if properties declared in the interface have either 1)
// an implementation or 2) there is a @synthesize/@dynamic implementation
// of the property in the @implementation.
- if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl))
- if (!(LangOpts.ObjCDefaultSynthProperties &&
- LangOpts.ObjCRuntime.isNonFragile()) ||
- IDecl->isObjCRequiresPropertyDefs())
- DiagnoseUnimplementedProperties(S, IMPDecl, CDecl);
-
+ if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
+ bool SynthesizeProperties = LangOpts.ObjCDefaultSynthProperties &&
+ LangOpts.ObjCRuntime.isNonFragile() &&
+ !IDecl->isObjCRequiresPropertyDefs();
+ DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, SynthesizeProperties);
+ }
+
SelectorSet ClsMap;
- for (ObjCImplementationDecl::classmeth_iterator
- I = IMPDecl->classmeth_begin(),
- E = IMPDecl->classmeth_end(); I != E; ++I)
- ClsMap.insert((*I)->getSelector());
+ for (const auto *I : IMPDecl->class_methods())
+ ClsMap.insert(I->getSelector());
// Check for type conflict of methods declared in a class/protocol and
// its implementation; if any.
@@ -1913,28 +1990,25 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
// Check and see if class methods in class interface have been
// implemented in the implementation class.
+ LazyProtocolNameSet ExplicitImplProtocols;
+
if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) {
- for (ObjCInterfaceDecl::all_protocol_iterator
- PI = I->all_referenced_protocol_begin(),
- E = I->all_referenced_protocol_end(); PI != E; ++PI)
- CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
- InsMap, ClsMap, I);
+ for (auto *PI : I->all_referenced_protocols())
+ CheckProtocolMethodDefs(*this, IMPDecl->getLocation(), PI, IncompleteImpl,
+ InsMap, ClsMap, I, ExplicitImplProtocols);
// Check class extensions (unnamed categories)
- for (ObjCInterfaceDecl::visible_extensions_iterator
- Ext = I->visible_extensions_begin(),
- ExtEnd = I->visible_extensions_end();
- Ext != ExtEnd; ++Ext) {
- ImplMethodsVsClassMethods(S, IMPDecl, *Ext, IncompleteImpl);
- }
+ for (auto *Ext : I->visible_extensions())
+ ImplMethodsVsClassMethods(S, IMPDecl, Ext, IncompleteImpl);
} else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
// For extended class, unimplemented methods in its protocols will
// be reported in the primary class.
if (!C->IsClassExtension()) {
- for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(),
- E = C->protocol_end(); PI != E; ++PI)
- CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
- InsMap, ClsMap, CDecl);
- DiagnoseUnimplementedProperties(S, IMPDecl, CDecl);
+ for (auto *P : C->protocols())
+ CheckProtocolMethodDefs(*this, IMPDecl->getLocation(), P,
+ IncompleteImpl, InsMap, ClsMap, CDecl,
+ ExplicitImplProtocols);
+ DiagnoseUnimplementedProperties(S, IMPDecl, CDecl,
+ /* SynthesizeProperties */ false);
}
} else
llvm_unreachable("invalid ObjCContainerDecl type.");
@@ -2103,8 +2177,8 @@ static bool tryMatchRecordTypes(ASTContext &Context,
bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
const ObjCMethodDecl *right,
MethodMatchStrategy strategy) {
- if (!matchTypes(Context, strategy,
- left->getResultType(), right->getResultType()))
+ if (!matchTypes(Context, strategy, left->getReturnType(),
+ right->getReturnType()))
return false;
// If either is hidden, it is not considered to match.
@@ -2145,9 +2219,9 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) {
List->setBits(List->getBits()+1);
// If the list is empty, make it a singleton list.
- if (List->Method == 0) {
+ if (List->Method == nullptr) {
List->Method = Method;
- List->setNext(0);
+ List->setNext(nullptr);
return;
}
@@ -2187,7 +2261,7 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) {
// We have a new signature for an existing method - add it.
// This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>();
- Previous->setNext(new (Mem) ObjCMethodList(Method, 0));
+ Previous->setNext(new (Mem) ObjCMethodList(Method, nullptr));
}
/// \brief Read the contents of the method pool for a given selector from
@@ -2233,7 +2307,7 @@ static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen,
// Don't complain about mismatches for -length if the method we
// chose has an integral result type.
- return (chosen->getResultType()->isIntegerType());
+ return (chosen->getReturnType()->isIntegerType());
}
ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
@@ -2244,7 +2318,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
GlobalMethodPool::iterator Pos = MethodPool.find(Sel);
if (Pos == MethodPool.end())
- return 0;
+ return nullptr;
// Gather the non-hidden methods.
ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
@@ -2262,7 +2336,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
// If there aren't any visible methods, we're done.
// FIXME: Recover if there are any known-but-hidden methods?
if (Methods.empty())
- return 0;
+ return nullptr;
if (Methods.size() == 1)
return Methods[0];
@@ -2273,10 +2347,8 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
// 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())
- != DiagnosticsEngine::Ignored));
+ receiverIdOrClass && warn &&
+ !Diags.isIgnored(diag::warn_strict_multiple_method_decl, R.getBegin());
if (strictSelectorMatch) {
for (unsigned I = 1, N = Methods.size(); I != N; ++I) {
if (!MatchTwoMethodDeclarations(Methods[0], Methods[I], MMS_strict)) {
@@ -2324,15 +2396,19 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) {
GlobalMethodPool::iterator Pos = MethodPool.find(Sel);
if (Pos == MethodPool.end())
- return 0;
+ return nullptr;
GlobalMethods &Methods = Pos->second;
-
- if (Methods.first.Method && Methods.first.Method->isDefined())
- return Methods.first.Method;
- if (Methods.second.Method && Methods.second.Method->isDefined())
- return Methods.second.Method;
- return 0;
+ for (const ObjCMethodList *Method = &Methods.first; Method;
+ Method = Method->getNext())
+ if (Method->Method && Method->Method->isDefined())
+ return Method->Method;
+
+ for (const ObjCMethodList *Method = &Methods.second; Method;
+ Method = Method->getNext())
+ if (Method->Method && Method->Method->isDefined())
+ return Method->Method;
+ return nullptr;
}
static void
@@ -2364,7 +2440,8 @@ static bool HelperIsMethodInObjCType(Sema &S, Selector Sel,
return true;
if (S.LookupMethodInObjectType(Sel, ObjectType, true/*Instance method*/))
return true;
- return S.LookupMethodInObjectType(Sel, ObjectType, false/*Class method*/) != 0;
+ return S.LookupMethodInObjectType(Sel, ObjectType, false/*Class method*/) !=
+ nullptr;
}
const ObjCMethodDecl *
@@ -2376,7 +2453,7 @@ Sema::SelectorsForTypoCorrection(Selector Sel,
if (ObjectType.isNull())
ObjectIsId = ObjectIsClass = false;
else if (!ObjectType->isObjCObjectPointerType())
- return 0;
+ return nullptr;
else if (const ObjCObjectPointerType *ObjCPtr =
ObjectType->getAsObjCInterfacePointerType()) {
ObjectType = QualType(ObjCPtr->getInterfaceType(), 0);
@@ -2387,8 +2464,8 @@ Sema::SelectorsForTypoCorrection(Selector Sel,
else if (ObjectType->isObjCClassType() || ObjectType->isObjCQualifiedClassType())
ObjectIsId = false;
else
- return 0;
-
+ return nullptr;
+
for (GlobalMethodPool::iterator b = MethodPool.begin(),
e = MethodPool.end(); b != e; b++) {
// instance methods
@@ -2420,52 +2497,7 @@ Sema::SelectorsForTypoCorrection(Selector Sel,
HelperSelectorsForTypoCorrection(SelectedMethods,
Sel.getAsString(), Methods[i]);
}
- return (SelectedMethods.size() == 1) ? SelectedMethods[0] : NULL;
-}
-
-static void
-HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S,
- ObjCMethodList &MethList) {
- ObjCMethodList *M = &MethList;
- ObjCMethodDecl *TargetMethod = M->Method;
- while (TargetMethod &&
- isa<ObjCImplDecl>(TargetMethod->getDeclContext())) {
- M = M->getNext();
- TargetMethod = M ? M->Method : 0;
- }
- if (!TargetMethod)
- return;
- bool FirstTime = true;
- for (M = M->getNext(); M; M=M->getNext()) {
- ObjCMethodDecl *MatchingMethodDecl = M->Method;
- if (isa<ObjCImplDecl>(MatchingMethodDecl->getDeclContext()))
- continue;
- if (!S.MatchTwoMethodDeclarations(TargetMethod,
- MatchingMethodDecl, Sema::MMS_loose)) {
- if (FirstTime) {
- FirstTime = false;
- S.Diag(TargetMethod->getLocation(), diag::warning_multiple_selectors)
- << TargetMethod->getSelector();
- }
- S.Diag(MatchingMethodDecl->getLocation(), diag::note_also_found);
- }
- }
-}
-
-void Sema::DiagnoseMismatchedMethodsInGlobalPool() {
- unsigned DIAG = diag::warning_multiple_selectors;
- if (Diags.getDiagnosticLevel(DIAG, SourceLocation())
- == DiagnosticsEngine::Ignored)
- return;
- for (GlobalMethodPool::iterator b = MethodPool.begin(),
- e = MethodPool.end(); b != e; b++) {
- // first, instance methods
- ObjCMethodList &InstMethList = b->second.first;
- HelperToDiagnoseMismatchedMethodsInGlobalPool(*this, InstMethList);
- // second, class methods
- ObjCMethodList &ClsMethList = b->second.second;
- HelperToDiagnoseMismatchedMethodsInGlobalPool(*this, ClsMethList);
- }
+ return (SelectedMethods.size() == 1) ? SelectedMethods[0] : nullptr;
}
/// DiagnoseDuplicateIvars -
@@ -2475,9 +2507,7 @@ void Sema::DiagnoseMismatchedMethodsInGlobalPool() {
/// class's \@implementation is seen.
void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID,
ObjCInterfaceDecl *SID) {
- for (ObjCInterfaceDecl::ivar_iterator IVI = ID->ivar_begin(),
- IVE = ID->ivar_end(); IVI != IVE; ++IVI) {
- ObjCIvarDecl* Ivar = *IVI;
+ for (auto *Ivar : ID->ivars()) {
if (Ivar->isInvalidDecl())
continue;
if (IdentifierInfo *II = Ivar->getIdentifier()) {
@@ -2516,7 +2546,7 @@ Sema::ObjCContainerKind Sema::getObjCContainerKind() const {
Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
ArrayRef<DeclGroupPtrTy> allTUVars) {
if (getObjCContainerKind() == Sema::OCK_None)
- return 0;
+ return nullptr;
assert(AtEnd.isValid() && "Invalid location for '@end'");
@@ -2603,10 +2633,8 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
// ProcessPropertyDecl is responsible for diagnosing conflicts with any
// user-defined setter/getter. It also synthesizes setter/getter methods
// and adds them to the DeclContext and global method pools.
- for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(),
- E = CDecl->prop_end();
- I != E; ++I)
- ProcessPropertyDecl(*I, CDecl);
+ for (auto *I : CDecl->properties())
+ ProcessPropertyDecl(I, CDecl);
CDecl->setAtEndRange(AtEnd);
}
if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
@@ -2617,13 +2645,8 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
// of the other class extensions. Mark them as synthesized as
// property will be synthesized when property with same name is
// seen in the @implementation.
- for (ObjCInterfaceDecl::visible_extensions_iterator
- Ext = IDecl->visible_extensions_begin(),
- ExtEnd = IDecl->visible_extensions_end();
- Ext != ExtEnd; ++Ext) {
- for (ObjCContainerDecl::prop_iterator I = Ext->prop_begin(),
- E = Ext->prop_end(); I != E; ++I) {
- ObjCPropertyDecl *Property = *I;
+ for (const auto *Ext : IDecl->visible_extensions()) {
+ for (const auto *Property : Ext->properties()) {
// Skip over properties declared @dynamic
if (const ObjCPropertyImplDecl *PIDecl
= IC->FindPropertyImplDecl(Property->getIdentifier()))
@@ -2631,10 +2654,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
== ObjCPropertyImplDecl::Dynamic)
continue;
- for (ObjCInterfaceDecl::visible_extensions_iterator
- Ext = IDecl->visible_extensions_begin(),
- ExtEnd = IDecl->visible_extensions_end();
- Ext != ExtEnd; ++Ext) {
+ for (const auto *Ext : IDecl->visible_extensions()) {
if (ObjCMethodDecl *GetterMethod
= Ext->getInstanceMethod(Property->getGetterName()))
GetterMethod->setPropertyAccessor(true);
@@ -2648,14 +2668,17 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
ImplMethodsVsClassMethods(S, IC, IDecl);
AtomicPropertySetterGetterRules(IC, IDecl);
DiagnoseOwningPropertyGetterSynthesis(IC);
-
+ DiagnoseUnusedBackingIvarInAccessor(S, IC);
+ if (IDecl->hasDesignatedInitializers())
+ DiagnoseMissingDesignatedInitOverrides(IC, IDecl);
+
bool HasRootClassAttr = IDecl->hasAttr<ObjCRootClassAttr>();
- if (IDecl->getSuperClass() == NULL) {
+ if (IDecl->getSuperClass() == nullptr) {
// This class has no superclass, so check that it has been marked with
// __attribute((objc_root_class)).
if (!HasRootClassAttr) {
SourceLocation DeclLoc(IDecl->getLocation());
- SourceLocation SuperClassLoc(PP.getLocForEndOfToken(DeclLoc));
+ SourceLocation SuperClassLoc(getLocForEndOfToken(DeclLoc));
Diag(DeclLoc, diag::warn_objc_root_class_missing)
<< IDecl->getIdentifier();
// See if NSObject is in the current scope, and if it is, suggest
@@ -2729,72 +2752,14 @@ CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) {
return (Decl::ObjCDeclQualifier) (unsigned) PQTVal;
}
-static inline
-unsigned countAlignAttr(const AttrVec &A) {
- unsigned count=0;
- for (AttrVec::const_iterator i = A.begin(), e = A.end(); i != e; ++i)
- if ((*i)->getKind() == attr::Aligned)
- ++count;
- return count;
-}
-
-static inline
-bool containsInvalidMethodImplAttribute(ObjCMethodDecl *IMD,
- const AttrVec &A) {
- // If method is only declared in implementation (private method),
- // No need to issue any diagnostics on method definition with attributes.
- if (!IMD)
- return false;
-
- // method declared in interface has no attribute.
- // But implementation has attributes. This is invalid.
- // Except when implementation has 'Align' attribute which is
- // immaterial to method declared in interface.
- if (!IMD->hasAttrs())
- return (A.size() > countAlignAttr(A));
-
- const AttrVec &D = IMD->getAttrs();
-
- unsigned countAlignOnImpl = countAlignAttr(A);
- if (!countAlignOnImpl && (A.size() != D.size()))
- return true;
- else if (countAlignOnImpl) {
- unsigned countAlignOnDecl = countAlignAttr(D);
- if (countAlignOnDecl && (A.size() != D.size()))
- return true;
- else if (!countAlignOnDecl &&
- ((A.size()-countAlignOnImpl) != D.size()))
- return true;
- }
-
- // attributes on method declaration and definition must match exactly.
- // Note that we have at most a couple of attributes on methods, so this
- // n*n search is good enough.
- for (AttrVec::const_iterator i = A.begin(), e = A.end(); i != e; ++i) {
- if ((*i)->getKind() == attr::Aligned)
- continue;
- bool match = false;
- for (AttrVec::const_iterator i1 = D.begin(), e1 = D.end(); i1 != e1; ++i1) {
- if ((*i)->getKind() == (*i1)->getKind()) {
- match = true;
- break;
- }
- }
- if (!match)
- return true;
- }
-
- return false;
-}
-
/// \brief Check whether the declared result type of the given Objective-C
/// method declaration is compatible with the method's class.
///
static Sema::ResultTypeCompatibilityKind
CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method,
ObjCInterfaceDecl *CurrentClass) {
- QualType ResultType = Method->getResultType();
-
+ QualType ResultType = Method->getReturnType();
+
// If an Objective-C method inherits its related result type, then its
// declared result type must be compatible with its own class type. The
// declared result type is compatible if:
@@ -2928,12 +2893,8 @@ private:
return;
// - categories,
- for (ObjCInterfaceDecl::known_categories_iterator
- cat = iface->known_categories_begin(),
- catEnd = iface->known_categories_end();
- cat != catEnd; ++cat) {
- search(*cat);
- }
+ for (auto *Cat : iface->known_categories())
+ search(Cat);
// - the super class, and
if (ObjCInterfaceDecl *super = iface->getSuperClass())
@@ -3095,19 +3056,19 @@ Decl *Sema::ActOnMethodDeclaration(
// Make sure we can establish a context for the method.
if (!CurContext->isObjCContainer()) {
Diag(MethodLoc, diag::error_missing_method_context);
- return 0;
+ return nullptr;
}
ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext);
Decl *ClassDecl = cast<Decl>(OCD);
QualType resultDeclType;
bool HasRelatedResultType = false;
- TypeSourceInfo *ResultTInfo = 0;
+ TypeSourceInfo *ReturnTInfo = nullptr;
if (ReturnType) {
- resultDeclType = GetTypeFromParser(ReturnType, &ResultTInfo);
+ resultDeclType = GetTypeFromParser(ReturnType, &ReturnTInfo);
if (CheckFunctionReturnType(resultDeclType, MethodLoc))
- return 0;
+ return nullptr;
HasRelatedResultType = (resultDeclType == Context.getObjCInstanceType());
} else { // get the type for "id".
@@ -3116,18 +3077,14 @@ Decl *Sema::ActOnMethodDeclaration(
<< FixItHint::CreateInsertion(SelectorLocs.front(), "(id)");
}
- ObjCMethodDecl* ObjCMethod =
- ObjCMethodDecl::Create(Context, MethodLoc, EndLoc, Sel,
- resultDeclType,
- ResultTInfo,
- CurContext,
- MethodType == tok::minus, isVariadic,
- /*isPropertyAccessor=*/false,
- /*isImplicitlyDeclared=*/false, /*isDefined=*/false,
- MethodDeclKind == tok::objc_optional
- ? ObjCMethodDecl::Optional
- : ObjCMethodDecl::Required,
- HasRelatedResultType);
+ ObjCMethodDecl *ObjCMethod = ObjCMethodDecl::Create(
+ Context, MethodLoc, EndLoc, Sel, resultDeclType, ReturnTInfo, CurContext,
+ MethodType == tok::minus, isVariadic,
+ /*isPropertyAccessor=*/false,
+ /*isImplicitlyDeclared=*/false, /*isDefined=*/false,
+ MethodDeclKind == tok::objc_optional ? ObjCMethodDecl::Optional
+ : ObjCMethodDecl::Required,
+ HasRelatedResultType);
SmallVector<ParmVarDecl*, 16> Params;
@@ -3137,7 +3094,7 @@ Decl *Sema::ActOnMethodDeclaration(
if (!ArgInfo[i].Type) {
ArgType = Context.getObjCIdType();
- DI = 0;
+ DI = nullptr;
} else {
ArgType = GetTypeFromParser(ArgInfo[i].Type, &DI);
}
@@ -3204,7 +3161,7 @@ Decl *Sema::ActOnMethodDeclaration(
ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList);
// Add the method now.
- const ObjCMethodDecl *PrevMethod = 0;
+ const ObjCMethodDecl *PrevMethod = nullptr;
if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(ClassDecl)) {
if (MethodType == tok::minus) {
PrevMethod = ImpDecl->getInstanceMethod(Sel);
@@ -3214,24 +3171,22 @@ Decl *Sema::ActOnMethodDeclaration(
ImpDecl->addClassMethod(ObjCMethod);
}
- ObjCMethodDecl *IMD = 0;
+ ObjCMethodDecl *IMD = nullptr;
if (ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface())
IMD = IDecl->lookupMethod(ObjCMethod->getSelector(),
ObjCMethod->isInstanceMethod());
if (IMD && IMD->hasAttr<ObjCRequiresSuperAttr>() &&
!ObjCMethod->hasAttr<ObjCRequiresSuperAttr>()) {
// merge the attribute into implementation.
- ObjCMethod->addAttr(
- new (Context) ObjCRequiresSuperAttr(ObjCMethod->getLocation(), Context));
- }
- if (ObjCMethod->hasAttrs() &&
- containsInvalidMethodImplAttribute(IMD, ObjCMethod->getAttrs())) {
- SourceLocation MethodLoc = IMD->getLocation();
- if (!getSourceManager().isInSystemHeader(MethodLoc)) {
- Diag(EndLoc, diag::warn_attribute_method_def);
- Diag(MethodLoc, diag::note_method_declared_at)
+ ObjCMethod->addAttr(ObjCRequiresSuperAttr::CreateImplicit(Context,
+ ObjCMethod->getLocation()));
+ }
+ if (isa<ObjCCategoryImplDecl>(ImpDecl)) {
+ ObjCMethodFamily family =
+ ObjCMethod->getSelector().getMethodFamily();
+ if (family == OMF_dealloc && IMD && IMD->isOverriding())
+ Diag(ObjCMethod->getLocation(), diag::warn_dealloc_in_category)
<< ObjCMethod->getDeclName();
- }
}
} else {
cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod);
@@ -3482,8 +3437,6 @@ void Sema::DiagnoseUseOfUnimplementedSelectors() {
ReferencedSelectors[Sels[I].first] = Sels[I].second;
}
- DiagnoseMismatchedMethodsInGlobalPool();
-
// Warning will be issued only when selector table is
// generated (which means there is at lease one implementation
// in the TU). This is to match gcc's behavior.
@@ -3503,39 +3456,93 @@ void Sema::DiagnoseUseOfUnimplementedSelectors() {
ObjCIvarDecl *
Sema::GetIvarBackingPropertyAccessor(const ObjCMethodDecl *Method,
const ObjCPropertyDecl *&PDecl) const {
-
+ if (Method->isClassMethod())
+ return nullptr;
const ObjCInterfaceDecl *IDecl = Method->getClassInterface();
if (!IDecl)
- return 0;
- Method = IDecl->lookupMethod(Method->getSelector(), true);
+ return nullptr;
+ Method = IDecl->lookupMethod(Method->getSelector(), /*isInstance=*/true,
+ /*shallowCategoryLookup=*/false,
+ /*followSuper=*/false);
if (!Method || !Method->isPropertyAccessor())
- return 0;
- if ((PDecl = Method->findPropertyDecl())) {
- if (!PDecl->getDeclContext())
- return 0;
- // Make sure property belongs to accessor's class and not to
- // one of its super classes.
- if (const ObjCInterfaceDecl *CID =
- dyn_cast<ObjCInterfaceDecl>(PDecl->getDeclContext()))
- if (CID != IDecl)
- return 0;
- return PDecl->getPropertyIvarDecl();
- }
- return 0;
-}
-
-void Sema::DiagnoseUnusedBackingIvarInAccessor(Scope *S) {
- if (S->hasUnrecoverableErrorOccurred() || !S->isInObjcMethodScope())
- return;
-
- const ObjCMethodDecl *CurMethod = getCurMethodDecl();
- if (!CurMethod)
+ return nullptr;
+ if ((PDecl = Method->findPropertyDecl()))
+ if (ObjCIvarDecl *IV = PDecl->getPropertyIvarDecl()) {
+ // property backing ivar must belong to property's class
+ // or be a private ivar in class's implementation.
+ // FIXME. fix the const-ness issue.
+ IV = const_cast<ObjCInterfaceDecl *>(IDecl)->lookupInstanceVariable(
+ IV->getIdentifier());
+ return IV;
+ }
+ return nullptr;
+}
+
+namespace {
+ /// Used by Sema::DiagnoseUnusedBackingIvarInAccessor to check if a property
+ /// accessor references the backing ivar.
+ class UnusedBackingIvarChecker :
+ public DataRecursiveASTVisitor<UnusedBackingIvarChecker> {
+ public:
+ Sema &S;
+ const ObjCMethodDecl *Method;
+ const ObjCIvarDecl *IvarD;
+ bool AccessedIvar;
+ bool InvokedSelfMethod;
+
+ UnusedBackingIvarChecker(Sema &S, const ObjCMethodDecl *Method,
+ const ObjCIvarDecl *IvarD)
+ : S(S), Method(Method), IvarD(IvarD),
+ AccessedIvar(false), InvokedSelfMethod(false) {
+ assert(IvarD);
+ }
+
+ bool VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ if (E->getDecl() == IvarD) {
+ AccessedIvar = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ if (E->getReceiverKind() == ObjCMessageExpr::Instance &&
+ S.isSelfExpr(E->getInstanceReceiver(), Method)) {
+ InvokedSelfMethod = true;
+ }
+ return true;
+ }
+ };
+}
+
+void Sema::DiagnoseUnusedBackingIvarInAccessor(Scope *S,
+ const ObjCImplementationDecl *ImplD) {
+ if (S->hasUnrecoverableErrorOccurred())
return;
- const ObjCPropertyDecl *PDecl;
- const ObjCIvarDecl *IV = GetIvarBackingPropertyAccessor(CurMethod, PDecl);
- if (IV && !IV->getBackingIvarReferencedInAccessor()) {
- Diag(getCurMethodDecl()->getLocation(), diag::warn_unused_property_backing_ivar)
- << IV->getDeclName();
- Diag(PDecl->getLocation(), diag::note_property_declare);
+
+ for (const auto *CurMethod : ImplD->instance_methods()) {
+ unsigned DIAG = diag::warn_unused_property_backing_ivar;
+ SourceLocation Loc = CurMethod->getLocation();
+ if (Diags.isIgnored(DIAG, Loc))
+ continue;
+
+ const ObjCPropertyDecl *PDecl;
+ const ObjCIvarDecl *IV = GetIvarBackingPropertyAccessor(CurMethod, PDecl);
+ if (!IV)
+ continue;
+
+ UnusedBackingIvarChecker Checker(*this, CurMethod, IV);
+ Checker.TraverseStmt(CurMethod->getBody());
+ if (Checker.AccessedIvar)
+ continue;
+
+ // Do not issue this warning if backing ivar is used somewhere and accessor
+ // implementation makes a self call. This is to prevent false positive in
+ // cases where the ivar is accessed by another method that the accessor
+ // delegates to.
+ if (!IV->isReferenced() || !Checker.InvokedSelfMethod) {
+ Diag(Loc, DIAG) << IV;
+ Diag(PDecl->getLocation(), diag::note_property_declare);
+ }
}
}
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 3e8f324027dc..b92fcbd2a0d9 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -12,13 +12,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
@@ -132,6 +132,25 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
return SourceDecl->getType()->castAs<FunctionProtoType>();
}
+void Sema::UpdateExceptionSpec(FunctionDecl *FD,
+ const FunctionProtoType::ExtProtoInfo &EPI) {
+ const FunctionProtoType *Proto = FD->getType()->castAs<FunctionProtoType>();
+
+ // Overwrite the exception spec and rebuild the function type.
+ FunctionProtoType::ExtProtoInfo NewEPI = Proto->getExtProtoInfo();
+ NewEPI.ExceptionSpecType = EPI.ExceptionSpecType;
+ NewEPI.NumExceptions = EPI.NumExceptions;
+ NewEPI.Exceptions = EPI.Exceptions;
+ NewEPI.NoexceptExpr = EPI.NoexceptExpr;
+ FD->setType(Context.getFunctionType(Proto->getReturnType(),
+ Proto->getParamTypes(), NewEPI));
+
+ // If we've fully resolved the exception specification, notify listeners.
+ if (!isUnresolvedExceptionSpec(EPI.ExceptionSpecType))
+ if (auto *Listener = getASTMutationListener())
+ Listener->ResolvedExceptionSpec(FD);
+}
+
/// Determine whether a function has an implicitly-generated exception
/// specification.
static bool hasImplicitExceptionSpec(FunctionDecl *Decl) {
@@ -140,10 +159,13 @@ static bool hasImplicitExceptionSpec(FunctionDecl *Decl) {
Decl->getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
return false;
- // If the user didn't declare the function, its exception specification must
- // be implicit.
+ // For a function that the user didn't declare:
+ // - if this is a destructor, its exception specification is implicit.
+ // - if this is 'operator delete' or 'operator delete[]', the exception
+ // specification is as-if an explicit exception specification was given
+ // (per [basic.stc.dynamic]p2).
if (!Decl->getTypeSourceInfo())
- return true;
+ return isa<CXXDestructorDecl>(Decl);
const FunctionProtoType *Ty =
Decl->getTypeSourceInfo()->getType()->getAs<FunctionProtoType>();
@@ -155,9 +177,13 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;
bool MissingExceptionSpecification = false;
bool MissingEmptyExceptionSpecification = false;
+
unsigned DiagID = diag::err_mismatched_exception_spec;
- if (getLangOpts().MicrosoftExt)
- DiagID = diag::warn_mismatched_exception_spec;
+ bool ReturnValueOnError = true;
+ if (getLangOpts().MicrosoftExt) {
+ DiagID = diag::ext_mismatched_exception_spec;
+ ReturnValueOnError = false;
+ }
// Check the types as written: they must match before any exception
// specification adjustment is applied.
@@ -182,9 +208,9 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
}
// The failure was something other than an missing exception
- // specification; return an error.
+ // specification; return an error, except in MS mode where this is a warning.
if (!MissingExceptionSpecification)
- return true;
+ return ReturnValueOnError;
const FunctionProtoType *NewProto =
New->getType()->castAs<FunctionProtoType>();
@@ -203,8 +229,8 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
Old->isExternC()) {
FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
EPI.ExceptionSpecType = EST_DynamicNone;
- QualType NewType = Context.getFunctionType(NewProto->getResultType(),
- NewProto->getArgTypes(), EPI);
+ QualType NewType = Context.getFunctionType(NewProto->getReturnType(),
+ NewProto->getParamTypes(), EPI);
New->setType(NewType);
return false;
}
@@ -224,8 +250,8 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
// Update the type of the function with the appropriate exception
// specification.
- QualType NewType = Context.getFunctionType(NewProto->getResultType(),
- NewProto->getArgTypes(), EPI);
+ QualType NewType = Context.getFunctionType(NewProto->getReturnType(),
+ NewProto->getParamTypes(), EPI);
New->setType(NewType);
// Warn about the lack of exception specification.
@@ -239,16 +265,13 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
case EST_Dynamic: {
OS << "throw(";
bool OnFirstException = true;
- for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(),
- EEnd = OldProto->exception_end();
- E != EEnd;
- ++E) {
+ for (const auto &E : OldProto->exceptions()) {
if (OnFirstException)
OnFirstException = false;
else
OS << ", ";
- OS << E->getAsString(getPrintingPolicy());
+ OS << E.getAsString(getPrintingPolicy());
}
OS << ")";
break;
@@ -260,7 +283,8 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
case EST_ComputedNoexcept:
OS << "noexcept(";
- OldProto->getNoexceptExpr()->printPretty(OS, 0, getPrintingPolicy());
+ assert(OldProto->getNoexceptExpr() != nullptr && "Expected non-null Expr");
+ OldProto->getNoexceptExpr()->printPretty(OS, nullptr, getPrintingPolicy());
OS << ")";
break;
@@ -273,7 +297,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) {
TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens();
if (FunctionTypeLoc FTLoc = TL.getAs<FunctionTypeLoc>())
- FixItLoc = PP.getLocForEndOfToken(FTLoc.getLocalRangeEnd());
+ FixItLoc = getLocForEndOfToken(FTLoc.getLocalRangeEnd());
}
if (FixItLoc.isInvalid())
@@ -302,10 +326,14 @@ bool Sema::CheckEquivalentExceptionSpec(
const FunctionProtoType *New, SourceLocation NewLoc) {
unsigned DiagID = diag::err_mismatched_exception_spec;
if (getLangOpts().MicrosoftExt)
- DiagID = diag::warn_mismatched_exception_spec;
- return CheckEquivalentExceptionSpec(PDiag(DiagID),
- PDiag(diag::note_previous_declaration),
- Old, OldLoc, New, NewLoc);
+ DiagID = diag::ext_mismatched_exception_spec;
+ bool Result = CheckEquivalentExceptionSpec(PDiag(DiagID),
+ PDiag(diag::note_previous_declaration), Old, OldLoc, New, NewLoc);
+
+ // In Microsoft mode, mismatching exception specifications just cause a warning.
+ if (getLangOpts().MicrosoftExt)
+ return false;
+ return Result;
}
/// CheckEquivalentExceptionSpec - Check if the two types have compatible
@@ -428,7 +456,7 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
// throw(std::bad_alloc) as equivalent for operator new and operator new[].
// This is because the implicit declaration changed, but old code would break.
if (getLangOpts().CPlusPlus11 && IsOperatorNew) {
- const FunctionProtoType *WithExceptions = 0;
+ const FunctionProtoType *WithExceptions = nullptr;
if (OldEST == EST_None && NewEST == EST_Dynamic)
WithExceptions = New;
else if (OldEST == EST_Dynamic && NewEST == EST_None)
@@ -441,15 +469,8 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
IdentifierInfo* Name = ExRecord->getIdentifier();
if (Name && Name->getName() == "bad_alloc") {
// It's called bad_alloc, but is it in std?
- DeclContext* DC = ExRecord->getDeclContext();
- DC = DC->getEnclosingNamespaceContext();
- if (NamespaceDecl* NS = dyn_cast<NamespaceDecl>(DC)) {
- IdentifierInfo* NSName = NS->getIdentifier();
- DC = DC->getParent();
- if (NSName && NSName->getName() == "std" &&
- DC->getEnclosingNamespaceContext()->isTranslationUnit()) {
- return false;
- }
+ if (ExRecord->isInStdNamespace()) {
+ return false;
}
}
}
@@ -488,13 +509,11 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
// Both have a dynamic exception spec. Collect the first set, then compare
// to the second.
llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes;
- for (FunctionProtoType::exception_iterator I = Old->exception_begin(),
- E = Old->exception_end(); I != E; ++I)
- OldTypes.insert(Context.getCanonicalType(*I).getUnqualifiedType());
+ for (const auto &I : Old->exceptions())
+ OldTypes.insert(Context.getCanonicalType(I).getUnqualifiedType());
- for (FunctionProtoType::exception_iterator I = New->exception_begin(),
- E = New->exception_end(); I != E && Success; ++I) {
- CanQualType TypePtr = Context.getCanonicalType(*I).getUnqualifiedType();
+ for (const auto &I : New->exceptions()) {
+ CanQualType TypePtr = Context.getCanonicalType(I).getUnqualifiedType();
if(OldTypes.count(TypePtr))
NewTypes.insert(TypePtr);
else
@@ -602,10 +621,9 @@ bool Sema::CheckExceptionSpecSubset(
"Exception spec subset: non-dynamic case slipped through.");
// Neither contains everything or nothing. Do a proper comparison.
- for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(),
- SubE = Subset->exception_end(); SubI != SubE; ++SubI) {
+ for (const auto &SubI : Subset->exceptions()) {
// Take one type from the subset.
- QualType CanonicalSubT = Context.getCanonicalType(*SubI);
+ QualType CanonicalSubT = Context.getCanonicalType(SubI);
// Unwrap pointers and references so that we can do checks within a class
// hierarchy. Don't unwrap member pointers; they don't have hierarchy
// conversions on the pointee.
@@ -624,10 +642,8 @@ bool Sema::CheckExceptionSpecSubset(
bool Contained = false;
// Make sure it's in the superset.
- for (FunctionProtoType::exception_iterator SuperI =
- Superset->exception_begin(), SuperE = Superset->exception_end();
- SuperI != SuperE; ++SuperI) {
- QualType CanonicalSuperT = Context.getCanonicalType(*SuperI);
+ for (const auto &SuperI : Superset->exceptions()) {
+ QualType CanonicalSuperT = Context.getCanonicalType(SuperI);
// SubT must be SuperT or derived from it, or pointer or reference to
// such types.
if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>())
@@ -711,23 +727,21 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
const FunctionProtoType *Target, SourceLocation TargetLoc,
const FunctionProtoType *Source, SourceLocation SourceLoc)
{
- if (CheckSpecForTypesEquivalent(*this,
- PDiag(diag::err_deep_exception_specs_differ) << 0,
- PDiag(),
- Target->getResultType(), TargetLoc,
- Source->getResultType(), SourceLoc))
+ if (CheckSpecForTypesEquivalent(
+ *this, PDiag(diag::err_deep_exception_specs_differ) << 0, PDiag(),
+ Target->getReturnType(), TargetLoc, Source->getReturnType(),
+ SourceLoc))
return true;
// We shouldn't even be testing this unless the arguments are otherwise
// compatible.
- assert(Target->getNumArgs() == Source->getNumArgs() &&
+ assert(Target->getNumParams() == Source->getNumParams() &&
"Functions have different argument counts.");
- for (unsigned i = 0, E = Target->getNumArgs(); i != E; ++i) {
- if (CheckSpecForTypesEquivalent(*this,
- PDiag(diag::err_deep_exception_specs_differ) << 1,
- PDiag(),
- Target->getArgType(i), TargetLoc,
- Source->getArgType(i), SourceLoc))
+ for (unsigned i = 0, E = Target->getNumParams(); i != E; ++i) {
+ if (CheckSpecForTypesEquivalent(
+ *this, PDiag(diag::err_deep_exception_specs_differ) << 1, PDiag(),
+ Target->getParamType(i), TargetLoc, Source->getParamType(i),
+ SourceLoc))
return true;
}
return false;
@@ -773,7 +787,7 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
}
unsigned DiagID = diag::err_override_exception_spec;
if (getLangOpts().MicrosoftExt)
- DiagID = diag::warn_override_exception_spec;
+ DiagID = diag::ext_override_exception_spec;
return CheckExceptionSpecSubset(PDiag(DiagID),
PDiag(diag::note_overridden_virtual_function),
Old->getType()->getAs<FunctionProtoType>(),
@@ -1063,7 +1077,6 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::AddrLabelExprClass:
case Expr::ArrayTypeTraitExprClass:
case Expr::AtomicExprClass:
- case Expr::BinaryTypeTraitExprClass:
case Expr::TypeTraitExprClass:
case Expr::CXXBoolLiteralExprClass:
case Expr::CXXNoexceptExprClass:
@@ -1086,7 +1099,6 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::PredefinedExprClass:
case Expr::SizeOfPackExprClass:
case Expr::StringLiteralClass:
- case Expr::UnaryTypeTraitExprClass:
// These expressions can never throw.
return CT_Cannot;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index e1f65f4a4e1b..35dad82523c9 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -59,8 +59,8 @@ bool Sema::CanUseDecl(NamedDecl *D) {
// If the function has a deduced return type, and we can't deduce it,
// then we can't use it either.
- if (getLangOpts().CPlusPlus1y && FD->getResultType()->isUndeducedType() &&
- DeduceReturnType(FD, SourceLocation(), /*Diagnose*/false))
+ if (getLangOpts().CPlusPlus1y && FD->getReturnType()->isUndeducedType() &&
+ DeduceReturnType(FD, SourceLocation(), /*Diagnose*/ false))
return false;
}
@@ -83,9 +83,16 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) {
static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
NamedDecl *D, SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass) {
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ bool ObjCPropertyAccess) {
// See if this declaration is unavailable or deprecated.
std::string Message;
+
+ // Forward class declarations get their attributes from their definition.
+ if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
+ if (IDecl->getDefinition())
+ D = IDecl->getDefinition();
+ }
AvailabilityResult Result = D->getAvailability(&Message);
if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D))
if (Result == AR_Available) {
@@ -94,11 +101,11 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
Result = TheEnumDecl->getAvailability(&Message);
}
- const ObjCPropertyDecl *ObjCPDecl = 0;
+ const ObjCPropertyDecl *ObjCPDecl = nullptr;
if (Result == AR_Deprecated || Result == AR_Unavailable) {
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
- AvailabilityResult PDeclResult = PD->getAvailability(0);
+ AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
if (PDeclResult == Result)
ObjCPDecl = PD;
}
@@ -111,32 +118,19 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
break;
case AR_Deprecated:
- S.EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass, ObjCPDecl);
+ if (S.getCurContextAvailability() != AR_Deprecated)
+ S.EmitAvailabilityWarning(Sema::AD_Deprecation,
+ D, Message, Loc, UnknownObjCClass, ObjCPDecl,
+ ObjCPropertyAccess);
break;
-
+
case AR_Unavailable:
- if (S.getCurContextAvailability() != AR_Unavailable) {
- if (Message.empty()) {
- if (!UnknownObjCClass) {
- S.Diag(Loc, diag::err_unavailable) << D->getDeclName();
- if (ObjCPDecl)
- S.Diag(ObjCPDecl->getLocation(), diag::note_property_attribute)
- << ObjCPDecl->getDeclName() << 1;
- }
- else
- S.Diag(Loc, diag::warn_unavailable_fwdclass_message)
- << D->getDeclName();
- }
- else
- S.Diag(Loc, diag::err_unavailable_message)
- << D->getDeclName() << Message;
- S.Diag(D->getLocation(), diag::note_unavailable_here)
- << isa<FunctionDecl>(D) << false;
- if (ObjCPDecl)
- S.Diag(ObjCPDecl->getLocation(), diag::note_property_attribute)
- << ObjCPDecl->getDeclName() << 1;
- }
+ if (S.getCurContextAvailability() != AR_Unavailable)
+ S.EmitAvailabilityWarning(Sema::AD_Unavailable,
+ D, Message, Loc, UnknownObjCClass, ObjCPDecl,
+ ObjCPropertyAccess);
break;
+
}
return Result;
}
@@ -176,16 +170,14 @@ void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
}
}
- Diag(Decl->getLocation(), diag::note_unavailable_here)
- << 1 << true;
+ Diag(Decl->getLocation(), diag::note_availability_specified_here)
+ << Decl << true;
}
/// \brief Determine whether a FunctionDecl was ever declared with an
/// explicit storage class.
static bool hasAnyExplicitStorageClass(const FunctionDecl *D) {
- for (FunctionDecl::redecl_iterator I = D->redecls_begin(),
- E = D->redecls_end();
- I != E; ++I) {
+ for (auto I : D->redecls()) {
if (I->getStorageClass() != SC_None)
return true;
}
@@ -234,15 +226,14 @@ static void diagnoseUseOfInternalDeclInInlineFunction(Sema &S,
if (!DowngradeWarning && UsedFn)
DowngradeWarning = UsedFn->isInlined() || UsedFn->hasAttr<ConstAttr>();
- S.Diag(Loc, DowngradeWarning ? diag::ext_internal_in_extern_inline
- : diag::warn_internal_in_extern_inline)
+ S.Diag(Loc, DowngradeWarning ? diag::ext_internal_in_extern_inline_quiet
+ : diag::ext_internal_in_extern_inline)
<< /*IsVar=*/!UsedFn << D;
S.MaybeSuggestAddingStaticToDecl(Current);
- S.Diag(D->getCanonicalDecl()->getLocation(),
- diag::note_internal_decl_declared_here)
- << D;
+ S.Diag(D->getCanonicalDecl()->getLocation(), diag::note_entity_declared_at)
+ << D;
}
void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) {
@@ -269,7 +260,8 @@ void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) {
/// referenced), false otherwise.
///
bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
- const ObjCInterfaceDecl *UnknownObjCClass) {
+ const ObjCInterfaceDecl *UnknownObjCClass,
+ bool ObjCPropertyAccess) {
if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) {
// If there were any diagnostics suppressed by template argument deduction,
// emit them now.
@@ -279,13 +271,18 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
SmallVectorImpl<PartialDiagnosticAt> &Suppressed = Pos->second;
for (unsigned I = 0, N = Suppressed.size(); I != N; ++I)
Diag(Suppressed[I].first, Suppressed[I].second);
-
+
// Clear out the list of suppressed diagnostics, so that we don't emit
// them again for this specialization. However, we don't obsolete this
// entry from the table, because we want to avoid ever emitting these
// diagnostics again.
Suppressed.clear();
}
+
+ // C++ [basic.start.main]p3:
+ // The function 'main' shall not be used within a program.
+ if (cast<FunctionDecl>(D)->isMain())
+ Diag(Loc, diag::ext_main_used);
}
// See if this is an auto-typed variable whose initializer we are parsing.
@@ -305,11 +302,11 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
// If the function has a deduced return type, and we can't deduce it,
// then we can't use it either.
- if (getLangOpts().CPlusPlus1y && FD->getResultType()->isUndeducedType() &&
+ if (getLangOpts().CPlusPlus1y && FD->getReturnType()->isUndeducedType() &&
DeduceReturnType(FD, Loc))
return true;
}
- DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass);
+ DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass, ObjCPropertyAccess);
DiagnoseUnusedOfDecl(*this, D, Loc);
@@ -354,7 +351,7 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
calleeType = CT_Function;
} else if (isa<VarDecl>(D)) {
QualType type = cast<ValueDecl>(D)->getType();
- const FunctionType *fn = 0;
+ const FunctionType *fn = nullptr;
if (const PointerType *ptr = type->getAs<PointerType>()) {
fn = ptr->getPointeeType()->getAs<FunctionType>();
if (!fn) return;
@@ -367,7 +364,7 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
}
if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fn)) {
- numFormalParams = proto->getNumArgs();
+ numFormalParams = proto->getNumParams();
} else {
numFormalParams = 0;
}
@@ -438,16 +435,22 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) {
if (E->getType()->isPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(E);
if (result.isInvalid()) return ExprError();
- E = result.take();
+ E = result.get();
}
QualType Ty = E->getType();
assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type");
- if (Ty->isFunctionType())
+ if (Ty->isFunctionType()) {
+ // If we are here, we are not calling a function but taking
+ // its address (which is not allowed in OpenCL v1.0 s6.8.a.3).
+ if (getLangOpts().OpenCL) {
+ Diag(E->getExprLoc(), diag::err_opencl_taking_function_address);
+ return ExprError();
+ }
E = ImpCastExprToType(E, Context.getPointerType(Ty),
- CK_FunctionToPointerDecay).take();
- else if (Ty->isArrayType()) {
+ CK_FunctionToPointerDecay).get();
+ } else if (Ty->isArrayType()) {
// In C90 mode, arrays only promote to pointers if the array expression is
// an lvalue. The relevant legalese is C90 6.2.2.1p3: "an lvalue that has
// type 'array of type' is converted to an expression that has type 'pointer
@@ -461,9 +464,9 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) {
//
if (getLangOpts().C99 || getLangOpts().CPlusPlus || E->isLValue())
E = ImpCastExprToType(E, Context.getArrayDecayedType(Ty),
- CK_ArrayToPointerDecay).take();
+ CK_ArrayToPointerDecay).get();
}
- return Owned(E);
+ return E;
}
static void CheckForNullPointerDereference(Sema &S, Expr *E) {
@@ -503,7 +506,7 @@ static void DiagnoseDirectIsaAccess(Sema &S, const ObjCIvarRefExpr *OIRE,
BaseType = BaseType->getPointeeType();
if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>())
if (ObjCInterfaceDecl *IDecl = OTy->getInterface()) {
- ObjCInterfaceDecl *ClassDeclared = 0;
+ ObjCInterfaceDecl *ClassDeclared = nullptr;
ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
if (!ClassDeclared->getSuperClass()
&& (*ClassDeclared->ivar_begin()) == IV) {
@@ -546,13 +549,13 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
if (E->getType()->isPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(E);
if (result.isInvalid()) return ExprError();
- E = result.take();
+ E = result.get();
}
// C++ [conv.lval]p1:
// A glvalue of a non-function, non-array type T can be
// converted to a prvalue.
- if (!E->isGLValue()) return Owned(E);
+ if (!E->isGLValue()) return E;
QualType T = E->getType();
assert(!T.isNull() && "r-value conversion on typeless expression?");
@@ -563,7 +566,7 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
(E->getType() == Context.OverloadTy ||
T->isDependentType() ||
T->isRecordType()))
- return Owned(E);
+ return E;
// The C standard is actually really unclear on this point, and
// DR106 tells us what the result should be but not why. It's
@@ -571,7 +574,7 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
// lvalue-to-rvalue at all. Note that expressions of unqualified
// 'void' type are never l-values, but qualified void can be.
if (T->isVoidType())
- return Owned(E);
+ return E;
// OpenCL usually rejects direct accesses to values of 'half' type.
if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp16 &&
@@ -596,8 +599,8 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
}
else if (const ObjCIvarRefExpr *OIRE =
dyn_cast<ObjCIvarRefExpr>(E->IgnoreParenCasts()))
- DiagnoseDirectIsaAccess(*this, OIRE, SourceLocation(), /* Expr*/0);
-
+ DiagnoseDirectIsaAccess(*this, OIRE, SourceLocation(), /* Expr*/nullptr);
+
// C++ [conv.lval]p1:
// [...] If T is a non-class type, the type of the prvalue is the
// cv-unqualified version of T. Otherwise, the type of the
@@ -618,16 +621,16 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
E->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
ExprNeedsCleanups = true;
- ExprResult Res = Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue,
- E, 0, VK_RValue));
+ ExprResult Res = ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, E,
+ nullptr, VK_RValue);
// C11 6.3.2.1p2:
// ... if the lvalue has atomic type, the value has the non-atomic version
// of the type of the lvalue ...
if (const AtomicType *Atomic = T->getAs<AtomicType>()) {
T = Atomic->getValueType().getUnqualifiedType();
- Res = Owned(ImplicitCastExpr::Create(Context, T, CK_AtomicToNonAtomic,
- Res.get(), 0, VK_RValue));
+ Res = ImplicitCastExpr::Create(Context, T, CK_AtomicToNonAtomic, Res.get(),
+ nullptr, VK_RValue);
}
return Res;
@@ -637,12 +640,30 @@ ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E) {
ExprResult Res = DefaultFunctionArrayConversion(E);
if (Res.isInvalid())
return ExprError();
- Res = DefaultLvalueConversion(Res.take());
+ Res = DefaultLvalueConversion(Res.get());
if (Res.isInvalid())
return ExprError();
return Res;
}
+/// CallExprUnaryConversions - a special case of an unary conversion
+/// performed on a function designator of a call expression.
+ExprResult Sema::CallExprUnaryConversions(Expr *E) {
+ QualType Ty = E->getType();
+ ExprResult Res = E;
+ // Only do implicit cast for a function type, but not for a pointer
+ // to function type.
+ if (Ty->isFunctionType()) {
+ Res = ImpCastExprToType(E, Context.getPointerType(Ty),
+ CK_FunctionToPointerDecay).get();
+ if (Res.isInvalid())
+ return ExprError();
+ }
+ Res = DefaultLvalueConversion(Res.get());
+ if (Res.isInvalid())
+ return ExprError();
+ return Res.get();
+}
/// UsualUnaryConversions - Performs various conversions that are common to most
/// operators (C99 6.3). The conversions of array and function types are
@@ -654,14 +675,14 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) {
ExprResult Res = DefaultFunctionArrayLvalueConversion(E);
if (Res.isInvalid())
return ExprError();
- E = Res.take();
+ E = Res.get();
QualType Ty = E->getType();
assert(!Ty.isNull() && "UsualUnaryConversions - missing type");
// Half FP have to be promoted to float unless it is natively supported
if (Ty->isHalfType() && !getLangOpts().NativeHalfType)
- return ImpCastExprToType(Res.take(), Context.FloatTy, CK_FloatingCast);
+ return ImpCastExprToType(Res.get(), Context.FloatTy, CK_FloatingCast);
// Try to perform integral promotions if the object has a theoretically
// promotable type.
@@ -682,16 +703,16 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) {
QualType PTy = Context.isPromotableBitField(E);
if (!PTy.isNull()) {
- E = ImpCastExprToType(E, PTy, CK_IntegralCast).take();
- return Owned(E);
+ E = ImpCastExprToType(E, PTy, CK_IntegralCast).get();
+ return E;
}
if (Ty->isPromotableIntegerType()) {
QualType PT = Context.getPromotedIntegerType(Ty);
- E = ImpCastExprToType(E, PT, CK_IntegralCast).take();
- return Owned(E);
+ E = ImpCastExprToType(E, PT, CK_IntegralCast).get();
+ return E;
}
}
- return Owned(E);
+ return E;
}
/// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that
@@ -705,14 +726,14 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
ExprResult Res = UsualUnaryConversions(E);
if (Res.isInvalid())
return ExprError();
- E = Res.take();
+ E = Res.get();
// If this is a 'float' or '__fp16' (CVR qualified or typedef) promote to
// double.
const BuiltinType *BTy = Ty->getAs<BuiltinType>();
if (BTy && (BTy->getKind() == BuiltinType::Half ||
BTy->getKind() == BuiltinType::Float))
- E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).take();
+ E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).get();
// C++ performs lvalue-to-rvalue conversion as a default argument
// promotion, even on class types, but note:
@@ -728,14 +749,13 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
if (getLangOpts().CPlusPlus && E->isGLValue() && !isUnevaluatedContext()) {
ExprResult Temp = PerformCopyInitialization(
InitializedEntity::InitializeTemporary(E->getType()),
- E->getExprLoc(),
- Owned(E));
+ E->getExprLoc(), E);
if (Temp.isInvalid())
return ExprError();
E = Temp.get();
}
- return Owned(E);
+ return E;
}
/// Determine the degree of POD-ness for an expression.
@@ -792,19 +812,25 @@ void Sema::checkVariadicArgument(const Expr *E, VariadicCallType CT) {
// Complain about passing non-POD types through varargs.
switch (VAK) {
- case VAK_Valid:
- break;
-
case VAK_ValidInCXX11:
DiagRuntimeBehavior(
- E->getLocStart(), 0,
+ E->getLocStart(), nullptr,
PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg)
- << E->getType() << CT);
+ << Ty << CT);
+ // Fall through.
+ case VAK_Valid:
+ if (Ty->isRecordType()) {
+ // This is unlikely to be what the user intended. If the class has a
+ // 'c_str' member function, the user probably meant to call that.
+ DiagRuntimeBehavior(E->getLocStart(), nullptr,
+ PDiag(diag::warn_pass_class_arg_to_vararg)
+ << Ty << CT << hasCStrMethod(E) << ".c_str()");
+ }
break;
case VAK_Undefined:
DiagRuntimeBehavior(
- E->getLocStart(), 0,
+ E->getLocStart(), nullptr,
PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
<< getLangOpts().CPlusPlus11 << Ty << CT);
break;
@@ -812,7 +838,7 @@ void Sema::checkVariadicArgument(const Expr *E, VariadicCallType CT) {
case VAK_Invalid:
if (Ty->isObjCObjectType())
DiagRuntimeBehavior(
- E->getLocStart(), 0,
+ E->getLocStart(), nullptr,
PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
<< Ty << CT);
else
@@ -838,14 +864,14 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
ExprResult ExprRes = CheckPlaceholderExpr(E);
if (ExprRes.isInvalid())
return ExprError();
- E = ExprRes.take();
+ E = ExprRes.get();
}
}
ExprResult ExprRes = DefaultArgumentPromotion(E);
if (ExprRes.isInvalid())
return ExprError();
- E = ExprRes.take();
+ E = ExprRes.get();
// Diagnostics regarding non-POD argument types are
// emitted along with format string checking in Sema::CheckFunctionCall().
@@ -879,7 +905,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
diag::err_call_incomplete_argument))
return ExprError();
- return Owned(E);
+ return E;
}
/// \brief Converts an integer to complex float type. Helper function of
@@ -896,12 +922,12 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr,
if (SkipCast) return false;
if (IntTy->isIntegerType()) {
QualType fpTy = cast<ComplexType>(ComplexTy)->getElementType();
- IntExpr = S.ImpCastExprToType(IntExpr.take(), fpTy, CK_IntegralToFloating);
- IntExpr = S.ImpCastExprToType(IntExpr.take(), ComplexTy,
+ IntExpr = S.ImpCastExprToType(IntExpr.get(), fpTy, CK_IntegralToFloating);
+ IntExpr = S.ImpCastExprToType(IntExpr.get(), ComplexTy,
CK_FloatingRealToComplex);
} else {
assert(IntTy->isComplexIntegerType());
- IntExpr = S.ImpCastExprToType(IntExpr.take(), ComplexTy,
+ IntExpr = S.ImpCastExprToType(IntExpr.get(), ComplexTy,
CK_IntegralComplexToFloatingComplex);
}
return false;
@@ -919,12 +945,12 @@ handleComplexFloatToComplexFloatConverstion(Sema &S, ExprResult &LHS,
if (order < 0) {
// _Complex float -> _Complex double
if (!IsCompAssign)
- LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_FloatingComplexCast);
+ LHS = S.ImpCastExprToType(LHS.get(), RHSType, CK_FloatingComplexCast);
return RHSType;
}
if (order > 0)
// _Complex float -> _Complex double
- RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_FloatingComplexCast);
+ RHS = S.ImpCastExprToType(RHS.get(), LHSType, CK_FloatingComplexCast);
return LHSType;
}
@@ -945,8 +971,8 @@ static QualType handleOtherComplexFloatConversion(Sema &S,
// float -> _Complex double
if (ConvertOtherExpr) {
QualType fp = cast<ComplexType>(ComplexTy)->getElementType();
- OtherExpr = S.ImpCastExprToType(OtherExpr.take(), fp, CK_FloatingCast);
- OtherExpr = S.ImpCastExprToType(OtherExpr.take(), ComplexTy,
+ OtherExpr = S.ImpCastExprToType(OtherExpr.get(), fp, CK_FloatingCast);
+ OtherExpr = S.ImpCastExprToType(OtherExpr.get(), ComplexTy,
CK_FloatingRealToComplex);
}
return ComplexTy;
@@ -958,12 +984,12 @@ static QualType handleOtherComplexFloatConversion(Sema &S,
// double -> _Complex double
if (ConvertOtherExpr)
- OtherExpr = S.ImpCastExprToType(OtherExpr.take(), result,
+ OtherExpr = S.ImpCastExprToType(OtherExpr.get(), result,
CK_FloatingRealToComplex);
// _Complex float -> _Complex double
if (ConvertComplexExpr && order < 0)
- ComplexExpr = S.ImpCastExprToType(ComplexExpr.take(), result,
+ ComplexExpr = S.ImpCastExprToType(ComplexExpr.get(), result,
CK_FloatingComplexCast);
return result;
@@ -1025,7 +1051,7 @@ static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr,
if (IntTy->isIntegerType()) {
if (ConvertInt)
// Convert intExpr to the lhs floating point type.
- IntExpr = S.ImpCastExprToType(IntExpr.take(), FloatTy,
+ IntExpr = S.ImpCastExprToType(IntExpr.get(), FloatTy,
CK_IntegralToFloating);
return FloatTy;
}
@@ -1036,12 +1062,12 @@ static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr,
// _Complex int -> _Complex float
if (ConvertInt)
- IntExpr = S.ImpCastExprToType(IntExpr.take(), result,
+ IntExpr = S.ImpCastExprToType(IntExpr.get(), result,
CK_IntegralComplexToFloatingComplex);
// float -> _Complex float
if (ConvertFloat)
- FloatExpr = S.ImpCastExprToType(FloatExpr.take(), result,
+ FloatExpr = S.ImpCastExprToType(FloatExpr.get(), result,
CK_FloatingRealToComplex);
return result;
@@ -1060,13 +1086,13 @@ static QualType handleFloatConversion(Sema &S, ExprResult &LHS,
if (LHSFloat && RHSFloat) {
int order = S.Context.getFloatingTypeOrder(LHSType, RHSType);
if (order > 0) {
- RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_FloatingCast);
+ RHS = S.ImpCastExprToType(RHS.get(), LHSType, CK_FloatingCast);
return LHSType;
}
assert(order < 0 && "illegal float comparison");
if (!IsCompAssign)
- LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_FloatingCast);
+ LHS = S.ImpCastExprToType(LHS.get(), RHSType, CK_FloatingCast);
return RHSType;
}
@@ -1108,29 +1134,29 @@ static QualType handleIntegerConversion(Sema &S, ExprResult &LHS,
if (LHSSigned == RHSSigned) {
// Same signedness; use the higher-ranked type
if (order >= 0) {
- RHS = (*doRHSCast)(S, RHS.take(), LHSType);
+ RHS = (*doRHSCast)(S, RHS.get(), LHSType);
return LHSType;
} else if (!IsCompAssign)
- LHS = (*doLHSCast)(S, LHS.take(), RHSType);
+ LHS = (*doLHSCast)(S, LHS.get(), RHSType);
return RHSType;
} else if (order != (LHSSigned ? 1 : -1)) {
// The unsigned type has greater than or equal rank to the
// signed type, so use the unsigned type
if (RHSSigned) {
- RHS = (*doRHSCast)(S, RHS.take(), LHSType);
+ RHS = (*doRHSCast)(S, RHS.get(), LHSType);
return LHSType;
} else if (!IsCompAssign)
- LHS = (*doLHSCast)(S, LHS.take(), RHSType);
+ LHS = (*doLHSCast)(S, LHS.get(), RHSType);
return RHSType;
} else if (S.Context.getIntWidth(LHSType) != S.Context.getIntWidth(RHSType)) {
// The two types are different widths; if we are here, that
// means the signed type is larger than the unsigned type, so
// use the signed type.
if (LHSSigned) {
- RHS = (*doRHSCast)(S, RHS.take(), LHSType);
+ RHS = (*doRHSCast)(S, RHS.get(), LHSType);
return LHSType;
} else if (!IsCompAssign)
- LHS = (*doLHSCast)(S, LHS.take(), RHSType);
+ LHS = (*doLHSCast)(S, LHS.get(), RHSType);
return RHSType;
} else {
// The signed type is higher-ranked than the unsigned type,
@@ -1139,9 +1165,9 @@ static QualType handleIntegerConversion(Sema &S, ExprResult &LHS,
// to the signed type.
QualType result =
S.Context.getCorrespondingUnsignedType(LHSSigned ? LHSType : RHSType);
- RHS = (*doRHSCast)(S, RHS.take(), result);
+ RHS = (*doRHSCast)(S, RHS.get(), result);
if (!IsCompAssign)
- LHS = (*doLHSCast)(S, LHS.take(), result);
+ LHS = (*doLHSCast)(S, LHS.get(), result);
return result;
}
}
@@ -1171,7 +1197,7 @@ static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS,
handleIntegerConversion<doComplexIntegralCast, doIntegralCast>
(S, LHS, RHS, LHSEltType, RHSType, IsCompAssign);
QualType ComplexType = S.Context.getComplexType(ScalarType);
- RHS = S.ImpCastExprToType(RHS.take(), ComplexType,
+ RHS = S.ImpCastExprToType(RHS.get(), ComplexType,
CK_IntegralRealToComplex);
return ComplexType;
@@ -1186,7 +1212,7 @@ static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS,
QualType ComplexType = S.Context.getComplexType(ScalarType);
if (!IsCompAssign)
- LHS = S.ImpCastExprToType(LHS.take(), ComplexType,
+ LHS = S.ImpCastExprToType(LHS.get(), ComplexType,
CK_IntegralRealToComplex);
return ComplexType;
}
@@ -1198,12 +1224,12 @@ static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS,
QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
bool IsCompAssign) {
if (!IsCompAssign) {
- LHS = UsualUnaryConversions(LHS.take());
+ LHS = UsualUnaryConversions(LHS.get());
if (LHS.isInvalid())
return QualType();
}
- RHS = UsualUnaryConversions(RHS.take());
+ RHS = UsualUnaryConversions(RHS.get());
if (RHS.isInvalid())
return QualType();
@@ -1235,7 +1261,7 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
if (!LHSBitfieldPromoteTy.isNull())
LHSType = LHSBitfieldPromoteTy;
if (LHSType != LHSUnpromotedType && !IsCompAssign)
- LHS = ImpCastExprToType(LHS.take(), LHSType, CK_IntegralCast);
+ LHS = ImpCastExprToType(LHS.get(), LHSType, CK_IntegralCast);
// If both types are identical, no conversion is needed.
if (LHSType == RHSType)
@@ -1284,7 +1310,7 @@ Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc,
if (ArgTypes[i])
(void) GetTypeFromParser(ArgTypes[i], &Types[i]);
else
- Types[i] = 0;
+ Types[i] = nullptr;
}
ExprResult ER = CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc,
@@ -1307,7 +1333,7 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
if (ControllingExpr->getType()->isPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(ControllingExpr);
if (result.isInvalid()) return ExprError();
- ControllingExpr = result.take();
+ ControllingExpr = result.get();
}
bool TypeErrorFound = false,
@@ -1369,10 +1395,9 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
// If we determined that the generic selection is result-dependent, don't
// try to compute the result expression.
if (IsResultDependent)
- return Owned(new (Context) GenericSelectionExpr(
- Context, KeyLoc, ControllingExpr,
- Types, Exprs,
- DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack));
+ return new (Context) GenericSelectionExpr(
+ Context, KeyLoc, ControllingExpr, Types, Exprs, DefaultLoc, RParenLoc,
+ ContainsUnexpandedParameterPack);
SmallVector<unsigned, 1> CompatIndices;
unsigned DefaultIndex = -1U;
@@ -1424,11 +1449,9 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
unsigned ResultIndex =
CompatIndices.size() ? CompatIndices[0] : DefaultIndex;
- return Owned(new (Context) GenericSelectionExpr(
- Context, KeyLoc, ControllingExpr,
- Types, Exprs,
- DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack,
- ResultIndex));
+ return new (Context) GenericSelectionExpr(
+ Context, KeyLoc, ControllingExpr, Types, Exprs, DefaultLoc, RParenLoc,
+ ContainsUnexpandedParameterPack, ResultIndex);
}
/// getUDSuffixLoc - Create a SourceLocation for a ud-suffix, given the
@@ -1476,16 +1499,15 @@ static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope,
/// string.
///
ExprResult
-Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks,
- Scope *UDLScope) {
- assert(NumStringToks && "Must have at least one string!");
+Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
+ assert(!StringToks.empty() && "Must have at least one string!");
- StringLiteralParser Literal(StringToks, NumStringToks, PP);
+ StringLiteralParser Literal(StringToks, PP);
if (Literal.hadError)
return ExprError();
SmallVector<SourceLocation, 4> StringTokLocs;
- for (unsigned i = 0; i != NumStringToks; ++i)
+ for (unsigned i = 0; i != StringToks.size(); ++i)
StringTokLocs.push_back(StringToks[i].getLocation());
QualType CharTy = Context.CharTy;
@@ -1528,7 +1550,7 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks,
&StringTokLocs[0],
StringTokLocs.size());
if (Literal.getUDSuffix().empty())
- return Owned(Lit);
+ return Lit;
// We're building a user-defined literal.
IdentifierInfo *UDSuffix = &Context.Idents.get(Literal.getUDSuffix());
@@ -1643,7 +1665,7 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
NameInfo.getLoc(), Ty, VK, FoundD, TemplateArgs);
} else {
assert(!TemplateArgs && "No template arguments for non-variable"
- " template specialization referrences");
+ " template specialization references");
E = DeclRefExpr::Create(
Context,
SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(),
@@ -1653,20 +1675,16 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
MarkDeclRefReferenced(E);
if (getLangOpts().ObjCARCWeak && isa<VarDecl>(D) &&
- Ty.getObjCLifetime() == Qualifiers::OCL_Weak) {
- DiagnosticsEngine::Level Level =
- Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
- E->getLocStart());
- if (Level != DiagnosticsEngine::Ignored)
+ Ty.getObjCLifetime() == Qualifiers::OCL_Weak &&
+ !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getLocStart()))
recordUseOfEvaluatedWeak(E);
- }
// Just in case we're building an illegal pointer-to-member.
FieldDecl *FD = dyn_cast<FieldDecl>(D);
if (FD && FD->isBitField())
E->setObjectKind(OK_BitField);
- return Owned(E);
+ return E;
}
/// Decomposes the given name into a DeclarationNameInfo, its location, and
@@ -1697,7 +1715,7 @@ Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
TemplateArgs = &Buffer;
} else {
NameInfo = GetNameFromUnqualifiedId(Id);
- TemplateArgs = 0;
+ TemplateArgs = nullptr;
}
}
@@ -1724,7 +1742,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// original lookup would not have found something because it was a
// dependent name.
DeclContext *DC = (SS.isEmpty() && !CallsUndergoingInstantiation.empty())
- ? CurContext : 0;
+ ? CurContext : nullptr;
while (DC) {
if (isa<CXXRecordDecl>(DC)) {
LookupQualifiedName(R, DC);
@@ -1748,8 +1766,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// Give a code modification hint to insert 'this->'.
// TODO: fixit for inserting 'Base<T>::' in the other cases.
// Actually quite difficult!
- if (getLangOpts().MicrosoftMode)
- diagnostic = diag::warn_found_via_dependent_bases_lookup;
+ if (getLangOpts().MSVCCompat)
+ diagnostic = diag::ext_found_via_dependent_bases_lookup;
if (isInstance) {
Diag(R.getNameLoc(), diagnostic) << Name
<< FixItHint::CreateInsertion(R.getNameLoc(), "this->");
@@ -1782,9 +1800,9 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
CXXDependentScopeMemberExpr::Create(
Context, DepThis, DepThisType, true, SourceLocation(),
SS.getWithLocInContext(Context),
- ULE->getTemplateKeywordLoc(), 0,
+ ULE->getTemplateKeywordLoc(), nullptr,
R.getLookupNameInfo(),
- ULE->hasExplicitTemplateArgs() ? &TList : 0);
+ ULE->hasExplicitTemplateArgs() ? &TList : nullptr);
CallsUndergoingInstantiation.back()->setCallee(DepExpr);
} else {
Diag(R.getNameLoc(), diagnostic) << Name;
@@ -1814,7 +1832,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// function definition declared at class scope then we must set
// DC to the lexical parent to be able to search into the parent
// class.
- if (getLangOpts().MicrosoftMode && isa<FunctionDecl>(DC) &&
+ if (getLangOpts().MSVCCompat && isa<FunctionDecl>(DC) &&
cast<FunctionDecl>(DC)->getFriendObjectKind() &&
DC->getLexicalParent()->isRecord())
DC = DC->getLexicalParent();
@@ -1825,7 +1843,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// We didn't find anything, so try to correct for a typo.
TypoCorrection Corrected;
if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(),
- S, &SS, CCC))) {
+ S, &SS, CCC, CTK_ErrorRecovery))) {
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
bool DroppedSpecifier =
Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr;
@@ -1836,7 +1854,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
NamedDecl *ND = Corrected.getCorrectionDecl();
if (ND) {
if (Corrected.isOverloaded()) {
- OverloadCandidateSet OCS(R.getNameLoc());
+ OverloadCandidateSet OCS(R.getNameLoc(),
+ OverloadCandidateSet::CSK_Normal);
OverloadCandidateSet::iterator Best;
for (TypoCorrection::decl_iterator CD = Corrected.begin(),
CDEnd = Corrected.end();
@@ -1863,6 +1882,17 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
}
}
R.addDecl(ND);
+ if (getLangOpts().CPlusPlus && ND->isCXXClassMember()) {
+ CXXRecordDecl *Record = nullptr;
+ if (Corrected.getCorrectionSpecifier()) {
+ const Type *Ty = Corrected.getCorrectionSpecifier()->getAsType();
+ Record = Ty->getAsCXXRecordDecl();
+ }
+ if (!Record)
+ Record = cast<CXXRecordDecl>(
+ ND->getDeclContext()->getRedeclContext());
+ R.setNamingClass(Record);
+ }
AcceptableWithRecovery =
isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND);
@@ -1913,6 +1943,53 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
return true;
}
+/// In Microsoft mode, if we are inside a template class whose parent class has
+/// dependent base classes, and we can't resolve an unqualified identifier, then
+/// assume the identifier is a member of a dependent base class. We can only
+/// recover successfully in static methods, instance methods, and other contexts
+/// where 'this' is available. This doesn't precisely match MSVC's
+/// instantiation model, but it's close enough.
+static Expr *
+recoverFromMSUnqualifiedLookup(Sema &S, ASTContext &Context,
+ DeclarationNameInfo &NameInfo,
+ SourceLocation TemplateKWLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ // Only try to recover from lookup into dependent bases in static methods or
+ // contexts where 'this' is available.
+ QualType ThisType = S.getCurrentThisType();
+ const CXXRecordDecl *RD = nullptr;
+ if (!ThisType.isNull())
+ RD = ThisType->getPointeeType()->getAsCXXRecordDecl();
+ else if (auto *MD = dyn_cast<CXXMethodDecl>(S.CurContext))
+ RD = MD->getParent();
+ if (!RD || !RD->hasAnyDependentBases())
+ return nullptr;
+
+ // Diagnose this as unqualified lookup into a dependent base class. If 'this'
+ // is available, suggest inserting 'this->' as a fixit.
+ SourceLocation Loc = NameInfo.getLoc();
+ auto DB = S.Diag(Loc, diag::ext_undeclared_unqual_id_with_dependent_base);
+ DB << NameInfo.getName() << RD;
+
+ if (!ThisType.isNull()) {
+ DB << FixItHint::CreateInsertion(Loc, "this->");
+ return CXXDependentScopeMemberExpr::Create(
+ Context, /*This=*/nullptr, ThisType, /*IsArrow=*/true,
+ /*Op=*/SourceLocation(), NestedNameSpecifierLoc(), TemplateKWLoc,
+ /*FirstQualifierInScope=*/nullptr, NameInfo, TemplateArgs);
+ }
+
+ // Synthesize a fake NNS that points to the derived class. This will
+ // perform name lookup during template instantiation.
+ CXXScopeSpec SS;
+ auto *NNS =
+ NestedNameSpecifier::Create(Context, nullptr, true, RD->getTypeForDecl());
+ SS.MakeTrivial(Context, NNS, SourceRange(Loc, Loc));
+ return DependentScopeDeclRefExpr::Create(
+ Context, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo,
+ TemplateArgs);
+}
+
ExprResult Sema::ActOnIdExpression(Scope *S,
CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
@@ -2000,77 +2077,59 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
if (E.isInvalid())
return ExprError();
- if (Expr *Ex = E.takeAs<Expr>())
- return Owned(Ex);
+ if (Expr *Ex = E.getAs<Expr>())
+ return Ex;
}
}
if (R.isAmbiguous())
return ExprError();
+ // This could be an implicitly declared function reference (legal in C90,
+ // extension in C99, forbidden in C++).
+ if (R.empty() && HasTrailingLParen && II && !getLangOpts().CPlusPlus) {
+ NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *II, S);
+ if (D) R.addDecl(D);
+ }
+
// Determine whether this name might be a candidate for
// argument-dependent lookup.
bool ADL = UseArgumentDependentLookup(SS, R, HasTrailingLParen);
if (R.empty() && !ADL) {
-
- // Otherwise, this could be an implicitly declared function reference (legal
- // in C90, extension in C99, forbidden in C++).
- if (HasTrailingLParen && II && !getLangOpts().CPlusPlus) {
- NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *II, S);
- if (D) R.addDecl(D);
+ if (SS.isEmpty() && getLangOpts().MSVCCompat) {
+ if (Expr *E = recoverFromMSUnqualifiedLookup(*this, Context, NameInfo,
+ TemplateKWLoc, TemplateArgs))
+ return E;
}
+ // Don't diagnose an empty lookup for inline assembly.
+ if (IsInlineAsmIdentifier)
+ return ExprError();
+
// If this name wasn't predeclared and if this is not a function
// call, diagnose the problem.
- if (R.empty()) {
- // In Microsoft mode, if we are inside a template class member function
- // whose parent class has dependent base classes, and we can't resolve
- // an identifier, then assume the identifier is a member of a dependent
- // base class. The goal is to postpone name lookup to instantiation time
- // to be able to search into the type dependent base classes.
- // FIXME: If we want 100% compatibility with MSVC, we will have delay all
- // unqualified name lookup. Any name lookup during template parsing means
- // clang might find something that MSVC doesn't. For now, we only handle
- // the common case of members of a dependent base class.
- if (getLangOpts().MicrosoftMode) {
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext);
- if (MD && MD->isInstance() && MD->getParent()->hasAnyDependentBases()) {
- assert(SS.isEmpty() && "qualifiers should be already handled");
- QualType ThisType = MD->getThisType(Context);
- // Since the 'this' expression is synthesized, we don't need to
- // perform the double-lookup check.
- NamedDecl *FirstQualifierInScope = 0;
- return Owned(CXXDependentScopeMemberExpr::Create(
- Context, /*This=*/0, ThisType, /*IsArrow=*/true,
- /*Op=*/SourceLocation(), SS.getWithLocInContext(Context),
- TemplateKWLoc, FirstQualifierInScope, NameInfo, TemplateArgs));
- }
- }
+ CorrectionCandidateCallback DefaultValidator;
+ DefaultValidator.IsAddressOfOperand = IsAddressOfOperand;
+ assert((!CCC || CCC->IsAddressOfOperand == IsAddressOfOperand) &&
+ "Typo correction callback misconfigured");
+ if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator))
+ return ExprError();
- // Don't diagnose an empty lookup for inline assmebly.
- if (IsInlineAsmIdentifier)
- return ExprError();
+ assert(!R.empty() &&
+ "DiagnoseEmptyLookup returned false but added no results");
- CorrectionCandidateCallback DefaultValidator;
- if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator))
+ // If we found an Objective-C instance variable, let
+ // LookupInObjCMethod build the appropriate expression to
+ // reference the ivar.
+ if (ObjCIvarDecl *Ivar = R.getAsSingle<ObjCIvarDecl>()) {
+ R.clear();
+ ExprResult E(LookupInObjCMethod(R, S, Ivar->getIdentifier()));
+ // In a hopelessly buggy code, Objective-C instance variable
+ // lookup fails and no expression will be built to reference it.
+ if (!E.isInvalid() && !E.get())
return ExprError();
-
- assert(!R.empty() &&
- "DiagnoseEmptyLookup returned false but added no results");
-
- // If we found an Objective-C instance variable, let
- // LookupInObjCMethod build the appropriate expression to
- // reference the ivar.
- if (ObjCIvarDecl *Ivar = R.getAsSingle<ObjCIvarDecl>()) {
- R.clear();
- ExprResult E(LookupInObjCMethod(R, S, Ivar->getIdentifier()));
- // In a hopelessly buggy code, Objective-C instance variable
- // lookup fails and no expression will be built to reference it.
- if (!E.isInvalid() && !E.get())
- return ExprError();
- return E;
- }
+ return E;
}
}
@@ -2145,11 +2204,12 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
ExprResult
Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
const DeclarationNameInfo &NameInfo,
- bool IsAddressOfOperand) {
+ bool IsAddressOfOperand,
+ TypeSourceInfo **RecoveryTSI) {
DeclContext *DC = computeDeclContext(SS, false);
if (!DC)
return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
- NameInfo, /*TemplateArgs=*/0);
+ NameInfo, /*TemplateArgs=*/nullptr);
if (RequireCompleteDeclContext(SS, DC))
return ExprError();
@@ -2162,7 +2222,7 @@ Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)
return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
- NameInfo, /*TemplateArgs=*/0);
+ NameInfo, /*TemplateArgs=*/nullptr);
if (R.empty()) {
Diag(NameInfo.getLoc(), diag::err_no_member)
@@ -2170,6 +2230,41 @@ Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
return ExprError();
}
+ if (const TypeDecl *TD = R.getAsSingle<TypeDecl>()) {
+ // Diagnose a missing typename if this resolved unambiguously to a type in
+ // a dependent context. If we can recover with a type, downgrade this to
+ // a warning in Microsoft compatibility mode.
+ unsigned DiagID = diag::err_typename_missing;
+ if (RecoveryTSI && getLangOpts().MSVCCompat)
+ DiagID = diag::ext_typename_missing;
+ SourceLocation Loc = SS.getBeginLoc();
+ auto D = Diag(Loc, DiagID);
+ D << SS.getScopeRep() << NameInfo.getName().getAsString()
+ << SourceRange(Loc, NameInfo.getEndLoc());
+
+ // Don't recover if the caller isn't expecting us to or if we're in a SFINAE
+ // context.
+ if (!RecoveryTSI)
+ return ExprError();
+
+ // Only issue the fixit if we're prepared to recover.
+ D << FixItHint::CreateInsertion(Loc, "typename ");
+
+ // Recover by pretending this was an elaborated type.
+ QualType Ty = Context.getTypeDeclType(TD);
+ TypeLocBuilder TLB;
+ TLB.pushTypeSpec(Ty).setNameLoc(NameInfo.getLoc());
+
+ QualType ET = getElaboratedType(ETK_None, SS, Ty);
+ ElaboratedTypeLoc QTL = TLB.push<ElaboratedTypeLoc>(ET);
+ QTL.setElaboratedKeywordLoc(SourceLocation());
+ QTL.setQualifierLoc(SS.getWithLocInContext(Context));
+
+ *RecoveryTSI = TLB.getTypeSourceInfo(Context, ET);
+
+ return ExprEmpty();
+ }
+
// Defend against this resolving to an implicit member access. We usually
// won't get here if this might be a legitimate a class member (we end up in
// BuildMemberReferenceExpr instead), but this can be valid if we're forming
@@ -2177,7 +2272,7 @@ Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
if (!R.empty() && (*R.begin())->isCXXClassMember() && !IsAddressOfOperand)
return BuildPossibleImplicitMemberExpr(SS,
/*TemplateKWLoc=*/SourceLocation(),
- R, /*TemplateArgs=*/0);
+ R, /*TemplateArgs=*/nullptr);
return BuildDeclarationNameExpr(SS, R, /* ADL */ false);
}
@@ -2219,11 +2314,11 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
else
LookForIvars = (Lookup.isSingleResult() &&
Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod());
- ObjCInterfaceDecl *IFace = 0;
+ ObjCInterfaceDecl *IFace = nullptr;
if (LookForIvars) {
IFace = CurMethod->getClassInterface();
ObjCInterfaceDecl *ClassDeclared;
- ObjCIvarDecl *IV = 0;
+ ObjCIvarDecl *IV = nullptr;
if (IFace && (IV = IFace->lookupInstanceVariable(II, ClassDeclared))) {
// Diagnose using an ivar in a class method.
if (IsClassMethod)
@@ -2258,20 +2353,12 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
if (SelfExpr.isInvalid())
return ExprError();
- SelfExpr = DefaultLvalueConversion(SelfExpr.take());
+ SelfExpr = DefaultLvalueConversion(SelfExpr.get());
if (SelfExpr.isInvalid())
return ExprError();
MarkAnyDeclReferenced(Loc, IV, true);
- if (!IV->getBackingIvarReferencedInAccessor()) {
- // Mark this ivar 'referenced' in this method, if it is a backing ivar
- // of a property and current method is one of its property accessor.
- const ObjCPropertyDecl *PDecl;
- const ObjCIvarDecl *BIV = GetIvarBackingPropertyAccessor(CurMethod, PDecl);
- if (BIV && BIV == IV)
- IV->setBackingIvarReferencedInAccessor(true);
- }
-
+
ObjCMethodFamily MF = CurMethod->getMethodFamily();
if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize &&
!IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV))
@@ -2279,14 +2366,12 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(),
Loc, IV->getLocation(),
- SelfExpr.take(),
+ SelfExpr.get(),
true, true);
if (getLangOpts().ObjCAutoRefCount) {
if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
- DiagnosticsEngine::Level Level =
- Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, Loc);
- if (Level != DiagnosticsEngine::Ignored)
+ if (!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
recordUseOfEvaluatedWeak(Result);
}
if (CurContext->isClosure())
@@ -2294,7 +2379,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
<< FixItHint::CreateInsertion(Loc, "self->");
}
- return Owned(Result);
+ return Result;
}
} else if (CurMethod->isInstanceMethod()) {
// We should warn if a local variable hides an ivar.
@@ -2327,7 +2412,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
}
}
// Sentinel value saying that we didn't do anything special.
- return Owned((Expr*) 0);
+ return ExprResult((Expr *)nullptr);
}
/// \brief Cast a base object to a member's actual type.
@@ -2354,7 +2439,7 @@ Sema::PerformObjectMemberConversion(Expr *From,
NamedDecl *Member) {
CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Member->getDeclContext());
if (!RD)
- return Owned(From);
+ return From;
QualType DestRecordType;
QualType DestType;
@@ -2374,7 +2459,7 @@ Sema::PerformObjectMemberConversion(Expr *From,
}
} else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member)) {
if (Method->isStatic())
- return Owned(From);
+ return From;
DestType = Method->getThisType(Context);
DestRecordType = DestType->getPointeeType();
@@ -2388,15 +2473,15 @@ Sema::PerformObjectMemberConversion(Expr *From,
}
} else {
// No conversion necessary.
- return Owned(From);
+ return From;
}
if (DestType->isDependentType() || FromType->isDependentType())
- return Owned(From);
+ return From;
// If the unqualified types are the same, no conversion is necessary.
if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType))
- return Owned(From);
+ return From;
SourceRange FromRange = From->getSourceRange();
SourceLocation FromLoc = FromRange.getBegin();
@@ -2439,7 +2524,7 @@ Sema::PerformObjectMemberConversion(Expr *From,
if (PointerConversions)
QType = Context.getPointerType(QType);
From = ImpCastExprToType(From, QType, CK_UncheckedDerivedToBase,
- VK, &BasePath).take();
+ VK, &BasePath).get();
FromType = QType;
FromRecordType = QRecordType;
@@ -2447,7 +2532,7 @@ Sema::PerformObjectMemberConversion(Expr *From,
// If the qualifier type was the same as the destination type,
// we're done.
if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType))
- return Owned(From);
+ return From;
}
}
@@ -2476,7 +2561,7 @@ Sema::PerformObjectMemberConversion(Expr *From,
if (PointerConversions)
UType = Context.getPointerType(UType);
From = ImpCastExprToType(From, UType, CK_UncheckedDerivedToBase,
- VK, &BasePath).take();
+ VK, &BasePath).get();
FromType = UType;
FromRecordType = URecordType;
}
@@ -2604,7 +2689,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
NeedsADL, R.isOverloadedResult(),
R.begin(), R.end());
- return Owned(ULE);
+ return ULE;
}
/// \brief Complete semantic analysis for a reference to the given declaration.
@@ -2755,7 +2840,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
// If we're referring to a function with an __unknown_anytype
// result type, make the entire expression __unknown_anytype.
- if (fty->getResultType() == Context.UnknownAnyTy) {
+ if (fty->getReturnType() == Context.UnknownAnyTy) {
type = Context.UnknownAnyTy;
valueKind = VK_RValue;
break;
@@ -2774,7 +2859,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
// type.
if (!cast<FunctionDecl>(VD)->hasPrototype() &&
isa<FunctionProtoType>(fty))
- type = Context.getFunctionNoProtoType(fty->getResultType(),
+ type = Context.getFunctionNoProtoType(fty->getReturnType(),
fty->getExtInfo());
// Functions are r-values in C.
@@ -2792,7 +2877,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
// This should only be possible with a type written directly.
if (const FunctionProtoType *proto
= dyn_cast<FunctionProtoType>(VD->getType()))
- if (proto->getResultType() == Context.UnknownAnyTy) {
+ if (proto->getReturnType() == Context.UnknownAnyTy) {
type = Context.UnknownAnyTy;
valueKind = VK_RValue;
break;
@@ -2820,7 +2905,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
PredefinedExpr::IdentType IT) {
// Pick the current block, lambda, captured statement or function.
- Decl *currentDecl = 0;
+ Decl *currentDecl = nullptr;
if (const BlockScopeInfo *BSI = getCurBlock())
currentDecl = BSI->TheDecl;
else if (const LambdaScopeInfo *LSI = getCurLambda())
@@ -2851,7 +2936,7 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
}
- return Owned(new (Context) PredefinedExpr(Loc, ResTy, IT));
+ return new (Context) PredefinedExpr(Loc, ResTy, IT);
}
ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
@@ -2862,6 +2947,7 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
case tok::kw___func__: IT = PredefinedExpr::Func; break; // [C99 6.4.2.2]
case tok::kw___FUNCTION__: IT = PredefinedExpr::Function; break;
case tok::kw___FUNCDNAME__: IT = PredefinedExpr::FuncDName; break; // [MS]
+ case tok::kw___FUNCSIG__: IT = PredefinedExpr::FuncSig; break; // [MS]
case tok::kw_L__FUNCTION__: IT = PredefinedExpr::LFunction; break;
case tok::kw___PRETTY_FUNCTION__: IT = PredefinedExpr::PrettyFunction; break;
}
@@ -2905,7 +2991,7 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) {
Tok.getLocation());
if (Literal.getUDSuffix().empty())
- return Owned(Lit);
+ return Lit;
// We're building a user-defined literal.
IdentifierInfo *UDSuffix = &Context.Idents.get(Literal.getUDSuffix());
@@ -2924,8 +3010,8 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) {
ExprResult Sema::ActOnIntegerConstant(SourceLocation Loc, uint64_t Val) {
unsigned IntSize = Context.getTargetInfo().getIntWidth();
- return Owned(IntegerLiteral::Create(Context, llvm::APInt(IntSize, Val),
- Context.IntTy, Loc));
+ return IntegerLiteral::Create(Context, llvm::APInt(IntSize, Val),
+ Context.IntTy, Loc);
}
static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal,
@@ -3090,10 +3176,10 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
if (Ty == Context.DoubleTy) {
if (getLangOpts().SinglePrecisionConstants) {
- Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).take();
+ Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).get();
} else if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp64) {
Diag(Tok.getLocation(), diag::warn_double_const_requires_fp64);
- Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).take();
+ Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).get();
}
}
} else if (!Literal.isIntegerLiteral()) {
@@ -3117,8 +3203,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
// may be wider than [u]intmax_t.
// FIXME: Actually, they don't. We seem to have accidentally invented the
// i128 suffix.
- if (Literal.isMicrosoftInteger && MaxWidth < 128 &&
- PP.getTargetInfo().hasInt128Type())
+ if (Literal.MicrosoftInteger == 128 && MaxWidth < 128 &&
+ Context.getTargetInfo().hasInt128Type())
MaxWidth = 128;
llvm::APInt ResultVal(MaxWidth, 0);
@@ -3138,7 +3224,22 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
// Check from smallest to largest, picking the smallest type we can.
unsigned Width = 0;
- if (!Literal.isLong && !Literal.isLongLong) {
+
+ // Microsoft specific integer suffixes are explicitly sized.
+ if (Literal.MicrosoftInteger) {
+ if (Literal.MicrosoftInteger > MaxWidth) {
+ // If this target doesn't support __int128, error and force to ull.
+ Diag(Tok.getLocation(), diag::err_int128_unsupported);
+ Width = MaxWidth;
+ Ty = Context.getIntMaxType();
+ } else {
+ Width = Literal.MicrosoftInteger;
+ Ty = Context.getIntTypeForBitwidth(Width,
+ /*Signed=*/!Literal.isUnsigned);
+ }
+ }
+
+ if (Ty.isNull() && !Literal.isLong && !Literal.isLongLong) {
// Are int/unsigned possibilities?
unsigned IntSize = Context.getTargetInfo().getIntWidth();
@@ -3185,22 +3286,11 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
Width = LongLongSize;
}
}
-
- // If it doesn't fit in unsigned long long, and we're using Microsoft
- // extensions, then its a 128-bit integer literal.
- if (Ty.isNull() && Literal.isMicrosoftInteger &&
- PP.getTargetInfo().hasInt128Type()) {
- if (Literal.isUnsigned)
- Ty = Context.UnsignedInt128Ty;
- else
- Ty = Context.Int128Ty;
- Width = 128;
- }
// If we still couldn't decide a type, we probably have something that
// does not fit in a signed long long, but has no U suffix.
if (Ty.isNull()) {
- Diag(Tok.getLocation(), diag::warn_integer_too_large_for_signed);
+ Diag(Tok.getLocation(), diag::ext_integer_too_large_for_signed);
Ty = Context.UnsignedLongLongTy;
Width = Context.getTargetInfo().getLongLongWidth();
}
@@ -3216,12 +3306,12 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
Res = new (Context) ImaginaryLiteral(Res,
Context.getComplexType(Res->getType()));
- return Owned(Res);
+ return Res;
}
ExprResult Sema::ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E) {
- assert((E != 0) && "ActOnParenExpr() missing expr");
- return Owned(new (Context) ParenExpr(L, R, E));
+ assert(E && "ActOnParenExpr() missing expr");
+ return new (Context) ParenExpr(L, R, E);
}
static bool CheckVecStepTraitOperandType(Sema &S, QualType T,
@@ -3259,9 +3349,12 @@ static bool CheckExtensionTraitOperandType(Sema &S, QualType T,
return false;
}
- // Allow sizeof(void)/alignof(void) as an extension.
+ // Allow sizeof(void)/alignof(void) as an extension, unless in OpenCL where
+ // this is an error (OpenCL v1.1 s6.3.k)
if (T->isVoidType()) {
- S.Diag(Loc, diag::ext_sizeof_alignof_void_type) << TraitKind << ArgRange;
+ unsigned DiagID = S.LangOpts.OpenCL ? diag::err_opencl_sizeof_alignof_type
+ : diag::ext_sizeof_alignof_void_type;
+ S.Diag(Loc, DiagID) << TraitKind << ArgRange;
return false;
}
@@ -3302,7 +3395,7 @@ static void warnOnSizeofOnArrayDecay(Sema &S, SourceLocation Loc, QualType T,
<< ICE->getSubExpr()->getType();
}
-/// \brief Check the constrains on expression operands to unary type expression
+/// \brief Check the constraints on expression operands to unary type expression
/// and type traits.
///
/// Completes any types necessary and validates the constraints on the operand
@@ -3323,10 +3416,21 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
E->getSourceRange(), ExprKind))
return false;
- if (RequireCompleteExprType(E,
- diag::err_sizeof_alignof_incomplete_type,
- ExprKind, E->getSourceRange()))
- return true;
+ // 'alignof' applied to an expression only requires the base element type of
+ // the expression to be complete. 'sizeof' requires the expression's type to
+ // be complete (and will attempt to complete it if it's an array of unknown
+ // bound).
+ if (ExprKind == UETT_AlignOf) {
+ if (RequireCompleteType(E->getExprLoc(),
+ Context.getBaseElementType(E->getType()),
+ diag::err_sizeof_alignof_incomplete_type, ExprKind,
+ E->getSourceRange()))
+ return true;
+ } else {
+ if (RequireCompleteExprType(E, diag::err_sizeof_alignof_incomplete_type,
+ ExprKind, E->getSourceRange()))
+ return true;
+ }
// Completing the expression's type may have changed it.
ExprTy = E->getType();
@@ -3391,13 +3495,21 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType,
if (ExprType->isDependentType())
return false;
- // C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
- // the result is the size of the referenced type."
- // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
- // result shall be the alignment of the referenced type."
+ // C++ [expr.sizeof]p2:
+ // When applied to a reference or a reference type, the result
+ // is the size of the referenced type.
+ // C++11 [expr.alignof]p3:
+ // When alignof is applied to a reference type, the result
+ // shall be the alignment of the referenced type.
if (const ReferenceType *Ref = ExprType->getAs<ReferenceType>())
ExprType = Ref->getPointeeType();
+ // C11 6.5.3.4/3, C++11 [expr.alignof]p3:
+ // When alignof or _Alignof is applied to an array type, the result
+ // is the alignment of the element type.
+ if (ExprKind == UETT_AlignOf)
+ ExprType = Context.getBaseElementType(ExprType);
+
if (ExprKind == UETT_VecStep)
return CheckVecStepTraitOperandType(*this, ExprType, OpLoc, ExprRange);
@@ -3437,7 +3549,7 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E) {
return true;
}
- ValueDecl *D = 0;
+ ValueDecl *D = nullptr;
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
D = DRE->getDecl();
} else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
@@ -3447,21 +3559,10 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E) {
// If it's a field, require the containing struct to have a
// complete definition so that we can compute the layout.
//
- // This requires a very particular set of circumstances. For a
- // field to be contained within an incomplete type, we must in the
- // process of parsing that type. To have an expression refer to a
- // field, it must be an id-expression or a member-expression, but
- // the latter are always ill-formed when the base type is
- // incomplete, including only being partially complete. An
- // id-expression can never refer to a field in C because fields
- // are not in the ordinary namespace. In C++, an id-expression
- // can implicitly be a member access, but only if there's an
- // implicit 'this' value, and all such contexts are subject to
- // delayed parsing --- except for trailing return types in C++11.
- // And if an id-expression referring to a field occurs in a
- // context that lacks a 'this' value, it's ill-formed --- except,
- // agian, in C++11, where such references are allowed in an
- // unevaluated context. So C++11 introduces some new complexity.
+ // This can happen in C++11 onwards, either by naming the member
+ // in a way that is not transformed into a member access expression
+ // (in an unevaluated operand, for instance), or by naming the member
+ // in a trailing-return-type.
//
// For the record, since __alignof__ on expressions is a GCC
// extension, GCC seems to permit this but always gives the
@@ -3518,9 +3619,8 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
return ExprError();
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
- return Owned(new (Context) UnaryExprOrTypeTraitExpr(ExprKind, TInfo,
- Context.getSizeType(),
- OpLoc, R.getEnd()));
+ return new (Context) UnaryExprOrTypeTraitExpr(
+ ExprKind, TInfo, Context.getSizeType(), OpLoc, R.getEnd());
}
/// \brief Build a sizeof or alignof expression given an expression
@@ -3555,13 +3655,12 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
if (ExprKind == UETT_SizeOf && E->getType()->isVariableArrayType()) {
PE = TransformToPotentiallyEvaluated(E);
if (PE.isInvalid()) return ExprError();
- E = PE.take();
+ E = PE.get();
}
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
- return Owned(new (Context) UnaryExprOrTypeTraitExpr(
- ExprKind, E, Context.getSizeType(), OpLoc,
- E->getSourceRange().getEnd()));
+ return new (Context) UnaryExprOrTypeTraitExpr(
+ ExprKind, E, Context.getSizeType(), OpLoc, E->getSourceRange().getEnd());
}
/// ActOnUnaryExprOrTypeTraitExpr - Handle @c sizeof(type) and @c sizeof @c
@@ -3572,7 +3671,7 @@ Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc,
UnaryExprOrTypeTrait ExprKind, bool IsType,
void *TyOrEx, const SourceRange &ArgRange) {
// If error parsing type, ignore.
- if (TyOrEx == 0) return ExprError();
+ if (!TyOrEx) return ExprError();
if (IsType) {
TypeSourceInfo *TInfo;
@@ -3592,7 +3691,7 @@ static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc,
// _Real and _Imag are only l-values for normal l-values.
if (V.get()->getObjectKind() != OK_Ordinary) {
- V = S.DefaultLvalueConversion(V.take());
+ V = S.DefaultLvalueConversion(V.get());
if (V.isInvalid())
return QualType();
}
@@ -3634,7 +3733,7 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
// Since this might is a postfix expression, get rid of ParenListExprs.
ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Input);
if (Result.isInvalid()) return ExprError();
- Input = Result.take();
+ Input = Result.get();
return BuildUnaryOp(S, OpLoc, Opc, Input);
}
@@ -3663,7 +3762,7 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
if (isa<ParenListExpr>(base)) {
ExprResult result = MaybeConvertParenListExprToParenExpr(S, base);
if (result.isInvalid()) return ExprError();
- base = result.take();
+ base = result.get();
}
// Handle any non-overload placeholder types in the base and index
@@ -3674,21 +3773,19 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
if (base->getType()->isNonOverloadPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(base);
if (result.isInvalid()) return ExprError();
- base = result.take();
+ base = result.get();
}
if (idx->getType()->isNonOverloadPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(idx);
if (result.isInvalid()) return ExprError();
- idx = result.take();
+ idx = result.get();
}
// Build an unanalyzed expression if either operand is type-dependent.
if (getLangOpts().CPlusPlus &&
(base->isTypeDependent() || idx->isTypeDependent())) {
- return Owned(new (Context) ArraySubscriptExpr(base, idx,
- Context.DependentTy,
- VK_LValue, OK_Ordinary,
- rbLoc));
+ return new (Context) ArraySubscriptExpr(base, idx, Context.DependentTy,
+ VK_LValue, OK_Ordinary, rbLoc);
}
// Use C++ overloaded-operator rules if either operand has record
@@ -3720,12 +3817,12 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
ExprResult Result = DefaultFunctionArrayLvalueConversion(LHSExp);
if (Result.isInvalid())
return ExprError();
- LHSExp = Result.take();
+ LHSExp = Result.get();
}
ExprResult Result = DefaultFunctionArrayLvalueConversion(RHSExp);
if (Result.isInvalid())
return ExprError();
- RHSExp = Result.take();
+ RHSExp = Result.get();
QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType();
ExprValueKind VK = VK_LValue;
@@ -3753,7 +3850,8 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
// Use custom logic if this should be the pseudo-object subscript
// expression.
if (!LangOpts.isSubscriptPointerArithmetic())
- return BuildObjCSubscriptExpression(RLoc, BaseExpr, IndexExpr, 0, 0);
+ return BuildObjCSubscriptExpression(RLoc, BaseExpr, IndexExpr, nullptr,
+ nullptr);
ResultType = PTy->getPointeeType();
} else if (const PointerType *PTy = RHSTy->getAs<PointerType>()) {
@@ -3790,7 +3888,7 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
Diag(LHSExp->getLocStart(), diag::ext_subscript_non_lvalue) <<
LHSExp->getSourceRange();
LHSExp = ImpCastExprToType(LHSExp, Context.getArrayDecayedType(LHSTy),
- CK_ArrayToPointerDecay).take();
+ CK_ArrayToPointerDecay).get();
LHSTy = LHSExp->getType();
BaseExpr = LHSExp;
@@ -3801,7 +3899,7 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
Diag(RHSExp->getLocStart(), diag::ext_subscript_non_lvalue) <<
RHSExp->getSourceRange();
RHSExp = ImpCastExprToType(RHSExp, Context.getArrayDecayedType(RHSTy),
- CK_ArrayToPointerDecay).take();
+ CK_ArrayToPointerDecay).get();
RHSTy = RHSExp->getType();
BaseExpr = RHSExp;
@@ -3847,8 +3945,8 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
assert(VK == VK_RValue || LangOpts.CPlusPlus ||
!ResultType.isCForbiddenLValueType());
- return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp,
- ResultType, VK, OK, RLoc));
+ return new (Context)
+ ArraySubscriptExpr(LHSExp, RHSExp, ResultType, VK, OK, RLoc);
}
ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
@@ -3871,7 +3969,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
// Instantiate the expression.
MultiLevelTemplateArgumentList MutiLevelArgList
- = getTemplateInstantiationArgs(FD, 0, /*RelativeToPrimary=*/true);
+ = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary=*/true);
InstantiatingTemplate Inst(*this, CallLoc, Param,
MutiLevelArgList.getInnermost());
@@ -3897,17 +3995,17 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
InitializationKind Kind
= InitializationKind::CreateCopy(Param->getLocation(),
/*FIXME:EqualLoc*/UninstExpr->getLocStart());
- Expr *ResultE = Result.takeAs<Expr>();
+ Expr *ResultE = Result.getAs<Expr>();
InitializationSequence InitSeq(*this, Entity, Kind, ResultE);
Result = InitSeq.Perform(*this, Entity, Kind, ResultE);
if (Result.isInvalid())
return ExprError();
- Expr *Arg = Result.takeAs<Expr>();
+ Expr *Arg = Result.getAs<Expr>();
CheckCompletedExpr(Arg, Param->getOuterLocStart());
// Build the default argument expression.
- return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param, Arg));
+ return CXXDefaultArgExpr::Create(Context, CallLoc, Param, Arg);
}
// If the default expression creates temporaries, we need to
@@ -3934,7 +4032,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
// as being "referenced".
MarkDeclarationsReferencedInExpr(Param->getDefaultArg(),
/*SkipLocalVariables=*/true);
- return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param));
+ return CXXDefaultArgExpr::Create(Context, CallLoc, Param);
}
@@ -3961,11 +4059,11 @@ namespace {
class FunctionCallCCC : public FunctionCallFilterCCC {
public:
FunctionCallCCC(Sema &SemaRef, const IdentifierInfo *FuncName,
- unsigned NumArgs, bool HasExplicitTemplateArgs)
- : FunctionCallFilterCCC(SemaRef, NumArgs, HasExplicitTemplateArgs),
+ unsigned NumArgs, MemberExpr *ME)
+ : FunctionCallFilterCCC(SemaRef, NumArgs, false, ME),
FunctionName(FuncName) {}
- virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ bool ValidateCandidate(const TypoCorrection &candidate) override {
if (!candidate.getCorrectionSpecifier() ||
candidate.getCorrectionAsIdentifierInfo() != FunctionName) {
return false;
@@ -3979,17 +4077,21 @@ private:
};
}
-static TypoCorrection TryTypoCorrectionForCall(Sema &S,
- DeclarationNameInfo FuncName,
+static TypoCorrection TryTypoCorrectionForCall(Sema &S, Expr *Fn,
+ FunctionDecl *FDecl,
ArrayRef<Expr *> Args) {
- FunctionCallCCC CCC(S, FuncName.getName().getAsIdentifierInfo(),
- Args.size(), false);
- if (TypoCorrection Corrected =
- S.CorrectTypo(FuncName, Sema::LookupOrdinaryName,
- S.getScopeForContext(S.CurContext), NULL, CCC)) {
+ MemberExpr *ME = dyn_cast<MemberExpr>(Fn);
+ DeclarationName FuncName = FDecl->getDeclName();
+ SourceLocation NameLoc = ME ? ME->getMemberLoc() : Fn->getLocStart();
+ FunctionCallCCC CCC(S, FuncName.getAsIdentifierInfo(), Args.size(), ME);
+
+ if (TypoCorrection Corrected = S.CorrectTypo(
+ DeclarationNameInfo(FuncName, NameLoc), Sema::LookupOrdinaryName,
+ S.getScopeForContext(S.CurContext), nullptr, CCC,
+ Sema::CTK_ErrorRecovery)) {
if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
if (Corrected.isOverloaded()) {
- OverloadCandidateSet OCS(FuncName.getLoc());
+ OverloadCandidateSet OCS(NameLoc, OverloadCandidateSet::CSK_Normal);
OverloadCandidateSet::iterator Best;
for (TypoCorrection::decl_iterator CD = Corrected.begin(),
CDEnd = Corrected.end();
@@ -3998,7 +4100,7 @@ static TypoCorrection TryTypoCorrectionForCall(Sema &S,
S.AddOverloadCandidate(FD, DeclAccessPair::make(FD, AS_none), Args,
OCS);
}
- switch (OCS.BestViableFunction(S, FuncName.getLoc(), Best)) {
+ switch (OCS.BestViableFunction(S, NameLoc, Best)) {
case OR_Success:
ND = Best->Function;
Corrected.setCorrectionDecl(ND);
@@ -4037,9 +4139,9 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
// C99 6.5.2.2p7 - the arguments are implicitly converted, as if by
// assignment, to the types of the corresponding parameter, ...
- unsigned NumArgsInProto = Proto->getNumArgs();
+ unsigned NumParams = Proto->getNumParams();
bool Invalid = false;
- unsigned MinArgs = FDecl ? FDecl->getMinRequiredArguments() : NumArgsInProto;
+ unsigned MinArgs = FDecl ? FDecl->getMinRequiredArguments() : NumParams;
unsigned FnKind = Fn->getType()->isBlockPointerType()
? 1 /* block */
: (IsExecConfig ? 3 /* kernel function (exec config) */
@@ -4047,35 +4149,29 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
// If too few arguments are available (and we don't have default
// arguments for the remaining parameters), don't make the call.
- if (Args.size() < NumArgsInProto) {
+ if (Args.size() < NumParams) {
if (Args.size() < MinArgs) {
- MemberExpr *ME = dyn_cast<MemberExpr>(Fn);
TypoCorrection TC;
- if (FDecl && (TC = TryTypoCorrectionForCall(
- *this, DeclarationNameInfo(FDecl->getDeclName(),
- (ME ? ME->getMemberLoc()
- : Fn->getLocStart())),
- Args))) {
+ if (FDecl && (TC = TryTypoCorrectionForCall(*this, Fn, FDecl, Args))) {
unsigned diag_id =
- MinArgs == NumArgsInProto && !Proto->isVariadic()
+ MinArgs == NumParams && !Proto->isVariadic()
? diag::err_typecheck_call_too_few_args_suggest
: diag::err_typecheck_call_too_few_args_at_least_suggest;
diagnoseTypo(TC, PDiag(diag_id) << FnKind << MinArgs
<< static_cast<unsigned>(Args.size())
- << Fn->getSourceRange());
+ << TC.getCorrectionRange());
} else if (MinArgs == 1 && FDecl && FDecl->getParamDecl(0)->getDeclName())
- Diag(RParenLoc, MinArgs == NumArgsInProto && !Proto->isVariadic()
- ? diag::err_typecheck_call_too_few_args_one
- : diag::err_typecheck_call_too_few_args_at_least_one)
- << FnKind
- << FDecl->getParamDecl(0) << Fn->getSourceRange();
+ Diag(RParenLoc,
+ MinArgs == NumParams && !Proto->isVariadic()
+ ? diag::err_typecheck_call_too_few_args_one
+ : diag::err_typecheck_call_too_few_args_at_least_one)
+ << FnKind << FDecl->getParamDecl(0) << Fn->getSourceRange();
else
- Diag(RParenLoc, MinArgs == NumArgsInProto && !Proto->isVariadic()
- ? diag::err_typecheck_call_too_few_args
- : diag::err_typecheck_call_too_few_args_at_least)
- << FnKind
- << MinArgs << static_cast<unsigned>(Args.size())
- << Fn->getSourceRange();
+ Diag(RParenLoc, MinArgs == NumParams && !Proto->isVariadic()
+ ? diag::err_typecheck_call_too_few_args
+ : diag::err_typecheck_call_too_few_args_at_least)
+ << FnKind << MinArgs << static_cast<unsigned>(Args.size())
+ << Fn->getSourceRange();
// Emit the location of the prototype.
if (!TC && FDecl && !FDecl->getBuiltinID() && !IsExecConfig)
@@ -4084,46 +4180,41 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
return true;
}
- Call->setNumArgs(Context, NumArgsInProto);
+ Call->setNumArgs(Context, NumParams);
}
// If too many are passed and not variadic, error on the extras and drop
// them.
- if (Args.size() > NumArgsInProto) {
+ if (Args.size() > NumParams) {
if (!Proto->isVariadic()) {
TypoCorrection TC;
- if (FDecl && (TC = TryTypoCorrectionForCall(
- *this, DeclarationNameInfo(FDecl->getDeclName(),
- Fn->getLocStart()),
- Args))) {
+ if (FDecl && (TC = TryTypoCorrectionForCall(*this, Fn, FDecl, Args))) {
unsigned diag_id =
- MinArgs == NumArgsInProto && !Proto->isVariadic()
+ MinArgs == NumParams && !Proto->isVariadic()
? diag::err_typecheck_call_too_many_args_suggest
: diag::err_typecheck_call_too_many_args_at_most_suggest;
- diagnoseTypo(TC, PDiag(diag_id) << FnKind << NumArgsInProto
+ diagnoseTypo(TC, PDiag(diag_id) << FnKind << NumParams
<< static_cast<unsigned>(Args.size())
- << Fn->getSourceRange());
- } else if (NumArgsInProto == 1 && FDecl &&
+ << TC.getCorrectionRange());
+ } else if (NumParams == 1 && FDecl &&
FDecl->getParamDecl(0)->getDeclName())
- Diag(Args[NumArgsInProto]->getLocStart(),
- MinArgs == NumArgsInProto
- ? diag::err_typecheck_call_too_many_args_one
- : diag::err_typecheck_call_too_many_args_at_most_one)
- << FnKind
- << FDecl->getParamDecl(0) << static_cast<unsigned>(Args.size())
- << Fn->getSourceRange()
- << SourceRange(Args[NumArgsInProto]->getLocStart(),
- Args.back()->getLocEnd());
+ Diag(Args[NumParams]->getLocStart(),
+ MinArgs == NumParams
+ ? diag::err_typecheck_call_too_many_args_one
+ : diag::err_typecheck_call_too_many_args_at_most_one)
+ << FnKind << FDecl->getParamDecl(0)
+ << static_cast<unsigned>(Args.size()) << Fn->getSourceRange()
+ << SourceRange(Args[NumParams]->getLocStart(),
+ Args.back()->getLocEnd());
else
- Diag(Args[NumArgsInProto]->getLocStart(),
- MinArgs == NumArgsInProto
- ? diag::err_typecheck_call_too_many_args
- : diag::err_typecheck_call_too_many_args_at_most)
- << FnKind
- << NumArgsInProto << static_cast<unsigned>(Args.size())
- << Fn->getSourceRange()
- << SourceRange(Args[NumArgsInProto]->getLocStart(),
- Args.back()->getLocEnd());
+ Diag(Args[NumParams]->getLocStart(),
+ MinArgs == NumParams
+ ? diag::err_typecheck_call_too_many_args
+ : diag::err_typecheck_call_too_many_args_at_most)
+ << FnKind << NumParams << static_cast<unsigned>(Args.size())
+ << Fn->getSourceRange()
+ << SourceRange(Args[NumParams]->getLocStart(),
+ Args.back()->getLocEnd());
// Emit the location of the prototype.
if (!TC && FDecl && !FDecl->getBuiltinID() && !IsExecConfig)
@@ -4131,7 +4222,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
<< FDecl;
// This deletes the extra arguments.
- Call->setNumArgs(Context, NumArgsInProto);
+ Call->setNumArgs(Context, NumParams);
return true;
}
}
@@ -4149,28 +4240,21 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
return false;
}
-bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
- FunctionDecl *FDecl,
+bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl,
const FunctionProtoType *Proto,
- unsigned FirstProtoArg,
- ArrayRef<Expr *> Args,
+ unsigned FirstParam, ArrayRef<Expr *> Args,
SmallVectorImpl<Expr *> &AllArgs,
- VariadicCallType CallType,
- bool AllowExplicit,
+ VariadicCallType CallType, bool AllowExplicit,
bool IsListInitialization) {
- unsigned NumArgsInProto = Proto->getNumArgs();
- unsigned NumArgsToCheck = Args.size();
+ unsigned NumParams = Proto->getNumParams();
bool Invalid = false;
- if (Args.size() != NumArgsInProto)
- // Use default arguments for missing arguments
- NumArgsToCheck = NumArgsInProto;
unsigned ArgIx = 0;
// Continue to check argument types (even if we have too few/many args).
- for (unsigned i = FirstProtoArg; i != NumArgsToCheck; i++) {
- QualType ProtoArgType = Proto->getArgType(i);
+ for (unsigned i = FirstParam; i < NumParams; i++) {
+ QualType ProtoArgType = Proto->getParamType(i);
Expr *Arg;
- ParmVarDecl *Param;
+ ParmVarDecl *Param = FDecl ? FDecl->getParamDecl(i) : nullptr;
if (ArgIx < Args.size()) {
Arg = Args[ArgIx++];
@@ -4179,11 +4263,6 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
diag::err_call_incomplete_argument, Arg))
return true;
- // Pass the argument
- Param = 0;
- if (FDecl && i < FDecl->getNumParams())
- Param = FDecl->getParamDecl(i);
-
// Strip the unbridged-cast placeholder expression off, if applicable.
bool CFAudited = false;
if (Arg->getType() == Context.ARCUnbridgedCastTy &&
@@ -4195,34 +4274,31 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
(!Param || !Param->hasAttr<CFConsumedAttr>()))
CFAudited = true;
- InitializedEntity Entity = Param ?
- InitializedEntity::InitializeParameter(Context, Param, ProtoArgType)
- : InitializedEntity::InitializeParameter(Context, ProtoArgType,
- Proto->isArgConsumed(i));
-
+ InitializedEntity Entity =
+ Param ? InitializedEntity::InitializeParameter(Context, Param,
+ ProtoArgType)
+ : InitializedEntity::InitializeParameter(
+ Context, ProtoArgType, Proto->isParamConsumed(i));
+
// Remember that parameter belongs to a CF audited API.
if (CFAudited)
Entity.setParameterCFAudited();
-
- ExprResult ArgE = PerformCopyInitialization(Entity,
- SourceLocation(),
- Owned(Arg),
- IsListInitialization,
- AllowExplicit);
+
+ ExprResult ArgE = PerformCopyInitialization(
+ Entity, SourceLocation(), Arg, IsListInitialization, AllowExplicit);
if (ArgE.isInvalid())
return true;
- Arg = ArgE.takeAs<Expr>();
+ Arg = ArgE.getAs<Expr>();
} else {
- assert(FDecl && "can't use default arguments without a known callee");
- Param = FDecl->getParamDecl(i);
+ assert(Param && "can't use default arguments without a known callee");
ExprResult ArgExpr =
BuildCXXDefaultArgExpr(CallLoc, FDecl, Param);
if (ArgExpr.isInvalid())
return true;
- Arg = ArgExpr.takeAs<Expr>();
+ Arg = ArgExpr.getAs<Expr>();
}
// Check for array bounds violations for each argument to the call. This
@@ -4240,13 +4316,13 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
if (CallType != VariadicDoesNotApply) {
// Assume that extern "C" functions with variadic arguments that
// return __unknown_anytype aren't *really* variadic.
- if (Proto->getResultType() == Context.UnknownAnyTy &&
- FDecl && FDecl->isExternC()) {
+ if (Proto->getReturnType() == Context.UnknownAnyTy && FDecl &&
+ FDecl->isExternC()) {
for (unsigned i = ArgIx, e = Args.size(); i != e; ++i) {
QualType paramType; // ignored
ExprResult arg = checkUnknownAnyArg(CallLoc, Args[i], paramType);
Invalid |= arg.isInvalid();
- AllArgs.push_back(arg.take());
+ AllArgs.push_back(arg.get());
}
// Otherwise do argument promotion, (C99 6.5.2.2p7).
@@ -4255,7 +4331,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], CallType,
FDecl);
Invalid |= Arg.isInvalid();
- AllArgs.push_back(Arg.take());
+ AllArgs.push_back(Arg.get());
}
}
@@ -4377,7 +4453,7 @@ static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args) {
if (isPlaceholderToRemoveAsArg(args[i]->getType())) {
ExprResult result = S.CheckPlaceholderExpr(args[i]);
if (result.isInvalid()) hasInvalid = true;
- else args[i] = result.take();
+ else args[i] = result.get();
}
}
return hasInvalid;
@@ -4393,7 +4469,7 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
// Since this might be a postfix expression, get rid of ParenListExprs.
ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Fn);
if (Result.isInvalid()) return ExprError();
- Fn = Result.take();
+ Fn = Result.get();
if (checkArgsForPlaceholders(*this, ArgExprs))
return ExprError();
@@ -4409,14 +4485,13 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
ArgExprs.back()->getLocEnd()));
}
- return Owned(new (Context) CallExpr(Context, Fn, None,
- Context.VoidTy, VK_RValue,
- RParenLoc));
+ return new (Context)
+ CallExpr(Context, Fn, None, Context.VoidTy, VK_RValue, RParenLoc);
}
if (Fn->getType() == Context.PseudoObjectTy) {
ExprResult result = CheckPlaceholderExpr(Fn);
if (result.isInvalid()) return ExprError();
- Fn = result.take();
+ Fn = result.get();
}
// Determine whether this is a dependent call inside a C++ template,
@@ -4431,25 +4506,24 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
if (Dependent) {
if (ExecConfig) {
- return Owned(new (Context) CUDAKernelCallExpr(
+ return new (Context) CUDAKernelCallExpr(
Context, Fn, cast<CallExpr>(ExecConfig), ArgExprs,
- Context.DependentTy, VK_RValue, RParenLoc));
+ Context.DependentTy, VK_RValue, RParenLoc);
} else {
- return Owned(new (Context) CallExpr(Context, Fn, ArgExprs,
- Context.DependentTy, VK_RValue,
- RParenLoc));
+ return new (Context) CallExpr(
+ Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc);
}
}
// Determine whether this is a call to an object (C++ [over.call.object]).
if (Fn->getType()->isRecordType())
- return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc,
- ArgExprs, RParenLoc));
+ return BuildCallToObjectOfClassType(S, Fn, LParenLoc, ArgExprs,
+ RParenLoc);
if (Fn->getType() == Context.UnknownAnyTy) {
ExprResult result = rebuildUnknownAnyFunction(*this, Fn);
if (result.isInvalid()) return ExprError();
- Fn = result.take();
+ Fn = result.get();
}
if (Fn->getType() == Context.BoundMemberTy) {
@@ -4479,12 +4553,12 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
if (Fn->getType() == Context.UnknownAnyTy) {
ExprResult result = rebuildUnknownAnyFunction(*this, Fn);
if (result.isInvalid()) return ExprError();
- Fn = result.take();
+ Fn = result.get();
}
Expr *NakedFn = Fn->IgnoreParens();
- NamedDecl *NDecl = 0;
+ NamedDecl *NDecl = nullptr;
if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(NakedFn))
if (UnOp->getOpcode() == UO_AddrOf)
NakedFn = UnOp->getSubExpr()->IgnoreParens();
@@ -4494,6 +4568,21 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
else if (isa<MemberExpr>(NakedFn))
NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl();
+ if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NDecl)) {
+ if (FD->hasAttr<EnableIfAttr>()) {
+ if (const EnableIfAttr *Attr = CheckEnableIf(FD, ArgExprs, true)) {
+ Diag(Fn->getLocStart(),
+ isa<CXXMethodDecl>(FD) ?
+ diag::err_ovl_no_viable_member_function_in_call :
+ diag::err_ovl_no_viable_function_in_call)
+ << FD << FD->getSourceRange();
+ Diag(FD->getLocation(),
+ diag::note_ovl_candidate_disabled_by_enable_if_attr)
+ << Attr->getCond()->getSourceRange() << Attr->getMessage();
+ }
+ }
+ }
+
return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs, RParenLoc,
ExecConfig, IsExecConfig);
}
@@ -4511,7 +4600,7 @@ Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
ConfigDecl, false, ConfigQTy, VK_LValue, LLLLoc);
MarkFunctionReferenced(LLLLoc, ConfigDecl);
- return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, 0,
+ return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, nullptr,
/*IsExecConfig=*/true);
}
@@ -4532,8 +4621,7 @@ ExprResult Sema::ActOnAsTypeExpr(Expr *E, ParsedType ParsedDestTy,
<< DstTy
<< SrcTy
<< E->getSourceRange());
- return Owned(new (Context) AsTypeExpr(E, DstTy, VK, OK, BuiltinLoc,
- RParenLoc));
+ return new (Context) AsTypeExpr(E, DstTy, VK, OK, BuiltinLoc, RParenLoc);
}
/// ActOnConvertVectorExpr - create a new convert-vector expression from the
@@ -4571,13 +4659,13 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
if (BuiltinID &&
Fn->getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn)) {
Result = ImpCastExprToType(Fn, Context.getPointerType(FDecl->getType()),
- CK_BuiltinFnToFnPtr).take();
+ CK_BuiltinFnToFnPtr).get();
} else {
- Result = UsualUnaryConversions(Fn);
+ Result = CallExprUnaryConversions(Fn);
}
if (Result.isInvalid())
return ExprError();
- Fn = Result.take();
+ Fn = Result.get();
// Make the call expr early, before semantic checks. This guarantees cleanup
// of arguments and function on error.
@@ -4601,7 +4689,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
// C99 6.5.2.2p1 - "The expression that denotes the called function shall
// have type pointer to function".
FuncT = PT->getPointeeType()->getAs<FunctionType>();
- if (FuncT == 0)
+ if (!FuncT)
return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function)
<< Fn->getType() << Fn->getSourceRange());
} else if (const BlockPointerType *BPT =
@@ -4612,7 +4700,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
if (Fn->getType() == Context.UnknownAnyTy) {
ExprResult rewrite = rebuildUnknownAnyFunction(*this, Fn);
if (rewrite.isInvalid()) return ExprError();
- Fn = rewrite.take();
+ Fn = rewrite.get();
TheCall->setCallee(Fn);
goto retry;
}
@@ -4629,7 +4717,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
<< FDecl->getName() << Fn->getSourceRange());
// CUDA: Kernel function must have 'void' return type
- if (!FuncT->getResultType()->isVoidType())
+ if (!FuncT->getReturnType()->isVoidType())
return ExprError(Diag(LParenLoc, diag::err_kern_type_not_void_return)
<< Fn->getType() << Fn->getSourceRange());
} else {
@@ -4641,14 +4729,13 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
}
// Check for a valid return type
- if (CheckCallReturnType(FuncT->getResultType(),
- Fn->getLocStart(), TheCall,
+ if (CheckCallReturnType(FuncT->getReturnType(), Fn->getLocStart(), TheCall,
FDecl))
return ExprError();
// We know the result type of the call, set it.
TheCall->setType(FuncT->getCallResultType(Context));
- TheCall->setValueKind(Expr::getValueKindForType(FuncT->getResultType()));
+ TheCall->setValueKind(Expr::getValueKindForType(FuncT->getReturnType()));
const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT);
if (Proto) {
@@ -4661,7 +4748,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
if (FDecl) {
// Check if we have too few/too many template arguments, based
// on our knowledge of the function definition.
- const FunctionDecl *Def = 0;
+ const FunctionDecl *Def = nullptr;
if (FDecl->hasBody(Def) && Args.size() != Def->param_size()) {
Proto = Def->getType()->getAs<FunctionProtoType>();
if (!Proto || !(Proto->isVariadic() && Args.size() >= Def->param_size()))
@@ -4679,18 +4766,15 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
for (unsigned i = 0, e = Args.size(); i != e; i++) {
Expr *Arg = Args[i];
- if (Proto && i < Proto->getNumArgs()) {
- InitializedEntity Entity
- = InitializedEntity::InitializeParameter(Context,
- Proto->getArgType(i),
- Proto->isArgConsumed(i));
- ExprResult ArgE = PerformCopyInitialization(Entity,
- SourceLocation(),
- Owned(Arg));
+ if (Proto && i < Proto->getNumParams()) {
+ InitializedEntity Entity = InitializedEntity::InitializeParameter(
+ Context, Proto->getParamType(i), Proto->isParamConsumed(i));
+ ExprResult ArgE =
+ PerformCopyInitialization(Entity, SourceLocation(), Arg);
if (ArgE.isInvalid())
return true;
- Arg = ArgE.takeAs<Expr>();
+ Arg = ArgE.getAs<Expr>();
} else {
ExprResult ArgE = DefaultArgumentPromotion(Arg);
@@ -4698,7 +4782,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
if (ArgE.isInvalid())
return true;
- Arg = ArgE.takeAs<Expr>();
+ Arg = ArgE.getAs<Expr>();
}
if (RequireCompleteType(Arg->getLocStart(),
@@ -4785,7 +4869,7 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
return ExprError();
LiteralExpr = Result.get();
- bool isFileScope = getCurFunctionOrMethodDecl() == 0;
+ bool isFileScope = getCurFunctionOrMethodDecl() == nullptr;
if (isFileScope &&
!LiteralExpr->isTypeDependent() &&
!LiteralExpr->isValueDependent() &&
@@ -4815,7 +4899,7 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
// of one failure would be terrible for indexing/etc.
if (result.isInvalid()) continue;
- InitArgList[I] = result.take();
+ InitArgList[I] = result.get();
}
}
@@ -4825,7 +4909,7 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitArgList,
RBraceLoc);
E->setType(Context.VoidTy); // FIXME: just a place holder for now.
- return Owned(E);
+ return E;
}
/// Do an explicit extend of the given block pointer if we're in ARC.
@@ -4838,7 +4922,7 @@ static void maybeExtendBlockObject(Sema &S, ExprResult &E) {
E = ImplicitCastExpr::Create(S.Context, E.get()->getType(),
CK_ARCExtendBlockObject, E.get(),
- /*base path*/ 0, VK_RValue);
+ /*base path*/ nullptr, VK_RValue);
S.ExprNeedsCleanups = true;
}
@@ -4876,8 +4960,13 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
case Type::STK_BlockPointer:
case Type::STK_ObjCObjectPointer:
switch (DestTy->getScalarTypeKind()) {
- case Type::STK_CPointer:
+ case Type::STK_CPointer: {
+ unsigned SrcAS = SrcTy->getPointeeType().getAddressSpace();
+ unsigned DestAS = DestTy->getPointeeType().getAddressSpace();
+ if (SrcAS != DestAS)
+ return CK_AddressSpaceConversion;
return CK_BitCast;
+ }
case Type::STK_BlockPointer:
return (SrcKind == Type::STK_BlockPointer
? CK_BitCast : CK_AnyPointerToBlockPointerCast);
@@ -4917,12 +5006,12 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
case Type::STK_Floating:
return CK_IntegralToFloating;
case Type::STK_IntegralComplex:
- Src = ImpCastExprToType(Src.take(),
+ Src = ImpCastExprToType(Src.get(),
DestTy->castAs<ComplexType>()->getElementType(),
CK_IntegralCast);
return CK_IntegralRealToComplex;
case Type::STK_FloatingComplex:
- Src = ImpCastExprToType(Src.take(),
+ Src = ImpCastExprToType(Src.get(),
DestTy->castAs<ComplexType>()->getElementType(),
CK_IntegralToFloating);
return CK_FloatingRealToComplex;
@@ -4940,12 +5029,12 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
case Type::STK_Integral:
return CK_FloatingToIntegral;
case Type::STK_FloatingComplex:
- Src = ImpCastExprToType(Src.take(),
+ Src = ImpCastExprToType(Src.get(),
DestTy->castAs<ComplexType>()->getElementType(),
CK_FloatingCast);
return CK_FloatingRealToComplex;
case Type::STK_IntegralComplex:
- Src = ImpCastExprToType(Src.take(),
+ Src = ImpCastExprToType(Src.get(),
DestTy->castAs<ComplexType>()->getElementType(),
CK_FloatingToIntegral);
return CK_IntegralRealToComplex;
@@ -4968,13 +5057,13 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
QualType ET = SrcTy->castAs<ComplexType>()->getElementType();
if (Context.hasSameType(ET, DestTy))
return CK_FloatingComplexToReal;
- Src = ImpCastExprToType(Src.take(), ET, CK_FloatingComplexToReal);
+ Src = ImpCastExprToType(Src.get(), ET, CK_FloatingComplexToReal);
return CK_FloatingCast;
}
case Type::STK_Bool:
return CK_FloatingComplexToBoolean;
case Type::STK_Integral:
- Src = ImpCastExprToType(Src.take(),
+ Src = ImpCastExprToType(Src.get(),
SrcTy->castAs<ComplexType>()->getElementType(),
CK_FloatingComplexToReal);
return CK_FloatingToIntegral;
@@ -4997,13 +5086,13 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
QualType ET = SrcTy->castAs<ComplexType>()->getElementType();
if (Context.hasSameType(ET, DestTy))
return CK_IntegralComplexToReal;
- Src = ImpCastExprToType(Src.take(), ET, CK_IntegralComplexToReal);
+ Src = ImpCastExprToType(Src.get(), ET, CK_IntegralComplexToReal);
return CK_IntegralCast;
}
case Type::STK_Bool:
return CK_IntegralComplexToBoolean;
case Type::STK_Floating:
- Src = ImpCastExprToType(Src.take(),
+ Src = ImpCastExprToType(Src.get(),
SrcTy->castAs<ComplexType>()->getElementType(),
CK_IntegralComplexToReal);
return CK_IntegralToFloating;
@@ -5020,12 +5109,55 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) {
llvm_unreachable("Unhandled scalar cast");
}
+static bool breakDownVectorType(QualType type, uint64_t &len,
+ QualType &eltType) {
+ // Vectors are simple.
+ if (const VectorType *vecType = type->getAs<VectorType>()) {
+ len = vecType->getNumElements();
+ eltType = vecType->getElementType();
+ assert(eltType->isScalarType());
+ return true;
+ }
+
+ // We allow lax conversion to and from non-vector types, but only if
+ // they're real types (i.e. non-complex, non-pointer scalar types).
+ if (!type->isRealType()) return false;
+
+ len = 1;
+ eltType = type;
+ return true;
+}
+
+static bool VectorTypesMatch(Sema &S, QualType srcTy, QualType destTy) {
+ uint64_t srcLen, destLen;
+ QualType srcElt, destElt;
+ if (!breakDownVectorType(srcTy, srcLen, srcElt)) return false;
+ if (!breakDownVectorType(destTy, destLen, destElt)) return false;
+
+ // ASTContext::getTypeSize will return the size rounded up to a
+ // power of 2, so instead of using that, we need to use the raw
+ // element size multiplied by the element count.
+ uint64_t srcEltSize = S.Context.getTypeSize(srcElt);
+ uint64_t destEltSize = S.Context.getTypeSize(destElt);
+
+ return (srcLen * srcEltSize == destLen * destEltSize);
+}
+
+/// Is this a legal conversion between two known vector types?
+bool Sema::isLaxVectorConversion(QualType srcTy, QualType destTy) {
+ assert(destTy->isVectorType() || srcTy->isVectorType());
+
+ if (!Context.getLangOpts().LaxVectorConversions)
+ return false;
+ return VectorTypesMatch(*this, srcTy, destTy);
+}
+
bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty,
CastKind &Kind) {
assert(VectorTy->isVectorType() && "Not a vector type!");
if (Ty->isVectorType() || Ty->isIntegerType()) {
- if (Context.getTypeSize(VectorTy) != Context.getTypeSize(Ty))
+ if (!VectorTypesMatch(*this, Ty, VectorTy))
return Diag(R.getBegin(),
Ty->isVectorType() ?
diag::err_invalid_conversion_between_vectors :
@@ -5051,7 +5183,7 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
// In OpenCL, casts between vectors of different types are not allowed.
// (See OpenCL 6.2).
if (SrcTy->isVectorType()) {
- if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy)
+ if (!VectorTypesMatch(*this, SrcTy, DestTy)
|| (getLangOpts().OpenCL &&
(DestTy.getCanonicalType() != SrcTy.getCanonicalType()))) {
Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors)
@@ -5059,7 +5191,7 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
return ExprError();
}
Kind = CK_BitCast;
- return Owned(CastExpr);
+ return CastExpr;
}
// All non-pointer scalars can be cast to ExtVector type. The appropriate
@@ -5071,21 +5203,21 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
<< DestTy << SrcTy << R;
QualType DestElemTy = DestTy->getAs<ExtVectorType>()->getElementType();
- ExprResult CastExprRes = Owned(CastExpr);
+ ExprResult CastExprRes = CastExpr;
CastKind CK = PrepareScalarCast(CastExprRes, DestElemTy);
if (CastExprRes.isInvalid())
return ExprError();
- CastExpr = ImpCastExprToType(CastExprRes.take(), DestElemTy, CK).take();
+ CastExpr = ImpCastExprToType(CastExprRes.get(), DestElemTy, CK).get();
Kind = CK_VectorSplat;
- return Owned(CastExpr);
+ return CastExpr;
}
ExprResult
Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
Declarator &D, ParsedType &Ty,
SourceLocation RParenLoc, Expr *CastExpr) {
- assert(!D.isInvalidType() && (CastExpr != 0) &&
+ assert(!D.isInvalidType() && (CastExpr != nullptr) &&
"ActOnCastExpr(): missing type or expr");
TypeSourceInfo *castTInfo = GetTypeForDeclaratorCast(D, CastExpr->getType());
@@ -5134,9 +5266,17 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
if (isa<ParenListExpr>(CastExpr)) {
ExprResult Result = MaybeConvertParenListExprToParenExpr(S, CastExpr);
if (Result.isInvalid()) return ExprError();
- CastExpr = Result.take();
+ CastExpr = Result.get();
}
+ if (getLangOpts().CPlusPlus && !castType->isVoidType() &&
+ !getSourceManager().isInSystemMacro(LParenLoc))
+ Diag(LParenLoc, diag::warn_old_style_cast) << CastExpr->getSourceRange();
+
+ CheckTollFreeBridgeCast(castType, CastExpr);
+
+ CheckObjCBridgeRelatedCast(castType, CastExpr);
+
return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, CastExpr);
}
@@ -5183,9 +5323,9 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
ExprResult Literal = DefaultLvalueConversion(exprs[0]);
if (Literal.isInvalid())
return ExprError();
- Literal = ImpCastExprToType(Literal.take(), ElemTy,
+ Literal = ImpCastExprToType(Literal.get(), ElemTy,
PrepareScalarCast(Literal, ElemTy));
- return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take());
+ return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.get());
}
else if (numExprs < numElems) {
Diag(E->getExprLoc(),
@@ -5205,9 +5345,9 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
ExprResult Literal = DefaultLvalueConversion(exprs[0]);
if (Literal.isInvalid())
return ExprError();
- Literal = ImpCastExprToType(Literal.take(), ElemTy,
+ Literal = ImpCastExprToType(Literal.get(), ElemTy,
PrepareScalarCast(Literal, ElemTy));
- return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take());
+ return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.get());
}
initExprs.append(exprs, exprs + numExprs);
@@ -5226,7 +5366,7 @@ ExprResult
Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *OrigExpr) {
ParenListExpr *E = dyn_cast<ParenListExpr>(OrigExpr);
if (!E)
- return Owned(OrigExpr);
+ return OrigExpr;
ExprResult Result(E->getExpr(0));
@@ -5243,7 +5383,7 @@ ExprResult Sema::ActOnParenListExpr(SourceLocation L,
SourceLocation R,
MultiExprArg Val) {
Expr *expr = new (Context) ParenListExpr(Context, L, Val, R);
- return Owned(expr);
+ return expr;
}
/// \brief Emit a specialized diagnostic when one expression is a null pointer
@@ -5324,8 +5464,8 @@ static bool checkConditionalConvertScalarsToVectors(Sema &S, ExprResult &LHS,
}
// Implicity convert these scalars to the type of the condition.
- LHS = S.ImpCastExprToType(LHS.take(), CondTy, CK_IntegralCast);
- RHS = S.ImpCastExprToType(RHS.take(), CondTy, CK_IntegralCast);
+ LHS = S.ImpCastExprToType(LHS.get(), CondTy, CK_IntegralCast);
+ RHS = S.ImpCastExprToType(RHS.get(), CondTy, CK_IntegralCast);
return false;
}
@@ -5341,8 +5481,8 @@ static QualType checkConditionalVoidType(Sema &S, ExprResult &LHS,
if (!RHSExpr->getType()->isVoidType())
S.Diag(LHSExpr->getLocStart(), diag::ext_typecheck_cond_one_void)
<< LHSExpr->getSourceRange();
- LHS = S.ImpCastExprToType(LHS.take(), S.Context.VoidTy, CK_ToVoid);
- RHS = S.ImpCastExprToType(RHS.take(), S.Context.VoidTy, CK_ToVoid);
+ LHS = S.ImpCastExprToType(LHS.get(), S.Context.VoidTy, CK_ToVoid);
+ RHS = S.ImpCastExprToType(RHS.get(), S.Context.VoidTy, CK_ToVoid);
return S.Context.VoidTy;
}
@@ -5355,7 +5495,7 @@ static bool checkConditionalNullPointer(Sema &S, ExprResult &NullExpr,
Expr::NPC_ValueDependentIsNull))
return true;
- NullExpr = S.ImpCastExprToType(NullExpr.take(), PointerTy, CK_NullToPointer);
+ NullExpr = S.ImpCastExprToType(NullExpr.get(), PointerTy, CK_NullToPointer);
return false;
}
@@ -5407,15 +5547,15 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
QualType CompositeTy = S.Context.mergeTypes(lhptee, rhptee);
if (CompositeTy.isNull()) {
- S.Diag(Loc, diag::warn_typecheck_cond_incompatible_pointers)
+ S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers)
<< LHSTy << RHSTy << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
// In this situation, we assume void* type. No especially good
// reason, but this is what gcc does, and we do have to pick
// to get a consistent AST.
QualType incompatTy = S.Context.getPointerType(S.Context.VoidTy);
- LHS = S.ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast);
- RHS = S.ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast);
+ LHS = S.ImpCastExprToType(LHS.get(), incompatTy, CK_BitCast);
+ RHS = S.ImpCastExprToType(RHS.get(), incompatTy, CK_BitCast);
return incompatTy;
}
@@ -5426,11 +5566,41 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
else
ResultTy = S.Context.getPointerType(ResultTy);
- LHS = S.ImpCastExprToType(LHS.take(), ResultTy, CK_BitCast);
- RHS = S.ImpCastExprToType(RHS.take(), ResultTy, CK_BitCast);
+ LHS = S.ImpCastExprToType(LHS.get(), ResultTy, CK_BitCast);
+ RHS = S.ImpCastExprToType(RHS.get(), ResultTy, CK_BitCast);
return ResultTy;
}
+/// \brief Returns true if QT is quelified-id and implements 'NSObject' and/or
+/// 'NSCopying' protocols (and nothing else); or QT is an NSObject and optionally
+/// implements 'NSObject' and/or NSCopying' protocols (and nothing else).
+static bool isObjCPtrBlockCompatible(Sema &S, ASTContext &C, QualType QT) {
+ if (QT->isObjCIdType())
+ return true;
+
+ const ObjCObjectPointerType *OPT = QT->getAs<ObjCObjectPointerType>();
+ if (!OPT)
+ return false;
+
+ if (ObjCInterfaceDecl *ID = OPT->getInterfaceDecl())
+ if (ID->getIdentifier() != &C.Idents.get("NSObject"))
+ return false;
+
+ ObjCProtocolDecl* PNSCopying =
+ S.LookupProtocol(&C.Idents.get("NSCopying"), SourceLocation());
+ ObjCProtocolDecl* PNSObject =
+ S.LookupProtocol(&C.Idents.get("NSObject"), SourceLocation());
+
+ for (auto *Proto : OPT->quals()) {
+ if ((PNSCopying && declaresSameEntity(Proto, PNSCopying)) ||
+ (PNSObject && declaresSameEntity(Proto, PNSObject)))
+ ;
+ else
+ return false;
+ }
+ return true;
+}
+
/// \brief Return the resulting type when the operands are both block pointers.
static QualType checkConditionalBlockPointerCompatibility(Sema &S,
ExprResult &LHS,
@@ -5442,8 +5612,8 @@ static QualType checkConditionalBlockPointerCompatibility(Sema &S,
if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) {
if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) {
QualType destType = S.Context.getPointerType(S.Context.VoidTy);
- LHS = S.ImpCastExprToType(LHS.take(), destType, CK_BitCast);
- RHS = S.ImpCastExprToType(RHS.take(), destType, CK_BitCast);
+ LHS = S.ImpCastExprToType(LHS.get(), destType, CK_BitCast);
+ RHS = S.ImpCastExprToType(RHS.get(), destType, CK_BitCast);
return destType;
}
S.Diag(Loc, diag::err_typecheck_cond_incompatible_operands)
@@ -5476,9 +5646,9 @@ checkConditionalObjectPointersCompatibility(Sema &S, ExprResult &LHS,
= S.Context.getQualifiedType(lhptee, rhptee.getQualifiers());
QualType destType = S.Context.getPointerType(destPointee);
// Add qualifiers if necessary.
- LHS = S.ImpCastExprToType(LHS.take(), destType, CK_NoOp);
+ LHS = S.ImpCastExprToType(LHS.get(), destType, CK_NoOp);
// Promote to void*.
- RHS = S.ImpCastExprToType(RHS.take(), destType, CK_BitCast);
+ RHS = S.ImpCastExprToType(RHS.get(), destType, CK_BitCast);
return destType;
}
if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) {
@@ -5486,9 +5656,9 @@ checkConditionalObjectPointersCompatibility(Sema &S, ExprResult &LHS,
= S.Context.getQualifiedType(rhptee, lhptee.getQualifiers());
QualType destType = S.Context.getPointerType(destPointee);
// Add qualifiers if necessary.
- RHS = S.ImpCastExprToType(RHS.take(), destType, CK_NoOp);
+ RHS = S.ImpCastExprToType(RHS.get(), destType, CK_NoOp);
// Promote to void*.
- LHS = S.ImpCastExprToType(LHS.take(), destType, CK_BitCast);
+ LHS = S.ImpCastExprToType(LHS.get(), destType, CK_BitCast);
return destType;
}
@@ -5507,10 +5677,10 @@ static bool checkPointerIntegerMismatch(Sema &S, ExprResult &Int,
Expr *Expr1 = IsIntFirstExpr ? Int.get() : PointerExpr;
Expr *Expr2 = IsIntFirstExpr ? PointerExpr : Int.get();
- S.Diag(Loc, diag::warn_typecheck_cond_pointer_integer_mismatch)
+ S.Diag(Loc, diag::ext_typecheck_cond_pointer_integer_mismatch)
<< Expr1->getType() << Expr2->getType()
<< Expr1->getSourceRange() << Expr2->getSourceRange();
- Int = S.ImpCastExprToType(Int.take(), PointerExpr->getType(),
+ Int = S.ImpCastExprToType(Int.get(), PointerExpr->getType(),
CK_IntegralToPointer);
return true;
}
@@ -5539,7 +5709,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
OK = OK_Ordinary;
// First, check the condition.
- Cond = UsualUnaryConversions(Cond.take());
+ Cond = UsualUnaryConversions(Cond.get());
if (Cond.isInvalid())
return QualType();
if (checkCondition(*this, Cond.get()))
@@ -5645,34 +5815,34 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
// redefinition type if an attempt is made to access its fields.
if (LHSTy->isObjCClassType() &&
(Context.hasSameType(RHSTy, Context.getObjCClassRedefinitionType()))) {
- RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_CPointerToObjCPointerCast);
+ RHS = ImpCastExprToType(RHS.get(), LHSTy, CK_CPointerToObjCPointerCast);
return LHSTy;
}
if (RHSTy->isObjCClassType() &&
(Context.hasSameType(LHSTy, Context.getObjCClassRedefinitionType()))) {
- LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_CPointerToObjCPointerCast);
+ LHS = ImpCastExprToType(LHS.get(), RHSTy, CK_CPointerToObjCPointerCast);
return RHSTy;
}
// And the same for struct objc_object* / id
if (LHSTy->isObjCIdType() &&
(Context.hasSameType(RHSTy, Context.getObjCIdRedefinitionType()))) {
- RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_CPointerToObjCPointerCast);
+ RHS = ImpCastExprToType(RHS.get(), LHSTy, CK_CPointerToObjCPointerCast);
return LHSTy;
}
if (RHSTy->isObjCIdType() &&
(Context.hasSameType(LHSTy, Context.getObjCIdRedefinitionType()))) {
- LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_CPointerToObjCPointerCast);
+ LHS = ImpCastExprToType(LHS.get(), RHSTy, CK_CPointerToObjCPointerCast);
return RHSTy;
}
// And the same for struct objc_selector* / SEL
if (Context.isObjCSelType(LHSTy) &&
(Context.hasSameType(RHSTy, Context.getObjCSelRedefinitionType()))) {
- RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.get(), LHSTy, CK_BitCast);
return LHSTy;
}
if (Context.isObjCSelType(RHSTy) &&
(Context.hasSameType(LHSTy, Context.getObjCSelRedefinitionType()))) {
- LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.get(), RHSTy, CK_BitCast);
return RHSTy;
}
// Check constraints for Objective-C object pointers types.
@@ -5721,13 +5891,13 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
<< LHSTy << RHSTy
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
QualType incompatTy = Context.getObjCIdType();
- LHS = ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast);
- RHS = ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.get(), incompatTy, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.get(), incompatTy, CK_BitCast);
return incompatTy;
}
// The object pointer types are compatible.
- LHS = ImpCastExprToType(LHS.take(), compositeType, CK_BitCast);
- RHS = ImpCastExprToType(RHS.take(), compositeType, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.get(), compositeType, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.get(), compositeType, CK_BitCast);
return compositeType;
}
// Check Objective-C object pointer types and 'void *'
@@ -5746,9 +5916,9 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
= Context.getQualifiedType(lhptee, rhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
// Add qualifiers if necessary.
- LHS = ImpCastExprToType(LHS.take(), destType, CK_NoOp);
+ LHS = ImpCastExprToType(LHS.get(), destType, CK_NoOp);
// Promote to void*.
- RHS = ImpCastExprToType(RHS.take(), destType, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.get(), destType, CK_BitCast);
return destType;
}
if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) {
@@ -5766,9 +5936,9 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
= Context.getQualifiedType(rhptee, lhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
// Add qualifiers if necessary.
- RHS = ImpCastExprToType(RHS.take(), destType, CK_NoOp);
+ RHS = ImpCastExprToType(RHS.get(), destType, CK_NoOp);
// Promote to void*.
- LHS = ImpCastExprToType(LHS.take(), destType, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.get(), destType, CK_BitCast);
return destType;
}
return QualType();
@@ -5900,9 +6070,9 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
Expr *RHSExpr) {
// If this is the gnu "x ?: y" extension, analyze the types as though the LHS
// was the condition.
- OpaqueValueExpr *opaqueValue = 0;
- Expr *commonExpr = 0;
- if (LHSExpr == 0) {
+ OpaqueValueExpr *opaqueValue = nullptr;
+ Expr *commonExpr = nullptr;
+ if (!LHSExpr) {
commonExpr = CondExpr;
// Lower out placeholder types first. This is important so that we don't
// try to capture a placeholder. This happens in few cases in C++; such
@@ -5910,7 +6080,7 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
if (commonExpr->hasPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(commonExpr);
if (!result.isUsable()) return ExprError();
- commonExpr = result.take();
+ commonExpr = result.get();
}
// We usually want to apply unary conversions *before* saving, except
// in the special case of a C++ l-value conditional.
@@ -5924,7 +6094,7 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
ExprResult commonRes = UsualUnaryConversions(commonExpr);
if (commonRes.isInvalid())
return ExprError();
- commonExpr = commonRes.take();
+ commonExpr = commonRes.get();
}
opaqueValue = new (Context) OpaqueValueExpr(commonExpr->getExprLoc(),
@@ -5937,7 +6107,7 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
- ExprResult Cond = Owned(CondExpr), LHS = Owned(LHSExpr), RHS = Owned(RHSExpr);
+ ExprResult Cond = CondExpr, LHS = LHSExpr, RHS = RHSExpr;
QualType result = CheckConditionalOperands(Cond, LHS, RHS,
VK, OK, QuestionLoc);
if (result.isNull() || Cond.isInvalid() || LHS.isInvalid() ||
@@ -5948,14 +6118,13 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
RHS.get());
if (!commonExpr)
- return Owned(new (Context) ConditionalOperator(Cond.take(), QuestionLoc,
- LHS.take(), ColonLoc,
- RHS.take(), result, VK, OK));
+ return new (Context)
+ ConditionalOperator(Cond.get(), QuestionLoc, LHS.get(), ColonLoc,
+ RHS.get(), result, VK, OK);
- return Owned(new (Context)
- BinaryConditionalOperator(commonExpr, opaqueValue, Cond.take(), LHS.take(),
- RHS.take(), QuestionLoc, ColonLoc, result, VK,
- OK));
+ return new (Context) BinaryConditionalOperator(
+ commonExpr, opaqueValue, Cond.get(), LHS.get(), RHS.get(), QuestionLoc,
+ ColonLoc, result, VK, OK);
}
// checkPointerTypesForAssignment - This is a very tricky routine (despite
@@ -5971,15 +6140,16 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) {
// get the "pointed to" type (ignoring qualifiers at the top level)
const Type *lhptee, *rhptee;
Qualifiers lhq, rhq;
- llvm::tie(lhptee, lhq) = cast<PointerType>(LHSType)->getPointeeType().split();
- llvm::tie(rhptee, rhq) = cast<PointerType>(RHSType)->getPointeeType().split();
+ std::tie(lhptee, lhq) =
+ cast<PointerType>(LHSType)->getPointeeType().split().asPair();
+ std::tie(rhptee, rhq) =
+ cast<PointerType>(RHSType)->getPointeeType().split().asPair();
Sema::AssignConvertType ConvTy = Sema::Compatible;
// C99 6.5.16.1p1: This following citation is common to constraints
// 3 & 4 (below). ...and the type *pointed to* by the left has all the
// qualifiers of the type *pointed to* by the right;
- Qualifiers lq;
// As a special case, 'non-__weak A *' -> 'non-__weak const *' is okay.
if (lhq.getObjCLifetime() != rhq.getObjCLifetime() &&
@@ -6206,7 +6376,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
if (result != Compatible)
return result;
if (Kind != CK_NoOp)
- RHS = ImpCastExprToType(RHS.take(), AtomicTy->getValueType(), Kind);
+ RHS = ImpCastExprToType(RHS.get(), AtomicTy->getValueType(), Kind);
Kind = CK_NonAtomicToAtomic;
return Compatible;
}
@@ -6237,7 +6407,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
QualType elType = cast<ExtVectorType>(LHSType)->getElementType();
if (elType != RHSType) {
Kind = PrepareScalarCast(RHS, elType);
- RHS = ImpCastExprToType(RHS.take(), elType, Kind);
+ RHS = ImpCastExprToType(RHS.get(), elType, Kind);
}
Kind = CK_VectorSplat;
return Compatible;
@@ -6257,8 +6427,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// If we are allowing lax vector conversions, and LHS and RHS are both
// vectors, the total size only needs to be the same. This is a bitcast;
// no bits are changed but the result type is different.
- if (getLangOpts().LaxVectorConversions &&
- (Context.getTypeSize(LHSType) == Context.getTypeSize(RHSType))) {
+ if (isLaxVectorConversion(RHSType, LHSType)) {
Kind = CK_BitCast;
return IncompatibleVectors;
}
@@ -6389,8 +6558,9 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
return IncompatiblePointer;
}
- // T^ -> A*
- if (RHSType->isBlockPointerType()) {
+ // Only under strict condition T^ is compatible with an Objective-C pointer.
+ if (RHSType->isBlockPointerType() &&
+ isObjCPtrBlockCompatible(*this, Context, LHSType)) {
maybeExtendBlockObject(*this, RHS);
Kind = CK_BlockPointerToObjCPointerCast;
return Compatible;
@@ -6451,7 +6621,7 @@ static void ConstructTransparentUnion(Sema &S, ASTContext &C,
FieldDecl *Field) {
// Build an initializer list that designates the appropriate member
// of the transparent union.
- Expr *E = EResult.take();
+ Expr *E = EResult.get();
InitListExpr *Initializer = new (C) InitListExpr(C, SourceLocation(),
E, SourceLocation());
Initializer->setType(UnionType);
@@ -6460,9 +6630,8 @@ static void ConstructTransparentUnion(Sema &S, ASTContext &C,
// Build a compound literal constructing a value of the transparent
// union type from this initializer list.
TypeSourceInfo *unionTInfo = C.getTrivialTypeSourceInfo(UnionType);
- EResult = S.Owned(
- new (C) CompoundLiteralExpr(SourceLocation(), unionTInfo, UnionType,
- VK_RValue, Initializer, false));
+ EResult = new (C) CompoundLiteralExpr(SourceLocation(), unionTInfo, UnionType,
+ VK_RValue, Initializer, false);
}
Sema::AssignConvertType
@@ -6478,27 +6647,25 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType,
// The field to initialize within the transparent union.
RecordDecl *UD = UT->getDecl();
- FieldDecl *InitField = 0;
+ FieldDecl *InitField = nullptr;
// It's compatible if the expression matches any of the fields.
- for (RecordDecl::field_iterator it = UD->field_begin(),
- itend = UD->field_end();
- it != itend; ++it) {
+ for (auto *it : UD->fields()) {
if (it->getType()->isPointerType()) {
// If the transparent union contains a pointer type, we allow:
// 1) void pointer
// 2) null pointer constant
if (RHSType->isPointerType())
if (RHSType->castAs<PointerType>()->getPointeeType()->isVoidType()) {
- RHS = ImpCastExprToType(RHS.take(), it->getType(), CK_BitCast);
- InitField = *it;
+ RHS = ImpCastExprToType(RHS.get(), it->getType(), CK_BitCast);
+ InitField = it;
break;
}
if (RHS.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
- RHS = ImpCastExprToType(RHS.take(), it->getType(),
+ RHS = ImpCastExprToType(RHS.get(), it->getType(),
CK_NullToPointer);
- InitField = *it;
+ InitField = it;
break;
}
}
@@ -6506,8 +6673,8 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType,
CastKind Kind = CK_Invalid;
if (CheckAssignmentConstraints(it->getType(), RHS, Kind)
== Compatible) {
- RHS = ImpCastExprToType(RHS.take(), it->getType(), Kind);
- InitField = *it;
+ RHS = ImpCastExprToType(RHS.get(), it->getType(), Kind);
+ InitField = it;
break;
}
}
@@ -6571,7 +6738,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
CastKind Kind;
CXXCastPath Path;
CheckPointerConversion(RHS.get(), LHSType, Kind, Path, false);
- RHS = ImpCastExprToType(RHS.take(), LHSType, Kind, VK_RValue, &Path);
+ RHS = ImpCastExprToType(RHS.get(), LHSType, Kind, VK_RValue, &Path);
return Compatible;
}
@@ -6582,7 +6749,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
//
// Suppress this for references: C++ 8.5.3p5.
if (!LHSType->isReferenceType()) {
- RHS = DefaultFunctionArrayLvalueConversion(RHS.take());
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
if (RHS.isInvalid())
return Incompatible;
}
@@ -6599,10 +6766,18 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// does not have reference type.
if (result != Incompatible && RHS.get()->getType() != LHSType) {
QualType Ty = LHSType.getNonLValueExprType(Context);
- Expr *E = RHS.take();
+ Expr *E = RHS.get();
if (getLangOpts().ObjCAutoRefCount)
CheckObjCARCConversion(SourceRange(), Ty, E, CCK_ImplicitConversion,
DiagnoseCFAudited);
+ if (getLangOpts().ObjC1 &&
+ (CheckObjCBridgeRelatedConversions(E->getLocStart(),
+ LHSType, E->getType(), E) ||
+ ConversionToObjCStringLiteralCheck(LHSType, E))) {
+ RHS = E;
+ return Compatible;
+ }
+
RHS = ImpCastExprToType(E, Ty, Kind);
}
return result;
@@ -6616,97 +6791,128 @@ QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &LHS,
return QualType();
}
+/// Try to convert a value of non-vector type to a vector type by converting
+/// the type to the element type of the vector and then performing a splat.
+/// If the language is OpenCL, we only use conversions that promote scalar
+/// rank; for C, Obj-C, and C++ we allow any real scalar conversion except
+/// for float->int.
+///
+/// \param scalar - if non-null, actually perform the conversions
+/// \return true if the operation fails (but without diagnosing the failure)
+static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar,
+ QualType scalarTy,
+ QualType vectorEltTy,
+ QualType vectorTy) {
+ // The conversion to apply to the scalar before splatting it,
+ // if necessary.
+ CastKind scalarCast = CK_Invalid;
+
+ if (vectorEltTy->isIntegralType(S.Context)) {
+ if (!scalarTy->isIntegralType(S.Context))
+ return true;
+ if (S.getLangOpts().OpenCL &&
+ S.Context.getIntegerTypeOrder(vectorEltTy, scalarTy) < 0)
+ return true;
+ scalarCast = CK_IntegralCast;
+ } else if (vectorEltTy->isRealFloatingType()) {
+ if (scalarTy->isRealFloatingType()) {
+ if (S.getLangOpts().OpenCL &&
+ S.Context.getFloatingTypeOrder(vectorEltTy, scalarTy) < 0)
+ return true;
+ scalarCast = CK_FloatingCast;
+ }
+ else if (scalarTy->isIntegralType(S.Context))
+ scalarCast = CK_IntegralToFloating;
+ else
+ return true;
+ } else {
+ return true;
+ }
+
+ // Adjust scalar if desired.
+ if (scalar) {
+ if (scalarCast != CK_Invalid)
+ *scalar = S.ImpCastExprToType(scalar->get(), vectorEltTy, scalarCast);
+ *scalar = S.ImpCastExprToType(scalar->get(), vectorTy, CK_VectorSplat);
+ }
+ return false;
+}
+
QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, bool IsCompAssign) {
if (!IsCompAssign) {
- LHS = DefaultFunctionArrayLvalueConversion(LHS.take());
+ LHS = DefaultFunctionArrayLvalueConversion(LHS.get());
if (LHS.isInvalid())
return QualType();
}
- RHS = DefaultFunctionArrayLvalueConversion(RHS.take());
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
if (RHS.isInvalid())
return QualType();
// For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
- QualType LHSType =
- Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType();
- QualType RHSType =
- Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType();
+ QualType LHSType = LHS.get()->getType().getUnqualifiedType();
+ QualType RHSType = RHS.get()->getType().getUnqualifiedType();
// If the vector types are identical, return.
- if (LHSType == RHSType)
+ if (Context.hasSameType(LHSType, RHSType))
return LHSType;
- // Handle the case of equivalent AltiVec and GCC vector types
- if (LHSType->isVectorType() && RHSType->isVectorType() &&
+ const VectorType *LHSVecType = LHSType->getAs<VectorType>();
+ const VectorType *RHSVecType = RHSType->getAs<VectorType>();
+ assert(LHSVecType || RHSVecType);
+
+ // If we have compatible AltiVec and GCC vector types, use the AltiVec type.
+ if (LHSVecType && RHSVecType &&
Context.areCompatibleVectorTypes(LHSType, RHSType)) {
- if (LHSType->isExtVectorType()) {
- RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
+ if (isa<ExtVectorType>(LHSVecType)) {
+ RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast);
return LHSType;
}
if (!IsCompAssign)
- LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.get(), RHSType, CK_BitCast);
return RHSType;
}
- if (getLangOpts().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?
- RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
- return LHSType;
+ // If there's an ext-vector type and a scalar, try to convert the scalar to
+ // the vector element type and splat.
+ if (!RHSVecType && isa<ExtVectorType>(LHSVecType)) {
+ if (!tryVectorConvertAndSplat(*this, &RHS, RHSType,
+ LHSVecType->getElementType(), LHSType))
+ return LHSType;
+ }
+ if (!LHSVecType && isa<ExtVectorType>(RHSVecType)) {
+ if (!tryVectorConvertAndSplat(*this, (IsCompAssign ? nullptr : &LHS),
+ LHSType, RHSVecType->getElementType(),
+ RHSType))
+ return RHSType;
}
- // 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() && !IsCompAssign) {
- swapped = true;
- std::swap(RHS, LHS);
- std::swap(RHSType, LHSType);
- }
-
- // Handle the case of an ext vector and scalar.
- if (const ExtVectorType *LV = LHSType->getAs<ExtVectorType>()) {
- QualType EltTy = LV->getElementType();
- if (EltTy->isIntegralType(Context) && RHSType->isIntegralType(Context)) {
- int order = Context.getIntegerTypeOrder(EltTy, RHSType);
- if (order > 0)
- RHS = ImpCastExprToType(RHS.take(), EltTy, CK_IntegralCast);
- if (order >= 0) {
- RHS = ImpCastExprToType(RHS.take(), LHSType, CK_VectorSplat);
- if (swapped) std::swap(RHS, LHS);
- return LHSType;
- }
- }
- if (EltTy->isRealFloatingType() && RHSType->isScalarType()) {
- if (RHSType->isRealFloatingType()) {
- int order = Context.getFloatingTypeOrder(EltTy, RHSType);
- if (order > 0)
- RHS = ImpCastExprToType(RHS.take(), EltTy, CK_FloatingCast);
- if (order >= 0) {
- RHS = ImpCastExprToType(RHS.take(), LHSType, CK_VectorSplat);
- if (swapped) std::swap(RHS, LHS);
- return LHSType;
- }
- }
- if (RHSType->isIntegralType(Context)) {
- RHS = ImpCastExprToType(RHS.take(), EltTy, CK_IntegralToFloating);
- RHS = ImpCastExprToType(RHS.take(), LHSType, CK_VectorSplat);
- if (swapped) std::swap(RHS, LHS);
- return LHSType;
- }
- }
+ // If we're allowing lax vector conversions, only the total (data) size
+ // needs to be the same.
+ // FIXME: Should we really be allowing this?
+ // FIXME: We really just pick the LHS type arbitrarily?
+ if (isLaxVectorConversion(RHSType, LHSType)) {
+ QualType resultType = LHSType;
+ RHS = ImpCastExprToType(RHS.get(), resultType, CK_BitCast);
+ return resultType;
}
- // Vectors of different size or scalar and non-ext-vector are errors.
- if (swapped) std::swap(RHS, LHS);
+ // Okay, the expression is invalid.
+
+ // If there's a non-vector, non-real operand, diagnose that.
+ if ((!RHSVecType && !RHSType->isRealType()) ||
+ (!LHSVecType && !LHSType->isRealType())) {
+ Diag(Loc, diag::err_typecheck_vector_not_convertable_non_scalar)
+ << LHSType << RHSType
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+ return QualType();
+ }
+
+ // Otherwise, use the generic diagnostic.
Diag(Loc, diag::err_typecheck_vector_not_convertable)
- << LHS.get()->getType() << RHS.get()->getType()
+ << LHSType << RHSType
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return QualType();
}
@@ -7159,7 +7365,7 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
return QualType();
// Check array bounds for pointer arithemtic
- CheckArrayAccess(LHS.get(), RHS.get(), /*ArraySubscriptExpr*/0,
+ CheckArrayAccess(LHS.get(), RHS.get(), /*ArraySubscriptExpr*/nullptr,
/*AllowOnePastEnd*/true, /*IndexNegated*/true);
if (CompLHSTy) *CompLHSTy = LHS.get()->getType();
@@ -7302,14 +7508,14 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS,
// For the LHS, do usual unary conversions, but then reset them away
// if this is a compound assignment.
ExprResult OldLHS = LHS;
- LHS = UsualUnaryConversions(LHS.take());
+ LHS = UsualUnaryConversions(LHS.get());
if (LHS.isInvalid())
return QualType();
QualType LHSType = LHS.get()->getType();
if (IsCompAssign) LHS = OldLHS;
// The RHS is simpler.
- RHS = UsualUnaryConversions(RHS.take());
+ RHS = UsualUnaryConversions(RHS.get());
if (RHS.isInvalid())
return QualType();
QualType RHSType = RHS.get()->getType();
@@ -7409,7 +7615,7 @@ static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc,
(LHSType->isMemberPointerType() && RHSType->isMemberPointerType()));
bool NonStandardCompositeType = false;
- bool *BoolPtr = S.isSFINAEContext() ? 0 : &NonStandardCompositeType;
+ bool *BoolPtr = S.isSFINAEContext() ? nullptr : &NonStandardCompositeType;
QualType T = S.FindCompositePointerType(Loc, LHS, RHS, BoolPtr);
if (T.isNull()) {
diagnoseDistinctPointerComparison(S, Loc, LHS, RHS, /*isError*/true);
@@ -7421,8 +7627,8 @@ static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc,
<< LHSType << RHSType << T << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
- LHS = S.ImpCastExprToType(LHS.take(), T, CK_BitCast);
- RHS = S.ImpCastExprToType(RHS.take(), T, CK_BitCast);
+ LHS = S.ImpCastExprToType(LHS.get(), T, CK_BitCast);
+ RHS = S.ImpCastExprToType(RHS.get(), T, CK_BitCast);
return false;
}
@@ -7488,11 +7694,11 @@ static bool hasIsEqualMethod(Sema &S, const Expr *LHS, const Expr *RHS) {
if (!Method)
return false;
- QualType T = Method->param_begin()[0]->getType();
+ QualType T = Method->parameters()[0]->getType();
if (!T->isObjCObjectPointerType())
return false;
-
- QualType R = Method->getResultType();
+
+ QualType R = Method->getReturnType();
if (!R->isScalarType())
return false;
@@ -7646,7 +7852,7 @@ static ValueDecl *getCompareDecl(Expr *E) {
if (Mem->isImplicitAccess())
return Mem->getMemberDecl();
}
- return 0;
+ return nullptr;
}
// C99 6.5.8, C++ [expr.rel]
@@ -7689,7 +7895,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
ValueDecl *DL = getCompareDecl(LHSStripped);
ValueDecl *DR = getCompareDecl(RHSStripped);
if (DL && DR && DL == DR && !IsWithinTemplateSpecialization(DL)) {
- DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
+ DiagRuntimeBehavior(Loc, nullptr, PDiag(diag::warn_comparison_always)
<< 0 // self-
<< (Opc == BO_EQ
|| Opc == BO_LE
@@ -7711,7 +7917,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
always_evals_to = 2; // e.g. array1 <= array2
break;
}
- DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
+ DiagRuntimeBehavior(Loc, nullptr, PDiag(diag::warn_comparison_always)
<< 1 // array
<< always_evals_to);
}
@@ -7723,8 +7929,8 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// Warn about comparisons against a string constant (unless the other
// operand is null), the user probably wants strcmp.
- Expr *literalString = 0;
- Expr *literalStringStripped = 0;
+ Expr *literalString = nullptr;
+ Expr *literalStringStripped = nullptr;
if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) &&
!RHSStripped->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
@@ -7739,7 +7945,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
}
if (literalString) {
- DiagRuntimeBehavior(Loc, 0,
+ DiagRuntimeBehavior(Loc, nullptr,
PDiag(diag::warn_stringcompare)
<< isa<ObjCEncodeExpr>(literalStringStripped)
<< literalString->getSourceRange());
@@ -7769,10 +7975,22 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
return ResultTy;
}
- bool LHSIsNull = LHS.get()->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNull);
- bool RHSIsNull = RHS.get()->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNull);
+ const Expr::NullPointerConstantKind LHSNullKind =
+ LHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull);
+ const Expr::NullPointerConstantKind RHSNullKind =
+ RHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull);
+ bool LHSIsNull = LHSNullKind != Expr::NPCK_NotNull;
+ bool RHSIsNull = RHSNullKind != Expr::NPCK_NotNull;
+
+ if (!IsRelational && LHSIsNull != RHSIsNull) {
+ bool IsEquality = Opc == BO_EQ;
+ if (RHSIsNull)
+ DiagnoseAlwaysNonNullPointer(LHS.get(), RHSNullKind, IsEquality,
+ RHS.get()->getSourceRange());
+ else
+ DiagnoseAlwaysNonNullPointer(RHS.get(), LHSNullKind, IsEquality,
+ LHS.get()->getSourceRange());
+ }
// All of the following pointer-related warnings are GCC extensions, except
// when handling null pointer constants.
@@ -7799,7 +8017,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
if (isSFINAEContext())
return QualType();
- RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast);
return ResultTy;
}
}
@@ -7830,10 +8048,14 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, /*isError*/false);
}
if (LCanPointeeTy != RCanPointeeTy) {
+ unsigned AddrSpaceL = LCanPointeeTy.getAddressSpace();
+ unsigned AddrSpaceR = RCanPointeeTy.getAddressSpace();
+ CastKind Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion
+ : CK_BitCast;
if (LHSIsNull && !RHSIsNull)
- LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.get(), RHSType, Kind);
else
- RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.get(), LHSType, Kind);
}
return ResultTy;
}
@@ -7849,7 +8071,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
((LHSType->isAnyPointerType() || LHSType->isNullPtrType()) ||
(!IsRelational &&
(LHSType->isMemberPointerType() || LHSType->isBlockPointerType())))) {
- RHS = ImpCastExprToType(RHS.take(), LHSType,
+ RHS = ImpCastExprToType(RHS.get(), LHSType,
LHSType->isMemberPointerType()
? CK_NullToMemberPointer
: CK_NullToPointer);
@@ -7859,7 +8081,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
((RHSType->isAnyPointerType() || RHSType->isNullPtrType()) ||
(!IsRelational &&
(RHSType->isMemberPointerType() || RHSType->isBlockPointerType())))) {
- LHS = ImpCastExprToType(LHS.take(), RHSType,
+ LHS = ImpCastExprToType(LHS.get(), RHSType,
RHSType->isMemberPointerType()
? CK_NullToMemberPointer
: CK_NullToPointer);
@@ -7895,7 +8117,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
<< LHSType << RHSType << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
}
- RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast);
return ResultTy;
}
@@ -7913,11 +8135,11 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
<< RHS.get()->getSourceRange();
}
if (LHSIsNull && !RHSIsNull)
- LHS = ImpCastExprToType(LHS.take(), RHSType,
+ LHS = ImpCastExprToType(LHS.get(), RHSType,
RHSType->isPointerType() ? CK_BitCast
: CK_AnyPointerToBlockPointerCast);
else
- RHS = ImpCastExprToType(RHS.take(), LHSType,
+ RHS = ImpCastExprToType(RHS.get(), LHSType,
LHSType->isPointerType() ? CK_BitCast
: CK_AnyPointerToBlockPointerCast);
return ResultTy;
@@ -7937,16 +8159,17 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
/*isError*/false);
}
if (LHSIsNull && !RHSIsNull) {
- Expr *E = LHS.take();
+ Expr *E = LHS.get();
if (getLangOpts().ObjCAutoRefCount)
CheckObjCARCConversion(SourceRange(), RHSType, E, CCK_ImplicitConversion);
LHS = ImpCastExprToType(E, RHSType,
RPT ? CK_BitCast :CK_CPointerToObjCPointerCast);
}
else {
- Expr *E = RHS.take();
+ Expr *E = RHS.get();
if (getLangOpts().ObjCAutoRefCount)
- CheckObjCARCConversion(SourceRange(), LHSType, E, CCK_ImplicitConversion);
+ CheckObjCARCConversion(SourceRange(), LHSType, E, CCK_ImplicitConversion, false,
+ Opc);
RHS = ImpCastExprToType(E, LHSType,
LPT ? CK_BitCast :CK_CPointerToObjCPointerCast);
}
@@ -7961,9 +8184,9 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
diagnoseObjCLiteralComparison(*this, Loc, LHS, RHS, Opc);
if (LHSIsNull && !RHSIsNull)
- LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast);
+ LHS = ImpCastExprToType(LHS.get(), RHSType, CK_BitCast);
else
- RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
+ RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast);
return ResultTy;
}
}
@@ -7995,10 +8218,10 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
}
if (LHSType->isIntegerType())
- LHS = ImpCastExprToType(LHS.take(), RHSType,
+ LHS = ImpCastExprToType(LHS.get(), RHSType,
LHSIsNull ? CK_NullToPointer : CK_IntegralToPointer);
else
- RHS = ImpCastExprToType(RHS.take(), LHSType,
+ RHS = ImpCastExprToType(RHS.get(), LHSType,
RHSIsNull ? CK_NullToPointer : CK_IntegralToPointer);
return ResultTy;
}
@@ -8006,12 +8229,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// Handle block pointers.
if (!IsRelational && RHSIsNull
&& LHSType->isBlockPointerType() && RHSType->isIntegerType()) {
- RHS = ImpCastExprToType(RHS.take(), LHSType, CK_NullToPointer);
+ RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
return ResultTy;
}
if (!IsRelational && LHSIsNull
&& LHSType->isIntegerType() && RHSType->isBlockPointerType()) {
- LHS = ImpCastExprToType(LHS.take(), RHSType, CK_NullToPointer);
+ LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
return ResultTy;
}
@@ -8068,7 +8291,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
if (DeclRefExpr* DRR
= dyn_cast<DeclRefExpr>(RHS.get()->IgnoreParenImpCasts()))
if (DRL->getDecl() == DRR->getDecl())
- DiagRuntimeBehavior(Loc, 0,
+ DiagRuntimeBehavior(Loc, nullptr,
PDiag(diag::warn_comparison_always)
<< 0 // self-
<< 2 // "a constant"
@@ -8112,13 +8335,13 @@ inline QualType Sema::CheckBitwiseOperands(
return InvalidOperands(Loc, LHS, RHS);
}
- ExprResult LHSResult = Owned(LHS), RHSResult = Owned(RHS);
+ ExprResult LHSResult = LHS, RHSResult = RHS;
QualType compType = UsualArithmeticConversions(LHSResult, RHSResult,
IsCompAssign);
if (LHSResult.isInvalid() || RHSResult.isInvalid())
return QualType();
- LHS = LHSResult.take();
- RHS = RHSResult.take();
+ LHS = LHSResult.get();
+ RHS = RHSResult.get();
if (!compType.isNull() && compType->isIntegralOrUnscopedEnumerationType())
return compType;
@@ -8146,7 +8369,8 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
// Parens on the RHS are ignored.
llvm::APSInt Result;
if (RHS.get()->EvaluateAsInt(Result, Context))
- if ((getLangOpts().Bool && !RHS.get()->getType()->isBooleanType()) ||
+ if ((getLangOpts().Bool && !RHS.get()->getType()->isBooleanType() &&
+ !RHS.get()->getExprLoc().isMacroID()) ||
(Result != 0 && Result != 1)) {
Diag(Loc, diag::warn_logical_instead_of_bitwise)
<< RHS.get()->getSourceRange()
@@ -8180,11 +8404,11 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
return InvalidOperands(Loc, LHS, RHS);
}
- LHS = UsualUnaryConversions(LHS.take());
+ LHS = UsualUnaryConversions(LHS.get());
if (LHS.isInvalid())
return QualType();
- RHS = UsualUnaryConversions(RHS.take());
+ RHS = UsualUnaryConversions(RHS.get());
if (RHS.isInvalid())
return QualType();
@@ -8224,7 +8448,7 @@ static bool IsReadonlyMessage(Expr *E, Sema &S) {
ObjCMessageExpr *Base =
dyn_cast<ObjCMessageExpr>(ME->getBase()->IgnoreParenImpCasts());
if (!Base) return false;
- return Base->getMethodDecl() != 0;
+ return Base->getMethodDecl() != nullptr;
}
/// Is the given expression (which must be 'const') a reference to a
@@ -8247,7 +8471,7 @@ static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) {
assert(var->hasLocalStorage() && "capture added 'const' to non-local?");
// Decide whether the first capture was for a block or a lambda.
- DeclContext *DC = S.CurContext, *Prev = 0;
+ DeclContext *DC = S.CurContext, *Prev = nullptr;
while (DC != var->getDeclContext()) {
Prev = DC;
DC = DC->getParent();
@@ -8464,10 +8688,8 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
// we do not warn to warn spuriously when 'x' and 'y' are on separate
// paths through the function. This should be revisited if
// -Wrepeated-use-of-weak is made flow-sensitive.
- DiagnosticsEngine::Level Level =
- Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
- RHS.get()->getLocStart());
- if (Level != DiagnosticsEngine::Ignored)
+ if (!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak,
+ RHS.get()->getLocStart()))
getCurFunction()->markSafeWeakUse(RHS.get());
} else if (getLangOpts().ObjCAutoRefCount) {
@@ -8499,8 +8721,8 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
// C99 6.5.17
static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc) {
- LHS = S.CheckPlaceholderExpr(LHS.take());
- RHS = S.CheckPlaceholderExpr(RHS.take());
+ LHS = S.CheckPlaceholderExpr(LHS.get());
+ RHS = S.CheckPlaceholderExpr(RHS.get());
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
@@ -8510,14 +8732,14 @@ static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS,
// So we treat the LHS as a ignored value, and in C++ we allow the
// containing site to determine what should be done with the RHS.
- LHS = S.IgnoredValueConversions(LHS.take());
+ LHS = S.IgnoredValueConversions(LHS.get());
if (LHS.isInvalid())
return QualType();
S.DiagnoseUnusedExprResult(LHS.get());
if (!S.getLangOpts().CPlusPlus) {
- RHS = S.DefaultFunctionArrayLvalueConversion(RHS.take());
+ RHS = S.DefaultFunctionArrayLvalueConversion(RHS.get());
if (RHS.isInvalid())
return QualType();
if (!RHS.get()->getType()->isVoidType())
@@ -8577,7 +8799,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
} else if (ResType->isPlaceholderType()) {
ExprResult PR = S.CheckPlaceholderExpr(Op);
if (PR.isInvalid()) return QualType();
- return CheckIncrementDecrementOperand(S, PR.take(), VK, OpLoc,
+ return CheckIncrementDecrementOperand(S, PR.get(), VK, OpLoc,
IsInc, IsPrefix);
} else if (S.getLangOpts().AltiVec && ResType->isVectorType()) {
// OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 )
@@ -8627,7 +8849,7 @@ static ValueDecl *getPrimaryDecl(Expr *E) {
// the base's value, so the object the base refers to is
// irrelevant.
if (cast<MemberExpr>(E)->isArrow())
- return 0;
+ return nullptr;
// Otherwise, the expression refers to a part of the base
return getPrimaryDecl(cast<MemberExpr>(E)->getBase());
case Stmt::ArraySubscriptExprClass: {
@@ -8638,7 +8860,7 @@ static ValueDecl *getPrimaryDecl(Expr *E) {
if (ICE->getSubExpr()->getType()->isArrayType())
return getPrimaryDecl(ICE->getSubExpr());
}
- return 0;
+ return nullptr;
}
case Stmt::UnaryOperatorClass: {
UnaryOperator *UO = cast<UnaryOperator>(E);
@@ -8649,7 +8871,7 @@ static ValueDecl *getPrimaryDecl(Expr *E) {
case UO_Extension:
return getPrimaryDecl(UO->getSubExpr());
default:
- return 0;
+ return nullptr;
}
}
case Stmt::ParenExprClass:
@@ -8659,7 +8881,7 @@ static ValueDecl *getPrimaryDecl(Expr *E) {
// the sub-expression; otherwise, the result here doesn't matter.
return getPrimaryDecl(cast<ImplicitCastExpr>(E)->getSubExpr());
default:
- return 0;
+ return nullptr;
}
}
@@ -8718,7 +8940,7 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
return QualType();
}
- OrigOp = CheckPlaceholderExpr(OrigOp.take());
+ OrigOp = CheckPlaceholderExpr(OrigOp.get());
if (OrigOp.isInvalid()) return QualType();
}
@@ -8730,6 +8952,12 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
// Make sure to ignore parentheses in subsequent checks
Expr *op = OrigOp.get()->IgnoreParens();
+ // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed.
+ if (LangOpts.OpenCL && op->getType()->isFunctionType()) {
+ Diag(op->getExprLoc(), diag::err_opencl_taking_function_address);
+ return QualType();
+ }
+
if (getLangOpts().C99) {
// Implement C99-only parts of addressof rules.
if (UnaryOperator* uOp = dyn_cast<UnaryOperator>(op)) {
@@ -8754,7 +8982,7 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
return QualType();
// Materialize the temporary as an lvalue so that we can take its address.
OrigOp = op = new (Context)
- MaterializeTemporaryExpr(op->getType(), OrigOp.take(), true, 0);
+ MaterializeTemporaryExpr(op->getType(), OrigOp.get(), true);
} else if (isa<ObjCSelectorExpr>(op)) {
return Context.getPointerType(op->getType());
} else if (lval == Expr::LV_MemberFunction) {
@@ -8793,8 +9021,11 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
if (isa<CXXDestructorDecl>(MD))
Diag(OpLoc, diag::err_typecheck_addrof_dtor) << op->getSourceRange();
- return Context.getMemberPointerType(op->getType(),
- Context.getTypeDeclType(MD->getParent()).getTypePtr());
+ QualType MPTy = Context.getMemberPointerType(
+ op->getType(), Context.getTypeDeclType(MD->getParent()).getTypePtr());
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft())
+ RequireCompleteType(OpLoc, MPTy, 0);
+ return MPTy;
} else if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) {
// C99 6.5.3.2p1
// The operand must be either an l-value or a function designator
@@ -8842,8 +9073,13 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
while (cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion())
Ctx = Ctx->getParent();
- return Context.getMemberPointerType(op->getType(),
- Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr());
+
+ QualType MPTy = Context.getMemberPointerType(
+ op->getType(),
+ Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr());
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft())
+ RequireCompleteType(OpLoc, MPTy, 0);
+ return MPTy;
}
}
} else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl))
@@ -8877,7 +9113,7 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
ExprResult ConvResult = S.UsualUnaryConversions(Op);
if (ConvResult.isInvalid())
return QualType();
- Op = ConvResult.take();
+ Op = ConvResult.get();
QualType OpTy = Op->getType();
QualType Result;
@@ -8887,10 +9123,6 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
Op->getSourceRange());
}
- // Note that per both C89 and C99, indirection is always legal, even if OpTy
- // is an incomplete type or void. It would be possible to warn about
- // dereferencing a void pointer, but it's completely well-defined, and such a
- // warning is unlikely to catch any mistakes.
if (const PointerType *PT = OpTy->getAs<PointerType>())
Result = PT->getPointeeType();
else if (const ObjCObjectPointerType *OPT =
@@ -8899,8 +9131,8 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
else {
ExprResult PR = S.CheckPlaceholderExpr(Op);
if (PR.isInvalid()) return QualType();
- if (PR.take() != Op)
- return CheckIndirectionOperand(S, PR.take(), VK, OpLoc);
+ if (PR.get() != Op)
+ return CheckIndirectionOperand(S, PR.get(), VK, OpLoc);
}
if (Result.isNull()) {
@@ -8909,6 +9141,19 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
return QualType();
}
+ // Note that per both C89 and C99, indirection is always legal, even if Result
+ // is an incomplete type or void. It would be possible to warn about
+ // dereferencing a void pointer, but it's completely well-defined, and such a
+ // warning is unlikely to catch any mistakes. In C++, indirection is not valid
+ // for pointers to 'void' but is fine for any other pointer type:
+ //
+ // C++ [expr.unary.op]p1:
+ // [...] the expression to which [the unary * operator] is applied shall
+ // be a pointer to an object type, or a pointer to a function type
+ if (S.getLangOpts().CPlusPlus && Result->isVoidType())
+ S.Diag(OpLoc, diag::ext_typecheck_indirection_through_void_pointer)
+ << OpTy << Op->getSourceRange();
+
// Dereferences are usually l-values...
VK = VK_LValue;
@@ -9021,7 +9266,7 @@ static void checkObjCPointerIntrospection(Sema &S, ExprResult &L, ExprResult &R,
if (!S.getLangOpts().ObjC1)
return;
- const Expr *ObjCPointerExpr = 0, *OtherExpr = 0;
+ const Expr *ObjCPointerExpr = nullptr, *OtherExpr = nullptr;
const Expr *LHS = L.get();
const Expr *RHS = R.get();
@@ -9078,10 +9323,10 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
ExprResult Init = InitSeq.Perform(*this, Entity, Kind, RHSExpr);
if (Init.isInvalid())
return Init;
- RHSExpr = Init.take();
+ RHSExpr = Init.get();
}
- ExprResult LHS = Owned(LHSExpr), RHS = Owned(RHSExpr);
+ ExprResult LHS = LHSExpr, RHS = RHSExpr;
QualType ResultTy; // Result type of the binary operator.
// The following two variables are used for compound assignment operators
QualType CompLHSTy; // Type of LHS after promotions for computation
@@ -9175,8 +9420,9 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
break;
case BO_AndAssign:
+ case BO_OrAssign: // fallthrough
+ DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc);
case BO_XorAssign:
- case BO_OrAssign:
CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, true);
CompLHSTy = CompResultTy;
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
@@ -9216,18 +9462,16 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
DiagnoseDirectIsaAccess(*this, OIRE, OpLoc, RHS.get());
if (CompResultTy.isNull())
- return Owned(new (Context) BinaryOperator(LHS.take(), RHS.take(), Opc,
- ResultTy, VK, OK, OpLoc,
- FPFeatures.fp_contract));
+ return new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, ResultTy, VK,
+ OK, OpLoc, FPFeatures.fp_contract);
if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() !=
OK_ObjCProperty) {
VK = VK_LValue;
OK = LHS.get()->getObjectKind();
}
- return Owned(new (Context) CompoundAssignOperator(LHS.take(), RHS.take(), Opc,
- ResultTy, VK, OK, CompLHSTy,
- CompResultTy, OpLoc,
- FPFeatures.fp_contract));
+ return new (Context) CompoundAssignOperator(
+ LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, CompLHSTy, CompResultTy,
+ OpLoc, FPFeatures.fp_contract);
}
/// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison
@@ -9445,8 +9689,8 @@ ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
tok::TokenKind Kind,
Expr *LHSExpr, Expr *RHSExpr) {
BinaryOperatorKind Opc = ConvertTokenKindToBinaryOpcode(Kind);
- assert((LHSExpr != 0) && "ActOnBinOp(): missing left expression");
- assert((RHSExpr != 0) && "ActOnBinOp(): missing right expression");
+ assert(LHSExpr && "ActOnBinOp(): missing left expression");
+ assert(RHSExpr && "ActOnBinOp(): missing right expression");
// Emit warnings for tricky precedence issues, e.g. "bitfield & 0x4 == 0"
DiagnoseBinOpPrecedence(*this, Opc, TokLoc, LHSExpr, RHSExpr);
@@ -9499,7 +9743,7 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
// instantiates to having an overloadable type.
ExprResult resolvedRHS = CheckPlaceholderExpr(RHSExpr);
if (resolvedRHS.isInvalid()) return ExprError();
- RHSExpr = resolvedRHS.take();
+ RHSExpr = resolvedRHS.get();
if (RHSExpr->isTypeDependent() ||
RHSExpr->getType()->isOverloadableType())
@@ -9508,7 +9752,7 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
ExprResult LHS = CheckPlaceholderExpr(LHSExpr);
if (LHS.isInvalid()) return ExprError();
- LHSExpr = LHS.take();
+ LHSExpr = LHS.get();
}
// Handle pseudo-objects in the RHS.
@@ -9532,7 +9776,7 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
ExprResult resolvedRHS = CheckPlaceholderExpr(RHSExpr);
if (!resolvedRHS.isUsable()) return ExprError();
- RHSExpr = resolvedRHS.take();
+ RHSExpr = resolvedRHS.get();
}
if (getLangOpts().CPlusPlus) {
@@ -9555,7 +9799,7 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
UnaryOperatorKind Opc,
Expr *InputExpr) {
- ExprResult Input = Owned(InputExpr);
+ ExprResult Input = InputExpr;
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
QualType resultType;
@@ -9574,14 +9818,14 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
resultType = CheckAddressOfOperand(Input, OpLoc);
break;
case UO_Deref: {
- Input = DefaultFunctionArrayLvalueConversion(Input.take());
+ Input = DefaultFunctionArrayLvalueConversion(Input.get());
if (Input.isInvalid()) return ExprError();
resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc);
break;
}
case UO_Plus:
case UO_Minus:
- Input = UsualUnaryConversions(Input.take());
+ Input = UsualUnaryConversions(Input.get());
if (Input.isInvalid()) return ExprError();
resultType = Input.get()->getType();
if (resultType->isDependentType())
@@ -9598,7 +9842,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
<< resultType << Input.get()->getSourceRange());
case UO_Not: // bitwise complement
- Input = UsualUnaryConversions(Input.take());
+ Input = UsualUnaryConversions(Input.get());
if (Input.isInvalid())
return ExprError();
resultType = Input.get()->getType();
@@ -9629,24 +9873,24 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
case UO_LNot: // logical negation
// Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5).
- Input = DefaultFunctionArrayLvalueConversion(Input.take());
+ Input = DefaultFunctionArrayLvalueConversion(Input.get());
if (Input.isInvalid()) return ExprError();
resultType = Input.get()->getType();
// Though we still have to promote half FP to float...
if (resultType->isHalfType() && !Context.getLangOpts().NativeHalfType) {
- Input = ImpCastExprToType(Input.take(), Context.FloatTy, CK_FloatingCast).take();
+ Input = ImpCastExprToType(Input.get(), Context.FloatTy, CK_FloatingCast).get();
resultType = Context.FloatTy;
}
if (resultType->isDependentType())
break;
- if (resultType->isScalarType()) {
+ if (resultType->isScalarType() && !isScopedEnumerationType(resultType)) {
// C99 6.5.3.3p1: ok, fallthrough;
if (Context.getLangOpts().CPlusPlus) {
// C++03 [expr.unary.op]p8, C++0x [expr.unary.op]p9:
// operand contextually converted to bool.
- Input = ImpCastExprToType(Input.take(), Context.BoolTy,
+ Input = ImpCastExprToType(Input.get(), Context.BoolTy,
ScalarTypeToBooleanCastKind(resultType));
} else if (Context.getLangOpts().OpenCL &&
Context.getLangOpts().OpenCLVersion < 120) {
@@ -9690,7 +9934,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
VK = Input.get()->getValueKind();
} else if (!getLangOpts().CPlusPlus) {
// In C, a volatile scalar is read by __imag. In C++, it is not.
- Input = DefaultLvalueConversion(Input.take());
+ Input = DefaultLvalueConversion(Input.get());
}
break;
case UO_Extension:
@@ -9709,8 +9953,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
if (Opc != UO_AddrOf && Opc != UO_Deref)
CheckArrayAccess(Input.get());
- return Owned(new (Context) UnaryOperator(Input.take(), Opc, resultType,
- VK, OK, OpLoc));
+ return new (Context)
+ UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc);
}
/// \brief Determine whether the given expression is a qualified member
@@ -9780,7 +10024,7 @@ ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
// Anything else needs to be handled now.
ExprResult Result = CheckPlaceholderExpr(Input);
if (Result.isInvalid()) return ExprError();
- Input = Result.take();
+ Input = Result.get();
}
if (getLangOpts().CPlusPlus && Input->getType()->isOverloadableType() &&
@@ -9813,8 +10057,8 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
LabelDecl *TheDecl) {
TheDecl->markUsed(Context);
// Create the AST node. The address of a label always has type 'void*'.
- return Owned(new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl,
- Context.getPointerType(Context.VoidTy)));
+ return new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl,
+ Context.getPointerType(Context.VoidTy));
}
/// Given the last statement in a statement-expression, check whether
@@ -9825,11 +10069,11 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
static Expr *maybeRebuildARCConsumingStmt(Stmt *Statement) {
// Should always be wrapped with one of these.
ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(Statement);
- if (!cleanups) return 0;
+ if (!cleanups) return nullptr;
ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(cleanups->getSubExpr());
if (!cast || cast->getCastKind() != CK_ARCConsumeObject)
- return 0;
+ return nullptr;
// Splice out the cast. This shouldn't modify any interesting
// features of the statement.
@@ -9864,7 +10108,7 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
PopExpressionEvaluationContext();
bool isFileScope
- = (getCurFunctionOrMethodDecl() == 0) && (getCurBlock() == 0);
+ = (getCurFunctionOrMethodDecl() == nullptr) && (getCurBlock() == nullptr);
if (isFileScope)
return ExprError(Diag(LPLoc, diag::err_stmtexpr_file_scope));
@@ -9872,13 +10116,13 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
// example, it is not possible to goto into a stmt expression apparently.
// More semantic analysis is needed.
- // If there are sub stmts in the compound stmt, take the type of the last one
+ // If there are sub-stmts in the compound stmt, take the type of the last one
// as the type of the stmtexpr.
QualType Ty = Context.VoidTy;
bool StmtExprMayBindToTemp = false;
if (!Compound->body_empty()) {
Stmt *LastStmt = Compound->body_back();
- LabelStmt *LastLabelStmt = 0;
+ LabelStmt *LastLabelStmt = nullptr;
// If LastStmt is a label, skip down through into the body.
while (LabelStmt *Label = dyn_cast<LabelStmt>(LastStmt)) {
LastLabelStmt = Label;
@@ -9914,11 +10158,11 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
if (LastExpr.isInvalid())
return ExprError();
- if (LastExpr.get() != 0) {
+ if (LastExpr.get() != nullptr) {
if (!LastLabelStmt)
- Compound->setLastStmt(LastExpr.take());
+ Compound->setLastStmt(LastExpr.get());
else
- LastLabelStmt->setSubStmt(LastExpr.take());
+ LastLabelStmt->setSubStmt(LastExpr.get());
StmtExprMayBindToTemp = true;
}
}
@@ -9930,7 +10174,7 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
Expr *ResStmtExpr = new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc);
if (StmtExprMayBindToTemp)
return MaybeBindToTemporary(ResStmtExpr);
- return Owned(ResStmtExpr);
+ return ResStmtExpr;
}
ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
@@ -9985,7 +10229,7 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
ExprResult IdxRval = DefaultLvalueConversion(static_cast<Expr*>(OC.U.E));
if (IdxRval.isInvalid())
return ExprError();
- Expr *Idx = IdxRval.take();
+ Expr *Idx = IdxRval.get();
// The expression must be an integral expression.
// FIXME: An integral constant expression?
@@ -10032,11 +10276,11 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
bool IsSafe = LangOpts.CPlusPlus11? CRD->isStandardLayout() : CRD->isPOD();
unsigned DiagID =
- LangOpts.CPlusPlus11? diag::warn_offsetof_non_standardlayout_type
- : diag::warn_offsetof_non_pod_type;
+ LangOpts.CPlusPlus11? diag::ext_offsetof_non_standardlayout_type
+ : diag::ext_offsetof_non_pod_type;
if (!IsSafe && !DidWarnAboutNonPOD &&
- DiagRuntimeBehavior(BuiltinLoc, 0,
+ DiagRuntimeBehavior(BuiltinLoc, nullptr,
PDiag(DiagID)
<< SourceRange(CompPtr[0].LocStart, OC.LocEnd)
<< CurrentType))
@@ -10047,7 +10291,7 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName);
LookupQualifiedName(R, RD);
FieldDecl *MemberDecl = R.getAsSingle<FieldDecl>();
- IndirectFieldDecl *IndirectMemberDecl = 0;
+ IndirectFieldDecl *IndirectMemberDecl = nullptr;
if (!MemberDecl) {
if ((IndirectMemberDecl = R.getAsSingle<IndirectFieldDecl>()))
MemberDecl = IndirectMemberDecl->getAnonField();
@@ -10092,12 +10336,10 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
}
if (IndirectMemberDecl) {
- for (IndirectFieldDecl::chain_iterator FI =
- IndirectMemberDecl->chain_begin(),
- FEnd = IndirectMemberDecl->chain_end(); FI != FEnd; FI++) {
- assert(isa<FieldDecl>(*FI));
+ for (auto *FI : IndirectMemberDecl->chain()) {
+ assert(isa<FieldDecl>(FI));
Comps.push_back(OffsetOfNode(OC.LocStart,
- cast<FieldDecl>(*FI), OC.LocEnd));
+ cast<FieldDecl>(FI), OC.LocEnd));
}
} else
Comps.push_back(OffsetOfNode(OC.LocStart, MemberDecl, OC.LocEnd));
@@ -10105,8 +10347,8 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
CurrentType = MemberDecl->getType().getNonReferenceType();
}
- return Owned(OffsetOfExpr::Create(Context, Context.getSizeType(), BuiltinLoc,
- TInfo, Comps, Exprs, RParenLoc));
+ return OffsetOfExpr::Create(Context, Context.getSizeType(), BuiltinLoc, TInfo,
+ Comps, Exprs, RParenLoc);
}
ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
@@ -10152,7 +10394,7 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
diag::err_typecheck_choose_expr_requires_constant, false);
if (CondICE.isInvalid())
return ExprError();
- CondExpr = CondICE.take();
+ CondExpr = CondICE.get();
CondIsTrue = condEval.getZExtValue();
// If the condition is > zero, then the AST type is the same as the LSHExpr.
@@ -10164,10 +10406,9 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
OK = ActiveExpr->getObjectKind();
}
- return Owned(new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr,
- resType, VK, OK, RPLoc, CondIsTrue,
- resType->isDependentType(),
- ValueDependent));
+ return new (Context)
+ ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, resType, VK, OK, RPLoc,
+ CondIsTrue, resType->isDependentType(), ValueDependent);
}
//===----------------------------------------------------------------------===//
@@ -10204,7 +10445,8 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {
void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
Scope *CurScope) {
- assert(ParamInfo.getIdentifier()==0 && "block-id should have no identifier!");
+ assert(ParamInfo.getIdentifier() == nullptr &&
+ "block-id should have no identifier!");
assert(ParamInfo.getContext() == Declarator::BlockLiteralContext);
BlockScopeInfo *CurBlock = getCurBlock();
@@ -10241,7 +10483,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
ExplicitSignature.getLocalRangeEnd()) {
// This would be much cheaper if we stored TypeLocs instead of
// TypeSourceInfos.
- TypeLoc Result = ExplicitSignature.getResultLoc();
+ TypeLoc Result = ExplicitSignature.getReturnLoc();
unsigned Size = Result.getFullDataSize();
Sig = Context.CreateTypeSourceInfo(Result.getType(), Size);
Sig->getTypeLoc().initializeFullCopy(Result, Size);
@@ -10254,7 +10496,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
CurBlock->FunctionType = T;
const FunctionType *Fn = T->getAs<FunctionType>();
- QualType RetTy = Fn->getResultType();
+ QualType RetTy = Fn->getReturnType();
bool isVariadic =
(isa<FunctionProtoType>(Fn) && cast<FunctionProtoType>(Fn)->isVariadic());
@@ -10273,9 +10515,9 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
// Push block parameters from the declarator if we had them.
SmallVector<ParmVarDecl*, 8> Params;
if (ExplicitSignature) {
- for (unsigned I = 0, E = ExplicitSignature.getNumArgs(); I != E; ++I) {
- ParmVarDecl *Param = ExplicitSignature.getArg(I);
- if (Param->getIdentifier() == 0 &&
+ for (unsigned I = 0, E = ExplicitSignature.getNumParams(); I != E; ++I) {
+ ParmVarDecl *Param = ExplicitSignature.getParam(I);
+ if (Param->getIdentifier() == nullptr &&
!Param->isImplicit() &&
!Param->isInvalidDecl() &&
!getLangOpts().CPlusPlus)
@@ -10286,12 +10528,9 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
// Fake up parameter variables if we have a typedef, like
// ^ fntype { ... }
} else if (const FunctionProtoType *Fn = T->getAs<FunctionProtoType>()) {
- for (FunctionProtoType::arg_type_iterator
- I = Fn->arg_type_begin(), E = Fn->arg_type_end(); I != E; ++I) {
- ParmVarDecl *Param =
- BuildParmVarDeclForTypedef(CurBlock->TheDecl,
- ParamInfo.getLocStart(),
- *I);
+ for (const auto &I : Fn->param_types()) {
+ ParmVarDecl *Param = BuildParmVarDeclForTypedef(
+ CurBlock->TheDecl, ParamInfo.getLocStart(), I);
Params.push_back(Param);
}
}
@@ -10308,15 +10547,14 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
// Put the parameter variables in scope.
- for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(),
- E = CurBlock->TheDecl->param_end(); AI != E; ++AI) {
- (*AI)->setOwningFunction(CurBlock->TheDecl);
+ for (auto AI : CurBlock->TheDecl->params()) {
+ AI->setOwningFunction(CurBlock->TheDecl);
// If this has an identifier, add it to the scope stack.
- if ((*AI)->getIdentifier()) {
- CheckShadow(CurBlock->TheScope, *AI);
+ if (AI->getIdentifier()) {
+ CheckShadow(CurBlock->TheScope, AI);
- PushOnScopeChains(*AI, CurBlock->TheScope);
+ PushOnScopeChains(AI, CurBlock->TheScope);
}
}
}
@@ -10358,7 +10596,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (!BSI->ReturnType.isNull())
RetTy = BSI->ReturnType;
- bool NoReturn = BSI->TheDecl->getAttr<NoReturnAttr>();
+ bool NoReturn = BSI->TheDecl->hasAttr<NoReturnAttr>();
QualType BlockTy;
// Set the captured variables on the block.
@@ -10390,7 +10628,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
// Otherwise, if we don't need to change anything about the function type,
// preserve its sugar structure.
- } else if (FTy->getResultType() == RetTy &&
+ } else if (FTy->getReturnType() == RetTy &&
(!NoReturn || FTy->getNoReturnAttr())) {
BlockTy = BSI->FunctionType;
@@ -10400,7 +10638,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.TypeQuals = 0; // FIXME: silently?
EPI.ExtInfo = Ext;
- BlockTy = Context.getFunctionType(RetTy, FPT->getArgTypes(), EPI);
+ BlockTy = Context.getFunctionType(RetTy, FPT->getParamTypes(), EPI);
}
// If we don't have a function type, just build one from nothing.
@@ -10416,7 +10654,6 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
// If needed, diagnose invalid gotos and switches in the block.
if (getCurFunction()->NeedsScopeChecking() &&
- !hasAnyUnrecoverableErrorsInThisFunction() &&
!PP.isCodeCompletionEnabled())
DiagnoseInvalidJumps(cast<CompoundStmt>(Body));
@@ -10427,7 +10664,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
// to deduce an implicit return type.
if (getLangOpts().CPlusPlus && RetTy->isRecordType() &&
!BSI->TheDecl->isDependentContext())
- computeNRVO(Body, getCurBlock());
+ computeNRVO(Body, BSI);
BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
@@ -10442,10 +10679,8 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
// It also gets a branch-protected scope if any of the captured
// variables needs destruction.
- for (BlockDecl::capture_const_iterator
- ci = Result->getBlockDecl()->capture_begin(),
- ce = Result->getBlockDecl()->capture_end(); ci != ce; ++ci) {
- const VarDecl *var = ci->getVariable();
+ for (const auto &CI : Result->getBlockDecl()->captures()) {
+ const VarDecl *var = CI.getVariable();
if (var->getType().isDestructedType() != QualType::DK_none) {
getCurFunction()->setHasBranchProtectedScope();
break;
@@ -10453,7 +10688,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
}
}
- return Owned(Result);
+ return Result;
}
ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
@@ -10480,7 +10715,7 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
ExprResult Result = UsualUnaryConversions(E);
if (Result.isInvalid())
return ExprError();
- E = Result.take();
+ E = Result.get();
} else if (VaListType->isRecordType() && getLangOpts().CPlusPlus) {
// If va_list is a record type and we are compiling in C++ mode,
// check the argument using reference binding.
@@ -10490,7 +10725,7 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
ExprResult Init = PerformCopyInitialization(Entity, SourceLocation(), E);
if (Init.isInvalid())
return ExprError();
- E = Init.takeAs<Expr>();
+ E = Init.getAs<Expr>();
} else {
// Otherwise, the va_list argument must be an l-value because
// it is modified by va_arg.
@@ -10546,7 +10781,7 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
}
QualType T = TInfo->getType().getNonLValueExprType(Context);
- return Owned(new (Context) VAArgExpr(BuiltinLoc, E, TInfo, RPLoc, T));
+ return new (Context) VAArgExpr(BuiltinLoc, E, TInfo, RPLoc, T);
}
ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
@@ -10564,41 +10799,40 @@ ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
llvm_unreachable("I don't know size of pointer!");
}
- return Owned(new (Context) GNUNullExpr(Ty, TokenLoc));
+ return new (Context) GNUNullExpr(Ty, TokenLoc);
}
-static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType,
- Expr *SrcExpr, FixItHint &Hint,
- bool &IsNSString) {
- if (!SemaRef.getLangOpts().ObjC1)
- return;
+bool
+Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp) {
+ if (!getLangOpts().ObjC1)
+ return false;
const ObjCObjectPointerType *PT = DstType->getAs<ObjCObjectPointerType>();
if (!PT)
- return;
+ return false;
- // Check if the destination is of type 'id'.
if (!PT->isObjCIdType()) {
// Check if the destination is the 'NSString' interface.
const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
if (!ID || !ID->getIdentifier()->isStr("NSString"))
- return;
- IsNSString = true;
+ return false;
}
-
+
// Ignore any parens, implicit casts (should only be
// array-to-pointer decays), and not-so-opaque values. The last is
// important for making this trigger for property assignments.
- SrcExpr = SrcExpr->IgnoreParenImpCasts();
+ Expr *SrcExpr = Exp->IgnoreParenImpCasts();
if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(SrcExpr))
if (OV->getSourceExpr())
SrcExpr = OV->getSourceExpr()->IgnoreParenImpCasts();
StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr);
if (!SL || !SL->isAscii())
- return;
-
- Hint = FixItHint::CreateInsertion(SL->getLocStart(), "@");
+ return false;
+ Diag(SL->getLocStart(), diag::err_missing_atsign_prefix)
+ << FixItHint::CreateInsertion(SL->getLocStart(), "@");
+ Exp = BuildObjCStringLiteral(SL->getLocStart(), SL).get();
+ return true;
}
bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
@@ -10617,7 +10851,8 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
ConversionFixItGenerator ConvHints;
bool MayHaveConvFixit = false;
bool MayHaveFunctionDiff = false;
- bool IsNSString = false;
+ const ObjCInterfaceDecl *IFace = nullptr;
+ const ObjCProtocolDecl *PDecl = nullptr;
switch (ConvTy) {
case Compatible:
@@ -10635,7 +10870,6 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
MayHaveConvFixit = true;
break;
case IncompatiblePointer:
- MakeObjCStringLiteralFixItHint(*this, DstType, SrcExpr, Hint, IsNSString);
DiagKind =
(Action == AA_Passing_CFAudited ?
diag::err_arc_typecheck_convert_incompatible_pointer :
@@ -10649,8 +10883,6 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
SrcType = SrcType.getUnqualifiedType();
DstType = DstType.getUnqualifiedType();
}
- else if (IsNSString && !Hint.isNull())
- DiagKind = diag::warn_missing_atsign_prefix;
MayHaveConvFixit = true;
break;
case IncompatiblePointerSign:
@@ -10702,11 +10934,32 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
case IncompatibleBlockPointer:
DiagKind = diag::err_typecheck_convert_incompatible_block_pointer;
break;
- case IncompatibleObjCQualifiedId:
- // FIXME: Diagnose the problem in ObjCQualifiedIdTypesAreCompatible, since
- // it can give a more specific diagnostic.
+ case IncompatibleObjCQualifiedId: {
+ if (SrcType->isObjCQualifiedIdType()) {
+ const ObjCObjectPointerType *srcOPT =
+ SrcType->getAs<ObjCObjectPointerType>();
+ for (auto *srcProto : srcOPT->quals()) {
+ PDecl = srcProto;
+ break;
+ }
+ if (const ObjCInterfaceType *IFaceT =
+ DstType->getAs<ObjCObjectPointerType>()->getInterfaceType())
+ IFace = IFaceT->getDecl();
+ }
+ else if (DstType->isObjCQualifiedIdType()) {
+ const ObjCObjectPointerType *dstOPT =
+ DstType->getAs<ObjCObjectPointerType>();
+ for (auto *dstProto : dstOPT->quals()) {
+ PDecl = dstProto;
+ break;
+ }
+ if (const ObjCInterfaceType *IFaceT =
+ SrcType->getAs<ObjCObjectPointerType>()->getInterfaceType())
+ IFace = IFaceT->getDecl();
+ }
DiagKind = diag::warn_incompatible_qualified_id;
break;
+ }
case IncompatibleVectors:
DiagKind = diag::warn_incompatible_vectors;
break;
@@ -10764,7 +11017,11 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
HandleFunctionTypeMismatch(FDiag, SecondType, FirstType);
Diag(Loc, FDiag);
-
+ if (DiagKind == diag::warn_incompatible_qualified_id &&
+ PDecl && IFace && !IFace->hasDefinition())
+ Diag(IFace->getLocation(), diag::not_incomplete_class_and_qualified_id)
+ << IFace->getName() << PDecl->getName();
+
if (SecondType == Context.OverloadTy)
NoteAllOverloadCandidates(OverloadExpr::find(SrcExpr).Expression,
FirstType);
@@ -10784,7 +11041,7 @@ ExprResult Sema::VerifyIntegerConstantExpression(Expr *E,
llvm::APSInt *Result) {
class SimpleICEDiagnoser : public VerifyICEDiagnoser {
public:
- virtual void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) {
+ void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) override {
S.Diag(Loc, diag::err_expr_not_ice) << S.LangOpts.CPlusPlus << SR;
}
} Diagnoser;
@@ -10803,7 +11060,7 @@ ExprResult Sema::VerifyIntegerConstantExpression(Expr *E,
IDDiagnoser(unsigned DiagID)
: VerifyICEDiagnoser(DiagID == 0), DiagID(DiagID) { }
- virtual void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) {
+ void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) override {
S.Diag(Loc, DiagID) << SR;
}
} Diagnoser(DiagID);
@@ -10835,40 +11092,40 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
: ICEConvertDiagnoser(/*AllowScopedEnumerations*/false,
Silent, true) {}
- virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
- QualType T) {
+ SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
+ QualType T) override {
return S.Diag(Loc, diag::err_ice_not_integral) << T;
}
- virtual SemaDiagnosticBuilder diagnoseIncomplete(
- Sema &S, SourceLocation Loc, QualType T) {
+ SemaDiagnosticBuilder diagnoseIncomplete(
+ Sema &S, SourceLocation Loc, QualType T) override {
return S.Diag(Loc, diag::err_ice_incomplete_type) << T;
}
- virtual SemaDiagnosticBuilder diagnoseExplicitConv(
- Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
+ SemaDiagnosticBuilder diagnoseExplicitConv(
+ Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override {
return S.Diag(Loc, diag::err_ice_explicit_conversion) << T << ConvTy;
}
- virtual SemaDiagnosticBuilder noteExplicitConv(
- Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
+ SemaDiagnosticBuilder noteExplicitConv(
+ Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override {
return S.Diag(Conv->getLocation(), diag::note_ice_conversion_here)
<< ConvTy->isEnumeralType() << ConvTy;
}
- virtual SemaDiagnosticBuilder diagnoseAmbiguous(
- Sema &S, SourceLocation Loc, QualType T) {
+ SemaDiagnosticBuilder diagnoseAmbiguous(
+ Sema &S, SourceLocation Loc, QualType T) override {
return S.Diag(Loc, diag::err_ice_ambiguous_conversion) << T;
}
- virtual SemaDiagnosticBuilder noteAmbiguous(
- Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
+ SemaDiagnosticBuilder noteAmbiguous(
+ Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override {
return S.Diag(Conv->getLocation(), diag::note_ice_conversion_here)
<< ConvTy->isEnumeralType() << ConvTy;
}
- virtual SemaDiagnosticBuilder diagnoseConversion(
- Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
+ SemaDiagnosticBuilder diagnoseConversion(
+ Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override {
llvm_unreachable("conversion functions are permitted");
}
} ConvertDiagnoser(Diagnoser.Suppress);
@@ -10877,7 +11134,7 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
ConvertDiagnoser);
if (Converted.isInvalid())
return Converted;
- E = Converted.take();
+ E = Converted.get();
if (!E->getType()->isIntegralOrUnscopedEnumerationType())
return ExprError();
} else if (!E->getType()->isIntegralOrUnscopedEnumerationType()) {
@@ -10892,7 +11149,7 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
if (!getLangOpts().CPlusPlus11 && E->isIntegerConstantExpr(Context)) {
if (Result)
*Result = E->EvaluateKnownConstInt(Context);
- return Owned(E);
+ return E;
}
Expr::EvalResult EvalResult;
@@ -10910,7 +11167,7 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
if (Folded && getLangOpts().CPlusPlus11 && Notes.empty()) {
if (Result)
*Result = EvalResult.Val.getInt();
- return Owned(E);
+ return E;
}
// If our only note is the usual "invalid subexpression" note, just point
@@ -10938,7 +11195,7 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
if (Result)
*Result = EvalResult.Val.getInt();
- return Owned(E);
+ return E;
}
namespace {
@@ -10957,7 +11214,7 @@ namespace {
// FIXME: This does the right thing, but maybe we need a more general
// fix to TreeTransform?
StmtResult TransformLabelStmt(LabelStmt *S) {
- S->getDecl()->setStmt(0);
+ S->getDecl()->setStmt(nullptr);
return BaseTransform::TransformLabelStmt(S);
}
@@ -11174,37 +11431,32 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
// Note that this declaration has been used.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
+ Constructor = cast<CXXConstructorDecl>(Constructor->getFirstDecl());
if (Constructor->isDefaulted() && !Constructor->isDeleted()) {
if (Constructor->isDefaultConstructor()) {
- if (Constructor->isTrivial())
+ if (Constructor->isTrivial() && !Constructor->hasAttr<DLLExportAttr>())
return;
- if (!Constructor->isUsed(false))
- DefineImplicitDefaultConstructor(Loc, Constructor);
+ DefineImplicitDefaultConstructor(Loc, Constructor);
} else if (Constructor->isCopyConstructor()) {
- if (!Constructor->isUsed(false))
- DefineImplicitCopyConstructor(Loc, Constructor);
+ DefineImplicitCopyConstructor(Loc, Constructor);
} else if (Constructor->isMoveConstructor()) {
- if (!Constructor->isUsed(false))
- DefineImplicitMoveConstructor(Loc, Constructor);
+ DefineImplicitMoveConstructor(Loc, Constructor);
}
} else if (Constructor->getInheritedConstructor()) {
- if (!Constructor->isUsed(false))
- DefineInheritingConstructor(Loc, Constructor);
+ DefineInheritingConstructor(Loc, Constructor);
}
-
- MarkVTableUsed(Loc, Constructor->getParent());
} else if (CXXDestructorDecl *Destructor =
dyn_cast<CXXDestructorDecl>(Func)) {
- if (Destructor->isDefaulted() && !Destructor->isDeleted() &&
- !Destructor->isUsed(false))
+ Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl());
+ if (Destructor->isDefaulted() && !Destructor->isDeleted())
DefineImplicitDestructor(Loc, Destructor);
if (Destructor->isVirtual())
MarkVTableUsed(Loc, Destructor->getParent());
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
- if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted() &&
- MethodDecl->isOverloadedOperator() &&
+ if (MethodDecl->isOverloadedOperator() &&
MethodDecl->getOverloadedOperator() == OO_Equal) {
- if (!MethodDecl->isUsed(false)) {
+ MethodDecl = cast<CXXMethodDecl>(MethodDecl->getFirstDecl());
+ if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) {
if (MethodDecl->isCopyAssignmentOperator())
DefineImplicitCopyAssignment(Loc, MethodDecl);
else
@@ -11212,7 +11464,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
}
} else if (isa<CXXConversionDecl>(MethodDecl) &&
MethodDecl->getParent()->isLambda()) {
- CXXConversionDecl *Conversion = cast<CXXConversionDecl>(MethodDecl);
+ CXXConversionDecl *Conversion =
+ cast<CXXConversionDecl>(MethodDecl->getFirstDecl());
if (Conversion->isLambdaToBlockPointerConversion())
DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion);
else
@@ -11276,10 +11529,9 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
}
} else {
// Walk redefinitions, as some of them may be instantiable.
- for (FunctionDecl::redecl_iterator i(Func->redecls_begin()),
- e(Func->redecls_end()); i != e; ++i) {
+ for (auto i : Func->redecls()) {
if (!i->isUsed(false) && i->isImplicitlyInstantiable())
- MarkFunctionReferenced(Loc, *i);
+ MarkFunctionReferenced(Loc, i);
}
}
@@ -11345,8 +11597,8 @@ diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
<< var->getIdentifier();
}
- S.Diag(var->getLocation(), diag::note_local_variable_declared_here)
- << var->getIdentifier();
+ S.Diag(var->getLocation(), diag::note_entity_declared_at)
+ << var->getIdentifier();
// FIXME: Add additional diagnostic info about class etc. which prevents
// capture.
@@ -11388,7 +11640,7 @@ static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *
if (Diagnose)
diagnoseUncapturableValueReference(S, Loc, Var, DC);
}
- return 0;
+ return nullptr;
}
// Certain capturing entities (lambdas, blocks etc.) are not allowed to capture
@@ -11414,7 +11666,7 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
}
// Prohibit variably-modified types; they're difficult to deal with.
- if (Var->getType()->isVariablyModifiedType()) {
+ if (Var->getType()->isVariablyModifiedType() && (IsBlock || IsLambda)) {
if (Diagnose) {
if (IsBlock)
S.Diag(Loc, diag::err_ref_vm_type);
@@ -11465,7 +11717,7 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
QualType &DeclRefType,
const bool Nested,
Sema &S) {
- Expr *CopyExpr = 0;
+ Expr *CopyExpr = nullptr;
bool ByRef = false;
// Blocks are not allowed to capture arrays.
@@ -11523,7 +11775,7 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
= S.PerformCopyInitialization(
InitializedEntity::InitializeBlock(Var->getLocation(),
CaptureType, false),
- Loc, S.Owned(DeclRef));
+ Loc, DeclRef);
// Build a full-expression copy expression if initialization
// succeeded and used a non-trivial constructor. Recover from
@@ -11532,7 +11784,7 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
!cast<CXXConstructExpr>(Result.get())->getConstructor()
->isTrivial()) {
Result = S.MaybeCreateExprWithCleanups(Result);
- CopyExpr = Result.take();
+ CopyExpr = Result.get();
}
}
}
@@ -11562,18 +11814,17 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
bool ByRef = true;
// Using an LValue reference type is consistent with Lambdas (see below).
CaptureType = S.Context.getLValueReferenceType(DeclRefType);
- Expr *CopyExpr = 0;
+ Expr *CopyExpr = nullptr;
if (BuildAndDiagnose) {
// The current implementation assumes that all variables are captured
- // by references. Since there is no capture by copy, no expression evaluation
- // will be needed.
- //
+ // by references. Since there is no capture by copy, no expression
+ // evaluation will be needed.
RecordDecl *RD = RSI->TheRecordDecl;
FieldDecl *Field
- = FieldDecl::Create(S.Context, RD, Loc, Loc, 0, CaptureType,
+ = FieldDecl::Create(S.Context, RD, Loc, Loc, nullptr, CaptureType,
S.Context.getTrivialTypeSourceInfo(CaptureType, Loc),
- 0, false, ICIS_NoInit);
+ nullptr, false, ICIS_NoInit);
Field->setImplicit(true);
Field->setAccess(AS_private);
RD->addDecl(Field);
@@ -11605,9 +11856,9 @@ static ExprResult addAsFieldToClosureType(Sema &S,
// Build the non-static data member.
FieldDecl *Field
- = FieldDecl::Create(S.Context, Lambda, Loc, Loc, 0, FieldType,
+ = FieldDecl::Create(S.Context, Lambda, Loc, Loc, nullptr, FieldType,
S.Context.getTrivialTypeSourceInfo(FieldType, Loc),
- 0, false, ICIS_NoInit);
+ nullptr, false, ICIS_NoInit);
Field->setImplicit(true);
Field->setAccess(AS_private);
Lambda->addDecl(Field);
@@ -11645,7 +11896,7 @@ static ExprResult addAsFieldToClosureType(Sema &S,
while (const ConstantArrayType *Array
= S.Context.getAsConstantArrayType(BaseType)) {
// Create the iteration variable for this array index.
- IdentifierInfo *IterationVarName = 0;
+ IdentifierInfo *IterationVarName = nullptr;
{
SmallString<8> Str;
llvm::raw_svector_ostream OS(Str);
@@ -11665,20 +11916,20 @@ static ExprResult addAsFieldToClosureType(Sema &S,
= S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc);
assert(!IterationVarRef.isInvalid() &&
"Reference to invented variable cannot fail!");
- IterationVarRef = S.DefaultLvalueConversion(IterationVarRef.take());
+ IterationVarRef = S.DefaultLvalueConversion(IterationVarRef.get());
assert(!IterationVarRef.isInvalid() &&
"Conversion of invented variable cannot fail!");
// Subscript the array with this iteration variable.
ExprResult Subscript = S.CreateBuiltinArraySubscriptExpr(
- Ref, Loc, IterationVarRef.take(), Loc);
+ Ref, Loc, IterationVarRef.get(), Loc);
if (Subscript.isInvalid()) {
S.CleanupVarDeclMarking();
S.DiscardCleanupsInEvaluationContext();
return ExprError();
}
- Ref = Subscript.take();
+ Ref = Subscript.get();
BaseType = Array->getElementType();
}
@@ -11778,19 +12029,28 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
return false;
}
- if (S.RequireNonAbstractType(Loc, CaptureType,
- diag::err_capture_of_abstract_type))
- return false;
+ // Make sure that by-copy captures are of a complete and non-abstract type.
+ if (BuildAndDiagnose) {
+ if (!CaptureType->isDependentType() &&
+ S.RequireCompleteType(Loc, CaptureType,
+ diag::err_capture_of_incomplete_type,
+ Var->getDeclName()))
+ return false;
+
+ if (S.RequireNonAbstractType(Loc, CaptureType,
+ diag::err_capture_of_abstract_type))
+ return false;
+ }
}
// Capture this variable in the lambda.
- Expr *CopyExpr = 0;
+ Expr *CopyExpr = nullptr;
if (BuildAndDiagnose) {
ExprResult Result = addAsFieldToClosureType(S, LSI, Var,
CaptureType, DeclRefType, Loc,
RefersToEnclosingLocal);
if (!Result.isInvalid())
- CopyExpr = Result.take();
+ CopyExpr = Result.get();
}
// Compute the type of a reference to this captured variable.
@@ -11893,8 +12153,107 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation ExprLoc,
// certain types of variables (unnamed, variably modified types etc.)
// so check for eligibility.
if (!isVariableCapturable(CSI, Var, ExprLoc, BuildAndDiagnose, *this))
- return true;
-
+ return true;
+
+ // Try to capture variable-length arrays types.
+ if (Var->getType()->isVariablyModifiedType()) {
+ // We're going to walk down into the type and look for VLA
+ // expressions.
+ QualType QTy = Var->getType();
+ if (ParmVarDecl *PVD = dyn_cast_or_null<ParmVarDecl>(Var))
+ QTy = PVD->getOriginalType();
+ do {
+ const Type *Ty = QTy.getTypePtr();
+ switch (Ty->getTypeClass()) {
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#define NON_CANONICAL_TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+ QTy = QualType();
+ break;
+ // 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::Elaborated:
+ case Type::TemplateSpecialization:
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ case Type::ObjCObjectPointer:
+ llvm_unreachable("type class is never variably-modified!");
+ case Type::Adjusted:
+ QTy = cast<AdjustedType>(Ty)->getOriginalType();
+ break;
+ case Type::Decayed:
+ QTy = cast<DecayedType>(Ty)->getPointeeType();
+ break;
+ case Type::Pointer:
+ QTy = cast<PointerType>(Ty)->getPointeeType();
+ break;
+ case Type::BlockPointer:
+ QTy = cast<BlockPointerType>(Ty)->getPointeeType();
+ break;
+ case Type::LValueReference:
+ case Type::RValueReference:
+ QTy = cast<ReferenceType>(Ty)->getPointeeType();
+ break;
+ case Type::MemberPointer:
+ QTy = cast<MemberPointerType>(Ty)->getPointeeType();
+ break;
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ // Losing element qualification here is fine.
+ QTy = 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 (Expr *Size = Vat->getSizeExpr()) {
+ MarkDeclarationsReferencedInExpr(Size);
+ }
+ QTy = Vat->getElementType();
+ break;
+ }
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ QTy = cast<FunctionType>(Ty)->getReturnType();
+ break;
+ case Type::Paren:
+ case Type::TypeOf:
+ case Type::UnaryTransform:
+ case Type::Attributed:
+ case Type::SubstTemplateTypeParm:
+ case Type::PackExpansion:
+ // Keep walking after single level desugaring.
+ QTy = QTy.getSingleStepDesugaredType(getASTContext());
+ break;
+ case Type::Typedef:
+ QTy = cast<TypedefType>(Ty)->desugar();
+ break;
+ case Type::Decltype:
+ QTy = cast<DecltypeType>(Ty)->desugar();
+ break;
+ case Type::Auto:
+ QTy = cast<AutoType>(Ty)->getDeducedType();
+ break;
+ case Type::TypeOfExpr:
+ QTy = cast<TypeOfExprType>(Ty)->getUnderlyingExpr()->getType();
+ break;
+ case Type::Atomic:
+ QTy = cast<AtomicType>(Ty)->getValueType();
+ break;
+ }
+ } while (!QTy.isNull() && QTy->isVariablyModifiedType());
+ }
+
if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None && !Explicit) {
// No capture-default, and this is not an explicit capture
// so cannot capture this variable.
@@ -11964,7 +12323,7 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
QualType DeclRefType;
return tryCaptureVariable(Var, Loc, Kind, EllipsisLoc,
/*BuildAndDiagnose=*/true, CaptureType,
- DeclRefType, 0);
+ DeclRefType, nullptr);
}
QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
@@ -11974,7 +12333,7 @@ QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
// Determine whether we can capture this variable.
if (tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(),
/*BuildAndDiagnose=*/false, CaptureType,
- DeclRefType, 0))
+ DeclRefType, nullptr))
return QualType();
return DeclRefType;
@@ -11991,7 +12350,7 @@ static inline bool IsVariableNonDependentAndAConstantExpression(VarDecl *Var,
if (Var->getType()->isDependentType())
return false;
- const VarDecl *DefVD = 0;
+ const VarDecl *DefVD = nullptr;
Var->getAnyInitializer(DefVD);
if (!DefVD)
return false;
@@ -12017,7 +12376,7 @@ void Sema::UpdateMarkingForLValueToRValue(Expr *E) {
// variable.
if (LambdaScopeInfo *LSI = getCurLambda()) {
Expr *SansParensExpr = E->IgnoreParens();
- VarDecl *Var = 0;
+ VarDecl *Var = nullptr;
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SansParensExpr))
Var = dyn_cast<VarDecl>(DRE->getFoundDecl());
else if (MemberExpr *ME = dyn_cast<MemberExpr>(SansParensExpr))
@@ -12056,7 +12415,8 @@ void Sema::CleanupVarDeclMarking() {
llvm_unreachable("Unexpcted expression");
}
- MarkVarDeclODRUsed(Var, Loc, *this, /*MaxFunctionScopeIndex Pointer*/ 0);
+ MarkVarDeclODRUsed(Var, Loc, *this,
+ /*MaxFunctionScopeIndex Pointer*/ nullptr);
}
MaybeODRUseExprs.clear();
@@ -12069,42 +12429,39 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
"Invalid Expr argument to DoMarkVarDeclReferenced");
Var->setReferenced();
- // If the context is not PotentiallyEvaluated and not Unevaluated
- // (i.e PotentiallyEvaluatedIfUsed) do not bother to consider variables
- // in this context for odr-use unless we are within a lambda.
- // If we don't know whether the context is potentially evaluated or not
- // (for e.g., if we're in a generic lambda), we want to add a potential
- // capture and eventually analyze for odr-use.
- // We should also be able to analyze certain constructs in a non-generic
- // lambda setting for potential odr-use and capture violation:
- // template<class T> void foo(T t) {
- // auto L = [](int i) { return t; };
- // }
- //
+ // If the context is not potentially evaluated, this is not an odr-use and
+ // does not trigger instantiation.
if (!IsPotentiallyEvaluatedContext(SemaRef)) {
+ if (SemaRef.isUnevaluatedContext())
+ return;
- if (SemaRef.isUnevaluatedContext()) return;
+ // If we don't yet know whether this context is going to end up being an
+ // evaluated context, and we're referencing a variable from an enclosing
+ // scope, add a potential capture.
+ //
+ // FIXME: Is this necessary? These contexts are only used for default
+ // arguments, where local variables can't be used.
+ const bool RefersToEnclosingScope =
+ (SemaRef.CurContext != Var->getDeclContext() &&
+ Var->getDeclContext()->isFunctionOrMethod() &&
+ Var->hasLocalStorage());
+ if (!RefersToEnclosingScope)
+ return;
- const bool refersToEnclosingScope =
- (SemaRef.CurContext != Var->getDeclContext() &&
- Var->getDeclContext()->isFunctionOrMethod());
- if (!refersToEnclosingScope) return;
-
if (LambdaScopeInfo *const LSI = SemaRef.getCurLambda()) {
// If a variable could potentially be odr-used, defer marking it so
- // until we finish analyzing the full expression for any lvalue-to-rvalue
+ // until we finish analyzing the full expression for any lvalue-to-rvalue
// or discarded value conversions that would obviate odr-use.
// Add it to the list of potential captures that will be analyzed
// later (ActOnFinishFullExpr) for eventual capture and odr-use marking
// unless the variable is a reference that was initialized by a constant
// expression (this will never need to be captured or odr-used).
- const bool IsConstantExpr = IsVariableNonDependentAndAConstantExpression(
- Var, SemaRef.Context);
assert(E && "Capture variable should be used in an expression.");
- if (!IsConstantExpr || !Var->getType()->isReferenceType())
- LSI->addPotentialCapture(E->IgnoreParens());
- }
- return;
+ if (!Var->getType()->isReferenceType() ||
+ !IsVariableNonDependentAndAConstantExpression(Var, SemaRef.Context))
+ LSI->addPotentialCapture(E->IgnoreParens());
+ }
+ return;
}
VarTemplateSpecializationDecl *VarSpec =
@@ -12112,10 +12469,10 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
assert(!isa<VarTemplatePartialSpecializationDecl>(Var) &&
"Can't instantiate a partial template specialization.");
- // Implicit instantiation of static data members, static data member
- // templates of class templates, and variable template specializations.
- // Delay instantiations of variable templates, except for those
- // that could be used in a constant expression.
+ // Perform implicit instantiation of static data members, static data member
+ // templates of class templates, and variable template specializations. Delay
+ // instantiations of variable templates, except for those that could be used
+ // in a constant expression.
TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
if (isTemplateInstantiation(TSK)) {
bool TryInstantiating = TSK == TSK_ImplicitInstantiation;
@@ -12155,6 +12512,7 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
}
}
}
+
// Per C++11 [basic.def.odr], a variable is odr-used "unless it satisfies
// the requirements for appearing in a constant expression (5.19) and, if
// it is an object, the lvalue-to-rvalue conversion (4.1)
@@ -12164,22 +12522,20 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
// C++03 depends on whether we get the C++03 version correct. The second
// part does not apply to references, since they are not objects.
if (E && IsVariableAConstantExpression(Var, SemaRef.Context)) {
- // A reference initialized by a constant expression can never be
+ // A reference initialized by a constant expression can never be
// odr-used, so simply ignore it.
- // But a non-reference might get odr-used if it doesn't undergo
- // an lvalue-to-rvalue or is discarded, so track it.
if (!Var->getType()->isReferenceType())
SemaRef.MaybeODRUseExprs.insert(E);
- }
- else
- MarkVarDeclODRUsed(Var, Loc, SemaRef, /*MaxFunctionScopeIndex ptr*/0);
+ } else
+ MarkVarDeclODRUsed(Var, Loc, SemaRef,
+ /*MaxFunctionScopeIndex ptr*/ nullptr);
}
/// \brief Mark a variable referenced, and check whether it is odr-used
/// (C++ [basic.def.odr]p2, C99 6.9p3). Note that this should not be
/// used directly for normal expressions referring to VarDecl.
void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) {
- DoMarkVarDeclReferenced(*this, Loc, Var, 0);
+ DoMarkVarDeclReferenced(*this, Loc, Var, nullptr);
}
static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
@@ -12241,9 +12597,9 @@ void Sema::MarkMemberReferenced(MemberExpr *E) {
}
/// \brief Perform marking for a reference to an arbitrary declaration. It
-/// marks the declaration referenced, and performs odr-use checking for functions
-/// and variables. This method should not be used when building an normal
-/// expression which refers to a variable.
+/// marks the declaration referenced, and performs odr-use checking for
+/// functions and variables. This method should not be used when building a
+/// normal expression which refers to a variable.
void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool OdrUse) {
if (OdrUse) {
if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
@@ -12277,7 +12633,7 @@ namespace {
}
bool MarkReferencedDecls::TraverseTemplateArgument(
- const TemplateArgument &Arg) {
+ const TemplateArgument &Arg) {
if (Arg.getKind() == TemplateArgument::Declaration) {
if (Decl *D = Arg.getAsDecl())
S.MarkAnyDeclReferenced(Loc, D, true);
@@ -12324,7 +12680,7 @@ namespace {
S.MarkDeclRefReferenced(E);
}
-
+
void VisitMemberExpr(MemberExpr *E) {
S.MarkMemberReferenced(E);
Inherited::VisitMemberExpr(E);
@@ -12447,8 +12803,8 @@ bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
public:
CallReturnIncompleteDiagnoser(FunctionDecl *FD, CallExpr *CE)
: FD(FD), CE(CE) { }
-
- virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) {
+
+ void diagnose(Sema &S, SourceLocation Loc, QualType T) override {
if (!FD) {
S.Diag(Loc, diag::err_call_incomplete_return)
<< T << CE->getSourceRange();
@@ -12457,9 +12813,8 @@ bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
S.Diag(Loc, diag::err_call_function_incomplete_return)
<< CE->getSourceRange() << FD->getDeclName() << T;
- S.Diag(FD->getLocation(),
- diag::note_function_with_incomplete_return_type_declared_here)
- << FD->getDeclName();
+ S.Diag(FD->getLocation(), diag::note_entity_declared_at)
+ << FD->getDeclName();
}
} Diagnoser(FD, CE);
@@ -12563,7 +12918,7 @@ ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) {
ExprResult result = CheckPlaceholderExpr(E);
if (result.isInvalid()) return ExprError();
- E = result.take();
+ E = result.get();
if (!E->isTypeDependent()) {
if (getLangOpts().CPlusPlus)
@@ -12572,7 +12927,7 @@ ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) {
ExprResult ERes = DefaultFunctionArrayLvalueConversion(E);
if (ERes.isInvalid())
return ExprError();
- E = ERes.take();
+ E = ERes.get();
QualType T = E->getType();
if (!T->isScalarType()) { // C99 6.8.4.1p1
@@ -12582,7 +12937,7 @@ ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) {
}
}
- return Owned(E);
+ return E;
}
ExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc,
@@ -12619,7 +12974,7 @@ namespace {
ExprResult SubResult = Visit(E->getSubExpr());
if (SubResult.isInvalid()) return ExprError();
- Expr *SubExpr = SubResult.take();
+ Expr *SubExpr = SubResult.get();
E->setSubExpr(SubExpr);
E->setType(SubExpr->getType());
E->setValueKind(SubExpr->getValueKind());
@@ -12639,7 +12994,7 @@ namespace {
ExprResult SubResult = Visit(E->getSubExpr());
if (SubResult.isInvalid()) return ExprError();
- Expr *SubExpr = SubResult.take();
+ Expr *SubExpr = SubResult.get();
E->setSubExpr(SubExpr);
E->setType(S.Context.getPointerType(SubExpr->getType()));
assert(E->getValueKind() == VK_RValue);
@@ -12676,7 +13031,7 @@ namespace {
static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *FunctionExpr) {
ExprResult Result = RebuildUnknownAnyFunction(S).Visit(FunctionExpr);
if (Result.isInvalid()) return ExprError();
- return S.DefaultFunctionArrayConversion(Result.take());
+ return S.DefaultFunctionArrayConversion(Result.get());
}
namespace {
@@ -12713,7 +13068,7 @@ namespace {
template <class T> ExprResult rebuildSugarExpr(T *E) {
ExprResult SubResult = Visit(E->getSubExpr());
if (SubResult.isInvalid()) return ExprError();
- Expr *SubExpr = SubResult.take();
+ Expr *SubExpr = SubResult.get();
E->setSubExpr(SubExpr);
E->setType(SubExpr->getType());
E->setValueKind(SubExpr->getValueKind());
@@ -12744,7 +13099,7 @@ namespace {
DestType = Ptr->getPointeeType();
ExprResult SubResult = Visit(E->getSubExpr());
if (SubResult.isInvalid()) return ExprError();
- E->setSubExpr(SubResult.take());
+ E->setSubExpr(SubResult.get());
return E;
}
@@ -12825,7 +13180,7 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *E) {
// This is a hack, but it is far superior to moving the
// corresponding target-specific code from IR-gen to Sema/AST.
- ArrayRef<QualType> ParamTypes = Proto->getArgTypes();
+ ArrayRef<QualType> ParamTypes = Proto->getParamTypes();
SmallVector<QualType, 8> ArgTypes;
if (ParamTypes.empty() && Proto->isVariadic()) { // the special case
ArgTypes.reserve(E->getNumArgs());
@@ -12866,7 +13221,7 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *E) {
// Finally, we can recurse.
ExprResult CalleeResult = Visit(CalleeExpr);
if (!CalleeResult.isUsable()) return ExprError();
- E->setCallee(CalleeResult.take());
+ E->setCallee(CalleeResult.get());
// Bind a temporary if necessary.
return S.MaybeBindToTemporary(E);
@@ -12882,8 +13237,8 @@ ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *E) {
// Rewrite the method result type if available.
if (ObjCMethodDecl *Method = E->getMethodDecl()) {
- assert(Method->getResultType() == S.Context.UnknownAnyTy);
- Method->setResultType(DestType);
+ assert(Method->getReturnType() == S.Context.UnknownAnyTy);
+ Method->setReturnType(DestType);
}
// Change the type of the message.
@@ -12907,8 +13262,8 @@ ExprResult RebuildUnknownAnyExpr::VisitImplicitCastExpr(ImplicitCastExpr *E) {
ExprResult Result = Visit(E->getSubExpr());
if (!Result.isUsable()) return ExprError();
- E->setSubExpr(Result.take());
- return S.Owned(E);
+ E->setSubExpr(Result.get());
+ return E;
} else if (E->getCastKind() == CK_LValueToRValue) {
assert(E->getValueKind() == VK_RValue);
assert(E->getObjectKind() == OK_Ordinary);
@@ -12923,8 +13278,8 @@ ExprResult RebuildUnknownAnyExpr::VisitImplicitCastExpr(ImplicitCastExpr *E) {
ExprResult Result = Visit(E->getSubExpr());
if (!Result.isUsable()) return ExprError();
- E->setSubExpr(Result.take());
- return S.Owned(E);
+ E->setSubExpr(Result.get());
+ return E;
} else {
llvm_unreachable("Unhandled cast type!");
}
@@ -12942,7 +13297,7 @@ ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) {
DestType = Ptr->getPointeeType();
ExprResult Result = resolveDecl(E, VD);
if (Result.isInvalid()) return ExprError();
- return S.ImpCastExprToType(Result.take(), Type,
+ return S.ImpCastExprToType(Result.get(), Type,
CK_FunctionToPointerDecay, VK_RValue);
}
@@ -12984,7 +13339,7 @@ ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) {
VD->setType(DestType);
E->setType(Type);
E->setValueKind(ValueKind);
- return S.Owned(E);
+ return E;
}
/// Check a cast of an unknown-any type. We intentionally only
@@ -12996,7 +13351,7 @@ ExprResult Sema::checkUnknownAnyCast(SourceRange TypeRange, QualType CastType,
ExprResult result = RebuildUnknownAnyExpr(*this, CastType).Visit(CastExpr);
if (!result.isUsable()) return ExprError();
- CastExpr = result.take();
+ CastExpr = result.get();
VK = CastExpr->getValueKind();
CastKind = CK_NoOp;
@@ -13027,7 +13382,7 @@ ExprResult Sema::checkUnknownAnyArg(SourceLocation callLoc,
InitializedEntity entity =
InitializedEntity::InitializeParameter(Context, paramType,
/*consumed*/ false);
- return PerformCopyInitialization(entity, callLoc, Owned(arg));
+ return PerformCopyInitialization(entity, callLoc, arg);
}
static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) {
@@ -13077,7 +13432,7 @@ static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) {
/// Returns true if there was an error and no recovery was possible.
ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
const BuiltinType *placeholderType = E->getType()->getAsPlaceholderType();
- if (!placeholderType) return Owned(E);
+ if (!placeholderType) return E;
switch (placeholderType->getKind()) {
@@ -13085,7 +13440,7 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
case BuiltinType::Overload: {
// Try to resolve a single function template specialization.
// This is obligatory.
- ExprResult result = Owned(E);
+ ExprResult result = E;
if (ResolveAndFixSingleFunctionTemplateSpecialization(result, false)) {
return result;
@@ -13099,7 +13454,7 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
// Bound member functions.
case BuiltinType::BoundMember: {
- ExprResult result = Owned(E);
+ ExprResult result = E;
tryToRecoverWithCall(result, PDiag(diag::err_bound_member_function),
/*complain*/ true);
return result;
@@ -13109,7 +13464,7 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
case BuiltinType::ARCUnbridgedCast: {
Expr *realCast = stripARCUnbridgedCast(E);
diagnoseARCUnbridgedCast(realCast);
- return Owned(realCast);
+ return realCast;
}
// Expressions of unknown type.
@@ -13120,9 +13475,22 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
case BuiltinType::PseudoObject:
return checkPseudoObjectRValue(E);
- case BuiltinType::BuiltinFn:
+ case BuiltinType::BuiltinFn: {
+ // Accept __noop without parens by implicitly converting it to a call expr.
+ auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts());
+ if (DRE) {
+ auto *FD = cast<FunctionDecl>(DRE->getDecl());
+ if (FD->getBuiltinID() == Builtin::BI__noop) {
+ E = ImpCastExprToType(E, Context.getPointerType(FD->getType()),
+ CK_BuiltinFnToFnPtr).get();
+ return new (Context) CallExpr(Context, E, None, Context.IntTy,
+ VK_RValue, SourceLocation());
+ }
+ }
+
Diag(E->getLocStart(), diag::err_builtin_fn_use);
return ExprError();
+ }
// Everything else should be impossible.
#define BUILTIN_TYPE(Id, SingletonId) \
@@ -13160,6 +13528,6 @@ Sema::ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) {
}
if (Context.getBOOLDecl())
BoolT = Context.getBOOLType();
- return Owned(new (Context) ObjCBoolLiteralExpr(Kind == tok::kw___objc_yes,
- BoolT, OpLoc));
+ return new (Context)
+ ObjCBoolLiteralExpr(Kind == tok::kw___objc_yes, BoolT, OpLoc);
}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 20118b57126d..0dabdca29553 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -15,6 +15,7 @@
#include "clang/Sema/SemaInternal.h"
#include "TypeLocBuilder.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
@@ -106,7 +107,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
// For this reason, we're currently only doing the C++03 version of this
// code; the C++0x version has to wait until we get a proper spec.
QualType SearchType;
- DeclContext *LookupCtx = 0;
+ DeclContext *LookupCtx = nullptr;
bool isDependent = false;
bool LookInScope = false;
@@ -117,38 +118,33 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
SearchType = GetTypeFromParser(ObjectTypePtr);
if (SS.isSet()) {
- NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
+ NestedNameSpecifier *NNS = SS.getScopeRep();
bool AlreadySearched = false;
bool LookAtPrefix = true;
- // C++ [basic.lookup.qual]p6:
+ // C++11 [basic.lookup.qual]p6:
// If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier,
// the type-names are looked up as types in the scope designated by the
- // nested-name-specifier. In a qualified-id of the form:
+ // nested-name-specifier. Similarly, in a qualified-id of the form:
//
- // ::[opt] nested-name-specifier ~ class-name
+ // nested-name-specifier[opt] class-name :: ~ class-name
//
- // where the nested-name-specifier designates a namespace scope, and in
- // a qualified-id of the form:
+ // the second class-name is looked up in the same scope as the first.
//
- // ::opt nested-name-specifier class-name :: ~ class-name
- //
- // the class-names are looked up as types in the scope designated by
- // the nested-name-specifier.
- //
- // Here, we check the first case (completely) and determine whether the
- // code below is permitted to look at the prefix of the
- // nested-name-specifier.
+ // Here, we determine whether the code below is permitted to look at the
+ // prefix of the nested-name-specifier.
DeclContext *DC = computeDeclContext(SS, EnteringContext);
if (DC && DC->isFileContext()) {
AlreadySearched = true;
LookupCtx = DC;
isDependent = false;
- } else if (DC && isa<CXXRecordDecl>(DC))
+ } else if (DC && isa<CXXRecordDecl>(DC)) {
LookAtPrefix = false;
+ LookInScope = true;
+ }
// The second case from the C++03 rules quoted further above.
- NestedNameSpecifier *Prefix = 0;
+ NestedNameSpecifier *Prefix = nullptr;
if (AlreadySearched) {
// Nothing left to do.
} else if (LookAtPrefix && (Prefix = NNS->getPrefix())) {
@@ -163,8 +159,6 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
LookupCtx = computeDeclContext(SS, EnteringContext);
isDependent = LookupCtx && LookupCtx->isDependentContext();
}
-
- LookInScope = false;
} else if (ObjectTypePtr) {
// C++ [basic.lookup.classref]p3:
// If the unqualified-id is ~type-name, the type-name is looked up
@@ -184,7 +178,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
LookInScope = true;
}
- TypeDecl *NonMatchingTypeDecl = 0;
+ TypeDecl *NonMatchingTypeDecl = nullptr;
LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName);
for (unsigned Step = 0; Step != 2; ++Step) {
// Look for the name first in the computed lookup context (if we
@@ -209,7 +203,8 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
Context.hasSameUnqualifiedType(T, SearchType)) {
// We found our type!
- return ParsedType::make(T);
+ return CreateParsedType(T,
+ Context.getTrivialTypeSourceInfo(T, NameLoc));
}
if (!SearchType.isNull())
@@ -245,7 +240,9 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
= dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) {
if (Spec->getSpecializedTemplate()->getCanonicalDecl() ==
Template->getCanonicalDecl())
- return ParsedType::make(MemberOfType);
+ return CreateParsedType(
+ MemberOfType,
+ Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc));
}
continue;
@@ -264,7 +261,9 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
// specialized.
if (TemplateDecl *SpecTemplate = SpecName.getAsTemplateDecl()) {
if (SpecTemplate->getCanonicalDecl() == Template->getCanonicalDecl())
- return ParsedType::make(MemberOfType);
+ return CreateParsedType(
+ MemberOfType,
+ Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc));
continue;
}
@@ -275,7 +274,9 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
= SpecName.getAsDependentTemplateName()) {
if (DepTemplate->isIdentifier() &&
DepTemplate->getIdentifier() == Template->getIdentifier())
- return ParsedType::make(MemberOfType);
+ return CreateParsedType(
+ MemberOfType,
+ Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc));
continue;
}
@@ -333,6 +334,34 @@ ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) {
return ParsedType();
}
+bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS,
+ const UnqualifiedId &Name) {
+ assert(Name.getKind() == UnqualifiedId::IK_LiteralOperatorId);
+
+ if (!SS.isValid())
+ return false;
+
+ switch (SS.getScopeRep()->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ // Per C++11 [over.literal]p2, literal operators can only be declared at
+ // namespace scope. Therefore, this unqualified-id cannot name anything.
+ // Reject it early, because we have no AST representation for this in the
+ // case where the scope is dependent.
+ Diag(Name.getLocStart(), diag::err_literal_operator_id_outside_namespace)
+ << SS.getScopeRep();
+ return true;
+
+ case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ return false;
+ }
+
+ llvm_unreachable("unknown nested name specifier kind");
+}
+
/// \brief Build a C++ typeid expression with a type operand.
ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
SourceLocation TypeidLoc,
@@ -351,9 +380,8 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid))
return ExprError();
- return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(),
- Operand,
- SourceRange(TypeidLoc, RParenLoc)));
+ return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), Operand,
+ SourceRange(TypeidLoc, RParenLoc));
}
/// \brief Build a C++ typeid expression with an expression operand.
@@ -365,7 +393,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
if (E->getType()->isPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(E);
if (result.isInvalid()) return ExprError();
- E = result.take();
+ E = result.get();
}
QualType T = E->getType();
@@ -386,7 +414,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
// and recheck the subexpression.
ExprResult Result = TransformToPotentiallyEvaluated(E);
if (Result.isInvalid()) return ExprError();
- E = Result.take();
+ E = Result.get();
// We require a vtable to query the type at run time.
MarkVTableUsed(TypeidLoc, RecordD);
@@ -402,13 +430,12 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
QualType UnqualT = Context.getUnqualifiedArrayType(T, Quals);
if (!Context.hasSameType(T, UnqualT)) {
T = UnqualT;
- E = ImpCastExprToType(E, UnqualT, CK_NoOp, E->getValueKind()).take();
+ E = ImpCastExprToType(E, UnqualT, CK_NoOp, E->getValueKind()).get();
}
}
- return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(),
- E,
- SourceRange(TypeidLoc, RParenLoc)));
+ return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), E,
+ SourceRange(TypeidLoc, RParenLoc));
}
/// ActOnCXXTypeidOfType - Parse typeid( type-id ) or typeid (expression);
@@ -426,7 +453,7 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
CXXTypeInfoDecl = R.getAsSingle<RecordDecl>();
// Microsoft's typeinfo doesn't have type_info in std but in the global
// namespace if _HAS_EXCEPTIONS is defined to 0. See PR13153.
- if (!CXXTypeInfoDecl && LangOpts.MicrosoftMode) {
+ if (!CXXTypeInfoDecl && LangOpts.MSVCCompat) {
LookupQualifiedName(R, Context.getTranslationUnitDecl());
CXXTypeInfoDecl = R.getAsSingle<RecordDecl>();
}
@@ -442,7 +469,7 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
if (isType) {
// The operand is a type; handle it as such.
- TypeSourceInfo *TInfo = 0;
+ TypeSourceInfo *TInfo = nullptr;
QualType T = GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrExpr),
&TInfo);
if (T.isNull())
@@ -474,9 +501,8 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
}
}
- return Owned(new (Context) CXXUuidofExpr(TypeInfoType.withConst(),
- Operand,
- SourceRange(TypeidLoc, RParenLoc)));
+ return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), Operand,
+ SourceRange(TypeidLoc, RParenLoc));
}
/// \brief Build a Microsoft __uuidof expression with an expression operand.
@@ -495,9 +521,8 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
}
}
- return Owned(new (Context) CXXUuidofExpr(TypeInfoType.withConst(),
- E,
- SourceRange(TypeidLoc, RParenLoc)));
+ return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), E,
+ SourceRange(TypeidLoc, RParenLoc));
}
/// ActOnCXXUuidof - Parse __uuidof( type-id ) or __uuidof (expression);
@@ -518,7 +543,7 @@ Sema::ActOnCXXUuidof(SourceLocation OpLoc, SourceLocation LParenLoc,
if (isType) {
// The operand is a type; handle it as such.
- TypeSourceInfo *TInfo = 0;
+ TypeSourceInfo *TInfo = nullptr;
QualType T = GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrExpr),
&TInfo);
if (T.isNull())
@@ -539,14 +564,14 @@ ExprResult
Sema::ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) {
assert((Kind == tok::kw_true || Kind == tok::kw_false) &&
"Unknown C++ Boolean value!");
- return Owned(new (Context) CXXBoolLiteralExpr(Kind == tok::kw_true,
- Context.BoolTy, OpLoc));
+ return new (Context)
+ CXXBoolLiteralExpr(Kind == tok::kw_true, Context.BoolTy, OpLoc);
}
/// ActOnCXXNullPtrLiteral - Parse 'nullptr'.
ExprResult
Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) {
- return Owned(new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc));
+ return new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc);
}
/// ActOnCXXThrow - Parse throw expressions.
@@ -593,16 +618,19 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
if (!getLangOpts().CXXExceptions &&
!getSourceManager().isInSystemHeader(OpLoc))
Diag(OpLoc, diag::err_exceptions_disabled) << "throw";
-
+
+ if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())
+ Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw";
+
if (Ex && !Ex->isTypeDependent()) {
ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex, IsThrownVarInScope);
if (ExRes.isInvalid())
return ExprError();
- Ex = ExRes.take();
+ Ex = ExRes.get();
}
- return Owned(new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc,
- IsThrownVarInScope));
+ return new (Context)
+ CXXThrowExpr(Ex, Context.VoidTy, OpLoc, IsThrownVarInScope);
}
/// CheckCXXThrowOperand - Validate the operand of a throw.
@@ -616,12 +644,12 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
// or "pointer to function returning T", [...]
if (E->getType().hasQualifiers())
E = ImpCastExprToType(E, E->getType().getUnqualifiedType(), CK_NoOp,
- E->getValueKind()).take();
+ E->getValueKind()).get();
ExprResult Res = DefaultFunctionArrayConversion(E);
if (Res.isInvalid())
return ExprError();
- E = Res.take();
+ E = Res.get();
// If the type of the exception would be an incomplete type or a pointer
// to an incomplete type other than (cv) void the program is ill-formed.
@@ -657,24 +685,24 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
// 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;
+ const VarDecl *NRVOVariable = nullptr;
if (IsThrownVarInScope)
NRVOVariable = getCopyElisionCandidate(QualType(), E, false);
-
+
InitializedEntity Entity =
InitializedEntity::InitializeException(ThrowLoc, E->getType(),
- /*NRVO=*/NRVOVariable != 0);
+ /*NRVO=*/NRVOVariable != nullptr);
Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable,
QualType(), E,
IsThrownVarInScope);
if (Res.isInvalid())
return ExprError();
- E = Res.take();
+ E = Res.get();
// If the exception has class type, we need additional handling.
const RecordType *RecordTy = Ty->getAs<RecordType>();
if (!RecordTy)
- return Owned(E);
+ return E;
CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
// If we are throwing a polymorphic class type or pointer thereof,
@@ -683,22 +711,22 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
// If a pointer is thrown, the referenced object will not be destroyed.
if (isPointer)
- return Owned(E);
+ return E;
// If the class has a destructor, we must be able to call it.
if (RD->hasIrrelevantDestructor())
- return Owned(E);
+ return E;
CXXDestructorDecl *Destructor = LookupDestructor(RD);
if (!Destructor)
- return Owned(E);
+ return E;
MarkFunctionReferenced(E->getExprLoc(), Destructor);
CheckDestructorAccess(E->getExprLoc(), Destructor,
PDiag(diag::err_access_dtor_exception) << Ty);
if (DiagnoseUseOfDecl(Destructor, E->getExprLoc()))
return ExprError();
- return Owned(E);
+ return E;
}
QualType Sema::getCurrentThisType() {
@@ -708,7 +736,20 @@ QualType Sema::getCurrentThisType() {
if (method && method->isInstance())
ThisTy = method->getThisType(Context);
}
-
+ if (ThisTy.isNull()) {
+ if (isGenericLambdaCallOperatorSpecialization(CurContext) &&
+ CurContext->getParent()->getParent()->isRecord()) {
+ // This is a generic lambda call operator that is being instantiated
+ // within a default initializer - so use the enclosing class as 'this'.
+ // There is no enclosing member function to retrieve the 'this' pointer
+ // from.
+ QualType ClassTy = Context.getTypeDeclType(
+ cast<CXXRecordDecl>(CurContext->getParent()->getParent()));
+ // There are no cv-qualifiers for 'this' within default initializers,
+ // per [expr.prim.general]p4.
+ return Context.getPointerType(ClassTy);
+ }
+ }
return ThisTy;
}
@@ -720,8 +761,8 @@ Sema::CXXThisScopeRAII::CXXThisScopeRAII(Sema &S,
{
if (!Enabled || !ContextDecl)
return;
-
- CXXRecordDecl *Record = 0;
+
+ CXXRecordDecl *Record = nullptr;
if (ClassTemplateDecl *Template = dyn_cast<ClassTemplateDecl>(ContextDecl))
Record = Template->getTemplatedDecl();
else
@@ -744,9 +785,9 @@ Sema::CXXThisScopeRAII::~CXXThisScopeRAII() {
static Expr *captureThis(ASTContext &Context, RecordDecl *RD,
QualType ThisTy, SourceLocation Loc) {
FieldDecl *Field
- = FieldDecl::Create(Context, RD, Loc, Loc, 0, ThisTy,
+ = FieldDecl::Create(Context, RD, Loc, Loc, nullptr, ThisTy,
Context.getTrivialTypeSourceInfo(ThisTy, Loc),
- 0, false, ICIS_NoInit);
+ nullptr, false, ICIS_NoInit);
Field->setImplicit(true);
Field->setAccess(AS_private);
RD->addDecl(Field);
@@ -801,7 +842,7 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit,
for (unsigned idx = MaxFunctionScopesIndex; NumClosures;
--idx, --NumClosures) {
CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]);
- Expr *ThisExpr = 0;
+ Expr *ThisExpr = nullptr;
QualType ThisTy = getCurrentThisType();
if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI))
// For lambda expressions, build a field and an initializing expression.
@@ -825,7 +866,7 @@ ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use);
CheckCXXThisCapture(Loc);
- return Owned(new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false));
+ return new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false);
}
bool Sema::isThisOutsideMemberFunctionBody(QualType BaseType) {
@@ -869,10 +910,8 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc();
if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) {
- return Owned(CXXUnresolvedConstructExpr::Create(Context, TInfo,
- LParenLoc,
- Exprs,
- RParenLoc));
+ return CXXUnresolvedConstructExpr::Create(Context, TInfo, LParenLoc, Exprs,
+ RParenLoc);
}
bool ListInitialization = LParenLoc.isInvalid();
@@ -928,9 +967,9 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
// want, since it will be treated as an initializer list in further
// processing. Explicitly insert a cast here.
QualType ResultType = Result.get()->getType();
- Result = Owned(CXXFunctionalCastExpr::Create(
+ Result = CXXFunctionalCastExpr::Create(
Context, ResultType, Expr::getValueKindForType(TInfo->getType()), TInfo,
- CK_NoOp, Result.take(), /*Path=*/ 0, LParenLoc, RParenLoc));
+ CK_NoOp, Result.get(), /*Path=*/nullptr, LParenLoc, RParenLoc);
}
// FIXME: Improve AST representation?
@@ -1016,7 +1055,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
Declarator &D, Expr *Initializer) {
bool TypeContainsAuto = D.getDeclSpec().containsPlaceholderType();
- Expr *ArraySize = 0;
+ Expr *ArraySize = nullptr;
// If the specified type is an array, unwrap it and save the expression.
if (D.getNumTypeObjects() > 0 &&
D.getTypeObject(0).Kind == DeclaratorChunk::Array) {
@@ -1054,12 +1093,12 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
Array.NumElts
= CheckConvertedConstantExpression(NumElts, Context.getSizeType(), Value,
CCEK_NewExpr)
- .take();
+ .get();
} else {
Array.NumElts
- = VerifyIntegerConstantExpression(NumElts, 0,
+ = VerifyIntegerConstantExpression(NumElts, nullptr,
diag::err_new_array_nonconst)
- .take();
+ .get();
}
if (!Array.NumElts)
return ExprError();
@@ -1068,7 +1107,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
- TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/0);
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/nullptr);
QualType AllocType = TInfo->getType();
if (D.isInvalidType())
return ExprError();
@@ -1145,22 +1184,15 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
NumInits = List->getNumExprs();
}
- // Determine whether we've already built the initializer.
- bool HaveCompleteInit = false;
- if (Initializer && isa<CXXConstructExpr>(Initializer) &&
- !isa<CXXTemporaryObjectExpr>(Initializer))
- HaveCompleteInit = true;
- else if (Initializer && isa<ImplicitValueInitExpr>(Initializer))
- HaveCompleteInit = true;
-
- // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
+ // C++11 [dcl.spec.auto]p6. Deduce the type which 'auto' stands in for.
if (TypeMayContainAuto && AllocType->isUndeducedType()) {
if (initStyle == CXXNewExpr::NoInit || NumInits == 0)
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
<< AllocType << TypeRange);
- if (initStyle == CXXNewExpr::ListInit)
+ if (initStyle == CXXNewExpr::ListInit ||
+ (NumInits == 1 && isa<InitListExpr>(Inits[0])))
return ExprError(Diag(Inits[0]->getLocStart(),
- diag::err_auto_new_requires_parens)
+ diag::err_auto_new_list_init)
<< AllocType << TypeRange);
if (NumInits > 1) {
Expr *FirstBad = Inits[1];
@@ -1194,7 +1226,8 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange))
return ExprError();
- if (initStyle == CXXNewExpr::ListInit && isStdInitializerList(AllocType, 0)) {
+ if (initStyle == CXXNewExpr::ListInit &&
+ isStdInitializerList(AllocType, nullptr)) {
Diag(AllocTypeInfo->getTypeLoc().getBeginLoc(),
diag::warn_dangling_std_initializer_list)
<< /*at end of FE*/0 << Inits[0]->getSourceRange();
@@ -1213,7 +1246,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
if (ArraySize && ArraySize->getType()->isNonOverloadPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(ArraySize);
if (result.isInvalid()) return ExprError();
- ArraySize = result.take();
+ ArraySize = result.get();
}
// C++98 5.3.4p6: "The expression in a direct-new-declarator shall have
// integral or enumeration type with a non-negative value."
@@ -1225,9 +1258,8 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
if (ArraySize && !ArraySize->isTypeDependent()) {
ExprResult ConvertedSize;
if (getLangOpts().CPlusPlus1y) {
- unsigned IntWidth = Context.getTargetInfo().getIntWidth();
- assert(IntWidth && "Builtin type of size 0?");
- llvm::APSInt Value(IntWidth);
+ assert(Context.getTargetInfo().getIntWidth() && "Builtin type of size 0?");
+
ConvertedSize = PerformImplicitConversion(ArraySize, Context.getSizeType(),
AA_Converting);
@@ -1245,43 +1277,43 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
SizeConvertDiagnoser(Expr *ArraySize)
: ICEConvertDiagnoser(/*AllowScopedEnumerations*/false, false, false),
ArraySize(ArraySize) {}
-
- virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
- QualType T) {
+
+ SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
+ QualType T) override {
return S.Diag(Loc, diag::err_array_size_not_integral)
<< S.getLangOpts().CPlusPlus11 << T;
}
-
- virtual SemaDiagnosticBuilder diagnoseIncomplete(
- Sema &S, SourceLocation Loc, QualType T) {
+
+ SemaDiagnosticBuilder diagnoseIncomplete(
+ Sema &S, SourceLocation Loc, QualType T) override {
return S.Diag(Loc, diag::err_array_size_incomplete_type)
<< T << ArraySize->getSourceRange();
}
-
- virtual SemaDiagnosticBuilder diagnoseExplicitConv(
- Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
+
+ SemaDiagnosticBuilder diagnoseExplicitConv(
+ Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override {
return S.Diag(Loc, diag::err_array_size_explicit_conversion) << T << ConvTy;
}
-
- virtual SemaDiagnosticBuilder noteExplicitConv(
- Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
+
+ SemaDiagnosticBuilder noteExplicitConv(
+ Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override {
return S.Diag(Conv->getLocation(), diag::note_array_size_conversion)
<< ConvTy->isEnumeralType() << ConvTy;
}
-
- virtual SemaDiagnosticBuilder diagnoseAmbiguous(
- Sema &S, SourceLocation Loc, QualType T) {
+
+ SemaDiagnosticBuilder diagnoseAmbiguous(
+ Sema &S, SourceLocation Loc, QualType T) override {
return S.Diag(Loc, diag::err_array_size_ambiguous_conversion) << T;
}
-
- virtual SemaDiagnosticBuilder noteAmbiguous(
- Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
+
+ SemaDiagnosticBuilder noteAmbiguous(
+ Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override {
return S.Diag(Conv->getLocation(), diag::note_array_size_conversion)
<< ConvTy->isEnumeralType() << ConvTy;
}
virtual SemaDiagnosticBuilder diagnoseConversion(
- Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
+ Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override {
return S.Diag(Loc,
S.getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_array_size_conversion
@@ -1296,7 +1328,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
if (ConvertedSize.isInvalid())
return ExprError();
- ArraySize = ConvertedSize.take();
+ ArraySize = ConvertedSize.get();
QualType SizeType = ArraySize->getType();
if (!SizeType->isIntegralOrUnscopedEnumerationType())
@@ -1359,8 +1391,8 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// be signed, larger than size_t, whatever.
}
- FunctionDecl *OperatorNew = 0;
- FunctionDecl *OperatorDelete = 0;
+ FunctionDecl *OperatorNew = nullptr;
+ FunctionDecl *OperatorDelete = nullptr;
if (!AllocType->isDependentType() &&
!Expr::hasAnyTypeDependentArguments(PlacementArgs) &&
@@ -1379,12 +1411,14 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
SmallVector<Expr *, 8> AllPlaceArgs;
if (OperatorNew) {
- // Add default arguments, if any.
const FunctionProtoType *Proto =
- OperatorNew->getType()->getAs<FunctionProtoType>();
- VariadicCallType CallType =
- Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply;
+ OperatorNew->getType()->getAs<FunctionProtoType>();
+ VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction
+ : VariadicDoesNotApply;
+ // We've already converted the placement args, just fill in any default
+ // arguments. Skip the first parameter because we don't have a corresponding
+ // argument.
if (GatherArgumentsForCall(PlacementLParen, OperatorNew, Proto, 1,
PlacementArgs, AllPlaceArgs, CallType))
return ExprError();
@@ -1392,6 +1426,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
if (!AllPlaceArgs.empty())
PlacementArgs = AllPlaceArgs;
+ // FIXME: This is wrong: PlacementArgs misses out the first (size) argument.
DiagnoseSentinelCalls(OperatorNew, PlacementLParen, PlacementArgs);
// FIXME: Missing call to CheckFunctionCall or equivalent
@@ -1438,8 +1473,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// do it now.
if (!AllocType->isDependentType() &&
!Expr::hasAnyTypeDependentArguments(
- llvm::makeArrayRef(Inits, NumInits)) &&
- !HaveCompleteInit) {
+ llvm::makeArrayRef(Inits, NumInits))) {
// C++11 [expr.new]p15:
// A new-expression that creates an object of type T initializes that
// object as follows:
@@ -1469,9 +1503,9 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// we don't want the initialized object to be destructed.
if (CXXBindTemporaryExpr *Binder =
dyn_cast_or_null<CXXBindTemporaryExpr>(FullInit.get()))
- FullInit = Owned(Binder->getSubExpr());
+ FullInit = Binder->getSubExpr();
- Initializer = FullInit.take();
+ Initializer = FullInit.get();
}
// Mark the new and delete operators as referenced.
@@ -1504,13 +1538,11 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
}
}
- return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew,
- OperatorDelete,
- UsualArrayDeleteWantsSize,
- PlacementArgs, TypeIdParens,
- ArraySize, initStyle, Initializer,
- ResultType, AllocTypeInfo,
- Range, DirectInitRange));
+ return new (Context)
+ CXXNewExpr(Context, UseGlobal, OperatorNew, OperatorDelete,
+ UsualArrayDeleteWantsSize, PlacementArgs, TypeIdParens,
+ ArraySize, initStyle, Initializer, ResultType, AllocTypeInfo,
+ Range, DirectInitRange);
}
/// \brief Checks that a type is suitable as the allocated type
@@ -1623,7 +1655,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// Didn't find a member overload. Look for a global one.
DeclareGlobalNewDelete();
DeclContext *TUDecl = Context.getTranslationUnitDecl();
- bool FallbackEnabled = IsArray && Context.getLangOpts().MicrosoftMode;
+ bool FallbackEnabled = IsArray && Context.getLangOpts().MSVCCompat;
if (FindAllocationOverload(StartLoc, Range, NewName, AllocArgs, TUDecl,
/*AllowMissing=*/FallbackEnabled, OperatorNew,
/*Diagnose=*/!FallbackEnabled)) {
@@ -1645,15 +1677,10 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// We don't need an operator delete if we're running under
// -fno-exceptions.
if (!getLangOpts().Exceptions) {
- OperatorDelete = 0;
+ OperatorDelete = nullptr;
return false;
}
- // FindAllocationOverload can change the passed in arguments, so we need to
- // copy them back.
- if (!PlaceArgs.empty())
- std::copy(AllocArgs.begin() + 1, AllocArgs.end(), PlaceArgs.data());
-
// C++ [expr.new]p19:
//
// If the new-expression begins with a unary :: operator, the
@@ -1708,8 +1735,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
SmallVector<QualType, 4> ArgTypes;
ArgTypes.push_back(Context.VoidPtrTy);
- for (unsigned I = 1, N = Proto->getNumArgs(); I < N; ++I)
- ArgTypes.push_back(Proto->getArgType(I));
+ for (unsigned I = 1, N = Proto->getNumParams(); I < N; ++I)
+ ArgTypes.push_back(Proto->getParamType(I));
FunctionProtoType::ExtProtoInfo EPI;
EPI.Variadic = Proto->isVariadic();
@@ -1721,13 +1748,14 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
for (LookupResult::iterator D = FoundDelete.begin(),
DEnd = FoundDelete.end();
D != DEnd; ++D) {
- FunctionDecl *Fn = 0;
+ FunctionDecl *Fn = nullptr;
if (FunctionTemplateDecl *FnTmpl
= dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) {
// Perform template argument deduction to try to match the
// expected function type.
TemplateDeductionInfo Info(StartLoc);
- if (DeduceTemplateArguments(FnTmpl, 0, ExpectedFunctionType, Fn, Info))
+ if (DeduceTemplateArguments(FnTmpl, nullptr, ExpectedFunctionType, Fn,
+ Info))
continue;
} else
Fn = cast<FunctionDecl>((*D)->getUnderlyingDecl());
@@ -1763,7 +1791,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
else
Matches.erase(Matches.begin() + 1);
assert(Matches[0].second->getNumParams() == 2 &&
- "found an unexpected uusal deallocation function");
+ "found an unexpected usual deallocation function");
}
}
@@ -1797,8 +1825,22 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
return false;
}
-/// FindAllocationOverload - Find an fitting overload for the allocation
-/// function in the specified scope.
+/// \brief Find an fitting overload for the allocation function
+/// in the specified scope.
+///
+/// \param StartLoc The location of the 'new' token.
+/// \param Range The range of the placement arguments.
+/// \param Name The name of the function ('operator new' or 'operator new[]').
+/// \param Args The placement arguments specified.
+/// \param Ctx The scope in which we should search; either a class scope or the
+/// translation unit.
+/// \param AllowMissing If \c true, report an error if we can't find any
+/// allocation functions. Otherwise, succeed but don't fill in \p
+/// Operator.
+/// \param Operator Filled in with the found allocation function. Unchanged if
+/// no allocation function was found.
+/// \param Diagnose If \c true, issue errors if the allocation function is not
+/// usable.
bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
DeclarationName Name, MultiExprArg Args,
DeclContext *Ctx,
@@ -1818,7 +1860,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
R.suppressDiagnostics();
- OverloadCandidateSet Candidates(StartLoc);
+ OverloadCandidateSet Candidates(StartLoc, OverloadCandidateSet::CSK_Normal);
for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end();
Alloc != AllocEnd; ++Alloc) {
// Even member operator new/delete are implicitly treated as
@@ -1827,7 +1869,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
if (FunctionTemplateDecl *FnTemplate = dyn_cast<FunctionTemplateDecl>(D)) {
AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(),
- /*ExplicitTemplateArgs=*/0,
+ /*ExplicitTemplateArgs=*/nullptr,
Args, Candidates,
/*SuppressUserConversions=*/false);
continue;
@@ -1844,33 +1886,11 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
case OR_Success: {
// Got one!
FunctionDecl *FnDecl = Best->Function;
- MarkFunctionReferenced(StartLoc, FnDecl);
- // The first argument is size_t, and the first parameter must be size_t,
- // too. This is checked on declaration and can be assumed. (It can't be
- // asserted on, though, since invalid decls are left in there.)
- // Watch out for variadic allocator function.
- unsigned NumArgsInFnDecl = FnDecl->getNumParams();
- for (unsigned i = 0; (i < Args.size() && i < NumArgsInFnDecl); ++i) {
- InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
- FnDecl->getParamDecl(i));
-
- if (!Diagnose && !CanPerformCopyInitialization(Entity, Owned(Args[i])))
- return true;
-
- ExprResult Result
- = PerformCopyInitialization(Entity, SourceLocation(), Owned(Args[i]));
- if (Result.isInvalid())
- return true;
-
- Args[i] = Result.takeAs<Expr>();
- }
-
- Operator = FnDecl;
-
if (CheckAllocationAccess(StartLoc, Range, R.getNamingClass(),
Best->FoundDecl, Diagnose) == AR_inaccessible)
return true;
+ Operator = FnDecl;
return false;
}
@@ -1970,7 +1990,7 @@ void Sema::DeclareGlobalNewDelete() {
getOrCreateStdNamespace(),
SourceLocation(), SourceLocation(),
&PP.getIdentifierTable().get("bad_alloc"),
- 0);
+ nullptr);
getStdBadAlloc()->setImplicit(true);
}
@@ -2031,8 +2051,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
if (InitialParam1Type == Param1 &&
(NumParams == 1 || InitialParam2Type == Param2)) {
if (AddMallocAttr && !Func->hasAttr<MallocAttr>())
- Func->addAttr(::new (Context) MallocAttr(SourceLocation(),
- Context));
+ Func->addAttr(MallocAttr::CreateImplicit(Context));
// Make the function visible to name lookup, even if we found it in
// an unimported module. It either is an implicitly-declared global
// allocation function, or is suppressing that function.
@@ -2043,18 +2062,16 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
}
}
+ FunctionProtoType::ExtProtoInfo EPI;
+
QualType BadAllocType;
bool HasBadAllocExceptionSpec
= (Name.getCXXOverloadedOperator() == OO_New ||
Name.getCXXOverloadedOperator() == OO_Array_New);
- if (HasBadAllocExceptionSpec && !getLangOpts().CPlusPlus11) {
- assert(StdBadAlloc && "Must have std::bad_alloc declared");
- BadAllocType = Context.getTypeDeclType(getStdBadAlloc());
- }
-
- FunctionProtoType::ExtProtoInfo EPI;
if (HasBadAllocExceptionSpec) {
if (!getLangOpts().CPlusPlus11) {
+ BadAllocType = Context.getTypeDeclType(getStdBadAlloc());
+ assert(StdBadAlloc && "Must have std::bad_alloc declared");
EPI.ExceptionSpecType = EST_Dynamic;
EPI.NumExceptions = 1;
EPI.Exceptions = &BadAllocType;
@@ -2071,24 +2088,24 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
FunctionDecl *Alloc =
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(),
SourceLocation(), Name,
- FnType, /*TInfo=*/0, SC_None, false, true);
+ FnType, /*TInfo=*/nullptr, SC_None, false, true);
Alloc->setImplicit();
if (AddMallocAttr)
- Alloc->addAttr(::new (Context) MallocAttr(SourceLocation(), Context));
+ Alloc->addAttr(MallocAttr::CreateImplicit(Context));
ParmVarDecl *ParamDecls[2];
- for (unsigned I = 0; I != NumParams; ++I)
+ for (unsigned I = 0; I != NumParams; ++I) {
ParamDecls[I] = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
- SourceLocation(), 0,
- Params[I], /*TInfo=*/0,
- SC_None, 0);
+ SourceLocation(), nullptr,
+ Params[I], /*TInfo=*/nullptr,
+ SC_None, nullptr);
+ ParamDecls[I]->setImplicit();
+ }
Alloc->setParams(ArrayRef<ParmVarDecl*>(ParamDecls, NumParams));
- // FIXME: Also add this declaration to the IdentifierResolver, but
- // make sure it is at the end of the chain to coincide with the
- // global scope.
Context.getTranslationUnitDecl()->addDecl(Alloc);
+ IdResolver.tryAddTopLevelDecl(Alloc, Name);
}
FunctionDecl *Sema::FindUsualDeallocationFunction(SourceLocation StartLoc,
@@ -2125,7 +2142,7 @@ FunctionDecl *Sema::FindUsualDeallocationFunction(SourceLocation StartLoc,
else
Matches.erase(Matches.begin() + 1);
assert(Matches[0]->getNumParams() == NumArgs &&
- "found an unexpected uusal deallocation function");
+ "found an unexpected usual deallocation function");
}
assert(Matches.size() == 1 &&
@@ -2206,7 +2223,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
return true;
}
- Operator = 0;
+ Operator = nullptr;
return false;
}
@@ -2224,14 +2241,14 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
//
// DR599 amends "pointer type" to "pointer to object type" in both cases.
- ExprResult Ex = Owned(ExE);
- FunctionDecl *OperatorDelete = 0;
+ ExprResult Ex = ExE;
+ FunctionDecl *OperatorDelete = nullptr;
bool ArrayFormAsWritten = ArrayForm;
bool UsualArrayDeleteWantsSize = false;
if (!Ex.get()->isTypeDependent()) {
// Perform lvalue-to-rvalue cast, if needed.
- Ex = DefaultLvalueConversion(Ex.take());
+ Ex = DefaultLvalueConversion(Ex.get());
if (Ex.isInvalid())
return ExprError();
@@ -2241,7 +2258,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
public:
DeleteConverter() : ContextualImplicitConverter(false, true) {}
- bool match(QualType ConvType) {
+ bool match(QualType ConvType) override {
// FIXME: If we have an operator T* and an operator void*, we must pick
// the operator T*.
if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
@@ -2251,44 +2268,46 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
}
SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc,
- QualType T) {
+ QualType T) override {
return S.Diag(Loc, diag::err_delete_operand) << T;
}
SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc,
- QualType T) {
+ QualType T) override {
return S.Diag(Loc, diag::err_delete_incomplete_class_type) << T;
}
SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc,
- QualType T, QualType ConvTy) {
+ QualType T,
+ QualType ConvTy) override {
return S.Diag(Loc, diag::err_delete_explicit_conversion) << T << ConvTy;
}
SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv,
- QualType ConvTy) {
+ QualType ConvTy) override {
return S.Diag(Conv->getLocation(), diag::note_delete_conversion)
<< ConvTy;
}
SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
- QualType T) {
+ QualType T) override {
return S.Diag(Loc, diag::err_ambiguous_delete_operand) << T;
}
SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv,
- QualType ConvTy) {
+ QualType ConvTy) override {
return S.Diag(Conv->getLocation(), diag::note_delete_conversion)
<< ConvTy;
}
SemaDiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc,
- QualType T, QualType ConvTy) {
+ QualType T,
+ QualType ConvTy) override {
llvm_unreachable("conversion functions are permitted");
}
} Converter;
- Ex = PerformContextualImplicitConversion(StartLoc, Ex.take(), Converter);
+ Ex = PerformContextualImplicitConversion(StartLoc, Ex.get(), Converter);
if (Ex.isInvalid())
return ExprError();
Type = Ex.get()->getType();
@@ -2305,7 +2324,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
diag::err_address_space_qualified_delete)
<< Pointee.getUnqualifiedType() << AddressSpace;
- CXXRecordDecl *PointeeRD = 0;
+ CXXRecordDecl *PointeeRD = nullptr;
if (Pointee->isVoidType() && !isSFINAEContext()) {
// The C++ standard bans deleting a pointer to a non-object type, which
// effectively bans deletion of "void*". However, most compilers support
@@ -2413,10 +2432,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
}
}
- return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm,
- ArrayFormAsWritten,
- UsualArrayDeleteWantsSize,
- OperatorDelete, Ex.take(), StartLoc));
+ return new (Context) CXXDeleteExpr(
+ Context.VoidTy, UseGlobal, ArrayForm, ArrayFormAsWritten,
+ UsualArrayDeleteWantsSize, OperatorDelete, Ex.get(), StartLoc);
}
/// \brief Check the use of the given variable as a C++ condition in an if,
@@ -2440,19 +2458,15 @@ ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar,
diag::err_invalid_use_of_array_type)
<< ConditionVar->getSourceRange());
- ExprResult Condition =
- Owned(DeclRefExpr::Create(Context, NestedNameSpecifierLoc(),
- SourceLocation(),
- ConditionVar,
- /*enclosing*/ false,
- ConditionVar->getLocation(),
- ConditionVar->getType().getNonReferenceType(),
- VK_LValue));
+ ExprResult Condition = DeclRefExpr::Create(
+ Context, NestedNameSpecifierLoc(), SourceLocation(), ConditionVar,
+ /*enclosing*/ false, ConditionVar->getLocation(),
+ ConditionVar->getType().getNonReferenceType(), VK_LValue);
MarkDeclRefReferenced(cast<DeclRefExpr>(Condition.get()));
if (ConvertToBoolean) {
- Condition = CheckBooleanCondition(Condition.take(), StmtLoc);
+ Condition = CheckBooleanCondition(Condition.get(), StmtLoc);
if (Condition.isInvalid())
return ExprError();
}
@@ -2537,15 +2551,15 @@ static ExprResult BuildCXXCastArgument(Sema &S,
InitializedEntity::InitializeTemporary(Ty),
Constructor->getAccess());
- ExprResult Result
- = S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
- ConstructorArgs, HadMultipleCandidates,
- /*ListInit*/ false, /*ZeroInit*/ false,
- CXXConstructExpr::CK_Complete, SourceRange());
+ ExprResult Result = S.BuildCXXConstructExpr(
+ CastLoc, Ty, cast<CXXConstructorDecl>(Method),
+ ConstructorArgs, HadMultipleCandidates,
+ /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false,
+ CXXConstructExpr::CK_Complete, SourceRange());
if (Result.isInvalid())
return ExprError();
- return S.MaybeBindToTemporary(Result.takeAs<Expr>());
+ return S.MaybeBindToTemporary(Result.getAs<Expr>());
}
case CK_UserDefinedConversion: {
@@ -2558,13 +2572,11 @@ static ExprResult BuildCXXCastArgument(Sema &S,
if (Result.isInvalid())
return ExprError();
// Record usage of conversion in an implicit cast.
- Result = S.Owned(ImplicitCastExpr::Create(S.Context,
- Result.get()->getType(),
- CK_UserDefinedConversion,
- Result.get(), 0,
- Result.get()->getValueKind()));
+ Result = ImplicitCastExpr::Create(S.Context, Result.get()->getType(),
+ CK_UserDefinedConversion, Result.get(),
+ nullptr, Result.get()->getValueKind());
- S.CheckMemberOperatorAccess(CastLoc, From, /*arg*/ 0, FoundDecl);
+ S.CheckMemberOperatorAccess(CastLoc, From, /*arg*/ nullptr, FoundDecl);
return S.MaybeBindToTemporary(Result.get());
}
@@ -2587,7 +2599,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
Action, CCK);
if (Res.isInvalid())
return ExprError();
- From = Res.take();
+ From = Res.get();
break;
}
@@ -2623,7 +2635,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
CCK);
if (Res.isInvalid())
return ExprError();
- From = Res.take();
+ From = Res.get();
}
ExprResult CastArg
@@ -2638,7 +2650,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
if (CastArg.isInvalid())
return ExprError();
- From = CastArg.take();
+ From = CastArg.get();
return PerformImplicitConversion(From, ToType, ICS.UserDefined.After,
AA_Converting, CCK);
@@ -2658,7 +2670,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
}
// Everything went well.
- return Owned(From);
+ return From;
}
/// PerformImplicitConversion - Perform an implicit conversion of the
@@ -2688,20 +2700,17 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
From, /*FIXME:ConstructLoc*/SourceLocation(),
ConstructorArgs))
return ExprError();
- return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
- ToType, SCS.CopyConstructor,
- ConstructorArgs,
- /*HadMultipleCandidates*/ false,
- /*ListInit*/ false, /*ZeroInit*/ false,
- CXXConstructExpr::CK_Complete,
- SourceRange());
+ return BuildCXXConstructExpr(
+ /*FIXME:ConstructLoc*/ SourceLocation(), ToType, SCS.CopyConstructor,
+ ConstructorArgs, /*HadMultipleCandidates*/ false,
+ /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false,
+ CXXConstructExpr::CK_Complete, SourceRange());
}
- return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
- ToType, SCS.CopyConstructor,
- From, /*HadMultipleCandidates*/ false,
- /*ListInit*/ false, /*ZeroInit*/ false,
- CXXConstructExpr::CK_Complete,
- SourceRange());
+ return BuildCXXConstructExpr(
+ /*FIXME:ConstructLoc*/ SourceLocation(), ToType, SCS.CopyConstructor,
+ From, /*HadMultipleCandidates*/ false,
+ /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false,
+ CXXConstructExpr::CK_Complete, SourceRange());
}
// Resolve overloaded function references.
@@ -2738,20 +2747,20 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
FromType = FromType.getUnqualifiedType();
ExprResult FromRes = DefaultLvalueConversion(From);
assert(!FromRes.isInvalid() && "Can't perform deduced conversion?!");
- From = FromRes.take();
+ From = FromRes.get();
break;
}
case ICK_Array_To_Pointer:
FromType = Context.getArrayDecayedType(FromType);
From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
break;
case ICK_Function_To_Pointer:
FromType = Context.getPointerType(FromType);
From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
break;
default:
@@ -2775,7 +2784,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
return ExprError();
From = ImpCastExprToType(From, ToType, CK_NoOp,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
break;
case ICK_Integral_Promotion:
@@ -2785,17 +2794,17 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
SCS.Second == ICK_Integral_Promotion &&
"only enums with fixed underlying type can promote to bool");
From = ImpCastExprToType(From, ToType, CK_IntegralToBoolean,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
} else {
From = ImpCastExprToType(From, ToType, CK_IntegralCast,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
}
break;
case ICK_Floating_Promotion:
case ICK_Floating_Conversion:
From = ImpCastExprToType(From, ToType, CK_FloatingCast,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
break;
case ICK_Complex_Promotion:
@@ -2814,22 +2823,22 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
CK = CK_IntegralComplexCast;
}
From = ImpCastExprToType(From, ToType, CK,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
break;
}
case ICK_Floating_Integral:
if (ToType->isRealFloatingType())
From = ImpCastExprToType(From, ToType, CK_IntegralToFloating,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
else
From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
break;
case ICK_Compatible_Conversion:
From = ImpCastExprToType(From, ToType, CK_NoOp,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
break;
case ICK_Writeback_Conversion:
@@ -2874,12 +2883,12 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
if (Kind == CK_BlockPointerToObjCPointerCast) {
ExprResult E = From;
(void) PrepareCastToObjCObjectPointer(E);
- From = E.take();
+ From = E.get();
}
if (getLangOpts().ObjCAutoRefCount)
CheckObjCARCConversion(SourceRange(), ToType, From, CCK);
From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
- .take();
+ .get();
break;
}
@@ -2891,20 +2900,20 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
if (CheckExceptionSpecCompatibility(From, ToType))
return ExprError();
From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
- .take();
+ .get();
break;
}
case ICK_Boolean_Conversion:
// Perform half-to-boolean conversion via float.
if (From->getType()->isHalfType()) {
- From = ImpCastExprToType(From, Context.FloatTy, CK_FloatingCast).take();
+ From = ImpCastExprToType(From, Context.FloatTy, CK_FloatingCast).get();
FromType = Context.FloatTy;
}
From = ImpCastExprToType(From, Context.BoolTy,
ScalarTypeToBooleanCastKind(FromType),
- VK_RValue, /*BasePath=*/0, CCK).take();
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
break;
case ICK_Derived_To_Base: {
@@ -2919,18 +2928,18 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
From = ImpCastExprToType(From, ToType.getNonReferenceType(),
CK_DerivedToBase, From->getValueKind(),
- &BasePath, CCK).take();
+ &BasePath, CCK).get();
break;
}
case ICK_Vector_Conversion:
From = ImpCastExprToType(From, ToType, CK_BitCast,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
break;
case ICK_Vector_Splat:
From = ImpCastExprToType(From, ToType, CK_VectorSplat,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
break;
case ICK_Complex_Real:
@@ -2944,16 +2953,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
// do nothing
} else if (From->getType()->isRealFloatingType()) {
From = ImpCastExprToType(From, ElType,
- isFloatingComplex ? CK_FloatingCast : CK_FloatingToIntegral).take();
+ isFloatingComplex ? CK_FloatingCast : CK_FloatingToIntegral).get();
} else {
assert(From->getType()->isIntegerType());
From = ImpCastExprToType(From, ElType,
- isFloatingComplex ? CK_IntegralToFloating : CK_IntegralCast).take();
+ isFloatingComplex ? CK_IntegralToFloating : CK_IntegralCast).get();
}
// y -> _Complex y
From = ImpCastExprToType(From, ToType,
isFloatingComplex ? CK_FloatingRealToComplex
- : CK_IntegralRealToComplex).take();
+ : CK_IntegralRealToComplex).get();
// Case 2. _Complex x -> y
} else {
@@ -2967,7 +2976,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
From = ImpCastExprToType(From, ElType,
isFloatingComplex ? CK_FloatingComplexToReal
: CK_IntegralComplexToReal,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
// x -> y
if (Context.hasSameUnqualifiedType(ElType, ToType)) {
@@ -2975,29 +2984,29 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
} else if (ToType->isRealFloatingType()) {
From = ImpCastExprToType(From, ToType,
isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
} else {
assert(ToType->isIntegerType());
From = ImpCastExprToType(From, ToType,
isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
}
}
break;
case ICK_Block_Pointer_Conversion: {
From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast,
- VK_RValue, /*BasePath=*/0, CCK).take();
+ VK_RValue, /*BasePath=*/nullptr, CCK).get();
break;
}
case ICK_TransparentUnionConversion: {
- ExprResult FromRes = Owned(From);
+ ExprResult FromRes = From;
Sema::AssignConvertType ConvTy =
CheckTransparentUnionArgumentConstraints(ToType, FromRes);
if (FromRes.isInvalid())
return ExprError();
- From = FromRes.take();
+ From = FromRes.get();
assert ((ConvTy == Sema::Compatible) &&
"Improper transparent union conversion");
(void)ConvTy;
@@ -3007,7 +3016,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
case ICK_Zero_Event_Conversion:
From = ImpCastExprToType(From, ToType,
CK_ZeroToOCLEvent,
- From->getValueKind()).take();
+ From->getValueKind()).get();
break;
case ICK_Lvalue_To_Rvalue:
@@ -3029,12 +3038,15 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
ExprValueKind VK = ToType->isReferenceType() ?
From->getValueKind() : VK_RValue;
From = ImpCastExprToType(From, ToType.getNonLValueExprType(Context),
- CK_NoOp, VK, /*BasePath=*/0, CCK).take();
+ CK_NoOp, VK, /*BasePath=*/nullptr, CCK).get();
if (SCS.DeprecatedStringLiteralToCharPtr &&
- !getLangOpts().WritableStrings)
- Diag(From->getLocStart(), diag::warn_deprecated_string_literal_conversion)
+ !getLangOpts().WritableStrings) {
+ Diag(From->getLocStart(), getLangOpts().CPlusPlus11
+ ? diag::ext_deprecated_string_literal_conversion
+ : diag::warn_deprecated_string_literal_conversion)
<< ToType.getNonReferenceType();
+ }
break;
}
@@ -3049,22 +3061,10 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
assert(Context.hasSameType(
ToAtomicType->castAs<AtomicType>()->getValueType(), From->getType()));
From = ImpCastExprToType(From, ToAtomicType, CK_NonAtomicToAtomic,
- VK_RValue, 0, CCK).take();
+ VK_RValue, nullptr, CCK).get();
}
- return Owned(From);
-}
-
-ExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait UTT,
- SourceLocation KWLoc,
- ParsedType Ty,
- SourceLocation RParen) {
- TypeSourceInfo *TSInfo;
- QualType T = GetTypeFromParser(Ty, &TSInfo);
-
- if (!TSInfo)
- TSInfo = Context.getTrivialTypeSourceInfo(T);
- return BuildUnaryTypeTrait(UTT, KWLoc, TSInfo, RParen);
+ return From;
}
/// \brief Check the completeness of a type in a unary type trait.
@@ -3073,8 +3073,7 @@ ExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait UTT,
/// it. If completing the type fails, a diagnostic is emitted and false
/// returned. If completing the type succeeds or no completion was required,
/// returns true.
-static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
- UnaryTypeTrait UTT,
+static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
SourceLocation Loc,
QualType ArgTy) {
// C++0x [meta.unary.prop]p3:
@@ -3087,6 +3086,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
// these class templates. We also try to follow any GCC documented behavior
// in these expressions to ensure portability of standard libraries.
switch (UTT) {
+ default: llvm_unreachable("not a UTT");
// is_complete_type somewhat obviously cannot require a complete type.
case UTT_IsCompleteType:
// Fall-through
@@ -3139,6 +3139,8 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
case UTT_IsPolymorphic:
case UTT_IsAbstract:
case UTT_IsInterfaceClass:
+ case UTT_IsDestructible:
+ case UTT_IsNothrowDestructible:
// Fall-through
// These traits require a complete type.
@@ -3173,7 +3175,6 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
return !S.RequireCompleteType(
Loc, ElTy, diag::err_incomplete_type_used_in_type_trait_expr);
}
- llvm_unreachable("Type trait not handled by switch");
}
static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op,
@@ -3203,7 +3204,7 @@ static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op,
const FunctionProtoType *CPT =
Operator->getType()->getAs<FunctionProtoType>();
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
- if (!CPT || !CPT->isNothrow(Self.Context))
+ if (!CPT || !CPT->isNothrow(C))
return false;
}
}
@@ -3212,12 +3213,13 @@ static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op,
return false;
}
-static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
+static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
SourceLocation KeyLoc, QualType T) {
assert(!T->isDependentType() && "Cannot evaluate traits of dependent type");
ASTContext &C = Self.Context;
switch(UTT) {
+ default: llvm_unreachable("not a UTT");
// Type trait expressions corresponding to the primary type category
// predicates in C++0x [meta.unary.cat].
case UTT_IsVoid:
@@ -3404,8 +3406,12 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
return RD->hasTrivialCopyAssignment() &&
!RD->hasNonTrivialCopyAssignment();
return false;
+ case UTT_IsDestructible:
+ case UTT_IsNothrowDestructible:
+ // FIXME: Implement UTT_IsDestructible and UTT_IsNothrowDestructible.
+ // For now, let's fall through.
case UTT_HasTrivialDestructor:
- // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+ // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
// If __is_pod (type) is true or type is a reference type
// then the trait is true, else if type is a cv class or union
// type (or array thereof) with a trivial destructor
@@ -3488,9 +3494,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
if (!CPT)
return false;
- // FIXME: check whether evaluating default arguments can throw.
+ // TODO: check whether evaluating default arguments can throw.
// For now, we'll be conservative and assume that they can throw.
- if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1)
+ if (!CPT->isNothrow(Self.Context) || CPT->getNumParams() > 1)
return false;
}
}
@@ -3499,7 +3505,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
}
return false;
case UTT_HasNothrowConstructor:
- // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+ // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
// If __has_trivial_constructor (type) is true then the trait is
// true, else if type is a cv class or union type (or array
// thereof) with a default constructor that is known not to
@@ -3511,6 +3517,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
!RD->hasNonTrivialDefaultConstructor())
return true;
+ bool FoundConstructor = false;
DeclContext::lookup_const_result R = Self.LookupConstructors(RD);
for (DeclContext::lookup_const_iterator Con = R.begin(),
ConEnd = R.end(); Con != ConEnd; ++Con) {
@@ -3519,16 +3526,19 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
continue;
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
if (Constructor->isDefaultConstructor()) {
+ FoundConstructor = true;
const FunctionProtoType *CPT
= Constructor->getType()->getAs<FunctionProtoType>();
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
if (!CPT)
return false;
- // TODO: check whether evaluating default arguments can throw.
+ // FIXME: check whether evaluating default arguments can throw.
// For now, we'll be conservative and assume that they can throw.
- return CPT->isNothrow(Self.Context) && CPT->getNumArgs() == 0;
+ if (!CPT->isNothrow(Self.Context) || CPT->getNumParams() > 0)
+ return false;
}
}
+ return FoundConstructor;
}
return false;
case UTT_HasVirtualDestructor:
@@ -3549,41 +3559,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// function call.
return !T->isIncompleteType();
}
- llvm_unreachable("Type trait not covered by switch");
-}
-
-ExprResult Sema::BuildUnaryTypeTrait(UnaryTypeTrait UTT,
- SourceLocation KWLoc,
- TypeSourceInfo *TSInfo,
- SourceLocation RParen) {
- QualType T = TSInfo->getType();
- if (!CheckUnaryTypeTraitTypeCompleteness(*this, UTT, KWLoc, T))
- return ExprError();
-
- bool Value = false;
- if (!T->isDependentType())
- Value = EvaluateUnaryTypeTrait(*this, UTT, KWLoc, T);
-
- return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, UTT, TSInfo, Value,
- RParen, Context.BoolTy));
-}
-
-ExprResult Sema::ActOnBinaryTypeTrait(BinaryTypeTrait BTT,
- SourceLocation KWLoc,
- ParsedType LhsTy,
- ParsedType RhsTy,
- SourceLocation RParen) {
- TypeSourceInfo *LhsTSInfo;
- QualType LhsT = GetTypeFromParser(LhsTy, &LhsTSInfo);
- if (!LhsTSInfo)
- LhsTSInfo = Context.getTrivialTypeSourceInfo(LhsT);
-
- TypeSourceInfo *RhsTSInfo;
- QualType RhsT = GetTypeFromParser(RhsTy, &RhsTSInfo);
- if (!RhsTSInfo)
- RhsTSInfo = Context.getTrivialTypeSourceInfo(RhsT);
-
- return BuildBinaryTypeTrait(BTT, KWLoc, LhsTSInfo, RhsTSInfo, RParen);
}
/// \brief Determine whether T has a non-trivial Objective-C lifetime in
@@ -3605,10 +3580,22 @@ static bool hasNontrivialObjCLifetime(QualType T) {
llvm_unreachable("Unknown ObjC lifetime qualifier");
}
+static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
+ QualType RhsT, SourceLocation KeyLoc);
+
static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
ArrayRef<TypeSourceInfo *> Args,
SourceLocation RParenLoc) {
+ if (Kind <= UTT_Last)
+ return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]->getType());
+
+ if (Kind <= BTT_Last)
+ return EvaluateBinaryTypeTrait(S, Kind, Args[0]->getType(),
+ Args[1]->getType(), RParenLoc);
+
switch (Kind) {
+ case clang::TT_IsConstructible:
+ case clang::TT_IsNothrowConstructible:
case clang::TT_IsTriviallyConstructible: {
// C++11 [meta.unary.prop]:
// is_trivially_constructible is defined as:
@@ -3623,11 +3610,7 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
// variable t:
//
// T t(create<Args>()...);
- if (Args.empty()) {
- S.Diag(KWLoc, diag::err_type_trait_arity)
- << 1 << 1 << 1 << (int)Args.size();
- return false;
- }
+ assert(!Args.empty());
// Precondition: T and all types in the parameter pack Args shall be
// complete types, (possibly cv-qualified) void, or arrays of
@@ -3646,6 +3629,11 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
if (Args[0]->getType()->isIncompleteType())
return false;
+ // Make sure the first argument is not an abstract type.
+ CXXRecordDecl *RD = Args[0]->getType()->getAsCXXRecordDecl();
+ if (RD && RD->isAbstract())
+ return false;
+
SmallVector<OpaqueValueExpr, 2> OpaqueArgExprs;
SmallVector<Expr *, 2> ArgExprs;
ArgExprs.reserve(Args.size() - 1);
@@ -3671,21 +3659,33 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
InitializationSequence Init(S, To, InitKind, ArgExprs);
if (Init.Failed())
return false;
-
+
ExprResult Result = Init.Perform(S, To, InitKind, ArgExprs);
if (Result.isInvalid() || SFINAE.hasErrorOccurred())
return false;
- // Under Objective-C ARC, if the destination has non-trivial Objective-C
- // lifetime, this is a non-trivial construction.
- if (S.getLangOpts().ObjCAutoRefCount &&
- hasNontrivialObjCLifetime(Args[0]->getType().getNonReferenceType()))
- return false;
+ if (Kind == clang::TT_IsConstructible)
+ return true;
+
+ if (Kind == clang::TT_IsNothrowConstructible)
+ return S.canThrow(Result.get()) == CT_Cannot;
- // The initialization succeeded; now make sure there are no non-trivial
- // calls.
- return !Result.get()->hasNonTrivialCall(S.Context);
+ if (Kind == clang::TT_IsTriviallyConstructible) {
+ // Under Objective-C ARC, if the destination has non-trivial Objective-C
+ // lifetime, this is a non-trivial construction.
+ if (S.getLangOpts().ObjCAutoRefCount &&
+ hasNontrivialObjCLifetime(Args[0]->getType().getNonReferenceType()))
+ return false;
+
+ // The initialization succeeded; now make sure there are no non-trivial
+ // calls.
+ return !Result.get()->hasNonTrivialCall(S.Context);
+ }
+
+ llvm_unreachable("unhandled type trait");
+ return false;
}
+ default: llvm_unreachable("not a TT");
}
return false;
@@ -3694,6 +3694,12 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
ArrayRef<TypeSourceInfo *> Args,
SourceLocation RParenLoc) {
+ QualType ResultType = Context.getLogicalOperationType();
+
+ if (Kind <= UTT_Last && !CheckUnaryTypeTraitTypeCompleteness(
+ *this, Kind, KWLoc, Args[0]->getType()))
+ return ExprError();
+
bool Dependent = false;
for (unsigned I = 0, N = Args.size(); I != N; ++I) {
if (Args[I]->getType()->isDependentType()) {
@@ -3701,17 +3707,17 @@ ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
break;
}
}
-
- bool Value = false;
+
+ bool Result = false;
if (!Dependent)
- Value = evaluateTypeTrait(*this, Kind, KWLoc, Args, RParenLoc);
-
- return TypeTraitExpr::Create(Context, Context.BoolTy, KWLoc, Kind,
- Args, RParenLoc, Value);
+ Result = evaluateTypeTrait(*this, Kind, KWLoc, Args, RParenLoc);
+
+ return TypeTraitExpr::Create(Context, ResultType, KWLoc, Kind, Args,
+ RParenLoc, Result);
}
-ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
- ArrayRef<ParsedType> Args,
+ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
+ ArrayRef<ParsedType> Args,
SourceLocation RParenLoc) {
SmallVector<TypeSourceInfo *, 4> ConvertedArgs;
ConvertedArgs.reserve(Args.size());
@@ -3724,13 +3730,12 @@ ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
ConvertedArgs.push_back(TInfo);
}
-
+
return BuildTypeTrait(Kind, KWLoc, ConvertedArgs, RParenLoc);
}
-static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT,
- QualType LhsT, QualType RhsT,
- SourceLocation KeyLoc) {
+static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
+ QualType RhsT, SourceLocation KeyLoc) {
assert(!LhsT->isDependentType() && !RhsT->isDependentType() &&
"Cannot evaluate traits of dependent types");
@@ -3833,7 +3838,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT,
ExprResult Result = Init.Perform(Self, To, Kind, FromPtr);
return !Result.isInvalid() && !SFINAE.hasErrorOccurred();
}
-
+
+ case BTT_IsNothrowAssignable:
case BTT_IsTriviallyAssignable: {
// C++11 [meta.unary.prop]p3:
// is_trivially_assignable is defined as:
@@ -3875,56 +3881,30 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT,
EnterExpressionEvaluationContext Unevaluated(Self, Sema::Unevaluated);
Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true);
Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
- ExprResult Result = Self.BuildBinOp(/*S=*/0, KeyLoc, BO_Assign, &Lhs, &Rhs);
+ ExprResult Result = Self.BuildBinOp(/*S=*/nullptr, KeyLoc, BO_Assign, &Lhs,
+ &Rhs);
if (Result.isInvalid() || SFINAE.hasErrorOccurred())
return false;
- // Under Objective-C ARC, if the destination has non-trivial Objective-C
- // lifetime, this is a non-trivial assignment.
- if (Self.getLangOpts().ObjCAutoRefCount &&
- hasNontrivialObjCLifetime(LhsT.getNonReferenceType()))
- return false;
-
- return !Result.get()->hasNonTrivialCall(Self.Context);
- }
- }
- llvm_unreachable("Unknown type trait or not implemented");
-}
+ if (BTT == BTT_IsNothrowAssignable)
+ return Self.canThrow(Result.get()) == CT_Cannot;
-ExprResult Sema::BuildBinaryTypeTrait(BinaryTypeTrait BTT,
- SourceLocation KWLoc,
- TypeSourceInfo *LhsTSInfo,
- TypeSourceInfo *RhsTSInfo,
- SourceLocation RParen) {
- QualType LhsT = LhsTSInfo->getType();
- QualType RhsT = RhsTSInfo->getType();
+ if (BTT == BTT_IsTriviallyAssignable) {
+ // Under Objective-C ARC, if the destination has non-trivial Objective-C
+ // lifetime, this is a non-trivial assignment.
+ if (Self.getLangOpts().ObjCAutoRefCount &&
+ hasNontrivialObjCLifetime(LhsT.getNonReferenceType()))
+ return false;
- if (BTT == BTT_TypeCompatible) {
- if (getLangOpts().CPlusPlus) {
- Diag(KWLoc, diag::err_types_compatible_p_in_cplusplus)
- << SourceRange(KWLoc, RParen);
- return ExprError();
+ return !Result.get()->hasNonTrivialCall(Self.Context);
}
- }
-
- bool Value = false;
- if (!LhsT->isDependentType() && !RhsT->isDependentType())
- Value = EvaluateBinaryTypeTrait(*this, BTT, LhsT, RhsT, KWLoc);
- // Select trait result type.
- QualType ResultType;
- switch (BTT) {
- case BTT_IsBaseOf: ResultType = Context.BoolTy; break;
- case BTT_IsConvertible: ResultType = Context.BoolTy; break;
- case BTT_IsSame: ResultType = Context.BoolTy; break;
- case BTT_TypeCompatible: ResultType = Context.IntTy; break;
- case BTT_IsConvertibleTo: ResultType = Context.BoolTy; break;
- case BTT_IsTriviallyAssignable: ResultType = Context.BoolTy;
+ llvm_unreachable("unhandled type trait");
+ return false;
}
-
- return Owned(new (Context) BinaryTypeTraitExpr(KWLoc, BTT, LhsTSInfo,
- RhsTSInfo, Value, RParen,
- ResultType));
+ default: llvm_unreachable("not a BTT");
+ }
+ llvm_unreachable("Unknown type trait or not implemented");
}
ExprResult Sema::ActOnArrayTypeTrait(ArrayTypeTrait ATT,
@@ -4012,9 +3992,8 @@ ExprResult Sema::BuildArrayTypeTrait(ArrayTypeTrait ATT,
// returns 'size_t'. On Windows, the primary platform for the Embarcadero
// compiler, there is no difference. On several other platforms this is an
// important distinction.
- return Owned(new (Context) ArrayTypeTraitExpr(KWLoc, ATT, TSInfo, Value,
- DimExpr, RParen,
- Context.getSizeType()));
+ return new (Context) ArrayTypeTraitExpr(KWLoc, ATT, TSInfo, Value, DimExpr,
+ RParen, Context.getSizeType());
}
ExprResult Sema::ActOnExpressionTrait(ExpressionTrait ET,
@@ -4047,13 +4026,13 @@ ExprResult Sema::BuildExpressionTrait(ExpressionTrait ET,
} else if (Queried->getType()->isPlaceholderType()) {
ExprResult PE = CheckPlaceholderExpr(Queried);
if (PE.isInvalid()) return ExprError();
- return BuildExpressionTrait(ET, KWLoc, PE.take(), RParen);
+ return BuildExpressionTrait(ET, KWLoc, PE.get(), RParen);
}
bool Value = EvaluateExpressionTrait(ET, Queried);
- return Owned(new (Context) ExpressionTraitExpr(KWLoc, ET, Queried, Value,
- RParen, Context.BoolTy));
+ return new (Context)
+ ExpressionTraitExpr(KWLoc, ET, Queried, Value, RParen, Context.BoolTy);
}
QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS,
@@ -4066,12 +4045,12 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS,
// The LHS undergoes lvalue conversions if this is ->*.
if (isIndirect) {
- LHS = DefaultLvalueConversion(LHS.take());
+ LHS = DefaultLvalueConversion(LHS.get());
if (LHS.isInvalid()) return QualType();
}
// The RHS always undergoes lvalue conversions.
- RHS = DefaultLvalueConversion(RHS.take());
+ RHS = DefaultLvalueConversion(RHS.get());
if (RHS.isInvalid()) return QualType();
const char *OpSpelling = isIndirect ? "->*" : ".*";
@@ -4117,23 +4096,24 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS,
OpSpelling, (int)isIndirect)) {
return QualType();
}
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
- /*DetectVirtual=*/false);
- // FIXME: Would it be useful to print full ambiguity paths, or is that
- // overkill?
- if (!IsDerivedFrom(LHSType, Class, Paths) ||
- Paths.isAmbiguous(Context.getCanonicalType(Class))) {
+
+ if (!IsDerivedFrom(LHSType, Class)) {
Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling
<< (int)isIndirect << LHS.get()->getType();
return QualType();
}
+
+ CXXCastPath BasePath;
+ if (CheckDerivedToBaseConversion(LHSType, Class, Loc,
+ SourceRange(LHS.get()->getLocStart(),
+ RHS.get()->getLocEnd()),
+ &BasePath))
+ return QualType();
+
// Cast LHS to type of use.
QualType UseType = isIndirect ? Context.getPointerType(Class) : Class;
ExprValueKind VK = isIndirect ? VK_RValue : LHS.get()->getValueKind();
-
- CXXCastPath BasePath;
- BuildBasePathArray(Paths, BasePath);
- LHS = ImpCastExprToType(LHS.take(), UseType, CK_DerivedToBase, VK,
+ LHS = ImpCastExprToType(LHS.get(), UseType, CK_DerivedToBase, VK,
&BasePath);
}
@@ -4296,7 +4276,8 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS,
SourceLocation QuestionLoc) {
Expr *Args[2] = { LHS.get(), RHS.get() };
- OverloadCandidateSet CandidateSet(QuestionLoc);
+ OverloadCandidateSet CandidateSet(QuestionLoc,
+ OverloadCandidateSet::CSK_Operator);
Self.AddBuiltinOperatorCandidates(OO_Conditional, QuestionLoc, Args,
CandidateSet);
@@ -4355,7 +4336,7 @@ static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) {
InitializedEntity Entity = InitializedEntity::InitializeTemporary(T);
InitializationKind Kind = InitializationKind::CreateCopy(E.get()->getLocStart(),
SourceLocation());
- Expr *Arg = E.take();
+ Expr *Arg = E.get();
InitializationSequence InitSeq(Self, Entity, Kind, Arg);
ExprResult Result = InitSeq.Perform(Self, Entity, Kind, Arg);
if (Result.isInvalid())
@@ -4379,7 +4360,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// C++11 [expr.cond]p1
// The first expression is contextually converted to bool.
if (!Cond.get()->isTypeDependent()) {
- ExprResult CondRes = CheckCXXBooleanCondition(Cond.take());
+ ExprResult CondRes = CheckCXXBooleanCondition(Cond.get());
if (CondRes.isInvalid())
return QualType();
Cond = CondRes;
@@ -4400,42 +4381,21 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
bool LVoid = LTy->isVoidType();
bool RVoid = RTy->isVoidType();
if (LVoid || RVoid) {
- // ... then the [l2r] conversions are performed on the second and third
- // operands ...
- LHS = DefaultFunctionArrayLvalueConversion(LHS.take());
- RHS = DefaultFunctionArrayLvalueConversion(RHS.take());
- if (LHS.isInvalid() || RHS.isInvalid())
- return QualType();
-
- // Finish off the lvalue-to-rvalue conversion by copy-initializing a
- // temporary if necessary. DefaultFunctionArrayLvalueConversion doesn't
- // do this part for us.
- ExprResult &NonVoid = LVoid ? RHS : LHS;
- if (NonVoid.get()->getType()->isRecordType() &&
- NonVoid.get()->isGLValue()) {
- if (RequireNonAbstractType(QuestionLoc, NonVoid.get()->getType(),
- diag::err_allocation_of_abstract_type))
- return QualType();
- InitializedEntity Entity =
- InitializedEntity::InitializeTemporary(NonVoid.get()->getType());
- NonVoid = PerformCopyInitialization(Entity, SourceLocation(), NonVoid);
- if (NonVoid.isInvalid())
- return QualType();
+ // ... one of the following shall hold:
+ // -- The second or the third operand (but not both) is a (possibly
+ // parenthesized) throw-expression; the result is of the type
+ // and value category of the other.
+ bool LThrow = isa<CXXThrowExpr>(LHS.get()->IgnoreParenImpCasts());
+ bool RThrow = isa<CXXThrowExpr>(RHS.get()->IgnoreParenImpCasts());
+ if (LThrow != RThrow) {
+ Expr *NonThrow = LThrow ? RHS.get() : LHS.get();
+ VK = NonThrow->getValueKind();
+ // DR (no number yet): the result is a bit-field if the
+ // non-throw-expression operand is a bit-field.
+ OK = NonThrow->getObjectKind();
+ return NonThrow->getType();
}
- LTy = LHS.get()->getType();
- RTy = RHS.get()->getType();
-
- // ... and one of the following shall hold:
- // -- The second or the third operand (but not both) is a throw-
- // expression; the result is of the type of the other and is a prvalue.
- bool LThrow = isa<CXXThrowExpr>(LHS.get()->IgnoreParenCasts());
- bool RThrow = isa<CXXThrowExpr>(RHS.get()->IgnoreParenCasts());
- if (LThrow && !RThrow)
- return RTy;
- if (RThrow && !LThrow)
- return LTy;
-
// -- Both the second and third operands have type void; the result is of
// type void and is a prvalue.
if (LVoid && RVoid)
@@ -4456,7 +4416,6 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// those operands to the type of the other.
if (!Context.hasSameType(LTy, RTy) &&
(LTy->isRecordType() || RTy->isRecordType())) {
- ImplicitConversionSequence ICSLeftToRight, ICSRightToLeft;
// These return true if a single direction is already ambiguous.
QualType L2RType, R2LType;
bool HaveL2R, HaveR2L;
@@ -4501,11 +4460,11 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
Qualifiers LCVR = Qualifiers::fromCVRMask(LTy.getCVRQualifiers());
Qualifiers RCVR = Qualifiers::fromCVRMask(RTy.getCVRQualifiers());
if (RCVR.isStrictSupersetOf(LCVR)) {
- LHS = ImpCastExprToType(LHS.take(), RTy, CK_NoOp, LVK);
+ LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK);
LTy = LHS.get()->getType();
}
else if (LCVR.isStrictSupersetOf(RCVR)) {
- RHS = ImpCastExprToType(RHS.take(), LTy, CK_NoOp, RVK);
+ RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK);
RTy = RHS.get()->getType();
}
}
@@ -4542,8 +4501,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// C++11 [expr.cond]p6
// Lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard
// conversions are performed on the second and third operands.
- LHS = DefaultFunctionArrayLvalueConversion(LHS.take());
- RHS = DefaultFunctionArrayLvalueConversion(RHS.take());
+ LHS = DefaultFunctionArrayLvalueConversion(LHS.get());
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
LTy = LHS.get()->getType();
@@ -4610,7 +4569,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// operand. The result is of the common type.
bool NonStandardCompositeType = false;
QualType Composite = FindCompositePointerType(QuestionLoc, LHS, RHS,
- isSFINAEContext()? 0 : &NonStandardCompositeType);
+ isSFINAEContext() ? nullptr
+ : &NonStandardCompositeType);
if (!Composite.isNull()) {
if (NonStandardCompositeType)
Diag(QuestionLoc,
@@ -4669,12 +4629,12 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
!T2->isAnyPointerType() && !T2->isMemberPointerType()) {
if (T1->isNullPtrType() &&
E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
- E2 = ImpCastExprToType(E2, T1, CK_NullToPointer).take();
+ E2 = ImpCastExprToType(E2, T1, CK_NullToPointer).get();
return T1;
}
if (T2->isNullPtrType() &&
E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
- E1 = ImpCastExprToType(E1, T2, CK_NullToPointer).take();
+ E1 = ImpCastExprToType(E1, T2, CK_NullToPointer).get();
return T2;
}
return QualType();
@@ -4682,16 +4642,16 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
if (T2->isMemberPointerType())
- E1 = ImpCastExprToType(E1, T2, CK_NullToMemberPointer).take();
+ E1 = ImpCastExprToType(E1, T2, CK_NullToMemberPointer).get();
else
- E1 = ImpCastExprToType(E1, T2, CK_NullToPointer).take();
+ E1 = ImpCastExprToType(E1, T2, CK_NullToPointer).get();
return T2;
}
if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
if (T1->isMemberPointerType())
- E2 = ImpCastExprToType(E2, T1, CK_NullToMemberPointer).take();
+ E2 = ImpCastExprToType(E2, T1, CK_NullToMemberPointer).get();
else
- E2 = ImpCastExprToType(E2, T1, CK_NullToPointer).take();
+ E2 = ImpCastExprToType(E2, T1, CK_NullToPointer).get();
return T1;
}
@@ -4734,7 +4694,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
QualifierUnion.push_back(
Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
- MemberOfClass.push_back(std::make_pair((const Type *)0, (const Type *)0));
+ MemberOfClass.push_back(std::make_pair(nullptr, nullptr));
continue;
}
@@ -4829,14 +4789,14 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
= E1ToC1.Perform(*this, Entity1, Kind, E1);
if (E1Result.isInvalid())
return QualType();
- E1 = E1Result.takeAs<Expr>();
+ E1 = E1Result.getAs<Expr>();
// Convert E2 to Composite1
ExprResult E2Result
= E2ToC1.Perform(*this, Entity1, Kind, E2);
if (E2Result.isInvalid())
return QualType();
- E2 = E2Result.takeAs<Expr>();
+ E2 = E2Result.getAs<Expr>();
return Composite1;
}
@@ -4854,14 +4814,14 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
= E1ToC2.Perform(*this, Entity2, Kind, E1);
if (E1Result.isInvalid())
return QualType();
- E1 = E1Result.takeAs<Expr>();
+ E1 = E1Result.getAs<Expr>();
// Convert E2 to Composite2
ExprResult E2Result
= E2ToC2.Perform(*this, Entity2, Kind, E2);
if (E2Result.isInvalid())
return QualType();
- E2 = E2Result.takeAs<Expr>();
+ E2 = E2Result.getAs<Expr>();
return Composite2;
}
@@ -4874,7 +4834,7 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
// If the result is a glvalue, we shouldn't bind it.
if (!E->isRValue())
- return Owned(E);
+ return E;
// In ARC, calls that return a retainable type can return retained,
// in which case we have to insert a consuming cast.
@@ -4917,13 +4877,13 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
// we don't want any extra casts here.
} else if (isa<CastExpr>(E) &&
isa<BlockExpr>(cast<CastExpr>(E)->getSubExpr())) {
- return Owned(E);
+ return E;
// 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 {
- ObjCMethodDecl *D = 0;
+ ObjCMethodDecl *D = nullptr;
if (ObjCMessageExpr *Send = dyn_cast<ObjCMessageExpr>(E)) {
D = Send->getMethodDecl();
} else if (ObjCBoxedExpr *BoxedExpr = dyn_cast<ObjCBoxedExpr>(E)) {
@@ -4942,28 +4902,28 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
// return an object.
if (!ReturnsRetained &&
D && D->getMethodFamily() == OMF_performSelector)
- return Owned(E);
+ return E;
}
// Don't reclaim an object of Class type.
if (!ReturnsRetained && E->getType()->isObjCARCImplicitlyUnretainedType())
- return Owned(E);
+ return E;
ExprNeedsCleanups = true;
CastKind ck = (ReturnsRetained ? CK_ARCConsumeObject
: CK_ARCReclaimReturnedObject);
- return Owned(ImplicitCastExpr::Create(Context, E->getType(), ck, E, 0,
- VK_RValue));
+ return ImplicitCastExpr::Create(Context, E->getType(), ck, E, nullptr,
+ VK_RValue);
}
if (!getLangOpts().CPlusPlus)
- return Owned(E);
+ return E;
// Search for the base element type (cf. ASTContext::getBaseElementType) with
// a fast path for the common case that the type is directly a RecordType.
const Type *T = Context.getCanonicalType(E->getType().getTypePtr());
- const RecordType *RT = 0;
+ const RecordType *RT = nullptr;
while (!RT) {
switch (T->getTypeClass()) {
case Type::Record:
@@ -4976,7 +4936,7 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
T = cast<ArrayType>(T)->getElementType().getTypePtr();
break;
default:
- return Owned(E);
+ return E;
}
}
@@ -4984,10 +4944,10 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
// not processing a decltype expression.
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
if (RD->isInvalidDecl() || RD->isDependentContext())
- return Owned(E);
+ return E;
bool IsDecltype = ExprEvalContexts.back().IsDecltype;
- CXXDestructorDecl *Destructor = IsDecltype ? 0 : LookupDestructor(RD);
+ CXXDestructorDecl *Destructor = IsDecltype ? nullptr : LookupDestructor(RD);
if (Destructor) {
MarkFunctionReferenced(E->getExprLoc(), Destructor);
@@ -4999,7 +4959,7 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
// If destructor is trivial, we can avoid the extra copy.
if (Destructor->isTrivial())
- return Owned(E);
+ return E;
// We need a cleanup, but we don't need to remember the temporary.
ExprNeedsCleanups = true;
@@ -5011,7 +4971,7 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
if (IsDecltype)
ExprEvalContexts.back().DelayedDecltypeBinds.push_back(Bind);
- return Owned(Bind);
+ return Bind;
}
ExprResult
@@ -5019,11 +4979,11 @@ Sema::MaybeCreateExprWithCleanups(ExprResult SubExpr) {
if (SubExpr.isInvalid())
return ExprError();
- return Owned(MaybeCreateExprWithCleanups(SubExpr.take()));
+ return MaybeCreateExprWithCleanups(SubExpr.get());
}
Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) {
- assert(SubExpr && "sub expression can't be null!");
+ assert(SubExpr && "subexpression can't be null!");
CleanupVarDeclMarking();
@@ -5044,7 +5004,7 @@ Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) {
}
Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
- assert(SubStmt && "sub statement can't be null!");
+ assert(SubStmt && "sub-statement can't be null!");
CleanupVarDeclMarking();
@@ -5085,8 +5045,8 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
if (SubExpr.isInvalid())
return ExprError();
if (SubExpr.get() == PE->getSubExpr())
- return Owned(E);
- return ActOnParenExpr(PE->getLParen(), PE->getRParen(), SubExpr.take());
+ return E;
+ return ActOnParenExpr(PE->getLParen(), PE->getRParen(), SubExpr.get());
}
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
if (BO->getOpcode() == BO_Comma) {
@@ -5094,30 +5054,30 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
if (RHS.isInvalid())
return ExprError();
if (RHS.get() == BO->getRHS())
- return Owned(E);
- return Owned(new (Context) BinaryOperator(BO->getLHS(), RHS.take(),
- BO_Comma, BO->getType(),
- BO->getValueKind(),
- BO->getObjectKind(),
- BO->getOperatorLoc(),
- BO->isFPContractable()));
+ return E;
+ return new (Context) BinaryOperator(
+ BO->getLHS(), RHS.get(), BO_Comma, BO->getType(), BO->getValueKind(),
+ BO->getObjectKind(), BO->getOperatorLoc(), BO->isFPContractable());
}
}
CXXBindTemporaryExpr *TopBind = dyn_cast<CXXBindTemporaryExpr>(E);
- if (TopBind)
- E = TopBind->getSubExpr();
+ CallExpr *TopCall = TopBind ? dyn_cast<CallExpr>(TopBind->getSubExpr())
+ : nullptr;
+ if (TopCall)
+ E = TopCall;
+ else
+ TopBind = nullptr;
// Disable the special decltype handling now.
ExprEvalContexts.back().IsDecltype = false;
// In MS mode, don't perform any extra checking of call return types within a
// decltype expression.
- if (getLangOpts().MicrosoftMode)
- return Owned(E);
+ if (getLangOpts().MSVCCompat)
+ return E;
// Perform the semantic checks we delayed until this point.
- CallExpr *TopCall = dyn_cast<CallExpr>(E);
for (unsigned I = 0, N = ExprEvalContexts.back().DelayedDecltypeCalls.size();
I != N; ++I) {
CallExpr *Call = ExprEvalContexts.back().DelayedDecltypeCalls[I];
@@ -5158,12 +5118,12 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
}
// Possibly strip off the top CXXBindTemporaryExpr.
- return Owned(E);
+ return E;
}
/// Note a set of 'operator->' functions that were used for a member access.
static void noteOperatorArrows(Sema &S,
- llvm::ArrayRef<FunctionDecl *> OperatorArrows) {
+ ArrayRef<FunctionDecl *> OperatorArrows) {
unsigned SkipStart = OperatorArrows.size(), SkipCount = 0;
// FIXME: Make this configurable?
unsigned Limit = 9;
@@ -5198,7 +5158,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,
Result = CheckPlaceholderExpr(Base);
if (Result.isInvalid()) return ExprError();
- Base = Result.take();
+ Base = Result.get();
QualType BaseType = Base->getType();
MayBePseudoDestructor = false;
@@ -5212,7 +5172,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,
ObjectType = ParsedType::make(BaseType);
MayBePseudoDestructor = true;
- return Owned(Base);
+ return Base;
}
// C++ [over.match.oper]p8:
@@ -5245,7 +5205,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,
// separate note) instead of having the error reported back to here
// and giving a diagnostic with a fixit attached to the error itself.
(FirstIteration && CurFD && CurFD->isFunctionTemplateSpecialization())
- ? 0
+ ? nullptr
: &NoArrowOperatorFound);
if (Result.isInvalid()) {
if (NoArrowOperatorFound) {
@@ -5259,7 +5219,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,
Diag(OpLoc, diag::err_typecheck_member_reference_arrow)
<< BaseType << Base->getSourceRange();
CallExpr *CE = dyn_cast<CallExpr>(Base);
- if (Decl *CD = (CE ? CE->getCalleeDecl() : 0)) {
+ if (Decl *CD = (CE ? CE->getCalleeDecl() : nullptr)) {
Diag(CD->getLocStart(),
diag::note_member_reference_arrow_from_operator_arrow);
}
@@ -5302,7 +5262,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,
} else if (!BaseType->isRecordType()) {
ObjectType = ParsedType();
MayBePseudoDestructor = true;
- return Owned(Base);
+ return Base;
}
// The object type must be complete (or dependent), or
@@ -5331,7 +5291,7 @@ ExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc,
<< isa<CXXPseudoDestructorExpr>(MemExpr)
<< FixItHint::CreateInsertion(ExpectedLParenLoc, "()");
- return ActOnCallExpr(/*Scope*/ 0,
+ return ActOnCallExpr(/*Scope*/ nullptr,
MemExpr,
/*LPLoc*/ ExpectedLParenLoc,
None,
@@ -5343,7 +5303,7 @@ static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base,
if (Base->hasPlaceholderType()) {
ExprResult result = S.CheckPlaceholderExpr(Base);
if (result.isInvalid()) return true;
- Base = result.take();
+ Base = result.get();
}
ObjectType = Base->getType();
@@ -5388,12 +5348,13 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
if (!ObjectType->isDependentType() && !ObjectType->isScalarType() &&
!ObjectType->isVectorType()) {
- if (getLangOpts().MicrosoftMode && ObjectType->isVoidType())
+ if (getLangOpts().MSVCCompat && ObjectType->isVoidType())
Diag(OpLoc, diag::ext_pseudo_dtor_on_void) << Base->getSourceRange();
- else
+ else {
Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar)
<< ObjectType << Base->getSourceRange();
- return ExprError();
+ return ExprError();
+ }
}
// C++ [expr.pseudo]p2:
@@ -5453,7 +5414,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
<< ScopeTypeInfo->getTypeLoc().getLocalSourceRange();
ScopeType = QualType();
- ScopeTypeInfo = 0;
+ ScopeTypeInfo = nullptr;
}
}
@@ -5467,7 +5428,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
Destructed);
if (HasTrailingLParen)
- return Owned(Result);
+ return Result;
return DiagnoseDtorReference(Destructed.getLocation(), Result);
}
@@ -5505,7 +5466,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
// Convert the name of the type being destructed (following the ~) into a
// type (with source-location information).
QualType DestructedType;
- TypeSourceInfo *DestructedTypeInfo = 0;
+ TypeSourceInfo *DestructedTypeInfo = nullptr;
PseudoDestructorTypeStorage Destructed;
if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) {
ParsedType T = getTypeName(*SecondTypeName.Identifier,
@@ -5560,7 +5521,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
}
// Convert the name of the scope type (the type prior to '::') into a type.
- TypeSourceInfo *ScopeTypeInfo = 0;
+ TypeSourceInfo *ScopeTypeInfo = nullptr;
QualType ScopeType;
if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
FirstTypeName.Identifier) {
@@ -5629,7 +5590,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
PseudoDestructorTypeStorage Destructed(DestructedTypeInfo);
return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, CXXScopeSpec(),
- 0, SourceLocation(), TildeLoc,
+ nullptr, SourceLocation(), TildeLoc,
Destructed, HasTrailingLParen);
}
@@ -5662,22 +5623,21 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
return Exp;
}
}
-
- ExprResult Exp = PerformObjectArgumentInitialization(E, /*Qualifier=*/0,
+ ExprResult Exp = PerformObjectArgumentInitialization(E, /*Qualifier=*/nullptr,
FoundDecl, Method);
if (Exp.isInvalid())
return true;
MemberExpr *ME =
- new (Context) MemberExpr(Exp.take(), /*IsArrow=*/false, Method,
+ new (Context) MemberExpr(Exp.get(), /*IsArrow=*/false, Method,
SourceLocation(), Context.BoundMemberTy,
VK_RValue, OK_Ordinary);
if (HadMultipleCandidates)
ME->setHadMultipleCandidates(true);
MarkMemberReferenced(ME);
- QualType ResultType = Method->getResultType();
+ QualType ResultType = Method->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultType);
ResultType = ResultType.getNonLValueExprType(Context);
@@ -5690,8 +5650,8 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand,
SourceLocation RParen) {
CanThrowResult CanThrow = canThrow(Operand);
- return Owned(new (Context) CXXNoexceptExpr(Context.BoolTy, Operand,
- CanThrow, KeyLoc, RParen));
+ return new (Context)
+ CXXNoexceptExpr(Context.BoolTy, Operand, CanThrow, KeyLoc, RParen);
}
ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation,
@@ -5759,8 +5719,8 @@ static bool IsSpecialDiscardedValue(Expr *E) {
ExprResult Sema::IgnoredValueConversions(Expr *E) {
if (E->hasPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(E);
- if (result.isInvalid()) return Owned(E);
- E = result.take();
+ if (result.isInvalid()) return E;
+ E = result.get();
}
// C99 6.3.2.1:
@@ -5775,7 +5735,7 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
if (!getLangOpts().CPlusPlus && E->getType()->isFunctionType())
return DefaultFunctionArrayConversion(E);
- return Owned(E);
+ return E;
}
if (getLangOpts().CPlusPlus) {
@@ -5788,30 +5748,30 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
IsSpecialDiscardedValue(E)) {
ExprResult Res = DefaultLvalueConversion(E);
if (Res.isInvalid())
- return Owned(E);
- E = Res.take();
+ return E;
+ E = Res.get();
}
- return Owned(E);
+ return E;
}
// GCC seems to also exclude expressions of incomplete enum type.
if (const EnumType *T = E->getType()->getAs<EnumType>()) {
if (!T->getDecl()->isComplete()) {
// FIXME: stupid workaround for a codegen bug!
- E = ImpCastExprToType(E, Context.VoidTy, CK_ToVoid).take();
- return Owned(E);
+ E = ImpCastExprToType(E, Context.VoidTy, CK_ToVoid).get();
+ return E;
}
}
ExprResult Res = DefaultFunctionArrayLvalueConversion(E);
if (Res.isInvalid())
- return Owned(E);
- E = Res.take();
+ return E;
+ E = Res.get();
if (!E->getType()->isVoidType())
RequireCompleteType(E->getExprLoc(), E->getType(),
diag::err_incomplete_type);
- return Owned(E);
+ return E;
}
// If we can unambiguously determine whether Var can never be used
@@ -5829,7 +5789,7 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var,
ASTContext &Context) {
if (isa<ParmVarDecl>(Var)) return true;
- const VarDecl *DefVD = 0;
+ const VarDecl *DefVD = nullptr;
// If there is no initializer - this can not be a constant expression.
if (!Var->getAnyInitializer(DefVD)) return true;
@@ -5849,42 +5809,58 @@ static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var,
return !IsVariableAConstantExpression(Var, Context);
}
-/// \brief Check if the current lambda scope has any potential captures, and
-/// whether they can be captured by any of the enclosing lambdas that are
-/// ready to capture. If there is a lambda that can capture a nested
-/// potential-capture, go ahead and do so. Also, check to see if any
-/// variables are uncaptureable or do not involve an odr-use so do not
-/// need to be captured.
+/// \brief Check if the current lambda has any potential captures
+/// that must be captured by any of its enclosing lambdas that are ready to
+/// capture. If there is a lambda that can capture a nested
+/// potential-capture, go ahead and do so. Also, check to see if any
+/// variables are uncaptureable or do not involve an odr-use so do not
+/// need to be captured.
+
+static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
+ Expr *const FE, LambdaScopeInfo *const CurrentLSI, Sema &S) {
-static void CheckLambdaCaptures(Expr *const FE,
- LambdaScopeInfo *const CurrentLSI, Sema &S) {
-
assert(!S.isUnevaluatedContext());
assert(S.CurContext->isDependentContext());
- const bool IsFullExprInstantiationDependent =
- FE->isInstantiationDependent();
- // All the potentially captureable variables in the current nested
+ assert(CurrentLSI->CallOperator == S.CurContext &&
+ "The current call operator must be synchronized with Sema's CurContext");
+
+ const bool IsFullExprInstantiationDependent = FE->isInstantiationDependent();
+
+ ArrayRef<const FunctionScopeInfo *> FunctionScopesArrayRef(
+ S.FunctionScopes.data(), S.FunctionScopes.size());
+
+ // All the potentially captureable variables in the current nested
// lambda (within a generic outer lambda), must be captured by an
// outer lambda that is enclosed within a non-dependent context.
-
- for (size_t I = 0, N = CurrentLSI->getNumPotentialVariableCaptures();
- I != N; ++I) {
- Expr *VarExpr = 0;
- VarDecl *Var = 0;
+ const unsigned NumPotentialCaptures =
+ CurrentLSI->getNumPotentialVariableCaptures();
+ for (unsigned I = 0; I != NumPotentialCaptures; ++I) {
+ Expr *VarExpr = nullptr;
+ VarDecl *Var = nullptr;
CurrentLSI->getPotentialVariableCapture(I, Var, VarExpr);
- //
- if (CurrentLSI->isVariableExprMarkedAsNonODRUsed(VarExpr) &&
+ // If the variable is clearly identified as non-odr-used and the full
+ // expression is not instantiation dependent, only then do we not
+ // need to check enclosing lambda's for speculative captures.
+ // For e.g.:
+ // Even though 'x' is not odr-used, it should be captured.
+ // int test() {
+ // const int x = 10;
+ // auto L = [=](auto a) {
+ // (void) +x + a;
+ // };
+ // }
+ if (CurrentLSI->isVariableExprMarkedAsNonODRUsed(VarExpr) &&
!IsFullExprInstantiationDependent)
- continue;
- // Climb up until we find a lambda that can capture:
- // - a generic-or-non-generic lambda call operator that is enclosed
- // within a non-dependent context.
- unsigned FunctionScopeIndexOfCapturableLambda = 0;
- if (GetInnermostEnclosingCapturableLambda(
- S.FunctionScopes, FunctionScopeIndexOfCapturableLambda,
- S.CurContext, Var, S)) {
- MarkVarDeclODRUsed(Var, VarExpr->getExprLoc(),
- S, &FunctionScopeIndexOfCapturableLambda);
+ continue;
+
+ // If we have a capture-capable lambda for the variable, go ahead and
+ // capture the variable in that lambda (and all its enclosing lambdas).
+ if (const Optional<unsigned> Index =
+ getStackIndexOfNearestEnclosingCaptureCapableLambda(
+ FunctionScopesArrayRef, Var, S)) {
+ const unsigned FunctionScopeIndexOfCapturableLambda = Index.getValue();
+ MarkVarDeclODRUsed(Var, VarExpr->getExprLoc(), S,
+ &FunctionScopeIndexOfCapturableLambda);
}
const bool IsVarNeverAConstantExpression =
VariableCanNeverBeAConstantExpression(Var, S.Context);
@@ -5900,27 +5876,32 @@ static void CheckLambdaCaptures(Expr *const FE,
if (S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit,
/*EllipsisLoc*/ SourceLocation(),
/*BuildAndDiagnose*/false, CaptureType,
- DeclRefType, 0)) {
+ DeclRefType, nullptr)) {
// We will never be able to capture this variable, and we need
// to be able to in any and all instantiations, so diagnose it.
S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit,
/*EllipsisLoc*/ SourceLocation(),
/*BuildAndDiagnose*/true, CaptureType,
- DeclRefType, 0);
+ DeclRefType, nullptr);
}
}
}
+ // Check if 'this' needs to be captured.
if (CurrentLSI->hasPotentialThisCapture()) {
- unsigned FunctionScopeIndexOfCapturableLambda = 0;
- if (GetInnermostEnclosingCapturableLambda(
- S.FunctionScopes, FunctionScopeIndexOfCapturableLambda,
- S.CurContext, /*0 is 'this'*/ 0, S)) {
- S.CheckCXXThisCapture(CurrentLSI->PotentialThisCaptureLocation,
- /*Explicit*/false, /*BuildAndDiagnose*/true,
- &FunctionScopeIndexOfCapturableLambda);
+ // If we have a capture-capable lambda for 'this', go ahead and capture
+ // 'this' in that lambda (and all its enclosing lambdas).
+ if (const Optional<unsigned> Index =
+ getStackIndexOfNearestEnclosingCaptureCapableLambda(
+ FunctionScopesArrayRef, /*0 is 'this'*/ nullptr, S)) {
+ const unsigned FunctionScopeIndexOfCapturableLambda = Index.getValue();
+ S.CheckCXXThisCapture(CurrentLSI->PotentialThisCaptureLocation,
+ /*Explicit*/ false, /*BuildAndDiagnose*/ true,
+ &FunctionScopeIndexOfCapturableLambda);
}
}
+
+ // Reset all the potential captures at the end of each full-expression.
CurrentLSI->clearPotentialCaptures();
}
@@ -5929,7 +5910,7 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
bool DiscardedValue,
bool IsConstexpr,
bool IsLambdaInitCaptureInitializer) {
- ExprResult FullExpr = Owned(FE);
+ ExprResult FullExpr = FE;
if (!FullExpr.get())
return ExprError();
@@ -5956,17 +5937,17 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
// Top-level expressions default to 'id' when we're in a debugger.
if (DiscardedValue && getLangOpts().DebuggerCastResultToId &&
FullExpr.get()->getType() == Context.UnknownAnyTy) {
- FullExpr = forceUnknownAnyToType(FullExpr.take(), Context.getObjCIdType());
+ FullExpr = forceUnknownAnyToType(FullExpr.get(), Context.getObjCIdType());
if (FullExpr.isInvalid())
return ExprError();
}
if (DiscardedValue) {
- FullExpr = CheckPlaceholderExpr(FullExpr.take());
+ FullExpr = CheckPlaceholderExpr(FullExpr.get());
if (FullExpr.isInvalid())
return ExprError();
- FullExpr = IgnoredValueConversions(FullExpr.take());
+ FullExpr = IgnoredValueConversions(FullExpr.get());
if (FullExpr.isInvalid())
return ExprError();
}
@@ -6017,11 +5998,12 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
// FunctionScopes.size() in InstantiatingTemplate's
// constructor/destructor.
// - Teach the handful of places that iterate over FunctionScopes to
- // stop at the outermost enclosing lexical scope."
- const bool IsInLambdaDeclContext = isLambdaCallOperator(CurContext);
- if (IsInLambdaDeclContext && CurrentLSI &&
+ // stop at the outermost enclosing lexical scope."
+ const bool IsInLambdaDeclContext = isLambdaCallOperator(CurContext);
+ if (IsInLambdaDeclContext && CurrentLSI &&
CurrentLSI->hasPotentialCaptures() && !FullExpr.isInvalid())
- CheckLambdaCaptures(FE, CurrentLSI, *this);
+ CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(FE, CurrentLSI,
+ *this);
return MaybeCreateExprWithCleanups(FullExpr);
}
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index f6accb15bf98..ef7898208cae 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -206,7 +206,7 @@ static void diagnoseInstanceReference(Sema &SemaRef,
DeclContext *FunctionLevelDC = SemaRef.getFunctionLevelDeclContext();
CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FunctionLevelDC);
- CXXRecordDecl *ContextClass = Method ? Method->getParent() : 0;
+ CXXRecordDecl *ContextClass = Method ? Method->getParent() : nullptr;
CXXRecordDecl *RepClass = dyn_cast<CXXRecordDecl>(Rep->getDeclContext());
bool InStaticMethod = Method && Method->isStatic();
@@ -292,7 +292,7 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK,
// 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 HexSwizzle = (*compStr == 's' || *compStr == 'S') && compStr[1];
bool HasRepeated = false;
bool HasIndex[16] = {};
@@ -384,13 +384,12 @@ static Decl *FindGetterSetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDe
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,
+ for (const auto *I : PDecl->protocols()) {
+ if (Decl *D = FindGetterSetterNameDeclFromProtocolList(I, Member, Sel,
Context))
return D;
}
- return 0;
+ return nullptr;
}
static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy,
@@ -398,26 +397,23 @@ static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy,
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) {
+ Decl *GDecl = nullptr;
+ for (const auto *I : QIdTy->quals()) {
if (Member)
- if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(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)) {
+ 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) {
+ for (const auto *I : QIdTy->quals()) {
// Search in the protocol-qualifier list of current protocol.
- GDecl = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel,
- Context);
+ GDecl = FindGetterSetterNameDeclFromProtocolList(I, Member, Sel, Context);
if (GDecl)
return GDecl;
}
@@ -459,12 +455,10 @@ Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
// Get the type being accessed in BaseType. If this is an arrow, the BaseExpr
// must have pointer type, and the accessed type is the pointee.
- return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType,
- IsArrow, OpLoc,
- SS.getWithLocInContext(Context),
- TemplateKWLoc,
- FirstQualifierInScope,
- NameInfo, TemplateArgs));
+ return CXXDependentScopeMemberExpr::Create(
+ Context, BaseExpr, BaseType, IsArrow, OpLoc,
+ SS.getWithLocInContext(Context), TemplateKWLoc, FirstQualifierInScope,
+ NameInfo, TemplateArgs);
}
/// We know that the given qualified member reference points only to
@@ -546,7 +540,7 @@ class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback {
explicit RecordMemberExprValidatorCCC(const RecordType *RTy)
: Record(RTy->getDecl()) {}
- virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ bool ValidateCandidate(const TypoCorrection &candidate) override {
NamedDecl *ND = candidate.getCorrectionDecl();
// Don't accept candidates that cannot be member functions, constants,
// variables, or templates.
@@ -559,11 +553,9 @@ class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Record)) {
// Accept candidates that occur in any of the current class' base classes.
- for (CXXRecordDecl::base_class_const_iterator BS = RD->bases_begin(),
- BSEnd = RD->bases_end();
- BS != BSEnd; ++BS) {
+ for (const auto &BS : RD->bases()) {
if (const RecordType *BSTy = dyn_cast_or_null<RecordType>(
- BS->getType().getTypePtrOrNull())) {
+ BS.getType().getTypePtrOrNull())) {
if (BSTy->getDecl()->containsDecl(ND))
return true;
}
@@ -596,7 +588,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0);
bool MOUS;
- SemaRef.LookupTemplateName(R, 0, SS, ObjectType, false, MOUS);
+ SemaRef.LookupTemplateName(R, nullptr, SS, ObjectType, false, MOUS);
return false;
}
@@ -632,8 +624,9 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
DeclarationName Name = R.getLookupName();
RecordMemberExprValidatorCCC Validator(RTy);
TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(),
- R.getLookupKind(), NULL,
- &SS, Validator, DC);
+ R.getLookupKind(), nullptr,
+ &SS, Validator,
+ Sema::CTK_ErrorRecovery, DC);
R.clear();
if (Corrected.isResolved() && !Corrected.isKeyword()) {
R.setLookupName(Corrected.getCorrection());
@@ -648,7 +641,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
// information to do overload resolution, so we don't know which previous
// declaration to point to.
if (Corrected.isOverloaded())
- Corrected.setCorrectionDecl(0);
+ Corrected.setCorrectionDecl(nullptr);
bool DroppedSpecifier =
Corrected.WillReplaceSpecifier() &&
Name.getAsString() == Corrected.getAsString(SemaRef.getLangOpts());
@@ -660,6 +653,11 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
return false;
}
+static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
+ ExprResult &BaseExpr, bool &IsArrow,
+ SourceLocation OpLoc, CXXScopeSpec &SS,
+ Decl *ObjCImpDecl, bool HasTemplateArgs);
+
ExprResult
Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
SourceLocation OpLoc, bool IsArrow,
@@ -667,7 +665,8 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierInScope,
const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo *TemplateArgs) {
+ const TemplateArgumentListInfo *TemplateArgs,
+ ActOnMemberAccessExtraArgs *ExtraArgs) {
if (BaseType->isDependentType() ||
(SS.isSet() && isDependentScopeSpecifier(SS)))
return ActOnDependentMemberExpr(Base, BaseType,
@@ -683,24 +682,23 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType();
if (LookupMemberExprInRecord(*this, R, SourceRange(),
RecordTy->getAs<RecordType>(),
- OpLoc, SS, TemplateArgs != 0))
+ OpLoc, SS, TemplateArgs != nullptr))
return ExprError();
// Explicit member accesses.
} else {
- ExprResult BaseResult = Owned(Base);
- ExprResult Result =
- LookupMemberExpr(R, BaseResult, IsArrow, OpLoc,
- SS, /*ObjCImpDecl*/ 0, TemplateArgs != 0);
+ ExprResult BaseResult = Base;
+ ExprResult Result = LookupMemberExpr(
+ *this, R, BaseResult, IsArrow, OpLoc, SS,
+ ExtraArgs ? ExtraArgs->ObjCImpDecl : nullptr,
+ TemplateArgs != nullptr);
if (BaseResult.isInvalid())
return ExprError();
- Base = BaseResult.take();
+ Base = BaseResult.get();
- if (Result.isInvalid()) {
- Owned(Base);
+ if (Result.isInvalid())
return ExprError();
- }
if (Result.get())
return Result;
@@ -711,7 +709,8 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
return BuildMemberReferenceExpr(Base, BaseType,
OpLoc, IsArrow, SS, TemplateKWLoc,
- FirstQualifierInScope, R, TemplateArgs);
+ FirstQualifierInScope, R, TemplateArgs,
+ false, ExtraArgs);
}
static ExprResult
@@ -751,7 +750,7 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
= BuildDeclarationNameExpr(EmptySS, baseNameInfo, baseVariable);
if (result.isInvalid()) return ExprError();
- baseObjectExpr = result.take();
+ baseObjectExpr = result.get();
baseObjectIsPointer = false;
baseQuals = baseObjectExpr->getType().getQualifiers();
@@ -807,12 +806,10 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer,
EmptySS, field, foundDecl,
- memberNameInfo).take();
+ memberNameInfo).get();
if (!result)
return ExprError();
- baseObjectIsPointer = false;
-
// FIXME: check qualified member access
}
@@ -829,10 +826,10 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false,
(FI == FEnd? SS : EmptySS), field,
- fakeFoundDecl, memberNameInfo).take();
+ fakeFoundDecl, memberNameInfo).get();
}
- return Owned(result);
+ return result;
}
static ExprResult
@@ -849,16 +846,13 @@ BuildMSPropertyRefExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
}
/// \brief Build a MemberExpr AST node.
-static MemberExpr *BuildMemberExpr(Sema &SemaRef,
- ASTContext &C, Expr *Base, bool isArrow,
- const CXXScopeSpec &SS,
- SourceLocation TemplateKWLoc,
- ValueDecl *Member,
- DeclAccessPair FoundDecl,
- const DeclarationNameInfo &MemberNameInfo,
- QualType Ty,
- ExprValueKind VK, ExprObjectKind OK,
- const TemplateArgumentListInfo *TemplateArgs = 0) {
+static MemberExpr *
+BuildMemberExpr(Sema &SemaRef, ASTContext &C, Expr *Base, bool isArrow,
+ const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
+ ValueDecl *Member, DeclAccessPair FoundDecl,
+ const DeclarationNameInfo &MemberNameInfo, QualType Ty,
+ ExprValueKind VK, ExprObjectKind OK,
+ const TemplateArgumentListInfo *TemplateArgs = nullptr) {
assert((!isArrow || Base->isRValue()) && "-> base must be a pointer rvalue");
MemberExpr *E =
MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C),
@@ -1006,7 +1000,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
TemplateKWLoc, MemberNameInfo,
TemplateArgs, R.begin(), R.end());
- return Owned(MemExpr);
+ return MemExpr;
}
assert(R.isSingleResult());
@@ -1043,10 +1037,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
}
// Check the use of this member.
- if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) {
- Owned(BaseExpr);
+ if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc))
return ExprError();
- }
if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow,
@@ -1064,10 +1056,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
OpLoc);
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
- return Owned(BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS,
- TemplateKWLoc, Var, FoundDecl, MemberNameInfo,
- Var->getType().getNonReferenceType(),
- VK_LValue, OK_Ordinary));
+ return BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS, TemplateKWLoc,
+ Var, FoundDecl, MemberNameInfo,
+ Var->getType().getNonReferenceType(), VK_LValue,
+ OK_Ordinary);
}
if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) {
@@ -1081,21 +1073,18 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
type = MemberFn->getType();
}
- return Owned(BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS,
- TemplateKWLoc, MemberFn, FoundDecl,
- MemberNameInfo, type, valueKind,
- OK_Ordinary));
+ return BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS, TemplateKWLoc,
+ MemberFn, FoundDecl, MemberNameInfo, type, valueKind,
+ OK_Ordinary);
}
assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
- return Owned(BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS,
- TemplateKWLoc, Enum, FoundDecl, MemberNameInfo,
- Enum->getType(), VK_RValue, OK_Ordinary));
+ return BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS, TemplateKWLoc,
+ 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)
@@ -1138,7 +1127,7 @@ static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) {
if (opty && !opty->getObjectType()->getInterface())
return false;
- base = S.ImpCastExprToType(base.take(), redef, CK_BitCast);
+ base = S.ImpCastExprToType(base.get(), redef, CK_BitCast);
return true;
}
@@ -1170,15 +1159,14 @@ Sema::PerformMemberExprBaseConversion(Expr *Base, bool IsArrow) {
///
/// 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) {
+static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
+ ExprResult &BaseExpr, bool &IsArrow,
+ SourceLocation OpLoc, CXXScopeSpec &SS,
+ Decl *ObjCImpDecl, bool HasTemplateArgs) {
assert(BaseExpr.get() && "no base expression");
// Perform default conversions.
- BaseExpr = PerformMemberExprBaseConversion(BaseExpr.take(), IsArrow);
+ BaseExpr = S.PerformMemberExprBaseConversion(BaseExpr.get(), IsArrow);
if (BaseExpr.isInvalid())
return ExprError();
@@ -1206,8 +1194,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// overloaded operator->, but that should have been dealt with
// by now--or a diagnostic message already issued if a problem
// was encountered while looking for the overloaded operator->.
- if (!getLangOpts().CPlusPlus) {
- Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ if (!S.getLangOpts().CPlusPlus) {
+ S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
<< BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
<< FixItHint::CreateReplacement(OpLoc, ".");
}
@@ -1215,7 +1203,7 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
} else if (BaseType->isFunctionType()) {
goto fail;
} else {
- Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
+ S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
<< BaseType << BaseExpr.get()->getSourceRange();
return ExprError();
}
@@ -1223,24 +1211,24 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// Handle field access to simple records.
if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
- if (LookupMemberExprInRecord(*this, R, BaseExpr.get()->getSourceRange(),
+ if (LookupMemberExprInRecord(S, 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);
+ return ExprResult((Expr *)nullptr);
}
// Handle ivar access to Objective-C objects.
if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) {
if (!SS.isEmpty() && !SS.isInvalid()) {
- Diag(SS.getRange().getBegin(), diag::err_qualified_objc_access)
+ S.Diag(SS.getRange().getBegin(), diag::err_qualified_objc_access)
<< 1 << SS.getScopeRep()
<< FixItHint::CreateRemoval(SS.getRange());
SS.clear();
}
-
+
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
// There are three cases for the base type:
@@ -1249,40 +1237,41 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// - an interface
ObjCInterfaceDecl *IDecl = OTy->getInterface();
if (!IDecl) {
- if (getLangOpts().ObjCAutoRefCount &&
+ if (S.getLangOpts().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,
- OpLoc,
- Context.getObjCClassType()));
- if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ return new (S.Context) ObjCIsaExpr(BaseExpr.get(), IsArrow, MemberLoc,
+ OpLoc, S.Context.getObjCClassType());
+ if (ShouldTryAgainWithRedefinitionType(S, BaseExpr))
+ return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs);
goto fail;
}
-
- if (RequireCompleteType(OpLoc, BaseType, diag::err_typecheck_incomplete_tag,
- BaseExpr.get()))
+
+ if (S.RequireCompleteType(OpLoc, BaseType,
+ diag::err_typecheck_incomplete_tag,
+ BaseExpr.get()))
return ExprError();
-
- ObjCInterfaceDecl *ClassDeclared = 0;
+
+ ObjCInterfaceDecl *ClassDeclared = nullptr;
ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
if (!IV) {
// Attempt to correct for typos in ivar names.
DeclFilterCCC<ObjCIvarDecl> Validator;
Validator.IsObjCIvarLookup = IsArrow;
- if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
- LookupMemberName, NULL, NULL,
- Validator, IDecl)) {
+ if (TypoCorrection Corrected = S.CorrectTypo(
+ R.getLookupNameInfo(), Sema::LookupMemberName, nullptr, nullptr,
+ Validator, Sema::CTK_ErrorRecovery, IDecl)) {
IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>();
- diagnoseTypo(Corrected,
- PDiag(diag::err_typecheck_member_reference_ivar_suggest)
- << IDecl->getDeclName() << MemberName);
+ S.diagnoseTypo(
+ Corrected,
+ S.PDiag(diag::err_typecheck_member_reference_ivar_suggest)
+ << IDecl->getDeclName() << MemberName);
// Figure out the class that declares the ivar.
assert(!ClassDeclared);
@@ -1292,20 +1281,19 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
ClassDeclared = cast<ObjCInterfaceDecl>(D);
} else {
if (IsArrow && IDecl->FindPropertyDeclaration(Member)) {
- Diag(MemberLoc,
- diag::err_property_found_suggest)
- << Member << BaseExpr.get()->getType()
- << FixItHint::CreateReplacement(OpLoc, ".");
+ S.Diag(MemberLoc, diag::err_property_found_suggest)
+ << Member << BaseExpr.get()->getType()
+ << FixItHint::CreateReplacement(OpLoc, ".");
return ExprError();
}
- Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
- << IDecl->getDeclName() << MemberName
- << BaseExpr.get()->getSourceRange();
+ S.Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
+ << IDecl->getDeclName() << MemberName
+ << BaseExpr.get()->getSourceRange();
return ExprError();
}
}
-
+
assert(ClassDeclared);
// If the decl being referenced had an error, return an error for this
@@ -1315,14 +1303,14 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
return ExprError();
// Check whether we can reference this field.
- if (DiagnoseUseOfDecl(IV, MemberLoc))
+ if (S.DiagnoseUseOfDecl(IV, MemberLoc))
return ExprError();
if (IV->getAccessControl() != ObjCIvarDecl::Public &&
IV->getAccessControl() != ObjCIvarDecl::Package) {
- ObjCInterfaceDecl *ClassOfMethodDecl = 0;
- if (ObjCMethodDecl *MD = getCurMethodDecl())
+ ObjCInterfaceDecl *ClassOfMethodDecl = nullptr;
+ if (ObjCMethodDecl *MD = S.getCurMethodDecl())
ClassOfMethodDecl = MD->getClassInterface();
- else if (ObjCImpDecl && getCurFunctionDecl()) {
+ else if (ObjCImpDecl && S.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
@@ -1336,20 +1324,20 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
dyn_cast<ObjCCategoryImplDecl>(ObjCImpDecl))
ClassOfMethodDecl = CatImplClass->getClassInterface();
}
- if (!getLangOpts().DebuggerSupport) {
+ if (!S.getLangOpts().DebuggerSupport) {
if (IV->getAccessControl() == ObjCIvarDecl::Private) {
if (!declaresSameEntity(ClassDeclared, IDecl) ||
!declaresSameEntity(ClassOfMethodDecl, ClassDeclared))
- Diag(MemberLoc, diag::error_private_ivar_access)
+ S.Diag(MemberLoc, diag::error_private_ivar_access)
<< IV->getDeclName();
} else if (!IDecl->isSuperClassOf(ClassOfMethodDecl))
// @protected
- Diag(MemberLoc, diag::error_protected_ivar_access)
- << IV->getDeclName();
+ S.Diag(MemberLoc, diag::error_protected_ivar_access)
+ << IV->getDeclName();
}
}
bool warn = true;
- if (getLangOpts().ObjCAutoRefCount) {
+ if (S.getLangOpts().ObjCAutoRefCount) {
Expr *BaseExp = BaseExpr.get()->IgnoreParenImpCasts();
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(BaseExp))
if (UO->getOpcode() == UO_Deref)
@@ -1357,55 +1345,50 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
if (DeclRefExpr *DE = dyn_cast<DeclRefExpr>(BaseExp))
if (DE->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
- Diag(DE->getLocation(), diag::error_arc_weak_ivar_access);
+ S.Diag(DE->getLocation(), diag::error_arc_weak_ivar_access);
warn = false;
}
}
if (warn) {
- if (ObjCMethodDecl *MD = getCurMethodDecl()) {
+ if (ObjCMethodDecl *MD = S.getCurMethodDecl()) {
ObjCMethodFamily MF = MD->getMethodFamily();
warn = (MF != OMF_init && MF != OMF_dealloc &&
MF != OMF_finalize &&
- !IvarBacksCurrentMethodAccessor(IDecl, MD, IV));
+ !S.IvarBacksCurrentMethodAccessor(IDecl, MD, IV));
}
if (warn)
- Diag(MemberLoc, diag::warn_direct_ivar_access) << IV->getDeclName();
+ S.Diag(MemberLoc, diag::warn_direct_ivar_access) << IV->getDeclName();
}
- ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(),
- MemberLoc, OpLoc,
- BaseExpr.take(),
- IsArrow);
+ ObjCIvarRefExpr *Result = new (S.Context) ObjCIvarRefExpr(
+ IV, IV->getType(), MemberLoc, OpLoc, BaseExpr.get(), IsArrow);
- if (getLangOpts().ObjCAutoRefCount) {
+ if (S.getLangOpts().ObjCAutoRefCount) {
if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
- DiagnosticsEngine::Level Level =
- Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
- MemberLoc);
- if (Level != DiagnosticsEngine::Ignored)
- recordUseOfEvaluatedWeak(Result);
+ if (!S.Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, MemberLoc))
+ S.recordUseOfEvaluatedWeak(Result);
}
}
- return Owned(Result);
+ return Result;
}
// Objective-C property access.
const ObjCObjectPointerType *OPT;
if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) {
if (!SS.isEmpty() && !SS.isInvalid()) {
- Diag(SS.getRange().getBegin(), diag::err_qualified_objc_access)
- << 0 << SS.getScopeRep()
- << FixItHint::CreateRemoval(SS.getRange());
+ S.Diag(SS.getRange().getBegin(), diag::err_qualified_objc_access)
+ << 0 << SS.getScopeRep() << FixItHint::CreateRemoval(SS.getRange());
SS.clear();
}
// This actually uses the base as an r-value.
- BaseExpr = DefaultLvalueConversion(BaseExpr.take());
+ BaseExpr = S.DefaultLvalueConversion(BaseExpr.get());
if (BaseExpr.isInvalid())
return ExprError();
- assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr.get()->getType()));
+ assert(S.Context.hasSameUnqualifiedType(BaseType,
+ BaseExpr.get()->getType()));
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
@@ -1414,77 +1397,75 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// 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)) {
+ Selector Sel = S.PP.getSelectorTable().getNullarySelector(Member);
+ if (Decl *PMDecl =
+ FindGetterSetterNameDecl(OPT, Member, Sel, S.Context)) {
if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) {
// Check the use of this declaration
- if (DiagnoseUseOfDecl(PD, MemberLoc))
+ if (S.DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
- return Owned(new (Context) ObjCPropertyRefExpr(PD,
- Context.PseudoObjectTy,
- VK_LValue,
- OK_ObjCProperty,
- MemberLoc,
- BaseExpr.take()));
+ return new (S.Context)
+ ObjCPropertyRefExpr(PD, S.Context.PseudoObjectTy, VK_LValue,
+ OK_ObjCProperty, MemberLoc, BaseExpr.get());
}
if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) {
// Check the use of this method.
- if (DiagnoseUseOfDecl(OMD, MemberLoc))
+ if (S.DiagnoseUseOfDecl(OMD, MemberLoc))
return ExprError();
Selector SetterSel =
- SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
- PP.getSelectorTable(),
+ SelectorTable::constructSetterSelector(S.PP.getIdentifierTable(),
+ S.PP.getSelectorTable(),
Member);
- ObjCMethodDecl *SMD = 0;
- if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0,
- SetterSel, Context))
+ ObjCMethodDecl *SMD = nullptr;
+ if (Decl *SDecl = FindGetterSetterNameDecl(OPT,
+ /*Property id*/ nullptr,
+ SetterSel, S.Context))
SMD = dyn_cast<ObjCMethodDecl>(SDecl);
-
- return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD,
- Context.PseudoObjectTy,
- VK_LValue, OK_ObjCProperty,
- MemberLoc, BaseExpr.take()));
+
+ return new (S.Context)
+ ObjCPropertyRefExpr(OMD, SMD, S.Context.PseudoObjectTy, VK_LValue,
+ OK_ObjCProperty, MemberLoc, BaseExpr.get());
}
}
// 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,
+ if (IsArrow && ShouldTryAgainWithRedefinitionType(S, BaseExpr))
+ return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs);
- return ExprError(Diag(MemberLoc, diag::err_property_not_found)
+ return ExprError(S.Diag(MemberLoc, diag::err_property_not_found)
<< MemberName << BaseType);
}
// 'Class', unqualified only.
if (OT->isObjCClass()) {
// Only works in a method declaration (??!).
- ObjCMethodDecl *MD = getCurMethodDecl();
+ ObjCMethodDecl *MD = S.getCurMethodDecl();
if (!MD) {
- if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ if (ShouldTryAgainWithRedefinitionType(S, BaseExpr))
+ return LookupMemberExpr(S, 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);
+ Selector Sel = S.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))
+ if (S.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::constructSetterSelector(PP.getIdentifierTable(),
- PP.getSelectorTable(),
+ SelectorTable::constructSetterSelector(S.PP.getIdentifierTable(),
+ S.PP.getSelectorTable(),
Member);
ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
if (!Setter) {
@@ -1493,28 +1474,27 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
Setter = IFace->lookupPrivateMethod(SetterSel, false);
}
- if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
+ if (Setter && S.DiagnoseUseOfDecl(Setter, MemberLoc))
return ExprError();
if (Getter || Setter) {
- return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- Context.PseudoObjectTy,
- VK_LValue, OK_ObjCProperty,
- MemberLoc, BaseExpr.take()));
+ return new (S.Context) ObjCPropertyRefExpr(
+ Getter, Setter, S.Context.PseudoObjectTy, VK_LValue,
+ OK_ObjCProperty, MemberLoc, BaseExpr.get());
}
- if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ if (ShouldTryAgainWithRedefinitionType(S, BaseExpr))
+ return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs);
- return ExprError(Diag(MemberLoc, diag::err_property_not_found)
+ return ExprError(S.Diag(MemberLoc, diag::err_property_not_found)
<< MemberName << BaseType);
}
// Normal property access.
- return HandleExprPropertyRefExpr(OPT, BaseExpr.get(), OpLoc,
- MemberName, MemberLoc,
- SourceLocation(), QualType(), false);
+ return S.HandleExprPropertyRefExpr(OPT, BaseExpr.get(), OpLoc, MemberName,
+ MemberLoc, SourceLocation(), QualType(),
+ false);
}
// Handle 'field access' to vectors, such as 'V.xx'.
@@ -1522,24 +1502,22 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// 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,
+ QualType ret = CheckExtVectorComponent(S, BaseType, VK, OpLoc,
Member, MemberLoc);
if (ret.isNull())
return ExprError();
- return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr.take(),
- *Member, MemberLoc));
+ return new (S.Context)
+ ExtVectorElementExpr(ret, VK, BaseExpr.get(), *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.getObjCSelRedefinitionType()->isObjCSelType()) {
- BaseExpr = ImpCastExprToType(BaseExpr.take(),
- Context.getObjCSelRedefinitionType(),
- CK_BitCast);
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ if (IsArrow && BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) &&
+ !S.Context.getObjCSelRedefinitionType()->isObjCSelType()) {
+ BaseExpr = S.ImpCastExprToType(
+ BaseExpr.get(), S.Context.getObjCSelRedefinitionType(), CK_BitCast);
+ return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs);
}
@@ -1556,31 +1534,31 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
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()
+ S.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,
+ return LookupMemberExpr(S, 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.
- if (tryToRecoverWithCall(BaseExpr,
- PDiag(diag::err_member_reference_needs_call),
- /*complain*/ false,
- IsArrow ? &isPointerToRecordType : &isRecordType)) {
+ if (S.tryToRecoverWithCall(
+ BaseExpr, S.PDiag(diag::err_member_reference_needs_call),
+ /*complain*/ false,
+ IsArrow ? &isPointerToRecordType : &isRecordType)) {
if (BaseExpr.isInvalid())
return ExprError();
- BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ BaseExpr = S.DefaultFunctionArrayConversion(BaseExpr.get());
+ return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs);
}
- Diag(OpLoc, diag::err_typecheck_member_reference_struct_union)
+ S.Diag(OpLoc, diag::err_typecheck_member_reference_struct_union)
<< BaseType << BaseExpr.get()->getSourceRange() << MemberLoc;
return ExprError();
@@ -1610,6 +1588,19 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
if (SS.isSet() && SS.isInvalid())
return ExprError();
+ // The only way a reference to a destructor can be used is to
+ // immediately call it. If the next token is not a '(', produce
+ // a diagnostic and build the call now.
+ if (!HasTrailingLParen &&
+ Id.getKind() == UnqualifiedId::IK_DestructorName) {
+ ExprResult DtorAccess =
+ ActOnMemberAccessExpr(S, Base, OpLoc, OpKind, SS, TemplateKWLoc, Id,
+ ObjCImpDecl, /*HasTrailingLParen*/true);
+ if (DtorAccess.isInvalid())
+ return DtorAccess;
+ return DiagnoseDtorReference(Id.getLocStart(), DtorAccess.get());
+ }
+
// Warn about the explicit constructor calls Microsoft extension.
if (getLangOpts().MicrosoftExt &&
Id.getKind() == UnqualifiedId::IK_ConstructorName)
@@ -1628,54 +1619,25 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
bool IsArrow = (OpKind == tok::arrow);
NamedDecl *FirstQualifierInScope
- = (!SS.isSet() ? 0 : FindFirstQualifierInScope(S,
- static_cast<NestedNameSpecifier*>(SS.getScopeRep())));
+ = (!SS.isSet() ? nullptr : FindFirstQualifierInScope(S, 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();
+ Base = Result.get();
if (Base->getType()->isDependentType() || Name.isDependentName() ||
isDependentScopeSpecifier(SS)) {
- Result = ActOnDependentMemberExpr(Base, Base->getType(),
- IsArrow, OpLoc,
- SS, TemplateKWLoc, 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 Result;
- }
-
- ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl, HasTrailingLParen};
- Result = BuildMemberReferenceExpr(Base, Base->getType(),
- OpLoc, IsArrow, SS, TemplateKWLoc,
- FirstQualifierInScope, R, TemplateArgs,
- false, &ExtraArgs);
+ return ActOnDependentMemberExpr(Base, Base->getType(), IsArrow, OpLoc, SS,
+ TemplateKWLoc, FirstQualifierInScope,
+ NameInfo, TemplateArgs);
}
- return Result;
+ ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl,
+ HasTrailingLParen};
+ return BuildMemberReferenceExpr(Base, Base->getType(), OpLoc, IsArrow, SS,
+ TemplateKWLoc, FirstQualifierInScope,
+ NameInfo, TemplateArgs, &ExtraArgs);
}
static ExprResult
@@ -1734,10 +1696,9 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
FoundDecl, Field);
if (Base.isInvalid())
return ExprError();
- return S.Owned(BuildMemberExpr(S, S.Context, Base.take(), IsArrow, SS,
- /*TemplateKWLoc=*/SourceLocation(),
- Field, FoundDecl, MemberNameInfo,
- MemberType, VK, OK));
+ return BuildMemberExpr(S, S.Context, Base.get(), IsArrow, SS,
+ /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
+ MemberNameInfo, MemberType, VK, OK);
}
/// Builds an implicit member access expression. The current context
@@ -1753,21 +1714,14 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
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,
- R.begin().getPair());
-
+
// If this is known to be an instance access, go ahead and build an
// implicit 'this' expression now.
// 'this' expression now.
QualType ThisTy = getCurrentThisType();
assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'");
-
- Expr *baseExpr = 0; // null signifies implicit access
+
+ Expr *baseExpr = nullptr; // null signifies implicit access
if (IsKnownInstance) {
SourceLocation Loc = R.getNameLoc();
if (SS.getRange().isValid())
@@ -1775,11 +1729,11 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
CheckCXXThisCapture(Loc);
baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true);
}
-
+
return BuildMemberReferenceExpr(baseExpr, ThisTy,
/*OpLoc*/ SourceLocation(),
/*IsArrow*/ true,
SS, TemplateKWLoc,
- /*FirstQualifierInScope*/ 0,
+ /*FirstQualifierInScope*/ nullptr,
R, TemplateArgs);
}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index cc8eacee6103..500233203c79 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -67,10 +67,14 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
// Create the aggregate string with the appropriate content and location
// information.
- S = StringLiteral::Create(Context, StrBuf,
- StringLiteral::Ascii, /*Pascal=*/false,
- Context.getPointerType(Context.CharTy),
- &StrLocs[0], StrLocs.size());
+ const ConstantArrayType *CAT = Context.getAsConstantArrayType(S->getType());
+ assert(CAT && "String literal not of constant array type!");
+ QualType StrTy = Context.getConstantArrayType(
+ CAT->getElementType(), llvm::APInt(32, StrBuf.size() + 1),
+ CAT->getSizeModifier(), CAT->getIndexTypeCVRQualifiers());
+ S = StringLiteral::Create(Context, StrBuf, StringLiteral::Ascii,
+ /*Pascal=*/false, StrTy, &StrLocs[0],
+ StrLocs.size());
}
return BuildObjCStringLiteral(AtLocs[0], S);
@@ -89,7 +93,7 @@ ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){
if (!Ty.isNull()) {
Ty = Context.getObjCObjectPointerType(Ty);
} else if (getLangOpts().NoConstantCFStrings) {
- IdentifierInfo *NSIdent=0;
+ IdentifierInfo *NSIdent=nullptr;
std::string StringClass(getLangOpts().ObjCConstantStringClass);
if (StringClass.empty())
@@ -129,7 +133,7 @@ ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){
ObjCInterfaceDecl::Create (Context,
Context.getTranslationUnitDecl(),
SourceLocation(), NSIdent,
- 0, SourceLocation());
+ nullptr, SourceLocation());
Ty = Context.getObjCInterfaceType(NSStringIDecl);
Context.setObjCNSStringType(Ty);
}
@@ -152,7 +156,7 @@ static bool validateBoxingMethod(Sema &S, SourceLocation Loc,
}
// Make sure the return type is reasonable.
- QualType ReturnType = Method->getResultType();
+ QualType ReturnType = Method->getReturnType();
if (!ReturnType->isObjCObjectPointerType()) {
S.Diag(Loc, diag::err_objc_literal_method_sig)
<< Sel;
@@ -178,7 +182,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
S.Diag(Loc, diag::err_invalid_nsnumber_type)
<< NumberType << R;
}
- return 0;
+ return nullptr;
}
// If we already looked up this method, we're done.
@@ -204,15 +208,15 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
S.NSNumberDecl = ObjCInterfaceDecl::Create(CX,
CX.getTranslationUnitDecl(),
SourceLocation(), NSNumberId,
- 0, SourceLocation());
+ nullptr, SourceLocation());
} else {
// Otherwise, require a declaration of NSNumber.
S.Diag(Loc, diag::err_undeclared_nsnumber);
- return 0;
+ return nullptr;
}
} else if (!S.NSNumberDecl->hasDefinition()) {
S.Diag(Loc, diag::err_undeclared_nsnumber);
- return 0;
+ return nullptr;
}
// generate the pointer to NSNumber type.
@@ -224,26 +228,25 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
ObjCMethodDecl *Method = S.NSNumberDecl->lookupClassMethod(Sel);
if (!Method && S.getLangOpts().DebuggerObjCLiteral) {
// create a stub definition this NSNumber factory method.
- TypeSourceInfo *ResultTInfo = 0;
- Method = ObjCMethodDecl::Create(CX, SourceLocation(), SourceLocation(), Sel,
- S.NSNumberPointer, ResultTInfo,
- S.NSNumberDecl,
- /*isInstance=*/false, /*isVariadic=*/false,
- /*isPropertyAccessor=*/false,
- /*isImplicitlyDeclared=*/true,
- /*isDefined=*/false,
- ObjCMethodDecl::Required,
- /*HasRelatedResultType=*/false);
+ TypeSourceInfo *ReturnTInfo = nullptr;
+ Method =
+ ObjCMethodDecl::Create(CX, SourceLocation(), SourceLocation(), Sel,
+ S.NSNumberPointer, ReturnTInfo, S.NSNumberDecl,
+ /*isInstance=*/false, /*isVariadic=*/false,
+ /*isPropertyAccessor=*/false,
+ /*isImplicitlyDeclared=*/true,
+ /*isDefined=*/false, ObjCMethodDecl::Required,
+ /*HasRelatedResultType=*/false);
ParmVarDecl *value = ParmVarDecl::Create(S.Context, Method,
SourceLocation(), SourceLocation(),
&CX.Idents.get("value"),
- NumberType, /*TInfo=*/0, SC_None,
- 0);
+ NumberType, /*TInfo=*/nullptr,
+ SC_None, nullptr);
Method->setMethodParams(S.Context, value, None);
}
if (!validateBoxingMethod(S, Loc, S.NSNumberDecl, Sel, Method))
- return 0;
+ return nullptr;
// Note: if the parameter type is out-of-line, we'll catch it later in the
// implicit conversion.
@@ -288,12 +291,12 @@ ExprResult Sema::BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number) {
return ExprError();
// Convert the number to the type that the parameter expects.
- ParmVarDecl *ParamDecl = Method->param_begin()[0];
+ ParmVarDecl *ParamDecl = Method->parameters()[0];
InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
ParamDecl);
ExprResult ConvertedNumber = PerformCopyInitialization(Entity,
SourceLocation(),
- Owned(Number));
+ Number);
if (ConvertedNumber.isInvalid())
return ExprError();
Number = ConvertedNumber.get();
@@ -441,10 +444,10 @@ static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element,
ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
if (ValueExpr->isTypeDependent()) {
ObjCBoxedExpr *BoxedExpr =
- new (Context) ObjCBoxedExpr(ValueExpr, Context.DependentTy, NULL, SR);
- return Owned(BoxedExpr);
+ new (Context) ObjCBoxedExpr(ValueExpr, Context.DependentTy, nullptr, SR);
+ return BoxedExpr;
}
- ObjCMethodDecl *BoxingMethod = NULL;
+ ObjCMethodDecl *BoxingMethod = nullptr;
QualType BoxedType;
// Convert the expression to an RValue, so we can check for pointer types...
ExprResult RValue = DefaultFunctionArrayLvalueConversion(ValueExpr);
@@ -470,7 +473,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
NSStringDecl = ObjCInterfaceDecl::Create(Context, TU,
SourceLocation(),
NSStringId,
- 0, SourceLocation());
+ nullptr, SourceLocation());
} else {
Diag(SR.getBegin(), diag::err_undeclared_nsstring);
return ExprError();
@@ -492,25 +495,23 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
BoxingMethod = NSStringDecl->lookupClassMethod(stringWithUTF8String);
if (!BoxingMethod && getLangOpts().DebuggerObjCLiteral) {
// Debugger needs to work even if NSString hasn't been defined.
- TypeSourceInfo *ResultTInfo = 0;
- ObjCMethodDecl *M =
- ObjCMethodDecl::Create(Context, SourceLocation(), SourceLocation(),
- stringWithUTF8String, NSStringPointer,
- ResultTInfo, NSStringDecl,
- /*isInstance=*/false, /*isVariadic=*/false,
- /*isPropertyAccessor=*/false,
- /*isImplicitlyDeclared=*/true,
- /*isDefined=*/false,
- ObjCMethodDecl::Required,
- /*HasRelatedResultType=*/false);
+ TypeSourceInfo *ReturnTInfo = nullptr;
+ ObjCMethodDecl *M = ObjCMethodDecl::Create(
+ Context, SourceLocation(), SourceLocation(), stringWithUTF8String,
+ NSStringPointer, ReturnTInfo, NSStringDecl,
+ /*isInstance=*/false, /*isVariadic=*/false,
+ /*isPropertyAccessor=*/false,
+ /*isImplicitlyDeclared=*/true,
+ /*isDefined=*/false, ObjCMethodDecl::Required,
+ /*HasRelatedResultType=*/false);
QualType ConstCharType = Context.CharTy.withConst();
ParmVarDecl *value =
ParmVarDecl::Create(Context, M,
SourceLocation(), SourceLocation(),
&Context.Idents.get("value"),
Context.getPointerType(ConstCharType),
- /*TInfo=*/0,
- SC_None, 0);
+ /*TInfo=*/nullptr,
+ SC_None, nullptr);
M->setMethodParams(Context, value, None);
BoxingMethod = M;
}
@@ -554,7 +555,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
break;
}
}
-
+ CheckForIntOverflow(ValueExpr);
// FIXME: Do I need to do anything special with BoolTy expressions?
// Look for the appropriate method within NSNumber.
@@ -580,12 +581,12 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
}
// Convert the expression to the type that the parameter requires.
- ParmVarDecl *ParamDecl = BoxingMethod->param_begin()[0];
+ ParmVarDecl *ParamDecl = BoxingMethod->parameters()[0];
InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
ParamDecl);
ExprResult ConvertedValueExpr = PerformCopyInitialization(Entity,
SourceLocation(),
- Owned(ValueExpr));
+ ValueExpr);
if (ConvertedValueExpr.isInvalid())
return ExprError();
ValueExpr = ConvertedValueExpr.get();
@@ -623,13 +624,9 @@ ExprResult Sema::BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr,
BaseExpr = Result.get();
// Build the pseudo-object expression.
- return Owned(ObjCSubscriptRefExpr::Create(Context,
- BaseExpr,
- IndexExpr,
- Context.PseudoObjectTy,
- getterMethod,
- setterMethod, RB));
-
+ return ObjCSubscriptRefExpr::Create(Context, BaseExpr, IndexExpr,
+ Context.PseudoObjectTy, getterMethod,
+ setterMethod, RB);
}
ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
@@ -645,7 +642,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
Context.getTranslationUnitDecl(),
SourceLocation(),
NSAPIObj->getNSClassId(NSAPI::ClassId_NSArray),
- 0, SourceLocation());
+ nullptr, SourceLocation());
if (!NSArrayDecl) {
Diag(SR.getBegin(), diag::err_undeclared_nsarray);
@@ -660,31 +657,30 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
Sel = NSAPIObj->getNSArraySelector(NSAPI::NSArr_arrayWithObjectsCount);
ObjCMethodDecl *Method = NSArrayDecl->lookupClassMethod(Sel);
if (!Method && getLangOpts().DebuggerObjCLiteral) {
- TypeSourceInfo *ResultTInfo = 0;
- Method = ObjCMethodDecl::Create(Context,
- SourceLocation(), SourceLocation(), Sel,
- IdT,
- ResultTInfo,
- Context.getTranslationUnitDecl(),
- false /*Instance*/, false/*isVariadic*/,
- /*isPropertyAccessor=*/false,
- /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
- ObjCMethodDecl::Required,
- false);
+ TypeSourceInfo *ReturnTInfo = nullptr;
+ Method = ObjCMethodDecl::Create(
+ Context, SourceLocation(), SourceLocation(), Sel, IdT, ReturnTInfo,
+ Context.getTranslationUnitDecl(), false /*Instance*/,
+ false /*isVariadic*/,
+ /*isPropertyAccessor=*/false,
+ /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
+ ObjCMethodDecl::Required, false);
SmallVector<ParmVarDecl *, 2> Params;
ParmVarDecl *objects = ParmVarDecl::Create(Context, Method,
SourceLocation(),
SourceLocation(),
&Context.Idents.get("objects"),
Context.getPointerType(IdT),
- /*TInfo=*/0, SC_None, 0);
+ /*TInfo=*/nullptr,
+ SC_None, nullptr);
Params.push_back(objects);
ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method,
SourceLocation(),
SourceLocation(),
&Context.Idents.get("cnt"),
Context.UnsignedLongTy,
- /*TInfo=*/0, SC_None, 0);
+ /*TInfo=*/nullptr, SC_None,
+ nullptr);
Params.push_back(cnt);
Method->setMethodParams(Context, Params, None);
}
@@ -693,13 +689,13 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
return ExprError();
// Dig out the type that all elements should be converted to.
- QualType T = Method->param_begin()[0]->getType();
+ QualType T = Method->parameters()[0]->getType();
const PointerType *PtrT = T->getAs<PointerType>();
if (!PtrT ||
!Context.hasSameUnqualifiedType(PtrT->getPointeeType(), IdT)) {
Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
<< Sel;
- Diag(Method->param_begin()[0]->getLocation(),
+ Diag(Method->parameters()[0]->getLocation(),
diag::note_objc_literal_method_param)
<< 0 << T
<< Context.getPointerType(IdT.withConst());
@@ -707,13 +703,13 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
}
// Check that the 'count' parameter is integral.
- if (!Method->param_begin()[1]->getType()->isIntegerType()) {
+ if (!Method->parameters()[1]->getType()->isIntegerType()) {
Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
<< Sel;
- Diag(Method->param_begin()[1]->getLocation(),
+ Diag(Method->parameters()[1]->getLocation(),
diag::note_objc_literal_method_param)
<< 1
- << Method->param_begin()[1]->getType()
+ << Method->parameters()[1]->getType()
<< "integral";
return ExprError();
}
@@ -722,7 +718,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
ArrayWithObjectsMethod = Method;
}
- QualType ObjectsType = ArrayWithObjectsMethod->param_begin()[0]->getType();
+ QualType ObjectsType = ArrayWithObjectsMethod->parameters()[0]->getType();
QualType RequiredType = ObjectsType->castAs<PointerType>()->getPointeeType();
// Check that each of the elements provided is valid in a collection literal,
@@ -761,7 +757,7 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
Context.getTranslationUnitDecl(),
SourceLocation(),
NSAPIObj->getNSClassId(NSAPI::ClassId_NSDictionary),
- 0, SourceLocation());
+ nullptr, SourceLocation());
if (!NSDictionaryDecl) {
Diag(SR.getBegin(), diag::err_undeclared_nsdictionary);
@@ -780,7 +776,7 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
Method = ObjCMethodDecl::Create(Context,
SourceLocation(), SourceLocation(), Sel,
IdT,
- 0 /*TypeSourceInfo */,
+ nullptr /*TypeSourceInfo */,
Context.getTranslationUnitDecl(),
false /*Instance*/, false/*isVariadic*/,
/*isPropertyAccessor=*/false,
@@ -793,21 +789,24 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
SourceLocation(),
&Context.Idents.get("objects"),
Context.getPointerType(IdT),
- /*TInfo=*/0, SC_None, 0);
+ /*TInfo=*/nullptr, SC_None,
+ nullptr);
Params.push_back(objects);
ParmVarDecl *keys = ParmVarDecl::Create(Context, Method,
SourceLocation(),
SourceLocation(),
&Context.Idents.get("keys"),
Context.getPointerType(IdT),
- /*TInfo=*/0, SC_None, 0);
+ /*TInfo=*/nullptr, SC_None,
+ nullptr);
Params.push_back(keys);
ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method,
SourceLocation(),
SourceLocation(),
&Context.Idents.get("cnt"),
Context.UnsignedLongTy,
- /*TInfo=*/0, SC_None, 0);
+ /*TInfo=*/nullptr, SC_None,
+ nullptr);
Params.push_back(cnt);
Method->setMethodParams(Context, Params, None);
}
@@ -817,13 +816,13 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
return ExprError();
// Dig out the type that all values should be converted to.
- QualType ValueT = Method->param_begin()[0]->getType();
+ QualType ValueT = Method->parameters()[0]->getType();
const PointerType *PtrValue = ValueT->getAs<PointerType>();
if (!PtrValue ||
!Context.hasSameUnqualifiedType(PtrValue->getPointeeType(), IdT)) {
Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
<< Sel;
- Diag(Method->param_begin()[0]->getLocation(),
+ Diag(Method->parameters()[0]->getLocation(),
diag::note_objc_literal_method_param)
<< 0 << ValueT
<< Context.getPointerType(IdT.withConst());
@@ -831,7 +830,7 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
}
// Dig out the type that all keys should be converted to.
- QualType KeyT = Method->param_begin()[1]->getType();
+ QualType KeyT = Method->parameters()[1]->getType();
const PointerType *PtrKey = KeyT->getAs<PointerType>();
if (!PtrKey ||
!Context.hasSameUnqualifiedType(PtrKey->getPointeeType(),
@@ -857,7 +856,7 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
if (err) {
Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
<< Sel;
- Diag(Method->param_begin()[1]->getLocation(),
+ Diag(Method->parameters()[1]->getLocation(),
diag::note_objc_literal_method_param)
<< 1 << KeyT
<< Context.getPointerType(IdT.withConst());
@@ -866,11 +865,11 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
}
// Check that the 'count' parameter is integral.
- QualType CountType = Method->param_begin()[2]->getType();
+ QualType CountType = Method->parameters()[2]->getType();
if (!CountType->isIntegerType()) {
Diag(SR.getBegin(), diag::err_objc_literal_method_sig)
<< Sel;
- Diag(Method->param_begin()[2]->getLocation(),
+ Diag(Method->parameters()[2]->getLocation(),
diag::note_objc_literal_method_param)
<< 2 << CountType
<< "integral";
@@ -881,9 +880,9 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
DictionaryWithObjectsMethod = Method;
}
- QualType ValuesT = DictionaryWithObjectsMethod->param_begin()[0]->getType();
+ QualType ValuesT = DictionaryWithObjectsMethod->parameters()[0]->getType();
QualType ValueT = ValuesT->castAs<PointerType>()->getPointeeType();
- QualType KeysT = DictionaryWithObjectsMethod->param_begin()[1]->getType();
+ QualType KeysT = DictionaryWithObjectsMethod->parameters()[1]->getType();
QualType KeyT = KeysT->castAs<PointerType>()->getPointeeType();
// Check that each of the keys and values provided is valid in a collection
@@ -975,11 +974,68 @@ ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc,
return BuildObjCEncodeExpression(AtLoc, TInfo, RParenLoc);
}
+static bool HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S,
+ SourceLocation AtLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc,
+ ObjCMethodDecl *Method,
+ ObjCMethodList &MethList) {
+ ObjCMethodList *M = &MethList;
+ bool Warned = false;
+ for (M = M->getNext(); M; M=M->getNext()) {
+ ObjCMethodDecl *MatchingMethodDecl = M->Method;
+ if (MatchingMethodDecl == Method ||
+ isa<ObjCImplDecl>(MatchingMethodDecl->getDeclContext()) ||
+ MatchingMethodDecl->getSelector() != Method->getSelector())
+ continue;
+ if (!S.MatchTwoMethodDeclarations(Method,
+ MatchingMethodDecl, Sema::MMS_loose)) {
+ if (!Warned) {
+ Warned = true;
+ S.Diag(AtLoc, diag::warning_multiple_selectors)
+ << Method->getSelector() << FixItHint::CreateInsertion(LParenLoc, "(")
+ << FixItHint::CreateInsertion(RParenLoc, ")");
+ S.Diag(Method->getLocation(), diag::note_method_declared_at)
+ << Method->getDeclName();
+ }
+ S.Diag(MatchingMethodDecl->getLocation(), diag::note_method_declared_at)
+ << MatchingMethodDecl->getDeclName();
+ }
+ }
+ return Warned;
+}
+
+static void DiagnoseMismatchedSelectors(Sema &S, SourceLocation AtLoc,
+ ObjCMethodDecl *Method,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc,
+ bool WarnMultipleSelectors) {
+ if (!WarnMultipleSelectors ||
+ S.Diags.isIgnored(diag::warning_multiple_selectors, SourceLocation()))
+ return;
+ bool Warned = false;
+ for (Sema::GlobalMethodPool::iterator b = S.MethodPool.begin(),
+ e = S.MethodPool.end(); b != e; b++) {
+ // first, instance methods
+ ObjCMethodList &InstMethList = b->second.first;
+ if (HelperToDiagnoseMismatchedMethodsInGlobalPool(S, AtLoc, LParenLoc, RParenLoc,
+ Method, InstMethList))
+ Warned = true;
+
+ // second, class methods
+ ObjCMethodList &ClsMethList = b->second.second;
+ if (HelperToDiagnoseMismatchedMethodsInGlobalPool(S, AtLoc, LParenLoc, RParenLoc,
+ Method, ClsMethList) || Warned)
+ return;
+ }
+}
+
ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
SourceLocation AtLoc,
SourceLocation SelLoc,
SourceLocation LParenLoc,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ bool WarnMultipleSelectors) {
ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel,
SourceRange(LParenLoc, RParenLoc), false, false);
if (!Method)
@@ -996,10 +1052,13 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
} else
Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
- }
+ } else
+ DiagnoseMismatchedSelectors(*this, AtLoc, Method, LParenLoc, RParenLoc,
+ WarnMultipleSelectors);
- if (!Method ||
- Method->getImplementationControl() != ObjCMethodDecl::Optional) {
+ if (Method &&
+ Method->getImplementationControl() != ObjCMethodDecl::Optional &&
+ !getSourceManager().isInSystemHeader(Method->getLocation())) {
llvm::DenseMap<Selector, SourceLocation>::iterator Pos
= ReferencedSelectors.find(Sel);
if (Pos == ReferencedSelectors.end())
@@ -1063,7 +1122,7 @@ ObjCMethodDecl *Sema::tryCaptureObjCSelf(SourceLocation Loc) {
// still have a 'self', and we really do still need to capture it!
ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(DC);
if (!method)
- return 0;
+ return nullptr;
tryCaptureVariable(method->getSelfDecl(), Loc);
@@ -1120,7 +1179,8 @@ QualType Sema::getMessageSendResultType(QualType ReceiverType,
static const ObjCMethodDecl *
findExplicitInstancetypeDeclarer(const ObjCMethodDecl *MD,
QualType instancetype) {
- if (MD->getResultType() == instancetype) return MD;
+ if (MD->getReturnType() == instancetype)
+ return MD;
// For these purposes, a method in an @implementation overrides a
// declaration in the @interface.
@@ -1147,7 +1207,7 @@ findExplicitInstancetypeDeclarer(const ObjCMethodDecl *MD,
return result;
}
- return 0;
+ return nullptr;
}
void Sema::EmitRelatedResultTypeNoteForReturn(QualType destType) {
@@ -1155,7 +1215,7 @@ void Sema::EmitRelatedResultTypeNoteForReturn(QualType destType) {
// type doesn't match the method's declared return type.
ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurContext);
if (!MD || !MD->hasRelatedResultType() ||
- Context.hasSameUnqualifiedType(destType, MD->getResultType()))
+ Context.hasSameUnqualifiedType(destType, MD->getReturnType()))
return;
// Look for a method overridden by this method which explicitly uses
@@ -1164,7 +1224,7 @@ void Sema::EmitRelatedResultTypeNoteForReturn(QualType destType) {
findExplicitInstancetypeDeclarer(MD, Context.getObjCInstanceType())) {
SourceLocation loc;
SourceRange range;
- if (TypeSourceInfo *TSI = overridden->getResultTypeSourceInfo()) {
+ if (TypeSourceInfo *TSI = overridden->getReturnTypeSourceInfo()) {
range = TSI->getTypeLoc().getSourceRange();
loc = range.getBegin();
}
@@ -1195,13 +1255,12 @@ void Sema::EmitRelatedResultTypeNote(const Expr *E) {
if (!Method->hasRelatedResultType())
return;
-
- if (Context.hasSameUnqualifiedType(Method->getResultType()
- .getNonReferenceType(),
- MsgSend->getType()))
+
+ if (Context.hasSameUnqualifiedType(
+ Method->getReturnType().getNonReferenceType(), MsgSend->getType()))
return;
-
- if (!Context.hasSameUnqualifiedType(Method->getResultType(),
+
+ if (!Context.hasSameUnqualifiedType(Method->getReturnType(),
Context.getObjCInstanceType()))
return;
@@ -1239,7 +1298,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
}
if (result.isInvalid())
return true;
- Args[i] = result.take();
+ Args[i] = result.get();
}
unsigned DiagID;
@@ -1287,7 +1346,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
ReturnType = getMessageSendResultType(ReceiverType, Method, isClassMessage,
isSuperMessage);
- VK = Expr::getValueKindForType(Method->getResultType());
+ VK = Expr::getValueKindForType(Method->getReturnType());
unsigned NumNamedArgs = Sel.getNumArgs();
// Method might have more arguments than selector indicates. This is due
@@ -1309,7 +1368,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
Expr *argExpr = Args[i];
- ParmVarDecl *param = Method->param_begin()[i];
+ ParmVarDecl *param = Method->parameters()[i];
assert(argExpr && "CheckMessageArgumentTypes(): missing expression");
// Strip the unbridged-cast placeholder expression off unless it's
@@ -1326,7 +1385,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
if (argE.isInvalid()) {
IsError = true;
} else {
- Args[i] = argE.take();
+ Args[i] = argE.get();
// Update the parameter type in-place.
param->setType(paramType);
@@ -1341,11 +1400,11 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
param);
- ExprResult ArgE = PerformCopyInitialization(Entity, SelLoc, Owned(argExpr));
+ ExprResult ArgE = PerformCopyInitialization(Entity, SelLoc, argExpr);
if (ArgE.isInvalid())
IsError = true;
else
- Args[i] = ArgE.takeAs<Expr>();
+ Args[i] = ArgE.getAs<Expr>();
}
// Promote additional arguments to variadic methods.
@@ -1355,9 +1414,9 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
continue;
ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod,
- 0);
+ nullptr);
IsError |= Arg.isInvalid();
- Args[i] = Arg.take();
+ Args[i] = Arg.get();
}
} else {
// Check for extra arguments to non-variadic methods.
@@ -1380,10 +1439,14 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
return IsError;
}
-bool Sema::isSelfExpr(Expr *receiver) {
+bool Sema::isSelfExpr(Expr *RExpr) {
// 'self' is objc 'self' in an objc method only.
- ObjCMethodDecl *method =
- dyn_cast_or_null<ObjCMethodDecl>(CurContext->getNonClosureAncestor());
+ ObjCMethodDecl *Method =
+ dyn_cast_or_null<ObjCMethodDecl>(CurContext->getNonClosureAncestor());
+ return isSelfExpr(RExpr, Method);
+}
+
+bool Sema::isSelfExpr(Expr *receiver, const ObjCMethodDecl *method) {
if (!method) return false;
receiver = receiver->IgnoreParenLValueCasts();
@@ -1409,12 +1472,11 @@ ObjCMethodDecl *Sema::LookupMethodInObjectType(Selector sel, QualType type,
}
// Check qualifiers.
- for (ObjCObjectType::qual_iterator
- i = objType->qual_begin(), e = objType->qual_end(); i != e; ++i)
- if (ObjCMethodDecl *method = (*i)->lookupMethod(sel, isInstance))
+ for (const auto *I : objType->quals())
+ if (ObjCMethodDecl *method = I->lookupMethod(sel, isInstance))
return method;
- return 0;
+ return nullptr;
}
/// LookupMethodInQualifiedType - Lookups up a method in protocol qualifier
@@ -1423,15 +1485,13 @@ ObjCMethodDecl *Sema::LookupMethodInQualifiedType(Selector Sel,
const ObjCObjectPointerType *OPT,
bool Instance)
{
- ObjCMethodDecl *MD = 0;
- for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
- E = OPT->qual_end(); I != E; ++I) {
- ObjCProtocolDecl *PROTO = (*I);
+ ObjCMethodDecl *MD = nullptr;
+ for (const auto *PROTO : OPT->quals()) {
if ((MD = PROTO->lookupMethod(Sel, Instance))) {
return MD;
}
}
- return 0;
+ return nullptr;
}
static void DiagnoseARCUseOfWeakReceiver(Sema &S, Expr *Receiver) {
@@ -1444,15 +1504,15 @@ static void DiagnoseARCUseOfWeakReceiver(Sema &S, Expr *Receiver) {
Expr *RExpr = Receiver->IgnoreParenImpCasts();
SourceLocation Loc = RExpr->getLocStart();
QualType T = RExpr->getType();
- const ObjCPropertyDecl *PDecl = 0;
- const ObjCMethodDecl *GDecl = 0;
+ const ObjCPropertyDecl *PDecl = nullptr;
+ const ObjCMethodDecl *GDecl = nullptr;
if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(RExpr)) {
RExpr = POE->getSyntacticForm();
if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(RExpr)) {
if (PRE->isImplicitProperty()) {
GDecl = PRE->getImplicitPropertyGetter();
if (GDecl) {
- T = GDecl->getResultType();
+ T = GDecl->getReturnType();
}
}
else {
@@ -1525,37 +1585,29 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
if (Super)
- return Owned(new (Context) ObjCPropertyRefExpr(PD, Context.PseudoObjectTy,
- VK_LValue, OK_ObjCProperty,
- MemberLoc,
- SuperLoc, SuperType));
+ return new (Context)
+ ObjCPropertyRefExpr(PD, Context.PseudoObjectTy, VK_LValue,
+ OK_ObjCProperty, MemberLoc, SuperLoc, SuperType);
else
- return Owned(new (Context) ObjCPropertyRefExpr(PD, Context.PseudoObjectTy,
- VK_LValue, OK_ObjCProperty,
- MemberLoc, BaseExpr));
+ return new (Context)
+ ObjCPropertyRefExpr(PD, Context.PseudoObjectTy, VK_LValue,
+ OK_ObjCProperty, MemberLoc, BaseExpr);
}
// Check protocols on qualified interfaces.
- for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
- E = OPT->qual_end(); I != E; ++I)
- if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
+ for (const auto *I : OPT->quals())
+ if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration(Member)) {
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
if (Super)
- return Owned(new (Context) ObjCPropertyRefExpr(PD,
- Context.PseudoObjectTy,
- VK_LValue,
- OK_ObjCProperty,
- MemberLoc,
- SuperLoc, SuperType));
+ return new (Context) ObjCPropertyRefExpr(
+ PD, Context.PseudoObjectTy, VK_LValue, OK_ObjCProperty, MemberLoc,
+ SuperLoc, SuperType);
else
- return Owned(new (Context) ObjCPropertyRefExpr(PD,
- Context.PseudoObjectTy,
- VK_LValue,
- OK_ObjCProperty,
- MemberLoc,
- BaseExpr));
+ return new (Context)
+ ObjCPropertyRefExpr(PD, Context.PseudoObjectTy, VK_LValue,
+ OK_ObjCProperty, MemberLoc, BaseExpr);
}
// If that failed, look for an "implicit" property by seeing if the nullary
// selector is implemented.
@@ -1601,24 +1653,21 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
if (Getter || Setter) {
if (Super)
- return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- Context.PseudoObjectTy,
- VK_LValue, OK_ObjCProperty,
- MemberLoc,
- SuperLoc, SuperType));
+ return new (Context)
+ ObjCPropertyRefExpr(Getter, Setter, Context.PseudoObjectTy, VK_LValue,
+ OK_ObjCProperty, MemberLoc, SuperLoc, SuperType);
else
- return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- Context.PseudoObjectTy,
- VK_LValue, OK_ObjCProperty,
- MemberLoc, BaseExpr));
+ return new (Context)
+ ObjCPropertyRefExpr(Getter, Setter, Context.PseudoObjectTy, VK_LValue,
+ OK_ObjCProperty, MemberLoc, BaseExpr);
}
// Attempt to correct for typos in property names.
DeclFilterCCC<ObjCPropertyDecl> Validator;
if (TypoCorrection Corrected = CorrectTypo(
- DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL,
- NULL, Validator, IFace, false, OPT)) {
+ DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName,
+ nullptr, nullptr, Validator, CTK_ErrorRecovery, IFace, false, OPT)) {
diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest)
<< MemberName << QualType(OPT, 0));
DeclarationName TypoResult = Corrected.getCorrection();
@@ -1665,7 +1714,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
receiverNameLoc);
bool IsSuper = false;
- if (IFace == 0) {
+ if (!IFace) {
// If the "receiver" is 'super' in a method, handle it as an expression-like
// property reference.
if (receiverNamePtr->isStr("super")) {
@@ -1683,9 +1732,9 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
}
QualType T = Context.getObjCInterfaceType(Super);
T = Context.getObjCObjectPointerType(T);
-
+
return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(),
- /*BaseExpr*/0,
+ /*BaseExpr*/nullptr,
SourceLocation()/*OpLoc*/,
&propertyName,
propertyNameLoc,
@@ -1697,9 +1746,10 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
IFace = CurMethod->getClassInterface()->getSuperClass();
}
}
-
- if (IFace == 0) {
- Diag(receiverNameLoc, diag::err_expected_ident_or_lparen);
+
+ if (!IFace) {
+ Diag(receiverNameLoc, diag::err_expected_either) << tok::identifier
+ << tok::l_paren;
return ExprError();
}
}
@@ -1710,10 +1760,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
// If this reference is in an @implementation, check for 'private' methods.
if (!Getter)
- if (ObjCMethodDecl *CurMeth = getCurMethodDecl())
- if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
- if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation())
- Getter = ImpDecl->getClassMethod(Sel);
+ Getter = IFace->lookupPrivateClassMethod(Sel);
if (Getter) {
// FIXME: refactor/share with ActOnMemberReference().
@@ -1732,10 +1779,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
if (!Setter) {
// If this reference is in an @implementation, also check for 'private'
// methods.
- if (ObjCMethodDecl *CurMeth = getCurMethodDecl())
- if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
- if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation())
- Setter = ImpDecl->getClassMethod(SetterSel);
+ Setter = IFace->lookupPrivateClassMethod(SetterSel);
}
// Look through local category implementations associated with the class.
if (!Setter)
@@ -1746,18 +1790,14 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
if (Getter || Setter) {
if (IsSuper)
- return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- Context.PseudoObjectTy,
- VK_LValue, OK_ObjCProperty,
- propertyNameLoc,
- receiverNameLoc,
- Context.getObjCInterfaceType(IFace)));
-
- return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- Context.PseudoObjectTy,
- VK_LValue, OK_ObjCProperty,
- propertyNameLoc,
- receiverNameLoc, IFace));
+ return new (Context)
+ ObjCPropertyRefExpr(Getter, Setter, Context.PseudoObjectTy, VK_LValue,
+ OK_ObjCProperty, propertyNameLoc, receiverNameLoc,
+ Context.getObjCInterfaceType(IFace));
+
+ return new (Context) ObjCPropertyRefExpr(
+ Getter, Setter, Context.PseudoObjectTy, VK_LValue, OK_ObjCProperty,
+ propertyNameLoc, receiverNameLoc, IFace);
}
return ExprError(Diag(propertyNameLoc, diag::err_property_not_found)
<< &propertyName << Context.getObjCInterfaceType(IFace));
@@ -1773,7 +1813,7 @@ class ObjCInterfaceOrSuperCCC : public CorrectionCandidateCallback {
WantObjCSuper = Method->getClassInterface()->getSuperClass();
}
- virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ bool ValidateCandidate(const TypoCorrection &candidate) override {
return candidate.getCorrectionDeclAs<ObjCInterfaceDecl>() ||
candidate.isKeyword("super");
}
@@ -1855,7 +1895,8 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
ObjCInterfaceOrSuperCCC Validator(getCurMethodDecl());
if (TypoCorrection Corrected =
CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S,
- NULL, Validator, NULL, false, NULL, false)) {
+ nullptr, Validator, CTK_ErrorRecovery, nullptr, false,
+ nullptr, false)) {
if (Corrected.isKeyword()) {
// If we've found the keyword "super" (the only keyword that would be
// returned by CorrectTypo), this is a send to super.
@@ -1918,16 +1959,16 @@ ExprResult Sema::ActOnSuperMessage(Scope *S,
// message to the superclass instance.
QualType SuperTy = Context.getObjCInterfaceType(Super);
SuperTy = Context.getObjCObjectPointerType(SuperTy);
- return BuildInstanceMessage(0, SuperTy, SuperLoc,
- Sel, /*Method=*/0,
+ return BuildInstanceMessage(nullptr, SuperTy, SuperLoc,
+ Sel, /*Method=*/nullptr,
LBracLoc, SelectorLocs, RBracLoc, Args);
}
// Since we are in a class method, this is a class message to
// the superclass.
- return BuildClassMessage(/*ReceiverTypeInfo=*/0,
+ return BuildClassMessage(/*ReceiverTypeInfo=*/nullptr,
Context.getObjCInterfaceType(Super),
- SuperLoc, Sel, /*Method=*/0,
+ SuperLoc, Sel, /*Method=*/nullptr,
LBracLoc, SelectorLocs, RBracLoc, Args);
}
@@ -1938,7 +1979,7 @@ ExprResult Sema::BuildClassMessageImplicit(QualType ReceiverType,
Selector Sel,
ObjCMethodDecl *Method,
MultiExprArg Args) {
- TypeSourceInfo *receiverTypeInfo = 0;
+ TypeSourceInfo *receiverTypeInfo = nullptr;
if (!ReceiverType.isNull())
receiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType);
@@ -1954,7 +1995,7 @@ static void applyCocoaAPICheck(Sema &S, const ObjCMessageExpr *Msg,
bool (*refactor)(const ObjCMessageExpr *,
const NSAPI &, edit::Commit &)) {
SourceLocation MsgLoc = Msg->getExprLoc();
- if (S.Diags.getDiagnosticLevel(DiagID, MsgLoc) == DiagnosticsEngine::Ignored)
+ if (S.Diags.isIgnored(DiagID, MsgLoc))
return;
SourceManager &SM = S.SourceMgr;
@@ -2050,15 +2091,14 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
unsigned NumArgs = ArgsIn.size();
Expr **Args = ArgsIn.data();
assert(SuperLoc.isInvalid() && "Message to super with dependent type");
- return Owned(ObjCMessageExpr::Create(Context, ReceiverType,
- VK_RValue, LBracLoc, ReceiverTypeInfo,
- Sel, SelectorLocs, /*Method=*/0,
- makeArrayRef(Args, NumArgs),RBracLoc,
- isImplicit));
+ return ObjCMessageExpr::Create(
+ Context, ReceiverType, VK_RValue, LBracLoc, ReceiverTypeInfo, Sel,
+ SelectorLocs, /*Method=*/nullptr, makeArrayRef(Args, NumArgs), RBracLoc,
+ isImplicit);
}
// Find the class to which we are sending this message.
- ObjCInterfaceDecl *Class = 0;
+ ObjCInterfaceDecl *Class = nullptr;
const ObjCObjectType *ClassType = ReceiverType->getAs<ObjCObjectType>();
if (!ClassType || !(Class = ClassType->getInterface())) {
Diag(Loc, diag::err_invalid_receiver_class_message)
@@ -2110,8 +2150,8 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
ReturnType, VK))
return ExprError();
- if (Method && !Method->getResultType()->isVoidType() &&
- RequireCompleteType(LBracLoc, Method->getResultType(),
+ if (Method && !Method->getReturnType()->isVoidType() &&
+ RequireCompleteType(LBracLoc, Method->getReturnType(),
diag::err_illegal_message_expr_incomplete_type))
return ExprError();
@@ -2154,8 +2194,9 @@ ExprResult Sema::ActOnClassMessage(Scope *S,
ReceiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType, LBracLoc);
return BuildClassMessage(ReceiverTypeInfo, ReceiverType,
- /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0,
- LBracLoc, SelectorLocs, RBracLoc, Args);
+ /*SuperLoc=*/SourceLocation(), Sel,
+ /*Method=*/nullptr, LBracLoc, SelectorLocs, RBracLoc,
+ Args);
}
ExprResult Sema::BuildInstanceMessageImplicit(Expr *Receiver,
@@ -2234,7 +2275,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
else
Result = CheckPlaceholderExpr(Receiver);
if (Result.isInvalid()) return ExprError();
- Receiver = Result.take();
+ Receiver = Result.get();
}
if (Receiver->isTypeDependent()) {
@@ -2243,11 +2284,10 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
unsigned NumArgs = ArgsIn.size();
Expr **Args = ArgsIn.data();
assert(SuperLoc.isInvalid() && "Message to super with dependent type");
- return Owned(ObjCMessageExpr::Create(Context, Context.DependentTy,
- VK_RValue, LBracLoc, Receiver, Sel,
- SelectorLocs, /*Method=*/0,
- makeArrayRef(Args, NumArgs),
- RBracLoc, isImplicit));
+ return ObjCMessageExpr::Create(
+ Context, Context.DependentTy, VK_RValue, LBracLoc, Receiver, Sel,
+ SelectorLocs, /*Method=*/nullptr, makeArrayRef(Args, NumArgs),
+ RBracLoc, isImplicit);
}
// If necessary, apply function/array conversion to the receiver.
@@ -2255,7 +2295,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
ExprResult Result = DefaultFunctionArrayLvalueConversion(Receiver);
if (Result.isInvalid())
return ExprError();
- Receiver = Result.take();
+ Receiver = Result.get();
ReceiverType = Receiver->getType();
// If the receiver is an ObjC pointer, a block pointer, or an
@@ -2274,14 +2314,14 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
<< Receiver->getSourceRange();
if (ReceiverType->isPointerType()) {
Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
- CK_CPointerToObjCPointerCast).take();
+ CK_CPointerToObjCPointerCast).get();
} else {
// TODO: specialized warning on null receivers?
bool IsNull = Receiver->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull);
CastKind Kind = IsNull ? CK_NullToPointer : CK_IntegralToPointer;
Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
- Kind).take();
+ Kind).get();
}
ReceiverType = Receiver->getType();
} else if (getLangOpts().CPlusPlus) {
@@ -2292,7 +2332,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
ExprResult result = PerformContextuallyConvertToObjCPointer(Receiver);
if (result.isUsable()) {
- Receiver = result.take();
+ Receiver = result.get();
ReceiverType = Receiver->getType();
}
}
@@ -2369,7 +2409,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
}
} else {
- ObjCInterfaceDecl* ClassDecl = 0;
+ ObjCInterfaceDecl *ClassDecl = nullptr;
// We allow sending a message to a qualified ID ("id<foo>"), which is ok as
// long as one of the protocols implements the selector (if not, warn).
@@ -2389,7 +2429,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// Try to complete the type. Under ARC, this is a hard error from which
// we don't try to recover.
- const ObjCInterfaceDecl *forwardClass = 0;
+ const ObjCInterfaceDecl *forwardClass = nullptr;
if (RequireCompleteType(Loc, OCIType->getPointeeType(),
getLangOpts().ObjCAutoRefCount
? diag::err_arc_receiver_forward_instance
@@ -2402,7 +2442,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
forwardClass = OCIType->getInterfaceDecl();
Diag(Receiver ? Receiver->getLocStart()
: SuperLoc, diag::note_receiver_is_id);
- Method = 0;
+ Method = nullptr;
} else {
Method = ClassDecl->lookupInstanceMethod(Sel);
}
@@ -2447,6 +2487,52 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
}
+ FunctionScopeInfo *DIFunctionScopeInfo =
+ (Method && Method->getMethodFamily() == OMF_init)
+ ? getEnclosingFunction() : nullptr;
+
+ if (DIFunctionScopeInfo &&
+ DIFunctionScopeInfo->ObjCIsDesignatedInit &&
+ (SuperLoc.isValid() || isSelfExpr(Receiver))) {
+ bool isDesignatedInitChain = false;
+ if (SuperLoc.isValid()) {
+ if (const ObjCObjectPointerType *
+ OCIType = ReceiverType->getAsObjCInterfacePointerType()) {
+ if (const ObjCInterfaceDecl *ID = OCIType->getInterfaceDecl()) {
+ // Either we know this is a designated initializer or we
+ // conservatively assume it because we don't know for sure.
+ if (!ID->declaresOrInheritsDesignatedInitializers() ||
+ ID->isDesignatedInitializer(Sel)) {
+ isDesignatedInitChain = true;
+ DIFunctionScopeInfo->ObjCWarnForNoDesignatedInitChain = false;
+ }
+ }
+ }
+ }
+ if (!isDesignatedInitChain) {
+ const ObjCMethodDecl *InitMethod = nullptr;
+ bool isDesignated =
+ getCurMethodDecl()->isDesignatedInitializerForTheInterface(&InitMethod);
+ assert(isDesignated && InitMethod);
+ (void)isDesignated;
+ Diag(SelLoc, SuperLoc.isValid() ?
+ diag::warn_objc_designated_init_non_designated_init_call :
+ diag::warn_objc_designated_init_non_super_designated_init_call);
+ Diag(InitMethod->getLocation(),
+ diag::note_objc_designated_init_marked_here);
+ }
+ }
+
+ if (DIFunctionScopeInfo &&
+ DIFunctionScopeInfo->ObjCIsSecondaryInit &&
+ (SuperLoc.isValid() || isSelfExpr(Receiver))) {
+ if (SuperLoc.isValid()) {
+ Diag(SelLoc, diag::warn_objc_secondary_init_super_init_call);
+ } else {
+ DIFunctionScopeInfo->ObjCWarnForNoInitDelegation = false;
+ }
+ }
+
// Check the message arguments.
unsigned NumArgs = ArgsIn.size();
Expr **Args = ArgsIn.data();
@@ -2459,9 +2545,9 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
ClassMessage, SuperLoc.isValid(),
LBracLoc, RBracLoc, ReturnType, VK))
return ExprError();
-
- if (Method && !Method->getResultType()->isVoidType() &&
- RequireCompleteType(LBracLoc, Method->getResultType(),
+
+ if (Method && !Method->getReturnType()->isVoidType() &&
+ RequireCompleteType(LBracLoc, Method->getReturnType(),
diag::err_illegal_message_expr_incomplete_type))
return ExprError();
@@ -2562,7 +2648,14 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
if (getLangOpts().ObjCAutoRefCount) {
- DiagnoseARCUseOfWeakReceiver(*this, Receiver);
+ // Do not warn about IBOutlet weak property receivers being set to null
+ // as this cannot asynchronously happen.
+ bool WarnWeakReceiver = true;
+ if (isImplicit && Method)
+ if (const ObjCPropertyDecl *PropertyDecl = Method->findPropertyDecl())
+ WarnWeakReceiver = !PropertyDecl->hasAttr<IBOutletAttr>();
+ if (WarnWeakReceiver)
+ DiagnoseARCUseOfWeakReceiver(*this, Receiver);
// In ARC, annotate delegate init calls.
if (Result->getMethodFamily() == OMF_init &&
@@ -2574,7 +2667,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// The implicit assignment to self means we also don't want to
// consume the result.
Result->setDelegateInitCall(true);
- return Owned(Result);
+ return Result;
}
}
@@ -2588,19 +2681,13 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak;
if (!IsWeak && Sel.isUnarySelector())
IsWeak = ReturnType.getObjCLifetime() & Qualifiers::OCL_Weak;
-
- if (IsWeak) {
- DiagnosticsEngine::Level Level =
- Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
- LBracLoc);
- if (Level != DiagnosticsEngine::Ignored)
- getCurFunction()->recordUseOfWeak(Result, Prop);
-
- }
+ if (IsWeak &&
+ !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, LBracLoc))
+ getCurFunction()->recordUseOfWeak(Result, Prop);
}
}
}
-
+
return MaybeBindToTemporary(Result);
}
@@ -2633,7 +2720,7 @@ ExprResult Sema::ActOnInstanceMessage(Scope *S,
if (isa<ParenListExpr>(Receiver)) {
ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Receiver);
if (Result.isInvalid()) return ExprError();
- Receiver = Result.take();
+ Receiver = Result.get();
}
if (RespondsToSelectorSel.isNull()) {
@@ -2642,10 +2729,11 @@ ExprResult Sema::ActOnInstanceMessage(Scope *S,
}
if (Sel == RespondsToSelectorSel)
RemoveSelectorFromWarningCache(*this, Args[0]);
-
+
return BuildInstanceMessage(Receiver, Receiver->getType(),
- /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0,
- LBracLoc, SelectorLocs, RBracLoc, Args);
+ /*SuperLoc=*/SourceLocation(), Sel,
+ /*Method=*/nullptr, LBracLoc, SelectorLocs,
+ RBracLoc, Args);
}
enum ARCConversionTypeClass {
@@ -2859,7 +2947,7 @@ namespace {
ACCResult checkCallToFunction(FunctionDecl *fn) {
// Require a CF*Ref return type.
- if (!isCFType(fn->getResultType()))
+ if (!isCFType(fn->getReturnType()))
return ACC_invalid;
if (!isAnyRetainable(TargetClass))
@@ -2912,7 +3000,7 @@ namespace {
// Check for message sends to functions returning CF types. We
// just obey the Cocoa conventions with these, even though the
// return type is CF.
- if (!isAnyRetainable(TargetClass) || !isCFType(method->getResultType()))
+ if (!isAnyRetainable(TargetClass) || !isCFType(method->getReturnType()))
return ACC_invalid;
// If the method is explicitly marked not-retained, it's +0.
@@ -3045,6 +3133,31 @@ static void addFixitForObjCARCConversion(Sema &S,
}
}
+template <typename T>
+static inline T *getObjCBridgeAttr(const TypedefType *TD) {
+ TypedefNameDecl *TDNDecl = TD->getDecl();
+ QualType QT = TDNDecl->getUnderlyingType();
+ if (QT->isPointerType()) {
+ QT = QT->getPointeeType();
+ if (const RecordType *RT = QT->getAs<RecordType>())
+ if (RecordDecl *RD = RT->getDecl()->getMostRecentDecl())
+ return RD->getAttr<T>();
+ }
+ return nullptr;
+}
+
+static ObjCBridgeRelatedAttr *ObjCBridgeRelatedAttrFromType(QualType T,
+ TypedefNameDecl *&TDNDecl) {
+ while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) {
+ TDNDecl = TD->getDecl();
+ if (ObjCBridgeRelatedAttr *ObjCBAttr =
+ getObjCBridgeAttr<ObjCBridgeRelatedAttr>(TD))
+ return ObjCBAttr;
+ T = TDNDecl->getUnderlyingType();
+ }
+ return nullptr;
+}
+
static void
diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
QualType castType, ARCConversionTypeClass castACTC,
@@ -3059,6 +3172,12 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
return;
QualType castExprType = castExpr->getType();
+ TypedefNameDecl *TDNDecl = nullptr;
+ if ((castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable &&
+ ObjCBridgeRelatedAttrFromType(castType, TDNDecl)) ||
+ (exprACTC == ACTC_coreFoundation && castACTC == ACTC_retainable &&
+ ObjCBridgeRelatedAttrFromType(castExprType, TDNDecl)))
+ return;
unsigned srcKind = 0;
switch (exprACTC) {
@@ -3099,9 +3218,10 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
DiagnosticBuilder DiagB =
(CCK != Sema::CCK_OtherCast) ? S.Diag(noteLoc, diag::note_arc_bridge)
: S.Diag(noteLoc, diag::note_arc_cstyle_bridge);
-
+
addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
- castType, castExpr, realCast, "__bridge ", 0);
+ castType, castExpr, realCast, "__bridge ",
+ nullptr);
}
if (CreateRule != ACC_plusZero)
{
@@ -3111,15 +3231,15 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
S.Diag(br ? castExpr->getExprLoc() : noteLoc,
diag::note_arc_bridge_transfer)
<< castExprType << br;
-
+
addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
castType, castExpr, realCast, "__bridge_transfer ",
- br ? "CFBridgingRelease" : 0);
+ br ? "CFBridgingRelease" : nullptr);
}
return;
}
-
+
// Bridge from a CF type to an ARC type.
if (exprACTC == ACTC_retainable && isAnyRetainable(castACTC)) {
bool br = S.isKnownName("CFBridgingRetain");
@@ -3140,7 +3260,8 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
(CCK != Sema::CCK_OtherCast) ? S.Diag(noteLoc, diag::note_arc_bridge)
: S.Diag(noteLoc, diag::note_arc_cstyle_bridge);
addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
- castType, castExpr, realCast, "__bridge ", 0);
+ castType, castExpr, realCast, "__bridge ",
+ nullptr);
}
if (CreateRule != ACC_plusZero)
{
@@ -3150,10 +3271,10 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
S.Diag(br ? castExpr->getExprLoc() : noteLoc,
diag::note_arc_bridge_retained)
<< castType << br;
-
+
addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
castType, castExpr, realCast, "__bridge_retained ",
- br ? "CFBridgingRetain" : 0);
+ br ? "CFBridgingRetain" : nullptr);
}
return;
@@ -3165,26 +3286,17 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
<< castRange << castExpr->getSourceRange();
}
-static inline ObjCBridgeAttr *getObjCBridgeAttr(const TypedefType *TD) {
- TypedefNameDecl *TDNDecl = TD->getDecl();
- QualType QT = TDNDecl->getUnderlyingType();
- if (QT->isPointerType()) {
- QT = QT->getPointeeType();
- if (const RecordType *RT = QT->getAs<RecordType>())
- if (RecordDecl *RD = RT->getDecl())
- if (RD->hasAttr<ObjCBridgeAttr>())
- return RD->getAttr<ObjCBridgeAttr>();
- }
- return 0;
-}
-
-static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr) {
+template <typename TB>
+static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr,
+ bool &HadTheAttribute, bool warn) {
QualType T = castExpr->getType();
+ HadTheAttribute = false;
while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) {
TypedefNameDecl *TDNDecl = TD->getDecl();
- if (ObjCBridgeAttr *ObjCBAttr = getObjCBridgeAttr(TD)) {
+ if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) {
if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
- NamedDecl *Target = 0;
+ HadTheAttribute = true;
+ NamedDecl *Target = nullptr;
// Check for an existing type with this name.
LookupResult R(S, DeclarationName(Parm), SourceLocation(),
Sema::LookupOrdinaryName);
@@ -3196,39 +3308,56 @@ static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr) {
castType->getAsObjCInterfacePointerType()) {
ObjCInterfaceDecl *CastClass
= InterfacePointerType->getObjectType()->getInterface();
- if ((CastClass == ExprClass) || (CastClass && ExprClass->isSuperClassOf(CastClass)))
+ if ((CastClass == ExprClass) ||
+ (CastClass && ExprClass->isSuperClassOf(CastClass)))
return true;
- S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge)
- << T << Target->getName() << castType->getPointeeType();
- return true;
- } else {
- S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge)
- << T << Target->getName() << castType;
+ if (warn)
+ S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge)
+ << T << Target->getName() << castType->getPointeeType();
+ return false;
+ } else if (castType->isObjCIdType() ||
+ (S.Context.ObjCObjectAdoptsQTypeProtocols(
+ castType, ExprClass)))
+ // ok to cast to 'id'.
+ // casting to id<p-list> is ok if bridge type adopts all of
+ // p-list protocols.
return true;
+ else {
+ if (warn) {
+ S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge)
+ << T << Target->getName() << castType;
+ S.Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ S.Diag(Target->getLocStart(), diag::note_declared_at);
+ }
+ return false;
}
}
}
S.Diag(castExpr->getLocStart(), diag::err_objc_cf_bridged_not_interface)
- << castExpr->getType() << Parm->getName();
+ << castExpr->getType() << Parm;
S.Diag(TDNDecl->getLocStart(), diag::note_declared_at);
if (Target)
S.Diag(Target->getLocStart(), diag::note_declared_at);
+ return true;
}
- return true;
+ return false;
}
T = TDNDecl->getUnderlyingType();
}
- return false;
+ return true;
}
-// (CFErrorRef)ns
-static bool CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr) {
+template <typename TB>
+static bool CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr,
+ bool &HadTheAttribute, bool warn) {
QualType T = castType;
+ HadTheAttribute = false;
while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) {
TypedefNameDecl *TDNDecl = TD->getDecl();
- if (ObjCBridgeAttr *ObjCBAttr = getObjCBridgeAttr(TD)) {
+ if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) {
if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
- NamedDecl *Target = 0;
+ HadTheAttribute = true;
+ NamedDecl *Target = nullptr;
// Check for an existing type with this name.
LookupResult R(S, DeclarationName(Parm), SourceLocation(),
Sema::LookupOrdinaryName);
@@ -3240,17 +3369,30 @@ static bool CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr) {
castExpr->getType()->getAsObjCInterfacePointerType()) {
ObjCInterfaceDecl *ExprClass
= InterfacePointerType->getObjectType()->getInterface();
- if ((CastClass == ExprClass) || (ExprClass && CastClass->isSuperClassOf(ExprClass)))
+ if ((CastClass == ExprClass) ||
+ (ExprClass && CastClass->isSuperClassOf(ExprClass)))
return true;
- S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge_to_cf)
- << castExpr->getType()->getPointeeType() << T;
- S.Diag(TDNDecl->getLocStart(), diag::note_declared_at);
- return true;
- } else {
- S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge_to_cf)
- << castExpr->getType() << castType;
- S.Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ if (warn) {
+ S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge_to_cf)
+ << castExpr->getType()->getPointeeType() << T;
+ S.Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ }
+ return false;
+ } else if (castExpr->getType()->isObjCIdType() ||
+ (S.Context.QIdProtocolsAdoptObjCObjectProtocols(
+ castExpr->getType(), CastClass)))
+ // ok to cast an 'id' expression to a CFtype.
+ // ok to cast an 'id<plist>' expression to CFtype provided plist
+ // adopts all of CFtype's ObjetiveC's class plist.
return true;
+ else {
+ if (warn) {
+ S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge_to_cf)
+ << castExpr->getType() << castType;
+ S.Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ S.Diag(Target->getLocStart(), diag::note_declared_at);
+ }
+ return false;
}
}
}
@@ -3259,18 +3401,262 @@ static bool CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr) {
S.Diag(TDNDecl->getLocStart(), diag::note_declared_at);
if (Target)
S.Diag(Target->getLocStart(), diag::note_declared_at);
+ return true;
}
- return true;
+ return false;
}
T = TDNDecl->getUnderlyingType();
}
+ return true;
+}
+
+void Sema::CheckTollFreeBridgeCast(QualType castType, Expr *castExpr) {
+ if (!getLangOpts().ObjC1)
+ return;
+ // warn in presence of __bridge casting to or from a toll free bridge cast.
+ ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExpr->getType());
+ ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType);
+ if (castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation) {
+ bool HasObjCBridgeAttr;
+ bool ObjCBridgeAttrWillNotWarn =
+ CheckObjCBridgeNSCast<ObjCBridgeAttr>(*this, castType, castExpr, HasObjCBridgeAttr,
+ false);
+ if (ObjCBridgeAttrWillNotWarn && HasObjCBridgeAttr)
+ return;
+ bool HasObjCBridgeMutableAttr;
+ bool ObjCBridgeMutableAttrWillNotWarn =
+ CheckObjCBridgeNSCast<ObjCBridgeMutableAttr>(*this, castType, castExpr,
+ HasObjCBridgeMutableAttr, false);
+ if (ObjCBridgeMutableAttrWillNotWarn && HasObjCBridgeMutableAttr)
+ return;
+
+ if (HasObjCBridgeAttr)
+ CheckObjCBridgeNSCast<ObjCBridgeAttr>(*this, castType, castExpr, HasObjCBridgeAttr,
+ true);
+ else if (HasObjCBridgeMutableAttr)
+ CheckObjCBridgeNSCast<ObjCBridgeMutableAttr>(*this, castType, castExpr,
+ HasObjCBridgeMutableAttr, true);
+ }
+ else if (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable) {
+ bool HasObjCBridgeAttr;
+ bool ObjCBridgeAttrWillNotWarn =
+ CheckObjCBridgeCFCast<ObjCBridgeAttr>(*this, castType, castExpr, HasObjCBridgeAttr,
+ false);
+ if (ObjCBridgeAttrWillNotWarn && HasObjCBridgeAttr)
+ return;
+ bool HasObjCBridgeMutableAttr;
+ bool ObjCBridgeMutableAttrWillNotWarn =
+ CheckObjCBridgeCFCast<ObjCBridgeMutableAttr>(*this, castType, castExpr,
+ HasObjCBridgeMutableAttr, false);
+ if (ObjCBridgeMutableAttrWillNotWarn && HasObjCBridgeMutableAttr)
+ return;
+
+ if (HasObjCBridgeAttr)
+ CheckObjCBridgeCFCast<ObjCBridgeAttr>(*this, castType, castExpr, HasObjCBridgeAttr,
+ true);
+ else if (HasObjCBridgeMutableAttr)
+ CheckObjCBridgeCFCast<ObjCBridgeMutableAttr>(*this, castType, castExpr,
+ HasObjCBridgeMutableAttr, true);
+ }
+}
+
+void Sema::CheckObjCBridgeRelatedCast(QualType castType, Expr *castExpr) {
+ QualType SrcType = castExpr->getType();
+ if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(castExpr)) {
+ if (PRE->isExplicitProperty()) {
+ if (ObjCPropertyDecl *PDecl = PRE->getExplicitProperty())
+ SrcType = PDecl->getType();
+ }
+ else if (PRE->isImplicitProperty()) {
+ if (ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter())
+ SrcType = Getter->getReturnType();
+
+ }
+ }
+
+ ARCConversionTypeClass srcExprACTC = classifyTypeForARCConversion(SrcType);
+ ARCConversionTypeClass castExprACTC = classifyTypeForARCConversion(castType);
+ if (srcExprACTC != ACTC_retainable || castExprACTC != ACTC_coreFoundation)
+ return;
+ CheckObjCBridgeRelatedConversions(castExpr->getLocStart(),
+ castType, SrcType, castExpr);
+ return;
+}
+
+bool Sema::CheckTollFreeBridgeStaticCast(QualType castType, Expr *castExpr,
+ CastKind &Kind) {
+ if (!getLangOpts().ObjC1)
+ return false;
+ ARCConversionTypeClass exprACTC =
+ classifyTypeForARCConversion(castExpr->getType());
+ ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType);
+ if ((castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation) ||
+ (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable)) {
+ CheckTollFreeBridgeCast(castType, castExpr);
+ Kind = (castACTC == ACTC_coreFoundation) ? CK_BitCast
+ : CK_CPointerToObjCPointerCast;
+ return true;
+ }
+ return false;
+}
+
+bool Sema::checkObjCBridgeRelatedComponents(SourceLocation Loc,
+ QualType DestType, QualType SrcType,
+ ObjCInterfaceDecl *&RelatedClass,
+ ObjCMethodDecl *&ClassMethod,
+ ObjCMethodDecl *&InstanceMethod,
+ TypedefNameDecl *&TDNDecl,
+ bool CfToNs) {
+ QualType T = CfToNs ? SrcType : DestType;
+ ObjCBridgeRelatedAttr *ObjCBAttr = ObjCBridgeRelatedAttrFromType(T, TDNDecl);
+ if (!ObjCBAttr)
+ return false;
+
+ IdentifierInfo *RCId = ObjCBAttr->getRelatedClass();
+ IdentifierInfo *CMId = ObjCBAttr->getClassMethod();
+ IdentifierInfo *IMId = ObjCBAttr->getInstanceMethod();
+ if (!RCId)
+ return false;
+ NamedDecl *Target = nullptr;
+ // Check for an existing type with this name.
+ LookupResult R(*this, DeclarationName(RCId), SourceLocation(),
+ Sema::LookupOrdinaryName);
+ if (!LookupName(R, TUScope)) {
+ Diag(Loc, diag::err_objc_bridged_related_invalid_class) << RCId
+ << SrcType << DestType;
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ return false;
+ }
+ Target = R.getFoundDecl();
+ if (Target && isa<ObjCInterfaceDecl>(Target))
+ RelatedClass = cast<ObjCInterfaceDecl>(Target);
+ else {
+ Diag(Loc, diag::err_objc_bridged_related_invalid_class_name) << RCId
+ << SrcType << DestType;
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ if (Target)
+ Diag(Target->getLocStart(), diag::note_declared_at);
+ return false;
+ }
+
+ // Check for an existing class method with the given selector name.
+ if (CfToNs && CMId) {
+ Selector Sel = Context.Selectors.getUnarySelector(CMId);
+ ClassMethod = RelatedClass->lookupMethod(Sel, false);
+ if (!ClassMethod) {
+ Diag(Loc, diag::err_objc_bridged_related_known_method)
+ << SrcType << DestType << Sel << false;
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ return false;
+ }
+ }
+
+ // Check for an existing instance method with the given selector name.
+ if (!CfToNs && IMId) {
+ Selector Sel = Context.Selectors.getNullarySelector(IMId);
+ InstanceMethod = RelatedClass->lookupMethod(Sel, true);
+ if (!InstanceMethod) {
+ Diag(Loc, diag::err_objc_bridged_related_known_method)
+ << SrcType << DestType << Sel << true;
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc,
+ QualType DestType, QualType SrcType,
+ Expr *&SrcExpr) {
+ ARCConversionTypeClass rhsExprACTC = classifyTypeForARCConversion(SrcType);
+ ARCConversionTypeClass lhsExprACTC = classifyTypeForARCConversion(DestType);
+ bool CfToNs = (rhsExprACTC == ACTC_coreFoundation && lhsExprACTC == ACTC_retainable);
+ bool NsToCf = (rhsExprACTC == ACTC_retainable && lhsExprACTC == ACTC_coreFoundation);
+ if (!CfToNs && !NsToCf)
+ return false;
+
+ ObjCInterfaceDecl *RelatedClass;
+ ObjCMethodDecl *ClassMethod = nullptr;
+ ObjCMethodDecl *InstanceMethod = nullptr;
+ TypedefNameDecl *TDNDecl = nullptr;
+ if (!checkObjCBridgeRelatedComponents(Loc, DestType, SrcType, RelatedClass,
+ ClassMethod, InstanceMethod, TDNDecl, CfToNs))
+ return false;
+
+ if (CfToNs) {
+ // Implicit conversion from CF to ObjC object is needed.
+ if (ClassMethod) {
+ std::string ExpressionString = "[";
+ ExpressionString += RelatedClass->getNameAsString();
+ ExpressionString += " ";
+ ExpressionString += ClassMethod->getSelector().getAsString();
+ SourceLocation SrcExprEndLoc = PP.getLocForEndOfToken(SrcExpr->getLocEnd());
+ // Provide a fixit: [RelatedClass ClassMethod SrcExpr]
+ Diag(Loc, diag::err_objc_bridged_related_known_method)
+ << SrcType << DestType << ClassMethod->getSelector() << false
+ << FixItHint::CreateInsertion(SrcExpr->getLocStart(), ExpressionString)
+ << FixItHint::CreateInsertion(SrcExprEndLoc, "]");
+ Diag(RelatedClass->getLocStart(), diag::note_declared_at);
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+
+ QualType receiverType =
+ Context.getObjCInterfaceType(RelatedClass);
+ // Argument.
+ Expr *args[] = { SrcExpr };
+ ExprResult msg = BuildClassMessageImplicit(receiverType, false,
+ ClassMethod->getLocation(),
+ ClassMethod->getSelector(), ClassMethod,
+ MultiExprArg(args, 1));
+ SrcExpr = msg.get();
+ return true;
+ }
+ }
+ else {
+ // Implicit conversion from ObjC type to CF object is needed.
+ if (InstanceMethod) {
+ std::string ExpressionString;
+ SourceLocation SrcExprEndLoc = PP.getLocForEndOfToken(SrcExpr->getLocEnd());
+ if (InstanceMethod->isPropertyAccessor())
+ if (const ObjCPropertyDecl *PDecl = InstanceMethod->findPropertyDecl()) {
+ // fixit: ObjectExpr.propertyname when it is aproperty accessor.
+ ExpressionString = ".";
+ ExpressionString += PDecl->getNameAsString();
+ Diag(Loc, diag::err_objc_bridged_related_known_method)
+ << SrcType << DestType << InstanceMethod->getSelector() << true
+ << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString);
+ }
+ if (ExpressionString.empty()) {
+ // Provide a fixit: [ObjectExpr InstanceMethod]
+ ExpressionString = " ";
+ ExpressionString += InstanceMethod->getSelector().getAsString();
+ ExpressionString += "]";
+
+ Diag(Loc, diag::err_objc_bridged_related_known_method)
+ << SrcType << DestType << InstanceMethod->getSelector() << true
+ << FixItHint::CreateInsertion(SrcExpr->getLocStart(), "[")
+ << FixItHint::CreateInsertion(SrcExprEndLoc, ExpressionString);
+ }
+ Diag(RelatedClass->getLocStart(), diag::note_declared_at);
+ Diag(TDNDecl->getLocStart(), diag::note_declared_at);
+
+ ExprResult msg =
+ BuildInstanceMessageImplicit(SrcExpr, SrcType,
+ InstanceMethod->getLocation(),
+ InstanceMethod->getSelector(),
+ InstanceMethod, None);
+ SrcExpr = msg.get();
+ return true;
+ }
+ }
return false;
}
Sema::ARCConversionResult
Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
Expr *&castExpr, CheckedConversionKind CCK,
- bool DiagnoseCFAudited) {
+ bool DiagnoseCFAudited,
+ BinaryOperatorKind Opc) {
QualType castExprType = castExpr->getType();
// For the purposes of the classification, we assume reference types
@@ -3324,17 +3710,6 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
if (castACTC == ACTC_indirectRetainable && exprACTC == ACTC_voidPtr &&
CCK != CCK_ImplicitConversion)
return ACR_okay;
-
- if (castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation &&
- (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast))
- if (CheckObjCBridgeNSCast(*this, castType, castExpr))
- return ACR_okay;
-
- if (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable &&
- (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast))
- if (CheckObjCBridgeCFCast(*this, castType, castExpr))
- return ACR_okay;
-
switch (ARCCastChecker(Context, exprACTC, castACTC, false).Visit(castExpr)) {
// For invalid casts, fall through.
@@ -3350,7 +3725,7 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
case ACC_plusOne:
castExpr = ImplicitCastExpr::Create(Context, castExpr->getType(),
CK_ARCConsumeObject, castExpr,
- 0, VK_RValue);
+ nullptr, VK_RValue);
ExprNeedsCleanups = true;
return ACR_okay;
}
@@ -3362,14 +3737,23 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
CCK != CCK_ImplicitConversion)
return ACR_unbridged;
+ // Do not issue bridge cast" diagnostic when implicit casting a cstring
+ // to 'NSString *'. Let caller issue a normal mismatched diagnostic with
+ // suitable fix-it.
+ if (castACTC == ACTC_retainable && exprACTC == ACTC_none &&
+ ConversionToObjCStringLiteralCheck(castType, castExpr))
+ return ACR_okay;
+
// Do not issue "bridge cast" diagnostic when implicit casting
// a retainable object to a CF type parameter belonging to an audited
// CF API function. Let caller issue a normal type mismatched diagnostic
// instead.
if (!DiagnoseCFAudited || exprACTC != ACTC_retainable ||
castACTC != ACTC_coreFoundation)
- diagnoseObjCARCConversion(*this, castRange, castType, castACTC,
- castExpr, castExpr, exprACTC, CCK);
+ if (!(exprACTC == ACTC_voidPtr && castACTC == ACTC_retainable &&
+ (Opc == BO_NE || Opc == BO_EQ)))
+ diagnoseObjCARCConversion(*this, castRange, castType, castACTC,
+ castExpr, castExpr, exprACTC, CCK);
return ACR_okay;
}
@@ -3486,7 +3870,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
Expr *SubExpr) {
ExprResult SubResult = UsualUnaryConversions(SubExpr);
if (SubResult.isInvalid()) return ExprError();
- SubExpr = SubResult.take();
+ SubExpr = SubResult.get();
QualType T = TSInfo->getType();
QualType FromType = SubExpr->getType();
@@ -3545,7 +3929,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
// Produce the object before casting it.
SubExpr = ImplicitCastExpr::Create(Context, FromType,
CK_ARCProduceObject,
- SubExpr, 0, VK_RValue);
+ SubExpr, nullptr, VK_RValue);
break;
case OBC_BridgeTransfer: {
@@ -3584,7 +3968,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
if (MustConsume) {
ExprNeedsCleanups = true;
Result = ImplicitCastExpr::Create(Context, T, CK_ARCConsumeObject, Result,
- 0, VK_RValue);
+ nullptr, VK_RValue);
}
return Result;
@@ -3597,8 +3981,10 @@ ExprResult Sema::ActOnObjCBridgedCast(Scope *S,
ParsedType Type,
SourceLocation RParenLoc,
Expr *SubExpr) {
- TypeSourceInfo *TSInfo = 0;
+ TypeSourceInfo *TSInfo = nullptr;
QualType T = GetTypeFromParser(Type, &TSInfo);
+ if (Kind == OBC_Bridge)
+ CheckTollFreeBridgeCast(T, SubExpr);
if (!TSInfo)
TSInfo = Context.getTrivialTypeSourceInfo(T, LParenLoc);
return BuildObjCBridgedCast(LParenLoc, Kind, BridgeKeywordLoc, TSInfo,
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 034c1b6c7184..06ca9aed6a87 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -17,7 +17,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/TypeLoc.h"
-#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/Designator.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/SemaInternal.h"
@@ -70,7 +70,7 @@ static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT,
// Otherwise we can only handle string literals.
StringLiteral *SL = dyn_cast<StringLiteral>(Init);
- if (SL == 0)
+ if (!SL)
return SIF_Other;
const QualType ElemTy =
@@ -189,7 +189,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
// C99 6.7.8p14.
if (StrLength-1 > CAT->getSize().getZExtValue())
S.Diag(Str->getLocStart(),
- diag::warn_initializer_string_for_char_array_too_long)
+ diag::ext_initializer_string_for_char_array_too_long)
<< Str->getSourceRange();
}
@@ -313,15 +313,20 @@ class InitListChecker {
int numArrayElements(QualType DeclType);
int numStructUnionElements(QualType DeclType);
- void FillInValueInitForField(unsigned Init, FieldDecl *Field,
+ static ExprResult PerformEmptyInit(Sema &SemaRef,
+ SourceLocation Loc,
+ const InitializedEntity &Entity,
+ bool VerifyOnly);
+ void FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
const InitializedEntity &ParentEntity,
InitListExpr *ILE, bool &RequiresSecondPass);
- void FillInValueInitializations(const InitializedEntity &Entity,
+ void FillInEmptyInitializations(const InitializedEntity &Entity,
InitListExpr *ILE, bool &RequiresSecondPass);
bool CheckFlexibleArrayInit(const InitializedEntity &Entity,
Expr *InitExpr, FieldDecl *Field,
bool TopLevelObject);
- void CheckValueInitializable(const InitializedEntity &Entity);
+ void CheckEmptyInitializable(const InitializedEntity &Entity,
+ SourceLocation Loc);
public:
InitListChecker(Sema &S, const InitializedEntity &Entity,
@@ -334,33 +339,134 @@ public:
};
} // end anonymous namespace
-void InitListChecker::CheckValueInitializable(const InitializedEntity &Entity) {
- assert(VerifyOnly &&
- "CheckValueInitializable is only inteded for verification mode.");
-
- SourceLocation Loc;
+ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef,
+ SourceLocation Loc,
+ const InitializedEntity &Entity,
+ bool VerifyOnly) {
InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc,
true);
- InitializationSequence InitSeq(SemaRef, Entity, Kind, None);
- if (InitSeq.Failed())
+ MultiExprArg SubInit;
+ Expr *InitExpr;
+ InitListExpr DummyInitList(SemaRef.Context, Loc, None, Loc);
+
+ // C++ [dcl.init.aggr]p7:
+ // If there are fewer initializer-clauses in the list than there are
+ // members in the aggregate, then each member not explicitly initialized
+ // ...
+ bool EmptyInitList = SemaRef.getLangOpts().CPlusPlus11 &&
+ Entity.getType()->getBaseElementTypeUnsafe()->isRecordType();
+ if (EmptyInitList) {
+ // C++1y / DR1070:
+ // shall be initialized [...] from an empty initializer list.
+ //
+ // We apply the resolution of this DR to C++11 but not C++98, since C++98
+ // does not have useful semantics for initialization from an init list.
+ // We treat this as copy-initialization, because aggregate initialization
+ // always performs copy-initialization on its elements.
+ //
+ // Only do this if we're initializing a class type, to avoid filling in
+ // the initializer list where possible.
+ InitExpr = VerifyOnly ? &DummyInitList : new (SemaRef.Context)
+ InitListExpr(SemaRef.Context, Loc, None, Loc);
+ InitExpr->setType(SemaRef.Context.VoidTy);
+ SubInit = InitExpr;
+ Kind = InitializationKind::CreateCopy(Loc, Loc);
+ } else {
+ // C++03:
+ // shall be value-initialized.
+ }
+
+ InitializationSequence InitSeq(SemaRef, Entity, Kind, SubInit);
+ // libstdc++4.6 marks the vector default constructor as explicit in
+ // _GLIBCXX_DEBUG mode, so recover using the C++03 logic in that case.
+ // stlport does so too. Look for std::__debug for libstdc++, and for
+ // std:: for stlport. This is effectively a compiler-side implementation of
+ // LWG2193.
+ if (!InitSeq && EmptyInitList && InitSeq.getFailureKind() ==
+ InitializationSequence::FK_ExplicitConstructor) {
+ OverloadCandidateSet::iterator Best;
+ OverloadingResult O =
+ InitSeq.getFailedCandidateSet()
+ .BestViableFunction(SemaRef, Kind.getLocation(), Best);
+ (void)O;
+ assert(O == OR_Success && "Inconsistent overload resolution");
+ CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
+ CXXRecordDecl *R = CtorDecl->getParent();
+
+ if (CtorDecl->getMinRequiredArguments() == 0 &&
+ CtorDecl->isExplicit() && R->getDeclName() &&
+ SemaRef.SourceMgr.isInSystemHeader(CtorDecl->getLocation())) {
+
+
+ bool IsInStd = false;
+ for (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(R->getDeclContext());
+ ND && !IsInStd; ND = dyn_cast<NamespaceDecl>(ND->getParent())) {
+ if (SemaRef.getStdNamespace()->InEnclosingNamespaceSetOf(ND))
+ IsInStd = true;
+ }
+
+ if (IsInStd && llvm::StringSwitch<bool>(R->getName())
+ .Cases("basic_string", "deque", "forward_list", true)
+ .Cases("list", "map", "multimap", "multiset", true)
+ .Cases("priority_queue", "queue", "set", "stack", true)
+ .Cases("unordered_map", "unordered_set", "vector", true)
+ .Default(false)) {
+ InitSeq.InitializeFrom(
+ SemaRef, Entity,
+ InitializationKind::CreateValue(Loc, Loc, Loc, true),
+ MultiExprArg(), /*TopLevelOfInitList=*/false);
+ // Emit a warning for this. System header warnings aren't shown
+ // by default, but people working on system headers should see it.
+ if (!VerifyOnly) {
+ SemaRef.Diag(CtorDecl->getLocation(),
+ diag::warn_invalid_initializer_from_system_header);
+ SemaRef.Diag(Entity.getDecl()->getLocation(),
+ diag::note_used_in_initialization_here);
+ }
+ }
+ }
+ }
+ if (!InitSeq) {
+ if (!VerifyOnly) {
+ InitSeq.Diagnose(SemaRef, Entity, Kind, SubInit);
+ if (Entity.getKind() == InitializedEntity::EK_Member)
+ SemaRef.Diag(Entity.getDecl()->getLocation(),
+ diag::note_in_omitted_aggregate_initializer)
+ << /*field*/1 << Entity.getDecl();
+ else if (Entity.getKind() == InitializedEntity::EK_ArrayElement)
+ SemaRef.Diag(Loc, diag::note_in_omitted_aggregate_initializer)
+ << /*array element*/0 << Entity.getElementIndex();
+ }
+ return ExprError();
+ }
+
+ return VerifyOnly ? ExprResult(static_cast<Expr *>(nullptr))
+ : InitSeq.Perform(SemaRef, Entity, Kind, SubInit);
+}
+
+void InitListChecker::CheckEmptyInitializable(const InitializedEntity &Entity,
+ SourceLocation Loc) {
+ assert(VerifyOnly &&
+ "CheckEmptyInitializable is only inteded for verification mode.");
+ if (PerformEmptyInit(SemaRef, Loc, Entity, /*VerifyOnly*/true).isInvalid())
hadError = true;
}
-void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
+void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
const InitializedEntity &ParentEntity,
InitListExpr *ILE,
bool &RequiresSecondPass) {
- SourceLocation Loc = ILE->getLocStart();
+ SourceLocation Loc = ILE->getLocEnd();
unsigned NumInits = ILE->getNumInits();
InitializedEntity MemberEntity
= InitializedEntity::InitializeMember(Field, &ParentEntity);
if (Init >= NumInits || !ILE->getInit(Init)) {
- // If there's no explicit initializer but we have a default initializer, use
- // that. This only happens in C++1y, since classes with default
- // initializers are not aggregates in C++11.
+ // C++1y [dcl.init.aggr]p7:
+ // If there are fewer initializer-clauses in the list than there are
+ // members in the aggregate, then each member not explicitly initialized
+ // shall be initialized from its brace-or-equal-initializer [...]
if (Field->hasInClassInitializer()) {
- Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context,
- ILE->getRBraceLoc(), Field);
+ Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context, Loc, Field);
if (Init < NumInits)
ILE->setInit(Init, DIE);
else {
@@ -370,9 +476,6 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
return;
}
- // FIXME: We probably don't need to handle references
- // specially here, since value-initialization of references is
- // handled in InitializationSequence.
if (Field->getType()->isReferenceType()) {
// C++ [dcl.init.aggr]p9:
// If an incomplete or empty initializer-list leaves a
@@ -387,17 +490,8 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
return;
}
- InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc,
- true);
- InitializationSequence InitSeq(SemaRef, MemberEntity, Kind, None);
- if (!InitSeq) {
- InitSeq.Diagnose(SemaRef, MemberEntity, Kind, None);
- hadError = true;
- return;
- }
-
- ExprResult MemberInit
- = InitSeq.Perform(SemaRef, MemberEntity, Kind, None);
+ ExprResult MemberInit = PerformEmptyInit(SemaRef, Loc, MemberEntity,
+ /*VerifyOnly*/false);
if (MemberInit.isInvalid()) {
hadError = true;
return;
@@ -406,18 +500,18 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
if (hadError) {
// Do nothing
} else if (Init < NumInits) {
- ILE->setInit(Init, MemberInit.takeAs<Expr>());
- } else if (InitSeq.isConstructorInitialization()) {
- // Value-initialization requires a constructor call, so
+ ILE->setInit(Init, MemberInit.getAs<Expr>());
+ } else if (!isa<ImplicitValueInitExpr>(MemberInit.get())) {
+ // Empty initialization requires a constructor call, so
// extend the initializer list to include the constructor
// call and make a note that we'll need to take another pass
// through the initializer list.
- ILE->updateInit(SemaRef.Context, Init, MemberInit.takeAs<Expr>());
+ ILE->updateInit(SemaRef.Context, Init, MemberInit.getAs<Expr>());
RequiresSecondPass = true;
}
} else if (InitListExpr *InnerILE
= dyn_cast<InitListExpr>(ILE->getInit(Init)))
- FillInValueInitializations(MemberEntity, InnerILE,
+ FillInEmptyInitializations(MemberEntity, InnerILE,
RequiresSecondPass);
}
@@ -425,42 +519,35 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
/// with expressions that perform value-initialization of the
/// appropriate type.
void
-InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
+InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
InitListExpr *ILE,
bool &RequiresSecondPass) {
assert((ILE->getType() != SemaRef.Context.VoidTy) &&
"Should not have void type");
- SourceLocation Loc = ILE->getLocStart();
- if (ILE->getSyntacticForm())
- Loc = ILE->getSyntacticForm()->getLocStart();
if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) {
const RecordDecl *RDecl = RType->getDecl();
if (RDecl->isUnion() && ILE->getInitializedFieldInUnion())
- FillInValueInitForField(0, ILE->getInitializedFieldInUnion(),
+ FillInEmptyInitForField(0, ILE->getInitializedFieldInUnion(),
Entity, ILE, RequiresSecondPass);
else if (RDecl->isUnion() && isa<CXXRecordDecl>(RDecl) &&
cast<CXXRecordDecl>(RDecl)->hasInClassInitializer()) {
- for (RecordDecl::field_iterator Field = RDecl->field_begin(),
- FieldEnd = RDecl->field_end();
- Field != FieldEnd; ++Field) {
+ for (auto *Field : RDecl->fields()) {
if (Field->hasInClassInitializer()) {
- FillInValueInitForField(0, *Field, Entity, ILE, RequiresSecondPass);
+ FillInEmptyInitForField(0, Field, Entity, ILE, RequiresSecondPass);
break;
}
}
} else {
unsigned Init = 0;
- for (RecordDecl::field_iterator Field = RDecl->field_begin(),
- FieldEnd = RDecl->field_end();
- Field != FieldEnd; ++Field) {
+ for (auto *Field : RDecl->fields()) {
if (Field->isUnnamedBitfield())
continue;
if (hadError)
return;
- FillInValueInitForField(Init, *Field, Entity, ILE, RequiresSecondPass);
+ FillInEmptyInitForField(Init, Field, Entity, ILE, RequiresSecondPass);
if (hadError)
return;
@@ -494,7 +581,6 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
} else
ElementType = ILE->getType();
-
for (unsigned Init = 0; Init != NumElements; ++Init) {
if (hadError)
return;
@@ -503,19 +589,11 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
ElementEntity.getKind() == InitializedEntity::EK_VectorElement)
ElementEntity.setElementIndex(Init);
- Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) : 0);
+ Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) : nullptr);
if (!InitExpr && !ILE->hasArrayFiller()) {
- InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc,
- true);
- InitializationSequence InitSeq(SemaRef, ElementEntity, Kind, None);
- if (!InitSeq) {
- InitSeq.Diagnose(SemaRef, ElementEntity, Kind, None);
- hadError = true;
- return;
- }
-
- ExprResult ElementInit
- = InitSeq.Perform(SemaRef, ElementEntity, Kind, None);
+ ExprResult ElementInit = PerformEmptyInit(SemaRef, ILE->getLocEnd(),
+ ElementEntity,
+ /*VerifyOnly*/false);
if (ElementInit.isInvalid()) {
hadError = true;
return;
@@ -527,29 +605,29 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
// For arrays, just set the expression used for value-initialization
// of the "holes" in the array.
if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement)
- ILE->setArrayFiller(ElementInit.takeAs<Expr>());
+ ILE->setArrayFiller(ElementInit.getAs<Expr>());
else
- ILE->setInit(Init, ElementInit.takeAs<Expr>());
+ ILE->setInit(Init, ElementInit.getAs<Expr>());
} else {
// For arrays, just set the expression used for value-initialization
// of the rest of elements and exit.
if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement) {
- ILE->setArrayFiller(ElementInit.takeAs<Expr>());
+ ILE->setArrayFiller(ElementInit.getAs<Expr>());
return;
}
- if (InitSeq.isConstructorInitialization()) {
- // Value-initialization requires a constructor call, so
+ if (!isa<ImplicitValueInitExpr>(ElementInit.get())) {
+ // Empty initialization requires a constructor call, so
// extend the initializer list to include the constructor
// call and make a note that we'll need to take another pass
// through the initializer list.
- ILE->updateInit(SemaRef.Context, Init, ElementInit.takeAs<Expr>());
+ ILE->updateInit(SemaRef.Context, Init, ElementInit.getAs<Expr>());
RequiresSecondPass = true;
}
}
} else if (InitListExpr *InnerILE
= dyn_cast_or_null<InitListExpr>(InitExpr))
- FillInValueInitializations(ElementEntity, InnerILE, RequiresSecondPass);
+ FillInEmptyInitializations(ElementEntity, InnerILE, RequiresSecondPass);
}
}
@@ -561,15 +639,15 @@ InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
hadError = false;
FullyStructuredList =
- getStructuredSubobjectInit(IL, 0, T, 0, 0, IL->getSourceRange());
+ getStructuredSubobjectInit(IL, 0, T, nullptr, 0, IL->getSourceRange());
CheckExplicitInitList(Entity, IL, T, FullyStructuredList,
/*TopLevelObject=*/true);
if (!hadError && !VerifyOnly) {
bool RequiresSecondPass = false;
- FillInValueInitializations(Entity, FullyStructuredList, RequiresSecondPass);
+ FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass);
if (RequiresSecondPass && !hadError)
- FillInValueInitializations(Entity, FullyStructuredList,
+ FillInEmptyInitializations(Entity, FullyStructuredList,
RequiresSecondPass);
}
}
@@ -587,13 +665,10 @@ int InitListChecker::numArrayElements(QualType DeclType) {
int InitListChecker::numStructUnionElements(QualType DeclType) {
RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl();
int InitializableMembers = 0;
- for (RecordDecl::field_iterator
- Field = structDecl->field_begin(),
- FieldEnd = structDecl->field_end();
- Field != FieldEnd; ++Field) {
+ for (const auto *Field : structDecl->fields())
if (!Field->isUnnamedBitfield())
++InitializableMembers;
- }
+
if (structDecl->isUnion())
return std::min(InitializableMembers, 1);
return InitializableMembers - structDecl->hasFlexibleArrayMember();
@@ -661,13 +736,13 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
if (T->isArrayType() || T->isRecordType()) {
SemaRef.Diag(StructuredSubobjectInitList->getLocStart(),
diag::warn_missing_braces)
- << StructuredSubobjectInitList->getSourceRange()
- << FixItHint::CreateInsertion(
- StructuredSubobjectInitList->getLocStart(), "{")
- << FixItHint::CreateInsertion(
- SemaRef.PP.getLocForEndOfToken(
- StructuredSubobjectInitList->getLocEnd()),
- "}");
+ << StructuredSubobjectInitList->getSourceRange()
+ << FixItHint::CreateInsertion(
+ StructuredSubobjectInitList->getLocStart(), "{")
+ << FixItHint::CreateInsertion(
+ SemaRef.getLocForEndOfToken(
+ StructuredSubobjectInitList->getLocEnd()),
+ "}");
}
}
}
@@ -681,7 +756,6 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
InitListExpr *IList, QualType &T,
InitListExpr *StructuredList,
bool TopLevelObject) {
- assert(IList->isExplicit() && "Illegal Implicit InitListExpr");
if (!VerifyOnly) {
SyntacticToSemantic[IList] = StructuredList;
StructuredList->setSyntacticForm(IList);
@@ -714,7 +788,7 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
if (StructuredIndex == 1 &&
IsStringInit(StructuredList->getInit(0), T, SemaRef.Context) ==
SIF_None) {
- unsigned DK = diag::warn_excess_initializers_in_char_array_initializer;
+ unsigned DK = diag::ext_excess_initializers_in_char_array_initializer;
if (SemaRef.getLangOpts().CPlusPlus) {
DK = diag::err_excess_initializers_in_char_array_initializer;
hadError = true;
@@ -733,7 +807,7 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
CurrentObjectType->isUnionType()? 3 :
4;
- unsigned DK = diag::warn_excess_initializers;
+ unsigned DK = diag::ext_excess_initializers;
if (SemaRef.getLangOpts().CPlusPlus) {
DK = diag::err_excess_initializers;
hadError = true;
@@ -840,6 +914,15 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
assert(SemaRef.getLangOpts().CPlusPlus &&
"non-aggregate records are only possible in C++");
// C++ initialization is handled later.
+ } else if (isa<ImplicitValueInitExpr>(expr)) {
+ // This happens during template instantiation when we see an InitListExpr
+ // that we've already checked once.
+ assert(SemaRef.Context.hasSameType(expr->getType(), ElemType) &&
+ "found implicit initialization for the wrong type");
+ if (!VerifyOnly)
+ UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+ ++Index;
+ return;
}
// FIXME: Need to handle atomic aggregate types with implicit init lists.
@@ -886,7 +969,7 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
hadError = true;
UpdateStructuredListElement(StructuredList, StructuredIndex,
- Result.takeAs<Expr>());
+ Result.getAs<Expr>());
}
++Index;
return;
@@ -902,7 +985,7 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// compatible structure or union type. In the latter case, the
// initial value of the object, including unnamed members, is
// that of the expression.
- ExprResult ExprRes = SemaRef.Owned(expr);
+ ExprResult ExprRes = expr;
if ((ElemType->isRecordType() || ElemType->isVectorType()) &&
SemaRef.CheckSingleAssignmentConstraints(ElemType, ExprRes,
!VerifyOnly)
@@ -910,16 +993,16 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
if (ExprRes.isInvalid())
hadError = true;
else {
- ExprRes = SemaRef.DefaultFunctionArrayLvalueConversion(ExprRes.take());
+ ExprRes = SemaRef.DefaultFunctionArrayLvalueConversion(ExprRes.get());
if (ExprRes.isInvalid())
hadError = true;
}
UpdateStructuredListElement(StructuredList, StructuredIndex,
- ExprRes.takeAs<Expr>());
+ ExprRes.getAs<Expr>());
++Index;
return;
}
- ExprRes.release();
+ ExprRes.get();
// Fall through for subaggregate initialization
}
@@ -938,8 +1021,7 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
if (!VerifyOnly) {
// We cannot initialize this element, so let
// PerformCopyInitialization produce the appropriate diagnostic.
- SemaRef.PerformCopyInitialization(Entity, SourceLocation(),
- SemaRef.Owned(expr),
+ SemaRef.PerformCopyInitialization(Entity, SourceLocation(), expr,
/*TopLevelOfInitList=*/true);
}
hadError = true;
@@ -1005,9 +1087,11 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
Expr *expr = IList->getInit(Index);
if (InitListExpr *SubIList = dyn_cast<InitListExpr>(expr)) {
+ // FIXME: This is invalid, and accepting it causes overload resolution
+ // to pick the wrong overload in some corner cases.
if (!VerifyOnly)
SemaRef.Diag(SubIList->getLocStart(),
- diag::warn_many_braces_around_scalar_init)
+ diag::ext_many_braces_around_scalar_init)
<< SubIList->getSourceRange();
CheckScalarType(Entity, SubIList, DeclType, Index, StructuredList,
@@ -1025,23 +1109,22 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
}
if (VerifyOnly) {
- if (!SemaRef.CanPerformCopyInitialization(Entity, SemaRef.Owned(expr)))
+ if (!SemaRef.CanPerformCopyInitialization(Entity,expr))
hadError = true;
++Index;
return;
}
ExprResult Result =
- SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(),
- SemaRef.Owned(expr),
+ SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(), expr,
/*TopLevelOfInitList=*/true);
- Expr *ResultExpr = 0;
+ Expr *ResultExpr = nullptr;
if (Result.isInvalid())
hadError = true; // types weren't compatible.
else {
- ResultExpr = Result.takeAs<Expr>();
+ ResultExpr = Result.getAs<Expr>();
if (ResultExpr != expr) {
// The type was promoted, update initializer list.
@@ -1088,21 +1171,20 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity,
}
if (VerifyOnly) {
- if (!SemaRef.CanPerformCopyInitialization(Entity, SemaRef.Owned(expr)))
+ if (!SemaRef.CanPerformCopyInitialization(Entity,expr))
hadError = true;
++Index;
return;
}
ExprResult Result =
- SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(),
- SemaRef.Owned(expr),
- /*TopLevelOfInitList=*/true);
+ SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(), expr,
+ /*TopLevelOfInitList=*/true);
if (Result.isInvalid())
hadError = true;
- expr = Result.takeAs<Expr>();
+ expr = Result.getAs<Expr>();
IList->setInit(Index, expr);
if (hadError)
@@ -1125,8 +1207,9 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
if (Index >= IList->getNumInits()) {
// Make sure the element type can be value-initialized.
if (VerifyOnly)
- CheckValueInitializable(
- InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity));
+ CheckEmptyInitializable(
+ InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity),
+ IList->getLocEnd());
return;
}
@@ -1136,22 +1219,21 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
Expr *Init = IList->getInit(Index);
if (!isa<InitListExpr>(Init) && Init->getType()->isVectorType()) {
if (VerifyOnly) {
- if (!SemaRef.CanPerformCopyInitialization(Entity, SemaRef.Owned(Init)))
+ if (!SemaRef.CanPerformCopyInitialization(Entity, Init))
hadError = true;
++Index;
return;
}
- ExprResult Result =
- SemaRef.PerformCopyInitialization(Entity, Init->getLocStart(),
- SemaRef.Owned(Init),
- /*TopLevelOfInitList=*/true);
+ ExprResult Result =
+ SemaRef.PerformCopyInitialization(Entity, Init->getLocStart(), Init,
+ /*TopLevelOfInitList=*/true);
- Expr *ResultExpr = 0;
+ Expr *ResultExpr = nullptr;
if (Result.isInvalid())
hadError = true; // types weren't compatible.
else {
- ResultExpr = Result.takeAs<Expr>();
+ ResultExpr = Result.getAs<Expr>();
if (ResultExpr != Init) {
// The type was promoted, update initializer list.
@@ -1174,7 +1256,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
// Don't attempt to go past the end of the init list
if (Index >= IList->getNumInits()) {
if (VerifyOnly)
- CheckValueInitializable(ElementEntity);
+ CheckEmptyInitializable(ElementEntity, IList->getLocEnd());
break;
}
@@ -1182,6 +1264,46 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
CheckSubElementType(ElementEntity, IList, elementType, Index,
StructuredList, StructuredIndex);
}
+
+ if (VerifyOnly)
+ return;
+
+ bool isBigEndian = SemaRef.Context.getTargetInfo().isBigEndian();
+ const VectorType *T = Entity.getType()->getAs<VectorType>();
+ if (isBigEndian && (T->getVectorKind() == VectorType::NeonVector ||
+ T->getVectorKind() == VectorType::NeonPolyVector)) {
+ // The ability to use vector initializer lists is a GNU vector extension
+ // and is unrelated to the NEON intrinsics in arm_neon.h. On little
+ // endian machines it works fine, however on big endian machines it
+ // exhibits surprising behaviour:
+ //
+ // uint32x2_t x = {42, 64};
+ // return vget_lane_u32(x, 0); // Will return 64.
+ //
+ // Because of this, explicitly call out that it is non-portable.
+ //
+ SemaRef.Diag(IList->getLocStart(),
+ diag::warn_neon_vector_initializer_non_portable);
+
+ const char *typeCode;
+ unsigned typeSize = SemaRef.Context.getTypeSize(elementType);
+
+ if (elementType->isFloatingType())
+ typeCode = "f";
+ else if (elementType->isSignedIntegerType())
+ typeCode = "s";
+ else if (elementType->isUnsignedIntegerType())
+ typeCode = "u";
+ else
+ llvm_unreachable("Invalid element type!");
+
+ SemaRef.Diag(IList->getLocStart(),
+ SemaRef.Context.getTypeSize(VT) > 64 ?
+ diag::note_neon_vector_initializer_non_portable_q :
+ diag::note_neon_vector_initializer_non_portable)
+ << typeCode << typeSize;
+ }
+
return;
}
@@ -1293,7 +1415,7 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
// Handle this designated initializer. elementIndex will be
// updated to be the next array element we'll initialize.
if (CheckDesignatedInitializer(Entity, IList, DIE, 0,
- DeclType, 0, &elementIndex, Index,
+ DeclType, nullptr, &elementIndex, Index,
StructuredList, StructuredIndex, true,
false)) {
hadError = true;
@@ -1351,8 +1473,9 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
// If so, check if doing that is possible.
// FIXME: This needs to detect holes left by designated initializers too.
if (maxElementsKnown && elementIndex < maxElements)
- CheckValueInitializable(InitializedEntity::InitializeElement(
- SemaRef.Context, 0, Entity));
+ CheckEmptyInitializable(InitializedEntity::InitializeElement(
+ SemaRef.Context, 0, Entity),
+ IList->getLocEnd());
}
}
@@ -1437,8 +1560,9 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
Field != FieldEnd; ++Field) {
if (Field->getDeclName()) {
if (VerifyOnly)
- CheckValueInitializable(
- InitializedEntity::InitializeMember(*Field, &Entity));
+ CheckEmptyInitializable(
+ InitializedEntity::InitializeMember(*Field, &Entity),
+ IList->getLocEnd());
else
StructuredList->setInitializedFieldInUnion(*Field);
break;
@@ -1468,7 +1592,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
// Handle this designated initializer. Field will be updated to
// the next field that we'll be initializing.
if (CheckDesignatedInitializer(Entity, IList, DIE, 0,
- DeclType, &Field, 0, Index,
+ DeclType, &Field, nullptr, Index,
StructuredList, StructuredIndex,
true, TopLevelObject))
hadError = true;
@@ -1538,7 +1662,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
it != end; ++it) {
if (!it->isUnnamedBitfield() && !it->hasInClassInitializer()) {
SemaRef.Diag(IList->getSourceRange().getEnd(),
- diag::warn_missing_field_initializers) << it->getName();
+ diag::warn_missing_field_initializers) << *it;
break;
}
}
@@ -1550,8 +1674,9 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
// FIXME: Should check for holes left by designated initializers too.
for (; Field != FieldEnd && !hadError; ++Field) {
if (!Field->isUnnamedBitfield() && !Field->hasInClassInitializer())
- CheckValueInitializable(
- InitializedEntity::InitializeMember(*Field, &Entity));
+ CheckEmptyInitializable(
+ InitializedEntity::InitializeMember(*Field, &Entity),
+ IList->getLocEnd());
}
}
@@ -1592,12 +1717,12 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
for (IndirectFieldDecl::chain_iterator PI = IndirectField->chain_begin(),
PE = IndirectField->chain_end(); PI != PE; ++PI) {
if (PI + 1 == PE)
- Replacements.push_back(Designator((IdentifierInfo *)0,
+ Replacements.push_back(Designator((IdentifierInfo *)nullptr,
DIE->getDesignator(DesigIdx)->getDotLoc(),
DIE->getDesignator(DesigIdx)->getFieldLoc()));
else
- Replacements.push_back(Designator((IdentifierInfo *)0, SourceLocation(),
- SourceLocation()));
+ Replacements.push_back(Designator((IdentifierInfo *)nullptr,
+ SourceLocation(), SourceLocation()));
assert(isa<FieldDecl>(*PI));
Replacements.back().setField(cast<FieldDecl>(*PI));
}
@@ -1614,7 +1739,7 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef,
static IndirectFieldDecl *FindIndirectFieldDesignator(FieldDecl *AnonField,
IdentifierInfo *FieldName) {
if (!FieldName)
- return 0;
+ return nullptr;
assert(AnonField->isAnonymousStructOrUnion());
Decl *NextDecl = AnonField->getNextDeclInContext();
@@ -1624,7 +1749,7 @@ static IndirectFieldDecl *FindIndirectFieldDesignator(FieldDecl *AnonField,
return IF;
NextDecl = NextDecl->getNextDeclInContext();
}
- return 0;
+ return nullptr;
}
static DesignatedInitExpr *CloneDesignatedInitExpr(Sema &SemaRef,
@@ -1648,7 +1773,7 @@ class FieldInitializerValidatorCCC : public CorrectionCandidateCallback {
explicit FieldInitializerValidatorCCC(RecordDecl *RD)
: Record(RD) {}
- virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ bool ValidateCandidate(const TypoCorrection &candidate) override {
FieldDecl *FD = candidate.getCorrectionDeclAs<FieldDecl>();
return FD && FD->getDeclContext()->getRedeclContext()->Equals(Record);
}
@@ -1813,15 +1938,15 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// may find nothing, or may find a member of an anonymous
// struct/union.
DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
- FieldDecl *ReplacementField = 0;
+ FieldDecl *ReplacementField = nullptr;
if (Lookup.empty()) {
// Name lookup didn't find anything. Determine whether this
// was a typo for another field name.
FieldInitializerValidatorCCC Validator(RT->getDecl());
if (TypoCorrection Corrected = SemaRef.CorrectTypo(
DeclarationNameInfo(FieldName, D->getFieldLoc()),
- Sema::LookupMemberName, /*Scope=*/ 0, /*SS=*/ 0, Validator,
- RT->getDecl())) {
+ Sema::LookupMemberName, /*Scope=*/ nullptr, /*SS=*/ nullptr,
+ Validator, Sema::CTK_ErrorRecovery, RT->getDecl())) {
SemaRef.diagnoseTypo(
Corrected,
SemaRef.PDiag(diag::err_field_designator_unknown_suggest)
@@ -1886,7 +2011,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// remove existing initializer
StructuredList->resizeInits(SemaRef.Context, 0);
- StructuredList->setInitializedFieldInUnion(0);
+ StructuredList->setInitializedFieldInUnion(nullptr);
}
StructuredList->setInitializedFieldInUnion(*Field);
@@ -1984,7 +2109,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
InitializedEntity MemberEntity =
InitializedEntity::InitializeMember(*Field, &Entity);
if (CheckDesignatedInitializer(MemberEntity, IList, DIE, DesigIdx + 1,
- FieldType, 0, 0, Index,
+ FieldType, nullptr, nullptr, Index,
StructuredList, newStructuredIndex,
true, false))
return true;
@@ -2043,7 +2168,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
return true;
}
- Expr *IndexExpr = 0;
+ Expr *IndexExpr = nullptr;
llvm::APSInt DesignatedStartIndex, DesignatedEndIndex;
if (D->isArrayDesignator()) {
IndexExpr = DIE->getArrayIndex(*D);
@@ -2128,7 +2253,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
Context, CodeUnit, PromotedCharTy, SubExpr->getExprLoc());
if (CharTy != PromotedCharTy)
Init = ImplicitCastExpr::Create(Context, CharTy, CK_IntegralCast,
- Init, 0, VK_RValue);
+ Init, nullptr, VK_RValue);
StructuredList->updateInit(Context, i, Init);
}
} else {
@@ -2150,7 +2275,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
Context, CodeUnit, PromotedCharTy, SubExpr->getExprLoc());
if (CharTy != PromotedCharTy)
Init = ImplicitCastExpr::Create(Context, CharTy, CK_IntegralCast,
- Init, 0, VK_RValue);
+ Init, nullptr, VK_RValue);
StructuredList->updateInit(Context, i, Init);
}
}
@@ -2180,7 +2305,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
ElementEntity.setElementIndex(ElementIndex);
if (CheckDesignatedInitializer(ElementEntity, IList, DIE, DesigIdx + 1,
- ElementType, 0, 0, Index,
+ ElementType, nullptr, nullptr, Index,
StructuredList, ElementIndex,
(DesignatedStartIndex == DesignatedEndIndex),
false))
@@ -2220,8 +2345,8 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
unsigned StructuredIndex,
SourceRange InitRange) {
if (VerifyOnly)
- return 0; // No structured list in verification-only mode.
- Expr *ExistingInit = 0;
+ return nullptr; // No structured list in verification-only mode.
+ Expr *ExistingInit = nullptr;
if (!StructuredList)
ExistingInit = SyntacticToSemantic.lookup(IList);
else if (StructuredIndex < StructuredList->getNumInits())
@@ -2291,8 +2416,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
if (RDecl->isUnion())
NumElements = 1;
else
- NumElements = std::distance(RDecl->field_begin(),
- RDecl->field_end());
+ NumElements = std::distance(RDecl->field_begin(), RDecl->field_end());
}
Result->reserveInits(SemaRef.Context, NumElements);
@@ -2380,7 +2504,7 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
Expr *Index = static_cast<Expr *>(D.getArrayIndex());
llvm::APSInt IndexValue;
if (!Index->isTypeDependent() && !Index->isValueDependent())
- Index = CheckArrayDesignatorExpr(*this, Index, IndexValue).take();
+ Index = CheckArrayDesignatorExpr(*this, Index, IndexValue).get();
if (!Index)
Invalid = true;
else {
@@ -2403,9 +2527,9 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
EndIndex->isValueDependent();
if (!StartDependent)
StartIndex =
- CheckArrayDesignatorExpr(*this, StartIndex, StartValue).take();
+ CheckArrayDesignatorExpr(*this, StartIndex, StartValue).get();
if (!EndDependent)
- EndIndex = CheckArrayDesignatorExpr(*this, EndIndex, EndValue).take();
+ EndIndex = CheckArrayDesignatorExpr(*this, EndIndex, EndValue).get();
if (!StartIndex || !EndIndex)
Invalid = true;
@@ -2447,13 +2571,13 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
= DesignatedInitExpr::Create(Context,
Designators.data(), Designators.size(),
InitExpressions, Loc, GNUSyntax,
- Init.takeAs<Expr>());
+ Init.getAs<Expr>());
if (!getLangOpts().C99)
Diag(DIE->getLocStart(), diag::ext_designated_init)
<< DIE->getSourceRange();
- return Owned(DIE);
+ return DIE;
}
//===----------------------------------------------------------------------===//
@@ -2484,7 +2608,7 @@ InitializedEntity::InitializeBase(ASTContext &Context,
bool IsInheritedVirtualBase) {
InitializedEntity Result;
Result.Kind = EK_Base;
- Result.Parent = 0;
+ Result.Parent = nullptr;
Result.Base = reinterpret_cast<uintptr_t>(Base);
if (IsInheritedVirtualBase)
Result.Base |= 0x01;
@@ -2549,7 +2673,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const {
case EK_LambdaCapture:
case EK_CompoundLiteralInit:
case EK_RelatedResult:
- return 0;
+ return nullptr;
}
llvm_unreachable("Invalid EntityKind!");
@@ -2643,12 +2767,13 @@ void InitializationSequence::Step::Destroy() {
case SK_QualificationConversionRValue:
case SK_QualificationConversionXValue:
case SK_QualificationConversionLValue:
+ case SK_AtomicConversion:
case SK_LValueToRValue:
case SK_ListInitialization:
- case SK_ListConstructorCall:
case SK_UnwrapInitList:
case SK_RewrapInitList:
case SK_ConstructorInitialization:
+ case SK_ConstructorInitializationFromList:
case SK_ZeroInitialization:
case SK_CAssignment:
case SK_StringInit:
@@ -2659,6 +2784,7 @@ void InitializationSequence::Step::Destroy() {
case SK_PassByIndirectRestore:
case SK_ProduceObjCObject:
case SK_StdInitializerList:
+ case SK_StdInitializerListConstructorCall:
case SK_OCLSamplerInit:
case SK_OCLZeroEvent:
break;
@@ -2794,6 +2920,13 @@ void InitializationSequence::AddQualificationConversionStep(QualType Ty,
Steps.push_back(S);
}
+void InitializationSequence::AddAtomicConversionStep(QualType Ty) {
+ Step S;
+ S.Kind = SK_AtomicConversion;
+ S.Type = Ty;
+ Steps.push_back(S);
+}
+
void InitializationSequence::AddLValueToRValueStep(QualType Ty) {
assert(!Ty.hasQualifiers() && "rvalues may not have qualifiers");
@@ -2829,8 +2962,9 @@ InitializationSequence
bool HadMultipleCandidates,
bool FromInitList, bool AsInitList) {
Step S;
- S.Kind = FromInitList && !AsInitList ? SK_ListConstructorCall
- : SK_ConstructorInitialization;
+ S.Kind = FromInitList ? AsInitList ? SK_StdInitializerListConstructorCall
+ : SK_ConstructorInitializationFromList
+ : SK_ConstructorInitialization;
S.Type = T;
S.Function.HadMultipleCandidates = HadMultipleCandidates;
S.Function.Function = Constructor;
@@ -3026,7 +3160,7 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
bool SuppressUserConversions = false;
// Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = 0;
+ CXXConstructorDecl *Constructor = nullptr;
FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D);
if (ConstructorTmpl)
Constructor = cast<CXXConstructorDecl>(
@@ -3057,7 +3191,7 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
(!OnlyListConstructors || S.isInitListConstructor(Constructor))) {
if (ConstructorTmpl)
S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
- /*ExplicitArgs*/ 0, Args,
+ /*ExplicitArgs*/ nullptr, Args,
CandidateSet, SuppressUserConversions);
else {
// C++ [over.match.copy]p1:
@@ -3243,7 +3377,7 @@ static void TryValueInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
InitializationSequence &Sequence,
- InitListExpr *InitList = 0);
+ InitListExpr *InitList = nullptr);
/// \brief Attempt list initialization of a reference.
static void TryReferenceListInitialization(Sema &S,
@@ -3442,7 +3576,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
bool AllowExplicit = Kind.AllowExplicit();
bool AllowExplicitConvs = Kind.allowExplicitConversionFunctionsInRefBinding();
- const RecordType *T1RecordType = 0;
+ const RecordType *T1RecordType = nullptr;
if (AllowRValues && (T1RecordType = T1->getAs<RecordType>()) &&
!S.RequireCompleteType(Kind.getLocation(), T1, 0)) {
// The type we're converting to is a class type. Enumerate its constructors
@@ -3460,7 +3594,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
// Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = 0;
+ CXXConstructorDecl *Constructor = nullptr;
FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D);
if (ConstructorTmpl)
Constructor = cast<CXXConstructorDecl>(
@@ -3472,7 +3606,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
Constructor->isConvertingConstructor(AllowExplicit)) {
if (ConstructorTmpl)
S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
- /*ExplicitArgs*/ 0,
+ /*ExplicitArgs*/ nullptr,
Initializer, CandidateSet,
/*SuppressUserConversions=*/true);
else
@@ -3485,7 +3619,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
if (T1RecordType && T1RecordType->getDecl()->isInvalidDecl())
return OR_No_Viable_Function;
- const RecordType *T2RecordType = 0;
+ const RecordType *T2RecordType = nullptr;
if ((T2RecordType = T2->getAs<RecordType>()) &&
!S.RequireCompleteType(Kind.getLocation(), T2, 0)) {
// The type we're converting from is a class type, enumerate its conversion
@@ -3520,10 +3654,13 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
if (ConvTemplate)
S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
ActingDC, Initializer,
- DestType, CandidateSet);
+ DestType, CandidateSet,
+ /*AllowObjCConversionOnExplicit=*/
+ false);
else
S.AddConversionCandidate(Conv, I.getPair(), ActingDC,
- Initializer, DestType, CandidateSet);
+ Initializer, DestType, CandidateSet,
+ /*AllowObjCConversionOnExplicit=*/false);
}
}
}
@@ -3545,7 +3682,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
// Compute the returned type of the conversion.
if (isa<CXXConversionDecl>(Function))
- T2 = Function->getResultType();
+ T2 = Function->getReturnType();
else
T2 = cv1T1;
@@ -4045,12 +4182,11 @@ static void TryDefaultInitialization(Sema &S,
/// which enumerates all conversion functions and performs overload resolution
/// to select the best.
static void TryUserDefinedConversion(Sema &S,
- const InitializedEntity &Entity,
+ QualType DestType,
const InitializationKind &Kind,
Expr *Initializer,
InitializationSequence &Sequence,
bool TopLevelOfInitList) {
- QualType DestType = Entity.getType();
assert(!DestType->isReferenceType() && "References are handled elsewhere");
QualType SourceType = Initializer->getType();
assert((DestType->isRecordType() || SourceType->isRecordType()) &&
@@ -4085,7 +4221,7 @@ static void TryUserDefinedConversion(Sema &S,
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
// Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = 0;
+ CXXConstructorDecl *Constructor = nullptr;
FunctionTemplateDecl *ConstructorTmpl
= dyn_cast<FunctionTemplateDecl>(D);
if (ConstructorTmpl)
@@ -4098,7 +4234,7 @@ static void TryUserDefinedConversion(Sema &S,
Constructor->isConvertingConstructor(AllowExplicit)) {
if (ConstructorTmpl)
S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
- /*ExplicitArgs*/ 0,
+ /*ExplicitArgs*/ nullptr,
Initializer, CandidateSet,
/*SuppressUserConversions=*/true);
else
@@ -4143,10 +4279,11 @@ static void TryUserDefinedConversion(Sema &S,
if (ConvTemplate)
S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
ActingDC, Initializer, DestType,
- CandidateSet);
+ CandidateSet, AllowExplicit);
else
S.AddConversionCandidate(Conv, I.getPair(), ActingDC,
- Initializer, DestType, CandidateSet);
+ Initializer, DestType, CandidateSet,
+ AllowExplicit);
}
}
}
@@ -4413,7 +4550,7 @@ InitializationSequence::InitializationSequence(Sema &S,
const InitializationKind &Kind,
MultiExprArg Args,
bool TopLevelOfInitList)
- : FailedCandidateSet(Kind.getLocation()) {
+ : FailedCandidateSet(Kind.getLocation(), OverloadCandidateSet::CSK_Normal) {
InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList);
}
@@ -4436,7 +4573,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
SetFailed(FK_PlaceholderType);
return;
}
- Args[I] = result.take();
+ Args[I] = result.get();
}
// C++0x [dcl.init]p16:
@@ -4457,9 +4594,16 @@ void InitializationSequence::InitializeFrom(Sema &S,
setSequenceKind(NormalSequence);
QualType SourceType;
- Expr *Initializer = 0;
+ Expr *Initializer = nullptr;
if (Args.size() == 1) {
Initializer = Args[0];
+ if (S.getLangOpts().ObjC1) {
+ if (S.CheckObjCBridgeRelatedConversions(Initializer->getLocStart(),
+ DestType, Initializer->getType(),
+ Initializer) ||
+ S.ConversionToObjCStringLiteralCheck(DestType, Initializer))
+ Args[0] = Initializer;
+ }
if (!isa<InitListExpr>(Initializer))
SourceType = Initializer->getType();
}
@@ -4603,7 +4747,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
(Context.hasSameUnqualifiedType(SourceType, DestType) ||
S.IsDerivedFrom(SourceType, DestType))))
TryConstructorInitialization(S, Entity, Kind, Args,
- Entity.getType(), *this);
+ DestType, *this);
// - Otherwise (i.e., for the remaining copy-initialization cases),
// user-defined conversion sequences that can convert from the source
// type to the destination type or (when a conversion function is
@@ -4611,7 +4755,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
// 13.3.1.4, and the best one is chosen through overload resolution
// (13.3).
else
- TryUserDefinedConversion(S, Entity, Kind, Initializer, *this,
+ TryUserDefinedConversion(S, DestType, Kind, Initializer, *this,
TopLevelOfInitList);
return;
}
@@ -4625,9 +4769,22 @@ void InitializationSequence::InitializeFrom(Sema &S,
// - Otherwise, if the source type is a (possibly cv-qualified) class
// type, conversion functions are considered.
if (!SourceType.isNull() && SourceType->isRecordType()) {
- TryUserDefinedConversion(S, Entity, Kind, Initializer, *this,
+ // For a conversion to _Atomic(T) from either T or a class type derived
+ // from T, initialize the T object then convert to _Atomic type.
+ bool NeedAtomicConversion = false;
+ if (const AtomicType *Atomic = DestType->getAs<AtomicType>()) {
+ if (Context.hasSameUnqualifiedType(SourceType, Atomic->getValueType()) ||
+ S.IsDerivedFrom(SourceType, Atomic->getValueType())) {
+ DestType = Atomic->getValueType();
+ NeedAtomicConversion = true;
+ }
+ }
+
+ TryUserDefinedConversion(S, DestType, Kind, Initializer, *this,
TopLevelOfInitList);
MaybeProduceObjCObject(S, *this, Entity);
+ if (!Failed() && NeedAtomicConversion)
+ AddAtomicConversionStep(Entity.getType());
return;
}
@@ -4636,16 +4793,16 @@ void InitializationSequence::InitializeFrom(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.
-
+
ImplicitConversionSequence ICS
- = S.TryImplicitConversion(Initializer, Entity.getType(),
+ = S.TryImplicitConversion(Initializer, DestType,
/*SuppressUserConversions*/true,
/*AllowExplicitConversions*/ false,
/*InOverloadResolution*/ false,
/*CStyle=*/Kind.isCStyleOrFunctionalCast(),
allowObjCWritebackConversion);
-
- if (ICS.isStandard() &&
+
+ if (ICS.isStandard() &&
ICS.Standard.Second == ICK_Writeback_Conversion) {
// Objective-C ARC writeback conversion.
@@ -4666,7 +4823,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
AddConversionSequenceStep(LvalueICS, ICS.Standard.getToType(0));
}
- AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy);
+ AddPassByIndirectCopyRestoreStep(DestType, ShouldCopy);
} else if (ICS.isBad()) {
DeclAccessPair dap;
if (isLibstdcxxPointerReturnFalseHack(S, Entity, Initializer)) {
@@ -4678,7 +4835,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
else
SetFailed(InitializationSequence::FK_ConversionFailed);
} else {
- AddConversionSequenceStep(ICS, Entity.getType(), TopLevelOfInitList);
+ AddConversionSequenceStep(ICS, DestType, TopLevelOfInitList);
MaybeProduceObjCObject(S, *this, Entity);
}
@@ -4811,7 +4968,7 @@ static void LookupCopyAndMoveConstructors(Sema &S,
for (SmallVectorImpl<NamedDecl *>::iterator
CI = Ctors.begin(), CE = Ctors.end(); CI != CE; ++CI) {
NamedDecl *D = *CI;
- CXXConstructorDecl *Constructor = 0;
+ CXXConstructorDecl *Constructor = nullptr;
if ((Constructor = dyn_cast<CXXConstructorDecl>(D))) {
// Handle copy/moveconstructors, only.
@@ -4841,7 +4998,7 @@ static void LookupCopyAndMoveConstructors(Sema &S,
// candidates?
DeclAccessPair FoundDecl
= DeclAccessPair::make(ConstructorTmpl, ConstructorTmpl->getAccess());
- S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, 0,
+ S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, nullptr,
CurInitExpr, CandidateSet, true);
}
}
@@ -4907,7 +5064,7 @@ static ExprResult CopyObject(Sema &S,
bool IsExtraneousCopy) {
// Determine which class type we're copying to.
Expr *CurInitExpr = (Expr *)CurInit.get();
- CXXRecordDecl *Class = 0;
+ CXXRecordDecl *Class = nullptr;
if (const RecordType *Record = T->getAs<RecordType>())
Class = cast<CXXRecordDecl>(Record->getDecl());
if (!Class)
@@ -4939,7 +5096,7 @@ static ExprResult CopyObject(Sema &S,
// Only consider constructors and constructor templates. Per
// C++0x [dcl.init]p16, second bullet to class types, this initialization
// is direct-initialization.
- OverloadCandidateSet CandidateSet(Loc);
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
LookupCopyAndMoveConstructors(S, CandidateSet, Class, CurInitExpr);
bool HadMultipleCandidates = (CandidateSet.size() > 1);
@@ -4977,7 +5134,7 @@ static ExprResult CopyObject(Sema &S,
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function);
SmallVector<Expr*, 8> ConstructorArgs;
- CurInit.release(); // Ownership transferred into MultiExprArg, below.
+ CurInit.get(); // Ownership transferred into MultiExprArg, below.
S.CheckConstructorAccess(Loc, Constructor, Entity,
Best->FoundDecl.getAccess(), IsExtraneousCopy);
@@ -5005,7 +5162,7 @@ static ExprResult CopyObject(Sema &S,
S.BuildCXXDefaultArgExpr(Loc, Constructor, Parm);
}
- return S.Owned(CurInitExpr);
+ return CurInitExpr;
}
// Determine the arguments required to actually perform the
@@ -5019,13 +5176,14 @@ static ExprResult CopyObject(Sema &S,
ConstructorArgs,
HadMultipleCandidates,
/*ListInit*/ false,
+ /*StdInitListInit*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
// If we're supposed to bind temporaries, do so.
if (!CurInit.isInvalid() && shouldBindAsTemporary(Entity))
- CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+ CurInit = S.MaybeBindToTemporary(CurInit.getAs<Expr>());
return CurInit;
}
@@ -5042,12 +5200,11 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
return;
SourceLocation Loc = getInitializationLoc(Entity, CurInitExpr);
- if (S.Diags.getDiagnosticLevel(diag::warn_cxx98_compat_temp_copy, Loc)
- == DiagnosticsEngine::Ignored)
+ if (S.Diags.isIgnored(diag::warn_cxx98_compat_temp_copy, Loc))
return;
// Find constructors which would have been considered.
- OverloadCandidateSet CandidateSet(Loc);
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
LookupCopyAndMoveConstructors(
S, CandidateSet, cast<CXXRecordDecl>(Record->getDecl()), CurInitExpr);
@@ -5141,6 +5298,7 @@ PerformConstructorInitialization(Sema &S,
const InitializationSequence::Step& Step,
bool &ConstructorInitRequiresZeroInit,
bool IsListInitialization,
+ bool IsStdInitListInitialization,
SourceLocation LBraceLoc,
SourceLocation RBraceLoc) {
unsigned NumArgs = Args.size();
@@ -5164,7 +5322,7 @@ PerformConstructorInitialization(Sema &S,
S.DefineImplicitDefaultConstructor(Loc, Constructor);
}
- ExprResult CurInit = S.Owned((Expr *)0);
+ ExprResult CurInit((Expr *)nullptr);
// C++ [over.match.copy]p1:
// - When initializing a temporary to be bound to the first parameter
@@ -5199,13 +5357,10 @@ PerformConstructorInitialization(Sema &S,
? SourceRange(LBraceLoc, RBraceLoc)
: Kind.getParenRange();
- CurInit = S.Owned(
- new (S.Context) CXXTemporaryObjectExpr(S.Context, Constructor,
- TSInfo, ConstructorArgs,
- ParenOrBraceRange,
- HadMultipleCandidates,
- IsListInitialization,
- ConstructorInitRequiresZeroInit));
+ CurInit = new (S.Context) CXXTemporaryObjectExpr(
+ S.Context, Constructor, TSInfo, ConstructorArgs, ParenOrBraceRange,
+ HadMultipleCandidates, IsListInitialization,
+ IsStdInitListInitialization, ConstructorInitRequiresZeroInit);
} else {
CXXConstructExpr::ConstructionKind ConstructKind =
CXXConstructExpr::CK_Complete;
@@ -5218,10 +5373,13 @@ PerformConstructorInitialization(Sema &S,
ConstructKind = CXXConstructExpr::CK_Delegating;
}
- // Only get the parenthesis range if it is a direct construction.
- SourceRange parenRange =
- Kind.getKind() == InitializationKind::IK_Direct ?
- Kind.getParenRange() : SourceRange();
+ // Only get the parenthesis or brace range if it is a list initialization or
+ // direct construction.
+ SourceRange ParenOrBraceRange;
+ if (IsListInitialization)
+ ParenOrBraceRange = SourceRange(LBraceLoc, RBraceLoc);
+ else if (Kind.getKind() == InitializationKind::IK_Direct)
+ ParenOrBraceRange = Kind.getParenRange();
// If the entity allows NRVO, mark the construction as elidable
// unconditionally.
@@ -5231,18 +5389,20 @@ PerformConstructorInitialization(Sema &S,
ConstructorArgs,
HadMultipleCandidates,
IsListInitialization,
+ IsStdInitListInitialization,
ConstructorInitRequiresZeroInit,
ConstructKind,
- parenRange);
+ ParenOrBraceRange);
else
CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
Constructor,
ConstructorArgs,
HadMultipleCandidates,
IsListInitialization,
+ IsStdInitListInitialization,
ConstructorInitRequiresZeroInit,
ConstructKind,
- parenRange);
+ ParenOrBraceRange);
}
if (CurInit.isInvalid())
return ExprError();
@@ -5254,7 +5414,7 @@ PerformConstructorInitialization(Sema &S,
return ExprError();
if (shouldBindAsTemporary(Entity))
- CurInit = S.MaybeBindToTemporary(CurInit.take());
+ CurInit = S.MaybeBindToTemporary(CurInit.get());
return CurInit;
}
@@ -5302,25 +5462,25 @@ InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) {
/// Determine the declaration which an initialized entity ultimately refers to,
/// for the purpose of lifetime-extending a temporary bound to a reference in
/// the initialization of \p Entity.
-static const ValueDecl *
-getDeclForTemporaryLifetimeExtension(const InitializedEntity &Entity,
- const ValueDecl *FallbackDecl = 0) {
+static const InitializedEntity *getEntityForTemporaryLifetimeExtension(
+ const InitializedEntity *Entity,
+ const InitializedEntity *FallbackDecl = nullptr) {
// C++11 [class.temporary]p5:
- switch (Entity.getKind()) {
+ switch (Entity->getKind()) {
case InitializedEntity::EK_Variable:
// The temporary [...] persists for the lifetime of the reference
- return Entity.getDecl();
+ return Entity;
case InitializedEntity::EK_Member:
// For subobjects, we look at the complete object.
- if (Entity.getParent())
- return getDeclForTemporaryLifetimeExtension(*Entity.getParent(),
- Entity.getDecl());
+ if (Entity->getParent())
+ return getEntityForTemporaryLifetimeExtension(Entity->getParent(),
+ Entity);
// except:
// -- A temporary bound to a reference member in a constructor's
// ctor-initializer persists until the constructor exits.
- return Entity.getDecl();
+ return Entity;
case InitializedEntity::EK_Parameter:
case InitializedEntity::EK_Parameter_CF_Audited:
@@ -5335,7 +5495,7 @@ getDeclForTemporaryLifetimeExtension(const InitializedEntity &Entity,
// -- A temporary bound to a reference in a new-initializer persists
// until the completion of the full-expression containing the
// new-initializer.
- return 0;
+ return nullptr;
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_CompoundLiteralInit:
@@ -5343,12 +5503,12 @@ getDeclForTemporaryLifetimeExtension(const InitializedEntity &Entity,
// We don't yet know the storage duration of the surrounding temporary.
// Assume it's got full-expression duration for now, it will patch up our
// storage duration if that's not correct.
- return 0;
+ return nullptr;
case InitializedEntity::EK_ArrayElement:
// For subobjects, we look at the complete object.
- return getDeclForTemporaryLifetimeExtension(*Entity.getParent(),
- FallbackDecl);
+ return getEntityForTemporaryLifetimeExtension(Entity->getParent(),
+ FallbackDecl);
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
@@ -5363,17 +5523,20 @@ getDeclForTemporaryLifetimeExtension(const InitializedEntity &Entity,
case InitializedEntity::EK_Exception:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_ComplexElement:
- return 0;
+ return nullptr;
}
llvm_unreachable("unknown entity kind");
}
-static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD);
+static void performLifetimeExtension(Expr *Init,
+ const InitializedEntity *ExtendingEntity);
/// Update a glvalue expression that is used as the initializer of a reference
/// to note that its lifetime is extended.
/// \return \c true if any temporary had its lifetime extended.
-static bool performReferenceExtension(Expr *Init, const ValueDecl *ExtendingD) {
+static bool
+performReferenceExtension(Expr *Init,
+ const InitializedEntity *ExtendingEntity) {
if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
if (ILE->getNumInits() == 1 && ILE->isGLValue()) {
// This is just redundant braces around an initializer. Step over it.
@@ -5407,8 +5570,9 @@ static bool performReferenceExtension(Expr *Init, const ValueDecl *ExtendingD) {
if (MaterializeTemporaryExpr *ME = dyn_cast<MaterializeTemporaryExpr>(Init)) {
// Update the storage duration of the materialized temporary.
// FIXME: Rebuild the expression instead of mutating it.
- ME->setExtendingDecl(ExtendingD);
- performLifetimeExtension(ME->GetTemporaryExpr(), ExtendingD);
+ ME->setExtendingDecl(ExtendingEntity->getDecl(),
+ ExtendingEntity->allocateManglingNumber());
+ performLifetimeExtension(ME->GetTemporaryExpr(), ExtendingEntity);
return true;
}
@@ -5417,7 +5581,8 @@ static bool performReferenceExtension(Expr *Init, const ValueDecl *ExtendingD) {
/// Update a prvalue expression that is going to be materialized as a
/// lifetime-extended temporary.
-static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) {
+static void performLifetimeExtension(Expr *Init,
+ const InitializedEntity *ExtendingEntity) {
// Dig out the expression which constructs the extended temporary.
SmallVector<const Expr *, 2> CommaLHSs;
SmallVector<SubobjectAdjustment, 2> Adjustments;
@@ -5429,14 +5594,14 @@ static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) {
if (CXXStdInitializerListExpr *ILE =
dyn_cast<CXXStdInitializerListExpr>(Init)) {
- performReferenceExtension(ILE->getSubExpr(), ExtendingD);
+ performReferenceExtension(ILE->getSubExpr(), ExtendingEntity);
return;
}
if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
if (ILE->getType()->isArrayType()) {
for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I)
- performLifetimeExtension(ILE->getInit(I), ExtendingD);
+ performLifetimeExtension(ILE->getInit(I), ExtendingEntity);
return;
}
@@ -5448,25 +5613,23 @@ static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) {
// bound to temporaries, those temporaries are also lifetime-extended.
if (RD->isUnion() && ILE->getInitializedFieldInUnion() &&
ILE->getInitializedFieldInUnion()->getType()->isReferenceType())
- performReferenceExtension(ILE->getInit(0), ExtendingD);
+ performReferenceExtension(ILE->getInit(0), ExtendingEntity);
else {
unsigned Index = 0;
- for (RecordDecl::field_iterator I = RD->field_begin(),
- E = RD->field_end();
- I != E; ++I) {
+ for (const auto *I : RD->fields()) {
if (Index >= ILE->getNumInits())
break;
if (I->isUnnamedBitfield())
continue;
Expr *SubInit = ILE->getInit(Index);
if (I->getType()->isReferenceType())
- performReferenceExtension(SubInit, ExtendingD);
+ performReferenceExtension(SubInit, ExtendingEntity);
else if (isa<InitListExpr>(SubInit) ||
isa<CXXStdInitializerListExpr>(SubInit))
// This may be either aggregate-initialization of a member or
// initialization of a std::initializer_list object. Either way,
// we should recursively lifetime-extend that initializer.
- performLifetimeExtension(SubInit, ExtendingD);
+ performLifetimeExtension(SubInit, ExtendingEntity);
++Index;
}
}
@@ -5555,7 +5718,7 @@ InitializationSequence::Perform(Sema &S,
*ResultType
= S.Context.getDependentSizedArrayType(ArrayT->getElementType(),
- /*NumElts=*/0,
+ /*NumElts=*/nullptr,
ArrayT->getSizeModifier(),
ArrayT->getIndexTypeCVRQualifiers(),
Brackets);
@@ -5578,7 +5741,7 @@ InitializationSequence::Perform(Sema &S,
// No steps means no initialization.
if (Steps.empty())
- return S.Owned((Expr *)0);
+ return ExprResult((Expr *)nullptr);
if (S.getLangOpts().CPlusPlus11 && Entity.getType()->isReferenceType() &&
Args.size() == 1 && isa<InitListExpr>(Args[0]) &&
@@ -5611,7 +5774,7 @@ InitializationSequence::Perform(Sema &S,
*ResultType = Entity.getDecl() ? Entity.getDecl()->getType() :
Entity.getType();
- ExprResult CurInit = S.Owned((Expr *)0);
+ ExprResult CurInit((Expr *)nullptr);
// For initialization steps that start with a single initializer,
// grab the only argument out the Args and place it into the "current"
@@ -5628,6 +5791,7 @@ InitializationSequence::Perform(Sema &S,
case SK_QualificationConversionLValue:
case SK_QualificationConversionXValue:
case SK_QualificationConversionRValue:
+ case SK_AtomicConversion:
case SK_LValueToRValue:
case SK_ConversionSequence:
case SK_ConversionSequenceNoNarrowing:
@@ -5652,7 +5816,8 @@ InitializationSequence::Perform(Sema &S,
}
case SK_ConstructorInitialization:
- case SK_ListConstructorCall:
+ case SK_ConstructorInitializationFromList:
+ case SK_StdInitializerListConstructorCall:
case SK_ZeroInitialization:
break;
}
@@ -5710,11 +5875,9 @@ InitializationSequence::Perform(Sema &S,
(Step->Kind == SK_CastDerivedToBaseXValue ?
VK_XValue :
VK_RValue);
- CurInit = S.Owned(ImplicitCastExpr::Create(S.Context,
- Step->Type,
- CK_DerivedToBase,
- CurInit.get(),
- &BasePath, VK));
+ CurInit =
+ ImplicitCastExpr::Create(S.Context, Step->Type, CK_DerivedToBase,
+ CurInit.get(), &BasePath, VK);
break;
}
@@ -5726,7 +5889,7 @@ InitializationSequence::Perform(Sema &S,
S.Diag(Kind.getLocation(), diag::err_reference_bind_to_bitfield)
<< Entity.getType().isVolatileQualified()
<< (BitField ? BitField->getDeclName() : DeclarationName())
- << (BitField != NULL)
+ << (BitField != nullptr)
<< CurInit.get()->getSourceRange();
if (BitField)
S.Diag(BitField->getLocation(), diag::note_bitfield_decl);
@@ -5752,12 +5915,12 @@ InitializationSequence::Perform(Sema &S,
// Even though we didn't materialize a temporary, the binding may still
// extend the lifetime of a temporary. This happens if we bind a reference
// to the result of a cast to reference type.
- if (const ValueDecl *ExtendingDecl =
- getDeclForTemporaryLifetimeExtension(Entity)) {
- if (performReferenceExtension(CurInit.get(), ExtendingDecl))
- warnOnLifetimeExtension(S, Entity, CurInit.get(), false,
- ExtendingDecl);
- }
+ if (const InitializedEntity *ExtendingEntity =
+ getEntityForTemporaryLifetimeExtension(&Entity))
+ if (performReferenceExtension(CurInit.get(), ExtendingEntity))
+ warnOnLifetimeExtension(S, Entity, CurInit.get(),
+ /*IsInitializerList=*/false,
+ ExtendingEntity->getDecl());
break;
@@ -5769,19 +5932,18 @@ InitializationSequence::Perform(Sema &S,
if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))
return ExprError();
- // Maybe lifetime-extend the temporary's subobjects to match the
- // entity's lifetime.
- const ValueDecl *ExtendingDecl =
- getDeclForTemporaryLifetimeExtension(Entity);
- if (ExtendingDecl) {
- performLifetimeExtension(CurInit.get(), ExtendingDecl);
- warnOnLifetimeExtension(S, Entity, CurInit.get(), false, ExtendingDecl);
- }
-
// Materialize the temporary into memory.
MaterializeTemporaryExpr *MTE = new (S.Context) MaterializeTemporaryExpr(
Entity.getType().getNonReferenceType(), CurInit.get(),
- Entity.getType()->isLValueReferenceType(), ExtendingDecl);
+ Entity.getType()->isLValueReferenceType());
+
+ // Maybe lifetime-extend the temporary's subobjects to match the
+ // entity's lifetime.
+ if (const InitializedEntity *ExtendingEntity =
+ getEntityForTemporaryLifetimeExtension(&Entity))
+ if (performReferenceExtension(MTE, ExtendingEntity))
+ warnOnLifetimeExtension(S, Entity, CurInit.get(), /*IsInitializerList=*/false,
+ ExtendingEntity->getDecl());
// If we're binding to an Objective-C object that has lifetime, we
// need cleanups. Likewise if we're extending this temporary to automatic
@@ -5793,7 +5955,7 @@ InitializationSequence::Perform(Sema &S,
MTE->getType().isDestructedType()))
S.ExprNeedsCleanups = true;
- CurInit = S.Owned(MTE);
+ CurInit = MTE;
break;
}
@@ -5815,7 +5977,7 @@ InitializationSequence::Perform(Sema &S,
// Build a call to the selected constructor.
SmallVector<Expr*, 8> ConstructorArgs;
SourceLocation Loc = CurInit.get()->getLocStart();
- CurInit.release(); // Ownership transferred into MultiExprArg, below.
+ CurInit.get(); // Ownership transferred into MultiExprArg, below.
// Determine the arguments required to actually perform the constructor
// call.
@@ -5830,6 +5992,7 @@ InitializationSequence::Perform(Sema &S,
ConstructorArgs,
HadMultipleCandidates,
/*ListInit*/ false,
+ /*StdInitListInit*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
@@ -5851,7 +6014,7 @@ InitializationSequence::Perform(Sema &S,
} else {
// Build a call to the conversion function.
CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn);
- S.CheckMemberOperatorAccess(Kind.getLocation(), CurInit.get(), 0,
+ S.CheckMemberOperatorAccess(Kind.getLocation(), CurInit.get(), nullptr,
FoundFn);
if (S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()))
return ExprError();
@@ -5860,7 +6023,8 @@ InitializationSequence::Perform(Sema &S,
// derived-to-base conversion? I believe the answer is "no", because
// we don't want to turn off access control here for c-style casts.
ExprResult CurInitExprRes =
- S.PerformObjectArgumentInitialization(CurInit.take(), /*Qualifier=*/0,
+ S.PerformObjectArgumentInitialization(CurInit.get(),
+ /*Qualifier=*/nullptr,
FoundFn, Conversion);
if(CurInitExprRes.isInvalid())
return ExprError();
@@ -5874,7 +6038,7 @@ InitializationSequence::Perform(Sema &S,
CastKind = CK_UserDefinedConversion;
- CreatedObject = Conversion->getResultType()->isRecordType();
+ CreatedObject = Conversion->getReturnType()->isRecordType();
}
bool RequiresCopy = !IsCopy && !isReferenceBinding(Steps.back());
@@ -5893,12 +6057,11 @@ InitializationSequence::Perform(Sema &S,
}
}
- CurInit = S.Owned(ImplicitCastExpr::Create(S.Context,
- CurInit.get()->getType(),
- CastKind, CurInit.get(), 0,
- CurInit.get()->getValueKind()));
+ CurInit = ImplicitCastExpr::Create(S.Context, CurInit.get()->getType(),
+ CastKind, CurInit.get(), nullptr,
+ CurInit.get()->getValueKind());
if (MaybeBindToTemp)
- CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+ CurInit = S.MaybeBindToTemporary(CurInit.getAs<Expr>());
if (RequiresCopy)
CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity,
CurInit, /*IsExtraneousCopy=*/false);
@@ -5915,17 +6078,22 @@ InitializationSequence::Perform(Sema &S,
(Step->Kind == SK_QualificationConversionXValue ?
VK_XValue :
VK_RValue);
- CurInit = S.ImpCastExprToType(CurInit.take(), Step->Type, CK_NoOp, VK);
+ CurInit = S.ImpCastExprToType(CurInit.get(), Step->Type, CK_NoOp, VK);
+ break;
+ }
+
+ case SK_AtomicConversion: {
+ assert(CurInit.get()->isRValue() && "cannot convert glvalue to atomic");
+ CurInit = S.ImpCastExprToType(CurInit.get(), Step->Type,
+ CK_NonAtomicToAtomic, VK_RValue);
break;
}
case SK_LValueToRValue: {
assert(CurInit.get()->isGLValue() && "cannot load from a prvalue");
- CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, Step->Type,
- CK_LValueToRValue,
- CurInit.take(),
- /*BasePath=*/0,
- VK_RValue));
+ CurInit = ImplicitCastExpr::Create(S.Context, Step->Type,
+ CK_LValueToRValue, CurInit.get(),
+ /*BasePath=*/nullptr, VK_RValue);
break;
}
@@ -5978,14 +6146,14 @@ InitializationSequence::Perform(Sema &S,
InitListExpr *StructuredInitList =
PerformInitList.getFullyStructuredList();
- CurInit.release();
+ CurInit.get();
CurInit = shouldBindAsTemporary(InitEntity)
? S.MaybeBindToTemporary(StructuredInitList)
- : S.Owned(StructuredInitList);
+ : StructuredInitList;
break;
}
- case SK_ListConstructorCall: {
+ case SK_ConstructorInitializationFromList: {
// When an initializer list is passed for a parameter of type "reference
// to object", we don't get an EK_Temporary entity, but instead an
// EK_Parameter entity with reference type.
@@ -6004,29 +6172,31 @@ InitializationSequence::Perform(Sema &S,
Entity,
Kind, Arg, *Step,
ConstructorInitRequiresZeroInit,
- /*IsListInitialization*/ true,
+ /*IsListInitialization*/true,
+ /*IsStdInitListInit*/false,
InitList->getLBraceLoc(),
InitList->getRBraceLoc());
break;
}
case SK_UnwrapInitList:
- CurInit = S.Owned(cast<InitListExpr>(CurInit.take())->getInit(0));
+ CurInit = cast<InitListExpr>(CurInit.get())->getInit(0);
break;
case SK_RewrapInitList: {
- Expr *E = CurInit.take();
+ Expr *E = CurInit.get();
InitListExpr *Syntactic = Step->WrappingSyntacticList;
InitListExpr *ILE = new (S.Context) InitListExpr(S.Context,
Syntactic->getLBraceLoc(), E, Syntactic->getRBraceLoc());
ILE->setSyntacticForm(Syntactic);
ILE->setType(E->getType());
ILE->setValueKind(E->getValueKind());
- CurInit = S.Owned(ILE);
+ CurInit = ILE;
break;
}
- case SK_ConstructorInitialization: {
+ case SK_ConstructorInitialization:
+ case SK_StdInitializerListConstructorCall: {
// When an initializer list is passed for a parameter of type "reference
// to object", we don't get an EK_Temporary entity, but instead an
// EK_Parameter entity with reference type.
@@ -6036,13 +6206,15 @@ InitializationSequence::Perform(Sema &S,
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(
Entity.getType().getNonReferenceType());
bool UseTemporary = Entity.getType()->isReferenceType();
- CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity
- : Entity,
- Kind, Args, *Step,
- ConstructorInitRequiresZeroInit,
- /*IsListInitialization*/ false,
- /*LBraceLoc*/ SourceLocation(),
- /*RBraceLoc*/ SourceLocation());
+ bool IsStdInitListInit =
+ Step->Kind == SK_StdInitializerListConstructorCall;
+ CurInit = PerformConstructorInitialization(
+ S, UseTemporary ? TempEntity : Entity, Kind, Args, *Step,
+ ConstructorInitRequiresZeroInit,
+ /*IsListInitialization*/IsStdInitListInit,
+ /*IsStdInitListInitialization*/IsStdInitListInit,
+ /*LBraceLoc*/SourceLocation(),
+ /*RBraceLoc*/SourceLocation());
break;
}
@@ -6051,7 +6223,7 @@ InitializationSequence::Perform(Sema &S,
++NextStep;
if (NextStep != StepEnd &&
(NextStep->Kind == SK_ConstructorInitialization ||
- NextStep->Kind == SK_ListConstructorCall)) {
+ NextStep->Kind == SK_ConstructorInitializationFromList)) {
// The need for zero-initialization is recorded directly into
// the call to the object's constructor within the next step.
ConstructorInitRequiresZeroInit = true;
@@ -6063,12 +6235,11 @@ InitializationSequence::Perform(Sema &S,
TSInfo = S.Context.getTrivialTypeSourceInfo(Step->Type,
Kind.getRange().getBegin());
- CurInit = S.Owned(new (S.Context) CXXScalarValueInitExpr(
- TSInfo->getType().getNonLValueExprType(S.Context),
- TSInfo,
- Kind.getRange().getEnd()));
+ CurInit = new (S.Context) CXXScalarValueInitExpr(
+ TSInfo->getType().getNonLValueExprType(S.Context), TSInfo,
+ Kind.getRange().getEnd());
} else {
- CurInit = S.Owned(new (S.Context) ImplicitValueInitExpr(Step->Type));
+ CurInit = new (S.Context) ImplicitValueInitExpr(Step->Type);
}
break;
}
@@ -6115,7 +6286,7 @@ InitializationSequence::Perform(Sema &S,
}
case SK_ObjCObjectConversion:
- CurInit = S.ImpCastExprToType(CurInit.take(), Step->Type,
+ CurInit = S.ImpCastExprToType(CurInit.get(), Step->Type,
CK_ObjCObjectLValueCast,
CurInit.get()->getValueKind());
break;
@@ -6153,15 +6324,15 @@ InitializationSequence::Perform(Sema &S,
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));
+ CurInit = new (S.Context) ObjCIndirectCopyRestoreExpr(
+ CurInit.get(), Step->Type,
+ Step->Kind == SK_PassByIndirectCopyRestore);
break;
case SK_ProduceObjCObject:
- CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, Step->Type,
- CK_ARCProduceObject,
- CurInit.take(), 0, VK_RValue));
+ CurInit =
+ ImplicitCastExpr::Create(S.Context, Step->Type, CK_ARCProduceObject,
+ CurInit.get(), nullptr, VK_RValue);
break;
case SK_StdInitializerList: {
@@ -6169,34 +6340,33 @@ InitializationSequence::Perform(Sema &S,
diag::warn_cxx98_compat_initializer_list_init)
<< CurInit.get()->getSourceRange();
- // Maybe lifetime-extend the array temporary's subobjects to match the
- // entity's lifetime.
- const ValueDecl *ExtendingDecl =
- getDeclForTemporaryLifetimeExtension(Entity);
- if (ExtendingDecl) {
- performLifetimeExtension(CurInit.get(), ExtendingDecl);
- warnOnLifetimeExtension(S, Entity, CurInit.get(), true, ExtendingDecl);
- }
-
// Materialize the temporary into memory.
MaterializeTemporaryExpr *MTE = new (S.Context)
MaterializeTemporaryExpr(CurInit.get()->getType(), CurInit.get(),
- /*lvalue reference*/ false, ExtendingDecl);
+ /*BoundToLvalueReference=*/false);
+
+ // Maybe lifetime-extend the array temporary's subobjects to match the
+ // entity's lifetime.
+ if (const InitializedEntity *ExtendingEntity =
+ getEntityForTemporaryLifetimeExtension(&Entity))
+ if (performReferenceExtension(MTE, ExtendingEntity))
+ warnOnLifetimeExtension(S, Entity, CurInit.get(),
+ /*IsInitializerList=*/true,
+ ExtendingEntity->getDecl());
// Wrap it in a construction of a std::initializer_list<T>.
- CurInit = S.Owned(
- new (S.Context) CXXStdInitializerListExpr(Step->Type, MTE));
+ CurInit = new (S.Context) CXXStdInitializerListExpr(Step->Type, MTE);
// Bind the result, in case the library has given initializer_list a
// non-trivial destructor.
if (shouldBindAsTemporary(Entity))
- CurInit = S.MaybeBindToTemporary(CurInit.take());
+ CurInit = S.MaybeBindToTemporary(CurInit.get());
break;
}
case SK_OCLSamplerInit: {
assert(Step->Type->isSamplerT() &&
- "Sampler initialization on non sampler type.");
+ "Sampler initialization on non-sampler type.");
QualType SourceType = CurInit.get()->getType();
@@ -6212,9 +6382,9 @@ InitializationSequence::Perform(Sema &S,
}
case SK_OCLZeroEvent: {
assert(Step->Type->isEventT() &&
- "Event initialization on non event type.");
+ "Event initialization on non-event type.");
- CurInit = S.ImpCastExprToType(CurInit.take(), Step->Type,
+ CurInit = S.ImpCastExprToType(CurInit.get(), Step->Type,
CK_ZeroToOCLEvent,
CurInit.get()->getValueKind());
break;
@@ -6246,8 +6416,7 @@ static bool DiagnoseUninitializedReference(Sema &S, SourceLocation Loc,
if (!RD || !RD->hasUninitializedReferenceMember())
return false;
- for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
- FE = RD->field_end(); FI != FE; ++FI) {
+ for (const auto *FI : RD->fields()) {
if (FI->isUnnamedBitfield())
continue;
@@ -6257,10 +6426,8 @@ static bool DiagnoseUninitializedReference(Sema &S, SourceLocation Loc,
}
}
- for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
- BE = RD->bases_end();
- BI != BE; ++BI) {
- if (DiagnoseUninitializedReference(S, BI->getLocStart(), BI->getType())) {
+ for (const auto &BI : RD->bases()) {
+ if (DiagnoseUninitializedReference(S, BI.getLocStart(), BI.getType())) {
S.Diag(Loc, diag::note_value_initialization_here) << RD;
return true;
}
@@ -6505,7 +6672,7 @@ bool InitializationSequence::Diagnose(Sema &S,
else
R = SourceRange(Args.front()->getLocEnd(), Args.back()->getLocEnd());
- R.setBegin(S.PP.getLocForEndOfToken(R.getBegin()));
+ R.setBegin(S.getLocForEndOfToken(R.getBegin()));
if (Kind.isCStyleOrFunctionalCast())
S.Diag(Kind.getLocation(), diag::err_builtin_func_cast_more_than_one_arg)
<< R;
@@ -6533,7 +6700,8 @@ bool InitializationSequence::Diagnose(Sema &S,
Args.back()->getLocEnd());
if (Failure == FK_ListConstructorOverloadFailed) {
- assert(Args.size() == 1 && "List construction from other than 1 argument.");
+ assert(Args.size() == 1 &&
+ "List construction from other than 1 argument.");
InitListExpr *InitList = cast<InitListExpr>(Args[0]);
Args = MultiExprArg(InitList->getInits(), InitList->getNumInits());
}
@@ -6578,7 +6746,8 @@ bool InitializationSequence::Diagnose(Sema &S,
<< S.Context.getTypeDeclType(Constructor->getParent())
<< /*member=*/1
<< Entity.getName();
- S.Diag(Entity.getDecl()->getLocation(), diag::note_field_decl);
+ S.Diag(Entity.getDecl()->getLocation(),
+ diag::note_member_declared_at);
if (const RecordType *Record
= Entity.getType()->getAs<RecordType>())
@@ -6870,6 +7039,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "qualification conversion (lvalue)";
break;
+ case SK_AtomicConversion:
+ OS << "non-atomic-to-atomic conversion";
+ break;
+
case SK_LValueToRValue:
OS << "load (lvalue to rvalue)";
break;
@@ -6890,10 +7063,6 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "list aggregate initialization";
break;
- case SK_ListConstructorCall:
- OS << "list initialization via constructor";
- break;
-
case SK_UnwrapInitList:
OS << "unwrap reference initializer list";
break;
@@ -6906,6 +7075,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "constructor initialization";
break;
+ case SK_ConstructorInitializationFromList:
+ OS << "list initialization via constructor";
+ break;
+
case SK_ZeroInitialization:
OS << "zero initialization";
break;
@@ -6946,6 +7119,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "std::initializer_list from initializer list";
break;
+ case SK_StdInitializerListConstructorCall:
+ OS << "list initialization from std::initializer_list";
+ break;
+
case SK_OCLSamplerInit:
OS << "OpenCL sampler_t from integer constant";
break;
@@ -6970,7 +7147,7 @@ static void DiagnoseNarrowingInInitList(Sema &S,
QualType PreNarrowingType,
QualType EntityType,
const Expr *PostInit) {
- const StandardConversionSequence *SCS = 0;
+ const StandardConversionSequence *SCS = nullptr;
switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion:
SCS = &ICS.Standard;
@@ -7047,11 +7224,11 @@ static void DiagnoseNarrowingInInitList(Sema &S,
return;
}
OS << ">(";
- S.Diag(PostInit->getLocStart(), diag::note_init_list_narrowing_override)
- << PostInit->getSourceRange()
- << FixItHint::CreateInsertion(PostInit->getLocStart(), OS.str())
- << FixItHint::CreateInsertion(
- S.getPreprocessor().getLocForEndOfToken(PostInit->getLocEnd()), ")");
+ S.Diag(PostInit->getLocStart(), diag::note_init_list_narrowing_silence)
+ << PostInit->getSourceRange()
+ << FixItHint::CreateInsertion(PostInit->getLocStart(), OS.str())
+ << FixItHint::CreateInsertion(
+ S.getLocForEndOfToken(PostInit->getLocEnd()), ")");
}
//===----------------------------------------------------------------------===//
@@ -7091,7 +7268,7 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity,
EqualLoc,
AllowExplicit);
InitializationSequence Seq(*this, Entity, Kind, InitE, TopLevelOfInitList);
- Init.release();
+ Init.get();
ExprResult Result = Seq.Perform(*this, Entity, Kind, InitE);
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index a7d5b6526464..0cf4ed7c6081 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -11,125 +11,214 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/DeclSpec.h"
+#include "TypeLocBuilder.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLambda.h"
-#include "TypeLocBuilder.h"
using namespace clang;
using namespace sema;
-// returns -1 if none of the lambdas on the scope stack can capture.
-// A lambda 'L' is capture-ready for a certain variable 'V' if,
-// - its enclosing context is non-dependent
-// - and if the chain of lambdas between L and the lambda in which
-// V is potentially used, call all capture or have captured V.
-static inline int GetScopeIndexOfNearestCaptureReadyLambda(
- ArrayRef<clang::sema::FunctionScopeInfo*> FunctionScopes,
- DeclContext *const CurContext, VarDecl *VD) {
+/// \brief Examines the FunctionScopeInfo stack to determine the nearest
+/// enclosing lambda (to the current lambda) that is 'capture-ready' for
+/// the variable referenced in the current lambda (i.e. \p VarToCapture).
+/// If successful, returns the index into Sema's FunctionScopeInfo stack
+/// of the capture-ready lambda's LambdaScopeInfo.
+///
+/// Climbs down the stack of lambdas (deepest nested lambda - i.e. current
+/// lambda - is on top) to determine the index of the nearest enclosing/outer
+/// lambda that is ready to capture the \p VarToCapture being referenced in
+/// the current lambda.
+/// As we climb down the stack, we want the index of the first such lambda -
+/// that is the lambda with the highest index that is 'capture-ready'.
+///
+/// A lambda 'L' is capture-ready for 'V' (var or this) if:
+/// - its enclosing context is non-dependent
+/// - and if the chain of lambdas between L and the lambda in which
+/// V is potentially used (i.e. the lambda at the top of the scope info
+/// stack), can all capture or have already captured V.
+/// If \p VarToCapture is 'null' then we are trying to capture 'this'.
+///
+/// Note that a lambda that is deemed 'capture-ready' still needs to be checked
+/// for whether it is 'capture-capable' (see
+/// getStackIndexOfNearestEnclosingCaptureCapableLambda), before it can truly
+/// capture.
+///
+/// \param FunctionScopes - Sema's stack of nested FunctionScopeInfo's (which a
+/// LambdaScopeInfo inherits from). The current/deepest/innermost lambda
+/// is at the top of the stack and has the highest index.
+/// \param VarToCapture - the variable to capture. If NULL, capture 'this'.
+///
+/// \returns An Optional<unsigned> Index that if evaluates to 'true' contains
+/// the index (into Sema's FunctionScopeInfo stack) of the innermost lambda
+/// which is capture-ready. If the return value evaluates to 'false' then
+/// no lambda is capture-ready for \p VarToCapture.
+
+static inline Optional<unsigned>
+getStackIndexOfNearestEnclosingCaptureReadyLambda(
+ ArrayRef<const clang::sema::FunctionScopeInfo *> FunctionScopes,
+ VarDecl *VarToCapture) {
+ // Label failure to capture.
+ const Optional<unsigned> NoLambdaIsCaptureReady;
+
+ assert(
+ isa<clang::sema::LambdaScopeInfo>(
+ FunctionScopes[FunctionScopes.size() - 1]) &&
+ "The function on the top of sema's function-info stack must be a lambda");
- DeclContext *EnclosingDC = CurContext;
- // If VD is null, we are attempting to capture 'this'
- const bool IsCapturingThis = !VD;
+ // If VarToCapture is null, we are attempting to capture 'this'.
+ const bool IsCapturingThis = !VarToCapture;
const bool IsCapturingVariable = !IsCapturingThis;
- int RetIndex = -1;
+
+ // Start with the current lambda at the top of the stack (highest index).
unsigned CurScopeIndex = FunctionScopes.size() - 1;
- while (!EnclosingDC->isTranslationUnit() &&
- EnclosingDC->isDependentContext() && isLambdaCallOperator(EnclosingDC)) {
- RetIndex = CurScopeIndex;
- clang::sema::LambdaScopeInfo *LSI =
- cast<sema::LambdaScopeInfo>(FunctionScopes[CurScopeIndex]);
- // We have crawled up to an intervening lambda that contains the
- // variable declaration - so not only does it not need to capture;
- // none of the enclosing lambdas need to capture it, and since all
- // other nested lambdas are dependent (otherwise we wouldn't have
- // arrived here) - we don't yet have a lambda that can capture the
+ DeclContext *EnclosingDC =
+ cast<sema::LambdaScopeInfo>(FunctionScopes[CurScopeIndex])->CallOperator;
+
+ do {
+ const clang::sema::LambdaScopeInfo *LSI =
+ cast<sema::LambdaScopeInfo>(FunctionScopes[CurScopeIndex]);
+ // IF we have climbed down to an intervening enclosing lambda that contains
+ // the variable declaration - it obviously can/must not capture the
// variable.
- if (IsCapturingVariable && VD->getDeclContext()->Equals(EnclosingDC))
- return -1;
- // All intervening lambda call operators have to be able to capture.
+ // Since its enclosing DC is dependent, all the lambdas between it and the
+ // innermost nested lambda are dependent (otherwise we wouldn't have
+ // arrived here) - so we don't yet have a lambda that can capture the
+ // variable.
+ if (IsCapturingVariable &&
+ VarToCapture->getDeclContext()->Equals(EnclosingDC))
+ return NoLambdaIsCaptureReady;
+
+ // For an enclosing lambda to be capture ready for an entity, all
+ // intervening lambda's have to be able to capture that entity. If even
+ // one of the intervening lambda's is not capable of capturing the entity
+ // then no enclosing lambda can ever capture that entity.
+ // For e.g.
+ // const int x = 10;
+ // [=](auto a) { #1
+ // [](auto b) { #2 <-- an intervening lambda that can never capture 'x'
+ // [=](auto c) { #3
+ // f(x, c); <-- can not lead to x's speculative capture by #1 or #2
+ // }; }; };
// If they do not have a default implicit capture, check to see
// if the entity has already been explicitly captured.
- // If even a single dependent enclosing lambda lacks the capability
- // to ever capture this variable, there is no further enclosing
+ // If even a single dependent enclosing lambda lacks the capability
+ // to ever capture this variable, there is no further enclosing
// non-dependent lambda that can capture this variable.
if (LSI->ImpCaptureStyle == sema::LambdaScopeInfo::ImpCap_None) {
- if (IsCapturingVariable && !LSI->isCaptured(VD))
- return -1;
+ if (IsCapturingVariable && !LSI->isCaptured(VarToCapture))
+ return NoLambdaIsCaptureReady;
if (IsCapturingThis && !LSI->isCXXThisCaptured())
- return -1;
+ return NoLambdaIsCaptureReady;
}
EnclosingDC = getLambdaAwareParentOfDeclContext(EnclosingDC);
+
+ assert(CurScopeIndex);
--CurScopeIndex;
- }
+ } while (!EnclosingDC->isTranslationUnit() &&
+ EnclosingDC->isDependentContext() &&
+ isLambdaCallOperator(EnclosingDC));
+
+ assert(CurScopeIndex < (FunctionScopes.size() - 1));
// If the enclosingDC is not dependent, then the immediately nested lambda
- // is capture-ready.
+ // (one index above) is capture-ready.
if (!EnclosingDC->isDependentContext())
- return RetIndex;
- return -1;
+ return CurScopeIndex + 1;
+ return NoLambdaIsCaptureReady;
}
-// Given a lambda's call operator and a variable (or null for 'this'),
-// compute the nearest enclosing lambda that is capture-ready (i.e
-// the enclosing context is not dependent, and all intervening lambdas can
-// either implicitly or explicitly capture Var)
-//
-// The approach is as follows, for the entity VD ('this' if null):
-// - start with the current lambda
-// - if it is non-dependent and can capture VD, return it.
-// - if it is dependent and has an implicit or explicit capture, check its parent
-// whether the parent is non-depdendent and all its intervening lambdas
-// can capture, if so return the child.
-// [Note: When we hit a generic lambda specialization, do not climb up
-// the scope stack any further since not only do we not need to,
-// the scope stack will often not be synchronized with any lambdas
-// enclosing the specialized generic lambda]
-//
-// Return the CallOperator of the capturable lambda and set function scope
-// index to the correct index within the function scope stack to correspond
-// to the capturable lambda.
-// If VarDecl *VD is null, we check for 'this' capture.
-CXXMethodDecl* clang::GetInnermostEnclosingCapturableLambda(
- ArrayRef<sema::FunctionScopeInfo*> FunctionScopes,
- unsigned &FunctionScopeIndex,
- DeclContext *const CurContext, VarDecl *VD,
- Sema &S) {
-
- const int IndexOfCaptureReadyLambda =
- GetScopeIndexOfNearestCaptureReadyLambda(FunctionScopes,CurContext, VD);
- if (IndexOfCaptureReadyLambda == -1) return 0;
- assert(IndexOfCaptureReadyLambda >= 0);
- const unsigned IndexOfCaptureReadyLambdaU =
- static_cast<unsigned>(IndexOfCaptureReadyLambda);
- sema::LambdaScopeInfo *const CaptureReadyLambdaLSI =
- cast<sema::LambdaScopeInfo>(FunctionScopes[IndexOfCaptureReadyLambdaU]);
- // If VD is null, we are attempting to capture 'this'
- const bool IsCapturingThis = !VD;
+
+/// \brief Examines the FunctionScopeInfo stack to determine the nearest
+/// enclosing lambda (to the current lambda) that is 'capture-capable' for
+/// the variable referenced in the current lambda (i.e. \p VarToCapture).
+/// If successful, returns the index into Sema's FunctionScopeInfo stack
+/// of the capture-capable lambda's LambdaScopeInfo.
+///
+/// Given the current stack of lambdas being processed by Sema and
+/// the variable of interest, to identify the nearest enclosing lambda (to the
+/// current lambda at the top of the stack) that can truly capture
+/// a variable, it has to have the following two properties:
+/// a) 'capture-ready' - be the innermost lambda that is 'capture-ready':
+/// - climb down the stack (i.e. starting from the innermost and examining
+/// each outer lambda step by step) checking if each enclosing
+/// lambda can either implicitly or explicitly capture the variable.
+/// Record the first such lambda that is enclosed in a non-dependent
+/// context. If no such lambda currently exists return failure.
+/// b) 'capture-capable' - make sure the 'capture-ready' lambda can truly
+/// capture the variable by checking all its enclosing lambdas:
+/// - check if all outer lambdas enclosing the 'capture-ready' lambda
+/// identified above in 'a' can also capture the variable (this is done
+/// via tryCaptureVariable for variables and CheckCXXThisCapture for
+/// 'this' by passing in the index of the Lambda identified in step 'a')
+///
+/// \param FunctionScopes - Sema's stack of nested FunctionScopeInfo's (which a
+/// LambdaScopeInfo inherits from). The current/deepest/innermost lambda
+/// is at the top of the stack.
+///
+/// \param VarToCapture - the variable to capture. If NULL, capture 'this'.
+///
+///
+/// \returns An Optional<unsigned> Index that if evaluates to 'true' contains
+/// the index (into Sema's FunctionScopeInfo stack) of the innermost lambda
+/// which is capture-capable. If the return value evaluates to 'false' then
+/// no lambda is capture-capable for \p VarToCapture.
+
+Optional<unsigned> clang::getStackIndexOfNearestEnclosingCaptureCapableLambda(
+ ArrayRef<const sema::FunctionScopeInfo *> FunctionScopes,
+ VarDecl *VarToCapture, Sema &S) {
+
+ const Optional<unsigned> NoLambdaIsCaptureCapable;
+
+ const Optional<unsigned> OptionalStackIndex =
+ getStackIndexOfNearestEnclosingCaptureReadyLambda(FunctionScopes,
+ VarToCapture);
+ if (!OptionalStackIndex)
+ return NoLambdaIsCaptureCapable;
+
+ const unsigned IndexOfCaptureReadyLambda = OptionalStackIndex.getValue();
+ assert(((IndexOfCaptureReadyLambda != (FunctionScopes.size() - 1)) ||
+ S.getCurGenericLambda()) &&
+ "The capture ready lambda for a potential capture can only be the "
+ "current lambda if it is a generic lambda");
+
+ const sema::LambdaScopeInfo *const CaptureReadyLambdaLSI =
+ cast<sema::LambdaScopeInfo>(FunctionScopes[IndexOfCaptureReadyLambda]);
+
+ // If VarToCapture is null, we are attempting to capture 'this'
+ const bool IsCapturingThis = !VarToCapture;
const bool IsCapturingVariable = !IsCapturingThis;
if (IsCapturingVariable) {
- // Now check to see if this lambda can truly capture, and also
- // if all enclosing lambdas of this lambda allow this capture.
+ // Check if the capture-ready lambda can truly capture the variable, by
+ // checking whether all enclosing lambdas of the capture-ready lambda allow
+ // the capture - i.e. make sure it is capture-capable.
QualType CaptureType, DeclRefType;
- const bool CanCaptureVariable = !S.tryCaptureVariable(VD,
- /*ExprVarIsUsedInLoc*/SourceLocation(), clang::Sema::TryCapture_Implicit,
- /*EllipsisLoc*/ SourceLocation(),
- /*BuildAndDiagnose*/false, CaptureType, DeclRefType,
- &IndexOfCaptureReadyLambdaU);
- if (!CanCaptureVariable) return 0;
- } else {
- const bool CanCaptureThis = !S.CheckCXXThisCapture(
- CaptureReadyLambdaLSI->PotentialThisCaptureLocation, false, false,
- &IndexOfCaptureReadyLambdaU);
- if (!CanCaptureThis) return 0;
- } // end 'this' capture test
- FunctionScopeIndex = IndexOfCaptureReadyLambdaU;
- return CaptureReadyLambdaLSI->CallOperator;
+ const bool CanCaptureVariable =
+ !S.tryCaptureVariable(VarToCapture,
+ /*ExprVarIsUsedInLoc*/ SourceLocation(),
+ clang::Sema::TryCapture_Implicit,
+ /*EllipsisLoc*/ SourceLocation(),
+ /*BuildAndDiagnose*/ false, CaptureType,
+ DeclRefType, &IndexOfCaptureReadyLambda);
+ if (!CanCaptureVariable)
+ return NoLambdaIsCaptureCapable;
+ } else {
+ // Check if the capture-ready lambda can truly capture 'this' by checking
+ // whether all enclosing lambdas of the capture-ready lambda can capture
+ // 'this'.
+ const bool CanCaptureThis =
+ !S.CheckCXXThisCapture(
+ CaptureReadyLambdaLSI->PotentialThisCaptureLocation,
+ /*Explicit*/ false, /*BuildAndDiagnose*/ false,
+ &IndexOfCaptureReadyLambda);
+ if (!CanCaptureThis)
+ return NoLambdaIsCaptureCapable;
+ }
+ return IndexOfCaptureReadyLambda;
}
static inline TemplateParameterList *
@@ -142,17 +231,14 @@ getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) {
SourceLocation LAngleLoc = IntroRange.getBegin();
SourceLocation RAngleLoc = IntroRange.getEnd();
LSI->GLTemplateParameterList = TemplateParameterList::Create(
- SemaRef.Context,
- /*Template kw loc*/SourceLocation(),
- LAngleLoc,
- (NamedDecl**)LSI->AutoTemplateParams.data(),
- LSI->AutoTemplateParams.size(), RAngleLoc);
+ SemaRef.Context,
+ /*Template kw loc*/ SourceLocation(), LAngleLoc,
+ (NamedDecl **)LSI->AutoTemplateParams.data(),
+ LSI->AutoTemplateParams.size(), RAngleLoc);
}
return LSI->GLTemplateParameterList;
}
-
-
CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange,
TypeSourceInfo *Info,
bool KnownDependent,
@@ -169,7 +255,7 @@ CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange,
IsGenericLambda,
CaptureDefault);
DC->addDecl(Class);
-
+
return Class;
}
@@ -230,18 +316,18 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC,
if ((IsInNonspecializedTemplate &&
!(ManglingContextDecl && isa<ParmVarDecl>(ManglingContextDecl))) ||
isInInlineFunction(CurContext)) {
- ManglingContextDecl = 0;
+ ManglingContextDecl = nullptr;
return &Context.getManglingNumberContext(DC);
}
- ManglingContextDecl = 0;
- return 0;
+ ManglingContextDecl = nullptr;
+ return nullptr;
case StaticDataMember:
// -- the initializers of nonspecialized static members of template classes
if (!IsInNonspecializedTemplate) {
- ManglingContextDecl = 0;
- return 0;
+ ManglingContextDecl = nullptr;
+ return nullptr;
}
// Fall through to get the current context.
@@ -277,10 +363,10 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
// dependent type.
if (Class->isDependentContext() || TemplateParams) {
const FunctionProtoType *FPT = MethodType->castAs<FunctionProtoType>();
- QualType Result = FPT->getResultType();
+ QualType Result = FPT->getReturnType();
if (Result->isUndeducedType()) {
Result = SubstAutoType(Result, Context.DependentTy);
- MethodType = Context.getFunctionType(Result, FPT->getArgTypes(),
+ MethodType = Context.getFunctionType(Result, FPT->getParamTypes(),
FPT->getExtProtoInfo());
}
}
@@ -317,7 +403,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
FunctionTemplateDecl::Create(Context, Class,
Method->getLocation(), MethodName,
TemplateParams,
- Method) : 0;
+ Method) : nullptr;
if (TemplateMethod) {
TemplateMethod->setLexicalDeclContext(CurContext);
TemplateMethod->setAccess(AS_public);
@@ -331,10 +417,8 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
const_cast<ParmVarDecl **>(Params.end()),
/*CheckParameterNames=*/false);
- for (CXXMethodDecl::param_iterator P = Method->param_begin(),
- PEnd = Method->param_end();
- P != PEnd; ++P)
- (*P)->setOwningFunction(Method);
+ for (auto P : Method->params())
+ P->setOwningFunction(Method);
}
Decl *ManglingContextDecl;
@@ -369,8 +453,8 @@ void Sema::buildLambdaScope(LambdaScopeInfo *LSI,
LSI->Mutable = Mutable;
if (ExplicitResultType) {
- LSI->ReturnType = CallOperator->getResultType();
-
+ LSI->ReturnType = CallOperator->getReturnType();
+
if (!LSI->ReturnType->isDependentType() &&
!LSI->ReturnType->isVoidType()) {
if (RequireCompleteType(CallOperator->getLocStart(), LSI->ReturnType,
@@ -420,7 +504,7 @@ static EnumDecl *findEnumForBlockReturn(Expr *E) {
= dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
return cast<EnumDecl>(D->getDeclContext());
}
- return 0;
+ return nullptr;
}
// - it is a comma expression whose RHS is an enumerator-like
@@ -428,7 +512,7 @@ static EnumDecl *findEnumForBlockReturn(Expr *E) {
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
if (BO->getOpcode() == BO_Comma)
return findEnumForBlockReturn(BO->getRHS());
- return 0;
+ return nullptr;
}
// - it is a statement-expression whose value expression is an
@@ -436,7 +520,7 @@ static EnumDecl *findEnumForBlockReturn(Expr *E) {
if (StmtExpr *SE = dyn_cast<StmtExpr>(E)) {
if (Expr *last = dyn_cast_or_null<Expr>(SE->getSubStmt()->body_back()))
return findEnumForBlockReturn(last);
- return 0;
+ return nullptr;
}
// - it is a ternary conditional operator (not the GNU ?:
@@ -446,7 +530,7 @@ static EnumDecl *findEnumForBlockReturn(Expr *E) {
if (EnumDecl *ED = findEnumForBlockReturn(CO->getTrueExpr()))
if (ED == findEnumForBlockReturn(CO->getFalseExpr()))
return ED;
- return 0;
+ return nullptr;
}
// (implicitly:)
@@ -467,7 +551,7 @@ static EnumDecl *findEnumForBlockReturn(Expr *E) {
}
// Otherwise, nope.
- return 0;
+ return nullptr;
}
/// Attempt to find a type T for which the returned expression of the
@@ -475,7 +559,7 @@ static EnumDecl *findEnumForBlockReturn(Expr *E) {
static EnumDecl *findEnumForBlockReturn(ReturnStmt *ret) {
if (Expr *retValue = ret->getRetValue())
return findEnumForBlockReturn(retValue);
- return 0;
+ return nullptr;
}
/// Attempt to find a common type T for which all of the returned
@@ -486,16 +570,16 @@ static EnumDecl *findCommonEnumForBlockReturns(ArrayRef<ReturnStmt*> returns) {
// Try to find one for the first return.
EnumDecl *ED = findEnumForBlockReturn(*i);
- if (!ED) return 0;
+ if (!ED) return nullptr;
// Check that the rest of the returns have the same enum.
for (++i; i != e; ++i) {
if (findEnumForBlockReturn(*i) != ED)
- return 0;
+ return nullptr;
}
// Never infer an anonymous enum type.
- if (!ED->hasNameForLinkage()) return 0;
+ if (!ED->hasNameForLinkage()) return nullptr;
return ED;
}
@@ -519,7 +603,7 @@ static void adjustBlockReturnsToEnum(Sema &S, ArrayRef<ReturnStmt*> returns,
Expr *E = (cleanups ? cleanups->getSubExpr() : retValue);
E = ImplicitCastExpr::Create(S.Context, returnType, CK_IntegralCast,
- E, /*base path*/ 0, VK_RValue);
+ E, /*base path*/ nullptr, VK_RValue);
if (cleanups) {
cleanups->setSubExpr(E);
} else {
@@ -651,6 +735,9 @@ QualType Sema::performLambdaInitCaptureInitialization(SourceLocation Loc,
return QualType();
} else {
DeduceInit = CXXDirectInit->getExpr(0);
+ if (isa<InitListExpr>(DeduceInit))
+ Diag(CXXDirectInit->getLocStart(), diag::err_init_capture_paren_braces)
+ << DeclarationName(Id) << Loc;
}
}
@@ -695,7 +782,7 @@ QualType Sema::performLambdaInitCaptureInitialization(SourceLocation Loc,
if (Result.isInvalid())
return QualType();
- Init = Result.takeAs<Expr>();
+ Init = Result.getAs<Expr>();
// The init-capture initialization is a full-expression that must be
// processed as one before we enter the declcontext of the lambda's
@@ -706,7 +793,7 @@ QualType Sema::performLambdaInitCaptureInitialization(SourceLocation Loc,
if (Result.isInvalid())
return QualType();
- Init = Result.takeAs<Expr>();
+ Init = Result.getAs<Expr>();
return DeducedType;
}
@@ -732,7 +819,8 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
FieldDecl *Sema::buildInitCaptureField(LambdaScopeInfo *LSI, VarDecl *Var) {
FieldDecl *Field = FieldDecl::Create(
Context, LSI->Lambda, Var->getLocation(), Var->getLocation(),
- 0, Var->getType(), Var->getTypeSourceInfo(), 0, false, ICIS_NoInit);
+ nullptr, Var->getType(), Var->getTypeSourceInfo(), nullptr, false,
+ ICIS_NoInit);
Field->setImplicit(true);
Field->setAccess(AS_private);
LSI->Lambda->addDecl(Field);
@@ -758,7 +846,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// has template params, only then are we in a dependent scope.
if (TemplateParams) {
TmplScope = TmplScope->getParent();
- TmplScope = TmplScope ? TmplScope->getTemplateParamParent() : 0;
+ TmplScope = TmplScope ? TmplScope->getTemplateParamParent() : nullptr;
}
if (TmplScope && !TmplScope->decl_empty())
KnownDependent = true;
@@ -811,14 +899,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
ExplicitResultType = FTI.hasTrailingReturnType();
- if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
- cast<ParmVarDecl>(FTI.ArgInfo[0].Param)->getType()->isVoidType()) {
- // Empty arg list, don't push any params.
- checkVoidParamDecl(cast<ParmVarDecl>(FTI.ArgInfo[0].Param));
- } else {
- Params.reserve(FTI.NumArgs);
- for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
- Params.push_back(cast<ParmVarDecl>(FTI.ArgInfo[i].Param));
+ if (FTIHasNonVoidParameters(FTI)) {
+ Params.reserve(FTI.NumParams);
+ for (unsigned i = 0, e = FTI.NumParams; i != e; ++i)
+ Params.push_back(cast<ParmVarDecl>(FTI.Params[i].Param));
}
// Check for unexpanded parameter packs in the method type.
@@ -848,27 +932,40 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
ExplicitResultType,
!Method->isConst());
+ // C++11 [expr.prim.lambda]p9:
+ // A lambda-expression whose smallest enclosing scope is a block scope is a
+ // local lambda expression; any other lambda expression shall not have a
+ // capture-default or simple-capture in its lambda-introducer.
+ //
+ // For simple-captures, this is covered by the check below that any named
+ // entity is a variable that can be captured.
+ //
+ // For DR1632, we also allow a capture-default in any context where we can
+ // odr-use 'this' (in particular, in a default initializer for a non-static
+ // data member).
+ if (Intro.Default != LCD_None && !Class->getParent()->isFunctionOrMethod() &&
+ (getCurrentThisType().isNull() ||
+ CheckCXXThisCapture(SourceLocation(), /*Explicit*/true,
+ /*BuildAndDiagnose*/false)))
+ Diag(Intro.DefaultLoc, diag::err_capture_default_non_local);
+
// Distinct capture names, for diagnostics.
llvm::SmallSet<IdentifierInfo*, 8> CaptureNames;
// Handle explicit captures.
SourceLocation PrevCaptureLoc
= Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc;
- for (SmallVectorImpl<LambdaCapture>::const_iterator
- C = Intro.Captures.begin(),
- E = Intro.Captures.end();
- C != E;
+ for (auto C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E;
PrevCaptureLoc = C->Loc, ++C) {
if (C->Kind == LCK_This) {
// C++11 [expr.prim.lambda]p8:
// An identifier or this shall not appear more than once in a
// lambda-capture.
if (LSI->isCXXThisCaptured()) {
- Diag(C->Loc, diag::err_capture_more_than_once)
- << "'this'"
- << SourceRange(LSI->getCXXThisCapture().getLocation())
- << FixItHint::CreateRemoval(
- SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+ Diag(C->Loc, diag::err_capture_more_than_once)
+ << "'this'" << SourceRange(LSI->getCXXThisCapture().getLocation())
+ << FixItHint::CreateRemoval(
+ SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc));
continue;
}
@@ -877,8 +974,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// lambda-capture shall not contain this [...].
if (Intro.Default == LCD_ByCopy) {
Diag(C->Loc, diag::err_this_capture_with_copy_default)
- << FixItHint::CreateRemoval(
- SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+ << FixItHint::CreateRemoval(
+ SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc));
continue;
}
@@ -900,7 +997,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (C->Init.isInvalid())
continue;
- VarDecl *Var = 0;
+ VarDecl *Var = nullptr;
if (C->Init.isUsable()) {
Diag(C->Loc, getLangOpts().CPlusPlus1y
? diag::warn_cxx11_compat_init_capture
@@ -916,7 +1013,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (C->InitCaptureType.get().isNull())
continue;
Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(),
- C->Id, C->Init.take());
+ C->Id, C->Init.get());
// C++1y [expr.prim.lambda]p11:
// An init-capture behaves as if it declares and explicitly
// captures a variable [...] whose declarative region is the
@@ -931,13 +1028,13 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// each identifier it contains shall be preceded by &.
if (C->Kind == LCK_ByRef && Intro.Default == LCD_ByRef) {
Diag(C->Loc, diag::err_reference_capture_with_reference_default)
- << FixItHint::CreateRemoval(
- SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+ << FixItHint::CreateRemoval(
+ SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc));
continue;
} else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) {
Diag(C->Loc, diag::err_copy_capture_with_copy_default)
- << FixItHint::CreateRemoval(
- SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+ << FixItHint::CreateRemoval(
+ SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc));
continue;
}
@@ -958,6 +1055,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
}
Var = R.getAsSingle<VarDecl>();
+ if (Var && DiagnoseUseOfDecl(Var, C->Loc))
+ continue;
}
// C++11 [expr.prim.lambda]p8:
@@ -966,9 +1065,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (!CaptureNames.insert(C->Id)) {
if (Var && LSI->isCaptured(Var)) {
Diag(C->Loc, diag::err_capture_more_than_once)
- << C->Id << SourceRange(LSI->getCapture(Var).getLocation())
- << FixItHint::CreateRemoval(
- SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+ << C->Id << SourceRange(LSI->getCapture(Var).getLocation())
+ << FixItHint::CreateRemoval(
+ SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc));
} else
// Previous capture captured something different (one or both was
// an init-cpature): no fixit.
@@ -1033,6 +1132,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope,
bool IsInstantiation) {
+ LambdaScopeInfo *LSI = getCurLambda();
+
// Leave the expression-evaluation context.
DiscardCleanupsInEvaluationContext();
PopExpressionEvaluationContext();
@@ -1042,15 +1143,11 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope,
PopDeclContext();
// Finalize the lambda.
- LambdaScopeInfo *LSI = getCurLambda();
CXXRecordDecl *Class = LSI->Lambda;
Class->setInvalidDecl();
- SmallVector<Decl*, 4> Fields;
- for (RecordDecl::field_iterator i = Class->field_begin(),
- e = Class->field_end(); i != e; ++i)
- Fields.push_back(*i);
- ActOnFields(0, Class->getLocation(), Class, Fields,
- SourceLocation(), SourceLocation(), 0);
+ SmallVector<Decl*, 4> Fields(Class->fields());
+ ActOnFields(nullptr, Class->getLocation(), Class, Fields, SourceLocation(),
+ SourceLocation(), nullptr);
CheckCompletedCXXClass(Class);
PopFunctionScopeInfo();
@@ -1077,8 +1174,9 @@ static void addFunctionPointerConversion(Sema &S,
InvokerExtInfo.TypeQuals = 0;
assert(InvokerExtInfo.RefQualifier == RQ_None &&
"Lambda's call operator should not have a reference qualifier");
- InvokerFunctionTy = S.Context.getFunctionType(CallOpProto->getResultType(),
- CallOpProto->getArgTypes(), InvokerExtInfo);
+ InvokerFunctionTy =
+ S.Context.getFunctionType(CallOpProto->getReturnType(),
+ CallOpProto->getParamTypes(), InvokerExtInfo);
PtrToFunctionTy = S.Context.getPointerType(InvokerFunctionTy);
}
@@ -1122,7 +1220,7 @@ static void addFunctionPointerConversion(Sema &S,
ConvTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>();
// Get the result of the conversion function which is a pointer-to-function.
PointerTypeLoc PtrToFunctionTL =
- ConvTL.getResultLoc().getAs<PointerTypeLoc>();
+ ConvTL.getReturnLoc().getAs<PointerTypeLoc>();
// Do the same for the TypeSourceInfo that is used to name the conversion
// operator.
PointerTypeLoc ConvNamePtrToFunctionTL =
@@ -1156,9 +1254,9 @@ static void addFunctionPointerConversion(Sema &S,
From->getType(),
From->getTypeSourceInfo(),
From->getStorageClass(),
- /*DefaultArg=*/0));
- CallOpConvTL.setArg(I, From);
- CallOpConvNameTL.setArg(I, From);
+ /*DefaultArg=*/nullptr));
+ CallOpConvTL.setParam(I, From);
+ CallOpConvNameTL.setParam(I, From);
}
CXXConversionDecl *Conversion
@@ -1244,7 +1342,7 @@ static void addBlockPointerConversion(Sema &S,
FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
ExtInfo.TypeQuals = 0;
QualType FunctionTy = S.Context.getFunctionType(
- Proto->getResultType(), Proto->getArgTypes(), ExtInfo);
+ Proto->getReturnType(), Proto->getParamTypes(), ExtInfo);
BlockPtrTy = S.Context.getBlockPointerType(FunctionTy);
}
@@ -1276,7 +1374,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
Scope *CurScope,
bool IsInstantiation) {
// Collect information from the lambda scope.
- SmallVector<LambdaExpr::Capture, 4> Captures;
+ SmallVector<LambdaCapture, 4> Captures;
SmallVector<Expr *, 4> CaptureInits;
LambdaCaptureDefault CaptureDefault;
SourceLocation CaptureDefaultLoc;
@@ -1309,9 +1407,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
// Handle 'this' capture.
if (From.isThisCapture()) {
- Captures.push_back(LambdaExpr::Capture(From.getLocation(),
- IsImplicit,
- LCK_This));
+ Captures.push_back(
+ LambdaCapture(From.getLocation(), IsImplicit, LCK_This));
CaptureInits.push_back(new (Context) CXXThisExpr(From.getLocation(),
getCurrentThisType(),
/*isImplicit=*/true));
@@ -1320,8 +1417,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
VarDecl *Var = From.getVariable();
LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef;
- Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit,
- Kind, Var, From.getEllipsisLoc()));
+ Captures.push_back(LambdaCapture(From.getLocation(), IsImplicit, Kind,
+ Var, From.getEllipsisLoc()));
CaptureInits.push_back(From.getInitExpr());
}
@@ -1369,7 +1466,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
const FunctionProtoType *Proto
= CallOperator->getType()->getAs<FunctionProtoType>();
QualType FunctionTy = Context.getFunctionType(
- LSI->ReturnType, Proto->getArgTypes(), Proto->getExtProtoInfo());
+ LSI->ReturnType, Proto->getParamTypes(), Proto->getExtProtoInfo());
CallOperator->setType(FunctionTy);
}
// C++ [expr.prim.lambda]p7:
@@ -1407,12 +1504,9 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
// Finalize the lambda class.
- SmallVector<Decl*, 4> Fields;
- for (RecordDecl::field_iterator i = Class->field_begin(),
- e = Class->field_end(); i != e; ++i)
- Fields.push_back(*i);
- ActOnFields(0, Class->getLocation(), Class, Fields,
- SourceLocation(), SourceLocation(), 0);
+ SmallVector<Decl*, 4> Fields(Class->fields());
+ ActOnFields(nullptr, Class->getLocation(), Class, Fields, SourceLocation(),
+ SourceLocation(), nullptr);
CheckCompletedCXXClass(Class);
}
@@ -1478,7 +1572,7 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
/*NRVO=*/false),
CurrentLocation, Src);
if (!Init.isInvalid())
- Init = ActOnFinishFullExpr(Init.take());
+ Init = ActOnFinishFullExpr(Init.get());
if (Init.isInvalid())
return ExprError();
@@ -1502,7 +1596,7 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
From->getType(),
From->getTypeSourceInfo(),
From->getStorageClass(),
- /*DefaultArg=*/0));
+ /*DefaultArg=*/nullptr));
}
Block->setParams(BlockParams);
@@ -1514,11 +1608,11 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
TypeSourceInfo *CapVarTSI =
Context.getTrivialTypeSourceInfo(Src->getType());
VarDecl *CapVar = VarDecl::Create(Context, Block, ConvLocation,
- ConvLocation, 0,
+ ConvLocation, nullptr,
Src->getType(), CapVarTSI,
SC_None);
BlockDecl::Capture Capture(/*Variable=*/CapVar, /*ByRef=*/false,
- /*Nested=*/false, /*Copy=*/Init.take());
+ /*Nested=*/false, /*Copy=*/Init.get());
Block->setCaptures(Context, &Capture, &Capture + 1,
/*CapturesCXXThis=*/false);
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 919c6ad61ab2..fe2c8161b871 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Lex/ModuleLoader.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/Overload.h"
@@ -113,10 +114,8 @@ namespace {
if (Ctx && Ctx->isFileContext()) {
visit(Ctx, Ctx);
} else if (!Ctx || Ctx->isFunctionOrMethod()) {
- Scope::udir_iterator I = S->using_directives_begin(),
- End = S->using_directives_end();
- for (; I != End; ++I)
- visit(*I, InnermostFileDC);
+ for (auto *I : S->using_directives())
+ visit(I, InnermostFileDC);
}
}
}
@@ -153,9 +152,7 @@ namespace {
void addUsingDirectives(DeclContext *DC, DeclContext *EffectiveDC) {
SmallVector<DeclContext*,4> queue;
while (true) {
- DeclContext::udir_iterator I, End;
- for (llvm::tie(I, End) = DC->getUsingDirectives(); I != End; ++I) {
- UsingDirectiveDecl *UD = *I;
+ for (auto UD : DC->using_directives()) {
DeclContext *NS = UD->getNominatedNamespace();
if (visited.insert(NS)) {
addUsingDirective(UD, EffectiveDC);
@@ -248,10 +245,11 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
IDNS = Decl::IDNS_Tag;
}
break;
+
case Sema::LookupLabel:
IDNS = Decl::IDNS_Label;
break;
-
+
case Sema::LookupMemberName:
IDNS = Decl::IDNS_Member;
if (CPlusPlus)
@@ -267,8 +265,10 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
break;
case Sema::LookupUsingDeclName:
- IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag
- | Decl::IDNS_Member | Decl::IDNS_Using;
+ assert(Redeclaration && "should only be used for redecl lookup");
+ IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member |
+ Decl::IDNS_Using | Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend |
+ Decl::IDNS_LocalExtern;
break;
case Sema::LookupObjCProtocolName:
@@ -288,36 +288,33 @@ void LookupResult::configure() {
IDNS = getIDNS(LookupKind, SemaRef.getLangOpts().CPlusPlus,
isForRedeclaration());
- if (!isForRedeclaration()) {
- // If we're looking for one of the allocation or deallocation
- // operators, make sure that the implicitly-declared new and delete
- // operators can be found.
- switch (NameInfo.getName().getCXXOverloadedOperator()) {
- case OO_New:
- case OO_Delete:
- case OO_Array_New:
- case OO_Array_Delete:
- SemaRef.DeclareGlobalNewDelete();
- break;
+ // If we're looking for one of the allocation or deallocation
+ // operators, make sure that the implicitly-declared new and delete
+ // operators can be found.
+ switch (NameInfo.getName().getCXXOverloadedOperator()) {
+ case OO_New:
+ case OO_Delete:
+ case OO_Array_New:
+ case OO_Array_Delete:
+ SemaRef.DeclareGlobalNewDelete();
+ break;
- default:
- break;
- }
+ default:
+ break;
+ }
- // Compiler builtins are always visible, regardless of where they end
- // up being declared.
- if (IdentifierInfo *Id = NameInfo.getName().getAsIdentifierInfo()) {
- if (unsigned BuiltinID = Id->getBuiltinID()) {
- if (!SemaRef.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
- AllowHidden = true;
- }
+ // Compiler builtins are always visible, regardless of where they end
+ // up being declared.
+ if (IdentifierInfo *Id = NameInfo.getName().getAsIdentifierInfo()) {
+ if (unsigned BuiltinID = Id->getBuiltinID()) {
+ if (!SemaRef.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
+ AllowHidden = true;
}
}
}
-void LookupResult::sanityImpl() const {
- // Note that this function is never called by NDEBUG builds. See
- // LookupResult::sanity().
+bool LookupResult::sanity() const {
+ // This function is never called by NDEBUG builds.
assert(ResultKind != NotFound || Decls.size() == 0);
assert(ResultKind != Found || Decls.size() == 1);
assert(ResultKind != FoundOverloaded || Decls.size() > 1 ||
@@ -327,9 +324,10 @@ void LookupResult::sanityImpl() const {
assert(ResultKind != Ambiguous || Decls.size() > 1 ||
(Decls.size() == 1 && (Ambiguity == AmbiguousBaseSubobjects ||
Ambiguity == AmbiguousBaseSubobjectTypes)));
- assert((Paths != NULL) == (ResultKind == Ambiguous &&
- (Ambiguity == AmbiguousBaseSubobjectTypes ||
- Ambiguity == AmbiguousBaseSubobjects)));
+ assert((Paths != nullptr) == (ResultKind == Ambiguous &&
+ (Ambiguity == AmbiguousBaseSubobjectTypes ||
+ Ambiguity == AmbiguousBaseSubobjects)));
+ return true;
}
// Necessary because CXXBasePaths is not complete in Sema.h
@@ -544,14 +542,6 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
R.addDecl(D);
return true;
}
-
- if (R.isForRedeclaration()) {
- // If we're redeclaring this function anyway, forget that
- // this was a builtin at all.
- S.Context.BuiltinInfo.ForgetBuiltin(BuiltinID, S.Context.Idents);
- }
-
- return false;
}
}
}
@@ -734,7 +724,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
// specialization into the result set. We do this to avoid forcing all
// callers to perform special deduction for conversion functions.
TemplateDeductionInfo Info(R.getNameLoc());
- FunctionDecl *Specialization = 0;
+ FunctionDecl *Specialization = nullptr;
const FunctionProtoType *ConvProto
= ConvTemplate->getTemplatedDecl()->getType()->getAs<FunctionProtoType>();
@@ -753,7 +743,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
// Perform template argument deduction against the type that we would
// expect the function to have.
- if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType,
+ if (R.getSema().DeduceTemplateArguments(ConvTemplate, nullptr, ExpectedType,
Specialization, Info)
== Sema::TDK_Success) {
R.addDecl(Specialization);
@@ -777,7 +767,7 @@ CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context,
// Perform direct name lookup into the namespaces nominated by the
// using directives whose common ancestor is this namespace.
UnqualUsingDirectiveSet::const_iterator UI, UEnd;
- llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(NS);
+ std::tie(UI, UEnd) = UDirs.getNamespacesFor(NS);
for (; UI != UEnd; ++UI)
if (LookupDirect(S, R, UI->getNominatedNamespace()))
@@ -803,7 +793,7 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) {
// it leaves the current template parameter scope.
static std::pair<DeclContext *, bool> findOuterContext(Scope *S) {
DeclContext *DC = S->getEntity();
- DeclContext *Lexical = 0;
+ DeclContext *Lexical = nullptr;
for (Scope *OuterS = S->getParent(); OuterS;
OuterS = OuterS->getParent()) {
if (OuterS->getEntity()) {
@@ -926,7 +916,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
UnqualUsingDirectiveSet UDirs;
bool VisitedUsingDirectives = false;
bool LeftStartingScope = false;
- DeclContext *OutsideOfTemplateParamDC = 0;
+ DeclContext *OutsideOfTemplateParamDC = nullptr;
// When performing a scope lookup, we want to find local extern decls.
FindLocalExternScope FindLocals(R);
@@ -983,13 +973,13 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
// findOuterContext(). This implements the name lookup behavior
// of C++ [temp.local]p8.
Ctx = OutsideOfTemplateParamDC;
- OutsideOfTemplateParamDC = 0;
+ OutsideOfTemplateParamDC = nullptr;
}
if (Ctx) {
DeclContext *OuterCtx;
bool SearchAfterTemplateScope;
- llvm::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S);
+ std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S);
if (SearchAfterTemplateScope)
OutsideOfTemplateParamDC = OuterCtx;
@@ -1126,13 +1116,13 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
// findOuterContext(). This implements the name lookup behavior
// of C++ [temp.local]p8.
Ctx = OutsideOfTemplateParamDC;
- OutsideOfTemplateParamDC = 0;
+ OutsideOfTemplateParamDC = nullptr;
}
if (Ctx) {
DeclContext *OuterCtx;
bool SearchAfterTemplateScope;
- llvm::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S);
+ std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S);
if (SearchAfterTemplateScope)
OutsideOfTemplateParamDC = OuterCtx;
@@ -1224,7 +1214,7 @@ llvm::DenseSet<Module*> &Sema::getLookupModules() {
I != N; ++I) {
Module *M = getDefiningModule(ActiveTemplateInstantiations[I].Entity);
if (M && !LookupModulesCache.insert(M).second)
- M = 0;
+ M = nullptr;
ActiveTemplateInstantiationLookupModules.push_back(M);
}
return LookupModulesCache;
@@ -1278,15 +1268,14 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) {
assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case");
- for (Decl::redecl_iterator RD = D->redecls_begin(), RDEnd = D->redecls_end();
- RD != RDEnd; ++RD) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(*RD)) {
+ for (auto RD : D->redecls()) {
+ if (auto ND = dyn_cast<NamedDecl>(RD)) {
if (LookupResult::isVisible(SemaRef, ND))
return ND;
}
}
- return 0;
+ return nullptr;
}
NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const {
@@ -1381,10 +1370,10 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
// then we'll need to perform our checks based on the matching
// DeclContexts rather than matching scopes.
if (S && isNamespaceOrTranslationUnitScope(S))
- S = 0;
+ S = nullptr;
// Compute the DeclContext, if we need it.
- DeclContext *DC = 0;
+ DeclContext *DC = nullptr;
if (!S)
DC = (*I)->getDeclContext()->getRedeclContext();
@@ -1462,10 +1451,8 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
DeclContext *StartDC) {
assert(StartDC->isFileContext() && "start context is not a file context");
- DeclContext::udir_iterator I = StartDC->using_directives_begin();
- DeclContext::udir_iterator E = StartDC->using_directives_end();
-
- if (I == E) return false;
+ DeclContext::udir_range UsingDirectives = StartDC->using_directives();
+ if (UsingDirectives.begin() == UsingDirectives.end()) return false;
// We have at least added all these contexts to the queue.
llvm::SmallPtrSet<DeclContext*, 8> Visited;
@@ -1477,8 +1464,8 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
// We have already looked into the initial namespace; seed the queue
// with its using-children.
- for (; I != E; ++I) {
- NamespaceDecl *ND = (*I)->getNominatedNamespace()->getOriginalNamespace();
+ for (auto *I : UsingDirectives) {
+ NamespaceDecl *ND = I->getNominatedNamespace()->getOriginalNamespace();
if (Visited.insert(ND))
Queue.push_back(ND);
}
@@ -1525,8 +1512,8 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
continue;
}
- for (llvm::tie(I,E) = ND->getUsingDirectives(); I != E; ++I) {
- NamespaceDecl *Nom = (*I)->getNominatedNamespace();
+ for (auto I : ND->using_directives()) {
+ NamespaceDecl *Nom = I->getNominatedNamespace();
if (Visited.insert(Nom))
Queue.push_back(Nom);
}
@@ -1667,7 +1654,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
Paths.setOrigin(LookupRec);
// Look for this member in our base classes
- CXXRecordDecl::BaseMatchesCallback *BaseCallback = 0;
+ CXXRecordDecl::BaseMatchesCallback *BaseCallback = nullptr;
switch (R.getLookupKind()) {
case LookupObjCImplicitSelfParam:
case LookupOrdinaryName:
@@ -1736,7 +1723,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
!= Context.getCanonicalType(PathElement.Base->getType())) {
// We found members of the given name in two subobjects of
// different types. If the declaration sets aren't the same, this
- // this lookup is ambiguous.
+ // lookup is ambiguous.
if (HasOnlyStaticMembers(Path->Decls.begin(), Path->Decls.end())) {
CXXBasePaths::paths_iterator FirstPath = Paths.begin();
DeclContext::lookup_iterator FirstD = FirstPath->Decls.begin();
@@ -1780,9 +1767,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// Lookup in a base class succeeded; return these results.
- DeclContext::lookup_result DR = Paths.front().Decls;
- for (DeclContext::lookup_iterator I = DR.begin(), E = DR.end(); I != E; ++I) {
- NamedDecl *D = *I;
+ for (auto *D : Paths.front().Decls) {
AccessSpecifier AS = CXXRecordDecl::MergeAccess(SubobjectAccess,
D->getAccess());
R.addDecl(D, AS);
@@ -1890,16 +1875,15 @@ void Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
llvm::SmallPtrSet<NamedDecl*,8> TagDecls;
- LookupResult::iterator DI, DE = Result.end();
- for (DI = Result.begin(); DI != DE; ++DI)
- if (TagDecl *TD = dyn_cast<TagDecl>(*DI)) {
+ for (auto *D : Result)
+ if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
TagDecls.insert(TD);
Diag(TD->getLocation(), diag::note_hidden_tag);
}
- for (DI = Result.begin(); DI != DE; ++DI)
- if (!isa<TagDecl>(*DI))
- Diag((*DI)->getLocation(), diag::note_hiding_object);
+ for (auto *D : Result)
+ if (!isa<TagDecl>(D))
+ Diag(D->getLocation(), diag::note_hiding_object);
// For recovery purposes, go ahead and implement the hiding.
LookupResult::Filter F = Result.makeFilter();
@@ -1914,9 +1898,8 @@ void Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
case LookupResult::AmbiguousReference: {
Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange;
- LookupResult::iterator DI = Result.begin(), DE = Result.end();
- for (; DI != DE; ++DI)
- Diag((*DI)->getLocation(), diag::note_ambiguous_candidate) << *DI;
+ for (auto *D : Result)
+ Diag(D->getLocation(), diag::note_ambiguous_candidate) << D;
break;
}
}
@@ -2003,10 +1986,8 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
break;
case TemplateArgument::Pack:
- for (TemplateArgument::pack_iterator P = Arg.pack_begin(),
- PEnd = Arg.pack_end();
- P != PEnd; ++P)
- addAssociatedClassesAndNamespaces(Result, *P);
+ for (const auto &P : Arg.pack_elements())
+ addAssociatedClassesAndNamespaces(Result, P);
break;
}
}
@@ -2039,6 +2020,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
// Add the class itself. If we've already seen this class, we don't
// need to visit base classes.
+ //
+ // FIXME: That's not correct, we may have added this class only because it
+ // was the enclosing class of another class, and in that case we won't have
+ // added its base classes yet.
if (!Result.Classes.insert(Class))
return;
@@ -2065,12 +2050,8 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
}
// Only recurse into base classes for complete types.
- if (!Class->hasDefinition()) {
- QualType type = Result.S.Context.getTypeDeclType(Class);
- if (Result.S.RequireCompleteType(Result.InstantiationLoc, type,
- /*no diagnostic*/ 0))
- return;
- }
+ if (!Class->hasDefinition())
+ return;
// Add direct and indirect base classes along with their associated
// namespaces.
@@ -2081,10 +2062,8 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
Class = Bases.pop_back_val();
// Visit the base classes.
- for (CXXRecordDecl::base_class_iterator Base = Class->bases_begin(),
- BaseEnd = Class->bases_end();
- Base != BaseEnd; ++Base) {
- const RecordType *BaseType = Base->getType()->getAs<RecordType>();
+ for (const auto &Base : Class->bases()) {
+ const RecordType *BaseType = Base.getType()->getAs<RecordType>();
// In dependent contexts, we do ADL twice, and the first time around,
// the base type might be a dependent TemplateSpecializationType, or a
// TemplateTypeParmType. If that happens, simply ignore it.
@@ -2164,6 +2143,8 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
// classes. Its associated namespaces are the namespaces in
// which its associated classes are defined.
case Type::Record: {
+ Result.S.RequireCompleteType(Result.InstantiationLoc, QualType(T, 0),
+ /*no diagnostic*/ 0);
CXXRecordDecl *Class
= cast<CXXRecordDecl>(cast<RecordType>(T)->getDecl());
addAssociatedClassesAndNamespaces(Result, Class);
@@ -2192,15 +2173,13 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
// types and those associated with the return type.
case Type::FunctionProto: {
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
- for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
- ArgEnd = Proto->arg_type_end();
- Arg != ArgEnd; ++Arg)
- Queue.push_back(Arg->getTypePtr());
+ for (const auto &Arg : Proto->param_types())
+ Queue.push_back(Arg.getTypePtr());
// fallthrough
}
case Type::FunctionNoProto: {
const FunctionType *FnType = cast<FunctionType>(T);
- T = FnType->getResultType().getTypePtr();
+ T = FnType->getReturnType().getTypePtr();
continue;
}
@@ -2315,14 +2294,9 @@ void Sema::FindAssociatedClassesAndNamespaces(
UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Arg);
if (!ULE) continue;
- for (UnresolvedSetIterator I = ULE->decls_begin(), E = ULE->decls_end();
- I != E; ++I) {
+ for (const auto *D : ULE->decls()) {
// Look through any using declarations to find the underlying function.
- NamedDecl *Fn = (*I)->getUnderlyingDecl();
-
- FunctionDecl *FDecl = dyn_cast<FunctionDecl>(Fn);
- if (!FDecl)
- FDecl = cast<FunctionTemplateDecl>(Fn)->getTemplatedDecl();
+ const FunctionDecl *FDecl = D->getUnderlyingDecl()->getAsFunction();
// Add the classes and namespaces associated with the parameter
// types and return type of this function.
@@ -2331,43 +2305,6 @@ void Sema::FindAssociatedClassesAndNamespaces(
}
}
-/// IsAcceptableNonMemberOperatorCandidate - Determine whether Fn is
-/// an acceptable non-member overloaded operator for a call whose
-/// arguments have types T1 (and, if non-empty, T2). This routine
-/// implements the check in C++ [over.match.oper]p3b2 concerning
-/// enumeration types.
-static bool
-IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
- QualType T1, QualType T2,
- ASTContext &Context) {
- if (T1->isDependentType() || (!T2.isNull() && T2->isDependentType()))
- return true;
-
- if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType()))
- return true;
-
- const FunctionProtoType *Proto = Fn->getType()->getAs<FunctionProtoType>();
- if (Proto->getNumArgs() < 1)
- return false;
-
- if (T1->isEnumeralType()) {
- QualType ArgType = Proto->getArgType(0).getNonReferenceType();
- if (Context.hasSameUnqualifiedType(T1, ArgType))
- return true;
- }
-
- if (Proto->getNumArgs() < 2)
- return false;
-
- if (!T2.isNull() && T2->isEnumeralType()) {
- QualType ArgType = Proto->getArgType(1).getNonReferenceType();
- if (Context.hasSameUnqualifiedType(T2, ArgType))
- return true;
- }
-
- return false;
-}
-
NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name,
SourceLocation Loc,
LookupNameKind NameKind,
@@ -2394,37 +2331,13 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
// unqualified lookup of operator@ in the context of the
// expression according to the usual rules for name lookup in
// unqualified function calls (3.4.2) except that all member
- // functions are ignored. However, if no operand has a class
- // type, only those non-member functions in the lookup set
- // that have a first parameter of type T1 or "reference to
- // (possibly cv-qualified) T1", when T1 is an enumeration
- // type, or (if there is a right operand) a second parameter
- // of type T2 or "reference to (possibly cv-qualified) T2",
- // when T2 is an enumeration type, are candidate functions.
+ // functions are ignored.
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
LookupResult Operators(*this, OpName, SourceLocation(), LookupOperatorName);
LookupName(Operators, S);
assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous");
-
- if (Operators.empty())
- return;
-
- for (LookupResult::iterator Op = Operators.begin(), OpEnd = Operators.end();
- Op != OpEnd; ++Op) {
- NamedDecl *Found = (*Op)->getUnderlyingDecl();
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Found)) {
- if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
- Functions.addDecl(*Op, Op.getAccess()); // FIXME: canonical FD
- } else if (FunctionTemplateDecl *FunTmpl
- = dyn_cast<FunctionTemplateDecl>(Found)) {
- // FIXME: friend operators?
- // FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate,
- // later?
- if (!FunTmpl->getDeclContext()->isRecord())
- Functions.addDecl(*Op, Op.getAccess());
- }
- }
+ Functions.append(Operators.begin(), Operators.end());
}
Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
@@ -2481,7 +2394,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
// if necessary and make sure that implicit functions are declared.
CanQualType CanTy = Context.getCanonicalType(Context.getTagDeclType(RD));
DeclarationName Name;
- Expr *Arg = 0;
+ Expr *Arg = nullptr;
unsigned NumArgs;
QualType ArgType = CanTy;
@@ -2545,7 +2458,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
// Now we perform lookup on the name we computed earlier and do overload
// resolution. Lookup is only performed directly into the class since there
// will always be a (possibly implicit) declaration to shadow any others.
- OverloadCandidateSet OCS((SourceLocation()));
+ OverloadCandidateSet OCS(RD->getLocation(), OverloadCandidateSet::CSK_Normal);
DeclContext::lookup_result R = RD->lookup(Name);
assert(!R.empty() &&
"lookup for a constructor or assignment operator was empty");
@@ -2554,11 +2467,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
// from an external source and invalidate lookup_result.
SmallVector<NamedDecl *, 8> Candidates(R.begin(), R.end());
- for (SmallVectorImpl<NamedDecl *>::iterator I = Candidates.begin(),
- E = Candidates.end();
- I != E; ++I) {
- NamedDecl *Cand = *I;
-
+ for (auto *Cand : Candidates) {
if (Cand->isInvalidDecl())
continue;
@@ -2585,12 +2494,12 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
dyn_cast<FunctionTemplateDecl>(Cand)) {
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
AddMethodTemplateCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public),
- RD, 0, ThisTy, Classification,
+ RD, nullptr, ThisTy, Classification,
llvm::makeArrayRef(&Arg, NumArgs),
OCS, true);
else
AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public),
- 0, llvm::makeArrayRef(&Arg, NumArgs),
+ nullptr, llvm::makeArrayRef(&Arg, NumArgs),
OCS, true);
} else {
assert(isa<UsingDecl>(Cand) && "illegal Kind of operator = Decl");
@@ -2610,12 +2519,12 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
break;
case OR_Ambiguous:
- Result->setMethod(0);
+ Result->setMethod(nullptr);
Result->setKind(SpecialMemberOverloadResult::Ambiguous);
break;
case OR_No_Viable_Function:
- Result->setMethod(0);
+ Result->setMethod(nullptr);
Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted);
break;
}
@@ -2812,14 +2721,8 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
// operator template, but not both.
if (FoundRaw && FoundTemplate) {
Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) << R.getLookupName();
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- Decl *D = *I;
- if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D))
- D = USD->getTargetDecl();
- if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D))
- D = FunTmpl->getTemplatedDecl();
- NoteOverloadCandidate(cast<FunctionDecl>(D));
- }
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
+ NoteOverloadCandidate((*I)->getUnderlyingDecl()->getAsFunction());
return LOLR_Error;
}
@@ -2845,20 +2748,14 @@ void ADLResult::insert(NamedDecl *New) {
// If we haven't yet seen a decl for this key, or the last decl
// was exactly this one, we're done.
- if (Old == 0 || Old == New) {
+ if (Old == nullptr || Old == New) {
Old = New;
return;
}
// Otherwise, decide which is a more recent redeclaration.
- FunctionDecl *OldFD, *NewFD;
- if (isa<FunctionTemplateDecl>(New)) {
- OldFD = cast<FunctionTemplateDecl>(Old)->getTemplatedDecl();
- NewFD = cast<FunctionTemplateDecl>(New)->getTemplatedDecl();
- } else {
- OldFD = cast<FunctionDecl>(Old);
- NewFD = cast<FunctionDecl>(New);
- }
+ FunctionDecl *OldFD = Old->getAsFunction();
+ FunctionDecl *NewFD = New->getAsFunction();
FunctionDecl *Cursor = NewFD;
while (true) {
@@ -2877,9 +2774,8 @@ void ADLResult::insert(NamedDecl *New) {
Old = New;
}
-void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
- SourceLocation Loc, ArrayRef<Expr *> Args,
- ADLResult &Result) {
+void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
+ ArrayRef<Expr *> Args, ADLResult &Result) {
// Find all of the associated namespaces and classes based on the
// arguments we have.
AssociatedNamespaceSet AssociatedNamespaces;
@@ -2888,13 +2784,6 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
AssociatedNamespaces,
AssociatedClasses);
- QualType T1, T2;
- if (Operator) {
- T1 = Args[0]->getType();
- if (Args.size() >= 2)
- T2 = Args[1]->getType();
- }
-
// C++ [basic.lookup.argdep]p3:
// Let X be the lookup set produced by unqualified lookup (3.4.1)
// and let Y be the lookup set produced by argument dependent
@@ -2906,9 +2795,7 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
//
// Here, we compute Y and add its members to the overloaded
// candidate set.
- for (AssociatedNamespaceSet::iterator NS = AssociatedNamespaces.begin(),
- NSEnd = AssociatedNamespaces.end();
- NS != NSEnd; ++NS) {
+ for (auto *NS : AssociatedNamespaces) {
// When considering an associated namespace, the lookup is the
// same as the lookup performed when the associated namespace is
// used as a qualifier (3.4.3.2) except that:
@@ -2920,10 +2807,8 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
// associated classes are visible within their respective
// namespaces even if they are not visible during an ordinary
// lookup (11.4).
- DeclContext::lookup_result R = (*NS)->lookup(Name);
- for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
- ++I) {
- NamedDecl *D = *I;
+ DeclContext::lookup_result R = NS->lookup(Name);
+ for (auto *D : R) {
// If the only declaration here is an ordinary friend, consider
// it only if it was declared in an associated classes.
if ((D->getIdentifierNamespace() & Decl::IDNS_Ordinary) == 0) {
@@ -2947,12 +2832,7 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
- if (isa<FunctionDecl>(D)) {
- if (Operator &&
- !IsAcceptableNonMemberOperatorCandidate(cast<FunctionDecl>(D),
- T1, T2, Context))
- continue;
- } else if (!isa<FunctionTemplateDecl>(D))
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D))
continue;
Result.insert(D);
@@ -3045,35 +2925,33 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
if (Pos == SM->end())
continue;
- for (ShadowMapEntry::iterator I = Pos->second.begin(),
- IEnd = Pos->second.end();
- I != IEnd; ++I) {
+ for (auto *D : Pos->second) {
// A tag declaration does not hide a non-tag declaration.
- if ((*I)->hasTagIdentifierNamespace() &&
+ if (D->hasTagIdentifierNamespace() &&
(IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary |
Decl::IDNS_ObjCProtocol)))
continue;
// Protocols are in distinct namespaces from everything else.
- if ((((*I)->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol)
+ if (((D->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol)
|| (IDNS & Decl::IDNS_ObjCProtocol)) &&
- (*I)->getIdentifierNamespace() != IDNS)
+ D->getIdentifierNamespace() != IDNS)
continue;
// Functions and function templates in the same scope overload
// rather than hide. FIXME: Look for hiding based on function
// signatures!
- if ((*I)->isFunctionOrFunctionTemplate() &&
- ND->isFunctionOrFunctionTemplate() &&
+ if (D->getUnderlyingDecl()->isFunctionOrFunctionTemplate() &&
+ ND->getUnderlyingDecl()->isFunctionOrFunctionTemplate() &&
SM == ShadowMaps.rbegin())
continue;
// We've found a declaration that hides this one.
- return *I;
+ return D;
}
}
- return 0;
+ return nullptr;
}
static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
@@ -3092,13 +2970,9 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
Result.getSema().ForceDeclarationOfImplicitMembers(Class);
// Enumerate all of the results in this context.
- for (DeclContext::all_lookups_iterator L = Ctx->lookups_begin(),
- LEnd = Ctx->lookups_end();
- L != LEnd; ++L) {
- DeclContext::lookup_result R = *L;
- for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
- ++I) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(*I)) {
+ for (const auto &R : Ctx->lookups()) {
+ for (auto *I : R) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(I)) {
if ((ND = Result.getAcceptableDecl(ND))) {
Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
Visited.add(ND);
@@ -3110,9 +2984,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
// Traverse using directives for qualified name lookup.
if (QualifiedNameLookup) {
ShadowContextRAII Shadow(Visited);
- DeclContext::udir_iterator I, E;
- for (llvm::tie(I, E) = Ctx->getUsingDirectives(); I != E; ++I) {
- LookupVisibleDecls((*I)->getNominatedNamespace(), Result,
+ for (auto I : Ctx->using_directives()) {
+ LookupVisibleDecls(I->getNominatedNamespace(), Result,
QualifiedNameLookup, InBaseClass, Consumer, Visited);
}
}
@@ -3122,10 +2995,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
if (!Record->hasDefinition())
return;
- for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(),
- BEnd = Record->bases_end();
- B != BEnd; ++B) {
- QualType BaseType = B->getType();
+ for (const auto &B : Record->bases()) {
+ QualType BaseType = B.getType();
// Don't look into dependent bases, because name lookup can't look
// there anyway.
@@ -3165,21 +3036,16 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
// Traverse the contexts of Objective-C classes.
if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) {
// Traverse categories.
- for (ObjCInterfaceDecl::visible_categories_iterator
- Cat = IFace->visible_categories_begin(),
- CatEnd = IFace->visible_categories_end();
- Cat != CatEnd; ++Cat) {
+ for (auto *Cat : IFace->visible_categories()) {
ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(*Cat, Result, QualifiedNameLookup, false,
+ LookupVisibleDecls(Cat, Result, QualifiedNameLookup, false,
Consumer, Visited);
}
// Traverse protocols.
- for (ObjCInterfaceDecl::all_protocol_iterator
- I = IFace->all_referenced_protocol_begin(),
- E = IFace->all_referenced_protocol_end(); I != E; ++I) {
+ for (auto *I : IFace->all_referenced_protocols()) {
ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
+ LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer,
Visited);
}
@@ -3198,17 +3064,15 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
QualifiedNameLookup, InBaseClass, Consumer, Visited);
}
} else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) {
- for (ObjCProtocolDecl::protocol_iterator I = Protocol->protocol_begin(),
- E = Protocol->protocol_end(); I != E; ++I) {
+ for (auto *I : Protocol->protocols()) {
ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
+ LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer,
Visited);
}
} else if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Ctx)) {
- for (ObjCCategoryDecl::protocol_iterator I = Category->protocol_begin(),
- E = Category->protocol_end(); I != E; ++I) {
+ for (auto *I : Category->protocols()) {
ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
+ LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer,
Visited);
}
@@ -3234,18 +3098,17 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
(S->getEntity())->isFunctionOrMethod()) {
FindLocalExternScope FindLocals(Result);
// Walk through the declarations in this Scope.
- for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
- D != DEnd; ++D) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
+ for (auto *D : S->decls()) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
if ((ND = Result.getAcceptableDecl(ND))) {
- Consumer.FoundDecl(ND, Visited.checkHidden(ND), 0, false);
+ Consumer.FoundDecl(ND, Visited.checkHidden(ND), nullptr, false);
Visited.add(ND);
}
}
}
// FIXME: C++ [temp.local]p8
- DeclContext *Entity = 0;
+ DeclContext *Entity = nullptr;
if (S->getEntity()) {
// Look into this scope's declaration context, along with any of its
// parent lookup contexts (e.g., enclosing classes), up to the point
@@ -3297,7 +3160,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
// Lookup visible declarations in any namespaces found by using
// directives.
UnqualUsingDirectiveSet::const_iterator UI, UEnd;
- llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(Entity);
+ std::tie(UI, UEnd) = UDirs.getNamespacesFor(Entity);
for (; UI != UEnd; ++UI)
LookupVisibleDecls(const_cast<DeclContext *>(UI->getNominatedNamespace()),
Result, /*QualifiedNameLookup=*/false,
@@ -3355,7 +3218,7 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc,
SourceLocation GnuLabelLoc) {
// Do a lookup to see if we have a label with this name already.
- NamedDecl *Res = 0;
+ NamedDecl *Res = nullptr;
if (GnuLabelLoc.isValid()) {
// Local label definitions always shadow existing labels.
@@ -3370,8 +3233,8 @@ LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc,
// If we found a label, check to see if it is in the same context as us.
// When in a Block, we don't want to reuse a label in an enclosing function.
if (Res && Res->getDeclContext() != CurContext)
- Res = 0;
- if (Res == 0) {
+ Res = nullptr;
+ if (!Res) {
// If not forward referenced or defined already, create the backing decl.
Res = LabelDecl::Create(Context, CurContext, Loc, II);
Scope *S = CurScope->getFnParent();
@@ -3385,54 +3248,106 @@ LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc,
// Typo correction
//===----------------------------------------------------------------------===//
-namespace {
+static bool isCandidateViable(CorrectionCandidateCallback &CCC,
+ TypoCorrection &Candidate) {
+ Candidate.setCallbackDistance(CCC.RankCandidate(Candidate));
+ return Candidate.getEditDistance(false) != TypoCorrection::InvalidDistance;
+}
-typedef SmallVector<TypoCorrection, 1> TypoResultList;
-typedef llvm::StringMap<TypoResultList, llvm::BumpPtrAllocator> TypoResultsMap;
-typedef std::map<unsigned, TypoResultsMap> TypoEditDistanceMap;
+static void LookupPotentialTypoResult(Sema &SemaRef,
+ LookupResult &Res,
+ IdentifierInfo *Name,
+ Scope *S, CXXScopeSpec *SS,
+ DeclContext *MemberContext,
+ bool EnteringContext,
+ bool isObjCIvarLookup,
+ bool FindHidden);
-static const unsigned MaxTypoDistanceResultSets = 5;
+// Fill the supplied vector with the IdentifierInfo pointers for each piece of
+// the given NestedNameSpecifier (i.e. given a NestedNameSpecifier "foo::bar::",
+// fill the vector with the IdentifierInfo pointers for "foo" and "bar").
+static void getNestedNameSpecifierIdentifiers(
+ NestedNameSpecifier *NNS,
+ SmallVectorImpl<const IdentifierInfo*> &Identifiers) {
+ if (NestedNameSpecifier *Prefix = NNS->getPrefix())
+ getNestedNameSpecifierIdentifiers(Prefix, Identifiers);
+ else
+ Identifiers.clear();
-class TypoCorrectionConsumer : public VisibleDeclConsumer {
- /// \brief The name written that is a typo in the source.
- StringRef Typo;
+ const IdentifierInfo *II = nullptr;
- /// \brief The results found that have the smallest edit distance
- /// found (so far) with the typo name.
- ///
- /// The pointer value being set to the current DeclContext indicates
- /// whether there is a keyword with this name.
- TypoEditDistanceMap CorrectionResults;
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ II = NNS->getAsIdentifier();
+ break;
- Sema &SemaRef;
+ case NestedNameSpecifier::Namespace:
+ if (NNS->getAsNamespace()->isAnonymousNamespace())
+ return;
+ II = NNS->getAsNamespace()->getIdentifier();
+ break;
+
+ case NestedNameSpecifier::NamespaceAlias:
+ II = NNS->getAsNamespaceAlias()->getIdentifier();
+ break;
+
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ case NestedNameSpecifier::TypeSpec:
+ II = QualType(NNS->getAsType(), 0).getBaseTypeIdentifier();
+ break;
+
+ case NestedNameSpecifier::Global:
+ return;
+ }
+
+ if (II)
+ Identifiers.push_back(II);
+}
+
+namespace {
+
+static const unsigned MaxTypoDistanceResultSets = 5;
+
+class TypoCorrectionConsumer : public VisibleDeclConsumer {
+ typedef SmallVector<TypoCorrection, 1> TypoResultList;
+ typedef llvm::StringMap<TypoResultList> TypoResultsMap;
+ typedef std::map<unsigned, TypoResultsMap> TypoEditDistanceMap;
public:
- explicit TypoCorrectionConsumer(Sema &SemaRef, IdentifierInfo *Typo)
- : Typo(Typo->getName()),
- SemaRef(SemaRef) {}
+ explicit TypoCorrectionConsumer(Sema &SemaRef,
+ const DeclarationNameInfo &TypoName,
+ Sema::LookupNameKind LookupKind,
+ Scope *S, CXXScopeSpec *SS,
+ CorrectionCandidateCallback &CCC,
+ DeclContext *MemberContext,
+ bool EnteringContext)
+ : Typo(TypoName.getName().getAsIdentifierInfo()), SemaRef(SemaRef), S(S),
+ SS(SS), CorrectionValidator(CCC), MemberContext(MemberContext),
+ Result(SemaRef, TypoName, LookupKind),
+ Namespaces(SemaRef.Context, SemaRef.CurContext, SS),
+ EnteringContext(EnteringContext), SearchNamespaces(false) {
+ Result.suppressDiagnostics();
+ }
- bool includeHiddenDecls() const { return true; }
+ bool includeHiddenDecls() const override { return true; }
- virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
- bool InBaseClass);
+ // Methods for adding potential corrections to the consumer.
+ void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
+ bool InBaseClass) override;
void FoundName(StringRef Name);
void addKeywordResult(StringRef Keyword);
- void addName(StringRef Name, NamedDecl *ND, NestedNameSpecifier *NNS = NULL,
- bool isKeyword = false);
void addCorrection(TypoCorrection Correction);
- typedef TypoResultsMap::iterator result_iterator;
- typedef TypoEditDistanceMap::iterator distance_iterator;
- distance_iterator begin() { return CorrectionResults.begin(); }
- distance_iterator end() { return CorrectionResults.end(); }
- void erase(distance_iterator I) { CorrectionResults.erase(I); }
- unsigned size() const { return CorrectionResults.size(); }
bool empty() const { return CorrectionResults.empty(); }
+ /// \brief Return the list of TypoCorrections for the given identifier from
+ /// the set of corrections that have the closest edit distance, if any.
TypoResultList &operator[](StringRef Name) {
return CorrectionResults.begin()->second[Name];
}
+ /// \brief Return the edit distance of the corrections that have the
+ /// closest/best edit distance from the original typop.
unsigned getBestEditDistance(bool Normalized) {
if (CorrectionResults.empty())
return (std::numeric_limits<unsigned>::max)();
@@ -3441,10 +3356,101 @@ public:
return Normalized ? TypoCorrection::NormalizeEditDistance(BestED) : BestED;
}
- TypoResultsMap &getBestResults() {
- return CorrectionResults.begin()->second;
- }
+ /// \brief Set-up method to add to the consumer the set of namespaces to use
+ /// in performing corrections to nested name specifiers. This method also
+ /// implicitly adds all of the known classes in the current AST context to the
+ /// to the consumer for correcting nested name specifiers.
+ void
+ addNamespaces(const llvm::MapVector<NamespaceDecl *, bool> &KnownNamespaces);
+
+ /// \brief Return the next typo correction that passes all internal filters
+ /// and is deemed valid by the consumer's CorrectionCandidateCallback,
+ /// starting with the corrections that have the closest edit distance. An
+ /// empty TypoCorrection is returned once no more viable corrections remain
+ /// in the consumer.
+ TypoCorrection getNextCorrection();
+
+private:
+ class NamespaceSpecifierSet {
+ struct SpecifierInfo {
+ DeclContext* DeclCtx;
+ NestedNameSpecifier* NameSpecifier;
+ unsigned EditDistance;
+ };
+
+ typedef SmallVector<DeclContext*, 4> DeclContextList;
+ typedef SmallVector<SpecifierInfo, 16> SpecifierInfoList;
+
+ ASTContext &Context;
+ DeclContextList CurContextChain;
+ std::string CurNameSpecifier;
+ SmallVector<const IdentifierInfo*, 4> CurContextIdentifiers;
+ SmallVector<const IdentifierInfo*, 4> CurNameSpecifierIdentifiers;
+ 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();
+
+ unsigned buildNestedNameSpecifier(DeclContextList &DeclChain,
+ NestedNameSpecifier *&NNS);
+
+ public:
+ NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext,
+ CXXScopeSpec *CurScopeSpec);
+
+ /// \brief Add the DeclContext (a namespace or record) to the set, computing
+ /// the corresponding NestedNameSpecifier and its distance in the process.
+ void addNameSpecifier(DeclContext *Ctx);
+
+ typedef SpecifierInfoList::iterator iterator;
+ iterator begin() {
+ if (!isSorted) sortNamespaces();
+ return Specifiers.begin();
+ }
+ iterator end() { return Specifiers.end(); }
+ };
+
+ void addName(StringRef Name, NamedDecl *ND,
+ NestedNameSpecifier *NNS = nullptr, bool isKeyword = false);
+
+ /// \brief Find any visible decls for the given typo correction candidate.
+ /// If none are found, it to the set of candidates for which qualified lookups
+ /// will be performed to find possible nested name specifier changes.
+ bool resolveCorrection(TypoCorrection &Candidate);
+
+ /// \brief Perform qualified lookups on the queued set of typo correction
+ /// candidates and add the nested name specifier changes to each candidate if
+ /// a lookup succeeds (at which point the candidate will be returned to the
+ /// main pool of potential corrections).
+ void performQualifiedLookups();
+ /// \brief The name written that is a typo in the source.
+ IdentifierInfo *Typo;
+
+ /// \brief The results found that have the smallest edit distance
+ /// found (so far) with the typo name.
+ ///
+ /// The pointer value being set to the current DeclContext indicates
+ /// whether there is a keyword with this name.
+ TypoEditDistanceMap CorrectionResults;
+
+ Sema &SemaRef;
+ Scope *S;
+ CXXScopeSpec *SS;
+ CorrectionCandidateCallback &CorrectionValidator;
+ DeclContext *MemberContext;
+ LookupResult Result;
+ NamespaceSpecifierSet Namespaces;
+ SmallVector<TypoCorrection, 2> QualifiedResults;
+ bool EnteringContext;
+ bool SearchNamespaces;
};
}
@@ -3464,7 +3470,7 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
// Only consider visible declarations and declarations from modules with
// names that exactly match.
- if (!LookupResult::isVisible(SemaRef, ND) && Name->getName() != Typo &&
+ if (!LookupResult::isVisible(SemaRef, ND) && Name != Typo &&
!findAcceptableDecl(SemaRef, ND))
return;
@@ -3474,27 +3480,28 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
void TypoCorrectionConsumer::FoundName(StringRef Name) {
// Compute the edit distance between the typo and the name of this
// entity, and add the identifier to the list of results.
- addName(Name, NULL);
+ addName(Name, nullptr);
}
void TypoCorrectionConsumer::addKeywordResult(StringRef Keyword) {
// Compute the edit distance between the typo and this keyword,
// and add the keyword to the list of results.
- addName(Keyword, NULL, NULL, true);
+ addName(Keyword, nullptr, nullptr, true);
}
void TypoCorrectionConsumer::addName(StringRef Name, NamedDecl *ND,
NestedNameSpecifier *NNS, bool isKeyword) {
// 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 && Typo.size() / MinED < 3)
+ StringRef TypoStr = Typo->getName();
+ unsigned MinED = abs((int)Name.size() - (int)TypoStr.size());
+ if (MinED && TypoStr.size() / MinED < 3)
return;
// Compute an upper bound on the allowable edit distance, so that the
// edit-distance algorithm can short-circuit.
- unsigned UpperBound = (Typo.size() + 2) / 3 + 1;
- unsigned ED = Typo.edit_distance(Name, true, UpperBound);
+ unsigned UpperBound = (TypoStr.size() + 2) / 3 + 1;
+ unsigned ED = TypoStr.edit_distance(Name, true, UpperBound);
if (ED >= UpperBound) return;
TypoCorrection TC(&SemaRef.Context.Idents.get(Name), ND, NNS, ED);
@@ -3503,7 +3510,21 @@ void TypoCorrectionConsumer::addName(StringRef Name, NamedDecl *ND,
}
void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) {
+ StringRef TypoStr = Typo->getName();
StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName();
+
+ // For very short typos, ignore potential corrections that have a different
+ // base identifier from the typo or which have a normalized edit distance
+ // longer than the typo itself.
+ if (TypoStr.size() < 3 &&
+ (Name != TypoStr || Correction.getEditDistance(true) > TypoStr.size()))
+ return;
+
+ // If the correction is resolved but is not viable, ignore it.
+ if (Correction.isResolved() &&
+ !isCandidateViable(CorrectionValidator, Correction))
+ return;
+
TypoResultList &CList =
CorrectionResults[Correction.getEditDistance(false)][Name];
@@ -3528,130 +3549,212 @@ void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) {
CList.push_back(Correction);
while (CorrectionResults.size() > MaxTypoDistanceResultSets)
- erase(llvm::prior(CorrectionResults.end()));
+ CorrectionResults.erase(std::prev(CorrectionResults.end()));
}
-// Fill the supplied vector with the IdentifierInfo pointers for each piece of
-// the given NestedNameSpecifier (i.e. given a NestedNameSpecifier "foo::bar::",
-// fill the vector with the IdentifierInfo pointers for "foo" and "bar").
-static void getNestedNameSpecifierIdentifiers(
- NestedNameSpecifier *NNS,
- SmallVectorImpl<const IdentifierInfo*> &Identifiers) {
- if (NestedNameSpecifier *Prefix = NNS->getPrefix())
- getNestedNameSpecifierIdentifiers(Prefix, Identifiers);
- else
- Identifiers.clear();
+void TypoCorrectionConsumer::addNamespaces(
+ const llvm::MapVector<NamespaceDecl *, bool> &KnownNamespaces) {
+ SearchNamespaces = true;
- const IdentifierInfo *II = NULL;
+ for (auto KNPair : KnownNamespaces)
+ Namespaces.addNameSpecifier(KNPair.first);
- switch (NNS->getKind()) {
- case NestedNameSpecifier::Identifier:
- II = NNS->getAsIdentifier();
- break;
+ bool SSIsTemplate = false;
+ if (NestedNameSpecifier *NNS =
+ (SS && SS->isValid()) ? SS->getScopeRep() : nullptr) {
+ if (const Type *T = NNS->getAsType())
+ SSIsTemplate = T->getTypeClass() == Type::TemplateSpecialization;
+ }
+ for (const auto *TI : SemaRef.getASTContext().types()) {
+ if (CXXRecordDecl *CD = TI->getAsCXXRecordDecl()) {
+ CD = CD->getCanonicalDecl();
+ if (!CD->isDependentType() && !CD->isAnonymousStructOrUnion() &&
+ !CD->isUnion() && CD->getIdentifier() &&
+ (SSIsTemplate || !isa<ClassTemplateSpecializationDecl>(CD)) &&
+ (CD->isBeingDefined() || CD->isCompleteDefinition()))
+ Namespaces.addNameSpecifier(CD);
+ }
+ }
+}
- case NestedNameSpecifier::Namespace:
- if (NNS->getAsNamespace()->isAnonymousNamespace())
- return;
- II = NNS->getAsNamespace()->getIdentifier();
- break;
+TypoCorrection TypoCorrectionConsumer::getNextCorrection() {
+ while (!CorrectionResults.empty()) {
+ auto DI = CorrectionResults.begin();
+ if (DI->second.empty()) {
+ CorrectionResults.erase(DI);
+ continue;
+ }
- case NestedNameSpecifier::NamespaceAlias:
- II = NNS->getAsNamespaceAlias()->getIdentifier();
+ auto RI = DI->second.begin();
+ if (RI->second.empty()) {
+ DI->second.erase(RI);
+ performQualifiedLookups();
+ continue;
+ }
+
+ TypoCorrection TC = RI->second.pop_back_val();
+ if (TC.isResolved() || resolveCorrection(TC))
+ return TC;
+ }
+ return TypoCorrection();
+}
+
+bool TypoCorrectionConsumer::resolveCorrection(TypoCorrection &Candidate) {
+ IdentifierInfo *Name = Candidate.getCorrectionAsIdentifierInfo();
+ DeclContext *TempMemberContext = MemberContext;
+ CXXScopeSpec *TempSS = SS;
+retry_lookup:
+ LookupPotentialTypoResult(SemaRef, Result, Name, S, TempSS, TempMemberContext,
+ EnteringContext,
+ CorrectionValidator.IsObjCIvarLookup,
+ Name == Typo && !Candidate.WillReplaceSpecifier());
+ switch (Result.getResultKind()) {
+ case LookupResult::NotFound:
+ case LookupResult::NotFoundInCurrentInstantiation:
+ case LookupResult::FoundUnresolvedValue:
+ if (TempSS) {
+ // Immediately retry the lookup without the given CXXScopeSpec
+ TempSS = nullptr;
+ Candidate.WillReplaceSpecifier(true);
+ goto retry_lookup;
+ }
+ if (TempMemberContext) {
+ if (SS && !TempSS)
+ TempSS = SS;
+ TempMemberContext = nullptr;
+ goto retry_lookup;
+ }
+ if (SearchNamespaces)
+ QualifiedResults.push_back(Candidate);
break;
- case NestedNameSpecifier::TypeSpecWithTemplate:
- case NestedNameSpecifier::TypeSpec:
- II = QualType(NNS->getAsType(), 0).getBaseTypeIdentifier();
+ case LookupResult::Ambiguous:
+ // We don't deal with ambiguities.
break;
- case NestedNameSpecifier::Global:
- return;
+ case LookupResult::Found:
+ case LookupResult::FoundOverloaded:
+ // Store all of the Decls for overloaded symbols
+ for (auto *TRD : Result)
+ Candidate.addCorrectionDecl(TRD);
+ if (!isCandidateViable(CorrectionValidator, Candidate)) {
+ if (SearchNamespaces)
+ QualifiedResults.push_back(Candidate);
+ break;
+ }
+ return true;
}
-
- if (II)
- Identifiers.push_back(II);
+ return false;
}
-namespace {
-
-class SpecifierInfo {
- public:
- DeclContext* DeclCtx;
- NestedNameSpecifier* NameSpecifier;
- unsigned EditDistance;
+void TypoCorrectionConsumer::performQualifiedLookups() {
+ unsigned TypoLen = Typo->getName().size();
+ for (auto QR : QualifiedResults) {
+ for (auto NSI : Namespaces) {
+ DeclContext *Ctx = NSI.DeclCtx;
+ const Type *NSType = NSI.NameSpecifier->getAsType();
+
+ // If the current NestedNameSpecifier refers to a class and the
+ // current correction candidate is the name of that class, then skip
+ // it as it is unlikely a qualified version of the class' constructor
+ // is an appropriate correction.
+ if (CXXRecordDecl *NSDecl = NSType ? NSType->getAsCXXRecordDecl() : 0) {
+ if (NSDecl->getIdentifier() == QR.getCorrectionAsIdentifierInfo())
+ continue;
+ }
- SpecifierInfo(DeclContext *Ctx, NestedNameSpecifier *NNS, unsigned ED)
- : DeclCtx(Ctx), NameSpecifier(NNS), EditDistance(ED) {}
-};
+ TypoCorrection TC(QR);
+ TC.ClearCorrectionDecls();
+ TC.setCorrectionSpecifier(NSI.NameSpecifier);
+ TC.setQualifierDistance(NSI.EditDistance);
+ TC.setCallbackDistance(0); // Reset the callback distance
+
+ // If the current correction candidate and namespace combination are
+ // too far away from the original typo based on the normalized edit
+ // distance, then skip performing a qualified name lookup.
+ unsigned TmpED = TC.getEditDistance(true);
+ if (QR.getCorrectionAsIdentifierInfo() != Typo && TmpED &&
+ TypoLen / TmpED < 3)
+ continue;
-typedef SmallVector<DeclContext*, 4> DeclContextList;
-typedef SmallVector<SpecifierInfo, 16> SpecifierInfoList;
-
-class NamespaceSpecifierSet {
- ASTContext &Context;
- DeclContextList CurContextChain;
- std::string CurNameSpecifier;
- SmallVector<const IdentifierInfo*, 4> CurContextIdentifiers;
- SmallVector<const IdentifierInfo*, 4> CurNameSpecifierIdentifiers;
- 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:
- NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext,
- CXXScopeSpec *CurScopeSpec)
- : Context(Context), CurContextChain(BuildContextChain(CurContext)),
- isSorted(false) {
- if (NestedNameSpecifier *NNS =
- CurScopeSpec ? CurScopeSpec->getScopeRep() : 0) {
- llvm::raw_string_ostream SpecifierOStream(CurNameSpecifier);
- NNS->print(SpecifierOStream, Context.getPrintingPolicy());
+ Result.clear();
+ Result.setLookupName(QR.getCorrectionAsIdentifierInfo());
+ if (!SemaRef.LookupQualifiedName(Result, Ctx))
+ continue;
- getNestedNameSpecifierIdentifiers(NNS, CurNameSpecifierIdentifiers);
- }
- // Build the list of identifiers that would be used for an absolute
- // (from the global context) NestedNameSpecifier referring to the current
- // context.
- for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(),
- CEnd = CurContextChain.rend();
- C != CEnd; ++C) {
- if (NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C))
- CurContextIdentifiers.push_back(ND->getIdentifier());
+ // Any corrections added below will be validated in subsequent
+ // iterations of the main while() loop over the Consumer's contents.
+ switch (Result.getResultKind()) {
+ case LookupResult::Found:
+ case LookupResult::FoundOverloaded: {
+ if (SS && SS->isValid()) {
+ std::string NewQualified = TC.getAsString(SemaRef.getLangOpts());
+ std::string OldQualified;
+ llvm::raw_string_ostream OldOStream(OldQualified);
+ SS->getScopeRep()->print(OldOStream, SemaRef.getPrintingPolicy());
+ OldOStream << Typo->getName();
+ // If correction candidate would be an identical written qualified
+ // identifer, then the existing CXXScopeSpec probably included a
+ // typedef that didn't get accounted for properly.
+ if (OldOStream.str() == NewQualified)
+ break;
+ }
+ for (LookupResult::iterator TRD = Result.begin(), TRDEnd = Result.end();
+ TRD != TRDEnd; ++TRD) {
+ if (SemaRef.CheckMemberAccess(TC.getCorrectionRange().getBegin(),
+ NSType ? NSType->getAsCXXRecordDecl()
+ : nullptr,
+ TRD.getPair()) == Sema::AR_accessible)
+ TC.addCorrectionDecl(*TRD);
+ }
+ if (TC.isResolved())
+ addCorrection(TC);
+ break;
+ }
+ case LookupResult::NotFound:
+ case LookupResult::NotFoundInCurrentInstantiation:
+ case LookupResult::Ambiguous:
+ case LookupResult::FoundUnresolvedValue:
+ break;
+ }
}
-
- // Add the global context as a NestedNameSpecifier
- Distances.insert(1);
- DistanceMap[1].push_back(
- SpecifierInfo(cast<DeclContext>(Context.getTranslationUnitDecl()),
- NestedNameSpecifier::GlobalSpecifier(Context), 1));
}
+ QualifiedResults.clear();
+}
- /// \brief Add the DeclContext (a namespace or record) to the set, computing
- /// the corresponding NestedNameSpecifier and its distance in the process.
- void AddNameSpecifier(DeclContext *Ctx);
+TypoCorrectionConsumer::NamespaceSpecifierSet::NamespaceSpecifierSet(
+ ASTContext &Context, DeclContext *CurContext, CXXScopeSpec *CurScopeSpec)
+ : Context(Context), CurContextChain(buildContextChain(CurContext)),
+ isSorted(false) {
+ if (NestedNameSpecifier *NNS =
+ CurScopeSpec ? CurScopeSpec->getScopeRep() : nullptr) {
+ llvm::raw_string_ostream SpecifierOStream(CurNameSpecifier);
+ NNS->print(SpecifierOStream, Context.getPrintingPolicy());
- typedef SpecifierInfoList::iterator iterator;
- iterator begin() {
- if (!isSorted) SortNamespaces();
- return Specifiers.begin();
+ getNestedNameSpecifierIdentifiers(NNS, CurNameSpecifierIdentifiers);
+ }
+ // Build the list of identifiers that would be used for an absolute
+ // (from the global context) NestedNameSpecifier referring to the current
+ // context.
+ for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(),
+ CEnd = CurContextChain.rend();
+ C != CEnd; ++C) {
+ if (NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C))
+ CurContextIdentifiers.push_back(ND->getIdentifier());
}
- iterator end() { return Specifiers.end(); }
-};
+ // Add the global context as a NestedNameSpecifier
+ Distances.insert(1);
+ SpecifierInfo SI = {cast<DeclContext>(Context.getTranslationUnitDecl()),
+ NestedNameSpecifier::GlobalSpecifier(Context), 1};
+ DistanceMap[1].push_back(SI);
}
-DeclContextList NamespaceSpecifierSet::BuildContextChain(DeclContext *Start) {
+auto TypoCorrectionConsumer::NamespaceSpecifierSet::buildContextChain(
+ DeclContext *Start) -> DeclContextList {
assert(Start && "Building a context chain from a null context");
DeclContextList Chain;
- for (DeclContext *DC = Start->getPrimaryContext(); DC != NULL;
+ for (DeclContext *DC = Start->getPrimaryContext(); DC != nullptr;
DC = DC->getLookupParent()) {
NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(DC);
if (!DC->isInlineNamespace() && !DC->isTransparentContext() &&
@@ -3661,7 +3764,7 @@ DeclContextList NamespaceSpecifierSet::BuildContextChain(DeclContext *Start) {
return Chain;
}
-void NamespaceSpecifierSet::SortNamespaces() {
+void TypoCorrectionConsumer::NamespaceSpecifierSet::sortNamespaces() {
SmallVector<unsigned, 4> sortedDistances;
sortedDistances.append(Distances.begin(), Distances.end());
@@ -3669,19 +3772,17 @@ void NamespaceSpecifierSet::SortNamespaces() {
std::sort(sortedDistances.begin(), sortedDistances.end());
Specifiers.clear();
- for (SmallVectorImpl<unsigned>::iterator DI = sortedDistances.begin(),
- DIEnd = sortedDistances.end();
- DI != DIEnd; ++DI) {
- SpecifierInfoList &SpecList = DistanceMap[*DI];
+ for (auto D : sortedDistances) {
+ SpecifierInfoList &SpecList = DistanceMap[D];
Specifiers.append(SpecList.begin(), SpecList.end());
}
isSorted = true;
}
-static unsigned BuildNestedNameSpecifier(ASTContext &Context,
- DeclContextList &DeclChain,
- NestedNameSpecifier *&NNS) {
+unsigned
+TypoCorrectionConsumer::NamespaceSpecifierSet::buildNestedNameSpecifier(
+ DeclContextList &DeclChain, NestedNameSpecifier *&NNS) {
unsigned NumSpecifiers = 0;
for (DeclContextList::reverse_iterator C = DeclChain.rbegin(),
CEnd = DeclChain.rend();
@@ -3698,10 +3799,11 @@ static unsigned BuildNestedNameSpecifier(ASTContext &Context,
return NumSpecifiers;
}
-void NamespaceSpecifierSet::AddNameSpecifier(DeclContext *Ctx) {
- NestedNameSpecifier *NNS = NULL;
+void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier(
+ DeclContext *Ctx) {
+ NestedNameSpecifier *NNS = nullptr;
unsigned NumSpecifiers = 0;
- DeclContextList NamespaceDeclChain(BuildContextChain(Ctx));
+ DeclContextList NamespaceDeclChain(buildContextChain(Ctx));
DeclContextList FullNamespaceDeclChain(NamespaceDeclChain);
// Eliminate common elements from the two DeclContext chains.
@@ -3713,14 +3815,14 @@ void NamespaceSpecifierSet::AddNameSpecifier(DeclContext *Ctx) {
}
// Build the NestedNameSpecifier from what is left of the NamespaceDeclChain
- NumSpecifiers = BuildNestedNameSpecifier(Context, NamespaceDeclChain, NNS);
+ NumSpecifiers = buildNestedNameSpecifier(NamespaceDeclChain, NNS);
// Add an explicit leading '::' specifier if needed.
if (NamespaceDeclChain.empty()) {
// Rebuild the NestedNameSpecifier as a globally-qualified specifier.
NNS = NestedNameSpecifier::GlobalSpecifier(Context);
NumSpecifiers =
- BuildNestedNameSpecifier(Context, FullNamespaceDeclChain, NNS);
+ buildNestedNameSpecifier(FullNamespaceDeclChain, NNS);
} else if (NamedDecl *ND =
dyn_cast_or_null<NamedDecl>(NamespaceDeclChain.back())) {
IdentifierInfo *Name = ND->getIdentifier();
@@ -3742,7 +3844,7 @@ void NamespaceSpecifierSet::AddNameSpecifier(DeclContext *Ctx) {
// Rebuild the NestedNameSpecifier as a globally-qualified specifier.
NNS = NestedNameSpecifier::GlobalSpecifier(Context);
NumSpecifiers =
- BuildNestedNameSpecifier(Context, FullNamespaceDeclChain, NNS);
+ buildNestedNameSpecifier(FullNamespaceDeclChain, NNS);
}
}
@@ -3760,7 +3862,8 @@ void NamespaceSpecifierSet::AddNameSpecifier(DeclContext *Ctx) {
isSorted = false;
Distances.insert(NumSpecifiers);
- DistanceMap[NumSpecifiers].push_back(SpecifierInfo(Ctx, NNS, NumSpecifiers));
+ SpecifierInfo SI = {Ctx, NNS, NumSpecifiers};
+ DistanceMap[NumSpecifiers].push_back(SI);
}
/// \brief Perform name lookup for a possible result for typo correction.
@@ -3960,17 +4063,10 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
}
}
-static bool isCandidateViable(CorrectionCandidateCallback &CCC,
- TypoCorrection &Candidate) {
- Candidate.setCallbackDistance(CCC.RankCandidate(Candidate));
- return Candidate.getEditDistance(false) != TypoCorrection::InvalidDistance;
-}
-
/// \brief Check whether the declarations found for a typo correction are
/// visible, and if none of them are, convert the correction to an 'import
/// a module' correction.
-static void checkCorrectionVisibility(Sema &SemaRef, TypoCorrection &TC,
- DeclarationName TypoName) {
+static void checkCorrectionVisibility(Sema &SemaRef, TypoCorrection &TC) {
if (TC.begin() == TC.end())
return;
@@ -4045,6 +4141,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
Sema::LookupNameKind LookupKind,
Scope *S, CXXScopeSpec *SS,
CorrectionCandidateCallback &CCC,
+ CorrectTypoKind Mode,
DeclContext *MemberContext,
bool EnteringContext,
const ObjCObjectPointerType *OPT,
@@ -4064,7 +4161,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// In Microsoft mode, don't perform typo correction in a template member
// function dependent context because it interferes with the "lookup into
// dependent bases of class templates" feature.
- if (getLangOpts().MicrosoftMode && CurContext->isDependentContext() &&
+ if (getLangOpts().MSVCCompat && CurContext->isDependentContext() &&
isa<CXXMethodDecl>(CurContext))
return TypoCorrection();
@@ -4099,9 +4196,17 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
if (getLangOpts().AltiVec && Typo->isStr("vector"))
return TypoCorrection();
- NamespaceSpecifierSet Namespaces(Context, CurContext, SS);
+ // If we're handling a missing symbol error, using modules, and the
+ // special search all modules option is used, look for a missing import.
+ if ((Mode == CTK_ErrorRecovery) && getLangOpts().Modules &&
+ getLangOpts().ModulesSearchAll) {
+ // The following has the side effect of loading the missing module.
+ getModuleLoader().lookupMissingImports(Typo->getName(),
+ TypoName.getLocStart());
+ }
- TypoCorrectionConsumer Consumer(*this, Typo);
+ TypoCorrectionConsumer Consumer(*this, TypoName, LookupKind, S, SS, CCC,
+ MemberContext, EnteringContext);
// If a callback object considers an empty typo correction candidate to be
// viable, assume it does not do any actual validation of the candidates.
@@ -4116,10 +4221,8 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// Look in qualified interfaces.
if (OPT) {
- for (ObjCObjectPointerType::qual_iterator
- I = OPT->qual_begin(), E = OPT->qual_end();
- I != E; ++I)
- LookupVisibleDecls(*I, LookupKind, Consumer);
+ for (auto *I : OPT->quals())
+ LookupVisibleDecls(I, LookupKind, Consumer);
}
} else if (SS && SS->isSet()) {
QualifiedDC = computeDeclContext(*SS, EnteringContext);
@@ -4182,16 +4285,14 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// For unqualified lookup, look through all of the names that we have
// seen in this translation unit.
// FIXME: Re-add the ability to skip very unlikely potential corrections.
- for (IdentifierTable::iterator I = Context.Idents.begin(),
- IEnd = Context.Idents.end();
- I != IEnd; ++I)
- Consumer.FoundName(I->getKey());
+ for (const auto &I : Context.Idents)
+ Consumer.FoundName(I.getKey());
// Walk through identifiers in external identifier sources.
// FIXME: Re-add the ability to skip very unlikely potential corrections.
if (IdentifierInfoLookup *External
= Context.Idents.getExternalIdentifierLookup()) {
- OwningPtr<IdentifierIterator> Iter(External->getIdentifiers());
+ std::unique_ptr<IdentifierIterator> Iter(External->getIdentifiers());
do {
StringRef Name = Iter->Next();
if (Name.empty())
@@ -4224,240 +4325,19 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
SmallVector<NamespaceDecl *, 4> ExternalKnownNamespaces;
LoadedExternalKnownNamespaces = true;
ExternalSource->ReadKnownNamespaces(ExternalKnownNamespaces);
- for (unsigned I = 0, N = ExternalKnownNamespaces.size(); I != N; ++I)
- KnownNamespaces[ExternalKnownNamespaces[I]] = true;
+ for (auto *N : ExternalKnownNamespaces)
+ KnownNamespaces[N] = true;
}
- for (llvm::MapVector<NamespaceDecl*, bool>::iterator
- KNI = KnownNamespaces.begin(),
- KNIEnd = KnownNamespaces.end();
- KNI != KNIEnd; ++KNI)
- Namespaces.AddNameSpecifier(KNI->first);
-
- for (ASTContext::type_iterator TI = Context.types_begin(),
- TIEnd = Context.types_end();
- TI != TIEnd; ++TI) {
- if (CXXRecordDecl *CD = (*TI)->getAsCXXRecordDecl()) {
- CD = CD->getCanonicalDecl();
- if (!CD->isDependentType() && !CD->isAnonymousStructOrUnion() &&
- !CD->isUnion() &&
- (CD->isBeingDefined() || CD->isCompleteDefinition()))
- Namespaces.AddNameSpecifier(CD);
- }
- }
+ Consumer.addNamespaces(KnownNamespaces);
}
- // Weed out any names that could not be found by name lookup or, if a
- // CorrectionCandidateCallback object was provided, failed validation.
- SmallVector<TypoCorrection, 16> QualifiedResults;
- LookupResult TmpRes(*this, TypoName, LookupKind);
- TmpRes.suppressDiagnostics();
- while (!Consumer.empty()) {
- TypoCorrectionConsumer::distance_iterator DI = Consumer.begin();
- for (TypoCorrectionConsumer::result_iterator I = DI->second.begin(),
- IEnd = DI->second.end();
- I != IEnd; /* Increment in loop. */) {
- // If we only want nested name specifier corrections, ignore potential
- // corrections that have a different base identifier from the typo.
- if (AllowOnlyNNSChanges &&
- I->second.front().getCorrectionAsIdentifierInfo() != Typo) {
- TypoCorrectionConsumer::result_iterator Prev = I;
- ++I;
- DI->second.erase(Prev);
- continue;
- }
-
- // If the item already has been looked up or is a keyword, keep it.
- // If a validator callback object was given, drop the correction
- // unless it passes validation.
- bool Viable = false;
- for (TypoResultList::iterator RI = I->second.begin();
- RI != I->second.end(); /* Increment in loop. */) {
- TypoResultList::iterator Prev = RI;
- ++RI;
- if (Prev->isResolved()) {
- if (!isCandidateViable(CCC, *Prev))
- RI = I->second.erase(Prev);
- else
- Viable = true;
- }
- }
- if (Viable || I->second.empty()) {
- TypoCorrectionConsumer::result_iterator Prev = I;
- ++I;
- if (!Viable)
- DI->second.erase(Prev);
- continue;
- }
- assert(I->second.size() == 1 && "Expected a single unresolved candidate");
-
- // Perform name lookup on this name.
- TypoCorrection &Candidate = I->second.front();
- IdentifierInfo *Name = Candidate.getCorrectionAsIdentifierInfo();
- DeclContext *TempMemberContext = MemberContext;
- CXXScopeSpec *TempSS = SS;
-retry_lookup:
- LookupPotentialTypoResult(*this, TmpRes, Name, S, TempSS,
- TempMemberContext, EnteringContext,
- CCC.IsObjCIvarLookup,
- Name == TypoName.getName() &&
- !Candidate.WillReplaceSpecifier());
-
- switch (TmpRes.getResultKind()) {
- case LookupResult::NotFound:
- case LookupResult::NotFoundInCurrentInstantiation:
- case LookupResult::FoundUnresolvedValue:
- if (TempSS) {
- // Immediately retry the lookup without the given CXXScopeSpec
- TempSS = NULL;
- Candidate.WillReplaceSpecifier(true);
- goto retry_lookup;
- }
- if (TempMemberContext) {
- if (SS && !TempSS)
- TempSS = SS;
- TempMemberContext = NULL;
- goto retry_lookup;
- }
- QualifiedResults.push_back(Candidate);
- // 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;
-
- case LookupResult::Ambiguous:
- // We don't deal with ambiguities.
- return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
-
- case LookupResult::FoundOverloaded: {
- TypoCorrectionConsumer::result_iterator Prev = I;
- // Store all of the Decls for overloaded symbols
- for (LookupResult::iterator TRD = TmpRes.begin(),
- TRDEnd = TmpRes.end();
- TRD != TRDEnd; ++TRD)
- Candidate.addCorrectionDecl(*TRD);
- ++I;
- if (!isCandidateViable(CCC, Candidate)) {
- QualifiedResults.push_back(Candidate);
- DI->second.erase(Prev);
- }
- break;
- }
-
- case LookupResult::Found: {
- TypoCorrectionConsumer::result_iterator Prev = I;
- Candidate.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>());
- ++I;
- if (!isCandidateViable(CCC, Candidate)) {
- QualifiedResults.push_back(Candidate);
- DI->second.erase(Prev);
- }
- break;
- }
-
- }
- }
-
- if (DI->second.empty())
- Consumer.erase(DI);
- else if (!getLangOpts().CPlusPlus || QualifiedResults.empty() || !DI->first)
- // If there are results in the closest possible bucket, stop
- break;
-
- // Only perform the qualified lookups for C++
- if (SearchNamespaces) {
- TmpRes.suppressDiagnostics();
- for (SmallVector<TypoCorrection,
- 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;
- const Type *NSType = NI->NameSpecifier->getAsType();
-
- // If the current NestedNameSpecifier refers to a class and the
- // current correction candidate is the name of that class, then skip
- // it as it is unlikely a qualified version of the class' constructor
- // is an appropriate correction.
- if (CXXRecordDecl *NSDecl =
- NSType ? NSType->getAsCXXRecordDecl() : 0) {
- if (NSDecl->getIdentifier() == QRI->getCorrectionAsIdentifierInfo())
- continue;
- }
-
- TypoCorrection TC(*QRI);
- TC.ClearCorrectionDecls();
- TC.setCorrectionSpecifier(NI->NameSpecifier);
- TC.setQualifierDistance(NI->EditDistance);
- TC.setCallbackDistance(0); // Reset the callback distance
-
- // If the current correction candidate and namespace combination are
- // too far away from the original typo based on the normalized edit
- // distance, then skip performing a qualified name lookup.
- unsigned TmpED = TC.getEditDistance(true);
- if (QRI->getCorrectionAsIdentifierInfo() != Typo &&
- TmpED && TypoLen / TmpED < 3)
- continue;
-
- TmpRes.clear();
- TmpRes.setLookupName(QRI->getCorrectionAsIdentifierInfo());
- if (!LookupQualifiedName(TmpRes, Ctx)) continue;
-
- // Any corrections added below will be validated in subsequent
- // iterations of the main while() loop over the Consumer's contents.
- switch (TmpRes.getResultKind()) {
- case LookupResult::Found:
- case LookupResult::FoundOverloaded: {
- if (SS && SS->isValid()) {
- std::string NewQualified = TC.getAsString(getLangOpts());
- std::string OldQualified;
- llvm::raw_string_ostream OldOStream(OldQualified);
- SS->getScopeRep()->print(OldOStream, getPrintingPolicy());
- OldOStream << TypoName;
- // If correction candidate would be an identical written qualified
- // identifer, then the existing CXXScopeSpec probably included a
- // typedef that didn't get accounted for properly.
- if (OldOStream.str() == NewQualified)
- break;
- }
- for (LookupResult::iterator TRD = TmpRes.begin(),
- TRDEnd = TmpRes.end();
- TRD != TRDEnd; ++TRD) {
- if (CheckMemberAccess(TC.getCorrectionRange().getBegin(),
- NSType ? NSType->getAsCXXRecordDecl() : 0,
- TRD.getPair()) == AR_accessible)
- TC.addCorrectionDecl(*TRD);
- }
- if (TC.isResolved())
- Consumer.addCorrection(TC);
- break;
- }
- case LookupResult::NotFound:
- case LookupResult::NotFoundInCurrentInstantiation:
- case LookupResult::Ambiguous:
- case LookupResult::FoundUnresolvedValue:
- break;
- }
- }
- }
- }
-
- QualifiedResults.clear();
- }
-
- // No corrections remain...
- if (Consumer.empty())
+ TypoCorrection BestTC = Consumer.getNextCorrection();
+ TypoCorrection SecondBestTC = Consumer.getNextCorrection();
+ if (!BestTC)
return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
- TypoResultsMap &BestResults = Consumer.getBestResults();
- ED = Consumer.getBestEditDistance(true);
+ ED = BestTC.getEditDistance();
if (!AllowOnlyNNSChanges && ED > 0 && TypoLen / ED < 3) {
// If this was an unqualified lookup and we believe the callback
@@ -4468,11 +4348,9 @@ retry_lookup:
}
// If only a single name remains, return that result.
- if (BestResults.size() == 1) {
- const TypoResultList &CorrectionList = BestResults.begin()->second;
- const TypoCorrection &Result = CorrectionList.front();
- if (CorrectionList.size() != 1)
- return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
+ if (!SecondBestTC ||
+ SecondBestTC.getEditDistance(false) > BestTC.getEditDistance(false)) {
+ const TypoCorrection &Result = BestTC;
// Don't correct to a keyword that's the same as the typo; the keyword
// wasn't actually in scope.
@@ -4485,39 +4363,42 @@ retry_lookup:
TypoCorrection TC = Result;
TC.setCorrectionRange(SS, TypoName);
- checkCorrectionVisibility(*this, TC, TypoName.getName());
+ checkCorrectionVisibility(*this, TC);
return TC;
}
- else if (BestResults.size() > 1
- // Ugly hack equivalent to CTC == CTC_ObjCMessageReceiver;
- // WantObjCSuper is only true for CTC_ObjCMessageReceiver and for
- // some instances of CTC_Unknown, while WantRemainingKeywords is true
- // for CTC_Unknown but not for CTC_ObjCMessageReceiver.
- && CCC.WantObjCSuper && !CCC.WantRemainingKeywords
- && BestResults["super"].front().isKeyword()) {
+ // Ugly hack equivalent to CTC == CTC_ObjCMessageReceiver;
+ // WantObjCSuper is only true for CTC_ObjCMessageReceiver and for
+ // some instances of CTC_Unknown, while WantRemainingKeywords is true
+ // for CTC_Unknown but not for CTC_ObjCMessageReceiver.
+ else if (SecondBestTC && CCC.WantObjCSuper && !CCC.WantRemainingKeywords) {
// Prefer 'super' when we're completing in a message-receiver
// context.
+ if (BestTC.getCorrection().getAsString() != "super") {
+ if (SecondBestTC.getCorrection().getAsString() == "super")
+ BestTC = SecondBestTC;
+ else if (Consumer["super"].front().isKeyword())
+ BestTC = Consumer["super"].front();
+ }
// Don't correct to a keyword that's the same as the typo; the keyword
// wasn't actually in scope.
- if (ED == 0)
+ if (BestTC.getEditDistance() == 0 ||
+ BestTC.getCorrection().getAsString() != "super")
return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
// Record the correction for unqualified lookup.
if (IsUnqualifiedLookup)
- UnqualifiedTyposCorrected[Typo] = BestResults["super"].front();
+ UnqualifiedTyposCorrected[Typo] = BestTC;
- TypoCorrection TC = BestResults["super"].front();
- TC.setCorrectionRange(SS, TypoName);
- return TC;
+ BestTC.setCorrectionRange(SS, TypoName);
+ return BestTC;
}
- // If this was an unqualified lookup and we believe the callback object did
- // not filter out possible corrections, note that no correction was found.
- if (IsUnqualifiedLookup && !ValidatingCallback)
- (void)UnqualifiedTyposCorrected[Typo];
-
- return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
+ // Record the failure's location if needed and return an empty correction. If
+ // this was an unqualified lookup and we believe the callback object did not
+ // filter out possible corrections, also cache the failure for the typo.
+ return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure,
+ IsUnqualifiedLookup && !ValidatingCallback);
}
void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) {
@@ -4552,19 +4433,34 @@ bool CorrectionCandidateCallback::ValidateCandidate(const TypoCorrection &candid
return WantTypeSpecifiers || WantExpressionKeywords || WantCXXNamedCasts ||
WantRemainingKeywords || WantObjCSuper;
- for (TypoCorrection::const_decl_iterator CDecl = candidate.begin(),
- CDeclEnd = candidate.end();
- CDecl != CDeclEnd; ++CDecl) {
- if (!isa<TypeDecl>(*CDecl))
- return true;
+ bool HasNonType = false;
+ bool HasStaticMethod = false;
+ bool HasNonStaticMethod = false;
+ for (Decl *D : candidate) {
+ if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
+ D = FTD->getTemplatedDecl();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
+ if (Method->isStatic())
+ HasStaticMethod = true;
+ else
+ HasNonStaticMethod = true;
+ }
+ if (!isa<TypeDecl>(D))
+ HasNonType = true;
}
- return WantTypeSpecifiers;
+ if (IsAddressOfOperand && HasNonStaticMethod && !HasStaticMethod &&
+ !candidate.getCorrectionSpecifier())
+ return false;
+
+ return WantTypeSpecifiers || HasNonType;
}
FunctionCallFilterCCC::FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,
- bool HasExplicitTemplateArgs)
- : NumArgs(NumArgs), HasExplicitTemplateArgs(HasExplicitTemplateArgs) {
+ bool HasExplicitTemplateArgs,
+ MemberExpr *ME)
+ : NumArgs(NumArgs), HasExplicitTemplateArgs(HasExplicitTemplateArgs),
+ CurContext(SemaRef.CurContext), MemberFn(ME) {
WantTypeSpecifiers = SemaRef.getLangOpts().CPlusPlus;
WantRemainingKeywords = false;
}
@@ -4573,11 +4469,9 @@ bool FunctionCallFilterCCC::ValidateCandidate(const TypoCorrection &candidate) {
if (!candidate.getCorrectionDecl())
return candidate.isKeyword();
- for (TypoCorrection::const_decl_iterator DI = candidate.begin(),
- DIEnd = candidate.end();
- DI != DIEnd; ++DI) {
- FunctionDecl *FD = 0;
- NamedDecl *ND = (*DI)->getUnderlyingDecl();
+ for (auto *C : candidate) {
+ FunctionDecl *FD = nullptr;
+ NamedDecl *ND = C->getUnderlyingDecl();
if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
FD = FTD->getTemplatedDecl();
if (!HasExplicitTemplateArgs && !FD) {
@@ -4589,13 +4483,35 @@ bool FunctionCallFilterCCC::ValidateCandidate(const TypoCorrection &candidate) {
if (ValType->isAnyPointerType() || ValType->isReferenceType())
ValType = ValType->getPointeeType();
if (const FunctionProtoType *FPT = ValType->getAs<FunctionProtoType>())
- if (FPT->getNumArgs() == NumArgs)
+ if (FPT->getNumParams() == NumArgs)
return true;
}
}
- if (FD && FD->getNumParams() >= NumArgs &&
- FD->getMinRequiredArguments() <= NumArgs)
- return true;
+
+ // Skip the current candidate if it is not a FunctionDecl or does not accept
+ // the current number of arguments.
+ if (!FD || !(FD->getNumParams() >= NumArgs &&
+ FD->getMinRequiredArguments() <= NumArgs))
+ continue;
+
+ // If the current candidate is a non-static C++ method, skip the candidate
+ // unless the method being corrected--or the current DeclContext, if the
+ // function being corrected is not a method--is a method in the same class
+ // or a descendent class of the candidate's parent class.
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ if (MemberFn || !MD->isStatic()) {
+ CXXMethodDecl *CurMD =
+ MemberFn
+ ? dyn_cast_or_null<CXXMethodDecl>(MemberFn->getMemberDecl())
+ : dyn_cast_or_null<CXXMethodDecl>(CurContext);
+ CXXRecordDecl *CurRD =
+ CurMD ? CurMD->getParent()->getCanonicalDecl() : nullptr;
+ CXXRecordDecl *RD = MD->getParent()->getCanonicalDecl();
+ if (!CurRD || (CurRD != RD && !CurRD->isDerivedFrom(RD)))
+ continue;
+ }
+ }
+ return true;
}
return false;
}
@@ -4613,7 +4529,7 @@ static const NamedDecl *getDefinitionToImport(const NamedDecl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->getDefinition();
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- return FD->isDefined(FD) ? FD : 0;
+ return FD->isDefined(FD) ? FD : nullptr;
if (const TagDecl *TD = dyn_cast<TagDecl>(D))
return TD->getDefinition();
if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
@@ -4622,7 +4538,7 @@ static const NamedDecl *getDefinitionToImport(const NamedDecl *D) {
return PD->getDefinition();
if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
return getDefinitionToImport(TD->getTemplatedDecl());
- return 0;
+ return nullptr;
}
/// \brief Diagnose a successfully-corrected typo. Separated from the correction
@@ -4665,9 +4581,9 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction,
Diag(Def->getLocation(), diag::note_previous_declaration);
// Recover by implicitly importing this module.
- if (!isSFINAEContext() && ErrorRecovery)
- createImplicitModuleImport(Correction.getCorrectionRange().getBegin(),
- Owner);
+ if (ErrorRecovery)
+ createImplicitModuleImportForErrorRecovery(
+ Correction.getCorrectionRange().getBegin(), Owner);
return;
}
@@ -4675,7 +4591,7 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction,
<< CorrectedQuotedStr << (ErrorRecovery ? FixTypo : FixItHint());
NamedDecl *ChosenDecl =
- Correction.isKeyword() ? 0 : Correction.getCorrectionDecl();
+ Correction.isKeyword() ? nullptr : Correction.getCorrectionDecl();
if (PrevNote.getDiagID() && ChosenDecl)
Diag(ChosenDecl->getLocation(), PrevNote)
<< CorrectedQuotedStr << (ErrorRecovery ? FixItHint() : FixTypo);
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index d9d9cec1b700..8eb806ba301a 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -19,7 +19,6 @@
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallString.h"
@@ -132,11 +131,8 @@ CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop,
}
// Check this property against any protocols we inherit.
- for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
- PEnd = Proto->protocol_end();
- P != PEnd; ++P) {
- CheckPropertyAgainstProtocol(S, Prop, *P, Known);
- }
+ for (auto *P : Proto->protocols())
+ CheckPropertyAgainstProtocol(S, Prop, P, Known);
}
Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
@@ -168,7 +164,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
// Proceed with constructing the ObjCPropertyDecls.
ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext);
- ObjCPropertyDecl *Res = 0;
+ ObjCPropertyDecl *Res = nullptr;
if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
if (CDecl->IsClassExtension()) {
Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc,
@@ -179,7 +175,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
isOverridingProperty, TSI,
MethodImplKind);
if (!Res)
- return 0;
+ return nullptr;
}
}
@@ -204,7 +200,8 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
// For a class, compare the property against a property in our superclass.
bool FoundInSuper = false;
- if (ObjCInterfaceDecl *Super = IFace->getSuperClass()) {
+ ObjCInterfaceDecl *CurrentInterfaceDecl = IFace;
+ while (ObjCInterfaceDecl *Super = CurrentInterfaceDecl->getSuperClass()) {
DeclContext::lookup_result R = Super->lookup(Res->getDeclName());
for (unsigned I = 0, N = R.size(); I != N; ++I) {
if (ObjCPropertyDecl *SuperProp = dyn_cast<ObjCPropertyDecl>(R[I])) {
@@ -213,37 +210,30 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
break;
}
}
+ if (FoundInSuper)
+ break;
+ else
+ CurrentInterfaceDecl = Super;
}
if (FoundInSuper) {
// Also compare the property against a property in our protocols.
- for (ObjCInterfaceDecl::protocol_iterator P = IFace->protocol_begin(),
- PEnd = IFace->protocol_end();
- P != PEnd; ++P) {
- CheckPropertyAgainstProtocol(*this, Res, *P, KnownProtos);
+ for (auto *P : CurrentInterfaceDecl->protocols()) {
+ CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
}
} else {
// Slower path: look in all protocols we referenced.
- for (ObjCInterfaceDecl::all_protocol_iterator
- P = IFace->all_referenced_protocol_begin(),
- PEnd = IFace->all_referenced_protocol_end();
- P != PEnd; ++P) {
- CheckPropertyAgainstProtocol(*this, Res, *P, KnownProtos);
+ for (auto *P : IFace->all_referenced_protocols()) {
+ CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
}
}
} else if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
- for (ObjCCategoryDecl::protocol_iterator P = Cat->protocol_begin(),
- PEnd = Cat->protocol_end();
- P != PEnd; ++P) {
- CheckPropertyAgainstProtocol(*this, Res, *P, KnownProtos);
- }
+ for (auto *P : Cat->protocols())
+ CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
} else {
ObjCProtocolDecl *Proto = cast<ObjCProtocolDecl>(ClassDecl);
- for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
- PEnd = Proto->protocol_end();
- P != PEnd; ++P) {
- CheckPropertyAgainstProtocol(*this, Res, *P, KnownProtos);
- }
+ for (auto *P : Proto->protocols())
+ CheckPropertyAgainstProtocol(*this, Res, P, KnownProtos);
}
ActOnDocumentableDecl(Res);
@@ -302,8 +292,7 @@ static bool LocPropertyAttribute( ASTContext &Context, const char *attrName,
Token Tok;
do {
lexer.LexFromRawLexer(Tok);
- if (Tok.is(tok::raw_identifier) &&
- StringRef(Tok.getRawIdentifierData(), Tok.getLength()) == attrName) {
+ if (Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == attrName) {
Loc = Tok.getLocation();
return true;
}
@@ -321,21 +310,6 @@ static unsigned getOwnershipRule(unsigned attr) {
ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
}
-static const char *NameOfOwnershipAttribute(unsigned attr) {
- if (attr & ObjCPropertyDecl::OBJC_PR_assign)
- return "assign";
- if (attr & ObjCPropertyDecl::OBJC_PR_retain )
- return "retain";
- if (attr & ObjCPropertyDecl::OBJC_PR_copy)
- return "copy";
- if (attr & ObjCPropertyDecl::OBJC_PR_weak)
- return "weak";
- if (attr & ObjCPropertyDecl::OBJC_PR_strong)
- return "strong";
- assert(attr & ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
- return "unsafe_unretained";
-}
-
ObjCPropertyDecl *
Sema::HandlePropertyInClassExtension(Scope *S,
SourceLocation AtLoc,
@@ -358,15 +332,12 @@ Sema::HandlePropertyInClassExtension(Scope *S,
if (CCPrimary) {
// Check for duplicate declaration of this property in current and
// other class extensions.
- for (ObjCInterfaceDecl::known_extensions_iterator
- Ext = CCPrimary->known_extensions_begin(),
- ExtEnd = CCPrimary->known_extensions_end();
- Ext != ExtEnd; ++Ext) {
+ for (const auto *Ext : CCPrimary->known_extensions()) {
if (ObjCPropertyDecl *prevDecl
- = ObjCPropertyDecl::findPropertyDecl(*Ext, PropertyId)) {
+ = ObjCPropertyDecl::findPropertyDecl(Ext, PropertyId)) {
Diag(AtLoc, diag::err_duplicate_property);
Diag(prevDecl->getLocation(), diag::note_property_declare);
- return 0;
+ return nullptr;
}
}
}
@@ -398,7 +369,7 @@ Sema::HandlePropertyInClassExtension(Scope *S,
if (!CCPrimary) {
Diag(CDecl->getLocation(), diag::err_continuation_class);
*isOverridingProperty = true;
- return 0;
+ return nullptr;
}
// Find the property in continuation class's primary class only.
@@ -416,12 +387,14 @@ Sema::HandlePropertyInClassExtension(Scope *S,
// A case of continuation class adding a new property in the class. This
// is not what it was meant for. However, gcc supports it and so should we.
// Make sure setter/getters are declared here.
- ProcessPropertyDecl(PrimaryPDecl, CCPrimary, /* redeclaredProperty = */ 0,
+ ProcessPropertyDecl(PrimaryPDecl, CCPrimary,
+ /* redeclaredProperty = */ nullptr,
/* lexicalDC = */ CDecl);
PDecl->setGetterMethodDecl(PrimaryPDecl->getGetterMethodDecl());
PDecl->setSetterMethodDecl(PrimaryPDecl->getSetterMethodDecl());
if (ASTMutationListener *L = Context.getASTMutationListener())
- L->AddedObjCPropertyInClassExtension(PrimaryPDecl, /*OrigProp=*/0, CDecl);
+ L->AddedObjCPropertyInClassExtension(PrimaryPDecl, /*OrigProp=*/nullptr,
+ CDecl);
return PrimaryPDecl;
}
if (!Context.hasSameType(PIDecl->getType(), PDecl->getType())) {
@@ -441,7 +414,7 @@ Sema::HandlePropertyInClassExtension(Scope *S,
Diag(AtLoc,
diag::err_type_mismatch_continuation_class) << PDecl->getType();
Diag(PIDecl->getLocation(), diag::note_property_declare);
- return 0;
+ return nullptr;
}
}
@@ -478,6 +451,18 @@ Sema::HandlePropertyInClassExtension(Scope *S,
DeclContext *DC = cast<DeclContext>(CCPrimary);
if (!ObjCPropertyDecl::findPropertyDecl(DC,
PIDecl->getDeclName().getAsIdentifierInfo())) {
+ // In mrr mode, 'readwrite' property must have an explicit
+ // memory attribute. If none specified, select the default (assign).
+ if (!getLangOpts().ObjCAutoRefCount) {
+ if (!(PIkind & (ObjCDeclSpec::DQ_PR_assign |
+ ObjCDeclSpec::DQ_PR_retain |
+ ObjCDeclSpec::DQ_PR_strong |
+ ObjCDeclSpec::DQ_PR_copy |
+ ObjCDeclSpec::DQ_PR_unsafe_unretained |
+ ObjCDeclSpec::DQ_PR_weak)))
+ PIkind |= ObjCPropertyDecl::OBJC_PR_assign;
+ }
+
// Protocol is not in the primary class. Must build one for it.
ObjCDeclSpec ProtocolPropertyODS;
// FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind
@@ -520,7 +505,7 @@ Sema::HandlePropertyInClassExtension(Scope *S,
Diag(AtLoc, diag)
<< CCPrimary->getDeclName();
Diag(PIDecl->getLocation(), diag::note_property_declare);
- return 0;
+ return nullptr;
}
*isOverridingProperty = true;
// Make sure setter decl is synthesized, and added to primary class's list.
@@ -565,7 +550,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
if (T->isObjCObjectType()) {
SourceLocation StarLoc = TInfo->getTypeLoc().getLocEnd();
- StarLoc = PP.getLocForEndOfToken(StarLoc);
+ StarLoc = getLocForEndOfToken(StarLoc);
Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object)
<< FixItHint::CreateInsertion(StarLoc, "*");
T = Context.getObjCObjectPointerType(T);
@@ -763,18 +748,14 @@ DiagnosePropertyMismatchDeclInProtocols(Sema &S, SourceLocation AtLoc,
ObjCInterfaceDecl *ClassDecl,
ObjCPropertyDecl *Property) {
ObjCInterfaceDecl::ProtocolPropertyMap PropMap;
- for (ObjCInterfaceDecl::all_protocol_iterator
- PI = ClassDecl->all_referenced_protocol_begin(),
- E = ClassDecl->all_referenced_protocol_end(); PI != E; ++PI) {
- if (const ObjCProtocolDecl *PDecl = (*PI)->getDefinition())
+ for (const auto *PI : ClassDecl->all_referenced_protocols()) {
+ if (const ObjCProtocolDecl *PDecl = PI->getDefinition())
PDecl->collectInheritedProtocolProperties(Property, PropMap);
}
if (ObjCInterfaceDecl *SDecl = ClassDecl->getSuperClass())
while (SDecl) {
- for (ObjCInterfaceDecl::all_protocol_iterator
- PI = SDecl->all_referenced_protocol_begin(),
- E = SDecl->all_referenced_protocol_end(); PI != E; ++PI) {
- if (const ObjCProtocolDecl *PDecl = (*PI)->getDefinition())
+ for (const auto *PI : SDecl->all_referenced_protocols()) {
+ if (const ObjCProtocolDecl *PDecl = PI->getDefinition())
PDecl->collectInheritedProtocolProperties(Property, PropMap);
}
SDecl = SDecl->getSuperClass();
@@ -824,19 +805,19 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// Make sure we have a context for the property implementation declaration.
if (!ClassImpDecl) {
Diag(AtLoc, diag::error_missing_property_context);
- return 0;
+ return nullptr;
}
if (PropertyIvarLoc.isInvalid())
PropertyIvarLoc = PropertyLoc;
SourceLocation PropertyDiagLoc = PropertyLoc;
if (PropertyDiagLoc.isInvalid())
PropertyDiagLoc = ClassImpDecl->getLocStart();
- ObjCPropertyDecl *property = 0;
- ObjCInterfaceDecl* IDecl = 0;
+ ObjCPropertyDecl *property = nullptr;
+ ObjCInterfaceDecl *IDecl = nullptr;
// Find the class or category class where this property must have
// a declaration.
- ObjCImplementationDecl *IC = 0;
- ObjCCategoryImplDecl* CatImplClass = 0;
+ ObjCImplementationDecl *IC = nullptr;
+ ObjCCategoryImplDecl *CatImplClass = nullptr;
if ((IC = dyn_cast<ObjCImplementationDecl>(ClassImpDecl))) {
IDecl = IC->getClassInterface();
// We always synthesize an interface for an implementation
@@ -848,7 +829,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
property = IDecl->FindPropertyDeclaration(PropertyId);
if (!property) {
Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName();
- return 0;
+ return nullptr;
}
unsigned PIkind = property->getPropertyAttributesAsWritten();
if ((PIkind & (ObjCPropertyDecl::OBJC_PR_atomic |
@@ -865,7 +846,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (!CD->IsClassExtension()) {
Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName();
Diag(property->getLocation(), diag::note_property_declare);
- return 0;
+ return nullptr;
}
}
if (Synthesize&&
@@ -875,9 +856,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
bool ReadWriteProperty = false;
// Search into the class extensions and see if 'readonly property is
// redeclared 'readwrite', then no warning is to be issued.
- for (ObjCInterfaceDecl::known_extensions_iterator
- Ext = IDecl->known_extensions_begin(),
- ExtEnd = IDecl->known_extensions_end(); Ext != ExtEnd; ++Ext) {
+ for (auto *Ext : IDecl->known_extensions()) {
DeclContext::lookup_result R = Ext->lookup(property->getDeclName());
if (!R.empty())
if (ObjCPropertyDecl *ExtProp = dyn_cast<ObjCPropertyDecl>(R[0])) {
@@ -891,7 +870,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (!ReadWriteProperty) {
Diag(property->getLocation(), diag::warn_auto_readonly_iboutlet_property)
- << property->getName();
+ << property;
SourceLocation readonlyLoc;
if (LocPropertyAttribute(Context, "readonly",
property->getLParenLoc(), readonlyLoc)) {
@@ -910,12 +889,12 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
} else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
if (Synthesize) {
Diag(AtLoc, diag::error_synthesize_category_decl);
- return 0;
+ return nullptr;
}
IDecl = CatImplClass->getClassInterface();
if (!IDecl) {
Diag(AtLoc, diag::error_missing_property_interface);
- return 0;
+ return nullptr;
}
ObjCCategoryDecl *Category =
IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier());
@@ -923,19 +902,19 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// If category for this implementation not found, it is an error which
// has already been reported eralier.
if (!Category)
- return 0;
+ return nullptr;
// Look for this property declaration in @implementation's category
property = Category->FindPropertyDeclaration(PropertyId);
if (!property) {
Diag(PropertyLoc, diag::error_bad_category_property_decl)
<< Category->getDeclName();
- return 0;
+ return nullptr;
}
} else {
Diag(AtLoc, diag::error_bad_property_context);
- return 0;
+ return nullptr;
}
- ObjCIvarDecl *Ivar = 0;
+ ObjCIvarDecl *Ivar = nullptr;
bool CompleteTypeErr = false;
bool compat = true;
// Check that we have a valid, previously declared ivar for @synthesize
@@ -983,14 +962,14 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// an ivar matching property name and issue warning; since this
// is the most common case of not using an ivar used for backing
// property in non-default synthesis case.
- ObjCInterfaceDecl *ClassDeclared=0;
+ ObjCInterfaceDecl *ClassDeclared=nullptr;
ObjCIvarDecl *originalIvar =
IDecl->lookupInstanceVariable(property->getIdentifier(),
ClassDeclared);
if (originalIvar) {
Diag(PropertyDiagLoc,
diag::warn_autosynthesis_property_ivar_match)
- << PropertyId << (Ivar == 0) << PropertyIvar
+ << PropertyId << (Ivar == nullptr) << PropertyIvar
<< originalIvar->getIdentifier();
Diag(property->getLocation(), diag::note_property_declare);
Diag(originalIvar->getLocation(), diag::note_ivar_decl);
@@ -1049,9 +1028,9 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl,
PropertyIvarLoc,PropertyIvarLoc, PropertyIvar,
- PropertyIvarType, /*Dinfo=*/0,
+ PropertyIvarType, /*Dinfo=*/nullptr,
ObjCIvarDecl::Private,
- (Expr *)0, true);
+ (Expr *)nullptr, true);
if (RequireNonAbstractType(PropertyIvarLoc,
PropertyIvarType,
diag::err_abstract_type_in_decl,
@@ -1163,21 +1142,23 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
ImplicitParamDecl *SelfDecl = getterMethod->getSelfDecl();
DeclRefExpr *SelfExpr =
new (Context) DeclRefExpr(SelfDecl, false, SelfDecl->getType(),
- VK_RValue, PropertyDiagLoc);
+ VK_LValue, PropertyDiagLoc);
MarkDeclRefReferenced(SelfExpr);
+ Expr *LoadSelfExpr =
+ ImplicitCastExpr::Create(Context, SelfDecl->getType(),
+ CK_LValueToRValue, SelfExpr, nullptr,
+ VK_RValue);
Expr *IvarRefExpr =
new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc,
Ivar->getLocation(),
- SelfExpr, true, true);
- ExprResult Res =
- PerformCopyInitialization(InitializedEntity::InitializeResult(
- PropertyDiagLoc,
- getterMethod->getResultType(),
- /*NRVO=*/false),
- PropertyDiagLoc,
- Owned(IvarRefExpr));
+ LoadSelfExpr, true, true);
+ ExprResult Res = PerformCopyInitialization(
+ InitializedEntity::InitializeResult(PropertyDiagLoc,
+ getterMethod->getReturnType(),
+ /*NRVO=*/false),
+ PropertyDiagLoc, IvarRefExpr);
if (!Res.isInvalid()) {
- Expr *ResExpr = Res.takeAs<Expr>();
+ Expr *ResExpr = Res.getAs<Expr>();
if (ResExpr)
ResExpr = MaybeCreateExprWithCleanups(ResExpr);
PIDecl->setGetterCXXConstructor(ResExpr);
@@ -1211,12 +1192,16 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl();
DeclRefExpr *SelfExpr =
new (Context) DeclRefExpr(SelfDecl, false, SelfDecl->getType(),
- VK_RValue, PropertyDiagLoc);
+ VK_LValue, PropertyDiagLoc);
MarkDeclRefReferenced(SelfExpr);
+ Expr *LoadSelfExpr =
+ ImplicitCastExpr::Create(Context, SelfDecl->getType(),
+ CK_LValueToRValue, SelfExpr, nullptr,
+ VK_RValue);
Expr *lhs =
new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc,
Ivar->getLocation(),
- SelfExpr, true, true);
+ LoadSelfExpr, true, true);
ObjCMethodDecl::param_iterator P = setterMethod->param_begin();
ParmVarDecl *Param = (*P);
QualType T = Param->getType().getNonReferenceType();
@@ -1227,7 +1212,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
BO_Assign, lhs, rhs);
if (property->getPropertyAttributes() &
ObjCPropertyDecl::OBJC_PR_atomic) {
- Expr *callExpr = Res.takeAs<Expr>();
+ Expr *callExpr = Res.getAs<Expr>();
if (const CXXOperatorCallExpr *CXXCE =
dyn_cast_or_null<CXXOperatorCallExpr>(callExpr))
if (const FunctionDecl *FuncDecl = CXXCE->getDirectCallee())
@@ -1240,7 +1225,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
diag::note_callee_decl) << FuncDecl;
}
}
- PIDecl->setSetterCXXAssignment(Res.takeAs<Expr>());
+ PIDecl->setSetterCXXAssignment(Res.getAs<Expr>());
}
}
@@ -1258,7 +1243,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
= IC->FindPropertyImplDecl(PropertyId)) {
Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
- return 0;
+ return nullptr;
}
IC->addPropertyImplementation(PIDecl);
if (getLangOpts().ObjCDefaultSynthProperties &&
@@ -1267,8 +1252,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// Diagnose if an ivar was lazily synthesdized due to a previous
// use and if 1) property is @dynamic or 2) property is synthesized
// but it requires an ivar of different name.
- ObjCInterfaceDecl *ClassDeclared=0;
- ObjCIvarDecl *Ivar = 0;
+ ObjCInterfaceDecl *ClassDeclared=nullptr;
+ ObjCIvarDecl *Ivar = nullptr;
if (!Synthesize)
Ivar = IDecl->lookupInstanceVariable(PropertyId, ClassDeclared);
else {
@@ -1297,7 +1282,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
CatImplClass->FindPropertyImplDecl(PropertyId)) {
Diag(PropertyDiagLoc, diag::error_property_implemented) << PropertyId;
Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
- return 0;
+ return nullptr;
}
CatImplClass->addPropertyImplementation(PIDecl);
}
@@ -1394,7 +1379,7 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
SourceLocation Loc) {
if (!GetterMethod)
return false;
- QualType GetterType = GetterMethod->getResultType().getNonReferenceType();
+ QualType GetterType = GetterMethod->getReturnType().getNonReferenceType();
QualType PropertyIvarType = property->getType().getNonReferenceType();
bool compat = Context.hasSameType(PropertyIvarType, GetterType);
if (!compat) {
@@ -1433,37 +1418,32 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
/// CollectImmediateProperties - This routine collects all properties in
/// the class and its conforming protocols; but not those in its super class.
-void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
- ObjCContainerDecl::PropertyMap &PropMap,
- ObjCContainerDecl::PropertyMap &SuperPropMap) {
+static void CollectImmediateProperties(ObjCContainerDecl *CDecl,
+ ObjCContainerDecl::PropertyMap &PropMap,
+ ObjCContainerDecl::PropertyMap &SuperPropMap,
+ bool IncludeProtocols = true) {
+
if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
- for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
- E = IDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
+ for (auto *Prop : IDecl->properties())
PropMap[Prop->getIdentifier()] = Prop;
+ if (IncludeProtocols) {
+ // Scan through class's protocols.
+ for (auto *PI : IDecl->all_referenced_protocols())
+ CollectImmediateProperties(PI, PropMap, SuperPropMap);
}
- // scan through class's protocols.
- for (ObjCInterfaceDecl::all_protocol_iterator
- PI = IDecl->all_referenced_protocol_begin(),
- E = IDecl->all_referenced_protocol_end(); PI != E; ++PI)
- CollectImmediateProperties((*PI), PropMap, SuperPropMap);
}
if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
if (!CATDecl->IsClassExtension())
- for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(),
- E = CATDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
+ for (auto *Prop : CATDecl->properties())
PropMap[Prop->getIdentifier()] = Prop;
- }
- // scan through class's protocols.
- for (ObjCCategoryDecl::protocol_iterator PI = CATDecl->protocol_begin(),
- E = CATDecl->protocol_end(); PI != E; ++PI)
- CollectImmediateProperties((*PI), PropMap, SuperPropMap);
+ if (IncludeProtocols) {
+ // Scan through class's protocols.
+ for (auto *PI : CATDecl->protocols())
+ CollectImmediateProperties(PI, PropMap, SuperPropMap);
+ }
}
else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
+ for (auto *Prop : PDecl->properties()) {
ObjCPropertyDecl *PropertyFromSuper = SuperPropMap[Prop->getIdentifier()];
// Exclude property for protocols which conform to class's super-class,
// as super-class has to implement the property.
@@ -1475,9 +1455,8 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
}
}
// scan through protocol's protocols.
- for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
- E = PDecl->protocol_end(); PI != E; ++PI)
- CollectImmediateProperties((*PI), PropMap, SuperPropMap);
+ for (auto *PI : PDecl->protocols())
+ CollectImmediateProperties(PI, PropMap, SuperPropMap);
}
}
@@ -1510,17 +1489,35 @@ Sema::IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace,
// look up a property declaration whose one of its accessors is implemented
// by this method.
- for (ObjCContainerDecl::prop_iterator P = IFace->prop_begin(),
- E = IFace->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *property = *P;
- if ((property->getGetterName() == IMD->getSelector() ||
- property->getSetterName() == IMD->getSelector()) &&
- (property->getPropertyIvarDecl() == IV))
+ for (const auto *Property : IFace->properties()) {
+ if ((Property->getGetterName() == IMD->getSelector() ||
+ Property->getSetterName() == IMD->getSelector()) &&
+ (Property->getPropertyIvarDecl() == IV))
return true;
}
return false;
}
+static bool SuperClassImplementsProperty(ObjCInterfaceDecl *IDecl,
+ ObjCPropertyDecl *Prop) {
+ bool SuperClassImplementsGetter = false;
+ bool SuperClassImplementsSetter = false;
+ if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly)
+ SuperClassImplementsSetter = true;
+
+ while (IDecl->getSuperClass()) {
+ ObjCInterfaceDecl *SDecl = IDecl->getSuperClass();
+ if (!SuperClassImplementsGetter && SDecl->getInstanceMethod(Prop->getGetterName()))
+ SuperClassImplementsGetter = true;
+
+ if (!SuperClassImplementsSetter && SDecl->getInstanceMethod(Prop->getSetterName()))
+ SuperClassImplementsSetter = true;
+ if (SuperClassImplementsGetter && SuperClassImplementsSetter)
+ return true;
+ IDecl = IDecl->getSuperClass();
+ }
+ return false;
+}
/// \brief Default synthesizes all properties which must be synthesized
/// in class's \@implementation.
@@ -1559,7 +1556,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
!IMPDecl->getInstanceMethod(Prop->getSetterName()) &&
!IDecl->HasUserDeclaredSetterMethod(Prop)) {
Diag(Prop->getLocation(), diag::warn_no_autosynthesis_property)
- << Prop->getIdentifier()->getName();
+ << Prop->getIdentifier();
Diag(PropInSuperClass->getLocation(), diag::note_property_declare);
}
continue;
@@ -1568,17 +1565,23 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) {
if (PID->getPropertyDecl() != Prop) {
Diag(Prop->getLocation(), diag::warn_no_autosynthesis_shared_ivar_property)
- << Prop->getIdentifier()->getName();
+ << Prop->getIdentifier();
if (!PID->getLocation().isInvalid())
Diag(PID->getLocation(), diag::note_property_synthesize);
}
continue;
}
- if (isa<ObjCProtocolDecl>(Prop->getDeclContext())) {
+ if (ObjCProtocolDecl *Proto =
+ dyn_cast<ObjCProtocolDecl>(Prop->getDeclContext())) {
// We won't auto-synthesize properties declared in protocols.
- Diag(IMPDecl->getLocation(),
- diag::warn_auto_synthesizing_protocol_property);
- Diag(Prop->getLocation(), diag::note_property_declare);
+ // Suppress the warning if class's superclass implements property's
+ // getter and implements property's setter (if readwrite property).
+ if (!SuperClassImplementsProperty(IDecl, Prop)) {
+ Diag(IMPDecl->getLocation(),
+ diag::warn_auto_synthesizing_protocol_property)
+ << Prop << Proto;
+ Diag(Prop->getLocation(), diag::note_property_declare);
+ }
continue;
}
@@ -1610,44 +1613,108 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) {
DefaultSynthesizeProperties(S, IC, IDecl);
}
+static void DiagnoseUnimplementedAccessor(Sema &S,
+ ObjCInterfaceDecl *PrimaryClass,
+ Selector Method,
+ ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl *CDecl,
+ ObjCCategoryDecl *C,
+ ObjCPropertyDecl *Prop,
+ Sema::SelectorSet &SMap) {
+ // When reporting on missing property setter/getter implementation in
+ // categories, do not report when they are declared in primary class,
+ // class's protocol, or one of it super classes. This is because,
+ // the class is going to implement them.
+ if (!SMap.count(Method) &&
+ (PrimaryClass == nullptr ||
+ !PrimaryClass->lookupPropertyAccessor(Method, C))) {
+ S.Diag(IMPDecl->getLocation(),
+ isa<ObjCCategoryDecl>(CDecl) ?
+ diag::warn_setter_getter_impl_required_in_category :
+ diag::warn_setter_getter_impl_required)
+ << Prop->getDeclName() << Method;
+ S.Diag(Prop->getLocation(),
+ diag::note_property_declare);
+ if (S.LangOpts.ObjCDefaultSynthProperties &&
+ S.LangOpts.ObjCRuntime.isNonFragile())
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))
+ if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())
+ S.Diag(RID->getLocation(), diag::note_suppressed_class_declare);
+ }
+}
+
void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
- ObjCContainerDecl *CDecl) {
- ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
- ObjCInterfaceDecl *IDecl;
- // Gather properties which need not be implemented in this class
- // or category.
- if (!(IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)))
- if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
- // For categories, no need to implement properties declared in
- // its primary class (and its super classes) if property is
- // declared in one of those containers.
- if ((IDecl = C->getClassInterface())) {
- ObjCInterfaceDecl::PropertyDeclOrder PO;
- IDecl->collectPropertiesToImplement(NoNeedToImplPropMap, PO);
+ ObjCContainerDecl *CDecl,
+ bool SynthesizeProperties) {
+ ObjCContainerDecl::PropertyMap PropMap;
+ ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
+
+ if (!SynthesizeProperties) {
+ ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
+ // Gather properties which need not be implemented in this class
+ // or category.
+ if (!IDecl)
+ if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
+ // For categories, no need to implement properties declared in
+ // its primary class (and its super classes) if property is
+ // declared in one of those containers.
+ if ((IDecl = C->getClassInterface())) {
+ ObjCInterfaceDecl::PropertyDeclOrder PO;
+ IDecl->collectPropertiesToImplement(NoNeedToImplPropMap, PO);
+ }
+ }
+ if (IDecl)
+ CollectSuperClassPropertyImplementations(IDecl, NoNeedToImplPropMap);
+
+ CollectImmediateProperties(CDecl, PropMap, NoNeedToImplPropMap);
+ }
+
+ // Scan the @interface to see if any of the protocols it adopts
+ // require an explicit implementation, via attribute
+ // 'objc_protocol_requires_explicit_implementation'.
+ if (IDecl) {
+ std::unique_ptr<ObjCContainerDecl::PropertyMap> LazyMap;
+
+ for (auto *PDecl : IDecl->all_referenced_protocols()) {
+ if (!PDecl->hasAttr<ObjCExplicitProtocolImplAttr>())
+ continue;
+ // Lazily construct a set of all the properties in the @interface
+ // of the class, without looking at the superclass. We cannot
+ // use the call to CollectImmediateProperties() above as that
+ // utilizes information from the super class's properties as well
+ // as scans the adopted protocols. This work only triggers for protocols
+ // with the attribute, which is very rare, and only occurs when
+ // analyzing the @implementation.
+ if (!LazyMap) {
+ ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
+ LazyMap.reset(new ObjCContainerDecl::PropertyMap());
+ CollectImmediateProperties(CDecl, *LazyMap, NoNeedToImplPropMap,
+ /* IncludeProtocols */ false);
+ }
+ // Add the properties of 'PDecl' to the list of properties that
+ // need to be implemented.
+ for (auto *PropDecl : PDecl->properties()) {
+ if ((*LazyMap)[PropDecl->getIdentifier()])
+ continue;
+ PropMap[PropDecl->getIdentifier()] = PropDecl;
}
}
- if (IDecl)
- CollectSuperClassPropertyImplementations(IDecl, NoNeedToImplPropMap);
-
- ObjCContainerDecl::PropertyMap PropMap;
- CollectImmediateProperties(CDecl, PropMap, NoNeedToImplPropMap);
+ }
+
if (PropMap.empty())
return;
llvm::DenseSet<ObjCPropertyDecl *> PropImplMap;
- for (ObjCImplDecl::propimpl_iterator
- I = IMPDecl->propimpl_begin(),
- EI = IMPDecl->propimpl_end(); I != EI; ++I)
+ for (const auto *I : IMPDecl->property_impls())
PropImplMap.insert(I->getPropertyDecl());
SelectorSet InsMap;
// Collect property accessors implemented in current implementation.
- for (ObjCImplementationDecl::instmeth_iterator
- I = IMPDecl->instmeth_begin(), E = IMPDecl->instmeth_end(); I!=E; ++I)
- InsMap.insert((*I)->getSelector());
+ for (const auto *I : IMPDecl->instance_methods())
+ InsMap.insert(I->getSelector());
ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl);
- ObjCInterfaceDecl *PrimaryClass = 0;
+ ObjCInterfaceDecl *PrimaryClass = nullptr;
if (C && !C->IsClassExtension())
if ((PrimaryClass = C->getClassInterface()))
// Report unimplemented properties in the category as well.
@@ -1655,9 +1722,8 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
// When reporting on missing setter/getters, do not report when
// setter/getter is implemented in category's primary class
// implementation.
- for (ObjCImplementationDecl::instmeth_iterator
- I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I)
- InsMap.insert((*I)->getSelector());
+ for (const auto *I : IMP->instance_methods())
+ InsMap.insert(I->getSelector());
}
for (ObjCContainerDecl::PropertyMap::iterator
@@ -1669,45 +1735,14 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
PropImplMap.count(Prop) ||
Prop->getAvailability() == AR_Unavailable)
continue;
- // When reporting on missing property getter implementation in
- // categories, do not report when they are declared in primary class,
- // class's protocol, or one of it super classes. This is because,
- // the class is going to implement them.
- if (!InsMap.count(Prop->getGetterName()) &&
- (PrimaryClass == 0 ||
- !PrimaryClass->lookupPropertyAccessor(Prop->getGetterName(), C))) {
- Diag(IMPDecl->getLocation(),
- isa<ObjCCategoryDecl>(CDecl) ?
- diag::warn_setter_getter_impl_required_in_category :
- diag::warn_setter_getter_impl_required)
- << Prop->getDeclName() << Prop->getGetterName();
- Diag(Prop->getLocation(),
- diag::note_property_declare);
- if (LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCRuntime.isNonFragile())
- if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))
- if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())
- Diag(RID->getLocation(), diag::note_suppressed_class_declare);
-
- }
- // When reporting on missing property setter implementation in
- // categories, do not report when they are declared in primary class,
- // class's protocol, or one of it super classes. This is because,
- // the class is going to implement them.
- if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName()) &&
- (PrimaryClass == 0 ||
- !PrimaryClass->lookupPropertyAccessor(Prop->getSetterName(), C))) {
- Diag(IMPDecl->getLocation(),
- isa<ObjCCategoryDecl>(CDecl) ?
- diag::warn_setter_getter_impl_required_in_category :
- diag::warn_setter_getter_impl_required)
- << Prop->getDeclName() << Prop->getSetterName();
- Diag(Prop->getLocation(),
- diag::note_property_declare);
- if (LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCRuntime.isNonFragile())
- if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))
- if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())
- Diag(RID->getLocation(), diag::note_suppressed_class_declare);
- }
+
+ // Diagnose unimplemented getters and setters.
+ DiagnoseUnimplementedAccessor(*this,
+ PrimaryClass, Prop->getGetterName(), IMPDecl, CDecl, C, Prop, InsMap);
+ if (!Prop->isReadOnly())
+ DiagnoseUnimplementedAccessor(*this,
+ PrimaryClass, Prop->getSetterName(),
+ IMPDecl, CDecl, C, Prop, InsMap);
}
}
@@ -1717,12 +1752,9 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
// Rules apply in non-GC mode only
if (getLangOpts().getGC() != LangOptions::NonGC)
return;
- for (ObjCContainerDecl::prop_iterator I = IDecl->prop_begin(),
- E = IDecl->prop_end();
- I != E; ++I) {
- ObjCPropertyDecl *Property = *I;
- ObjCMethodDecl *GetterMethod = 0;
- ObjCMethodDecl *SetterMethod = 0;
+ for (const auto *Property : IDecl->properties()) {
+ ObjCMethodDecl *GetterMethod = nullptr;
+ ObjCMethodDecl *SetterMethod = nullptr;
bool LookedUpGetterSetter = false;
unsigned Attributes = Property->getPropertyAttributes();
@@ -1758,15 +1790,14 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
if (!LookedUpGetterSetter) {
GetterMethod = IMPDecl->getInstanceMethod(Property->getGetterName());
SetterMethod = IMPDecl->getInstanceMethod(Property->getSetterName());
- LookedUpGetterSetter = true;
}
if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) {
SourceLocation MethodLoc =
(GetterMethod ? GetterMethod->getLocation()
: SetterMethod->getLocation());
Diag(MethodLoc, diag::warn_atomic_property_rule)
- << Property->getIdentifier() << (GetterMethod != 0)
- << (SetterMethod != 0);
+ << Property->getIdentifier() << (GetterMethod != nullptr)
+ << (SetterMethod != nullptr);
// fixit stuff.
if (!AttributesAsWritten) {
if (Property->getLParenLoc().isValid()) {
@@ -1805,12 +1836,7 @@ void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D
if (getLangOpts().getGC() == 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;
-
+ for (const auto *PID : D->property_impls()) {
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() &&
!D->getInstanceMethod(PD->getGetterName())) {
@@ -1821,27 +1847,51 @@ void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D
if (family == OMF_alloc || family == OMF_copy ||
family == OMF_mutableCopy || family == OMF_new) {
if (getLangOpts().ObjCAutoRefCount)
- Diag(PID->getLocation(), diag::err_ownin_getter_rule);
+ Diag(PD->getLocation(), diag::err_cocoa_naming_owned_rule);
else
- Diag(PID->getLocation(), diag::warn_owning_getter_rule);
- Diag(PD->getLocation(), diag::note_property_declare);
+ Diag(PD->getLocation(), diag::warn_cocoa_naming_owned_rule);
}
}
}
}
+void Sema::DiagnoseMissingDesignatedInitOverrides(
+ const ObjCImplementationDecl *ImplD,
+ const ObjCInterfaceDecl *IFD) {
+ assert(IFD->hasDesignatedInitializers());
+ const ObjCInterfaceDecl *SuperD = IFD->getSuperClass();
+ if (!SuperD)
+ return;
+
+ SelectorSet InitSelSet;
+ for (const auto *I : ImplD->instance_methods())
+ if (I->getMethodFamily() == OMF_init)
+ InitSelSet.insert(I->getSelector());
+
+ SmallVector<const ObjCMethodDecl *, 8> DesignatedInits;
+ SuperD->getDesignatedInitializers(DesignatedInits);
+ for (SmallVector<const ObjCMethodDecl *, 8>::iterator
+ I = DesignatedInits.begin(), E = DesignatedInits.end(); I != E; ++I) {
+ const ObjCMethodDecl *MD = *I;
+ if (!InitSelSet.count(MD->getSelector())) {
+ Diag(ImplD->getLocation(),
+ diag::warn_objc_implementation_missing_designated_init_override)
+ << MD->getSelector();
+ Diag(MD->getLocation(), diag::note_objc_designated_init_marked_here);
+ }
+ }
+}
+
/// AddPropertyAttrs - Propagates attributes from a property to the
/// implicitly-declared getter or setter for that property.
static void AddPropertyAttrs(Sema &S, ObjCMethodDecl *PropertyMethod,
ObjCPropertyDecl *Property) {
// Should we just clone all attributes over?
- for (Decl::attr_iterator A = Property->attr_begin(),
- AEnd = Property->attr_end();
- A != AEnd; ++A) {
- if (isa<DeprecatedAttr>(*A) ||
- isa<UnavailableAttr>(*A) ||
- isa<AvailabilityAttr>(*A))
- PropertyMethod->addAttr((*A)->clone(S.Context));
+ for (const auto *A : Property->attrs()) {
+ if (isa<DeprecatedAttr>(A) ||
+ isa<UnavailableAttr>(A) ||
+ isa<AvailabilityAttr>(A))
+ PropertyMethod->addAttr(A->clone(S.Context));
}
}
@@ -1857,6 +1907,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
ObjCMethodDecl *GetterMethod, *SetterMethod;
+ if (CD->isInvalidDecl())
+ return;
+
GetterMethod = CD->getInstanceMethod(property->getGetterName());
SetterMethod = CD->getInstanceMethod(property->getSetterName());
DiagnosePropertyAccessorMismatch(property, GetterMethod,
@@ -1866,8 +1919,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
ObjCPropertyDecl::PropertyAttributeKind CAttr =
property->getPropertyAttributes();
if ((!(CAttr & ObjCPropertyDecl::OBJC_PR_readonly)) &&
- Context.getCanonicalType(SetterMethod->getResultType()) !=
- Context.VoidTy)
+ Context.getCanonicalType(SetterMethod->getReturnType()) !=
+ Context.VoidTy)
Diag(SetterMethod->getLocation(), diag::err_setter_type_void);
if (SetterMethod->param_size() != 1 ||
!Context.hasSameUnqualifiedType(
@@ -1897,8 +1950,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc,
property->getGetterName(),
- property->getType(), 0, CD, /*isInstance=*/true,
- /*isVariadic=*/false, /*isPropertyAccessor=*/true,
+ property->getType(), nullptr, CD,
+ /*isInstance=*/true, /*isVariadic=*/false,
+ /*isPropertyAccessor=*/true,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
(property->getPropertyImplementation() ==
ObjCPropertyDecl::Optional) ?
@@ -1913,12 +1967,17 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
if (lexicalDC)
GetterMethod->setLexicalDeclContext(lexicalDC);
if (property->hasAttr<NSReturnsNotRetainedAttr>())
- GetterMethod->addAttr(
- ::new (Context) NSReturnsNotRetainedAttr(Loc, Context));
+ GetterMethod->addAttr(NSReturnsNotRetainedAttr::CreateImplicit(Context,
+ Loc));
if (property->hasAttr<ObjCReturnsInnerPointerAttr>())
GetterMethod->addAttr(
- ::new (Context) ObjCReturnsInnerPointerAttr(Loc, Context));
+ ObjCReturnsInnerPointerAttr::CreateImplicit(Context, Loc));
+
+ if (const SectionAttr *SA = property->getAttr<SectionAttr>())
+ GetterMethod->addAttr(
+ SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section,
+ SA->getName(), Loc));
if (getLangOpts().ObjCAutoRefCount)
CheckARCMethodDecl(GetterMethod);
@@ -1941,8 +2000,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
SetterMethod =
ObjCMethodDecl::Create(Context, Loc, Loc,
- property->getSetterName(), Context.VoidTy, 0,
- CD, /*isInstance=*/true, /*isVariadic=*/false,
+ property->getSetterName(), Context.VoidTy,
+ nullptr, CD, /*isInstance=*/true,
+ /*isVariadic=*/false,
/*isPropertyAccessor=*/true,
/*isImplicitlyDeclared=*/true,
/*isDefined=*/false,
@@ -1957,9 +2017,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
Loc, Loc,
property->getIdentifier(),
property->getType().getUnqualifiedType(),
- /*TInfo=*/0,
+ /*TInfo=*/nullptr,
SC_None,
- 0);
+ nullptr);
SetterMethod->setMethodParams(Context, Argument, None);
AddPropertyAttrs(*this, SetterMethod, property);
@@ -1969,7 +2029,10 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
// and the real context should be the same.
if (lexicalDC)
SetterMethod->setLexicalDeclContext(lexicalDC);
-
+ if (const SectionAttr *SA = property->getAttr<SectionAttr>())
+ SetterMethod->addAttr(
+ SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section,
+ SA->getName(), Loc));
// It's possible for the user to have set a very odd custom
// setter selector that causes it to have a method family.
if (getLangOpts().ObjCAutoRefCount)
@@ -2027,27 +2090,19 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
QualType PropertyTy = PropertyDecl->getType();
unsigned PropertyOwnership = getOwnershipRule(Attributes);
- if (Attributes & ObjCDeclSpec::DQ_PR_readonly) {
- if (getLangOpts().ObjCAutoRefCount &&
- PropertyTy->isObjCRetainableType() &&
- !PropertyOwnership) {
- // 'readonly' property with no obvious lifetime.
- // its life time will be determined by its backing ivar.
- return;
- }
- else if (PropertyOwnership) {
- if (!getSourceManager().isInSystemHeader(Loc))
- Diag(Loc, diag::warn_objc_property_attr_mutually_exclusive)
- << "readonly" << NameOfOwnershipAttribute(Attributes);
- return;
- }
- }
+ // 'readonly' property with no obvious lifetime.
+ // its life time will be determined by its backing ivar.
+ if (getLangOpts().ObjCAutoRefCount &&
+ Attributes & ObjCDeclSpec::DQ_PR_readonly &&
+ PropertyTy->isObjCRetainableType() &&
+ !PropertyOwnership)
+ return;
// Check for copy or retain on non-object types.
if ((Attributes & (ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy |
ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong)) &&
!PropertyTy->isObjCRetainableType() &&
- !PropertyDecl->getAttr<ObjCNSObjectAttr>()) {
+ !PropertyDecl->hasAttr<ObjCNSObjectAttr>()) {
Diag(Loc, diag::err_objc_property_requires_object)
<< (Attributes & ObjCDeclSpec::DQ_PR_weak ? "weak" :
Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain (or strong)");
@@ -2079,7 +2134,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
<< "assign" << "weak";
Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
}
- if (PropertyDecl->getAttr<IBOutletCollectionAttr>())
+ if (PropertyDecl->hasAttr<IBOutletCollectionAttr>())
Diag(Loc, diag::warn_iboutletcollection_property_assign);
} else if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) {
if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index c63caf46b9e0..7f2af68e55d5 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -1,4 +1,4 @@
-//===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ----------===//
+//===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ---------===//
//
// The LLVM Compiler Infrastructure
//
@@ -12,19 +12,20 @@
///
//===----------------------------------------------------------------------===//
-#include "clang/Basic/OpenMPKinds.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/OpenMPKinds.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h"
-#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaInternal.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -34,11 +35,31 @@ using namespace clang;
namespace {
/// \brief Default data sharing attributes, which can be applied to directive.
enum DefaultDataSharingAttributes {
- DSA_unspecified = 0, /// \brief Data sharing attribute not specified.
- DSA_none = 1 << 0, /// \brief Default data sharing attribute 'none'.
- DSA_shared = 1 << 1 /// \brief Default data sharing attribute 'shared'.
+ DSA_unspecified = 0, /// \brief Data sharing attribute not specified.
+ DSA_none = 1 << 0, /// \brief Default data sharing attribute 'none'.
+ DSA_shared = 1 << 1 /// \brief Default data sharing attribute 'shared'.
+};
+
+template <class T> struct MatchesAny {
+ explicit MatchesAny(ArrayRef<T> Arr) : Arr(std::move(Arr)) {}
+ bool operator()(T Kind) {
+ for (auto KindEl : Arr)
+ if (KindEl == Kind)
+ return true;
+ return false;
+ }
+
+private:
+ ArrayRef<T> Arr;
+};
+struct MatchesAlways {
+ MatchesAlways() {}
+ template <class T> bool operator()(T) { return true; }
};
+typedef MatchesAny<OpenMPClauseKind> MatchesAnyClause;
+typedef MatchesAny<OpenMPDirectiveKind> MatchesAnyDirective;
+
/// \brief Stack for tracking declarations used in OpenMP directives and
/// clauses and their data-sharing attributes.
class DSAStackTy {
@@ -47,47 +68,60 @@ public:
OpenMPDirectiveKind DKind;
OpenMPClauseKind CKind;
DeclRefExpr *RefExpr;
- DSAVarData() : DKind(OMPD_unknown), CKind(OMPC_unknown), RefExpr(0) { }
+ SourceLocation ImplicitDSALoc;
+ DSAVarData()
+ : DKind(OMPD_unknown), CKind(OMPC_unknown), RefExpr(nullptr),
+ ImplicitDSALoc() {}
};
+
private:
struct DSAInfo {
OpenMPClauseKind Attributes;
DeclRefExpr *RefExpr;
};
typedef llvm::SmallDenseMap<VarDecl *, DSAInfo, 64> DeclSAMapTy;
+ typedef llvm::SmallDenseMap<VarDecl *, DeclRefExpr *, 64> AlignedMapTy;
struct SharingMapTy {
DeclSAMapTy SharingMap;
+ AlignedMapTy AlignedMap;
DefaultDataSharingAttributes DefaultAttr;
+ SourceLocation DefaultAttrLoc;
OpenMPDirectiveKind Directive;
DeclarationNameInfo DirectiveName;
Scope *CurScope;
- SharingMapTy(OpenMPDirectiveKind DKind,
- const DeclarationNameInfo &Name,
- Scope *CurScope)
- : SharingMap(), DefaultAttr(DSA_unspecified), Directive(DKind),
- DirectiveName(Name), CurScope(CurScope) { }
+ SourceLocation ConstructLoc;
+ SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
+ Scope *CurScope, SourceLocation Loc)
+ : SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified),
+ Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope),
+ ConstructLoc(Loc) {}
SharingMapTy()
- : SharingMap(), DefaultAttr(DSA_unspecified),
- Directive(OMPD_unknown), DirectiveName(),
- CurScope(0) { }
+ : SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified),
+ Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr),
+ ConstructLoc() {}
};
typedef SmallVector<SharingMapTy, 64> StackTy;
/// \brief Stack of used declaration and their data-sharing attributes.
StackTy Stack;
- Sema &Actions;
+ Sema &SemaRef;
typedef SmallVector<SharingMapTy, 8>::reverse_iterator reverse_iterator;
DSAVarData getDSA(StackTy::reverse_iterator Iter, VarDecl *D);
+
+ /// \brief Checks if the variable is a local for OpenMP region.
+ bool isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter);
+
public:
- explicit DSAStackTy(Sema &S) : Stack(1), Actions(S) { }
+ explicit DSAStackTy(Sema &S) : Stack(1), SemaRef(S) {}
void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName,
- Scope *CurScope) {
- Stack.push_back(SharingMapTy(DKind, DirName, CurScope));
+ Scope *CurScope, SourceLocation Loc) {
+ Stack.push_back(SharingMapTy(DKind, DirName, CurScope, Loc));
+ Stack.back().DefaultAttrLoc = Loc;
}
void pop() {
@@ -95,51 +129,90 @@ public:
Stack.pop_back();
}
+ /// \brief If 'aligned' declaration for given variable \a D was not seen yet,
+ /// add it and return NULL; otherwise return previous occurrence's expression
+ /// for diagnostics.
+ DeclRefExpr *addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE);
+
/// \brief Adds explicit data sharing attribute to the specified declaration.
void addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A);
- /// \brief Checks if the variable is a local for OpenMP region.
- bool isOpenMPLocal(VarDecl *D);
-
/// \brief Returns data sharing attributes from top of the stack for the
/// specified declaration.
- DSAVarData getTopDSA(VarDecl *D);
+ DSAVarData getTopDSA(VarDecl *D, bool FromParent);
/// \brief Returns data-sharing attributes for the specified declaration.
- DSAVarData getImplicitDSA(VarDecl *D);
- /// \brief Checks if the specified variables has \a CKind data-sharing
- /// attribute in \a DKind directive.
- DSAVarData hasDSA(VarDecl *D, OpenMPClauseKind CKind,
- OpenMPDirectiveKind DKind = OMPD_unknown);
-
+ DSAVarData getImplicitDSA(VarDecl *D, bool FromParent);
+ /// \brief Checks if the specified variables has data-sharing attributes which
+ /// match specified \a CPred predicate in any directive which matches \a DPred
+ /// predicate.
+ template <class ClausesPredicate, class DirectivesPredicate>
+ DSAVarData hasDSA(VarDecl *D, ClausesPredicate CPred,
+ DirectivesPredicate DPred, bool FromParent);
+ /// \brief Checks if the specified variables has data-sharing attributes which
+ /// match specified \a CPred predicate in any innermost directive which
+ /// matches \a DPred predicate.
+ template <class ClausesPredicate, class DirectivesPredicate>
+ DSAVarData hasInnermostDSA(VarDecl *D, ClausesPredicate CPred,
+ DirectivesPredicate DPred,
+ bool FromParent);
+ /// \brief Finds a directive which matches specified \a DPred predicate.
+ template <class NamedDirectivesPredicate>
+ bool hasDirective(NamedDirectivesPredicate DPred, bool FromParent);
/// \brief Returns currently analyzed directive.
OpenMPDirectiveKind getCurrentDirective() const {
return Stack.back().Directive;
}
+ /// \brief Returns parent directive.
+ OpenMPDirectiveKind getParentDirective() const {
+ if (Stack.size() > 2)
+ return Stack[Stack.size() - 2].Directive;
+ return OMPD_unknown;
+ }
/// \brief Set default data sharing attribute to none.
- void setDefaultDSANone() { Stack.back().DefaultAttr = DSA_none; }
+ void setDefaultDSANone(SourceLocation Loc) {
+ Stack.back().DefaultAttr = DSA_none;
+ Stack.back().DefaultAttrLoc = Loc;
+ }
/// \brief Set default data sharing attribute to shared.
- void setDefaultDSAShared() { Stack.back().DefaultAttr = DSA_shared; }
+ void setDefaultDSAShared(SourceLocation Loc) {
+ Stack.back().DefaultAttr = DSA_shared;
+ Stack.back().DefaultAttrLoc = Loc;
+ }
DefaultDataSharingAttributes getDefaultDSA() const {
return Stack.back().DefaultAttr;
}
+ SourceLocation getDefaultDSALocation() const {
+ return Stack.back().DefaultAttrLoc;
+ }
+ /// \brief Checks if the specified variable is a threadprivate.
+ bool isThreadPrivate(VarDecl *D) {
+ DSAVarData DVar = getTopDSA(D, false);
+ return isOpenMPThreadPrivate(DVar.CKind);
+ }
+
+ Scope *getCurScope() const { return Stack.back().CurScope; }
Scope *getCurScope() { return Stack.back().CurScope; }
+ SourceLocation getConstructLoc() { return Stack.back().ConstructLoc; }
};
-} // end anonymous namespace.
+bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) {
+ return isOpenMPParallelDirective(DKind) || DKind == OMPD_task ||
+ DKind == OMPD_unknown;
+}
+} // namespace
DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
VarDecl *D) {
DSAVarData DVar;
- if (Iter == Stack.rend() - 1) {
+ if (Iter == std::prev(Stack.rend())) {
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a region but not in construct]
// File-scope or namespace-scope variables referenced in called routines
// in the region are shared unless they appear in a threadprivate
// directive.
- // TODO
if (!D->isFunctionOrMethodVarDecl())
DVar.CKind = OMPC_shared;
@@ -152,12 +225,24 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
return DVar;
}
+
DVar.DKind = Iter->Directive;
+ // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
+ // in a Construct, C/C++, predetermined, p.1]
+ // Variables with automatic storage duration that are declared in a scope
+ // inside the construct are private.
+ if (isOpenMPLocal(D, Iter) && D->isLocalVarDecl() &&
+ (D->getStorageClass() == SC_Auto || D->getStorageClass() == SC_None)) {
+ DVar.CKind = OMPC_private;
+ return DVar;
+ }
+
// Explicitly specified attributes and local variables with predetermined
// attributes.
if (Iter->SharingMap.count(D)) {
DVar.RefExpr = Iter->SharingMap[D].RefExpr;
DVar.CKind = Iter->SharingMap[D].Attributes;
+ DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
return DVar;
}
@@ -168,6 +253,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
switch (Iter->DefaultAttr) {
case DSA_shared:
DVar.CKind = OMPC_shared;
+ DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
return DVar;
case DSA_none:
return DVar;
@@ -176,7 +262,8 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
// in a Construct, implicitly determined, p.2]
// In a parallel construct, if no default clause is present, these
// variables are shared.
- if (DVar.DKind == OMPD_parallel) {
+ DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
+ if (isOpenMPParallelDirective(DVar.DKind)) {
DVar.CKind = OMPC_shared;
return DVar;
}
@@ -186,29 +273,30 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
// In a task construct, if no default clause is present, a variable that in
// the enclosing context is determined to be shared by all implicit tasks
// bound to the current team is shared.
- // TODO
if (DVar.DKind == OMPD_task) {
DSAVarData DVarTemp;
- for (StackTy::reverse_iterator I = Iter + 1,
- EE = Stack.rend() - 1;
+ for (StackTy::reverse_iterator I = std::next(Iter),
+ EE = std::prev(Stack.rend());
I != EE; ++I) {
- // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
+ // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables
+ // Referenced
// in a Construct, implicitly determined, p.6]
// In a task construct, if no default clause is present, a variable
// whose data-sharing attribute is not determined by the rules above is
// firstprivate.
DVarTemp = getDSA(I, D);
if (DVarTemp.CKind != OMPC_shared) {
- DVar.RefExpr = 0;
+ DVar.RefExpr = nullptr;
DVar.DKind = OMPD_task;
DVar.CKind = OMPC_firstprivate;
return DVar;
}
- if (I->Directive == OMPD_parallel) break;
+ if (isParallelOrTaskRegion(I->Directive))
+ break;
}
DVar.DKind = OMPD_task;
DVar.CKind =
- (DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared;
+ (DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared;
return DVar;
}
}
@@ -217,7 +305,21 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
// For constructs other than task, if no default clause is present, these
// variables inherit their data-sharing attributes from the enclosing
// context.
- return getDSA(Iter + 1, D);
+ return getDSA(std::next(Iter), D);
+}
+
+DeclRefExpr *DSAStackTy::addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE) {
+ assert(Stack.size() > 1 && "Data sharing attributes stack is empty");
+ auto It = Stack.back().AlignedMap.find(D);
+ if (It == Stack.back().AlignedMap.end()) {
+ assert(NewDE && "Unexpected nullptr expr to be added into aligned map");
+ Stack.back().AlignedMap[D] = NewDE;
+ return nullptr;
+ } else {
+ assert(It->second && "Unexpected nullptr expr in the aligned map");
+ return It->second;
+ }
+ return nullptr;
}
void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) {
@@ -231,26 +333,26 @@ void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) {
}
}
-bool DSAStackTy::isOpenMPLocal(VarDecl *D) {
- Scope *CurScope = getCurScope();
- while (CurScope && !CurScope->isDeclScope(D))
- CurScope = CurScope->getParent();
- while (CurScope && !CurScope->isOpenMPDirectiveScope())
- CurScope = CurScope->getParent();
- bool isOpenMPLocal = !!CurScope;
- if (!isOpenMPLocal) {
- CurScope = getCurScope();
- while (CurScope && !CurScope->isOpenMPDirectiveScope())
+bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) {
+ if (Stack.size() > 2) {
+ reverse_iterator I = Iter, E = std::prev(Stack.rend());
+ Scope *TopScope = nullptr;
+ while (I != E && !isParallelOrTaskRegion(I->Directive)) {
+ ++I;
+ }
+ if (I == E)
+ return false;
+ TopScope = I->CurScope ? I->CurScope->getParent() : nullptr;
+ Scope *CurScope = getCurScope();
+ while (CurScope != TopScope && !CurScope->isDeclScope(D)) {
CurScope = CurScope->getParent();
- isOpenMPLocal =
- CurScope &&
- isa<CapturedDecl>(D->getDeclContext()) &&
- CurScope->getFnParent()->getEntity()->Encloses(D->getDeclContext());
+ }
+ return CurScope != TopScope;
}
- return isOpenMPLocal;
+ return false;
}
-DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) {
+DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) {
DSAVarData DVar;
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
@@ -270,20 +372,29 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) {
// in a Construct, C/C++, predetermined, p.1]
// Variables with automatic storage duration that are declared in a scope
// inside the construct are private.
- if (isOpenMPLocal(D) && D->isLocalVarDecl() &&
- (D->getStorageClass() == SC_Auto ||
- D->getStorageClass() == SC_None)) {
- DVar.CKind = OMPC_private;
- return DVar;
+ OpenMPDirectiveKind Kind =
+ FromParent ? getParentDirective() : getCurrentDirective();
+ auto StartI = std::next(Stack.rbegin());
+ auto EndI = std::prev(Stack.rend());
+ if (FromParent && StartI != EndI) {
+ StartI = std::next(StartI);
+ }
+ if (!isParallelOrTaskRegion(Kind)) {
+ if (isOpenMPLocal(D, StartI) && D->isLocalVarDecl() &&
+ (D->getStorageClass() == SC_Auto || D->getStorageClass() == SC_None)) {
+ DVar.CKind = OMPC_private;
+ return DVar;
+ }
}
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++, predetermined, p.4]
- // Static data memebers are shared.
+ // Static data members are shared.
if (D->isStaticDataMember()) {
- // Variables with const-qualified type having no mutable member may be listed
- // in a firstprivate clause, even if they are static data members.
- DSAVarData DVarTemp = hasDSA(D, OMPC_firstprivate);
+ // Variables with const-qualified type having no mutable member may be
+ // listed in a firstprivate clause, even if they are static data members.
+ DSAVarData DVarTemp = hasDSA(D, MatchesAnyClause(OMPC_firstprivate),
+ MatchesAlways(), FromParent);
if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr)
return DVar;
@@ -292,7 +403,7 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) {
}
QualType Type = D->getType().getNonReferenceType().getCanonicalType();
- bool IsConstant = Type.isConstant(Actions.getASTContext());
+ bool IsConstant = Type.isConstant(SemaRef.getASTContext());
while (Type->isArrayType()) {
QualType ElemType = cast<ArrayType>(Type.getTypePtr())->getElementType();
Type = ElemType.getNonReferenceType().getCanonicalType();
@@ -301,13 +412,14 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) {
// in a Construct, C/C++, predetermined, p.6]
// Variables with const qualified type having no mutable member are
// shared.
- CXXRecordDecl *RD = Actions.getLangOpts().CPlusPlus ?
- Type->getAsCXXRecordDecl() : 0;
+ CXXRecordDecl *RD =
+ SemaRef.getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr;
if (IsConstant &&
- !(Actions.getLangOpts().CPlusPlus && RD && RD->hasMutableFields())) {
+ !(SemaRef.getLangOpts().CPlusPlus && RD && RD->hasMutableFields())) {
// Variables with const-qualified type having no mutable member may be
// listed in a firstprivate clause, even if they are static data members.
- DSAVarData DVarTemp = hasDSA(D, OMPC_firstprivate);
+ DSAVarData DVarTemp = hasDSA(D, MatchesAnyClause(OMPC_firstprivate),
+ MatchesAlways(), FromParent);
if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr)
return DVar;
@@ -319,56 +431,151 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) {
// in a Construct, C/C++, predetermined, p.7]
// Variables with static storage duration that are declared in a scope
// inside the construct are shared.
- if (isOpenMPLocal(D) && D->isStaticLocal()) {
+ if (D->isStaticLocal()) {
DVar.CKind = OMPC_shared;
return DVar;
}
// Explicitly specified attributes and local variables with predetermined
// attributes.
- if (Stack.back().SharingMap.count(D)) {
- DVar.RefExpr = Stack.back().SharingMap[D].RefExpr;
- DVar.CKind = Stack.back().SharingMap[D].Attributes;
+ auto I = std::prev(StartI);
+ if (I->SharingMap.count(D)) {
+ DVar.RefExpr = I->SharingMap[D].RefExpr;
+ DVar.CKind = I->SharingMap[D].Attributes;
+ DVar.ImplicitDSALoc = I->DefaultAttrLoc;
}
return DVar;
}
-DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(VarDecl *D) {
- return getDSA(Stack.rbegin() + 1, D);
+DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(VarDecl *D, bool FromParent) {
+ auto StartI = Stack.rbegin();
+ auto EndI = std::prev(Stack.rend());
+ if (FromParent && StartI != EndI) {
+ StartI = std::next(StartI);
+ }
+ return getDSA(StartI, D);
+}
+
+template <class ClausesPredicate, class DirectivesPredicate>
+DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, ClausesPredicate CPred,
+ DirectivesPredicate DPred,
+ bool FromParent) {
+ auto StartI = std::next(Stack.rbegin());
+ auto EndI = std::prev(Stack.rend());
+ if (FromParent && StartI != EndI) {
+ StartI = std::next(StartI);
+ }
+ for (auto I = StartI, EE = EndI; I != EE; ++I) {
+ if (!DPred(I->Directive) && !isParallelOrTaskRegion(I->Directive))
+ continue;
+ DSAVarData DVar = getDSA(I, D);
+ if (CPred(DVar.CKind))
+ return DVar;
+ }
+ return DSAVarData();
}
-DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, OpenMPClauseKind CKind,
- OpenMPDirectiveKind DKind) {
- for (StackTy::reverse_iterator I = Stack.rbegin() + 1,
- E = Stack.rend() - 1;
- I != E; ++I) {
- if (DKind != OMPD_unknown && DKind != I->Directive) continue;
+template <class ClausesPredicate, class DirectivesPredicate>
+DSAStackTy::DSAVarData
+DSAStackTy::hasInnermostDSA(VarDecl *D, ClausesPredicate CPred,
+ DirectivesPredicate DPred, bool FromParent) {
+ auto StartI = std::next(Stack.rbegin());
+ auto EndI = std::prev(Stack.rend());
+ if (FromParent && StartI != EndI) {
+ StartI = std::next(StartI);
+ }
+ for (auto I = StartI, EE = EndI; I != EE; ++I) {
+ if (!DPred(I->Directive))
+ break;
DSAVarData DVar = getDSA(I, D);
- if (DVar.CKind == CKind)
+ if (CPred(DVar.CKind))
return DVar;
+ return DSAVarData();
}
return DSAVarData();
}
+template <class NamedDirectivesPredicate>
+bool DSAStackTy::hasDirective(NamedDirectivesPredicate DPred, bool FromParent) {
+ auto StartI = std::next(Stack.rbegin());
+ auto EndI = std::prev(Stack.rend());
+ if (FromParent && StartI != EndI) {
+ StartI = std::next(StartI);
+ }
+ for (auto I = StartI, EE = EndI; I != EE; ++I) {
+ if (DPred(I->Directive, I->DirectiveName, I->ConstructLoc))
+ return true;
+ }
+ return false;
+}
+
void Sema::InitDataSharingAttributesStack() {
VarDataSharingAttributesStack = new DSAStackTy(*this);
}
#define DSAStack static_cast<DSAStackTy *>(VarDataSharingAttributesStack)
-void Sema::DestroyDataSharingAttributesStack() {
- delete DSAStack;
-}
+void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; }
void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind,
const DeclarationNameInfo &DirName,
- Scope *CurScope) {
- DSAStack->push(DKind, DirName, CurScope);
+ Scope *CurScope, SourceLocation Loc) {
+ DSAStack->push(DKind, DirName, CurScope, Loc);
PushExpressionEvaluationContext(PotentiallyEvaluated);
}
void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
+ // OpenMP [2.14.3.5, Restrictions, C/C++, p.1]
+ // A variable of class type (or array thereof) that appears in a lastprivate
+ // clause requires an accessible, unambiguous default constructor for the
+ // class type, unless the list item is also specified in a firstprivate
+ // clause.
+ if (auto D = dyn_cast_or_null<OMPExecutableDirective>(CurDirective)) {
+ for (auto C : D->clauses()) {
+ if (auto Clause = dyn_cast<OMPLastprivateClause>(C)) {
+ for (auto VarRef : Clause->varlists()) {
+ if (VarRef->isValueDependent() || VarRef->isTypeDependent())
+ continue;
+ auto VD = cast<VarDecl>(cast<DeclRefExpr>(VarRef)->getDecl());
+ auto DVar = DSAStack->getTopDSA(VD, false);
+ if (DVar.CKind == OMPC_lastprivate) {
+ SourceLocation ELoc = VarRef->getExprLoc();
+ auto Type = VarRef->getType();
+ if (Type->isArrayType())
+ Type = QualType(Type->getArrayElementTypeNoTypeQual(), 0);
+ CXXRecordDecl *RD =
+ getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr;
+ // FIXME This code must be replaced by actual constructing of the
+ // lastprivate variable.
+ if (RD) {
+ CXXConstructorDecl *CD = LookupDefaultConstructor(RD);
+ PartialDiagnostic PD =
+ PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
+ if (!CD ||
+ CheckConstructorAccess(
+ ELoc, CD, InitializedEntity::InitializeTemporary(Type),
+ CD->getAccess(), PD) == AR_inaccessible ||
+ CD->isDeleted()) {
+ Diag(ELoc, diag::err_omp_required_method)
+ << getOpenMPClauseName(OMPC_lastprivate) << 0;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl
+ : diag::note_defined_here)
+ << VD;
+ Diag(RD->getLocation(), diag::note_previous_decl) << RD;
+ continue;
+ }
+ MarkFunctionReferenced(ELoc, CD);
+ DiagnoseUseOfDecl(CD, ELoc);
+ }
+ }
+ }
+ }
+ }
+ }
+
DSAStack->pop();
DiscardCleanupsInEvaluationContext();
PopExpressionEvaluationContext();
@@ -378,20 +585,21 @@ namespace {
class VarDeclFilterCCC : public CorrectionCandidateCallback {
private:
- Sema &Actions;
+ Sema &SemaRef;
+
public:
- VarDeclFilterCCC(Sema &S) : Actions(S) { }
- virtual bool ValidateCandidate(const TypoCorrection &Candidate) {
+ explicit VarDeclFilterCCC(Sema &S) : SemaRef(S) {}
+ bool ValidateCandidate(const TypoCorrection &Candidate) override {
NamedDecl *ND = Candidate.getCorrectionDecl();
if (VarDecl *VD = dyn_cast_or_null<VarDecl>(ND)) {
return VD->hasGlobalStorage() &&
- Actions.isDeclInScope(ND, Actions.getCurLexicalContext(),
- Actions.getCurScope());
+ SemaRef.isDeclInScope(ND, SemaRef.getCurLexicalContext(),
+ SemaRef.getCurScope());
}
return false;
}
};
-}
+} // namespace
ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
CXXScopeSpec &ScopeSpec,
@@ -405,12 +613,14 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
VarDecl *VD;
if (!Lookup.isSingleResult()) {
VarDeclFilterCCC Validator(*this);
- if (TypoCorrection Corrected = CorrectTypo(Id, LookupOrdinaryName, CurScope,
- 0, Validator)) {
+ if (TypoCorrection Corrected =
+ CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr, Validator,
+ CTK_ErrorRecovery)) {
diagnoseTypo(Corrected,
- PDiag(Lookup.empty()? diag::err_undeclared_var_use_suggest
- : diag::err_omp_expected_var_arg_suggest)
- << Id.getName());
+ PDiag(Lookup.empty()
+ ? diag::err_undeclared_var_use_suggest
+ : diag::err_omp_expected_var_arg_suggest)
+ << Id.getName());
VD = Corrected.getCorrectionDeclAs<VarDecl>();
} else {
Diag(Id.getLoc(), Lookup.empty() ? diag::err_undeclared_var_use
@@ -420,8 +630,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
}
} else {
if (!(VD = Lookup.getAsSingle<VarDecl>())) {
- Diag(Id.getLoc(), diag::err_omp_expected_var_arg)
- << Id.getName();
+ Diag(Id.getLoc(), diag::err_omp_expected_var_arg) << Id.getName();
Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at);
return ExprError();
}
@@ -432,12 +641,12 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
// Variables must be file-scope, namespace-scope, or static block-scope.
if (!VD->hasGlobalStorage()) {
Diag(Id.getLoc(), diag::err_omp_global_var_arg)
- << getOpenMPDirectiveName(OMPD_threadprivate)
- << !VD->isStaticLocal();
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
+ << getOpenMPDirectiveName(OMPD_threadprivate) << !VD->isStaticLocal();
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD;
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
return ExprError();
}
@@ -449,11 +658,12 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
if (CanonicalVD->getDeclContext()->isTranslationUnit() &&
!getCurLexicalContext()->isTranslationUnit()) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
- diag::note_defined_here) << VD;
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
return ExprError();
}
// OpenMP [2.9.2, Restrictions, C/C++, p.3]
@@ -463,11 +673,12 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
if (CanonicalVD->isStaticDataMember() &&
!CanonicalVD->getDeclContext()->Equals(getCurLexicalContext())) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
- diag::note_defined_here) << VD;
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
return ExprError();
}
// OpenMP [2.9.2, Restrictions, C/C++, p.4]
@@ -478,11 +689,12 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
(!getCurLexicalContext()->isFileContext() ||
!getCurLexicalContext()->Encloses(CanonicalVD->getDeclContext()))) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
- diag::note_defined_here) << VD;
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
return ExprError();
}
// OpenMP [2.9.2, Restrictions, C/C++, p.6]
@@ -491,11 +703,12 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
if (CanonicalVD->isStaticLocal() && CurScope &&
!isDeclInScope(ND, getCurLexicalContext(), CurScope)) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
- diag::note_defined_here) << VD;
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
return ExprError();
}
@@ -504,19 +717,18 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
// of the variables in its list.
if (VD->isUsed()) {
Diag(Id.getLoc(), diag::err_omp_var_used)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
return ExprError();
}
QualType ExprType = VD->getType().getNonReferenceType();
- ExprResult DE = BuildDeclRefExpr(VD, ExprType, VK_RValue, Id.getLoc());
- DSAStack->addDSA(VD, cast<DeclRefExpr>(DE.get()), OMPC_threadprivate);
+ ExprResult DE = BuildDeclRefExpr(VD, ExprType, VK_LValue, Id.getLoc());
return DE;
}
-Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective(
- SourceLocation Loc,
- ArrayRef<Expr *> VarList) {
+Sema::DeclGroupPtrTy
+Sema::ActOnOpenMPThreadprivateDirective(SourceLocation Loc,
+ ArrayRef<Expr *> VarList) {
if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, VarList)) {
CurContext->addDecl(D);
return DeclGroupPtrTy::make(DeclGroupRef(D));
@@ -524,14 +736,40 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective(
return DeclGroupPtrTy();
}
-OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
- SourceLocation Loc,
- ArrayRef<Expr *> VarList) {
+namespace {
+class LocalVarRefChecker : public ConstStmtVisitor<LocalVarRefChecker, bool> {
+ Sema &SemaRef;
+
+public:
+ bool VisitDeclRefExpr(const DeclRefExpr *E) {
+ if (auto VD = dyn_cast<VarDecl>(E->getDecl())) {
+ if (VD->hasLocalStorage()) {
+ SemaRef.Diag(E->getLocStart(),
+ diag::err_omp_local_var_in_threadprivate_init)
+ << E->getSourceRange();
+ SemaRef.Diag(VD->getLocation(), diag::note_defined_here)
+ << VD << VD->getSourceRange();
+ return true;
+ }
+ }
+ return false;
+ }
+ bool VisitStmt(const Stmt *S) {
+ for (auto Child : S->children()) {
+ if (Child && Visit(Child))
+ return true;
+ }
+ return false;
+ }
+ explicit LocalVarRefChecker(Sema &SemaRef) : SemaRef(SemaRef) {}
+};
+} // namespace
+
+OMPThreadPrivateDecl *
+Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) {
SmallVector<Expr *, 8> Vars;
- for (ArrayRef<Expr *>::iterator I = VarList.begin(),
- E = VarList.end();
- I != E; ++I) {
- DeclRefExpr *DE = cast<DeclRefExpr>(*I);
+ for (auto &RefExpr : VarList) {
+ DeclRefExpr *DE = cast<DeclRefExpr>(RefExpr);
VarDecl *VD = cast<VarDecl>(DE->getDecl());
SourceLocation ILoc = DE->getExprLoc();
@@ -546,64 +784,130 @@ OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
// A threadprivate variable must not have a reference type.
if (VD->getType()->isReferenceType()) {
Diag(ILoc, diag::err_omp_ref_type_arg)
- << getOpenMPDirectiveName(OMPD_threadprivate)
- << VD->getType();
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
- diag::note_defined_here) << VD;
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD->getType();
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
continue;
}
// Check if this is a TLS variable.
if (VD->getTLSKind()) {
Diag(ILoc, diag::err_omp_var_thread_local) << VD;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
- diag::note_defined_here) << VD;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
continue;
}
- Vars.push_back(*I);
+ // Check if initial value of threadprivate variable reference variable with
+ // local storage (it is not supported by runtime).
+ if (auto Init = VD->getAnyInitializer()) {
+ LocalVarRefChecker Checker(*this);
+ if (Checker.Visit(Init))
+ continue;
+ }
+
+ Vars.push_back(RefExpr);
+ DSAStack->addDSA(VD, DE, OMPC_threadprivate);
+ }
+ OMPThreadPrivateDecl *D = nullptr;
+ if (!Vars.empty()) {
+ D = OMPThreadPrivateDecl::Create(Context, getCurLexicalContext(), Loc,
+ Vars);
+ D->setAccess(AS_public);
+ }
+ return D;
+}
+
+static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack,
+ const VarDecl *VD, DSAStackTy::DSAVarData DVar,
+ bool IsLoopIterVar = false) {
+ if (DVar.RefExpr) {
+ SemaRef.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(DVar.CKind);
+ return;
+ }
+ enum {
+ PDSA_StaticMemberShared,
+ PDSA_StaticLocalVarShared,
+ PDSA_LoopIterVarPrivate,
+ PDSA_LoopIterVarLinear,
+ PDSA_LoopIterVarLastprivate,
+ PDSA_ConstVarShared,
+ PDSA_GlobalVarShared,
+ PDSA_TaskVarFirstprivate,
+ PDSA_LocalVarPrivate,
+ PDSA_Implicit
+ } Reason = PDSA_Implicit;
+ bool ReportHint = false;
+ auto ReportLoc = VD->getLocation();
+ if (IsLoopIterVar) {
+ if (DVar.CKind == OMPC_private)
+ Reason = PDSA_LoopIterVarPrivate;
+ else if (DVar.CKind == OMPC_lastprivate)
+ Reason = PDSA_LoopIterVarLastprivate;
+ else
+ Reason = PDSA_LoopIterVarLinear;
+ } else if (DVar.DKind == OMPD_task && DVar.CKind == OMPC_firstprivate) {
+ Reason = PDSA_TaskVarFirstprivate;
+ ReportLoc = DVar.ImplicitDSALoc;
+ } else if (VD->isStaticLocal())
+ Reason = PDSA_StaticLocalVarShared;
+ else if (VD->isStaticDataMember())
+ Reason = PDSA_StaticMemberShared;
+ else if (VD->isFileVarDecl())
+ Reason = PDSA_GlobalVarShared;
+ else if (VD->getType().isConstant(SemaRef.getASTContext()))
+ Reason = PDSA_ConstVarShared;
+ else if (VD->isLocalVarDecl() && DVar.CKind == OMPC_private) {
+ ReportHint = true;
+ Reason = PDSA_LocalVarPrivate;
+ }
+ if (Reason != PDSA_Implicit) {
+ SemaRef.Diag(ReportLoc, diag::note_omp_predetermined_dsa)
+ << Reason << ReportHint
+ << getOpenMPDirectiveName(Stack->getCurrentDirective());
+ } else if (DVar.ImplicitDSALoc.isValid()) {
+ SemaRef.Diag(DVar.ImplicitDSALoc, diag::note_omp_implicit_dsa)
+ << getOpenMPClauseName(DVar.CKind);
}
- return Vars.empty() ?
- 0 : OMPThreadPrivateDecl::Create(Context,
- getCurLexicalContext(),
- Loc, Vars);
}
namespace {
class DSAAttrChecker : public StmtVisitor<DSAAttrChecker, void> {
DSAStackTy *Stack;
- Sema &Actions;
+ Sema &SemaRef;
bool ErrorFound;
CapturedStmt *CS;
llvm::SmallVector<Expr *, 8> ImplicitFirstprivate;
+ llvm::DenseMap<VarDecl *, Expr *> VarsWithInheritedDSA;
+
public:
void VisitDeclRefExpr(DeclRefExpr *E) {
- if(VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) {
+ if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
// Skip internally declared variables.
- if (VD->isLocalVarDecl() && !CS->capturesVariable(VD)) return;
+ if (VD->isLocalVarDecl() && !CS->capturesVariable(VD))
+ return;
- SourceLocation ELoc = E->getExprLoc();
+ auto DVar = Stack->getTopDSA(VD, false);
+ // Check if the variable has explicit DSA set and stop analysis if it so.
+ if (DVar.RefExpr) return;
- OpenMPDirectiveKind DKind = Stack->getCurrentDirective();
- DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD);
- if (DVar.CKind != OMPC_unknown) {
- if (DKind == OMPD_task && DVar.CKind != OMPC_shared &&
- DVar.CKind != OMPC_threadprivate && !DVar.RefExpr)
- ImplicitFirstprivate.push_back(DVar.RefExpr);
- return;
- }
+ auto ELoc = E->getExprLoc();
+ auto DKind = Stack->getCurrentDirective();
// The default(none) clause requires that each variable that is referenced
// in the construct, and does not have a predetermined data-sharing
// attribute, must have its data-sharing attribute explicitly determined
// by being listed in a data-sharing attribute clause.
if (DVar.CKind == OMPC_unknown && Stack->getDefaultDSA() == DSA_none &&
- (DKind == OMPD_parallel || DKind == OMPD_task)) {
- ErrorFound = true;
- Actions.Diag(ELoc, diag::err_omp_no_dsa_for_variable) << VD;
+ isParallelOrTaskRegion(DKind) &&
+ VarsWithInheritedDSA.count(VD) == 0) {
+ VarsWithInheritedDSA[VD] = E;
return;
}
@@ -611,84 +915,593 @@ public:
// A list item that appears in a reduction clause of the innermost
// enclosing worksharing or parallel construct may not be accessed in an
// explicit task.
- // TODO:
+ DVar = Stack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction),
+ [](OpenMPDirectiveKind K) -> bool {
+ return isOpenMPParallelDirective(K) ||
+ isOpenMPWorksharingDirective(K);
+ },
+ false);
+ if (DKind == OMPD_task && DVar.CKind == OMPC_reduction) {
+ ErrorFound = true;
+ SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task);
+ ReportOriginalDSA(SemaRef, Stack, VD, DVar);
+ return;
+ }
// Define implicit data-sharing attributes for task.
- DVar = Stack->getImplicitDSA(VD);
+ DVar = Stack->getImplicitDSA(VD, false);
if (DKind == OMPD_task && DVar.CKind != OMPC_shared)
- ImplicitFirstprivate.push_back(DVar.RefExpr);
+ ImplicitFirstprivate.push_back(E);
}
}
void VisitOMPExecutableDirective(OMPExecutableDirective *S) {
- for (ArrayRef<OMPClause *>::iterator I = S->clauses().begin(),
- E = S->clauses().end();
- I != E; ++I)
- if (OMPClause *C = *I)
- for (StmtRange R = C->children(); R; ++R)
- if (Stmt *Child = *R)
- Visit(Child);
+ for (auto *C : S->clauses()) {
+ // Skip analysis of arguments of implicitly defined firstprivate clause
+ // for task directives.
+ if (C && (!isa<OMPFirstprivateClause>(C) || C->getLocStart().isValid()))
+ for (auto *CC : C->children()) {
+ if (CC)
+ Visit(CC);
+ }
+ }
}
void VisitStmt(Stmt *S) {
- for (Stmt::child_iterator I = S->child_begin(), E = S->child_end();
- I != E; ++I)
- if (Stmt *Child = *I)
- if (!isa<OMPExecutableDirective>(Child))
- Visit(Child);
+ for (auto *C : S->children()) {
+ if (C && !isa<OMPExecutableDirective>(C))
+ Visit(C);
}
+ }
bool isErrorFound() { return ErrorFound; }
ArrayRef<Expr *> getImplicitFirstprivate() { return ImplicitFirstprivate; }
+ llvm::DenseMap<VarDecl *, Expr *> &getVarsWithInheritedDSA() {
+ return VarsWithInheritedDSA;
+ }
- DSAAttrChecker(DSAStackTy *S, Sema &Actions, CapturedStmt *CS)
- : Stack(S), Actions(Actions), ErrorFound(false), CS(CS) { }
+ DSAAttrChecker(DSAStackTy *S, Sema &SemaRef, CapturedStmt *CS)
+ : Stack(S), SemaRef(SemaRef), ErrorFound(false), CS(CS) {}
};
+} // namespace
+
+void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
+ switch (DKind) {
+ case OMPD_parallel: {
+ QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
+ QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty);
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(".global_tid.", KmpInt32PtrTy),
+ std::make_pair(".bound_tid.", KmpInt32PtrTy),
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
+ case OMPD_simd: {
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
+ case OMPD_for: {
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
+ case OMPD_sections: {
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
+ case OMPD_section: {
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
+ case OMPD_single: {
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
+ case OMPD_master: {
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
+ case OMPD_critical: {
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
+ case OMPD_parallel_for: {
+ QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
+ QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty);
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(".global_tid.", KmpInt32PtrTy),
+ std::make_pair(".bound_tid.", KmpInt32PtrTy),
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
+ case OMPD_parallel_sections: {
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
+ case OMPD_task: {
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
+ case OMPD_taskyield: {
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
+ case OMPD_barrier: {
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
+ case OMPD_taskwait: {
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
+ case OMPD_flush: {
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params);
+ break;
+ }
+ case OMPD_threadprivate:
+ llvm_unreachable("OpenMP Directive is not allowed");
+ case OMPD_unknown:
+ llvm_unreachable("Unknown OpenMP directive");
+ }
+}
+
+static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
+ OpenMPDirectiveKind CurrentRegion,
+ const DeclarationNameInfo &CurrentName,
+ SourceLocation StartLoc) {
+ // Allowed nesting of constructs
+ // +------------------+-----------------+------------------------------------+
+ // | Parent directive | Child directive | Closely (!), No-Closely(+), Both(*)|
+ // +------------------+-----------------+------------------------------------+
+ // | parallel | parallel | * |
+ // | parallel | for | * |
+ // | parallel | master | * |
+ // | parallel | critical | * |
+ // | parallel | simd | * |
+ // | parallel | sections | * |
+ // | parallel | section | + |
+ // | parallel | single | * |
+ // | parallel | parallel for | * |
+ // | parallel |parallel sections| * |
+ // | parallel | task | * |
+ // | parallel | taskyield | * |
+ // | parallel | barrier | * |
+ // | parallel | taskwait | * |
+ // | parallel | flush | * |
+ // +------------------+-----------------+------------------------------------+
+ // | for | parallel | * |
+ // | for | for | + |
+ // | for | master | + |
+ // | for | critical | * |
+ // | for | simd | * |
+ // | for | sections | + |
+ // | for | section | + |
+ // | for | single | + |
+ // | for | parallel for | * |
+ // | for |parallel sections| * |
+ // | for | task | * |
+ // | for | taskyield | * |
+ // | for | barrier | + |
+ // | for | taskwait | * |
+ // | for | flush | * |
+ // +------------------+-----------------+------------------------------------+
+ // | master | parallel | * |
+ // | master | for | + |
+ // | master | master | * |
+ // | master | critical | * |
+ // | master | simd | * |
+ // | master | sections | + |
+ // | master | section | + |
+ // | master | single | + |
+ // | master | parallel for | * |
+ // | master |parallel sections| * |
+ // | master | task | * |
+ // | master | taskyield | * |
+ // | master | barrier | + |
+ // | master | taskwait | * |
+ // | master | flush | * |
+ // +------------------+-----------------+------------------------------------+
+ // | critical | parallel | * |
+ // | critical | for | + |
+ // | critical | master | * |
+ // | critical | critical | * (should have dirrerent names) |
+ // | critical | simd | * |
+ // | critical | sections | + |
+ // | critical | section | + |
+ // | critical | single | + |
+ // | critical | parallel for | * |
+ // | critical |parallel sections| * |
+ // | critical | task | * |
+ // | critical | taskyield | * |
+ // | critical | barrier | + |
+ // | critical | taskwait | * |
+ // +------------------+-----------------+------------------------------------+
+ // | simd | parallel | |
+ // | simd | for | |
+ // | simd | master | |
+ // | simd | critical | |
+ // | simd | simd | |
+ // | simd | sections | |
+ // | simd | section | |
+ // | simd | single | |
+ // | simd | parallel for | |
+ // | simd |parallel sections| |
+ // | simd | task | |
+ // | simd | taskyield | |
+ // | simd | barrier | |
+ // | simd | taskwait | |
+ // | simd | flush | |
+ // +------------------+-----------------+------------------------------------+
+ // | sections | parallel | * |
+ // | sections | for | + |
+ // | sections | master | + |
+ // | sections | critical | * |
+ // | sections | simd | * |
+ // | sections | sections | + |
+ // | sections | section | * |
+ // | sections | single | + |
+ // | sections | parallel for | * |
+ // | sections |parallel sections| * |
+ // | sections | task | * |
+ // | sections | taskyield | * |
+ // | sections | barrier | + |
+ // | sections | taskwait | * |
+ // | sections | flush | * |
+ // +------------------+-----------------+------------------------------------+
+ // | section | parallel | * |
+ // | section | for | + |
+ // | section | master | + |
+ // | section | critical | * |
+ // | section | simd | * |
+ // | section | sections | + |
+ // | section | section | + |
+ // | section | single | + |
+ // | section | parallel for | * |
+ // | section |parallel sections| * |
+ // | section | task | * |
+ // | section | taskyield | * |
+ // | section | barrier | + |
+ // | section | taskwait | * |
+ // | section | flush | * |
+ // +------------------+-----------------+------------------------------------+
+ // | single | parallel | * |
+ // | single | for | + |
+ // | single | master | + |
+ // | single | critical | * |
+ // | single | simd | * |
+ // | single | sections | + |
+ // | single | section | + |
+ // | single | single | + |
+ // | single | parallel for | * |
+ // | single |parallel sections| * |
+ // | single | task | * |
+ // | single | taskyield | * |
+ // | single | barrier | + |
+ // | single | taskwait | * |
+ // | single | flush | * |
+ // +------------------+-----------------+------------------------------------+
+ // | parallel for | parallel | * |
+ // | parallel for | for | + |
+ // | parallel for | master | + |
+ // | parallel for | critical | * |
+ // | parallel for | simd | * |
+ // | parallel for | sections | + |
+ // | parallel for | section | + |
+ // | parallel for | single | + |
+ // | parallel for | parallel for | * |
+ // | parallel for |parallel sections| * |
+ // | parallel for | task | * |
+ // | parallel for | taskyield | * |
+ // | parallel for | barrier | + |
+ // | parallel for | taskwait | * |
+ // | parallel for | flush | * |
+ // +------------------+-----------------+------------------------------------+
+ // | parallel sections| parallel | * |
+ // | parallel sections| for | + |
+ // | parallel sections| master | + |
+ // | parallel sections| critical | + |
+ // | parallel sections| simd | * |
+ // | parallel sections| sections | + |
+ // | parallel sections| section | * |
+ // | parallel sections| single | + |
+ // | parallel sections| parallel for | * |
+ // | parallel sections|parallel sections| * |
+ // | parallel sections| task | * |
+ // | parallel sections| taskyield | * |
+ // | parallel sections| barrier | + |
+ // | parallel sections| taskwait | * |
+ // | parallel sections| flush | * |
+ // +------------------+-----------------+------------------------------------+
+ // | task | parallel | * |
+ // | task | for | + |
+ // | task | master | + |
+ // | task | critical | * |
+ // | task | simd | * |
+ // | task | sections | + |
+ // | task | section | + |
+ // | task | single | + |
+ // | task | parallel for | * |
+ // | task |parallel sections| * |
+ // | task | task | * |
+ // | task | taskyield | * |
+ // | task | barrier | + |
+ // | task | taskwait | * |
+ // | task | flush | * |
+ // +------------------+-----------------+------------------------------------+
+ if (Stack->getCurScope()) {
+ auto ParentRegion = Stack->getParentDirective();
+ bool NestingProhibited = false;
+ bool CloseNesting = true;
+ bool ShouldBeInParallelRegion = false;
+ if (isOpenMPSimdDirective(ParentRegion)) {
+ // OpenMP [2.16, Nesting of Regions]
+ // OpenMP constructs may not be nested inside a simd region.
+ SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_simd);
+ return true;
+ }
+ if (CurrentRegion == OMPD_section) {
+ // OpenMP [2.7.2, sections Construct, Restrictions]
+ // Orphaned section directives are prohibited. That is, the section
+ // directives must appear within the sections construct and must not be
+ // encountered elsewhere in the sections region.
+ if (ParentRegion != OMPD_sections &&
+ ParentRegion != OMPD_parallel_sections) {
+ SemaRef.Diag(StartLoc, diag::err_omp_orphaned_section_directive)
+ << (ParentRegion != OMPD_unknown)
+ << getOpenMPDirectiveName(ParentRegion);
+ return true;
+ }
+ return false;
+ }
+ if (CurrentRegion == OMPD_master) {
+ // OpenMP [2.16, Nesting of Regions]
+ // A master region may not be closely nested inside a worksharing,
+ // atomic (TODO), or explicit task region.
+ NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) ||
+ ParentRegion == OMPD_task;
+ } else if (CurrentRegion == OMPD_critical && CurrentName.getName()) {
+ // OpenMP [2.16, Nesting of Regions]
+ // A critical region may not be nested (closely or otherwise) inside a
+ // critical region with the same name. Note that this restriction is not
+ // sufficient to prevent deadlock.
+ SourceLocation PreviousCriticalLoc;
+ bool DeadLock =
+ Stack->hasDirective([CurrentName, &PreviousCriticalLoc](
+ OpenMPDirectiveKind K,
+ const DeclarationNameInfo &DNI,
+ SourceLocation Loc)
+ ->bool {
+ if (K == OMPD_critical &&
+ DNI.getName() == CurrentName.getName()) {
+ PreviousCriticalLoc = Loc;
+ return true;
+ } else
+ return false;
+ },
+ false /* skip top directive */);
+ if (DeadLock) {
+ SemaRef.Diag(StartLoc,
+ diag::err_omp_prohibited_region_critical_same_name)
+ << CurrentName.getName();
+ if (PreviousCriticalLoc.isValid())
+ SemaRef.Diag(PreviousCriticalLoc,
+ diag::note_omp_previous_critical_region);
+ return true;
+ }
+ } else if (CurrentRegion == OMPD_barrier) {
+ // OpenMP [2.16, Nesting of Regions]
+ // A barrier region may not be closely nested inside a worksharing,
+ // explicit task, critical, ordered(TODO), atomic(TODO), or master
+ // region.
+ NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) ||
+ ParentRegion == OMPD_task ||
+ ParentRegion == OMPD_master ||
+ ParentRegion == OMPD_critical;
+ } else if (isOpenMPWorksharingDirective(CurrentRegion) &&
+ !isOpenMPParallelDirective(CurrentRegion) &&
+ !isOpenMPSimdDirective(CurrentRegion)) {
+ // OpenMP [2.16, Nesting of Regions]
+ // A worksharing region may not be closely nested inside a worksharing,
+ // explicit task, critical, ordered, atomic, or master region.
+ // TODO
+ NestingProhibited = (isOpenMPWorksharingDirective(ParentRegion) &&
+ !isOpenMPSimdDirective(ParentRegion)) ||
+ ParentRegion == OMPD_task ||
+ ParentRegion == OMPD_master ||
+ ParentRegion == OMPD_critical;
+ ShouldBeInParallelRegion = true;
+ }
+ if (NestingProhibited) {
+ SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region)
+ << CloseNesting << getOpenMPDirectiveName(ParentRegion)
+ << ShouldBeInParallelRegion << getOpenMPDirectiveName(CurrentRegion);
+ return true;
+ }
+ }
+ return false;
}
StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind,
+ const DeclarationNameInfo &DirName,
ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
- assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected");
-
StmtResult Res = StmtError();
-
- // Check default data sharing attributes for referenced variables.
- DSAAttrChecker DSAChecker(DSAStack, *this, cast<CapturedStmt>(AStmt));
- DSAChecker.Visit(cast<CapturedStmt>(AStmt)->getCapturedStmt());
- if (DSAChecker.isErrorFound())
+ if (CheckNestingOfRegions(*this, DSAStack, Kind, DirName, StartLoc))
return StmtError();
- // Generate list of implicitly defined firstprivate variables.
+
llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit;
+ llvm::DenseMap<VarDecl *, Expr *> VarsWithInheritedDSA;
+ bool ErrorFound = false;
ClausesWithImplicit.append(Clauses.begin(), Clauses.end());
+ if (AStmt) {
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
- bool ErrorFound = false;
- if (!DSAChecker.getImplicitFirstprivate().empty()) {
- if (OMPClause *Implicit =
- ActOnOpenMPFirstprivateClause(DSAChecker.getImplicitFirstprivate(),
- SourceLocation(), SourceLocation(),
- SourceLocation())) {
- ClausesWithImplicit.push_back(Implicit);
- ErrorFound = cast<OMPFirstprivateClause>(Implicit)->varlist_size() !=
- DSAChecker.getImplicitFirstprivate().size();
- } else
- ErrorFound = true;
+ // Check default data sharing attributes for referenced variables.
+ DSAAttrChecker DSAChecker(DSAStack, *this, cast<CapturedStmt>(AStmt));
+ DSAChecker.Visit(cast<CapturedStmt>(AStmt)->getCapturedStmt());
+ if (DSAChecker.isErrorFound())
+ return StmtError();
+ // Generate list of implicitly defined firstprivate variables.
+ VarsWithInheritedDSA = DSAChecker.getVarsWithInheritedDSA();
+
+ if (!DSAChecker.getImplicitFirstprivate().empty()) {
+ if (OMPClause *Implicit = ActOnOpenMPFirstprivateClause(
+ DSAChecker.getImplicitFirstprivate(), SourceLocation(),
+ SourceLocation(), SourceLocation())) {
+ ClausesWithImplicit.push_back(Implicit);
+ ErrorFound = cast<OMPFirstprivateClause>(Implicit)->varlist_size() !=
+ DSAChecker.getImplicitFirstprivate().size();
+ } else
+ ErrorFound = true;
+ }
}
switch (Kind) {
case OMPD_parallel:
- Res = ActOnOpenMPParallelDirective(ClausesWithImplicit, AStmt,
- StartLoc, EndLoc);
+ Res = ActOnOpenMPParallelDirective(ClausesWithImplicit, AStmt, StartLoc,
+ EndLoc);
+ break;
+ case OMPD_simd:
+ Res = ActOnOpenMPSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc,
+ VarsWithInheritedDSA);
+ break;
+ case OMPD_for:
+ Res = ActOnOpenMPForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc,
+ VarsWithInheritedDSA);
+ break;
+ case OMPD_sections:
+ Res = ActOnOpenMPSectionsDirective(ClausesWithImplicit, AStmt, StartLoc,
+ EndLoc);
+ break;
+ case OMPD_section:
+ assert(ClausesWithImplicit.empty() &&
+ "No clauses are allowed for 'omp section' directive");
+ Res = ActOnOpenMPSectionDirective(AStmt, StartLoc, EndLoc);
+ break;
+ case OMPD_single:
+ Res = ActOnOpenMPSingleDirective(ClausesWithImplicit, AStmt, StartLoc,
+ EndLoc);
+ break;
+ case OMPD_master:
+ assert(ClausesWithImplicit.empty() &&
+ "No clauses are allowed for 'omp master' directive");
+ Res = ActOnOpenMPMasterDirective(AStmt, StartLoc, EndLoc);
+ break;
+ case OMPD_critical:
+ assert(ClausesWithImplicit.empty() &&
+ "No clauses are allowed for 'omp critical' directive");
+ Res = ActOnOpenMPCriticalDirective(DirName, AStmt, StartLoc, EndLoc);
+ break;
+ case OMPD_parallel_for:
+ Res = ActOnOpenMPParallelForDirective(ClausesWithImplicit, AStmt, StartLoc,
+ EndLoc, VarsWithInheritedDSA);
+ break;
+ case OMPD_parallel_sections:
+ Res = ActOnOpenMPParallelSectionsDirective(ClausesWithImplicit, AStmt,
+ StartLoc, EndLoc);
break;
- case OMPD_threadprivate:
case OMPD_task:
+ Res =
+ ActOnOpenMPTaskDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc);
+ break;
+ case OMPD_taskyield:
+ assert(ClausesWithImplicit.empty() &&
+ "No clauses are allowed for 'omp taskyield' directive");
+ assert(AStmt == nullptr &&
+ "No associated statement allowed for 'omp taskyield' directive");
+ Res = ActOnOpenMPTaskyieldDirective(StartLoc, EndLoc);
+ break;
+ case OMPD_barrier:
+ assert(ClausesWithImplicit.empty() &&
+ "No clauses are allowed for 'omp barrier' directive");
+ assert(AStmt == nullptr &&
+ "No associated statement allowed for 'omp barrier' directive");
+ Res = ActOnOpenMPBarrierDirective(StartLoc, EndLoc);
+ break;
+ case OMPD_taskwait:
+ assert(ClausesWithImplicit.empty() &&
+ "No clauses are allowed for 'omp taskwait' directive");
+ assert(AStmt == nullptr &&
+ "No associated statement allowed for 'omp taskwait' directive");
+ Res = ActOnOpenMPTaskwaitDirective(StartLoc, EndLoc);
+ break;
+ case OMPD_flush:
+ assert(AStmt == nullptr &&
+ "No associated statement allowed for 'omp flush' directive");
+ Res = ActOnOpenMPFlushDirective(ClausesWithImplicit, StartLoc, EndLoc);
+ break;
+ case OMPD_threadprivate:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
- case NUM_OPENMP_DIRECTIVES:
llvm_unreachable("Unknown OpenMP directive");
}
- if (ErrorFound) return StmtError();
+ for (auto P : VarsWithInheritedDSA) {
+ Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable)
+ << P.first << P.second->getSourceRange();
+ }
+ if (!VarsWithInheritedDSA.empty())
+ return StmtError();
+
+ if (ErrorFound)
+ return StmtError();
return Res;
}
@@ -696,31 +1509,1004 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
+ assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ CapturedStmt *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+
getCurFunction()->setHasBranchProtectedScope();
- return Owned(OMPParallelDirective::Create(Context, StartLoc, EndLoc,
- Clauses, AStmt));
+ return OMPParallelDirective::Create(Context, StartLoc, EndLoc, Clauses,
+ AStmt);
}
-OMPClause *Sema::ActOnOpenMPSimpleClause(OpenMPClauseKind Kind,
- unsigned Argument,
- SourceLocation ArgumentLoc,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
- OMPClause *Res = 0;
+namespace {
+/// \brief Helper class for checking canonical form of the OpenMP loops and
+/// extracting iteration space of each loop in the loop nest, that will be used
+/// for IR generation.
+class OpenMPIterationSpaceChecker {
+ /// \brief Reference to Sema.
+ Sema &SemaRef;
+ /// \brief A location for diagnostics (when there is no some better location).
+ SourceLocation DefaultLoc;
+ /// \brief A location for diagnostics (when increment is not compatible).
+ SourceLocation ConditionLoc;
+ /// \brief A source location for referring to condition later.
+ SourceRange ConditionSrcRange;
+ /// \brief Loop variable.
+ VarDecl *Var;
+ /// \brief Lower bound (initializer for the var).
+ Expr *LB;
+ /// \brief Upper bound.
+ Expr *UB;
+ /// \brief Loop step (increment).
+ Expr *Step;
+ /// \brief This flag is true when condition is one of:
+ /// Var < UB
+ /// Var <= UB
+ /// UB > Var
+ /// UB >= Var
+ bool TestIsLessOp;
+ /// \brief This flag is true when condition is strict ( < or > ).
+ bool TestIsStrictOp;
+ /// \brief This flag is true when step is subtracted on each iteration.
+ bool SubtractStep;
+
+public:
+ OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc)
+ : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc),
+ ConditionSrcRange(SourceRange()), Var(nullptr), LB(nullptr),
+ UB(nullptr), Step(nullptr), TestIsLessOp(false), TestIsStrictOp(false),
+ SubtractStep(false) {}
+ /// \brief Check init-expr for canonical loop form and save loop counter
+ /// variable - #Var and its initialization value - #LB.
+ bool CheckInit(Stmt *S);
+ /// \brief Check test-expr for canonical form, save upper-bound (#UB), flags
+ /// for less/greater and for strict/non-strict comparison.
+ bool CheckCond(Expr *S);
+ /// \brief Check incr-expr for canonical loop form and return true if it
+ /// does not conform, otherwise save loop step (#Step).
+ bool CheckInc(Expr *S);
+ /// \brief Return the loop counter variable.
+ VarDecl *GetLoopVar() const { return Var; }
+ /// \brief Return true if any expression is dependent.
+ bool Dependent() const;
+
+private:
+ /// \brief Check the right-hand side of an assignment in the increment
+ /// expression.
+ bool CheckIncRHS(Expr *RHS);
+ /// \brief Helper to set loop counter variable and its initializer.
+ bool SetVarAndLB(VarDecl *NewVar, Expr *NewLB);
+ /// \brief Helper to set upper bound.
+ bool SetUB(Expr *NewUB, bool LessOp, bool StrictOp, const SourceRange &SR,
+ const SourceLocation &SL);
+ /// \brief Helper to set loop increment.
+ bool SetStep(Expr *NewStep, bool Subtract);
+};
+
+bool OpenMPIterationSpaceChecker::Dependent() const {
+ if (!Var) {
+ assert(!LB && !UB && !Step);
+ return false;
+ }
+ return Var->getType()->isDependentType() || (LB && LB->isValueDependent()) ||
+ (UB && UB->isValueDependent()) || (Step && Step->isValueDependent());
+}
+
+bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar, Expr *NewLB) {
+ // State consistency checking to ensure correct usage.
+ assert(Var == nullptr && LB == nullptr && UB == nullptr && Step == nullptr &&
+ !TestIsLessOp && !TestIsStrictOp);
+ if (!NewVar || !NewLB)
+ return true;
+ Var = NewVar;
+ LB = NewLB;
+ return false;
+}
+
+bool OpenMPIterationSpaceChecker::SetUB(Expr *NewUB, bool LessOp, bool StrictOp,
+ const SourceRange &SR,
+ const SourceLocation &SL) {
+ // State consistency checking to ensure correct usage.
+ assert(Var != nullptr && LB != nullptr && UB == nullptr && Step == nullptr &&
+ !TestIsLessOp && !TestIsStrictOp);
+ if (!NewUB)
+ return true;
+ UB = NewUB;
+ TestIsLessOp = LessOp;
+ TestIsStrictOp = StrictOp;
+ ConditionSrcRange = SR;
+ ConditionLoc = SL;
+ return false;
+}
+
+bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) {
+ // State consistency checking to ensure correct usage.
+ assert(Var != nullptr && LB != nullptr && Step == nullptr);
+ if (!NewStep)
+ return true;
+ if (!NewStep->isValueDependent()) {
+ // Check that the step is integer expression.
+ SourceLocation StepLoc = NewStep->getLocStart();
+ ExprResult Val =
+ SemaRef.PerformOpenMPImplicitIntegerConversion(StepLoc, NewStep);
+ if (Val.isInvalid())
+ return true;
+ NewStep = Val.get();
+
+ // OpenMP [2.6, Canonical Loop Form, Restrictions]
+ // If test-expr is of form var relational-op b and relational-op is < or
+ // <= then incr-expr must cause var to increase on each iteration of the
+ // loop. If test-expr is of form var relational-op b and relational-op is
+ // > or >= then incr-expr must cause var to decrease on each iteration of
+ // the loop.
+ // If test-expr is of form b relational-op var and relational-op is < or
+ // <= then incr-expr must cause var to decrease on each iteration of the
+ // loop. If test-expr is of form b relational-op var and relational-op is
+ // > or >= then incr-expr must cause var to increase on each iteration of
+ // the loop.
+ llvm::APSInt Result;
+ bool IsConstant = NewStep->isIntegerConstantExpr(Result, SemaRef.Context);
+ bool IsUnsigned = !NewStep->getType()->hasSignedIntegerRepresentation();
+ bool IsConstNeg =
+ IsConstant && Result.isSigned() && (Subtract != Result.isNegative());
+ bool IsConstZero = IsConstant && !Result.getBoolValue();
+ if (UB && (IsConstZero ||
+ (TestIsLessOp ? (IsConstNeg || (IsUnsigned && Subtract))
+ : (!IsConstNeg || (IsUnsigned && !Subtract))))) {
+ SemaRef.Diag(NewStep->getExprLoc(),
+ diag::err_omp_loop_incr_not_compatible)
+ << Var << TestIsLessOp << NewStep->getSourceRange();
+ SemaRef.Diag(ConditionLoc,
+ diag::note_omp_loop_cond_requres_compatible_incr)
+ << TestIsLessOp << ConditionSrcRange;
+ return true;
+ }
+ }
+
+ Step = NewStep;
+ SubtractStep = Subtract;
+ return false;
+}
+
+bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S) {
+ // Check init-expr for canonical loop form and save loop counter
+ // variable - #Var and its initialization value - #LB.
+ // OpenMP [2.6] Canonical loop form. init-expr may be one of the following:
+ // var = lb
+ // integer-type var = lb
+ // random-access-iterator-type var = lb
+ // pointer-type var = lb
+ //
+ if (!S) {
+ SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_init);
+ return true;
+ }
+ if (Expr *E = dyn_cast<Expr>(S))
+ S = E->IgnoreParens();
+ if (auto BO = dyn_cast<BinaryOperator>(S)) {
+ if (BO->getOpcode() == BO_Assign)
+ if (auto DRE = dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens()))
+ return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), BO->getLHS());
+ } else if (auto DS = dyn_cast<DeclStmt>(S)) {
+ if (DS->isSingleDecl()) {
+ if (auto Var = dyn_cast_or_null<VarDecl>(DS->getSingleDecl())) {
+ if (Var->hasInit()) {
+ // Accept non-canonical init form here but emit ext. warning.
+ if (Var->getInitStyle() != VarDecl::CInit)
+ SemaRef.Diag(S->getLocStart(),
+ diag::ext_omp_loop_not_canonical_init)
+ << S->getSourceRange();
+ return SetVarAndLB(Var, Var->getInit());
+ }
+ }
+ }
+ } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S))
+ if (CE->getOperator() == OO_Equal)
+ if (auto DRE = dyn_cast<DeclRefExpr>(CE->getArg(0)))
+ return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), CE->getArg(1));
+
+ SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_init)
+ << S->getSourceRange();
+ return true;
+}
+
+/// \brief Ignore parenthesizes, implicit casts, copy constructor and return the
+/// variable (which may be the loop variable) if possible.
+static const VarDecl *GetInitVarDecl(const Expr *E) {
+ if (!E)
+ return nullptr;
+ E = E->IgnoreParenImpCasts();
+ if (auto *CE = dyn_cast_or_null<CXXConstructExpr>(E))
+ if (const CXXConstructorDecl *Ctor = CE->getConstructor())
+ if (Ctor->isCopyConstructor() && CE->getNumArgs() == 1 &&
+ CE->getArg(0) != nullptr)
+ E = CE->getArg(0)->IgnoreParenImpCasts();
+ auto DRE = dyn_cast_or_null<DeclRefExpr>(E);
+ if (!DRE)
+ return nullptr;
+ return dyn_cast<VarDecl>(DRE->getDecl());
+}
+
+bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) {
+ // Check test-expr for canonical form, save upper-bound UB, flags for
+ // less/greater and for strict/non-strict comparison.
+ // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following:
+ // var relational-op b
+ // b relational-op var
+ //
+ if (!S) {
+ SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << Var;
+ return true;
+ }
+ S = S->IgnoreParenImpCasts();
+ SourceLocation CondLoc = S->getLocStart();
+ if (auto BO = dyn_cast<BinaryOperator>(S)) {
+ if (BO->isRelationalOp()) {
+ if (GetInitVarDecl(BO->getLHS()) == Var)
+ return SetUB(BO->getRHS(),
+ (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_LE),
+ (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT),
+ BO->getSourceRange(), BO->getOperatorLoc());
+ if (GetInitVarDecl(BO->getRHS()) == Var)
+ return SetUB(BO->getLHS(),
+ (BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE),
+ (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT),
+ BO->getSourceRange(), BO->getOperatorLoc());
+ }
+ } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S)) {
+ if (CE->getNumArgs() == 2) {
+ auto Op = CE->getOperator();
+ switch (Op) {
+ case OO_Greater:
+ case OO_GreaterEqual:
+ case OO_Less:
+ case OO_LessEqual:
+ if (GetInitVarDecl(CE->getArg(0)) == Var)
+ return SetUB(CE->getArg(1), Op == OO_Less || Op == OO_LessEqual,
+ Op == OO_Less || Op == OO_Greater, CE->getSourceRange(),
+ CE->getOperatorLoc());
+ if (GetInitVarDecl(CE->getArg(1)) == Var)
+ return SetUB(CE->getArg(0), Op == OO_Greater || Op == OO_GreaterEqual,
+ Op == OO_Less || Op == OO_Greater, CE->getSourceRange(),
+ CE->getOperatorLoc());
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond)
+ << S->getSourceRange() << Var;
+ return true;
+}
+
+bool OpenMPIterationSpaceChecker::CheckIncRHS(Expr *RHS) {
+ // RHS of canonical loop form increment can be:
+ // var + incr
+ // incr + var
+ // var - incr
+ //
+ RHS = RHS->IgnoreParenImpCasts();
+ if (auto BO = dyn_cast<BinaryOperator>(RHS)) {
+ if (BO->isAdditiveOp()) {
+ bool IsAdd = BO->getOpcode() == BO_Add;
+ if (GetInitVarDecl(BO->getLHS()) == Var)
+ return SetStep(BO->getRHS(), !IsAdd);
+ if (IsAdd && GetInitVarDecl(BO->getRHS()) == Var)
+ return SetStep(BO->getLHS(), false);
+ }
+ } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(RHS)) {
+ bool IsAdd = CE->getOperator() == OO_Plus;
+ if ((IsAdd || CE->getOperator() == OO_Minus) && CE->getNumArgs() == 2) {
+ if (GetInitVarDecl(CE->getArg(0)) == Var)
+ return SetStep(CE->getArg(1), !IsAdd);
+ if (IsAdd && GetInitVarDecl(CE->getArg(1)) == Var)
+ return SetStep(CE->getArg(0), false);
+ }
+ }
+ SemaRef.Diag(RHS->getLocStart(), diag::err_omp_loop_not_canonical_incr)
+ << RHS->getSourceRange() << Var;
+ return true;
+}
+
+bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) {
+ // Check incr-expr for canonical loop form and return true if it
+ // does not conform.
+ // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following:
+ // ++var
+ // var++
+ // --var
+ // var--
+ // var += incr
+ // var -= incr
+ // var = var + incr
+ // var = incr + var
+ // var = var - incr
+ //
+ if (!S) {
+ SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) << Var;
+ return true;
+ }
+ S = S->IgnoreParens();
+ if (auto UO = dyn_cast<UnaryOperator>(S)) {
+ if (UO->isIncrementDecrementOp() && GetInitVarDecl(UO->getSubExpr()) == Var)
+ return SetStep(
+ SemaRef.ActOnIntegerConstant(UO->getLocStart(),
+ (UO->isDecrementOp() ? -1 : 1)).get(),
+ false);
+ } else if (auto BO = dyn_cast<BinaryOperator>(S)) {
+ switch (BO->getOpcode()) {
+ case BO_AddAssign:
+ case BO_SubAssign:
+ if (GetInitVarDecl(BO->getLHS()) == Var)
+ return SetStep(BO->getRHS(), BO->getOpcode() == BO_SubAssign);
+ break;
+ case BO_Assign:
+ if (GetInitVarDecl(BO->getLHS()) == Var)
+ return CheckIncRHS(BO->getRHS());
+ break;
+ default:
+ break;
+ }
+ } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S)) {
+ switch (CE->getOperator()) {
+ case OO_PlusPlus:
+ case OO_MinusMinus:
+ if (GetInitVarDecl(CE->getArg(0)) == Var)
+ return SetStep(
+ SemaRef.ActOnIntegerConstant(
+ CE->getLocStart(),
+ ((CE->getOperator() == OO_MinusMinus) ? -1 : 1)).get(),
+ false);
+ break;
+ case OO_PlusEqual:
+ case OO_MinusEqual:
+ if (GetInitVarDecl(CE->getArg(0)) == Var)
+ return SetStep(CE->getArg(1), CE->getOperator() == OO_MinusEqual);
+ break;
+ case OO_Equal:
+ if (GetInitVarDecl(CE->getArg(0)) == Var)
+ return CheckIncRHS(CE->getArg(1));
+ break;
+ default:
+ break;
+ }
+ }
+ SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_incr)
+ << S->getSourceRange() << Var;
+ return true;
+}
+} // namespace
+
+/// \brief Called on a for stmt to check and extract its iteration space
+/// for further processing (such as collapsing).
+static bool CheckOpenMPIterationSpace(
+ OpenMPDirectiveKind DKind, Stmt *S, Sema &SemaRef, DSAStackTy &DSA,
+ unsigned CurrentNestedLoopCount, unsigned NestedLoopCount,
+ Expr *NestedLoopCountExpr,
+ llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ // OpenMP [2.6, Canonical Loop Form]
+ // for (init-expr; test-expr; incr-expr) structured-block
+ auto For = dyn_cast_or_null<ForStmt>(S);
+ if (!For) {
+ SemaRef.Diag(S->getLocStart(), diag::err_omp_not_for)
+ << (NestedLoopCountExpr != nullptr) << getOpenMPDirectiveName(DKind)
+ << NestedLoopCount << (CurrentNestedLoopCount > 0)
+ << CurrentNestedLoopCount;
+ if (NestedLoopCount > 1)
+ SemaRef.Diag(NestedLoopCountExpr->getExprLoc(),
+ diag::note_omp_collapse_expr)
+ << NestedLoopCountExpr->getSourceRange();
+ return true;
+ }
+ assert(For->getBody());
+
+ OpenMPIterationSpaceChecker ISC(SemaRef, For->getForLoc());
+
+ // Check init.
+ auto Init = For->getInit();
+ if (ISC.CheckInit(Init)) {
+ return true;
+ }
+
+ bool HasErrors = false;
+
+ // Check loop variable's type.
+ auto Var = ISC.GetLoopVar();
+
+ // OpenMP [2.6, Canonical Loop Form]
+ // Var is one of the following:
+ // A variable of signed or unsigned integer type.
+ // For C++, a variable of a random access iterator type.
+ // For C, a variable of a pointer type.
+ auto VarType = Var->getType();
+ if (!VarType->isDependentType() && !VarType->isIntegerType() &&
+ !VarType->isPointerType() &&
+ !(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) {
+ SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_variable_type)
+ << SemaRef.getLangOpts().CPlusPlus;
+ HasErrors = true;
+ }
+
+ // OpenMP, 2.14.1.1 Data-sharing Attribute Rules for Variables Referenced in a
+ // Construct
+ // The loop iteration variable(s) in the associated for-loop(s) of a for or
+ // parallel for construct is (are) private.
+ // The loop iteration variable in the associated for-loop of a simd construct
+ // with just one associated for-loop is linear with a constant-linear-step
+ // that is the increment of the associated for-loop.
+ // Exclude loop var from the list of variables with implicitly defined data
+ // sharing attributes.
+ while (VarsWithImplicitDSA.count(Var) > 0)
+ VarsWithImplicitDSA.erase(Var);
+
+ // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced in
+ // a Construct, C/C++].
+ // The loop iteration variable in the associated for-loop of a simd construct
+ // with just one associated for-loop may be listed in a linear clause with a
+ // constant-linear-step that is the increment of the associated for-loop.
+ // The loop iteration variable(s) in the associated for-loop(s) of a for or
+ // parallel for construct may be listed in a private or lastprivate clause.
+ DSAStackTy::DSAVarData DVar = DSA.getTopDSA(Var, false);
+ auto PredeterminedCKind =
+ isOpenMPSimdDirective(DKind)
+ ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate)
+ : OMPC_private;
+ if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
+ DVar.CKind != PredeterminedCKind) ||
+ (isOpenMPWorksharingDirective(DKind) && DVar.CKind != OMPC_unknown &&
+ DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) &&
+ (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) {
+ SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa)
+ << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind)
+ << getOpenMPClauseName(PredeterminedCKind);
+ ReportOriginalDSA(SemaRef, &DSA, Var, DVar, true);
+ HasErrors = true;
+ } else {
+ // Make the loop iteration variable private (for worksharing constructs),
+ // linear (for simd directives with the only one associated loop) or
+ // lastprivate (for simd directives with several collapsed loops).
+ DSA.addDSA(Var, nullptr, PredeterminedCKind);
+ }
+
+ assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars");
+
+ // Check test-expr.
+ HasErrors |= ISC.CheckCond(For->getCond());
+
+ // Check incr-expr.
+ HasErrors |= ISC.CheckInc(For->getInc());
+
+ if (ISC.Dependent())
+ return HasErrors;
+
+ // FIXME: Build loop's iteration space representation.
+ return HasErrors;
+}
+
+/// \brief A helper routine to skip no-op (attributed, compound) stmts get the
+/// next nested for loop. If \a IgnoreCaptured is true, it skips captured stmt
+/// to get the first for loop.
+static Stmt *IgnoreContainerStmts(Stmt *S, bool IgnoreCaptured) {
+ if (IgnoreCaptured)
+ if (auto CapS = dyn_cast_or_null<CapturedStmt>(S))
+ S = CapS->getCapturedStmt();
+ // OpenMP [2.8.1, simd construct, Restrictions]
+ // All loops associated with the construct must be perfectly nested; that is,
+ // there must be no intervening code nor any OpenMP directive between any two
+ // loops.
+ while (true) {
+ if (auto AS = dyn_cast_or_null<AttributedStmt>(S))
+ S = AS->getSubStmt();
+ else if (auto CS = dyn_cast_or_null<CompoundStmt>(S)) {
+ if (CS->size() != 1)
+ break;
+ S = CS->body_back();
+ } else
+ break;
+ }
+ return S;
+}
+
+/// \brief Called on a for stmt to check itself and nested loops (if any).
+/// \return Returns 0 if one of the collapsed stmts is not canonical for loop,
+/// number of collapsed loops otherwise.
+static unsigned
+CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr,
+ Stmt *AStmt, Sema &SemaRef, DSAStackTy &DSA,
+ llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ unsigned NestedLoopCount = 1;
+ if (NestedLoopCountExpr) {
+ // Found 'collapse' clause - calculate collapse number.
+ llvm::APSInt Result;
+ if (NestedLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext()))
+ NestedLoopCount = Result.getLimitedValue();
+ }
+ // This is helper routine for loop directives (e.g., 'for', 'simd',
+ // 'for simd', etc.).
+ Stmt *CurStmt = IgnoreContainerStmts(AStmt, true);
+ for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) {
+ if (CheckOpenMPIterationSpace(DKind, CurStmt, SemaRef, DSA, Cnt,
+ NestedLoopCount, NestedLoopCountExpr,
+ VarsWithImplicitDSA))
+ return 0;
+ // Move on to the next nested for loop, or to the loop body.
+ CurStmt = IgnoreContainerStmts(cast<ForStmt>(CurStmt)->getBody(), false);
+ }
+
+ // FIXME: Build resulting iteration space for IR generation (collapsing
+ // iteration spaces when loop count > 1 ('collapse' clause)).
+ return NestedLoopCount;
+}
+
+static Expr *GetCollapseNumberExpr(ArrayRef<OMPClause *> Clauses) {
+ auto CollapseFilter = [](const OMPClause *C) -> bool {
+ return C->getClauseKind() == OMPC_collapse;
+ };
+ OMPExecutableDirective::filtered_clause_iterator<decltype(CollapseFilter)> I(
+ Clauses, CollapseFilter);
+ if (I)
+ return cast<OMPCollapseClause>(*I)->getNumForLoops();
+ return nullptr;
+}
+
+StmtResult Sema::ActOnOpenMPSimdDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ // In presence of clause 'collapse', it will define the nested loops number.
+ unsigned NestedLoopCount =
+ CheckOpenMPLoop(OMPD_simd, GetCollapseNumberExpr(Clauses), AStmt, *this,
+ *DSAStack, VarsWithImplicitDSA);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ getCurFunction()->setHasBranchProtectedScope();
+ return OMPSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount,
+ Clauses, AStmt);
+}
+
+StmtResult Sema::ActOnOpenMPForDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ // In presence of clause 'collapse', it will define the nested loops number.
+ unsigned NestedLoopCount =
+ CheckOpenMPLoop(OMPD_for, GetCollapseNumberExpr(Clauses), AStmt, *this,
+ *DSAStack, VarsWithImplicitDSA);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ getCurFunction()->setHasBranchProtectedScope();
+ return OMPForDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount,
+ Clauses, AStmt);
+}
+
+StmtResult Sema::ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ auto BaseStmt = AStmt;
+ while (CapturedStmt *CS = dyn_cast_or_null<CapturedStmt>(BaseStmt))
+ BaseStmt = CS->getCapturedStmt();
+ if (auto C = dyn_cast_or_null<CompoundStmt>(BaseStmt)) {
+ auto S = C->children();
+ if (!S)
+ return StmtError();
+ // All associated statements must be '#pragma omp section' except for
+ // the first one.
+ for (++S; S; ++S) {
+ auto SectionStmt = *S;
+ if (!SectionStmt || !isa<OMPSectionDirective>(SectionStmt)) {
+ if (SectionStmt)
+ Diag(SectionStmt->getLocStart(),
+ diag::err_omp_sections_substmt_not_section);
+ return StmtError();
+ }
+ }
+ } else {
+ Diag(AStmt->getLocStart(), diag::err_omp_sections_not_compound_stmt);
+ return StmtError();
+ }
+
+ getCurFunction()->setHasBranchProtectedScope();
+
+ return OMPSectionsDirective::Create(Context, StartLoc, EndLoc, Clauses,
+ AStmt);
+}
+
+StmtResult Sema::ActOnOpenMPSectionDirective(Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected");
+
+ getCurFunction()->setHasBranchProtectedScope();
+
+ return OMPSectionDirective::Create(Context, StartLoc, EndLoc, AStmt);
+}
+
+StmtResult Sema::ActOnOpenMPSingleDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected");
+
+ getCurFunction()->setHasBranchProtectedScope();
+
+ return OMPSingleDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt);
+}
+
+StmtResult Sema::ActOnOpenMPMasterDirective(Stmt *AStmt,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected");
+
+ getCurFunction()->setHasBranchProtectedScope();
+
+ return OMPMasterDirective::Create(Context, StartLoc, EndLoc, AStmt);
+}
+
+StmtResult
+Sema::ActOnOpenMPCriticalDirective(const DeclarationNameInfo &DirName,
+ Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected");
+
+ getCurFunction()->setHasBranchProtectedScope();
+
+ return OMPCriticalDirective::Create(Context, DirName, StartLoc, EndLoc,
+ AStmt);
+}
+
+StmtResult Sema::ActOnOpenMPParallelForDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ CapturedStmt *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+
+ // In presence of clause 'collapse', it will define the nested loops number.
+ unsigned NestedLoopCount =
+ CheckOpenMPLoop(OMPD_parallel_for, GetCollapseNumberExpr(Clauses), AStmt,
+ *this, *DSAStack, VarsWithImplicitDSA);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ getCurFunction()->setHasBranchProtectedScope();
+ return OMPParallelForDirective::Create(Context, StartLoc, EndLoc,
+ NestedLoopCount, Clauses, AStmt);
+}
+
+StmtResult
+Sema::ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ auto BaseStmt = AStmt;
+ while (CapturedStmt *CS = dyn_cast_or_null<CapturedStmt>(BaseStmt))
+ BaseStmt = CS->getCapturedStmt();
+ if (auto C = dyn_cast_or_null<CompoundStmt>(BaseStmt)) {
+ auto S = C->children();
+ if (!S)
+ return StmtError();
+ // All associated statements must be '#pragma omp section' except for
+ // the first one.
+ for (++S; S; ++S) {
+ auto SectionStmt = *S;
+ if (!SectionStmt || !isa<OMPSectionDirective>(SectionStmt)) {
+ if (SectionStmt)
+ Diag(SectionStmt->getLocStart(),
+ diag::err_omp_parallel_sections_substmt_not_section);
+ return StmtError();
+ }
+ }
+ } else {
+ Diag(AStmt->getLocStart(),
+ diag::err_omp_parallel_sections_not_compound_stmt);
+ return StmtError();
+ }
+
+ getCurFunction()->setHasBranchProtectedScope();
+
+ return OMPParallelSectionsDirective::Create(Context, StartLoc, EndLoc,
+ Clauses, AStmt);
+}
+
+StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ assert(AStmt && isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ CapturedStmt *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+
+ getCurFunction()->setHasBranchProtectedScope();
+
+ return OMPTaskDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt);
+}
+
+StmtResult Sema::ActOnOpenMPTaskyieldDirective(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return OMPTaskyieldDirective::Create(Context, StartLoc, EndLoc);
+}
+
+StmtResult Sema::ActOnOpenMPBarrierDirective(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return OMPBarrierDirective::Create(Context, StartLoc, EndLoc);
+}
+
+StmtResult Sema::ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return OMPTaskwaitDirective::Create(Context, StartLoc, EndLoc);
+}
+
+StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ assert(Clauses.size() <= 1 && "Extra clauses in flush directive");
+ return OMPFlushDirective::Create(Context, StartLoc, EndLoc, Clauses);
+}
+
+OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ OMPClause *Res = nullptr;
+ switch (Kind) {
+ case OMPC_if:
+ Res = ActOnOpenMPIfClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_final:
+ Res = ActOnOpenMPFinalClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_num_threads:
+ Res = ActOnOpenMPNumThreadsClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_safelen:
+ Res = ActOnOpenMPSafelenClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_collapse:
+ Res = ActOnOpenMPCollapseClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_default:
+ case OMPC_proc_bind:
+ case OMPC_schedule:
+ case OMPC_private:
+ case OMPC_firstprivate:
+ case OMPC_lastprivate:
+ case OMPC_shared:
+ case OMPC_reduction:
+ case OMPC_linear:
+ case OMPC_aligned:
+ case OMPC_copyin:
+ case OMPC_copyprivate:
+ case OMPC_ordered:
+ case OMPC_nowait:
+ case OMPC_untied:
+ case OMPC_mergeable:
+ case OMPC_threadprivate:
+ case OMPC_flush:
+ case OMPC_unknown:
+ llvm_unreachable("Clause is not allowed.");
+ }
+ return Res;
+}
+
+OMPClause *Sema::ActOnOpenMPIfClause(Expr *Condition, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ Expr *ValExpr = Condition;
+ if (!Condition->isValueDependent() && !Condition->isTypeDependent() &&
+ !Condition->isInstantiationDependent() &&
+ !Condition->containsUnexpandedParameterPack()) {
+ ExprResult Val = ActOnBooleanCondition(DSAStack->getCurScope(),
+ Condition->getExprLoc(), Condition);
+ if (Val.isInvalid())
+ return nullptr;
+
+ ValExpr = Val.get();
+ }
+
+ return new (Context) OMPIfClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ Expr *ValExpr = Condition;
+ if (!Condition->isValueDependent() && !Condition->isTypeDependent() &&
+ !Condition->isInstantiationDependent() &&
+ !Condition->containsUnexpandedParameterPack()) {
+ ExprResult Val = ActOnBooleanCondition(DSAStack->getCurScope(),
+ Condition->getExprLoc(), Condition);
+ if (Val.isInvalid())
+ return nullptr;
+
+ ValExpr = Val.get();
+ }
+
+ return new (Context) OMPFinalClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+}
+
+ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc,
+ Expr *Op) {
+ if (!Op)
+ return ExprError();
+
+ class IntConvertDiagnoser : public ICEConvertDiagnoser {
+ public:
+ IntConvertDiagnoser()
+ : ICEConvertDiagnoser(/*AllowScopedEnumerations*/ false, false, true) {}
+ SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
+ QualType T) override {
+ return S.Diag(Loc, diag::err_omp_not_integral) << T;
+ }
+ SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc,
+ QualType T) override {
+ return S.Diag(Loc, diag::err_omp_incomplete_type) << T;
+ }
+ SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc,
+ QualType T,
+ QualType ConvTy) override {
+ return S.Diag(Loc, diag::err_omp_explicit_conversion) << T << ConvTy;
+ }
+ SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv,
+ QualType ConvTy) override {
+ return S.Diag(Conv->getLocation(), diag::note_omp_conversion_here)
+ << ConvTy->isEnumeralType() << ConvTy;
+ }
+ SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
+ QualType T) override {
+ return S.Diag(Loc, diag::err_omp_ambiguous_conversion) << T;
+ }
+ SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv,
+ QualType ConvTy) override {
+ return S.Diag(Conv->getLocation(), diag::note_omp_conversion_here)
+ << ConvTy->isEnumeralType() << ConvTy;
+ }
+ SemaDiagnosticBuilder diagnoseConversion(Sema &, SourceLocation, QualType,
+ QualType) override {
+ llvm_unreachable("conversion functions are permitted");
+ }
+ } ConvertDiagnoser;
+ return PerformContextualImplicitConversion(Loc, Op, ConvertDiagnoser);
+}
+
+OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ Expr *ValExpr = NumThreads;
+ if (!NumThreads->isValueDependent() && !NumThreads->isTypeDependent() &&
+ !NumThreads->isInstantiationDependent() &&
+ !NumThreads->containsUnexpandedParameterPack()) {
+ SourceLocation NumThreadsLoc = NumThreads->getLocStart();
+ ExprResult Val =
+ PerformOpenMPImplicitIntegerConversion(NumThreadsLoc, NumThreads);
+ if (Val.isInvalid())
+ return nullptr;
+
+ ValExpr = Val.get();
+
+ // OpenMP [2.5, Restrictions]
+ // The num_threads expression must evaluate to a positive integer value.
+ llvm::APSInt Result;
+ if (ValExpr->isIntegerConstantExpr(Result, Context) && Result.isSigned() &&
+ !Result.isStrictlyPositive()) {
+ Diag(NumThreadsLoc, diag::err_omp_negative_expression_in_clause)
+ << "num_threads" << NumThreads->getSourceRange();
+ return nullptr;
+ }
+ }
+
+ return new (Context)
+ OMPNumThreadsClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+}
+
+ExprResult Sema::VerifyPositiveIntegerConstantInClause(Expr *E,
+ OpenMPClauseKind CKind) {
+ if (!E)
+ return ExprError();
+ if (E->isValueDependent() || E->isTypeDependent() ||
+ E->isInstantiationDependent() || E->containsUnexpandedParameterPack())
+ return E;
+ llvm::APSInt Result;
+ ExprResult ICE = VerifyIntegerConstantExpression(E, &Result);
+ if (ICE.isInvalid())
+ return ExprError();
+ if (!Result.isStrictlyPositive()) {
+ Diag(E->getExprLoc(), diag::err_omp_negative_expression_in_clause)
+ << getOpenMPClauseName(CKind) << E->getSourceRange();
+ return ExprError();
+ }
+ return ICE;
+}
+
+OMPClause *Sema::ActOnOpenMPSafelenClause(Expr *Len, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ // OpenMP [2.8.1, simd construct, Description]
+ // The parameter of the safelen clause must be a constant
+ // positive integer expression.
+ ExprResult Safelen = VerifyPositiveIntegerConstantInClause(Len, OMPC_safelen);
+ if (Safelen.isInvalid())
+ return nullptr;
+ return new (Context)
+ OMPSafelenClause(Safelen.get(), StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPCollapseClause(Expr *NumForLoops,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ // OpenMP [2.7.1, loop construct, Description]
+ // OpenMP [2.8.1, simd construct, Description]
+ // OpenMP [2.9.6, distribute construct, Description]
+ // The parameter of the collapse clause must be a constant
+ // positive integer expression.
+ ExprResult NumForLoopsResult =
+ VerifyPositiveIntegerConstantInClause(NumForLoops, OMPC_collapse);
+ if (NumForLoopsResult.isInvalid())
+ return nullptr;
+ return new (Context)
+ OMPCollapseClause(NumForLoopsResult.get(), StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPSimpleClause(
+ OpenMPClauseKind Kind, unsigned Argument, SourceLocation ArgumentLoc,
+ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) {
+ OMPClause *Res = nullptr;
switch (Kind) {
case OMPC_default:
Res =
- ActOnOpenMPDefaultClause(static_cast<OpenMPDefaultClauseKind>(Argument),
- ArgumentLoc, StartLoc, LParenLoc, EndLoc);
+ ActOnOpenMPDefaultClause(static_cast<OpenMPDefaultClauseKind>(Argument),
+ ArgumentLoc, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_proc_bind:
+ Res = ActOnOpenMPProcBindClause(
+ static_cast<OpenMPProcBindClauseKind>(Argument), ArgumentLoc, StartLoc,
+ LParenLoc, EndLoc);
+ break;
+ case OMPC_if:
+ case OMPC_final:
+ case OMPC_num_threads:
+ case OMPC_safelen:
+ case OMPC_collapse:
+ case OMPC_schedule:
case OMPC_private:
case OMPC_firstprivate:
+ case OMPC_lastprivate:
case OMPC_shared:
+ case OMPC_reduction:
+ case OMPC_linear:
+ case OMPC_aligned:
+ case OMPC_copyin:
+ case OMPC_copyprivate:
+ case OMPC_ordered:
+ case OMPC_nowait:
+ case OMPC_untied:
+ case OMPC_mergeable:
case OMPC_threadprivate:
+ case OMPC_flush:
case OMPC_unknown:
- case NUM_OPENMP_CLAUSES:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -733,17 +2519,18 @@ OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind,
SourceLocation EndLoc) {
if (Kind == OMPC_DEFAULT_unknown) {
std::string Values;
- std::string Sep(NUM_OPENMP_DEFAULT_KINDS > 1 ? ", " : "");
- for (unsigned i = OMPC_DEFAULT_unknown + 1;
- i < NUM_OPENMP_DEFAULT_KINDS; ++i) {
+ static_assert(OMPC_DEFAULT_unknown > 0,
+ "OMPC_DEFAULT_unknown not greater than 0");
+ std::string Sep(", ");
+ for (unsigned i = 0; i < OMPC_DEFAULT_unknown; ++i) {
Values += "'";
Values += getOpenMPSimpleClauseTypeName(OMPC_default, i);
Values += "'";
switch (i) {
- case NUM_OPENMP_DEFAULT_KINDS - 2:
+ case OMPC_DEFAULT_unknown - 2:
Values += " or ";
break;
- case NUM_OPENMP_DEFAULT_KINDS - 1:
+ case OMPC_DEFAULT_unknown - 1:
break;
default:
Values += Sep;
@@ -751,29 +2538,219 @@ OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind,
}
}
Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
- << Values << getOpenMPClauseName(OMPC_default);
- return 0;
+ << Values << getOpenMPClauseName(OMPC_default);
+ return nullptr;
}
switch (Kind) {
case OMPC_DEFAULT_none:
- DSAStack->setDefaultDSANone();
+ DSAStack->setDefaultDSANone(KindKwLoc);
break;
case OMPC_DEFAULT_shared:
- DSAStack->setDefaultDSAShared();
+ DSAStack->setDefaultDSAShared(KindKwLoc);
break;
- default:
+ case OMPC_DEFAULT_unknown:
+ llvm_unreachable("Clause kind is not allowed.");
break;
}
- return new (Context) OMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc,
- EndLoc);
+ return new (Context)
+ OMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
}
-OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
- ArrayRef<Expr *> VarList,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
+OMPClause *Sema::ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind,
+ SourceLocation KindKwLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ if (Kind == OMPC_PROC_BIND_unknown) {
+ std::string Values;
+ std::string Sep(", ");
+ for (unsigned i = 0; i < OMPC_PROC_BIND_unknown; ++i) {
+ Values += "'";
+ Values += getOpenMPSimpleClauseTypeName(OMPC_proc_bind, i);
+ Values += "'";
+ switch (i) {
+ case OMPC_PROC_BIND_unknown - 2:
+ Values += " or ";
+ break;
+ case OMPC_PROC_BIND_unknown - 1:
+ break;
+ default:
+ Values += Sep;
+ break;
+ }
+ }
+ Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
+ << Values << getOpenMPClauseName(OMPC_proc_bind);
+ return nullptr;
+ }
+ return new (Context)
+ OMPProcBindClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
+ OpenMPClauseKind Kind, unsigned Argument, Expr *Expr,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ArgumentLoc, SourceLocation CommaLoc,
+ SourceLocation EndLoc) {
+ OMPClause *Res = nullptr;
+ switch (Kind) {
+ case OMPC_schedule:
+ Res = ActOnOpenMPScheduleClause(
+ static_cast<OpenMPScheduleClauseKind>(Argument), Expr, StartLoc,
+ LParenLoc, ArgumentLoc, CommaLoc, EndLoc);
+ break;
+ case OMPC_if:
+ case OMPC_final:
+ case OMPC_num_threads:
+ case OMPC_safelen:
+ case OMPC_collapse:
+ case OMPC_default:
+ case OMPC_proc_bind:
+ case OMPC_private:
+ case OMPC_firstprivate:
+ case OMPC_lastprivate:
+ case OMPC_shared:
+ case OMPC_reduction:
+ case OMPC_linear:
+ case OMPC_aligned:
+ case OMPC_copyin:
+ case OMPC_copyprivate:
+ case OMPC_ordered:
+ case OMPC_nowait:
+ case OMPC_untied:
+ case OMPC_mergeable:
+ case OMPC_threadprivate:
+ case OMPC_flush:
+ case OMPC_unknown:
+ llvm_unreachable("Clause is not allowed.");
+ }
+ return Res;
+}
+
+OMPClause *Sema::ActOnOpenMPScheduleClause(
+ OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc,
+ SourceLocation EndLoc) {
+ if (Kind == OMPC_SCHEDULE_unknown) {
+ std::string Values;
+ std::string Sep(", ");
+ for (unsigned i = 0; i < OMPC_SCHEDULE_unknown; ++i) {
+ Values += "'";
+ Values += getOpenMPSimpleClauseTypeName(OMPC_schedule, i);
+ Values += "'";
+ switch (i) {
+ case OMPC_SCHEDULE_unknown - 2:
+ Values += " or ";
+ break;
+ case OMPC_SCHEDULE_unknown - 1:
+ break;
+ default:
+ Values += Sep;
+ break;
+ }
+ }
+ Diag(KindLoc, diag::err_omp_unexpected_clause_value)
+ << Values << getOpenMPClauseName(OMPC_schedule);
+ return nullptr;
+ }
+ Expr *ValExpr = ChunkSize;
+ if (ChunkSize) {
+ if (!ChunkSize->isValueDependent() && !ChunkSize->isTypeDependent() &&
+ !ChunkSize->isInstantiationDependent() &&
+ !ChunkSize->containsUnexpandedParameterPack()) {
+ SourceLocation ChunkSizeLoc = ChunkSize->getLocStart();
+ ExprResult Val =
+ PerformOpenMPImplicitIntegerConversion(ChunkSizeLoc, ChunkSize);
+ if (Val.isInvalid())
+ return nullptr;
+
+ ValExpr = Val.get();
+
+ // OpenMP [2.7.1, Restrictions]
+ // chunk_size must be a loop invariant integer expression with a positive
+ // value.
+ llvm::APSInt Result;
+ if (ValExpr->isIntegerConstantExpr(Result, Context) &&
+ Result.isSigned() && !Result.isStrictlyPositive()) {
+ Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause)
+ << "schedule" << ChunkSize->getSourceRange();
+ return nullptr;
+ }
+ }
+ }
+
+ return new (Context) OMPScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc,
+ EndLoc, Kind, ValExpr);
+}
+
+OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ OMPClause *Res = nullptr;
+ switch (Kind) {
+ case OMPC_ordered:
+ Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc);
+ break;
+ case OMPC_nowait:
+ Res = ActOnOpenMPNowaitClause(StartLoc, EndLoc);
+ break;
+ case OMPC_untied:
+ Res = ActOnOpenMPUntiedClause(StartLoc, EndLoc);
+ break;
+ case OMPC_mergeable:
+ Res = ActOnOpenMPMergeableClause(StartLoc, EndLoc);
+ break;
+ case OMPC_if:
+ case OMPC_final:
+ case OMPC_num_threads:
+ case OMPC_safelen:
+ case OMPC_collapse:
+ case OMPC_schedule:
+ case OMPC_private:
+ case OMPC_firstprivate:
+ case OMPC_lastprivate:
+ case OMPC_shared:
+ case OMPC_reduction:
+ case OMPC_linear:
+ case OMPC_aligned:
+ case OMPC_copyin:
+ case OMPC_copyprivate:
+ case OMPC_default:
+ case OMPC_proc_bind:
+ case OMPC_threadprivate:
+ case OMPC_flush:
+ case OMPC_unknown:
+ llvm_unreachable("Clause is not allowed.");
+ }
+ return Res;
+}
+
+OMPClause *Sema::ActOnOpenMPOrderedClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
- OMPClause *Res = 0;
+ return new (Context) OMPOrderedClause(StartLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPNowaitClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPNowaitClause(StartLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPUntiedClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPUntiedClause(StartLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPMergeableClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPMergeableClause(StartLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPVarListClause(
+ OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr,
+ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc,
+ SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec,
+ const DeclarationNameInfo &ReductionId) {
+ OMPClause *Res = nullptr;
switch (Kind) {
case OMPC_private:
Res = ActOnOpenMPPrivateClause(VarList, StartLoc, LParenLoc, EndLoc);
@@ -781,13 +2758,47 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
case OMPC_firstprivate:
Res = ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_lastprivate:
+ Res = ActOnOpenMPLastprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
+ break;
case OMPC_shared:
Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_reduction:
+ Res = ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
+ EndLoc, ReductionIdScopeSpec, ReductionId);
+ break;
+ case OMPC_linear:
+ Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc,
+ ColonLoc, EndLoc);
+ break;
+ case OMPC_aligned:
+ Res = ActOnOpenMPAlignedClause(VarList, TailExpr, StartLoc, LParenLoc,
+ ColonLoc, EndLoc);
+ break;
+ case OMPC_copyin:
+ Res = ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_copyprivate:
+ Res = ActOnOpenMPCopyprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_flush:
+ Res = ActOnOpenMPFlushClause(VarList, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_if:
+ case OMPC_final:
+ case OMPC_num_threads:
+ case OMPC_safelen:
+ case OMPC_collapse:
case OMPC_default:
+ case OMPC_proc_bind:
+ case OMPC_schedule:
+ case OMPC_ordered:
+ case OMPC_nowait:
+ case OMPC_untied:
+ case OMPC_mergeable:
case OMPC_threadprivate:
case OMPC_unknown:
- case NUM_OPENMP_CLAUSES:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -798,25 +2809,23 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
- for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end();
- I != E; ++I) {
- assert(*I && "NULL expr in OpenMP private clause.");
- if (isa<DependentScopeDeclRefExpr>(*I)) {
+ for (auto &RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP private clause.");
+ if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
- Vars.push_back(*I);
+ Vars.push_back(RefExpr);
continue;
}
- SourceLocation ELoc = (*I)->getExprLoc();
+ SourceLocation ELoc = RefExpr->getExprLoc();
// OpenMP [2.1, C/C++]
// A list item is a variable name.
// OpenMP [2.9.3.3, Restrictions, p.1]
// A variable that is part of another variable (as an array or
// structure element) cannot appear in a private clause.
- DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(*I);
+ DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr);
if (!DE || !isa<VarDecl>(DE->getDecl())) {
- Diag(ELoc, diag::err_omp_expected_var_name)
- << (*I)->getSourceRange();
+ Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
continue;
}
Decl *D = DE->getDecl();
@@ -838,39 +2847,44 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
}
if (Type->isReferenceType()) {
Diag(ELoc, diag::err_omp_clause_ref_type_arg)
- << getOpenMPClauseName(OMPC_private) << Type;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
- diag::note_defined_here) << VD;
+ << getOpenMPClauseName(OMPC_private) << Type;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
continue;
}
// OpenMP [2.9.3.3, Restrictions, C/C++, p.1]
// A variable of class type (or array thereof) that appears in a private
- // clause requires an accesible, unambiguous default constructor for the
+ // clause requires an accessible, unambiguous default constructor for the
// class type.
while (Type.getNonReferenceType()->isArrayType()) {
- Type = cast<ArrayType>(
- Type.getNonReferenceType().getTypePtr())->getElementType();
+ Type = cast<ArrayType>(Type.getNonReferenceType().getTypePtr())
+ ->getElementType();
}
- CXXRecordDecl *RD = getLangOpts().CPlusPlus ?
- Type.getNonReferenceType()->getAsCXXRecordDecl() : 0;
+ CXXRecordDecl *RD = getLangOpts().CPlusPlus
+ ? Type.getNonReferenceType()->getAsCXXRecordDecl()
+ : nullptr;
+ // FIXME This code must be replaced by actual constructing/destructing of
+ // the private variable.
if (RD) {
CXXConstructorDecl *CD = LookupDefaultConstructor(RD);
PartialDiagnostic PD =
- PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
+ PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
if (!CD ||
CheckConstructorAccess(ELoc, CD,
InitializedEntity::InitializeTemporary(Type),
CD->getAccess(), PD) == AR_inaccessible ||
CD->isDeleted()) {
Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_private) << 0;
+ << getOpenMPClauseName(OMPC_private) << 0;
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
VarDecl::DeclarationOnly;
- Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
- diag::note_defined_here) << VD;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
Diag(RD->getLocation(), diag::note_previous_decl) << RD;
continue;
}
@@ -882,11 +2896,12 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
DD->isDeleted()) {
Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_private) << 4;
+ << getOpenMPClauseName(OMPC_private) << 4;
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
VarDecl::DeclarationOnly;
- Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
- diag::note_defined_here) << VD;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
Diag(RD->getLocation(), diag::note_previous_decl) << RD;
continue;
}
@@ -902,18 +2917,11 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
// listed below. For these exceptions only, listing a predetermined
// variable in a data-sharing attribute clause is allowed and overrides
// the variable's predetermined data-sharing attributes.
- DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private) {
- Diag(ELoc, diag::err_omp_wrong_dsa)
- << getOpenMPClauseName(DVar.CKind)
- << getOpenMPClauseName(OMPC_private);
- if (DVar.RefExpr) {
- Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
- << getOpenMPClauseName(DVar.CKind);
- } else {
- Diag(VD->getLocation(), diag::note_omp_predetermined_dsa)
- << getOpenMPClauseName(DVar.CKind);
- }
+ Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_private);
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
continue;
}
@@ -921,7 +2929,8 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
Vars.push_back(DE);
}
- if (Vars.empty()) return 0;
+ if (Vars.empty())
+ return nullptr;
return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
}
@@ -931,25 +2940,28 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
- for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end();
- I != E; ++I) {
- assert(*I && "NULL expr in OpenMP firstprivate clause.");
- if (isa<DependentScopeDeclRefExpr>(*I)) {
+ bool IsImplicitClause =
+ StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid();
+ auto ImplicitClauseLoc = DSAStack->getConstructLoc();
+
+ for (auto &RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP firstprivate clause.");
+ if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
- Vars.push_back(*I);
+ Vars.push_back(RefExpr);
continue;
}
- SourceLocation ELoc = (*I)->getExprLoc();
+ SourceLocation ELoc = IsImplicitClause ? ImplicitClauseLoc
+ : RefExpr->getExprLoc();
// OpenMP [2.1, C/C++]
// A list item is a variable name.
// OpenMP [2.9.3.3, Restrictions, p.1]
// A variable that is part of another variable (as an array or
// structure element) cannot appear in a private clause.
- DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(*I);
+ DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr);
if (!DE || !isa<VarDecl>(DE->getDecl())) {
- Diag(ELoc, diag::err_omp_expected_var_name)
- << (*I)->getSourceRange();
+ Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
continue;
}
Decl *D = DE->getDecl();
@@ -970,37 +2982,56 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
continue;
}
if (Type->isReferenceType()) {
- Diag(ELoc, diag::err_omp_clause_ref_type_arg)
- << getOpenMPClauseName(OMPC_firstprivate) << Type;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
- diag::note_defined_here) << VD;
+ if (IsImplicitClause) {
+ Diag(ImplicitClauseLoc,
+ diag::err_omp_task_predetermined_firstprivate_ref_type_arg)
+ << Type;
+ Diag(RefExpr->getExprLoc(), diag::note_used_here);
+ } else {
+ Diag(ELoc, diag::err_omp_clause_ref_type_arg)
+ << getOpenMPClauseName(OMPC_firstprivate) << Type;
+ }
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
continue;
}
// OpenMP [2.9.3.4, Restrictions, C/C++, p.1]
// A variable of class type (or array thereof) that appears in a private
- // clause requires an accesible, unambiguous copy constructor for the
+ // clause requires an accessible, unambiguous copy constructor for the
// class type.
Type = Context.getBaseElementType(Type);
- CXXRecordDecl *RD = getLangOpts().CPlusPlus ?
- Type.getNonReferenceType()->getAsCXXRecordDecl() : 0;
+ CXXRecordDecl *RD = getLangOpts().CPlusPlus
+ ? Type.getNonReferenceType()->getAsCXXRecordDecl()
+ : nullptr;
+ // FIXME This code must be replaced by actual constructing/destructing of
+ // the firstprivate variable.
if (RD) {
CXXConstructorDecl *CD = LookupCopyingConstructor(RD, 0);
PartialDiagnostic PD =
- PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
+ PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
if (!CD ||
CheckConstructorAccess(ELoc, CD,
InitializedEntity::InitializeTemporary(Type),
CD->getAccess(), PD) == AR_inaccessible ||
CD->isDeleted()) {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_firstprivate) << 1;
+ if (IsImplicitClause) {
+ Diag(ImplicitClauseLoc,
+ diag::err_omp_task_predetermined_firstprivate_required_method)
+ << 0;
+ Diag(RefExpr->getExprLoc(), diag::note_used_here);
+ } else {
+ Diag(ELoc, diag::err_omp_required_method)
+ << getOpenMPClauseName(OMPC_firstprivate) << 1;
+ }
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
VarDecl::DeclarationOnly;
- Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
- diag::note_defined_here) << VD;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
Diag(RD->getLocation(), diag::note_previous_decl) << RD;
continue;
}
@@ -1011,12 +3042,20 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
if (DD) {
if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
DD->isDeleted()) {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_firstprivate) << 4;
+ if (IsImplicitClause) {
+ Diag(ImplicitClauseLoc,
+ diag::err_omp_task_predetermined_firstprivate_required_method)
+ << 1;
+ Diag(RefExpr->getExprLoc(), diag::note_used_here);
+ } else {
+ Diag(ELoc, diag::err_omp_required_method)
+ << getOpenMPClauseName(OMPC_firstprivate) << 4;
+ }
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
VarDecl::DeclarationOnly;
- Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
- diag::note_defined_here) << VD;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
Diag(RD->getLocation(), diag::note_previous_decl) << RD;
continue;
}
@@ -1025,10 +3064,9 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
}
}
- // If StartLoc and EndLoc are invalid - this is an implicit firstprivate
- // variable and it was checked already.
- if (StartLoc.isValid() && EndLoc.isValid()) {
- DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
+ // If an implicit firstprivate variable found it was checked already.
+ if (!IsImplicitClause) {
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
Type = Type.getNonReferenceType().getCanonicalType();
bool IsConstant = Type.isConstant(Context);
Type = Context.getBaseElementType(Type);
@@ -1036,14 +3074,12 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
// A list item that specifies a given variable may not appear in more
// than one clause on the same directive, except that a variable may be
// specified in both firstprivate and lastprivate clauses.
- // TODO: add processing for lastprivate.
if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate &&
- DVar.RefExpr) {
+ DVar.CKind != OMPC_lastprivate && DVar.RefExpr) {
Diag(ELoc, diag::err_omp_wrong_dsa)
- << getOpenMPClauseName(DVar.CKind)
- << getOpenMPClauseName(OMPC_firstprivate);
- Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
- << getOpenMPClauseName(DVar.CKind);
+ << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_firstprivate);
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
continue;
}
@@ -1061,18 +3097,31 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
if (!(IsConstant || VD->isStaticDataMember()) && !DVar.RefExpr &&
DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared) {
Diag(ELoc, diag::err_omp_wrong_dsa)
- << getOpenMPClauseName(DVar.CKind)
- << getOpenMPClauseName(OMPC_firstprivate);
- Diag(VD->getLocation(), diag::note_omp_predetermined_dsa)
- << getOpenMPClauseName(DVar.CKind);
+ << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_firstprivate);
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
continue;
}
+ OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
// OpenMP [2.9.3.4, Restrictions, p.2]
// A list item that is private within a parallel region must not appear
// in a firstprivate clause on a worksharing construct if any of the
// worksharing regions arising from the worksharing construct ever bind
// to any of the parallel regions arising from the parallel construct.
+ if (isOpenMPWorksharingDirective(CurrDir) &&
+ !isOpenMPParallelDirective(CurrDir)) {
+ DVar = DSAStack->getImplicitDSA(VD, true);
+ if (DVar.CKind != OMPC_shared &&
+ (isOpenMPParallelDirective(DVar.DKind) ||
+ DVar.DKind == OMPD_unknown)) {
+ Diag(ELoc, diag::err_omp_required_access)
+ << getOpenMPClauseName(OMPC_firstprivate)
+ << getOpenMPClauseName(OMPC_shared);
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ continue;
+ }
+ }
// OpenMP [2.9.3.4, Restrictions, p.3]
// A list item that appears in a reduction clause of a parallel construct
// must not appear in a firstprivate clause on a worksharing or task
@@ -1084,43 +3133,214 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
// construct must not appear in a firstprivate clause in a task construct
// encountered during execution of any of the worksharing regions arising
// from the worksharing construct.
- // TODO:
+ if (CurrDir == OMPD_task) {
+ DVar =
+ DSAStack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction),
+ [](OpenMPDirectiveKind K) -> bool {
+ return isOpenMPParallelDirective(K) ||
+ isOpenMPWorksharingDirective(K);
+ },
+ false);
+ if (DVar.CKind == OMPC_reduction &&
+ (isOpenMPParallelDirective(DVar.DKind) ||
+ isOpenMPWorksharingDirective(DVar.DKind))) {
+ Diag(ELoc, diag::err_omp_parallel_reduction_in_task_firstprivate)
+ << getOpenMPDirectiveName(DVar.DKind);
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ continue;
+ }
+ }
}
DSAStack->addDSA(VD, DE, OMPC_firstprivate);
Vars.push_back(DE);
}
- if (Vars.empty()) return 0;
+ if (Vars.empty())
+ return nullptr;
return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
Vars);
}
+OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (auto &RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP lastprivate clause.");
+ if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ continue;
+ }
+
+ SourceLocation ELoc = RefExpr->getExprLoc();
+ // OpenMP [2.1, C/C++]
+ // A list item is a variable name.
+ // OpenMP [2.14.3.5, Restrictions, p.1]
+ // A variable that is part of another variable (as an array or structure
+ // element) cannot appear in a lastprivate clause.
+ DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr);
+ if (!DE || !isa<VarDecl>(DE->getDecl())) {
+ Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
+ continue;
+ }
+ Decl *D = DE->getDecl();
+ VarDecl *VD = cast<VarDecl>(D);
+
+ QualType Type = VD->getType();
+ if (Type->isDependentType() || Type->isInstantiationDependentType()) {
+ // It will be analyzed later.
+ Vars.push_back(DE);
+ continue;
+ }
+
+ // OpenMP [2.14.3.5, Restrictions, C/C++, p.2]
+ // A variable that appears in a lastprivate clause must not have an
+ // incomplete type or a reference type.
+ if (RequireCompleteType(ELoc, Type,
+ diag::err_omp_lastprivate_incomplete_type)) {
+ continue;
+ }
+ if (Type->isReferenceType()) {
+ Diag(ELoc, diag::err_omp_clause_ref_type_arg)
+ << getOpenMPClauseName(OMPC_lastprivate) << Type;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+
+ // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
+ // in a Construct]
+ // Variables with the predetermined data-sharing attributes may not be
+ // listed in data-sharing attributes clauses, except for the cases
+ // listed below.
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
+ if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_lastprivate &&
+ DVar.CKind != OMPC_firstprivate &&
+ (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) {
+ Diag(ELoc, diag::err_omp_wrong_dsa)
+ << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_lastprivate);
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ continue;
+ }
+
+ OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
+ // OpenMP [2.14.3.5, Restrictions, p.2]
+ // A list item that is private within a parallel region, or that appears in
+ // the reduction clause of a parallel construct, must not appear in a
+ // lastprivate clause on a worksharing construct if any of the corresponding
+ // worksharing regions ever binds to any of the corresponding parallel
+ // regions.
+ if (isOpenMPWorksharingDirective(CurrDir) &&
+ !isOpenMPParallelDirective(CurrDir)) {
+ DVar = DSAStack->getImplicitDSA(VD, true);
+ if (DVar.CKind != OMPC_shared) {
+ Diag(ELoc, diag::err_omp_required_access)
+ << getOpenMPClauseName(OMPC_lastprivate)
+ << getOpenMPClauseName(OMPC_shared);
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ continue;
+ }
+ }
+ // OpenMP [2.14.3.5, Restrictions, C++, p.1,2]
+ // A variable of class type (or array thereof) that appears in a
+ // lastprivate clause requires an accessible, unambiguous default
+ // constructor for the class type, unless the list item is also specified
+ // in a firstprivate clause.
+ // A variable of class type (or array thereof) that appears in a
+ // lastprivate clause requires an accessible, unambiguous copy assignment
+ // operator for the class type.
+ while (Type.getNonReferenceType()->isArrayType())
+ Type = cast<ArrayType>(Type.getNonReferenceType().getTypePtr())
+ ->getElementType();
+ CXXRecordDecl *RD = getLangOpts().CPlusPlus
+ ? Type.getNonReferenceType()->getAsCXXRecordDecl()
+ : nullptr;
+ // FIXME This code must be replaced by actual copying and destructing of the
+ // lastprivate variable.
+ if (RD) {
+ CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0);
+ DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess());
+ if (MD) {
+ if (CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible ||
+ MD->isDeleted()) {
+ Diag(ELoc, diag::err_omp_required_method)
+ << getOpenMPClauseName(OMPC_lastprivate) << 2;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ Diag(RD->getLocation(), diag::note_previous_decl) << RD;
+ continue;
+ }
+ MarkFunctionReferenced(ELoc, MD);
+ DiagnoseUseOfDecl(MD, ELoc);
+ }
+
+ CXXDestructorDecl *DD = RD->getDestructor();
+ if (DD) {
+ PartialDiagnostic PD =
+ PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
+ if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
+ DD->isDeleted()) {
+ Diag(ELoc, diag::err_omp_required_method)
+ << getOpenMPClauseName(OMPC_lastprivate) << 4;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ Diag(RD->getLocation(), diag::note_previous_decl) << RD;
+ continue;
+ }
+ MarkFunctionReferenced(ELoc, DD);
+ DiagnoseUseOfDecl(DD, ELoc);
+ }
+ }
+
+ if (DVar.CKind != OMPC_firstprivate)
+ DSAStack->addDSA(VD, DE, OMPC_lastprivate);
+ Vars.push_back(DE);
+ }
+
+ if (Vars.empty())
+ return nullptr;
+
+ return OMPLastprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
+ Vars);
+}
+
OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
- for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end();
- I != E; ++I) {
- assert(*I && "NULL expr in OpenMP shared clause.");
- if (isa<DependentScopeDeclRefExpr>(*I)) {
+ for (auto &RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP shared clause.");
+ if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
- Vars.push_back(*I);
+ Vars.push_back(RefExpr);
continue;
}
- SourceLocation ELoc = (*I)->getExprLoc();
+ SourceLocation ELoc = RefExpr->getExprLoc();
// OpenMP [2.1, C/C++]
// A list item is a variable name.
- // OpenMP [2.9.3.4, Restrictions, p.1]
- // A variable that is part of another variable (as an array or
- // structure element) cannot appear in a private clause.
- DeclRefExpr *DE = dyn_cast<DeclRefExpr>(*I);
+ // OpenMP [2.14.3.2, Restrictions, p.1]
+ // A variable that is part of another variable (as an array or structure
+ // element) cannot appear in a shared unless it is a static data member
+ // of a C++ class.
+ DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr);
if (!DE || !isa<VarDecl>(DE->getDecl())) {
- Diag(ELoc, diag::err_omp_expected_var_name)
- << (*I)->getSourceRange();
+ Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
continue;
}
Decl *D = DE->getDecl();
@@ -1140,13 +3360,12 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
// listed below. For these exceptions only, listing a predetermined
// variable in a data-sharing attribute clause is allowed and overrides
// the variable's predetermined data-sharing attributes.
- DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
- if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared && DVar.RefExpr) {
- Diag(ELoc, diag::err_omp_wrong_dsa)
- << getOpenMPClauseName(DVar.CKind)
- << getOpenMPClauseName(OMPC_shared);
- Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
- << getOpenMPClauseName(DVar.CKind);
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
+ if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared &&
+ DVar.RefExpr) {
+ Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_shared);
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
continue;
}
@@ -1154,9 +3373,730 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
Vars.push_back(DE);
}
- if (Vars.empty()) return 0;
+ if (Vars.empty())
+ return nullptr;
return OMPSharedClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
}
+namespace {
+class DSARefChecker : public StmtVisitor<DSARefChecker, bool> {
+ DSAStackTy *Stack;
+
+public:
+ bool VisitDeclRefExpr(DeclRefExpr *E) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) {
+ DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, false);
+ if (DVar.CKind == OMPC_shared && !DVar.RefExpr)
+ return false;
+ if (DVar.CKind != OMPC_unknown)
+ return true;
+ DSAStackTy::DSAVarData DVarPrivate =
+ Stack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(), false);
+ if (DVarPrivate.CKind != OMPC_unknown)
+ return true;
+ return false;
+ }
+ return false;
+ }
+ bool VisitStmt(Stmt *S) {
+ for (auto Child : S->children()) {
+ if (Child && Visit(Child))
+ return true;
+ }
+ return false;
+ }
+ explicit DSARefChecker(DSAStackTy *S) : Stack(S) {}
+};
+} // namespace
+
+OMPClause *Sema::ActOnOpenMPReductionClause(
+ ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc,
+ CXXScopeSpec &ReductionIdScopeSpec,
+ const DeclarationNameInfo &ReductionId) {
+ // TODO: Allow scope specification search when 'declare reduction' is
+ // supported.
+ assert(ReductionIdScopeSpec.isEmpty() &&
+ "No support for scoped reduction identifiers yet.");
+
+ auto DN = ReductionId.getName();
+ auto OOK = DN.getCXXOverloadedOperator();
+ BinaryOperatorKind BOK = BO_Comma;
+
+ // OpenMP [2.14.3.6, reduction clause]
+ // C
+ // reduction-identifier is either an identifier or one of the following
+ // operators: +, -, *, &, |, ^, && and ||
+ // C++
+ // reduction-identifier is either an id-expression or one of the following
+ // operators: +, -, *, &, |, ^, && and ||
+ // FIXME: Only 'min' and 'max' identifiers are supported for now.
+ switch (OOK) {
+ case OO_Plus:
+ case OO_Minus:
+ BOK = BO_AddAssign;
+ break;
+ case OO_Star:
+ BOK = BO_MulAssign;
+ break;
+ case OO_Amp:
+ BOK = BO_AndAssign;
+ break;
+ case OO_Pipe:
+ BOK = BO_OrAssign;
+ break;
+ case OO_Caret:
+ BOK = BO_XorAssign;
+ break;
+ case OO_AmpAmp:
+ BOK = BO_LAnd;
+ break;
+ case OO_PipePipe:
+ BOK = BO_LOr;
+ break;
+ default:
+ if (auto II = DN.getAsIdentifierInfo()) {
+ if (II->isStr("max"))
+ BOK = BO_GT;
+ else if (II->isStr("min"))
+ BOK = BO_LT;
+ }
+ break;
+ }
+ SourceRange ReductionIdRange;
+ if (ReductionIdScopeSpec.isValid()) {
+ ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc());
+ }
+ ReductionIdRange.setEnd(ReductionId.getEndLoc());
+ if (BOK == BO_Comma) {
+ // Not allowed reduction identifier is found.
+ Diag(ReductionId.getLocStart(), diag::err_omp_unknown_reduction_identifier)
+ << ReductionIdRange;
+ return nullptr;
+ }
+
+ SmallVector<Expr *, 8> Vars;
+ for (auto RefExpr : VarList) {
+ assert(RefExpr && "nullptr expr in OpenMP reduction clause.");
+ if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ continue;
+ }
+
+ if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
+ RefExpr->isInstantiationDependent() ||
+ RefExpr->containsUnexpandedParameterPack()) {
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ continue;
+ }
+
+ auto ELoc = RefExpr->getExprLoc();
+ auto ERange = RefExpr->getSourceRange();
+ // OpenMP [2.1, C/C++]
+ // A list item is a variable or array section, subject to the restrictions
+ // specified in Section 2.4 on page 42 and in each of the sections
+ // describing clauses and directives for which a list appears.
+ // OpenMP [2.14.3.3, Restrictions, p.1]
+ // A variable that is part of another variable (as an array or
+ // structure element) cannot appear in a private clause.
+ auto DE = dyn_cast<DeclRefExpr>(RefExpr);
+ if (!DE || !isa<VarDecl>(DE->getDecl())) {
+ Diag(ELoc, diag::err_omp_expected_var_name) << ERange;
+ continue;
+ }
+ auto D = DE->getDecl();
+ auto VD = cast<VarDecl>(D);
+ auto Type = VD->getType();
+ // OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
+ // A variable that appears in a private clause must not have an incomplete
+ // type or a reference type.
+ if (RequireCompleteType(ELoc, Type,
+ diag::err_omp_reduction_incomplete_type))
+ continue;
+ // OpenMP [2.14.3.6, reduction clause, Restrictions]
+ // Arrays may not appear in a reduction clause.
+ if (Type.getNonReferenceType()->isArrayType()) {
+ Diag(ELoc, diag::err_omp_reduction_type_array) << Type << ERange;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+ // OpenMP [2.14.3.6, reduction clause, Restrictions]
+ // A list item that appears in a reduction clause must not be
+ // const-qualified.
+ if (Type.getNonReferenceType().isConstant(Context)) {
+ Diag(ELoc, diag::err_omp_const_variable)
+ << getOpenMPClauseName(OMPC_reduction) << Type << ERange;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+ // OpenMP [2.9.3.6, Restrictions, C/C++, p.4]
+ // If a list-item is a reference type then it must bind to the same object
+ // for all threads of the team.
+ VarDecl *VDDef = VD->getDefinition();
+ if (Type->isReferenceType() && VDDef) {
+ DSARefChecker Check(DSAStack);
+ if (Check.Visit(VDDef->getInit())) {
+ Diag(ELoc, diag::err_omp_reduction_ref_type_arg) << ERange;
+ Diag(VDDef->getLocation(), diag::note_defined_here) << VDDef;
+ continue;
+ }
+ }
+ // OpenMP [2.14.3.6, reduction clause, Restrictions]
+ // The type of a list item that appears in a reduction clause must be valid
+ // for the reduction-identifier. For a max or min reduction in C, the type
+ // of the list item must be an allowed arithmetic data type: char, int,
+ // float, double, or _Bool, possibly modified with long, short, signed, or
+ // unsigned. For a max or min reduction in C++, the type of the list item
+ // must be an allowed arithmetic data type: char, wchar_t, int, float,
+ // double, or bool, possibly modified with long, short, signed, or unsigned.
+ if ((BOK == BO_GT || BOK == BO_LT) &&
+ !(Type->isScalarType() ||
+ (getLangOpts().CPlusPlus && Type->isArithmeticType()))) {
+ Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg)
+ << getLangOpts().CPlusPlus;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+ if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) &&
+ !getLangOpts().CPlusPlus && Type->isFloatingType()) {
+ Diag(ELoc, diag::err_omp_clause_floating_type_arg);
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+ bool Suppress = getDiagnostics().getSuppressAllDiagnostics();
+ getDiagnostics().setSuppressAllDiagnostics(true);
+ ExprResult ReductionOp =
+ BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BOK,
+ RefExpr, RefExpr);
+ getDiagnostics().setSuppressAllDiagnostics(Suppress);
+ if (ReductionOp.isInvalid()) {
+ Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type
+ << ReductionIdRange;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+
+ // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
+ // in a Construct]
+ // Variables with the predetermined data-sharing attributes may not be
+ // listed in data-sharing attributes clauses, except for the cases
+ // listed below. For these exceptions only, listing a predetermined
+ // variable in a data-sharing attribute clause is allowed and overrides
+ // the variable's predetermined data-sharing attributes.
+ // OpenMP [2.14.3.6, Restrictions, p.3]
+ // Any number of reduction clauses can be specified on the directive,
+ // but a list item can appear only once in the reduction clauses for that
+ // directive.
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
+ if (DVar.CKind == OMPC_reduction) {
+ Diag(ELoc, diag::err_omp_once_referenced)
+ << getOpenMPClauseName(OMPC_reduction);
+ if (DVar.RefExpr) {
+ Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced);
+ }
+ } else if (DVar.CKind != OMPC_unknown) {
+ Diag(ELoc, diag::err_omp_wrong_dsa)
+ << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_reduction);
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ continue;
+ }
+
+ // OpenMP [2.14.3.6, Restrictions, p.1]
+ // A list item that appears in a reduction clause of a worksharing
+ // construct must be shared in the parallel regions to which any of the
+ // worksharing regions arising from the worksharing construct bind.
+ OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
+ if (isOpenMPWorksharingDirective(CurrDir) &&
+ !isOpenMPParallelDirective(CurrDir)) {
+ DVar = DSAStack->getImplicitDSA(VD, true);
+ if (DVar.CKind != OMPC_shared) {
+ Diag(ELoc, diag::err_omp_required_access)
+ << getOpenMPClauseName(OMPC_reduction)
+ << getOpenMPClauseName(OMPC_shared);
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ continue;
+ }
+ }
+
+ CXXRecordDecl *RD = getLangOpts().CPlusPlus
+ ? Type.getNonReferenceType()->getAsCXXRecordDecl()
+ : nullptr;
+ // FIXME This code must be replaced by actual constructing/destructing of
+ // the reduction variable.
+ if (RD) {
+ CXXConstructorDecl *CD = LookupDefaultConstructor(RD);
+ PartialDiagnostic PD =
+ PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
+ if (!CD ||
+ CheckConstructorAccess(ELoc, CD,
+ InitializedEntity::InitializeTemporary(Type),
+ CD->getAccess(), PD) == AR_inaccessible ||
+ CD->isDeleted()) {
+ Diag(ELoc, diag::err_omp_required_method)
+ << getOpenMPClauseName(OMPC_reduction) << 0;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ Diag(RD->getLocation(), diag::note_previous_decl) << RD;
+ continue;
+ }
+ MarkFunctionReferenced(ELoc, CD);
+ DiagnoseUseOfDecl(CD, ELoc);
+
+ CXXDestructorDecl *DD = RD->getDestructor();
+ if (DD) {
+ if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
+ DD->isDeleted()) {
+ Diag(ELoc, diag::err_omp_required_method)
+ << getOpenMPClauseName(OMPC_reduction) << 4;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ Diag(RD->getLocation(), diag::note_previous_decl) << RD;
+ continue;
+ }
+ MarkFunctionReferenced(ELoc, DD);
+ DiagnoseUseOfDecl(DD, ELoc);
+ }
+ }
+
+ DSAStack->addDSA(VD, DE, OMPC_reduction);
+ Vars.push_back(DE);
+ }
+
+ if (Vars.empty())
+ return nullptr;
+
+ return OMPReductionClause::Create(
+ Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars,
+ ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId);
+}
+
+OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (auto &RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP linear clause.");
+ if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ continue;
+ }
+
+ // OpenMP [2.14.3.7, linear clause]
+ // A list item that appears in a linear clause is subject to the private
+ // clause semantics described in Section 2.14.3.3 on page 159 except as
+ // noted. In addition, the value of the new list item on each iteration
+ // of the associated loop(s) corresponds to the value of the original
+ // list item before entering the construct plus the logical number of
+ // the iteration times linear-step.
+
+ SourceLocation ELoc = RefExpr->getExprLoc();
+ // OpenMP [2.1, C/C++]
+ // A list item is a variable name.
+ // OpenMP [2.14.3.3, Restrictions, p.1]
+ // A variable that is part of another variable (as an array or
+ // structure element) cannot appear in a private clause.
+ DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr);
+ if (!DE || !isa<VarDecl>(DE->getDecl())) {
+ Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
+ continue;
+ }
+
+ VarDecl *VD = cast<VarDecl>(DE->getDecl());
+
+ // OpenMP [2.14.3.7, linear clause]
+ // A list-item cannot appear in more than one linear clause.
+ // A list-item that appears in a linear clause cannot appear in any
+ // other data-sharing attribute clause.
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
+ if (DVar.RefExpr) {
+ Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_linear);
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ continue;
+ }
+
+ QualType QType = VD->getType();
+ if (QType->isDependentType() || QType->isInstantiationDependentType()) {
+ // It will be analyzed later.
+ Vars.push_back(DE);
+ continue;
+ }
+
+ // A variable must not have an incomplete type or a reference type.
+ if (RequireCompleteType(ELoc, QType,
+ diag::err_omp_linear_incomplete_type)) {
+ continue;
+ }
+ if (QType->isReferenceType()) {
+ Diag(ELoc, diag::err_omp_clause_ref_type_arg)
+ << getOpenMPClauseName(OMPC_linear) << QType;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+
+ // A list item must not be const-qualified.
+ if (QType.isConstant(Context)) {
+ Diag(ELoc, diag::err_omp_const_variable)
+ << getOpenMPClauseName(OMPC_linear);
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+
+ // A list item must be of integral or pointer type.
+ QType = QType.getUnqualifiedType().getCanonicalType();
+ const Type *Ty = QType.getTypePtrOrNull();
+ if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) &&
+ !Ty->isPointerType())) {
+ Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << QType;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+
+ DSAStack->addDSA(VD, DE, OMPC_linear);
+ Vars.push_back(DE);
+ }
+
+ if (Vars.empty())
+ return nullptr;
+
+ Expr *StepExpr = Step;
+ if (Step && !Step->isValueDependent() && !Step->isTypeDependent() &&
+ !Step->isInstantiationDependent() &&
+ !Step->containsUnexpandedParameterPack()) {
+ SourceLocation StepLoc = Step->getLocStart();
+ ExprResult Val = PerformOpenMPImplicitIntegerConversion(StepLoc, Step);
+ if (Val.isInvalid())
+ return nullptr;
+ StepExpr = Val.get();
+
+ // Warn about zero linear step (it would be probably better specified as
+ // making corresponding variables 'const').
+ llvm::APSInt Result;
+ if (StepExpr->isIntegerConstantExpr(Result, Context) &&
+ !Result.isNegative() && !Result.isStrictlyPositive())
+ Diag(StepLoc, diag::warn_omp_linear_step_zero) << Vars[0]
+ << (Vars.size() > 1);
+ }
+
+ return OMPLinearClause::Create(Context, StartLoc, LParenLoc, ColonLoc, EndLoc,
+ Vars, StepExpr);
+}
+
+OMPClause *Sema::ActOnOpenMPAlignedClause(
+ ArrayRef<Expr *> VarList, Expr *Alignment, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc) {
+
+ SmallVector<Expr *, 8> Vars;
+ for (auto &RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP aligned clause.");
+ if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ continue;
+ }
+
+ SourceLocation ELoc = RefExpr->getExprLoc();
+ // OpenMP [2.1, C/C++]
+ // A list item is a variable name.
+ DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr);
+ if (!DE || !isa<VarDecl>(DE->getDecl())) {
+ Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
+ continue;
+ }
+
+ VarDecl *VD = cast<VarDecl>(DE->getDecl());
+
+ // OpenMP [2.8.1, simd construct, Restrictions]
+ // The type of list items appearing in the aligned clause must be
+ // array, pointer, reference to array, or reference to pointer.
+ QualType QType = DE->getType()
+ .getNonReferenceType()
+ .getUnqualifiedType()
+ .getCanonicalType();
+ const Type *Ty = QType.getTypePtrOrNull();
+ if (!Ty || (!Ty->isDependentType() && !Ty->isArrayType() &&
+ !Ty->isPointerType())) {
+ Diag(ELoc, diag::err_omp_aligned_expected_array_or_ptr)
+ << QType << getLangOpts().CPlusPlus << RefExpr->getSourceRange();
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+
+ // OpenMP [2.8.1, simd construct, Restrictions]
+ // A list-item cannot appear in more than one aligned clause.
+ if (DeclRefExpr *PrevRef = DSAStack->addUniqueAligned(VD, DE)) {
+ Diag(ELoc, diag::err_omp_aligned_twice) << RefExpr->getSourceRange();
+ Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(OMPC_aligned);
+ continue;
+ }
+
+ Vars.push_back(DE);
+ }
+
+ // OpenMP [2.8.1, simd construct, Description]
+ // The parameter of the aligned clause, alignment, must be a constant
+ // positive integer expression.
+ // If no optional parameter is specified, implementation-defined default
+ // alignments for SIMD instructions on the target platforms are assumed.
+ if (Alignment != nullptr) {
+ ExprResult AlignResult =
+ VerifyPositiveIntegerConstantInClause(Alignment, OMPC_aligned);
+ if (AlignResult.isInvalid())
+ return nullptr;
+ Alignment = AlignResult.get();
+ }
+ if (Vars.empty())
+ return nullptr;
+
+ return OMPAlignedClause::Create(Context, StartLoc, LParenLoc, ColonLoc,
+ EndLoc, Vars, Alignment);
+}
+
+OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (auto &RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP copyin clause.");
+ if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ continue;
+ }
+
+ SourceLocation ELoc = RefExpr->getExprLoc();
+ // OpenMP [2.1, C/C++]
+ // A list item is a variable name.
+ // OpenMP [2.14.4.1, Restrictions, p.1]
+ // A list item that appears in a copyin clause must be threadprivate.
+ DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr);
+ if (!DE || !isa<VarDecl>(DE->getDecl())) {
+ Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
+ continue;
+ }
+
+ Decl *D = DE->getDecl();
+ VarDecl *VD = cast<VarDecl>(D);
+
+ QualType Type = VD->getType();
+ if (Type->isDependentType() || Type->isInstantiationDependentType()) {
+ // It will be analyzed later.
+ Vars.push_back(DE);
+ continue;
+ }
+
+ // OpenMP [2.14.4.1, Restrictions, C/C++, p.1]
+ // A list item that appears in a copyin clause must be threadprivate.
+ if (!DSAStack->isThreadPrivate(VD)) {
+ Diag(ELoc, diag::err_omp_required_access)
+ << getOpenMPClauseName(OMPC_copyin)
+ << getOpenMPDirectiveName(OMPD_threadprivate);
+ continue;
+ }
+
+ // OpenMP [2.14.4.1, Restrictions, C/C++, p.2]
+ // A variable of class type (or array thereof) that appears in a
+ // copyin clause requires an accessible, unambiguous copy assignment
+ // operator for the class type.
+ Type = Context.getBaseElementType(Type);
+ CXXRecordDecl *RD =
+ getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr;
+ // FIXME This code must be replaced by actual assignment of the
+ // threadprivate variable.
+ if (RD) {
+ CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0);
+ DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess());
+ if (MD) {
+ if (CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible ||
+ MD->isDeleted()) {
+ Diag(ELoc, diag::err_omp_required_method)
+ << getOpenMPClauseName(OMPC_copyin) << 2;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ Diag(RD->getLocation(), diag::note_previous_decl) << RD;
+ continue;
+ }
+ MarkFunctionReferenced(ELoc, MD);
+ DiagnoseUseOfDecl(MD, ELoc);
+ }
+ }
+
+ DSAStack->addDSA(VD, DE, OMPC_copyin);
+ Vars.push_back(DE);
+ }
+
+ if (Vars.empty())
+ return nullptr;
+
+ return OMPCopyinClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
+}
+
+OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (auto &RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP copyprivate clause.");
+ if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ continue;
+ }
+
+ SourceLocation ELoc = RefExpr->getExprLoc();
+ // OpenMP [2.1, C/C++]
+ // A list item is a variable name.
+ // OpenMP [2.14.4.1, Restrictions, p.1]
+ // A list item that appears in a copyin clause must be threadprivate.
+ DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr);
+ if (!DE || !isa<VarDecl>(DE->getDecl())) {
+ Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
+ continue;
+ }
+
+ Decl *D = DE->getDecl();
+ VarDecl *VD = cast<VarDecl>(D);
+
+ QualType Type = VD->getType();
+ if (Type->isDependentType() || Type->isInstantiationDependentType()) {
+ // It will be analyzed later.
+ Vars.push_back(DE);
+ continue;
+ }
+
+ // OpenMP [2.14.4.2, Restrictions, p.2]
+ // A list item that appears in a copyprivate clause may not appear in a
+ // private or firstprivate clause on the single construct.
+ if (!DSAStack->isThreadPrivate(VD)) {
+ auto DVar = DSAStack->getTopDSA(VD, false);
+ if (DVar.CKind != OMPC_copyprivate && DVar.CKind != OMPC_unknown &&
+ !(DVar.CKind == OMPC_private && !DVar.RefExpr)) {
+ Diag(ELoc, diag::err_omp_wrong_dsa)
+ << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_copyprivate);
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ continue;
+ }
+
+ // OpenMP [2.11.4.2, Restrictions, p.1]
+ // All list items that appear in a copyprivate clause must be either
+ // threadprivate or private in the enclosing context.
+ if (DVar.CKind == OMPC_unknown) {
+ DVar = DSAStack->getImplicitDSA(VD, false);
+ if (DVar.CKind == OMPC_shared) {
+ Diag(ELoc, diag::err_omp_required_access)
+ << getOpenMPClauseName(OMPC_copyprivate)
+ << "threadprivate or private in the enclosing context";
+ ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ continue;
+ }
+ }
+ }
+
+ // OpenMP [2.14.4.1, Restrictions, C/C++, p.2]
+ // A variable of class type (or array thereof) that appears in a
+ // copyin clause requires an accessible, unambiguous copy assignment
+ // operator for the class type.
+ Type = Context.getBaseElementType(Type);
+ CXXRecordDecl *RD =
+ getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr;
+ // FIXME This code must be replaced by actual assignment of the
+ // threadprivate variable.
+ if (RD) {
+ CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0);
+ DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess());
+ if (MD) {
+ if (CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible ||
+ MD->isDeleted()) {
+ Diag(ELoc, diag::err_omp_required_method)
+ << getOpenMPClauseName(OMPC_copyprivate) << 2;
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ Diag(RD->getLocation(), diag::note_previous_decl) << RD;
+ continue;
+ }
+ MarkFunctionReferenced(ELoc, MD);
+ DiagnoseUseOfDecl(MD, ELoc);
+ }
+ }
+
+ // No need to mark vars as copyprivate, they are already threadprivate or
+ // implicitly private.
+ Vars.push_back(DE);
+ }
+
+ if (Vars.empty())
+ return nullptr;
+
+ return OMPCopyprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
+}
+
+OMPClause *Sema::ActOnOpenMPFlushClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ if (VarList.empty())
+ return nullptr;
+
+ return OMPFlushClause::Create(Context, StartLoc, LParenLoc, EndLoc, VarList);
+}
+
#undef DSAStack
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 802f2b7290b3..03001d89f07e 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -20,9 +20,9 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/SemaInternal.h"
@@ -33,6 +33,7 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include <algorithm>
+#include <cstdlib>
namespace clang {
using namespace sema;
@@ -60,8 +61,8 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl,
S.MarkDeclRefReferenced(DRE);
- ExprResult E = S.Owned(DRE);
- E = S.DefaultFunctionArrayConversion(E.take());
+ ExprResult E = DRE;
+ E = S.DefaultFunctionArrayConversion(E.get());
if (E.isInvalid())
return ExprError();
return E;
@@ -215,7 +216,7 @@ void StandardConversionSequence::setAsIdentityConversion() {
BindsToRvalue = false;
BindsImplicitObjectArgumentWithoutRefQualifier = false;
ObjCLifetimeConversionBinding = false;
- CopyConstructor = 0;
+ CopyConstructor = nullptr;
}
/// getRank - Retrieve the rank of this standard conversion sequence
@@ -573,7 +574,7 @@ DeductionFailureInfo MakeDeductionFailureInfo(ASTContext &Context,
DeductionFailureInfo Result;
Result.Result = static_cast<unsigned>(TDK);
Result.HasDiagnostic = false;
- Result.Data = 0;
+ Result.Data = nullptr;
switch (TDK) {
case Sema::TDK_Success:
case Sema::TDK_Invalid:
@@ -644,12 +645,12 @@ void DeductionFailureInfo::Destroy() {
case Sema::TDK_Underqualified:
case Sema::TDK_NonDeducedMismatch:
// FIXME: Destroy the data?
- Data = 0;
+ Data = nullptr;
break;
case Sema::TDK_SubstitutionFailure:
// FIXME: Destroy the template argument list?
- Data = 0;
+ Data = nullptr;
if (PartialDiagnosticAt *Diag = getSFINAEDiagnostic()) {
Diag->~PartialDiagnosticAt();
HasDiagnostic = false;
@@ -665,7 +666,7 @@ void DeductionFailureInfo::Destroy() {
PartialDiagnosticAt *DeductionFailureInfo::getSFINAEDiagnostic() {
if (HasDiagnostic)
return static_cast<PartialDiagnosticAt*>(static_cast<void*>(Diagnostic));
- return 0;
+ return nullptr;
}
TemplateParameter DeductionFailureInfo::getTemplateParameter() {
@@ -709,7 +710,7 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() {
case Sema::TDK_Underqualified:
case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_FailedOverloadResolution:
- return 0;
+ return nullptr;
case Sema::TDK_SubstitutionFailure:
return static_cast<TemplateArgumentList*>(Data);
@@ -719,7 +720,7 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() {
break;
}
- return 0;
+ return nullptr;
}
const TemplateArgument *DeductionFailureInfo::getFirstArg() {
@@ -733,7 +734,7 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() {
case Sema::TDK_InvalidExplicitArguments:
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_FailedOverloadResolution:
- return 0;
+ return nullptr;
case Sema::TDK_Inconsistent:
case Sema::TDK_Underqualified:
@@ -745,7 +746,7 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() {
break;
}
- return 0;
+ return nullptr;
}
const TemplateArgument *DeductionFailureInfo::getSecondArg() {
@@ -759,7 +760,7 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() {
case Sema::TDK_InvalidExplicitArguments:
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_FailedOverloadResolution:
- return 0;
+ return nullptr;
case Sema::TDK_Inconsistent:
case Sema::TDK_Underqualified:
@@ -771,7 +772,7 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() {
break;
}
- return 0;
+ return nullptr;
}
Expr *DeductionFailureInfo::getExpr() {
@@ -779,7 +780,7 @@ Expr *DeductionFailureInfo::getExpr() {
Sema::TDK_FailedOverloadResolution)
return static_cast<Expr*>(Data);
- return 0;
+ return nullptr;
}
void OverloadCandidateSet::destroyCandidates() {
@@ -829,8 +830,9 @@ namespace {
/// without this, they will be immediately diagnosed as errors
///
/// Return true on unrecoverable error.
-static bool checkPlaceholderForOverload(Sema &S, Expr *&E,
- UnbridgedCastsSet *unbridgedCasts = 0) {
+static bool
+checkPlaceholderForOverload(Sema &S, Expr *&E,
+ UnbridgedCastsSet *unbridgedCasts = nullptr) {
if (const BuiltinType *placeholder = E->getType()->getAsPlaceholderType()) {
// We can't handle overloaded expressions here because overload
// resolution might reasonably tweak them.
@@ -849,7 +851,7 @@ static bool checkPlaceholderForOverload(Sema &S, Expr *&E,
if (result.isInvalid())
return true;
- E = result.take();
+ E = result.get();
return false;
}
@@ -930,24 +932,15 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
(OldIsUsingDecl || NewIsUsingDecl) && CurContext->isRecord() &&
!New->getFriendObjectKind();
- if (FunctionTemplateDecl *OldT = dyn_cast<FunctionTemplateDecl>(OldD)) {
- if (!IsOverload(New, OldT->getTemplatedDecl(), UseMemberUsingDeclRules)) {
- if (UseMemberUsingDeclRules && OldIsUsingDecl) {
- HideUsingShadowDecl(S, cast<UsingShadowDecl>(*I));
- continue;
- }
-
- Match = *I;
- return Ovl_Match;
- }
- } else if (FunctionDecl *OldF = dyn_cast<FunctionDecl>(OldD)) {
+ if (FunctionDecl *OldF = OldD->getAsFunction()) {
if (!IsOverload(New, OldF, UseMemberUsingDeclRules)) {
if (UseMemberUsingDeclRules && OldIsUsingDecl) {
HideUsingShadowDecl(S, cast<UsingShadowDecl>(*I));
continue;
}
- if (!shouldLinkPossiblyHiddenDecl(*I, New))
+ if (!isa<FunctionTemplateDecl>(OldD) &&
+ !shouldLinkPossiblyHiddenDecl(*I, New))
continue;
Match = *I;
@@ -991,7 +984,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
// C++ [temp.fct]p2:
// A function template can be overloaded with other function templates
// and with normal (non-template) functions.
- if ((OldTemplate == 0) != (NewTemplate == 0))
+ if ((OldTemplate == nullptr) != (NewTemplate == nullptr))
return true;
// Is the function New an overload of the function Old?
@@ -1008,16 +1001,16 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
isa<FunctionNoProtoType>(NewQType.getTypePtr()))
return false;
- const FunctionProtoType* OldType = cast<FunctionProtoType>(OldQType);
- const FunctionProtoType* NewType = cast<FunctionProtoType>(NewQType);
+ const FunctionProtoType *OldType = cast<FunctionProtoType>(OldQType);
+ const FunctionProtoType *NewType = cast<FunctionProtoType>(NewQType);
// The signature of a function includes the types of its
// parameters (C++ 1.3.10), which includes the presence or absence
// of the ellipsis; see C++ DR 357).
if (OldQType != NewQType &&
- (OldType->getNumArgs() != NewType->getNumArgs() ||
+ (OldType->getNumParams() != NewType->getNumParams() ||
OldType->isVariadic() != NewType->isVariadic() ||
- !FunctionArgTypesAreEqual(OldType, NewType)))
+ !FunctionParamTypesAreEqual(OldType, NewType)))
return true;
// C++ [temp.over.link]p4:
@@ -1036,7 +1029,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
(!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
OldTemplate->getTemplateParameters(),
false, TPL_TemplateMatch) ||
- OldType->getResultType() != NewType->getResultType()))
+ OldType->getReturnType() != NewType->getReturnType()))
return true;
// If the function is a class member, its signature includes the
@@ -1085,6 +1078,22 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
return true;
}
+ // enable_if attributes are an order-sensitive part of the signature.
+ for (specific_attr_iterator<EnableIfAttr>
+ NewI = New->specific_attr_begin<EnableIfAttr>(),
+ NewE = New->specific_attr_end<EnableIfAttr>(),
+ OldI = Old->specific_attr_begin<EnableIfAttr>(),
+ OldE = Old->specific_attr_end<EnableIfAttr>();
+ NewI != NewE || OldI != OldE; ++NewI, ++OldI) {
+ if (NewI == NewE || OldI == OldE)
+ return true;
+ llvm::FoldingSetNodeID NewID, OldID;
+ NewI->getCond()->Profile(NewID, Context, true);
+ OldI->getCond()->Profile(OldID, Context, true);
+ if (NewID != OldID)
+ return true;
+ }
+
// The signatures match; this is not an overload.
return false;
}
@@ -1120,13 +1129,15 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
}
// Attempt user-defined conversion.
- OverloadCandidateSet Conversions(From->getExprLoc());
+ OverloadCandidateSet Conversions(From->getExprLoc(),
+ OverloadCandidateSet::CSK_Normal);
OverloadingResult UserDefResult
= IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, Conversions,
AllowExplicit, AllowObjCConversionOnExplicit);
if (UserDefResult == OR_Success) {
ICS.setUserDefined();
+ ICS.UserDefined.Before.setAsIdentityConversion();
// C++ [over.ics.user]p4:
// A conversion of an expression of class type to the same class
// type is given Exact Match rank, and a conversion of an
@@ -1153,17 +1164,6 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
ICS.Standard.Second = ICK_Derived_To_Base;
}
}
-
- // C++ [over.best.ics]p4:
- // However, when considering the argument of a user-defined
- // conversion function that is a candidate by 13.3.1.3 when
- // invoked for the copying of the temporary in the second step
- // of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or
- // 13.3.1.6 in all cases, only standard conversion sequences and
- // ellipsis conversion sequences are allowed.
- if (SuppressUserConversions && ICS.isUserDefined()) {
- ICS.setBad(BadConversionSequence::suppressed_user, From, ToType);
- }
} else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) {
ICS.setAmbiguous();
ICS.Ambiguous.setFromType(From->getType());
@@ -1246,7 +1246,7 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
// copy/move constructor, since overloading just assumes that it
// exists. When we actually perform initialization, we'll find the
// appropriate constructor to copy the returned object, if needed.
- ICS.Standard.CopyConstructor = 0;
+ ICS.Standard.CopyConstructor = nullptr;
// Determine whether this is considered a derived-to-base conversion.
if (!S.Context.hasSameUnqualifiedType(FromType, ToType))
@@ -1298,7 +1298,9 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
bool AllowObjCWritebackConversion
= getLangOpts().ObjCAutoRefCount &&
(Action == AA_Passing || Action == AA_Sending);
-
+ if (getLangOpts().ObjC1)
+ CheckObjCBridgeRelatedConversions(From->getLocStart(),
+ ToType, From->getType(), From);
ICS = clang::TryImplicitConversion(*this, From, ToType,
/*SuppressUserConversions=*/false,
AllowExplicit,
@@ -1362,7 +1364,7 @@ bool Sema::IsNoReturnConversion(QualType FromType, QualType ToType,
///
/// \param ICK Will be set to the vector conversion kind, if this is a vector
/// conversion.
-static bool IsVectorConversion(ASTContext &Context, QualType FromType,
+static bool IsVectorConversion(Sema &S, QualType FromType,
QualType ToType, ImplicitConversionKind &ICK) {
// We need at least one of these types to be a vector type to have a vector
// conversion.
@@ -1370,7 +1372,7 @@ static bool IsVectorConversion(ASTContext &Context, QualType FromType,
return false;
// Identical types require no conversions.
- if (Context.hasSameUnqualifiedType(FromType, ToType))
+ if (S.Context.hasSameUnqualifiedType(FromType, ToType))
return false;
// There are no conversions between extended vector types, only identity.
@@ -1392,9 +1394,8 @@ static bool IsVectorConversion(ASTContext &Context, QualType FromType,
// 2)lax vector conversions are permitted and the vector types are of the
// same size
if (ToType->isVectorType() && FromType->isVectorType()) {
- if (Context.areCompatibleVectorTypes(FromType, ToType) ||
- (Context.getLangOpts().LaxVectorConversions &&
- (Context.getTypeSize(FromType) == Context.getTypeSize(ToType)))) {
+ if (S.Context.areCompatibleVectorTypes(FromType, ToType) ||
+ S.isLaxVectorConversion(FromType, ToType)) {
ICK = ICK_Vector_Conversion;
return true;
}
@@ -1425,10 +1426,9 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// Standard conversions (C++ [conv])
SCS.setAsIdentityConversion();
- SCS.DeprecatedStringLiteralToCharPtr = false;
SCS.IncompatibleObjC = false;
SCS.setFromType(FromType);
- SCS.CopyConstructor = 0;
+ SCS.CopyConstructor = nullptr;
// There are no standard conversions for class types in C++, so
// abort early. When overloading in C, however, we do permit
@@ -1524,7 +1524,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
FromType = S.Context.getArrayDecayedType(FromType);
if (S.IsStringLiteralToNonConstPointerConversion(From, ToType)) {
- // This conversion is deprecated. (C++ D.4).
+ // This conversion is deprecated in C++03 (D.4)
SCS.DeprecatedStringLiteralToCharPtr = true;
// For the purpose of ranking in overload resolution
@@ -1624,7 +1624,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
InOverloadResolution, FromType)) {
// Pointer to member conversions (4.11).
SCS.Second = ICK_Pointer_Member;
- } else if (IsVectorConversion(S.Context, FromType, ToType, SecondICK)) {
+ } else if (IsVectorConversion(S, FromType, ToType, SecondICK)) {
SCS.Second = SecondICK;
FromType = ToType.getUnqualifiedType();
} else if (!S.getLangOpts().CPlusPlus &&
@@ -1707,9 +1707,7 @@ IsTransparentUnionStandardConversion(Sema &S, Expr* From,
// The field to initialize within the transparent union.
RecordDecl *UD = UT->getDecl();
// It's compatible if the expression matches any of the fields.
- for (RecordDecl::field_iterator it = UD->field_begin(),
- itend = UD->field_end();
- it != itend; ++it) {
+ for (const auto *it : UD->fields()) {
if (IsStandardConversion(S, From, it->getType(), InOverloadResolution, SCS,
CStyle, /*ObjCWritebackConversion=*/false)) {
ToType = it->getType();
@@ -1914,7 +1912,7 @@ bool Sema::IsComplexPromotion(QualType FromType, QualType ToType) {
return IsFloatingPointPromotion(FromComplex->getElementType(),
ToComplex->getElementType()) ||
- IsIntegralPromotion(0, FromComplex->getElementType(),
+ IsIntegralPromotion(nullptr, FromComplex->getElementType(),
ToComplex->getElementType());
}
@@ -2288,17 +2286,17 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
// Perform the quick checks that will tell us whether these
// function types are obviously different.
- if (FromFunctionType->getNumArgs() != ToFunctionType->getNumArgs() ||
+ if (FromFunctionType->getNumParams() != ToFunctionType->getNumParams() ||
FromFunctionType->isVariadic() != ToFunctionType->isVariadic() ||
FromFunctionType->getTypeQuals() != ToFunctionType->getTypeQuals())
return false;
bool HasObjCConversion = false;
- if (Context.getCanonicalType(FromFunctionType->getResultType())
- == Context.getCanonicalType(ToFunctionType->getResultType())) {
+ if (Context.getCanonicalType(FromFunctionType->getReturnType()) ==
+ Context.getCanonicalType(ToFunctionType->getReturnType())) {
// Okay, the types match exactly. Nothing to do.
- } else if (isObjCPointerConversion(FromFunctionType->getResultType(),
- ToFunctionType->getResultType(),
+ } else if (isObjCPointerConversion(FromFunctionType->getReturnType(),
+ ToFunctionType->getReturnType(),
ConvertedType, IncompatibleObjC)) {
// Okay, we have an Objective-C pointer conversion.
HasObjCConversion = true;
@@ -2308,10 +2306,10 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
}
// Check argument types.
- for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumArgs();
+ for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumParams();
ArgIdx != NumArgs; ++ArgIdx) {
- QualType FromArgType = FromFunctionType->getArgType(ArgIdx);
- QualType ToArgType = ToFunctionType->getArgType(ArgIdx);
+ QualType FromArgType = FromFunctionType->getParamType(ArgIdx);
+ QualType ToArgType = ToFunctionType->getParamType(ArgIdx);
if (Context.getCanonicalType(FromArgType)
== Context.getCanonicalType(ToArgType)) {
// Okay, the types match exactly. Nothing to do.
@@ -2436,7 +2434,7 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
// Perform the quick checks that will tell us whether these
// function types are obviously different.
- if (FromFunctionType->getNumArgs() != ToFunctionType->getNumArgs() ||
+ if (FromFunctionType->getNumParams() != ToFunctionType->getNumParams() ||
FromFunctionType->isVariadic() != ToFunctionType->isVariadic())
return false;
@@ -2446,12 +2444,12 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
return false;
bool IncompatibleObjC = false;
- if (Context.hasSameType(FromFunctionType->getResultType(),
- ToFunctionType->getResultType())) {
+ if (Context.hasSameType(FromFunctionType->getReturnType(),
+ ToFunctionType->getReturnType())) {
// Okay, the types match exactly. Nothing to do.
} else {
- QualType RHS = FromFunctionType->getResultType();
- QualType LHS = ToFunctionType->getResultType();
+ QualType RHS = FromFunctionType->getReturnType();
+ QualType LHS = ToFunctionType->getReturnType();
if ((!getLangOpts().CPlusPlus || !RHS->isRecordType()) &&
!RHS.hasQualifiers() && LHS.hasQualifiers())
LHS = LHS.getUnqualifiedType();
@@ -2469,11 +2467,11 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
}
// Check argument types.
- for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumArgs();
+ for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumParams();
ArgIdx != NumArgs; ++ArgIdx) {
IncompatibleObjC = false;
- QualType FromArgType = FromFunctionType->getArgType(ArgIdx);
- QualType ToArgType = ToFunctionType->getArgType(ArgIdx);
+ QualType FromArgType = FromFunctionType->getParamType(ArgIdx);
+ QualType ToArgType = ToFunctionType->getParamType(ArgIdx);
if (Context.hasSameType(FromArgType, ToArgType)) {
// Okay, the types match exactly. Nothing to do.
} else if (isObjCPointerConversion(ToArgType, FromArgType,
@@ -2518,7 +2516,7 @@ void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
if (FromType->isMemberPointerType() && ToType->isMemberPointerType()) {
const MemberPointerType *FromMember = FromType->getAs<MemberPointerType>(),
*ToMember = ToType->getAs<MemberPointerType>();
- if (FromMember->getClass() != ToMember->getClass()) {
+ if (!Context.hasSameType(FromMember->getClass(), ToMember->getClass())) {
PDiag << ft_different_class << QualType(ToMember->getClass(), 0)
<< QualType(FromMember->getClass(), 0);
return;
@@ -2558,26 +2556,26 @@ void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
return;
}
- if (FromFunction->getNumArgs() != ToFunction->getNumArgs()) {
- PDiag << ft_parameter_arity << ToFunction->getNumArgs()
- << FromFunction->getNumArgs();
+ if (FromFunction->getNumParams() != ToFunction->getNumParams()) {
+ PDiag << ft_parameter_arity << ToFunction->getNumParams()
+ << FromFunction->getNumParams();
return;
}
// Handle different parameter types.
unsigned ArgPos;
- if (!FunctionArgTypesAreEqual(FromFunction, ToFunction, &ArgPos)) {
+ if (!FunctionParamTypesAreEqual(FromFunction, ToFunction, &ArgPos)) {
PDiag << ft_parameter_mismatch << ArgPos + 1
- << ToFunction->getArgType(ArgPos)
- << FromFunction->getArgType(ArgPos);
+ << ToFunction->getParamType(ArgPos)
+ << FromFunction->getParamType(ArgPos);
return;
}
// Handle different return type.
- if (!Context.hasSameType(FromFunction->getResultType(),
- ToFunction->getResultType())) {
- PDiag << ft_return_type << ToFunction->getResultType()
- << FromFunction->getResultType();
+ if (!Context.hasSameType(FromFunction->getReturnType(),
+ ToFunction->getReturnType())) {
+ PDiag << ft_return_type << ToFunction->getReturnType()
+ << FromFunction->getReturnType();
return;
}
@@ -2592,19 +2590,21 @@ void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
PDiag << ft_default;
}
-/// FunctionArgTypesAreEqual - This routine checks two function proto types
+/// FunctionParamTypesAreEqual - This routine checks two function proto types
/// for equality of their argument types. Caller has already checked that
/// they have same number of arguments. If the parameters are different,
/// ArgPos will have the parameter index of the first different parameter.
-bool Sema::FunctionArgTypesAreEqual(const FunctionProtoType *OldType,
- const FunctionProtoType *NewType,
- unsigned *ArgPos) {
- for (FunctionProtoType::arg_type_iterator O = OldType->arg_type_begin(),
- N = NewType->arg_type_begin(),
- E = OldType->arg_type_end(); O && (O != E); ++O, ++N) {
+bool Sema::FunctionParamTypesAreEqual(const FunctionProtoType *OldType,
+ const FunctionProtoType *NewType,
+ unsigned *ArgPos) {
+ for (FunctionProtoType::param_type_iterator O = OldType->param_type_begin(),
+ N = NewType->param_type_begin(),
+ E = OldType->param_type_end();
+ O && (O != E); ++O, ++N) {
if (!Context.hasSameType(O->getUnqualifiedType(),
N->getUnqualifiedType())) {
- if (ArgPos) *ArgPos = O - OldType->arg_type_begin();
+ if (ArgPos)
+ *ArgPos = O - OldType->param_type_begin();
return false;
}
}
@@ -2919,8 +2919,8 @@ static bool isFirstArgumentCompatibleWithType(ASTContext &Context,
QualType Type) {
const FunctionProtoType *CtorType =
Constructor->getType()->getAs<FunctionProtoType>();
- if (CtorType->getNumArgs() > 0) {
- QualType FirstArg = CtorType->getArgType(0);
+ if (CtorType->getNumParams() > 0) {
+ QualType FirstArg = CtorType->getParamType(0);
if (Context.hasSameUnqualifiedType(Type, FirstArg.getNonReferenceType()))
return true;
}
@@ -2940,7 +2940,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
// Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = 0;
+ CXXConstructorDecl *Constructor = nullptr;
FunctionTemplateDecl *ConstructorTmpl
= dyn_cast<FunctionTemplateDecl>(D);
if (ConstructorTmpl)
@@ -2959,7 +2959,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
isFirstArgumentCompatibleWithType(S.Context, Constructor, ToType);
if (ConstructorTmpl)
S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
- /*ExplicitArgs*/ 0,
+ /*ExplicitArgs*/ nullptr,
From, CandidateSet,
SuppressUserConversions);
else
@@ -3075,7 +3075,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
// Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = 0;
+ CXXConstructorDecl *Constructor = nullptr;
FunctionTemplateDecl *ConstructorTmpl
= dyn_cast<FunctionTemplateDecl>(D);
if (ConstructorTmpl)
@@ -3102,7 +3102,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
}
if (ConstructorTmpl)
S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
- /*ExplicitArgs*/ 0,
+ /*ExplicitArgs*/ nullptr,
llvm::makeArrayRef(Args, NumArgs),
CandidateSet, SuppressUserConversions);
else
@@ -3236,23 +3236,21 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
bool
Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
ImplicitConversionSequence ICS;
- OverloadCandidateSet CandidateSet(From->getExprLoc());
+ OverloadCandidateSet CandidateSet(From->getExprLoc(),
+ OverloadCandidateSet::CSK_Normal);
OverloadingResult OvResult =
IsUserDefinedConversion(*this, From, ToType, ICS.UserDefined,
CandidateSet, false, false);
if (OvResult == OR_Ambiguous)
- Diag(From->getLocStart(),
- diag::err_typecheck_ambiguous_condition)
- << From->getType() << ToType << From->getSourceRange();
+ Diag(From->getLocStart(), diag::err_typecheck_ambiguous_condition)
+ << From->getType() << ToType << From->getSourceRange();
else if (OvResult == OR_No_Viable_Function && !CandidateSet.empty()) {
if (!RequireCompleteType(From->getLocStart(), ToType,
- diag::err_typecheck_nonviable_condition_incomplete,
+ diag::err_typecheck_nonviable_condition_incomplete,
From->getType(), From->getSourceRange()))
- Diag(From->getLocStart(),
- diag::err_typecheck_nonviable_condition)
- << From->getType() << From->getSourceRange() << ToType;
- }
- else
+ Diag(From->getLocStart(), diag::err_typecheck_nonviable_condition)
+ << From->getType() << From->getSourceRange() << ToType;
+ } else
return false;
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, From);
return true;
@@ -3262,37 +3260,43 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
/// of two user-defined conversion sequences to determine whether any ordering
/// is possible.
static ImplicitConversionSequence::CompareKind
-compareConversionFunctions(Sema &S,
- FunctionDecl *Function1,
+compareConversionFunctions(Sema &S, FunctionDecl *Function1,
FunctionDecl *Function2) {
if (!S.getLangOpts().ObjC1 || !S.getLangOpts().CPlusPlus11)
return ImplicitConversionSequence::Indistinguishable;
-
+
// Objective-C++:
// If both conversion functions are implicitly-declared conversions from
- // a lambda closure type to a function pointer and a block pointer,
+ // a lambda closure type to a function pointer and a block pointer,
// respectively, always prefer the conversion to a function pointer,
// because the function pointer is more lightweight and is more likely
// to keep code working.
- CXXConversionDecl *Conv1 = dyn_cast<CXXConversionDecl>(Function1);
+ CXXConversionDecl *Conv1 = dyn_cast_or_null<CXXConversionDecl>(Function1);
if (!Conv1)
return ImplicitConversionSequence::Indistinguishable;
-
+
CXXConversionDecl *Conv2 = dyn_cast<CXXConversionDecl>(Function2);
if (!Conv2)
return ImplicitConversionSequence::Indistinguishable;
-
+
if (Conv1->getParent()->isLambda() && Conv2->getParent()->isLambda()) {
bool Block1 = Conv1->getConversionType()->isBlockPointerType();
bool Block2 = Conv2->getConversionType()->isBlockPointerType();
if (Block1 != Block2)
- return Block1? ImplicitConversionSequence::Worse
- : ImplicitConversionSequence::Better;
+ return Block1 ? ImplicitConversionSequence::Worse
+ : ImplicitConversionSequence::Better;
}
return ImplicitConversionSequence::Indistinguishable;
}
-
+
+static bool hasDeprecatedStringLiteralToCharPtrConversion(
+ const ImplicitConversionSequence &ICS) {
+ return (ICS.isStandard() && ICS.Standard.DeprecatedStringLiteralToCharPtr) ||
+ (ICS.isUserDefined() &&
+ ICS.UserDefined.Before.DeprecatedStringLiteralToCharPtr);
+}
+
/// CompareImplicitConversionSequences - Compare two implicit
/// conversion sequences to determine whether one is better than the
/// other or if they are indistinguishable (C++ 13.3.3.2).
@@ -3315,6 +3319,32 @@ CompareImplicitConversionSequences(Sema &S,
// described in 13.3.3.2, the ambiguous conversion sequence is
// treated as a user-defined sequence that is indistinguishable
// from any other user-defined conversion sequence.
+
+ // String literal to 'char *' conversion has been deprecated in C++03. It has
+ // been removed from C++11. We still accept this conversion, if it happens at
+ // the best viable function. Otherwise, this conversion is considered worse
+ // than ellipsis conversion. Consider this as an extension; this is not in the
+ // standard. For example:
+ //
+ // int &f(...); // #1
+ // void f(char*); // #2
+ // void g() { int &r = f("foo"); }
+ //
+ // In C++03, we pick #2 as the best viable function.
+ // In C++11, we pick #1 as the best viable function, because ellipsis
+ // conversion is better than string-literal to char* conversion (since there
+ // is no such conversion in C++11). If there was no #1 at all or #1 couldn't
+ // convert arguments, #2 would be the best viable function in C++11.
+ // If the best viable function has this conversion, a warning will be issued
+ // in C++03, or an ExtWarn (+SFINAE failure) will be issued in C++11.
+
+ if (S.getLangOpts().CPlusPlus11 && !S.getLangOpts().WritableStrings &&
+ hasDeprecatedStringLiteralToCharPtrConversion(ICS1) !=
+ hasDeprecatedStringLiteralToCharPtrConversion(ICS2))
+ return hasDeprecatedStringLiteralToCharPtrConversion(ICS1)
+ ? ImplicitConversionSequence::Worse
+ : ImplicitConversionSequence::Better;
+
if (ICS1.getKindRank() < ICS2.getKindRank())
return ImplicitConversionSequence::Better;
if (ICS2.getKindRank() < ICS1.getKindRank())
@@ -3424,8 +3454,9 @@ compareStandardConversionSubsets(ASTContext &Context,
/// \brief Determine whether one of the given reference bindings is better
/// than the other based on what kind of bindings they are.
-static bool isBetterReferenceBindingKind(const StandardConversionSequence &SCS1,
- const StandardConversionSequence &SCS2) {
+static bool
+isBetterReferenceBindingKind(const StandardConversionSequence &SCS1,
+ const StandardConversionSequence &SCS2) {
// C++0x [over.ics.rank]p3b4:
// -- S1 and S2 are reference bindings (8.5.3) and neither refers to an
// implicit object parameter of a non-static member function declared
@@ -3446,7 +3477,7 @@ static bool isBetterReferenceBindingKind(const StandardConversionSequence &SCS1,
return (!SCS1.IsLvalueReference && SCS1.BindsToRvalue &&
SCS2.IsLvalueReference) ||
(SCS1.IsLvalueReference && SCS1.BindsToFunctionLvalue &&
- !SCS2.IsLvalueReference);
+ !SCS2.IsLvalueReference && SCS2.BindsToFunctionLvalue);
}
/// CompareStandardConversionSequences - Compare two standard
@@ -3613,11 +3644,10 @@ CompareStandardConversionSequences(Sema &S,
// }
// Here, MSVC will call f(int) instead of generating a compile error
// as clang will do in standard mode.
- if (S.getLangOpts().MicrosoftMode &&
- SCS1.Second == ICK_Integral_Conversion &&
- SCS2.Second == ICK_Floating_Integral &&
+ if (S.getLangOpts().MSVCCompat && SCS1.Second == ICK_Integral_Conversion &&
+ SCS2.Second == ICK_Floating_Integral &&
S.Context.getTypeSize(SCS1.getFromType()) ==
- S.Context.getTypeSize(SCS1.getToType(2)))
+ S.Context.getTypeSize(SCS1.getToType(2)))
return ImplicitConversionSequence::Better;
return ImplicitConversionSequence::Indistinguishable;
@@ -4035,7 +4065,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
CXXRecordDecl *T2RecordDecl
= dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
- OverloadCandidateSet CandidateSet(DeclLoc);
+ OverloadCandidateSet CandidateSet(DeclLoc, OverloadCandidateSet::CSK_Normal);
std::pair<CXXRecordDecl::conversion_iterator,
CXXRecordDecl::conversion_iterator>
Conversions = T2RecordDecl->getVisibleConversionFunctions();
@@ -4226,7 +4256,8 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
ICS.Standard.BindsToRvalue = false;
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
- ICS.Standard.CopyConstructor = 0;
+ ICS.Standard.CopyConstructor = nullptr;
+ ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
// Nothing more to do: the inaccessibility/ambiguity check for
// derived-to-base conversions is suppressed when we're
@@ -4294,13 +4325,14 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
// standard library implementors; therefore, we need the xvalue check here.
ICS.Standard.DirectBinding =
S.getLangOpts().CPlusPlus11 ||
- (InitCategory.isPRValue() && !T2->isRecordType());
+ !(InitCategory.isPRValue() || T2->isRecordType());
ICS.Standard.IsLvalueReference = !isRValRef;
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
ICS.Standard.BindsToRvalue = InitCategory.isRValue();
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
- ICS.Standard.CopyConstructor = 0;
+ ICS.Standard.CopyConstructor = nullptr;
+ ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
return ICS;
}
@@ -4330,6 +4362,10 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
return ICS;
}
+ // A temporary of function type cannot be created; don't even try.
+ if (T1->isFunctionType())
+ return ICS;
+
// -- Otherwise, a temporary of type "cv1 T1" is created and
// initialized from the initializer expression using the
// rules for a non-reference copy initialization (8.5). The
@@ -4391,28 +4427,34 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
if (ICS.isStandard()) {
ICS.Standard.ReferenceBinding = true;
ICS.Standard.IsLvalueReference = !isRValRef;
- ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
+ ICS.Standard.BindsToFunctionLvalue = false;
ICS.Standard.BindsToRvalue = true;
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
ICS.Standard.ObjCLifetimeConversionBinding = false;
} else if (ICS.isUserDefined()) {
- // Don't allow rvalue references to bind to lvalues.
- if (DeclType->isRValueReferenceType()) {
- if (const ReferenceType *RefType
- = ICS.UserDefined.ConversionFunction->getResultType()
- ->getAs<LValueReferenceType>()) {
- if (!RefType->getPointeeType()->isFunctionType()) {
- ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, Init,
- DeclType);
- return ICS;
- }
- }
+ const ReferenceType *LValRefType =
+ ICS.UserDefined.ConversionFunction->getReturnType()
+ ->getAs<LValueReferenceType>();
+
+ // C++ [over.ics.ref]p3:
+ // Except for an implicit object parameter, for which see 13.3.1, a
+ // standard conversion sequence cannot be formed if it requires [...]
+ // binding an rvalue reference to an lvalue other than a function
+ // lvalue.
+ // Note that the function case is not possible here.
+ if (DeclType->isRValueReferenceType() && LValRefType) {
+ // FIXME: This is the wrong BadConversionSequence. The problem is binding
+ // an rvalue reference to a (non-function) lvalue, not binding an lvalue
+ // reference to an rvalue!
+ ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, Init, DeclType);
+ return ICS;
}
-
+
+ ICS.UserDefined.Before.setAsIdentityConversion();
ICS.UserDefined.After.ReferenceBinding = true;
ICS.UserDefined.After.IsLvalueReference = !isRValRef;
- ICS.UserDefined.After.BindsToFunctionLvalue = T2->isFunctionType();
- ICS.UserDefined.After.BindsToRvalue = true;
+ ICS.UserDefined.After.BindsToFunctionLvalue = false;
+ ICS.UserDefined.After.BindsToRvalue = !LValRefType;
ICS.UserDefined.After.BindsImplicitObjectArgumentWithoutRefQualifier = false;
ICS.UserDefined.After.ObjCLifetimeConversionBinding = false;
}
@@ -4515,7 +4557,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
InitializedEntity Entity =
InitializedEntity::InitializeParameter(S.Context, ToType,
/*Consumed=*/false);
- if (S.CanPerformCopyInitialization(Entity, S.Owned(From))) {
+ if (S.CanPerformCopyInitialization(Entity, From)) {
Result.setUserDefined();
Result.UserDefined.Before.setAsIdentityConversion();
// Initializer lists don't have a type.
@@ -4525,7 +4567,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
Result.UserDefined.After.setAsIdentityConversion();
Result.UserDefined.After.setFromType(ToType);
Result.UserDefined.After.setAllToTypes(ToType);
- Result.UserDefined.ConversionFunction = 0;
+ Result.UserDefined.ConversionFunction = nullptr;
}
return Result;
}
@@ -4836,13 +4878,13 @@ Sema::PerformObjectArgumentInitialization(Expr *From,
PerformObjectMemberConversion(From, Qualifier, FoundDecl, Method);
if (FromRes.isInvalid())
return ExprError();
- From = FromRes.take();
+ From = FromRes.get();
}
if (!Context.hasSameType(From->getType(), DestType))
From = ImpCastExprToType(From, DestType, CK_NoOp,
- From->getValueKind()).take();
- return Owned(From);
+ From->getValueKind()).get();
+ return From;
}
/// TryContextuallyConvertToBool - Attempt to contextually convert the
@@ -4954,7 +4996,7 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
/*InOverloadResolution=*/false,
/*CStyle=*/false,
/*AllowObjcWritebackConversion=*/false);
- StandardConversionSequence *SCS = 0;
+ StandardConversionSequence *SCS = nullptr;
switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion:
if (!CheckConvertedConstantConversions(*this, ICS.Standard))
@@ -5124,7 +5166,7 @@ diagnoseAmbiguousConversion(Sema &SemaRef, SourceLocation Loc, Expr *From,
QualType ConvTy = Conv->getConversionType().getNonReferenceType();
Converter.noteAmbiguous(SemaRef, Conv, ConvTy);
}
- return SemaRef.Owned(From);
+ return From;
}
static bool
@@ -5147,7 +5189,7 @@ diagnoseNoViableConversion(Sema &SemaRef, SourceLocation Loc, Expr *&From,
<< FixItHint::CreateInsertion(From->getLocStart(),
"static_cast<" + TypeStr + ">(")
<< FixItHint::CreateInsertion(
- SemaRef.PP.getLocForEndOfToken(From->getLocEnd()), ")");
+ SemaRef.getLocForEndOfToken(From->getLocEnd()), ")");
Converter.noteExplicitConv(SemaRef, Conversion, ConvTy);
// If we aren't in a SFINAE context, build a call to the
@@ -5155,15 +5197,15 @@ diagnoseNoViableConversion(Sema &SemaRef, SourceLocation Loc, Expr *&From,
if (SemaRef.isSFINAEContext())
return true;
- SemaRef.CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);
+ SemaRef.CheckMemberOperatorAccess(From->getExprLoc(), From, nullptr, Found);
ExprResult Result = SemaRef.BuildCXXMemberCallExpr(From, Found, Conversion,
HadMultipleCandidates);
if (Result.isInvalid())
return true;
// Record usage of conversion in an implicit cast.
From = ImplicitCastExpr::Create(SemaRef.Context, Result.get()->getType(),
- CK_UserDefinedConversion, Result.get(), 0,
- Result.get()->getValueKind());
+ CK_UserDefinedConversion, Result.get(),
+ nullptr, Result.get()->getValueKind());
}
return false;
}
@@ -5174,7 +5216,7 @@ static bool recordConversion(Sema &SemaRef, SourceLocation Loc, Expr *&From,
DeclAccessPair &Found) {
CXXConversionDecl *Conversion =
cast<CXXConversionDecl>(Found->getUnderlyingDecl());
- SemaRef.CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);
+ SemaRef.CheckMemberOperatorAccess(From->getExprLoc(), From, nullptr, Found);
QualType ToType = Conversion->getConversionType().getNonReferenceType();
if (!Converter.SuppressConversion) {
@@ -5191,8 +5233,8 @@ static bool recordConversion(Sema &SemaRef, SourceLocation Loc, Expr *&From,
return true;
// Record usage of conversion in an implicit cast.
From = ImplicitCastExpr::Create(SemaRef.Context, Result.get()->getType(),
- CK_UserDefinedConversion, Result.get(), 0,
- Result.get()->getValueKind());
+ CK_UserDefinedConversion, Result.get(),
+ nullptr, Result.get()->getValueKind());
return false;
}
@@ -5257,14 +5299,14 @@ ExprResult Sema::PerformContextualImplicitConversion(
SourceLocation Loc, Expr *From, ContextualImplicitConverter &Converter) {
// We can't perform any more checking for type-dependent expressions.
if (From->isTypeDependent())
- return Owned(From);
+ return From;
// Process placeholders immediately.
if (From->hasPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(From);
if (result.isInvalid())
return result;
- From = result.take();
+ From = result.get();
}
// If the expression already has a matching type, we're golden.
@@ -5280,7 +5322,7 @@ ExprResult Sema::PerformContextualImplicitConversion(
if (!RecordTy || !getLangOpts().CPlusPlus) {
if (!Converter.Suppress)
Converter.diagnoseNoMatch(*this, Loc, T) << From->getSourceRange();
- return Owned(From);
+ return From;
}
// We must have a complete class type.
@@ -5291,13 +5333,13 @@ ExprResult Sema::PerformContextualImplicitConversion(
TypeDiagnoserPartialDiag(ContextualImplicitConverter &Converter, Expr *From)
: TypeDiagnoser(Converter.Suppress), Converter(Converter), From(From) {}
- virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) {
+ void diagnose(Sema &S, SourceLocation Loc, QualType T) override {
Converter.diagnoseIncomplete(S, Loc, T) << From->getSourceRange();
}
} IncompleteDiagnoser(Converter, From);
if (RequireCompleteType(Loc, T, IncompleteDiagnoser))
- return Owned(From);
+ return From;
// Look for a conversion to an integral or enumeration type.
UnresolvedSet<4>
@@ -5381,7 +5423,7 @@ ExprResult Sema::PerformContextualImplicitConversion(
// If one unique T is found:
// First, build a candidate set from the previously recorded
// potentially viable conversions.
- OverloadCandidateSet CandidateSet(Loc);
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
collectViableConversionCandidates(*this, From, ToType, ViableConversions,
CandidateSet);
@@ -5438,6 +5480,45 @@ ExprResult Sema::PerformContextualImplicitConversion(
return finishContextualImplicitConversion(*this, Loc, From, Converter);
}
+/// IsAcceptableNonMemberOperatorCandidate - Determine whether Fn is
+/// an acceptable non-member overloaded operator for a call whose
+/// arguments have types T1 (and, if non-empty, T2). This routine
+/// implements the check in C++ [over.match.oper]p3b2 concerning
+/// enumeration types.
+static bool IsAcceptableNonMemberOperatorCandidate(ASTContext &Context,
+ FunctionDecl *Fn,
+ ArrayRef<Expr *> Args) {
+ QualType T1 = Args[0]->getType();
+ QualType T2 = Args.size() > 1 ? Args[1]->getType() : QualType();
+
+ if (T1->isDependentType() || (!T2.isNull() && T2->isDependentType()))
+ return true;
+
+ if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType()))
+ return true;
+
+ const FunctionProtoType *Proto = Fn->getType()->getAs<FunctionProtoType>();
+ if (Proto->getNumParams() < 1)
+ return false;
+
+ if (T1->isEnumeralType()) {
+ QualType ArgType = Proto->getParamType(0).getNonReferenceType();
+ if (Context.hasSameUnqualifiedType(T1, ArgType))
+ return true;
+ }
+
+ if (Proto->getNumParams() < 2)
+ return false;
+
+ if (!T2.isNull() && T2->isEnumeralType()) {
+ QualType ArgType = Proto->getParamType(1).getNonReferenceType();
+ if (Context.hasSameUnqualifiedType(T2, ArgType))
+ return true;
+ }
+
+ return false;
+}
+
/// AddOverloadCandidate - Adds the given function to the set of
/// candidate functions, using the given function call arguments. If
/// @p SuppressUserConversions, then don't allow user-defined
@@ -5450,11 +5531,11 @@ void
Sema::AddOverloadCandidate(FunctionDecl *Function,
DeclAccessPair FoundDecl,
ArrayRef<Expr *> Args,
- OverloadCandidateSet& CandidateSet,
+ OverloadCandidateSet &CandidateSet,
bool SuppressUserConversions,
bool PartialOverloading,
bool AllowExplicit) {
- const FunctionProtoType* Proto
+ const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
assert(Proto && "Functions without a prototype cannot be overloaded");
assert(!Function->getDescribedFunctionTemplate() &&
@@ -5481,6 +5562,17 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
if (!CandidateSet.isNewCandidate(Function))
return;
+ // C++ [over.match.oper]p3:
+ // if no operand has a class type, only those non-member functions in the
+ // lookup set that have a first parameter of type T1 or "reference to
+ // (possibly cv-qualified) T1", when T1 is an enumeration type, or (if there
+ // is a right operand) a second parameter of type T2 or "reference to
+ // (possibly cv-qualified) T2", when T2 is an enumeration type, are
+ // candidate functions.
+ if (CandidateSet.getKind() == OverloadCandidateSet::CSK_Operator &&
+ !IsAcceptableNonMemberOperatorCandidate(Context, Function, Args))
+ return;
+
// C++11 [class.copy]p11: [DR1402]
// A defaulted move constructor that is defined as deleted is ignored by
// overload resolution.
@@ -5513,12 +5605,12 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
Candidate.IgnoreObjectArgument = false;
Candidate.ExplicitCallArguments = Args.size();
- unsigned NumArgsInProto = Proto->getNumArgs();
+ unsigned NumParams = Proto->getNumParams();
// (C++ 13.3.2p2): A candidate function having fewer than m
// parameters is viable only if it has an ellipsis in its parameter
// list (8.3.5).
- if ((Args.size() + (PartialOverloading && Args.size())) > NumArgsInProto &&
+ if ((Args.size() + (PartialOverloading && Args.size())) > NumParams &&
!Proto->isVariadic()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_many_arguments;
@@ -5550,12 +5642,12 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// Determine the implicit conversion sequences for each of the
// arguments.
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
- if (ArgIdx < NumArgsInProto) {
+ if (ArgIdx < NumParams) {
// (C++ 13.3.2p3): for F to be a viable function, there shall
// exist for each argument an implicit conversion sequence
// (13.3.3.1) that converts that argument to the corresponding
// parameter of F.
- QualType ParamType = Proto->getArgType(ArgIdx);
+ QualType ParamType = Proto->getParamType(ArgIdx);
Candidate.Conversions[ArgIdx]
= TryCopyInitialization(*this, Args[ArgIdx], ParamType,
SuppressUserConversions,
@@ -5566,7 +5658,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
if (Candidate.Conversions[ArgIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
- break;
+ return;
}
} else {
// (C++ 13.3.2p2): For the purposes of overload resolution, any
@@ -5575,6 +5667,78 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
Candidate.Conversions[ArgIdx].setEllipsis();
}
}
+
+ if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_enable_if;
+ Candidate.DeductionFailure.Data = FailedAttr;
+ return;
+ }
+}
+
+static bool IsNotEnableIfAttr(Attr *A) { return !isa<EnableIfAttr>(A); }
+
+EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
+ bool MissingImplicitThis) {
+ // FIXME: specific_attr_iterator<EnableIfAttr> iterates in reverse order, but
+ // we need to find the first failing one.
+ if (!Function->hasAttrs())
+ return nullptr;
+ AttrVec Attrs = Function->getAttrs();
+ AttrVec::iterator E = std::remove_if(Attrs.begin(), Attrs.end(),
+ IsNotEnableIfAttr);
+ if (Attrs.begin() == E)
+ return nullptr;
+ std::reverse(Attrs.begin(), E);
+
+ SFINAETrap Trap(*this);
+
+ // Convert the arguments.
+ SmallVector<Expr *, 16> ConvertedArgs;
+ bool InitializationFailed = false;
+ for (unsigned i = 0, e = Args.size(); i != e; ++i) {
+ if (i == 0 && !MissingImplicitThis && isa<CXXMethodDecl>(Function) &&
+ !cast<CXXMethodDecl>(Function)->isStatic() &&
+ !isa<CXXConstructorDecl>(Function)) {
+ CXXMethodDecl *Method = cast<CXXMethodDecl>(Function);
+ ExprResult R =
+ PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/nullptr,
+ Method, Method);
+ if (R.isInvalid()) {
+ InitializationFailed = true;
+ break;
+ }
+ ConvertedArgs.push_back(R.get());
+ } else {
+ ExprResult R =
+ PerformCopyInitialization(InitializedEntity::InitializeParameter(
+ Context,
+ Function->getParamDecl(i)),
+ SourceLocation(),
+ Args[i]);
+ if (R.isInvalid()) {
+ InitializationFailed = true;
+ break;
+ }
+ ConvertedArgs.push_back(R.get());
+ }
+ }
+
+ if (InitializationFailed || Trap.hasErrorOccurred())
+ return cast<EnableIfAttr>(Attrs[0]);
+
+ for (AttrVec::iterator I = Attrs.begin(); I != E; ++I) {
+ APValue Result;
+ EnableIfAttr *EIA = cast<EnableIfAttr>(*I);
+ if (!EIA->getCond()->EvaluateWithSubstitution(
+ Result, Context, Function,
+ ArrayRef<const Expr*>(ConvertedArgs.data(),
+ ConvertedArgs.size())) ||
+ !Result.isInt() || !Result.getInt().getBoolValue()) {
+ return EIA;
+ }
+ }
+ return nullptr;
}
/// \brief Add all of the function declarations in the given function set to
@@ -5632,7 +5796,7 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) &&
"Expected a member function template");
AddMethodTemplateCandidate(TD, FoundDecl, ActingContext,
- /*ExplicitArgs*/ 0,
+ /*ExplicitArgs*/ nullptr,
ObjectType, ObjectClassification,
Args, CandidateSet,
SuppressUserConversions);
@@ -5656,9 +5820,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr::Classification ObjectClassification,
ArrayRef<Expr *> Args,
- OverloadCandidateSet& CandidateSet,
+ OverloadCandidateSet &CandidateSet,
bool SuppressUserConversions) {
- const FunctionProtoType* Proto
+ const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
assert(Proto && "Methods without a prototype cannot be overloaded");
assert(!isa<CXXConstructorDecl>(Method) &&
@@ -5685,12 +5849,12 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
Candidate.IgnoreObjectArgument = false;
Candidate.ExplicitCallArguments = Args.size();
- unsigned NumArgsInProto = Proto->getNumArgs();
+ unsigned NumParams = Proto->getNumParams();
// (C++ 13.3.2p2): A candidate function having fewer than m
// parameters is viable only if it has an ellipsis in its parameter
// list (8.3.5).
- if (Args.size() > NumArgsInProto && !Proto->isVariadic()) {
+ if (Args.size() > NumParams && !Proto->isVariadic()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
@@ -5730,12 +5894,12 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// Determine the implicit conversion sequences for each of the
// arguments.
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
- if (ArgIdx < NumArgsInProto) {
+ if (ArgIdx < NumParams) {
// (C++ 13.3.2p3): for F to be a viable function, there shall
// exist for each argument an implicit conversion sequence
// (13.3.3.1) that converts that argument to the corresponding
// parameter of F.
- QualType ParamType = Proto->getArgType(ArgIdx);
+ QualType ParamType = Proto->getParamType(ArgIdx);
Candidate.Conversions[ArgIdx + 1]
= TryCopyInitialization(*this, Args[ArgIdx], ParamType,
SuppressUserConversions,
@@ -5745,15 +5909,22 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
- break;
+ return;
}
} else {
// (C++ 13.3.2p2): For the purposes of overload resolution, any
// argument for which there is no corresponding parameter is
- // considered to ""match the ellipsis" (C+ 13.3.3.1.3).
+ // considered to "match the ellipsis" (C+ 13.3.3.1.3).
Candidate.Conversions[ArgIdx + 1].setEllipsis();
}
}
+
+ if (EnableIfAttr *FailedAttr = CheckEnableIf(Method, Args, true)) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_enable_if;
+ Candidate.DeductionFailure.Data = FailedAttr;
+ return;
+ }
}
/// \brief Add a C++ member function template as a candidate to the candidate
@@ -5782,7 +5953,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
// function template are combined with the set of non-template candidate
// functions.
TemplateDeductionInfo Info(CandidateSet.getLocation());
- FunctionDecl *Specialization = 0;
+ FunctionDecl *Specialization = nullptr;
if (TemplateDeductionResult Result
= DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs, Args,
Specialization, Info)) {
@@ -5832,7 +6003,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
// function template are combined with the set of non-template candidate
// functions.
TemplateDeductionInfo Info(CandidateSet.getLocation());
- FunctionDecl *Specialization = 0;
+ FunctionDecl *Specialization = nullptr;
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, Args,
Specialization, Info)) {
@@ -5969,7 +6140,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
return;
}
- // We won't go through a user-define type conversion function to convert a
+ // We won't go through a user-defined type conversion function to convert a
// derived to base as such conversions are given Conversion Rank. They only
// go through a copy constructor. 13.3.3.1.2-p4 [over.ics.user]
QualType FromCanon
@@ -6029,6 +6200,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
GetConversionRank(ICS.Standard.Second) != ICR_Exact_Match) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_final_conversion_not_exact;
+ return;
}
// C++0x [dcl.init.ref]p5:
@@ -6040,18 +6212,26 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
ICS.Standard.First == ICK_Lvalue_To_Rvalue) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_final_conversion;
+ return;
}
break;
case ImplicitConversionSequence::BadConversion:
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_final_conversion;
- break;
+ return;
default:
llvm_unreachable(
"Can only end up with a standard conversion sequence or failure");
}
+
+ if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, ArrayRef<Expr*>())) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_enable_if;
+ Candidate.DeductionFailure.Data = FailedAttr;
+ return;
+ }
}
/// \brief Adds a conversion function template specialization
@@ -6073,7 +6253,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
return;
TemplateDeductionInfo Info(CandidateSet.getLocation());
- CXXConversionDecl *Specialization = 0;
+ CXXConversionDecl *Specialization = nullptr;
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, ToType,
Specialization, Info)) {
@@ -6117,7 +6297,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size() + 1);
Candidate.FoundDecl = FoundDecl;
- Candidate.Function = 0;
+ Candidate.Function = nullptr;
Candidate.Surrogate = Conversion;
Candidate.Viable = true;
Candidate.IsSurrogate = true;
@@ -6151,12 +6331,12 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
Candidate.Conversions[0].UserDefined.After.setAsIdentityConversion();
// Find the
- unsigned NumArgsInProto = Proto->getNumArgs();
+ unsigned NumParams = Proto->getNumParams();
// (C++ 13.3.2p2): A candidate function having fewer than m
// parameters is viable only if it has an ellipsis in its parameter
// list (8.3.5).
- if (Args.size() > NumArgsInProto && !Proto->isVariadic()) {
+ if (Args.size() > NumParams && !Proto->isVariadic()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
@@ -6164,7 +6344,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// Function types don't have any default arguments, so just check if
// we have enough arguments.
- if (Args.size() < NumArgsInProto) {
+ if (Args.size() < NumParams) {
// Not enough arguments.
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_few_arguments;
@@ -6174,12 +6354,12 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// Determine the implicit conversion sequences for each of the
// arguments.
for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) {
- if (ArgIdx < NumArgsInProto) {
+ if (ArgIdx < NumParams) {
// (C++ 13.3.2p3): for F to be a viable function, there shall
// exist for each argument an implicit conversion sequence
// (13.3.3.1) that converts that argument to the corresponding
// parameter of F.
- QualType ParamType = Proto->getArgType(ArgIdx);
+ QualType ParamType = Proto->getParamType(ArgIdx);
Candidate.Conversions[ArgIdx + 1]
= TryCopyInitialization(*this, Args[ArgIdx], ParamType,
/*SuppressUserConversions=*/false,
@@ -6189,7 +6369,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
- break;
+ return;
}
} else {
// (C++ 13.3.2p2): For the purposes of overload resolution, any
@@ -6198,6 +6378,13 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
Candidate.Conversions[ArgIdx + 1].setEllipsis();
}
}
+
+ if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, ArrayRef<Expr*>())) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_enable_if;
+ Candidate.DeductionFailure.Data = FailedAttr;
+ return;
+ }
}
/// \brief Add overload candidates for overloaded operators that are
@@ -6270,8 +6457,8 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
// Add this candidate
OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size());
- Candidate.FoundDecl = DeclAccessPair::make(0, AS_none);
- Candidate.Function = 0;
+ Candidate.FoundDecl = DeclAccessPair::make(nullptr, AS_none);
+ Candidate.Function = nullptr;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.BuiltinTypes.ResultTy = ResultTy;
@@ -7951,7 +8138,7 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
/// candidate set (C++ [basic.lookup.argdep]).
void
Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
- bool Operator, SourceLocation Loc,
+ SourceLocation Loc,
ArrayRef<Expr *> Args,
TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
@@ -7966,7 +8153,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
// we supposed to consider on ADL candidates, anyway?
// FIXME: Pass in the explicit template arguments?
- ArgumentDependentLookup(Name, Operator, Loc, Args, Fns);
+ ArgumentDependentLookup(Name, Loc, Args, Fns);
// Erase all of the candidates we already knew about.
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
@@ -8051,18 +8238,48 @@ isBetterOverloadCandidate(Sema &S,
if (HasBetterConversion)
return true;
- // - F1 is a non-template function and F2 is a function template
+ // -- the context is an initialization by user-defined conversion
+ // (see 8.5, 13.3.1.5) and the standard conversion sequence
+ // from the return type of F1 to the destination type (i.e.,
+ // the type of the entity being initialized) is a better
+ // conversion sequence than the standard conversion sequence
+ // from the return type of F2 to the destination type.
+ if (UserDefinedConversion && Cand1.Function && Cand2.Function &&
+ isa<CXXConversionDecl>(Cand1.Function) &&
+ isa<CXXConversionDecl>(Cand2.Function)) {
+ // First check whether we prefer one of the conversion functions over the
+ // other. This only distinguishes the results in non-standard, extension
+ // cases such as the conversion from a lambda closure type to a function
+ // pointer or block.
+ ImplicitConversionSequence::CompareKind Result =
+ compareConversionFunctions(S, Cand1.Function, Cand2.Function);
+ if (Result == ImplicitConversionSequence::Indistinguishable)
+ Result = CompareStandardConversionSequences(S,
+ Cand1.FinalConversion,
+ Cand2.FinalConversion);
+
+ if (Result != ImplicitConversionSequence::Indistinguishable)
+ return Result == ImplicitConversionSequence::Better;
+
+ // FIXME: Compare kind of reference binding if conversion functions
+ // convert to a reference type used in direct reference binding, per
+ // C++14 [over.match.best]p1 section 2 bullet 3.
+ }
+
+ // -- F1 is a non-template function and F2 is a function template
// specialization, or, if not that,
- if ((!Cand1.Function || !Cand1.Function->getPrimaryTemplate()) &&
- Cand2.Function && Cand2.Function->getPrimaryTemplate())
- return true;
+ bool Cand1IsSpecialization = Cand1.Function &&
+ Cand1.Function->getPrimaryTemplate();
+ bool Cand2IsSpecialization = Cand2.Function &&
+ Cand2.Function->getPrimaryTemplate();
+ if (Cand1IsSpecialization != Cand2IsSpecialization)
+ return Cand2IsSpecialization;
// -- F1 and F2 are function template specializations, and the function
// template for F1 is more specialized than the template for F2
// according to the partial ordering rules described in 14.5.5.2, or,
// if not that,
- if (Cand1.Function && Cand1.Function->getPrimaryTemplate() &&
- Cand2.Function && Cand2.Function->getPrimaryTemplate()) {
+ if (Cand1IsSpecialization && Cand2IsSpecialization) {
if (FunctionTemplateDecl *BetterTemplate
= S.getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(),
Cand2.Function->getPrimaryTemplate(),
@@ -8074,39 +8291,49 @@ isBetterOverloadCandidate(Sema &S,
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
}
- // -- the context is an initialization by user-defined conversion
- // (see 8.5, 13.3.1.5) and the standard conversion sequence
- // from the return type of F1 to the destination type (i.e.,
- // the type of the entity being initialized) is a better
- // conversion sequence than the standard conversion sequence
- // from the return type of F2 to the destination type.
- if (UserDefinedConversion && Cand1.Function && Cand2.Function &&
- isa<CXXConversionDecl>(Cand1.Function) &&
- isa<CXXConversionDecl>(Cand2.Function)) {
- // First check whether we prefer one of the conversion functions over the
- // other. This only distinguishes the results in non-standard, extension
- // cases such as the conversion from a lambda closure type to a function
- // pointer or block.
- ImplicitConversionSequence::CompareKind FuncResult
- = compareConversionFunctions(S, Cand1.Function, Cand2.Function);
- if (FuncResult != ImplicitConversionSequence::Indistinguishable)
- return FuncResult;
-
- switch (CompareStandardConversionSequences(S,
- Cand1.FinalConversion,
- Cand2.FinalConversion)) {
- case ImplicitConversionSequence::Better:
- // Cand1 has a better conversion sequence.
- return true;
-
- case ImplicitConversionSequence::Worse:
- // Cand1 can't be better than Cand2.
+ // Check for enable_if value-based overload resolution.
+ if (Cand1.Function && Cand2.Function &&
+ (Cand1.Function->hasAttr<EnableIfAttr>() ||
+ Cand2.Function->hasAttr<EnableIfAttr>())) {
+ // FIXME: The next several lines are just
+ // specific_attr_iterator<EnableIfAttr> but going in declaration order,
+ // instead of reverse order which is how they're stored in the AST.
+ AttrVec Cand1Attrs;
+ if (Cand1.Function->hasAttrs()) {
+ Cand1Attrs = Cand1.Function->getAttrs();
+ Cand1Attrs.erase(std::remove_if(Cand1Attrs.begin(), Cand1Attrs.end(),
+ IsNotEnableIfAttr),
+ Cand1Attrs.end());
+ std::reverse(Cand1Attrs.begin(), Cand1Attrs.end());
+ }
+
+ AttrVec Cand2Attrs;
+ if (Cand2.Function->hasAttrs()) {
+ Cand2Attrs = Cand2.Function->getAttrs();
+ Cand2Attrs.erase(std::remove_if(Cand2Attrs.begin(), Cand2Attrs.end(),
+ IsNotEnableIfAttr),
+ Cand2Attrs.end());
+ std::reverse(Cand2Attrs.begin(), Cand2Attrs.end());
+ }
+
+ // Candidate 1 is better if it has strictly more attributes and
+ // the common sequence is identical.
+ if (Cand1Attrs.size() <= Cand2Attrs.size())
return false;
- case ImplicitConversionSequence::Indistinguishable:
- // Do nothing
- break;
+ auto Cand1I = Cand1Attrs.begin();
+ for (auto &Cand2A : Cand2Attrs) {
+ auto &Cand1A = *Cand1I++;
+ llvm::FoldingSetNodeID Cand1ID, Cand2ID;
+ cast<EnableIfAttr>(Cand1A)->getCond()->Profile(Cand1ID,
+ S.getASTContext(), true);
+ cast<EnableIfAttr>(Cand2A)->getCond()->Profile(Cand2ID,
+ S.getASTContext(), true);
+ if (Cand1ID != Cand2ID)
+ return false;
}
+
+ return true;
}
return false;
@@ -8557,18 +8784,18 @@ void DiagnoseArityMismatch(Sema &S, Decl *D, unsigned NumFormalArgs) {
// at least / at most / exactly
unsigned mode, modeCount;
if (NumFormalArgs < MinParams) {
- if (MinParams != FnTy->getNumArgs() ||
- FnTy->isVariadic() || FnTy->isTemplateVariadic())
+ if (MinParams != FnTy->getNumParams() || FnTy->isVariadic() ||
+ FnTy->isTemplateVariadic())
mode = 0; // "at least"
else
mode = 2; // "exactly"
modeCount = MinParams;
} else {
- if (MinParams != FnTy->getNumArgs())
+ if (MinParams != FnTy->getNumParams())
mode = 1; // "at most"
else
mode = 2; // "exactly"
- modeCount = FnTy->getNumArgs();
+ modeCount = FnTy->getNumParams();
}
std::string Description;
@@ -8576,12 +8803,12 @@ void DiagnoseArityMismatch(Sema &S, Decl *D, unsigned NumFormalArgs) {
if (modeCount == 1 && Fn->getParamDecl(0)->getDeclName())
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity_one)
- << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode
- << Fn->getParamDecl(0) << NumFormalArgs;
+ << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != nullptr)
+ << mode << Fn->getParamDecl(0) << NumFormalArgs;
else
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity)
- << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != 0) << mode
- << modeCount << NumFormalArgs;
+ << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != nullptr)
+ << mode << modeCount << NumFormalArgs;
MaybeEmitInheritedConstructorNote(S, Fn);
}
@@ -8817,6 +9044,15 @@ void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) {
<< (unsigned) FnKind << CalleeTarget << CallerTarget;
}
+void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) {
+ FunctionDecl *Callee = Cand->Function;
+ EnableIfAttr *Attr = static_cast<EnableIfAttr*>(Cand->DeductionFailure.Data);
+
+ S.Diag(Callee->getLocation(),
+ diag::note_ovl_candidate_disabled_by_enable_if_attr)
+ << Attr->getCond()->getSourceRange() << Attr->getMessage();
+}
+
/// Generates a 'note' diagnostic for an overload candidate. We've
/// already generated a primary error at the call site.
///
@@ -8880,6 +9116,9 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_bad_target:
return DiagnoseBadTarget(S, Cand);
+
+ case ovl_fail_enable_if:
+ return DiagnoseFailedEnableIfAttr(S, Cand);
}
}
@@ -8991,7 +9230,10 @@ static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) {
struct CompareOverloadCandidatesForDisplay {
Sema &S;
- CompareOverloadCandidatesForDisplay(Sema &S) : S(S) {}
+ size_t NumArgs;
+
+ CompareOverloadCandidatesForDisplay(Sema &S, size_t nArgs)
+ : S(S), NumArgs(nArgs) {}
bool operator()(const OverloadCandidate *L,
const OverloadCandidate *R) {
@@ -9016,8 +9258,24 @@ struct CompareOverloadCandidatesForDisplay {
if (!L->Viable) {
// 1. Arity mismatches come after other candidates.
if (L->FailureKind == ovl_fail_too_many_arguments ||
- L->FailureKind == ovl_fail_too_few_arguments)
+ L->FailureKind == ovl_fail_too_few_arguments) {
+ if (R->FailureKind == ovl_fail_too_many_arguments ||
+ R->FailureKind == ovl_fail_too_few_arguments) {
+ int LDist = std::abs((int)L->getNumParams() - (int)NumArgs);
+ int RDist = std::abs((int)R->getNumParams() - (int)NumArgs);
+ if (LDist == RDist) {
+ if (L->FailureKind == R->FailureKind)
+ // Sort non-surrogates before surrogates.
+ return !L->IsSurrogate && R->IsSurrogate;
+ // Sort candidates requiring fewer parameters than there were
+ // arguments given after candidates requiring more parameters
+ // than there were arguments given.
+ return L->FailureKind == ovl_fail_too_many_arguments;
+ }
+ return LDist < RDist;
+ }
return false;
+ }
if (R->FailureKind == ovl_fail_too_many_arguments ||
R->FailureKind == ovl_fail_too_few_arguments)
return true;
@@ -9160,15 +9418,14 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
}
// Fill in the rest of the conversions.
- unsigned NumArgsInProto = Proto->getNumArgs();
+ unsigned NumParams = Proto->getNumParams();
for (; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) {
- if (ArgIdx < NumArgsInProto) {
- Cand->Conversions[ConvIdx]
- = TryCopyInitialization(S, Args[ArgIdx], Proto->getArgType(ArgIdx),
- SuppressUserConversions,
- /*InOverloadResolution=*/true,
- /*AllowObjCWritebackConversion=*/
- S.getLangOpts().ObjCAutoRefCount);
+ if (ArgIdx < NumParams) {
+ Cand->Conversions[ConvIdx] = TryCopyInitialization(
+ S, Args[ArgIdx], Proto->getParamType(ArgIdx), SuppressUserConversions,
+ /*InOverloadResolution=*/true,
+ /*AllowObjCWritebackConversion=*/
+ S.getLangOpts().ObjCAutoRefCount);
// Store the FixIt in the candidate if it exists.
if (!Unfixable && Cand->Conversions[ConvIdx].isBad())
Unfixable = !Cand->TryToFixBadConversion(ConvIdx, S);
@@ -9205,7 +9462,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S,
}
std::sort(Cands.begin(), Cands.end(),
- CompareOverloadCandidatesForDisplay(S));
+ CompareOverloadCandidatesForDisplay(S, Args.size()));
bool ReportedAmbiguousConversions = false;
@@ -9320,7 +9577,7 @@ void TemplateSpecCandidateSet::NoteCandidates(Sema &S, SourceLocation Loc) {
for (iterator Cand = begin(), LastCand = end(); Cand != LastCand; ++Cand) {
if (Cand->Specialization)
Cands.push_back(Cand);
- // Otherwise, this is a non matching builtin candidate. We do not,
+ // Otherwise, this is a non-matching builtin candidate. We do not,
// in general, want to list every possible builtin candidate.
}
@@ -9486,7 +9743,7 @@ private:
// resulting template argument list is used to generate a single
// function template specialization, which is added to the set of
// overloaded functions considered.
- FunctionDecl *Specialization = 0;
+ FunctionDecl *Specialization = nullptr;
TemplateDeductionInfo Info(FailedCandidates.getLocation());
if (Sema::TemplateDeductionResult Result
= S.DeduceTemplateArguments(FunctionTemplate,
@@ -9531,7 +9788,7 @@ private:
// If any candidate has a placeholder return type, trigger its deduction
// now.
if (S.getLangOpts().CPlusPlus1y &&
- FunDecl->getResultType()->isUndeducedType() &&
+ FunDecl->getReturnType()->isUndeducedType() &&
S.DeduceReturnType(FunDecl, SourceExpr->getLocStart(), Complain))
return false;
@@ -9622,7 +9879,7 @@ private:
// [...] any function template specializations in the set are
// eliminated if the set also contains a non-template function, [...]
for (unsigned I = 0, N = Matches.size(); I != N; ) {
- if (Matches[I].second->getPrimaryTemplate() == 0)
+ if (Matches[I].second->getPrimaryTemplate() == nullptr)
++I;
else {
Matches[I] = Matches[--N];
@@ -9694,12 +9951,12 @@ public:
int getNumMatches() const { return Matches.size(); }
FunctionDecl* getMatchingFunctionDecl() const {
- if (Matches.size() != 1) return 0;
+ if (Matches.size() != 1) return nullptr;
return Matches[0].second;
}
const DeclAccessPair* getMatchingFunctionAccessPair() const {
- if (Matches.size() != 1) return 0;
+ if (Matches.size() != 1) return nullptr;
return &Matches[0].first;
}
};
@@ -9730,7 +9987,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr,
AddressOfFunctionResolver Resolver(*this, AddressOfExpr, TargetType,
Complain);
int NumMatches = Resolver.getNumMatches();
- FunctionDecl* Fn = 0;
+ FunctionDecl *Fn = nullptr;
if (NumMatches == 0 && Complain) {
if (Resolver.IsInvalidFormOfPointerToMemberFunction())
Resolver.ComplainIsInvalidFormOfPointerToMemberFunction();
@@ -9779,7 +10036,7 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
// If we didn't actually find any template-ids, we're done.
if (!ovl->hasExplicitTemplateArgs())
- return 0;
+ return nullptr;
TemplateArgumentListInfo ExplicitTemplateArgs;
ovl->getExplicitTemplateArgs().copyInto(ExplicitTemplateArgs);
@@ -9787,7 +10044,7 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
// Look through all of the overloaded functions, searching for one
// whose type matches exactly.
- FunctionDecl *Matched = 0;
+ FunctionDecl *Matched = nullptr;
for (UnresolvedSetIterator I = ovl->decls_begin(),
E = ovl->decls_end(); I != E; ++I) {
// C++0x [temp.arg.explicit]p3:
@@ -9805,7 +10062,7 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
// resulting template argument list is used to generate a single
// function template specialization, which is added to the set of
// overloaded functions considered.
- FunctionDecl *Specialization = 0;
+ FunctionDecl *Specialization = nullptr;
TemplateDeductionInfo Info(FailedCandidates.getLocation());
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs,
@@ -9828,7 +10085,7 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
<< ovl->getName();
NoteAllOverloadCandidates(ovl);
}
- return 0;
+ return nullptr;
}
Matched = Specialization;
@@ -9836,9 +10093,9 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
}
if (Matched && getLangOpts().CPlusPlus1y &&
- Matched->getResultType()->isUndeducedType() &&
+ Matched->getReturnType()->isUndeducedType() &&
DeduceReturnType(Matched, ovl->getExprLoc(), Complain))
- return 0;
+ return nullptr;
return Matched;
}
@@ -9896,12 +10153,12 @@ bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
// Fix the expression to refer to 'fn'.
SingleFunctionExpression =
- Owned(FixOverloadedFunctionReference(SrcExpr.take(), found, fn));
+ FixOverloadedFunctionReference(SrcExpr.get(), found, fn);
// If desired, do function-to-pointer decay.
if (doFunctionPointerConverion) {
SingleFunctionExpression =
- DefaultFunctionArrayLvalueConversion(SingleFunctionExpression.take());
+ DefaultFunctionArrayLvalueConversion(SingleFunctionExpression.get());
if (SingleFunctionExpression.isInvalid()) {
SrcExpr = ExprError();
return true;
@@ -9999,7 +10256,7 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
// It would be nice to avoid this copy.
TemplateArgumentListInfo TABuffer;
- TemplateArgumentListInfo *ExplicitTemplateArgs = 0;
+ TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr;
if (ULE->hasExplicitTemplateArgs()) {
ULE->copyTemplateArgumentsInto(TABuffer);
ExplicitTemplateArgs = &TABuffer;
@@ -10012,8 +10269,7 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
/*KnownValid*/ true);
if (ULE->requiresADL())
- AddArgumentDependentLookupCandidates(ULE->getName(), /*Operator*/ false,
- ULE->getExprLoc(),
+ AddArgumentDependentLookupCandidates(ULE->getName(), ULE->getExprLoc(),
Args, ExplicitTemplateArgs,
CandidateSet, PartialOverloading);
}
@@ -10040,6 +10296,7 @@ static bool canBeDeclaredInNamespace(const DeclarationName &Name) {
static bool
DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
const CXXScopeSpec &SS, LookupResult &R,
+ OverloadCandidateSet::CandidateSetKind CSK,
TemplateArgumentListInfo *ExplicitTemplateArgs,
ArrayRef<Expr *> Args) {
if (SemaRef.ActiveTemplateInstantiations.empty() || !SS.isEmpty())
@@ -10061,7 +10318,7 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
return false;
}
- OverloadCandidateSet Candidates(FnLoc);
+ OverloadCandidateSet Candidates(FnLoc, CSK);
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
AddOverloadedCallCandidate(SemaRef, I.getPair(),
ExplicitTemplateArgs, Args,
@@ -10145,7 +10402,8 @@ DiagnoseTwoPhaseOperatorLookup(Sema &SemaRef, OverloadedOperatorKind Op,
SemaRef.Context.DeclarationNames.getCXXOperatorName(Op);
LookupResult R(SemaRef, OpName, OpLoc, Sema::LookupOperatorName);
return DiagnoseTwoPhaseLookup(SemaRef, OpLoc, CXXScopeSpec(), R,
- /*ExplicitTemplateArgs=*/0, Args);
+ OverloadCandidateSet::CSK_Operator,
+ /*ExplicitTemplateArgs=*/nullptr, Args);
}
namespace {
@@ -10171,7 +10429,7 @@ static ExprResult
BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
- llvm::MutableArrayRef<Expr *> Args,
+ MutableArrayRef<Expr *> Args,
SourceLocation RParenLoc,
bool EmptyLookup, bool AllowTypoCorrection) {
// Do not try to recover if it is already building a recovery call.
@@ -10189,7 +10447,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
SourceLocation TemplateKWLoc = ULE->getTemplateKeywordLoc();
TemplateArgumentListInfo TABuffer;
- TemplateArgumentListInfo *ExplicitTemplateArgs = 0;
+ TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr;
if (ULE->hasExplicitTemplateArgs()) {
ULE->copyTemplateArgumentsInto(TABuffer);
ExplicitTemplateArgs = &TABuffer;
@@ -10198,12 +10456,14 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(),
Sema::LookupOrdinaryName);
FunctionCallFilterCCC Validator(SemaRef, Args.size(),
- ExplicitTemplateArgs != 0);
+ ExplicitTemplateArgs != nullptr,
+ dyn_cast<MemberExpr>(Fn));
NoTypoCorrectionCCC RejectAll;
CorrectionCandidateCallback *CCC = AllowTypoCorrection ?
(CorrectionCandidateCallback*)&Validator :
(CorrectionCandidateCallback*)&RejectAll;
if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R,
+ OverloadCandidateSet::CSK_Normal,
ExplicitTemplateArgs, Args) &&
(!EmptyLookup ||
SemaRef.DiagnoseEmptyLookup(S, SS, R, *CCC,
@@ -10230,7 +10490,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
// This shouldn't cause an infinite loop because we're giving it
// an expression with viable lookup results, which should never
// end up here.
- return SemaRef.ActOnCallExpr(/*Scope*/ 0, NewFn.take(), LParenLoc,
+ return SemaRef.ActOnCallExpr(/*Scope*/ nullptr, NewFn.get(), LParenLoc,
MultiExprArg(Args.data(), Args.size()),
RParenLoc);
}
@@ -10280,13 +10540,13 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn,
// create a type dependent CallExpr. The goal is to postpone name lookup
// to instantiation time to be able to search into type dependent base
// classes.
- if (getLangOpts().MicrosoftMode && CurContext->isDependentContext() &&
+ if (getLangOpts().MSVCCompat && CurContext->isDependentContext() &&
(isa<FunctionDecl>(CurContext) || isa<CXXRecordDecl>(CurContext))) {
CallExpr *CE = new (Context) CallExpr(Context, Fn, Args,
Context.DependentTy, VK_RValue,
RParenLoc);
CE->setTypeDependent(true);
- *Result = Owned(CE);
+ *Result = CE;
return true;
}
return false;
@@ -10382,7 +10642,8 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn,
SourceLocation RParenLoc,
Expr *ExecConfig,
bool AllowTypoCorrection) {
- OverloadCandidateSet CandidateSet(Fn->getExprLoc());
+ OverloadCandidateSet CandidateSet(Fn->getExprLoc(),
+ OverloadCandidateSet::CSK_Normal);
ExprResult result;
if (buildOverloadedCallSet(S, Fn, ULE, Args, LParenLoc, &CandidateSet,
@@ -10435,7 +10696,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
if (checkPlaceholderForOverload(*this, Input))
return ExprError();
- Expr *Args[2] = { Input, 0 };
+ Expr *Args[2] = { Input, nullptr };
unsigned NumArgs = 1;
// For post-increment and post-decrement, add the implicit '0' as
@@ -10452,26 +10713,22 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
if (Input->isTypeDependent()) {
if (Fns.empty())
- return Owned(new (Context) UnaryOperator(Input,
- Opc,
- Context.DependentTy,
- VK_RValue, OK_Ordinary,
- OpLoc));
+ return new (Context) UnaryOperator(Input, Opc, Context.DependentTy,
+ VK_RValue, OK_Ordinary, OpLoc);
- CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators
+ CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators
UnresolvedLookupExpr *Fn
= UnresolvedLookupExpr::Create(Context, NamingClass,
NestedNameSpecifierLoc(), OpNameInfo,
/*ADL*/ true, IsOverloaded(Fns),
Fns.begin(), Fns.end());
- return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, ArgsArray,
- Context.DependentTy,
- VK_RValue,
- OpLoc, false));
+ return new (Context)
+ CXXOperatorCallExpr(Context, Op, Fn, ArgsArray, Context.DependentTy,
+ VK_RValue, OpLoc, false);
}
// Build an empty overload set.
- OverloadCandidateSet CandidateSet(OpLoc);
+ OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator);
// Add the candidates from the given function set.
AddFunctionCandidates(Fns, ArgsArray, CandidateSet, false);
@@ -10480,8 +10737,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
AddMemberOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
// Add candidates from ADL.
- AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true, OpLoc,
- ArgsArray, /*ExplicitTemplateArgs*/ 0,
+ AddArgumentDependentLookupCandidates(OpName, OpLoc, ArgsArray,
+ /*ExplicitTemplateArgs*/nullptr,
CandidateSet);
// Add builtin operator candidates.
@@ -10502,14 +10759,14 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
- CheckMemberOperatorAccess(OpLoc, Args[0], 0, Best->FoundDecl);
+ CheckMemberOperatorAccess(OpLoc, Args[0], nullptr, Best->FoundDecl);
ExprResult InputRes =
- PerformObjectArgumentInitialization(Input, /*Qualifier=*/0,
+ PerformObjectArgumentInitialization(Input, /*Qualifier=*/nullptr,
Best->FoundDecl, Method);
if (InputRes.isInvalid())
return ExprError();
- Input = InputRes.take();
+ Input = InputRes.get();
} else {
// Convert the arguments.
ExprResult InputInit
@@ -10520,7 +10777,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
Input);
if (InputInit.isInvalid())
return ExprError();
- Input = InputInit.take();
+ Input = InputInit.get();
}
// Build the actual expression node.
@@ -10530,17 +10787,16 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
return ExprError();
// Determine the result type.
- QualType ResultTy = FnDecl->getResultType();
+ QualType ResultTy = FnDecl->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
Args[0] = Input;
CallExpr *TheCall =
- new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(), ArgsArray,
+ new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.get(), ArgsArray,
ResultTy, VK, OpLoc, false);
- if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall,
- FnDecl))
+ if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl))
return ExprError();
return MaybeBindToTemporary(TheCall);
@@ -10553,7 +10809,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
Best->Conversions[0], AA_Passing);
if (InputRes.isInvalid())
return ExprError();
- Input = InputRes.take();
+ Input = InputRes.get();
break;
}
}
@@ -10619,7 +10875,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
const UnresolvedSetImpl &Fns,
Expr *LHS, Expr *RHS) {
Expr *Args[2] = { LHS, RHS };
- LHS=RHS=0; //Please use only Args instead of LHS/RHS couple
+ LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple
BinaryOperator::Opcode Opc = static_cast<BinaryOperator::Opcode>(OpcIn);
OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc);
@@ -10632,24 +10888,18 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// If there are no functions to store, just build a dependent
// BinaryOperator or CompoundAssignment.
if (Opc <= BO_Assign || Opc > BO_OrAssign)
- return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc,
- Context.DependentTy,
- VK_RValue, OK_Ordinary,
- OpLoc,
- FPFeatures.fp_contract));
-
- return Owned(new (Context) CompoundAssignOperator(Args[0], Args[1], Opc,
- Context.DependentTy,
- VK_LValue,
- OK_Ordinary,
- Context.DependentTy,
- Context.DependentTy,
- OpLoc,
- FPFeatures.fp_contract));
+ return new (Context) BinaryOperator(
+ Args[0], Args[1], Opc, Context.DependentTy, VK_RValue, OK_Ordinary,
+ OpLoc, FPFeatures.fp_contract);
+
+ return new (Context) CompoundAssignOperator(
+ Args[0], Args[1], Opc, Context.DependentTy, VK_LValue, OK_Ordinary,
+ Context.DependentTy, Context.DependentTy, OpLoc,
+ FPFeatures.fp_contract);
}
// FIXME: save results of ADL from here?
- CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators
+ CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators
// TODO: provide better source location info in DNLoc component.
DeclarationNameInfo OpNameInfo(OpName, OpLoc);
UnresolvedLookupExpr *Fn
@@ -10657,9 +10907,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
NestedNameSpecifierLoc(), OpNameInfo,
/*ADL*/ true, IsOverloaded(Fns),
Fns.begin(), Fns.end());
- return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, Args,
- Context.DependentTy, VK_RValue,
- OpLoc, FPFeatures.fp_contract));
+ return new (Context)
+ CXXOperatorCallExpr(Context, Op, Fn, Args, Context.DependentTy,
+ VK_RValue, OpLoc, FPFeatures.fp_contract);
}
// Always do placeholder-like conversions on the RHS.
@@ -10687,7 +10937,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// Build an empty overload set.
- OverloadCandidateSet CandidateSet(OpLoc);
+ OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator);
// Add the candidates from the given function set.
AddFunctionCandidates(Fns, Args, CandidateSet, false);
@@ -10696,9 +10946,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet);
// Add candidates from ADL.
- AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true,
- OpLoc, Args,
- /*ExplicitTemplateArgs*/ 0,
+ AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
+ /*ExplicitTemplateArgs*/ nullptr,
CandidateSet);
// Add builtin operator candidates.
@@ -10726,23 +10975,23 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
PerformCopyInitialization(
InitializedEntity::InitializeParameter(Context,
FnDecl->getParamDecl(0)),
- SourceLocation(), Owned(Args[1]));
+ SourceLocation(), Args[1]);
if (Arg1.isInvalid())
return ExprError();
ExprResult Arg0 =
- PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0,
+ PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/nullptr,
Best->FoundDecl, Method);
if (Arg0.isInvalid())
return ExprError();
- Args[0] = Arg0.takeAs<Expr>();
- Args[1] = RHS = Arg1.takeAs<Expr>();
+ Args[0] = Arg0.getAs<Expr>();
+ Args[1] = RHS = Arg1.getAs<Expr>();
} else {
// Convert the arguments.
ExprResult Arg0 = PerformCopyInitialization(
InitializedEntity::InitializeParameter(Context,
FnDecl->getParamDecl(0)),
- SourceLocation(), Owned(Args[0]));
+ SourceLocation(), Args[0]);
if (Arg0.isInvalid())
return ExprError();
@@ -10750,11 +10999,11 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
PerformCopyInitialization(
InitializedEntity::InitializeParameter(Context,
FnDecl->getParamDecl(1)),
- SourceLocation(), Owned(Args[1]));
+ SourceLocation(), Args[1]);
if (Arg1.isInvalid())
return ExprError();
- Args[0] = LHS = Arg0.takeAs<Expr>();
- Args[1] = RHS = Arg1.takeAs<Expr>();
+ Args[0] = LHS = Arg0.getAs<Expr>();
+ Args[1] = RHS = Arg1.getAs<Expr>();
}
// Build the actual expression node.
@@ -10765,16 +11014,16 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return ExprError();
// Determine the result type.
- QualType ResultTy = FnDecl->getResultType();
+ QualType ResultTy = FnDecl->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
CXXOperatorCallExpr *TheCall =
- new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(),
+ new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.get(),
Args, ResultTy, VK, OpLoc,
FPFeatures.fp_contract);
- if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall,
+ if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall,
FnDecl))
return ExprError();
@@ -10795,14 +11044,14 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
Best->Conversions[0], AA_Passing);
if (ArgsRes0.isInvalid())
return ExprError();
- Args[0] = ArgsRes0.take();
+ Args[0] = ArgsRes0.get();
ExprResult ArgsRes1 =
PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1],
Best->Conversions[1], AA_Passing);
if (ArgsRes1.isInvalid())
return ExprError();
- Args[1] = ArgsRes1.take();
+ Args[1] = ArgsRes1.get();
break;
}
}
@@ -10897,7 +11146,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// expression.
if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) {
- CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators
+ CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators
// CHECKME: no 'operator' keyword?
DeclarationNameInfo OpNameInfo(OpName, LLoc);
OpNameInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc));
@@ -10909,11 +11158,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
UnresolvedSetIterator());
// Can't add any actual overloads yet
- return Owned(new (Context) CXXOperatorCallExpr(Context, OO_Subscript, Fn,
- Args,
- Context.DependentTy,
- VK_RValue,
- RLoc, false));
+ return new (Context)
+ CXXOperatorCallExpr(Context, OO_Subscript, Fn, Args,
+ Context.DependentTy, VK_RValue, RLoc, false);
}
// Handle placeholders on both operands.
@@ -10923,7 +11170,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
return ExprError();
// Build an empty overload set.
- OverloadCandidateSet CandidateSet(LLoc);
+ OverloadCandidateSet CandidateSet(LLoc, OverloadCandidateSet::CSK_Operator);
// Subscript can only be overloaded as a member function.
@@ -10951,11 +11198,11 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
ExprResult Arg0 =
- PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0,
+ PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/nullptr,
Best->FoundDecl, Method);
if (Arg0.isInvalid())
return ExprError();
- Args[0] = Arg0.take();
+ Args[0] = Arg0.get();
// Convert the arguments.
ExprResult InputInit
@@ -10963,11 +11210,11 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
Context,
FnDecl->getParamDecl(0)),
SourceLocation(),
- Owned(Args[1]));
+ Args[1]);
if (InputInit.isInvalid())
return ExprError();
- Args[1] = InputInit.takeAs<Expr>();
+ Args[1] = InputInit.getAs<Expr>();
// Build the actual expression node.
DeclarationNameInfo OpLocInfo(OpName, LLoc);
@@ -10981,18 +11228,17 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
return ExprError();
// Determine the result type
- QualType ResultTy = FnDecl->getResultType();
+ QualType ResultTy = FnDecl->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
CXXOperatorCallExpr *TheCall =
new (Context) CXXOperatorCallExpr(Context, OO_Subscript,
- FnExpr.take(), Args,
+ FnExpr.get(), Args,
ResultTy, VK, RLoc,
false);
- if (CheckCallReturnType(FnDecl->getResultType(), LLoc, TheCall,
- FnDecl))
+ if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl))
return ExprError();
return MaybeBindToTemporary(TheCall);
@@ -11005,14 +11251,14 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
Best->Conversions[0], AA_Passing);
if (ArgsRes0.isInvalid())
return ExprError();
- Args[0] = ArgsRes0.take();
+ Args[0] = ArgsRes0.get();
ExprResult ArgsRes1 =
PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1],
Best->Conversions[1], AA_Passing);
if (ArgsRes1.isInvalid())
return ExprError();
- Args[1] = ArgsRes1.take();
+ Args[1] = ArgsRes1.get();
break;
}
@@ -11084,7 +11330,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
const FunctionProtoType *proto = fnType->castAs<FunctionProtoType>();
QualType resultType = proto->getCallResultType(Context);
- ExprValueKind valueKind = Expr::getValueKindForType(proto->getResultType());
+ ExprValueKind valueKind = Expr::getValueKindForType(proto->getReturnType());
// Check that the object type isn't more qualified than the
// member function we're calling.
@@ -11105,17 +11351,16 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
<< qualsString
<< (qualsString.find(' ') == std::string::npos ? 1 : 2);
}
-
+
CXXMemberCallExpr *call
= new (Context) CXXMemberCallExpr(Context, MemExprE, Args,
resultType, valueKind, RParenLoc);
- if (CheckCallReturnType(proto->getResultType(),
- op->getRHS()->getLocStart(),
- call, 0))
+ if (CheckCallReturnType(proto->getReturnType(), op->getRHS()->getLocStart(),
+ call, nullptr))
return ExprError();
- if (ConvertArgumentsForCall(call, op, 0, proto, Args, RParenLoc))
+ if (ConvertArgumentsForCall(call, op, nullptr, proto, Args, RParenLoc))
return ExprError();
if (CheckOtherCall(call, proto))
@@ -11129,9 +11374,9 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
return ExprError();
MemberExpr *MemExpr;
- CXXMethodDecl *Method = 0;
- DeclAccessPair FoundDecl = DeclAccessPair::make(0, AS_public);
- NestedNameSpecifier *Qualifier = 0;
+ CXXMethodDecl *Method = nullptr;
+ DeclAccessPair FoundDecl = DeclAccessPair::make(nullptr, AS_public);
+ NestedNameSpecifier *Qualifier = nullptr;
if (isa<MemberExpr>(NakedMemExpr)) {
MemExpr = cast<MemberExpr>(NakedMemExpr);
Method = cast<CXXMethodDecl>(MemExpr->getMemberDecl());
@@ -11148,10 +11393,11 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
: UnresExpr->getBase()->Classify(Context);
// Add overload candidates
- OverloadCandidateSet CandidateSet(UnresExpr->getMemberLoc());
+ OverloadCandidateSet CandidateSet(UnresExpr->getMemberLoc(),
+ OverloadCandidateSet::CSK_Normal);
// FIXME: avoid copy.
- TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0;
+ TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr;
if (UnresExpr->hasExplicitTemplateArgs()) {
UnresExpr->copyTemplateArgumentsInto(TemplateArgsBuffer);
TemplateArgs = &TemplateArgsBuffer;
@@ -11250,7 +11496,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
MemExpr = cast<MemberExpr>(MemExprE->IgnoreParens());
}
- QualType ResultType = Method->getResultType();
+ QualType ResultType = Method->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultType);
ResultType = ResultType.getNonLValueExprType(Context);
@@ -11260,7 +11506,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
ResultType, VK, RParenLoc);
// Check for a valid return type.
- if (CheckCallReturnType(Method->getResultType(), MemExpr->getMemberLoc(),
+ if (CheckCallReturnType(Method->getReturnType(), MemExpr->getMemberLoc(),
TheCall, Method))
return ExprError();
@@ -11273,7 +11519,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
FoundDecl, Method);
if (ObjectArg.isInvalid())
return ExprError();
- MemExpr->setBase(ObjectArg.take());
+ MemExpr->setBase(ObjectArg.get());
}
// Convert the rest of the arguments
@@ -11316,7 +11562,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
SourceLocation RParenLoc) {
if (checkPlaceholderForOverload(*this, Obj))
return ExprError();
- ExprResult Object = Owned(Obj);
+ ExprResult Object = Obj;
UnbridgedCastsSet UnbridgedCasts;
if (checkArgPlaceholdersForOverload(*this, Args, UnbridgedCasts))
@@ -11332,7 +11578,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// operators of T. The function call operators of T are obtained by
// ordinary lookup of the name operator() in the context of
// (E).operator().
- OverloadCandidateSet CandidateSet(LParenLoc);
+ OverloadCandidateSet CandidateSet(LParenLoc,
+ OverloadCandidateSet::CSK_Operator);
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call);
if (RequireCompleteType(LParenLoc, Object.get()->getType(),
@@ -11445,14 +11692,15 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
UnbridgedCasts.restore();
- if (Best->Function == 0) {
+ if (Best->Function == nullptr) {
// Since there is no function declaration, this is one of the
// surrogate candidates. Dig out the conversion function.
CXXConversionDecl *Conv
= cast<CXXConversionDecl>(
Best->Conversions[0].UserDefined.ConversionFunction);
- CheckMemberOperatorAccess(LParenLoc, Object.get(), 0, Best->FoundDecl);
+ CheckMemberOperatorAccess(LParenLoc, Object.get(), nullptr,
+ Best->FoundDecl);
if (DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc))
return ExprError();
assert(Conv == Best->FoundDecl.getDecl() &&
@@ -11468,14 +11716,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
if (Call.isInvalid())
return ExprError();
// Record usage of conversion in an implicit cast.
- Call = Owned(ImplicitCastExpr::Create(Context, Call.get()->getType(),
- CK_UserDefinedConversion,
- Call.get(), 0, VK_RValue));
+ Call = ImplicitCastExpr::Create(Context, Call.get()->getType(),
+ CK_UserDefinedConversion, Call.get(),
+ nullptr, VK_RValue);
return ActOnCallExpr(S, Call.get(), LParenLoc, Args, RParenLoc);
}
- CheckMemberOperatorAccess(LParenLoc, Object.get(), 0, Best->FoundDecl);
+ CheckMemberOperatorAccess(LParenLoc, Object.get(), nullptr, Best->FoundDecl);
// We found an overloaded operator(). Build a CXXOperatorCallExpr
// that calls this method, using Object for the implicit object
@@ -11489,7 +11737,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
const FunctionProtoType *Proto =
Method->getType()->getAs<FunctionProtoType>();
- unsigned NumArgsInProto = Proto->getNumArgs();
+ unsigned NumParams = Proto->getNumParams();
DeclarationNameInfo OpLocInfo(
Context.DeclarationNames.getCXXOperatorName(OO_Call), LParenLoc);
@@ -11503,45 +11751,44 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// Build the full argument list for the method call (the implicit object
// parameter is placed at the beginning of the list).
- llvm::OwningArrayPtr<Expr *> MethodArgs(new Expr*[Args.size() + 1]);
+ std::unique_ptr<Expr * []> MethodArgs(new Expr *[Args.size() + 1]);
MethodArgs[0] = Object.get();
std::copy(Args.begin(), Args.end(), &MethodArgs[1]);
// Once we've built TheCall, all of the expressions are properly
// owned.
- QualType ResultTy = Method->getResultType();
+ QualType ResultTy = Method->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
CXXOperatorCallExpr *TheCall = new (Context)
- CXXOperatorCallExpr(Context, OO_Call, NewFn.take(),
+ CXXOperatorCallExpr(Context, OO_Call, NewFn.get(),
llvm::makeArrayRef(MethodArgs.get(), Args.size() + 1),
ResultTy, VK, RParenLoc, false);
MethodArgs.reset();
- if (CheckCallReturnType(Method->getResultType(), LParenLoc, TheCall,
- Method))
+ if (CheckCallReturnType(Method->getReturnType(), LParenLoc, TheCall, Method))
return true;
// We may have default arguments. If so, we need to allocate more
// slots in the call for them.
- if (Args.size() < NumArgsInProto)
- TheCall->setNumArgs(Context, NumArgsInProto + 1);
+ if (Args.size() < NumParams)
+ TheCall->setNumArgs(Context, NumParams + 1);
bool IsError = false;
// Initialize the implicit object parameter.
ExprResult ObjRes =
- PerformObjectArgumentInitialization(Object.get(), /*Qualifier=*/0,
+ PerformObjectArgumentInitialization(Object.get(), /*Qualifier=*/nullptr,
Best->FoundDecl, Method);
if (ObjRes.isInvalid())
IsError = true;
else
Object = ObjRes;
- TheCall->setArg(0, Object.take());
+ TheCall->setArg(0, Object.get());
// Check the argument types.
- for (unsigned i = 0; i != NumArgsInProto; i++) {
+ for (unsigned i = 0; i != NumParams; i++) {
Expr *Arg;
if (i < Args.size()) {
Arg = Args[i];
@@ -11555,7 +11802,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
SourceLocation(), Arg);
IsError |= InputInit.isInvalid();
- Arg = InputInit.takeAs<Expr>();
+ Arg = InputInit.getAs<Expr>();
} else {
ExprResult DefArg
= BuildCXXDefaultArgExpr(LParenLoc, Method, Method->getParamDecl(i));
@@ -11564,7 +11811,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
break;
}
- Arg = DefArg.takeAs<Expr>();
+ Arg = DefArg.getAs<Expr>();
}
TheCall->setArg(i + 1, Arg);
@@ -11573,10 +11820,11 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// If this is a variadic call, handle args passed through "...".
if (Proto->isVariadic()) {
// Promote the arguments (C99 6.5.2.2p7).
- for (unsigned i = NumArgsInProto, e = Args.size(); i < e; i++) {
- ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, 0);
+ for (unsigned i = NumParams, e = Args.size(); i < e; i++) {
+ ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod,
+ nullptr);
IsError |= Arg.isInvalid();
- TheCall->setArg(i + 1, Arg.take());
+ TheCall->setArg(i + 1, Arg.get());
}
}
@@ -11612,7 +11860,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
// overload resolution mechanism (13.3).
DeclarationName OpName =
Context.DeclarationNames.getCXXOperatorName(OO_Arrow);
- OverloadCandidateSet CandidateSet(Loc);
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Operator);
const RecordType *BaseRecord = Base->getType()->getAs<RecordType>();
if (RequireCompleteType(Loc, Base->getType(),
@@ -11675,16 +11923,16 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
return ExprError();
}
- CheckMemberOperatorAccess(OpLoc, Base, 0, Best->FoundDecl);
+ CheckMemberOperatorAccess(OpLoc, Base, nullptr, Best->FoundDecl);
// Convert the object parameter.
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
ExprResult BaseResult =
- PerformObjectArgumentInitialization(Base, /*Qualifier=*/0,
+ PerformObjectArgumentInitialization(Base, /*Qualifier=*/nullptr,
Best->FoundDecl, Method);
if (BaseResult.isInvalid())
return ExprError();
- Base = BaseResult.take();
+ Base = BaseResult.get();
// Build the operator call.
ExprResult FnExpr = CreateFunctionRefExpr(*this, Method, Best->FoundDecl,
@@ -11692,15 +11940,14 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
if (FnExpr.isInvalid())
return ExprError();
- QualType ResultTy = Method->getResultType();
+ QualType ResultTy = Method->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
CXXOperatorCallExpr *TheCall =
- new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr.take(),
+ new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr.get(),
Base, ResultTy, VK, OpLoc, false);
- if (CheckCallReturnType(Method->getResultType(), OpLoc, TheCall,
- Method))
+ if (CheckCallReturnType(Method->getReturnType(), OpLoc, TheCall, Method))
return ExprError();
return MaybeBindToTemporary(TheCall);
@@ -11715,7 +11962,8 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
TemplateArgumentListInfo *TemplateArgs) {
SourceLocation UDSuffixLoc = SuffixInfo.getCXXLiteralOperatorNameLoc();
- OverloadCandidateSet CandidateSet(UDSuffixLoc);
+ OverloadCandidateSet CandidateSet(UDSuffixLoc,
+ OverloadCandidateSet::CSK_Normal);
AddFunctionCandidates(R.asUnresolvedSet(), Args, CandidateSet, true,
TemplateArgs);
@@ -11758,22 +12006,22 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
SourceLocation(), Args[ArgIdx]);
if (InputInit.isInvalid())
return true;
- ConvArgs[ArgIdx] = InputInit.take();
+ ConvArgs[ArgIdx] = InputInit.get();
}
- QualType ResultTy = FD->getResultType();
+ QualType ResultTy = FD->getReturnType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
UserDefinedLiteral *UDL =
- new (Context) UserDefinedLiteral(Context, Fn.take(),
+ new (Context) UserDefinedLiteral(Context, Fn.get(),
llvm::makeArrayRef(ConvArgs, Args.size()),
ResultTy, VK, LitEndLoc, UDSuffixLoc);
- if (CheckCallReturnType(FD->getResultType(), UDSuffixLoc, UDL, FD))
+ if (CheckCallReturnType(FD->getReturnType(), UDSuffixLoc, UDL, FD))
return ExprError();
- if (CheckFunctionCall(FD, UDL, NULL))
+ if (CheckFunctionCall(FD, UDL, nullptr))
return ExprError();
return MaybeBindToTemporary(UDL);
@@ -11800,16 +12048,16 @@ Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc,
BuildMemberReferenceExpr(Range, Range->getType(), Loc,
/*IsPtr=*/false, CXXScopeSpec(),
/*TemplateKWLoc=*/SourceLocation(),
- /*FirstQualifierInScope=*/0,
+ /*FirstQualifierInScope=*/nullptr,
MemberLookup,
- /*TemplateArgs=*/0);
+ /*TemplateArgs=*/nullptr);
if (MemberRef.isInvalid()) {
*CallExpr = ExprError();
Diag(Range->getLocStart(), diag::note_in_for_range)
<< RangeLoc << BEF << Range->getType();
return FRS_DiagnosticIssued;
}
- *CallExpr = ActOnCallExpr(S, MemberRef.get(), Loc, None, Loc, 0);
+ *CallExpr = ActOnCallExpr(S, MemberRef.get(), Loc, None, Loc, nullptr);
if (CallExpr->isInvalid()) {
*CallExpr = ExprError();
Diag(Range->getLocStart(), diag::note_in_for_range)
@@ -11819,7 +12067,7 @@ Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc,
} else {
UnresolvedSet<0> FoundNames;
UnresolvedLookupExpr *Fn =
- UnresolvedLookupExpr::Create(Context, /*NamingClass=*/0,
+ UnresolvedLookupExpr::Create(Context, /*NamingClass=*/nullptr,
NestedNameSpecifierLoc(), NameInfo,
/*NeedsADL=*/true, /*Overloaded=*/false,
FoundNames.begin(), FoundNames.end());
@@ -11839,7 +12087,7 @@ Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc,
return FRS_NoViableFunction;
}
*CallExpr = FinishOverloadedCallExpr(*this, S, Fn, Fn, Loc, Range,
- Loc, 0, CandidateSet, &Best,
+ Loc, nullptr, CandidateSet, &Best,
OverloadResult,
/*AllowTypoCorrection=*/false);
if (CallExpr->isInvalid() || OverloadResult != OR_Success) {
@@ -11881,7 +12129,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
return ImplicitCastExpr::Create(Context, ICE->getType(),
ICE->getCastKind(),
- SubExpr, 0,
+ SubExpr, nullptr,
ICE->getValueKind());
}
@@ -11893,7 +12141,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
// Do nothing: static member functions aren't any different
// from non-member functions.
} else {
- // Fix the sub expression, which really has to be an
+ // Fix the subexpression, which really has to be an
// UnresolvedLookupExpr holding an overloaded member function
// or template.
Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(),
@@ -11932,7 +12180,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
// FIXME: avoid copy.
- TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0;
+ TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr;
if (ULE->hasExplicitTemplateArgs()) {
ULE->copyTemplateArgumentsInto(TemplateArgsBuffer);
TemplateArgs = &TemplateArgsBuffer;
@@ -11955,7 +12203,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
if (UnresolvedMemberExpr *MemExpr = dyn_cast<UnresolvedMemberExpr>(E)) {
// FIXME: avoid copy.
- TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0;
+ TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr;
if (MemExpr->hasExplicitTemplateArgs()) {
MemExpr->copyTemplateArgumentsInto(TemplateArgsBuffer);
TemplateArgs = &TemplateArgsBuffer;
@@ -12022,7 +12270,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
ExprResult Sema::FixOverloadedFunctionReference(ExprResult E,
DeclAccessPair Found,
FunctionDecl *Fn) {
- return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Found, Fn));
+ return FixOverloadedFunctionReference(E.get(), Found, Fn);
}
} // end namespace clang
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
index af74f0d4a3e8..aa3e89ed67a9 100644
--- a/lib/Sema/SemaPseudoObject.cpp
+++ b/lib/Sema/SemaPseudoObject.cpp
@@ -31,6 +31,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Lex/Preprocessor.h"
@@ -235,7 +236,10 @@ namespace {
}
/// Return true if assignments have a non-void result.
- bool CanCaptureValueOfType(QualType ty) {
+ bool CanCaptureValue(Expr *exp) {
+ if (exp->isGLValue())
+ return true;
+ QualType ty = exp->getType();
assert(!ty->isIncompleteType());
assert(!ty->isDependentType());
@@ -264,7 +268,8 @@ namespace {
public:
ObjCPropertyOpBuilder(Sema &S, ObjCPropertyRefExpr *refExpr) :
PseudoOpBuilder(S, refExpr->getLocation()), RefExpr(refExpr),
- SyntacticRefExpr(0), InstanceReceiver(0), Getter(0), Setter(0) {
+ SyntacticRefExpr(nullptr), InstanceReceiver(nullptr), Getter(nullptr),
+ Setter(nullptr) {
}
ExprResult buildRValueOperation(Expr *op);
@@ -279,11 +284,12 @@ namespace {
bool tryBuildGetOfReference(Expr *op, ExprResult &result);
bool findSetter(bool warn=true);
bool findGetter();
+ void DiagnoseUnsupportedPropertyUse();
- Expr *rebuildAndCaptureObject(Expr *syntacticBase);
- ExprResult buildGet();
- ExprResult buildSet(Expr *op, SourceLocation, bool);
- ExprResult complete(Expr *SyntacticForm);
+ Expr *rebuildAndCaptureObject(Expr *syntacticBase) override;
+ ExprResult buildGet() override;
+ ExprResult buildSet(Expr *op, SourceLocation, bool) override;
+ ExprResult complete(Expr *SyntacticForm) override;
bool isWeakProperty() const;
};
@@ -303,21 +309,21 @@ namespace {
ObjCSubscriptOpBuilder(Sema &S, ObjCSubscriptRefExpr *refExpr) :
PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()),
RefExpr(refExpr),
- InstanceBase(0), InstanceKey(0),
- AtIndexGetter(0), AtIndexSetter(0) { }
-
+ InstanceBase(nullptr), InstanceKey(nullptr),
+ AtIndexGetter(nullptr), AtIndexSetter(nullptr) {}
+
ExprResult buildRValueOperation(Expr *op);
ExprResult buildAssignmentOperation(Scope *Sc,
SourceLocation opLoc,
BinaryOperatorKind opcode,
Expr *LHS, Expr *RHS);
- Expr *rebuildAndCaptureObject(Expr *syntacticBase);
-
+ Expr *rebuildAndCaptureObject(Expr *syntacticBase) override;
+
bool findAtIndexGetter();
bool findAtIndexSetter();
-
- ExprResult buildGet();
- ExprResult buildSet(Expr *op, SourceLocation, bool);
+
+ ExprResult buildGet() override;
+ ExprResult buildSet(Expr *op, SourceLocation, bool) override;
};
class MSPropertyOpBuilder : public PseudoOpBuilder {
@@ -328,9 +334,9 @@ namespace {
PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()),
RefExpr(refExpr) {}
- Expr *rebuildAndCaptureObject(Expr *);
- ExprResult buildGet();
- ExprResult buildSet(Expr *op, SourceLocation, bool);
+ Expr *rebuildAndCaptureObject(Expr *) override;
+ ExprResult buildGet() override;
+ ExprResult buildSet(Expr *op, SourceLocation, bool) override;
};
}
@@ -388,7 +394,7 @@ ExprResult PseudoOpBuilder::buildRValueOperation(Expr *op) {
ExprResult getExpr = buildGet();
if (getExpr.isInvalid()) return ExprError();
- addResultSemanticExpr(getExpr.take());
+ addResultSemanticExpr(getExpr.get());
return complete(syntacticBase);
}
@@ -421,7 +427,7 @@ PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc,
BinaryOperatorKind nonCompound =
BinaryOperator::getOpForCompoundAssignment(opcode);
result = S.BuildBinOp(Sc, opcLoc, nonCompound,
- opLHS.take(), capturedRHS);
+ opLHS.get(), capturedRHS);
if (result.isInvalid()) return ExprError();
syntactic =
@@ -436,9 +442,9 @@ PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc,
// The result of the assignment, if not void, is the value set into
// the l-value.
- result = buildSet(result.take(), opcLoc, /*captureSetValueAsResult*/ true);
+ result = buildSet(result.get(), opcLoc, /*captureSetValueAsResult*/ true);
if (result.isInvalid()) return ExprError();
- addSemanticExpr(result.take());
+ addSemanticExpr(result.get());
return complete(syntactic);
}
@@ -461,8 +467,8 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
// That's the postfix result.
if (UnaryOperator::isPostfix(opcode) &&
- (result.get()->isTypeDependent() || CanCaptureValueOfType(resultType))) {
- result = capture(result.take());
+ (result.get()->isTypeDependent() || CanCaptureValue(result.get()))) {
+ result = capture(result.get());
setResultToLastSemantic();
}
@@ -472,17 +478,17 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
GenericLoc);
if (UnaryOperator::isIncrementOp(opcode)) {
- result = S.BuildBinOp(Sc, opcLoc, BO_Add, result.take(), one);
+ result = S.BuildBinOp(Sc, opcLoc, BO_Add, result.get(), one);
} else {
- result = S.BuildBinOp(Sc, opcLoc, BO_Sub, result.take(), one);
+ result = S.BuildBinOp(Sc, opcLoc, BO_Sub, result.get(), one);
}
if (result.isInvalid()) return ExprError();
// Store that back into the result. The value stored is the result
// of a prefix operation.
- result = buildSet(result.take(), opcLoc, UnaryOperator::isPrefix(opcode));
+ result = buildSet(result.get(), opcLoc, UnaryOperator::isPrefix(opcode));
if (result.isInvalid()) return ExprError();
- addSemanticExpr(result.take());
+ addSemanticExpr(result.get());
UnaryOperator *syntactic =
new (S.Context) UnaryOperator(syntacticOp, opcode, resultType,
@@ -536,11 +542,11 @@ bool ObjCPropertyOpBuilder::isWeakProperty() const {
if (RefExpr->isExplicitProperty()) {
const ObjCPropertyDecl *Prop = RefExpr->getExplicitProperty();
if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)
- return true;
+ return !Prop->hasAttr<IBOutletAttr>();
T = Prop->getType();
} else if (Getter) {
- T = Getter->getResultType();
+ T = Getter->getReturnType();
} else {
return false;
}
@@ -563,19 +569,17 @@ bool ObjCPropertyOpBuilder::findGetter() {
assert(setter && "both setter and getter are null - cannot happen");
IdentifierInfo *setterName =
setter->getSelector().getIdentifierInfoForSlot(0);
- const char *compStr = setterName->getNameStart();
- compStr += 3;
- IdentifierInfo *getterName = &S.Context.Idents.get(compStr);
+ IdentifierInfo *getterName =
+ &S.Context.Idents.get(setterName->getName().substr(3));
GetterSelector =
S.PP.getSelectorTable().getNullarySelector(getterName);
return false;
-
}
}
ObjCPropertyDecl *prop = RefExpr->getExplicitProperty();
Getter = LookupMethodInReceiverType(S, prop->getGetterName(), RefExpr);
- return (Getter != 0);
+ return (Getter != nullptr);
}
/// Try to find the most accurate setter declaration for the property
@@ -621,7 +625,7 @@ bool ObjCPropertyOpBuilder::findSetter(bool warn) {
if (ObjCPropertyDecl *prop1 = IFace->FindPropertyDeclaration(AltMember))
if (prop != prop1 && (prop1->getSetterMethodDecl() == setter)) {
S.Diag(RefExpr->getExprLoc(), diag::error_property_setter_ambiguous_use)
- << prop->getName() << prop1->getName() << setter->getSelector();
+ << prop << prop1 << setter->getSelector();
S.Diag(prop->getLocation(), diag::note_property_declare);
S.Diag(prop1->getLocation(), diag::note_property_declare);
}
@@ -638,9 +642,21 @@ bool ObjCPropertyOpBuilder::findSetter(bool warn) {
return false;
}
+void ObjCPropertyOpBuilder::DiagnoseUnsupportedPropertyUse() {
+ if (S.getCurLexicalContext()->isObjCContainer() &&
+ S.getCurLexicalContext()->getDeclKind() != Decl::ObjCCategoryImpl &&
+ S.getCurLexicalContext()->getDeclKind() != Decl::ObjCImplementation) {
+ if (ObjCPropertyDecl *prop = RefExpr->getExplicitProperty()) {
+ S.Diag(RefExpr->getLocation(),
+ diag::err_property_function_in_objc_container);
+ S.Diag(prop->getLocation(), diag::note_property_declare);
+ }
+ }
+}
+
/// Capture the base object of an Objective-C property expression.
Expr *ObjCPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) {
- assert(InstanceReceiver == 0);
+ assert(InstanceReceiver == nullptr);
// If we have a base, capture it in an OVE and rebuild the syntactic
// form to use the OVE as its base.
@@ -661,7 +677,10 @@ Expr *ObjCPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) {
/// Load from an Objective-C property reference.
ExprResult ObjCPropertyOpBuilder::buildGet() {
findGetter();
- assert(Getter);
+ if (!Getter) {
+ DiagnoseUnsupportedPropertyUse();
+ return ExprError();
+ }
if (SyntacticRefExpr)
SyntacticRefExpr->setIsMessagingGetter();
@@ -675,10 +694,12 @@ ExprResult ObjCPropertyOpBuilder::buildGet() {
assert(InstanceReceiver);
receiverType = InstanceReceiver->getType();
}
-
+ if (!Getter->isImplicit())
+ S.DiagnoseUseOfDecl(Getter, GenericLoc, nullptr, true);
// Build a message-send.
ExprResult msg;
- if (Getter->isInstanceMethod() || RefExpr->isObjectReceiver()) {
+ if ((Getter->isInstanceMethod() && !RefExpr->isClassReceiver()) ||
+ RefExpr->isObjectReceiver()) {
assert(InstanceReceiver || RefExpr->isSuperReceiver());
msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType,
GenericLoc, Getter->getSelector(),
@@ -697,8 +718,10 @@ ExprResult ObjCPropertyOpBuilder::buildGet() {
/// value being set as the value of the property operation.
ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
bool captureSetValueAsResult) {
- bool hasSetter = findSetter(false);
- assert(hasSetter); (void) hasSetter;
+ if (!findSetter(false)) {
+ DiagnoseUnsupportedPropertyUse();
+ return ExprError();
+ }
if (SyntacticRefExpr)
SyntacticRefExpr->setIsMessagingSetter();
@@ -727,7 +750,7 @@ ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
Sema::AA_Assigning))
return ExprError();
- op = opResult.take();
+ op = opResult.get();
assert(op && "successful assignment left argument invalid?");
}
else if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(op)) {
@@ -747,7 +770,10 @@ ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
// Build a message-send.
ExprResult msg;
- if (Setter->isInstanceMethod() || RefExpr->isObjectReceiver()) {
+ if (!Setter->isImplicit())
+ S.DiagnoseUseOfDecl(Setter, GenericLoc, nullptr, true);
+ if ((Setter->isInstanceMethod() && !RefExpr->isClassReceiver()) ||
+ RefExpr->isObjectReceiver()) {
msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType,
GenericLoc, SetterSelector, Setter,
MultiExprArg(args, 1));
@@ -762,7 +788,7 @@ ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
ObjCMessageExpr *msgExpr =
cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit());
Expr *arg = msgExpr->getArg(0);
- if (CanCaptureValueOfType(arg->getType()))
+ if (CanCaptureValue(arg))
msgExpr->setArg(0, captureValueAsResult(arg));
}
@@ -788,13 +814,20 @@ ExprResult ObjCPropertyOpBuilder::buildRValueOperation(Expr *op) {
// As a special case, if the method returns 'id', try to get
// a better type from the property.
- if (RefExpr->isExplicitProperty() && result.get()->isRValue() &&
- result.get()->getType()->isObjCIdType()) {
+ if (RefExpr->isExplicitProperty() && result.get()->isRValue()) {
QualType propType = RefExpr->getExplicitProperty()->getType();
- if (const ObjCObjectPointerType *ptr
- = propType->getAs<ObjCObjectPointerType>()) {
- if (!ptr->isObjCIdType())
- result = S.ImpCastExprToType(result.get(), propType, CK_BitCast);
+ if (result.get()->getType()->isObjCIdType()) {
+ if (const ObjCObjectPointerType *ptr
+ = propType->getAs<ObjCObjectPointerType>()) {
+ if (!ptr->isObjCIdType())
+ result = S.ImpCastExprToType(result.get(), propType, CK_BitCast);
+ }
+ }
+ if (S.getLangOpts().ObjCAutoRefCount) {
+ Qualifiers::ObjCLifetime LT = propType.getObjCLifetime();
+ if (LT == Qualifiers::OCL_Weak)
+ if (!S.Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, RefExpr->getLocation()))
+ S.getCurFunction()->markSafeWeakUse(RefExpr);
}
}
@@ -810,10 +843,15 @@ bool ObjCPropertyOpBuilder::tryBuildGetOfReference(Expr *op,
if (!S.getLangOpts().CPlusPlus) return false;
findGetter();
- assert(Getter && "property has no setter and no getter!");
+ if (!Getter) {
+ // The property has no setter and no getter! This can happen if the type is
+ // invalid. Error have already been reported.
+ result = ExprError();
+ return true;
+ }
// Only do this if the getter returns an l-value reference type.
- QualType resultType = Getter->getResultType();
+ QualType resultType = Getter->getReturnType();
if (!resultType->isLValueReferenceType()) return false;
result = buildRValueOperation(op);
@@ -834,7 +872,7 @@ ObjCPropertyOpBuilder::buildAssignmentOperation(Scope *Sc,
ExprResult result;
if (tryBuildGetOfReference(LHS, result)) {
if (result.isInvalid()) return ExprError();
- return S.BuildBinOp(Sc, opcLoc, opcode, result.take(), RHS);
+ return S.BuildBinOp(Sc, opcLoc, opcode, result.get(), RHS);
}
// Otherwise, it's an error.
@@ -878,7 +916,7 @@ ObjCPropertyOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
ExprResult result;
if (tryBuildGetOfReference(op, result)) {
if (result.isInvalid()) return ExprError();
- return S.BuildUnaryOp(Sc, opcLoc, opcode, result.take());
+ return S.BuildUnaryOp(Sc, opcLoc, opcode, result.get());
}
// Otherwise, it's an error.
@@ -906,14 +944,11 @@ ObjCPropertyOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
}
ExprResult ObjCPropertyOpBuilder::complete(Expr *SyntacticForm) {
- if (S.getLangOpts().ObjCAutoRefCount && isWeakProperty()) {
- DiagnosticsEngine::Level Level =
- S.Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
- SyntacticForm->getLocStart());
- if (Level != DiagnosticsEngine::Ignored)
+ if (S.getLangOpts().ObjCAutoRefCount && isWeakProperty() &&
+ !S.Diags.isIgnored(diag::warn_arc_repeated_use_of_weak,
+ SyntacticForm->getLocStart()))
S.recordUseOfEvaluatedWeak(SyntacticRefExpr,
SyntacticRefExpr->isMessagingGetter());
- }
return PseudoOpBuilder::complete(SyntacticForm);
}
@@ -961,8 +996,8 @@ ObjCSubscriptOpBuilder::buildAssignmentOperation(Scope *Sc,
/// Capture the base object of an Objective-C Index'ed expression.
Expr *ObjCSubscriptOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) {
- assert(InstanceBase == 0);
-
+ assert(InstanceBase == nullptr);
+
// Capture base expression in an OVE and rebuild the syntactic
// form to use the OVE as its base expression.
InstanceBase = capture(RefExpr->getBaseExpr());
@@ -1011,8 +1046,6 @@ Sema::ObjCSubscriptKind
// Look for a conversion to an integral, enumeration type, or
// objective-C pointer type.
- UnresolvedSet<4> ViableConversions;
- UnresolvedSet<4> ExplicitConversions;
std::pair<CXXRecordDecl::conversion_iterator,
CXXRecordDecl::conversion_iterator> Conversions
= cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions();
@@ -1069,7 +1102,7 @@ static void CheckKeyForObjCARCConversion(Sema &S, QualType ContainerT,
true /*instance*/);
if (!Getter)
return;
- QualType T = Getter->param_begin()[0]->getType();
+ QualType T = Getter->parameters()[0]->getType();
S.CheckObjCARCConversion(Key->getSourceRange(),
T, Key, Sema::CCK_ImplicitConversion);
}
@@ -1130,7 +1163,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
AtIndexGetter = ObjCMethodDecl::Create(S.Context, SourceLocation(),
SourceLocation(), AtIndexGetterSelector,
S.Context.getObjCIdType() /*ReturnType*/,
- 0 /*TypeSourceInfo */,
+ nullptr /*TypeSourceInfo */,
S.Context.getTranslationUnitDecl(),
true /*Instance*/, false/*isVariadic*/,
/*isPropertyAccessor=*/false,
@@ -1143,9 +1176,9 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
: &S.Context.Idents.get("key"),
arrayRef ? S.Context.UnsignedLongTy
: S.Context.getObjCIdType(),
- /*TInfo=*/0,
+ /*TInfo=*/nullptr,
SC_None,
- 0);
+ nullptr);
AtIndexGetter->setMethodParams(S.Context, Argument, None);
}
@@ -1162,17 +1195,17 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
}
if (AtIndexGetter) {
- QualType T = AtIndexGetter->param_begin()[0]->getType();
+ QualType T = AtIndexGetter->parameters()[0]->getType();
if ((arrayRef && !T->isIntegralOrEnumerationType()) ||
(!arrayRef && !T->isObjCObjectPointerType())) {
S.Diag(RefExpr->getKeyExpr()->getExprLoc(),
arrayRef ? diag::err_objc_subscript_index_type
: diag::err_objc_subscript_key_type) << T;
- S.Diag(AtIndexGetter->param_begin()[0]->getLocation(),
+ S.Diag(AtIndexGetter->parameters()[0]->getLocation(),
diag::note_parameter_type) << T;
return false;
}
- QualType R = AtIndexGetter->getResultType();
+ QualType R = AtIndexGetter->getReturnType();
if (!R->isObjCObjectPointerType()) {
S.Diag(RefExpr->getKeyExpr()->getExprLoc(),
diag::err_objc_indexing_method_result_type) << R << arrayRef;
@@ -1239,26 +1272,23 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
BaseT->isObjCQualifiedIdType());
if (!AtIndexSetter && S.getLangOpts().DebuggerObjCLiteral) {
- TypeSourceInfo *ResultTInfo = 0;
+ TypeSourceInfo *ReturnTInfo = nullptr;
QualType ReturnType = S.Context.VoidTy;
- AtIndexSetter = ObjCMethodDecl::Create(S.Context, SourceLocation(),
- SourceLocation(), AtIndexSetterSelector,
- ReturnType,
- ResultTInfo,
- S.Context.getTranslationUnitDecl(),
- true /*Instance*/, false/*isVariadic*/,
- /*isPropertyAccessor=*/false,
- /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
- ObjCMethodDecl::Required,
- false);
+ AtIndexSetter = ObjCMethodDecl::Create(
+ S.Context, SourceLocation(), SourceLocation(), AtIndexSetterSelector,
+ ReturnType, ReturnTInfo, S.Context.getTranslationUnitDecl(),
+ true /*Instance*/, false /*isVariadic*/,
+ /*isPropertyAccessor=*/false,
+ /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
+ ObjCMethodDecl::Required, false);
SmallVector<ParmVarDecl *, 2> Params;
ParmVarDecl *object = ParmVarDecl::Create(S.Context, AtIndexSetter,
SourceLocation(), SourceLocation(),
&S.Context.Idents.get("object"),
S.Context.getObjCIdType(),
- /*TInfo=*/0,
+ /*TInfo=*/nullptr,
SC_None,
- 0);
+ nullptr);
Params.push_back(object);
ParmVarDecl *key = ParmVarDecl::Create(S.Context, AtIndexSetter,
SourceLocation(), SourceLocation(),
@@ -1266,9 +1296,9 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
: &S.Context.Idents.get("key"),
arrayRef ? S.Context.UnsignedLongTy
: S.Context.getObjCIdType(),
- /*TInfo=*/0,
+ /*TInfo=*/nullptr,
SC_None,
- 0);
+ nullptr);
Params.push_back(key);
AtIndexSetter->setMethodParams(S.Context, Params, None);
}
@@ -1288,26 +1318,26 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
bool err = false;
if (AtIndexSetter && arrayRef) {
- QualType T = AtIndexSetter->param_begin()[1]->getType();
+ QualType T = AtIndexSetter->parameters()[1]->getType();
if (!T->isIntegralOrEnumerationType()) {
S.Diag(RefExpr->getKeyExpr()->getExprLoc(),
diag::err_objc_subscript_index_type) << T;
- S.Diag(AtIndexSetter->param_begin()[1]->getLocation(),
+ S.Diag(AtIndexSetter->parameters()[1]->getLocation(),
diag::note_parameter_type) << T;
err = true;
}
- T = AtIndexSetter->param_begin()[0]->getType();
+ T = AtIndexSetter->parameters()[0]->getType();
if (!T->isObjCObjectPointerType()) {
S.Diag(RefExpr->getBaseExpr()->getExprLoc(),
diag::err_objc_subscript_object_type) << T << arrayRef;
- S.Diag(AtIndexSetter->param_begin()[0]->getLocation(),
+ S.Diag(AtIndexSetter->parameters()[0]->getLocation(),
diag::note_parameter_type) << T;
err = true;
}
}
else if (AtIndexSetter && !arrayRef)
for (unsigned i=0; i <2; i++) {
- QualType T = AtIndexSetter->param_begin()[i]->getType();
+ QualType T = AtIndexSetter->parameters()[i]->getType();
if (!T->isObjCObjectPointerType()) {
if (i == 1)
S.Diag(RefExpr->getKeyExpr()->getExprLoc(),
@@ -1315,7 +1345,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
else
S.Diag(RefExpr->getBaseExpr()->getExprLoc(),
diag::err_objc_subscript_dic_object_type) << T;
- S.Diag(AtIndexSetter->param_begin()[i]->getLocation(),
+ S.Diag(AtIndexSetter->parameters()[i]->getLocation(),
diag::note_parameter_type) << T;
err = true;
}
@@ -1339,6 +1369,8 @@ ExprResult ObjCSubscriptOpBuilder::buildGet() {
// Arguments.
Expr *args[] = { Index };
assert(InstanceBase);
+ if (AtIndexGetter)
+ S.DiagnoseUseOfDecl(AtIndexGetter, GenericLoc);
msg = S.BuildInstanceMessageImplicit(InstanceBase, receiverType,
GenericLoc,
AtIndexGetterSelector, AtIndexGetter,
@@ -1355,7 +1387,8 @@ ExprResult ObjCSubscriptOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
bool captureSetValueAsResult) {
if (!findAtIndexSetter())
return ExprError();
-
+ if (AtIndexSetter)
+ S.DiagnoseUseOfDecl(AtIndexSetter, GenericLoc);
QualType receiverType = InstanceBase->getType();
Expr *Index = InstanceKey;
@@ -1373,7 +1406,7 @@ ExprResult ObjCSubscriptOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
ObjCMessageExpr *msgExpr =
cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit());
Expr *arg = msgExpr->getArg(0);
- if (CanCaptureValueOfType(arg->getType()))
+ if (CanCaptureValue(arg))
msgExpr->setArg(0, captureValueAsResult(arg));
}
@@ -1395,8 +1428,8 @@ Expr *MSPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) {
ExprResult MSPropertyOpBuilder::buildGet() {
if (!RefExpr->getPropertyDecl()->hasGetter()) {
- S.Diag(RefExpr->getMemberLoc(), diag::err_no_getter_for_property)
- << RefExpr->getPropertyDecl()->getName();
+ S.Diag(RefExpr->getMemberLoc(), diag::err_no_accessor_for_property)
+ << 0 /* getter */ << RefExpr->getPropertyDecl();
return ExprError();
}
@@ -1408,15 +1441,16 @@ ExprResult MSPropertyOpBuilder::buildGet() {
ExprResult GetterExpr = S.ActOnMemberAccessExpr(
S.getCurScope(), RefExpr->getBaseExpr(), SourceLocation(),
RefExpr->isArrow() ? tok::arrow : tok::period, SS, SourceLocation(),
- GetterName, 0, true);
+ GetterName, nullptr, true);
if (GetterExpr.isInvalid()) {
- S.Diag(RefExpr->getMemberLoc(), diag::error_cannot_find_suitable_getter)
- << RefExpr->getPropertyDecl()->getName();
+ S.Diag(RefExpr->getMemberLoc(),
+ diag::error_cannot_find_suitable_accessor) << 0 /* getter */
+ << RefExpr->getPropertyDecl();
return ExprError();
}
MultiExprArg ArgExprs;
- return S.ActOnCallExpr(S.getCurScope(), GetterExpr.take(),
+ return S.ActOnCallExpr(S.getCurScope(), GetterExpr.get(),
RefExpr->getSourceRange().getBegin(), ArgExprs,
RefExpr->getSourceRange().getEnd());
}
@@ -1424,8 +1458,8 @@ ExprResult MSPropertyOpBuilder::buildGet() {
ExprResult MSPropertyOpBuilder::buildSet(Expr *op, SourceLocation sl,
bool captureSetValueAsResult) {
if (!RefExpr->getPropertyDecl()->hasSetter()) {
- S.Diag(RefExpr->getMemberLoc(), diag::err_no_setter_for_property)
- << RefExpr->getPropertyDecl()->getName();
+ S.Diag(RefExpr->getMemberLoc(), diag::err_no_accessor_for_property)
+ << 1 /* setter */ << RefExpr->getPropertyDecl();
return ExprError();
}
@@ -1437,16 +1471,17 @@ ExprResult MSPropertyOpBuilder::buildSet(Expr *op, SourceLocation sl,
ExprResult SetterExpr = S.ActOnMemberAccessExpr(
S.getCurScope(), RefExpr->getBaseExpr(), SourceLocation(),
RefExpr->isArrow() ? tok::arrow : tok::period, SS, SourceLocation(),
- SetterName, 0, true);
+ SetterName, nullptr, true);
if (SetterExpr.isInvalid()) {
- S.Diag(RefExpr->getMemberLoc(), diag::error_cannot_find_suitable_setter)
- << RefExpr->getPropertyDecl()->getName();
+ S.Diag(RefExpr->getMemberLoc(),
+ diag::error_cannot_find_suitable_accessor) << 1 /* setter */
+ << RefExpr->getPropertyDecl();
return ExprError();
}
SmallVector<Expr*, 1> ArgExprs;
ArgExprs.push_back(op);
- return S.ActOnCallExpr(S.getCurScope(), SetterExpr.take(),
+ return S.ActOnCallExpr(S.getCurScope(), SetterExpr.get(),
RefExpr->getSourceRange().getBegin(), ArgExprs,
op->getSourceRange().getEnd());
}
@@ -1513,7 +1548,7 @@ ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,
if (RHS->getType()->isNonOverloadPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(RHS);
if (result.isInvalid()) return ExprError();
- RHS = result.take();
+ RHS = result.get();
}
Expr *opaqueRef = LHS->IgnoreParens();
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 9bd8678c876a..278e6d66828b 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -49,7 +49,7 @@ StmtResult Sema::ActOnExprStmt(ExprResult FE) {
// operand, even incomplete types.
// Same thing in for stmt first clause (when expr) and third clause.
- return Owned(static_cast<Stmt*>(FE.take()));
+ return StmtResult(FE.getAs<Stmt>());
}
@@ -60,7 +60,7 @@ StmtResult Sema::ActOnExprStmtError() {
StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc,
bool HasLeadingEmptyMacro) {
- return Owned(new (Context) NullStmt(SemiLoc, HasLeadingEmptyMacro));
+ return new (Context) NullStmt(SemiLoc, HasLeadingEmptyMacro);
}
StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, SourceLocation StartLoc,
@@ -70,7 +70,7 @@ StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, SourceLocation StartLoc,
// If we have an invalid decl, just return an error.
if (DG.isNull()) return StmtError();
- return Owned(new (Context) DeclStmt(DG, StartLoc, EndLoc));
+ return new (Context) DeclStmt(DG, StartLoc, EndLoc);
}
void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) {
@@ -95,7 +95,7 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) {
// foreach variables are never actually initialized in the way that
// the parser came up with.
- var->setInit(0);
+ var->setInit(nullptr);
// In ARC, we don't need to retain the iteration variable of a fast
// enumeration loop. Rather than actually trying to catch that
@@ -114,25 +114,38 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) {
}
}
-/// \brief Diagnose unused '==' and '!=' as likely typos for '=' or '|='.
+/// \brief Diagnose unused comparisons, both builtin and overloaded operators.
+/// For '==' and '!=', suggest fixits for '=' or '|='.
///
/// Adding a cast to void (or other expression wrappers) will prevent the
/// warning from firing.
static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) {
SourceLocation Loc;
- bool IsNotEqual, CanAssign;
+ bool IsNotEqual, CanAssign, IsRelational;
if (const BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) {
- if (Op->getOpcode() != BO_EQ && Op->getOpcode() != BO_NE)
+ if (!Op->isComparisonOp())
return false;
+ IsRelational = Op->isRelationalOp();
Loc = Op->getOperatorLoc();
IsNotEqual = Op->getOpcode() == BO_NE;
CanAssign = Op->getLHS()->IgnoreParenImpCasts()->isLValue();
} else if (const CXXOperatorCallExpr *Op = dyn_cast<CXXOperatorCallExpr>(E)) {
- if (Op->getOperator() != OO_EqualEqual &&
- Op->getOperator() != OO_ExclaimEqual)
+ switch (Op->getOperator()) {
+ default:
return false;
+ case OO_EqualEqual:
+ case OO_ExclaimEqual:
+ IsRelational = false;
+ break;
+ case OO_Less:
+ case OO_Greater:
+ case OO_GreaterEqual:
+ case OO_LessEqual:
+ IsRelational = true;
+ break;
+ }
Loc = Op->getOperatorLoc();
IsNotEqual = Op->getOperator() == OO_ExclaimEqual;
@@ -148,11 +161,11 @@ static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) {
return false;
S.Diag(Loc, diag::warn_unused_comparison)
- << (unsigned)IsNotEqual << E->getSourceRange();
+ << (unsigned)IsRelational << (unsigned)IsNotEqual << E->getSourceRange();
// If the LHS is a plausible entity to assign to, provide a fixit hint to
// correct common typos.
- if (CanAssign) {
+ if (!IsRelational && CanAssign) {
if (IsNotEqual)
S.Diag(Loc, diag::note_inequality_comparison_to_or_assign)
<< FixItHint::CreateReplacement(Loc, "|=");
@@ -216,17 +229,17 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
// is written in a macro body, only warn if it has the warn_unused_result
// attribute.
if (const Decl *FD = CE->getCalleeDecl()) {
- if (FD->getAttr<WarnUnusedResultAttr>()) {
+ if (FD->hasAttr<WarnUnusedResultAttr>()) {
Diag(Loc, diag::warn_unused_result) << R1 << R2;
return;
}
if (ShouldSuppress)
return;
- if (FD->getAttr<PureAttr>()) {
+ if (FD->hasAttr<PureAttr>()) {
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "pure";
return;
}
- if (FD->getAttr<ConstAttr>()) {
+ if (FD->hasAttr<ConstAttr>()) {
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "const";
return;
}
@@ -240,9 +253,15 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
return;
}
const ObjCMethodDecl *MD = ME->getMethodDecl();
- if (MD && MD->getAttr<WarnUnusedResultAttr>()) {
- Diag(Loc, diag::warn_unused_result) << R1 << R2;
- return;
+ if (MD) {
+ if (MD->hasAttr<WarnUnusedResultAttr>()) {
+ Diag(Loc, diag::warn_unused_result) << R1 << R2;
+ return;
+ }
+ if (MD->isPropertyAccessor()) {
+ Diag(Loc, diag::warn_unused_property_expr);
+ return;
+ }
}
} else if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) {
const Expr *Source = POE->getSyntacticForm();
@@ -276,7 +295,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
return;
}
- DiagRuntimeBehavior(Loc, 0, PDiag(DiagID) << R1 << R2);
+ DiagRuntimeBehavior(Loc, nullptr, PDiag(DiagID) << R1 << R2);
}
void Sema::ActOnStartOfCompoundStmt() {
@@ -331,14 +350,14 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
DiagnoseEmptyLoopBody(Elts[i], Elts[i + 1]);
}
- return Owned(new (Context) CompoundStmt(Context, Elts, L, R));
+ return new (Context) CompoundStmt(Context, Elts, L, R);
}
StmtResult
Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal,
SourceLocation DotDotDotLoc, Expr *RHSVal,
SourceLocation ColonLoc) {
- assert((LHSVal != 0) && "missing expression in case statement");
+ assert(LHSVal && "missing expression in case statement");
if (getCurFunction()->SwitchStack.empty()) {
Diag(CaseLoc, diag::err_case_not_in_switch);
@@ -349,7 +368,7 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal,
// C99 6.8.4.2p3: The expression shall be an integer constant.
// However, GCC allows any evaluatable integer expression.
if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent()) {
- LHSVal = VerifyIntegerConstantExpression(LHSVal).take();
+ LHSVal = VerifyIntegerConstantExpression(LHSVal).get();
if (!LHSVal)
return StmtError();
}
@@ -357,21 +376,21 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal,
// GCC extension: The expression shall be an integer constant.
if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent()) {
- RHSVal = VerifyIntegerConstantExpression(RHSVal).take();
+ RHSVal = VerifyIntegerConstantExpression(RHSVal).get();
// Recover from an error by just forgetting about it.
}
}
LHSVal = ActOnFinishFullExpr(LHSVal, LHSVal->getExprLoc(), false,
- getLangOpts().CPlusPlus11).take();
+ getLangOpts().CPlusPlus11).get();
if (RHSVal)
RHSVal = ActOnFinishFullExpr(RHSVal, RHSVal->getExprLoc(), false,
- getLangOpts().CPlusPlus11).take();
+ getLangOpts().CPlusPlus11).get();
CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc,
ColonLoc);
getCurFunction()->SwitchStack.back()->addSwitchCase(CS);
- return Owned(CS);
+ return CS;
}
/// ActOnCaseStmtBody - This installs a statement as the body of a case.
@@ -389,12 +408,12 @@ Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc,
if (getCurFunction()->SwitchStack.empty()) {
Diag(DefaultLoc, diag::err_default_not_in_switch);
- return Owned(SubStmt);
+ return SubStmt;
}
DefaultStmt *DS = new (Context) DefaultStmt(DefaultLoc, ColonLoc, SubStmt);
getCurFunction()->SwitchStack.back()->addSwitchCase(DS);
- return Owned(DS);
+ return DS;
}
StmtResult
@@ -404,7 +423,7 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl,
if (TheDecl->getStmt()) {
Diag(IdentLoc, diag::err_redefinition_of_label) << TheDecl->getDeclName();
Diag(TheDecl->getLocation(), diag::note_previous_definition);
- return Owned(SubStmt);
+ return SubStmt;
}
// Otherwise, things are good. Fill in the declaration and return it.
@@ -414,7 +433,7 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl,
TheDecl->setLocStart(IdentLoc);
TheDecl->setLocation(IdentLoc);
}
- return Owned(LS);
+ return LS;
}
StmtResult Sema::ActOnAttributedStmt(SourceLocation AttrLoc,
@@ -422,7 +441,7 @@ StmtResult Sema::ActOnAttributedStmt(SourceLocation AttrLoc,
Stmt *SubStmt) {
// Fill in the declaration and return it.
AttributedStmt *LS = AttributedStmt::Create(Context, AttrLoc, Attrs, SubStmt);
- return Owned(LS);
+ return LS;
}
StmtResult
@@ -438,14 +457,14 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar,
ExprResult CondResult(CondVal.release());
- VarDecl *ConditionVar = 0;
+ VarDecl *ConditionVar = nullptr;
if (CondVar) {
ConditionVar = cast<VarDecl>(CondVar);
CondResult = CheckConditionVariable(ConditionVar, IfLoc, true);
if (CondResult.isInvalid())
return StmtError();
}
- Expr *ConditionExpr = CondResult.takeAs<Expr>();
+ Expr *ConditionExpr = CondResult.getAs<Expr>();
if (!ConditionExpr)
return StmtError();
@@ -458,8 +477,8 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar,
DiagnoseUnusedExprResult(elseStmt);
- return Owned(new (Context) IfStmt(Context, IfLoc, ConditionVar, ConditionExpr,
- thenStmt, ElseLoc, elseStmt));
+ return new (Context) IfStmt(Context, IfLoc, ConditionVar, ConditionExpr,
+ thenStmt, ElseLoc, elseStmt);
}
/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
@@ -499,7 +518,6 @@ void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val,
// We don't diagnose this overflow, because it is implementation-defined
// behavior.
// FIXME: Introduce a second, default-ignored warning for this case?
- llvm::APSInt OldVal(Val);
Val.setIsSigned(NewSign);
}
}
@@ -568,14 +586,14 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
Decl *CondVar) {
ExprResult CondResult;
- VarDecl *ConditionVar = 0;
+ VarDecl *ConditionVar = nullptr;
if (CondVar) {
ConditionVar = cast<VarDecl>(CondVar);
CondResult = CheckConditionVariable(ConditionVar, SourceLocation(), false);
if (CondResult.isInvalid())
return StmtError();
- Cond = CondResult.release();
+ Cond = CondResult.get();
}
if (!Cond)
@@ -589,41 +607,41 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
: ICEConvertDiagnoser(/*AllowScopedEnumerations*/true, false, true),
Cond(Cond) {}
- virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
- QualType T) {
+ SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
+ QualType T) override {
return S.Diag(Loc, diag::err_typecheck_statement_requires_integer) << T;
}
- virtual SemaDiagnosticBuilder diagnoseIncomplete(
- Sema &S, SourceLocation Loc, QualType T) {
+ SemaDiagnosticBuilder diagnoseIncomplete(
+ Sema &S, SourceLocation Loc, QualType T) override {
return S.Diag(Loc, diag::err_switch_incomplete_class_type)
<< T << Cond->getSourceRange();
}
- virtual SemaDiagnosticBuilder diagnoseExplicitConv(
- Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
+ SemaDiagnosticBuilder diagnoseExplicitConv(
+ Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override {
return S.Diag(Loc, diag::err_switch_explicit_conversion) << T << ConvTy;
}
- virtual SemaDiagnosticBuilder noteExplicitConv(
- Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
+ SemaDiagnosticBuilder noteExplicitConv(
+ Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override {
return S.Diag(Conv->getLocation(), diag::note_switch_conversion)
<< ConvTy->isEnumeralType() << ConvTy;
}
- virtual SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
- QualType T) {
+ SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
+ QualType T) override {
return S.Diag(Loc, diag::err_switch_multiple_conversions) << T;
}
- virtual SemaDiagnosticBuilder noteAmbiguous(
- Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
+ SemaDiagnosticBuilder noteAmbiguous(
+ Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override {
return S.Diag(Conv->getLocation(), diag::note_switch_conversion)
<< ConvTy->isEnumeralType() << ConvTy;
}
- virtual SemaDiagnosticBuilder diagnoseConversion(
- Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
+ SemaDiagnosticBuilder diagnoseConversion(
+ Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override {
llvm_unreachable("conversion functions are permitted");
}
} SwitchDiagnoser(Cond);
@@ -631,25 +649,25 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
CondResult =
PerformContextualImplicitConversion(SwitchLoc, Cond, SwitchDiagnoser);
if (CondResult.isInvalid()) return StmtError();
- Cond = CondResult.take();
+ Cond = CondResult.get();
// C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
CondResult = UsualUnaryConversions(Cond);
if (CondResult.isInvalid()) return StmtError();
- Cond = CondResult.take();
+ Cond = CondResult.get();
if (!CondVar) {
CondResult = ActOnFinishFullExpr(Cond, SwitchLoc);
if (CondResult.isInvalid())
return StmtError();
- Cond = CondResult.take();
+ Cond = CondResult.get();
}
getCurFunction()->setHasBranchIntoScope();
SwitchStmt *SS = new (Context) SwitchStmt(Context, ConditionVar, Cond);
getCurFunction()->SwitchStack.push_back(SS);
- return Owned(SS);
+ return SS;
}
static void AdjustAPSInt(llvm::APSInt &Val, unsigned BitWidth, bool IsSigned) {
@@ -660,6 +678,29 @@ static void AdjustAPSInt(llvm::APSInt &Val, unsigned BitWidth, bool IsSigned) {
Val.setIsSigned(IsSigned);
}
+/// Returns true if we should emit a diagnostic about this case expression not
+/// being a part of the enum used in the switch controlling expression.
+static bool ShouldDiagnoseSwitchCaseNotInEnum(const ASTContext &Ctx,
+ const EnumDecl *ED,
+ const Expr *CaseExpr) {
+ // Don't warn if the 'case' expression refers to a static const variable of
+ // the enum type.
+ CaseExpr = CaseExpr->IgnoreParenImpCasts();
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CaseExpr)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (!VD->hasGlobalStorage())
+ return true;
+ QualType VarType = VD->getType();
+ if (!VarType.isConstQualified())
+ return true;
+ QualType EnumType = Ctx.getTypeDeclType(ED);
+ if (Ctx.hasSameUnqualifiedType(EnumType, VarType))
+ return false;
+ }
+ }
+ return true;
+}
+
StmtResult
Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
Stmt *BodyStmt) {
@@ -667,6 +708,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
assert(SS == getCurFunction()->SwitchStack.back() &&
"switch stack missing push/pop!");
+ if (!BodyStmt) return StmtError();
SS->setBody(BodyStmt, SwitchLoc);
getCurFunction()->SwitchStack.pop_back();
@@ -721,7 +763,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
typedef std::vector<std::pair<llvm::APSInt, CaseStmt*> > CaseRangesTy;
CaseRangesTy CaseRanges;
- DefaultStmt *TheDefaultStmt = 0;
+ DefaultStmt *TheDefaultStmt = nullptr;
bool CaseListIsErroneous = false;
@@ -762,7 +804,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
CaseListIsErroneous = true;
continue;
}
- Lo = ConvLo.take();
+ Lo = ConvLo.get();
} else {
// We already verified that the expression has a i-c-e value (C99
// 6.8.4.2p3) - get that value now.
@@ -770,8 +812,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// If the LHS is not the same type as the condition, insert an implicit
// cast.
- Lo = DefaultLvalueConversion(Lo).take();
- Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).take();
+ Lo = DefaultLvalueConversion(Lo).get();
+ Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).get();
}
// Convert the value to the same width/sign as the condition had prior to
@@ -883,14 +925,14 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
CaseListIsErroneous = true;
continue;
}
- Hi = ConvHi.take();
+ Hi = ConvHi.get();
} else {
HiVal = Hi->EvaluateKnownConstInt(Context);
// If the RHS is not the same type as the condition, insert an
// implicit cast.
- Hi = DefaultLvalueConversion(Hi).take();
- Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).take();
+ Hi = DefaultLvalueConversion(Hi).get();
+ Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).get();
}
// Convert the value to the same width/sign as the condition.
@@ -928,7 +970,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// Check to see whether the case range overlaps with any
// singleton cases.
- CaseStmt *OverlapStmt = 0;
+ CaseStmt *OverlapStmt = nullptr;
llvm::APSInt OverlapVal(32);
// Find the smallest value >= the lower bound. If I is in the
@@ -993,11 +1035,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// Gather all enum values, set their type and sort them,
// allowing easier comparison with CaseVals.
- for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin();
- EDI != ED->enumerator_end(); ++EDI) {
+ for (auto *EDI : ED->enumerators()) {
llvm::APSInt Val = EDI->getInitVal();
AdjustAPSInt(Val, CondWidth, CondIsSigned);
- EnumVals.push_back(std::make_pair(Val, *EDI));
+ EnumVals.push_back(std::make_pair(Val, EDI));
}
std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
EnumValsTy::iterator EIend =
@@ -1009,9 +1050,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
CI != CaseVals.end(); CI++) {
while (EI != EIend && EI->first < CI->first)
EI++;
- if (EI == EIend || EI->first > CI->first)
- Diag(CI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum)
- << CondTypeBeforePromotion;
+ if (EI == EIend || EI->first > CI->first) {
+ Expr *CaseExpr = CI->second->getLHS();
+ if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr))
+ Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
+ << CondTypeBeforePromotion;
+ }
}
// See which of case ranges aren't in enum
EI = EnumVals.begin();
@@ -1021,8 +1065,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
EI++;
if (EI == EIend || EI->first != RI->first) {
- Diag(RI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum)
- << CondTypeBeforePromotion;
+ Expr *CaseExpr = RI->second->getLHS();
+ if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr))
+ Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
+ << CondTypeBeforePromotion;
}
llvm::APSInt Hi =
@@ -1030,9 +1076,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
AdjustAPSInt(Hi, CondWidth, CondIsSigned);
while (EI != EIend && EI->first < Hi)
EI++;
- if (EI == EIend || EI->first != Hi)
- Diag(RI->second->getRHS()->getExprLoc(), diag::warn_not_in_enum)
- << CondTypeBeforePromotion;
+ if (EI == EIend || EI->first != Hi) {
+ Expr *CaseExpr = RI->second->getRHS();
+ if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr))
+ Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
+ << CondTypeBeforePromotion;
+ }
}
// Check which enum vals aren't in switch
@@ -1044,7 +1093,6 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
for (EI = EnumVals.begin(); EI != EIend; EI++){
// Drop unneeded case values
- llvm::APSInt CIVal;
while (CI != CaseVals.end() && CI->first < EI->first)
CI++;
@@ -1100,27 +1148,26 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
}
}
- DiagnoseEmptyStmtBody(CondExpr->getLocEnd(), BodyStmt,
- diag::warn_empty_switch_body);
+ if (BodyStmt)
+ DiagnoseEmptyStmtBody(CondExpr->getLocEnd(), BodyStmt,
+ diag::warn_empty_switch_body);
// FIXME: If the case list was broken is some way, we don't have a good system
// to patch it up. Instead, just return the whole substmt as broken.
if (CaseListIsErroneous)
return StmtError();
- return Owned(SS);
+ return SS;
}
void
Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
Expr *SrcExpr) {
- if (Diags.getDiagnosticLevel(diag::warn_not_in_enum_assignment,
- SrcExpr->getExprLoc()) ==
- DiagnosticsEngine::Ignored)
+ if (Diags.isIgnored(diag::warn_not_in_enum_assignment, SrcExpr->getExprLoc()))
return;
if (const EnumType *ET = DstType->getAs<EnumType>())
- if (!Context.hasSameType(SrcType, DstType) &&
+ if (!Context.hasSameUnqualifiedType(SrcType, DstType) &&
SrcType->isIntegerType()) {
if (!SrcExpr->isTypeDependent() && !SrcExpr->isValueDependent() &&
SrcExpr->isIntegerConstantExpr(Context)) {
@@ -1137,11 +1184,10 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
// Gather all enum values, set their type and sort them,
// allowing easier comparison with rhs constant.
- for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin();
- EDI != ED->enumerator_end(); ++EDI) {
+ for (auto *EDI : ED->enumerators()) {
llvm::APSInt Val = EDI->getInitVal();
AdjustAPSInt(Val, DstWidth, DstIsSigned);
- EnumVals.push_back(std::make_pair(Val, *EDI));
+ EnumVals.push_back(std::make_pair(Val, EDI));
}
if (EnumVals.empty())
return;
@@ -1155,7 +1201,7 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
EI++;
if (EI == EIend || EI->first != RhsVal) {
Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment)
- << DstType;
+ << DstType.getUnqualifiedType();
}
}
}
@@ -1166,24 +1212,25 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond,
Decl *CondVar, Stmt *Body) {
ExprResult CondResult(Cond.release());
- VarDecl *ConditionVar = 0;
+ VarDecl *ConditionVar = nullptr;
if (CondVar) {
ConditionVar = cast<VarDecl>(CondVar);
CondResult = CheckConditionVariable(ConditionVar, WhileLoc, true);
if (CondResult.isInvalid())
return StmtError();
}
- Expr *ConditionExpr = CondResult.take();
+ Expr *ConditionExpr = CondResult.get();
if (!ConditionExpr)
return StmtError();
+ CheckBreakContinueBinding(ConditionExpr);
DiagnoseUnusedExprResult(Body);
if (isa<NullStmt>(Body))
getCurCompoundScope().setHasEmptyLoopBodies();
- return Owned(new (Context) WhileStmt(Context, ConditionVar, ConditionExpr,
- Body, WhileLoc));
+ return new (Context)
+ WhileStmt(Context, ConditionVar, ConditionExpr, Body, WhileLoc);
}
StmtResult
@@ -1192,19 +1239,20 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body,
Expr *Cond, SourceLocation CondRParen) {
assert(Cond && "ActOnDoStmt(): missing expression");
+ CheckBreakContinueBinding(Cond);
ExprResult CondResult = CheckBooleanCondition(Cond, DoLoc);
if (CondResult.isInvalid())
return StmtError();
- Cond = CondResult.take();
+ Cond = CondResult.get();
CondResult = ActOnFinishFullExpr(Cond, DoLoc);
if (CondResult.isInvalid())
return StmtError();
- Cond = CondResult.take();
+ Cond = CondResult.get();
DiagnoseUnusedExprResult(Body);
- return Owned(new (Context) DoStmt(Body, Cond, DoLoc, WhileLoc, CondRParen));
+ return new (Context) DoStmt(Body, Cond, DoLoc, WhileLoc, CondRParen);
}
namespace {
@@ -1362,9 +1410,8 @@ namespace {
// Condition is empty
if (!Second) return;
- if (S.Diags.getDiagnosticLevel(diag::warn_variables_not_in_loop_body,
- Second->getLocStart())
- == DiagnosticsEngine::Ignored)
+ if (S.Diags.isIgnored(diag::warn_variables_not_in_loop_body,
+ Second->getLocStart()))
return;
PartialDiagnostic PDiag = S.PDiag(diag::warn_variables_not_in_loop_body);
@@ -1454,25 +1501,33 @@ namespace {
return false;
}
- // A visitor to determine if a continue statement is a subexpression.
- class ContinueFinder : public EvaluatedExprVisitor<ContinueFinder> {
- bool Found;
+ // A visitor to determine if a continue or break statement is a
+ // subexpression.
+ class BreakContinueFinder : public EvaluatedExprVisitor<BreakContinueFinder> {
+ SourceLocation BreakLoc;
+ SourceLocation ContinueLoc;
public:
- ContinueFinder(Sema &S, Stmt* Body) :
- Inherited(S.Context),
- Found(false) {
+ BreakContinueFinder(Sema &S, Stmt* Body) :
+ Inherited(S.Context) {
Visit(Body);
}
- typedef EvaluatedExprVisitor<ContinueFinder> Inherited;
+ typedef EvaluatedExprVisitor<BreakContinueFinder> Inherited;
void VisitContinueStmt(ContinueStmt* E) {
- Found = true;
+ ContinueLoc = E->getContinueLoc();
+ }
+
+ void VisitBreakStmt(BreakStmt* E) {
+ BreakLoc = E->getBreakLoc();
}
- bool ContinueFound() { return Found; }
+ bool ContinueFound() { return ContinueLoc.isValid(); }
+ bool BreakFound() { return BreakLoc.isValid(); }
+ SourceLocation GetContinueLoc() { return ContinueLoc; }
+ SourceLocation GetBreakLoc() { return BreakLoc; }
- }; // end class ContinueFinder
+ }; // end class BreakContinueFinder
// Emit a warning when a loop increment/decrement appears twice per loop
// iteration. The conditions which trigger this warning are:
@@ -1483,9 +1538,8 @@ namespace {
// Return when there is nothing to check.
if (!Body || !Third) return;
- if (S.Diags.getDiagnosticLevel(diag::warn_redundant_loop_iteration,
- Third->getLocStart())
- == DiagnosticsEngine::Ignored)
+ if (S.Diags.isIgnored(diag::warn_redundant_loop_iteration,
+ Third->getLocStart()))
return;
// Get the last statement from the loop body.
@@ -1501,11 +1555,11 @@ namespace {
if (!ProcessIterationStmt(S, LastStmt, LastIncrement, LastDRE)) return;
// Check that the two statements are both increments or both decrements
- // on the same varaible.
+ // on the same variable.
if (LoopIncrement != LastIncrement ||
LoopDRE->getDecl() != LastDRE->getDecl()) return;
- if (ContinueFinder(S, Body).ContinueFound()) return;
+ if (BreakContinueFinder(S, Body).ContinueFound()) return;
S.Diag(LastDRE->getLocation(), diag::warn_redundant_loop_iteration)
<< LastDRE->getDecl() << LastIncrement;
@@ -1515,6 +1569,25 @@ namespace {
} // end namespace
+
+void Sema::CheckBreakContinueBinding(Expr *E) {
+ if (!E || getLangOpts().CPlusPlus)
+ return;
+ BreakContinueFinder BCFinder(*this, E);
+ Scope *BreakParent = CurScope->getBreakParent();
+ if (BCFinder.BreakFound() && BreakParent) {
+ if (BreakParent->getFlags() & Scope::SwitchScope) {
+ Diag(BCFinder.GetBreakLoc(), diag::warn_break_binds_to_switch);
+ } else {
+ Diag(BCFinder.GetBreakLoc(), diag::warn_loop_ctrl_binds_to_inner)
+ << "break";
+ }
+ } else if (BCFinder.ContinueFound() && CurScope->getContinueParent()) {
+ Diag(BCFinder.GetContinueLoc(), diag::warn_loop_ctrl_binds_to_inner)
+ << "continue";
+ }
+}
+
StmtResult
Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
Stmt *First, FullExprArg second, Decl *secondVar,
@@ -1525,24 +1598,26 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
// C99 6.8.5p3: The declaration part of a 'for' statement shall only
// declare identifiers for objects having storage class 'auto' or
// 'register'.
- for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE=DS->decl_end();
- DI!=DE; ++DI) {
- VarDecl *VD = dyn_cast<VarDecl>(*DI);
+ for (auto *DI : DS->decls()) {
+ VarDecl *VD = dyn_cast<VarDecl>(DI);
if (VD && VD->isLocalVarDecl() && !VD->hasLocalStorage())
- VD = 0;
- if (VD == 0) {
- Diag((*DI)->getLocation(), diag::err_non_local_variable_decl_in_for);
- (*DI)->setInvalidDecl();
+ VD = nullptr;
+ if (!VD) {
+ Diag(DI->getLocation(), diag::err_non_local_variable_decl_in_for);
+ DI->setInvalidDecl();
}
}
}
}
+ CheckBreakContinueBinding(second.get());
+ CheckBreakContinueBinding(third.get());
+
CheckForLoopConditionalStatement(*this, second.get(), third.get(), Body);
CheckForRedundantIteration(*this, third.get(), Body);
ExprResult SecondResult(second.release());
- VarDecl *ConditionVar = 0;
+ VarDecl *ConditionVar = nullptr;
if (secondVar) {
ConditionVar = cast<VarDecl>(secondVar);
SecondResult = CheckConditionVariable(ConditionVar, ForLoc, true);
@@ -1550,7 +1625,7 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
return StmtError();
}
- Expr *Third = third.release().takeAs<Expr>();
+ Expr *Third = third.release().getAs<Expr>();
DiagnoseUnusedExprResult(First);
DiagnoseUnusedExprResult(Third);
@@ -1559,10 +1634,8 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
if (isa<NullStmt>(Body))
getCurCompoundScope().setHasEmptyLoopBodies();
- return Owned(new (Context) ForStmt(Context, First,
- SecondResult.take(), ConditionVar,
- Third, Body, ForLoc, LParenLoc,
- RParenLoc));
+ return new (Context) ForStmt(Context, First, SecondResult.get(), ConditionVar,
+ Third, Body, ForLoc, LParenLoc, RParenLoc);
}
/// In an Objective C collection iteration statement:
@@ -1574,12 +1647,12 @@ StmtResult Sema::ActOnForEachLValueExpr(Expr *E) {
// use of pseudo-object l-values in this position.
ExprResult result = CheckPlaceholderExpr(E);
if (result.isInvalid()) return StmtError();
- E = result.take();
+ E = result.get();
ExprResult FullExpr = ActOnFinishFullExpr(E);
if (FullExpr.isInvalid())
return StmtError();
- return StmtResult(static_cast<Stmt*>(FullExpr.take()));
+ return StmtResult(static_cast<Stmt*>(FullExpr.get()));
}
ExprResult
@@ -1588,13 +1661,13 @@ Sema::CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) {
return ExprError();
// Bail out early if we've got a type-dependent expression.
- if (collection->isTypeDependent()) return Owned(collection);
+ if (collection->isTypeDependent()) return collection;
// Perform normal l-value conversion.
ExprResult result = DefaultFunctionArrayLvalueConversion(collection);
if (result.isInvalid())
return ExprError();
- collection = result.take();
+ collection = result.get();
// The operand needs to have object-pointer type.
// TODO: should we do a contextual conversion?
@@ -1627,7 +1700,7 @@ Sema::CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) {
};
Selector selector = Context.Selectors.getSelector(3, &selectorIdents[0]);
- ObjCMethodDecl *method = 0;
+ ObjCMethodDecl *method = nullptr;
// If there's an interface, look in both the public and private APIs.
if (iface) {
@@ -1650,7 +1723,7 @@ Sema::CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) {
}
// Wrap up any cleanups in the expression.
- return Owned(collection);
+ return collection;
}
StmtResult
@@ -1725,13 +1798,12 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
if (CollectionExprResult.isInvalid())
return StmtError();
- CollectionExprResult = ActOnFinishFullExpr(CollectionExprResult.take());
+ CollectionExprResult = ActOnFinishFullExpr(CollectionExprResult.get());
if (CollectionExprResult.isInvalid())
return StmtError();
- return Owned(new (Context) ObjCForCollectionStmt(First,
- CollectionExprResult.take(), 0,
- ForLoc, RParenLoc));
+ return new (Context) ObjCForCollectionStmt(First, CollectionExprResult.get(),
+ nullptr, ForLoc, RParenLoc);
}
/// Finish building a variable declaration for a for-range statement.
@@ -1809,7 +1881,7 @@ VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc,
static bool ObjCEnumerationCollection(Expr *Collection) {
return !Collection->isTypeDependent()
- && Collection->getType()->getAs<ObjCObjectPointerType>() != 0;
+ && Collection->getType()->getAs<ObjCObjectPointerType>() != nullptr;
}
/// ActOnCXXForRangeStmt - Check and build a C++11 for-range statement.
@@ -1868,7 +1940,7 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc,
// Claim the type doesn't contain auto: we've already done the checking.
DeclGroupPtrTy RangeGroup =
- BuildDeclaratorGroup(llvm::MutableArrayRef<Decl *>((Decl **)&RangeVar, 1),
+ BuildDeclaratorGroup(MutableArrayRef<Decl *>((Decl **)&RangeVar, 1),
/*TypeMayContainAuto=*/ false);
StmtResult RangeDecl = ActOnDeclStmt(RangeGroup, RangeLoc, RangeLoc);
if (RangeDecl.isInvalid()) {
@@ -1877,8 +1949,8 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc,
}
return BuildCXXForRangeStmt(ForLoc, ColonLoc, RangeDecl.get(),
- /*BeginEndDecl=*/0, /*Cond=*/0, /*Inc=*/0, DS,
- RParenLoc, Kind);
+ /*BeginEndDecl=*/nullptr, /*Cond=*/nullptr,
+ /*Inc=*/nullptr, DS, RParenLoc, Kind);
}
/// \brief Create the initialization, compare, and increment steps for
@@ -2100,9 +2172,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
// Find the array bound.
ExprResult BoundExpr;
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(UnqAT))
- BoundExpr = Owned(IntegerLiteral::Create(Context, CAT->getSize(),
- Context.getPointerDiffType(),
- RangeLoc));
+ BoundExpr = IntegerLiteral::Create(
+ Context, CAT->getSize(), Context.getPointerDiffType(), RangeLoc);
else if (const VariableArrayType *VAT =
dyn_cast<VariableArrayType>(UnqAT))
BoundExpr = VAT->getSizeExpr();
@@ -2123,7 +2194,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
return StmtError();
}
} else {
- OverloadCandidateSet CandidateSet(RangeLoc);
+ OverloadCandidateSet CandidateSet(RangeLoc,
+ OverloadCandidateSet::CSK_Normal);
Sema::BeginEndFunction BEFFailure;
ForRangeStatus RangeStatus =
BuildNonArrayForRange(*this, S, BeginRangeRef.get(),
@@ -2185,7 +2257,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
Decl *BeginEndDecls[] = { BeginVar, EndVar };
// Claim the type doesn't contain auto: we've already done the checking.
DeclGroupPtrTy BeginEndGroup =
- BuildDeclaratorGroup(llvm::MutableArrayRef<Decl *>(BeginEndDecls, 2),
+ BuildDeclaratorGroup(MutableArrayRef<Decl *>(BeginEndDecls, 2),
/*TypeMayContainAuto=*/ false);
BeginEndDecl = ActOnDeclStmt(BeginEndGroup, ColonLoc, ColonLoc);
@@ -2258,11 +2330,9 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
if (Kind == BFRK_Check)
return StmtResult();
- return Owned(new (Context) CXXForRangeStmt(RangeDS,
- cast_or_null<DeclStmt>(BeginEndDecl.get()),
- NotEqExpr.take(), IncrExpr.take(),
- LoopVarDS, /*Body=*/0, ForLoc,
- ColonLoc, RParenLoc));
+ return new (Context) CXXForRangeStmt(
+ RangeDS, cast_or_null<DeclStmt>(BeginEndDecl.get()), NotEqExpr.get(),
+ IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, ColonLoc, RParenLoc);
}
/// FinishObjCForCollectionStmt - Attach the body to a objective-C foreach
@@ -2301,7 +2371,7 @@ StmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc,
LabelDecl *TheDecl) {
getCurFunction()->setHasBranchIntoScope();
TheDecl->markUsed(Context);
- return Owned(new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc));
+ return new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc);
}
StmtResult
@@ -2311,12 +2381,12 @@ Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc,
if (!E->isTypeDependent()) {
QualType ETy = E->getType();
QualType DestTy = Context.getPointerType(Context.VoidTy.withConst());
- ExprResult ExprRes = Owned(E);
+ ExprResult ExprRes = E;
AssignConvertType ConvTy =
CheckSingleAssignmentConstraints(DestTy, ExprRes);
if (ExprRes.isInvalid())
return StmtError();
- E = ExprRes.take();
+ E = ExprRes.get();
if (DiagnoseAssignmentResult(ConvTy, StarLoc, DestTy, ETy, E, AA_Passing))
return StmtError();
}
@@ -2324,11 +2394,11 @@ Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc,
ExprResult ExprRes = ActOnFinishFullExpr(E);
if (ExprRes.isInvalid())
return StmtError();
- E = ExprRes.take();
+ E = ExprRes.get();
getCurFunction()->setHasIndirectGoto();
- return Owned(new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E));
+ return new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E);
}
StmtResult
@@ -2339,7 +2409,7 @@ Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {
return StmtError(Diag(ContinueLoc, diag::err_continue_not_in_loop));
}
- return Owned(new (Context) ContinueStmt(ContinueLoc));
+ return new (Context) ContinueStmt(ContinueLoc);
}
StmtResult
@@ -2349,8 +2419,11 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
// C99 6.8.6.3p1: A break shall appear only in or as a switch/loop body.
return StmtError(Diag(BreakLoc, diag::err_break_not_in_loop_or_switch));
}
+ if (S->isOpenMPLoopScope())
+ return StmtError(Diag(BreakLoc, diag::err_omp_loop_cannot_use_stmt)
+ << "break");
- return Owned(new (Context) BreakStmt(BreakLoc));
+ return new (Context) BreakStmt(BreakLoc);
}
/// \brief Determine whether the given expression is a candidate for
@@ -2371,52 +2444,62 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
///
/// \returns The NRVO candidate variable, if the return statement may use the
/// NRVO, or NULL if there is no such candidate.
-const VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType,
- Expr *E,
- bool AllowFunctionParameter) {
- QualType ExprType = E->getType();
+VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType,
+ Expr *E,
+ bool AllowFunctionParameter) {
+ if (!getLangOpts().CPlusPlus)
+ return nullptr;
+
+ // - in a return statement in a function [where] ...
+ // ... the expression is the name of a non-volatile automatic object ...
+ DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParens());
+ if (!DR || DR->refersToEnclosingLocal())
+ return nullptr;
+ VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
+ if (!VD)
+ return nullptr;
+
+ if (isCopyElisionCandidate(ReturnType, VD, AllowFunctionParameter))
+ return VD;
+ return nullptr;
+}
+
+bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD,
+ bool AllowFunctionParameter) {
+ QualType VDType = VD->getType();
// - in a return statement in a function with ...
// ... a class return type ...
- if (!ReturnType.isNull()) {
+ if (!ReturnType.isNull() && !ReturnType->isDependentType()) {
if (!ReturnType->isRecordType())
- return 0;
+ return false;
// ... the same cv-unqualified type as the function return type ...
- if (!Context.hasSameUnqualifiedType(ReturnType, ExprType))
- return 0;
+ if (!VDType->isDependentType() &&
+ !Context.hasSameUnqualifiedType(ReturnType, VDType))
+ return false;
}
- // ... the expression is the name of a non-volatile automatic object
- // (other than a function or catch-clause parameter)) ...
- const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParens());
- if (!DR || DR->refersToEnclosingLocal())
- return 0;
- const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
- if (!VD)
- return 0;
-
// ...object (other than a function or catch-clause parameter)...
if (VD->getKind() != Decl::Var &&
!(AllowFunctionParameter && VD->getKind() == Decl::ParmVar))
- return 0;
- if (VD->isExceptionVariable()) return 0;
+ return false;
+ if (VD->isExceptionVariable()) return false;
// ...automatic...
- if (!VD->hasLocalStorage()) return 0;
+ if (!VD->hasLocalStorage()) return false;
// ...non-volatile...
- if (VD->getType().isVolatileQualified()) return 0;
- if (VD->getType()->isReferenceType()) return 0;
+ if (VD->getType().isVolatileQualified()) return false;
// __block variables can't be allocated in a way that permits NRVO.
- if (VD->hasAttr<BlocksAttr>()) return 0;
+ if (VD->hasAttr<BlocksAttr>()) return false;
// Variables with higher required alignment than their type's ABI
// alignment cannot use NRVO.
- if (VD->hasAttr<AlignedAttr>() &&
+ if (!VD->getType()->isDependentType() && VD->hasAttr<AlignedAttr>() &&
Context.getDeclAlign(VD) > Context.getTypeAlignInChars(VD->getType()))
- return 0;
+ return false;
- return VD;
+ return true;
}
/// \brief Perform the initialization of a potentially-movable value, which
@@ -2476,7 +2559,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
// Promote "AsRvalue" to the heap, since we now need this
// expression node to persist.
Value = ImplicitCastExpr::Create(Context, Value->getType(),
- CK_NoOp, Value, 0, VK_XValue);
+ CK_NoOp, Value, nullptr, VK_XValue);
// Complete type-checking the initialization of the return type
// using the constructor we found.
@@ -2499,7 +2582,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
static bool hasDeducedReturnType(FunctionDecl *FD) {
const FunctionProtoType *FPT =
FD->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>();
- return FPT->getResultType()->isUndeducedType();
+ return FPT->getReturnType()->isUndeducedType();
}
/// ActOnCapScopeReturnStmt - Utility routine to type-check return statements
@@ -2518,7 +2601,7 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// FIXME: Blocks might have a return type of 'auto' explicitly specified.
FunctionDecl *FD = CurLambda->CallOperator;
if (CurCap->ReturnType.isNull())
- CurCap->ReturnType = FD->getResultType();
+ CurCap->ReturnType = FD->getReturnType();
AutoType *AT = CurCap->ReturnType->getContainedAutoType();
assert(AT && "lost auto type from lambda return type");
@@ -2526,7 +2609,7 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
FD->setInvalidDecl();
return StmtError();
}
- CurCap->ReturnType = FnRetType = FD->getResultType();
+ CurCap->ReturnType = FnRetType = FD->getReturnType();
} else if (CurCap->HasImplicitReturnType) {
// For blocks/lambdas with implicit return types, we check each return
// statement individually, and deduce the common return type when the block
@@ -2536,7 +2619,7 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp);
if (Result.isInvalid())
return StmtError();
- RetValExp = Result.take();
+ RetValExp = Result.get();
if (!CurContext->isDependentContext())
FnRetType = RetValExp->getType();
@@ -2582,7 +2665,7 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// Otherwise, verify that this result type matches the previous one. We are
// pickier with blocks than for normal functions because we don't have GCC
// compatibility to worry about here.
- const VarDecl *NRVOCandidate = 0;
+ const VarDecl *NRVOCandidate = nullptr;
if (FnRetType->isDependentType()) {
// Delay processing for now. TODO: there are lots of dependent
// types we can conclusively prove aren't void.
@@ -2596,7 +2679,7 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
Diag(ReturnLoc, diag::ext_return_has_void_expr) << "literal" << 2;
else {
Diag(ReturnLoc, diag::err_return_block_has_expr);
- RetValExp = 0;
+ RetValExp = nullptr;
}
}
} else if (!RetValExp) {
@@ -2613,22 +2696,24 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false);
InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc,
FnRetType,
- NRVOCandidate != 0);
+ NRVOCandidate != nullptr);
ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate,
FnRetType, RetValExp);
if (Res.isInvalid()) {
// FIXME: Cleanup temporaries here, anyway?
return StmtError();
}
- RetValExp = Res.take();
- CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+ RetValExp = Res.get();
+ CheckReturnValExpr(RetValExp, FnRetType, ReturnLoc);
+ } else {
+ NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false);
}
if (RetValExp) {
ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
if (ER.isInvalid())
return StmtError();
- RetValExp = ER.take();
+ RetValExp = ER.get();
}
ReturnStmt *Result = new (Context) ReturnStmt(ReturnLoc, RetValExp,
NRVOCandidate);
@@ -2636,12 +2721,10 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// If we need to check for the named return value optimization,
// or if we need to infer the return type,
// save the return statement in our scope for later processing.
- if (CurCap->HasImplicitReturnType ||
- (getLangOpts().CPlusPlus && FnRetType->isRecordType() &&
- !CurContext->isDependentContext()))
+ if (CurCap->HasImplicitReturnType || NRVOCandidate)
FunctionScopes.back()->Returns.push_back(Result);
- return Owned(Result);
+ return Result;
}
/// Deduce the return type for a function from a returned expression, per
@@ -2651,7 +2734,7 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
Expr *&RetExpr,
AutoType *AT) {
TypeLoc OrigResultType = FD->getTypeSourceInfo()->getTypeLoc().
- IgnoreParens().castAs<FunctionProtoTypeLoc>().getResultLoc();
+ IgnoreParens().castAs<FunctionProtoTypeLoc>().getReturnLoc();
QualType Deduced;
if (RetExpr && isa<InitListExpr>(RetExpr)) {
@@ -2735,7 +2818,24 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
}
StmtResult
-Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
+Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
+ Scope *CurScope) {
+ StmtResult R = BuildReturnStmt(ReturnLoc, RetValExp);
+ if (R.isInvalid()) {
+ return R;
+ }
+
+ if (VarDecl *VD =
+ const_cast<VarDecl*>(cast<ReturnStmt>(R.get())->getNRVOCandidate())) {
+ CurScope->addNRVOCandidate(VD);
+ } else {
+ CurScope->setNoNRVO();
+ }
+
+ return R;
+}
+
+StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// Check for unexpanded parameter packs.
if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp))
return StmtError();
@@ -2745,13 +2845,21 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
QualType FnRetType;
QualType RelatedRetType;
+ const AttrVec *Attrs = nullptr;
+ bool isObjCMethod = false;
+
if (const FunctionDecl *FD = getCurFunctionDecl()) {
- FnRetType = FD->getResultType();
+ FnRetType = FD->getReturnType();
+ if (FD->hasAttrs())
+ Attrs = &FD->getAttrs();
if (FD->isNoReturn())
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
<< FD->getDeclName();
} else if (ObjCMethodDecl *MD = getCurMethodDecl()) {
- FnRetType = MD->getResultType();
+ FnRetType = MD->getReturnType();
+ isObjCMethod = true;
+ if (MD->hasAttrs())
+ Attrs = &MD->getAttrs();
if (MD->hasRelatedResultType() && MD->getClassInterface()) {
// In the implementation of a method with a related return type, the
// type used to type-check the validity of return statements within the
@@ -2771,14 +2879,14 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
FD->setInvalidDecl();
return StmtError();
} else {
- FnRetType = FD->getResultType();
+ FnRetType = FD->getReturnType();
}
}
}
bool HasDependentReturnType = FnRetType->isDependentType();
- ReturnStmt *Result = 0;
+ ReturnStmt *Result = nullptr;
if (FnRetType->isVoidType()) {
if (RetValExp) {
if (isa<InitListExpr>(RetValExp)) {
@@ -2799,24 +2907,36 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
<< RetValExp->getSourceRange();
// Drop the expression.
- RetValExp = 0;
+ RetValExp = nullptr;
} else if (!RetValExp->isTypeDependent()) {
// C99 6.8.6.4p1 (ext_ since GCC warns)
unsigned D = diag::ext_return_has_expr;
- if (RetValExp->getType()->isVoidType())
- D = diag::ext_return_has_void_expr;
+ if (RetValExp->getType()->isVoidType()) {
+ NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
+ if (isa<CXXConstructorDecl>(CurDecl) ||
+ isa<CXXDestructorDecl>(CurDecl))
+ D = diag::err_ctor_dtor_returns_void;
+ else
+ D = diag::ext_return_has_void_expr;
+ }
else {
- ExprResult Result = Owned(RetValExp);
- Result = IgnoredValueConversions(Result.take());
+ ExprResult Result = RetValExp;
+ Result = IgnoredValueConversions(Result.get());
if (Result.isInvalid())
return StmtError();
- RetValExp = Result.take();
+ RetValExp = Result.get();
RetValExp = ImpCastExprToType(RetValExp,
- Context.VoidTy, CK_ToVoid).take();
+ Context.VoidTy, CK_ToVoid).get();
+ }
+ // return of void in constructor/destructor is illegal in C++.
+ if (D == diag::err_ctor_dtor_returns_void) {
+ NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
+ Diag(ReturnLoc, D)
+ << CurDecl->getDeclName() << isa<CXXDestructorDecl>(CurDecl)
+ << RetValExp->getSourceRange();
}
-
// return (some void expression); is legal in C++.
- if (D != diag::ext_return_has_void_expr ||
+ else if (D != diag::ext_return_has_void_expr ||
!getLangOpts().CPlusPlus) {
NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
@@ -2838,11 +2958,11 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
if (ER.isInvalid())
return StmtError();
- RetValExp = ER.take();
+ RetValExp = ER.get();
}
}
- Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0);
+ Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, nullptr);
} else if (!RetValExp && !HasDependentReturnType) {
unsigned DiagID = diag::warn_return_missing_expr; // C90 6.6.6.4p4
// C99 6.8.6.4p1 (ext_ since GCC warns)
@@ -2855,29 +2975,30 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
Result = new (Context) ReturnStmt(ReturnLoc);
} else {
assert(RetValExp || HasDependentReturnType);
- const VarDecl *NRVOCandidate = 0;
- if (!HasDependentReturnType && !RetValExp->isTypeDependent()) {
- // we have a non-void function with an expression, continue checking
+ const VarDecl *NRVOCandidate = nullptr;
- QualType RetType = (RelatedRetType.isNull() ? FnRetType : RelatedRetType);
+ QualType RetType = RelatedRetType.isNull() ? FnRetType : RelatedRetType;
- // C99 6.8.6.4p3(136): The return statement is not an assignment. The
- // overlap restriction of subclause 6.5.16.1 does not apply to the case of
- // function return.
+ // C99 6.8.6.4p3(136): The return statement is not an assignment. The
+ // overlap restriction of subclause 6.5.16.1 does not apply to the case of
+ // function return.
- // In C++ the return statement is handled via a copy initialization,
- // the C version of which boils down to CheckSingleAssignmentConstraints.
+ // In C++ the return statement is handled via a copy initialization,
+ // the C version of which boils down to CheckSingleAssignmentConstraints.
+ if (RetValExp)
NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false);
+ if (!HasDependentReturnType && !RetValExp->isTypeDependent()) {
+ // we have a non-void function with an expression, continue checking
InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc,
RetType,
- NRVOCandidate != 0);
+ NRVOCandidate != nullptr);
ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate,
RetType, RetValExp);
if (Res.isInvalid()) {
// FIXME: Clean up temporaries here anyway?
return StmtError();
}
- RetValExp = Res.takeAs<Expr>();
+ RetValExp = Res.getAs<Expr>();
// If we have a related result type, we need to implicitly
// convert back to the formal result type. We can't pretend to
@@ -2891,28 +3012,28 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// FIXME: Clean up temporaries here anyway?
return StmtError();
}
- RetValExp = Res.takeAs<Expr>();
+ RetValExp = Res.getAs<Expr>();
}
- CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+ CheckReturnValExpr(RetValExp, FnRetType, ReturnLoc, isObjCMethod, Attrs,
+ getCurFunctionDecl());
}
if (RetValExp) {
ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
if (ER.isInvalid())
return StmtError();
- RetValExp = ER.take();
+ RetValExp = ER.get();
}
Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate);
}
// If we need to check for the named return value optimization, save the
// return statement in our scope for later processing.
- if (getLangOpts().CPlusPlus && FnRetType->isRecordType() &&
- !CurContext->isDependentContext())
+ if (Result->getNRVOCandidate())
FunctionScopes.back()->Returns.push_back(Result);
- return Owned(Result);
+ return Result;
}
StmtResult
@@ -2923,12 +3044,12 @@ Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
if (Var && Var->isInvalidDecl())
return StmtError();
- return Owned(new (Context) ObjCAtCatchStmt(AtLoc, RParen, Var, Body));
+ return new (Context) ObjCAtCatchStmt(AtLoc, RParen, Var, Body);
}
StmtResult
Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, Stmt *Body) {
- return Owned(new (Context) ObjCAtFinallyStmt(AtLoc, Body));
+ return new (Context) ObjCAtFinallyStmt(AtLoc, Body);
}
StmtResult
@@ -2939,10 +3060,8 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try,
getCurFunction()->setHasBranchProtectedScope();
unsigned NumCatchStmts = CatchStmts.size();
- return Owned(ObjCAtTryStmt::Create(Context, AtLoc, Try,
- CatchStmts.data(),
- NumCatchStmts,
- Finally));
+ return ObjCAtTryStmt::Create(Context, AtLoc, Try, CatchStmts.data(),
+ NumCatchStmts, Finally);
}
StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw) {
@@ -2951,10 +3070,10 @@ StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw) {
if (Result.isInvalid())
return StmtError();
- Result = ActOnFinishFullExpr(Result.take());
+ Result = ActOnFinishFullExpr(Result.get());
if (Result.isInvalid())
return StmtError();
- Throw = Result.take();
+ Throw = Result.get();
QualType ThrowType = Throw->getType();
// Make sure the expression type is an ObjC pointer or "void *".
@@ -2967,7 +3086,7 @@ StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw) {
}
}
- return Owned(new (Context) ObjCAtThrowStmt(AtLoc, Throw));
+ return new (Context) ObjCAtThrowStmt(AtLoc, Throw);
}
StmtResult
@@ -2993,7 +3112,7 @@ Sema::ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, Expr *operand) {
ExprResult result = DefaultLvalueConversion(operand);
if (result.isInvalid())
return ExprError();
- operand = result.take();
+ operand = result.get();
// Make sure the expression type is an ObjC pointer or "void *".
QualType type = operand->getType();
@@ -3014,7 +3133,7 @@ Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SyncExpr,
Stmt *SyncBody) {
// We can't jump into or indirect-jump out of a @synchronized block.
getCurFunction()->setHasBranchProtectedScope();
- return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc, SyncExpr, SyncBody));
+ return new (Context) ObjCAtSynchronizedStmt(AtLoc, SyncExpr, SyncBody);
}
/// ActOnCXXCatchBlock - Takes an exception declaration and a handler block
@@ -3023,15 +3142,14 @@ StmtResult
Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, Decl *ExDecl,
Stmt *HandlerBlock) {
// There's nothing to test that ActOnExceptionDecl didn't already test.
- return Owned(new (Context) CXXCatchStmt(CatchLoc,
- cast_or_null<VarDecl>(ExDecl),
- HandlerBlock));
+ return new (Context)
+ CXXCatchStmt(CatchLoc, cast_or_null<VarDecl>(ExDecl), HandlerBlock);
}
StmtResult
Sema::ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body) {
getCurFunction()->setHasBranchProtectedScope();
- return Owned(new (Context) ObjCAutoreleasePoolStmt(AtLoc, Body));
+ return new (Context) ObjCAutoreleasePoolStmt(AtLoc, Body);
}
namespace {
@@ -3075,6 +3193,9 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
!getSourceManager().isInSystemHeader(TryLoc))
Diag(TryLoc, diag::err_exceptions_disabled) << "try";
+ if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())
+ Diag(TryLoc, diag::err_omp_simd_region_cannot_use_stmt) << "try";
+
const unsigned NumHandlers = Handlers.size();
assert(NumHandlers > 0 &&
"The parser shouldn't call this if there are no handlers.");
@@ -3125,19 +3246,18 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
// Neither of these are explicitly forbidden, but every compiler detects them
// and warns.
- return Owned(CXXTryStmt::Create(Context, TryLoc, TryBlock, Handlers));
+ return CXXTryStmt::Create(Context, TryLoc, TryBlock, Handlers);
}
-StmtResult
-Sema::ActOnSEHTryBlock(bool IsCXXTry,
- SourceLocation TryLoc,
- Stmt *TryBlock,
- Stmt *Handler) {
+StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
+ Stmt *TryBlock, Stmt *Handler,
+ int HandlerIndex, int HandlerParentIndex) {
assert(TryBlock && Handler);
getCurFunction()->setHasBranchProtectedScope();
- return Owned(SEHTryStmt::Create(Context,IsCXXTry,TryLoc,TryBlock,Handler));
+ return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler,
+ HandlerIndex, HandlerParentIndex);
}
StmtResult
@@ -3152,14 +3272,25 @@ Sema::ActOnSEHExceptBlock(SourceLocation Loc,
<< FilterExpr->getType());
}
- return Owned(SEHExceptStmt::Create(Context,Loc,FilterExpr,Block));
+ return SEHExceptStmt::Create(Context,Loc,FilterExpr,Block);
}
StmtResult
Sema::ActOnSEHFinallyBlock(SourceLocation Loc,
Stmt *Block) {
assert(Block);
- return Owned(SEHFinallyStmt::Create(Context,Loc,Block));
+ return SEHFinallyStmt::Create(Context,Loc,Block);
+}
+
+StmtResult
+Sema::ActOnSEHLeaveStmt(SourceLocation Loc, Scope *CurScope) {
+ Scope *SEHTryParent = CurScope;
+ while (SEHTryParent && !SEHTryParent->isSEHTryScope())
+ SEHTryParent = SEHTryParent->getParent();
+ if (!SEHTryParent)
+ return StmtError(Diag(Loc, diag::err_ms___leave_not_in___try));
+
+ return new (Context) SEHLeaveStmt(Loc);
}
StmtResult Sema::BuildMSDependentExistsStmt(SourceLocation KeywordLoc,
@@ -3192,30 +3323,20 @@ Sema::CreateCapturedStmtRecordDecl(CapturedDecl *&CD, SourceLocation Loc,
while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
DC = DC->getParent();
- RecordDecl *RD = 0;
+ RecordDecl *RD = nullptr;
if (getLangOpts().CPlusPlus)
- RD = CXXRecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, /*Id=*/0);
+ RD = CXXRecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc,
+ /*Id=*/nullptr);
else
- RD = RecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, /*Id=*/0);
+ RD = RecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, /*Id=*/nullptr);
DC->addDecl(RD);
RD->setImplicit();
RD->startDefinition();
+ assert(NumParams > 0 && "CapturedStmt requires context parameter");
CD = CapturedDecl::Create(Context, CurContext, NumParams);
DC->addDecl(CD);
-
- // Build the context parameter
- assert(NumParams > 0 && "CapturedStmt requires context parameter");
- DC = CapturedDecl::castToDeclContext(CD);
- IdentifierInfo *VarName = &Context.Idents.get("__context");
- QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD));
- ImplicitParamDecl *Param
- = ImplicitParamDecl::Create(Context, DC, Loc, VarName, ParamType);
- DC->addDecl(Param);
-
- CD->setContextParam(Param);
-
return RD;
}
@@ -3247,9 +3368,71 @@ static void buildCapturedStmtCaptureList(
void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
CapturedRegionKind Kind,
unsigned NumParams) {
- CapturedDecl *CD = 0;
+ CapturedDecl *CD = nullptr;
RecordDecl *RD = CreateCapturedStmtRecordDecl(CD, Loc, NumParams);
+ // Build the context parameter
+ DeclContext *DC = CapturedDecl::castToDeclContext(CD);
+ IdentifierInfo *ParamName = &Context.Idents.get("__context");
+ QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD));
+ ImplicitParamDecl *Param
+ = ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType);
+ DC->addDecl(Param);
+
+ CD->setContextParam(0, Param);
+
+ // Enter the capturing scope for this captured region.
+ PushCapturedRegionScope(CurScope, CD, RD, Kind);
+
+ if (CurScope)
+ PushDeclContext(CurScope, CD);
+ else
+ CurContext = CD;
+
+ PushExpressionEvaluationContext(PotentiallyEvaluated);
+}
+
+void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
+ CapturedRegionKind Kind,
+ ArrayRef<CapturedParamNameType> Params) {
+ CapturedDecl *CD = nullptr;
+ RecordDecl *RD = CreateCapturedStmtRecordDecl(CD, Loc, Params.size());
+
+ // Build the context parameter
+ DeclContext *DC = CapturedDecl::castToDeclContext(CD);
+ bool ContextIsFound = false;
+ unsigned ParamNum = 0;
+ for (ArrayRef<CapturedParamNameType>::iterator I = Params.begin(),
+ E = Params.end();
+ I != E; ++I, ++ParamNum) {
+ if (I->second.isNull()) {
+ assert(!ContextIsFound &&
+ "null type has been found already for '__context' parameter");
+ IdentifierInfo *ParamName = &Context.Idents.get("__context");
+ QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD));
+ ImplicitParamDecl *Param
+ = ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType);
+ DC->addDecl(Param);
+ CD->setContextParam(ParamNum, Param);
+ ContextIsFound = true;
+ } else {
+ IdentifierInfo *ParamName = &Context.Idents.get(I->first);
+ ImplicitParamDecl *Param
+ = ImplicitParamDecl::Create(Context, DC, Loc, ParamName, I->second);
+ DC->addDecl(Param);
+ CD->setParam(ParamNum, Param);
+ }
+ }
+ assert(ContextIsFound && "no null type for '__context' parameter");
+ if (!ContextIsFound) {
+ // Add __context implicitly if it is not specified.
+ IdentifierInfo *ParamName = &Context.Idents.get("__context");
+ QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD));
+ ImplicitParamDecl *Param =
+ ImplicitParamDecl::Create(Context, DC, Loc, ParamName, ParamType);
+ DC->addDecl(Param);
+ CD->setContextParam(ParamNum, Param);
+ }
// Enter the capturing scope for this captured region.
PushCapturedRegionScope(CurScope, CD, RD, Kind);
@@ -3269,12 +3452,9 @@ void Sema::ActOnCapturedRegionError() {
RecordDecl *Record = RSI->TheRecordDecl;
Record->setInvalidDecl();
- SmallVector<Decl*, 4> Fields;
- for (RecordDecl::field_iterator I = Record->field_begin(),
- E = Record->field_end(); I != E; ++I)
- Fields.push_back(*I);
- ActOnFields(/*Scope=*/0, Record->getLocation(), Record, Fields,
- SourceLocation(), SourceLocation(), /*AttributeList=*/0);
+ SmallVector<Decl*, 4> Fields(Record->fields());
+ ActOnFields(/*Scope=*/nullptr, Record->getLocation(), Record, Fields,
+ SourceLocation(), SourceLocation(), /*AttributeList=*/nullptr);
PopDeclContext();
PopFunctionScopeInfo();
@@ -3303,5 +3483,5 @@ StmtResult Sema::ActOnCapturedRegionEnd(Stmt *S) {
PopDeclContext();
PopFunctionScopeInfo();
- return Owned(Res);
+ return Res;
}
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index 9169032178fe..5d076cac940f 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -15,13 +15,13 @@
#include "clang/AST/RecordLayout.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
using namespace clang;
using namespace sema;
@@ -152,6 +152,12 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
diag::err_asm_invalid_lvalue_in_input)
<< Info.getConstraintStr()
<< InputExpr->getSourceRange());
+ } else {
+ ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]);
+ if (Result.isInvalid())
+ return StmtError();
+
+ Exprs[i] = Result.get();
}
if (Info.allowsRegister()) {
@@ -163,11 +169,6 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
}
}
- ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]);
- if (Result.isInvalid())
- return StmtError();
-
- Exprs[i] = Result.take();
InputConstraintInfos.push_back(Info);
const Type *Ty = Exprs[i]->getType().getTypePtr();
@@ -352,7 +353,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
InputExpr->isEvaluatable(Context)) {
CastKind castKind =
(OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast);
- InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).take();
+ InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).get();
Exprs[InputOpNo] = InputExpr;
NS->setInputExpr(i, InputExpr);
continue;
@@ -365,13 +366,13 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
return StmtError();
}
- return Owned(NS);
+ return NS;
}
ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
UnqualifiedId &Id,
- InlineAsmIdentifierInfo &Info,
+ llvm::InlineAsmIdentifierInfo &Info,
bool IsUnevaluatedContext) {
Info.clear();
@@ -382,7 +383,7 @@ ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
ExprResult Result = ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Id,
/*trailing lparen*/ false,
/*is & operand*/ false,
- /*CorrectionCandidateCallback=*/0,
+ /*CorrectionCandidateCallback=*/nullptr,
/*IsInlineAsmIdentifier=*/ true);
if (IsUnevaluatedContext)
@@ -390,7 +391,7 @@ ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
if (!Result.isUsable()) return Result;
- Result = CheckPlaceholderExpr(Result.take());
+ Result = CheckPlaceholderExpr(Result.get());
if (!Result.isUsable()) return Result;
QualType T = Result.get()->getType();
@@ -438,12 +439,14 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
if (!BaseResult.isSingleResult())
return true;
- const RecordType *RT = 0;
+ const RecordType *RT = nullptr;
NamedDecl *FoundDecl = BaseResult.getFoundDecl();
if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl))
RT = VD->getType()->getAs<RecordType>();
- else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(FoundDecl))
+ else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(FoundDecl))
RT = TD->getUnderlyingType()->getAs<RecordType>();
+ else if (TypeDecl *TD = dyn_cast<TypeDecl>(FoundDecl))
+ RT = TD->getTypeForDecl()->getAs<RecordType>();
if (!RT)
return true;
@@ -483,5 +486,5 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
/*IsVolatile*/ true, AsmToks, NumOutputs, NumInputs,
Constraints, Exprs, AsmString,
Clobbers, EndLoc);
- return Owned(NS);
+ return NS;
}
diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp
index eb0188a0db3d..a32e0fbcb622 100644
--- a/lib/Sema/SemaStmtAttr.cpp
+++ b/lib/Sema/SemaStmtAttr.cpp
@@ -12,12 +12,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "TargetAttributesSema.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Lex/Lexer.h"
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/LoopHint.h"
#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/StringExtras.h"
@@ -30,20 +29,164 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A,
S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target)
<< St->getLocStart();
if (isa<SwitchCase>(St)) {
- SourceLocation L = Lexer::getLocForEndOfToken(Range.getEnd(), 0,
- S.getSourceManager(), S.getLangOpts());
+ SourceLocation L = S.getLocForEndOfToken(Range.getEnd());
S.Diag(L, diag::note_fallthrough_insert_semi_fixit)
<< FixItHint::CreateInsertion(L, ";");
}
- return 0;
+ return nullptr;
}
if (S.getCurFunction()->SwitchStack.empty()) {
S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_outside_switch);
- return 0;
+ return nullptr;
}
- return ::new (S.Context) FallThroughAttr(A.getRange(), S.Context);
+ return ::new (S.Context) FallThroughAttr(A.getRange(), S.Context,
+ A.getAttributeSpellingListIndex());
}
+static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
+ SourceRange) {
+ IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0);
+ IdentifierLoc *OptionLoc = A.getArgAsIdent(1);
+ IdentifierInfo *OptionInfo = OptionLoc->Ident;
+ IdentifierLoc *ValueLoc = A.getArgAsIdent(2);
+ IdentifierInfo *ValueInfo = ValueLoc ? ValueLoc->Ident : nullptr;
+ Expr *ValueExpr = A.getArgAsExpr(3);
+
+ assert(OptionInfo && "Attribute must have valid option info.");
+
+ if (St->getStmtClass() != Stmt::DoStmtClass &&
+ St->getStmtClass() != Stmt::ForStmtClass &&
+ St->getStmtClass() != Stmt::CXXForRangeStmtClass &&
+ St->getStmtClass() != Stmt::WhileStmtClass) {
+ const char *Pragma = PragmaNameLoc->Ident->getName() == "unroll"
+ ? "#pragma unroll"
+ : "#pragma clang loop";
+ S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop) << Pragma;
+ return nullptr;
+ }
+
+ LoopHintAttr::OptionType Option;
+ LoopHintAttr::Spelling Spelling;
+ if (PragmaNameLoc->Ident->getName() == "unroll") {
+ Option = ValueLoc ? LoopHintAttr::UnrollCount : LoopHintAttr::Unroll;
+ Spelling = LoopHintAttr::Pragma_unroll;
+ } else {
+ Option = llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName())
+ .Case("vectorize", LoopHintAttr::Vectorize)
+ .Case("vectorize_width", LoopHintAttr::VectorizeWidth)
+ .Case("interleave", LoopHintAttr::Interleave)
+ .Case("interleave_count", LoopHintAttr::InterleaveCount)
+ .Case("unroll", LoopHintAttr::Unroll)
+ .Case("unroll_count", LoopHintAttr::UnrollCount)
+ .Default(LoopHintAttr::Vectorize);
+ Spelling = LoopHintAttr::Pragma_clang_loop;
+ }
+
+ int ValueInt;
+ if (Option == LoopHintAttr::Unroll &&
+ Spelling == LoopHintAttr::Pragma_unroll) {
+ ValueInt = 1;
+ } else if (Option == LoopHintAttr::Vectorize ||
+ Option == LoopHintAttr::Interleave ||
+ Option == LoopHintAttr::Unroll) {
+ if (!ValueInfo) {
+ S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword);
+ return nullptr;
+ }
+ if (ValueInfo->isStr("disable"))
+ ValueInt = 0;
+ else if (ValueInfo->isStr("enable"))
+ ValueInt = 1;
+ else {
+ S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword);
+ return nullptr;
+ }
+ } else if (Option == LoopHintAttr::VectorizeWidth ||
+ Option == LoopHintAttr::InterleaveCount ||
+ Option == LoopHintAttr::UnrollCount) {
+ // FIXME: We should support template parameters for the loop hint value.
+ // See bug report #19610.
+ llvm::APSInt ValueAPS;
+ if (!ValueExpr || !ValueExpr->isIntegerConstantExpr(ValueAPS, S.Context) ||
+ (ValueInt = ValueAPS.getSExtValue()) < 1) {
+ S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_value);
+ return nullptr;
+ }
+ } else
+ llvm_unreachable("Unknown loop hint option");
+
+ return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, ValueInt,
+ A.getRange());
+}
+
+static void CheckForIncompatibleAttributes(
+ Sema &S, const SmallVectorImpl<const Attr *> &Attrs) {
+ // There are 3 categories of loop hints: vectorize, interleave, and
+ // unroll. Each comes in two variants: an enable/disable form and a
+ // form which takes a numeric argument. For example:
+ // unroll(enable|disable) and unroll_count(N). The following array
+ // accumulate the hints encountered while iterating through the
+ // attributes to check for compatibility.
+ struct {
+ const LoopHintAttr *EnableAttr;
+ const LoopHintAttr *NumericAttr;
+ } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}};
+
+ for (const auto *I : Attrs) {
+ const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
+
+ // Skip non loop hint attributes
+ if (!LH)
+ continue;
+
+ int Option = LH->getOption();
+ int Category;
+ switch (Option) {
+ case LoopHintAttr::Vectorize:
+ case LoopHintAttr::VectorizeWidth:
+ Category = 0;
+ break;
+ case LoopHintAttr::Interleave:
+ case LoopHintAttr::InterleaveCount:
+ Category = 1;
+ break;
+ case LoopHintAttr::Unroll:
+ case LoopHintAttr::UnrollCount:
+ Category = 2;
+ break;
+ };
+
+ auto &CategoryState = HintAttrs[Category];
+ SourceLocation OptionLoc = LH->getRange().getBegin();
+ const LoopHintAttr *PrevAttr;
+ if (Option == LoopHintAttr::Vectorize ||
+ Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) {
+ // Enable|disable hint. For example, vectorize(enable).
+ PrevAttr = CategoryState.EnableAttr;
+ CategoryState.EnableAttr = LH;
+ } else {
+ // Numeric hint. For example, vectorize_width(8).
+ PrevAttr = CategoryState.NumericAttr;
+ CategoryState.NumericAttr = LH;
+ }
+
+ if (PrevAttr)
+ // Cannot specify same type of attribute twice.
+ S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
+ << /*Duplicate=*/true << PrevAttr->getDiagnosticName()
+ << LH->getDiagnosticName();
+
+ if (CategoryState.EnableAttr && !CategoryState.EnableAttr->getValue() &&
+ CategoryState.NumericAttr) {
+ // Disable hints are not compatible with numeric hints of the
+ // same category.
+ S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
+ << /*Duplicate=*/false
+ << CategoryState.EnableAttr->getDiagnosticName()
+ << CategoryState.NumericAttr->getDiagnosticName();
+ }
+ }
+}
static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
SourceRange Range) {
@@ -52,15 +195,17 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
S.Diag(A.getLoc(), A.isDeclspecAttribute() ?
diag::warn_unhandled_ms_attribute_ignored :
diag::warn_unknown_attribute_ignored) << A.getName();
- return 0;
+ return nullptr;
case AttributeList::AT_FallThrough:
return handleFallThroughAttr(S, St, A, Range);
+ case AttributeList::AT_LoopHint:
+ return handleLoopHintAttr(S, St, A, Range);
default:
// if we're here, then we parsed a known attribute, but didn't recognize
// it as a statement attribute => it is declaration attribute
S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt)
<< A.getName() << St->getLocStart();
- return 0;
+ return nullptr;
}
}
@@ -72,6 +217,8 @@ StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList,
Attrs.push_back(a);
}
+ CheckForIncompatibleAttributes(*this, Attrs);
+
if (Attrs.empty())
return S;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 28603daa267c..63581a44dbe5 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -10,8 +10,8 @@
//===----------------------------------------------------------------------===/
#include "TreeTransform.h"
-#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
@@ -20,6 +20,7 @@
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ParsedTemplate.h"
@@ -51,8 +52,8 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context,
if (isa<TemplateDecl>(D)) {
if (!AllowFunctionTemplates && isa<FunctionTemplateDecl>(D))
- return 0;
-
+ return nullptr;
+
return Orig;
}
@@ -78,10 +79,10 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context,
return Spec->getSpecializedTemplate();
}
- return 0;
+ return nullptr;
}
- return 0;
+ return nullptr;
}
void Sema::FilterAcceptableTemplateNames(LookupResult &R,
@@ -193,8 +194,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
TemplateDecl *TD = cast<TemplateDecl>((*R.begin())->getUnderlyingDecl());
if (SS.isSet() && !SS.isInvalid()) {
- NestedNameSpecifier *Qualifier
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ NestedNameSpecifier *Qualifier = SS.getScopeRep();
Template = Context.getQualifiedTemplateName(Qualifier,
hasTemplateKeyword, TD);
} else {
@@ -250,7 +250,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
bool &MemberOfUnknownSpecialization) {
// Determine where to perform name lookup
MemberOfUnknownSpecialization = false;
- DeclContext *LookupCtx = 0;
+ DeclContext *LookupCtx = nullptr;
bool isDependent = false;
if (!ObjectType.isNull()) {
// This nested-name-specifier occurs in a member access expression, e.g.,
@@ -325,7 +325,8 @@ void Sema::LookupTemplateName(LookupResult &Found,
FilterCCC.WantCXXNamedCasts = true;
if (TypoCorrection Corrected = CorrectTypo(Found.getLookupNameInfo(),
Found.getLookupKind(), S, &SS,
- FilterCCC, LookupCtx)) {
+ FilterCCC, CTK_ErrorRecovery,
+ LookupCtx)) {
Found.setLookupName(Corrected.getCorrection());
if (Corrected.getCorrectionDecl())
Found.addDecl(Corrected.getCorrectionDecl());
@@ -418,17 +419,12 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
// Since the 'this' expression is synthesized, we don't need to
// perform the double-lookup check.
- NamedDecl *FirstQualifierInScope = 0;
+ NamedDecl *FirstQualifierInScope = nullptr;
- return Owned(CXXDependentScopeMemberExpr::Create(Context,
- /*This*/ 0, ThisType,
- /*IsArrow*/ true,
- /*Op*/ SourceLocation(),
- SS.getWithLocInContext(Context),
- TemplateKWLoc,
- FirstQualifierInScope,
- NameInfo,
- TemplateArgs));
+ return CXXDependentScopeMemberExpr::Create(
+ Context, /*This*/ nullptr, ThisType, /*IsArrow*/ true,
+ /*Op*/ SourceLocation(), SS.getWithLocInContext(Context), TemplateKWLoc,
+ FirstQualifierInScope, NameInfo, TemplateArgs);
}
return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs);
@@ -439,11 +435,9 @@ Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
- return Owned(DependentScopeDeclRefExpr::Create(Context,
- SS.getWithLocInContext(Context),
- TemplateKWLoc,
- NameInfo,
- TemplateArgs));
+ return DependentScopeDeclRefExpr::Create(
+ Context, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo,
+ TemplateArgs);
}
/// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
@@ -474,7 +468,7 @@ TemplateDecl *Sema::AdjustDeclIfTemplate(Decl *&D) {
D = Temp->getTemplatedDecl();
return Temp;
}
- return 0;
+ return nullptr;
}
ParsedTemplateArgument ParsedTemplateArgument::getTemplatePackExpansion(
@@ -550,7 +544,7 @@ static void maybeDiagnoseTemplateParameterShadow(Sema &SemaRef, Scope *S,
/// ParamNameLoc is the location of the parameter name (if any).
/// If the type parameter has a default argument, it will be added
/// later via ActOnTypeParameterDefault.
-Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
+Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
SourceLocation EllipsisLoc,
SourceLocation KeyLoc,
IdentifierInfo *ParamName,
@@ -566,10 +560,11 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
if (!ParamName)
Loc = KeyLoc;
+ bool IsParameterPack = EllipsisLoc.isValid();
TemplateTypeParmDecl *Param
= TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(),
KeyLoc, Loc, Depth, Position, ParamName,
- Typename, Ellipsis);
+ Typename, IsParameterPack);
Param->setAccess(AS_public);
if (Invalid)
Param->setInvalidDecl();
@@ -585,7 +580,7 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
// C++0x [temp.param]p9:
// A default template-argument may be specified for any kind of
// template-parameter that is not a template parameter pack.
- if (DefaultArg && Ellipsis) {
+ if (DefaultArg && IsParameterPack) {
Diag(EqualLoc, diag::err_template_param_pack_default_arg);
DefaultArg = ParsedType();
}
@@ -715,7 +710,7 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
// template-parameter that is not a template parameter pack.
if (Default && IsParameterPack) {
Diag(EqualLoc, diag::err_template_param_pack_default_arg);
- Default = 0;
+ Default = nullptr;
}
// Check the well-formedness of the default template argument, if provided.
@@ -730,7 +725,7 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
Param->setInvalidDecl();
return Param;
}
- Default = DefaultRes.take();
+ Default = DefaultRes.get();
Param->setDefaultArgument(Default, false);
}
@@ -843,6 +838,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
AttributeList *Attr,
TemplateParameterList *TemplateParams,
AccessSpecifier AS, SourceLocation ModulePrivateLoc,
+ SourceLocation FriendLoc,
unsigned NumOuterTemplateParamLists,
TemplateParameterList** OuterTemplateParamLists) {
assert(TemplateParams && TemplateParams->size() > 0 &&
@@ -906,7 +902,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (Previous.isAmbiguous())
return true;
- NamedDecl *PrevDecl = 0;
+ NamedDecl *PrevDecl = nullptr;
if (Previous.begin() != Previous.end())
PrevDecl = (*Previous.begin())->getUnderlyingDecl();
@@ -949,7 +945,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Declarations in outer scopes don't matter. However, the outermost
// context we computed is the semantic context for our new
// declaration.
- PrevDecl = PrevClassTemplate = 0;
+ PrevDecl = PrevClassTemplate = nullptr;
SemanticContext = OutermostContext;
// Check that the chosen semantic context doesn't already contain a
@@ -968,8 +964,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
PrevDecl = (*Previous.begin())->getUnderlyingDecl();
}
}
- } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S))
- PrevDecl = PrevClassTemplate = 0;
+ } else if (PrevDecl &&
+ !isDeclInScope(PrevDecl, SemanticContext, S, SS.isValid()))
+ PrevDecl = PrevClassTemplate = nullptr;
if (PrevClassTemplate) {
// Ensure that the template parameter lists are compatible. Skip this check
@@ -1011,7 +1008,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(NameLoc, PrevDecl);
// Just pretend that we didn't see the previous declaration.
- PrevDecl = 0;
+ PrevDecl = nullptr;
} else if (PrevDecl) {
// C++ [temp]p5:
// A class template shall not have the same name as any other
@@ -1030,7 +1027,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (!(TUK == TUK_Friend && CurContext->isDependentContext()) &&
CheckTemplateParameterList(
TemplateParams,
- PrevClassTemplate ? PrevClassTemplate->getTemplateParameters() : 0,
+ PrevClassTemplate ? PrevClassTemplate->getTemplateParameters()
+ : nullptr,
(SS.isSet() && SemanticContext && SemanticContext->isRecord() &&
SemanticContext->isDependentContext())
? TPC_ClassTemplateMember
@@ -1052,7 +1050,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
CXXRecordDecl *NewClass =
CXXRecordDecl::Create(Context, Kind, SemanticContext, KWLoc, NameLoc, Name,
PrevClassTemplate?
- PrevClassTemplate->getTemplatedDecl() : 0,
+ PrevClassTemplate->getTemplatedDecl() : nullptr,
/*DelayTypeCreation=*/true);
SetNestedNameSpecifier(NewClass, SS);
if (NumOuterTemplateParamLists > 0)
@@ -1126,10 +1124,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
/* AddToContext = */ false);
}
- FriendDecl *Friend = FriendDecl::Create(Context, CurContext,
- NewClass->getLocation(),
- NewTemplate,
- /*FIXME:*/NewClass->getLocation());
+ FriendDecl *Friend = FriendDecl::Create(
+ Context, CurContext, NewClass->getLocation(), NewTemplate, FriendLoc);
Friend->setAccess(AS_public);
CurContext->addDecl(Friend);
}
@@ -1299,7 +1295,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
// Merge default arguments for template type parameters.
TemplateTypeParmDecl *OldTypeParm
- = OldParams? cast<TemplateTypeParmDecl>(*OldParam) : 0;
+ = OldParams? cast<TemplateTypeParmDecl>(*OldParam) : nullptr;
if (NewTypeParm->isParameterPack()) {
assert(!NewTypeParm->hasDefaultArgument() &&
@@ -1344,7 +1340,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
// Merge default arguments for non-type template parameters
NonTypeTemplateParmDecl *OldNonTypeParm
- = OldParams? cast<NonTypeTemplateParmDecl>(*OldParam) : 0;
+ = OldParams? cast<NonTypeTemplateParmDecl>(*OldParam) : nullptr;
if (NewNonTypeParm->isParameterPack()) {
assert(!NewNonTypeParm->hasDefaultArgument() &&
"Parameter packs can't have a default argument!");
@@ -1391,7 +1387,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
// Merge default arguments for template template parameters
TemplateTemplateParmDecl *OldTemplateParm
- = OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : 0;
+ = OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : nullptr;
if (NewTemplateParm->isParameterPack()) {
assert(!NewTemplateParm->hasDefaultArgument() &&
"Parameter packs can't have a default argument!");
@@ -1487,6 +1483,9 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> {
unsigned Depth;
bool Match;
+ SourceLocation MatchLoc;
+
+ DependencyChecker(unsigned Depth) : Depth(Depth), Match(false) {}
DependencyChecker(TemplateParameterList *Params) : Match(false) {
NamedDecl *ND = Params->getParam(0);
@@ -1500,14 +1499,19 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> {
}
}
- bool Matches(unsigned ParmDepth) {
+ bool Matches(unsigned ParmDepth, SourceLocation Loc = SourceLocation()) {
if (ParmDepth >= Depth) {
Match = true;
+ MatchLoc = Loc;
return true;
}
return false;
}
+ bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
+ return !Matches(TL.getTypePtr()->getDepth(), TL.getNameLoc());
+ }
+
bool VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
return !Matches(T->getDepth());
}
@@ -1515,21 +1519,28 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> {
bool TraverseTemplateName(TemplateName N) {
if (TemplateTemplateParmDecl *PD =
dyn_cast_or_null<TemplateTemplateParmDecl>(N.getAsTemplateDecl()))
- if (Matches(PD->getDepth())) return false;
+ if (Matches(PD->getDepth()))
+ return false;
return super::TraverseTemplateName(N);
}
bool VisitDeclRefExpr(DeclRefExpr *E) {
if (NonTypeTemplateParmDecl *PD =
- dyn_cast<NonTypeTemplateParmDecl>(E->getDecl())) {
- if (PD->getDepth() == Depth) {
- Match = true;
+ dyn_cast<NonTypeTemplateParmDecl>(E->getDecl()))
+ if (Matches(PD->getDepth(), E->getExprLoc()))
return false;
- }
- }
return super::VisitDeclRefExpr(E);
}
-
+
+ bool VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
+ return TraverseType(T->getReplacementType());
+ }
+
+ bool
+ VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) {
+ return TraverseTemplateArgument(T->getArgumentPack());
+ }
+
bool TraverseInjectedClassNameType(const InjectedClassNameType *T) {
return TraverseType(T->getInjectedSpecializationType());
}
@@ -1577,6 +1588,9 @@ static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context,
/// parameter lists. This scope specifier precedes a qualified name that is
/// being declared.
///
+/// \param TemplateId The template-id following the scope specifier, if there
+/// is one. Used to check for a missing 'template<>'.
+///
/// \param ParamLists the template parameter lists, from the outermost to the
/// innermost template parameter lists.
///
@@ -1595,6 +1609,7 @@ static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context,
/// itself a template).
TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS,
+ TemplateIdAnnotation *TemplateId,
ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend,
bool &IsExplicitSpecialization, bool &Invalid) {
IsExplicitSpecialization = false;
@@ -1701,6 +1716,37 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
// template<> for each enclosing class template that is
// explicitly specialized.
bool SawNonEmptyTemplateParameterList = false;
+
+ auto CheckExplicitSpecialization = [&](SourceRange Range, bool Recovery) {
+ if (SawNonEmptyTemplateParameterList) {
+ Diag(DeclLoc, diag::err_specialize_member_of_template)
+ << !Recovery << Range;
+ Invalid = true;
+ IsExplicitSpecialization = false;
+ return true;
+ }
+
+ return false;
+ };
+
+ auto DiagnoseMissingExplicitSpecialization = [&] (SourceRange Range) {
+ // Check that we can have an explicit specialization here.
+ if (CheckExplicitSpecialization(Range, true))
+ return true;
+
+ // We don't have a template header, but we should.
+ SourceLocation ExpectedTemplateLoc;
+ if (!ParamLists.empty())
+ ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc();
+ else
+ ExpectedTemplateLoc = DeclStartLoc;
+
+ Diag(DeclLoc, diag::err_template_spec_needs_header)
+ << Range
+ << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
+ return false;
+ };
+
unsigned ParamIdx = 0;
for (unsigned TypeIdx = 0, NumTypes = NestedTypes.size(); TypeIdx != NumTypes;
++TypeIdx) {
@@ -1714,7 +1760,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
// For a dependent type, the set of template parameters that we
// expect to see.
- TemplateParameterList *ExpectedTemplateParams = 0;
+ TemplateParameterList *ExpectedTemplateParams = nullptr;
// C++0x [temp.expl.spec]p15:
// A member or a member template may be nested within many enclosing
@@ -1771,13 +1817,9 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
// are not explicitly specialized as well.
if (ParamIdx < ParamLists.size()) {
if (ParamLists[ParamIdx]->size() == 0) {
- if (SawNonEmptyTemplateParameterList) {
- Diag(DeclLoc, diag::err_specialize_member_of_template)
- << ParamLists[ParamIdx]->getSourceRange();
- Invalid = true;
- IsExplicitSpecialization = false;
- return 0;
- }
+ if (CheckExplicitSpecialization(ParamLists[ParamIdx]->getSourceRange(),
+ false))
+ return nullptr;
} else
SawNonEmptyTemplateParameterList = true;
}
@@ -1798,30 +1840,22 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
ParamLists[ParamIdx]->getRAngleLoc())
<< getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
Invalid = true;
- return 0;
+ return nullptr;
}
-
+
// Consume this template header.
++ParamIdx;
continue;
- }
-
- if (!IsFriend) {
- // We don't have a template header, but we should.
- SourceLocation ExpectedTemplateLoc;
- if (!ParamLists.empty())
- ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc();
- else
- ExpectedTemplateLoc = DeclStartLoc;
-
- Diag(DeclLoc, diag::err_template_spec_needs_header)
- << getRangeOfTypeInNestedNameSpecifier(Context, T, SS)
- << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
}
-
+
+ if (!IsFriend)
+ if (DiagnoseMissingExplicitSpecialization(
+ getRangeOfTypeInNestedNameSpecifier(Context, T, SS)))
+ return nullptr;
+
continue;
}
-
+
if (NeedNonemptyTemplateHeader) {
// In friend declarations we can have template-ids which don't
// depend on the corresponding template parameter lists. But
@@ -1830,7 +1864,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
if (IsFriend && T->isDependentType()) {
if (ParamIdx < ParamLists.size() &&
DependsOnTemplateParameters(T, ParamLists[ParamIdx]))
- ExpectedTemplateParams = 0;
+ ExpectedTemplateParams = nullptr;
else
continue;
}
@@ -1842,9 +1876,9 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
ExpectedTemplateParams,
true, TPL_TemplateMatch))
Invalid = true;
-
+
if (!Invalid &&
- CheckTemplateParameterList(ParamLists[ParamIdx], 0,
+ CheckTemplateParameterList(ParamLists[ParamIdx], nullptr,
TPC_ClassTemplateMember))
Invalid = true;
@@ -1859,12 +1893,26 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
continue;
}
}
-
+
// If there were at least as many template-ids as there were template
// parameter lists, then there are no template parameter lists remaining for
// the declaration itself.
- if (ParamIdx >= ParamLists.size())
- return 0;
+ if (ParamIdx >= ParamLists.size()) {
+ if (TemplateId && !IsFriend) {
+ // We don't have a template header for the declaration itself, but we
+ // should.
+ IsExplicitSpecialization = true;
+ DiagnoseMissingExplicitSpecialization(SourceRange(TemplateId->LAngleLoc,
+ TemplateId->RAngleLoc));
+
+ // Fabricate an empty template parameter list for the invented header.
+ return TemplateParameterList::Create(Context, SourceLocation(),
+ SourceLocation(), nullptr, 0,
+ SourceLocation());
+ }
+
+ return nullptr;
+ }
// If there were too many template parameter lists, complain about that now.
if (ParamIdx < ParamLists.size() - 1) {
@@ -1905,14 +1953,11 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
// unspecialized, except that the declaration shall not explicitly
// specialize a class member template if its en- closing class templates
// are not explicitly specialized as well.
- if (ParamLists.back()->size() == 0 && SawNonEmptyTemplateParameterList) {
- Diag(DeclLoc, diag::err_specialize_member_of_template)
- << ParamLists[ParamIdx]->getSourceRange();
- Invalid = true;
- IsExplicitSpecialization = false;
- return 0;
- }
-
+ if (ParamLists.back()->size() == 0 &&
+ CheckExplicitSpecialization(ParamLists[ParamIdx]->getSourceRange(),
+ false))
+ return nullptr;
+
// Return the last template parameter list, which corresponds to the
// entity being declared.
return ParamLists.back();
@@ -1959,7 +2004,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
TemplateArgs);
TemplateDecl *Template = Name.getAsTemplateDecl();
- if (!Template || isa<FunctionTemplateDecl>(Template)) {
+ if (!Template || isa<FunctionTemplateDecl>(Template) ||
+ isa<VarTemplateDecl>(Template)) {
// We might have a substituted template template parameter pack. If so,
// build a template specialization type for it.
if (Name.getAsSubstTemplateTemplateParmPack())
@@ -1974,17 +2020,15 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// Check that the template argument list is well-formed for this
// template.
SmallVector<TemplateArgument, 4> Converted;
- bool ExpansionIntoFixedList = false;
if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs,
- false, Converted, &ExpansionIntoFixedList))
+ false, Converted))
return QualType();
QualType CanonType;
bool InstantiationDependent = false;
- TypeAliasTemplateDecl *AliasTemplate = 0;
- if (!ExpansionIntoFixedList &&
- (AliasTemplate = dyn_cast<TypeAliasTemplateDecl>(Template))) {
+ if (TypeAliasTemplateDecl *AliasTemplate =
+ dyn_cast<TypeAliasTemplateDecl>(Template)) {
// Find the canonical type for this type alias template specialization.
TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl();
if (Pattern->isInvalidDecl())
@@ -2072,10 +2116,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
= dyn_cast<ClassTemplateDecl>(Template)) {
// Find the class template specialization declaration that
// corresponds to these arguments.
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
ClassTemplateSpecializationDecl *Decl
- = ClassTemplate->findSpecialization(Converted.data(), Converted.size(),
- InsertPos);
+ = ClassTemplate->findSpecialization(Converted, InsertPos);
if (!Decl) {
// This is the first time we have referenced this class template
// specialization. Create the canonical declaration and add it to
@@ -2087,7 +2130,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
ClassTemplate->getLocation(),
ClassTemplate,
Converted.data(),
- Converted.size(), 0);
+ Converted.size(), nullptr);
ClassTemplate->AddSpecialization(Decl, InsertPos);
if (ClassTemplate->isOutOfLine())
Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext());
@@ -2267,8 +2310,8 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
}
static bool CheckTemplatePartialSpecializationArgs(
- Sema &S, TemplateParameterList *TemplateParams,
- SmallVectorImpl<TemplateArgument> &TemplateArgs);
+ Sema &S, SourceLocation NameLoc, TemplateParameterList *TemplateParams,
+ unsigned ExplicitArgs, SmallVectorImpl<TemplateArgument> &TemplateArgs);
static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized,
NamedDecl *PrevDecl,
@@ -2340,25 +2383,49 @@ static bool isSameAsPrimaryTemplate(TemplateParameterList *Params,
return true;
}
-DeclResult Sema::ActOnVarTemplateSpecialization(
- Scope *S, VarTemplateDecl *VarTemplate, Declarator &D, TypeSourceInfo *DI,
- SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
- VarDecl::StorageClass SC, bool IsPartialSpecialization) {
- assert(VarTemplate && "A variable template id without template?");
+/// Convert the parser's template argument list representation into our form.
+static TemplateArgumentListInfo
+makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) {
+ TemplateArgumentListInfo TemplateArgs(TemplateId.LAngleLoc,
+ TemplateId.RAngleLoc);
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId.getTemplateArgs(),
+ TemplateId.NumArgs);
+ S.translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
+ return TemplateArgs;
+}
+DeclResult Sema::ActOnVarTemplateSpecialization(
+ Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc,
+ TemplateParameterList *TemplateParams, VarDecl::StorageClass SC,
+ bool IsPartialSpecialization) {
// D must be variable template id.
assert(D.getName().getKind() == UnqualifiedId::IK_TemplateId &&
"Variable template specialization is declared with a template it.");
TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
+ TemplateArgumentListInfo TemplateArgs =
+ makeTemplateArgumentListInfo(*this, *TemplateId);
SourceLocation TemplateNameLoc = D.getIdentifierLoc();
SourceLocation LAngleLoc = TemplateId->LAngleLoc;
SourceLocation RAngleLoc = TemplateId->RAngleLoc;
- ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
- TemplateId->NumArgs);
- TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
- translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
- TemplateName Name(VarTemplate);
+
+ TemplateName Name = TemplateId->Template.get();
+
+ // The template-id must name a variable template.
+ VarTemplateDecl *VarTemplate =
+ dyn_cast_or_null<VarTemplateDecl>(Name.getAsTemplateDecl());
+ if (!VarTemplate) {
+ NamedDecl *FnTemplate;
+ if (auto *OTS = Name.getAsOverloadedTemplate())
+ FnTemplate = *OTS->begin();
+ else
+ FnTemplate = dyn_cast_or_null<FunctionTemplateDecl>(Name.getAsTemplateDecl());
+ if (FnTemplate)
+ return Diag(D.getIdentifierLoc(), diag::err_var_spec_no_template_but_method)
+ << FnTemplate->getDeclName();
+ return Diag(D.getIdentifierLoc(), diag::err_var_spec_no_template)
+ << IsPartialSpecialization;
+ }
// Check for unexpanded parameter packs in any of the template arguments.
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
@@ -2396,7 +2463,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// corresponds to these arguments.
if (IsPartialSpecialization) {
if (CheckTemplatePartialSpecializationArgs(
- *this, VarTemplate->getTemplateParameters(), Converted))
+ *this, TemplateNameLoc, VarTemplate->getTemplateParameters(),
+ TemplateArgs.size(), Converted))
return true;
bool InstantiationDependent;
@@ -2425,18 +2493,16 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
}
}
- void *InsertPos = 0;
- VarTemplateSpecializationDecl *PrevDecl = 0;
+ void *InsertPos = nullptr;
+ VarTemplateSpecializationDecl *PrevDecl = nullptr;
if (IsPartialSpecialization)
// FIXME: Template parameter list matters too
- PrevDecl = VarTemplate->findPartialSpecialization(
- Converted.data(), Converted.size(), InsertPos);
+ PrevDecl = VarTemplate->findPartialSpecialization(Converted, InsertPos);
else
- PrevDecl = VarTemplate->findSpecialization(Converted.data(),
- Converted.size(), InsertPos);
+ PrevDecl = VarTemplate->findSpecialization(Converted, InsertPos);
- VarTemplateSpecializationDecl *Specialization = 0;
+ VarTemplateSpecializationDecl *Specialization = nullptr;
// Check whether we can declare a variable template specialization in
// the current scope.
@@ -2452,7 +2518,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// the list of outer template parameters to reflect our new declaration.
Specialization = PrevDecl;
Specialization->setLocation(TemplateNameLoc);
- PrevDecl = 0;
+ PrevDecl = nullptr;
} else if (IsPartialSpecialization) {
// Create a new class template partial specialization declaration node.
VarTemplatePartialSpecializationDecl *PrevPartial =
@@ -2494,7 +2560,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
<< Param->getDeclName();
else
Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter)
- << "<anonymous>";
+ << "(anonymous)";
}
}
}
@@ -2589,18 +2655,17 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
// Check that the template argument list is well-formed for this template.
SmallVector<TemplateArgument, 4> Converted;
- bool ExpansionIntoFixedList = false;
if (CheckTemplateArgumentList(
Template, TemplateNameLoc,
const_cast<TemplateArgumentListInfo &>(TemplateArgs), false,
- Converted, &ExpansionIntoFixedList))
+ Converted))
return true;
// Find the variable template specialization declaration that
// corresponds to these arguments.
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (VarTemplateSpecializationDecl *Spec = Template->findSpecialization(
- Converted.data(), Converted.size(), InsertPos))
+ Converted, InsertPos))
// If we already have a variable template specialization, return it.
return Spec;
@@ -2652,11 +2717,6 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
}
}
- // If we're dealing with a member template where the template parameters
- // have been instantiated, this provides the original template parameters
- // from which the member template's parameters were instantiated.
- SmallVector<const NamedDecl *, 4> InstantiatedTemplateParameters;
-
if (Matched.size() >= 1) {
SmallVector<MatchResult, 4>::iterator Best = Matched.begin();
if (Matched.size() == 1) {
@@ -2756,7 +2816,7 @@ Sema::CheckVarTemplateId(const CXXScopeSpec &SS,
// Build an ordinary singleton decl ref.
return BuildDeclarationNameExpr(SS, NameInfo, Var,
- /*FoundD=*/0, TemplateArgs);
+ /*FoundD=*/nullptr, TemplateArgs);
}
ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
@@ -2779,10 +2839,13 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
assert(!R.isAmbiguous() && "ambiguous lookup when building templateid");
// In C++1y, check variable template ids.
- if (R.getAsSingle<VarTemplateDecl>()) {
- return Owned(CheckVarTemplateId(SS, R.getLookupNameInfo(),
- R.getAsSingle<VarTemplateDecl>(),
- TemplateKWLoc, TemplateArgs));
+ bool InstantiationDependent;
+ if (R.getAsSingle<VarTemplateDecl>() &&
+ !TemplateSpecializationType::anyDependentTemplateArguments(
+ *TemplateArgs, InstantiationDependent)) {
+ return CheckVarTemplateId(SS, R.getLookupNameInfo(),
+ R.getAsSingle<VarTemplateDecl>(),
+ TemplateKWLoc, TemplateArgs);
}
// We don't want lookup warnings at this point.
@@ -2796,7 +2859,7 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
RequiresADL, TemplateArgs,
R.begin(), R.end());
- return Owned(ULE);
+ return ULE;
}
// We actually only call this from template instantiation.
@@ -2815,7 +2878,7 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
bool MemberOfUnknownSpecialization;
LookupResult R(*this, NameInfo, LookupOrdinaryName);
- LookupTemplateName(R, (Scope*) 0, SS, QualType(), /*Entering*/ false,
+ LookupTemplateName(R, (Scope*)nullptr, SS, QualType(), /*Entering*/ false,
MemberOfUnknownSpecialization);
if (R.isAmbiguous())
@@ -2829,8 +2892,8 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
if (ClassTemplateDecl *Temp = R.getAsSingle<ClassTemplateDecl>()) {
Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_class_template)
- << (NestedNameSpecifier*) SS.getScopeRep()
- << NameInfo.getName() << SS.getRange();
+ << SS.getScopeRep()
+ << NameInfo.getName().getAsString() << SS.getRange();
Diag(Temp->getLocation(), diag::note_referenced_class_template);
return ExprError();
}
@@ -2859,7 +2922,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
diag::ext_template_outside_of_template)
<< FixItHint::CreateRemoval(TemplateKWLoc);
- DeclContext *LookupCtx = 0;
+ DeclContext *LookupCtx = nullptr;
if (SS.isSet())
LookupCtx = computeDeclContext(SS, EnteringContext);
if (!LookupCtx && ObjectType)
@@ -2903,8 +2966,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
}
}
- NestedNameSpecifier *Qualifier
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ NestedNameSpecifier *Qualifier = SS.getScopeRep();
switch (Name.getKind()) {
case UnqualifiedId::IK_Identifier:
@@ -2915,11 +2977,10 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
case UnqualifiedId::IK_OperatorFunctionId:
Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier,
Name.OperatorFunctionId.Operator));
- return TNK_Dependent_template_name;
+ return TNK_Function_template;
case UnqualifiedId::IK_LiteralOperatorId:
- llvm_unreachable(
- "We don't support these; Parse shouldn't have allowed propagation");
+ llvm_unreachable("literal operator id cannot have a dependent scope");
default:
break;
@@ -2934,9 +2995,11 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
}
bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
- const TemplateArgumentLoc &AL,
+ TemplateArgumentLoc &AL,
SmallVectorImpl<TemplateArgument> &Converted) {
const TemplateArgument &Arg = AL.getArgument();
+ QualType ArgType;
+ TypeSourceInfo *TSI = nullptr;
// Check template type parameter.
switch(Arg.getKind()) {
@@ -2944,6 +3007,8 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
// C++ [temp.arg.type]p1:
// A template-argument for a template-parameter which is a
// type shall be a type-id.
+ ArgType = Arg.getAsType();
+ TSI = AL.getTypeSourceInfo();
break;
case TemplateArgument::Template: {
// We have a template type parameter but the template argument
@@ -2978,18 +3043,38 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
}
}
- if (NameInfo.getName().isIdentifier()) {
+ if (auto *II = NameInfo.getName().getAsIdentifierInfo()) {
LookupResult Result(*this, NameInfo, LookupOrdinaryName);
LookupParsedName(Result, CurScope, &SS);
if (Result.getAsSingle<TypeDecl>() ||
Result.getResultKind() ==
- LookupResult::NotFoundInCurrentInstantiation) {
- // FIXME: Add a FixIt and fix up the template argument for recovery.
+ LookupResult::NotFoundInCurrentInstantiation) {
+ // Suggest that the user add 'typename' before the NNS.
SourceLocation Loc = AL.getSourceRange().getBegin();
- Diag(Loc, diag::err_template_arg_must_be_type_suggest);
+ Diag(Loc, getLangOpts().MSVCCompat
+ ? diag::ext_ms_template_type_arg_missing_typename
+ : diag::err_template_arg_must_be_type_suggest)
+ << FixItHint::CreateInsertion(Loc, "typename ");
Diag(Param->getLocation(), diag::note_template_param_here);
- return true;
+
+ // Recover by synthesizing a type using the location information that we
+ // already have.
+ ArgType =
+ Context.getDependentNameType(ETK_Typename, SS.getScopeRep(), II);
+ TypeLocBuilder TLB;
+ DependentNameTypeLoc TL = TLB.push<DependentNameTypeLoc>(ArgType);
+ TL.setElaboratedKeywordLoc(SourceLocation(/*synthesized*/));
+ TL.setQualifierLoc(SS.getWithLocInContext(Context));
+ TL.setNameLoc(NameInfo.getLoc());
+ TSI = TLB.getTypeSourceInfo(Context, ArgType);
+
+ // Overwrite our input TemplateArgumentLoc so that we can recover
+ // properly.
+ AL = TemplateArgumentLoc(TemplateArgument(ArgType),
+ TemplateArgumentLocInfo(TSI));
+
+ break;
}
}
// fallthrough
@@ -3005,11 +3090,11 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
}
}
- if (CheckTemplateArgument(Param, AL.getTypeSourceInfo()))
+ if (CheckTemplateArgument(Param, TSI))
return true;
// Add the converted template type argument.
- QualType ArgType = Context.getCanonicalType(Arg.getAsType());
+ ArgType = Context.getCanonicalType(ArgType);
// Objective-C ARC:
// If an explicitly-specified template argument type is a lifetime type
@@ -3063,7 +3148,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
Template, Converted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
- return 0;
+ return nullptr;
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
Converted.data(), Converted.size());
@@ -3239,7 +3324,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
if (Arg.isInvalid())
return TemplateArgumentLoc();
- Expr *ArgE = Arg.takeAs<Expr>();
+ Expr *ArgE = Arg.getAs<Expr>();
return TemplateArgumentLoc(TemplateArgument(ArgE), ArgE);
}
@@ -3291,7 +3376,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
///
/// \returns true on error, false otherwise.
bool Sema::CheckTemplateArgument(NamedDecl *Param,
- const TemplateArgumentLoc &Arg,
+ TemplateArgumentLoc &Arg,
NamedDecl *Template,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
@@ -3381,21 +3466,20 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
// so it was provided with a template keyword. However, its source
// location is not stored in the template argument structure.
SourceLocation TemplateKWLoc;
- ExprResult E = Owned(DependentScopeDeclRefExpr::Create(Context,
- SS.getWithLocInContext(Context),
- TemplateKWLoc,
- NameInfo, 0));
+ ExprResult E = DependentScopeDeclRefExpr::Create(
+ Context, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo,
+ nullptr);
// If we parsed the template argument as a pack expansion, create a
// pack expansion expression.
if (Arg.getArgument().getKind() == TemplateArgument::TemplateExpansion){
- E = ActOnPackExpansion(E.take(), Arg.getTemplateEllipsisLoc());
+ E = ActOnPackExpansion(E.get(), Arg.getTemplateEllipsisLoc());
if (E.isInvalid())
return true;
}
TemplateArgument Result;
- E = CheckTemplateArgument(NTTP, NTTPType, E.take(), Result);
+ E = CheckTemplateArgument(NTTP, NTTPType, E.get(), Result);
if (E.isInvalid())
return true;
@@ -3555,11 +3639,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs,
bool PartialTemplateArgs,
- SmallVectorImpl<TemplateArgument> &Converted,
- bool *ExpansionIntoFixedList) {
- if (ExpansionIntoFixedList)
- *ExpansionIntoFixedList = false;
-
+ SmallVectorImpl<TemplateArgument> &Converted) {
TemplateParameterList *Params = Template->getTemplateParameters();
SourceLocation RAngleLoc = TemplateArgs.getRAngleLoc();
@@ -3612,6 +3692,20 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
ArgumentPack.size(), Converted))
return true;
+ if (TemplateArgs[ArgIdx].getArgument().isPackExpansion() &&
+ isa<TypeAliasTemplateDecl>(Template) &&
+ !(Param + 1 == ParamEnd && (*Param)->isTemplateParameterPack() &&
+ !getExpandedPackSize(*Param))) {
+ // Core issue 1430: we have a pack expansion as an argument to an
+ // alias template, and it's not part of a final parameter pack. This
+ // can't be canonicalized, so reject it now.
+ Diag(TemplateArgs[ArgIdx].getLocation(),
+ diag::err_alias_template_expansion_into_fixed_list)
+ << TemplateArgs[ArgIdx].getSourceRange();
+ Diag((*Param)->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
// We're now done with this argument.
++ArgIdx;
@@ -3658,9 +3752,6 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
ArgumentPack.data(),
ArgumentPack.size()));
ArgumentPack.clear();
- } else if (ExpansionIntoFixedList) {
- // We have expanded a pack into a fixed list.
- *ExpansionIntoFixedList = true;
}
return false;
@@ -3738,7 +3829,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
if (E.isInvalid())
return true;
- Expr *Ex = E.takeAs<Expr>();
+ Expr *Ex = E.getAs<Expr>();
Arg = TemplateArgumentLoc(TemplateArgument(Ex), Ex);
} else {
TemplateTemplateParmDecl *TempParm
@@ -3785,6 +3876,17 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
++ArgIdx;
}
+ // If we're performing a partial argument substitution, allow any trailing
+ // pack expansions; they might be empty. This can happen even if
+ // PartialTemplateArgs is false (the list of arguments is complete but
+ // still dependent).
+ if (ArgIdx < NumArgs && CurrentInstantiationScope &&
+ CurrentInstantiationScope->getPartiallySubstitutedPack()) {
+ while (ArgIdx < NumArgs &&
+ TemplateArgs[ArgIdx].getArgument().isPackExpansion())
+ Converted.push_back(TemplateArgs[ArgIdx++].getArgument());
+ }
+
// If we have any leftover arguments, then there were too many arguments.
// Complain and fail.
if (ArgIdx < NumArgs)
@@ -3889,19 +3991,17 @@ bool UnnamedLocalNoLinkageFinder::VisitExtVectorType(const ExtVectorType* T) {
bool UnnamedLocalNoLinkageFinder::VisitFunctionProtoType(
const FunctionProtoType* T) {
- for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(),
- AEnd = T->arg_type_end();
- A != AEnd; ++A) {
- if (Visit(*A))
+ for (const auto &A : T->param_types()) {
+ if (Visit(A))
return true;
}
- return Visit(T->getResultType());
+ return Visit(T->getReturnType());
}
bool UnnamedLocalNoLinkageFinder::VisitFunctionNoProtoType(
const FunctionNoProtoType* T) {
- return Visit(T->getResultType());
+ return Visit(T->getReturnType());
}
bool UnnamedLocalNoLinkageFinder::VisitUnresolvedUsingType(
@@ -4057,12 +4157,17 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
//
// C++11 allows these, and even in C++03 we allow them as an extension with
// a warning.
- if (LangOpts.CPlusPlus11 ?
- Diags.getDiagnosticLevel(diag::warn_cxx98_compat_template_arg_unnamed_type,
- SR.getBegin()) != DiagnosticsEngine::Ignored ||
- Diags.getDiagnosticLevel(diag::warn_cxx98_compat_template_arg_local_type,
- SR.getBegin()) != DiagnosticsEngine::Ignored :
- Arg->hasUnnamedOrLocalType()) {
+ bool NeedsCheck;
+ if (LangOpts.CPlusPlus11)
+ NeedsCheck =
+ !Diags.isIgnored(diag::warn_cxx98_compat_template_arg_unnamed_type,
+ SR.getBegin()) ||
+ !Diags.isIgnored(diag::warn_cxx98_compat_template_arg_local_type,
+ SR.getBegin());
+ else
+ NeedsCheck = Arg->hasUnnamedOrLocalType();
+
+ if (NeedsCheck) {
UnnamedLocalNoLinkageFinder Finder(*this, SR);
(void)Finder.Visit(Context.getCanonicalType(Arg));
}
@@ -4091,7 +4196,7 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
ExprResult ArgRV = S.DefaultFunctionArrayConversion(Arg);
if (ArgRV.isInvalid())
return NPV_Error;
- Arg = ArgRV.take();
+ Arg = ArgRV.get();
Expr::EvalResult EvalResult;
SmallVector<PartialDiagnosticAt, 8> Notes;
@@ -4149,10 +4254,9 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
if (Arg->isNullPointerConstant(S.Context, Expr::NPC_NeverValueDependent)) {
std::string Code = "static_cast<" + ParamType.getAsString() + ">(";
S.Diag(Arg->getExprLoc(), diag::err_template_arg_untyped_null_constant)
- << ParamType
- << FixItHint::CreateInsertion(Arg->getLocStart(), Code)
- << FixItHint::CreateInsertion(S.PP.getLocForEndOfToken(Arg->getLocEnd()),
- ")");
+ << ParamType << FixItHint::CreateInsertion(Arg->getLocStart(), Code)
+ << FixItHint::CreateInsertion(S.getLocForEndOfToken(Arg->getLocEnd()),
+ ")");
S.Diag(Param->getLocation(), diag::note_template_param_here);
return NPV_NullPointer;
}
@@ -4232,22 +4336,6 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
Expr *Arg = ArgIn;
QualType ArgType = Arg->getType();
- // If our parameter has pointer type, check for a null template value.
- if (ParamType->isPointerType() || ParamType->isNullPtrType()) {
- switch (isNullPointerValueTemplateArgument(S, Param, ParamType, Arg)) {
- case NPV_NullPointer:
- S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument(ParamType, /*isNullPtr*/true);
- return false;
-
- case NPV_Error:
- return true;
-
- case NPV_NotNullPointer:
- break;
- }
- }
-
bool AddressTaken = false;
SourceLocation AddrOpLoc;
if (S.getLangOpts().MicrosoftExt) {
@@ -4335,6 +4423,33 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
Arg = subst->getReplacement()->IgnoreImpCasts();
}
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg);
+ ValueDecl *Entity = DRE ? DRE->getDecl() : nullptr;
+
+ // If our parameter has pointer type, check for a null template value.
+ if (ParamType->isPointerType() || ParamType->isNullPtrType()) {
+ NullPointerValueKind NPV;
+ // dllimport'd entities aren't constant but are available inside of template
+ // arguments.
+ if (Entity && Entity->hasAttr<DLLImportAttr>())
+ NPV = NPV_NotNullPointer;
+ else
+ NPV = isNullPointerValueTemplateArgument(S, Param, ParamType, ArgIn);
+ switch (NPV) {
+ case NPV_NullPointer:
+ S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
+ Converted = TemplateArgument(S.Context.getCanonicalType(ParamType),
+ /*isNullPtr=*/true);
+ return false;
+
+ case NPV_Error:
+ return true;
+
+ case NPV_NotNullPointer:
+ break;
+ }
+ }
+
// Stop checking the precise nature of the argument if it is value dependent,
// it should be checked when instantiated.
if (Arg->isValueDependent()) {
@@ -4351,7 +4466,6 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
return false;
}
- DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg);
if (!DRE) {
S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
<< Arg->getSourceRange();
@@ -4359,8 +4473,6 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
return true;
}
- ValueDecl *Entity = DRE->getDecl();
-
// Cannot refer to non-static data members
if (isa<FieldDecl>(Entity) || isa<IndirectFieldDecl>(Entity)) {
S.Diag(Arg->getLocStart(), diag::err_template_arg_field)
@@ -4522,7 +4634,10 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
return true;
case NPV_NullPointer:
S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument(ParamType, /*isNullPtr*/true);
+ Converted = TemplateArgument(S.Context.getCanonicalType(ParamType),
+ /*isNullPtr*/true);
+ if (S.Context.getTargetInfo().getCXXABI().isMicrosoft())
+ S.RequireCompleteType(Arg->getExprLoc(), ParamType, 0);
return false;
case NPV_NotNullPointer:
break;
@@ -4533,7 +4648,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
ParamType.getNonReferenceType(),
false, ObjCLifetimeConversion)) {
Arg = S.ImpCastExprToType(Arg, ParamType, CK_NoOp,
- Arg->getValueKind()).take();
+ Arg->getValueKind()).get();
ResultArg = Arg;
} else if (!S.Context.hasSameUnqualifiedType(Arg->getType(),
ParamType.getNonReferenceType())) {
@@ -4554,7 +4669,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
// template-parameter shall be one of: [...]
//
// -- a pointer to member expressed as described in 5.3.1.
- DeclRefExpr *DRE = 0;
+ DeclRefExpr *DRE = nullptr;
// 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
@@ -4581,7 +4696,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
if (UnOp->getOpcode() == UO_AddrOf) {
DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr());
if (DRE && !DRE->getQualifier())
- DRE = 0;
+ DRE = nullptr;
}
}
// A constant of pointer-to-member type.
@@ -4600,7 +4715,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
}
}
- DRE = 0;
+ DRE = nullptr;
}
if (!DRE)
@@ -4654,7 +4769,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) {
// FIXME: Produce a cloned, canonical expression?
Converted = TemplateArgument(Arg);
- return Owned(Arg);
+ return Arg;
}
// C++ [temp.arg.nontype]p5:
@@ -4698,7 +4813,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// we should be able to diagnose that prior to instantiation.
if (Arg->isValueDependent()) {
Converted = TemplateArgument(Arg);
- return Owned(Arg);
+ return Arg;
}
// C++ [temp.arg.nontype]p1:
@@ -4731,7 +4846,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
ExprResult ArgResult = DefaultLvalueConversion(Arg);
if (ArgResult.isInvalid())
return ExprError();
- Arg = ArgResult.take();
+ Arg = ArgResult.get();
QualType ArgType = Arg->getType();
@@ -4756,15 +4871,15 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
public:
TmplArgICEDiagnoser(QualType T) : T(T) { }
-
- virtual void diagnoseNotICE(Sema &S, SourceLocation Loc,
- SourceRange SR) {
+
+ void diagnoseNotICE(Sema &S, SourceLocation Loc,
+ SourceRange SR) override {
S.Diag(Loc, diag::err_template_arg_not_ice) << T << SR;
}
} Diagnoser(ArgType);
Arg = VerifyIntegerConstantExpression(Arg, &Value, Diagnoser,
- false).take();
+ false).get();
if (!Arg)
return ExprError();
}
@@ -4779,11 +4894,11 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// Okay: no conversion necessary
} else if (ParamType->isBooleanType()) {
// This is an integral-to-boolean conversion.
- Arg = ImpCastExprToType(Arg, ParamType, CK_IntegralToBoolean).take();
+ Arg = ImpCastExprToType(Arg, ParamType, CK_IntegralToBoolean).get();
} else if (IsIntegralPromotion(Arg, ArgType, ParamType) ||
!ParamType->isEnumeralType()) {
// This is an integral promotion or conversion.
- Arg = ImpCastExprToType(Arg, ParamType, CK_IntegralCast).take();
+ Arg = ImpCastExprToType(Arg, ParamType, CK_IntegralCast).get();
} else {
// We can't perform this conversion.
Diag(Arg->getLocStart(),
@@ -4800,7 +4915,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// The argument is value-dependent. Create a new
// TemplateArgument with the converted expression.
Converted = TemplateArgument(Arg);
- return Owned(Arg);
+ return Arg;
}
QualType IntegerType = Context.getCanonicalType(ParamType);
@@ -4854,7 +4969,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
ParamType->isEnumeralType()
? Context.getCanonicalType(ParamType)
: IntegerType);
- return Owned(Arg);
+ return Arg;
}
QualType ArgType = Arg->getType();
@@ -4902,13 +5017,13 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
ParamType,
Arg, Converted))
return ExprError();
- return Owned(Arg);
+ return Arg;
}
if (CheckTemplateArgumentPointerToMember(*this, Param, ParamType, Arg,
Converted))
return ExprError();
- return Owned(Arg);
+ return Arg;
}
if (ParamType->isPointerType()) {
@@ -4923,7 +5038,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
ParamType,
Arg, Converted))
return ExprError();
- return Owned(Arg);
+ return Arg;
}
if (const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>()) {
@@ -4954,14 +5069,14 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
ParamType,
Arg, Converted))
return ExprError();
- return Owned(Arg);
+ return Arg;
}
// Deal with parameters of type std::nullptr_t.
if (ParamType->isNullPtrType()) {
if (Arg->isTypeDependent() || Arg->isValueDependent()) {
Converted = TemplateArgument(Arg);
- return Owned(Arg);
+ return Arg;
}
switch (isNullPointerValueTemplateArgument(*this, Param, ParamType, Arg)) {
@@ -4976,8 +5091,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
case NPV_NullPointer:
Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument(ParamType, /*isNullPtr*/true);
- return Owned(Arg);
+ Converted = TemplateArgument(Context.getCanonicalType(ParamType),
+ /*isNullPtr*/true);
+ return Arg;
}
}
@@ -4988,7 +5104,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CheckTemplateArgumentPointerToMember(*this, Param, ParamType, Arg,
Converted))
return ExprError();
- return Owned(Arg);
+ return Arg;
}
/// \brief Check a template argument against its corresponding
@@ -4997,7 +5113,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
/// This routine implements the semantics of C++ [temp.arg.template].
/// It returns true if an error occurred, and false otherwise.
bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
- const TemplateArgumentLoc &Arg,
+ TemplateArgumentLoc &Arg,
unsigned ArgumentPackIndex) {
TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern();
TemplateDecl *Template = Name.getAsTemplateDecl();
@@ -5085,7 +5201,7 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
QualType ClassType
= Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext()));
NestedNameSpecifier *Qualifier
- = NestedNameSpecifier::Create(Context, 0, false,
+ = NestedNameSpecifier::Create(Context, nullptr, false,
ClassType.getTypePtr());
CXXScopeSpec SS;
SS.MakeTrivial(Context, Qualifier, Loc);
@@ -5114,7 +5230,7 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(),
ParamType.getUnqualifiedType(), false,
ObjCLifetimeConversion))
- RefExpr = ImpCastExprToType(RefExpr.take(), ParamType.getUnqualifiedType(), CK_NoOp);
+ RefExpr = ImpCastExprToType(RefExpr.get(), ParamType.getUnqualifiedType(), CK_NoOp);
assert(!RefExpr.isInvalid() &&
Context.hasSameType(((Expr*) RefExpr.get())->getType(),
@@ -5134,7 +5250,7 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
if (T->isFunctionType() || T->isArrayType()) {
// Decay functions and arrays.
- RefExpr = DefaultFunctionArrayConversion(RefExpr.take());
+ RefExpr = DefaultFunctionArrayConversion(RefExpr.get());
if (RefExpr.isInvalid())
return ExprError();
@@ -5211,12 +5327,13 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
if (OrigT->isEnumeralType()) {
// FIXME: This is a hack. We need a better way to handle substituted
// non-type template parameters.
- E = CStyleCastExpr::Create(Context, OrigT, VK_RValue, CK_IntegralCast, E, 0,
+ E = CStyleCastExpr::Create(Context, OrigT, VK_RValue, CK_IntegralCast, E,
+ nullptr,
Context.getTrivialTypeSourceInfo(OrigT, Loc),
Loc, Loc);
}
- return Owned(E);
+ return E;
}
/// \brief Match two template parameters within template parameter lists.
@@ -5450,18 +5567,19 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
(S->getFlags() & Scope::TemplateParamScope) != 0)
S = S->getParent();
- // C++ [temp]p2:
- // A template-declaration can appear only as a namespace scope or
- // class scope declaration.
+ // C++ [temp]p4:
+ // A template [...] shall not have C linkage.
DeclContext *Ctx = S->getEntity();
- if (Ctx && isa<LinkageSpecDecl>(Ctx) &&
- cast<LinkageSpecDecl>(Ctx)->getLanguage() != LinkageSpecDecl::lang_cxx)
+ if (Ctx && Ctx->isExternCContext())
return Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage)
<< TemplateParams->getSourceRange();
while (Ctx && isa<LinkageSpecDecl>(Ctx))
Ctx = Ctx->getParent();
+ // C++ [temp]p2:
+ // A template-declaration can appear only as a namespace scope or
+ // class scope declaration.
if (Ctx) {
if (Ctx->isFileContext())
return false;
@@ -5598,13 +5716,37 @@ static bool CheckTemplateSpecializationScope(Sema &S,
// A class template partial specialization may be declared or redeclared
// in any namespace scope in which its definition may be defined (14.5.1
// and 14.5.2).
- bool ComplainedAboutScope = false;
- DeclContext *SpecializedContext
+ DeclContext *SpecializedContext
= Specialized->getDeclContext()->getEnclosingNamespaceContext();
DeclContext *DC = S.CurContext->getEnclosingNamespaceContext();
- if ((!PrevDecl ||
- getTemplateSpecializationKind(PrevDecl) == TSK_Undeclared ||
- getTemplateSpecializationKind(PrevDecl) == TSK_ImplicitInstantiation)){
+
+ // Make sure that this redeclaration (or definition) occurs in an enclosing
+ // namespace.
+ // Note that HandleDeclarator() performs this check for explicit
+ // specializations of function templates, static data members, and member
+ // functions, so we skip the check here for those kinds of entities.
+ // FIXME: HandleDeclarator's diagnostics aren't quite as good, though.
+ // Should we refactor that check, so that it occurs later?
+ if (!DC->Encloses(SpecializedContext) &&
+ !(isa<FunctionTemplateDecl>(Specialized) ||
+ isa<FunctionDecl>(Specialized) ||
+ isa<VarTemplateDecl>(Specialized) ||
+ isa<VarDecl>(Specialized))) {
+ if (isa<TranslationUnitDecl>(SpecializedContext))
+ S.Diag(Loc, diag::err_template_spec_redecl_global_scope)
+ << EntityKind << Specialized;
+ else if (isa<NamespaceDecl>(SpecializedContext))
+ S.Diag(Loc, diag::err_template_spec_redecl_out_of_scope)
+ << EntityKind << Specialized
+ << cast<NamedDecl>(SpecializedContext);
+ else
+ llvm_unreachable("unexpected namespace context for specialization");
+
+ S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
+ } else if ((!PrevDecl ||
+ getTemplateSpecializationKind(PrevDecl) == TSK_Undeclared ||
+ getTemplateSpecializationKind(PrevDecl) ==
+ TSK_ImplicitInstantiation)) {
// C++ [temp.exp.spec]p2:
// An explicit specialization shall be declared in the namespace of which
// the template is a member, or, for member templates, in the namespace
@@ -5613,9 +5755,12 @@ static bool CheckTemplateSpecializationScope(Sema &S,
// static data member of a class template shall be declared in the
// namespace of which the class template is a member.
//
- // C++0x [temp.expl.spec]p2:
+ // C++11 [temp.expl.spec]p2:
// An explicit specialization shall be declared in a namespace enclosing
// the specialized template.
+ // C++11 [temp.explicit]p3:
+ // An explicit instantiation shall appear in an enclosing namespace of its
+ // template.
if (!DC->InEnclosingNamespaceSetOf(SpecializedContext)) {
bool IsCPlusPlus11Extension = DC->Encloses(SpecializedContext);
if (isa<TranslationUnitDecl>(SpecializedContext)) {
@@ -5636,46 +5781,42 @@ static bool CheckTemplateSpecializationScope(Sema &S,
}
S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
- ComplainedAboutScope =
- !(IsCPlusPlus11Extension && S.getLangOpts().CPlusPlus11);
}
}
- // Make sure that this redeclaration (or definition) occurs in an enclosing
- // namespace.
- // Note that HandleDeclarator() performs this check for explicit
- // specializations of function templates, static data members, and member
- // functions, so we skip the check here for those kinds of entities.
- // FIXME: HandleDeclarator's diagnostics aren't quite as good, though.
- // Should we refactor that check, so that it occurs later?
- if (!ComplainedAboutScope && !DC->Encloses(SpecializedContext) &&
- !(isa<FunctionTemplateDecl>(Specialized) || isa<VarDecl>(Specialized) ||
- isa<FunctionDecl>(Specialized))) {
- if (isa<TranslationUnitDecl>(SpecializedContext))
- S.Diag(Loc, diag::err_template_spec_redecl_global_scope)
- << EntityKind << Specialized;
- else if (isa<NamespaceDecl>(SpecializedContext))
- S.Diag(Loc, diag::err_template_spec_redecl_out_of_scope)
- << EntityKind << Specialized
- << cast<NamedDecl>(SpecializedContext);
-
- S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
- }
+ return false;
+}
- // FIXME: check for specialization-after-instantiation errors and such.
+static SourceRange findTemplateParameter(unsigned Depth, Expr *E) {
+ if (!E->isInstantiationDependent())
+ return SourceLocation();
+ DependencyChecker Checker(Depth);
+ Checker.TraverseStmt(E);
+ if (Checker.Match && Checker.MatchLoc.isInvalid())
+ return E->getSourceRange();
+ return Checker.MatchLoc;
+}
- return false;
+static SourceRange findTemplateParameter(unsigned Depth, TypeLoc TL) {
+ if (!TL.getType()->isDependentType())
+ return SourceLocation();
+ DependencyChecker Checker(Depth);
+ Checker.TraverseTypeLoc(TL);
+ if (Checker.Match && Checker.MatchLoc.isInvalid())
+ return TL.getSourceRange();
+ return Checker.MatchLoc;
}
/// \brief Subroutine of Sema::CheckTemplatePartialSpecializationArgs
/// that checks non-type template partial specialization arguments.
static bool CheckNonTypeTemplatePartialSpecializationArgs(
- Sema &S, NonTypeTemplateParmDecl *Param, const TemplateArgument *Args,
- unsigned NumArgs) {
+ Sema &S, SourceLocation TemplateNameLoc, NonTypeTemplateParmDecl *Param,
+ const TemplateArgument *Args, unsigned NumArgs, bool IsDefaultArgument) {
for (unsigned I = 0; I != NumArgs; ++I) {
if (Args[I].getKind() == TemplateArgument::Pack) {
if (CheckNonTypeTemplatePartialSpecializationArgs(
- S, Param, Args[I].pack_begin(), Args[I].pack_size()))
+ S, TemplateNameLoc, Param, Args[I].pack_begin(),
+ Args[I].pack_size(), IsDefaultArgument))
return true;
continue;
@@ -5713,22 +5854,43 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs(
// shall not involve a template parameter of the partial
// specialization except when the argument expression is a
// simple identifier.
- if (ArgExpr->isTypeDependent() || ArgExpr->isValueDependent()) {
- S.Diag(ArgExpr->getLocStart(),
- diag::err_dependent_non_type_arg_in_partial_spec)
- << ArgExpr->getSourceRange();
+ SourceRange ParamUseRange =
+ findTemplateParameter(Param->getDepth(), ArgExpr);
+ if (ParamUseRange.isValid()) {
+ if (IsDefaultArgument) {
+ S.Diag(TemplateNameLoc,
+ diag::err_dependent_non_type_arg_in_partial_spec);
+ S.Diag(ParamUseRange.getBegin(),
+ diag::note_dependent_non_type_default_arg_in_partial_spec)
+ << ParamUseRange;
+ } else {
+ S.Diag(ParamUseRange.getBegin(),
+ diag::err_dependent_non_type_arg_in_partial_spec)
+ << ParamUseRange;
+ }
return true;
}
// -- The type of a template parameter corresponding to a
// specialized non-type argument shall not be dependent on a
// parameter of the specialization.
- if (Param->getType()->isDependentType()) {
- S.Diag(ArgExpr->getLocStart(),
- diag::err_dependent_typed_non_type_arg_in_partial_spec)
- << Param->getType()
- << ArgExpr->getSourceRange();
- S.Diag(Param->getLocation(), diag::note_template_param_here);
+ //
+ // FIXME: We need to delay this check until instantiation in some cases:
+ //
+ // template<template<typename> class X> struct A {
+ // template<typename T, X<T> N> struct B;
+ // template<typename T> struct B<T, 0>;
+ // };
+ // template<typename> using X = int;
+ // A<X>::B<int, 0> b;
+ ParamUseRange = findTemplateParameter(
+ Param->getDepth(), Param->getTypeSourceInfo()->getTypeLoc());
+ if (ParamUseRange.isValid()) {
+ S.Diag(IsDefaultArgument ? TemplateNameLoc : ArgExpr->getLocStart(),
+ diag::err_dependent_typed_non_type_arg_in_partial_spec)
+ << Param->getType() << ParamUseRange;
+ S.Diag(Param->getLocation(), diag::note_template_param_here)
+ << (IsDefaultArgument ? ParamUseRange : SourceRange());
return true;
}
}
@@ -5739,15 +5901,17 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs(
/// \brief Check the non-type template arguments of a class template
/// partial specialization according to C++ [temp.class.spec]p9.
///
+/// \param TemplateNameLoc the location of the template name.
/// \param TemplateParams the template parameters of the primary class
-/// template.
-///
+/// template.
+/// \param NumExplicit the number of explicitly-specified template arguments.
/// \param TemplateArgs the template arguments of the class template
-/// partial specialization.
+/// partial specialization.
///
-/// \returns true if there was an error, false otherwise.
+/// \returns \c true if there was an error, \c false otherwise.
static bool CheckTemplatePartialSpecializationArgs(
- Sema &S, TemplateParameterList *TemplateParams,
+ Sema &S, SourceLocation TemplateNameLoc,
+ TemplateParameterList *TemplateParams, unsigned NumExplicit,
SmallVectorImpl<TemplateArgument> &TemplateArgs) {
const TemplateArgument *ArgList = TemplateArgs.data();
@@ -5757,7 +5921,8 @@ static bool CheckTemplatePartialSpecializationArgs(
if (!Param)
continue;
- if (CheckNonTypeTemplatePartialSpecializationArgs(S, Param, &ArgList[I], 1))
+ if (CheckNonTypeTemplatePartialSpecializationArgs(
+ S, TemplateNameLoc, Param, &ArgList[I], 1, I >= NumExplicit))
return true;
}
@@ -5769,23 +5934,23 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TagUseKind TUK,
SourceLocation KWLoc,
SourceLocation ModulePrivateLoc,
- CXXScopeSpec &SS,
- TemplateTy TemplateD,
- SourceLocation TemplateNameLoc,
- SourceLocation LAngleLoc,
- ASTTemplateArgsPtr TemplateArgsIn,
- SourceLocation RAngleLoc,
+ TemplateIdAnnotation &TemplateId,
AttributeList *Attr,
MultiTemplateParamsArg TemplateParameterLists) {
assert(TUK != TUK_Reference && "References are not specializations");
+ CXXScopeSpec &SS = TemplateId.SS;
+
// NOTE: KWLoc is the location of the tag keyword. This will instead
// store the location of the outermost template keyword in the declaration.
SourceLocation TemplateKWLoc = TemplateParameterLists.size() > 0
- ? TemplateParameterLists[0]->getTemplateLoc() : SourceLocation();
+ ? TemplateParameterLists[0]->getTemplateLoc() : KWLoc;
+ SourceLocation TemplateNameLoc = TemplateId.TemplateNameLoc;
+ SourceLocation LAngleLoc = TemplateId.LAngleLoc;
+ SourceLocation RAngleLoc = TemplateId.RAngleLoc;
// Find the class template we're specializing
- TemplateName Name = TemplateD.get();
+ TemplateName Name = TemplateId.Template.get();
ClassTemplateDecl *ClassTemplate
= dyn_cast_or_null<ClassTemplateDecl>(Name.getAsTemplateDecl());
@@ -5806,8 +5971,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
bool Invalid = false;
TemplateParameterList *TemplateParams =
MatchTemplateParametersToScopeSpecifier(
- TemplateNameLoc, TemplateNameLoc, SS, TemplateParameterLists,
- TUK == TUK_Friend, isExplicitSpecialization, Invalid);
+ KWLoc, TemplateNameLoc, SS, &TemplateId,
+ TemplateParameterLists, TUK == TUK_Friend, isExplicitSpecialization,
+ Invalid);
if (Invalid)
return true;
@@ -5858,11 +6024,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
<< SourceRange(LAngleLoc, RAngleLoc);
else
isExplicitSpecialization = true;
- } else if (TUK != TUK_Friend) {
- Diag(KWLoc, diag::err_template_spec_needs_header)
- << FixItHint::CreateInsertion(KWLoc, "template<> ");
- TemplateKWLoc = KWLoc;
- isExplicitSpecialization = true;
+ } else {
+ assert(TUK == TUK_Friend && "should have a 'template<>' for this decl");
}
// Check that the specialization uses the same tag kind as the
@@ -5882,10 +6045,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
}
// Translate the parser's template argument list in our AST format.
- TemplateArgumentListInfo TemplateArgs;
- TemplateArgs.setLAngleLoc(LAngleLoc);
- TemplateArgs.setRAngleLoc(RAngleLoc);
- translateTemplateArguments(TemplateArgsIn, TemplateArgs);
+ TemplateArgumentListInfo TemplateArgs =
+ makeTemplateArgumentListInfo(*this, TemplateId);
// Check for unexpanded parameter packs in any of the template arguments.
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
@@ -5904,7 +6065,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// corresponds to these arguments.
if (isPartialSpecialization) {
if (CheckTemplatePartialSpecializationArgs(
- *this, ClassTemplate->getTemplateParameters(), Converted))
+ *this, TemplateNameLoc, ClassTemplate->getTemplateParameters(),
+ TemplateArgs.size(), Converted))
return true;
bool InstantiationDependent;
@@ -5919,21 +6081,16 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
}
}
- void *InsertPos = 0;
- ClassTemplateSpecializationDecl *PrevDecl = 0;
+ void *InsertPos = nullptr;
+ ClassTemplateSpecializationDecl *PrevDecl = nullptr;
if (isPartialSpecialization)
// FIXME: Template parameter list matters, too
- PrevDecl
- = ClassTemplate->findPartialSpecialization(Converted.data(),
- Converted.size(),
- InsertPos);
+ PrevDecl = ClassTemplate->findPartialSpecialization(Converted, InsertPos);
else
- PrevDecl
- = ClassTemplate->findSpecialization(Converted.data(),
- Converted.size(), InsertPos);
+ PrevDecl = ClassTemplate->findSpecialization(Converted, InsertPos);
- ClassTemplateSpecializationDecl *Specialization = 0;
+ ClassTemplateSpecializationDecl *Specialization = nullptr;
// Check whether we can declare a class template specialization in
// the current scope.
@@ -5945,24 +6102,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// The canonical type
QualType CanonType;
- if (PrevDecl &&
- (PrevDecl->getSpecializationKind() == TSK_Undeclared ||
- TUK == TUK_Friend)) {
- // Since the only prior class template specialization with these
- // arguments was referenced but not declared, or we're only
- // referencing this specialization as a friend, reuse that
- // declaration node as our own, updating its source location and
- // the list of outer template parameters to reflect our new declaration.
- Specialization = PrevDecl;
- Specialization->setLocation(TemplateNameLoc);
- if (TemplateParameterLists.size() > 0) {
- Specialization->setTemplateParameterListsInfo(Context,
- TemplateParameterLists.size(),
- TemplateParameterLists.data());
- }
- PrevDecl = 0;
- CanonType = Context.getTypeDeclType(Specialization);
- } else if (isPartialSpecialization) {
+ if (isPartialSpecialization) {
// Build the canonical type that describes the converted template
// arguments of the class template partial specialization.
TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
@@ -5985,6 +6125,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
Attr,
TemplateParams,
AS_none, /*ModulePrivateLoc=*/SourceLocation(),
+ /*FriendLoc*/SourceLocation(),
TemplateParameterLists.size() - 1,
TemplateParameterLists.data());
}
@@ -6043,7 +6184,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
else
Diag(Param->getLocation(),
diag::note_partial_spec_unused_parameter)
- << "<anonymous>";
+ << "(anonymous)";
}
}
}
@@ -6187,7 +6328,7 @@ Decl *Sema::ActOnTemplateDeclarator(Scope *S,
Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D) {
- assert(getCurFunctionDecl() == 0 && "Function parsing confused");
+ assert(getCurFunctionDecl() == nullptr && "Function parsing confused");
DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
if (FTI.hasPrototype) {
@@ -6210,10 +6351,8 @@ static void StripImplicitInstantiation(NamedDecl *D) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
FD->setInlineSpecified(false);
- for (FunctionDecl::param_iterator I = FD->param_begin(),
- E = FD->param_end();
- I != E; ++I)
- (*I)->dropAttrs();
+ for (auto I : FD->params())
+ I->dropAttrs();
}
}
@@ -6407,8 +6546,12 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
// For a given template and a given set of template-arguments,
// - an explicit instantiation definition shall appear at most once
// in a program,
- Diag(NewLoc, diag::err_explicit_instantiation_duplicate)
- << PrevDecl;
+
+ // MSVCCompat: MSVC silently ignores duplicate explicit instantiations.
+ Diag(NewLoc, (getLangOpts().MSVCCompat)
+ ? diag::ext_explicit_instantiation_duplicate
+ : diag::err_explicit_instantiation_duplicate)
+ << PrevDecl;
Diag(DiagLocForExplicitInstantiation(PrevDecl, PrevPointOfInstantiation),
diag::note_previous_explicit_instantiation);
HasNoEffect = true;
@@ -6509,8 +6652,8 @@ bool Sema::CheckFunctionTemplateSpecialization(
const FunctionProtoType *FPT = FT->castAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.TypeQuals |= Qualifiers::Const;
- FT = Context.getFunctionType(FPT->getResultType(), FPT->getArgTypes(),
- EPI);
+ FT = Context.getFunctionType(FPT->getReturnType(),
+ FPT->getParamTypes(), EPI);
}
}
@@ -6522,7 +6665,7 @@ bool Sema::CheckFunctionTemplateSpecialization(
// specializing this template.
// FIXME: It is somewhat wasteful to build
TemplateDeductionInfo Info(FailedCandidates.getLocation());
- FunctionDecl *Specialization = 0;
+ FunctionDecl *Specialization = nullptr;
if (TemplateDeductionResult TDK = DeduceTemplateArguments(
cast<FunctionTemplateDecl>(FunTmpl->getFirstDecl()),
ExplicitTemplateArgs, FT, Specialization, Info)) {
@@ -6546,7 +6689,7 @@ bool Sema::CheckFunctionTemplateSpecialization(
FD->getLocation(),
PDiag(diag::err_function_template_spec_no_match) << FD->getDeclName(),
PDiag(diag::err_function_template_spec_ambiguous)
- << FD->getDeclName() << (ExplicitTemplateArgs != 0),
+ << FD->getDeclName() << (ExplicitTemplateArgs != nullptr),
PDiag(diag::note_function_template_spec_matched));
if (Result == Candidates.end())
@@ -6615,7 +6758,7 @@ bool Sema::CheckFunctionTemplateSpecialization(
const TemplateArgumentList* TemplArgs = new (Context)
TemplateArgumentList(Specialization->getTemplateSpecializationArgs());
FD->setFunctionTemplateSpecialization(Specialization->getPrimaryTemplate(),
- TemplArgs, /*InsertPos=*/0,
+ TemplArgs, /*InsertPos=*/nullptr,
SpecInfo->getTemplateSpecializationKind(),
ExplicitTemplateArgs);
@@ -6645,9 +6788,9 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
assert(!isa<TemplateDecl>(Member) && "Only for non-template members");
// Try to find the member we are instantiating.
- NamedDecl *Instantiation = 0;
- NamedDecl *InstantiatedFrom = 0;
- MemberSpecializationInfo *MSInfo = 0;
+ NamedDecl *Instantiation = nullptr;
+ NamedDecl *InstantiatedFrom = nullptr;
+ MemberSpecializationInfo *MSInfo = nullptr;
if (Previous.empty()) {
// Nowhere to look anyway.
@@ -6656,7 +6799,10 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
I != E; ++I) {
NamedDecl *D = (*I)->getUnderlyingDecl();
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
- if (Context.hasSameType(Function->getType(), Method->getType())) {
+ QualType Adjusted = Function->getType();
+ if (!hasExplicitCallingConv(Adjusted))
+ Adjusted = adjustCCAndNoReturn(Adjusted, Method->getType());
+ if (Context.hasSameType(Adjusted, Method->getType())) {
Instantiation = Method;
InstantiatedFrom = Method->getInstantiatedFromMemberFunction();
MSInfo = Method->getMemberSpecializationInfo();
@@ -6877,8 +7023,8 @@ static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) {
// name shall be a simple-template-id.
//
// C++98 has the same restriction, just worded differently.
- for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
- NNS; NNS = NNS->getPrefix())
+ for (NestedNameSpecifier *NNS = SS.getScopeRep(); NNS;
+ NNS = NNS->getPrefix())
if (const Type *T = NNS->getAsType())
if (isa<TemplateSpecializationType>(T))
return true;
@@ -6951,10 +7097,9 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// Find the class template specialization declaration that
// corresponds to these arguments.
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
ClassTemplateSpecializationDecl *PrevDecl
- = ClassTemplate->findSpecialization(Converted.data(),
- Converted.size(), InsertPos);
+ = ClassTemplate->findSpecialization(Converted, InsertPos);
TemplateSpecializationKind PrevDecl_TSK
= PrevDecl ? PrevDecl->getTemplateSpecializationKind() : TSK_Undeclared;
@@ -6968,7 +7113,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
SS.isSet()))
return true;
- ClassTemplateSpecializationDecl *Specialization = 0;
+ ClassTemplateSpecializationDecl *Specialization = nullptr;
bool HasNoEffect = false;
if (PrevDecl) {
@@ -6990,7 +7135,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// (Other source locations will be updated later.)
Specialization = PrevDecl;
Specialization->setLocation(TemplateNameLoc);
- PrevDecl = 0;
+ PrevDecl = nullptr;
}
}
@@ -7074,6 +7219,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// TSK_ExplicitInstantiationDefinition
if (Old_TSK == TSK_ExplicitInstantiationDeclaration &&
TSK == TSK_ExplicitInstantiationDefinition)
+ // FIXME: Need to notify the ASTMutationListener that we did this.
Def->setTemplateSpecializationKind(TSK);
InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK);
@@ -7102,7 +7248,8 @@ Sema::ActOnExplicitInstantiation(Scope *S,
KWLoc, SS, Name, NameLoc, Attr, AS_none,
/*ModulePrivateLoc=*/SourceLocation(),
MultiTemplateParamsArg(), Owned, IsDependent,
- SourceLocation(), false, TypeResult());
+ SourceLocation(), false, TypeResult(),
+ /*IsTypeSpecifier*/false);
assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
if (!TagD)
@@ -7342,13 +7489,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
}
// Translate the parser's template argument list into our AST format.
- TemplateArgumentListInfo TemplateArgs;
- TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
- TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);
- TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc);
- ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
- TemplateId->NumArgs);
- translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
+ TemplateArgumentListInfo TemplateArgs =
+ makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc,
D.getIdentifierLoc(), TemplateArgs);
@@ -7410,7 +7552,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
}
// FIXME: Create an ExplicitInstantiation node?
- return (Decl*) 0;
+ return (Decl*) nullptr;
}
// If the declarator is a template-id, translate the parser's template
@@ -7418,12 +7560,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
bool HasExplicitTemplateArgs = false;
TemplateArgumentListInfo TemplateArgs;
if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) {
- TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
- TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);
- TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc);
- ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
- TemplateId->NumArgs);
- translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
+ TemplateArgs = makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
HasExplicitTemplateArgs = true;
}
@@ -7455,10 +7592,11 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
continue;
TemplateDeductionInfo Info(FailedCandidates.getLocation());
- FunctionDecl *Specialization = 0;
+ FunctionDecl *Specialization = nullptr;
if (TemplateDeductionResult TDK
= DeduceTemplateArguments(FunTmpl,
- (HasExplicitTemplateArgs ? &TemplateArgs : 0),
+ (HasExplicitTemplateArgs ? &TemplateArgs
+ : nullptr),
R, Specialization, Info)) {
// Keep track of almost-matches.
FailedCandidates.addCandidate()
@@ -7511,7 +7649,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// FIXME: We may still want to build some representation of this
// explicit specialization.
if (HasNoEffect)
- return (Decl*) 0;
+ return (Decl*) nullptr;
}
Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
@@ -7519,7 +7657,11 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (Attr)
ProcessDeclAttributeList(S, Specialization, Attr);
- if (TSK == TSK_ExplicitInstantiationDefinition)
+ if (Specialization->isDefined()) {
+ // Let the ASTConsumer know that this function has been explicitly
+ // instantiated now, and its linkage might have changed.
+ Consumer.HandleTopLevelDecl(DeclGroupRef(Specialization));
+ } else if (TSK == TSK_ExplicitInstantiationDefinition)
InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization);
// C++0x [temp.explicit]p2:
@@ -7544,7 +7686,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
D.getCXXScopeSpec().isSet());
// FIXME: Create some kind of ExplicitInstantiationDecl here.
- return (Decl*) 0;
+ return (Decl*) nullptr;
}
TypeResult
@@ -7554,8 +7696,7 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// This has to hold, because SS is expected to be defined.
assert(Name && "Expected a name in a dependent tag");
- NestedNameSpecifier *NNS
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ NestedNameSpecifier *NNS = SS.getScopeRep();
if (!NNS)
return true;
@@ -7641,8 +7782,7 @@ Sema::ActOnTypenameType(Scope *S,
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
// Construct a dependent template specialization type.
assert(DTN && "dependent template has non-dependent name?");
- assert(DTN->getQualifier()
- == static_cast<NestedNameSpecifier*>(SS.getScopeRep()));
+ assert(DTN->getQualifier() == SS.getScopeRep());
QualType T = Context.getDependentTemplateSpecializationType(ETK_Typename,
DTN->getQualifier(),
DTN->getIdentifier(),
@@ -7758,7 +7898,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
LookupResult Result(*this, Name, IILoc, LookupOrdinaryName);
LookupQualifiedName(Result, Ctx);
unsigned DiagID = 0;
- Decl *Referenced = 0;
+ Decl *Referenced = nullptr;
switch (Result.getResultKind()) {
case LookupResult::NotFound: {
// If we're looking up 'type' within a template named 'enable_if', produce
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 8d66ff68efa6..53a75d227c7b 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -126,7 +126,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
unsigned TDF,
bool PartialOrdering = false,
SmallVectorImpl<RefParamPartialOrderingComparison> *
- RefParamComparisons = 0);
+ RefParamComparisons = nullptr);
static Sema::TemplateDeductionResult
DeduceTemplateArguments(Sema &S,
@@ -155,7 +155,7 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) {
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
return dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl());
- return 0;
+ return nullptr;
}
/// \brief Determine whether two declaration pointers refer to the same
@@ -297,6 +297,7 @@ checkDeducedTemplateArguments(ASTContext &Context,
XAEnd = X.pack_end(),
YA = Y.pack_begin();
XA != XAEnd; ++XA, ++YA) {
+ // FIXME: Do we need to merge the results together here?
if (checkDeducedTemplateArguments(Context,
DeducedTemplateArgument(*XA, X.wasDeducedFromArrayBound()),
DeducedTemplateArgument(*YA, Y.wasDeducedFromArrayBound()))
@@ -382,7 +383,7 @@ DeduceNonTypeTemplateArgument(Sema &S,
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
- D = D ? cast<ValueDecl>(D->getCanonicalDecl()) : 0;
+ D = D ? cast<ValueDecl>(D->getCanonicalDecl()) : nullptr;
TemplateArgument New(D, NTTP->getType()->isReferenceType());
DeducedTemplateArgument NewDeduced(New);
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
@@ -581,96 +582,181 @@ static TemplateParameter makeTemplateParameter(Decl *D) {
return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
}
-typedef SmallVector<SmallVector<DeducedTemplateArgument, 4>, 2>
- NewlyDeducedPacksType;
+/// A pack that we're currently deducing.
+struct clang::DeducedPack {
+ DeducedPack(unsigned Index) : Index(Index), Outer(nullptr) {}
-/// \brief Prepare to perform template argument deduction for all of the
-/// arguments in a set of argument packs.
-static void
-PrepareArgumentPackDeduction(Sema &S,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- ArrayRef<unsigned> PackIndices,
- SmallVectorImpl<DeducedTemplateArgument> &SavedPacks,
- NewlyDeducedPacksType &NewlyDeducedPacks) {
- // Save the deduced template arguments for each parameter pack expanded
- // by this pack expansion, then clear out the deduction.
- for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
- // Save the previously-deduced argument pack, then clear it out so that we
- // can deduce a new argument pack.
- SavedPacks[I] = Deduced[PackIndices[I]];
- Deduced[PackIndices[I]] = TemplateArgument();
-
- if (!S.CurrentInstantiationScope)
- continue;
+ // The index of the pack.
+ unsigned Index;
+
+ // The old value of the pack before we started deducing it.
+ DeducedTemplateArgument Saved;
+
+ // A deferred value of this pack from an inner deduction, that couldn't be
+ // deduced because this deduction hadn't happened yet.
+ DeducedTemplateArgument DeferredDeduction;
+
+ // The new value of the pack.
+ SmallVector<DeducedTemplateArgument, 4> New;
+
+ // The outer deduction for this pack, if any.
+ DeducedPack *Outer;
+};
+
+/// A scope in which we're performing pack deduction.
+class PackDeductionScope {
+public:
+ PackDeductionScope(Sema &S, TemplateParameterList *TemplateParams,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ TemplateDeductionInfo &Info, TemplateArgument Pattern)
+ : S(S), TemplateParams(TemplateParams), Deduced(Deduced), Info(Info) {
+ // Compute the set of template parameter indices that correspond to
+ // parameter packs expanded by the pack expansion.
+ {
+ llvm::SmallBitVector SawIndices(TemplateParams->size());
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
+ for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
+ unsigned Depth, Index;
+ std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
+ if (Depth == 0 && !SawIndices[Index]) {
+ SawIndices[Index] = true;
- // If the template argument pack was explicitly specified, add that to
- // the set of deduced arguments.
- const TemplateArgument *ExplicitArgs;
- unsigned NumExplicitArgs;
- if (NamedDecl *PartiallySubstitutedPack
- = S.CurrentInstantiationScope->getPartiallySubstitutedPack(
- &ExplicitArgs,
- &NumExplicitArgs)) {
- if (getDepthAndIndex(PartiallySubstitutedPack).second == PackIndices[I])
- NewlyDeducedPacks[I].append(ExplicitArgs,
- ExplicitArgs + NumExplicitArgs);
+ // Save the deduced template argument for the parameter pack expanded
+ // by this pack expansion, then clear out the deduction.
+ DeducedPack Pack(Index);
+ Pack.Saved = Deduced[Index];
+ Deduced[Index] = TemplateArgument();
+
+ Packs.push_back(Pack);
+ }
+ }
}
- }
-}
+ assert(!Packs.empty() && "Pack expansion without unexpanded packs?");
-/// \brief Finish template argument deduction for a set of argument packs,
-/// producing the argument packs and checking for consistency with prior
-/// deductions.
-static Sema::TemplateDeductionResult
-FinishArgumentPackDeduction(Sema &S,
- TemplateParameterList *TemplateParams,
- bool HasAnyArguments,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- ArrayRef<unsigned> PackIndices,
- SmallVectorImpl<DeducedTemplateArgument> &SavedPacks,
- NewlyDeducedPacksType &NewlyDeducedPacks,
- TemplateDeductionInfo &Info) {
- // Build argument packs for each of the parameter packs expanded by this
- // pack expansion.
- for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
- if (HasAnyArguments && NewlyDeducedPacks[I].empty()) {
- // We were not able to deduce anything for this parameter pack,
- // so just restore the saved argument pack.
- Deduced[PackIndices[I]] = SavedPacks[I];
- continue;
+ for (auto &Pack : Packs) {
+ if (Info.PendingDeducedPacks.size() > Pack.Index)
+ Pack.Outer = Info.PendingDeducedPacks[Pack.Index];
+ else
+ Info.PendingDeducedPacks.resize(Pack.Index + 1);
+ Info.PendingDeducedPacks[Pack.Index] = &Pack;
+
+ if (S.CurrentInstantiationScope) {
+ // If the template argument pack was explicitly specified, add that to
+ // the set of deduced arguments.
+ const TemplateArgument *ExplicitArgs;
+ unsigned NumExplicitArgs;
+ NamedDecl *PartiallySubstitutedPack =
+ S.CurrentInstantiationScope->getPartiallySubstitutedPack(
+ &ExplicitArgs, &NumExplicitArgs);
+ if (PartiallySubstitutedPack &&
+ getDepthAndIndex(PartiallySubstitutedPack).second == Pack.Index)
+ Pack.New.append(ExplicitArgs, ExplicitArgs + NumExplicitArgs);
+ }
}
+ }
+
+ ~PackDeductionScope() {
+ for (auto &Pack : Packs)
+ Info.PendingDeducedPacks[Pack.Index] = Pack.Outer;
+ }
- DeducedTemplateArgument NewPack;
-
- if (NewlyDeducedPacks[I].empty()) {
- // If we deduced an empty argument pack, create it now.
- NewPack = DeducedTemplateArgument(TemplateArgument::getEmptyPack());
- } else {
- TemplateArgument *ArgumentPack
- = new (S.Context) TemplateArgument [NewlyDeducedPacks[I].size()];
- std::copy(NewlyDeducedPacks[I].begin(), NewlyDeducedPacks[I].end(),
- ArgumentPack);
- NewPack
- = DeducedTemplateArgument(TemplateArgument(ArgumentPack,
- NewlyDeducedPacks[I].size()),
- NewlyDeducedPacks[I][0].wasDeducedFromArrayBound());
+ /// Move to deducing the next element in each pack that is being deduced.
+ void nextPackElement() {
+ // Capture the deduced template arguments for each parameter pack expanded
+ // by this pack expansion, add them to the list of arguments we've deduced
+ // for that pack, then clear out the deduced argument.
+ for (auto &Pack : Packs) {
+ DeducedTemplateArgument &DeducedArg = Deduced[Pack.Index];
+ if (!DeducedArg.isNull()) {
+ Pack.New.push_back(DeducedArg);
+ DeducedArg = DeducedTemplateArgument();
+ }
}
+ }
- DeducedTemplateArgument Result
- = checkDeducedTemplateArguments(S.Context, SavedPacks[I], NewPack);
- if (Result.isNull()) {
- Info.Param
- = makeTemplateParameter(TemplateParams->getParam(PackIndices[I]));
- Info.FirstArg = SavedPacks[I];
- Info.SecondArg = NewPack;
- return Sema::TDK_Inconsistent;
+ /// \brief Finish template argument deduction for a set of argument packs,
+ /// producing the argument packs and checking for consistency with prior
+ /// deductions.
+ Sema::TemplateDeductionResult finish(bool HasAnyArguments) {
+ // Build argument packs for each of the parameter packs expanded by this
+ // pack expansion.
+ for (auto &Pack : Packs) {
+ // Put back the old value for this pack.
+ Deduced[Pack.Index] = Pack.Saved;
+
+ // Build or find a new value for this pack.
+ DeducedTemplateArgument NewPack;
+ if (HasAnyArguments && Pack.New.empty()) {
+ if (Pack.DeferredDeduction.isNull()) {
+ // We were not able to deduce anything for this parameter pack
+ // (because it only appeared in non-deduced contexts), so just
+ // restore the saved argument pack.
+ continue;
+ }
+
+ NewPack = Pack.DeferredDeduction;
+ Pack.DeferredDeduction = TemplateArgument();
+ } else if (Pack.New.empty()) {
+ // If we deduced an empty argument pack, create it now.
+ NewPack = DeducedTemplateArgument(TemplateArgument::getEmptyPack());
+ } else {
+ TemplateArgument *ArgumentPack =
+ new (S.Context) TemplateArgument[Pack.New.size()];
+ std::copy(Pack.New.begin(), Pack.New.end(), ArgumentPack);
+ NewPack = DeducedTemplateArgument(
+ TemplateArgument(ArgumentPack, Pack.New.size()),
+ Pack.New[0].wasDeducedFromArrayBound());
+ }
+
+ // Pick where we're going to put the merged pack.
+ DeducedTemplateArgument *Loc;
+ if (Pack.Outer) {
+ if (Pack.Outer->DeferredDeduction.isNull()) {
+ // Defer checking this pack until we have a complete pack to compare
+ // it against.
+ Pack.Outer->DeferredDeduction = NewPack;
+ continue;
+ }
+ Loc = &Pack.Outer->DeferredDeduction;
+ } else {
+ Loc = &Deduced[Pack.Index];
+ }
+
+ // Check the new pack matches any previous value.
+ DeducedTemplateArgument OldPack = *Loc;
+ DeducedTemplateArgument Result =
+ checkDeducedTemplateArguments(S.Context, OldPack, NewPack);
+
+ // If we deferred a deduction of this pack, check that one now too.
+ if (!Result.isNull() && !Pack.DeferredDeduction.isNull()) {
+ OldPack = Result;
+ NewPack = Pack.DeferredDeduction;
+ Result = checkDeducedTemplateArguments(S.Context, OldPack, NewPack);
+ }
+
+ if (Result.isNull()) {
+ Info.Param =
+ makeTemplateParameter(TemplateParams->getParam(Pack.Index));
+ Info.FirstArg = OldPack;
+ Info.SecondArg = NewPack;
+ return Sema::TDK_Inconsistent;
+ }
+
+ *Loc = Result;
}
- Deduced[PackIndices[I]] = Result;
+ return Sema::TDK_Success;
}
- return Sema::TDK_Success;
-}
+private:
+ Sema &S;
+ TemplateParameterList *TemplateParams;
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced;
+ TemplateDeductionInfo &Info;
+
+ SmallVector<DeducedPack, 2> Packs;
+};
/// \brief Deduce the template arguments by comparing the list of parameter
/// types to the list of argument types, as in the parameter-type-lists of
@@ -715,7 +801,7 @@ DeduceTemplateArguments(Sema &S,
unsigned TDF,
bool PartialOrdering = false,
SmallVectorImpl<RefParamPartialOrderingComparison> *
- RefParamComparisons = 0) {
+ RefParamComparisons = nullptr) {
// Fast-path check to see if we have too many/too few arguments.
if (NumParams != NumArgs &&
!(NumParams && isa<PackExpansionType>(Params[NumParams - 1])) &&
@@ -773,33 +859,8 @@ DeduceTemplateArguments(Sema &S,
// comparison deduces template arguments for subsequent positions in the
// template parameter packs expanded by the function parameter pack.
- // Compute the set of template parameter indices that correspond to
- // parameter packs expanded by the pack expansion.
- SmallVector<unsigned, 2> PackIndices;
QualType Pattern = Expansion->getPattern();
- {
- llvm::SmallBitVector SawIndices(TemplateParams->size());
- SmallVector<UnexpandedParameterPack, 2> Unexpanded;
- S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
- for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
- unsigned Depth, Index;
- llvm::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
- if (Depth == 0 && !SawIndices[Index]) {
- SawIndices[Index] = true;
- PackIndices.push_back(Index);
- }
- }
- }
- assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?");
-
- // Keep track of the deduced template arguments for each parameter pack
- // expanded by this pack expansion (the outer index) and for each
- // template argument (the inner SmallVectors).
- NewlyDeducedPacksType NewlyDeducedPacks(PackIndices.size());
- SmallVector<DeducedTemplateArgument, 2>
- SavedPacks(PackIndices.size());
- PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks,
- NewlyDeducedPacks);
+ PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern);
bool HasAnyArguments = false;
for (; ArgIdx < NumArgs; ++ArgIdx) {
@@ -813,24 +874,12 @@ DeduceTemplateArguments(Sema &S,
RefParamComparisons))
return Result;
- // Capture the deduced template arguments for each parameter pack expanded
- // by this pack expansion, add them to the list of arguments we've deduced
- // for that pack, then clear out the deduced argument.
- for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
- DeducedTemplateArgument &DeducedArg = Deduced[PackIndices[I]];
- if (!DeducedArg.isNull()) {
- NewlyDeducedPacks[I].push_back(DeducedArg);
- DeducedArg = DeducedTemplateArgument();
- }
- }
+ PackScope.nextPackElement();
}
// Build argument packs for each of the parameter packs expanded by this
// pack expansion.
- if (Sema::TemplateDeductionResult Result
- = FinishArgumentPackDeduction(S, TemplateParams, HasAnyArguments,
- Deduced, PackIndices, SavedPacks,
- NewlyDeducedPacks, Info))
+ if (auto Result = PackScope.finish(HasAnyArguments))
return Result;
}
@@ -981,6 +1030,17 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
Comparison.Qualifiers = ParamMoreQualified;
else if (ArgQuals.isStrictSupersetOf(ParamQuals))
Comparison.Qualifiers = ArgMoreQualified;
+ else if (ArgQuals.getObjCLifetime() != ParamQuals.getObjCLifetime() &&
+ ArgQuals.withoutObjCLifetime()
+ == ParamQuals.withoutObjCLifetime()) {
+ // Prefer binding to non-__unsafe_autoretained parameters.
+ if (ArgQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone &&
+ ParamQuals.getObjCLifetime())
+ Comparison.Qualifiers = ParamMoreQualified;
+ else if (ParamQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone &&
+ ArgQuals.getObjCLifetime())
+ Comparison.Qualifiers = ArgMoreQualified;
+ }
RefParamComparisons->push_back(Comparison);
}
@@ -1364,19 +1424,17 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
return Sema::TDK_NonDeducedMismatch;
// Check return types.
- if (Sema::TemplateDeductionResult Result
- = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- FunctionProtoParam->getResultType(),
- FunctionProtoArg->getResultType(),
- Info, Deduced, 0))
+ if (Sema::TemplateDeductionResult Result =
+ DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, FunctionProtoParam->getReturnType(),
+ FunctionProtoArg->getReturnType(), Info, Deduced, 0))
return Result;
- return DeduceTemplateArguments(S, TemplateParams,
- FunctionProtoParam->arg_type_begin(),
- FunctionProtoParam->getNumArgs(),
- FunctionProtoArg->arg_type_begin(),
- FunctionProtoArg->getNumArgs(),
- Info, Deduced, SubTDF);
+ return DeduceTemplateArguments(
+ S, TemplateParams, FunctionProtoParam->param_type_begin(),
+ FunctionProtoParam->getNumParams(),
+ FunctionProtoArg->param_type_begin(),
+ FunctionProtoArg->getNumParams(), Info, Deduced, SubTDF);
}
case Type::InjectedClassName: {
@@ -1463,12 +1521,10 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// Visit base classes
CXXRecordDecl *Next = cast<CXXRecordDecl>(NextT->getDecl());
- for (CXXRecordDecl::base_class_iterator Base = Next->bases_begin(),
- BaseEnd = Next->bases_end();
- Base != BaseEnd; ++Base) {
- assert(Base->getType()->isRecordType() &&
+ for (const auto &Base : Next->bases()) {
+ assert(Base.getType()->isRecordType() &&
"Base class that isn't a record?");
- ToVisit.push_back(Base->getType()->getAs<RecordType>());
+ ToVisit.push_back(Base.getType()->getAs<RecordType>());
}
}
@@ -1845,41 +1901,18 @@ DeduceTemplateArguments(Sema &S,
// template parameter packs expanded by Pi.
TemplateArgument Pattern = Params[ParamIdx].getPackExpansionPattern();
- // Compute the set of template parameter indices that correspond to
- // parameter packs expanded by the pack expansion.
- SmallVector<unsigned, 2> PackIndices;
- {
- llvm::SmallBitVector SawIndices(TemplateParams->size());
- SmallVector<UnexpandedParameterPack, 2> Unexpanded;
- S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
- for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
- unsigned Depth, Index;
- llvm::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
- if (Depth == 0 && !SawIndices[Index]) {
- SawIndices[Index] = true;
- PackIndices.push_back(Index);
- }
- }
- }
- assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?");
-
// FIXME: If there are no remaining arguments, we can bail out early
// and set any deduced parameter packs to an empty argument pack.
// The latter part of this is a (minor) correctness issue.
- // Save the deduced template arguments for each parameter pack expanded
- // by this pack expansion, then clear out the deduction.
- SmallVector<DeducedTemplateArgument, 2>
- SavedPacks(PackIndices.size());
- NewlyDeducedPacksType NewlyDeducedPacks(PackIndices.size());
- PrepareArgumentPackDeduction(S, Deduced, PackIndices, SavedPacks,
- NewlyDeducedPacks);
+ // Prepare to deduce the packs within the pattern.
+ PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern);
// Keep track of the deduced template arguments for each parameter pack
// expanded by this pack expansion (the outer index) and for each
// template argument (the inner SmallVectors).
bool HasAnyArguments = false;
- while (hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs)) {
+ for (; hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs); ++ArgIdx) {
HasAnyArguments = true;
// Deduce template arguments from the pattern.
@@ -1888,26 +1921,12 @@ DeduceTemplateArguments(Sema &S,
Info, Deduced))
return Result;
- // Capture the deduced template arguments for each parameter pack expanded
- // by this pack expansion, add them to the list of arguments we've deduced
- // for that pack, then clear out the deduced argument.
- for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
- DeducedTemplateArgument &DeducedArg = Deduced[PackIndices[I]];
- if (!DeducedArg.isNull()) {
- NewlyDeducedPacks[I].push_back(DeducedArg);
- DeducedArg = DeducedTemplateArgument();
- }
- }
-
- ++ArgIdx;
+ PackScope.nextPackElement();
}
// Build argument packs for each of the parameter packs expanded by this
// pack expansion.
- if (Sema::TemplateDeductionResult Result
- = FinishArgumentPackDeduction(S, TemplateParams, HasAnyArguments,
- Deduced, PackIndices, SavedPacks,
- NewlyDeducedPacks, Info))
+ if (auto Result = PackScope.finish(HasAnyArguments))
return Result;
}
@@ -2013,21 +2032,21 @@ getTrivialTemplateArgumentLoc(Sema &S,
case TemplateArgument::Declaration: {
Expr *E
= S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
- .takeAs<Expr>();
+ .getAs<Expr>();
return TemplateArgumentLoc(TemplateArgument(E), E);
}
case TemplateArgument::NullPtr: {
Expr *E
= S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
- .takeAs<Expr>();
+ .getAs<Expr>();
return TemplateArgumentLoc(TemplateArgument(NTTPType, /*isNullPtr*/true),
E);
}
case TemplateArgument::Integral: {
Expr *E
- = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>();
+ = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).getAs<Expr>();
return TemplateArgumentLoc(TemplateArgument(E), E);
}
@@ -2076,13 +2095,11 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
// This is a template argument pack, so check each of its arguments against
// the template parameter.
SmallVector<TemplateArgument, 2> PackedArgsBuilder;
- for (TemplateArgument::pack_iterator PA = Arg.pack_begin(),
- PAEnd = Arg.pack_end();
- PA != PAEnd; ++PA) {
+ for (const auto &P : Arg.pack_elements()) {
// When converting the deduced template argument, append it to the
// general output list. We need to do this so that the template argument
// checking logic has all of the prior template arguments available.
- DeducedTemplateArgument InnerArg(*PA);
+ DeducedTemplateArgument InnerArg(P);
InnerArg.setDeducedFromArrayBound(Arg.wasDeducedFromArrayBound());
if (ConvertDeducedTemplateArgument(S, Param, InnerArg, Template,
NTTPType, PackedArgsBuilder.size(),
@@ -2274,8 +2291,8 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
return Result;
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
- InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial,
- DeducedArgs, Info);
+ InstantiatingTemplate Inst(*this, Info.getLocation(), Partial, DeducedArgs,
+ Info);
if (Inst.isInvalid())
return TDK_InstantiationDepth;
@@ -2438,8 +2455,8 @@ Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial,
return Result;
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
- InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial,
- DeducedArgs, Info);
+ InstantiatingTemplate Inst(*this, Info.getLocation(), Partial, DeducedArgs,
+ Info);
if (Inst.isInvalid())
return TDK_InstantiationDepth;
@@ -2454,7 +2471,7 @@ Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial,
static bool isSimpleTemplateIdType(QualType T) {
if (const TemplateSpecializationType *Spec
= T->getAs<TemplateSpecializationType>())
- return Spec->getTemplateName().getAsTemplateDecl() != 0;
+ return Spec->getTemplateName().getAsTemplateDecl() != nullptr;
return false;
}
@@ -2498,11 +2515,8 @@ Sema::SubstituteExplicitTemplateArguments(
if (ExplicitTemplateArgs.size() == 0) {
// No arguments to substitute; just copy over the parameter types and
// fill in the function type.
- for (FunctionDecl::param_iterator P = Function->param_begin(),
- PEnd = Function->param_end();
- P != PEnd;
- ++P)
- ParamTypes.push_back((*P)->getType());
+ for (auto P : Function->params())
+ ParamTypes.push_back(P->getType());
if (FunctionType)
*FunctionType = Function->getType();
@@ -2524,8 +2538,8 @@ Sema::SubstituteExplicitTemplateArguments(
// explicitly-specified template arguments against this function template,
// and then substitute them into the function parameter types.
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
- InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
- FunctionTemplate, DeducedArgs,
+ InstantiatingTemplate Inst(*this, Info.getLocation(), FunctionTemplate,
+ DeducedArgs,
ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution,
Info);
if (Inst.isInvalid())
@@ -2596,7 +2610,7 @@ Sema::SubstituteExplicitTemplateArguments(
// and the end of the function-definition, member-declarator, or
// declarator.
unsigned ThisTypeQuals = 0;
- CXXRecordDecl *ThisContext = 0;
+ CXXRecordDecl *ThisContext = nullptr;
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
ThisContext = Method->getParent();
ThisTypeQuals = Method->getTypeQualifiers();
@@ -2604,11 +2618,11 @@ Sema::SubstituteExplicitTemplateArguments(
CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals,
getLangOpts().CPlusPlus11);
-
- ResultType = SubstType(Proto->getResultType(),
- MultiLevelTemplateArgumentList(*ExplicitArgumentList),
- Function->getTypeSpecStartLoc(),
- Function->getDeclName());
+
+ ResultType =
+ SubstType(Proto->getReturnType(),
+ MultiLevelTemplateArgumentList(*ExplicitArgumentList),
+ Function->getTypeSpecStartLoc(), Function->getDeclName());
if (ResultType.isNull() || Trap.hasErrorOccurred())
return TDK_SubstitutionFailure;
}
@@ -2778,8 +2792,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// Enter a new template instantiation context while we instantiate the
// actual function declaration.
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
- InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
- FunctionTemplate, DeducedArgs,
+ InstantiatingTemplate Inst(*this, Info.getLocation(), FunctionTemplate,
+ DeducedArgs,
ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
Info);
if (Inst.isInvalid())
@@ -2800,9 +2814,19 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// argument, because it was explicitly-specified. Just record the
// presence of this argument.
Builder.push_back(Deduced[I]);
+ // We may have had explicitly-specified template arguments for a
+ // template parameter pack (that may or may not have been extended
+ // via additional deduced arguments).
+ if (Param->isParameterPack() && CurrentInstantiationScope) {
+ if (CurrentInstantiationScope->getPartiallySubstitutedPack() ==
+ Param) {
+ // Forget the partially-substituted pack; its substitution is now
+ // complete.
+ CurrentInstantiationScope->ResetPartiallySubstitutedPack();
+ }
+ }
continue;
}
-
// We have deduced this argument, so it still needs to be
// checked and converted.
@@ -2976,8 +3000,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
static QualType GetTypeOfFunction(Sema &S, const OverloadExpr::FindResult &R,
FunctionDecl *Fn) {
// We may need to deduce the return type of the function now.
- if (S.getLangOpts().CPlusPlus1y && Fn->getResultType()->isUndeducedType() &&
- S.DeduceReturnType(Fn, R.Expression->getExprLoc(), /*Diagnose*/false))
+ if (S.getLangOpts().CPlusPlus1y && Fn->getReturnType()->isUndeducedType() &&
+ S.DeduceReturnType(Fn, R.Expression->getExprLoc(), /*Diagnose*/ false))
return QualType();
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn))
@@ -3048,7 +3072,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
return QualType();
// Otherwise, see if we can resolve a function type
- FunctionDecl *Specialization = 0;
+ FunctionDecl *Specialization = nullptr;
TemplateDeductionInfo Info(Ovl->getNameLoc());
if (S.DeduceTemplateArguments(FunTmpl, &ExplicitTemplateArgs,
Specialization, Info))
@@ -3140,7 +3164,7 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
if (ArgType == S.Context.OverloadTy) {
ArgType = ResolveOverloadForDeduction(S, TemplateParams,
Arg, ParamType,
- ParamRefType != 0);
+ ParamRefType != nullptr);
if (ArgType.isNull())
return true;
}
@@ -3309,7 +3333,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
*ExplicitTemplateArgs,
Deduced,
ParamTypes,
- 0,
+ nullptr,
Info);
if (Result)
return Result;
@@ -3399,30 +3423,9 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
break;
QualType ParamPattern = ParamExpansion->getPattern();
- SmallVector<unsigned, 2> PackIndices;
- {
- llvm::SmallBitVector SawIndices(TemplateParams->size());
- SmallVector<UnexpandedParameterPack, 2> Unexpanded;
- collectUnexpandedParameterPacks(ParamPattern, Unexpanded);
- for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
- unsigned Depth, Index;
- llvm::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
- if (Depth == 0 && !SawIndices[Index]) {
- SawIndices[Index] = true;
- PackIndices.push_back(Index);
- }
- }
- }
- assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?");
+ PackDeductionScope PackScope(*this, TemplateParams, Deduced, Info,
+ ParamPattern);
- // Keep track of the deduced template arguments for each parameter pack
- // expanded by this pack expansion (the outer index) and for each
- // template argument (the inner SmallVectors).
- NewlyDeducedPacksType NewlyDeducedPacks(PackIndices.size());
- SmallVector<DeducedTemplateArgument, 2>
- SavedPacks(PackIndices.size());
- PrepareArgumentPackDeduction(*this, Deduced, PackIndices, SavedPacks,
- NewlyDeducedPacks);
bool HasAnyArguments = false;
for (; ArgIdx < Args.size(); ++ArgIdx) {
HasAnyArguments = true;
@@ -3431,7 +3434,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
ParamType = OrigParamType;
Expr *Arg = Args[ArgIdx];
QualType ArgType = Arg->getType();
-
+
unsigned TDF = 0;
if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams,
ParamType, ArgType, Arg,
@@ -3472,24 +3475,12 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
return Result;
}
- // Capture the deduced template arguments for each parameter pack expanded
- // by this pack expansion, add them to the list of arguments we've deduced
- // for that pack, then clear out the deduced argument.
- for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
- DeducedTemplateArgument &DeducedArg = Deduced[PackIndices[I]];
- if (!DeducedArg.isNull()) {
- NewlyDeducedPacks[I].push_back(DeducedArg);
- DeducedArg = DeducedTemplateArgument();
- }
- }
+ PackScope.nextPackElement();
}
// Build argument packs for each of the parameter packs expanded by this
// pack expansion.
- if (Sema::TemplateDeductionResult Result
- = FinishArgumentPackDeduction(*this, TemplateParams, HasAnyArguments,
- Deduced, PackIndices, SavedPacks,
- NewlyDeducedPacks, Info))
+ if (auto Result = PackScope.finish(HasAnyArguments))
return Result;
// After we've matching against a parameter pack, we're done.
@@ -3589,7 +3580,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// type so that we treat it as a non-deduced context in what follows.
bool HasDeducedReturnType = false;
if (getLangOpts().CPlusPlus1y && InOverloadResolution &&
- Function->getResultType()->getContainedAutoType()) {
+ Function->getReturnType()->getContainedAutoType()) {
FunctionType = SubstAutoType(FunctionType, Context.DependentTy);
HasDeducedReturnType = true;
}
@@ -3614,7 +3605,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// If the function has a deduced return type, deduce it now, so we can check
// that the deduced function type matches the requested type.
if (HasDeducedReturnType &&
- Specialization->getResultType()->isUndeducedType() &&
+ Specialization->getReturnType()->isUndeducedType() &&
DeduceReturnType(Specialization, Info.getLocation(), false))
return TDK_MiscellaneousDeductionFailure;
@@ -3643,7 +3634,7 @@ static inline void
SubstAutoWithinFunctionReturnType(FunctionDecl *F,
QualType TypeToReplaceAutoWith, Sema &S) {
assert(!TypeToReplaceAutoWith->getContainedAutoType());
- QualType AutoResultType = F->getResultType();
+ QualType AutoResultType = F->getReturnType();
assert(AutoResultType->getContainedAutoType());
QualType DeducedResultType = S.SubstAutoType(AutoResultType,
TypeToReplaceAutoWith);
@@ -3668,14 +3659,14 @@ SpecializeCorrespondingLambdaCallOperatorAndInvoker(
assert(LambdaClass && LambdaClass->isGenericLambda());
CXXMethodDecl *CallOpGeneric = LambdaClass->getLambdaCallOperator();
- QualType CallOpResultType = CallOpGeneric->getResultType();
+ QualType CallOpResultType = CallOpGeneric->getReturnType();
const bool GenericLambdaCallOperatorHasDeducedReturnType =
CallOpResultType->getContainedAutoType();
FunctionTemplateDecl *CallOpTemplate =
CallOpGeneric->getDescribedFunctionTemplate();
- FunctionDecl *CallOpSpecialized = 0;
+ FunctionDecl *CallOpSpecialized = nullptr;
// Use the deduced arguments of the conversion function, to specialize our
// generic lambda's call operator.
if (Sema::TemplateDeductionResult Result
@@ -3685,15 +3676,15 @@ SpecializeCorrespondingLambdaCallOperatorAndInvoker(
return Result;
// If we need to deduce the return type, do so (instantiates the callop).
- if (GenericLambdaCallOperatorHasDeducedReturnType &&
- CallOpSpecialized->getResultType()->isUndeducedType())
+ if (GenericLambdaCallOperatorHasDeducedReturnType &&
+ CallOpSpecialized->getReturnType()->isUndeducedType())
S.DeduceReturnType(CallOpSpecialized,
CallOpSpecialized->getPointOfInstantiation(),
/*Diagnose*/ true);
// Check to see if the return type of the destination ptr-to-function
// matches the return type of the call operator.
- if (!S.Context.hasSameType(CallOpSpecialized->getResultType(),
+ if (!S.Context.hasSameType(CallOpSpecialized->getReturnType(),
ReturnTypeOfDestFunctionPtr))
return Sema::TDK_NonDeducedMismatch;
// Since we have succeeded in matching the source and destination
@@ -3701,7 +3692,7 @@ SpecializeCorrespondingLambdaCallOperatorAndInvoker(
// specialized our corresponding call operator, we are ready to
// specialize the static invoker with the deduced arguments of our
// ptr-to-function.
- FunctionDecl *InvokerSpecialized = 0;
+ FunctionDecl *InvokerSpecialized = nullptr;
FunctionTemplateDecl *InvokerTemplate = LambdaClass->
getLambdaStaticInvoker()->getDescribedFunctionTemplate();
@@ -3712,8 +3703,8 @@ SpecializeCorrespondingLambdaCallOperatorAndInvoker(
"If the call operator succeeded so should the invoker!");
// Set the result type to match the corresponding call operator
// specialization's result type.
- if (GenericLambdaCallOperatorHasDeducedReturnType &&
- InvokerSpecialized->getResultType()->isUndeducedType()) {
+ if (GenericLambdaCallOperatorHasDeducedReturnType &&
+ InvokerSpecialized->getReturnType()->isUndeducedType()) {
// Be sure to get the type to replace 'auto' with and not
// the full result type of the call op specialization
// to substitute into the 'auto' of the invoker and conversion
@@ -3722,9 +3713,9 @@ SpecializeCorrespondingLambdaCallOperatorAndInvoker(
// int* (*fp)(int*) = [](auto* a) -> auto* { return a; };
// We don't want to subst 'int*' into 'auto' to get int**.
- QualType TypeToReplaceAutoWith =
- CallOpSpecialized->getResultType()->
- getContainedAutoType()->getDeducedType();
+ QualType TypeToReplaceAutoWith = CallOpSpecialized->getReturnType()
+ ->getContainedAutoType()
+ ->getDeducedType();
SubstAutoWithinFunctionReturnType(InvokerSpecialized,
TypeToReplaceAutoWith, S);
SubstAutoWithinFunctionReturnType(ConversionSpecialized,
@@ -3740,7 +3731,7 @@ SpecializeCorrespondingLambdaCallOperatorAndInvoker(
FunctionProtoType::ExtProtoInfo EPI = InvokerFPT->getExtProtoInfo();
EPI.TypeQuals = 0;
InvokerSpecialized->setType(S.Context.getFunctionType(
- InvokerFPT->getResultType(), InvokerFPT->getArgTypes(),EPI));
+ InvokerFPT->getReturnType(), InvokerFPT->getParamTypes(), EPI));
return Sema::TDK_Success;
}
/// \brief Deduce template arguments for a templated conversion
@@ -3844,7 +3835,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate,
// Create an Instantiation Scope for finalizing the operator.
LocalInstantiationScope InstScope(*this);
// Finish template argument deduction.
- FunctionDecl *ConversionSpecialized = 0;
+ FunctionDecl *ConversionSpecialized = nullptr;
TemplateDeductionResult Result
= FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0,
ConversionSpecialized, Info);
@@ -3863,8 +3854,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate,
"Can only convert from lambda to ptr-to-function");
const FunctionType *ToFunType =
A->getPointeeType().getTypePtr()->getAs<FunctionType>();
- const QualType DestFunctionPtrReturnType = ToFunType->getResultType();
-
+ const QualType DestFunctionPtrReturnType = ToFunType->getReturnType();
+
// Create the corresponding specializations of the call operator and
// the static-invoker; and if the return type is auto,
// deduce the return type and check if it matches the
@@ -3978,7 +3969,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) {
ExprResult NonPlaceholder = CheckPlaceholderExpr(Init);
if (NonPlaceholder.isInvalid())
return DAR_FailedAlreadyDiagnosed;
- Init = NonPlaceholder.take();
+ Init = NonPlaceholder.get();
}
if (Init->isTypeDependent() || Type.getType()->isDependentType()) {
@@ -4013,8 +4004,8 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) {
// Build template<class TemplParam> void Func(FuncParam);
TemplateTypeParmDecl *TemplParam =
- TemplateTypeParmDecl::Create(Context, 0, SourceLocation(), Loc, 0, 0, 0,
- false, false);
+ TemplateTypeParmDecl::Create(Context, nullptr, SourceLocation(), Loc, 0, 0,
+ nullptr, false, false);
QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0);
NamedDecl *TemplParamPtr = TemplParam;
FixedSizeTemplateParameterList<1> TemplateParams(Loc, Loc, &TemplParamPtr,
@@ -4109,12 +4100,12 @@ void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) {
bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
bool Diagnose) {
- assert(FD->getResultType()->isUndeducedType());
+ assert(FD->getReturnType()->isUndeducedType());
if (FD->getTemplateInstantiationPattern())
InstantiateFunctionDefinition(Loc, FD);
- bool StillUndeduced = FD->getResultType()->isUndeducedType();
+ bool StillUndeduced = FD->getReturnType()->isUndeducedType();
if (StillUndeduced && Diagnose && !FD->isInvalidDecl()) {
Diag(Loc, diag::err_auto_fn_used_before_defined) << FD;
Diag(FD->getLocation(), diag::note_callee_decl) << FD;
@@ -4195,35 +4186,25 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
// otherwise, the ordering rules for static functions against non-static
// functions don't make any sense.
//
- // C++98/03 doesn't have this provision, so instead we drop the
- // first argument of the free function, which seems to match
- // existing practice.
+ // C++98/03 doesn't have this provision but we've extended DR532 to cover
+ // it as wording was broken prior to it.
SmallVector<QualType, 4> Args1;
- unsigned Skip1 = 0, Skip2 = 0;
unsigned NumComparedArguments = NumCallArguments1;
if (!Method2 && Method1 && !Method1->isStatic()) {
- if (S.getLangOpts().CPlusPlus11) {
- // Compare 'this' from Method1 against first parameter from Method2.
- AddImplicitObjectParameterType(S.Context, Method1, Args1);
- ++NumComparedArguments;
- } else
- // Ignore first parameter from Method2.
- ++Skip2;
+ // Compare 'this' from Method1 against first parameter from Method2.
+ AddImplicitObjectParameterType(S.Context, Method1, Args1);
+ ++NumComparedArguments;
} else if (!Method1 && Method2 && !Method2->isStatic()) {
- if (S.getLangOpts().CPlusPlus11)
- // Compare 'this' from Method2 against first parameter from Method1.
- AddImplicitObjectParameterType(S.Context, Method2, Args2);
- else
- // Ignore first parameter from Method1.
- ++Skip1;
+ // Compare 'this' from Method2 against first parameter from Method1.
+ AddImplicitObjectParameterType(S.Context, Method2, Args2);
}
- Args1.insert(Args1.end(),
- Proto1->arg_type_begin() + Skip1, Proto1->arg_type_end());
- Args2.insert(Args2.end(),
- Proto2->arg_type_begin() + Skip2, Proto2->arg_type_end());
+ Args1.insert(Args1.end(), Proto1->param_type_begin(),
+ Proto1->param_type_end());
+ Args2.insert(Args2.end(), Proto2->param_type_begin(),
+ Proto2->param_type_end());
// C++ [temp.func.order]p5:
// The presence of unused ellipsis and default arguments has no effect on
@@ -4236,7 +4217,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
Args1.data(), Args1.size(), Info, Deduced,
TDF_None, /*PartialOrdering=*/true,
RefParamComparisons))
- return false;
+ return false;
break;
}
@@ -4244,12 +4225,10 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
case TPOC_Conversion:
// - In the context of a call to a conversion operator, the return types
// of the conversion function templates are used.
- if (DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
- Proto2->getResultType(),
- Proto1->getResultType(),
- Info, Deduced, TDF_None,
- /*PartialOrdering=*/true,
- RefParamComparisons))
+ if (DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, Proto2->getReturnType(), Proto1->getReturnType(),
+ Info, Deduced, TDF_None,
+ /*PartialOrdering=*/true, RefParamComparisons))
return false;
break;
@@ -4293,9 +4272,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
break;
case TPOC_Conversion:
- ::MarkUsedTemplateParameters(S.Context, Proto2->getResultType(), false,
- TemplateParams->getDepth(),
- UsedParameters);
+ ::MarkUsedTemplateParameters(S.Context, Proto2->getReturnType(), false,
+ TemplateParams->getDepth(), UsedParameters);
break;
case TPOC_Other:
@@ -4362,7 +4340,7 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
unsigned NumCallArguments2) {
SmallVector<RefParamPartialOrderingComparison, 4> RefParamComparisons;
bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
- NumCallArguments1, 0);
+ NumCallArguments1, nullptr);
bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
NumCallArguments2,
&RefParamComparisons);
@@ -4371,7 +4349,7 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
return Better1? FT1 : FT2;
if (!Better1 && !Better2) // Neither is better than the other
- return 0;
+ return nullptr;
// C++0x [temp.deduct.partial]p10:
// If for each type being considered a given template is at least as
@@ -4397,13 +4375,13 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
RefParamComparisons[I].ParamIsRvalueRef) {
Better2 = true;
if (Better1)
- return 0;
+ return nullptr;
continue;
} else if (!RefParamComparisons[I].ParamIsRvalueRef &&
RefParamComparisons[I].ArgIsRvalueRef) {
Better1 = true;
if (Better2)
- return 0;
+ return nullptr;
continue;
}
@@ -4418,13 +4396,13 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
case ParamMoreQualified:
Better1 = true;
if (Better2)
- return 0;
+ return nullptr;
continue;
case ArgMoreQualified:
Better2 = true;
if (Better1)
- return 0;
+ return nullptr;
continue;
}
@@ -4445,7 +4423,7 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
if (Variadic1 != Variadic2)
return Variadic1? FT2 : FT1;
- return 0;
+ return nullptr;
}
/// \brief Determine if the two templates are equivalent.
@@ -4610,11 +4588,10 @@ Sema::getMoreSpecializedPartialSpecialization(
PS2->getTemplateParameters(),
PT2, PT1, Info, Deduced, TDF_None,
/*PartialOrdering=*/true,
- /*RefParamComparisons=*/0);
+ /*RefParamComparisons=*/nullptr);
if (Better1) {
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),Deduced.end());
- InstantiatingTemplate Inst(*this, PS2->getLocation(), PS2, DeducedArgs,
- Info);
+ InstantiatingTemplate Inst(*this, Loc, PS2, DeducedArgs, Info);
Better1 = !::FinishTemplateArgumentDeduction(
*this, PS2, PS1->getTemplateArgs(), Deduced, Info);
}
@@ -4625,18 +4602,17 @@ Sema::getMoreSpecializedPartialSpecialization(
bool Better2 = !DeduceTemplateArgumentsByTypeMatch(
*this, PS1->getTemplateParameters(), PT1, PT2, Info, Deduced, TDF_None,
/*PartialOrdering=*/true,
- /*RefParamComparisons=*/0);
+ /*RefParamComparisons=*/nullptr);
if (Better2) {
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
Deduced.end());
- InstantiatingTemplate Inst(*this, PS1->getLocation(), PS1, DeducedArgs,
- Info);
+ InstantiatingTemplate Inst(*this, Loc, PS1, DeducedArgs, Info);
Better2 = !::FinishTemplateArgumentDeduction(
*this, PS1, PS2->getTemplateArgs(), Deduced, Info);
}
if (Better1 == Better2)
- return 0;
+ return nullptr;
return Better1 ? PS1 : PS2;
}
@@ -4653,7 +4629,7 @@ Sema::getMoreSpecializedPartialSpecialization(
SmallVector<DeducedTemplateArgument, 4> Deduced;
TemplateDeductionInfo Info(Loc);
- assert(PS1->getSpecializedTemplate() == PS1->getSpecializedTemplate() &&
+ assert(PS1->getSpecializedTemplate() == PS2->getSpecializedTemplate() &&
"the partial specializations being compared should specialize"
" the same template.");
TemplateName Name(PS1->getSpecializedTemplate());
@@ -4670,12 +4646,11 @@ Sema::getMoreSpecializedPartialSpecialization(
bool Better1 = !DeduceTemplateArgumentsByTypeMatch(
*this, PS2->getTemplateParameters(), PT2, PT1, Info, Deduced, TDF_None,
/*PartialOrdering=*/true,
- /*RefParamComparisons=*/0);
+ /*RefParamComparisons=*/nullptr);
if (Better1) {
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
Deduced.end());
- InstantiatingTemplate Inst(*this, PS2->getLocation(), PS2,
- DeducedArgs, Info);
+ InstantiatingTemplate Inst(*this, Loc, PS2, DeducedArgs, Info);
Better1 = !::FinishTemplateArgumentDeduction(*this, PS2,
PS1->getTemplateArgs(),
Deduced, Info);
@@ -4688,18 +4663,17 @@ Sema::getMoreSpecializedPartialSpecialization(
PS1->getTemplateParameters(),
PT1, PT2, Info, Deduced, TDF_None,
/*PartialOrdering=*/true,
- /*RefParamComparisons=*/0);
+ /*RefParamComparisons=*/nullptr);
if (Better2) {
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),Deduced.end());
- InstantiatingTemplate Inst(*this, PS1->getLocation(), PS1,
- DeducedArgs, Info);
+ InstantiatingTemplate Inst(*this, Loc, PS1, DeducedArgs, Info);
Better2 = !::FinishTemplateArgumentDeduction(*this, PS1,
PS2->getTemplateArgs(),
Deduced, Info);
}
if (Better1 == Better2)
- return 0;
+ return nullptr;
return Better1? PS1 : PS2;
}
@@ -4874,10 +4848,10 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
case Type::FunctionProto: {
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
- MarkUsedTemplateParameters(Ctx, Proto->getResultType(), OnlyDeduced,
- Depth, Used);
- for (unsigned I = 0, N = Proto->getNumArgs(); I != N; ++I)
- MarkUsedTemplateParameters(Ctx, Proto->getArgType(I), OnlyDeduced,
+ MarkUsedTemplateParameters(Ctx, Proto->getReturnType(), OnlyDeduced, Depth,
+ Used);
+ for (unsigned I = 0, N = Proto->getNumParams(); I != N; ++I)
+ MarkUsedTemplateParameters(Ctx, Proto->getParamType(I), OnlyDeduced,
Depth, Used);
break;
}
@@ -5061,10 +5035,8 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
break;
case TemplateArgument::Pack:
- for (TemplateArgument::pack_iterator P = TemplateArg.pack_begin(),
- PEnd = TemplateArg.pack_end();
- P != PEnd; ++P)
- MarkUsedTemplateParameters(Ctx, *P, OnlyDeduced, Depth, Used);
+ for (const auto &P : TemplateArg.pack_elements())
+ MarkUsedTemplateParameters(Ctx, P, OnlyDeduced, Depth, Used);
break;
}
}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 8904f3794955..14c64050168a 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -76,8 +76,18 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
// If this variable template specialization was instantiated from a
// specialized member that is a variable template, we're done.
assert(Spec->getSpecializedTemplate() && "No variable template?");
- if (Spec->getSpecializedTemplate()->isMemberSpecialization())
- return Result;
+ llvm::PointerUnion<VarTemplateDecl*,
+ VarTemplatePartialSpecializationDecl*> Specialized
+ = Spec->getSpecializedTemplateOrPartial();
+ if (VarTemplatePartialSpecializationDecl *Partial =
+ Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
+ if (Partial->isMemberSpecialization())
+ return Result;
+ } else {
+ VarTemplateDecl *Tmpl = Specialized.get<VarTemplateDecl *>();
+ if (Tmpl->isMemberSpecialization())
+ return Result;
+ }
}
// If we have a template template parameter with translation unit context,
@@ -190,50 +200,49 @@ bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const {
llvm_unreachable("Invalid InstantiationKind!");
}
-Sema::InstantiatingTemplate::
-InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
- Decl *Entity,
- SourceRange InstantiationRange)
- : SemaRef(SemaRef),
- SavedInNonInstantiationSFINAEContext(
- SemaRef.InNonInstantiationSFINAEContext)
-{
- Invalid = CheckInstantiationDepth(PointOfInstantiation,
- InstantiationRange);
+void Sema::InstantiatingTemplate::Initialize(
+ ActiveTemplateInstantiation::InstantiationKind Kind,
+ SourceLocation PointOfInstantiation, SourceRange InstantiationRange,
+ Decl *Entity, NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
+ sema::TemplateDeductionInfo *DeductionInfo) {
+ SavedInNonInstantiationSFINAEContext =
+ SemaRef.InNonInstantiationSFINAEContext;
+ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
if (!Invalid) {
ActiveTemplateInstantiation Inst;
- Inst.Kind = ActiveTemplateInstantiation::TemplateInstantiation;
+ Inst.Kind = Kind;
Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Entity = Entity;
- Inst.TemplateArgs = 0;
- Inst.NumTemplateArgs = 0;
+ Inst.Template = Template;
+ Inst.TemplateArgs = TemplateArgs.data();
+ Inst.NumTemplateArgs = TemplateArgs.size();
+ Inst.DeductionInfo = DeductionInfo;
Inst.InstantiationRange = InstantiationRange;
SemaRef.InNonInstantiationSFINAEContext = false;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
+ if (!Inst.isInstantiationRecord())
+ ++SemaRef.NonInstantiationEntries;
}
}
Sema::InstantiatingTemplate::
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ Decl *Entity,
+ SourceRange InstantiationRange)
+ : SemaRef(SemaRef)
+{
+ Initialize(ActiveTemplateInstantiation::TemplateInstantiation,
+ PointOfInstantiation, InstantiationRange, Entity);
+}
+
+Sema::InstantiatingTemplate::
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
FunctionDecl *Entity, ExceptionSpecification,
SourceRange InstantiationRange)
- : SemaRef(SemaRef),
- SavedInNonInstantiationSFINAEContext(
- SemaRef.InNonInstantiationSFINAEContext)
+ : SemaRef(SemaRef)
{
- Invalid = CheckInstantiationDepth(PointOfInstantiation,
- InstantiationRange);
- if (!Invalid) {
- ActiveTemplateInstantiation Inst;
- Inst.Kind = ActiveTemplateInstantiation::ExceptionSpecInstantiation;
- Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = Entity;
- Inst.TemplateArgs = 0;
- Inst.NumTemplateArgs = 0;
- Inst.InstantiationRange = InstantiationRange;
- SemaRef.InNonInstantiationSFINAEContext = false;
- SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- }
+ Initialize(ActiveTemplateInstantiation::ExceptionSpecInstantiation,
+ PointOfInstantiation, InstantiationRange, Entity);
}
Sema::InstantiatingTemplate::
@@ -241,24 +250,11 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
TemplateDecl *Template,
ArrayRef<TemplateArgument> TemplateArgs,
SourceRange InstantiationRange)
- : SemaRef(SemaRef),
- SavedInNonInstantiationSFINAEContext(
- SemaRef.InNonInstantiationSFINAEContext)
+ : SemaRef(SemaRef)
{
- Invalid = CheckInstantiationDepth(PointOfInstantiation,
- InstantiationRange);
- if (!Invalid) {
- ActiveTemplateInstantiation Inst;
- Inst.Kind
- = ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation;
- Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = Template;
- Inst.TemplateArgs = TemplateArgs.data();
- Inst.NumTemplateArgs = TemplateArgs.size();
- Inst.InstantiationRange = InstantiationRange;
- SemaRef.InNonInstantiationSFINAEContext = false;
- SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- }
+ Initialize(ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation,
+ PointOfInstantiation, InstantiationRange,
+ Template, nullptr, TemplateArgs);
}
Sema::InstantiatingTemplate::
@@ -268,26 +264,10 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
ActiveTemplateInstantiation::InstantiationKind Kind,
sema::TemplateDeductionInfo &DeductionInfo,
SourceRange InstantiationRange)
- : SemaRef(SemaRef),
- SavedInNonInstantiationSFINAEContext(
- SemaRef.InNonInstantiationSFINAEContext)
+ : SemaRef(SemaRef)
{
- Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
- if (!Invalid) {
- ActiveTemplateInstantiation Inst;
- Inst.Kind = Kind;
- Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = FunctionTemplate;
- Inst.TemplateArgs = TemplateArgs.data();
- Inst.NumTemplateArgs = TemplateArgs.size();
- Inst.DeductionInfo = &DeductionInfo;
- Inst.InstantiationRange = InstantiationRange;
- SemaRef.InNonInstantiationSFINAEContext = false;
- SemaRef.ActiveTemplateInstantiations.push_back(Inst);
-
- if (!Inst.isInstantiationRecord())
- ++SemaRef.NonInstantiationEntries;
- }
+ Initialize(Kind, PointOfInstantiation, InstantiationRange,
+ FunctionTemplate, nullptr, TemplateArgs, &DeductionInfo);
}
Sema::InstantiatingTemplate::
@@ -296,23 +276,11 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
ArrayRef<TemplateArgument> TemplateArgs,
sema::TemplateDeductionInfo &DeductionInfo,
SourceRange InstantiationRange)
- : SemaRef(SemaRef),
- SavedInNonInstantiationSFINAEContext(
- SemaRef.InNonInstantiationSFINAEContext)
+ : SemaRef(SemaRef)
{
- Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
- if (!Invalid) {
- ActiveTemplateInstantiation Inst;
- Inst.Kind = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution;
- Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = PartialSpec;
- Inst.TemplateArgs = TemplateArgs.data();
- Inst.NumTemplateArgs = TemplateArgs.size();
- Inst.DeductionInfo = &DeductionInfo;
- Inst.InstantiationRange = InstantiationRange;
- SemaRef.InNonInstantiationSFINAEContext = false;
- SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- }
+ Initialize(ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
+ PointOfInstantiation, InstantiationRange,
+ PartialSpec, nullptr, TemplateArgs, &DeductionInfo);
}
Sema::InstantiatingTemplate::InstantiatingTemplate(
@@ -320,22 +288,11 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
VarTemplatePartialSpecializationDecl *PartialSpec,
ArrayRef<TemplateArgument> TemplateArgs,
sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
- : SemaRef(SemaRef), SavedInNonInstantiationSFINAEContext(
- SemaRef.InNonInstantiationSFINAEContext) {
- Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
- if (!Invalid) {
- ActiveTemplateInstantiation Inst;
- Inst.Kind =
- ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution;
- Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = PartialSpec;
- Inst.TemplateArgs = TemplateArgs.data();
- Inst.NumTemplateArgs = TemplateArgs.size();
- Inst.DeductionInfo = &DeductionInfo;
- Inst.InstantiationRange = InstantiationRange;
- SemaRef.InNonInstantiationSFINAEContext = false;
- SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- }
+ : SemaRef(SemaRef)
+{
+ Initialize(ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
+ PointOfInstantiation, InstantiationRange,
+ PartialSpec, nullptr, TemplateArgs, &DeductionInfo);
}
Sema::InstantiatingTemplate::
@@ -343,47 +300,24 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
ParmVarDecl *Param,
ArrayRef<TemplateArgument> TemplateArgs,
SourceRange InstantiationRange)
- : SemaRef(SemaRef),
- SavedInNonInstantiationSFINAEContext(
- SemaRef.InNonInstantiationSFINAEContext)
+ : SemaRef(SemaRef)
{
- Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
- if (!Invalid) {
- ActiveTemplateInstantiation Inst;
- Inst.Kind
- = ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation;
- Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = Param;
- Inst.TemplateArgs = TemplateArgs.data();
- Inst.NumTemplateArgs = TemplateArgs.size();
- Inst.InstantiationRange = InstantiationRange;
- SemaRef.InNonInstantiationSFINAEContext = false;
- SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- }
+ Initialize(ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation,
+ PointOfInstantiation, InstantiationRange,
+ Param, nullptr, TemplateArgs);
}
+
Sema::InstantiatingTemplate::
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
NamedDecl *Template, NonTypeTemplateParmDecl *Param,
ArrayRef<TemplateArgument> TemplateArgs,
SourceRange InstantiationRange)
- : SemaRef(SemaRef),
- SavedInNonInstantiationSFINAEContext(
- SemaRef.InNonInstantiationSFINAEContext)
+ : SemaRef(SemaRef)
{
- Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
- if (!Invalid) {
- ActiveTemplateInstantiation Inst;
- Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
- Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Template = Template;
- Inst.Entity = Param;
- Inst.TemplateArgs = TemplateArgs.data();
- Inst.NumTemplateArgs = TemplateArgs.size();
- Inst.InstantiationRange = InstantiationRange;
- SemaRef.InNonInstantiationSFINAEContext = false;
- SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- }
+ Initialize(ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution,
+ PointOfInstantiation, InstantiationRange,
+ Param, Template, TemplateArgs);
}
Sema::InstantiatingTemplate::
@@ -391,23 +325,11 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
NamedDecl *Template, TemplateTemplateParmDecl *Param,
ArrayRef<TemplateArgument> TemplateArgs,
SourceRange InstantiationRange)
- : SemaRef(SemaRef),
- SavedInNonInstantiationSFINAEContext(
- SemaRef.InNonInstantiationSFINAEContext)
+ : SemaRef(SemaRef)
{
- Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
- if (!Invalid) {
- ActiveTemplateInstantiation Inst;
- Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
- Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Template = Template;
- Inst.Entity = Param;
- Inst.TemplateArgs = TemplateArgs.data();
- Inst.NumTemplateArgs = TemplateArgs.size();
- Inst.InstantiationRange = InstantiationRange;
- SemaRef.InNonInstantiationSFINAEContext = false;
- SemaRef.ActiveTemplateInstantiations.push_back(Inst);
- }
+ Initialize(ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution,
+ PointOfInstantiation, InstantiationRange,
+ Param, Template, TemplateArgs);
}
Sema::InstantiatingTemplate::
@@ -415,25 +337,11 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
TemplateDecl *Template, NamedDecl *Param,
ArrayRef<TemplateArgument> TemplateArgs,
SourceRange InstantiationRange)
- : SemaRef(SemaRef),
- SavedInNonInstantiationSFINAEContext(
- SemaRef.InNonInstantiationSFINAEContext)
+ : SemaRef(SemaRef)
{
- Invalid = false;
-
- ActiveTemplateInstantiation Inst;
- Inst.Kind = ActiveTemplateInstantiation::DefaultTemplateArgumentChecking;
- Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Template = Template;
- Inst.Entity = Param;
- Inst.TemplateArgs = TemplateArgs.data();
- Inst.NumTemplateArgs = TemplateArgs.size();
- Inst.InstantiationRange = InstantiationRange;
- SemaRef.InNonInstantiationSFINAEContext = false;
- SemaRef.ActiveTemplateInstantiations.push_back(Inst);
-
- assert(!Inst.isInstantiationRecord());
- ++SemaRef.NonInstantiationEntries;
+ Initialize(ActiveTemplateInstantiation::DefaultTemplateArgumentChecking,
+ PointOfInstantiation, InstantiationRange,
+ Param, Template, TemplateArgs);
}
void Sema::InstantiatingTemplate::Clear() {
@@ -624,8 +532,8 @@ void Sema::PrintInstantiationStack() {
std::string Name;
if (!Parm->getName().empty())
Name = std::string(" '") + Parm->getName().str() + "'";
-
- TemplateParameterList *TemplateParams = 0;
+
+ TemplateParameterList *TemplateParams = nullptr;
if (TemplateDecl *Template = dyn_cast<TemplateDecl>(Active->Template))
TemplateParams = Template->getTemplateParameters();
else
@@ -644,7 +552,7 @@ void Sema::PrintInstantiationStack() {
}
case ActiveTemplateInstantiation::DefaultTemplateArgumentChecking: {
- TemplateParameterList *TemplateParams = 0;
+ TemplateParameterList *TemplateParams = nullptr;
if (TemplateDecl *Template = dyn_cast<TemplateDecl>(Active->Template))
TemplateParams = Template->getTemplateParameters();
else
@@ -673,7 +581,7 @@ void Sema::PrintInstantiationStack() {
Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
if (InNonInstantiationSFINAEContext)
- return Optional<TemplateDeductionInfo *>(0);
+ return Optional<TemplateDeductionInfo *>(nullptr);
for (SmallVectorImpl<ActiveTemplateInstantiation>::const_reverse_iterator
Active = ActiveTemplateInstantiations.rbegin(),
@@ -789,7 +697,7 @@ namespace {
MultiLevelTemplateArgumentList &TemplateArgs
= const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
unsigned Depth, Index;
- llvm::tie(Depth, Index) = getDepthAndIndex(PartialPack);
+ std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
if (TemplateArgs.hasTemplateArgument(Depth, Index)) {
Result = TemplateArgs(Depth, Index);
TemplateArgs.setArgument(Depth, Index, TemplateArgument());
@@ -808,7 +716,7 @@ namespace {
MultiLevelTemplateArgumentList &TemplateArgs
= const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
unsigned Depth, Index;
- llvm::tie(Depth, Index) = getDepthAndIndex(PartialPack);
+ std::tie(Depth, Index) = getDepthAndIndex(PartialPack);
TemplateArgs.setArgument(Depth, Index, Arg);
}
}
@@ -853,11 +761,11 @@ namespace {
NestedNameSpecifierLoc QualifierLoc,
QualType T);
- TemplateName TransformTemplateName(CXXScopeSpec &SS,
- TemplateName Name,
- SourceLocation NameLoc,
- QualType ObjectType = QualType(),
- NamedDecl *FirstQualifierInScope = 0);
+ TemplateName
+ TransformTemplateName(CXXScopeSpec &SS, TemplateName Name,
+ SourceLocation NameLoc,
+ QualType ObjectType = QualType(),
+ NamedDecl *FirstQualifierInScope = nullptr);
ExprResult TransformPredefinedExpr(PredefinedExpr *E);
ExprResult TransformDeclRefExpr(DeclRefExpr *E);
@@ -929,8 +837,6 @@ namespace {
OldCallOperator->getDescribedFunctionTemplate();
NewCallOperatorTemplate->setInstantiatedFromMemberTemplate(
OldCallOperatorTemplate);
- // Mark the NewCallOperatorTemplate a specialization.
- NewCallOperatorTemplate->setMemberSpecialization();
} else
// For a non-generic lambda we set the NewCallOperator to
// be an instantiation of the OldCallOperator.
@@ -940,7 +846,7 @@ namespace {
return inherited::TransformLambdaScope(E, NewCallOperator,
InitCaptureExprsAndTypes);
}
- TemplateParameterList *TransformTemplateParameterList(
+ TemplateParameterList *TransformTemplateParameterList(
TemplateParameterList *OrigTPL) {
if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
@@ -979,7 +885,7 @@ getPackSubstitutedTemplateArgument(Sema &S, TemplateArgument Arg) {
Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
if (!D)
- return 0;
+ return nullptr;
if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
@@ -1015,7 +921,7 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
Decl *TemplateInstantiator::TransformDefinition(SourceLocation Loc, Decl *D) {
Decl *Inst = getSema().SubstDecl(D, getSema().CurContext, TemplateArgs);
if (!Inst)
- return 0;
+ return nullptr;
getSema().CurrentInstantiationScope->InstantiatedLocal(D, Inst);
return Inst;
@@ -1039,8 +945,8 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D,
"Missing argument pack");
if (getSema().ArgumentPackSubstitutionIndex == -1)
- return 0;
-
+ return nullptr;
+
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
@@ -1053,7 +959,7 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D,
// The resulting type is not a tag; complain.
getSema().Diag(Loc, diag::err_nested_name_spec_non_tag) << T;
- return 0;
+ return nullptr;
}
}
@@ -1178,7 +1084,7 @@ TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS,
ExprResult
TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
if (!E->isTypeDependent())
- return SemaRef.Owned(E);
+ return E;
return getSema().BuildPredefinedExpr(E->getLocation(), E->getIdentType());
}
@@ -1192,7 +1098,7 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
// arguments left unspecified.
if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(),
NTTP->getPosition()))
- return SemaRef.Owned(E);
+ return E;
TemplateArgument Arg = TemplateArgs(NTTP->getDepth(), NTTP->getPosition());
if (NTTP->isParameterPack()) {
@@ -1232,7 +1138,7 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
// case we just return that expression.
if (arg.getKind() == TemplateArgument::Expression) {
Expr *argExpr = arg.getAsExpr();
- result = SemaRef.Owned(argExpr);
+ result = argExpr;
type = argExpr->getType();
} else if (arg.getKind() == TemplateArgument::Declaration ||
@@ -1249,7 +1155,7 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
return ExprError();
} else {
// Propagate NULL template argument.
- VD = 0;
+ VD = nullptr;
}
// Derive the type we want the substituted decl to have. This had
@@ -1279,11 +1185,9 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
}
if (result.isInvalid()) return ExprError();
- Expr *resultExpr = result.take();
- return SemaRef.Owned(new (SemaRef.Context)
- SubstNonTypeTemplateParmExpr(type,
- resultExpr->getValueKind(),
- loc, parm, resultExpr));
+ Expr *resultExpr = result.get();
+ return new (SemaRef.Context) SubstNonTypeTemplateParmExpr(
+ type, resultExpr->getValueKind(), loc, parm, resultExpr);
}
ExprResult
@@ -1291,7 +1195,7 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *E) {
if (getSema().ArgumentPackSubstitutionIndex == -1) {
// We aren't expanding the parameter pack, so just return ourselves.
- return getSema().Owned(E);
+ return E;
}
TemplateArgument Arg = E->getArgumentPack();
@@ -1487,7 +1391,7 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
// the template parameter list of a member template inside the
// template we are instantiating). Create a new template type
// parameter with the template "level" reduced by one.
- TemplateTypeParmDecl *NewTTPDecl = 0;
+ TemplateTypeParmDecl *NewTTPDecl = nullptr;
if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl())
NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
TransformDecl(TL.getNameLoc(), OldTTPDecl));
@@ -1580,7 +1484,7 @@ TypeSourceInfo *Sema::SubstType(TypeLoc TL,
"instantiation stack");
if (TL.getType().isNull())
- return 0;
+ return nullptr;
if (!TL.getType()->isInstantiationDependentType() &&
!TL.getType()->isVariablyModifiedType()) {
@@ -1596,7 +1500,7 @@ TypeSourceInfo *Sema::SubstType(TypeLoc TL,
TLB.reserve(TL.getFullDataSize());
QualType Result = Instantiator.TransformType(TLB, TL);
if (Result.isNull())
- return 0;
+ return nullptr;
return TLB.getTypeSourceInfo(Context, Result);
}
@@ -1628,8 +1532,8 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
return false;
FunctionProtoTypeLoc FP = TL.castAs<FunctionProtoTypeLoc>();
- for (unsigned I = 0, E = FP.getNumArgs(); I != E; ++I) {
- ParmVarDecl *P = FP.getArg(I);
+ for (unsigned I = 0, E = FP.getNumParams(); I != E; ++I) {
+ ParmVarDecl *P = FP.getParam(I);
// This must be synthesized from a typedef.
if (!P) continue;
@@ -1682,7 +1586,7 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
Result = Instantiator.TransformType(TLB, TL);
}
if (Result.isNull())
- return 0;
+ return nullptr;
return TLB.getTypeSourceInfo(Context, Result);
}
@@ -1693,8 +1597,8 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
Optional<unsigned> NumExpansions,
bool ExpectParameterPack) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
- TypeSourceInfo *NewDI = 0;
-
+ TypeSourceInfo *NewDI = nullptr;
+
TypeLoc OldTL = OldDI->getTypeLoc();
if (PackExpansionTypeLoc ExpansionTL = OldTL.getAs<PackExpansionTypeLoc>()) {
@@ -1703,8 +1607,8 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
NewDI = SubstType(ExpansionTL.getPatternLoc(), TemplateArgs,
OldParm->getLocation(), OldParm->getDeclName());
if (!NewDI)
- return 0;
-
+ return nullptr;
+
if (NewDI->getType()->containsUnexpandedParameterPack()) {
// We still have unexpanded parameter packs, which means that
// our function parameter is still a function parameter pack.
@@ -1719,7 +1623,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
Diag(OldParm->getLocation(),
diag::err_function_parameter_pack_without_parameter_packs)
<< NewDI->getType();
- return 0;
+ return nullptr;
}
} else {
NewDI = SubstType(OldDI, TemplateArgs, OldParm->getLocation(),
@@ -1727,11 +1631,11 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
}
if (!NewDI)
- return 0;
+ return nullptr;
if (NewDI->getType()->isVoidType()) {
Diag(OldParm->getLocation(), diag::err_param_with_void_type);
- return 0;
+ return nullptr;
}
ParmVarDecl *NewParm = CheckParameter(Context.getTranslationUnitDecl(),
@@ -1741,8 +1645,8 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
NewDI->getType(), NewDI,
OldParm->getStorageClass());
if (!NewParm)
- return 0;
-
+ return nullptr;
+
// Mark the (new) default argument as uninstantiated (if any).
if (OldParm->hasUninstantiatedDefaultArg()) {
Expr *Arg = OldParm->getUninstantiatedDefaultArg();
@@ -1792,8 +1696,9 @@ bool Sema::SubstParmTypes(SourceLocation Loc,
TemplateInstantiator Instantiator(*this, TemplateArgs, Loc,
DeclarationName());
- return Instantiator.TransformFunctionTypeParams(Loc, Params, NumParams, 0,
- ParamTypes, OutParams);
+ return Instantiator.TransformFunctionTypeParams(Loc, Params, NumParams,
+ nullptr, ParamTypes,
+ OutParams);
}
/// \brief Perform substitution on the base class specifiers of the
@@ -1808,31 +1713,29 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
const MultiLevelTemplateArgumentList &TemplateArgs) {
bool Invalid = false;
SmallVector<CXXBaseSpecifier*, 4> InstantiatedBases;
- for (ClassTemplateSpecializationDecl::base_class_iterator
- Base = Pattern->bases_begin(), BaseEnd = Pattern->bases_end();
- Base != BaseEnd; ++Base) {
- if (!Base->getType()->isDependentType()) {
- if (const CXXRecordDecl *RD = Base->getType()->getAsCXXRecordDecl()) {
+ for (const auto Base : Pattern->bases()) {
+ if (!Base.getType()->isDependentType()) {
+ if (const CXXRecordDecl *RD = Base.getType()->getAsCXXRecordDecl()) {
if (RD->isInvalidDecl())
Instantiation->setInvalidDecl();
}
- InstantiatedBases.push_back(new (Context) CXXBaseSpecifier(*Base));
+ InstantiatedBases.push_back(new (Context) CXXBaseSpecifier(Base));
continue;
}
SourceLocation EllipsisLoc;
TypeSourceInfo *BaseTypeLoc;
- if (Base->isPackExpansion()) {
+ if (Base.isPackExpansion()) {
// This is a pack expansion. See whether we should expand it now, or
// wait until later.
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
- collectUnexpandedParameterPacks(Base->getTypeSourceInfo()->getTypeLoc(),
+ collectUnexpandedParameterPacks(Base.getTypeSourceInfo()->getTypeLoc(),
Unexpanded);
bool ShouldExpand = false;
bool RetainExpansion = false;
Optional<unsigned> NumExpansions;
- if (CheckParameterPacksForExpansion(Base->getEllipsisLoc(),
- Base->getSourceRange(),
+ if (CheckParameterPacksForExpansion(Base.getEllipsisLoc(),
+ Base.getSourceRange(),
Unexpanded,
TemplateArgs, ShouldExpand,
RetainExpansion,
@@ -1846,9 +1749,9 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, I);
- TypeSourceInfo *BaseTypeLoc = SubstType(Base->getTypeSourceInfo(),
+ TypeSourceInfo *BaseTypeLoc = SubstType(Base.getTypeSourceInfo(),
TemplateArgs,
- Base->getSourceRange().getBegin(),
+ Base.getSourceRange().getBegin(),
DeclarationName());
if (!BaseTypeLoc) {
Invalid = true;
@@ -1857,9 +1760,9 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
if (CXXBaseSpecifier *InstantiatedBase
= CheckBaseSpecifier(Instantiation,
- Base->getSourceRange(),
- Base->isVirtual(),
- Base->getAccessSpecifierAsWritten(),
+ Base.getSourceRange(),
+ Base.isVirtual(),
+ Base.getAccessSpecifierAsWritten(),
BaseTypeLoc,
SourceLocation()))
InstantiatedBases.push_back(InstantiatedBase);
@@ -1871,16 +1774,16 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
}
// The resulting base specifier will (still) be a pack expansion.
- EllipsisLoc = Base->getEllipsisLoc();
+ EllipsisLoc = Base.getEllipsisLoc();
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, -1);
- BaseTypeLoc = SubstType(Base->getTypeSourceInfo(),
+ BaseTypeLoc = SubstType(Base.getTypeSourceInfo(),
TemplateArgs,
- Base->getSourceRange().getBegin(),
+ Base.getSourceRange().getBegin(),
DeclarationName());
} else {
- BaseTypeLoc = SubstType(Base->getTypeSourceInfo(),
+ BaseTypeLoc = SubstType(Base.getTypeSourceInfo(),
TemplateArgs,
- Base->getSourceRange().getBegin(),
+ Base.getSourceRange().getBegin(),
DeclarationName());
}
@@ -1891,9 +1794,9 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
if (CXXBaseSpecifier *InstantiatedBase
= CheckBaseSpecifier(Instantiation,
- Base->getSourceRange(),
- Base->isVirtual(),
- Base->getAccessSpecifierAsWritten(),
+ Base.getSourceRange(),
+ Base.isVirtual(),
+ Base.getAccessSpecifierAsWritten(),
BaseTypeLoc,
EllipsisLoc))
InstantiatedBases.push_back(InstantiatedBase);
@@ -1945,7 +1848,7 @@ static bool DiagnoseUninstantiableTemplate(Sema &S,
S.Diag(PointOfInstantiation,
diag::err_implicit_instantiate_member_undefined)
<< S.Context.getTypeDeclType(Instantiation);
- S.Diag(Pattern->getLocation(), diag::note_member_of_template_here);
+ S.Diag(Pattern->getLocation(), diag::note_member_declared_at);
} else {
S.Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
<< (TSK != TSK_ImplicitInstantiation)
@@ -2008,7 +1911,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Spec->setTemplateSpecializationKind(TSK);
Spec->setPointOfInstantiation(PointOfInstantiation);
}
-
+
InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation);
if (Inst.isInvalid())
return true;
@@ -2030,7 +1933,12 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Start the definition of this instantiation.
Instantiation->startDefinition();
-
+
+ // The instantiation is visible here, even if it was first declared in an
+ // unimported module.
+ Instantiation->setHidden(false);
+
+ // FIXME: This loses the as-written tag kind for an explicit instantiation.
Instantiation->setTagKind(Pattern->getTagKind());
// Do substitution on the base class specifiers.
@@ -2045,9 +1953,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
LateInstantiatedAttrVec LateAttrs;
Instantiator.enableLateAttributeInstantiation(&LateAttrs);
- for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
- MemberEnd = Pattern->decls_end();
- Member != MemberEnd; ++Member) {
+ for (auto *Member : Pattern->decls()) {
// Don't instantiate members not belonging in this semantic context.
// e.g. for:
// @code
@@ -2057,19 +1963,19 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// @endcode
// 'class B' has the template as lexical context but semantically it is
// introduced in namespace scope.
- if ((*Member)->getDeclContext() != Pattern)
+ if (Member->getDeclContext() != Pattern)
continue;
- if ((*Member)->isInvalidDecl()) {
+ if (Member->isInvalidDecl()) {
Instantiation->setInvalidDecl();
continue;
}
- Decl *NewMember = Instantiator.Visit(*Member);
+ Decl *NewMember = Instantiator.Visit(Member);
if (NewMember) {
if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) {
Fields.push_back(Field);
- FieldDecl *OldField = cast<FieldDecl>(*Member);
+ FieldDecl *OldField = cast<FieldDecl>(Member);
if (OldField->getInClassInitializer())
FieldsWithMemberInitializers.push_back(std::make_pair(OldField,
Field));
@@ -2105,8 +2011,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
}
// Finish checking fields.
- ActOnFields(0, Instantiation->getLocation(), Instantiation, Fields,
- SourceLocation(), SourceLocation(), 0);
+ ActOnFields(nullptr, Instantiation->getLocation(), Instantiation, Fields,
+ SourceLocation(), SourceLocation(), nullptr);
CheckCompletedCXXClass(Instantiation);
// Attach any in-class member initializers now the class is complete.
@@ -2124,16 +2030,14 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
FieldDecl *NewField = FieldsWithMemberInitializers[I].second;
Expr *OldInit = OldField->getInClassInitializer();
+ ActOnStartCXXInClassMemberInitializer();
ExprResult NewInit = SubstInitializer(OldInit, TemplateArgs,
/*CXXDirectInit=*/false);
- if (NewInit.isInvalid())
- NewField->setInvalidDecl();
- else {
- Expr *Init = NewInit.take();
- assert(Init && "no-argument initializer in class");
- assert(!isa<ParenListExpr>(Init) && "call-style init in class");
- ActOnCXXInClassMemberInitializer(NewField, Init->getLocStart(), Init);
- }
+ Expr *Init = NewInit.get();
+ assert((!Init || !isa<ParenListExpr>(Init)) &&
+ "call-style init in class");
+ ActOnFinishCXXInClassMemberInitializer(NewField,
+ Init ? Init->getLocStart() : SourceLocation(), Init);
}
}
// Instantiate late parsed attributes, and attach them to their decls.
@@ -2161,6 +2065,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
ActOnFinishDelayedMemberInitializers(Instantiation);
+ // FIXME: We should do something similar for explicit instantiations so they
+ // end up in the right module.
if (TSK == TSK_ImplicitInstantiation) {
Instantiation->setLocation(Pattern->getLocation());
Instantiation->setLocStart(Pattern->getInnerLocStart());
@@ -2250,6 +2156,10 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation,
if (Inst.isInvalid())
return true;
+ // The instantiation is visible here, even if it was first declared in an
+ // unimported module.
+ Instantiation->setHidden(false);
+
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
ContextRAII SavedContext(*this, Instantiation);
@@ -2317,7 +2227,7 @@ bool Sema::InstantiateClassTemplateSpecialization(
return true;
ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
- CXXRecordDecl *Pattern = 0;
+ CXXRecordDecl *Pattern = nullptr;
// C++ [temp.class.spec.match]p1:
// When a class template is used in a context that requires an
@@ -2354,8 +2264,7 @@ bool Sema::InstantiateClassTemplateSpecialization(
// If we're dealing with a member template where the template parameters
// have been instantiated, this provides the original template parameters
// from which the member template's parameters were instantiated.
- SmallVector<const NamedDecl *, 4> InstantiatedTemplateParameters;
-
+
if (Matched.size() >= 1) {
SmallVectorImpl<MatchResult>::iterator Best = Matched.begin();
if (Matched.size() == 1) {
@@ -2459,16 +2368,17 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation,
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateSpecializationKind TSK) {
+ // FIXME: We need to notify the ASTMutationListener that we did all of these
+ // things, in case we have an explicit instantiation definition in a PCM, a
+ // module, or preamble, and the declaration is in an imported AST.
assert(
(TSK == TSK_ExplicitInstantiationDefinition ||
TSK == TSK_ExplicitInstantiationDeclaration ||
(TSK == TSK_ImplicitInstantiation && Instantiation->isLocalClass())) &&
"Unexpected template specialization kind!");
- for (DeclContext::decl_iterator D = Instantiation->decls_begin(),
- DEnd = Instantiation->decls_end();
- D != DEnd; ++D) {
+ for (auto *D : Instantiation->decls()) {
bool SuppressNew = false;
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(*D)) {
+ if (auto *Function = dyn_cast<FunctionDecl>(D)) {
if (FunctionDecl *Pattern
= Function->getInstantiatedFromMemberFunction()) {
MemberSpecializationInfo *MSInfo
@@ -2485,31 +2395,30 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
SuppressNew) ||
SuppressNew)
continue;
-
- if (Function->isDefined())
+
+ // C++11 [temp.explicit]p8:
+ // An explicit instantiation definition that names a class template
+ // specialization explicitly instantiates the class template
+ // specialization and is only an explicit instantiation definition
+ // of members whose definition is visible at the point of
+ // instantiation.
+ if (TSK == TSK_ExplicitInstantiationDefinition && !Pattern->isDefined())
continue;
- if (TSK == TSK_ExplicitInstantiationDefinition) {
- // C++0x [temp.explicit]p8:
- // An explicit instantiation definition that names a class template
- // specialization explicitly instantiates the class template
- // specialization and is only an explicit instantiation definition
- // of members whose definition is visible at the point of
- // instantiation.
- if (!Pattern->isDefined())
- continue;
-
- Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
-
+ Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+
+ if (Function->isDefined()) {
+ // Let the ASTConsumer know that this function has been explicitly
+ // instantiated now, and its linkage might have changed.
+ Consumer.HandleTopLevelDecl(DeclGroupRef(Function));
+ } else if (TSK == TSK_ExplicitInstantiationDefinition) {
InstantiateFunctionDefinition(PointOfInstantiation, Function);
- } else {
- Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
- if (TSK == TSK_ImplicitInstantiation)
- PendingLocalImplicitInstantiations.push_back(
- std::make_pair(Function, PointOfInstantiation));
+ } else if (TSK == TSK_ImplicitInstantiation) {
+ PendingLocalImplicitInstantiations.push_back(
+ std::make_pair(Function, PointOfInstantiation));
}
}
- } else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
+ } else if (auto *Var = dyn_cast<VarDecl>(D)) {
if (isa<VarTemplateSpecializationDecl>(Var))
continue;
@@ -2545,7 +2454,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
}
}
- } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) {
+ } else if (auto *Record = dyn_cast<CXXRecordDecl>(D)) {
// Always skip the injected-class-name, along with any
// redeclarations of nested classes, since both would cause us
// to try to instantiate the members of a class twice.
@@ -2602,7 +2511,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
if (Pattern)
InstantiateClassMembers(PointOfInstantiation, Pattern, TemplateArgs,
TSK);
- } else if (EnumDecl *Enum = dyn_cast<EnumDecl>(*D)) {
+ } else if (auto *Enum = dyn_cast<EnumDecl>(D)) {
MemberSpecializationInfo *MSInfo = Enum->getMemberSpecializationInfo();
assert(MSInfo && "No member specialization information?");
@@ -2660,7 +2569,7 @@ Sema::InstantiateClassTemplateSpecializationMembers(
StmtResult
Sema::SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs) {
if (!S)
- return Owned(S);
+ return S;
TemplateInstantiator Instantiator(*this, TemplateArgs,
SourceLocation(),
@@ -2671,7 +2580,7 @@ Sema::SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs) {
ExprResult
Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
if (!E)
- return Owned(E);
+ return E;
TemplateInstantiator Instantiator(*this, TemplateArgs,
SourceLocation(),
@@ -2774,7 +2683,7 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) {
if (const TagDecl *Tag = dyn_cast<TagDecl>(CheckD))
CheckD = Tag->getPreviousDecl();
else
- CheckD = 0;
+ CheckD = nullptr;
} while (CheckD);
// If we aren't combined with our outer scope, we're done.
@@ -2786,13 +2695,13 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) {
// deduction, we may not have values for template parameters yet.
if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
isa<TemplateTemplateParmDecl>(D))
- return 0;
+ return nullptr;
// If we didn't find the decl, then we either have a sema bug, or we have a
// forward reference to a label declaration. Return null to indicate that
// we have an uninstantiated label.
assert(isa<LabelDecl>(D) && "declaration not instantiated in this scope");
- return 0;
+ return nullptr;
}
void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) {
@@ -2839,7 +2748,7 @@ NamedDecl *LocalInstantiationScope::getPartiallySubstitutedPack(
const TemplateArgument **ExplicitArgs,
unsigned *NumExplicitArgs) const {
if (ExplicitArgs)
- *ExplicitArgs = 0;
+ *ExplicitArgs = nullptr;
if (NumExplicitArgs)
*NumExplicitArgs = 0;
@@ -2857,6 +2766,6 @@ NamedDecl *LocalInstantiationScope::getPartiallySubstitutedPack(
if (!Current->CombineWithOuterScope)
break;
}
-
- return 0;
+
+ return nullptr;
}
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 5c28e3b7a828..accec95bf708 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -12,13 +12,13 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/DependentDiagnostic.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Sema/Template.h"
@@ -79,7 +79,7 @@ static void instantiateDependentAlignedAttr(
EnterExpressionEvaluationContext Unevaluated(S, Sema::ConstantEvaluated);
ExprResult Result = S.SubstExpr(Aligned->getAlignmentExpr(), TemplateArgs);
if (!Result.isInvalid())
- S.AddAlignedAttr(Aligned->getLocation(), New, Result.takeAs<Expr>(),
+ S.AddAlignedAttr(Aligned->getLocation(), New, Result.getAs<Expr>(),
Aligned->getSpellingListIndex(), IsPackExpansion);
} else {
TypeSourceInfo *Result = S.SubstType(Aligned->getAlignmentType(),
@@ -129,14 +129,46 @@ static void instantiateDependentAlignedAttr(
}
}
+static void instantiateDependentEnableIfAttr(
+ Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
+ const EnableIfAttr *A, const Decl *Tmpl, Decl *New) {
+ Expr *Cond = nullptr;
+ {
+ EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated);
+ ExprResult Result = S.SubstExpr(A->getCond(), TemplateArgs);
+ if (Result.isInvalid())
+ return;
+ Cond = Result.getAs<Expr>();
+ }
+ if (A->getCond()->isTypeDependent() && !Cond->isTypeDependent()) {
+ ExprResult Converted = S.PerformContextuallyConvertToBool(Cond);
+ if (Converted.isInvalid())
+ return;
+ Cond = Converted.get();
+ }
+
+ SmallVector<PartialDiagnosticAt, 8> Diags;
+ if (A->getCond()->isValueDependent() && !Cond->isValueDependent() &&
+ !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(Tmpl),
+ Diags)) {
+ S.Diag(A->getLocation(), diag::err_enable_if_never_constant_expr);
+ for (int I = 0, N = Diags.size(); I != N; ++I)
+ S.Diag(Diags[I].first, Diags[I].second);
+ return;
+ }
+
+ EnableIfAttr *EIA = new (S.getASTContext())
+ EnableIfAttr(A->getLocation(), S.getASTContext(), Cond,
+ A->getMessage(),
+ A->getSpellingListIndex());
+ New->addAttr(EIA);
+}
+
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
const Decl *Tmpl, Decl *New,
LateInstantiatedAttrVec *LateAttrs,
LocalInstantiationScope *OuterMostScope) {
- for (AttrVec::const_iterator i = Tmpl->attr_begin(), e = Tmpl->attr_end();
- i != e; ++i) {
- const Attr *TmplAttr = *i;
-
+ for (const auto *TmplAttr : Tmpl->attrs()) {
// FIXME: This should be generalized to more than just the AlignedAttr.
const AlignedAttr *Aligned = dyn_cast<AlignedAttr>(TmplAttr);
if (Aligned && Aligned->isAlignmentDependent()) {
@@ -144,11 +176,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}
+ const EnableIfAttr *EnableIf = dyn_cast<EnableIfAttr>(TmplAttr);
+ if (EnableIf && EnableIf->getCond()->isValueDependent()) {
+ instantiateDependentEnableIfAttr(*this, TemplateArgs, EnableIf, Tmpl,
+ New);
+ continue;
+ }
+
assert(!TmplAttr->isPackExpansion());
if (TmplAttr->isLateParsed() && LateAttrs) {
// Late parsed attributes must be instantiated and attached after the
// enclosing class has been instantiated. See Sema::InstantiateClass.
- LocalInstantiationScope *Saved = 0;
+ LocalInstantiationScope *Saved = nullptr;
if (CurrentInstantiationScope)
Saved = CurrentInstantiationScope->cloneScopes(OuterMostScope);
LateAttrs->push_back(LateInstantiatedAttribute(TmplAttr, Saved, New));
@@ -258,7 +297,7 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(D->getLocation(), Prev,
TemplateArgs);
if (!InstPrev)
- return 0;
+ return nullptr;
TypedefNameDecl *InstPrevTypedef = cast<TypedefNameDecl>(InstPrev);
@@ -296,11 +335,11 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
- return 0;
+ return nullptr;
TypeAliasDecl *Pattern = D->getTemplatedDecl();
- TypeAliasTemplateDecl *PrevAliasTemplate = 0;
+ TypeAliasTemplateDecl *PrevAliasTemplate = nullptr;
if (Pattern->getPreviousDecl()) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
if (!Found.empty()) {
@@ -311,7 +350,7 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
TypeAliasDecl *AliasInst = cast_or_null<TypeAliasDecl>(
InstantiateTypedefNameDecl(Pattern, /*IsTypeAlias=*/true));
if (!AliasInst)
- return 0;
+ return nullptr;
TypeAliasTemplateDecl *Inst
= TypeAliasTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
@@ -341,7 +380,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
if (const RecordType *RecordTy = D->getType()->getAs<RecordType>())
if (RecordTy->getDecl()->isAnonymousStructOrUnion())
if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl())))
- return 0;
+ return nullptr;
// Do substitution on the type of the declaration
TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(),
@@ -349,12 +388,12 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
D->getTypeSpecStartLoc(),
D->getDeclName());
if (!DI)
- return 0;
+ return nullptr;
if (DI->getType()->isFunctionType()) {
SemaRef.Diag(D->getLocation(), diag::err_variable_instantiates_to_function)
<< D->isStaticDataMember() << DI->getType();
- return 0;
+ return nullptr;
}
DeclContext *DC = Owner;
@@ -373,10 +412,19 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
// Substitute the nested name specifier, if any.
if (SubstQualifier(D, Var))
- return 0;
+ return nullptr;
SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, Owner,
StartingScope, InstantiatingVarTemplate);
+
+ if (D->isNRVOVariable()) {
+ QualType ReturnType = cast<FunctionDecl>(DC)->getReturnType();
+ if (SemaRef.isCopyElisionCandidate(ReturnType, Var, false))
+ Var->setNRVOVariable(true);
+ }
+
+ Var->setImplicit(D->isImplicit());
+
return Var;
}
@@ -415,7 +463,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
Expr *BitWidth = D->getBitWidth();
if (Invalid)
- BitWidth = 0;
+ BitWidth = nullptr;
else if (BitWidth) {
// The bit-width expression is a constant expression.
EnterExpressionEvaluationContext Unevaluated(SemaRef,
@@ -425,9 +473,9 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
= SemaRef.SubstExpr(BitWidth, TemplateArgs);
if (InstantiatedBitWidth.isInvalid()) {
Invalid = true;
- BitWidth = 0;
+ BitWidth = nullptr;
} else
- BitWidth = InstantiatedBitWidth.takeAs<Expr>();
+ BitWidth = InstantiatedBitWidth.getAs<Expr>();
}
FieldDecl *Field = SemaRef.CheckFieldDecl(D->getDeclName(),
@@ -439,10 +487,10 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
D->getInClassInitStyle(),
D->getInnerLocStart(),
D->getAccess(),
- 0);
+ nullptr);
if (!Field) {
cast<Decl>(Owner)->setInvalidDecl();
- return 0;
+ return nullptr;
}
SemaRef.InstantiateAttrs(TemplateArgs, D, Field, LateAttrs, StartingScope);
@@ -476,7 +524,7 @@ Decl *TemplateDeclInstantiator::VisitMSPropertyDecl(MSPropertyDecl *D) {
if (DI->getType()->isVariablyModifiedType()) {
SemaRef.Diag(D->getLocation(), diag::err_property_is_variably_modified)
- << D->getName();
+ << D;
Invalid = true;
} else if (DI->getType()->isInstantiationDependentType()) {
DI = SemaRef.SubstType(DI, TemplateArgs,
@@ -499,11 +547,9 @@ Decl *TemplateDeclInstantiator::VisitMSPropertyDecl(MSPropertyDecl *D) {
SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType());
}
- MSPropertyDecl *Property = new (SemaRef.Context)
- MSPropertyDecl(Owner, D->getLocation(),
- D->getDeclName(), DI->getType(), DI,
- D->getLocStart(),
- D->getGetterId(), D->getSetterId());
+ MSPropertyDecl *Property = MSPropertyDecl::Create(
+ SemaRef.Context, Owner, D->getLocation(), D->getDeclName(), DI->getType(),
+ DI, D->getLocStart(), D->getGetterId(), D->getSetterId());
SemaRef.InstantiateAttrs(TemplateArgs, D, Property, LateAttrs,
StartingScope);
@@ -522,13 +568,11 @@ Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
new (SemaRef.Context)NamedDecl*[D->getChainingSize()];
int i = 0;
- for (IndirectFieldDecl::chain_iterator PI =
- D->chain_begin(), PE = D->chain_end();
- PI != PE; ++PI) {
- NamedDecl *Next = SemaRef.FindInstantiatedDecl(D->getLocation(), *PI,
+ for (auto *PI : D->chain()) {
+ NamedDecl *Next = SemaRef.FindInstantiatedDecl(D->getLocation(), PI,
TemplateArgs);
if (!Next)
- return 0;
+ return nullptr;
NamedChain[i++] = Next;
}
@@ -562,12 +606,12 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
D->getLocation(), DeclarationName());
}
if (!InstTy)
- return 0;
+ return nullptr;
FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getLocStart(),
D->getFriendLoc(), InstTy);
if (!FD)
- return 0;
+ return nullptr;
FD->setAccess(AS_public);
FD->setUnsupportedFriend(D->isUnsupportedFriend());
@@ -583,7 +627,7 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
// objects, with the most important detail being that the target
// decl should almost certainly not be placed in Owner.
Decl *NewND = Visit(ND);
- if (!NewND) return 0;
+ if (!NewND) return nullptr;
FriendDecl *FD =
FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(),
@@ -604,7 +648,7 @@ Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
ExprResult InstantiatedAssertExpr
= SemaRef.SubstExpr(AssertExpr, TemplateArgs);
if (InstantiatedAssertExpr.isInvalid())
- return 0;
+ return nullptr;
return SemaRef.BuildStaticAssertDeclaration(D->getLocation(),
InstantiatedAssertExpr.get(),
@@ -614,12 +658,12 @@ Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
}
Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
- EnumDecl *PrevDecl = 0;
+ EnumDecl *PrevDecl = nullptr;
if (D->getPreviousDecl()) {
NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getLocation(),
D->getPreviousDecl(),
TemplateArgs);
- if (!Prev) return 0;
+ if (!Prev) return nullptr;
PrevDecl = cast<EnumDecl>(Prev);
}
@@ -650,7 +694,9 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
Enum->setInstantiationOfMemberEnum(D, TSK_ImplicitInstantiation);
Enum->setAccess(D->getAccess());
- if (SubstQualifier(D, Enum)) return 0;
+ // Forward the mangling number from the template to the instantiated decl.
+ SemaRef.Context.setManglingNumber(Enum, SemaRef.Context.getManglingNumber(D));
+ if (SubstQualifier(D, Enum)) return nullptr;
Owner->addDecl(Enum);
EnumDecl *Def = D->getDefinition();
@@ -692,12 +738,10 @@ void TemplateDeclInstantiator::InstantiateEnumDefinition(
SmallVector<Decl*, 4> Enumerators;
- EnumConstantDecl *LastEnumConst = 0;
- for (EnumDecl::enumerator_iterator EC = Pattern->enumerator_begin(),
- ECEnd = Pattern->enumerator_end();
- EC != ECEnd; ++EC) {
+ EnumConstantDecl *LastEnumConst = nullptr;
+ for (auto *EC : Pattern->enumerators()) {
// The specified value for the enumerator.
- ExprResult Value = SemaRef.Owned((Expr *)0);
+ ExprResult Value((Expr *)nullptr);
if (Expr *UninstValue = EC->getInitExpr()) {
// The enumerator's value expression is a constant expression.
EnterExpressionEvaluationContext Unevaluated(SemaRef,
@@ -709,7 +753,7 @@ void TemplateDeclInstantiator::InstantiateEnumDefinition(
// Drop the initial value and continue.
bool isInvalid = false;
if (Value.isInvalid()) {
- Value = SemaRef.Owned((Expr *)0);
+ Value = nullptr;
isInvalid = true;
}
@@ -725,7 +769,7 @@ void TemplateDeclInstantiator::InstantiateEnumDefinition(
}
if (EnumConst) {
- SemaRef.InstantiateAttrs(TemplateArgs, *EC, EnumConst);
+ SemaRef.InstantiateAttrs(TemplateArgs, EC, EnumConst);
EnumConst->setAccess(Enum->getAccess());
Enum->addDecl(EnumConst);
@@ -736,7 +780,7 @@ void TemplateDeclInstantiator::InstantiateEnumDefinition(
!Enum->isScoped()) {
// If the enumeration is within a function or method, record the enum
// constant as a local.
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(*EC, EnumConst);
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(EC, EnumConst);
}
}
}
@@ -745,7 +789,7 @@ void TemplateDeclInstantiator::InstantiateEnumDefinition(
SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(),
Enum->getRBraceLoc(), Enum,
Enumerators,
- 0, 0);
+ nullptr, nullptr);
}
Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {
@@ -761,7 +805,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
- return NULL;
+ return nullptr;
CXXRecordDecl *Pattern = D->getTemplatedDecl();
@@ -773,11 +817,11 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
TemplateArgs);
if (!QualifierLoc)
- return 0;
+ return nullptr;
}
- CXXRecordDecl *PrevDecl = 0;
- ClassTemplateDecl *PrevClassTemplate = 0;
+ CXXRecordDecl *PrevDecl = nullptr;
+ ClassTemplateDecl *PrevClassTemplate = nullptr;
if (!isFriend && Pattern->getPreviousDecl()) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
@@ -798,7 +842,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
DC = SemaRef.computeDeclContext(SS);
- if (!DC) return 0;
+ if (!DC) return nullptr;
} else {
DC = SemaRef.FindInstantiatedContext(Pattern->getLocation(),
Pattern->getDeclContext(),
@@ -821,7 +865,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
SemaRef.Diag(Pattern->getLocation(), diag::err_not_tag_in_scope)
<< D->getTemplatedDecl()->getTagKind() << Pattern->getDeclName() << DC
<< QualifierLoc.getSourceRange();
- return 0;
+ return nullptr;
}
bool AdoptedPreviousTemplateParams = false;
@@ -843,11 +887,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (DCParent->isNamespace() &&
cast<NamespaceDecl>(DCParent)->getIdentifier() &&
cast<NamespaceDecl>(DCParent)->getIdentifier()->isStr("tr1")) {
- DeclContext *DCParent2 = DCParent->getParent();
- if (DCParent2->isNamespace() &&
- cast<NamespaceDecl>(DCParent2)->getIdentifier() &&
- cast<NamespaceDecl>(DCParent2)->getIdentifier()->isStr("std") &&
- DCParent2->getParent()->isTranslationUnit())
+ if (cast<Decl>(DCParent)->isInStdNamespace())
Complain = false;
}
}
@@ -860,7 +900,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Complain,
Sema::TPL_TemplateMatch)) {
if (Complain)
- return 0;
+ return nullptr;
AdoptedPreviousTemplateParams = true;
InstParams = PrevParams;
@@ -871,7 +911,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (!AdoptedPreviousTemplateParams &&
SemaRef.CheckTemplateParameterList(InstParams, PrevParams,
Sema::TPC_ClassTemplate))
- return 0;
+ return nullptr;
}
}
@@ -948,12 +988,12 @@ TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl(
DeclContext::lookup_result Found
= Owner->lookup(ClassTemplate->getDeclName());
if (Found.empty())
- return 0;
+ return nullptr;
ClassTemplateDecl *InstClassTemplate
= dyn_cast<ClassTemplateDecl>(Found.front());
if (!InstClassTemplate)
- return 0;
+ return nullptr;
if (ClassTemplatePartialSpecializationDecl *Result
= InstClassTemplate->findPartialSpecInstantiatedFromMember(D))
@@ -972,10 +1012,10 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateDecl(VarTemplateDecl *D) {
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
- return NULL;
+ return nullptr;
VarDecl *Pattern = D->getTemplatedDecl();
- VarTemplateDecl *PrevVarTemplate = 0;
+ VarTemplateDecl *PrevVarTemplate = nullptr;
if (Pattern->getPreviousDecl()) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
@@ -991,8 +1031,9 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateDecl(VarTemplateDecl *D) {
VarTemplateDecl *Inst = VarTemplateDecl::Create(
SemaRef.Context, DC, D->getLocation(), D->getIdentifier(), InstParams,
- VarInst, PrevVarTemplate);
+ VarInst);
VarInst->setDescribedVarTemplate(Inst);
+ Inst->setPreviousDecl(PrevVarTemplate);
Inst->setAccess(D->getAccess());
if (!PrevVarTemplate)
@@ -1052,9 +1093,9 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
- return NULL;
+ return nullptr;
- FunctionDecl *Instantiated = 0;
+ FunctionDecl *Instantiated = nullptr;
if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(D->getTemplatedDecl()))
Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod,
InstParams));
@@ -1064,7 +1105,7 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
InstParams));
if (!Instantiated)
- return 0;
+ return nullptr;
// Link the instantiated function template declaration to the function
// template from which it was instantiated.
@@ -1094,14 +1135,14 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
}
Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
- CXXRecordDecl *PrevDecl = 0;
+ CXXRecordDecl *PrevDecl = nullptr;
if (D->isInjectedClassName())
PrevDecl = cast<CXXRecordDecl>(Owner);
else if (D->getPreviousDecl()) {
NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getLocation(),
D->getPreviousDecl(),
TemplateArgs);
- if (!Prev) return 0;
+ if (!Prev) return nullptr;
PrevDecl = cast<CXXRecordDecl>(Prev);
}
@@ -1112,7 +1153,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
// Substitute the nested name specifier, if any.
if (SubstQualifier(D, Record))
- return 0;
+ return nullptr;
Record->setImplicit(D->isImplicit());
// FIXME: Check against AS_none is an ugly hack to work around the issue that
@@ -1135,19 +1176,20 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
if (D->isLocalClass())
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Record);
+ // Forward the mangling number from the template to the instantiated decl.
+ SemaRef.Context.setManglingNumber(Record,
+ SemaRef.Context.getManglingNumber(D));
+
Owner->addDecl(Record);
// DR1484 clarifies that the members of a local class are instantiated as part
// of the instantiation of their enclosing entity.
if (D->isCompleteDefinition() && D->isLocalClass()) {
- if (SemaRef.InstantiateClass(D->getLocation(), Record, D, TemplateArgs,
- TSK_ImplicitInstantiation,
- /*Complain=*/true)) {
- llvm_unreachable("InstantiateClass shouldn't fail here!");
- } else {
- SemaRef.InstantiateClassMembers(D->getLocation(), Record, TemplateArgs,
- TSK_ImplicitInstantiation);
- }
+ SemaRef.InstantiateClass(D->getLocation(), Record, D, TemplateArgs,
+ TSK_ImplicitInstantiation,
+ /*Complain=*/true);
+ SemaRef.InstantiateClassMembers(D->getLocation(), Record, TemplateArgs,
+ TSK_ImplicitInstantiation);
}
return Record;
}
@@ -1170,15 +1212,14 @@ static QualType adjustFunctionTypeForInstantiation(ASTContext &Context,
FunctionProtoType::ExtProtoInfo NewEPI = NewFunc->getExtProtoInfo();
NewEPI.ExtInfo = OrigFunc->getExtInfo();
- return Context.getFunctionType(NewFunc->getResultType(),
- NewFunc->getArgTypes(), NewEPI);
+ return Context.getFunctionType(NewFunc->getReturnType(),
+ NewFunc->getParamTypes(), NewEPI);
}
/// Normal class members are of more specific types and therefore
/// don't make it here. This function serves two purposes:
/// 1) instantiating function templates
/// 2) substituting friend declarations
-/// FIXME: preserve function definitions in case #2
Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
TemplateParameterList *TemplateParams) {
// Check whether there is already a function template specialization for
@@ -1187,10 +1228,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
if (FunctionTemplate && !TemplateParams) {
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
FunctionDecl *SpecFunc
- = FunctionTemplate->findSpecialization(Innermost.begin(), Innermost.size(),
- InsertPos);
+ = FunctionTemplate->findSpecialization(Innermost, InsertPos);
// If we already have a function template specialization, return it.
if (SpecFunc)
@@ -1203,7 +1243,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
else
isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
- bool MergeWithParentScope = (TemplateParams != 0) ||
+ bool MergeWithParentScope = (TemplateParams != nullptr) ||
Owner->isFunctionOrMethod() ||
!(isa<Decl>(Owner) &&
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
@@ -1212,7 +1252,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
SmallVector<ParmVarDecl *, 4> Params;
TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
if (!TInfo)
- return 0;
+ return nullptr;
QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
@@ -1220,7 +1260,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
TemplateArgs);
if (!QualifierLoc)
- return 0;
+ return nullptr;
}
// If we're instantiating a local function declaration, put the result
@@ -1234,7 +1274,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
DC = SemaRef.computeDeclContext(SS);
- if (!DC) return 0;
+ if (!DC) return nullptr;
} else {
DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(),
TemplateArgs);
@@ -1308,7 +1348,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
TemplateArgumentList::CreateCopy(SemaRef.Context,
Innermost.begin(),
Innermost.size()),
- /*InsertPos=*/0);
+ /*InsertPos=*/nullptr);
} else if (isFriend) {
// Note, we need this connection even if the friend doesn't have a body.
// Its body may exist but not have been attached yet due to deferred
@@ -1342,14 +1382,14 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Info->getRAngleLoc());
if (SemaRef.Subst(Info->getTemplateArgs(), Info->getNumTemplateArgs(),
ExplicitArgs, TemplateArgs))
- return 0;
+ return nullptr;
// Map the candidate templates to their instantiations.
for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I) {
Decl *Temp = SemaRef.FindInstantiatedDecl(D->getLocation(),
Info->getTemplate(I),
TemplateArgs);
- if (!Temp) return 0;
+ if (!Temp) return nullptr;
Previous.addDecl(cast<FunctionTemplateDecl>(Temp));
}
@@ -1375,7 +1415,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Previous.clear();
}
- SemaRef.CheckFunctionDeclaration(/*Scope*/ 0, Function, Previous,
+ SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous,
isExplicitSpecialization);
NamedDecl *PrincipalDecl = (TemplateParams
@@ -1388,73 +1428,56 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
PrincipalDecl->setObjectOfFriendDecl();
DC->makeDeclVisibleInContext(PrincipalDecl);
- bool queuedInstantiation = false;
+ bool QueuedInstantiation = false;
- // C++98 [temp.friend]p5: When a function is defined in a friend function
- // declaration in a class template, the function is defined at each
- // instantiation of the class template. The function is defined even if it
- // is never used.
- // C++11 [temp.friend]p4: When a function is defined in a friend function
- // declaration in a class template, the function is instantiated when the
- // function is odr-used.
- //
- // If -Wc++98-compat is enabled, we go through the motions of checking for a
- // redefinition, but don't instantiate the function.
- if ((!SemaRef.getLangOpts().CPlusPlus11 ||
- SemaRef.Diags.getDiagnosticLevel(
- diag::warn_cxx98_compat_friend_redefinition,
- Function->getLocation())
- != DiagnosticsEngine::Ignored) &&
- D->isThisDeclarationADefinition()) {
+ // C++11 [temp.friend]p4 (DR329):
+ // When a function is defined in a friend function declaration in a class
+ // template, the function is instantiated when the function is odr-used.
+ // The same restrictions on multiple declarations and definitions that
+ // apply to non-template function declarations and definitions also apply
+ // to these implicit definitions.
+ if (D->isThisDeclarationADefinition()) {
// Check for a function body.
- const FunctionDecl *Definition = 0;
+ const FunctionDecl *Definition = nullptr;
if (Function->isDefined(Definition) &&
Definition->getTemplateSpecializationKind() == TSK_Undeclared) {
- SemaRef.Diag(Function->getLocation(),
- SemaRef.getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_friend_redefinition :
- diag::err_redefinition) << Function->getDeclName();
+ SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
+ << Function->getDeclName();
SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition);
- if (!SemaRef.getLangOpts().CPlusPlus11)
- Function->setInvalidDecl();
}
// Check for redefinitions due to other instantiations of this or
// a similar friend function.
- else for (FunctionDecl::redecl_iterator R = Function->redecls_begin(),
- REnd = Function->redecls_end();
- R != REnd; ++R) {
- if (*R == Function)
+ else for (auto R : Function->redecls()) {
+ if (R == Function)
continue;
- switch (R->getFriendObjectKind()) {
- case Decl::FOK_None:
- if (!SemaRef.getLangOpts().CPlusPlus11 &&
- !queuedInstantiation && R->isUsed(false)) {
- if (MemberSpecializationInfo *MSInfo
- = Function->getMemberSpecializationInfo()) {
- if (MSInfo->getPointOfInstantiation().isInvalid()) {
- SourceLocation Loc = R->getLocation(); // FIXME
- MSInfo->setPointOfInstantiation(Loc);
- SemaRef.PendingLocalImplicitInstantiations.push_back(
- std::make_pair(Function, Loc));
- queuedInstantiation = true;
- }
+
+ // If some prior declaration of this function has been used, we need
+ // to instantiate its definition.
+ if (!QueuedInstantiation && R->isUsed(false)) {
+ if (MemberSpecializationInfo *MSInfo =
+ Function->getMemberSpecializationInfo()) {
+ if (MSInfo->getPointOfInstantiation().isInvalid()) {
+ SourceLocation Loc = R->getLocation(); // FIXME
+ MSInfo->setPointOfInstantiation(Loc);
+ SemaRef.PendingLocalImplicitInstantiations.push_back(
+ std::make_pair(Function, Loc));
+ QueuedInstantiation = true;
}
}
- break;
- default:
- if (const FunctionDecl *RPattern
- = R->getTemplateInstantiationPattern())
+ }
+
+ // If some prior declaration of this function was a friend with an
+ // uninstantiated definition, reject it.
+ if (R->getFriendObjectKind()) {
+ if (const FunctionDecl *RPattern =
+ R->getTemplateInstantiationPattern()) {
if (RPattern->isDefined(RPattern)) {
- SemaRef.Diag(Function->getLocation(),
- SemaRef.getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_friend_redefinition :
- diag::err_redefinition)
+ SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
<< Function->getDeclName();
SemaRef.Diag(R->getLocation(), diag::note_previous_definition);
- if (!SemaRef.getLangOpts().CPlusPlus11)
- Function->setInvalidDecl();
break;
}
+ }
}
}
}
@@ -1482,11 +1505,9 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
// specialization for this particular set of template arguments.
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
FunctionDecl *SpecFunc
- = FunctionTemplate->findSpecialization(Innermost.begin(),
- Innermost.size(),
- InsertPos);
+ = FunctionTemplate->findSpecialization(Innermost, InsertPos);
// If we already have a function template specialization, return it.
if (SpecFunc)
@@ -1499,7 +1520,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
else
isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
- bool MergeWithParentScope = (TemplateParams != 0) ||
+ bool MergeWithParentScope = (TemplateParams != nullptr) ||
!(isa<Decl>(Owner) &&
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
@@ -1513,7 +1534,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
TemplateParameterList *TempParams = D->getTemplateParameterList(I);
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
- return NULL;
+ return nullptr;
TempParamLists[I] = InstParams;
}
}
@@ -1521,7 +1542,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
SmallVector<ParmVarDecl *, 4> Params;
TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
if (!TInfo)
- return 0;
+ return nullptr;
QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
@@ -1529,7 +1550,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
TemplateArgs);
if (!QualifierLoc)
- return 0;
+ return nullptr;
}
DeclContext *DC = Owner;
@@ -1540,18 +1561,18 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
DC = SemaRef.computeDeclContext(SS);
if (DC && SemaRef.RequireCompleteDeclContext(SS, DC))
- return 0;
+ return nullptr;
} else {
DC = SemaRef.FindInstantiatedContext(D->getLocation(),
D->getDeclContext(),
TemplateArgs);
}
- if (!DC) return 0;
+ if (!DC) return nullptr;
}
// Build the instantiated method declaration.
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
- CXXMethodDecl *Method = 0;
+ CXXMethodDecl *Method = nullptr;
SourceLocation StartLoc = D->getInnerLocStart();
DeclarationNameInfo NameInfo
@@ -1577,7 +1598,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Sema::InstantiatingTemplate Inst(SemaRef, Constructor->getLocation(),
Inh);
if (Inst.isInvalid())
- return 0;
+ return nullptr;
Sema::ContextRAII SavedContext(SemaRef, Inh->getDeclContext());
LocalInstantiationScope LocalScope(SemaRef);
@@ -1588,7 +1609,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Inh = cast_or_null<CXXConstructorDecl>(
SemaRef.SubstDecl(Inh, Inh->getDeclContext(), InheritedArgs));
if (!Inh)
- return 0;
+ return nullptr;
}
cast<CXXConstructorDecl>(Method)->setInheritedConstructor(Inh);
}
@@ -1649,7 +1670,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
TemplateArgumentList::CreateCopy(SemaRef.Context,
Innermost.begin(),
Innermost.size()),
- /*InsertPos=*/0);
+ /*InsertPos=*/nullptr);
} else if (!isFriend) {
// Record that this is an instantiation of a member function.
Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
@@ -1692,7 +1713,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
}
if (!IsClassScopeSpecialization)
- SemaRef.CheckFunctionDeclaration(0, Method, Previous, false);
+ SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous, false);
if (D->isPure())
SemaRef.CheckPureMethod(Method, SourceRange());
@@ -1810,13 +1831,13 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
D->getLocation(),
D->getDeclName());
if (!NewDI)
- return 0;
+ return nullptr;
ExpandedParameterPackTypesAsWritten.push_back(NewDI);
QualType NewT =SemaRef.CheckNonTypeTemplateParameterType(NewDI->getType(),
D->getLocation());
if (NewT.isNull())
- return 0;
+ return nullptr;
ExpandedParameterPackTypes.push_back(NewT);
}
@@ -1845,7 +1866,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
TemplateArgs,
Expand, RetainExpansion,
NumExpansions))
- return 0;
+ return nullptr;
if (Expand) {
for (unsigned I = 0; I != *NumExpansions; ++I) {
@@ -1854,14 +1875,14 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
D->getLocation(),
D->getDeclName());
if (!NewDI)
- return 0;
+ return nullptr;
ExpandedParameterPackTypesAsWritten.push_back(NewDI);
QualType NewT = SemaRef.CheckNonTypeTemplateParameterType(
NewDI->getType(),
D->getLocation());
if (NewT.isNull())
- return 0;
+ return nullptr;
ExpandedParameterPackTypes.push_back(NewT);
}
@@ -1879,12 +1900,12 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
D->getLocation(),
D->getDeclName());
if (!NewPattern)
- return 0;
+ return nullptr;
DI = SemaRef.CheckPackExpansion(NewPattern, Expansion.getEllipsisLoc(),
NumExpansions);
if (!DI)
- return 0;
+ return nullptr;
T = DI->getType();
}
@@ -1893,7 +1914,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs,
D->getLocation(), D->getDeclName());
if (!DI)
- return 0;
+ return nullptr;
// Check that this type is acceptable for a non-type template parameter.
T = SemaRef.CheckNonTypeTemplateParameterType(DI->getType(),
@@ -1979,7 +2000,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
TemplateParameterList *Expansion =
SubstTemplateParams(D->getExpansionTemplateParameters(I));
if (!Expansion)
- return 0;
+ return nullptr;
ExpandedParams.push_back(Expansion);
}
@@ -2004,7 +2025,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
TemplateArgs,
Expand, RetainExpansion,
NumExpansions))
- return 0;
+ return nullptr;
if (Expand) {
for (unsigned I = 0; I != *NumExpansions; ++I) {
@@ -2012,7 +2033,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
LocalInstantiationScope Scope(SemaRef);
TemplateParameterList *Expansion = SubstTemplateParams(TempParams);
if (!Expansion)
- return 0;
+ return nullptr;
ExpandedParams.push_back(Expansion);
}
@@ -2029,7 +2050,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
LocalInstantiationScope Scope(SemaRef);
InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
- return 0;
+ return nullptr;
}
} else {
// Perform the actual substitution of template parameters within a new,
@@ -2037,7 +2058,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
LocalInstantiationScope Scope(SemaRef);
InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
- return 0;
+ return nullptr;
}
// Build the template template parameter.
@@ -2114,7 +2135,7 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
= SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(),
TemplateArgs);
if (!QualifierLoc)
- return 0;
+ return nullptr;
// The name info is non-dependent, so no transformation
// is required.
@@ -2149,7 +2170,7 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
}
if (!NewUD->isInvalidDecl() &&
- SemaRef.CheckUsingDeclQualifier(D->getUsingLoc(), SS,
+ SemaRef.CheckUsingDeclQualifier(D->getUsingLoc(), SS, NameInfo,
D->getLocation()))
NewUD->setInvalidDecl();
@@ -2162,24 +2183,21 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
return NewUD;
if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) {
- if (SemaRef.CheckInheritingConstructorUsingDecl(NewUD))
- NewUD->setInvalidDecl();
+ SemaRef.CheckInheritingConstructorUsingDecl(NewUD);
return NewUD;
}
bool isFunctionScope = Owner->isFunctionOrMethod();
// Process the shadow decls.
- for (UsingDecl::shadow_iterator I = D->shadow_begin(), E = D->shadow_end();
- I != E; ++I) {
- UsingShadowDecl *Shadow = *I;
+ for (auto *Shadow : D->shadows()) {
NamedDecl *InstTarget =
cast_or_null<NamedDecl>(SemaRef.FindInstantiatedDecl(
Shadow->getLocation(), Shadow->getTargetDecl(), TemplateArgs));
if (!InstTarget)
- return 0;
+ return nullptr;
- UsingShadowDecl *PrevDecl = 0;
+ UsingShadowDecl *PrevDecl = nullptr;
if (CheckRedeclaration) {
if (SemaRef.CheckUsingShadowDecl(NewUD, InstTarget, Prev, PrevDecl))
continue;
@@ -2189,7 +2207,8 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
}
UsingShadowDecl *InstShadow =
- SemaRef.BuildUsingShadowDecl(/*Scope*/0, NewUD, InstTarget, PrevDecl);
+ SemaRef.BuildUsingShadowDecl(/*Scope*/nullptr, NewUD, InstTarget,
+ PrevDecl);
SemaRef.Context.setInstantiatedFromUsingShadowDecl(InstShadow, Shadow);
if (isFunctionScope)
@@ -2201,7 +2220,7 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) {
// Ignore these; we handle them in bulk when processing the UsingDecl.
- return 0;
+ return nullptr;
}
Decl * TemplateDeclInstantiator
@@ -2210,7 +2229,7 @@ Decl * TemplateDeclInstantiator
= SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(),
TemplateArgs);
if (!QualifierLoc)
- return 0;
+ return nullptr;
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
@@ -2219,8 +2238,8 @@ Decl * TemplateDeclInstantiator
// Hence, no transformation is required for it.
DeclarationNameInfo NameInfo(D->getDeclName(), D->getLocation());
NamedDecl *UD =
- SemaRef.BuildUsingDeclaration(/*Scope*/ 0, D->getAccess(),
- D->getUsingLoc(), SS, NameInfo, 0,
+ SemaRef.BuildUsingDeclaration(/*Scope*/ nullptr, D->getAccess(),
+ D->getUsingLoc(), SS, NameInfo, nullptr,
/*instantiation*/ true,
/*typename*/ true, D->getTypenameLoc());
if (UD)
@@ -2234,7 +2253,7 @@ Decl * TemplateDeclInstantiator
NestedNameSpecifierLoc QualifierLoc
= SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(), TemplateArgs);
if (!QualifierLoc)
- return 0;
+ return nullptr;
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
@@ -2243,8 +2262,8 @@ Decl * TemplateDeclInstantiator
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
NamedDecl *UD =
- SemaRef.BuildUsingDeclaration(/*Scope*/ 0, D->getAccess(),
- D->getUsingLoc(), SS, NameInfo, 0,
+ SemaRef.BuildUsingDeclaration(/*Scope*/ nullptr, D->getAccess(),
+ D->getUsingLoc(), SS, NameInfo, nullptr,
/*instantiation*/ true,
/*typename*/ false, SourceLocation());
if (UD)
@@ -2258,13 +2277,13 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *Decl) {
CXXMethodDecl *OldFD = Decl->getSpecialization();
CXXMethodDecl *NewFD = cast<CXXMethodDecl>(VisitCXXMethodDecl(OldFD,
- 0, true));
+ nullptr, true));
LookupResult Previous(SemaRef, NewFD->getNameInfo(), Sema::LookupOrdinaryName,
Sema::ForRedeclaration);
TemplateArgumentListInfo TemplateArgs;
- TemplateArgumentListInfo* TemplateArgsPtr = 0;
+ TemplateArgumentListInfo *TemplateArgsPtr = nullptr;
if (Decl->hasExplicitTemplateArgs()) {
TemplateArgs = Decl->templateArgs();
TemplateArgsPtr = &TemplateArgs;
@@ -2288,10 +2307,8 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
OMPThreadPrivateDecl *D) {
SmallVector<Expr *, 5> Vars;
- for (ArrayRef<Expr *>::iterator I = D->varlist_begin(),
- E = D->varlist_end();
- I != E; ++I) {
- Expr *Var = SemaRef.SubstExpr(*I, TemplateArgs).take();
+ for (auto *I : D->varlists()) {
+ Expr *Var = SemaRef.SubstExpr(I, TemplateArgs).get();
assert(isa<DeclRefExpr>(Var) && "threadprivate arg is not a DeclRefExpr");
Vars.push_back(Var);
}
@@ -2299,15 +2316,18 @@ Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
OMPThreadPrivateDecl *TD =
SemaRef.CheckOMPThreadPrivateDecl(D->getLocation(), Vars);
+ TD->setAccess(AS_public);
+ Owner->addDecl(TD);
+
return TD;
}
Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
- return VisitFunctionDecl(D, 0);
+ return VisitFunctionDecl(D, nullptr);
}
Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
- return VisitCXXMethodDecl(D, 0);
+ return VisitCXXMethodDecl(D, nullptr);
}
Decl *TemplateDeclInstantiator::VisitRecordDecl(RecordDecl *D) {
@@ -2330,11 +2350,11 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
DeclContext::lookup_result Found
= Owner->lookup(ClassTemplate->getDeclName());
if (Found.empty())
- return 0;
+ return nullptr;
ClassTemplateDecl *InstClassTemplate
= dyn_cast<ClassTemplateDecl>(Found.front());
if (!InstClassTemplate)
- return 0;
+ return nullptr;
// Substitute into the template arguments of the class template explicit
// specialization.
@@ -2347,7 +2367,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
ArgLocs.push_back(Loc.getArgLoc(I));
if (SemaRef.Subst(ArgLocs.data(), ArgLocs.size(),
InstTemplateArgs, TemplateArgs))
- return 0;
+ return nullptr;
// Check that the template argument list is well-formed for this
// class template.
@@ -2357,14 +2377,13 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
InstTemplateArgs,
false,
Converted))
- return 0;
+ return nullptr;
// Figure out where to insert this class template explicit specialization
// in the member template's set of class template explicit specializations.
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
ClassTemplateSpecializationDecl *PrevDecl =
- InstClassTemplate->findSpecialization(Converted.data(), Converted.size(),
- InsertPos);
+ InstClassTemplate->findSpecialization(Converted, InsertPos);
// Check whether we've already seen a conflicting instantiation of this
// declaration (for instance, if there was a prior implicit instantiation).
@@ -2376,7 +2395,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
PrevDecl->getSpecializationKind(),
PrevDecl->getPointOfInstantiation(),
Ignored))
- return 0;
+ return nullptr;
// If PrevDecl was a definition and D is also a definition, diagnose.
// This happens in cases like:
@@ -2395,7 +2414,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
SemaRef.Diag(D->getLocation(), diag::err_redefinition) << PrevDecl;
SemaRef.Diag(PrevDecl->getDefinition()->getLocation(),
diag::note_previous_definition);
- return 0;
+ return nullptr;
}
// Create the class template partial specialization declaration.
@@ -2417,7 +2436,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
// Substitute the nested name specifier, if any.
if (SubstQualifier(D, InstD))
- return 0;
+ return nullptr;
// Build the canonical type that describes the converted template
// arguments of the class template explicit specialization.
@@ -2452,7 +2471,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
SemaRef.InstantiateClass(D->getLocation(), InstD, D, TemplateArgs,
TSK_ImplicitInstantiation,
/*Complain=*/true))
- return 0;
+ return nullptr;
return InstD;
}
@@ -2472,22 +2491,21 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
if (SemaRef.Subst(TemplateArgsInfo.getArgumentArray(),
TemplateArgsInfo.size(), VarTemplateArgsInfo, TemplateArgs))
- return 0;
+ return nullptr;
// Check that the template argument list is well-formed for this template.
SmallVector<TemplateArgument, 4> Converted;
- bool ExpansionIntoFixedList = false;
if (SemaRef.CheckTemplateArgumentList(
VarTemplate, VarTemplate->getLocStart(),
const_cast<TemplateArgumentListInfo &>(VarTemplateArgsInfo), false,
- Converted, &ExpansionIntoFixedList))
- return 0;
+ Converted))
+ return nullptr;
// Find the variable template specialization declaration that
// corresponds to these arguments.
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (VarTemplateSpecializationDecl *VarSpec = VarTemplate->findSpecialization(
- Converted.data(), Converted.size(), InsertPos))
+ Converted, InsertPos))
// If we already have a variable template specialization, return it.
return VarSpec;
@@ -2498,26 +2516,26 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
VarTemplateDecl *VarTemplate, VarDecl *D, void *InsertPos,
const TemplateArgumentListInfo &TemplateArgsInfo,
- llvm::ArrayRef<TemplateArgument> Converted) {
+ ArrayRef<TemplateArgument> Converted) {
// If this is the variable for an anonymous struct or union,
// instantiate the anonymous struct/union type first.
if (const RecordType *RecordTy = D->getType()->getAs<RecordType>())
if (RecordTy->getDecl()->isAnonymousStructOrUnion())
if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl())))
- return 0;
+ return nullptr;
// Do substitution on the type of the declaration
TypeSourceInfo *DI =
SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs,
D->getTypeSpecStartLoc(), D->getDeclName());
if (!DI)
- return 0;
+ return nullptr;
if (DI->getType()->isFunctionType()) {
SemaRef.Diag(D->getLocation(), diag::err_variable_instantiates_to_function)
<< D->isStaticDataMember() << DI->getType();
- return 0;
+ return nullptr;
}
// Build the instantiated declaration
@@ -2531,7 +2549,7 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
// Substitute the nested name specifier, if any.
if (SubstQualifier(D, Var))
- return 0;
+ return nullptr;
SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs,
Owner, StartingScope);
@@ -2551,7 +2569,7 @@ Decl *TemplateDeclInstantiator::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
SemaRef.Diag(D->getLocation(), DiagID)
<< D->getDeclKindName();
- return 0;
+ return nullptr;
}
Decl *TemplateDeclInstantiator::VisitDecl(Decl *D) {
@@ -2562,7 +2580,7 @@ Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs) {
TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
if (D->isInvalidDecl())
- return 0;
+ return nullptr;
return Instantiator.Visit(D);
}
@@ -2591,7 +2609,7 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
// Clean up if we had an error.
if (Invalid)
- return NULL;
+ return nullptr;
TemplateParameterList *InstL
= TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(),
@@ -2625,7 +2643,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
TemplateParameterList *TempParams = PartialSpec->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
- return 0;
+ return nullptr;
// Substitute into the template arguments of the class template partial
// specialization.
@@ -2636,7 +2654,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(),
TemplArgInfo->NumTemplateArgs,
InstTemplateArgs, TemplateArgs))
- return 0;
+ return nullptr;
// Check that the template argument list is well-formed for this
// class template.
@@ -2646,14 +2664,13 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
InstTemplateArgs,
false,
Converted))
- return 0;
+ return nullptr;
// Figure out where to insert this class template partial specialization
// in the member template's set of class template partial specializations.
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
ClassTemplateSpecializationDecl *PrevDecl
- = ClassTemplate->findPartialSpecialization(Converted.data(),
- Converted.size(), InsertPos);
+ = ClassTemplate->findPartialSpecialization(Converted, InsertPos);
// Build the canonical type that describes the converted template
// arguments of the class template partial specialization.
@@ -2696,7 +2713,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
<< WrittenTy->getType();
SemaRef.Diag(PrevDecl->getLocation(), diag::note_prev_partial_spec_here)
<< SemaRef.Context.getTypeDeclType(PrevDecl);
- return 0;
+ return nullptr;
}
@@ -2713,17 +2730,18 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
Converted.size(),
InstTemplateArgs,
CanonType,
- 0);
+ nullptr);
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
- return 0;
+ return nullptr;
InstPartialSpec->setInstantiatedFromMember(PartialSpec);
InstPartialSpec->setTypeAsWritten(WrittenTy);
// Add this partial specialization to the set of class template partial
// specializations.
- ClassTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/0);
+ ClassTemplate->AddPartialSpecialization(InstPartialSpec,
+ /*InsertPos=*/nullptr);
return InstPartialSpec;
}
@@ -2752,7 +2770,7 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
TemplateParameterList *TempParams = PartialSpec->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
- return 0;
+ return nullptr;
// Substitute into the template arguments of the variable template partial
// specialization.
@@ -2763,21 +2781,20 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(),
TemplArgInfo->NumTemplateArgs,
InstTemplateArgs, TemplateArgs))
- return 0;
+ return nullptr;
// Check that the template argument list is well-formed for this
// class template.
SmallVector<TemplateArgument, 4> Converted;
if (SemaRef.CheckTemplateArgumentList(VarTemplate, PartialSpec->getLocation(),
InstTemplateArgs, false, Converted))
- return 0;
+ return nullptr;
// Figure out where to insert this variable template partial specialization
// in the member template's set of variable template partial specializations.
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
VarTemplateSpecializationDecl *PrevDecl =
- VarTemplate->findPartialSpecialization(Converted.data(), Converted.size(),
- InsertPos);
+ VarTemplate->findPartialSpecialization(Converted, InsertPos);
// Build the canonical type that describes the converted template
// arguments of the variable template partial specialization.
@@ -2816,7 +2833,7 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
<< WrittenTy->getType();
SemaRef.Diag(PrevDecl->getLocation(),
diag::note_var_prev_partial_spec_here);
- return 0;
+ return nullptr;
}
// Do substitution on the type of the declaration
@@ -2824,13 +2841,13 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
PartialSpec->getTypeSourceInfo(), TemplateArgs,
PartialSpec->getTypeSpecStartLoc(), PartialSpec->getDeclName());
if (!DI)
- return 0;
+ return nullptr;
if (DI->getType()->isFunctionType()) {
SemaRef.Diag(PartialSpec->getLocation(),
diag::err_variable_instantiates_to_function)
<< PartialSpec->isStaticDataMember() << DI->getType();
- return 0;
+ return nullptr;
}
// Create the variable template partial specialization declaration.
@@ -2843,14 +2860,14 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
- return 0;
+ return nullptr;
InstPartialSpec->setInstantiatedFromMember(PartialSpec);
InstPartialSpec->setTypeAsWritten(WrittenTy);
// Add this partial specialization to the set of variable template partial
// specializations. The instantiation of the initializer is not necessary.
- VarTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/0);
+ VarTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/nullptr);
SemaRef.BuildVariableInstantiation(InstPartialSpec, PartialSpec, TemplateArgs,
LateAttrs, Owner, StartingScope);
@@ -2864,8 +2881,8 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
TypeSourceInfo *OldTInfo = D->getTypeSourceInfo();
assert(OldTInfo && "substituting function without type source info");
assert(Params.empty() && "parameter vector is non-empty at start");
-
- CXXRecordDecl *ThisContext = 0;
+
+ CXXRecordDecl *ThisContext = nullptr;
unsigned ThisTypeQuals = 0;
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
ThisContext = cast<CXXRecordDecl>(Owner);
@@ -2878,7 +2895,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
D->getDeclName(),
ThisContext, ThisTypeQuals);
if (!NewTInfo)
- return 0;
+ return nullptr;
TypeLoc OldTL = OldTInfo->getTypeLoc().IgnoreParens();
if (FunctionProtoTypeLoc OldProtoLoc = OldTL.getAs<FunctionProtoTypeLoc>()) {
@@ -2887,9 +2904,9 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
TypeLoc NewTL = NewTInfo->getTypeLoc().IgnoreParens();
FunctionProtoTypeLoc NewProtoLoc = NewTL.castAs<FunctionProtoTypeLoc>();
unsigned NewIdx = 0;
- for (unsigned OldIdx = 0, NumOldParams = OldProtoLoc.getNumArgs();
+ for (unsigned OldIdx = 0, NumOldParams = OldProtoLoc.getNumParams();
OldIdx != NumOldParams; ++OldIdx) {
- ParmVarDecl *OldParam = OldProtoLoc.getArg(OldIdx);
+ ParmVarDecl *OldParam = OldProtoLoc.getParam(OldIdx);
LocalInstantiationScope *Scope = SemaRef.CurrentInstantiationScope;
Optional<unsigned> NumArgumentsInExpansion;
@@ -2900,14 +2917,14 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
if (!NumArgumentsInExpansion) {
// Simple case: normal parameter, or a parameter pack that's
// instantiated to a (still-dependent) parameter pack.
- ParmVarDecl *NewParam = NewProtoLoc.getArg(NewIdx++);
+ ParmVarDecl *NewParam = NewProtoLoc.getParam(NewIdx++);
Params.push_back(NewParam);
Scope->InstantiatedLocal(OldParam, NewParam);
} else {
// Parameter pack expansion: make the instantiation an argument pack.
Scope->MakeInstantiatedLocalArgPack(OldParam);
for (unsigned I = 0; I != *NumArgumentsInExpansion; ++I) {
- ParmVarDecl *NewParam = NewProtoLoc.getArg(NewIdx++);
+ ParmVarDecl *NewParam = NewProtoLoc.getParam(NewIdx++);
Params.push_back(NewParam);
Scope->InstantiatedLocalPackArg(OldParam, NewParam);
}
@@ -2919,18 +2936,19 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
// the function parameters themselves.
const FunctionProtoType *OldProto =
cast<FunctionProtoType>(OldProtoLoc.getType());
- for (unsigned i = 0, i_end = OldProtoLoc.getNumArgs(); i != i_end; ++i) {
- ParmVarDecl *OldParam = OldProtoLoc.getArg(i);
+ for (unsigned i = 0, i_end = OldProtoLoc.getNumParams(); i != i_end;
+ ++i) {
+ ParmVarDecl *OldParam = OldProtoLoc.getParam(i);
if (!OldParam) {
Params.push_back(SemaRef.BuildParmVarDeclForTypedef(
- D, D->getLocation(), OldProto->getArgType(i)));
+ D, D->getLocation(), OldProto->getParamType(i)));
continue;
}
ParmVarDecl *Parm =
cast_or_null<ParmVarDecl>(VisitParmVarDecl(OldParam));
if (!Parm)
- return 0;
+ return nullptr;
Params.push_back(Parm);
}
}
@@ -2949,7 +2967,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(),
D->getNumParams(), TemplateArgs, ParamTypes,
&Params))
- return 0;
+ return nullptr;
}
return NewTInfo;
@@ -2969,6 +2987,14 @@ static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
// Simple case: not a parameter pack.
assert(FParamIdx < Function->getNumParams());
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
+ // If the parameter's type is not dependent, update it to match the type
+ // in the pattern. They can differ in top-level cv-qualifiers, and we want
+ // the pattern's type here. If the type is dependent, they can't differ,
+ // per core issue 1668.
+ // FIXME: Updating the type to work around this is at best fragile.
+ if (!PatternDecl->getType()->isDependentType())
+ FunctionParam->setType(PatternParam->getType());
+
FunctionParam->setDeclName(PatternParam->getDeclName());
Scope.InstantiatedLocal(PatternParam, FunctionParam);
++FParamIdx;
@@ -2983,6 +3009,9 @@ static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
"should only be called when all template arguments are known");
for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) {
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
+ if (!PatternDecl->getType()->isDependentType())
+ FunctionParam->setType(PatternParam->getType());
+
FunctionParam->setDeclName(PatternParam->getDeclName());
Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);
++FParamIdx;
@@ -3001,7 +3030,7 @@ static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
// "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
// and the end of the function-definition, member-declarator, or
// declarator.
- CXXRecordDecl *ThisContext = 0;
+ CXXRecordDecl *ThisContext = nullptr;
unsigned ThisTypeQuals = 0;
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(New)) {
ThisContext = Method->getParent();
@@ -3083,7 +3112,7 @@ static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
Exceptions.push_back(T);
}
- Expr *NoexceptExpr = 0;
+ Expr *NoexceptExpr = nullptr;
if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) {
EnterExpressionEvaluationContext Unevaluated(SemaRef,
Sema::ConstantEvaluated);
@@ -3092,29 +3121,23 @@ static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart());
if (E.isUsable()) {
- NoexceptExpr = E.take();
+ NoexceptExpr = E.get();
if (!NoexceptExpr->isTypeDependent() &&
!NoexceptExpr->isValueDependent())
NoexceptExpr
= SemaRef.VerifyIntegerConstantExpression(NoexceptExpr,
- 0, diag::err_noexcept_needs_constant_expression,
- /*AllowFold*/ false).take();
+ nullptr, diag::err_noexcept_needs_constant_expression,
+ /*AllowFold*/ false).get();
}
}
- // Rebuild the function type
- const FunctionProtoType *NewProto
- = New->getType()->getAs<FunctionProtoType>();
- assert(NewProto && "Template instantiation without function prototype?");
-
- FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
+ FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = Proto->getExceptionSpecType();
EPI.NumExceptions = Exceptions.size();
EPI.Exceptions = Exceptions.data();
EPI.NoexceptExpr = NoexceptExpr;
- New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
- NewProto->getArgTypes(), EPI));
+ SemaRef.UpdateExceptionSpec(New, EPI);
}
void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
@@ -3128,10 +3151,9 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
if (Inst.isInvalid()) {
// We hit the instantiation depth limit. Clear the exception specification
// so that our callers don't have to cope with EST_Uninstantiated.
- FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
+ FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_None;
- Decl->setType(Context.getFunctionType(Proto->getResultType(),
- Proto->getArgTypes(), EPI));
+ UpdateExceptionSpec(Decl, EPI);
return;
}
@@ -3141,7 +3163,7 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
LocalInstantiationScope Scope(*this);
MultiLevelTemplateArgumentList TemplateArgs =
- getTemplateInstantiationArgs(Decl, 0, /*RelativeToPrimary*/true);
+ getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true);
FunctionDecl *Template = Proto->getExceptionSpecTemplate();
addInstantiatedParametersToScope(*this, Decl, Template, Scope, TemplateArgs);
@@ -3161,6 +3183,10 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
if (Tmpl->isDeleted())
New->setDeletedAsWritten();
+ // Forward the mangling number from the template to the instantiated decl.
+ SemaRef.Context.setManglingNumber(New,
+ SemaRef.Context.getManglingNumber(Tmpl));
+
// If we are performing substituting explicitly-specified template arguments
// or deduced template arguments into a function template and we reach this
// point, we are now past the point where SFINAE applies and have committed
@@ -3211,7 +3237,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
EPI.ExceptionSpecDecl = New;
EPI.ExceptionSpecTemplate = ExceptionSpecTemplate;
New->setType(SemaRef.Context.getFunctionType(
- NewProto->getResultType(), NewProto->getArgTypes(), EPI));
+ NewProto->getReturnType(), NewProto->getParamTypes(), EPI));
} else {
::InstantiateExceptionSpec(SemaRef, New, Proto, TemplateArgs);
}
@@ -3339,14 +3365,22 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// initializer or return value, and class template specializations, other
// explicit instantiation declarations have the effect of suppressing the
// implicit instantiation of the entity to which they refer.
- if (Function->getTemplateSpecializationKind()
- == TSK_ExplicitInstantiationDeclaration &&
+ if (Function->getTemplateSpecializationKind() ==
+ TSK_ExplicitInstantiationDeclaration &&
!PatternDecl->isInlined() &&
- !PatternDecl->getResultType()->getContainedAutoType())
+ !PatternDecl->getReturnType()->getContainedAutoType())
return;
- if (PatternDecl->isInlined())
- Function->setImplicitlyInline();
+ if (PatternDecl->isInlined()) {
+ // Function, and all later redeclarations of it (from imported modules,
+ // for instance), are now implicitly inline.
+ for (auto *D = Function->getMostRecentDecl(); /**/;
+ D = D->getPreviousDecl()) {
+ D->setImplicitlyInline();
+ if (D == Function)
+ break;
+ }
+ }
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
if (Inst.isInvalid())
@@ -3383,14 +3417,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (PatternDecl->isDefaulted())
SetDeclDefaulted(Function, PatternDecl->getLocation());
else {
- ActOnStartOfFunctionDef(0, Function);
+ ActOnStartOfFunctionDef(nullptr, Function);
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
Sema::ContextRAII savedContext(*this, Function);
MultiLevelTemplateArgumentList TemplateArgs =
- getTemplateInstantiationArgs(Function, 0, false, PatternDecl);
+ getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl);
addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope,
TemplateArgs);
@@ -3413,6 +3447,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
PerformDependentDiagnostics(PatternDecl, TemplateArgs);
+ if (auto *Listener = getASTMutationListener())
+ Listener->FunctionDefinitionInstantiated(Function);
+
savedContext.pop();
}
@@ -3453,11 +3490,11 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
LateInstantiatedAttrVec *LateAttrs,
LocalInstantiationScope *StartingScope) {
if (FromVar->isInvalidDecl())
- return 0;
+ return nullptr;
InstantiatingTemplate Inst(*this, PointOfInstantiation, FromVar);
if (Inst.isInvalid())
- return 0;
+ return nullptr;
MultiLevelTemplateArgumentList TemplateArgLists;
TemplateArgLists.addOuterTemplateArguments(&TemplateArgList);
@@ -3467,7 +3504,18 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
// or may not be the declaration in the class; if it's in the class, we want
// to instantiate a member in the class (a declaration), and if it's outside,
// we want to instantiate a definition.
- FromVar = FromVar->getFirstDecl();
+ //
+ // If we're instantiating an explicitly-specialized member template or member
+ // partial specialization, don't do this. The member specialization completely
+ // replaces the original declaration in this case.
+ bool IsMemberSpec = false;
+ if (VarTemplatePartialSpecializationDecl *PartialSpec =
+ dyn_cast<VarTemplatePartialSpecializationDecl>(FromVar))
+ IsMemberSpec = PartialSpec->isMemberSpecialization();
+ else if (VarTemplateDecl *FromTemplate = FromVar->getDescribedVarTemplate())
+ IsMemberSpec = FromTemplate->isMemberSpecialization();
+ if (!IsMemberSpec)
+ FromVar = FromVar->getFirstDecl();
MultiLevelTemplateArgumentList MultiLevelList(TemplateArgList);
TemplateDeclInstantiator Instantiator(*this, FromVar->getDeclContext(),
@@ -3491,7 +3539,7 @@ VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl(
SubstType(PatternDecl->getTypeSourceInfo(), TemplateArgs,
PatternDecl->getTypeSpecStartLoc(), PatternDecl->getDeclName());
if (!DI)
- return 0;
+ return nullptr;
// Update the type of this variable template specialization.
VarSpec->setType(DI->getType());
@@ -3552,16 +3600,15 @@ void Sema::BuildVariableInstantiation(
InstantiateAttrs(TemplateArgs, OldVar, NewVar, LateAttrs, StartingScope);
- if (NewVar->hasAttrs())
- CheckAlignasUnderalignment(NewVar);
-
LookupResult Previous(
*this, NewVar->getDeclName(), NewVar->getLocation(),
NewVar->isLocalExternDecl() ? Sema::LookupRedeclarationWithLinkage
: Sema::LookupOrdinaryName,
Sema::ForRedeclaration);
- if (NewVar->isLocalExternDecl() && OldVar->getPreviousDecl()) {
+ if (NewVar->isLocalExternDecl() && OldVar->getPreviousDecl() &&
+ (!OldVar->getPreviousDecl()->getDeclContext()->isDependentContext() ||
+ OldVar->getPreviousDecl()->getDeclContext()==OldVar->getDeclContext())) {
// We have a previous declaration. Use that one, so we merge with the
// right type.
if (NamedDecl *NewPrev = FindInstantiatedDecl(
@@ -3589,9 +3636,16 @@ void Sema::BuildVariableInstantiation(
NewVar->setInstantiationOfStaticDataMember(OldVar,
TSK_ImplicitInstantiation);
+ // Forward the mangling number from the template to the instantiated decl.
+ Context.setManglingNumber(NewVar, Context.getManglingNumber(OldVar));
+ Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar));
+
// Delay instantiation of the initializer for variable templates until a
- // definition of the variable is needed.
- if (!isa<VarTemplateSpecializationDecl>(NewVar) && !InstantiatingVarTemplate)
+ // definition of the variable is needed. We need it right away if the type
+ // contains 'auto'.
+ if ((!isa<VarTemplateSpecializationDecl>(NewVar) &&
+ !InstantiatingVarTemplate) ||
+ NewVar->getType()->isUndeducedType())
InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
// Diagnose unused local variables with dependent types, where the diagnostic
@@ -3623,9 +3677,15 @@ void Sema::InstantiateVariableInitializer(
OldVar->getInitStyle() == VarDecl::CallInit);
if (!Init.isInvalid()) {
bool TypeMayContainAuto = true;
- if (Init.get()) {
+ Expr *InitExpr = Init.get();
+
+ if (Var->hasAttr<DLLImportAttr>() &&
+ (!InitExpr ||
+ !InitExpr->isConstantInitializer(getASTContext(), false))) {
+ // Do not dynamically initialize dllimport variables.
+ } else if (InitExpr) {
bool DirectInit = OldVar->isDirectInit();
- AddInitializerToDecl(Var, Init.take(), DirectInit, TypeMayContainAuto);
+ AddInitializerToDecl(Var, InitExpr, DirectInit, TypeMayContainAuto);
} else
ActOnUninitializedDecl(Var, TypeMayContainAuto);
} else {
@@ -3673,7 +3733,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
VarTemplateSpecializationDecl *VarSpec =
dyn_cast<VarTemplateSpecializationDecl>(Var);
- VarDecl *PatternDecl = 0, *Def = 0;
+ VarDecl *PatternDecl = nullptr, *Def = nullptr;
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Var);
@@ -3883,7 +3943,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
TemplateDeclInstantiator Instantiator(*this, Var->getDeclContext(),
TemplateArgs);
Var = cast_or_null<VarDecl>(Instantiator.VisitVarTemplateSpecializationDecl(
- VarSpec->getSpecializedTemplate(), Def, 0,
+ VarSpec->getSpecializedTemplate(), Def, nullptr,
VarSpec->getTemplateArgsInfo(), VarSpec->getTemplateArgs().asArray()));
if (Var) {
llvm::PointerUnion<VarTemplateDecl *,
@@ -3951,11 +4011,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
bool AnyErrors = Tmpl->isInvalidDecl();
// Instantiate all the initializers.
- for (CXXConstructorDecl::init_const_iterator Inits = Tmpl->init_begin(),
- InitsEnd = Tmpl->init_end();
- Inits != InitsEnd; ++Inits) {
- CXXCtorInitializer *Init = *Inits;
-
+ for (const auto *Init : Tmpl->inits()) {
// Only instantiate written initializers, let Sema re-construct implicit
// ones.
if (!Init->isWritten())
@@ -4008,7 +4064,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
// Build the initializer.
MemInitResult NewInit = BuildBaseInitializer(BaseTInfo->getType(),
- BaseTInfo, TempInit.take(),
+ BaseTInfo, TempInit.get(),
New->getParent(),
SourceLocation());
if (NewInit.isInvalid()) {
@@ -4043,10 +4099,10 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
}
if (Init->isBaseInitializer())
- NewInit = BuildBaseInitializer(TInfo->getType(), TInfo, TempInit.take(),
+ NewInit = BuildBaseInitializer(TInfo->getType(), TInfo, TempInit.get(),
New->getParent(), EllipsisLoc);
else
- NewInit = BuildDelegatingInitializer(TInfo, TempInit.take(),
+ NewInit = BuildDelegatingInitializer(TInfo, TempInit.get(),
cast<CXXRecordDecl>(CurContext->getParent()));
} else if (Init->isMemberInitializer()) {
FieldDecl *Member = cast_or_null<FieldDecl>(FindInstantiatedDecl(
@@ -4059,7 +4115,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
continue;
}
- NewInit = BuildMemberInitializer(Member, TempInit.take(),
+ NewInit = BuildMemberInitializer(Member, TempInit.get(),
Init->getSourceLocation());
} else if (Init->isIndirectMemberInitializer()) {
IndirectFieldDecl *IndirectMember =
@@ -4073,7 +4129,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
continue;
}
- NewInit = BuildMemberInitializer(IndirectMember, TempInit.take(),
+ NewInit = BuildMemberInitializer(IndirectMember, TempInit.get(),
Init->getSourceLocation());
}
@@ -4287,7 +4343,7 @@ static NamedDecl *findInstantiationOf(ASTContext &Ctx,
if (isInstantiationOf(Ctx, D, *first))
return cast<NamedDecl>(*first);
- return 0;
+ return nullptr;
}
/// \brief Finds the instantiation of the given declaration context
@@ -4339,7 +4395,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// find an instantiated decl for (T y) when the ParentDC for y is
// the translation unit.
// e.g. template <class T> void Foo(auto (*p)(T y) -> decltype(y())) {}
- // float baz(float(*)()) { return 0.0; }
+ // float baz(float(*)()) { return 0.0; }
// Foo(baz);
// The better fix here is perhaps to ensure that a ParmVarDecl, by the time
// it gets here, always has a FunctionOrMethod as its ParentDC??
@@ -4377,7 +4433,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
return D;
if (D->isInvalidDecl())
- return 0;
+ return nullptr;
// If we didn't find the decl, then we must have a label decl that hasn't
// been found yet. Lazily instantiate it and return it now.
@@ -4461,7 +4517,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
ParentDC = FindInstantiatedContext(Loc, ParentDC, TemplateArgs);
if (!ParentDC)
- return 0;
+ return nullptr;
if (ParentDC != D->getDeclContext()) {
// We performed some kind of instantiation in the parent context,
@@ -4480,13 +4536,13 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
IsBeingInstantiated = true;
if (!Tag->isBeingDefined() &&
RequireCompleteType(Loc, T, diag::err_incomplete_type))
- return 0;
+ return nullptr;
ParentDC = Tag->getDecl();
}
}
- NamedDecl *Result = 0;
+ NamedDecl *Result = nullptr;
if (D->getDeclName()) {
DeclContext::lookup_result Found = ParentDC->lookup(D->getDeclName());
Result = findInstantiationOf(Context, D, Found.begin(), Found.end());
@@ -4550,14 +4606,6 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
/// \brief Performs template instantiation for all implicit template
/// instantiations we have seen until this point.
void Sema::PerformPendingInstantiations(bool LocalOnly) {
- // Load pending instantiations from the external source.
- if (!LocalOnly && ExternalSource) {
- SmallVector<PendingImplicitInstantiation, 4> Pending;
- ExternalSource->ReadPendingInstantiations(Pending);
- PendingInstantiations.insert(PendingInstantiations.begin(),
- Pending.begin(), Pending.end());
- }
-
while (!PendingLocalImplicitInstantiations.empty() ||
(!LocalOnly && !PendingInstantiations.empty())) {
PendingImplicitInstantiation Inst;
@@ -4624,10 +4672,7 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
void Sema::PerformDependentDiagnostics(const DeclContext *Pattern,
const MultiLevelTemplateArgumentList &TemplateArgs) {
- for (DeclContext::ddiag_iterator I = Pattern->ddiag_begin(),
- E = Pattern->ddiag_end(); I != E; ++I) {
- DependentDiagnostic *DD = *I;
-
+ for (auto DD : Pattern->ddiags()) {
switch (DD->getKind()) {
case DependentDiagnostic::Access:
HandleDependentAccessCheck(*DD, TemplateArgs);
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 78aa7f893a1a..8e4ce0d9da6f 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -10,6 +10,7 @@
//===----------------------------------------------------------------------===/
#include "clang/Sema/Sema.h"
+#include "TypeLocBuilder.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeLoc.h"
@@ -18,7 +19,6 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
-#include "TypeLocBuilder.h"
using namespace clang;
@@ -223,7 +223,7 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
llvm::SmallPtrSet<IdentifierInfo *, 4> NamesKnown;
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
- IdentifierInfo *Name = 0;
+ IdentifierInfo *Name = nullptr;
if (const TemplateTypeParmType *TTP
= Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>())
Name = TTP->getIdentifier();
@@ -463,7 +463,7 @@ Sema::CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc,
Pattern->getTypeLoc().getSourceRange(),
EllipsisLoc, NumExpansions);
if (Result.isNull())
- return 0;
+ return nullptr;
TypeLocBuilder TLB;
TLB.pushFullCopy(Pattern->getTypeLoc());
@@ -509,8 +509,8 @@ ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
}
// Create the pack expansion expression and source-location information.
- return Owned(new (Context) PackExpansionExpr(Context.DependentTy, Pattern,
- EllipsisLoc, NumExpansions));
+ return new (Context)
+ PackExpansionExpr(Context.DependentTy, Pattern, EllipsisLoc, NumExpansions);
}
/// \brief Retrieve the depth and index of a parameter pack.
@@ -554,8 +554,8 @@ bool Sema::CheckParameterPacksForExpansion(
if (isa<ParmVarDecl>(ND))
IsFunctionParameterPack = true;
else
- llvm::tie(Depth, Index) = getDepthAndIndex(ND);
-
+ std::tie(Depth, Index) = getDepthAndIndex(ND);
+
Name = ND->getIdentifier();
}
@@ -599,7 +599,7 @@ bool Sema::CheckParameterPacksForExpansion(
if (NamedDecl *PartialPack
= CurrentInstantiationScope->getPartiallySubstitutedPack()){
unsigned PartialDepth, PartialIndex;
- llvm::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack);
+ std::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack);
if (PartialDepth == Depth && PartialIndex == Index)
RetainExpansion = true;
}
@@ -669,8 +669,8 @@ Optional<unsigned> Sema::getNumArgumentsInExpansion(QualType T,
Result = Size;
continue;
}
-
- llvm::tie(Depth, Index) = getDepthAndIndex(ND);
+
+ std::tie(Depth, Index) = getDepthAndIndex(ND);
}
if (Depth >= TemplateArgs.getNumLevels() ||
!TemplateArgs.hasTemplateArgument(Depth, Index))
@@ -730,14 +730,6 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_auto:
case TST_decltype_auto:
case TST_unknown_anytype:
- case TST_image1d_t:
- case TST_image1d_array_t:
- case TST_image1d_buffer_t:
- case TST_image2d_t:
- case TST_image2d_array_t:
- case TST_image3d_t:
- case TST_sampler_t:
- case TST_event_t:
case TST_error:
break;
}
@@ -775,7 +767,7 @@ namespace {
// Callback to only accept typo corrections that refer to parameter packs.
class ParameterPackValidatorCCC : public CorrectionCandidateCallback {
public:
- virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ bool ValidateCandidate(const TypoCorrection &candidate) override {
NamedDecl *ND = candidate.getCorrectionDecl();
return ND && ND->isParameterPack();
}
@@ -806,8 +798,8 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
// The identifier in a sizeof... expression shall name a parameter pack.
LookupResult R(*this, &Name, NameLoc, LookupOrdinaryName);
LookupName(R, S);
-
- NamedDecl *ParameterPack = 0;
+
+ NamedDecl *ParameterPack = nullptr;
ParameterPackValidatorCCC Validator;
switch (R.getResultKind()) {
case LookupResult::Found:
@@ -817,8 +809,8 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
- R.getLookupKind(), S, 0,
- Validator)) {
+ R.getLookupKind(), S, nullptr,
+ Validator, CTK_ErrorRecovery)) {
diagnoseTypo(Corrected,
PDiag(diag::err_sizeof_pack_no_pack_name_suggest) << &Name,
PDiag(diag::note_parameter_pack_here));
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index aa7459de2726..be1191c1e8e0 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
+#include "TypeLocBuilder.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
@@ -21,10 +22,8 @@
#include "clang/AST/Expr.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeLocVisitor.h"
-#include "clang/Basic/OpenCL.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h"
@@ -34,7 +33,6 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
-#include "TypeLocBuilder.h"
using namespace clang;
@@ -81,7 +79,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
StringRef name = attr.getName()->getName();
// The GC attributes are usually written with macros; special-case them.
- IdentifierInfo *II = attr.isArgIdent(0) ? attr.getArgAsIdent(0)->Ident : 0;
+ IdentifierInfo *II = attr.isArgIdent(0) ? attr.getArgAsIdent(0)->Ident
+ : nullptr;
if (useExpansionLoc && loc.isMacroID() && II) {
if (II->isStr("strong")) {
if (S.findMacroSpelling(loc, "__strong")) name = "__strong";
@@ -225,14 +224,14 @@ namespace {
assert(hasSavedAttrs);
if (savedAttrs.empty()) {
- getMutableDeclSpec().getAttributes().set(0);
+ getMutableDeclSpec().getAttributes().set(nullptr);
return;
}
getMutableDeclSpec().getAttributes().set(savedAttrs[0]);
for (unsigned i = 0, e = savedAttrs.size() - 1; i != e; ++i)
savedAttrs[i]->setNext(savedAttrs[i+1]);
- savedAttrs.back()->setNext(0);
+ savedAttrs.back()->setNext(nullptr);
}
};
}
@@ -312,7 +311,7 @@ static DeclaratorChunk *maybeMovePastReturnType(Declarator &declarator,
unsigned i) {
assert(i <= declarator.getNumTypeObjects());
- DeclaratorChunk *result = 0;
+ DeclaratorChunk *result = nullptr;
// First, look inwards past parens for a function declarator.
for (; i != 0; --i) {
@@ -380,7 +379,7 @@ static void distributeObjCPointerTypeAttr(TypeProcessingState &state,
case DeclaratorChunk::BlockPointer: {
// But don't move an ARC ownership attribute to the return type
// of a block.
- DeclaratorChunk *destChunk = 0;
+ DeclaratorChunk *destChunk = nullptr;
if (state.isProcessingDeclSpec() &&
attr.getKind() == AttributeList::AT_ObjCOwnership)
destChunk = maybeMovePastReturnType(declarator, i - 1);
@@ -664,7 +663,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
/*HasProto=*/true,
/*IsAmbiguous=*/false,
/*LParenLoc=*/NoLoc,
- /*ArgInfo=*/0,
+ /*ArgInfo=*/nullptr,
/*NumArgs=*/0,
/*EllipsisLoc=*/NoLoc,
/*RParenLoc=*/NoLoc,
@@ -676,10 +675,10 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
/*MutableLoc=*/NoLoc,
EST_None,
/*ESpecLoc=*/NoLoc,
- /*Exceptions=*/0,
- /*ExceptionRanges=*/0,
+ /*Exceptions=*/nullptr,
+ /*ExceptionRanges=*/nullptr,
/*NumExceptions=*/0,
- /*NoexceptExpr=*/0,
+ /*NoexceptExpr=*/nullptr,
loc, loc, declarator));
// For consistency, make sure the state still has us as processing
@@ -728,13 +727,15 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Result = Context.WCharTy;
else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) {
S.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec)
- << DS.getSpecifierName(DS.getTypeSpecType());
+ << DS.getSpecifierName(DS.getTypeSpecType(),
+ Context.getPrintingPolicy());
Result = Context.getSignedWCharType();
} else {
assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned &&
"Unknown TSS value");
S.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec)
- << DS.getSpecifierName(DS.getTypeSpecType());
+ << DS.getSpecifierName(DS.getTypeSpecType(),
+ Context.getPrintingPolicy());
Result = Context.getUnsignedWCharType();
}
break;
@@ -851,7 +852,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
break;
}
case DeclSpec::TST_int128:
- if (!S.PP.getTargetInfo().hasInt128Type())
+ if (!S.Context.getTargetInfo().hasInt128Type())
S.Diag(DS.getTypeSpecTypeLoc(), diag::err_int128_unsupported);
if (DS.getTypeSpecSign() == DeclSpec::TSS_unsigned)
Result = Context.UnsignedInt128Ty;
@@ -1058,38 +1059,6 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
}
break;
- case DeclSpec::TST_image1d_t:
- Result = Context.OCLImage1dTy;
- break;
-
- case DeclSpec::TST_image1d_array_t:
- Result = Context.OCLImage1dArrayTy;
- break;
-
- case DeclSpec::TST_image1d_buffer_t:
- Result = Context.OCLImage1dBufferTy;
- break;
-
- case DeclSpec::TST_image2d_t:
- Result = Context.OCLImage2dTy;
- break;
-
- case DeclSpec::TST_image2d_array_t:
- Result = Context.OCLImage2dArrayTy;
- break;
-
- case DeclSpec::TST_image3d_t:
- Result = Context.OCLImage3dTy;
- break;
-
- case DeclSpec::TST_sampler_t:
- Result = Context.OCLSamplerTy;
- break;
-
- case DeclSpec::TST_event_t:
- Result = Context.OCLEventTy;
- break;
-
case DeclSpec::TST_error:
Result = Context.IntTy;
declarator.setInvalidType(true);
@@ -1148,17 +1117,33 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
}
}
- // C++ [dcl.ref]p1:
+ // C++11 [dcl.ref]p1:
// Cv-qualified references are ill-formed except when the
- // cv-qualifiers are introduced through the use of a typedef
- // (7.1.3) or of a template type argument (14.3), in which
- // case the cv-qualifiers are ignored.
- // FIXME: Shouldn't we be checking SCS_typedef here?
+ // cv-qualifiers are introduced through the use of a typedef-name
+ // or decltype-specifier, in which case the cv-qualifiers are ignored.
+ //
+ // There don't appear to be any other contexts in which a cv-qualified
+ // reference type could be formed, so the 'ill-formed' clause here appears
+ // to never happen.
if (DS.getTypeSpecType() == DeclSpec::TST_typename &&
TypeQuals && Result->isReferenceType()) {
- TypeQuals &= ~DeclSpec::TQ_const;
- TypeQuals &= ~DeclSpec::TQ_volatile;
- TypeQuals &= ~DeclSpec::TQ_atomic;
+ // If this occurs outside a template instantiation, warn the user about
+ // it; they probably didn't mean to specify a redundant qualifier.
+ typedef std::pair<DeclSpec::TQ, SourceLocation> QualLoc;
+ QualLoc Quals[] = {
+ QualLoc(DeclSpec::TQ_const, DS.getConstSpecLoc()),
+ QualLoc(DeclSpec::TQ_volatile, DS.getVolatileSpecLoc()),
+ QualLoc(DeclSpec::TQ_atomic, DS.getAtomicSpecLoc())
+ };
+ for (unsigned I = 0, N = llvm::array_lengthof(Quals); I != N; ++I) {
+ if (S.ActiveTemplateInstantiations.empty()) {
+ if (TypeQuals & Quals[I].first)
+ S.Diag(Quals[I].second, diag::warn_typecheck_reference_qualifiers)
+ << DeclSpec::getSpecifierName(Quals[I].first) << Result
+ << FixItHint::CreateRemoval(Quals[I].second);
+ }
+ TypeQuals &= ~Quals[I].first;
+ }
}
// C90 6.5.3 constraints: "The same type qualifier shall not appear more
@@ -1327,6 +1312,59 @@ static QualType inferARCLifetimeForPointee(Sema &S, QualType type,
return S.Context.getQualifiedType(type, qs);
}
+static std::string getFunctionQualifiersAsString(const FunctionProtoType *FnTy){
+ std::string Quals =
+ Qualifiers::fromCVRMask(FnTy->getTypeQuals()).getAsString();
+
+ switch (FnTy->getRefQualifier()) {
+ case RQ_None:
+ break;
+
+ case RQ_LValue:
+ if (!Quals.empty())
+ Quals += ' ';
+ Quals += '&';
+ break;
+
+ case RQ_RValue:
+ if (!Quals.empty())
+ Quals += ' ';
+ Quals += "&&";
+ break;
+ }
+
+ return Quals;
+}
+
+namespace {
+/// Kinds of declarator that cannot contain a qualified function type.
+///
+/// C++98 [dcl.fct]p4 / C++11 [dcl.fct]p6:
+/// a function type with a cv-qualifier or a ref-qualifier can only appear
+/// at the topmost level of a type.
+///
+/// Parens and member pointers are permitted. We don't diagnose array and
+/// function declarators, because they don't allow function types at all.
+///
+/// The values of this enum are used in diagnostics.
+enum QualifiedFunctionKind { QFK_BlockPointer, QFK_Pointer, QFK_Reference };
+}
+
+/// Check whether the type T is a qualified function type, and if it is,
+/// diagnose that it cannot be contained within the given kind of declarator.
+static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc,
+ QualifiedFunctionKind QFK) {
+ // Does T refer to a function type with a cv-qualifier or a ref-qualifier?
+ const FunctionProtoType *FPT = T->getAs<FunctionProtoType>();
+ if (!FPT || (FPT->getTypeQuals() == 0 && FPT->getRefQualifier() == RQ_None))
+ return false;
+
+ S.Diag(Loc, diag::err_compound_qualified_function_type)
+ << QFK << isa<FunctionType>(T.IgnoreParens()) << T
+ << getFunctionQualifiersAsString(FPT);
+ return true;
+}
+
/// \brief Build a pointer type.
///
/// \param T The type to which we'll be building a pointer.
@@ -1349,6 +1387,9 @@ QualType Sema::BuildPointerType(QualType T,
return QualType();
}
+ if (checkQualifiedFunction(*this, T, Loc, QFK_Pointer))
+ return QualType();
+
assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType");
// In ARC, it is forbidden to build pointers to unqualified pointers.
@@ -1408,6 +1449,9 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
return QualType();
}
+ if (checkQualifiedFunction(*this, T, Loc, QFK_Reference))
+ return QualType();
+
// In ARC, it is forbidden to build references to unqualified pointers.
if (getLangOpts().ObjCAutoRefCount)
T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true);
@@ -1427,10 +1471,10 @@ static bool isArraySizeVLA(Sema &S, Expr *ArraySize, llvm::APSInt &SizeVal) {
public:
VLADiagnoser() : Sema::VerifyICEDiagnoser(true) {}
- virtual void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) {
+ void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) override {
}
- virtual void diagnoseFold(Sema &S, SourceLocation Loc, SourceRange SR) {
+ void diagnoseFold(Sema &S, SourceLocation Loc, SourceRange SR) override {
S.Diag(Loc, diag::ext_vla_folded_to_constant) << SR;
}
} Diagnoser;
@@ -1487,6 +1531,13 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
diag::err_array_of_abstract_type))
return QualType();
+ // Mentioning a member pointer type for an array type causes us to lock in
+ // an inheritance model, even if it's inside an unused typedef.
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft())
+ if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>())
+ if (!MPTy->getClass()->isDependentType())
+ RequireCompleteType(Loc, T, 0);
+
} else {
// C99 6.7.5.2p1: If the element type is an incomplete or function type,
// reject it (e.g. void ary[7], struct foo ary[7], void ary[7]())
@@ -1515,7 +1566,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
if (ArraySize && ArraySize->hasPlaceholderType()) {
ExprResult Result = CheckPlaceholderExpr(ArraySize);
if (Result.isInvalid()) return QualType();
- ArraySize = Result.take();
+ ArraySize = Result.get();
}
// Do lvalue-to-rvalue conversions on the array size expression.
@@ -1524,7 +1575,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
if (Result.isInvalid())
return QualType();
- ArraySize = Result.take();
+ ArraySize = Result.get();
}
// C99 6.7.5.2p1: The size expression shall have integer type.
@@ -1540,7 +1591,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
llvm::APSInt ConstVal(Context.getTypeSize(Context.getSizeType()));
if (!ArraySize) {
if (ASM == ArrayType::Star)
- T = Context.getVariableArrayType(T, 0, ASM, Quals, Brackets);
+ T = Context.getVariableArrayType(T, nullptr, ASM, Quals, Brackets);
else
T = Context.getIncompleteArrayType(T, ASM, Quals);
} else if (ArraySize->isTypeDependent() || ArraySize->isValueDependent()) {
@@ -1614,6 +1665,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
// Prohibit the use of non-POD types in VLAs.
QualType BaseT = Context.getBaseElementType(T);
if (!T->isDependentType() &&
+ !RequireCompleteType(Loc, BaseT, 0) &&
!BaseT.isPODType(Context) &&
!BaseT->isObjCLifetimeType()) {
Diag(Loc, diag::err_vla_non_pod)
@@ -1711,7 +1763,7 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) {
}
QualType Sema::BuildFunctionType(QualType T,
- llvm::MutableArrayRef<QualType> ParamTypes,
+ MutableArrayRef<QualType> ParamTypes,
SourceLocation Loc, DeclarationName Entity,
const FunctionProtoType::ExtProtoInfo &EPI) {
bool Invalid = false;
@@ -1769,13 +1821,13 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
// with reference type, or "cv void."
if (T->isReferenceType()) {
Diag(Loc, diag::err_illegal_decl_mempointer_to_reference)
- << (Entity? Entity.getAsString() : "type name") << T;
+ << getPrintableNameForEntity(Entity) << T;
return QualType();
}
if (T->isVoidType()) {
Diag(Loc, diag::err_illegal_decl_mempointer_to_void)
- << (Entity? Entity.getAsString() : "type name");
+ << getPrintableNameForEntity(Entity);
return QualType();
}
@@ -1784,35 +1836,10 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
return QualType();
}
- // C++ allows the class type in a member pointer to be an incomplete type.
- // In the Microsoft ABI, the size of the member pointer can vary
- // according to the class type, which means that we really need a
- // complete type if possible, which means we need to instantiate templates.
- //
- // If template instantiation fails or the type is just incomplete, we have to
- // add an extra slot to the member pointer. Yes, this does cause problems
- // when passing pointers between TUs that disagree about the size.
- if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
- CXXRecordDecl *RD = Class->getAsCXXRecordDecl();
- if (RD && !RD->hasAttr<MSInheritanceAttr>()) {
- // Lock in the inheritance model on the first use of a member pointer.
- // Otherwise we may disagree about the size at different points in the TU.
- // FIXME: MSVC picks a model on the first use that needs to know the size,
- // rather than on the first mention of the type, e.g. typedefs.
- if (RequireCompleteType(Loc, Class, 0) && !RD->isBeingDefined()) {
- // We know it doesn't have an attribute and it's incomplete, so use the
- // unspecified inheritance model. If we're in the record body, we can
- // figure out the inheritance model.
- for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(),
- E = RD->redecls_end(); I != E; ++I) {
- I->addAttr(::new (Context) UnspecifiedInheritanceAttr(
- RD->getSourceRange(), Context));
- }
- }
- }
- }
-
- // FIXME: Adjust member function pointer calling conventions.
+ // Adjust the default free function calling convention to the default method
+ // calling convention.
+ if (T->isFunctionType())
+ adjustMemberFunctionCC(T, /*IsStatic=*/false);
return Context.getMemberPointerType(T, Class.getTypePtr());
}
@@ -1836,17 +1863,20 @@ QualType Sema::BuildBlockPointerType(QualType T,
return QualType();
}
+ if (checkQualifiedFunction(*this, T, Loc, QFK_BlockPointer))
+ return QualType();
+
return Context.getBlockPointerType(T);
}
QualType Sema::GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo) {
QualType QT = Ty.get();
if (QT.isNull()) {
- if (TInfo) *TInfo = 0;
+ if (TInfo) *TInfo = nullptr;
return QualType();
}
- TypeSourceInfo *DI = 0;
+ TypeSourceInfo *DI = nullptr;
if (const LocInfoType *LIT = dyn_cast<LocInfoType>(QT)) {
QT = LIT->getType();
DI = LIT->getTypeSourceInfo();
@@ -1959,18 +1989,15 @@ static void inferARCWriteback(TypeProcessingState &state,
// TODO: mark whether we did this inference?
}
-static void diagnoseIgnoredQualifiers(
- Sema &S, unsigned Quals,
- SourceLocation FallbackLoc,
- SourceLocation ConstQualLoc = SourceLocation(),
- SourceLocation VolatileQualLoc = SourceLocation(),
- SourceLocation RestrictQualLoc = SourceLocation(),
- SourceLocation AtomicQualLoc = SourceLocation()) {
+void Sema::diagnoseIgnoredQualifiers(unsigned DiagID, unsigned Quals,
+ SourceLocation FallbackLoc,
+ SourceLocation ConstQualLoc,
+ SourceLocation VolatileQualLoc,
+ SourceLocation RestrictQualLoc,
+ SourceLocation AtomicQualLoc) {
if (!Quals)
return;
- const SourceManager &SM = S.getSourceManager();
-
struct Qual {
unsigned Mask;
const char *Name;
@@ -1997,7 +2024,8 @@ static void diagnoseIgnoredQualifiers(
SourceLocation QualLoc = QualKinds[I].Loc;
if (!QualLoc.isInvalid()) {
FixIts[NumQuals] = FixItHint::CreateRemoval(QualLoc);
- if (Loc.isInvalid() || SM.isBeforeInTranslationUnit(QualLoc, Loc))
+ if (Loc.isInvalid() ||
+ getSourceManager().isBeforeInTranslationUnit(QualLoc, Loc))
Loc = QualLoc;
}
@@ -2005,19 +2033,20 @@ static void diagnoseIgnoredQualifiers(
}
}
- S.Diag(Loc.isInvalid() ? FallbackLoc : Loc, diag::warn_qual_return_type)
+ Diag(Loc.isInvalid() ? FallbackLoc : Loc, DiagID)
<< QualStr << NumQuals << FixIts[0] << FixIts[1] << FixIts[2] << FixIts[3];
}
// Diagnose pointless type qualifiers on the return type of a function.
-static void diagnoseIgnoredFunctionQualifiers(Sema &S, QualType RetTy,
- Declarator &D,
- unsigned FunctionChunkIndex) {
+static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy,
+ Declarator &D,
+ unsigned FunctionChunkIndex) {
if (D.getTypeObject(FunctionChunkIndex).Fun.hasTrailingReturnType()) {
// FIXME: TypeSourceInfo doesn't preserve location information for
// qualifiers.
- diagnoseIgnoredQualifiers(S, RetTy.getLocalCVRQualifiers(),
- D.getIdentifierLoc());
+ S.diagnoseIgnoredQualifiers(diag::warn_qual_return_type,
+ RetTy.getLocalCVRQualifiers(),
+ D.getIdentifierLoc());
return;
}
@@ -2031,8 +2060,9 @@ static void diagnoseIgnoredFunctionQualifiers(Sema &S, QualType RetTy,
case DeclaratorChunk::Pointer: {
DeclaratorChunk::PointerTypeInfo &PTI = OuterChunk.Ptr;
- diagnoseIgnoredQualifiers(
- S, PTI.TypeQuals,
+ S.diagnoseIgnoredQualifiers(
+ diag::warn_qual_return_type,
+ PTI.TypeQuals,
SourceLocation(),
SourceLocation::getFromRawEncoding(PTI.ConstQualLoc),
SourceLocation::getFromRawEncoding(PTI.VolatileQualLoc),
@@ -2049,8 +2079,9 @@ static void diagnoseIgnoredFunctionQualifiers(Sema &S, QualType RetTy,
// FIXME: We can't currently provide an accurate source location and a
// fix-it hint for these.
unsigned AtomicQual = RetTy->isAtomicType() ? DeclSpec::TQ_atomic : 0;
- diagnoseIgnoredQualifiers(S, RetTy.getCVRQualifiers() | AtomicQual,
- D.getIdentifierLoc());
+ S.diagnoseIgnoredQualifiers(diag::warn_qual_return_type,
+ RetTy.getCVRQualifiers() | AtomicQual,
+ D.getIdentifierLoc());
return;
}
@@ -2065,12 +2096,13 @@ static void diagnoseIgnoredFunctionQualifiers(Sema &S, QualType RetTy,
// Just parens all the way out to the decl specifiers. Diagnose any qualifiers
// which are present there.
- diagnoseIgnoredQualifiers(S, D.getDeclSpec().getTypeQualifiers(),
- D.getIdentifierLoc(),
- D.getDeclSpec().getConstSpecLoc(),
- D.getDeclSpec().getVolatileSpecLoc(),
- D.getDeclSpec().getRestrictSpecLoc(),
- D.getDeclSpec().getAtomicSpecLoc());
+ S.diagnoseIgnoredQualifiers(diag::warn_qual_return_type,
+ D.getDeclSpec().getTypeQualifiers(),
+ D.getIdentifierLoc(),
+ D.getDeclSpec().getConstSpecLoc(),
+ D.getDeclSpec().getVolatileSpecLoc(),
+ D.getDeclSpec().getRestrictSpecLoc(),
+ D.getDeclSpec().getAtomicSpecLoc());
}
static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
@@ -2078,10 +2110,10 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
Sema &SemaRef = state.getSema();
Declarator &D = state.getDeclarator();
QualType T;
- ReturnTypeInfo = 0;
+ ReturnTypeInfo = nullptr;
// The TagDecl owned by the DeclSpec.
- TagDecl *OwnedTagDecl = 0;
+ TagDecl *OwnedTagDecl = nullptr;
bool ContainsPlaceholderType = false;
@@ -2303,67 +2335,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
return T;
}
-static std::string getFunctionQualifiersAsString(const FunctionProtoType *FnTy){
- std::string Quals =
- Qualifiers::fromCVRMask(FnTy->getTypeQuals()).getAsString();
-
- switch (FnTy->getRefQualifier()) {
- case RQ_None:
- break;
-
- case RQ_LValue:
- if (!Quals.empty())
- Quals += ' ';
- Quals += '&';
- break;
-
- case RQ_RValue:
- if (!Quals.empty())
- Quals += ' ';
- Quals += "&&";
- break;
- }
-
- return Quals;
-}
-
-/// Check that the function type T, which has a cv-qualifier or a ref-qualifier,
-/// can be contained within the declarator chunk DeclType, and produce an
-/// appropriate diagnostic if not.
-static void checkQualifiedFunction(Sema &S, QualType T,
- DeclaratorChunk &DeclType) {
- // C++98 [dcl.fct]p4 / C++11 [dcl.fct]p6: a function type with a
- // cv-qualifier or a ref-qualifier can only appear at the topmost level
- // of a type.
- int DiagKind = -1;
- switch (DeclType.Kind) {
- case DeclaratorChunk::Paren:
- case DeclaratorChunk::MemberPointer:
- // These cases are permitted.
- return;
- case DeclaratorChunk::Array:
- case DeclaratorChunk::Function:
- // These cases don't allow function types at all; no need to diagnose the
- // qualifiers separately.
- return;
- case DeclaratorChunk::BlockPointer:
- DiagKind = 0;
- break;
- case DeclaratorChunk::Pointer:
- DiagKind = 1;
- break;
- case DeclaratorChunk::Reference:
- DiagKind = 2;
- break;
- }
-
- assert(DiagKind != -1);
- S.Diag(DeclType.Loc, diag::err_compound_qualified_function_type)
- << DiagKind << isa<FunctionType>(T.IgnoreParens()) << T
- << getFunctionQualifiersAsString(T->castAs<FunctionProtoType>());
-}
-
-/// Produce an approprioate diagnostic for an ambiguity between a function
+/// Produce an appropriate diagnostic for an ambiguity between a function
/// declarator and a C++ direct-initializer.
static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
DeclaratorChunk &DeclType, QualType RT) {
@@ -2375,11 +2347,11 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
return;
// An initializer for a non-class type can have at most one argument.
- if (!RT->isRecordType() && FTI.NumArgs > 1)
+ if (!RT->isRecordType() && FTI.NumParams > 1)
return;
// An initializer for a reference must have exactly one argument.
- if (RT->isReferenceType() && FTI.NumArgs != 1)
+ if (RT->isReferenceType() && FTI.NumParams != 1)
return;
// Only warn if this declarator is declaring a function at block scope, and
@@ -2399,9 +2371,9 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
SourceRange ParenRange(DeclType.Loc, DeclType.EndLoc);
S.Diag(DeclType.Loc,
- FTI.NumArgs ? diag::warn_parens_disambiguated_as_function_declaration
- : diag::warn_empty_parens_are_function_decl)
- << ParenRange;
+ FTI.NumParams ? diag::warn_parens_disambiguated_as_function_declaration
+ : diag::warn_empty_parens_are_function_decl)
+ << ParenRange;
// If the declaration looks like:
// T var1,
@@ -2422,21 +2394,21 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
}
}
- if (FTI.NumArgs > 0) {
- // For a declaration with parameters, eg. "T var(T());", suggest adding parens
- // around the first parameter to turn the declaration into a variable
- // declaration.
- SourceRange Range = FTI.ArgInfo[0].Param->getSourceRange();
+ if (FTI.NumParams > 0) {
+ // For a declaration with parameters, eg. "T var(T());", suggest adding
+ // parens around the first parameter to turn the declaration into a
+ // variable declaration.
+ SourceRange Range = FTI.Params[0].Param->getSourceRange();
SourceLocation B = Range.getBegin();
- SourceLocation E = S.PP.getLocForEndOfToken(Range.getEnd());
+ SourceLocation E = S.getLocForEndOfToken(Range.getEnd());
// FIXME: Maybe we should suggest adding braces instead of parens
// in C++11 for classes that don't have an initializer_list constructor.
S.Diag(B, diag::note_additional_parens_for_variable_declaration)
<< FixItHint::CreateInsertion(B, "(")
<< FixItHint::CreateInsertion(E, ")");
} else {
- // For a declaration without parameters, eg. "T var();", suggest replacing the
- // parens with an initializer to turn the declaration into a variable
+ // For a declaration without parameters, eg. "T var();", suggest replacing
+ // the parens with an initializer to turn the declaration into a variable
// declaration.
const CXXRecordDecl *RD = RT->getAsCXXRecordDecl();
@@ -2579,10 +2551,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
unsigned chunkIndex = e - i - 1;
state.setCurrentChunkIndex(chunkIndex);
DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex);
- if (IsQualifiedFunction) {
- checkQualifiedFunction(S, T, DeclType);
- IsQualifiedFunction = DeclType.Kind == DeclaratorChunk::Paren;
- }
+ IsQualifiedFunction &= DeclType.Kind == DeclaratorChunk::Paren;
switch (DeclType.Kind) {
case DeclaratorChunk::Paren:
T = S.BuildParenType(T);
@@ -2625,7 +2594,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
T = S.BuildReferenceType(T, DeclType.Ref.LValueRef, DeclType.Loc, Name);
- Qualifiers Quals;
if (DeclType.Ref.HasRestrict)
T = S.BuildQualifiedType(T, DeclType.Loc, Qualifiers::Restrict);
break;
@@ -2727,11 +2695,13 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (!D.isInvalidType()) {
// trailing-return-type is only required if we're declaring a function,
// and not, for instance, a pointer to a function.
- if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
+ if (D.getDeclSpec().containsPlaceholderType() &&
!FTI.hasTrailingReturnType() && chunkIndex == 0 &&
!S.getLangOpts().CPlusPlus1y) {
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
- diag::err_auto_missing_trailing_return);
+ D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto
+ ? diag::err_auto_missing_trailing_return
+ : diag::err_deduced_return_type);
T = Context.IntTy;
D.setInvalidType(true);
} else if (FTI.hasTrailingReturnType()) {
@@ -2794,10 +2764,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
SourceLocation DiagLoc, FixitLoc;
if (TInfo) {
DiagLoc = TInfo->getTypeLoc().getLocStart();
- FixitLoc = S.PP.getLocForEndOfToken(TInfo->getTypeLoc().getLocEnd());
+ FixitLoc = S.getLocForEndOfToken(TInfo->getTypeLoc().getLocEnd());
} else {
DiagLoc = D.getDeclSpec().getTypeSpecTypeLoc();
- FixitLoc = S.PP.getLocForEndOfToken(D.getDeclSpec().getLocEnd());
+ FixitLoc = S.getLocForEndOfToken(D.getDeclSpec().getLocEnd());
}
S.Diag(DiagLoc, diag::err_object_cannot_be_passed_returned_by_value)
<< 0 << T
@@ -2820,7 +2790,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if ((T.getCVRQualifiers() || T->isAtomicType()) &&
!(S.getLangOpts().CPlusPlus &&
(T->isDependentType() || T->isRecordType())))
- diagnoseIgnoredFunctionQualifiers(S, T, D, chunkIndex);
+ diagnoseRedundantReturnTypeQualifiers(S, T, D, chunkIndex);
// Objective-C ARC ownership qualifiers are ignored on the function
// return type (by type canonicalization). Complain if this attribute
@@ -2882,14 +2852,14 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
FunctionType::ExtInfo EI(getCCForDeclaratorChunk(S, D, FTI, chunkIndex));
- if (!FTI.NumArgs && !FTI.isVariadic && !LangOpts.CPlusPlus) {
+ if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus) {
// Simple void foo(), where the incoming T is the result type.
T = Context.getFunctionNoProtoType(T, EI);
} 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 && !LangOpts.CPlusPlus) {
+ if (!FTI.NumParams && FTI.isVariadic && !LangOpts.CPlusPlus) {
bool Overloadable = false;
for (const AttributeList *Attrs = D.getAttributes();
Attrs; Attrs = Attrs->getNext()) {
@@ -2900,13 +2870,14 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
if (!Overloadable)
- S.Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg);
+ S.Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_param);
}
- if (FTI.NumArgs && FTI.ArgInfo[0].Param == 0) {
+ if (FTI.NumParams && FTI.Params[0].Param == nullptr) {
// C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function
// definition.
- S.Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration);
+ S.Diag(FTI.Params[0].IdentLoc,
+ diag::err_ident_list_in_fn_declaration);
D.setInvalidType(true);
// Recover by creating a K&R-style function type.
T = Context.getFunctionNoProtoType(T, EI);
@@ -2922,52 +2893,51 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
: FTI.RefQualifierIsLValueRef? RQ_LValue
: RQ_RValue;
- // Otherwise, we have a function with an argument list that is
+ // Otherwise, we have a function with a parameter list that is
// potentially variadic.
- SmallVector<QualType, 16> ArgTys;
- ArgTys.reserve(FTI.NumArgs);
+ SmallVector<QualType, 16> ParamTys;
+ ParamTys.reserve(FTI.NumParams);
- SmallVector<bool, 16> ConsumedArguments;
- ConsumedArguments.reserve(FTI.NumArgs);
- bool HasAnyConsumedArguments = false;
+ SmallVector<bool, 16> ConsumedParameters;
+ ConsumedParameters.reserve(FTI.NumParams);
+ bool HasAnyConsumedParameters = 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?");
+ for (unsigned i = 0, e = FTI.NumParams; i != e; ++i) {
+ ParmVarDecl *Param = cast<ParmVarDecl>(FTI.Params[i].Param);
+ QualType ParamTy = Param->getType();
+ assert(!ParamTy.isNull() && "Couldn't parse type?");
- // Look for 'void'. void is allowed only as a single argument to a
+ // Look for 'void'. void is allowed only as a single parameter to a
// function with no other parameters (C99 6.7.5.3p10). We record
- // int(void) as a FunctionProtoType with an empty argument list.
- if (ArgTy->isVoidType()) {
+ // int(void) as a FunctionProtoType with an empty parameter list.
+ if (ParamTy->isVoidType()) {
// If this is something like 'float(int, void)', reject it. 'void'
// is an incomplete type (C99 6.2.5p19) and function decls cannot
- // have arguments of incomplete type.
- if (FTI.NumArgs != 1 || FTI.isVariadic) {
+ // have parameters of incomplete type.
+ if (FTI.NumParams != 1 || FTI.isVariadic) {
S.Diag(DeclType.Loc, diag::err_void_only_param);
- ArgTy = Context.IntTy;
- Param->setType(ArgTy);
- } else if (FTI.ArgInfo[i].Ident) {
+ ParamTy = Context.IntTy;
+ Param->setType(ParamTy);
+ } else if (FTI.Params[i].Ident) {
// Reject, but continue to parse 'int(void abc)'.
- S.Diag(FTI.ArgInfo[i].IdentLoc,
- diag::err_param_with_void_type);
- ArgTy = Context.IntTy;
- Param->setType(ArgTy);
+ S.Diag(FTI.Params[i].IdentLoc, diag::err_param_with_void_type);
+ ParamTy = Context.IntTy;
+ Param->setType(ParamTy);
} else {
// Reject, but continue to parse 'float(const void)'.
- if (ArgTy.hasQualifiers())
+ if (ParamTy.hasQualifiers())
S.Diag(DeclType.Loc, diag::err_void_param_qualified);
- // Do not add 'void' to the ArgTys list.
+ // Do not add 'void' to the list.
break;
}
- } else if (ArgTy->isHalfType()) {
- // Disallow half FP arguments.
+ } else if (ParamTy->isHalfType()) {
+ // Disallow half FP parameters.
// FIXME: This really should be in BuildFunctionType.
if (S.getLangOpts().OpenCL) {
if (!S.getOpenCLOptions().cl_khr_fp16) {
S.Diag(Param->getLocation(),
- diag::err_opencl_half_argument) << ArgTy;
+ diag::err_opencl_half_param) << ParamTy;
D.setInvalidType();
Param->setInvalidDecl();
}
@@ -2977,12 +2947,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
D.setInvalidType();
}
} else if (!FTI.hasPrototype) {
- if (ArgTy->isPromotableIntegerType()) {
- ArgTy = Context.getPromotedIntegerType(ArgTy);
+ if (ParamTy->isPromotableIntegerType()) {
+ ParamTy = Context.getPromotedIntegerType(ParamTy);
Param->setKNRPromoted(true);
- } else if (const BuiltinType* BTy = ArgTy->getAs<BuiltinType>()) {
+ } else if (const BuiltinType* BTy = ParamTy->getAs<BuiltinType>()) {
if (BTy->getKind() == BuiltinType::Float) {
- ArgTy = Context.DoubleTy;
+ ParamTy = Context.DoubleTy;
Param->setKNRPromoted(true);
}
}
@@ -2990,20 +2960,20 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (LangOpts.ObjCAutoRefCount) {
bool Consumed = Param->hasAttr<NSConsumedAttr>();
- ConsumedArguments.push_back(Consumed);
- HasAnyConsumedArguments |= Consumed;
+ ConsumedParameters.push_back(Consumed);
+ HasAnyConsumedParameters |= Consumed;
}
- ArgTys.push_back(ArgTy);
+ ParamTys.push_back(ParamTy);
}
- if (HasAnyConsumedArguments)
- EPI.ConsumedArguments = ConsumedArguments.data();
+ if (HasAnyConsumedParameters)
+ EPI.ConsumedParameters = ConsumedParameters.data();
SmallVector<QualType, 4> Exceptions;
SmallVector<ParsedType, 2> DynamicExceptions;
SmallVector<SourceRange, 2> DynamicExceptionRanges;
- Expr *NoexceptExpr = 0;
+ Expr *NoexceptExpr = nullptr;
if (FTI.getExceptionSpecType() == EST_Dynamic) {
// FIXME: It's rather inefficient to have to split into two vectors
@@ -3026,7 +2996,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
Exceptions,
EPI);
- T = Context.getFunctionType(T, ArgTys, EPI);
+ T = Context.getFunctionType(T, ParamTys, EPI);
}
break;
@@ -3040,8 +3010,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
D.setInvalidType(true);
} else if (S.isDependentScopeSpecifier(SS) ||
dyn_cast_or_null<CXXRecordDecl>(S.computeDeclContext(SS))) {
- NestedNameSpecifier *NNS
- = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+ NestedNameSpecifier *NNS = SS.getScopeRep();
NestedNameSpecifier *NNSPrefix = NNS->getPrefix();
switch (NNS->getKind()) {
case NestedNameSpecifier::Identifier:
@@ -3126,6 +3095,13 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// alias-declaration,
// - the type-id in the default argument of a type-parameter, or
// - the type-id of a template-argument for a type-parameter
+ //
+ // FIXME: Checking this here is insufficient. We accept-invalid on:
+ //
+ // template<typename T> struct S { void f(T); };
+ // S<int() const> s;
+ //
+ // ... for instance.
if (IsQualifiedFunction &&
!(!FreeFunction &&
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) &&
@@ -3165,7 +3141,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
EPI.TypeQuals = 0;
EPI.RefQualifier = RQ_None;
- T = Context.getFunctionType(FnTy->getResultType(), FnTy->getArgTypes(),
+ T = Context.getFunctionType(FnTy->getReturnType(), FnTy->getParamTypes(),
EPI);
// Rebuild any parens around the identifier in the function type.
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
@@ -3283,7 +3259,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
TypeProcessingState state(*this, D);
- TypeSourceInfo *ReturnTypeInfo = 0;
+ TypeSourceInfo *ReturnTypeInfo = nullptr;
QualType T = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo);
if (T.isNull())
return Context.getNullTypeSourceInfo();
@@ -3318,7 +3294,7 @@ static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state,
if (attr->getKind() == AttributeList::AT_ObjCOwnership)
return;
- const char *attrStr = 0;
+ const char *attrStr = nullptr;
switch (ownership) {
case Qualifiers::OCL_None: llvm_unreachable("no ownership!");
case Qualifiers::OCL_ExplicitNone: attrStr = "none"; break;
@@ -3337,7 +3313,7 @@ static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state,
// 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(),
+ /*scope*/ nullptr, SourceLocation(),
/*args*/ &Args, 1, AttributeList::AS_GNU);
spliceAttrIntoList(*attr, chunk.getAttrListRef());
@@ -3398,7 +3374,7 @@ static void transferARCOwnership(TypeProcessingState &state,
TypeSourceInfo *Sema::GetTypeForDeclaratorCast(Declarator &D, QualType FromTy) {
TypeProcessingState state(*this, D);
- TypeSourceInfo *ReturnTypeInfo = 0;
+ TypeSourceInfo *ReturnTypeInfo = nullptr;
QualType declSpecTy = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo);
if (declSpecTy.isNull())
return Context.getNullTypeSourceInfo();
@@ -3476,10 +3452,17 @@ static void fillAttributedTypeLoc(AttributedTypeLoc TL,
}
TL.setAttrNameLoc(attrs->getLoc());
- if (TL.hasAttrExprOperand() && attrs->isArgExpr(0))
+ if (TL.hasAttrExprOperand()) {
+ assert(attrs->isArgExpr(0) && "mismatched attribute operand kind");
TL.setAttrExprOperand(attrs->getArgAsExpr(0));
- else if (TL.hasAttrEnumOperand() && attrs->isArgIdent(0))
- TL.setAttrEnumOperandLoc(attrs->getArgAsIdent(0)->Loc);
+ } else if (TL.hasAttrEnumOperand()) {
+ assert((attrs->isArgIdent(0) || attrs->isArgExpr(0)) &&
+ "unexpected attribute operand kind");
+ if (attrs->isArgIdent(0))
+ TL.setAttrEnumOperandLoc(attrs->getArgAsIdent(0)->Loc);
+ else
+ TL.setAttrEnumOperandLoc(attrs->getArgAsExpr(0)->getExprLoc());
+ }
// FIXME: preserve this information to here.
if (TL.hasAttrOperand())
@@ -3541,7 +3524,7 @@ namespace {
Visit(TL.getPointeeLoc());
}
void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
- TypeSourceInfo *TInfo = 0;
+ TypeSourceInfo *TInfo = nullptr;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
// If we got no declarator info from previous Sema routines,
@@ -3573,7 +3556,7 @@ namespace {
TL.setTypeofLoc(DS.getTypeSpecTypeLoc());
TL.setParensRange(DS.getTypeofParensRange());
assert(DS.getRepAsType());
- TypeSourceInfo *TInfo = 0;
+ TypeSourceInfo *TInfo = nullptr;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
TL.setUnderlyingTInfo(TInfo);
}
@@ -3583,7 +3566,7 @@ namespace {
TL.setKWLoc(DS.getTypeSpecTypeLoc());
TL.setParensRange(DS.getTypeofParensRange());
assert(DS.getRepAsType());
- TypeSourceInfo *TInfo = 0;
+ TypeSourceInfo *TInfo = nullptr;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
TL.setUnderlyingTInfo(TInfo);
}
@@ -3606,7 +3589,7 @@ namespace {
ElaboratedTypeKeyword Keyword
= TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType());
if (DS.getTypeSpecType() == TST_typename) {
- TypeSourceInfo *TInfo = 0;
+ TypeSourceInfo *TInfo = nullptr;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
if (TInfo) {
TL.copy(TInfo->getTypeLoc().castAs<ElaboratedTypeLoc>());
@@ -3622,7 +3605,7 @@ namespace {
}
void VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
assert(DS.getTypeSpecType() == TST_typename);
- TypeSourceInfo *TInfo = 0;
+ TypeSourceInfo *TInfo = nullptr;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
assert(TInfo);
TL.copy(TInfo->getTypeLoc().castAs<DependentNameTypeLoc>());
@@ -3630,7 +3613,7 @@ namespace {
void VisitDependentTemplateSpecializationTypeLoc(
DependentTemplateSpecializationTypeLoc TL) {
assert(DS.getTypeSpecType() == TST_typename);
- TypeSourceInfo *TInfo = 0;
+ TypeSourceInfo *TInfo = nullptr;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
assert(TInfo);
TL.copy(
@@ -3646,7 +3629,7 @@ namespace {
TL.setKWLoc(DS.getTypeSpecTypeLoc());
TL.setParensRange(DS.getTypeofParensRange());
- TypeSourceInfo *TInfo = 0;
+ TypeSourceInfo *TInfo = nullptr;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
assert(TInfo);
TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc());
@@ -3682,6 +3665,9 @@ namespace {
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
fillAttributedTypeLoc(TL, Chunk.getAttrs());
}
+ void VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
+ // nothing
+ }
void VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
assert(Chunk.Kind == DeclaratorChunk::BlockPointer);
TL.setCaretLoc(Chunk.Loc);
@@ -3763,9 +3749,9 @@ namespace {
const DeclaratorChunk::FunctionTypeInfo &FTI = Chunk.Fun;
TL.setLParenLoc(FTI.getLParenLoc());
TL.setRParenLoc(FTI.getRParenLoc());
- for (unsigned i = 0, e = TL.getNumArgs(), tpi = 0; i != e; ++i) {
- ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param);
- TL.setArg(tpi++, Param);
+ for (unsigned i = 0, e = TL.getNumParams(), tpi = 0; i != e; ++i) {
+ ParmVarDecl *Param = cast<ParmVarDecl>(FTI.Params[i].Param);
+ TL.setParam(tpi++, Param);
}
// FIXME: exception specs
}
@@ -3837,6 +3823,10 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
}
+ // FIXME: Ordering here?
+ while (AdjustedTypeLoc TL = CurrTL.getAs<AdjustedTypeLoc>())
+ CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
+
DeclaratorLocFiller(Context, D.getTypeObject(i)).Visit(CurrTL);
CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc();
}
@@ -3877,7 +3867,8 @@ void LocInfoType::getAsStringInternal(std::string &Str,
TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
// C99 6.7.6: Type names have no identifier. This is already validated by
// the parser.
- assert(D.getIdentifier() == 0 && "Type name should have no identifier!");
+ assert(D.getIdentifier() == nullptr &&
+ "Type name should have no identifier!");
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType T = TInfo->getType();
@@ -3936,44 +3927,60 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
return;
}
- // Check the attribute arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
- << Attr.getName() << 1;
- Attr.setInvalid();
- return;
- }
- Expr *ASArgExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
- llvm::APSInt addrSpace(32);
- if (ASArgExpr->isTypeDependent() || ASArgExpr->isValueDependent() ||
- !ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
- << Attr.getName() << AANT_ArgumentIntegerConstant
- << ASArgExpr->getSourceRange();
- Attr.setInvalid();
- return;
- }
-
- // Bounds checking.
- if (addrSpace.isSigned()) {
- if (addrSpace.isNegative()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_address_space_negative)
+ unsigned ASIdx;
+ if (Attr.getKind() == AttributeList::AT_AddressSpace) {
+ // Check the attribute arguments.
+ if (Attr.getNumArgs() != 1) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
+ << Attr.getName() << 1;
+ Attr.setInvalid();
+ return;
+ }
+ Expr *ASArgExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
+ llvm::APSInt addrSpace(32);
+ if (ASArgExpr->isTypeDependent() || ASArgExpr->isValueDependent() ||
+ !ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
+ << Attr.getName() << AANT_ArgumentIntegerConstant
<< ASArgExpr->getSourceRange();
Attr.setInvalid();
return;
}
- addrSpace.setIsSigned(false);
- }
- llvm::APSInt max(addrSpace.getBitWidth());
- max = Qualifiers::MaxAddressSpace;
- if (addrSpace > max) {
- S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high)
- << int(Qualifiers::MaxAddressSpace) << ASArgExpr->getSourceRange();
- Attr.setInvalid();
- return;
- }
- unsigned ASIdx = static_cast<unsigned>(addrSpace.getZExtValue());
+ // Bounds checking.
+ if (addrSpace.isSigned()) {
+ if (addrSpace.isNegative()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_address_space_negative)
+ << ASArgExpr->getSourceRange();
+ Attr.setInvalid();
+ return;
+ }
+ addrSpace.setIsSigned(false);
+ }
+ llvm::APSInt max(addrSpace.getBitWidth());
+ max = Qualifiers::MaxAddressSpace;
+ if (addrSpace > max) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high)
+ << int(Qualifiers::MaxAddressSpace) << ASArgExpr->getSourceRange();
+ Attr.setInvalid();
+ return;
+ }
+ ASIdx = static_cast<unsigned>(addrSpace.getZExtValue());
+ } else {
+ // The keyword-based type attributes imply which address space to use.
+ switch (Attr.getKind()) {
+ case AttributeList::AT_OpenCLGlobalAddressSpace:
+ ASIdx = LangAS::opencl_global; break;
+ case AttributeList::AT_OpenCLLocalAddressSpace:
+ ASIdx = LangAS::opencl_local; break;
+ case AttributeList::AT_OpenCLConstantAddressSpace:
+ ASIdx = LangAS::opencl_constant; break;
+ default:
+ assert(Attr.getKind() == AttributeList::AT_OpenCLPrivateAddressSpace);
+ ASIdx = 0; break;
+ }
+ }
+
Type = S.Context.getAddrSpaceQualType(Type, ASIdx);
}
@@ -4266,7 +4273,7 @@ namespace {
} else {
const Type *DTy = Ty->getUnqualifiedDesugaredType();
if (Ty == DTy) {
- Fn = 0;
+ Fn = nullptr;
return;
}
@@ -4276,7 +4283,7 @@ namespace {
}
}
- bool isFunctionType() const { return (Fn != 0); }
+ bool isFunctionType() const { return (Fn != nullptr); }
const FunctionType *get() const { return Fn; }
QualType wrap(Sema &S, const FunctionType *New) {
@@ -4586,73 +4593,38 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
return true;
}
+bool Sema::hasExplicitCallingConv(QualType &T) {
+ QualType R = T.IgnoreParens();
+ while (const AttributedType *AT = dyn_cast<AttributedType>(R)) {
+ if (AT->isCallingConv())
+ return true;
+ R = AT->getModifiedType().IgnoreParens();
+ }
+ return false;
+}
+
void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic) {
- const FunctionType *FT = T->castAs<FunctionType>();
+ FunctionTypeUnwrapper Unwrapped(*this, T);
+ const FunctionType *FT = Unwrapped.get();
bool IsVariadic = (isa<FunctionProtoType>(FT) &&
cast<FunctionProtoType>(FT)->isVariadic());
- CallingConv CC = FT->getCallConv();
// Only adjust types with the default convention. For example, on Windows we
// should adjust a __cdecl type to __thiscall for instance methods, and a
// __thiscall type to __cdecl for static methods.
- CallingConv DefaultCC =
+ CallingConv CurCC = FT->getCallConv();
+ CallingConv FromCC =
Context.getDefaultCallingConvention(IsVariadic, IsStatic);
- if (CC != DefaultCC)
+ CallingConv ToCC = Context.getDefaultCallingConvention(IsVariadic, !IsStatic);
+ if (CurCC != FromCC || FromCC == ToCC)
return;
- // Check if there was an explicit attribute, but only look through parens.
- // The intent is to look for an attribute on the current declarator, but not
- // one that came from a typedef.
- QualType R = T.IgnoreParens();
- while (const AttributedType *AT = dyn_cast<AttributedType>(R)) {
- if (AT->isCallingConv())
- return;
- R = AT->getModifiedType().IgnoreParens();
- }
-
- // FIXME: This loses sugar. This should probably be fixed with an implicit
- // AttributedType node that adjusts the convention.
- CC = Context.getDefaultCallingConvention(IsVariadic, !IsStatic);
- FT = Context.adjustFunctionType(FT, FT->getExtInfo().withCallingConv(CC));
- FunctionTypeUnwrapper Unwrapped(*this, T);
- T = Unwrapped.wrap(*this, FT);
-}
-
-/// Handle OpenCL image access qualifiers: read_only, write_only, read_write
-static void HandleOpenCLImageAccessAttribute(QualType& CurType,
- const AttributeList &Attr,
- Sema &S) {
- // Check the attribute arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
- << Attr.getName() << 1;
- Attr.setInvalid();
- return;
- }
- Expr *sizeExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
- llvm::APSInt arg(32);
- if (sizeExpr->isTypeDependent() || sizeExpr->isValueDependent() ||
- !sizeExpr->isIntegerConstantExpr(arg, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
- << Attr.getName() << AANT_ArgumentIntegerConstant
- << sizeExpr->getSourceRange();
- Attr.setInvalid();
+ if (hasExplicitCallingConv(T))
return;
- }
- unsigned iarg = static_cast<unsigned>(arg.getZExtValue());
- switch (iarg) {
- case CLIA_read_only:
- case CLIA_write_only:
- case CLIA_read_write:
- // Implemented in a separate patch
- break;
- default:
- // Implemented in a separate patch
- S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size)
- << sizeExpr->getSourceRange();
- Attr.setInvalid();
- break;
- }
+
+ FT = Context.adjustFunctionType(FT, FT->getExtInfo().withCallingConv(ToCC));
+ QualType Wrapped = Unwrapped.wrap(*this, FT);
+ T = Context.getAdjustedType(T, Wrapped);
}
/// HandleVectorSizeAttribute - this attribute is only applicable to integral
@@ -4757,17 +4729,25 @@ static void HandleExtVectorTypeAttr(QualType &CurType,
}
static bool isPermittedNeonBaseType(QualType &Ty,
- VectorType::VectorKind VecKind,
- bool IsAArch64) {
+ VectorType::VectorKind VecKind, Sema &S) {
const BuiltinType *BTy = Ty->getAs<BuiltinType>();
if (!BTy)
return false;
+ llvm::Triple Triple = S.Context.getTargetInfo().getTriple();
+
+ // Signed poly is mathematically wrong, but has been baked into some ABIs by
+ // now.
+ bool IsPolyUnsigned = Triple.getArch() == llvm::Triple::aarch64 ||
+ Triple.getArch() == llvm::Triple::aarch64_be ||
+ Triple.getArch() == llvm::Triple::arm64 ||
+ Triple.getArch() == llvm::Triple::arm64_be;
if (VecKind == VectorType::NeonPolyVector) {
- if (IsAArch64) {
+ if (IsPolyUnsigned) {
// AArch64 polynomial vectors are unsigned and support poly64.
return BTy->getKind() == BuiltinType::UChar ||
BTy->getKind() == BuiltinType::UShort ||
+ BTy->getKind() == BuiltinType::ULong ||
BTy->getKind() == BuiltinType::ULongLong;
} else {
// AArch32 polynomial vector are signed.
@@ -4778,7 +4758,12 @@ static bool isPermittedNeonBaseType(QualType &Ty,
// Non-polynomial vector types: the usual suspects are allowed, as well as
// float64_t on AArch64.
- if (IsAArch64 && BTy->getKind() == BuiltinType::Double)
+ bool Is64Bit = Triple.getArch() == llvm::Triple::aarch64 ||
+ Triple.getArch() == llvm::Triple::aarch64_be ||
+ Triple.getArch() == llvm::Triple::arm64 ||
+ Triple.getArch() == llvm::Triple::arm64_be;
+
+ if (Is64Bit && BTy->getKind() == BuiltinType::Double)
return true;
return BTy->getKind() == BuiltinType::SChar ||
@@ -4787,6 +4772,8 @@ static bool isPermittedNeonBaseType(QualType &Ty,
BTy->getKind() == BuiltinType::UShort ||
BTy->getKind() == BuiltinType::Int ||
BTy->getKind() == BuiltinType::UInt ||
+ BTy->getKind() == BuiltinType::Long ||
+ BTy->getKind() == BuiltinType::ULong ||
BTy->getKind() == BuiltinType::LongLong ||
BTy->getKind() == BuiltinType::ULongLong ||
BTy->getKind() == BuiltinType::Float ||
@@ -4828,10 +4815,7 @@ static void HandleNeonVectorTypeAttr(QualType& CurType,
return;
}
// Only certain element types are supported for Neon vectors.
- llvm::Triple::ArchType Arch =
- S.Context.getTargetInfo().getTriple().getArch();
- if (!isPermittedNeonBaseType(CurType, VecKind,
- Arch == llvm::Triple::aarch64)) {
+ if (!isPermittedNeonBaseType(CurType, VecKind, S)) {
S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType;
Attr.setInvalid();
return;
@@ -4911,6 +4895,10 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
// it it breaks large amounts of Linux software.
attr.setUsedAsTypeAttr();
break;
+ case AttributeList::AT_OpenCLPrivateAddressSpace:
+ case AttributeList::AT_OpenCLGlobalAddressSpace:
+ case AttributeList::AT_OpenCLLocalAddressSpace:
+ case AttributeList::AT_OpenCLConstantAddressSpace:
case AttributeList::AT_AddressSpace:
HandleAddressSpaceTypeAttribute(type, attr, state.getSema());
attr.setUsedAsTypeAttr();
@@ -4939,13 +4927,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
attr.setUsedAsTypeAttr();
break;
case AttributeList::AT_OpenCLImageAccess:
- HandleOpenCLImageAccessAttribute(type, attr, state.getSema());
+ // FIXME: there should be some type checking happening here, I would
+ // imagine, but the original handler's checking was entirely superfluous.
attr.setUsedAsTypeAttr();
break;
- case AttributeList::AT_Win64:
- attr.setUsedAsTypeAttr();
- break;
MS_TYPE_ATTRS_CASELIST:
if (!handleMSPointerTypeQualifierAttr(state, attr, type))
attr.setUsedAsTypeAttr();
@@ -5058,7 +5044,7 @@ namespace {
TypeDiagnoserDiag(unsigned DiagID)
: Sema::TypeDiagnoser(DiagID == 0), DiagID(DiagID) {}
- virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) {
+ void diagnose(Sema &S, SourceLocation Loc, QualType T) override {
if (Suppressed) return;
S.Diag(Loc, DiagID) << T;
}
@@ -5100,6 +5086,108 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
return false;
}
+/// \brief Determine whether there is any declaration of \p D that was ever a
+/// definition (perhaps before module merging) and is currently visible.
+/// \param D The definition of the entity.
+/// \param Suggested Filled in with the declaration that should be made visible
+/// in order to provide a definition of this entity.
+static bool hasVisibleDefinition(Sema &S, NamedDecl *D, NamedDecl **Suggested) {
+ // Easy case: if we don't have modules, all declarations are visible.
+ if (!S.getLangOpts().Modules)
+ return true;
+
+ // If this definition was instantiated from a template, map back to the
+ // pattern from which it was instantiated.
+ //
+ // FIXME: There must be a better place for this to live.
+ if (auto *RD = dyn_cast<CXXRecordDecl>(D)) {
+ if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
+ auto From = TD->getInstantiatedFrom();
+ if (auto *CTD = From.dyn_cast<ClassTemplateDecl*>()) {
+ while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) {
+ if (NewCTD->isMemberSpecialization())
+ break;
+ CTD = NewCTD;
+ }
+ RD = CTD->getTemplatedDecl();
+ } else if (auto *CTPSD = From.dyn_cast<
+ ClassTemplatePartialSpecializationDecl *>()) {
+ while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) {
+ if (NewCTPSD->isMemberSpecialization())
+ break;
+ CTPSD = NewCTPSD;
+ }
+ RD = CTPSD;
+ }
+ } else if (isTemplateInstantiation(RD->getTemplateSpecializationKind())) {
+ while (auto *NewRD = RD->getInstantiatedFromMemberClass())
+ RD = NewRD;
+ }
+ D = RD->getDefinition();
+ } else if (auto *ED = dyn_cast<EnumDecl>(D)) {
+ while (auto *NewED = ED->getInstantiatedFromMemberEnum())
+ ED = NewED;
+ if (ED->isFixed()) {
+ // If the enum has a fixed underlying type, any declaration of it will do.
+ *Suggested = nullptr;
+ for (auto *Redecl : ED->redecls()) {
+ if (LookupResult::isVisible(S, Redecl))
+ return true;
+ if (Redecl->isThisDeclarationADefinition() ||
+ (Redecl->isCanonicalDecl() && !*Suggested))
+ *Suggested = Redecl;
+ }
+ return false;
+ }
+ D = ED->getDefinition();
+ }
+ assert(D && "missing definition for pattern of instantiated definition");
+
+ // FIXME: If we merged any other decl into D, and that declaration is visible,
+ // then we should consider a definition to be visible.
+ *Suggested = D;
+ return LookupResult::isVisible(S, D);
+}
+
+/// Locks in the inheritance model for the given class and all of its bases.
+static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) {
+ RD = RD->getMostRecentDecl();
+ if (!RD->hasAttr<MSInheritanceAttr>()) {
+ MSInheritanceAttr::Spelling IM;
+
+ switch (S.MSPointerToMemberRepresentationMethod) {
+ case LangOptions::PPTMK_BestCase:
+ IM = RD->calculateInheritanceModel();
+ break;
+ case LangOptions::PPTMK_FullGeneralitySingleInheritance:
+ IM = MSInheritanceAttr::Keyword_single_inheritance;
+ break;
+ case LangOptions::PPTMK_FullGeneralityMultipleInheritance:
+ IM = MSInheritanceAttr::Keyword_multiple_inheritance;
+ break;
+ case LangOptions::PPTMK_FullGeneralityVirtualInheritance:
+ IM = MSInheritanceAttr::Keyword_unspecified_inheritance;
+ break;
+ }
+
+ RD->addAttr(MSInheritanceAttr::CreateImplicit(
+ S.getASTContext(), IM,
+ /*BestCase=*/S.MSPointerToMemberRepresentationMethod ==
+ LangOptions::PPTMK_BestCase,
+ S.ImplicitMSInheritanceAttrLoc.isValid()
+ ? S.ImplicitMSInheritanceAttrLoc
+ : RD->getSourceRange()));
+ }
+
+ if (RD->hasDefinition()) {
+ // Assign inheritance models to all of the base classes, because now we can
+ // form pointers to members of base classes without calling
+ // RequireCompleteType on the pointer to member of the base class type.
+ for (const CXXBaseSpecifier &BS : RD->bases())
+ assignInheritanceModel(S, BS.getType()->getAsCXXRecordDecl());
+ }
+}
+
/// \brief The implementation of RequireCompleteType
bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
TypeDiagnoser &Diagnoser) {
@@ -5112,62 +5200,70 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
// "Can't ask whether a dependent type is complete");
// If we have a complete type, we're done.
- NamedDecl *Def = 0;
+ NamedDecl *Def = nullptr;
if (!T->isIncompleteType(&Def)) {
// If we know about the definition but it is not visible, complain.
- if (!Diagnoser.Suppressed && Def && !LookupResult::isVisible(*this, Def)) {
+ NamedDecl *SuggestedDef = nullptr;
+ if (!Diagnoser.Suppressed && Def &&
+ !hasVisibleDefinition(*this, Def, &SuggestedDef)) {
// Suppress this error outside of a SFINAE context if we've already
// emitted the error once for this type. There's no usefulness in
// repeating the diagnostic.
// FIXME: Add a Fix-It that imports the corresponding module or includes
// the header.
- Module *Owner = Def->getOwningModule();
+ Module *Owner = SuggestedDef->getOwningModule();
Diag(Loc, diag::err_module_private_definition)
<< T << Owner->getFullModuleName();
- Diag(Def->getLocation(), diag::note_previous_definition);
+ Diag(SuggestedDef->getLocation(), diag::note_previous_definition);
+
+ // Try to recover by implicitly importing this module.
+ createImplicitModuleImportForErrorRecovery(Loc, Owner);
+ }
- if (!isSFINAEContext()) {
- // Recover by implicitly importing this module.
- createImplicitModuleImport(Loc, Owner);
+ // We lock in the inheritance model once somebody has asked us to ensure
+ // that a pointer-to-member type is complete.
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>()) {
+ if (!MPTy->getClass()->isDependentType()) {
+ RequireCompleteType(Loc, QualType(MPTy->getClass(), 0), 0);
+ assignInheritanceModel(*this, MPTy->getMostRecentCXXRecordDecl());
+ }
}
}
return false;
}
- // FIXME: If there's an unimported definition of this type in a module (for
+ const TagType *Tag = T->getAs<TagType>();
+ const ObjCInterfaceType *IFace = T->getAs<ObjCInterfaceType>();
+
+ // If there's an unimported definition of this type in a module (for
// instance, because we forward declared it, then imported the definition),
// import that definition now.
+ //
// FIXME: What about other cases where an import extends a redeclaration
// chain for a declaration that can be accessed through a mechanism other
// than name lookup (eg, referenced in a template, or a variable whose type
// could be completed by the module)?
+ if (Tag || IFace) {
+ NamedDecl *D =
+ Tag ? static_cast<NamedDecl *>(Tag->getDecl()) : IFace->getDecl();
- const TagType *Tag = T->getAs<TagType>();
- const ObjCInterfaceType *IFace = 0;
-
- if (Tag) {
// Avoid diagnosing invalid decls as incomplete.
- if (Tag->getDecl()->isInvalidDecl())
+ if (D->isInvalidDecl())
return true;
// Give the external AST source a chance to complete the type.
- if (Tag->getDecl()->hasExternalLexicalStorage()) {
- Context.getExternalSource()->CompleteType(Tag->getDecl());
- if (!Tag->isIncompleteType())
- return false;
- }
- }
- else if ((IFace = T->getAs<ObjCInterfaceType>())) {
- // Avoid diagnosing invalid decls as incomplete.
- if (IFace->getDecl()->isInvalidDecl())
- return true;
+ if (auto *Source = Context.getExternalSource()) {
+ if (Tag)
+ Source->CompleteType(Tag->getDecl());
+ else
+ Source->CompleteType(IFace->getDecl());
- // Give the external AST source a chance to complete the type.
- if (IFace->getDecl()->hasExternalLexicalStorage()) {
- Context.getExternalSource()->CompleteType(IFace->getDecl());
- if (!IFace->isIncompleteType())
- return false;
+ // If the external source completed the type, go through the motions
+ // again to ensure we're allowed to use the completed type.
+ if (!T->isIncompleteType())
+ return RequireCompleteTypeImpl(Loc, T, Diagnoser);
}
}
@@ -5310,29 +5406,26 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
if (RD->getNumVBases()) {
Diag(RD->getLocation(), diag::note_non_literal_virtual_base)
<< getLiteralDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases();
- for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
- E = RD->vbases_end(); I != E; ++I)
- Diag(I->getLocStart(),
- diag::note_constexpr_virtual_base_here) << I->getSourceRange();
+ for (const auto &I : RD->vbases())
+ Diag(I.getLocStart(), diag::note_constexpr_virtual_base_here)
+ << I.getSourceRange();
} else if (!RD->isAggregate() && !RD->hasConstexprNonCopyMoveConstructor() &&
!RD->hasTrivialDefaultConstructor()) {
Diag(RD->getLocation(), diag::note_non_literal_no_constexpr_ctors) << RD;
} else if (RD->hasNonLiteralTypeFieldsOrBases()) {
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- if (!I->getType()->isLiteralType(Context)) {
- Diag(I->getLocStart(),
+ for (const auto &I : RD->bases()) {
+ if (!I.getType()->isLiteralType(Context)) {
+ Diag(I.getLocStart(),
diag::note_non_literal_base_class)
- << RD << I->getType() << I->getSourceRange();
+ << RD << I.getType() << I.getSourceRange();
return true;
}
}
- for (CXXRecordDecl::field_iterator I = RD->field_begin(),
- E = RD->field_end(); I != E; ++I) {
+ for (const auto *I : RD->fields()) {
if (!I->getType()->isLiteralType(Context) ||
I->getType().isVolatileQualified()) {
Diag(I->getLocation(), diag::note_non_literal_field)
- << RD << *I << I->getType()
+ << RD << I << I->getType()
<< I->getType().isVolatileQualified();
return true;
}
@@ -5368,11 +5461,11 @@ QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword,
return T;
NestedNameSpecifier *NNS;
if (SS.isValid())
- NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ NNS = SS.getScopeRep();
else {
if (Keyword == ETK_None)
return T;
- NNS = 0;
+ NNS = nullptr;
}
return Context.getElaboratedType(Keyword, NNS, T);
}
@@ -5380,7 +5473,7 @@ QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword,
QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) {
ExprResult ER = CheckPlaceholderExpr(E);
if (ER.isInvalid()) return QualType();
- E = ER.take();
+ E = ER.get();
if (!E->isTypeDependent()) {
QualType T = E->getType();
@@ -5460,7 +5553,7 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) {
QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) {
ExprResult ER = CheckPlaceholderExpr(E);
if (ER.isInvalid()) return QualType();
- E = ER.take();
+ E = ER.get();
return Context.getDecltypeType(E, getDecltypeForExpr(*this, E));
}
@@ -5476,12 +5569,23 @@ QualType Sema::BuildUnaryTransformType(QualType BaseType,
} else {
QualType Underlying = BaseType;
if (!BaseType->isDependentType()) {
+ // The enum could be incomplete if we're parsing its definition or
+ // recovering from an error.
+ NamedDecl *FwdDecl = nullptr;
+ if (BaseType->isIncompleteType(&FwdDecl)) {
+ Diag(Loc, diag::err_underlying_type_of_incomplete_enum) << BaseType;
+ Diag(FwdDecl->getLocation(), diag::note_forward_declaration) << FwdDecl;
+ return QualType();
+ }
+
EnumDecl *ED = BaseType->getAs<EnumType>()->getDecl();
assert(ED && "EnumType has no EnumDecl");
+
DiagnoseUseOfDecl(ED, Loc);
+
Underlying = ED->getIntegerType();
+ assert(!Underlying.isNull());
}
- assert(!Underlying.isNull());
return Context.getUnaryTransformType(BaseType, Underlying,
UnaryTransformType::EnumUnderlyingType);
}
diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp
deleted file mode 100644
index 45067dee9b8d..000000000000
--- a/lib/Sema/TargetAttributesSema.cpp
+++ /dev/null
@@ -1,353 +0,0 @@
-//===-- TargetAttributesSema.cpp - Encapsulate target attributes-*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file contains semantic analysis implementation for target-specific
-// attributes.
-//
-//===----------------------------------------------------------------------===//
-
-#include "TargetAttributesSema.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/Sema/SemaInternal.h"
-#include "llvm/ADT/Triple.h"
-
-using namespace clang;
-
-TargetAttributesSema::~TargetAttributesSema() {}
-bool TargetAttributesSema::ProcessDeclAttribute(Scope *scope, Decl *D,
- const AttributeList &Attr, Sema &S) const {
- return false;
-}
-
-static void HandleARMInterruptAttr(Decl *d,
- const AttributeList &Attr, Sema &S) {
- // Check the attribute arguments.
- if (Attr.getNumArgs() > 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments)
- << 1;
- return;
- }
-
- StringRef Str;
- SourceLocation ArgLoc;
-
- if (Attr.getNumArgs() == 0)
- Str = "";
- else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc))
- return;
-
- ARMInterruptAttr::InterruptType Kind;
- if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
- << Attr.getName() << Str << ArgLoc;
- return;
- }
-
- unsigned Index = Attr.getAttributeSpellingListIndex();
- d->addAttr(::new (S.Context)
- ARMInterruptAttr(Attr.getLoc(), S.Context, Kind, Index));
-}
-
-namespace {
- class ARMAttributesSema : public TargetAttributesSema {
- public:
- ARMAttributesSema() { }
- bool ProcessDeclAttribute(Scope *scope, Decl *D,
- const AttributeList &Attr, Sema &S) const {
- if (Attr.getName()->getName() == "interrupt") {
- HandleARMInterruptAttr(D, Attr, S);
- return true;
- }
- return false;
- }
- };
-}
-
-static void HandleMSP430InterruptAttr(Decl *d,
- const AttributeList &Attr, Sema &S) {
- // Check the attribute arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
- << Attr.getName() << 1;
- return;
- }
-
- // FIXME: Check for decl - it should be void ()(void).
-
- Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
- llvm::APSInt NumParams(32);
- if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
- << Attr.getName() << AANT_ArgumentIntegerConstant
- << NumParamsExpr->getSourceRange();
- return;
- }
-
- unsigned Num = NumParams.getLimitedValue(255);
- if ((Num & 1) || Num > 30) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << "interrupt" << (int)NumParams.getSExtValue()
- << NumParamsExpr->getSourceRange();
- return;
- }
-
- d->addAttr(::new (S.Context) MSP430InterruptAttr(Attr.getLoc(), S.Context, Num));
- d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
- }
-
-namespace {
- class MSP430AttributesSema : public TargetAttributesSema {
- public:
- MSP430AttributesSema() { }
- bool ProcessDeclAttribute(Scope *scope, Decl *D,
- const AttributeList &Attr, Sema &S) const {
- if (Attr.getName()->getName() == "interrupt") {
- HandleMSP430InterruptAttr(D, Attr, S);
- return true;
- }
- return false;
- }
- };
-}
-
-static void HandleX86ForceAlignArgPointerAttr(Decl *D,
- const AttributeList& Attr,
- Sema &S) {
- // Check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
- << Attr.getName() << 0;
- return;
- }
-
- // If we try to apply it to a function pointer, don't warn, but don't
- // do anything, either. It doesn't matter anyway, because there's nothing
- // special about calling a force_align_arg_pointer function.
- ValueDecl *VD = dyn_cast<ValueDecl>(D);
- if (VD && VD->getType()->isFunctionPointerType())
- return;
- // Also don't warn on function pointer typedefs.
- TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
- if (TD && (TD->getUnderlyingType()->isFunctionPointerType() ||
- TD->getUnderlyingType()->isFunctionType()))
- return;
- // Attribute can only be applied to function types.
- if (!isa<FunctionDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << /* function */0;
- return;
- }
-
- D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getRange(),
- S.Context));
-}
-
-DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range,
- unsigned AttrSpellingListIndex) {
- if (D->hasAttr<DLLExportAttr>()) {
- Diag(Range.getBegin(), diag::warn_attribute_ignored) << "dllimport";
- return NULL;
- }
-
- if (D->hasAttr<DLLImportAttr>())
- return NULL;
-
- if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
- if (VD->hasDefinition()) {
- // dllimport cannot be applied to definitions.
- Diag(D->getLocation(), diag::warn_attribute_invalid_on_definition)
- << "dllimport";
- return NULL;
- }
- }
-
- return ::new (Context) DLLImportAttr(Range, Context,
- AttrSpellingListIndex);
-}
-
-static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
- // check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
- << Attr.getName() << 0;
- return;
- }
-
- // Attribute can be applied only to functions or variables.
- FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (!FD && !isa<VarDecl>(D)) {
- // Apparently Visual C++ thinks it is okay to not emit a warning
- // in this case, so only emit a warning when -fms-extensions is not
- // specified.
- if (!S.getLangOpts().MicrosoftExt)
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 2 /*variable and function*/;
- return;
- }
-
- // Currently, the dllimport attribute is ignored for inlined functions.
- // Warning is emitted.
- if (FD && FD->isInlineSpecified()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
- return;
- }
-
- unsigned Index = Attr.getAttributeSpellingListIndex();
- DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange(), Index);
- if (NewAttr)
- D->addAttr(NewAttr);
-}
-
-DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range,
- unsigned AttrSpellingListIndex) {
- if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) {
- Diag(Import->getLocation(), diag::warn_attribute_ignored) << "dllimport";
- D->dropAttr<DLLImportAttr>();
- }
-
- if (D->hasAttr<DLLExportAttr>())
- return NULL;
-
- return ::new (Context) DLLExportAttr(Range, Context,
- AttrSpellingListIndex);
-}
-
-static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
- // check the attribute arguments.
- if (Attr.getNumArgs() != 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
- << Attr.getName() << 0;
- return;
- }
-
- // Attribute can be applied only to functions or variables.
- FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (!FD && !isa<VarDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 2 /*variable and function*/;
- return;
- }
-
- // Currently, the dllexport attribute is ignored for inlined functions, unless
- // the -fkeep-inline-functions flag has been used. Warning is emitted;
- if (FD && FD->isInlineSpecified()) {
- // FIXME: ... unless the -fkeep-inline-functions flag has been used.
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport";
- return;
- }
-
- unsigned Index = Attr.getAttributeSpellingListIndex();
- DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange(), Index);
- if (NewAttr)
- D->addAttr(NewAttr);
-}
-
-namespace {
- class X86AttributesSema : public TargetAttributesSema {
- public:
- X86AttributesSema() { }
- bool ProcessDeclAttribute(Scope *scope, Decl *D,
- const AttributeList &Attr, Sema &S) const {
- const llvm::Triple &Triple(S.Context.getTargetInfo().getTriple());
- if (Triple.getOS() == llvm::Triple::Win32 ||
- Triple.getOS() == llvm::Triple::MinGW32) {
- switch (Attr.getKind()) {
- case AttributeList::AT_DLLImport: HandleDLLImportAttr(D, Attr, S);
- return true;
- case AttributeList::AT_DLLExport: HandleDLLExportAttr(D, Attr, S);
- return true;
- default: break;
- }
- }
- if (Triple.getArch() != llvm::Triple::x86_64 &&
- (Attr.getName()->getName() == "force_align_arg_pointer" ||
- Attr.getName()->getName() == "__force_align_arg_pointer__")) {
- HandleX86ForceAlignArgPointerAttr(D, Attr, S);
- return true;
- }
- return false;
- }
- };
-}
-
-static void HandleMips16Attr(Decl *D, const AttributeList &Attr, Sema &S) {
- // check the attribute arguments.
- if (Attr.getNumArgs()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
- << Attr.getName() << 0;
- return;
- }
- // Attribute can only be applied to function types.
- if (!isa<FunctionDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName() << /* function */0;
- return;
- }
- D->addAttr(::new (S.Context) Mips16Attr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
-static void HandleNoMips16Attr(Decl *D, const AttributeList &Attr, Sema &S) {
- // check the attribute arguments.
- if (Attr.getNumArgs()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
- << Attr.getName() << 0;
- return;
- }
- // Attribute can only be applied to function types.
- if (!isa<FunctionDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
- << Attr.getName() << /* function */0;
- return;
- }
- D->addAttr(::new (S.Context)
- NoMips16Attr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
-}
-
-namespace {
- class MipsAttributesSema : public TargetAttributesSema {
- public:
- MipsAttributesSema() { }
- bool ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr,
- Sema &S) const {
- if (Attr.getName()->getName() == "mips16") {
- HandleMips16Attr(D, Attr, S);
- return true;
- } else if (Attr.getName()->getName() == "nomips16") {
- HandleNoMips16Attr(D, Attr, S);
- return true;
- }
- return false;
- }
- };
-}
-
-const TargetAttributesSema &Sema::getTargetAttributesSema() const {
- if (TheTargetAttributesSema)
- return *TheTargetAttributesSema;
-
- const llvm::Triple &Triple(Context.getTargetInfo().getTriple());
- switch (Triple.getArch()) {
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- return *(TheTargetAttributesSema = new ARMAttributesSema);
- case llvm::Triple::msp430:
- return *(TheTargetAttributesSema = new MSP430AttributesSema);
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- return *(TheTargetAttributesSema = new X86AttributesSema);
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- return *(TheTargetAttributesSema = new MipsAttributesSema);
- default:
- return *(TheTargetAttributesSema = new TargetAttributesSema);
- }
-}
diff --git a/lib/Sema/TargetAttributesSema.h b/lib/Sema/TargetAttributesSema.h
deleted file mode 100644
index 410c900222f6..000000000000
--- a/lib/Sema/TargetAttributesSema.h
+++ /dev/null
@@ -1,27 +0,0 @@
-//===--- TargetAttributesSema.h - Semantic Analysis For Target Attributes -===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef CLANG_SEMA_TARGETSEMA_H
-#define CLANG_SEMA_TARGETSEMA_H
-
-namespace clang {
- class Scope;
- class Decl;
- class AttributeList;
- class Sema;
-
- class TargetAttributesSema {
- public:
- virtual ~TargetAttributesSema();
- virtual bool ProcessDeclAttribute(Scope *scope, Decl *D,
- const AttributeList &Attr, Sema &S) const;
- };
-}
-
-#endif
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 4351c2530719..312811d2c008 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -25,7 +25,6 @@
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenMP.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Designator.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Ownership.h"
@@ -345,7 +344,7 @@ public:
/// TransformExpr or TransformExprs.
///
/// \returns the transformed initializer.
- ExprResult TransformInitializer(Expr *Init, bool CXXDirectInit);
+ ExprResult TransformInitializer(Expr *Init, bool NotCopyInit);
/// \brief Transform the given list of expressions.
///
@@ -372,7 +371,7 @@ public:
/// \returns true if an error occurred, false otherwise.
bool TransformExprs(Expr **Inputs, unsigned NumInputs, bool IsCall,
SmallVectorImpl<Expr *> &Outputs,
- bool *ArgChanged = 0);
+ bool *ArgChanged = nullptr);
/// \brief Transform the given declaration, which is referenced from a type
/// or expression.
@@ -434,10 +433,10 @@ public:
/// By default, transforms all of the types and declarations within the
/// nested-name-specifier. Subclasses may override this function to provide
/// alternate behavior.
- NestedNameSpecifierLoc TransformNestedNameSpecifierLoc(
- NestedNameSpecifierLoc NNS,
- QualType ObjectType = QualType(),
- NamedDecl *FirstQualifierInScope = 0);
+ NestedNameSpecifierLoc
+ TransformNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
+ QualType ObjectType = QualType(),
+ NamedDecl *FirstQualifierInScope = nullptr);
/// \brief Transform the given declaration name.
///
@@ -468,11 +467,11 @@ public:
/// By default, transforms the template name by transforming the declarations
/// and nested-name-specifiers that occur within the template name.
/// Subclasses may override this function to provide alternate behavior.
- TemplateName TransformTemplateName(CXXScopeSpec &SS,
- TemplateName Name,
- SourceLocation NameLoc,
- QualType ObjectType = QualType(),
- NamedDecl *FirstQualifierInScope = 0);
+ TemplateName
+ TransformTemplateName(CXXScopeSpec &SS, TemplateName Name,
+ SourceLocation NameLoc,
+ QualType ObjectType = QualType(),
+ NamedDecl *FirstQualifierInScope = nullptr);
/// \brief Transform the given template argument.
///
@@ -605,8 +604,16 @@ public:
}
ExprResult TransformAddressOfOperand(Expr *E);
+
ExprResult TransformDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E,
- bool IsAddressOfOperand);
+ bool IsAddressOfOperand,
+ TypeSourceInfo **RecoveryTSI);
+
+ ExprResult TransformParenDependentScopeDeclRefExpr(
+ ParenExpr *PE, DependentScopeDeclRefExpr *DRE, bool IsAddressOfOperand,
+ TypeSourceInfo **RecoveryTSI);
+
+ StmtResult TransformOMPExecutableDirective(OMPExecutableDirective *S);
// FIXME: We use LLVM_ATTRIBUTE_NOINLINE because inlining causes a ridiculous
// amount of stack usage with clang.
@@ -743,7 +750,7 @@ public:
/// By default, performs semantic analysis when building the function type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildFunctionProtoType(QualType T,
- llvm::MutableArrayRef<QualType> ParamTypes,
+ MutableArrayRef<QualType> ParamTypes,
const FunctionProtoType::ExtProtoInfo &EPI);
/// \brief Build a new unprototyped function type.
@@ -848,7 +855,8 @@ public:
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
TemplateName InstName
- = getDerived().RebuildTemplateName(SS, *Name, NameLoc, QualType(), 0);
+ = getDerived().RebuildTemplateName(SS, *Name, NameLoc, QualType(),
+ nullptr);
if (InstName.isNull())
return QualType();
@@ -866,7 +874,7 @@ public:
getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args);
if (T.isNull()) return QualType();
- if (Keyword == ETK_None && QualifierLoc.getNestedNameSpecifier() == 0)
+ if (Keyword == ETK_None && QualifierLoc.getNestedNameSpecifier() == nullptr)
return T;
return SemaRef.Context.getElaboratedType(Keyword,
@@ -912,7 +920,7 @@ public:
if (SemaRef.RequireCompleteDeclContext(SS, DC))
return QualType();
- TagDecl *Tag = 0;
+ TagDecl *Tag = nullptr;
SemaRef.LookupQualifiedName(Result, DC);
switch (Result.getResultKind()) {
case LookupResult::NotFound:
@@ -951,9 +959,8 @@ public:
break;
}
default:
- // FIXME: Would be nice to highlight just the source range.
SemaRef.Diag(IdLoc, diag::err_not_tag_in_scope)
- << Kind << Id << DC;
+ << Kind << Id << DC << QualifierLoc.getSourceRange();
break;
}
return QualType();
@@ -1080,7 +1087,7 @@ public:
SourceLocation ColonLoc,
Stmt *SubStmt) {
return getSema().ActOnDefaultStmt(DefaultLoc, ColonLoc, SubStmt,
- /*CurScope=*/0);
+ /*CurScope=*/nullptr);
}
/// \brief Build a new label statement.
@@ -1187,14 +1194,14 @@ public:
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
StmtResult RebuildReturnStmt(SourceLocation ReturnLoc, Expr *Result) {
- return getSema().ActOnReturnStmt(ReturnLoc, Result);
+ return getSema().BuildReturnStmt(ReturnLoc, Result);
}
/// \brief Build a new declaration statement.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildDeclStmt(llvm::MutableArrayRef<Decl *> Decls,
+ StmtResult RebuildDeclStmt(MutableArrayRef<Decl *> Decls,
SourceLocation StartLoc, SourceLocation EndLoc) {
Sema::DeclGroupPtrTy DG = getSema().BuildDeclaratorGroup(Decls);
return getSema().ActOnDeclStmt(DG, StartLoc, EndLoc);
@@ -1286,21 +1293,78 @@ public:
return getSema().BuildObjCAtThrowStmt(AtLoc, Operand);
}
- /// \brief Build a new OpenMP parallel directive.
+ /// \brief Build a new OpenMP executable directive.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildOMPParallelDirective(ArrayRef<OMPClause *> Clauses,
- Stmt *AStmt,
- SourceLocation StartLoc,
- SourceLocation EndLoc) {
- return getSema().ActOnOpenMPParallelDirective(Clauses, AStmt,
- StartLoc, EndLoc);
+ StmtResult RebuildOMPExecutableDirective(OpenMPDirectiveKind Kind,
+ DeclarationNameInfo DirName,
+ ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPExecutableDirective(Kind, DirName, Clauses,
+ AStmt, StartLoc, EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'if' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPIfClause(Expr *Condition,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPIfClause(Condition, StartLoc,
+ LParenLoc, EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'final' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPFinalClause(Expr *Condition, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPFinalClause(Condition, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'num_threads' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPNumThreadsClause(Expr *NumThreads,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPNumThreadsClause(NumThreads, StartLoc,
+ LParenLoc, EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'safelen' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPSafelenClause(Expr *Len, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPSafelenClause(Len, StartLoc, LParenLoc, EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'collapse' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPCollapseClause(Expr *Num, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPCollapseClause(Num, StartLoc, LParenLoc,
+ EndLoc);
}
/// \brief Build a new OpenMP 'default' clause.
///
- /// By default, performs semantic analysis to build the new statement.
+ /// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
OMPClause *RebuildOMPDefaultClause(OpenMPDefaultClauseKind Kind,
SourceLocation KindKwLoc,
@@ -1311,9 +1375,37 @@ public:
StartLoc, LParenLoc, EndLoc);
}
+ /// \brief Build a new OpenMP 'proc_bind' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPProcBindClause(OpenMPProcBindClauseKind Kind,
+ SourceLocation KindKwLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPProcBindClause(Kind, KindKwLoc,
+ StartLoc, LParenLoc, EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'schedule' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPScheduleClause(OpenMPScheduleClauseKind Kind,
+ Expr *ChunkSize,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation KindLoc,
+ SourceLocation CommaLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPScheduleClause(
+ Kind, ChunkSize, StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc);
+ }
+
/// \brief Build a new OpenMP 'private' clause.
///
- /// By default, performs semantic analysis to build the new statement.
+ /// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
OMPClause *RebuildOMPPrivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
@@ -1325,7 +1417,7 @@ public:
/// \brief Build a new OpenMP 'firstprivate' clause.
///
- /// By default, performs semantic analysis to build the new statement.
+ /// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
OMPClause *RebuildOMPFirstprivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
@@ -1335,6 +1427,22 @@ public:
EndLoc);
}
+ /// \brief Build a new OpenMP 'lastprivate' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPLastprivateClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPLastprivateClause(VarList, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'shared' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
OMPClause *RebuildOMPSharedClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
@@ -1343,6 +1451,84 @@ public:
EndLoc);
}
+ /// \brief Build a new OpenMP 'reduction' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPReductionClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation EndLoc,
+ CXXScopeSpec &ReductionIdScopeSpec,
+ const DeclarationNameInfo &ReductionId) {
+ return getSema().ActOnOpenMPReductionClause(
+ VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec,
+ ReductionId);
+ }
+
+ /// \brief Build a new OpenMP 'linear' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPLinearClause(VarList, Step, StartLoc, LParenLoc,
+ ColonLoc, EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'aligned' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPAlignedClause(ArrayRef<Expr *> VarList, Expr *Alignment,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPAlignedClause(VarList, Alignment, StartLoc,
+ LParenLoc, ColonLoc, EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'copyin' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPCopyinClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'copyprivate' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPCopyprivateClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPCopyprivateClause(VarList, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'flush' pseudo clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPFlushClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPFlushClause(VarList, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
/// \brief Rebuild the operand to an Objective-C \@synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
@@ -1386,7 +1572,7 @@ public:
if (ForEachStmt.isInvalid())
return StmtError();
- return getSema().FinishObjCForCollectionStmt(ForEachStmt.take(), Body);
+ return getSema().FinishObjCForCollectionStmt(ForEachStmt.get(), Body);
}
/// \brief Build a new C++ exception declaration.
@@ -1398,7 +1584,7 @@ public:
SourceLocation StartLoc,
SourceLocation IdLoc,
IdentifierInfo *Id) {
- VarDecl *Var = getSema().BuildExceptionDeclaration(0, Declarator,
+ VarDecl *Var = getSema().BuildExceptionDeclaration(nullptr, Declarator,
StartLoc, IdLoc, Id);
if (Var)
getSema().CurContext->addDecl(Var);
@@ -1479,8 +1665,10 @@ public:
}
StmtResult RebuildSEHTryStmt(bool IsCXXTry, SourceLocation TryLoc,
- Stmt *TryBlock, Stmt *Handler) {
- return getSema().ActOnSEHTryBlock(IsCXXTry, TryLoc, TryBlock, Handler);
+ Stmt *TryBlock, Stmt *Handler, int HandlerIndex,
+ int HandlerParentIndex) {
+ return getSema().ActOnSEHTryBlock(IsCXXTry, TryLoc, TryBlock, Handler,
+ HandlerIndex, HandlerParentIndex);
}
StmtResult RebuildSEHExceptStmt(SourceLocation Loc, Expr *FilterExpr,
@@ -1548,7 +1736,7 @@ public:
ExprResult RebuildUnaryOperator(SourceLocation OpLoc,
UnaryOperatorKind Opc,
Expr *SubExpr) {
- return getSema().BuildUnaryOp(/*Scope=*/0, OpLoc, Opc, SubExpr);
+ return getSema().BuildUnaryOp(/*Scope=*/nullptr, OpLoc, Opc, SubExpr);
}
/// \brief Build a new builtin offsetof expression.
@@ -1600,7 +1788,7 @@ public:
SourceLocation LBracketLoc,
Expr *RHS,
SourceLocation RBracketLoc) {
- return getSema().ActOnArraySubscriptExpr(/*Scope=*/0, LHS,
+ return getSema().ActOnArraySubscriptExpr(/*Scope=*/nullptr, LHS,
LBracketLoc, RHS,
RBracketLoc);
}
@@ -1612,8 +1800,8 @@ public:
ExprResult RebuildCallExpr(Expr *Callee, SourceLocation LParenLoc,
MultiExprArg Args,
SourceLocation RParenLoc,
- Expr *ExecConfig = 0) {
- return getSema().ActOnCallExpr(/*Scope=*/0, Callee, LParenLoc,
+ Expr *ExecConfig = nullptr) {
+ return getSema().ActOnCallExpr(/*Scope=*/nullptr, Callee, LParenLoc,
Args, RParenLoc, ExecConfig);
}
@@ -1641,25 +1829,25 @@ public:
"unnamed member not of record type?");
BaseResult =
- getSema().PerformObjectMemberConversion(BaseResult.take(),
+ getSema().PerformObjectMemberConversion(BaseResult.get(),
QualifierLoc.getNestedNameSpecifier(),
FoundDecl, Member);
if (BaseResult.isInvalid())
return ExprError();
- Base = BaseResult.take();
+ Base = BaseResult.get();
ExprValueKind VK = isArrow ? VK_LValue : Base->getValueKind();
MemberExpr *ME =
new (getSema().Context) MemberExpr(Base, isArrow,
Member, MemberNameInfo,
cast<FieldDecl>(Member)->getType(),
VK, OK_Ordinary);
- return getSema().Owned(ME);
+ return ME;
}
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
- Base = BaseResult.take();
+ Base = BaseResult.get();
QualType BaseType = Base->getType();
// FIXME: this involves duplicating earlier analysis in a lot of
@@ -1681,7 +1869,7 @@ public:
ExprResult RebuildBinaryOperator(SourceLocation OpLoc,
BinaryOperatorKind Opc,
Expr *LHS, Expr *RHS) {
- return getSema().BuildBinOp(/*Scope=*/0, OpLoc, Opc, LHS, RHS);
+ return getSema().BuildBinOp(/*Scope=*/nullptr, OpLoc, Opc, LHS, RHS);
}
/// \brief Build a new conditional operator expression.
@@ -1735,9 +1923,9 @@ public:
return getSema().BuildMemberReferenceExpr(Base, Base->getType(),
OpLoc, /*IsArrow*/ false,
SS, SourceLocation(),
- /*FirstQualifierInScope*/ 0,
+ /*FirstQualifierInScope*/ nullptr,
NameInfo,
- /* TemplateArgs */ 0);
+ /* TemplateArgs */ nullptr);
}
/// \brief Build a new initializer list expression.
@@ -1784,7 +1972,7 @@ public:
/// any semantic analysis. Subclasses may override this routine to provide
/// different behavior.
ExprResult RebuildImplicitValueInitExpr(QualType T) {
- return SemaRef.Owned(new (SemaRef.Context) ImplicitValueInitExpr(T));
+ return new (SemaRef.Context) ImplicitValueInitExpr(T);
}
/// \brief Build a new \c va_arg expression.
@@ -2049,9 +2237,7 @@ public:
QualType ThisType,
bool isImplicit) {
getSema().CheckCXXThisCapture(ThisLoc);
- return getSema().Owned(
- new (getSema().Context) CXXThisExpr(ThisLoc, ThisType,
- isImplicit));
+ return new (getSema().Context) CXXThisExpr(ThisLoc, ThisType, isImplicit);
}
/// \brief Build a new C++ throw expression.
@@ -2070,8 +2256,7 @@ public:
/// provide different behavior.
ExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc,
ParmVarDecl *Param) {
- return getSema().Owned(CXXDefaultArgExpr::Create(getSema().Context, Loc,
- Param));
+ return CXXDefaultArgExpr::Create(getSema().Context, Loc, Param);
}
/// \brief Build a new C++11 default-initialization expression.
@@ -2081,8 +2266,7 @@ public:
/// routine to provide different behavior.
ExprResult RebuildCXXDefaultInitExpr(SourceLocation Loc,
FieldDecl *Field) {
- return getSema().Owned(CXXDefaultInitExpr::Create(getSema().Context, Loc,
- Field));
+ return CXXDefaultInitExpr::Create(getSema().Context, Loc, Field);
}
/// \brief Build a new C++ zero-initialization expression.
@@ -2135,29 +2319,6 @@ public:
Operand);
}
- /// \brief Build a new unary type trait expression.
- ///
- /// By default, performs semantic analysis to build the new expression.
- /// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildUnaryTypeTrait(UnaryTypeTrait Trait,
- SourceLocation StartLoc,
- TypeSourceInfo *T,
- SourceLocation RParenLoc) {
- return getSema().BuildUnaryTypeTrait(Trait, StartLoc, T, RParenLoc);
- }
-
- /// \brief Build a new binary type trait expression.
- ///
- /// By default, performs semantic analysis to build the new expression.
- /// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildBinaryTypeTrait(BinaryTypeTrait Trait,
- SourceLocation StartLoc,
- TypeSourceInfo *LhsT,
- TypeSourceInfo *RhsT,
- SourceLocation RParenLoc) {
- return getSema().BuildBinaryTypeTrait(Trait, StartLoc, LhsT, RhsT, RParenLoc);
- }
-
/// \brief Build a new type trait expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -2202,16 +2363,17 @@ public:
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs,
- bool IsAddressOfOperand) {
+ bool IsAddressOfOperand,
+ TypeSourceInfo **RecoveryTSI) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
if (TemplateArgs || TemplateKWLoc.isValid())
- return getSema().BuildQualifiedTemplateIdExpr(SS, TemplateKWLoc,
- NameInfo, TemplateArgs);
+ return getSema().BuildQualifiedTemplateIdExpr(SS, TemplateKWLoc, NameInfo,
+ TemplateArgs);
- return getSema().BuildQualifiedDeclarationNameExpr(SS, NameInfo,
- IsAddressOfOperand);
+ return getSema().BuildQualifiedDeclarationNameExpr(
+ SS, NameInfo, IsAddressOfOperand, RecoveryTSI);
}
/// \brief Build a new template-id expression.
@@ -2238,6 +2400,7 @@ public:
MultiExprArg Args,
bool HadMultipleCandidates,
bool ListInitialization,
+ bool StdInitListInitialization,
bool RequiresZeroInit,
CXXConstructExpr::ConstructionKind ConstructKind,
SourceRange ParenRange) {
@@ -2250,6 +2413,7 @@ public:
ConvertedArgs,
HadMultipleCandidates,
ListInitialization,
+ StdInitListInitialization,
RequiresZeroInit, ConstructKind,
ParenRange);
}
@@ -2394,8 +2558,7 @@ public:
ExprResult RebuildObjCEncodeExpr(SourceLocation AtLoc,
TypeSourceInfo *EncodeTypeInfo,
SourceLocation RParenLoc) {
- return SemaRef.Owned(SemaRef.BuildObjCEncodeExpression(AtLoc, EncodeTypeInfo,
- RParenLoc));
+ return SemaRef.BuildObjCEncodeExpression(AtLoc, EncodeTypeInfo, RParenLoc);
}
/// \brief Build a new Objective-C class message.
@@ -2437,25 +2600,13 @@ public:
bool IsArrow, bool IsFreeIvar) {
// FIXME: We lose track of the IsFreeIvar bit.
CXXScopeSpec SS;
- ExprResult Base = getSema().Owned(BaseArg);
- LookupResult R(getSema(), Ivar->getDeclName(), IvarLoc,
- Sema::LookupMemberName);
- ExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow,
- /*FIME:*/IvarLoc,
- SS, 0,
- false);
- if (Result.isInvalid() || Base.isInvalid())
- return ExprError();
-
- if (Result.get())
- return Result;
-
- return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
+ DeclarationNameInfo NameInfo(Ivar->getDeclName(), IvarLoc);
+ return getSema().BuildMemberReferenceExpr(BaseArg, BaseArg->getType(),
/*FIXME:*/IvarLoc, IsArrow,
SS, SourceLocation(),
- /*FirstQualifierInScope=*/0,
- R,
- /*TemplateArgs=*/0);
+ /*FirstQualifierInScope=*/nullptr,
+ NameInfo,
+ /*TemplateArgs=*/nullptr);
}
/// \brief Build a new Objective-C property reference expression.
@@ -2466,25 +2617,14 @@ public:
ObjCPropertyDecl *Property,
SourceLocation PropertyLoc) {
CXXScopeSpec SS;
- ExprResult Base = getSema().Owned(BaseArg);
- LookupResult R(getSema(), Property->getDeclName(), PropertyLoc,
- Sema::LookupMemberName);
- bool IsArrow = false;
- ExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow,
- /*FIME:*/PropertyLoc,
- SS, 0, false);
- if (Result.isInvalid() || Base.isInvalid())
- return ExprError();
-
- if (Result.get())
- return Result;
-
- return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
- /*FIXME:*/PropertyLoc, IsArrow,
+ DeclarationNameInfo NameInfo(Property->getDeclName(), PropertyLoc);
+ return getSema().BuildMemberReferenceExpr(BaseArg, BaseArg->getType(),
+ /*FIXME:*/PropertyLoc,
+ /*IsArrow=*/false,
SS, SourceLocation(),
- /*FirstQualifierInScope=*/0,
- R,
- /*TemplateArgs=*/0);
+ /*FirstQualifierInScope=*/nullptr,
+ NameInfo,
+ /*TemplateArgs=*/nullptr);
}
/// \brief Build a new Objective-C property reference expression.
@@ -2508,27 +2648,15 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildObjCIsaExpr(Expr *BaseArg, SourceLocation IsaLoc,
- SourceLocation OpLoc,
- bool IsArrow) {
+ SourceLocation OpLoc, bool IsArrow) {
CXXScopeSpec SS;
- ExprResult Base = getSema().Owned(BaseArg);
- LookupResult R(getSema(), &getSema().Context.Idents.get("isa"), IsaLoc,
- Sema::LookupMemberName);
- ExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow,
- OpLoc,
- SS, 0, false);
- if (Result.isInvalid() || Base.isInvalid())
- return ExprError();
-
- if (Result.get())
- return Result;
-
- return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
+ DeclarationNameInfo NameInfo(&getSema().Context.Idents.get("isa"), IsaLoc);
+ return getSema().BuildMemberReferenceExpr(BaseArg, BaseArg->getType(),
OpLoc, IsArrow,
SS, SourceLocation(),
- /*FirstQualifierInScope=*/0,
- R,
- /*TemplateArgs=*/0);
+ /*FirstQualifierInScope=*/nullptr,
+ NameInfo,
+ /*TemplateArgs=*/nullptr);
}
/// \brief Build a new shuffle vector expression.
@@ -2552,17 +2680,15 @@ public:
VK_RValue, BuiltinLoc);
QualType CalleePtrTy = SemaRef.Context.getPointerType(Builtin->getType());
Callee = SemaRef.ImpCastExprToType(Callee, CalleePtrTy,
- CK_BuiltinFnToFnPtr).take();
+ CK_BuiltinFnToFnPtr).get();
// Build the CallExpr
- ExprResult TheCall = SemaRef.Owned(
- new (SemaRef.Context) CallExpr(SemaRef.Context, Callee, SubExprs,
- Builtin->getCallResultType(),
- Expr::getValueKindForType(Builtin->getResultType()),
- RParenLoc));
+ ExprResult TheCall = new (SemaRef.Context) CallExpr(
+ SemaRef.Context, Callee, SubExprs, Builtin->getCallResultType(),
+ Expr::getValueKindForType(Builtin->getReturnType()), RParenLoc);
// Type-check the __builtin_shufflevector expression.
- return SemaRef.SemaBuiltinShuffleVector(cast<CallExpr>(TheCall.take()));
+ return SemaRef.SemaBuiltinShuffleVector(cast<CallExpr>(TheCall.get()));
}
/// \brief Build a new convert vector expression.
@@ -2657,12 +2783,16 @@ private:
QualType ObjectType,
NamedDecl *FirstQualifierInScope,
CXXScopeSpec &SS);
+
+ TypeSourceInfo *TransformTSIInObjectScope(TypeLoc TL, QualType ObjectType,
+ NamedDecl *FirstQualifierInScope,
+ CXXScopeSpec &SS);
};
template<typename Derived>
StmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) {
if (!S)
- return SemaRef.Owned(S);
+ return S;
switch (S->getStmtClass()) {
case Stmt::NoStmtClass: break;
@@ -2688,7 +2818,7 @@ StmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) {
}
}
- return SemaRef.Owned(S);
+ return S;
}
template<typename Derived>
@@ -2712,7 +2842,7 @@ OMPClause *TreeTransform<Derived>::TransformOMPClause(OMPClause *S) {
template<typename Derived>
ExprResult TreeTransform<Derived>::TransformExpr(Expr *E) {
if (!E)
- return SemaRef.Owned(E);
+ return E;
switch (E->getStmtClass()) {
case Stmt::NoStmtClass: break;
@@ -2723,16 +2853,16 @@ ExprResult TreeTransform<Derived>::TransformExpr(Expr *E) {
#include "clang/AST/StmtNodes.inc"
}
- return SemaRef.Owned(E);
+ return E;
}
template<typename Derived>
ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
- bool CXXDirectInit) {
+ bool NotCopyInit) {
// Initializers are instantiated like expressions, except that various outer
// layers are stripped.
if (!Init)
- return SemaRef.Owned(Init);
+ return Init;
if (ExprWithCleanups *ExprTemp = dyn_cast<ExprWithCleanups>(Init))
Init = ExprTemp->getSubExpr();
@@ -2748,13 +2878,13 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
if (CXXStdInitializerListExpr *ILE =
dyn_cast<CXXStdInitializerListExpr>(Init))
- return TransformInitializer(ILE->getSubExpr(), CXXDirectInit);
+ return TransformInitializer(ILE->getSubExpr(), NotCopyInit);
- // If this is not a direct-initializer, we only need to reconstruct
+ // If this is copy-initialization, we only need to reconstruct
// InitListExprs. Other forms of copy-initialization will be a no-op if
// the initializer is already the right type.
CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init);
- if (!CXXDirectInit && !(Construct && Construct->isListInitialization()))
+ if (!NotCopyInit && !(Construct && Construct->isListInitialization()))
return getDerived().TransformExpr(Init);
// Revert value-initialization back to empty parens.
@@ -2774,10 +2904,15 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
if (!Construct || isa<CXXTemporaryObjectExpr>(Construct))
return getDerived().TransformExpr(Init);
+ // If the initialization implicitly converted an initializer list to a
+ // std::initializer_list object, unwrap the std::initializer_list too.
+ if (Construct && Construct->isStdInitListInitialization())
+ return TransformInitializer(Construct->getArg(0), NotCopyInit);
+
SmallVector<Expr*, 8> NewArgs;
bool ArgChanged = false;
if (getDerived().TransformExprs(Construct->getArgs(), Construct->getNumArgs(),
- /*IsCall*/true, NewArgs, &ArgChanged))
+ /*IsCall*/true, NewArgs, &ArgChanged))
return ExprError();
// If this was list initialization, revert to list form.
@@ -2788,6 +2923,13 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
// Build a ParenListExpr to represent anything else.
SourceRange Parens = Construct->getParenOrBraceRange();
+ if (Parens.isInvalid()) {
+ // This was a variable declaration's initialization for which no initializer
+ // was specified.
+ assert(NewArgs.empty() &&
+ "no parens or braces but have direct init with arguments?");
+ return ExprEmpty();
+ }
return getDerived().RebuildParenListExpr(Parens.getBegin(), NewArgs,
Parens.getEnd());
}
@@ -2860,9 +3002,11 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
if (Out.isInvalid())
return true;
+ // FIXME: Can this happen? We should not try to expand the pack
+ // in this case.
if (Out.get()->containsUnexpandedParameterPack()) {
- Out = RebuildPackExpansion(Out.get(), Expansion->getEllipsisLoc(),
- OrigNumExpansions);
+ Out = getDerived().RebuildPackExpansion(
+ Out.get(), Expansion->getEllipsisLoc(), OrigNumExpansions);
if (Out.isInvalid())
return true;
}
@@ -2870,6 +3014,23 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
Outputs.push_back(Out.get());
}
+ // If we're supposed to retain a pack expansion, do so by temporarily
+ // forgetting the partially-substituted parameter pack.
+ if (RetainExpansion) {
+ ForgetPartiallySubstitutedPackRAII Forget(getDerived());
+
+ ExprResult Out = getDerived().TransformExpr(Pattern);
+ if (Out.isInvalid())
+ return true;
+
+ Out = getDerived().RebuildPackExpansion(
+ Out.get(), Expansion->getEllipsisLoc(), OrigNumExpansions);
+ if (Out.isInvalid())
+ return true;
+
+ Outputs.push_back(Out.get());
+ }
+
continue;
}
@@ -2906,7 +3067,7 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
switch (QNNS->getKind()) {
case NestedNameSpecifier::Identifier:
- if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/0,
+ if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/nullptr,
*QNNS->getAsIdentifier(),
Q.getLocalBeginLoc(),
Q.getLocalEndLoc(),
@@ -2974,7 +3135,7 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
}
// The qualifier-in-scope and object type only apply to the leftmost entity.
- FirstQualifierInScope = 0;
+ FirstQualifierInScope = nullptr;
ObjectType = QualType();
}
@@ -3023,7 +3184,7 @@ TreeTransform<Derived>
NewCanTy = SemaRef.Context.getCanonicalType(NewTInfo->getType());
}
else {
- NewTInfo = 0;
+ NewTInfo = nullptr;
TemporaryBase Rebase(*this, NameInfo.getLoc(), Name);
QualType NewT = getDerived().TransformType(Name.getCXXNameType());
if (NewT.isNull())
@@ -3074,7 +3235,7 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
if (SS.getScopeRep()) {
// These apply to the scope specifier, not the template.
ObjectType = QualType();
- FirstQualifierInScope = 0;
+ FirstQualifierInScope = nullptr;
}
if (!getDerived().AlwaysRebuild() &&
@@ -3193,7 +3354,7 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
case TemplateArgument::Type: {
TypeSourceInfo *DI = Input.getTypeSourceInfo();
- if (DI == NULL)
+ if (!DI)
DI = InventTypeSourceInfo(Input.getArgument().getAsType());
DI = getDerived().TransformType(DI);
@@ -3238,7 +3399,7 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
ExprResult E = getDerived().TransformExpr(InputExpr);
E = SemaRef.ActOnConstantExpression(E);
if (E.isInvalid()) return true;
- Output = TemplateArgumentLoc(TemplateArgument(E.take()), E.take());
+ Output = TemplateArgumentLoc(TemplateArgument(E.get()), E.get());
return false;
}
}
@@ -3463,7 +3624,7 @@ TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI) {
QualType Result = getDerived().TransformType(TLB, TL);
if (Result.isNull())
- return 0;
+ return nullptr;
return TLB.getTypeSourceInfo(SemaRef.Context, Result);
}
@@ -3564,52 +3725,14 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL,
QualType ObjectType,
NamedDecl *UnqualLookup,
CXXScopeSpec &SS) {
- QualType T = TL.getType();
- if (getDerived().AlreadyTransformed(T))
+ if (getDerived().AlreadyTransformed(TL.getType()))
return TL;
- TypeLocBuilder TLB;
- QualType Result;
-
- if (isa<TemplateSpecializationType>(T)) {
- TemplateSpecializationTypeLoc SpecTL =
- TL.castAs<TemplateSpecializationTypeLoc>();
-
- TemplateName Template =
- getDerived().TransformTemplateName(SS,
- SpecTL.getTypePtr()->getTemplateName(),
- SpecTL.getTemplateNameLoc(),
- ObjectType, UnqualLookup);
- if (Template.isNull())
- return TypeLoc();
-
- Result = getDerived().TransformTemplateSpecializationType(TLB, SpecTL,
- Template);
- } else if (isa<DependentTemplateSpecializationType>(T)) {
- DependentTemplateSpecializationTypeLoc SpecTL =
- TL.castAs<DependentTemplateSpecializationTypeLoc>();
-
- TemplateName Template
- = getDerived().RebuildTemplateName(SS,
- *SpecTL.getTypePtr()->getIdentifier(),
- SpecTL.getTemplateNameLoc(),
- ObjectType, UnqualLookup);
- if (Template.isNull())
- return TypeLoc();
-
- Result = getDerived().TransformDependentTemplateSpecializationType(TLB,
- SpecTL,
- Template,
- SS);
- } else {
- // Nothing special needs to be done for these.
- Result = getDerived().TransformType(TLB, TL);
- }
-
- if (Result.isNull())
- return TypeLoc();
-
- return TLB.getTypeSourceInfo(SemaRef.Context, Result)->getTypeLoc();
+ TypeSourceInfo *TSI =
+ TransformTSIInObjectScope(TL, ObjectType, UnqualLookup, SS);
+ if (TSI)
+ return TSI->getTypeLoc();
+ return TypeLoc();
}
template<typename Derived>
@@ -3618,16 +3741,23 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
QualType ObjectType,
NamedDecl *UnqualLookup,
CXXScopeSpec &SS) {
- // FIXME: Painfully copy-paste from the above!
-
- QualType T = TSInfo->getType();
- if (getDerived().AlreadyTransformed(T))
+ if (getDerived().AlreadyTransformed(TSInfo->getType()))
return TSInfo;
+ return TransformTSIInObjectScope(TSInfo->getTypeLoc(), ObjectType,
+ UnqualLookup, SS);
+}
+
+template <typename Derived>
+TypeSourceInfo *TreeTransform<Derived>::TransformTSIInObjectScope(
+ TypeLoc TL, QualType ObjectType, NamedDecl *UnqualLookup,
+ CXXScopeSpec &SS) {
+ QualType T = TL.getType();
+ assert(!getDerived().AlreadyTransformed(T));
+
TypeLocBuilder TLB;
QualType Result;
- TypeLoc TL = TSInfo->getTypeLoc();
if (isa<TemplateSpecializationType>(T)) {
TemplateSpecializationTypeLoc SpecTL =
TL.castAs<TemplateSpecializationTypeLoc>();
@@ -3638,7 +3768,7 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
SpecTL.getTemplateNameLoc(),
ObjectType, UnqualLookup);
if (Template.isNull())
- return 0;
+ return nullptr;
Result = getDerived().TransformTemplateSpecializationType(TLB, SpecTL,
Template);
@@ -3652,7 +3782,7 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
SpecTL.getTemplateNameLoc(),
ObjectType, UnqualLookup);
if (Template.isNull())
- return 0;
+ return nullptr;
Result = getDerived().TransformDependentTemplateSpecializationType(TLB,
SpecTL,
@@ -3664,7 +3794,7 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
}
if (Result.isNull())
- return 0;
+ return nullptr;
return TLB.getTypeSourceInfo(SemaRef.Context, Result);
}
@@ -3693,6 +3823,13 @@ QualType TreeTransform<Derived>::TransformComplexType(TypeLocBuilder &TLB,
return TransformTypeSpecType(TLB, T);
}
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformAdjustedType(TypeLocBuilder &TLB,
+ AdjustedTypeLoc TL) {
+ // Adjustments applied during transformation are handled elsewhere.
+ return getDerived().TransformType(TLB, TL.getOriginalLoc());
+}
+
template<typename Derived>
QualType TreeTransform<Derived>::TransformDecayedType(TypeLocBuilder &TLB,
DecayedTypeLoc TL) {
@@ -3833,7 +3970,7 @@ TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB,
return QualType();
TypeSourceInfo* OldClsTInfo = TL.getClassTInfo();
- TypeSourceInfo* NewClsTInfo = 0;
+ TypeSourceInfo *NewClsTInfo = nullptr;
if (OldClsTInfo) {
NewClsTInfo = getDerived().TransformType(OldClsTInfo);
if (!NewClsTInfo)
@@ -3861,6 +3998,14 @@ TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB,
return QualType();
}
+ // If we had to adjust the pointee type when building a member pointer, make
+ // sure to push TypeLoc info for it.
+ const MemberPointerType *MPT = Result->getAs<MemberPointerType>();
+ if (MPT && PointeeType != MPT->getPointeeType()) {
+ assert(isa<AdjustedType>(MPT->getPointeeType()));
+ TLB.push<AdjustedTypeLoc>(MPT->getPointeeType());
+ }
+
MemberPointerTypeLoc NewTL = TLB.push<MemberPointerTypeLoc>(Result);
NewTL.setSigilLoc(TL.getSigilLoc());
NewTL.setClassTInfo(NewClsTInfo);
@@ -3901,8 +4046,8 @@ TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB,
if (Size) {
EnterExpressionEvaluationContext Unevaluated(SemaRef,
Sema::ConstantEvaluated);
- Size = getDerived().TransformExpr(Size).template takeAs<Expr>();
- Size = SemaRef.ActOnConstantExpression(Size).take();
+ Size = getDerived().TransformExpr(Size).template getAs<Expr>();
+ Size = SemaRef.ActOnConstantExpression(Size).get();
}
NewTL.setSizeExpr(Size);
@@ -3932,7 +4077,7 @@ QualType TreeTransform<Derived>::TransformIncompleteArrayType(
IncompleteArrayTypeLoc NewTL = TLB.push<IncompleteArrayTypeLoc>(Result);
NewTL.setLBracketLoc(TL.getLBracketLoc());
NewTL.setRBracketLoc(TL.getRBracketLoc());
- NewTL.setSizeExpr(0);
+ NewTL.setSizeExpr(nullptr);
return Result;
}
@@ -3951,7 +4096,7 @@ TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB,
if (SizeResult.isInvalid())
return QualType();
- Expr *Size = SizeResult.take();
+ Expr *Size = SizeResult.get();
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
@@ -3966,7 +4111,9 @@ TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB,
return QualType();
}
- VariableArrayTypeLoc NewTL = TLB.push<VariableArrayTypeLoc>(Result);
+ // We might have constant size array now, but fortunately it has the same
+ // location layout.
+ ArrayTypeLoc NewTL = TLB.push<ArrayTypeLoc>(Result);
NewTL.setLBracketLoc(TL.getLBracketLoc());
NewTL.setRBracketLoc(TL.getRBracketLoc());
NewTL.setSizeExpr(Size);
@@ -4047,7 +4194,7 @@ QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType(
ElementType != T->getElementType() ||
Size.get() != T->getSizeExpr()) {
Result = getDerived().RebuildDependentSizedExtVectorType(ElementType,
- Size.take(),
+ Size.get(),
T->getAttributeLoc());
if (Result.isNull())
return QualType();
@@ -4118,7 +4265,7 @@ ParmVarDecl *TreeTransform<Derived>::TransformFunctionTypeParam(
ParmVarDecl *OldParm, int indexAdjustment, Optional<unsigned> NumExpansions,
bool ExpectParameterPack) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
- TypeSourceInfo *NewDI = 0;
+ TypeSourceInfo *NewDI = nullptr;
if (NumExpansions && isa<PackExpansionType>(OldDI->getType())) {
// If we're substituting into a pack expansion type and we know the
@@ -4133,14 +4280,14 @@ ParmVarDecl *TreeTransform<Derived>::TransformFunctionTypeParam(
QualType Result = getDerived().TransformType(TLB,
OldExpansionTL.getPatternLoc());
if (Result.isNull())
- return 0;
+ return nullptr;
Result = RebuildPackExpansionType(Result,
OldExpansionTL.getPatternLoc().getSourceRange(),
OldExpansionTL.getEllipsisLoc(),
NumExpansions);
if (Result.isNull())
- return 0;
+ return nullptr;
PackExpansionTypeLoc NewExpansionTL
= TLB.push<PackExpansionTypeLoc>(Result);
@@ -4149,7 +4296,7 @@ ParmVarDecl *TreeTransform<Derived>::TransformFunctionTypeParam(
} else
NewDI = getDerived().TransformType(OldDI);
if (!NewDI)
- return 0;
+ return nullptr;
if (NewDI == OldDI && indexAdjustment == 0)
return OldParm;
@@ -4162,7 +4309,7 @@ ParmVarDecl *TreeTransform<Derived>::TransformFunctionTypeParam(
NewDI->getType(),
NewDI,
OldParm->getStorageClass(),
- /* DefArg */ NULL);
+ /* DefArg */ nullptr);
newParm->setScopeInfo(OldParm->getFunctionScopeDepth(),
OldParm->getFunctionScopeIndex() + indexAdjustment);
return newParm;
@@ -4182,7 +4329,7 @@ bool TreeTransform<Derived>::
assert(OldParm->getFunctionScopeIndex() == i);
Optional<unsigned> NumExpansions;
- ParmVarDecl *NewParm = 0;
+ ParmVarDecl *NewParm = nullptr;
if (OldParm->isParameterPack()) {
// We have a function parameter pack that may need to be expanded.
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
@@ -4311,7 +4458,7 @@ bool TreeTransform<Derived>::
OutParamTypes.push_back(NewType);
if (PVars)
- PVars->push_back(0);
+ PVars->push_back(nullptr);
}
// We're done with the pack expansion.
@@ -4328,7 +4475,7 @@ bool TreeTransform<Derived>::
OutParamTypes.push_back(NewType);
if (PVars)
- PVars->push_back(0);
+ PVars->push_back(nullptr);
}
// We'll substitute the parameter now without expanding the pack
@@ -4350,7 +4497,7 @@ bool TreeTransform<Derived>::
OutParamTypes.push_back(NewType);
if (PVars)
- PVars->push_back(0);
+ PVars->push_back(nullptr);
}
#ifndef NDEBUG
@@ -4368,7 +4515,7 @@ template<typename Derived>
QualType
TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
FunctionProtoTypeLoc TL) {
- return getDerived().TransformFunctionProtoType(TLB, TL, 0, 0);
+ return getDerived().TransformFunctionProtoType(TLB, TL, nullptr, 0);
}
template<typename Derived>
@@ -4391,11 +4538,9 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
QualType ResultType;
if (T->hasTrailingReturn()) {
- if (getDerived().TransformFunctionTypeParams(TL.getBeginLoc(),
- TL.getParmArray(),
- TL.getNumArgs(),
- TL.getTypePtr()->arg_type_begin(),
- ParamTypes, &ParamDecls))
+ if (getDerived().TransformFunctionTypeParams(
+ TL.getBeginLoc(), TL.getParmArray(), TL.getNumParams(),
+ TL.getTypePtr()->param_type_begin(), ParamTypes, &ParamDecls))
return QualType();
{
@@ -4407,31 +4552,29 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
// declarator.
Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals);
- ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
+ ResultType = getDerived().TransformType(TLB, TL.getReturnLoc());
if (ResultType.isNull())
return QualType();
}
}
else {
- ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
+ ResultType = getDerived().TransformType(TLB, TL.getReturnLoc());
if (ResultType.isNull())
return QualType();
- if (getDerived().TransformFunctionTypeParams(TL.getBeginLoc(),
- TL.getParmArray(),
- TL.getNumArgs(),
- TL.getTypePtr()->arg_type_begin(),
- ParamTypes, &ParamDecls))
+ if (getDerived().TransformFunctionTypeParams(
+ TL.getBeginLoc(), TL.getParmArray(), TL.getNumParams(),
+ TL.getTypePtr()->param_type_begin(), ParamTypes, &ParamDecls))
return QualType();
}
// FIXME: Need to transform the exception-specification too.
QualType Result = TL.getType();
- if (getDerived().AlwaysRebuild() ||
- ResultType != T->getResultType() ||
- T->getNumArgs() != ParamTypes.size() ||
- !std::equal(T->arg_type_begin(), T->arg_type_end(), ParamTypes.begin())) {
+ if (getDerived().AlwaysRebuild() || ResultType != T->getReturnType() ||
+ T->getNumParams() != ParamTypes.size() ||
+ !std::equal(T->param_type_begin(), T->param_type_end(),
+ ParamTypes.begin())) {
Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes,
T->getExtProtoInfo());
if (Result.isNull())
@@ -4443,8 +4586,8 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
NewTL.setLParenLoc(TL.getLParenLoc());
NewTL.setRParenLoc(TL.getRParenLoc());
NewTL.setLocalRangeEnd(TL.getLocalRangeEnd());
- for (unsigned i = 0, e = NewTL.getNumArgs(); i != e; ++i)
- NewTL.setArg(i, ParamDecls[i]);
+ for (unsigned i = 0, e = NewTL.getNumParams(); i != e; ++i)
+ NewTL.setParam(i, ParamDecls[i]);
return Result;
}
@@ -4454,13 +4597,12 @@ QualType TreeTransform<Derived>::TransformFunctionNoProtoType(
TypeLocBuilder &TLB,
FunctionNoProtoTypeLoc TL) {
const FunctionNoProtoType *T = TL.getTypePtr();
- QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
+ QualType ResultType = getDerived().TransformType(TLB, TL.getReturnLoc());
if (ResultType.isNull())
return QualType();
QualType Result = TL.getType();
- if (getDerived().AlwaysRebuild() ||
- ResultType != T->getResultType())
+ if (getDerived().AlwaysRebuild() || ResultType != T->getReturnType())
Result = getDerived().RebuildFunctionNoProtoType(ResultType);
FunctionNoProtoTypeLoc NewTL = TLB.push<FunctionNoProtoTypeLoc>(Result);
@@ -4541,7 +4683,7 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
if (Result.isNull())
return QualType();
}
- else E.take();
+ else E.get();
TypeOfExprTypeLoc NewTL = TLB.push<TypeOfExprTypeLoc>(Result);
NewTL.setTypeofLoc(TL.getTypeofLoc());
@@ -4581,14 +4723,14 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
const DecltypeType *T = TL.getTypePtr();
// decltype expressions are not potentially evaluated contexts
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated, 0,
- /*IsDecltype=*/ true);
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated,
+ nullptr, /*IsDecltype=*/ true);
ExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr());
if (E.isInvalid())
return QualType();
- E = getSema().ActOnDecltypeExpression(E.take());
+ E = getSema().ActOnDecltypeExpression(E.get());
if (E.isInvalid())
return QualType();
@@ -4599,7 +4741,7 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
if (Result.isNull())
return QualType();
}
- else E.take();
+ else E.get();
DecltypeTypeLoc NewTL = TLB.push<DecltypeTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
@@ -5266,7 +5408,7 @@ TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB,
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformNullStmt(NullStmt *S) {
- return SemaRef.Owned(S);
+ return S;
}
template<typename Derived>
@@ -5284,13 +5426,12 @@ TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S,
bool SubStmtInvalid = false;
bool SubStmtChanged = false;
SmallVector<Stmt*, 8> Statements;
- for (CompoundStmt::body_iterator B = S->body_begin(), BEnd = S->body_end();
- B != BEnd; ++B) {
- StmtResult Result = getDerived().TransformStmt(*B);
+ for (auto *B : S->body()) {
+ StmtResult Result = getDerived().TransformStmt(B);
if (Result.isInvalid()) {
// Immediately fail if this was a DeclStmt, since it's very
// likely that this will cause problems for future statements.
- if (isa<DeclStmt>(*B))
+ if (isa<DeclStmt>(B))
return StmtError();
// Otherwise, just keep processing substatements and fail later.
@@ -5298,8 +5439,8 @@ TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S,
continue;
}
- SubStmtChanged = SubStmtChanged || Result.get() != *B;
- Statements.push_back(Result.takeAs<Stmt>());
+ SubStmtChanged = SubStmtChanged || Result.get() != B;
+ Statements.push_back(Result.getAs<Stmt>());
}
if (SubStmtInvalid)
@@ -5307,7 +5448,7 @@ TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S,
if (!getDerived().AlwaysRebuild() &&
!SubStmtChanged)
- return SemaRef.Owned(S);
+ return S;
return getDerived().RebuildCompoundStmt(S->getLBracLoc(),
Statements,
@@ -5409,7 +5550,7 @@ StmtResult
TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
// Transform the condition
ExprResult Cond;
- VarDecl *ConditionVar = 0;
+ VarDecl *ConditionVar = nullptr;
if (S->getConditionVariable()) {
ConditionVar
= cast_or_null<VarDecl>(
@@ -5426,7 +5567,7 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
// Convert the condition to a boolean value.
if (S->getCond()) {
- ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getIfLoc(),
+ ExprResult CondE = getSema().ActOnBooleanCondition(nullptr, S->getIfLoc(),
Cond.get());
if (CondE.isInvalid())
return StmtError();
@@ -5435,7 +5576,7 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
}
}
- Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.take()));
+ Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.get()));
if (!S->getConditionVariable() && S->getCond() && !FullCond.get())
return StmtError();
@@ -5454,7 +5595,7 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
ConditionVar == S->getConditionVariable() &&
Then.get() == S->getThen() &&
Else.get() == S->getElse())
- return SemaRef.Owned(S);
+ return S;
return getDerived().RebuildIfStmt(S->getIfLoc(), FullCond, ConditionVar,
Then.get(),
@@ -5466,7 +5607,7 @@ StmtResult
TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) {
// Transform the condition.
ExprResult Cond;
- VarDecl *ConditionVar = 0;
+ VarDecl *ConditionVar = nullptr;
if (S->getConditionVariable()) {
ConditionVar
= cast_or_null<VarDecl>(
@@ -5504,7 +5645,7 @@ StmtResult
TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
// Transform the condition
ExprResult Cond;
- VarDecl *ConditionVar = 0;
+ VarDecl *ConditionVar = nullptr;
if (S->getConditionVariable()) {
ConditionVar
= cast_or_null<VarDecl>(
@@ -5521,7 +5662,8 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
if (S->getCond()) {
// Convert the condition to a boolean value.
- ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getWhileLoc(),
+ ExprResult CondE = getSema().ActOnBooleanCondition(nullptr,
+ S->getWhileLoc(),
Cond.get());
if (CondE.isInvalid())
return StmtError();
@@ -5529,7 +5671,7 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
}
}
- Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.take()));
+ Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.get()));
if (!S->getConditionVariable() && S->getCond() && !FullCond.get())
return StmtError();
@@ -5564,7 +5706,7 @@ TreeTransform<Derived>::TransformDoStmt(DoStmt *S) {
if (!getDerived().AlwaysRebuild() &&
Cond.get() == S->getCond() &&
Body.get() == S->getBody())
- return SemaRef.Owned(S);
+ return S;
return getDerived().RebuildDoStmt(S->getDoLoc(), Body.get(), S->getWhileLoc(),
/*FIXME:*/S->getWhileLoc(), Cond.get(),
@@ -5581,7 +5723,7 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
// Transform the condition
ExprResult Cond;
- VarDecl *ConditionVar = 0;
+ VarDecl *ConditionVar = nullptr;
if (S->getConditionVariable()) {
ConditionVar
= cast_or_null<VarDecl>(
@@ -5598,7 +5740,8 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
if (S->getCond()) {
// Convert the condition to a boolean value.
- ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getForLoc(),
+ ExprResult CondE = getSema().ActOnBooleanCondition(nullptr,
+ S->getForLoc(),
Cond.get());
if (CondE.isInvalid())
return StmtError();
@@ -5607,7 +5750,7 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
}
}
- Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.take()));
+ Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.get()));
if (!S->getConditionVariable() && S->getCond() && !FullCond.get())
return StmtError();
@@ -5630,7 +5773,7 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
FullCond.get() == S->getCond() &&
Inc.get() == S->getInc() &&
Body.get() == S->getBody())
- return SemaRef.Owned(S);
+ return S;
return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(),
Init.get(), FullCond, ConditionVar,
@@ -5656,11 +5799,11 @@ TreeTransform<Derived>::TransformIndirectGotoStmt(IndirectGotoStmt *S) {
ExprResult Target = getDerived().TransformExpr(S->getTarget());
if (Target.isInvalid())
return StmtError();
- Target = SemaRef.MaybeCreateExprWithCleanups(Target.take());
+ Target = SemaRef.MaybeCreateExprWithCleanups(Target.get());
if (!getDerived().AlwaysRebuild() &&
Target.get() == S->getTarget())
- return SemaRef.Owned(S);
+ return S;
return getDerived().RebuildIndirectGotoStmt(S->getGotoLoc(), S->getStarLoc(),
Target.get());
@@ -5669,13 +5812,13 @@ TreeTransform<Derived>::TransformIndirectGotoStmt(IndirectGotoStmt *S) {
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformContinueStmt(ContinueStmt *S) {
- return SemaRef.Owned(S);
+ return S;
}
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformBreakStmt(BreakStmt *S) {
- return SemaRef.Owned(S);
+ return S;
}
template<typename Derived>
@@ -5695,21 +5838,19 @@ StmtResult
TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) {
bool DeclChanged = false;
SmallVector<Decl *, 4> Decls;
- for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
- D != DEnd; ++D) {
- Decl *Transformed = getDerived().TransformDefinition((*D)->getLocation(),
- *D);
+ for (auto *D : S->decls()) {
+ Decl *Transformed = getDerived().TransformDefinition(D->getLocation(), D);
if (!Transformed)
return StmtError();
- if (Transformed != *D)
+ if (Transformed != D)
DeclChanged = true;
Decls.push_back(Transformed);
}
if (!getDerived().AlwaysRebuild() && !DeclChanged)
- return SemaRef.Owned(S);
+ return S;
return getDerived().RebuildDeclStmt(Decls, S->getStartLoc(), S->getEndLoc());
}
@@ -5764,14 +5905,14 @@ TreeTransform<Derived>::TransformGCCAsmStmt(GCCAsmStmt *S) {
}
if (!getDerived().AlwaysRebuild() && !ExprsChanged)
- return SemaRef.Owned(S);
+ return S;
// Go through the clobbers.
for (unsigned I = 0, E = S->getNumClobbers(); I != E; ++I)
Clobbers.push_back(S->getClobberStringLiteral(I));
// No need to transform the asm string literal.
- AsmString = SemaRef.Owned(S->getAsmString());
+ AsmString = S->getAsmString();
return getDerived().RebuildGCCAsmStmt(S->getAsmLoc(), S->isSimple(),
S->isVolatile(), S->getNumOutputs(),
S->getNumInputs(), Names.data(),
@@ -5796,7 +5937,7 @@ TreeTransform<Derived>::TransformMSAsmStmt(MSAsmStmt *S) {
HadError = true;
} else {
HadChange |= (Result.get() != SrcExprs[i]);
- TransformedExprs.push_back(Result.take());
+ TransformedExprs.push_back(Result.get());
}
}
@@ -5828,7 +5969,7 @@ TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
return StmtError();
if (Catch.get() != S->getCatchStmt(I))
AnyCatchChanged = true;
- CatchStmts.push_back(Catch.release());
+ CatchStmts.push_back(Catch.get());
}
// Transform the @finally statement (if present).
@@ -5844,7 +5985,7 @@ TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
TryBody.get() == S->getTryBody() &&
!AnyCatchChanged &&
Finally.get() == S->getFinallyStmt())
- return SemaRef.Owned(S);
+ return S;
// Build a new statement.
return getDerived().RebuildObjCAtTryStmt(S->getAtTryLoc(), TryBody.get(),
@@ -5855,9 +5996,9 @@ template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformObjCAtCatchStmt(ObjCAtCatchStmt *S) {
// Transform the @catch parameter, if there is one.
- VarDecl *Var = 0;
+ VarDecl *Var = nullptr;
if (VarDecl *FromVar = S->getCatchParamDecl()) {
- TypeSourceInfo *TSInfo = 0;
+ TypeSourceInfo *TSInfo = nullptr;
if (FromVar->getTypeSourceInfo()) {
TSInfo = getDerived().TransformType(FromVar->getTypeSourceInfo());
if (!TSInfo)
@@ -5898,7 +6039,7 @@ TreeTransform<Derived>::TransformObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
// If nothing changed, just retain this statement.
if (!getDerived().AlwaysRebuild() &&
Body.get() == S->getFinallyBody())
- return SemaRef.Owned(S);
+ return S;
// Build a new statement.
return getDerived().RebuildObjCAtFinallyStmt(S->getAtFinallyLoc(),
@@ -5917,7 +6058,7 @@ TreeTransform<Derived>::TransformObjCAtThrowStmt(ObjCAtThrowStmt *S) {
if (!getDerived().AlwaysRebuild() &&
Operand.get() == S->getThrowExpr())
- return getSema().Owned(S);
+ return S;
return getDerived().RebuildObjCAtThrowStmt(S->getThrowLoc(), Operand.get());
}
@@ -5945,7 +6086,7 @@ TreeTransform<Derived>::TransformObjCAtSynchronizedStmt(
if (!getDerived().AlwaysRebuild() &&
Object.get() == S->getSynchExpr() &&
Body.get() == S->getSynchBody())
- return SemaRef.Owned(S);
+ return S;
// Build a new statement.
return getDerived().RebuildObjCAtSynchronizedStmt(S->getAtSynchronizedLoc(),
@@ -5964,7 +6105,7 @@ TreeTransform<Derived>::TransformObjCAutoreleasePoolStmt(
// If nothing changed, just retain this statement.
if (!getDerived().AlwaysRebuild() &&
Body.get() == S->getSubStmt())
- return SemaRef.Owned(S);
+ return S;
// Build a new statement.
return getDerived().RebuildObjCAutoreleasePoolStmt(
@@ -5995,7 +6136,7 @@ TreeTransform<Derived>::TransformObjCForCollectionStmt(
Element.get() == S->getElement() &&
Collection.get() == S->getCollection() &&
Body.get() == S->getBody())
- return SemaRef.Owned(S);
+ return S;
// Build a new statement.
return getDerived().RebuildObjCForCollectionStmt(S->getForLoc(),
@@ -6008,7 +6149,7 @@ TreeTransform<Derived>::TransformObjCForCollectionStmt(
template <typename Derived>
StmtResult TreeTransform<Derived>::TransformCXXCatchStmt(CXXCatchStmt *S) {
// Transform the exception declaration, if any.
- VarDecl *Var = 0;
+ VarDecl *Var = nullptr;
if (VarDecl *ExceptionDecl = S->getExceptionDecl()) {
TypeSourceInfo *T =
getDerived().TransformType(ExceptionDecl->getTypeSourceInfo());
@@ -6029,7 +6170,7 @@ StmtResult TreeTransform<Derived>::TransformCXXCatchStmt(CXXCatchStmt *S) {
if (!getDerived().AlwaysRebuild() && !Var &&
Handler.get() == S->getHandlerBlock())
- return SemaRef.Owned(S);
+ return S;
return getDerived().RebuildCXXCatchStmt(S->getCatchLoc(), Var, Handler.get());
}
@@ -6050,12 +6191,12 @@ StmtResult TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) {
return StmtError();
HandlerChanged = HandlerChanged || Handler.get() != S->getHandler(I);
- Handlers.push_back(Handler.takeAs<Stmt>());
+ Handlers.push_back(Handler.getAs<Stmt>());
}
if (!getDerived().AlwaysRebuild() && TryBlock.get() == S->getTryBlock() &&
!HandlerChanged)
- return SemaRef.Owned(S);
+ return S;
return getDerived().RebuildCXXTryStmt(S->getTryLoc(), TryBlock.get(),
Handlers);
@@ -6076,17 +6217,17 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
if (Cond.isInvalid())
return StmtError();
if (Cond.get())
- Cond = SemaRef.CheckBooleanCondition(Cond.take(), S->getColonLoc());
+ Cond = SemaRef.CheckBooleanCondition(Cond.get(), S->getColonLoc());
if (Cond.isInvalid())
return StmtError();
if (Cond.get())
- Cond = SemaRef.MaybeCreateExprWithCleanups(Cond.take());
+ Cond = SemaRef.MaybeCreateExprWithCleanups(Cond.get());
ExprResult Inc = getDerived().TransformExpr(S->getInc());
if (Inc.isInvalid())
return StmtError();
if (Inc.get())
- Inc = SemaRef.MaybeCreateExprWithCleanups(Inc.take());
+ Inc = SemaRef.MaybeCreateExprWithCleanups(Inc.get());
StmtResult LoopVar = getDerived().TransformStmt(S->getLoopVarStmt());
if (LoopVar.isInvalid())
@@ -6125,7 +6266,7 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
}
if (NewStmt.get() == S)
- return SemaRef.Owned(S);
+ return S;
return FinishCXXForRangeStmt(NewStmt.get(), Body.get());
}
@@ -6161,7 +6302,7 @@ TreeTransform<Derived>::TransformMSDependentExistsStmt(
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
bool Dependent = false;
- switch (getSema().CheckMicrosoftIfExistsSymbol(/*S=*/0, SS, NameInfo)) {
+ switch (getSema().CheckMicrosoftIfExistsSymbol(/*S=*/nullptr, SS, NameInfo)) {
case Sema::IER_Exists:
if (S->isIfExists())
break;
@@ -6237,10 +6378,11 @@ StmtResult TreeTransform<Derived>::TransformSEHTryStmt(SEHTryStmt *S) {
if (!getDerived().AlwaysRebuild() && TryBlock.get() == S->getTryBlock() &&
Handler.get() == S->getHandler())
- return SemaRef.Owned(S);
+ return S;
- return getDerived().RebuildSEHTryStmt(S->getIsCXXTry(), S->getTryLoc(),
- TryBlock.take(), Handler.take());
+ return getDerived().RebuildSEHTryStmt(
+ S->getIsCXXTry(), S->getTryLoc(), TryBlock.get(), Handler.get(),
+ S->getHandlerIndex(), S->getHandlerParentIndex());
}
template <typename Derived>
@@ -6249,7 +6391,7 @@ StmtResult TreeTransform<Derived>::TransformSEHFinallyStmt(SEHFinallyStmt *S) {
if (Block.isInvalid())
return StmtError();
- return getDerived().RebuildSEHFinallyStmt(S->getFinallyLoc(), Block.take());
+ return getDerived().RebuildSEHFinallyStmt(S->getFinallyLoc(), Block.get());
}
template <typename Derived>
@@ -6262,8 +6404,8 @@ StmtResult TreeTransform<Derived>::TransformSEHExceptStmt(SEHExceptStmt *S) {
if (Block.isInvalid())
return StmtError();
- return getDerived().RebuildSEHExceptStmt(S->getExceptLoc(), FilterExpr.take(),
- Block.take());
+ return getDerived().RebuildSEHExceptStmt(S->getExceptLoc(), FilterExpr.get(),
+ Block.get());
}
template <typename Derived>
@@ -6276,9 +6418,16 @@ StmtResult TreeTransform<Derived>::TransformSEHHandler(Stmt *Handler) {
template<typename Derived>
StmtResult
-TreeTransform<Derived>::TransformOMPParallelDirective(OMPParallelDirective *D) {
- DeclarationNameInfo DirName;
- getSema().StartOpenMPDSABlock(OMPD_parallel, DirName, 0);
+TreeTransform<Derived>::TransformSEHLeaveStmt(SEHLeaveStmt *S) {
+ return S;
+}
+
+//===----------------------------------------------------------------------===//
+// OpenMP directive transformation
+//===----------------------------------------------------------------------===//
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPExecutableDirective(
+ OMPExecutableDirective *D) {
// Transform the clauses
llvm::SmallVector<OMPClause *, 16> TClauses;
@@ -6288,101 +6437,473 @@ TreeTransform<Derived>::TransformOMPParallelDirective(OMPParallelDirective *D) {
I != E; ++I) {
if (*I) {
OMPClause *Clause = getDerived().TransformOMPClause(*I);
- if (!Clause) {
- getSema().EndOpenMPDSABlock(0);
- return StmtError();
- }
- TClauses.push_back(Clause);
+ if (Clause)
+ TClauses.push_back(Clause);
+ } else {
+ TClauses.push_back(nullptr);
}
- else {
- TClauses.push_back(0);
+ }
+ StmtResult AssociatedStmt;
+ if (D->hasAssociatedStmt()) {
+ if (!D->getAssociatedStmt()) {
+ return StmtError();
+ }
+ AssociatedStmt = getDerived().TransformStmt(D->getAssociatedStmt());
+ if (AssociatedStmt.isInvalid()) {
+ return StmtError();
}
}
- if (!D->getAssociatedStmt()) {
- getSema().EndOpenMPDSABlock(0);
+ if (TClauses.size() != Clauses.size()) {
return StmtError();
}
- StmtResult AssociatedStmt =
- getDerived().TransformStmt(D->getAssociatedStmt());
- if (AssociatedStmt.isInvalid()) {
- getSema().EndOpenMPDSABlock(0);
- return StmtError();
+
+ // Transform directive name for 'omp critical' directive.
+ DeclarationNameInfo DirName;
+ if (D->getDirectiveKind() == OMPD_critical) {
+ DirName = cast<OMPCriticalDirective>(D)->getDirectiveName();
+ DirName = getDerived().TransformDeclarationNameInfo(DirName);
}
- StmtResult Res = getDerived().RebuildOMPParallelDirective(TClauses,
- AssociatedStmt.take(),
- D->getLocStart(),
- D->getLocEnd());
- getSema().EndOpenMPDSABlock(Res.get());
+ return getDerived().RebuildOMPExecutableDirective(
+ D->getDirectiveKind(), DirName, TClauses, AssociatedStmt.get(),
+ D->getLocStart(), D->getLocEnd());
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPParallelDirective(OMPParallelDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
return Res;
}
-template<typename Derived>
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPSimdDirective(OMPSimdDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_simd, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPForDirective(OMPForDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_for, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPSectionsDirective(OMPSectionsDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_sections, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPSectionDirective(OMPSectionDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_section, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPSingleDirective(OMPSingleDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_single, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPMasterDirective(OMPMasterDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_master, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPCriticalDirective(OMPCriticalDirective *D) {
+ getDerived().getSema().StartOpenMPDSABlock(
+ OMPD_critical, D->getDirectiveName(), nullptr, D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPParallelForDirective(
+ OMPParallelForDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel_for, DirName,
+ nullptr, D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPParallelSectionsDirective(
+ OMPParallelSectionsDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel_sections, DirName,
+ nullptr, D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPTaskDirective(OMPTaskDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_task, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPTaskyieldDirective(
+ OMPTaskyieldDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_taskyield, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPBarrierDirective(OMPBarrierDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_barrier, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_taskwait, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPFlushDirective(OMPFlushDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_flush, DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+//===----------------------------------------------------------------------===//
+// OpenMP clause transformation
+//===----------------------------------------------------------------------===//
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPIfClause(OMPIfClause *C) {
+ ExprResult Cond = getDerived().TransformExpr(C->getCondition());
+ if (Cond.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPIfClause(Cond.get(), C->getLocStart(),
+ C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPFinalClause(OMPFinalClause *C) {
+ ExprResult Cond = getDerived().TransformExpr(C->getCondition());
+ if (Cond.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPFinalClause(Cond.get(), C->getLocStart(),
+ C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPNumThreadsClause(OMPNumThreadsClause *C) {
+ ExprResult NumThreads = getDerived().TransformExpr(C->getNumThreads());
+ if (NumThreads.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPNumThreadsClause(
+ NumThreads.get(), C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPSafelenClause(OMPSafelenClause *C) {
+ ExprResult E = getDerived().TransformExpr(C->getSafelen());
+ if (E.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPSafelenClause(
+ E.get(), C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPCollapseClause(OMPCollapseClause *C) {
+ ExprResult E = getDerived().TransformExpr(C->getNumForLoops());
+ if (E.isInvalid())
+ return 0;
+ return getDerived().RebuildOMPCollapseClause(
+ E.get(), C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPDefaultClause(OMPDefaultClause *C) {
- return getDerived().RebuildOMPDefaultClause(C->getDefaultKind(),
- C->getDefaultKindKwLoc(),
- C->getLocStart(),
- C->getLParenLoc(),
- C->getLocEnd());
+ return getDerived().RebuildOMPDefaultClause(
+ C->getDefaultKind(), C->getDefaultKindKwLoc(), C->getLocStart(),
+ C->getLParenLoc(), C->getLocEnd());
}
-template<typename Derived>
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPProcBindClause(OMPProcBindClause *C) {
+ return getDerived().RebuildOMPProcBindClause(
+ C->getProcBindKind(), C->getProcBindKindKwLoc(), C->getLocStart(),
+ C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPScheduleClause(OMPScheduleClause *C) {
+ ExprResult E = getDerived().TransformExpr(C->getChunkSize());
+ if (E.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPScheduleClause(
+ C->getScheduleKind(), E.get(), C->getLocStart(), C->getLParenLoc(),
+ C->getScheduleKindLoc(), C->getCommaLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPOrderedClause(OMPOrderedClause *C) {
+ // No need to rebuild this clause, no template-dependent parameters.
+ return C;
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPNowaitClause(OMPNowaitClause *C) {
+ // No need to rebuild this clause, no template-dependent parameters.
+ return C;
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPUntiedClause(OMPUntiedClause *C) {
+ // No need to rebuild this clause, no template-dependent parameters.
+ return C;
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPMergeableClause(OMPMergeableClause *C) {
+ // No need to rebuild this clause, no template-dependent parameters.
+ return C;
+}
+
+template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPPrivateClause(OMPPrivateClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
Vars.reserve(C->varlist_size());
- for (OMPPrivateClause::varlist_iterator I = C->varlist_begin(),
- E = C->varlist_end();
- I != E; ++I) {
- ExprResult EVar = getDerived().TransformExpr(cast<Expr>(*I));
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
if (EVar.isInvalid())
- return 0;
- Vars.push_back(EVar.take());
+ return nullptr;
+ Vars.push_back(EVar.get());
}
- return getDerived().RebuildOMPPrivateClause(Vars,
- C->getLocStart(),
- C->getLParenLoc(),
- C->getLocEnd());
+ return getDerived().RebuildOMPPrivateClause(
+ Vars, C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
}
-template<typename Derived>
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPFirstprivateClause(
+ OMPFirstprivateClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ return getDerived().RebuildOMPFirstprivateClause(
+ Vars, C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
OMPClause *
-TreeTransform<Derived>::TransformOMPFirstprivateClause(
- OMPFirstprivateClause *C) {
+TreeTransform<Derived>::TransformOMPLastprivateClause(OMPLastprivateClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
Vars.reserve(C->varlist_size());
- for (OMPFirstprivateClause::varlist_iterator I = C->varlist_begin(),
- E = C->varlist_end();
- I != E; ++I) {
- ExprResult EVar = getDerived().TransformExpr(cast<Expr>(*I));
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
if (EVar.isInvalid())
- return 0;
- Vars.push_back(EVar.take());
+ return nullptr;
+ Vars.push_back(EVar.get());
}
- return getDerived().RebuildOMPFirstprivateClause(Vars,
- C->getLocStart(),
- C->getLParenLoc(),
- C->getLocEnd());
+ return getDerived().RebuildOMPLastprivateClause(
+ Vars, C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
}
-template<typename Derived>
+template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPSharedClause(OMPSharedClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
Vars.reserve(C->varlist_size());
- for (OMPSharedClause::varlist_iterator I = C->varlist_begin(),
- E = C->varlist_end();
- I != E; ++I) {
- ExprResult EVar = getDerived().TransformExpr(cast<Expr>(*I));
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ return getDerived().RebuildOMPSharedClause(Vars, C->getLocStart(),
+ C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPReductionClause(OMPReductionClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ CXXScopeSpec ReductionIdScopeSpec;
+ ReductionIdScopeSpec.Adopt(C->getQualifierLoc());
+
+ DeclarationNameInfo NameInfo = C->getNameInfo();
+ if (NameInfo.getName()) {
+ NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo);
+ if (!NameInfo.getName())
+ return nullptr;
+ }
+ return getDerived().RebuildOMPReductionClause(
+ Vars, C->getLocStart(), C->getLParenLoc(), C->getColonLoc(),
+ C->getLocEnd(), ReductionIdScopeSpec, NameInfo);
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPLinearClause(OMPLinearClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
if (EVar.isInvalid())
- return 0;
- Vars.push_back(EVar.take());
+ return nullptr;
+ Vars.push_back(EVar.get());
}
- return getDerived().RebuildOMPSharedClause(Vars,
- C->getLocStart(),
+ ExprResult Step = getDerived().TransformExpr(C->getStep());
+ if (Step.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPLinearClause(Vars, Step.get(), C->getLocStart(),
C->getLParenLoc(),
- C->getLocEnd());
+ C->getColonLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPAlignedClause(OMPAlignedClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ ExprResult Alignment = getDerived().TransformExpr(C->getAlignment());
+ if (Alignment.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPAlignedClause(
+ Vars, Alignment.get(), C->getLocStart(), C->getLParenLoc(),
+ C->getColonLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPCopyinClause(OMPCopyinClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ return getDerived().RebuildOMPCopyinClause(Vars, C->getLocStart(),
+ C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPCopyprivateClause(OMPCopyprivateClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ return getDerived().RebuildOMPCopyprivateClause(
+ Vars, C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPFlushClause(OMPFlushClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ return getDerived().RebuildOMPFlushClause(Vars, C->getLocStart(),
+ C->getLParenLoc(), C->getLocEnd());
}
//===----------------------------------------------------------------------===//
@@ -6391,7 +6912,7 @@ TreeTransform<Derived>::TransformOMPSharedClause(OMPSharedClause *C) {
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E) {
- return SemaRef.Owned(E);
+ return E;
}
template<typename Derived>
@@ -6428,10 +6949,10 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
// FIXME: this is a bit instantiation-specific.
SemaRef.MarkDeclRefReferenced(E);
- return SemaRef.Owned(E);
+ return E;
}
- TemplateArgumentListInfo TransArgs, *TemplateArgs = 0;
+ TemplateArgumentListInfo TransArgs, *TemplateArgs = nullptr;
if (E->hasExplicitTemplateArgs()) {
TemplateArgs = &TransArgs;
TransArgs.setLAngleLoc(E->getLAngleLoc());
@@ -6449,31 +6970,31 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformIntegerLiteral(IntegerLiteral *E) {
- return SemaRef.Owned(E);
+ return E;
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformFloatingLiteral(FloatingLiteral *E) {
- return SemaRef.Owned(E);
+ return E;
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformImaginaryLiteral(ImaginaryLiteral *E) {
- return SemaRef.Owned(E);
+ return E;
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformStringLiteral(StringLiteral *E) {
- return SemaRef.Owned(E);
+ return E;
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) {
- return SemaRef.Owned(E);
+ return E;
}
template<typename Derived>
@@ -6502,19 +7023,19 @@ TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) {
return ExprError();
AssocTypes.push_back(AssocType);
} else {
- AssocTypes.push_back(0);
+ AssocTypes.push_back(nullptr);
}
ExprResult AssocExpr = getDerived().TransformExpr(E->getAssocExpr(i));
if (AssocExpr.isInvalid())
return ExprError();
- AssocExprs.push_back(AssocExpr.release());
+ AssocExprs.push_back(AssocExpr.get());
}
return getDerived().RebuildGenericSelectionExpr(E->getGenericLoc(),
E->getDefaultLoc(),
E->getRParenLoc(),
- ControllingExpr.release(),
+ ControllingExpr.get(),
AssocTypes,
AssocExprs);
}
@@ -6527,7 +7048,7 @@ TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) {
return ExprError();
if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildParenExpr(SubExpr.get(), E->getLParen(),
E->getRParen());
@@ -6540,7 +7061,7 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformAddressOfOperand(Expr *E) {
if (DependentScopeDeclRefExpr *DRE = dyn_cast<DependentScopeDeclRefExpr>(E))
- return getDerived().TransformDependentScopeDeclRefExpr(DRE, true);
+ return getDerived().TransformDependentScopeDeclRefExpr(DRE, true, nullptr);
else
return getDerived().TransformExpr(E);
}
@@ -6557,7 +7078,7 @@ TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) {
return ExprError();
if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildUnaryOperator(E->getOperatorLoc(),
E->getOpcode(),
@@ -6622,7 +7143,7 @@ TreeTransform<Derived>::TransformOffsetOfExpr(OffsetOfExpr *E) {
if (!getDerived().AlwaysRebuild() &&
Type == E->getTypeSourceInfo() &&
!ExprChanged)
- return SemaRef.Owned(E);
+ return E;
// Build a new offsetof expression.
return getDerived().RebuildOffsetOfExpr(E->getOperatorLoc(), Type,
@@ -6635,7 +7156,7 @@ ExprResult
TreeTransform<Derived>::TransformOpaqueValueExpr(OpaqueValueExpr *E) {
assert(getDerived().AlreadyTransformed(E->getType()) &&
"opaque value expression requires transformation");
- return SemaRef.Owned(E);
+ return E;
}
template<typename Derived>
@@ -6655,7 +7176,7 @@ TreeTransform<Derived>::TransformPseudoObjectExpr(PseudoObjectExpr *E) {
// expression must have been an lvalue-to-rvalue conversion which we
// should reapply.
if (result.get()->hasPlaceholderType(BuiltinType::PseudoObject))
- result = SemaRef.checkPseudoObjectRValue(result.take());
+ result = SemaRef.checkPseudoObjectRValue(result.get());
return result;
}
@@ -6672,7 +7193,7 @@ TreeTransform<Derived>::TransformUnaryExprOrTypeTraitExpr(
return ExprError();
if (!getDerived().AlwaysRebuild() && OldT == NewT)
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildUnaryExprOrTypeTrait(NewT, E->getOperatorLoc(),
E->getKind(),
@@ -6685,12 +7206,26 @@ TreeTransform<Derived>::TransformUnaryExprOrTypeTraitExpr(
EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated,
Sema::ReuseLambdaContextDecl);
- ExprResult SubExpr = getDerived().TransformExpr(E->getArgumentExpr());
- if (SubExpr.isInvalid())
+ // Try to recover if we have something like sizeof(T::X) where X is a type.
+ // Notably, there must be *exactly* one set of parens if X is a type.
+ TypeSourceInfo *RecoveryTSI = nullptr;
+ ExprResult SubExpr;
+ auto *PE = dyn_cast<ParenExpr>(E->getArgumentExpr());
+ if (auto *DRE =
+ PE ? dyn_cast<DependentScopeDeclRefExpr>(PE->getSubExpr()) : nullptr)
+ SubExpr = getDerived().TransformParenDependentScopeDeclRefExpr(
+ PE, DRE, false, &RecoveryTSI);
+ else
+ SubExpr = getDerived().TransformExpr(E->getArgumentExpr());
+
+ if (RecoveryTSI) {
+ return getDerived().RebuildUnaryExprOrTypeTrait(
+ RecoveryTSI, E->getOperatorLoc(), E->getKind(), E->getSourceRange());
+ } else if (SubExpr.isInvalid())
return ExprError();
if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getArgumentExpr())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildUnaryExprOrTypeTrait(SubExpr.get(),
E->getOperatorLoc(),
@@ -6713,7 +7248,7 @@ TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E) {
if (!getDerived().AlwaysRebuild() &&
LHS.get() == E->getLHS() &&
RHS.get() == E->getRHS())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildArraySubscriptExpr(LHS.get(),
/*FIXME:*/E->getLHS()->getLocStart(),
@@ -6793,7 +7328,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
// FIXME: this is a bit instantiation-specific.
SemaRef.MarkMemberReferenced(E);
- return SemaRef.Owned(E);
+ return E;
}
TemplateArgumentListInfo TransArgs;
@@ -6807,14 +7342,14 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
}
// FIXME: Bogus source location for the operator
- SourceLocation FakeOperatorLoc
- = SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd());
+ SourceLocation FakeOperatorLoc =
+ SemaRef.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd());
// FIXME: to do this check properly, we will need to preserve the
// first-qualifier-in-scope here, just in case we had a dependent
// base (and therefore couldn't do the check) and a
// nested-name-qualifier (and therefore could do the lookup).
- NamedDecl *FirstQualifierInScope = 0;
+ NamedDecl *FirstQualifierInScope = nullptr;
return getDerived().RebuildMemberExpr(Base.get(), FakeOperatorLoc,
E->isArrow(),
@@ -6824,7 +7359,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
Member,
FoundDecl,
(E->hasExplicitTemplateArgs()
- ? &TransArgs : 0),
+ ? &TransArgs : nullptr),
FirstQualifierInScope);
}
@@ -6842,7 +7377,7 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) {
if (!getDerived().AlwaysRebuild() &&
LHS.get() == E->getLHS() &&
RHS.get() == E->getRHS())
- return SemaRef.Owned(E);
+ return E;
Sema::FPContractStateRAII FPContractState(getSema());
getSema().FPFeatures.fp_contract = E->isFPContractable();
@@ -6875,11 +7410,11 @@ TransformBinaryConditionalOperator(BinaryConditionalOperator *e) {
if (!getDerived().AlwaysRebuild() &&
commonExpr.get() == e->getCommon() &&
rhs.get() == e->getFalseExpr())
- return SemaRef.Owned(e);
+ return e;
- return getDerived().RebuildConditionalOperator(commonExpr.take(),
+ return getDerived().RebuildConditionalOperator(commonExpr.get(),
e->getQuestionLoc(),
- 0,
+ nullptr,
e->getColonLoc(),
rhs.get());
}
@@ -6903,7 +7438,7 @@ TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E) {
Cond.get() == E->getCond() &&
LHS.get() == E->getLHS() &&
RHS.get() == E->getRHS())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildConditionalOperator(Cond.get(),
E->getQuestionLoc(),
@@ -6935,7 +7470,7 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) {
if (!getDerived().AlwaysRebuild() &&
Type == E->getTypeInfoAsWritten() &&
SubExpr.get() == E->getSubExpr())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildCStyleCastExpr(E->getLParenLoc(),
Type,
@@ -6978,11 +7513,11 @@ TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E) {
if (!getDerived().AlwaysRebuild() &&
Base.get() == E->getBase())
- return SemaRef.Owned(E);
+ return E;
// FIXME: Bad source location
- SourceLocation FakeOperatorLoc
- = SemaRef.PP.getLocForEndOfToken(E->getBase()->getLocEnd());
+ SourceLocation FakeOperatorLoc =
+ SemaRef.getLocForEndOfToken(E->getBase()->getLocEnd());
return getDerived().RebuildExtVectorElementExpr(Base.get(), FakeOperatorLoc,
E->getAccessorLoc(),
E->getAccessor());
@@ -6999,7 +7534,7 @@ TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) {
return ExprError();
if (!getDerived().AlwaysRebuild() && !InitChanged)
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildInitList(E->getLBraceLoc(), Inits,
E->getRBraceLoc(), E->getType());
@@ -7037,7 +7572,7 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) {
D->getLBracketLoc()));
ExprChanged = ExprChanged || Init.get() != E->getArrayIndex(*D);
- ArrayExprs.push_back(Index.release());
+ ArrayExprs.push_back(Index.get());
continue;
}
@@ -7059,14 +7594,14 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) {
ExprChanged = ExprChanged || Start.get() != E->getArrayRangeStart(*D) ||
End.get() != E->getArrayRangeEnd(*D);
- ArrayExprs.push_back(Start.release());
- ArrayExprs.push_back(End.release());
+ ArrayExprs.push_back(Start.get());
+ ArrayExprs.push_back(End.get());
}
if (!getDerived().AlwaysRebuild() &&
Init.get() == E->getInit() &&
!ExprChanged)
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildDesignatedInitExpr(Desig, ArrayExprs,
E->getEqualOrColonLoc(),
@@ -7087,7 +7622,7 @@ TreeTransform<Derived>::TransformImplicitValueInitExpr(
if (!getDerived().AlwaysRebuild() &&
T == E->getType())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildImplicitValueInitExpr(T);
}
@@ -7106,7 +7641,7 @@ TreeTransform<Derived>::TransformVAArgExpr(VAArgExpr *E) {
if (!getDerived().AlwaysRebuild() &&
TInfo == E->getWrittenTypeInfo() &&
SubExpr.get() == E->getSubExpr())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildVAArgExpr(E->getBuiltinLoc(), SubExpr.get(),
TInfo, E->getRParenLoc());
@@ -7185,7 +7720,7 @@ TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E) {
Cond.get() == E->getCond() &&
LHS.get() == E->getLHS() &&
RHS.get() == E->getRHS())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildChooseExpr(E->getBuiltinLoc(),
Cond.get(), LHS.get(), RHS.get(),
@@ -7195,7 +7730,7 @@ TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E) {
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformGNUNullExpr(GNUNullExpr *E) {
- return SemaRef.Owned(E);
+ return E;
}
template<typename Derived>
@@ -7218,9 +7753,8 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
return ExprError();
// FIXME: Poor location information
- SourceLocation FakeLParenLoc
- = SemaRef.PP.getLocForEndOfToken(
- static_cast<Expr *>(Object.get())->getLocEnd());
+ SourceLocation FakeLParenLoc = SemaRef.getLocForEndOfToken(
+ static_cast<Expr *>(Object.get())->getLocEnd());
// Transform the call arguments.
SmallVector<Expr*, 8> Args;
@@ -7338,7 +7872,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
if (!getDerived().AlwaysRebuild() &&
Type == E->getTypeInfoAsWritten() &&
SubExpr.get() == E->getSubExpr())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(),
E->getStmtClass(),
E->getAngleBrackets().getBegin(),
@@ -7391,7 +7925,7 @@ TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
if (!getDerived().AlwaysRebuild() &&
Type == E->getTypeInfoAsWritten() &&
SubExpr.get() == E->getSubExpr())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildCXXFunctionalCastExpr(Type,
E->getLParenLoc(),
@@ -7410,7 +7944,7 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) {
if (!getDerived().AlwaysRebuild() &&
TInfo == E->getTypeOperandSourceInfo())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildCXXTypeidExpr(E->getType(),
E->getLocStart(),
@@ -7431,7 +7965,7 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) {
if (!getDerived().AlwaysRebuild() &&
SubExpr.get() == E->getExprOperand())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildCXXTypeidExpr(E->getType(),
E->getLocStart(),
@@ -7450,7 +7984,7 @@ TreeTransform<Derived>::TransformCXXUuidofExpr(CXXUuidofExpr *E) {
if (!getDerived().AlwaysRebuild() &&
TInfo == E->getTypeOperandSourceInfo())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildCXXUuidofExpr(E->getType(),
E->getLocStart(),
@@ -7466,7 +8000,7 @@ TreeTransform<Derived>::TransformCXXUuidofExpr(CXXUuidofExpr *E) {
if (!getDerived().AlwaysRebuild() &&
SubExpr.get() == E->getExprOperand())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildCXXUuidofExpr(E->getType(),
E->getLocStart(),
@@ -7477,14 +8011,14 @@ TreeTransform<Derived>::TransformCXXUuidofExpr(CXXUuidofExpr *E) {
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
- return SemaRef.Owned(E);
+ return E;
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXNullPtrLiteralExpr(
CXXNullPtrLiteralExpr *E) {
- return SemaRef.Owned(E);
+ return E;
}
template<typename Derived>
@@ -7495,7 +8029,7 @@ TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
if (!getDerived().AlwaysRebuild() && T == E->getType()) {
// Make sure that we capture 'this'.
getSema().CheckCXXThisCapture(E->getLocStart());
- return SemaRef.Owned(E);
+ return E;
}
return getDerived().RebuildCXXThisExpr(E->getLocStart(), T, E->isImplicit());
@@ -7510,7 +8044,7 @@ TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E) {
if (!getDerived().AlwaysRebuild() &&
SubExpr.get() == E->getSubExpr())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildCXXThrowExpr(E->getThrowLoc(), SubExpr.get(),
E->isThrownVariableInScope());
@@ -7527,7 +8061,7 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
if (!getDerived().AlwaysRebuild() &&
Param == E->getParam())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildCXXDefaultArgExpr(E->getUsedLocation(), Param);
}
@@ -7542,7 +8076,7 @@ TreeTransform<Derived>::TransformCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
return ExprError();
if (!getDerived().AlwaysRebuild() && Field == E->getField())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildCXXDefaultInitExpr(E->getExprLoc(), Field);
}
@@ -7557,7 +8091,7 @@ TreeTransform<Derived>::TransformCXXScalarValueInitExpr(
if (!getDerived().AlwaysRebuild() &&
T == E->getTypeSourceInfo())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildCXXScalarValueInitExpr(T,
/*FIXME:*/T->getTypeLoc().getEndLoc(),
@@ -7590,12 +8124,12 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
Expr *OldInit = E->getInitializer();
ExprResult NewInit;
if (OldInit)
- NewInit = getDerived().TransformExpr(OldInit);
+ NewInit = getDerived().TransformInitializer(OldInit, true);
if (NewInit.isInvalid())
return ExprError();
// Transform new operator and delete operator.
- FunctionDecl *OperatorNew = 0;
+ FunctionDecl *OperatorNew = nullptr;
if (E->getOperatorNew()) {
OperatorNew = cast_or_null<FunctionDecl>(
getDerived().TransformDecl(E->getLocStart(),
@@ -7604,7 +8138,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
return ExprError();
}
- FunctionDecl *OperatorDelete = 0;
+ FunctionDecl *OperatorDelete = nullptr;
if (E->getOperatorDelete()) {
OperatorDelete = cast_or_null<FunctionDecl>(
getDerived().TransformDecl(E->getLocStart(),
@@ -7638,7 +8172,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
}
}
- return SemaRef.Owned(E);
+ return E;
}
QualType AllocType = AllocTypeInfo->getType();
@@ -7653,16 +8187,14 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
// Do nothing
} else if (const ConstantArrayType *ConsArrayT
= dyn_cast<ConstantArrayType>(ArrayT)) {
- ArraySize
- = SemaRef.Owned(IntegerLiteral::Create(SemaRef.Context,
- ConsArrayT->getSize(),
- SemaRef.Context.getSizeType(),
- /*FIXME:*/E->getLocStart()));
+ ArraySize = IntegerLiteral::Create(SemaRef.Context, ConsArrayT->getSize(),
+ SemaRef.Context.getSizeType(),
+ /*FIXME:*/ E->getLocStart());
AllocType = ConsArrayT->getElementType();
} else if (const DependentSizedArrayType *DepArrayT
= dyn_cast<DependentSizedArrayType>(ArrayT)) {
if (DepArrayT->getSizeExpr()) {
- ArraySize = SemaRef.Owned(DepArrayT->getSizeExpr());
+ ArraySize = DepArrayT->getSizeExpr();
AllocType = DepArrayT->getElementType();
}
}
@@ -7678,7 +8210,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
AllocTypeInfo,
ArraySize.get(),
E->getDirectInitRange(),
- NewInit.take());
+ NewInit.get());
}
template<typename Derived>
@@ -7689,7 +8221,7 @@ TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) {
return ExprError();
// Transform the delete operator, if known.
- FunctionDecl *OperatorDelete = 0;
+ FunctionDecl *OperatorDelete = nullptr;
if (E->getOperatorDelete()) {
OperatorDelete = cast_or_null<FunctionDecl>(
getDerived().TransformDecl(E->getLocStart(),
@@ -7716,7 +8248,7 @@ TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) {
}
}
- return SemaRef.Owned(E);
+ return E;
}
return getDerived().RebuildCXXDeleteExpr(E->getLocStart(),
@@ -7735,7 +8267,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
ParsedType ObjectTypePtr;
bool MayBePseudoDestructor = false;
- Base = SemaRef.ActOnStartCXXMemberReference(0, Base.get(),
+ Base = SemaRef.ActOnStartCXXMemberReference(nullptr, Base.get(),
E->getOperatorLoc(),
E->isArrow()? tok::arrow : tok::period,
ObjectTypePtr,
@@ -7758,7 +8290,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
if (E->getDestroyedTypeInfo()) {
TypeSourceInfo *DestroyedTypeInfo
= getDerived().TransformTypeInObjectScope(E->getDestroyedTypeInfo(),
- ObjectType, 0, SS);
+ ObjectType, nullptr, SS);
if (!DestroyedTypeInfo)
return ExprError();
Destroyed = DestroyedTypeInfo;
@@ -7772,7 +8304,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
ParsedType T = SemaRef.getDestructorName(E->getTildeLoc(),
*E->getDestroyedTypeIdentifier(),
E->getDestroyedTypeLoc(),
- /*Scope=*/0,
+ /*Scope=*/nullptr,
SS, ObjectTypePtr,
false);
if (!T)
@@ -7783,11 +8315,11 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
E->getDestroyedTypeLoc());
}
- TypeSourceInfo *ScopeTypeInfo = 0;
+ TypeSourceInfo *ScopeTypeInfo = nullptr;
if (E->getScopeTypeInfo()) {
CXXScopeSpec EmptySS;
ScopeTypeInfo = getDerived().TransformTypeInObjectScope(
- E->getScopeTypeInfo(), ObjectType, 0, EmptySS);
+ E->getScopeTypeInfo(), ObjectType, nullptr, EmptySS);
if (!ScopeTypeInfo)
return ExprError();
}
@@ -7829,9 +8361,8 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
// Expand using declarations.
if (isa<UsingDecl>(InstD)) {
UsingDecl *UD = cast<UsingDecl>(InstD);
- for (UsingDecl::shadow_iterator I = UD->shadow_begin(),
- E = UD->shadow_end(); I != E; ++I)
- R.addDecl(*I);
+ for (auto *I : UD->shadows())
+ R.addDecl(I);
continue;
}
@@ -7890,44 +8421,6 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
template<typename Derived>
ExprResult
-TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
- TypeSourceInfo *T = getDerived().TransformType(E->getQueriedTypeSourceInfo());
- if (!T)
- return ExprError();
-
- if (!getDerived().AlwaysRebuild() &&
- T == E->getQueriedTypeSourceInfo())
- return SemaRef.Owned(E);
-
- return getDerived().RebuildUnaryTypeTrait(E->getTrait(),
- E->getLocStart(),
- T,
- E->getLocEnd());
-}
-
-template<typename Derived>
-ExprResult
-TreeTransform<Derived>::TransformBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
- TypeSourceInfo *LhsT = getDerived().TransformType(E->getLhsTypeSourceInfo());
- if (!LhsT)
- return ExprError();
-
- TypeSourceInfo *RhsT = getDerived().TransformType(E->getRhsTypeSourceInfo());
- if (!RhsT)
- return ExprError();
-
- if (!getDerived().AlwaysRebuild() &&
- LhsT == E->getLhsTypeSourceInfo() && RhsT == E->getRhsTypeSourceInfo())
- return SemaRef.Owned(E);
-
- return getDerived().RebuildBinaryTypeTrait(E->getTrait(),
- E->getLocStart(),
- LhsT, RhsT,
- E->getLocEnd());
-}
-
-template<typename Derived>
-ExprResult
TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
bool ArgChanged = false;
SmallVector<TypeSourceInfo *, 4> Args;
@@ -8053,7 +8546,7 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
}
if (!getDerived().AlwaysRebuild() && !ArgChanged)
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildTypeTrait(E->getTrait(),
E->getLocStart(),
@@ -8070,7 +8563,7 @@ TreeTransform<Derived>::TransformArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
if (!getDerived().AlwaysRebuild() &&
T == E->getQueriedTypeSourceInfo())
- return SemaRef.Owned(E);
+ return E;
ExprResult SubExpr;
{
@@ -8080,7 +8573,7 @@ TreeTransform<Derived>::TransformArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
return ExprError();
if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getDimensionExpression())
- return SemaRef.Owned(E);
+ return E;
}
return getDerived().RebuildArrayTypeTrait(E->getTrait(),
@@ -8101,25 +8594,44 @@ TreeTransform<Derived>::TransformExpressionTraitExpr(ExpressionTraitExpr *E) {
return ExprError();
if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getQueriedExpression())
- return SemaRef.Owned(E);
+ return E;
}
return getDerived().RebuildExpressionTrait(
E->getTrait(), E->getLocStart(), SubExpr.get(), E->getLocEnd());
}
-template<typename Derived>
-ExprResult
-TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
- DependentScopeDeclRefExpr *E) {
- return TransformDependentScopeDeclRefExpr(E, /*IsAddressOfOperand*/false);
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformParenDependentScopeDeclRefExpr(
+ ParenExpr *PE, DependentScopeDeclRefExpr *DRE, bool AddrTaken,
+ TypeSourceInfo **RecoveryTSI) {
+ ExprResult NewDRE = getDerived().TransformDependentScopeDeclRefExpr(
+ DRE, AddrTaken, RecoveryTSI);
+
+ // Propagate both errors and recovered types, which return ExprEmpty.
+ if (!NewDRE.isUsable())
+ return NewDRE;
+
+ // We got an expr, wrap it up in parens.
+ if (!getDerived().AlwaysRebuild() && NewDRE.get() == DRE)
+ return PE;
+ return getDerived().RebuildParenExpr(NewDRE.get(), PE->getLParen(),
+ PE->getRParen());
+}
+
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
+ DependentScopeDeclRefExpr *E) {
+ return TransformDependentScopeDeclRefExpr(E, /*IsAddressOfOperand=*/false,
+ nullptr);
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
DependentScopeDeclRefExpr *E,
- bool IsAddressOfOperand) {
+ bool IsAddressOfOperand,
+ TypeSourceInfo **RecoveryTSI) {
assert(E->getQualifierLoc());
NestedNameSpecifierLoc QualifierLoc
= getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc());
@@ -8142,13 +8654,11 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
// Note: it is sufficient to compare the Name component of NameInfo:
// if name has not changed, DNLoc has not changed either.
NameInfo.getName() == E->getDeclName())
- return SemaRef.Owned(E);
+ return E;
- return getDerived().RebuildDependentScopeDeclRefExpr(QualifierLoc,
- TemplateKWLoc,
- NameInfo,
- /*TemplateArgs*/ 0,
- IsAddressOfOperand);
+ return getDerived().RebuildDependentScopeDeclRefExpr(
+ QualifierLoc, TemplateKWLoc, NameInfo, /*TemplateArgs=*/nullptr,
+ IsAddressOfOperand, RecoveryTSI);
}
TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc());
@@ -8157,11 +8667,9 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
TransArgs))
return ExprError();
- return getDerived().RebuildDependentScopeDeclRefExpr(QualifierLoc,
- TemplateKWLoc,
- NameInfo,
- &TransArgs,
- IsAddressOfOperand);
+ return getDerived().RebuildDependentScopeDeclRefExpr(
+ QualifierLoc, TemplateKWLoc, NameInfo, &TransArgs, IsAddressOfOperand,
+ RecoveryTSI);
}
template<typename Derived>
@@ -8202,7 +8710,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
// Mark the constructor as referenced.
// FIXME: Instantiation-specific
SemaRef.MarkFunctionReferenced(E->getLocStart(), Constructor);
- return SemaRef.Owned(E);
+ return E;
}
return getDerived().RebuildCXXConstructExpr(T, /*FIXME:*/E->getLocStart(),
@@ -8210,6 +8718,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
Args,
E->hadMultipleCandidates(),
E->isListInitialization(),
+ E->isStdInitListInitialization(),
E->requiresZeroInitialization(),
E->getConstructionKind(),
E->getParenOrBraceRange());
@@ -8323,8 +8832,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo();
FunctionProtoTypeLoc OldCallOpFPTL =
OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>();
- TypeSourceInfo *NewCallOpTSI = 0;
-
+ TypeSourceInfo *NewCallOpTSI = nullptr;
+
const bool CallOpWasAlreadyTransformed =
getDerived().AlreadyTransformed(OldCallOpTSI->getType());
@@ -8340,7 +8849,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
TypeLocBuilder NewCallOpTLBuilder;
QualType NewCallOpType = TransformFunctionProtoType(NewCallOpTLBuilder,
OldCallOpFPTL,
- 0, 0);
+ nullptr, 0);
NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context,
NewCallOpType);
}
@@ -8353,7 +8862,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
FunctionProtoTypeLoc NewCallOpFPTL =
NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>();
ParmVarDecl **NewParamDeclArray = NewCallOpFPTL.getParmArray();
- const unsigned NewNumArgs = NewCallOpFPTL.getNumArgs();
+ const unsigned NewNumArgs = NewCallOpFPTL.getNumParams();
for (unsigned I = 0; I < NewNumArgs; ++I) {
// If this call operator's type does not require transformation,
@@ -8416,7 +8925,8 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
bool Invalid = false;
// Introduce the context of the call operator.
- Sema::ContextRAII SavedContext(getSema(), CallOperator);
+ Sema::ContextRAII SavedContext(getSema(), CallOperator,
+ /*NewThisContext*/false);
LambdaScopeInfo *const LSI = getSema().getCurLambda();
// Enter the scope of the lambda.
@@ -8510,6 +9020,9 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
// Capture the transformed variable.
getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind);
}
+
+ // FIXME: Retain a pack expansion if RetainExpansion is true.
+
continue;
}
@@ -8537,7 +9050,7 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
getSema().PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
if (Invalid) {
- getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/0,
+ getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/nullptr,
/*IsInstantiation=*/true);
return ExprError();
}
@@ -8545,13 +9058,14 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
// Instantiate the body of the lambda expression.
StmtResult Body = getDerived().TransformStmt(E->getBody());
if (Body.isInvalid()) {
- getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/0,
+ getSema().ActOnLambdaError(E->getLocStart(), /*CurScope=*/nullptr,
/*IsInstantiation=*/true);
return ExprError();
}
- return getSema().ActOnLambdaExpr(E->getLocStart(), Body.take(),
- /*CurScope=*/0, /*IsInstantiation=*/true);
+ return getSema().ActOnLambdaExpr(E->getLocStart(), Body.get(),
+ /*CurScope=*/nullptr,
+ /*IsInstantiation=*/true);
}
template<typename Derived>
@@ -8572,7 +9086,7 @@ TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr(
if (!getDerived().AlwaysRebuild() &&
T == E->getTypeSourceInfo() &&
!ArgumentChanged)
- return SemaRef.Owned(E);
+ return E;
// FIXME: we're faking the locations of the commas
return getDerived().RebuildCXXUnresolvedConstructExpr(T,
@@ -8586,7 +9100,7 @@ ExprResult
TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
CXXDependentScopeMemberExpr *E) {
// Transform the base of the expression.
- ExprResult Base((Expr*) 0);
+ ExprResult Base((Expr*) nullptr);
Expr *OldBase;
QualType BaseType;
QualType ObjectType;
@@ -8599,7 +9113,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
// Start the member reference and compute the object's type.
ParsedType ObjectTy;
bool MayBePseudoDestructor = false;
- Base = SemaRef.ActOnStartCXXMemberReference(0, Base.get(),
+ Base = SemaRef.ActOnStartCXXMemberReference(nullptr, Base.get(),
E->getOperatorLoc(),
E->isArrow()? tok::arrow : tok::period,
ObjectTy,
@@ -8610,7 +9124,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
ObjectType = ObjectTy.get();
BaseType = ((Expr*) Base.get())->getType();
} else {
- OldBase = 0;
+ OldBase = nullptr;
BaseType = getDerived().TransformType(E->getBaseType());
ObjectType = BaseType->getAs<PointerType>()->getPointeeType();
}
@@ -8652,7 +9166,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
QualifierLoc == E->getQualifierLoc() &&
NameInfo.getName() == E->getMember() &&
FirstQualifierInScope == E->getFirstQualifierFoundInScope())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildCXXDependentScopeMemberExpr(Base.get(),
BaseType,
@@ -8662,7 +9176,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
TemplateKWLoc,
FirstQualifierInScope,
NameInfo,
- /*TemplateArgs*/ 0);
+ /*TemplateArgs*/nullptr);
}
TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc());
@@ -8686,13 +9200,13 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) {
// Transform the base of the expression.
- ExprResult Base((Expr*) 0);
+ ExprResult Base((Expr*) nullptr);
QualType BaseType;
if (!Old->isImplicitAccess()) {
Base = getDerived().TransformExpr(Old->getBase());
if (Base.isInvalid())
return ExprError();
- Base = getSema().PerformMemberExprBaseConversion(Base.take(),
+ Base = getSema().PerformMemberExprBaseConversion(Base.get(),
Old->isArrow());
if (Base.isInvalid())
return ExprError();
@@ -8734,9 +9248,8 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
// Expand using declarations.
if (isa<UsingDecl>(InstD)) {
UsingDecl *UD = cast<UsingDecl>(InstD);
- for (UsingDecl::shadow_iterator I = UD->shadow_begin(),
- E = UD->shadow_end(); I != E; ++I)
- R.addDecl(*I);
+ for (auto *I : UD->shadows())
+ R.addDecl(I);
continue;
}
@@ -8771,7 +9284,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
// first-qualifier-in-scope here, just in case we had a dependent
// base (and therefore couldn't do the check) and a
// nested-name-qualifier (and therefore could do the lookup).
- NamedDecl *FirstQualifierInScope = 0;
+ NamedDecl *FirstQualifierInScope = nullptr;
return getDerived().RebuildUnresolvedMemberExpr(Base.get(),
BaseType,
@@ -8782,7 +9295,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
FirstQualifierInScope,
R,
(Old->hasExplicitTemplateArgs()
- ? &TransArgs : 0));
+ ? &TransArgs : nullptr));
}
template<typename Derived>
@@ -8794,7 +9307,7 @@ TreeTransform<Derived>::TransformCXXNoexceptExpr(CXXNoexceptExpr *E) {
return ExprError();
if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getOperand())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildCXXNoexceptExpr(E->getSourceRange(),SubExpr.get());
}
@@ -8807,7 +9320,7 @@ TreeTransform<Derived>::TransformPackExpansionExpr(PackExpansionExpr *E) {
return ExprError();
if (!getDerived().AlwaysRebuild() && Pattern.get() == E->getPattern())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildPackExpansion(Pattern.get(), E->getEllipsisLoc(),
E->getNumExpansions());
@@ -8819,7 +9332,7 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
// If E is not value-dependent, then nothing will change when we transform it.
// Note: This is an instantiation-centric view.
if (!E->isValueDependent())
- return SemaRef.Owned(E);
+ return E;
// Note: None of the implementations of TryExpandParameterPacks can ever
// produce a diagnostic when given only a single unexpanded parameter pack,
@@ -8835,7 +9348,7 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
return ExprError();
if (RetainExpansion)
- return SemaRef.Owned(E);
+ return E;
NamedDecl *Pack = E->getPack();
if (!ShouldExpand) {
@@ -8858,7 +9371,7 @@ ExprResult
TreeTransform<Derived>::TransformSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *E) {
// Default behavior is to do nothing with this transformation.
- return SemaRef.Owned(E);
+ return E;
}
template<typename Derived>
@@ -8866,14 +9379,14 @@ ExprResult
TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr(
SubstNonTypeTemplateParmExpr *E) {
// Default behavior is to do nothing with this transformation.
- return SemaRef.Owned(E);
+ return E;
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
// Default behavior is to do nothing with this transformation.
- return SemaRef.Owned(E);
+ return E;
}
template<typename Derived>
@@ -8899,7 +9412,7 @@ TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) {
- return SemaRef.Owned(E);
+ return E;
}
template<typename Derived>
@@ -8911,7 +9424,7 @@ TreeTransform<Derived>::TransformObjCBoxedExpr(ObjCBoxedExpr *E) {
if (!getDerived().AlwaysRebuild() &&
SubExpr.get() == E->getSubExpr())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildObjCBoxedExpr(E->getSourceRange(), SubExpr.get());
}
@@ -9014,6 +9527,7 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
// If any unexpanded parameter packs remain, we still have a
// pack expansion.
+ // FIXME: Can this really happen?
if (Key.get()->containsUnexpandedParameterPack() ||
Value.get()->containsUnexpandedParameterPack())
Element.EllipsisLoc = OrigElement.EllipsisLoc;
@@ -9021,6 +9535,8 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
Elements.push_back(Element);
}
+ // FIXME: Retain a pack expansion if RetainExpansion is true.
+
// We've finished with this pack expansion.
continue;
}
@@ -9066,7 +9582,7 @@ TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) {
if (!getDerived().AlwaysRebuild() &&
EncodedTypeInfo == E->getEncodedTypeSourceInfo())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildObjCEncodeExpr(E->getAtLoc(),
EncodedTypeInfo,
@@ -9098,7 +9614,7 @@ TransformObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
if (!getDerived().AlwaysRebuild() &&
TSInfo == E->getTypeInfoAsWritten() &&
Result.get() == E->getSubExpr())
- return SemaRef.Owned(E);
+ return E;
return SemaRef.BuildObjCBridgedCast(E->getLParenLoc(), E->getBridgeKind(),
E->getBridgeKeywordLoc(), TSInfo,
@@ -9168,13 +9684,13 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformObjCSelectorExpr(ObjCSelectorExpr *E) {
- return SemaRef.Owned(E);
+ return E;
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) {
- return SemaRef.Owned(E);
+ return E;
}
template<typename Derived>
@@ -9190,7 +9706,7 @@ TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) {
// If nothing changed, just retain the existing expression.
if (!getDerived().AlwaysRebuild() &&
Base.get() == E->getBase())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildObjCIvarRefExpr(Base.get(), E->getDecl(),
E->getLocation(),
@@ -9203,7 +9719,7 @@ TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
// 'super' and types never change. Property never changes. Just
// retain the existing expression.
if (!E->isObjectReceiver())
- return SemaRef.Owned(E);
+ return E;
// Transform the base expression.
ExprResult Base = getDerived().TransformExpr(E->getBase());
@@ -9215,7 +9731,7 @@ TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
// If nothing changed, just retain the existing expression.
if (!getDerived().AlwaysRebuild() &&
Base.get() == E->getBase())
- return SemaRef.Owned(E);
+ return E;
if (E->isExplicitProperty())
return getDerived().RebuildObjCPropertyRefExpr(Base.get(),
@@ -9245,7 +9761,7 @@ TreeTransform<Derived>::TransformObjCSubscriptRefExpr(ObjCSubscriptRefExpr *E) {
// If nothing changed, just retain the existing expression.
if (!getDerived().AlwaysRebuild() &&
Key.get() == E->getKeyExpr() && Base.get() == E->getBaseExpr())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildObjCSubscriptRefExpr(E->getRBracket(),
Base.get(), Key.get(),
@@ -9264,7 +9780,7 @@ TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) {
// If nothing changed, just retain the existing expression.
if (!getDerived().AlwaysRebuild() &&
Base.get() == E->getBase())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildObjCIsaExpr(Base.get(), E->getIsaMemberLoc(),
E->getOpLoc(),
@@ -9283,7 +9799,7 @@ TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) {
if (!getDerived().AlwaysRebuild() &&
!ArgumentChanged)
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildShuffleVectorExpr(E->getBuiltinLoc(),
SubExprs,
@@ -9304,7 +9820,7 @@ TreeTransform<Derived>::TransformConvertVectorExpr(ConvertVectorExpr *E) {
if (!getDerived().AlwaysRebuild() &&
Type == E->getTypeSourceInfo() &&
SrcExpr.get() == E->getSrcExpr())
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildConvertVectorExpr(E->getBuiltinLoc(),
SrcExpr.get(), Type,
@@ -9316,7 +9832,7 @@ ExprResult
TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
BlockDecl *oldBlock = E->getBlockDecl();
- SemaRef.ActOnBlockStart(E->getCaretLocation(), /*Scope=*/0);
+ SemaRef.ActOnBlockStart(E->getCaretLocation(), /*Scope=*/nullptr);
BlockScopeInfo *blockScope = SemaRef.getCurBlock();
blockScope->TheDecl->setIsVariadic(oldBlock->isVariadic());
@@ -9330,14 +9846,14 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
if (getDerived().TransformFunctionTypeParams(E->getCaretLocation(),
oldBlock->param_begin(),
oldBlock->param_size(),
- 0, paramTypes, &params)) {
- getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/0);
+ nullptr, paramTypes, &params)) {
+ getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/nullptr);
return ExprError();
}
const FunctionProtoType *exprFunctionType = E->getFunctionType();
QualType exprResultType =
- getDerived().TransformType(exprFunctionType->getResultType());
+ getDerived().TransformType(exprFunctionType->getReturnType());
QualType functionType =
getDerived().RebuildFunctionProtoType(exprResultType, paramTypes,
@@ -9356,7 +9872,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
// Transform the body
StmtResult body = getDerived().TransformStmt(E->getBody());
if (body.isInvalid()) {
- getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/0);
+ getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/nullptr);
return ExprError();
}
@@ -9364,9 +9880,8 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
// In builds with assertions, make sure that we captured everything we
// captured before.
if (!SemaRef.getDiagnostics().hasErrorOccurred()) {
- for (BlockDecl::capture_iterator i = oldBlock->capture_begin(),
- e = oldBlock->capture_end(); i != e; ++i) {
- VarDecl *oldCapture = i->getVariable();
+ for (const auto &I : oldBlock->captures()) {
+ VarDecl *oldCapture = I.getVariable();
// Ignore parameter packs.
if (isa<ParmVarDecl>(oldCapture) &&
@@ -9383,7 +9898,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
#endif
return SemaRef.ActOnBlockStmtExpr(E->getCaretLocation(), body.get(),
- /*Scope=*/0);
+ /*Scope=*/nullptr);
}
template<typename Derived>
@@ -9405,7 +9920,7 @@ TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) {
if (!getDerived().AlwaysRebuild() &&
!ArgumentChanged)
- return SemaRef.Owned(E);
+ return E;
return getDerived().RebuildAtomicExpr(E->getBuiltinLoc(), SubExprs,
RetTy, E->getOp(), E->getRParenLoc());
@@ -9443,8 +9958,8 @@ QualType
TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType,
QualType ClassType,
SourceLocation Sigil) {
- return SemaRef.BuildMemberPointerType(PointeeType, ClassType,
- Sigil, getDerived().getBaseEntity());
+ return SemaRef.BuildMemberPointerType(PointeeType, ClassType, Sigil,
+ getDerived().getBaseEntity());
}
template<typename Derived>
@@ -9490,7 +10005,7 @@ TreeTransform<Derived>::RebuildConstantArrayType(QualType ElementType,
const llvm::APInt &Size,
unsigned IndexTypeQuals,
SourceRange BracketsRange) {
- return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, 0,
+ return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, nullptr,
IndexTypeQuals, BracketsRange);
}
@@ -9500,7 +10015,7 @@ TreeTransform<Derived>::RebuildIncompleteArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
unsigned IndexTypeQuals,
SourceRange BracketsRange) {
- return getDerived().RebuildArrayType(ElementType, SizeMod, 0, 0,
+ return getDerived().RebuildArrayType(ElementType, SizeMod, nullptr, nullptr,
IndexTypeQuals, BracketsRange);
}
@@ -9511,7 +10026,7 @@ TreeTransform<Derived>::RebuildVariableArrayType(QualType ElementType,
Expr *SizeExpr,
unsigned IndexTypeQuals,
SourceRange BracketsRange) {
- return getDerived().RebuildArrayType(ElementType, SizeMod, 0,
+ return getDerived().RebuildArrayType(ElementType, SizeMod, nullptr,
SizeExpr,
IndexTypeQuals, BracketsRange);
}
@@ -9523,7 +10038,7 @@ TreeTransform<Derived>::RebuildDependentSizedArrayType(QualType ElementType,
Expr *SizeExpr,
unsigned IndexTypeQuals,
SourceRange BracketsRange) {
- return getDerived().RebuildArrayType(ElementType, SizeMod, 0,
+ return getDerived().RebuildArrayType(ElementType, SizeMod, nullptr,
SizeExpr,
IndexTypeQuals, BracketsRange);
}
@@ -9559,7 +10074,7 @@ TreeTransform<Derived>::RebuildDependentSizedExtVectorType(QualType ElementType,
template<typename Derived>
QualType TreeTransform<Derived>::RebuildFunctionProtoType(
QualType T,
- llvm::MutableArrayRef<QualType> ParamTypes,
+ MutableArrayRef<QualType> ParamTypes,
const FunctionProtoType::ExtProtoInfo &EPI) {
return SemaRef.BuildFunctionType(T, ParamTypes,
getDerived().getBaseLocation(),
@@ -9655,7 +10170,7 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
TemplateName.setIdentifier(&Name, NameLoc);
Sema::TemplateTy Template;
SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller.
- getSema().ActOnDependentTemplateName(/*Scope=*/0,
+ getSema().ActOnDependentTemplateName(/*Scope=*/nullptr,
SS, TemplateKWLoc, TemplateName,
ParsedType::make(ObjectType),
/*EnteringContext=*/false,
@@ -9675,7 +10190,7 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
Name.setOperatorFunctionId(NameLoc, Operator, SymbolLocations);
SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller.
Sema::TemplateTy Template;
- getSema().ActOnDependentTemplateName(/*Scope=*/0,
+ getSema().ActOnDependentTemplateName(/*Scope=*/nullptr,
SS, TemplateKWLoc, Name,
ParsedType::make(ObjectType),
/*EnteringContext=*/false,
@@ -9693,6 +10208,24 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
Expr *Callee = OrigCallee->IgnoreParenCasts();
bool isPostIncDec = Second && (Op == OO_PlusPlus || Op == OO_MinusMinus);
+ if (First->getObjectKind() == OK_ObjCProperty) {
+ BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op);
+ if (BinaryOperator::isAssignmentOp(Opc))
+ return SemaRef.checkPseudoObjectAssignment(/*Scope=*/nullptr, OpLoc, Opc,
+ First, Second);
+ ExprResult Result = SemaRef.CheckPlaceholderExpr(First);
+ if (Result.isInvalid())
+ return ExprError();
+ First = Result.get();
+ }
+
+ if (Second && Second->getObjectKind() == OK_ObjCProperty) {
+ ExprResult Result = SemaRef.CheckPlaceholderExpr(Second);
+ if (Result.isInvalid())
+ return ExprError();
+ Second = Result.get();
+ }
+
// Determine whether this should be a builtin operation.
if (Op == OO_Subscript) {
if (!First->getType()->isOverloadableType() &&
@@ -9702,8 +10235,8 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
Second, OpLoc);
} else if (Op == OO_Arrow) {
// -> is never a builtin operation.
- return SemaRef.BuildOverloadedArrowExpr(0, First, OpLoc);
- } else if (Second == 0 || isPostIncDec) {
+ return SemaRef.BuildOverloadedArrowExpr(nullptr, First, OpLoc);
+ } else if (Second == nullptr || isPostIncDec) {
if (!First->getType()->isOverloadableType()) {
// The argument is not of overloadable type, so try to create a
// built-in unary operation.
@@ -9733,9 +10266,6 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Callee)) {
assert(ULE->requiresADL());
-
- // FIXME: Do we have to check
- // IsAcceptableNonMemberOperatorCandidate for each of these?
Functions.append(ULE->decls_begin(), ULE->decls_end());
} else {
// If we've resolved this to a particular non-member function, just call
@@ -9748,7 +10278,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
// Add any functions found via argument-dependent lookup.
Expr *Args[2] = { First, Second };
- unsigned NumArgs = 1 + (Second != 0);
+ unsigned NumArgs = 1 + (Second != nullptr);
// Create the overloaded operator invocation for unary operators.
if (NumArgs == 1 || isPostIncDec) {
@@ -9826,26 +10356,43 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
return getSema().BuildMemberReferenceExpr(Base, BaseType,
OperatorLoc, isArrow,
SS, TemplateKWLoc,
- /*FIXME: FirstQualifier*/ 0,
+ /*FIXME: FirstQualifier*/ nullptr,
NameInfo,
- /*TemplateArgs*/ 0);
+ /*TemplateArgs*/ nullptr);
}
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformCapturedStmt(CapturedStmt *S) {
SourceLocation Loc = S->getLocStart();
- unsigned NumParams = S->getCapturedDecl()->getNumParams();
- getSema().ActOnCapturedRegionStart(Loc, /*CurScope*/0,
- S->getCapturedRegionKind(), NumParams);
- StmtResult Body = getDerived().TransformStmt(S->getCapturedStmt());
+ CapturedDecl *CD = S->getCapturedDecl();
+ unsigned NumParams = CD->getNumParams();
+ unsigned ContextParamPos = CD->getContextParamPosition();
+ SmallVector<Sema::CapturedParamNameType, 4> Params;
+ for (unsigned I = 0; I < NumParams; ++I) {
+ if (I != ContextParamPos) {
+ Params.push_back(
+ std::make_pair(
+ CD->getParam(I)->getName(),
+ getDerived().TransformType(CD->getParam(I)->getType())));
+ } else {
+ Params.push_back(std::make_pair(StringRef(), QualType()));
+ }
+ }
+ getSema().ActOnCapturedRegionStart(Loc, /*CurScope*/nullptr,
+ S->getCapturedRegionKind(), Params);
+ StmtResult Body;
+ {
+ Sema::CompoundScopeRAII CompoundScope(getSema());
+ Body = getDerived().TransformStmt(S->getCapturedStmt());
+ }
if (Body.isInvalid()) {
getSema().ActOnCapturedRegionError();
return StmtError();
}
- return getSema().ActOnCapturedRegionEnd(Body.take());
+ return getSema().ActOnCapturedRegionEnd(Body.get());
}
} // end namespace clang
diff --git a/lib/Sema/TypeLocBuilder.cpp b/lib/Sema/TypeLocBuilder.cpp
index c7d43b704690..be995400df6d 100644
--- a/lib/Sema/TypeLocBuilder.cpp
+++ b/lib/Sema/TypeLocBuilder.cpp
@@ -62,7 +62,7 @@ void TypeLocBuilder::grow(size_t NewCapacity) {
TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment) {
#ifndef NDEBUG
- QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType();
+ QualType TLast = TypeLoc(T, nullptr).getNextTypeLoc().getType();
assert(TLast == LastTy &&
"mismatch between last type and new type's inner type");
LastTy = T;
diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h
index b1e909859b2f..c3f874e1a854 100644
--- a/lib/Sema/TypeLocBuilder.h
+++ b/lib/Sema/TypeLocBuilder.h
@@ -94,7 +94,7 @@ class TypeLocBuilder {
/// 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) {
- TyLocType Loc = TypeLoc(T, 0).castAs<TyLocType>();
+ TyLocType Loc = TypeLoc(T, nullptr).castAs<TyLocType>();
size_t LocalSize = Loc.getLocalDataSize();
unsigned LocalAlign = Loc.getLocalDataAlignment();
return pushImpl(T, LocalSize, LocalAlign).castAs<TyLocType>();
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index a8176878dc4e..ad046ffa277a 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -95,21 +95,21 @@ serialization::getDefinitiveDeclContext(const DeclContext *DC) {
case Decl::TranslationUnit:
case Decl::Namespace:
case Decl::LinkageSpec:
- return 0;
+ return nullptr;
// C/C++ tag types can only be defined in one place.
case Decl::Enum:
case Decl::Record:
if (const TagDecl *Def = cast<TagDecl>(DC)->getDefinition())
return Def;
- return 0;
+ return nullptr;
// FIXME: These can be defined in one place... except special member
// functions and out-of-line definitions.
case Decl::CXXRecord:
case Decl::ClassTemplateSpecialization:
case Decl::ClassTemplatePartialSpecialization:
- return 0;
+ return nullptr;
// Each function, method, and block declaration is its own DeclContext.
case Decl::Function:
@@ -131,14 +131,14 @@ serialization::getDefinitiveDeclContext(const DeclContext *DC) {
if (const ObjCProtocolDecl *Def
= cast<ObjCProtocolDecl>(DC)->getDefinition())
return Def;
- return 0;
+ return nullptr;
// FIXME: These are defined in one place, but properties in class extensions
// end up being back-patched into the main interface. See
// Sema::HandlePropertyInClassExtension for the offending code.
case Decl::ObjCInterface:
- return 0;
-
+ return nullptr;
+
default:
llvm_unreachable("Unhandled DeclContext in AST reader");
}
diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h
index ef81e6903243..c7669749260b 100644
--- a/lib/Serialization/ASTCommon.h
+++ b/lib/Serialization/ASTCommon.h
@@ -26,8 +26,13 @@ enum DeclUpdateKind {
UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
UPD_CXX_ADDED_ANONYMOUS_NAMESPACE,
UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER,
+ UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION,
+ UPD_CXX_INSTANTIATED_CLASS_DEFINITION,
+ UPD_CXX_RESOLVED_EXCEPTION_SPEC,
UPD_CXX_DEDUCED_RETURN_TYPE,
- UPD_DECL_MARKED_USED
+ UPD_DECL_MARKED_USED,
+ UPD_MANGLING_NUMBER,
+ UPD_STATIC_LOCAL_NUMBER
};
TypeIdx TypeIdxFromBuiltin(const BuiltinType *BT);
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 4d1b4b90b664..ae41654904c6 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManagerInternals.h"
@@ -29,6 +30,7 @@
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/Version.h"
#include "clang/Basic/VersionTuple.h"
+#include "clang/Frontend/Utils.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/MacroInfo.h"
@@ -49,16 +51,100 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SaveAndRestore.h"
-#include "llvm/Support/system_error.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstdio>
#include <iterator>
+#include <system_error>
using namespace clang;
using namespace clang::serialization;
using namespace clang::serialization::reader;
using llvm::BitstreamCursor;
+
+//===----------------------------------------------------------------------===//
+// ChainedASTReaderListener implementation
+//===----------------------------------------------------------------------===//
+
+bool
+ChainedASTReaderListener::ReadFullVersionInformation(StringRef FullVersion) {
+ return First->ReadFullVersionInformation(FullVersion) ||
+ Second->ReadFullVersionInformation(FullVersion);
+}
+void ChainedASTReaderListener::ReadModuleName(StringRef ModuleName) {
+ First->ReadModuleName(ModuleName);
+ Second->ReadModuleName(ModuleName);
+}
+void ChainedASTReaderListener::ReadModuleMapFile(StringRef ModuleMapPath) {
+ First->ReadModuleMapFile(ModuleMapPath);
+ Second->ReadModuleMapFile(ModuleMapPath);
+}
+bool ChainedASTReaderListener::ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain) {
+ return First->ReadLanguageOptions(LangOpts, Complain) ||
+ Second->ReadLanguageOptions(LangOpts, Complain);
+}
+bool
+ChainedASTReaderListener::ReadTargetOptions(const TargetOptions &TargetOpts,
+ bool Complain) {
+ return First->ReadTargetOptions(TargetOpts, Complain) ||
+ Second->ReadTargetOptions(TargetOpts, Complain);
+}
+bool ChainedASTReaderListener::ReadDiagnosticOptions(
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, bool Complain) {
+ return First->ReadDiagnosticOptions(DiagOpts, Complain) ||
+ Second->ReadDiagnosticOptions(DiagOpts, Complain);
+}
+bool
+ChainedASTReaderListener::ReadFileSystemOptions(const FileSystemOptions &FSOpts,
+ bool Complain) {
+ return First->ReadFileSystemOptions(FSOpts, Complain) ||
+ Second->ReadFileSystemOptions(FSOpts, Complain);
+}
+
+bool ChainedASTReaderListener::ReadHeaderSearchOptions(
+ const HeaderSearchOptions &HSOpts, bool Complain) {
+ return First->ReadHeaderSearchOptions(HSOpts, Complain) ||
+ Second->ReadHeaderSearchOptions(HSOpts, Complain);
+}
+bool ChainedASTReaderListener::ReadPreprocessorOptions(
+ const PreprocessorOptions &PPOpts, bool Complain,
+ std::string &SuggestedPredefines) {
+ return First->ReadPreprocessorOptions(PPOpts, Complain,
+ SuggestedPredefines) ||
+ Second->ReadPreprocessorOptions(PPOpts, Complain, SuggestedPredefines);
+}
+void ChainedASTReaderListener::ReadCounter(const serialization::ModuleFile &M,
+ unsigned Value) {
+ First->ReadCounter(M, Value);
+ Second->ReadCounter(M, Value);
+}
+bool ChainedASTReaderListener::needsInputFileVisitation() {
+ return First->needsInputFileVisitation() ||
+ Second->needsInputFileVisitation();
+}
+bool ChainedASTReaderListener::needsSystemInputFileVisitation() {
+ return First->needsSystemInputFileVisitation() ||
+ Second->needsSystemInputFileVisitation();
+}
+void ChainedASTReaderListener::visitModuleFile(StringRef Filename) {
+ First->visitModuleFile(Filename);
+ Second->visitModuleFile(Filename);
+}
+bool ChainedASTReaderListener::visitInputFile(StringRef Filename,
+ bool isSystem,
+ bool isOverridden) {
+ bool Continue = false;
+ if (First->needsInputFileVisitation() &&
+ (!isSystem || First->needsSystemInputFileVisitation()))
+ Continue |= First->visitInputFile(Filename, isSystem, isOverridden);
+ if (Second->needsInputFileVisitation() &&
+ (!isSystem || Second->needsSystemInputFileVisitation()))
+ Continue |= Second->visitInputFile(Filename, isSystem, isOverridden);
+ return Continue;
+}
+
//===----------------------------------------------------------------------===//
// PCH validator implementation
//===----------------------------------------------------------------------===//
@@ -140,8 +226,6 @@ static bool checkTargetOptions(const TargetOptions &TargetOpts,
CHECK_TARGET_OPT(Triple, "target");
CHECK_TARGET_OPT(CPU, "target CPU");
CHECK_TARGET_OPT(ABI, "target ABI");
- CHECK_TARGET_OPT(CXXABI, "target C++ ABI");
- CHECK_TARGET_OPT(LinkerVersion, "target linker version");
#undef CHECK_TARGET_OPT
// Compare feature sets.
@@ -197,14 +281,14 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts,
bool Complain) {
const LangOptions &ExistingLangOpts = PP.getLangOpts();
return checkLanguageOptions(LangOpts, ExistingLangOpts,
- Complain? &Reader.Diags : 0);
+ Complain? &Reader.Diags : nullptr);
}
bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts,
bool Complain) {
const TargetOptions &ExistingTargetOpts = PP.getTargetInfo().getTargetOpts();
return checkTargetOptions(TargetOpts, ExistingTargetOpts,
- Complain? &Reader.Diags : 0);
+ Complain? &Reader.Diags : nullptr);
}
namespace {
@@ -214,11 +298,124 @@ namespace {
DeclsMap;
}
+static bool checkDiagnosticGroupMappings(DiagnosticsEngine &StoredDiags,
+ DiagnosticsEngine &Diags,
+ bool Complain) {
+ typedef DiagnosticsEngine::Level Level;
+
+ // Check current mappings for new -Werror mappings, and the stored mappings
+ // for cases that were explicitly mapped to *not* be errors that are now
+ // errors because of options like -Werror.
+ DiagnosticsEngine *MappingSources[] = { &Diags, &StoredDiags };
+
+ for (DiagnosticsEngine *MappingSource : MappingSources) {
+ for (auto DiagIDMappingPair : MappingSource->getDiagnosticMappings()) {
+ diag::kind DiagID = DiagIDMappingPair.first;
+ Level CurLevel = Diags.getDiagnosticLevel(DiagID, SourceLocation());
+ if (CurLevel < DiagnosticsEngine::Error)
+ continue; // not significant
+ Level StoredLevel =
+ StoredDiags.getDiagnosticLevel(DiagID, SourceLocation());
+ if (StoredLevel < DiagnosticsEngine::Error) {
+ if (Complain)
+ Diags.Report(diag::err_pch_diagopt_mismatch) << "-Werror=" +
+ Diags.getDiagnosticIDs()->getWarningOptionForDiag(DiagID).str();
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool isExtHandlingFromDiagsError(DiagnosticsEngine &Diags) {
+ diag::Severity Ext = Diags.getExtensionHandlingBehavior();
+ if (Ext == diag::Severity::Warning && Diags.getWarningsAsErrors())
+ return true;
+ return Ext >= diag::Severity::Error;
+}
+
+static bool checkDiagnosticMappings(DiagnosticsEngine &StoredDiags,
+ DiagnosticsEngine &Diags,
+ bool IsSystem, bool Complain) {
+ // Top-level options
+ if (IsSystem) {
+ if (Diags.getSuppressSystemWarnings())
+ return false;
+ // If -Wsystem-headers was not enabled before, be conservative
+ if (StoredDiags.getSuppressSystemWarnings()) {
+ if (Complain)
+ Diags.Report(diag::err_pch_diagopt_mismatch) << "-Wsystem-headers";
+ return true;
+ }
+ }
+
+ if (Diags.getWarningsAsErrors() && !StoredDiags.getWarningsAsErrors()) {
+ if (Complain)
+ Diags.Report(diag::err_pch_diagopt_mismatch) << "-Werror";
+ return true;
+ }
+
+ if (Diags.getWarningsAsErrors() && Diags.getEnableAllWarnings() &&
+ !StoredDiags.getEnableAllWarnings()) {
+ if (Complain)
+ Diags.Report(diag::err_pch_diagopt_mismatch) << "-Weverything -Werror";
+ return true;
+ }
+
+ if (isExtHandlingFromDiagsError(Diags) &&
+ !isExtHandlingFromDiagsError(StoredDiags)) {
+ if (Complain)
+ Diags.Report(diag::err_pch_diagopt_mismatch) << "-pedantic-errors";
+ return true;
+ }
+
+ return checkDiagnosticGroupMappings(StoredDiags, Diags, Complain);
+}
+
+bool PCHValidator::ReadDiagnosticOptions(
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, bool Complain) {
+ DiagnosticsEngine &ExistingDiags = PP.getDiagnostics();
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(ExistingDiags.getDiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagIDs, DiagOpts.get()));
+ // This should never fail, because we would have processed these options
+ // before writing them to an ASTFile.
+ ProcessWarningOptions(*Diags, *DiagOpts, /*Report*/false);
+
+ ModuleManager &ModuleMgr = Reader.getModuleManager();
+ assert(ModuleMgr.size() >= 1 && "what ASTFile is this then");
+
+ // If the original import came from a file explicitly generated by the user,
+ // don't check the diagnostic mappings.
+ // FIXME: currently this is approximated by checking whether this is not a
+ // module import.
+ // Note: ModuleMgr.rbegin() may not be the current module, but it must be in
+ // the transitive closure of its imports, since unrelated modules cannot be
+ // imported until after this module finishes validation.
+ ModuleFile *TopImport = *ModuleMgr.rbegin();
+ while (!TopImport->ImportedBy.empty())
+ TopImport = TopImport->ImportedBy[0];
+ if (TopImport->Kind != MK_Module)
+ return false;
+
+ StringRef ModuleName = TopImport->ModuleName;
+ assert(!ModuleName.empty() && "diagnostic options read before module name");
+
+ Module *M = PP.getHeaderSearchInfo().lookupModule(ModuleName);
+ assert(M && "missing module");
+
+ // FIXME: if the diagnostics are incompatible, save a DiagnosticOptions that
+ // contains the union of their flags.
+ return checkDiagnosticMappings(*Diags, ExistingDiags, M->IsSystem, Complain);
+}
+
/// \brief Collect the macro definitions provided by the given preprocessor
/// options.
-static void collectMacroDefinitions(const PreprocessorOptions &PPOpts,
- MacroDefinitionsMap &Macros,
- SmallVectorImpl<StringRef> *MacroNames = 0){
+static void
+collectMacroDefinitions(const PreprocessorOptions &PPOpts,
+ MacroDefinitionsMap &Macros,
+ SmallVectorImpl<StringRef> *MacroNames = nullptr) {
for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) {
StringRef Macro = PPOpts.Macros[I].first;
bool IsUndef = PPOpts.Macros[I].second;
@@ -373,7 +570,7 @@ bool PCHValidator::ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
const PreprocessorOptions &ExistingPPOpts = PP.getPreprocessorOpts();
return checkPreprocessorOptions(PPOpts, ExistingPPOpts,
- Complain? &Reader.Diags : 0,
+ Complain? &Reader.Diags : nullptr,
PP.getFileManager(),
SuggestedPredefines,
PP.getLangOpts());
@@ -387,9 +584,10 @@ void PCHValidator::ReadCounter(const ModuleFile &M, unsigned Value) {
// AST reader implementation
//===----------------------------------------------------------------------===//
-void
-ASTReader::setDeserializationListener(ASTDeserializationListener *Listener) {
+void ASTReader::setDeserializationListener(ASTDeserializationListener *Listener,
+ bool TakeOwnership) {
DeserializationListener = Listener;
+ OwnsDeserializationListener = TakeOwnership;
}
@@ -401,19 +599,19 @@ unsigned ASTSelectorLookupTrait::ComputeHash(Selector Sel) {
std::pair<unsigned, unsigned>
ASTSelectorLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
- using namespace clang::io;
- unsigned KeyLen = ReadUnalignedLE16(d);
- unsigned DataLen = ReadUnalignedLE16(d);
+ using namespace llvm::support;
+ unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d);
+ unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d);
return std::make_pair(KeyLen, DataLen);
}
ASTSelectorLookupTrait::internal_key_type
ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) {
- using namespace clang::io;
+ using namespace llvm::support;
SelectorTable &SelTable = Reader.getContext().Selectors;
- unsigned N = ReadUnalignedLE16(d);
- IdentifierInfo *FirstII
- = Reader.getLocalIdentifier(F, ReadUnalignedLE32(d));
+ unsigned N = endian::readNext<uint16_t, little, unaligned>(d);
+ IdentifierInfo *FirstII = Reader.getLocalIdentifier(
+ F, endian::readNext<uint32_t, little, unaligned>(d));
if (N == 0)
return SelTable.getNullarySelector(FirstII);
else if (N == 1)
@@ -422,7 +620,8 @@ ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) {
SmallVector<IdentifierInfo *, 16> Args;
Args.push_back(FirstII);
for (unsigned I = 1; I != N; ++I)
- Args.push_back(Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)));
+ Args.push_back(Reader.getLocalIdentifier(
+ F, endian::readNext<uint32_t, little, unaligned>(d)));
return SelTable.getSelector(N, Args.data());
}
@@ -430,13 +629,16 @@ ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) {
ASTSelectorLookupTrait::data_type
ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d,
unsigned DataLen) {
- using namespace clang::io;
+ using namespace llvm::support;
data_type Result;
- Result.ID = Reader.getGlobalSelectorID(F, ReadUnalignedLE32(d));
- unsigned NumInstanceMethodsAndBits = ReadUnalignedLE16(d);
- unsigned NumFactoryMethodsAndBits = ReadUnalignedLE16(d);
+ Result.ID = Reader.getGlobalSelectorID(
+ F, endian::readNext<uint32_t, little, unaligned>(d));
+ unsigned NumInstanceMethodsAndBits =
+ endian::readNext<uint16_t, little, unaligned>(d);
+ unsigned NumFactoryMethodsAndBits =
+ endian::readNext<uint16_t, little, unaligned>(d);
Result.InstanceBits = NumInstanceMethodsAndBits & 0x3;
Result.FactoryBits = NumFactoryMethodsAndBits & 0x3;
unsigned NumInstanceMethods = NumInstanceMethodsAndBits >> 2;
@@ -444,15 +646,15 @@ ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d,
// Load instance methods
for (unsigned I = 0; I != NumInstanceMethods; ++I) {
- if (ObjCMethodDecl *Method
- = Reader.GetLocalDeclAs<ObjCMethodDecl>(F, ReadUnalignedLE32(d)))
+ if (ObjCMethodDecl *Method = Reader.GetLocalDeclAs<ObjCMethodDecl>(
+ F, endian::readNext<uint32_t, little, unaligned>(d)))
Result.Instance.push_back(Method);
}
// Load factory methods
for (unsigned I = 0; I != NumFactoryMethods; ++I) {
- if (ObjCMethodDecl *Method
- = Reader.GetLocalDeclAs<ObjCMethodDecl>(F, ReadUnalignedLE32(d)))
+ if (ObjCMethodDecl *Method = Reader.GetLocalDeclAs<ObjCMethodDecl>(
+ F, endian::readNext<uint32_t, little, unaligned>(d)))
Result.Factory.push_back(Method);
}
@@ -465,9 +667,9 @@ unsigned ASTIdentifierLookupTraitBase::ComputeHash(const internal_key_type& a) {
std::pair<unsigned, unsigned>
ASTIdentifierLookupTraitBase::ReadKeyDataLength(const unsigned char*& d) {
- using namespace clang::io;
- unsigned DataLen = ReadUnalignedLE16(d);
- unsigned KeyLen = ReadUnalignedLE16(d);
+ using namespace llvm::support;
+ unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d);
+ unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d);
return std::make_pair(KeyLen, DataLen);
}
@@ -490,8 +692,8 @@ static bool isInterestingIdentifier(IdentifierInfo &II) {
IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
const unsigned char* d,
unsigned DataLen) {
- using namespace clang::io;
- unsigned RawID = ReadUnalignedLE32(d);
+ using namespace llvm::support;
+ unsigned RawID = endian::readNext<uint32_t, little, unaligned>(d);
bool IsInteresting = RawID & 0x01;
// Wipe out the "is interesting" bit.
@@ -517,8 +719,8 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
return II;
}
- unsigned ObjCOrBuiltinID = ReadUnalignedLE16(d);
- unsigned Bits = ReadUnalignedLE16(d);
+ unsigned ObjCOrBuiltinID = endian::readNext<uint16_t, little, unaligned>(d);
+ unsigned Bits = endian::readNext<uint16_t, little, unaligned>(d);
bool CPlusPlusOperatorKeyword = Bits & 0x01;
Bits >>= 1;
bool HasRevertedTokenIDToIdentifier = Bits & 0x01;
@@ -567,11 +769,13 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
// If this identifier is a macro, deserialize the macro
// definition.
if (hadMacroDefinition) {
- uint32_t MacroDirectivesOffset = ReadUnalignedLE32(d);
+ uint32_t MacroDirectivesOffset =
+ endian::readNext<uint32_t, little, unaligned>(d);
DataLen -= 4;
SmallVector<uint32_t, 8> LocalMacroIDs;
if (hasSubmoduleMacros) {
- while (uint32_t LocalMacroID = ReadUnalignedLE32(d)) {
+ while (uint32_t LocalMacroID =
+ endian::readNext<uint32_t, little, unaligned>(d)) {
DataLen -= 4;
LocalMacroIDs.push_back(LocalMacroID);
}
@@ -579,11 +783,34 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
}
if (F.Kind == MK_Module) {
+ // Macro definitions are stored from newest to oldest, so reverse them
+ // before registering them.
+ llvm::SmallVector<unsigned, 8> MacroSizes;
for (SmallVectorImpl<uint32_t>::iterator
- I = LocalMacroIDs.begin(), E = LocalMacroIDs.end(); I != E; ++I) {
- MacroID MacID = Reader.getGlobalMacroID(F, *I);
- Reader.addPendingMacroFromModule(II, &F, MacID, F.DirectImportLoc);
+ I = LocalMacroIDs.begin(), E = LocalMacroIDs.end(); I != E; /**/) {
+ unsigned Size = 1;
+
+ static const uint32_t HasOverridesFlag = 0x80000000U;
+ if (I + 1 != E && (I[1] & HasOverridesFlag))
+ Size += 1 + (I[1] & ~HasOverridesFlag);
+
+ MacroSizes.push_back(Size);
+ I += Size;
+ }
+
+ SmallVectorImpl<uint32_t>::iterator I = LocalMacroIDs.end();
+ for (SmallVectorImpl<unsigned>::reverse_iterator SI = MacroSizes.rbegin(),
+ SE = MacroSizes.rend();
+ SI != SE; ++SI) {
+ I -= *SI;
+
+ uint32_t LocalMacroID = *I;
+ ArrayRef<uint32_t> Overrides;
+ if (*SI != 1)
+ Overrides = llvm::makeArrayRef(&I[2], *SI - 2);
+ Reader.addPendingMacroFromModule(II, &F, LocalMacroID, Overrides);
}
+ assert(I == LocalMacroIDs.begin());
} else {
Reader.addPendingMacroFromPCH(II, &F, MacroDirectivesOffset);
}
@@ -596,7 +823,8 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
if (DataLen > 0) {
SmallVector<uint32_t, 4> DeclIDs;
for (; DataLen > 0; DataLen -= 4)
- DeclIDs.push_back(Reader.getGlobalDeclID(F, ReadUnalignedLE32(d)));
+ DeclIDs.push_back(Reader.getGlobalDeclID(
+ F, endian::readNext<uint32_t, little, unaligned>(d)));
Reader.SetGloballyVisibleDecls(II, DeclIDs);
}
@@ -664,34 +892,37 @@ ASTDeclContextNameLookupTrait::GetInternalKey(
std::pair<unsigned, unsigned>
ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
- using namespace clang::io;
- unsigned KeyLen = ReadUnalignedLE16(d);
- unsigned DataLen = ReadUnalignedLE16(d);
+ using namespace llvm::support;
+ unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d);
+ unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d);
return std::make_pair(KeyLen, DataLen);
}
ASTDeclContextNameLookupTrait::internal_key_type
ASTDeclContextNameLookupTrait::ReadKey(const unsigned char* d, unsigned) {
- using namespace clang::io;
+ using namespace llvm::support;
DeclNameKey Key;
Key.Kind = (DeclarationName::NameKind)*d++;
switch (Key.Kind) {
case DeclarationName::Identifier:
- Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d));
+ Key.Data = (uint64_t)Reader.getLocalIdentifier(
+ F, endian::readNext<uint32_t, little, unaligned>(d));
break;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
Key.Data =
- (uint64_t)Reader.getLocalSelector(F, ReadUnalignedLE32(d))
- .getAsOpaquePtr();
+ (uint64_t)Reader.getLocalSelector(
+ F, endian::readNext<uint32_t, little, unaligned>(
+ d)).getAsOpaquePtr();
break;
case DeclarationName::CXXOperatorName:
Key.Data = *d++; // OverloadedOperatorKind
break;
case DeclarationName::CXXLiteralOperatorName:
- Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d));
+ Key.Data = (uint64_t)Reader.getLocalIdentifier(
+ F, endian::readNext<uint32_t, little, unaligned>(d));
break;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
@@ -708,8 +939,8 @@ ASTDeclContextNameLookupTrait::data_type
ASTDeclContextNameLookupTrait::ReadData(internal_key_type,
const unsigned char* d,
unsigned DataLen) {
- using namespace clang::io;
- unsigned NumDecls = ReadUnalignedLE16(d);
+ using namespace llvm::support;
+ unsigned NumDecls = endian::readNext<uint16_t, little, unaligned>(d);
LE32DeclID *Start = reinterpret_cast<LE32DeclID *>(
const_cast<unsigned char *>(d));
return std::make_pair(Start, Start + NumDecls);
@@ -749,11 +980,11 @@ bool ASTReader::ReadDeclContextStorage(ModuleFile &M,
Error("Expected visible lookup table block");
return true;
}
- Info.NameLookupTableData
- = ASTDeclContextNameLookupTable::Create(
- (const unsigned char *)Blob.data() + Record[0],
- (const unsigned char *)Blob.data(),
- ASTDeclContextNameLookupTrait(*this, M));
+ Info.NameLookupTableData = ASTDeclContextNameLookupTable::Create(
+ (const unsigned char *)Blob.data() + Record[0],
+ (const unsigned char *)Blob.data() + sizeof(uint32_t),
+ (const unsigned char *)Blob.data(),
+ ASTDeclContextNameLookupTrait(*this, M));
}
return false;
@@ -1023,8 +1254,8 @@ bool ASTReader::ReadSLocEntry(int ID) {
llvm::MemoryBuffer *Buffer
= llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), Name);
- SourceMgr.createFileIDForMemBuffer(Buffer, FileCharacter, ID,
- BaseOffset + Offset, IncludeLoc);
+ SourceMgr.createFileID(Buffer, FileCharacter, ID, BaseOffset + Offset,
+ IncludeLoc);
break;
}
@@ -1059,7 +1290,7 @@ std::pair<SourceLocation, StringRef> ASTReader::getModuleImportLoc(int ID) {
// FIXME: Can we map this down to a particular submodule? That would be
// ideal.
- return std::make_pair(M->ImportLoc, llvm::sys::path::stem(M->FileName));
+ return std::make_pair(M->ImportLoc, StringRef(M->ModuleName));
}
/// \brief Find the location where the module F is imported.
@@ -1070,14 +1301,10 @@ SourceLocation ASTReader::getImportLocation(ModuleFile *F) {
// Otherwise we have a PCH. It's considered to be "imported" at the first
// location of its includer.
if (F->ImportedBy.empty() || !F->ImportedBy[0]) {
- // Main file is the importer. We assume that it is the first entry in the
- // entry table. We can't ask the manager, because at the time of PCH loading
- // the main file entry doesn't exist yet.
- // The very first entry is the invalid instantiation loc, which takes up
- // offsets 0 and 1.
- return SourceLocation::getFromRawEncoding(2U);
- }
- //return F->Loaders[0]->FirstLoc;
+ // Main file is the importer.
+ assert(!SourceMgr.getMainFileID().isInvalid() && "missing main file");
+ return SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
+ }
return F->ImportedBy[0]->FirstLoc;
}
@@ -1126,7 +1353,7 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
Stream.JumpToBit(Offset);
RecordData Record;
SmallVector<IdentifierInfo*, 16> MacroArgs;
- MacroInfo *Macro = 0;
+ MacroInfo *Macro = nullptr;
while (true) {
// Advance to the next record, but if we get to the end of the block, don't
@@ -1169,6 +1396,7 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
MacroInfo *MI = PP.AllocateDeserializedMacroInfo(Loc, SubModID);
MI->setDefinitionEndLoc(ReadSourceLocation(F, Record, NextIndex));
MI->setIsUsed(Record[NextIndex++]);
+ MI->setUsedForHeaderGuard(Record[NextIndex++]);
if (RecType == PP_MACRO_FUNCTION_LIKE) {
// Decode function-like macro info.
@@ -1214,7 +1442,7 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
case PP_TOKEN: {
// If we see a TOKEN before a PP_MACRO_*, then the file is
// erroneous, just pretend we didn't see this.
- if (Macro == 0) break;
+ if (!Macro) break;
unsigned Idx = 0;
Token Tok = ReadToken(F, Record, Idx);
@@ -1262,16 +1490,18 @@ bool HeaderFileInfoTrait::EqualKey(internal_key_ref a, internal_key_ref b) {
std::pair<unsigned, unsigned>
HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) {
- unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d);
+ using namespace llvm::support;
+ unsigned KeyLen = (unsigned) endian::readNext<uint16_t, little, unaligned>(d);
unsigned DataLen = (unsigned) *d++;
return std::make_pair(KeyLen, DataLen);
}
HeaderFileInfoTrait::internal_key_type
HeaderFileInfoTrait::ReadKey(const unsigned char *d, unsigned) {
+ using namespace llvm::support;
internal_key_type ikey;
- ikey.Size = off_t(clang::io::ReadUnalignedLE64(d));
- ikey.ModTime = time_t(clang::io::ReadUnalignedLE64(d));
+ ikey.Size = off_t(endian::readNext<uint64_t, little, unaligned>(d));
+ ikey.ModTime = time_t(endian::readNext<uint64_t, little, unaligned>(d));
ikey.Filename = (const char *)d;
return ikey;
}
@@ -1280,7 +1510,7 @@ HeaderFileInfoTrait::data_type
HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
unsigned DataLen) {
const unsigned char *End = d + DataLen;
- using namespace clang::io;
+ using namespace llvm::support;
HeaderFileInfo HFI;
unsigned Flags = *d++;
HFI.HeaderRole = static_cast<ModuleMap::ModuleHeaderRole>
@@ -1290,10 +1520,11 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
HFI.DirInfo = (Flags >> 2) & 0x03;
HFI.Resolved = (Flags >> 1) & 0x01;
HFI.IndexHeaderMapHeader = Flags & 0x01;
- HFI.NumIncludes = ReadUnalignedLE16(d);
- HFI.ControllingMacroID = Reader.getGlobalIdentifierID(M,
- ReadUnalignedLE32(d));
- if (unsigned FrameworkOffset = ReadUnalignedLE32(d)) {
+ HFI.NumIncludes = endian::readNext<uint16_t, little, unaligned>(d);
+ HFI.ControllingMacroID = Reader.getGlobalIdentifierID(
+ M, endian::readNext<uint32_t, little, unaligned>(d));
+ if (unsigned FrameworkOffset =
+ endian::readNext<uint32_t, little, unaligned>(d)) {
// The framework offset is 1 greater than the actual offset,
// since 0 is used as an indicator for "no framework name".
StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1);
@@ -1301,7 +1532,7 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
}
if (d != End) {
- uint32_t LocalSMID = ReadUnalignedLE32(d);
+ uint32_t LocalSMID = endian::readNext<uint32_t, little, unaligned>(d);
if (LocalSMID) {
// This header is part of a module. Associate it with the module to enable
// implicit module import.
@@ -1323,12 +1554,19 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
return HFI;
}
-void ASTReader::addPendingMacroFromModule(IdentifierInfo *II,
- ModuleFile *M,
- GlobalMacroID GMacID,
- SourceLocation ImportLoc) {
+void
+ASTReader::addPendingMacroFromModule(IdentifierInfo *II, ModuleFile *M,
+ GlobalMacroID GMacID,
+ ArrayRef<SubmoduleID> Overrides) {
assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard");
- PendingMacroIDs[II].push_back(PendingMacroInfo(M, GMacID, ImportLoc));
+ SubmoduleID *OverrideData = nullptr;
+ if (!Overrides.empty()) {
+ OverrideData = new (Context) SubmoduleID[Overrides.size() + 1];
+ OverrideData[0] = Overrides.size();
+ for (unsigned I = 0; I != Overrides.size(); ++I)
+ OverrideData[I + 1] = getGlobalSubmoduleID(*M, Overrides[I]);
+ }
+ PendingMacroIDs[II].push_back(PendingMacroInfo(M, GMacID, OverrideData));
}
void ASTReader::addPendingMacroFromPCH(IdentifierInfo *II,
@@ -1452,7 +1690,7 @@ void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) {
// If there is a global index, look there first to determine which modules
// provably do not have any results for this identifier.
GlobalModuleIndex::HitSet Hits;
- GlobalModuleIndex::HitSet *HitsPtr = 0;
+ GlobalModuleIndex::HitSet *HitsPtr = nullptr;
if (!loadGlobalIndex()) {
if (GlobalIndex->lookupIdentifier(II.getName(), Hits)) {
HitsPtr = &Hits;
@@ -1474,7 +1712,60 @@ void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) {
// Update the generation for this identifier.
if (getContext().getLangOpts().Modules)
- IdentifierGeneration[II] = CurrentGeneration;
+ IdentifierGeneration[II] = getGeneration();
+}
+
+struct ASTReader::ModuleMacroInfo {
+ SubmoduleID SubModID;
+ MacroInfo *MI;
+ SubmoduleID *Overrides;
+ // FIXME: Remove this.
+ ModuleFile *F;
+
+ bool isDefine() const { return MI; }
+
+ SubmoduleID getSubmoduleID() const { return SubModID; }
+
+ ArrayRef<SubmoduleID> getOverriddenSubmodules() const {
+ if (!Overrides)
+ return None;
+ return llvm::makeArrayRef(Overrides + 1, *Overrides);
+ }
+
+ DefMacroDirective *import(Preprocessor &PP, SourceLocation ImportLoc) const {
+ if (!MI)
+ return nullptr;
+ return PP.AllocateDefMacroDirective(MI, ImportLoc, /*isImported=*/true);
+ }
+};
+
+ASTReader::ModuleMacroInfo *
+ASTReader::getModuleMacro(const PendingMacroInfo &PMInfo) {
+ ModuleMacroInfo Info;
+
+ uint32_t ID = PMInfo.ModuleMacroData.MacID;
+ if (ID & 1) {
+ // Macro undefinition.
+ Info.SubModID = getGlobalSubmoduleID(*PMInfo.M, ID >> 1);
+ Info.MI = nullptr;
+ } else {
+ // Macro definition.
+ GlobalMacroID GMacID = getGlobalMacroID(*PMInfo.M, ID >> 1);
+ assert(GMacID);
+
+ // If this macro has already been loaded, don't do so again.
+ // FIXME: This is highly dubious. Multiple macro definitions can have the
+ // same MacroInfo (and hence the same GMacID) due to #pragma push_macro etc.
+ if (MacrosLoaded[GMacID - NUM_PREDEF_MACRO_IDS])
+ return nullptr;
+
+ Info.MI = getMacro(GMacID);
+ Info.SubModID = Info.MI->getOwningModuleID();
+ }
+ Info.Overrides = PMInfo.ModuleMacroData.Overrides;
+ Info.F = PMInfo.M;
+
+ return new (Context) ModuleMacroInfo(Info);
}
void ASTReader::resolvePendingMacro(IdentifierInfo *II,
@@ -1486,42 +1777,21 @@ void ASTReader::resolvePendingMacro(IdentifierInfo *II,
PMInfo.PCHMacroData.MacroDirectivesOffset);
return;
}
-
- // Module Macro.
- GlobalMacroID GMacID = PMInfo.ModuleMacroData.GMacID;
- SourceLocation ImportLoc =
- SourceLocation::getFromRawEncoding(PMInfo.ModuleMacroData.ImportLoc);
+ // Module Macro.
- assert(GMacID);
- // If this macro has already been loaded, don't do so again.
- if (MacrosLoaded[GMacID - NUM_PREDEF_MACRO_IDS])
+ ModuleMacroInfo *MMI = getModuleMacro(PMInfo);
+ if (!MMI)
return;
- MacroInfo *MI = getMacro(GMacID);
- SubmoduleID SubModID = MI->getOwningModuleID();
- MacroDirective *MD = PP.AllocateDefMacroDirective(MI, ImportLoc,
- /*isImported=*/true);
-
- // Determine whether this macro definition is visible.
- bool Hidden = false;
- Module *Owner = 0;
- if (SubModID) {
- if ((Owner = getSubmodule(SubModID))) {
- if (Owner->NameVisibility == Module::Hidden) {
- // The owning module is not visible, and this macro definition
- // should not be, either.
- Hidden = true;
-
- // Note that this macro definition was hidden because its owning
- // module is not yet visible.
- HiddenNamesMap[Owner].push_back(HiddenName(II, MD));
- }
- }
+ Module *Owner = getSubmodule(MMI->getSubmoduleID());
+ if (Owner && Owner->NameVisibility == Module::Hidden) {
+ // Macros in the owning module are hidden. Just remember this macro to
+ // install if we make this module visible.
+ HiddenNamesMap[Owner].HiddenMacros.insert(std::make_pair(II, MMI));
+ } else {
+ installImportedMacro(II, MMI, Owner, /*FromFinalization*/false);
}
-
- if (!Hidden)
- installImportedMacro(II, MD, Owner);
}
void ASTReader::installPCHMacroDirectives(IdentifierInfo *II,
@@ -1548,10 +1818,10 @@ void ASTReader::installPCHMacroDirectives(IdentifierInfo *II,
}
// Deserialize the macro directives history in reverse source-order.
- MacroDirective *Latest = 0, *Earliest = 0;
+ MacroDirective *Latest = nullptr, *Earliest = nullptr;
unsigned Idx = 0, N = Record.size();
while (Idx < N) {
- MacroDirective *MD = 0;
+ MacroDirective *MD = nullptr;
SourceLocation Loc = ReadSourceLocation(M, Record, Idx);
MacroDirective::Kind K = (MacroDirective::Kind)Record[Idx++];
switch (K) {
@@ -1591,7 +1861,7 @@ void ASTReader::installPCHMacroDirectives(IdentifierInfo *II,
static bool areDefinedInSystemModules(MacroInfo *PrevMI, MacroInfo *NewMI,
Module *NewOwner, ASTReader &Reader) {
assert(PrevMI && NewMI);
- Module *PrevOwner = 0;
+ Module *PrevOwner = nullptr;
if (SubmoduleID PrevModID = PrevMI->getOwningModuleID())
PrevOwner = Reader.getSubmodule(PrevModID);
SourceManager &SrcMgr = Reader.getSourceManager();
@@ -1606,34 +1876,181 @@ static bool areDefinedInSystemModules(MacroInfo *PrevMI, MacroInfo *NewMI,
return PrevInSystem && NewInSystem;
}
-void ASTReader::installImportedMacro(IdentifierInfo *II, MacroDirective *MD,
- Module *Owner) {
- assert(II && MD);
+void ASTReader::removeOverriddenMacros(IdentifierInfo *II,
+ AmbiguousMacros &Ambig,
+ ArrayRef<SubmoduleID> Overrides) {
+ for (unsigned OI = 0, ON = Overrides.size(); OI != ON; ++OI) {
+ SubmoduleID OwnerID = Overrides[OI];
+
+ // If this macro is not yet visible, remove it from the hidden names list.
+ Module *Owner = getSubmodule(OwnerID);
+ HiddenNames &Hidden = HiddenNamesMap[Owner];
+ HiddenMacrosMap::iterator HI = Hidden.HiddenMacros.find(II);
+ if (HI != Hidden.HiddenMacros.end()) {
+ auto SubOverrides = HI->second->getOverriddenSubmodules();
+ Hidden.HiddenMacros.erase(HI);
+ removeOverriddenMacros(II, Ambig, SubOverrides);
+ }
+
+ // If this macro is already in our list of conflicts, remove it from there.
+ Ambig.erase(
+ std::remove_if(Ambig.begin(), Ambig.end(), [&](DefMacroDirective *MD) {
+ return MD->getInfo()->getOwningModuleID() == OwnerID;
+ }),
+ Ambig.end());
+ }
+}
- DefMacroDirective *DefMD = cast<DefMacroDirective>(MD);
+ASTReader::AmbiguousMacros *
+ASTReader::removeOverriddenMacros(IdentifierInfo *II,
+ ArrayRef<SubmoduleID> Overrides) {
MacroDirective *Prev = PP.getMacroDirective(II);
- if (Prev) {
- MacroDirective::DefInfo PrevDef = Prev->getDefinition();
- MacroInfo *PrevMI = PrevDef.getMacroInfo();
- MacroInfo *NewMI = DefMD->getInfo();
- if (NewMI != PrevMI && !PrevMI->isIdenticalTo(*NewMI, PP,
- /*Syntactically=*/true)) {
- // Before marking the macros as ambiguous, check if this is a case where
- // both macros are in system headers. If so, we trust that the system
- // did not get it wrong. This also handles cases where Clang's own
- // headers have a different spelling of certain system macros:
- // #define LONG_MAX __LONG_MAX__ (clang's limits.h)
- // #define LONG_MAX 0x7fffffffffffffffL (system's limits.h)
- if (!areDefinedInSystemModules(PrevMI, NewMI, Owner, *this)) {
- PrevDef.getDirective()->setAmbiguous(true);
- DefMD->setAmbiguous(true);
- }
+ if (!Prev && Overrides.empty())
+ return nullptr;
+
+ DefMacroDirective *PrevDef = Prev ? Prev->getDefinition().getDirective()
+ : nullptr;
+ if (PrevDef && PrevDef->isAmbiguous()) {
+ // We had a prior ambiguity. Check whether we resolve it (or make it worse).
+ AmbiguousMacros &Ambig = AmbiguousMacroDefs[II];
+ Ambig.push_back(PrevDef);
+
+ removeOverriddenMacros(II, Ambig, Overrides);
+
+ if (!Ambig.empty())
+ return &Ambig;
+
+ AmbiguousMacroDefs.erase(II);
+ } else {
+ // There's no ambiguity yet. Maybe we're introducing one.
+ AmbiguousMacros Ambig;
+ if (PrevDef)
+ Ambig.push_back(PrevDef);
+
+ removeOverriddenMacros(II, Ambig, Overrides);
+
+ if (!Ambig.empty()) {
+ AmbiguousMacros &Result = AmbiguousMacroDefs[II];
+ std::swap(Result, Ambig);
+ return &Result;
}
}
-
+
+ // We ended up with no ambiguity.
+ return nullptr;
+}
+
+void ASTReader::installImportedMacro(IdentifierInfo *II, ModuleMacroInfo *MMI,
+ Module *Owner, bool FromFinalization) {
+ assert(II && Owner);
+
+ SourceLocation ImportLoc = Owner->MacroVisibilityLoc;
+ if (ImportLoc.isInvalid() && !FromFinalization) {
+ // FIXME: If we made macros from this module visible but didn't provide a
+ // source location for the import, we don't have a location for the macro.
+ // Use the location at which the containing module file was first imported
+ // for now.
+ ImportLoc = MMI->F->DirectImportLoc;
+ assert(ImportLoc.isValid() && "no import location for a visible macro?");
+ }
+
+ AmbiguousMacros *Prev =
+ removeOverriddenMacros(II, MMI->getOverriddenSubmodules());
+
+ // Create a synthetic macro definition corresponding to the import (or null
+ // if this was an undefinition of the macro).
+ DefMacroDirective *MD = MMI->import(PP, ImportLoc);
+
+ // If there's no ambiguity, just install the macro.
+ if (!Prev) {
+ if (MD)
+ PP.appendMacroDirective(II, MD);
+ else
+ PP.appendMacroDirective(II, PP.AllocateUndefMacroDirective(ImportLoc));
+ return;
+ }
+ assert(!Prev->empty());
+
+ if (!MD) {
+ // We imported a #undef that didn't remove all prior definitions. The most
+ // recent prior definition remains, and we install it in the place of the
+ // imported directive.
+ MacroInfo *NewMI = Prev->back()->getInfo();
+ Prev->pop_back();
+ MD = PP.AllocateDefMacroDirective(NewMI, ImportLoc, /*Imported*/true);
+ }
+
+ // We're introducing a macro definition that creates or adds to an ambiguity.
+ // We can resolve that ambiguity if this macro is token-for-token identical to
+ // all of the existing definitions.
+ MacroInfo *NewMI = MD->getInfo();
+ assert(NewMI && "macro definition with no MacroInfo?");
+ while (!Prev->empty()) {
+ MacroInfo *PrevMI = Prev->back()->getInfo();
+ assert(PrevMI && "macro definition with no MacroInfo?");
+
+ // Before marking the macros as ambiguous, check if this is a case where
+ // both macros are in system headers. If so, we trust that the system
+ // did not get it wrong. This also handles cases where Clang's own
+ // headers have a different spelling of certain system macros:
+ // #define LONG_MAX __LONG_MAX__ (clang's limits.h)
+ // #define LONG_MAX 0x7fffffffffffffffL (system's limits.h)
+ //
+ // FIXME: Remove the defined-in-system-headers check. clang's limits.h
+ // overrides the system limits.h's macros, so there's no conflict here.
+ if (NewMI != PrevMI &&
+ !PrevMI->isIdenticalTo(*NewMI, PP, /*Syntactically=*/true) &&
+ !areDefinedInSystemModules(PrevMI, NewMI, Owner, *this))
+ break;
+
+ // The previous definition is the same as this one (or both are defined in
+ // system modules so we can assume they're equivalent); we don't need to
+ // track it any more.
+ Prev->pop_back();
+ }
+
+ if (!Prev->empty())
+ MD->setAmbiguous(true);
+
PP.appendMacroDirective(II, MD);
}
+ASTReader::InputFileInfo
+ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) {
+ // Go find this input file.
+ BitstreamCursor &Cursor = F.InputFilesCursor;
+ SavedStreamPosition SavedPosition(Cursor);
+ Cursor.JumpToBit(F.InputFileOffsets[ID-1]);
+
+ unsigned Code = Cursor.ReadCode();
+ RecordData Record;
+ StringRef Blob;
+
+ unsigned Result = Cursor.readRecord(Code, Record, &Blob);
+ assert(static_cast<InputFileRecordTypes>(Result) == INPUT_FILE &&
+ "invalid record type for input file");
+ (void)Result;
+
+ std::string Filename;
+ off_t StoredSize;
+ time_t StoredTime;
+ bool Overridden;
+
+ assert(Record[0] == ID && "Bogus stored ID or offset");
+ StoredSize = static_cast<off_t>(Record[1]);
+ StoredTime = static_cast<time_t>(Record[2]);
+ Overridden = static_cast<bool>(Record[3]);
+ Filename = Blob;
+ MaybeAddSystemRootToFilename(F, Filename);
+
+ InputFileInfo R = { std::move(Filename), StoredSize, StoredTime, Overridden };
+ return R;
+}
+
+std::string ASTReader::getInputFileName(ModuleFile &F, unsigned int ID) {
+ return readInputFileInfo(F, ID).Filename;
+}
+
InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
// If this ID is bogus, just return an empty input file.
if (ID == 0 || ID > F.InputFilesLoaded.size())
@@ -1643,107 +2060,113 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
if (F.InputFilesLoaded[ID-1].getFile())
return F.InputFilesLoaded[ID-1];
+ if (F.InputFilesLoaded[ID-1].isNotFound())
+ return InputFile();
+
// Go find this input file.
BitstreamCursor &Cursor = F.InputFilesCursor;
SavedStreamPosition SavedPosition(Cursor);
Cursor.JumpToBit(F.InputFileOffsets[ID-1]);
- unsigned Code = Cursor.ReadCode();
- RecordData Record;
- StringRef Blob;
- switch ((InputFileRecordTypes)Cursor.readRecord(Code, Record, &Blob)) {
- case INPUT_FILE: {
- unsigned StoredID = Record[0];
- assert(ID == StoredID && "Bogus stored ID or offset");
- (void)StoredID;
- off_t StoredSize = (off_t)Record[1];
- time_t StoredTime = (time_t)Record[2];
- bool Overridden = (bool)Record[3];
-
- // Get the file entry for this input file.
- StringRef OrigFilename = Blob;
- std::string Filename = OrigFilename;
- MaybeAddSystemRootToFilename(F, Filename);
- const FileEntry *File
- = Overridden? FileMgr.getVirtualFile(Filename, StoredSize, StoredTime)
- : FileMgr.getFile(Filename, /*OpenFile=*/false);
-
- // If we didn't find the file, resolve it relative to the
- // original directory from which this AST file was created.
- if (File == 0 && !F.OriginalDir.empty() && !CurrentDir.empty() &&
- F.OriginalDir != CurrentDir) {
- std::string Resolved = resolveFileRelativeToOriginalDir(Filename,
- F.OriginalDir,
- CurrentDir);
- if (!Resolved.empty())
- File = FileMgr.getFile(Resolved);
- }
-
- // For an overridden file, create a virtual file with the stored
- // size/timestamp.
- if (Overridden && File == 0) {
- File = FileMgr.getVirtualFile(Filename, StoredSize, StoredTime);
- }
-
- if (File == 0) {
- if (Complain) {
- std::string ErrorStr = "could not find file '";
- ErrorStr += Filename;
- ErrorStr += "' referenced by AST file";
- Error(ErrorStr.c_str());
- }
- return InputFile();
- }
+ InputFileInfo FI = readInputFileInfo(F, ID);
+ off_t StoredSize = FI.StoredSize;
+ time_t StoredTime = FI.StoredTime;
+ bool Overridden = FI.Overridden;
+ StringRef Filename = FI.Filename;
+
+ const FileEntry *File
+ = Overridden? FileMgr.getVirtualFile(Filename, StoredSize, StoredTime)
+ : FileMgr.getFile(Filename, /*OpenFile=*/false);
+
+ // If we didn't find the file, resolve it relative to the
+ // original directory from which this AST file was created.
+ if (File == nullptr && !F.OriginalDir.empty() && !CurrentDir.empty() &&
+ F.OriginalDir != CurrentDir) {
+ std::string Resolved = resolveFileRelativeToOriginalDir(Filename,
+ F.OriginalDir,
+ CurrentDir);
+ if (!Resolved.empty())
+ File = FileMgr.getFile(Resolved);
+ }
- // Check if there was a request to override the contents of the file
- // that was part of the precompiled header. Overridding such a file
- // can lead to problems when lexing using the source locations from the
- // PCH.
- SourceManager &SM = getSourceManager();
- if (!Overridden && SM.isFileOverridden(File)) {
- if (Complain)
- Error(diag::err_fe_pch_file_overridden, Filename);
- // After emitting the diagnostic, recover by disabling the override so
- // that the original file will be used.
- SM.disableFileContentsOverride(File);
- // The FileEntry is a virtual file entry with the size of the contents
- // that would override the original contents. Set it to the original's
- // size/time.
- FileMgr.modifyFileEntry(const_cast<FileEntry*>(File),
- StoredSize, StoredTime);
- }
+ // For an overridden file, create a virtual file with the stored
+ // size/timestamp.
+ if (Overridden && File == nullptr) {
+ File = FileMgr.getVirtualFile(Filename, StoredSize, StoredTime);
+ }
- bool IsOutOfDate = false;
+ if (File == nullptr) {
+ if (Complain) {
+ std::string ErrorStr = "could not find file '";
+ ErrorStr += Filename;
+ ErrorStr += "' referenced by AST file";
+ Error(ErrorStr.c_str());
+ }
+ // Record that we didn't find the file.
+ F.InputFilesLoaded[ID-1] = InputFile::getNotFound();
+ return InputFile();
+ }
- // For an overridden file, there is nothing to validate.
- if (!Overridden && (StoredSize != File->getSize()
+ // Check if there was a request to override the contents of the file
+ // that was part of the precompiled header. Overridding such a file
+ // can lead to problems when lexing using the source locations from the
+ // PCH.
+ SourceManager &SM = getSourceManager();
+ if (!Overridden && SM.isFileOverridden(File)) {
+ if (Complain)
+ Error(diag::err_fe_pch_file_overridden, Filename);
+ // After emitting the diagnostic, recover by disabling the override so
+ // that the original file will be used.
+ SM.disableFileContentsOverride(File);
+ // The FileEntry is a virtual file entry with the size of the contents
+ // that would override the original contents. Set it to the original's
+ // size/time.
+ FileMgr.modifyFileEntry(const_cast<FileEntry*>(File),
+ StoredSize, StoredTime);
+ }
+
+ bool IsOutOfDate = false;
+
+ // For an overridden file, there is nothing to validate.
+ if (!Overridden && (StoredSize != File->getSize()
#if !defined(LLVM_ON_WIN32)
- // In our regression testing, the Windows file system seems to
- // have inconsistent modification times that sometimes
- // erroneously trigger this error-handling path.
- || StoredTime != File->getModificationTime()
+ // In our regression testing, the Windows file system seems to
+ // have inconsistent modification times that sometimes
+ // erroneously trigger this error-handling path.
+ || StoredTime != File->getModificationTime()
#endif
- )) {
- if (Complain) {
- Error(diag::err_fe_pch_file_modified, Filename, F.FileName);
- if (Context.getLangOpts().Modules && !Diags.isDiagnosticInFlight()) {
- Diag(diag::note_module_cache_path)
- << PP.getHeaderSearchInfo().getModuleCachePath();
- }
+ )) {
+ if (Complain) {
+ // Build a list of the PCH imports that got us here (in reverse).
+ SmallVector<ModuleFile *, 4> ImportStack(1, &F);
+ while (ImportStack.back()->ImportedBy.size() > 0)
+ ImportStack.push_back(ImportStack.back()->ImportedBy[0]);
+
+ // The top-level PCH is stale.
+ StringRef TopLevelPCHName(ImportStack.back()->FileName);
+ Error(diag::err_fe_pch_file_modified, Filename, TopLevelPCHName);
+
+ // Print the import stack.
+ if (ImportStack.size() > 1 && !Diags.isDiagnosticInFlight()) {
+ Diag(diag::note_pch_required_by)
+ << Filename << ImportStack[0]->FileName;
+ for (unsigned I = 1; I < ImportStack.size(); ++I)
+ Diag(diag::note_pch_required_by)
+ << ImportStack[I-1]->FileName << ImportStack[I]->FileName;
}
- IsOutOfDate = true;
+ if (!Diags.isDiagnosticInFlight())
+ Diag(diag::note_pch_rebuild_required) << TopLevelPCHName;
}
- InputFile IF = InputFile(File, Overridden, IsOutOfDate);
-
- // Note that we've loaded this input file.
- F.InputFilesLoaded[ID-1] = IF;
- return IF;
- }
+ IsOutOfDate = true;
}
- return InputFile();
+ InputFile IF = InputFile(File, Overridden, IsOutOfDate);
+
+ // Note that we've loaded this input file.
+ F.InputFilesLoaded[ID-1] = IF;
+ return IF;
}
const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) {
@@ -1751,7 +2174,7 @@ const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) {
std::string Filename = filenameStrRef;
MaybeAddSystemRootToFilename(M, Filename);
const FileEntry *File = FileMgr.getFile(Filename);
- if (File == 0 && !M.OriginalDir.empty() && !CurrentDir.empty() &&
+ if (File == nullptr && !M.OriginalDir.empty() && !CurrentDir.empty() &&
M.OriginalDir != CurrentDir) {
std::string resolved = resolveFileRelativeToOriginalDir(Filename,
M.OriginalDir,
@@ -1791,6 +2214,7 @@ void ASTReader::MaybeAddSystemRootToFilename(ModuleFile &M,
ASTReader::ASTReadResult
ASTReader::ReadControlBlock(ModuleFile &F,
SmallVectorImpl<ImportedModule> &Loaded,
+ const ModuleFile *ImportedBy,
unsigned ClientLoadCapabilities) {
BitstreamCursor &Stream = F.Stream;
@@ -1808,20 +2232,54 @@ ASTReader::ReadControlBlock(ModuleFile &F,
case llvm::BitstreamEntry::Error:
Error("malformed block record in AST file");
return Failure;
- case llvm::BitstreamEntry::EndBlock:
- // Validate all of the non-system input files.
- if (!DisableValidation) {
+ case llvm::BitstreamEntry::EndBlock: {
+ // Validate input files.
+ const HeaderSearchOptions &HSOpts =
+ PP.getHeaderSearchInfo().getHeaderSearchOpts();
+
+ // All user input files reside at the index range [0, Record[1]), and
+ // system input files reside at [Record[1], Record[0]).
+ // Record is the one from INPUT_FILE_OFFSETS.
+ unsigned NumInputs = Record[0];
+ unsigned NumUserInputs = Record[1];
+
+ if (!DisableValidation &&
+ (ValidateSystemInputs || !HSOpts.ModulesValidateOncePerBuildSession ||
+ F.InputFilesValidationTimestamp <= HSOpts.BuildSessionTimestamp)) {
bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
- // All user input files reside at the index range [0, Record[1]).
- // Record is the one from INPUT_FILE_OFFSETS.
- for (unsigned I = 0, N = Record[1]; I < N; ++I) {
+
+ // If we are reading a module, we will create a verification timestamp,
+ // so we verify all input files. Otherwise, verify only user input
+ // files.
+
+ unsigned N = NumUserInputs;
+ if (ValidateSystemInputs ||
+ (HSOpts.ModulesValidateOncePerBuildSession && F.Kind == MK_Module))
+ N = NumInputs;
+
+ for (unsigned I = 0; I < N; ++I) {
InputFile IF = getInputFile(F, I+1, Complain);
if (!IF.getFile() || IF.isOutOfDate())
return OutOfDate;
}
}
+
+ if (Listener)
+ Listener->visitModuleFile(F.FileName);
+
+ if (Listener && Listener->needsInputFileVisitation()) {
+ unsigned N = Listener->needsSystemInputFileVisitation() ? NumInputs
+ : NumUserInputs;
+ for (unsigned I = 0; I < N; ++I) {
+ bool IsSystem = I >= NumUserInputs;
+ InputFileInfo FI = readInputFileInfo(F, I+1);
+ Listener->visitInputFile(FI.Filename, IsSystem, FI.Overridden);
+ }
+ }
+
return Success;
-
+ }
+
case llvm::BitstreamEntry::SubBlock:
switch (Entry.ID) {
case INPUT_FILES_BLOCK_ID:
@@ -1854,8 +2312,8 @@ ASTReader::ReadControlBlock(ModuleFile &F,
case METADATA: {
if (Record[0] != VERSION_MAJOR && !DisableValidation) {
if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
- Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old
- : diag::warn_pch_version_too_new);
+ Diag(Record[0] < VERSION_MAJOR? diag::err_pch_version_too_old
+ : diag::err_pch_version_too_new);
return VersionMismatch;
}
@@ -1871,7 +2329,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
StringRef ASTBranch = Blob;
if (StringRef(CurBranch) != ASTBranch && !DisableValidation) {
if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
- Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch;
+ Diag(diag::err_pch_different_branch) << ASTBranch << CurBranch;
return VersionMismatch;
}
break;
@@ -1916,7 +2374,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
if (Listener && &F == *ModuleMgr.begin() &&
ParseLanguageOptions(Record, Complain, *Listener) &&
- !DisableValidation)
+ !DisableValidation && !AllowConfigurationMismatch)
return ConfigurationMismatch;
break;
}
@@ -1925,17 +2383,17 @@ ASTReader::ReadControlBlock(ModuleFile &F,
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
if (Listener && &F == *ModuleMgr.begin() &&
ParseTargetOptions(Record, Complain, *Listener) &&
- !DisableValidation)
+ !DisableValidation && !AllowConfigurationMismatch)
return ConfigurationMismatch;
break;
}
case DIAGNOSTIC_OPTIONS: {
- bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+ bool Complain = (ClientLoadCapabilities & ARR_OutOfDate)==0;
if (Listener && &F == *ModuleMgr.begin() &&
ParseDiagnosticOptions(Record, Complain, *Listener) &&
!DisableValidation)
- return ConfigurationMismatch;
+ return OutOfDate;
break;
}
@@ -1943,7 +2401,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
if (Listener && &F == *ModuleMgr.begin() &&
ParseFileSystemOptions(Record, Complain, *Listener) &&
- !DisableValidation)
+ !DisableValidation && !AllowConfigurationMismatch)
return ConfigurationMismatch;
break;
}
@@ -1952,7 +2410,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
if (Listener && &F == *ModuleMgr.begin() &&
ParseHeaderSearchOptions(Record, Complain, *Listener) &&
- !DisableValidation)
+ !DisableValidation && !AllowConfigurationMismatch)
return ConfigurationMismatch;
break;
}
@@ -1962,7 +2420,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
if (Listener && &F == *ModuleMgr.begin() &&
ParsePreprocessorOptions(Record, Complain, *Listener,
SuggestedPredefines) &&
- !DisableValidation)
+ !DisableValidation && !AllowConfigurationMismatch)
return ConfigurationMismatch;
break;
}
@@ -1982,6 +2440,49 @@ ASTReader::ReadControlBlock(ModuleFile &F,
F.OriginalDir = Blob;
break;
+ case MODULE_NAME:
+ F.ModuleName = Blob;
+ if (Listener)
+ Listener->ReadModuleName(F.ModuleName);
+ break;
+
+ case MODULE_MAP_FILE:
+ F.ModuleMapPath = Blob;
+
+ // Try to resolve ModuleName in the current header search context and
+ // verify that it is found in the same module map file as we saved. If the
+ // top-level AST file is a main file, skip this check because there is no
+ // usable header search context.
+ assert(!F.ModuleName.empty() &&
+ "MODULE_NAME should come before MOUDLE_MAP_FILE");
+ if (F.Kind == MK_Module &&
+ (*ModuleMgr.begin())->Kind != MK_MainFile) {
+ Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName);
+ if (!M) {
+ assert(ImportedBy && "top-level import should be verified");
+ if ((ClientLoadCapabilities & ARR_Missing) == 0)
+ Diag(diag::err_imported_module_not_found)
+ << F.ModuleName << ImportedBy->FileName;
+ return Missing;
+ }
+
+ const FileEntry *StoredModMap = FileMgr.getFile(F.ModuleMapPath);
+ if (StoredModMap == nullptr || StoredModMap != M->ModuleMap) {
+ assert(M->ModuleMap && "found module is missing module map file");
+ assert(M->Name == F.ModuleName && "found module with different name");
+ assert(ImportedBy && "top-level import should be verified");
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Diag(diag::err_imported_module_modmap_changed)
+ << F.ModuleName << ImportedBy->FileName
+ << M->ModuleMap->getName() << F.ModuleMapPath;
+ return OutOfDate;
+ }
+ }
+
+ if (Listener)
+ Listener->ReadModuleMapFile(F.ModuleMapPath);
+ break;
+
case INPUT_FILE_OFFSETS:
F.InputFileOffsets = (const uint32_t *)Blob.data();
F.InputFilesLoaded.resize(Record[0]);
@@ -1990,12 +2491,13 @@ ASTReader::ReadControlBlock(ModuleFile &F,
}
}
-bool ASTReader::ReadASTBlock(ModuleFile &F) {
+ASTReader::ASTReadResult
+ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
BitstreamCursor &Stream = F.Stream;
if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
Error("malformed block record in AST file");
- return true;
+ return Failure;
}
// Read all of the records and blocks for the AST file.
@@ -2006,7 +2508,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
switch (Entry.Kind) {
case llvm::BitstreamEntry::Error:
Error("error at end of module block in AST file");
- return true;
+ return Failure;
case llvm::BitstreamEntry::EndBlock: {
// Outside of C++, we do not store a lookup map for the translation unit.
// Instead, mark it as needing a lookup map to be built if this module
@@ -2018,7 +2520,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
!getContext().getLangOpts().CPlusPlus)
DC->setMustBuildLookupTable();
- return false;
+ return Success;
}
case llvm::BitstreamEntry::SubBlock:
switch (Entry.ID) {
@@ -2032,17 +2534,10 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
// Read the abbrevs.
ReadBlockAbbrevs(F.DeclsCursor, DECLTYPES_BLOCK_ID)) {
Error("malformed block record in AST file");
- return true;
- }
- break;
-
- case DECL_UPDATES_BLOCK_ID:
- if (Stream.SkipBlock()) {
- Error("malformed block record in AST file");
- return true;
+ return Failure;
}
break;
-
+
case PREPROCESSOR_BLOCK_ID:
F.MacroCursor = Stream;
if (!PP.getExternalSource())
@@ -2051,7 +2546,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
if (Stream.SkipBlock() ||
ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) {
Error("malformed block record in AST file");
- return true;
+ return Failure;
}
F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo();
break;
@@ -2062,7 +2557,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
ReadBlockAbbrevs(F.PreprocessorDetailCursor,
PREPROCESSOR_DETAIL_BLOCK_ID)) {
Error("malformed preprocessor detail record in AST file");
- return true;
+ return Failure;
}
F.PreprocessorDetailStartOffset
= F.PreprocessorDetailCursor.GetCurrentBitNo();
@@ -2075,12 +2570,12 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case SOURCE_MANAGER_BLOCK_ID:
if (ReadSourceManagerBlock(F))
- return true;
+ return Failure;
break;
case SUBMODULE_BLOCK_ID:
- if (ReadSubmoduleBlock(F))
- return true;
+ if (ASTReadResult Result = ReadSubmoduleBlock(F, ClientLoadCapabilities))
+ return Result;
break;
case COMMENTS_BLOCK_ID: {
@@ -2088,7 +2583,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
if (Stream.SkipBlock() ||
ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) {
Error("malformed comments block in AST file");
- return true;
+ return Failure;
}
CommentsCursors.push_back(std::make_pair(C, &F));
break;
@@ -2097,7 +2592,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
default:
if (Stream.SkipBlock()) {
Error("malformed block record in AST file");
- return true;
+ return Failure;
}
break;
}
@@ -2118,7 +2613,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case TYPE_OFFSET: {
if (F.LocalNumTypes != 0) {
Error("duplicate TYPE_OFFSET record in AST file");
- return true;
+ return Failure;
}
F.TypeOffsets = (const uint32_t *)Blob.data();
F.LocalNumTypes = Record[0];
@@ -2142,7 +2637,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case DECL_OFFSET: {
if (F.LocalNumDecls != 0) {
Error("duplicate DECL_OFFSET record in AST file");
- return true;
+ return Failure;
}
F.DeclOffsets = (const DeclOffset *)Blob.data();
F.LocalNumDecls = Record[0];
@@ -2183,14 +2678,18 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
unsigned Idx = 0;
serialization::DeclID ID = ReadDeclID(F, Record, Idx);
ASTDeclContextNameLookupTable *Table =
- ASTDeclContextNameLookupTable::Create(
- (const unsigned char *)Blob.data() + Record[Idx++],
- (const unsigned char *)Blob.data(),
- ASTDeclContextNameLookupTrait(*this, F));
- if (ID == PREDEF_DECL_TRANSLATION_UNIT_ID) { // Is it the TU?
- DeclContext *TU = Context.getTranslationUnitDecl();
- F.DeclContextInfos[TU].NameLookupTableData = Table;
- TU->setHasExternalVisibleStorage(true);
+ ASTDeclContextNameLookupTable::Create(
+ (const unsigned char *)Blob.data() + Record[Idx++],
+ (const unsigned char *)Blob.data() + sizeof(uint32_t),
+ (const unsigned char *)Blob.data(),
+ ASTDeclContextNameLookupTrait(*this, F));
+ if (Decl *D = GetExistingDecl(ID)) {
+ auto *DC = cast<DeclContext>(D);
+ DC->getPrimaryContext()->setHasExternalVisibleStorage(true);
+ auto *&LookupTable = F.DeclContextInfos[DC].NameLookupTableData;
+ // FIXME: There should never be an existing lookup table.
+ delete LookupTable;
+ LookupTable = Table;
} else
PendingVisibleUpdates[ID].push_back(std::make_pair(Table, &F));
break;
@@ -2199,11 +2698,11 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case IDENTIFIER_TABLE:
F.IdentifierTableData = Blob.data();
if (Record[0]) {
- F.IdentifierLookupTable
- = ASTIdentifierLookupTable::Create(
- (const unsigned char *)F.IdentifierTableData + Record[0],
- (const unsigned char *)F.IdentifierTableData,
- ASTIdentifierLookupTrait(*this, F));
+ F.IdentifierLookupTable = ASTIdentifierLookupTable::Create(
+ (const unsigned char *)F.IdentifierTableData + Record[0],
+ (const unsigned char *)F.IdentifierTableData + sizeof(uint32_t),
+ (const unsigned char *)F.IdentifierTableData,
+ ASTIdentifierLookupTrait(*this, F));
PP.getIdentifierTable().setExternalIdentifierLookup(this);
}
@@ -2212,7 +2711,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case IDENTIFIER_OFFSET: {
if (F.LocalNumIdentifiers != 0) {
Error("duplicate IDENTIFIER_OFFSET record in AST file");
- return true;
+ return Failure;
}
F.IdentifierOffsets = (const uint32_t *)Blob.data();
F.LocalNumIdentifiers = Record[0];
@@ -2237,9 +2736,9 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
break;
}
- case EXTERNAL_DEFINITIONS:
+ case EAGERLY_DESERIALIZED_DECLS:
for (unsigned I = 0, N = Record.size(); I != N; ++I)
- ExternalDefinitions.push_back(getGlobalDeclID(F, Record[I]));
+ EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I]));
break;
case SPECIAL_TYPES:
@@ -2251,7 +2750,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
if (SpecialTypes.size() != Record.size()) {
Error("invalid special-types record");
- return true;
+ return Failure;
}
for (unsigned I = 0, N = Record.size(); I != N; ++I) {
@@ -2283,7 +2782,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case WEAK_UNDECLARED_IDENTIFIERS:
if (Record.size() % 4 != 0) {
Error("invalid weak identifiers record");
- return true;
+ return Failure;
}
// FIXME: Ignore weak undeclared identifiers from non-original PCH
@@ -2365,7 +2864,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
F.SLocEntryOffsets = (const uint32_t *)Blob.data();
F.LocalNumSLocEntries = Record[0];
unsigned SLocSpaceSize = Record[1];
- llvm::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) =
+ std::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) =
SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries,
SLocSpaceSize);
// Make our entry in the range map. BaseID is negative and growing, so
@@ -2384,9 +2883,9 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
// Initialize the remapping table.
// Invalid stays invalid.
- F.SLocRemap.insert(std::make_pair(0U, 0));
+ F.SLocRemap.insertOrReplace(std::make_pair(0U, 0));
// This module. Base was 2 when being compiled.
- F.SLocRemap.insert(std::make_pair(2U,
+ F.SLocRemap.insertOrReplace(std::make_pair(2U,
static_cast<int>(F.SLocEntryBaseOffset - 2)));
TotalNumSLocEntries += F.LocalNumSLocEntries;
@@ -2397,7 +2896,13 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
// Additional remapping information.
const unsigned char *Data = (const unsigned char*)Blob.data();
const unsigned char *DataEnd = Data + Blob.size();
-
+
+ // If we see this entry before SOURCE_LOCATION_OFFSETS, add placeholders.
+ if (F.SLocRemap.find(0) == F.SLocRemap.end()) {
+ F.SLocRemap.insert(std::make_pair(0U, 0));
+ F.SLocRemap.insert(std::make_pair(2U, 1));
+ }
+
// Continuous range maps we may be updating in our module.
ContinuousRangeMap<uint32_t, int, 2>::Builder SLocRemap(F.SLocRemap);
ContinuousRangeMap<uint32_t, int, 2>::Builder
@@ -2414,24 +2919,33 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
ContinuousRangeMap<uint32_t, int, 2>::Builder TypeRemap(F.TypeRemap);
while(Data < DataEnd) {
- uint16_t Len = io::ReadUnalignedLE16(Data);
+ using namespace llvm::support;
+ uint16_t Len = endian::readNext<uint16_t, little, unaligned>(Data);
StringRef Name = StringRef((const char*)Data, Len);
Data += Len;
ModuleFile *OM = ModuleMgr.lookup(Name);
if (!OM) {
Error("SourceLocation remap refers to unknown module");
- return true;
+ return Failure;
}
- uint32_t SLocOffset = io::ReadUnalignedLE32(Data);
- uint32_t IdentifierIDOffset = io::ReadUnalignedLE32(Data);
- uint32_t MacroIDOffset = io::ReadUnalignedLE32(Data);
- uint32_t PreprocessedEntityIDOffset = io::ReadUnalignedLE32(Data);
- uint32_t SubmoduleIDOffset = io::ReadUnalignedLE32(Data);
- uint32_t SelectorIDOffset = io::ReadUnalignedLE32(Data);
- uint32_t DeclIDOffset = io::ReadUnalignedLE32(Data);
- uint32_t TypeIndexOffset = io::ReadUnalignedLE32(Data);
-
+ uint32_t SLocOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t IdentifierIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t MacroIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t PreprocessedEntityIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t SubmoduleIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t SelectorIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t DeclIDOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+ uint32_t TypeIndexOffset =
+ endian::readNext<uint32_t, little, unaligned>(Data);
+
// Source location offset is mapped to OM->SLocEntryBaseOffset.
SLocRemap.insert(std::make_pair(SLocOffset,
static_cast<int>(OM->SLocEntryBaseOffset - SLocOffset)));
@@ -2461,7 +2975,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case SOURCE_MANAGER_LINE_TABLE:
if (ParseLineTable(F, Record))
- return true;
+ return Failure;
break;
case SOURCE_LOCATION_PRELOADS: {
@@ -2469,7 +2983,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
// which is based off F.SLocEntryBaseID.
if (!F.PreloadSLocEntries.empty()) {
Error("Multiple SOURCE_LOCATION_PRELOADS records in AST file");
- return true;
+ return Failure;
}
F.PreloadSLocEntries.swap(Record);
@@ -2484,7 +2998,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case VTABLE_USES:
if (Record.size() % 3 != 0) {
Error("Invalid VTABLE_USES record");
- return true;
+ return Failure;
}
// Later tables overwrite earlier ones.
@@ -2508,12 +3022,12 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case PENDING_IMPLICIT_INSTANTIATIONS:
if (PendingInstantiations.size() % 2 != 0) {
Error("Invalid existing PendingInstantiations");
- return true;
+ return Failure;
}
if (Record.size() % 2 != 0) {
Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block");
- return true;
+ return Failure;
}
for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
@@ -2526,7 +3040,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case SEMA_DECL_REFS:
if (Record.size() != 2) {
Error("Invalid SEMA_DECL_REFS block");
- return true;
+ return Failure;
}
for (unsigned I = 0, N = Record.size(); I != N; ++I)
SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I]));
@@ -2567,18 +3081,24 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case DECL_UPDATE_OFFSETS: {
if (Record.size() % 2 != 0) {
Error("invalid DECL_UPDATE_OFFSETS block in AST file");
- return true;
+ return Failure;
+ }
+ for (unsigned I = 0, N = Record.size(); I != N; I += 2) {
+ GlobalDeclID ID = getGlobalDeclID(F, Record[I]);
+ DeclUpdateOffsets[ID].push_back(std::make_pair(&F, Record[I + 1]));
+
+ // If we've already loaded the decl, perform the updates when we finish
+ // loading this block.
+ if (Decl *D = GetExistingDecl(ID))
+ PendingUpdateRecords.push_back(std::make_pair(ID, D));
}
- for (unsigned I = 0, N = Record.size(); I != N; I += 2)
- DeclUpdateOffsets[getGlobalDeclID(F, Record[I])]
- .push_back(std::make_pair(&F, Record[I+1]));
break;
}
case DECL_REPLACEMENTS: {
if (Record.size() % 3 != 0) {
Error("invalid DECL_REPLACEMENTS block in AST file");
- return true;
+ return Failure;
}
for (unsigned I = 0, N = Record.size(); I != N; I += 3)
ReplacedDecls[getGlobalDeclID(F, Record[I])]
@@ -2589,7 +3109,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case OBJC_CATEGORIES_MAP: {
if (F.LocalNumObjCCategoriesInMap != 0) {
Error("duplicate OBJC_CATEGORIES_MAP record in AST file");
- return true;
+ return Failure;
}
F.LocalNumObjCCategoriesInMap = Record[0];
@@ -2604,7 +3124,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case CXX_BASE_SPECIFIER_OFFSETS: {
if (F.LocalNumCXXBaseSpecifiers != 0) {
Error("duplicate CXX_BASE_SPECIFIER_OFFSETS record in AST file");
- return true;
+ return Failure;
}
F.LocalNumCXXBaseSpecifiers = Record[0];
@@ -2671,12 +3191,12 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case UNDEFINED_BUT_USED:
if (UndefinedButUsed.size() % 2 != 0) {
Error("Invalid existing UndefinedButUsed");
- return true;
+ return Failure;
}
if (Record.size() % 2 != 0) {
Error("invalid undefined-but-used record");
- return true;
+ return Failure;
}
for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
UndefinedButUsed.push_back(getGlobalDeclID(F, Record[I++]));
@@ -2690,9 +3210,11 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
// If we aren't loading a module (which has its own exports), make
// all of the imported modules visible.
// FIXME: Deal with macros-only imports.
- for (unsigned I = 0, N = Record.size(); I != N; ++I) {
- if (unsigned GlobalID = getGlobalSubmoduleID(F, Record[I]))
- ImportedModules.push_back(GlobalID);
+ for (unsigned I = 0, N = Record.size(); I != N; /**/) {
+ unsigned GlobalID = getGlobalSubmoduleID(F, Record[I++]);
+ SourceLocation Loc = ReadSourceLocation(F, Record, I);
+ if (GlobalID)
+ ImportedModules.push_back(ImportedSubmodule(GlobalID, Loc));
}
}
break;
@@ -2706,7 +3228,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case LOCAL_REDECLARATIONS_MAP: {
if (F.LocalNumRedeclarationsInMap != 0) {
Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file");
- return true;
+ return Failure;
}
F.LocalNumRedeclarationsInMap = Record[0];
@@ -2727,7 +3249,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case MACRO_OFFSET: {
if (F.LocalNumMacros != 0) {
Error("duplicate MACRO_OFFSET record in AST file");
- return true;
+ return Failure;
}
F.MacroOffsets = (const uint32_t *)Blob.data();
F.LocalNumMacros = Record[0];
@@ -2757,6 +3279,14 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
LateParsedTemplates.append(Record.begin(), Record.end());
break;
}
+
+ case OPTIMIZE_PRAGMA_OPTIONS:
+ if (Record.size() != 1) {
+ Error("invalid pragma optimize record");
+ return Failure;
+ }
+ OptimizeOffPragmaLocation = ReadSourceLocation(F, Record[0]);
+ break;
}
}
}
@@ -2790,31 +3320,27 @@ static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) {
}
}
-void ASTReader::makeNamesVisible(const HiddenNames &Names, Module *Owner) {
- for (unsigned I = 0, N = Names.size(); I != N; ++I) {
- switch (Names[I].getKind()) {
- case HiddenName::Declaration: {
- Decl *D = Names[I].getDecl();
- bool wasHidden = D->Hidden;
- D->Hidden = false;
+void ASTReader::makeNamesVisible(const HiddenNames &Names, Module *Owner,
+ bool FromFinalization) {
+ // FIXME: Only do this if Owner->NameVisibility == AllVisible.
+ for (Decl *D : Names.HiddenDecls) {
+ bool wasHidden = D->Hidden;
+ D->Hidden = false;
- if (wasHidden && SemaObj) {
- if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D)) {
- moveMethodToBackOfGlobalList(*SemaObj, Method);
- }
+ if (wasHidden && SemaObj) {
+ if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D)) {
+ moveMethodToBackOfGlobalList(*SemaObj, Method);
}
- break;
- }
- case HiddenName::MacroVisibility: {
- std::pair<IdentifierInfo *, MacroDirective *> Macro = Names[I].getMacro();
- installImportedMacro(Macro.first, Macro.second, Owner);
- break;
- }
}
}
+
+ assert((FromFinalization || Owner->NameVisibility >= Module::MacrosVisible) &&
+ "nothing to make visible?");
+ for (const auto &Macro : Names.HiddenMacros)
+ installImportedMacro(Macro.first, Macro.second, Owner, FromFinalization);
}
-void ASTReader::makeModuleVisible(Module *Mod,
+void ASTReader::makeModuleVisible(Module *Mod,
Module::NameVisibilityKind NameVisibility,
SourceLocation ImportLoc,
bool Complain) {
@@ -2829,21 +3355,28 @@ void ASTReader::makeModuleVisible(Module *Mod,
// there is nothing more to do.
continue;
}
-
+
if (!Mod->isAvailable()) {
// Modules that aren't available cannot be made visible.
continue;
}
// Update the module's name visibility.
+ if (NameVisibility >= Module::MacrosVisible &&
+ Mod->NameVisibility < Module::MacrosVisible)
+ Mod->MacroVisibilityLoc = ImportLoc;
Mod->NameVisibility = NameVisibility;
-
+
// If we've already deserialized any names from this module,
// mark them as visible.
HiddenNamesMapType::iterator Hidden = HiddenNamesMap.find(Mod);
if (Hidden != HiddenNamesMap.end()) {
- makeNamesVisible(Hidden->second, Hidden->first);
+ auto HiddenNames = std::move(*Hidden);
HiddenNamesMap.erase(Hidden);
+ makeNamesVisible(HiddenNames.second, HiddenNames.first,
+ /*FromFinalization*/false);
+ assert(HiddenNamesMap.find(Mod) == HiddenNamesMap.end() &&
+ "making names visible added hidden names");
}
// Push any exported modules onto the stack to be marked as visible.
@@ -2899,6 +3432,17 @@ bool ASTReader::isGlobalIndexUnavailable() const {
!hasGlobalIndex() && TriedLoadingGlobalIndex;
}
+static void updateModuleTimestamp(ModuleFile &MF) {
+ // Overwrite the timestamp file contents so that file's mtime changes.
+ std::string TimestampFilename = MF.getTimestampFilename();
+ std::string ErrorInfo;
+ llvm::raw_fd_ostream OS(TimestampFilename.c_str(), ErrorInfo,
+ llvm::sys::fs::F_Text);
+ if (!ErrorInfo.empty())
+ return;
+ OS << "Timestamp file\n";
+}
+
ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
ModuleKind Type,
SourceLocation ImportLoc,
@@ -2906,13 +3450,16 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
llvm::SaveAndRestore<SourceLocation>
SetCurImportLocRAII(CurrentImportLoc, ImportLoc);
+ // Defer any pending actions until we get to the end of reading the AST file.
+ Deserializing AnASTFile(this);
+
// Bump the generation number.
- unsigned PreviousGeneration = CurrentGeneration++;
+ unsigned PreviousGeneration = incrementGeneration(Context);
unsigned NumModules = ModuleMgr.size();
SmallVector<ImportedModule, 4> Loaded;
switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc,
- /*ImportedBy=*/0, Loaded,
+ /*ImportedBy=*/nullptr, Loaded,
0, 0,
ClientLoadCapabilities)) {
case Failure:
@@ -2920,18 +3467,23 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
case OutOfDate:
case VersionMismatch:
case ConfigurationMismatch:
- case HadErrors:
+ case HadErrors: {
+ llvm::SmallPtrSet<ModuleFile *, 4> LoadedSet;
+ for (const ImportedModule &IM : Loaded)
+ LoadedSet.insert(IM.Mod);
+
ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end(),
+ LoadedSet,
Context.getLangOpts().Modules
? &PP.getHeaderSearchInfo().getModuleMap()
- : 0);
+ : nullptr);
// If we find that any modules are unusable, the global index is going
// to be out-of-date. Just remove it.
GlobalIndex.reset();
- ModuleMgr.setGlobalIndex(0);
+ ModuleMgr.setGlobalIndex(nullptr);
return ReadResult;
-
+ }
case Success:
break;
}
@@ -2945,8 +3497,8 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
ModuleFile &F = *M->Mod;
// Read the AST block.
- if (ReadASTBlock(F))
- return Failure;
+ if (ASTReadResult Result = ReadASTBlock(F, ClientLoadCapabilities))
+ return Result;
// Once read, set the ModuleFile bit base offset and update the size in
// bits of all files we've seen.
@@ -3057,6 +3609,21 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
PreviousGeneration);
}
+ if (PP.getHeaderSearchInfo()
+ .getHeaderSearchOpts()
+ .ModulesValidateOncePerBuildSession) {
+ // Now we are certain that the module and all modules it depends on are
+ // up to date. Create or update timestamp files for modules that are
+ // located in the module cache (not for PCH files that could be anywhere
+ // in the filesystem).
+ for (unsigned I = 0, N = Loaded.size(); I != N; ++I) {
+ ImportedModule &M = Loaded[I];
+ if (M.Mod->Kind == MK_Module) {
+ updateModuleTimestamp(*M.Mod);
+ }
+ }
+ }
+
return Success;
}
@@ -3072,7 +3639,7 @@ ASTReader::ReadASTCore(StringRef FileName,
std::string ErrorStr;
ModuleManager::AddModuleResult AddResult
= ModuleMgr.addModule(FileName, Type, ImportLoc, ImportedBy,
- CurrentGeneration, ExpectedSize, ExpectedModTime,
+ getGeneration(), ExpectedSize, ExpectedModTime,
M, ErrorStr);
switch (AddResult) {
@@ -3162,7 +3729,7 @@ ASTReader::ReadASTCore(StringRef FileName,
break;
case CONTROL_BLOCK_ID:
HaveReadControlBlock = true;
- switch (ReadControlBlock(F, Loaded, ClientLoadCapabilities)) {
+ switch (ReadControlBlock(F, Loaded, ImportedBy, ClientLoadCapabilities)) {
case Success:
break;
@@ -3177,7 +3744,7 @@ ASTReader::ReadASTCore(StringRef FileName,
case AST_BLOCK_ID:
if (!HaveReadControlBlock) {
if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
- Diag(diag::warn_pch_version_too_old);
+ Diag(diag::err_pch_version_too_old);
return VersionMismatch;
}
@@ -3203,11 +3770,6 @@ void ASTReader::InitializeContext() {
DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID,
Context.getTranslationUnitDecl());
- // Make sure we load the declaration update records for the translation unit,
- // if there are any.
- loadDeclUpdateRecords(PREDEF_DECL_TRANSLATION_UNIT_ID,
- Context.getTranslationUnitDecl());
-
// FIXME: Find a better way to deal with collisions between these
// built-in types. Right now, we just ignore the problem.
@@ -3323,24 +3885,26 @@ void ASTReader::InitializeContext() {
Context.setcudaConfigureCallDecl(
cast<FunctionDecl>(GetDecl(CUDASpecialDeclRefs[0])));
}
-
+
// Re-export any modules that were imported by a non-module AST file.
- for (unsigned I = 0, N = ImportedModules.size(); I != N; ++I) {
- if (Module *Imported = getSubmodule(ImportedModules[I]))
+ // FIXME: This does not make macro-only imports visible again. It also doesn't
+ // make #includes mapped to module imports visible.
+ for (auto &Import : ImportedModules) {
+ if (Module *Imported = getSubmodule(Import.ID))
makeModuleVisible(Imported, Module::AllVisible,
- /*ImportLoc=*/SourceLocation(),
+ /*ImportLoc=*/Import.ImportLoc,
/*Complain=*/false);
}
ImportedModules.clear();
}
void ASTReader::finalizeForWriting() {
- for (HiddenNamesMapType::iterator Hidden = HiddenNamesMap.begin(),
- HiddenEnd = HiddenNamesMap.end();
- Hidden != HiddenEnd; ++Hidden) {
- makeNamesVisible(Hidden->second, Hidden->first);
+ while (!HiddenNamesMap.empty()) {
+ auto HiddenNames = std::move(*HiddenNamesMap.begin());
+ HiddenNamesMap.erase(HiddenNamesMap.begin());
+ makeNamesVisible(HiddenNames.second, HiddenNames.first,
+ /*FromFinalization*/true);
}
- HiddenNamesMap.clear();
}
/// \brief Given a cursor at the start of an AST file, scan ahead and drop the
@@ -3381,7 +3945,7 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
DiagnosticsEngine &Diags) {
// Open the AST file.
std::string ErrStr;
- OwningPtr<llvm::MemoryBuffer> Buffer;
+ std::unique_ptr<llvm::MemoryBuffer> Buffer;
Buffer.reset(FileMgr.getBufferForFile(ASTFileName, &ErrStr));
if (!Buffer) {
Diags.Report(diag::err_fe_unable_to_read_pch_file) << ASTFileName << ErrStr;
@@ -3448,18 +4012,18 @@ namespace {
{
}
- virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
- bool Complain) {
- return checkLanguageOptions(ExistingLangOpts, LangOpts, 0);
+ bool ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain) override {
+ return checkLanguageOptions(ExistingLangOpts, LangOpts, nullptr);
}
- virtual bool ReadTargetOptions(const TargetOptions &TargetOpts,
- bool Complain) {
- return checkTargetOptions(ExistingTargetOpts, TargetOpts, 0);
+ bool ReadTargetOptions(const TargetOptions &TargetOpts,
+ bool Complain) override {
+ return checkTargetOptions(ExistingTargetOpts, TargetOpts, nullptr);
}
- virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
- bool Complain,
- std::string &SuggestedPredefines) {
- return checkPreprocessorOptions(ExistingPPOpts, PPOpts, 0, FileMgr,
+ bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ bool Complain,
+ std::string &SuggestedPredefines) override {
+ return checkPreprocessorOptions(ExistingPPOpts, PPOpts, nullptr, FileMgr,
SuggestedPredefines, ExistingLangOpts);
}
};
@@ -3470,7 +4034,7 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
ASTReaderListener &Listener) {
// Open the AST file.
std::string ErrStr;
- OwningPtr<llvm::MemoryBuffer> Buffer;
+ std::unique_ptr<llvm::MemoryBuffer> Buffer;
Buffer.reset(FileMgr.getBufferForFile(Filename, &ErrStr));
if (!Buffer) {
return true;
@@ -3496,6 +4060,7 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
return true;
bool NeedsInputFiles = Listener.needsInputFileVisitation();
+ bool NeedsSystemInputFiles = Listener.needsSystemInputFileVisitation();
BitstreamCursor InputFilesCursor;
if (NeedsInputFiles) {
InputFilesCursor = Stream;
@@ -3539,6 +4104,12 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
break;
}
+ case MODULE_NAME:
+ Listener.ReadModuleName(Blob);
+ break;
+ case MODULE_MAP_FILE:
+ Listener.ReadModuleMapFile(Blob);
+ break;
case LANGUAGE_OPTIONS:
if (ParseLanguageOptions(Record, false, Listener))
return true;
@@ -3582,6 +4153,10 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
for (unsigned I = 0; I != NumInputFiles; ++I) {
// Go find this input file.
bool isSystemFile = I >= NumUserFiles;
+
+ if (isSystemFile && !NeedsSystemInputFiles)
+ break; // the rest are system input files
+
BitstreamCursor &Cursor = InputFilesCursor;
SavedStreamPosition SavedPosition(Cursor);
Cursor.JumpToBit(InputFileOffs[I]);
@@ -3592,7 +4167,8 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
bool shouldContinue = false;
switch ((InputFileRecordTypes)Cursor.readRecord(Code, Record, &Blob)) {
case INPUT_FILE:
- shouldContinue = Listener.visitInputFile(Blob, isSystemFile);
+ bool Overridden = static_cast<bool>(Record[3]);
+ shouldContinue = Listener.visitInputFile(Blob, isSystemFile, Overridden);
break;
}
if (!shouldContinue)
@@ -3618,16 +4194,17 @@ bool ASTReader::isAcceptableASTFile(StringRef Filename,
return !readASTFileControlBlock(Filename, FileMgr, validator);
}
-bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
+ASTReader::ASTReadResult
+ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
// Enter the submodule block.
if (F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) {
Error("malformed submodule block record in AST file");
- return true;
+ return Failure;
}
ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
bool First = true;
- Module *CurrentModule = 0;
+ Module *CurrentModule = nullptr;
RecordData Record;
while (true) {
llvm::BitstreamEntry Entry = F.Stream.advanceSkippingSubblocks();
@@ -3636,9 +4213,9 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case llvm::BitstreamEntry::SubBlock: // Handled for us already.
case llvm::BitstreamEntry::Error:
Error("malformed block record in AST file");
- return true;
+ return Failure;
case llvm::BitstreamEntry::EndBlock:
- return false;
+ return Success;
case llvm::BitstreamEntry::Record:
// The interesting case.
break;
@@ -3654,39 +4231,47 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_DEFINITION: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (Record.size() < 8) {
Error("malformed module definition");
- return true;
+ return Failure;
}
StringRef Name = Blob;
- SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[0]);
- SubmoduleID Parent = getGlobalSubmoduleID(F, Record[1]);
- bool IsFramework = Record[2];
- bool IsExplicit = Record[3];
- bool IsSystem = Record[4];
- bool InferSubmodules = Record[5];
- bool InferExplicitSubmodules = Record[6];
- bool InferExportWildcard = Record[7];
- bool ConfigMacrosExhaustive = Record[8];
-
- Module *ParentModule = 0;
- if (Parent)
+ unsigned Idx = 0;
+ SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[Idx++]);
+ SubmoduleID Parent = getGlobalSubmoduleID(F, Record[Idx++]);
+ bool IsFramework = Record[Idx++];
+ bool IsExplicit = Record[Idx++];
+ bool IsSystem = Record[Idx++];
+ bool IsExternC = Record[Idx++];
+ bool InferSubmodules = Record[Idx++];
+ bool InferExplicitSubmodules = Record[Idx++];
+ bool InferExportWildcard = Record[Idx++];
+ bool ConfigMacrosExhaustive = Record[Idx++];
+
+ Module *ParentModule = nullptr;
+ const FileEntry *ModuleMap = nullptr;
+ if (Parent) {
ParentModule = getSubmodule(Parent);
-
+ ModuleMap = ParentModule->ModuleMap;
+ }
+
+ if (!F.ModuleMapPath.empty())
+ ModuleMap = FileMgr.getFile(F.ModuleMapPath);
+
// Retrieve this (sub)module from the module map, creating it if
// necessary.
- CurrentModule = ModMap.findOrCreateModule(Name, ParentModule,
+ CurrentModule = ModMap.findOrCreateModule(Name, ParentModule, ModuleMap,
IsFramework,
IsExplicit).first;
SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS;
if (GlobalIndex >= SubmodulesLoaded.size() ||
SubmodulesLoaded[GlobalIndex]) {
Error("too many submodules");
- return true;
+ return Failure;
}
if (!ParentModule) {
@@ -3698,15 +4283,16 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
<< CurFile->getName()
<< F.File->getName();
}
- return true;
+ return Failure;
}
}
CurrentModule->setASTFile(F.File);
}
-
+
CurrentModule->IsFromModuleFile = true;
CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem;
+ CurrentModule->IsExternC = IsExternC;
CurrentModule->InferSubmodules = InferSubmodules;
CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
CurrentModule->InferExportWildcard = InferExportWildcard;
@@ -3727,7 +4313,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_UMBRELLA_HEADER: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -3737,8 +4323,9 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (!CurrentModule->getUmbrellaHeader())
ModMap.setUmbrellaHeader(CurrentModule, Umbrella);
else if (CurrentModule->getUmbrellaHeader() != Umbrella) {
- Error("mismatched umbrella headers in submodule");
- return true;
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Error("mismatched umbrella headers in submodule");
+ return OutOfDate;
}
}
break;
@@ -3747,7 +4334,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_HEADER: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -3762,7 +4349,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_EXCLUDED_HEADER: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -3777,7 +4364,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_PRIVATE_HEADER: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -3792,7 +4379,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_TOPHEADER: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -3805,7 +4392,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_UMBRELLA_DIR: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -3816,8 +4403,9 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (!CurrentModule->getUmbrellaDir())
ModMap.setUmbrellaDir(CurrentModule, Umbrella);
else if (CurrentModule->getUmbrellaDir() != Umbrella) {
- Error("mismatched umbrella directories in submodule");
- return true;
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Error("mismatched umbrella directories in submodule");
+ return OutOfDate;
}
}
break;
@@ -3826,7 +4414,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_METADATA: {
if (!First) {
Error("submodule metadata record not at beginning of block");
- return true;
+ return Failure;
}
First = false;
@@ -3852,7 +4440,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_IMPORTS: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -3873,7 +4461,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_EXPORTS: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -3897,7 +4485,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_REQUIRES: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -3911,7 +4499,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_LINK_LIBRARY:
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -3924,7 +4512,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_CONFIG_MACRO:
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -3936,7 +4524,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_CONFLICT: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -4004,8 +4592,6 @@ bool ASTReader::ParseTargetOptions(const RecordData &Record,
TargetOpts.Triple = ReadString(Record, Idx);
TargetOpts.CPU = ReadString(Record, Idx);
TargetOpts.ABI = ReadString(Record, Idx);
- TargetOpts.CXXABI = ReadString(Record, Idx);
- TargetOpts.LinkerVersion = ReadString(Record, Idx);
for (unsigned N = Record[Idx++]; N; --N) {
TargetOpts.FeaturesAsWritten.push_back(ReadString(Record, Idx));
}
@@ -4018,16 +4604,17 @@ bool ASTReader::ParseTargetOptions(const RecordData &Record,
bool ASTReader::ParseDiagnosticOptions(const RecordData &Record, bool Complain,
ASTReaderListener &Listener) {
- DiagnosticOptions DiagOpts;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
unsigned Idx = 0;
-#define DIAGOPT(Name, Bits, Default) DiagOpts.Name = Record[Idx++];
+#define DIAGOPT(Name, Bits, Default) DiagOpts->Name = Record[Idx++];
#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
- DiagOpts.set##Name(static_cast<Type>(Record[Idx++]));
+ DiagOpts->set##Name(static_cast<Type>(Record[Idx++]));
#include "clang/Basic/DiagnosticOptions.def"
- for (unsigned N = Record[Idx++]; N; --N) {
- DiagOpts.Warnings.push_back(ReadString(Record, Idx));
- }
+ for (unsigned N = Record[Idx++]; N; --N)
+ DiagOpts->Warnings.push_back(ReadString(Record, Idx));
+ for (unsigned N = Record[Idx++]; N; --N)
+ DiagOpts->Remarks.push_back(ReadString(Record, Idx));
return Listener.ReadDiagnosticOptions(DiagOpts, Complain);
}
@@ -4068,6 +4655,7 @@ bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record,
HSOpts.ResourceDir = ReadString(Record, Idx);
HSOpts.ModuleCachePath = ReadString(Record, Idx);
+ HSOpts.ModuleUserBuildPath = ReadString(Record, Idx);
HSOpts.DisableModuleHash = Record[Idx++];
HSOpts.UseBuiltinIncludes = Record[Idx++];
HSOpts.UseStandardSystemIncludes = Record[Idx++];
@@ -4149,7 +4737,7 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
if (!PP.getPreprocessingRecord()) {
Error("no preprocessing record");
- return 0;
+ return nullptr;
}
SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor);
@@ -4158,7 +4746,7 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
llvm::BitstreamEntry Entry =
M.PreprocessorDetailCursor.advance(BitstreamCursor::AF_DontPopBlockAtEnd);
if (Entry.Kind != llvm::BitstreamEntry::Record)
- return 0;
+ return nullptr;
// Read the record.
SourceRange Range(ReadSourceLocation(M, PPOffs.Begin),
@@ -4172,8 +4760,8 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
switch (RecType) {
case PPD_MACRO_EXPANSION: {
bool isBuiltin = Record[0];
- IdentifierInfo *Name = 0;
- MacroDefinition *Def = 0;
+ IdentifierInfo *Name = nullptr;
+ MacroDefinition *Def = nullptr;
if (isBuiltin)
Name = getLocalIdentifier(M, Record[1]);
else {
@@ -4207,7 +4795,7 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
case PPD_INCLUSION_DIRECTIVE: {
const char *FullFileNameStart = Blob.data() + Record[0];
StringRef FullFileName(FullFileNameStart, Blob.size() - Record[0]);
- const FileEntry *File = 0;
+ const FileEntry *File = nullptr;
if (!FullFileName.empty())
File = PP.getFileManager().getFile(FullFileName);
@@ -4276,15 +4864,13 @@ struct PPEntityComp {
}
-/// \brief Returns the first preprocessed entity ID that ends after \arg BLoc.
-PreprocessedEntityID
-ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const {
- if (SourceMgr.isLocalSourceLocation(BLoc))
+PreprocessedEntityID ASTReader::findPreprocessedEntity(SourceLocation Loc,
+ bool EndsAfter) const {
+ if (SourceMgr.isLocalSourceLocation(Loc))
return getTotalNumPreprocessedEntities();
- GlobalSLocOffsetMapType::const_iterator
- SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset -
- BLoc.getOffset() - 1);
+ GlobalSLocOffsetMapType::const_iterator SLocMapI = GlobalSLocOffsetMap.find(
+ SourceManager::MaxLoadedOffset - Loc.getOffset() - 1);
assert(SLocMapI != GlobalSLocOffsetMap.end() &&
"Corrupted global sloc offset map");
@@ -4301,21 +4887,26 @@ ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const {
pp_iterator First = pp_begin;
pp_iterator PPI;
- // Do a binary search manually instead of using std::lower_bound because
- // The end locations of entities may be unordered (when a macro expansion
- // is inside another macro argument), but for this case it is not important
- // whether we get the first macro expansion or its containing macro.
- while (Count > 0) {
- Half = Count/2;
- PPI = First;
- std::advance(PPI, Half);
- if (SourceMgr.isBeforeInTranslationUnit(ReadSourceLocation(M, PPI->End),
- BLoc)){
- First = PPI;
- ++First;
- Count = Count - Half - 1;
- } else
- Count = Half;
+ if (EndsAfter) {
+ PPI = std::upper_bound(pp_begin, pp_end, Loc,
+ PPEntityComp<&PPEntityOffset::Begin>(*this, M));
+ } else {
+ // Do a binary search manually instead of using std::lower_bound because
+ // The end locations of entities may be unordered (when a macro expansion
+ // is inside another macro argument), but for this case it is not important
+ // whether we get the first macro expansion or its containing macro.
+ while (Count > 0) {
+ Half = Count / 2;
+ PPI = First;
+ std::advance(PPI, Half);
+ if (SourceMgr.isBeforeInTranslationUnit(ReadSourceLocation(M, PPI->End),
+ Loc)) {
+ First = PPI;
+ ++First;
+ Count = Count - Half - 1;
+ } else
+ Count = Half;
+ }
}
if (PPI == pp_end)
@@ -4324,35 +4915,6 @@ ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const {
return M.BasePreprocessedEntityID + (PPI - pp_begin);
}
-/// \brief Returns the first preprocessed entity ID that begins after \arg ELoc.
-PreprocessedEntityID
-ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const {
- if (SourceMgr.isLocalSourceLocation(ELoc))
- return getTotalNumPreprocessedEntities();
-
- GlobalSLocOffsetMapType::const_iterator
- SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset -
- ELoc.getOffset() - 1);
- assert(SLocMapI != GlobalSLocOffsetMap.end() &&
- "Corrupted global sloc offset map");
-
- if (SLocMapI->second->NumPreprocessedEntities == 0)
- return findNextPreprocessedEntity(SLocMapI);
-
- ModuleFile &M = *SLocMapI->second;
- typedef const PPEntityOffset *pp_iterator;
- pp_iterator pp_begin = M.PreprocessedEntityOffsets;
- pp_iterator pp_end = pp_begin + M.NumPreprocessedEntities;
- pp_iterator PPI =
- std::upper_bound(pp_begin, pp_end, ELoc,
- PPEntityComp<&PPEntityOffset::Begin>(*this, M));
-
- if (PPI == pp_end)
- return findNextPreprocessedEntity(SLocMapI);
-
- return M.BasePreprocessedEntityID + (PPI - pp_begin);
-}
-
/// \brief Returns a pair of [Begin, End) indices of preallocated
/// preprocessed entities that \arg Range encompasses.
std::pair<unsigned, unsigned>
@@ -4361,8 +4923,9 @@ std::pair<unsigned, unsigned>
return std::make_pair(0,0);
assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin()));
- PreprocessedEntityID BeginID = findBeginPreprocessedEntity(Range.getBegin());
- PreprocessedEntityID EndID = findEndPreprocessedEntity(Range.getEnd());
+ PreprocessedEntityID BeginID =
+ findPreprocessedEntity(Range.getBegin(), false);
+ PreprocessedEntityID EndID = findPreprocessedEntity(Range.getEnd(), true);
return std::make_pair(BeginID, EndID);
}
@@ -4468,9 +5031,9 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
if (DiagID == (unsigned)-1) {
break; // no more diag/map pairs for this location.
}
- diag::Mapping Map = (diag::Mapping)F.PragmaDiagMappings[Idx++];
- DiagnosticMappingInfo MappingInfo = Diag.makeMappingInfo(Map, Loc);
- Diag.GetCurDiagState()->setMappingInfo(DiagID, MappingInfo);
+ diag::Severity Map = (diag::Severity)F.PragmaDiagMappings[Idx++];
+ DiagnosticMapping Mapping = Diag.makeUserMapping(Map, Loc);
+ Diag.GetCurDiagState()->setMapping(DiagID, Mapping);
}
}
}
@@ -4548,6 +5111,16 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
return DT;
}
+ case TYPE_ADJUSTED: {
+ if (Record.size() != 2) {
+ Error("Incorrect encoding of adjusted type");
+ return QualType();
+ }
+ QualType OriginalTy = readType(*Loc.F, Record, Idx);
+ QualType AdjustedTy = readType(*Loc.F, Record, Idx);
+ return Context.getAdjustedType(OriginalTy, AdjustedTy);
+ }
+
case TYPE_BLOCK_POINTER: {
if (Record.size() != 1) {
Error("Incorrect encoding of block pointer type");
@@ -4671,23 +5244,8 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
EPI.HasTrailingReturn = Record[Idx++];
EPI.TypeQuals = Record[Idx++];
EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]);
- ExceptionSpecificationType EST =
- static_cast<ExceptionSpecificationType>(Record[Idx++]);
- EPI.ExceptionSpecType = EST;
- SmallVector<QualType, 2> Exceptions;
- if (EST == EST_Dynamic) {
- EPI.NumExceptions = Record[Idx++];
- for (unsigned I = 0; I != EPI.NumExceptions; ++I)
- Exceptions.push_back(readType(*Loc.F, Record, Idx));
- EPI.Exceptions = Exceptions.data();
- } else if (EST == EST_ComputedNoexcept) {
- EPI.NoexceptExpr = ReadExpr(*Loc.F);
- } else if (EST == EST_Uninstantiated) {
- EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
- EPI.ExceptionSpecTemplate = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
- } else if (EST == EST_Unevaluated) {
- EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
- }
+ SmallVector<QualType, 8> ExceptionStorage;
+ readExceptionSpec(*Loc.F, ExceptionStorage, EPI, Record, Idx);
return Context.getFunctionType(ResultType, ParamTypes, EPI);
}
@@ -4837,9 +5395,9 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
unsigned Idx = 0;
QualType Parm = readType(*Loc.F, Record, Idx);
QualType Replacement = readType(*Loc.F, Record, Idx);
- return
- Context.getSubstTemplateTypeParmType(cast<TemplateTypeParmType>(Parm),
- Replacement);
+ return Context.getSubstTemplateTypeParmType(
+ cast<TemplateTypeParmType>(Parm),
+ Context.getCanonicalType(Replacement));
}
case TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK: {
@@ -4856,8 +5414,14 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
QualType TST = readType(*Loc.F, Record, Idx); // probably derivable
// FIXME: ASTContext::getInjectedClassNameType is not currently suitable
// for AST reading, too much interdependencies.
- return
- QualType(new (Context, TypeAlignment) InjectedClassNameType(D, TST), 0);
+ const Type *T;
+ if (const Type *Existing = D->getTypeForDecl())
+ T = Existing;
+ else if (auto *Prev = D->getPreviousDecl())
+ T = Prev->getTypeForDecl();
+ else
+ T = new (Context, TypeAlignment) InjectedClassNameType(D, TST);
+ return QualType(T, 0);
}
case TYPE_TEMPLATE_TYPE_PARM: {
@@ -4942,6 +5506,29 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
llvm_unreachable("Invalid TypeCode!");
}
+void ASTReader::readExceptionSpec(ModuleFile &ModuleFile,
+ SmallVectorImpl<QualType> &Exceptions,
+ FunctionProtoType::ExtProtoInfo &EPI,
+ const RecordData &Record, unsigned &Idx) {
+ ExceptionSpecificationType EST =
+ static_cast<ExceptionSpecificationType>(Record[Idx++]);
+ EPI.ExceptionSpecType = EST;
+ if (EST == EST_Dynamic) {
+ EPI.NumExceptions = Record[Idx++];
+ for (unsigned I = 0; I != EPI.NumExceptions; ++I)
+ Exceptions.push_back(readType(ModuleFile, Record, Idx));
+ EPI.Exceptions = Exceptions.data();
+ } else if (EST == EST_ComputedNoexcept) {
+ EPI.NoexceptExpr = ReadExpr(ModuleFile);
+ } else if (EST == EST_Uninstantiated) {
+ EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
+ EPI.ExceptionSpecTemplate =
+ ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
+ } else if (EST == EST_Unevaluated) {
+ EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
+ }
+}
+
class clang::TypeLocReader : public TypeLocVisitor<TypeLocReader> {
ASTReader &Reader;
ModuleFile &F;
@@ -4997,6 +5584,9 @@ void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) {
void TypeLocReader::VisitDecayedTypeLoc(DecayedTypeLoc TL) {
// nothing to do
}
+void TypeLocReader::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
+ // nothing to do
+}
void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
TL.setCaretLoc(ReadSourceLocation(Record, Idx));
}
@@ -5016,7 +5606,7 @@ void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) {
if (Record[Idx++])
TL.setSizeExpr(Reader.ReadExpr(F));
else
- TL.setSizeExpr(0);
+ TL.setSizeExpr(nullptr);
}
void TypeLocReader::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) {
VisitArrayTypeLoc(TL);
@@ -5046,8 +5636,8 @@ void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
TL.setLParenLoc(ReadSourceLocation(Record, Idx));
TL.setRParenLoc(ReadSourceLocation(Record, Idx));
TL.setLocalRangeEnd(ReadSourceLocation(Record, Idx));
- for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) {
- TL.setArg(i, ReadDeclAs<ParmVarDecl>(Record, Idx));
+ for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i) {
+ TL.setParam(i, ReadDeclAs<ParmVarDecl>(Record, Idx));
}
}
void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
@@ -5103,7 +5693,7 @@ void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) {
if (Record[Idx++])
TL.setAttrExprOperand(Reader.ReadExpr(F));
else
- TL.setAttrExprOperand(0);
+ TL.setAttrExprOperand(nullptr);
} else if (TL.hasAttrEnumOperand())
TL.setAttrEnumOperandLoc(ReadSourceLocation(Record, Idx));
}
@@ -5187,7 +5777,7 @@ TypeSourceInfo *ASTReader::GetTypeSourceInfo(ModuleFile &F,
unsigned &Idx) {
QualType InfoTy = readType(F, Record, Idx);
if (InfoTy.isNull())
- return 0;
+ return nullptr;
TypeSourceInfo *TInfo = getContext().CreateTypeSourceInfo(InfoTy);
TypeLocReader TLR(*this, F, Record, Idx);
@@ -5374,11 +5964,54 @@ Decl *ASTReader::GetExternalDecl(uint32_t ID) {
return GetDecl(ID);
}
-uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M, const RecordData &Record,
- unsigned &Idx){
- if (Idx >= Record.size())
+void ASTReader::CompleteRedeclChain(const Decl *D) {
+ if (NumCurrentElementsDeserializing) {
+ // We arrange to not care about the complete redeclaration chain while we're
+ // deserializing. Just remember that the AST has marked this one as complete
+ // but that it's not actually complete yet, so we know we still need to
+ // complete it later.
+ PendingIncompleteDeclChains.push_back(const_cast<Decl*>(D));
+ return;
+ }
+
+ const DeclContext *DC = D->getDeclContext()->getRedeclContext();
+
+ // Recursively ensure that the decl context itself is complete
+ // (in particular, this matters if the decl context is a namespace).
+ //
+ // FIXME: This should be performed by lookup instead of here.
+ cast<Decl>(DC)->getMostRecentDecl();
+
+ // If this is a named declaration, complete it by looking it up
+ // within its context.
+ //
+ // FIXME: We don't currently handle the cases where we can't do this;
+ // merging a class definition that contains unnamed entities should merge
+ // those entities. Likewise, merging a function definition should merge
+ // all mergeable entities within it.
+ if (isa<TranslationUnitDecl>(DC) || isa<NamespaceDecl>(DC) ||
+ isa<CXXRecordDecl>(DC) || isa<EnumDecl>(DC)) {
+ if (DeclarationName Name = cast<NamedDecl>(D)->getDeclName()) {
+ auto *II = Name.getAsIdentifierInfo();
+ if (isa<TranslationUnitDecl>(DC) && II) {
+ // Outside of C++, we don't have a lookup table for the TU, so update
+ // the identifier instead. In C++, either way should work fine.
+ if (II->isOutOfDate())
+ updateOutOfDateIdentifier(*II);
+ } else
+ DC->lookup(Name);
+ }
+ }
+}
+
+uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M,
+ const RecordData &Record,
+ unsigned &Idx) {
+ if (Idx >= Record.size() || Record[Idx] > M.LocalNumCXXBaseSpecifiers) {
+ Error("malformed AST file: missing C++ base specifier");
return 0;
-
+ }
+
unsigned LocalID = Record[Idx++];
return getGlobalBitOffset(M, M.CXXBaseSpecifiersOffsets[LocalID - 1]);
}
@@ -5393,8 +6026,8 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
unsigned Code = Cursor.ReadCode();
unsigned RecCode = Cursor.readRecord(Code, Record);
if (RecCode != DECL_CXX_BASE_SPECIFIERS) {
- Error("Malformed AST file: missing C++ base specifiers");
- return 0;
+ Error("malformed AST file: missing C++ base specifiers");
+ return nullptr;
}
unsigned Idx = 0;
@@ -5427,7 +6060,7 @@ bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID,
ModuleFile *ASTReader::getOwningModuleFile(const Decl *D) {
if (!D->isFromASTFile())
- return 0;
+ return nullptr;
GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(D->getGlobalID());
assert(I != GlobalDeclMap.end() && "Corrupted global declaration map");
return I->second;
@@ -5436,14 +6069,14 @@ ModuleFile *ASTReader::getOwningModuleFile(const Decl *D) {
SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) {
if (ID < NUM_PREDEF_DECL_IDS)
return SourceLocation();
-
+
unsigned Index = ID - NUM_PREDEF_DECL_IDS;
if (Index > DeclsLoaded.size()) {
Error("declaration ID out-of-range for AST file");
return SourceLocation();
}
-
+
if (Decl *D = DeclsLoaded[Index])
return D->getLocation();
@@ -5452,15 +6085,15 @@ SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) {
return ReadSourceLocation(*Rec.F, RawLocation);
}
-Decl *ASTReader::GetDecl(DeclID ID) {
- if (ID < NUM_PREDEF_DECL_IDS) {
+Decl *ASTReader::GetExistingDecl(DeclID ID) {
+ if (ID < NUM_PREDEF_DECL_IDS) {
switch ((PredefinedDeclIDs)ID) {
case PREDEF_DECL_NULL_ID:
- return 0;
-
+ return nullptr;
+
case PREDEF_DECL_TRANSLATION_UNIT_ID:
return Context.getTranslationUnitDecl();
-
+
case PREDEF_DECL_OBJC_ID_ID:
return Context.getObjCIdDecl();
@@ -5469,16 +6102,16 @@ Decl *ASTReader::GetDecl(DeclID ID) {
case PREDEF_DECL_OBJC_CLASS_ID:
return Context.getObjCClassDecl();
-
+
case PREDEF_DECL_OBJC_PROTOCOL_ID:
return Context.getObjCProtocolDecl();
-
+
case PREDEF_DECL_INT_128_ID:
return Context.getInt128Decl();
case PREDEF_DECL_UNSIGNED_INT_128_ID:
return Context.getUInt128Decl();
-
+
case PREDEF_DECL_OBJC_INSTANCETYPE_ID:
return Context.getObjCInstanceTypeDecl();
@@ -5486,15 +6119,30 @@ Decl *ASTReader::GetDecl(DeclID ID) {
return Context.getBuiltinVaListDecl();
}
}
-
+
unsigned Index = ID - NUM_PREDEF_DECL_IDS;
if (Index >= DeclsLoaded.size()) {
assert(0 && "declaration ID out-of-range for AST file");
Error("declaration ID out-of-range for AST file");
- return 0;
+ return nullptr;
}
-
+
+ return DeclsLoaded[Index];
+}
+
+Decl *ASTReader::GetDecl(DeclID ID) {
+ if (ID < NUM_PREDEF_DECL_IDS)
+ return GetExistingDecl(ID);
+
+ unsigned Index = ID - NUM_PREDEF_DECL_IDS;
+
+ if (Index >= DeclsLoaded.size()) {
+ assert(0 && "declaration ID out-of-range for AST file");
+ Error("declaration ID out-of-range for AST file");
+ return nullptr;
+ }
+
if (!DeclsLoaded[Index]) {
ReadDeclRecord(ID);
if (DeserializationListener)
@@ -5779,7 +6427,7 @@ static ModuleFile *getDefinitiveModuleFileFor(const DeclContext *DC,
if (const DeclContext *DefDC = getDefinitiveDeclContext(DC))
return Reader.getOwningModuleFile(cast<Decl>(DefDC));
- return 0;
+ return nullptr;
}
bool
@@ -5800,14 +6448,19 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
Contexts.push_back(DC);
if (DC->isNamespace()) {
- MergedDeclsMap::iterator Merged
- = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
+ auto Merged = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
if (Merged != MergedDecls.end()) {
for (unsigned I = 0, N = Merged->second.size(); I != N; ++I)
Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I])));
}
}
-
+ if (isa<CXXRecordDecl>(DC)) {
+ auto Merged = MergedLookups.find(DC);
+ if (Merged != MergedLookups.end())
+ Contexts.insert(Contexts.end(), Merged->second.begin(),
+ Merged->second.end());
+ }
+
DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls);
// If we can definitively determine which module file to look into,
@@ -5924,15 +6577,23 @@ static void PassObjCImplDeclToConsumer(ObjCImplDecl *ImplD,
ASTConsumer *Consumer) {
assert(ImplD && Consumer);
- for (ObjCImplDecl::method_iterator
- I = ImplD->meth_begin(), E = ImplD->meth_end(); I != E; ++I)
- Consumer->HandleInterestingDecl(DeclGroupRef(*I));
+ for (auto *I : ImplD->methods())
+ Consumer->HandleInterestingDecl(DeclGroupRef(I));
Consumer->HandleInterestingDecl(DeclGroupRef(ImplD));
}
void ASTReader::PassInterestingDeclsToConsumer() {
assert(Consumer);
+
+ if (PassingDeclsToConsumer)
+ return;
+
+ // Guard variable to avoid recursively redoing the process of passing
+ // decls to consumer.
+ SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer,
+ true);
+
while (!InterestingDecls.empty()) {
Decl *D = InterestingDecls.front();
InterestingDecls.pop_front();
@@ -5954,12 +6615,12 @@ void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) {
if (!Consumer)
return;
- for (unsigned I = 0, N = ExternalDefinitions.size(); I != N; ++I) {
+ for (unsigned I = 0, N = EagerlyDeserializedDecls.size(); I != N; ++I) {
// Force deserialization of this decl, which will cause it to be queued for
// passing to the consumer.
- GetDecl(ExternalDefinitions[I]);
+ GetDecl(EagerlyDeserializedDecls[I]);
}
- ExternalDefinitions.clear();
+ EagerlyDeserializedDecls.clear();
PassInterestingDeclsToConsumer();
}
@@ -5972,15 +6633,15 @@ void ASTReader::PrintStats() {
QualType());
unsigned NumDeclsLoaded
= DeclsLoaded.size() - std::count(DeclsLoaded.begin(), DeclsLoaded.end(),
- (Decl *)0);
+ (Decl *)nullptr);
unsigned NumIdentifiersLoaded
= IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(),
IdentifiersLoaded.end(),
- (IdentifierInfo *)0);
+ (IdentifierInfo *)nullptr);
unsigned NumMacrosLoaded
= MacrosLoaded.size() - std::count(MacrosLoaded.begin(),
MacrosLoaded.end(),
- (MacroInfo *)0);
+ (MacroInfo *)nullptr);
unsigned NumSelectorsLoaded
= SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(),
SelectorsLoaded.end(),
@@ -6164,6 +6825,11 @@ void ASTReader::UpdateSema() {
}
SemaDeclRefs.clear();
}
+
+ // Update the state of 'pragma clang optimize'. Use the same API as if we had
+ // encountered the pragma in the source.
+ if(OptimizeOffPragmaLocation.isValid())
+ SemaObj->ActOnPragmaOptimize(/* IsOn = */ false, OptimizeOffPragmaLocation);
}
IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) {
@@ -6174,7 +6840,7 @@ IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) {
// If there is a global index, look there first to determine which modules
// provably do not have any results for this identifier.
GlobalModuleIndex::HitSet Hits;
- GlobalModuleIndex::HitSet *HitsPtr = 0;
+ GlobalModuleIndex::HitSet *HitsPtr = nullptr;
if (!loadGlobalIndex()) {
if (GlobalIndex->lookupIdentifier(Name, Hits)) {
HitsPtr = &Hits;
@@ -6211,7 +6877,7 @@ namespace clang {
public:
explicit ASTIdentifierIterator(const ASTReader &Reader);
- virtual StringRef Next();
+ StringRef Next() override;
};
}
@@ -6330,7 +6996,7 @@ void ASTReader::ReadMethodPool(Selector Sel) {
// Get the selector generation and update it to the current generation.
unsigned &Generation = SelectorGeneration[Sel];
unsigned PriorGeneration = Generation;
- Generation = CurrentGeneration;
+ Generation = getGeneration();
// Search for methods defined with this selector.
++NumMethodPoolLookups;
@@ -6587,11 +7253,11 @@ ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II,
IdentifierInfo *ASTReader::DecodeIdentifierInfo(IdentifierID ID) {
if (ID == 0)
- return 0;
+ return nullptr;
if (IdentifiersLoaded.empty()) {
Error("no identifier table in AST file");
- return 0;
+ return nullptr;
}
ID -= 1;
@@ -6637,11 +7303,11 @@ IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) {
MacroInfo *ASTReader::getMacro(MacroID ID) {
if (ID == 0)
- return 0;
+ return nullptr;
if (MacrosLoaded.empty()) {
Error("no macro table in AST file");
- return 0;
+ return nullptr;
}
ID -= NUM_PREDEF_MACRO_IDS;
@@ -6688,12 +7354,12 @@ ASTReader::getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID) {
Module *ASTReader::getSubmodule(SubmoduleID GlobalID) {
if (GlobalID < NUM_PREDEF_SUBMODULE_IDS) {
assert(GlobalID == 0 && "Unhandled global submodule ID");
- return 0;
+ return nullptr;
}
if (GlobalID > SubmodulesLoaded.size()) {
Error("submodule ID out of range in AST file");
- return 0;
+ return nullptr;
}
return SubmodulesLoaded[GlobalID - NUM_PREDEF_SUBMODULE_IDS];
@@ -6716,7 +7382,7 @@ Selector ASTReader::DecodeSelector(serialization::SelectorID ID) {
return Selector();
}
- if (SelectorsLoaded[ID - 1].getAsOpaquePtr() == 0) {
+ if (SelectorsLoaded[ID - 1].getAsOpaquePtr() == nullptr) {
// Load this selector from the selector table.
GlobalSelectorMapType::iterator I = GlobalSelectorMap.find(ID);
assert(I != GlobalSelectorMap.end() && "Corrupted global selector map");
@@ -7012,16 +7678,16 @@ ASTReader::ReadCXXBaseSpecifier(ModuleFile &F,
std::pair<CXXCtorInitializer **, unsigned>
ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record,
unsigned &Idx) {
- CXXCtorInitializer **CtorInitializers = 0;
+ CXXCtorInitializer **CtorInitializers = nullptr;
unsigned NumInitializers = Record[Idx++];
if (NumInitializers) {
CtorInitializers
= new (Context) CXXCtorInitializer*[NumInitializers];
for (unsigned i=0; i != NumInitializers; ++i) {
- TypeSourceInfo *TInfo = 0;
+ TypeSourceInfo *TInfo = nullptr;
bool IsBaseVirtual = false;
- FieldDecl *Member = 0;
- IndirectFieldDecl *IndirectMember = 0;
+ FieldDecl *Member = nullptr;
+ IndirectFieldDecl *IndirectMember = nullptr;
CtorInitializerType Type = (CtorInitializerType)Record[Idx++];
switch (Type) {
@@ -7101,7 +7767,7 @@ NestedNameSpecifier *
ASTReader::ReadNestedNameSpecifier(ModuleFile &F,
const RecordData &Record, unsigned &Idx) {
unsigned N = Record[Idx++];
- NestedNameSpecifier *NNS = 0, *Prev = 0;
+ NestedNameSpecifier *NNS = nullptr, *Prev = nullptr;
for (unsigned I = 0; I != N; ++I) {
NestedNameSpecifier::SpecifierKind Kind
= (NestedNameSpecifier::SpecifierKind)Record[Idx++];
@@ -7128,8 +7794,8 @@ ASTReader::ReadNestedNameSpecifier(ModuleFile &F,
case NestedNameSpecifier::TypeSpecWithTemplate: {
const Type *T = readType(F, Record, Idx).getTypePtrOrNull();
if (!T)
- return 0;
-
+ return nullptr;
+
bool Template = Record[Idx++];
NNS = NestedNameSpecifier::Create(Context, Prev, Template, T);
break;
@@ -7276,14 +7942,14 @@ IdentifierTable &ASTReader::getIdentifierTable() {
/// \brief Record that the given ID maps to the given switch-case
/// statement.
void ASTReader::RecordSwitchCaseID(SwitchCase *SC, unsigned ID) {
- assert((*CurrSwitchCaseStmts)[ID] == 0 &&
+ assert((*CurrSwitchCaseStmts)[ID] == nullptr &&
"Already have a SwitchCase with this ID");
(*CurrSwitchCaseStmts)[ID] = SC;
}
/// \brief Retrieve the switch-case statement with the given ID.
SwitchCase *ASTReader::getSwitchCaseWithID(unsigned ID) {
- assert((*CurrSwitchCaseStmts)[ID] != 0 && "No SwitchCase with this ID");
+ assert((*CurrSwitchCaseStmts)[ID] != nullptr && "No SwitchCase with this ID");
return (*CurrSwitchCaseStmts)[ID];
}
@@ -7298,6 +7964,7 @@ void ASTReader::ReadComments() {
I = CommentsCursors.begin(),
E = CommentsCursors.end();
I != E; ++I) {
+ Comments.clear();
BitstreamCursor &Cursor = I->first;
serialization::ModuleFile &F = *I->second;
SavedStreamPosition SavedPosition(Cursor);
@@ -7306,7 +7973,7 @@ void ASTReader::ReadComments() {
while (true) {
llvm::BitstreamEntry Entry =
Cursor.advanceSkippingSubblocks(BitstreamCursor::AF_DontPopBlockAtEnd);
-
+
switch (Entry.Kind) {
case llvm::BitstreamEntry::SubBlock: // Handled for us already.
case llvm::BitstreamEntry::Error:
@@ -7336,15 +8003,29 @@ void ASTReader::ReadComments() {
}
}
}
- NextCursor:;
+ NextCursor:
+ Context.Comments.addDeserializedComments(Comments);
}
- Context.Comments.addCommentsToFront(Comments);
+}
+
+std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) {
+ // If we know the owning module, use it.
+ if (Module *M = D->getOwningModule())
+ return M->getFullModuleName();
+
+ // Otherwise, use the name of the top-level module the decl is within.
+ if (ModuleFile *M = getOwningModuleFile(D))
+ return M->ModuleName;
+
+ // Not from a module.
+ return "";
}
void ASTReader::finishPendingActions() {
- while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty() ||
+ while (!PendingIdentifierInfos.empty() ||
+ !PendingIncompleteDeclChains.empty() || !PendingDeclChains.empty() ||
!PendingMacroIDs.empty() || !PendingDeclContextInfos.empty() ||
- !PendingOdrMergeChecks.empty()) {
+ !PendingUpdateRecords.empty() || !PendingOdrMergeChecks.empty()) {
// If any identifiers with corresponding top-level declarations have
// been loaded, load those declarations now.
typedef llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2> >
@@ -7352,14 +8033,21 @@ void ASTReader::finishPendingActions() {
TopLevelDeclsMap TopLevelDecls;
while (!PendingIdentifierInfos.empty()) {
- // FIXME: std::move
IdentifierInfo *II = PendingIdentifierInfos.back().first;
- SmallVector<uint32_t, 4> DeclIDs = PendingIdentifierInfos.back().second;
+ SmallVector<uint32_t, 4> DeclIDs =
+ std::move(PendingIdentifierInfos.back().second);
PendingIdentifierInfos.pop_back();
SetGloballyVisibleDecls(II, DeclIDs, &TopLevelDecls[II]);
}
-
+
+ // For each decl chain that we wanted to complete while deserializing, mark
+ // it as "still needs to be completed".
+ for (unsigned I = 0; I != PendingIncompleteDeclChains.size(); ++I) {
+ markIncompleteDeclChain(PendingIncompleteDeclChains[I]);
+ }
+ PendingIncompleteDeclChains.clear();
+
// Load pending declaration chains.
for (unsigned I = 0; I != PendingDeclChains.size(); ++I) {
loadPendingDeclChain(PendingDeclChains[I]);
@@ -7382,14 +8070,14 @@ void ASTReader::finishPendingActions() {
SmallVector<PendingMacroInfo, 2> GlobalIDs;
GlobalIDs.swap(PendingMacroIDs.begin()[I].second);
// Initialize the macro history from chained-PCHs ahead of module imports.
- for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
+ for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
++IDIdx) {
const PendingMacroInfo &Info = GlobalIDs[IDIdx];
if (Info.M->Kind != MK_Module)
resolvePendingMacro(II, Info);
}
// Handle module imports.
- for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
+ for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
++IDIdx) {
const PendingMacroInfo &Info = GlobalIDs[IDIdx];
if (Info.M->Kind == MK_Module)
@@ -7408,6 +8096,30 @@ void ASTReader::finishPendingActions() {
Info.D->setDeclContextsImpl(SemaDC, LexicalDC, getContext());
}
+ // Perform any pending declaration updates.
+ //
+ // Don't do this if we have known-incomplete redecl chains: it relies on
+ // being able to walk redeclaration chains.
+ while (PendingDeclChains.empty() && !PendingUpdateRecords.empty()) {
+ auto Update = PendingUpdateRecords.pop_back_val();
+ ReadingKindTracker ReadingKind(Read_Decl, *this);
+ loadDeclUpdateRecords(Update.first, Update.second);
+ }
+
+ // Trigger the import of the full definition of each class that had any
+ // odr-merging problems, so we can produce better diagnostics for them.
+ for (auto &Merge : PendingOdrMergeFailures) {
+ Merge.first->buildLookup();
+ Merge.first->decls_begin();
+ Merge.first->bases_begin();
+ Merge.first->vbases_begin();
+ for (auto *RD : Merge.second) {
+ RD->decls_begin();
+ RD->bases_begin();
+ RD->vbases_begin();
+ }
+ }
+
// For each declaration from a merged context, check that the canonical
// definition of that context also contains a declaration of the same
// entity.
@@ -7430,16 +8142,14 @@ void ASTReader::finishPendingActions() {
llvm::SmallVector<const NamedDecl*, 4> Candidates;
for (DeclContext::lookup_iterator I = R.begin(), E = R.end();
!Found && I != E; ++I) {
- for (Decl::redecl_iterator RI = (*I)->redecls_begin(),
- RE = (*I)->redecls_end();
- RI != RE; ++RI) {
- if ((*RI)->getLexicalDeclContext() == CanonDef) {
+ for (auto RI : (*I)->redecls()) {
+ if (RI->getLexicalDeclContext() == CanonDef) {
// This declaration is present in the canonical definition. If it's
// in the same redecl chain, it's the one we're looking for.
- if ((*RI)->getCanonicalDecl() == DCanon)
+ if (RI->getCanonicalDecl() == DCanon)
Found = true;
else
- Candidates.push_back(cast<NamedDecl>(*RI));
+ Candidates.push_back(cast<NamedDecl>(RI));
break;
}
}
@@ -7448,11 +8158,11 @@ void ASTReader::finishPendingActions() {
if (!Found) {
D->setInvalidDecl();
- Module *CanonDefModule = cast<Decl>(CanonDef)->getOwningModule();
+ std::string CanonDefModule =
+ getOwningModuleNameForDiagnostic(cast<Decl>(CanonDef));
Diag(D->getLocation(), diag::err_module_odr_violation_missing_decl)
- << D << D->getOwningModule()->getFullModuleName()
- << CanonDef << !CanonDefModule
- << (CanonDefModule ? CanonDefModule->getFullModuleName() : "");
+ << D << getOwningModuleNameForDiagnostic(D)
+ << CanonDef << CanonDefModule.empty() << CanonDefModule;
if (Candidates.empty())
Diag(cast<Decl>(CanonDef)->getLocation(),
@@ -7463,6 +8173,8 @@ void ASTReader::finishPendingActions() {
diag::note_module_odr_violation_possible_decl)
<< Candidates[I];
}
+
+ DiagnosedOdrMergeFailures.insert(CanonDef);
}
}
}
@@ -7475,49 +8187,39 @@ void ASTReader::finishPendingActions() {
DEnd = PendingDefinitions.end();
D != DEnd; ++D) {
if (TagDecl *TD = dyn_cast<TagDecl>(*D)) {
- if (const TagType *TagT = dyn_cast<TagType>(TD->TypeForDecl)) {
+ if (const TagType *TagT = dyn_cast<TagType>(TD->getTypeForDecl())) {
// Make sure that the TagType points at the definition.
const_cast<TagType*>(TagT)->decl = TD;
}
- if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(*D)) {
- for (CXXRecordDecl::redecl_iterator R = RD->redecls_begin(),
- REnd = RD->redecls_end();
- R != REnd; ++R)
- cast<CXXRecordDecl>(*R)->DefinitionData = RD->DefinitionData;
-
+ if (auto RD = dyn_cast<CXXRecordDecl>(*D)) {
+ for (auto R : RD->redecls())
+ cast<CXXRecordDecl>(R)->DefinitionData = RD->DefinitionData;
}
continue;
}
- if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(*D)) {
+ if (auto ID = dyn_cast<ObjCInterfaceDecl>(*D)) {
// Make sure that the ObjCInterfaceType points at the definition.
const_cast<ObjCInterfaceType *>(cast<ObjCInterfaceType>(ID->TypeForDecl))
->Decl = ID;
- for (ObjCInterfaceDecl::redecl_iterator R = ID->redecls_begin(),
- REnd = ID->redecls_end();
- R != REnd; ++R)
+ for (auto R : ID->redecls())
R->Data = ID->Data;
continue;
}
- if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(*D)) {
- for (ObjCProtocolDecl::redecl_iterator R = PD->redecls_begin(),
- REnd = PD->redecls_end();
- R != REnd; ++R)
+ if (auto PD = dyn_cast<ObjCProtocolDecl>(*D)) {
+ for (auto R : PD->redecls())
R->Data = PD->Data;
continue;
}
- RedeclarableTemplateDecl *RTD
- = cast<RedeclarableTemplateDecl>(*D)->getCanonicalDecl();
- for (RedeclarableTemplateDecl::redecl_iterator R = RTD->redecls_begin(),
- REnd = RTD->redecls_end();
- R != REnd; ++R)
+ auto RTD = cast<RedeclarableTemplateDecl>(*D)->getCanonicalDecl();
+ for (auto R : RTD->redecls())
R->Common = RTD->Common;
}
PendingDefinitions.clear();
@@ -7541,6 +8243,46 @@ void ASTReader::finishPendingActions() {
MD->setLazyBody(PB->second);
}
PendingBodies.clear();
+
+ // Issue any pending ODR-failure diagnostics.
+ for (auto &Merge : PendingOdrMergeFailures) {
+ if (!DiagnosedOdrMergeFailures.insert(Merge.first))
+ continue;
+
+ bool Diagnosed = false;
+ for (auto *RD : Merge.second) {
+ // Multiple different declarations got merged together; tell the user
+ // where they came from.
+ if (Merge.first != RD) {
+ // FIXME: Walk the definition, figure out what's different,
+ // and diagnose that.
+ if (!Diagnosed) {
+ std::string Module = getOwningModuleNameForDiagnostic(Merge.first);
+ Diag(Merge.first->getLocation(),
+ diag::err_module_odr_violation_different_definitions)
+ << Merge.first << Module.empty() << Module;
+ Diagnosed = true;
+ }
+
+ Diag(RD->getLocation(),
+ diag::note_module_odr_violation_different_definitions)
+ << getOwningModuleNameForDiagnostic(RD);
+ }
+ }
+
+ if (!Diagnosed) {
+ // All definitions are updates to the same declaration. This happens if a
+ // module instantiates the declaration of a class template specialization
+ // and two or more other modules instantiate its definition.
+ //
+ // FIXME: Indicate which modules had instantiations of this definition.
+ // FIXME: How can this even happen?
+ Diag(Merge.first->getLocation(),
+ diag::err_module_odr_violation_different_instantiations)
+ << Merge.first;
+ }
+ }
+ PendingOdrMergeFailures.clear();
}
void ASTReader::FinishedDeserializing() {
@@ -7553,20 +8295,10 @@ void ASTReader::FinishedDeserializing() {
}
--NumCurrentElementsDeserializing;
- if (NumCurrentElementsDeserializing == 0 &&
- Consumer && !PassingDeclsToConsumer) {
- // Guard variable to avoid recursively redoing the process of passing
- // decls to consumer.
- SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer,
- true);
-
- while (!InterestingDecls.empty()) {
- // We are not in recursive loading, so it's safe to pass the "interesting"
- // decls to the consumer.
- Decl *D = InterestingDecls.front();
- InterestingDecls.pop_front();
- PassInterestingDeclToConsumer(D);
- }
+ if (NumCurrentElementsDeserializing == 0 && Consumer) {
+ // We are not in recursive loading, so it's safe to pass the "interesting"
+ // decls to the consumer.
+ PassInterestingDeclsToConsumer();
}
}
@@ -7585,34 +8317,39 @@ void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) {
}
}
-ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
- StringRef isysroot, bool DisableValidation,
- bool AllowASTWithCompilerErrors, bool UseGlobalIndex)
- : Listener(new PCHValidator(PP, *this)), DeserializationListener(0),
- SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()),
- Diags(PP.getDiagnostics()), SemaObj(0), PP(PP), Context(Context),
- Consumer(0), ModuleMgr(PP.getFileManager()),
- isysroot(isysroot), DisableValidation(DisableValidation),
- AllowASTWithCompilerErrors(AllowASTWithCompilerErrors),
- UseGlobalIndex(UseGlobalIndex), TriedLoadingGlobalIndex(false),
- CurrentGeneration(0), CurrSwitchCaseStmts(&SwitchCaseStmts),
- NumSLocEntriesRead(0), TotalNumSLocEntries(0),
- NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0),
- TotalNumMacros(0), NumIdentifierLookups(0), NumIdentifierLookupHits(0),
- NumSelectorsRead(0), NumMethodPoolEntriesRead(0),
- NumMethodPoolLookups(0), NumMethodPoolHits(0),
- NumMethodPoolTableLookups(0), NumMethodPoolTableHits(0),
- TotalNumMethodPoolEntries(0),
- NumLexicalDeclContextsRead(0), TotalLexicalDeclContexts(0),
- NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0),
- TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0),
- PassingDeclsToConsumer(false),
- NumCXXBaseSpecifiersLoaded(0), ReadingKind(Read_None)
-{
+ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot,
+ bool DisableValidation, bool AllowASTWithCompilerErrors,
+ bool AllowConfigurationMismatch, bool ValidateSystemInputs,
+ bool UseGlobalIndex)
+ : Listener(new PCHValidator(PP, *this)), DeserializationListener(nullptr),
+ OwnsDeserializationListener(false), SourceMgr(PP.getSourceManager()),
+ FileMgr(PP.getFileManager()), Diags(PP.getDiagnostics()),
+ SemaObj(nullptr), PP(PP), Context(Context), Consumer(nullptr),
+ ModuleMgr(PP.getFileManager()), isysroot(isysroot),
+ DisableValidation(DisableValidation),
+ AllowASTWithCompilerErrors(AllowASTWithCompilerErrors),
+ AllowConfigurationMismatch(AllowConfigurationMismatch),
+ ValidateSystemInputs(ValidateSystemInputs),
+ UseGlobalIndex(UseGlobalIndex), TriedLoadingGlobalIndex(false),
+ CurrSwitchCaseStmts(&SwitchCaseStmts),
+ NumSLocEntriesRead(0), TotalNumSLocEntries(0), NumStatementsRead(0),
+ TotalNumStatements(0), NumMacrosRead(0), TotalNumMacros(0),
+ NumIdentifierLookups(0), NumIdentifierLookupHits(0), NumSelectorsRead(0),
+ NumMethodPoolEntriesRead(0), NumMethodPoolLookups(0),
+ NumMethodPoolHits(0), NumMethodPoolTableLookups(0),
+ NumMethodPoolTableHits(0), TotalNumMethodPoolEntries(0),
+ NumLexicalDeclContextsRead(0), TotalLexicalDeclContexts(0),
+ NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0),
+ TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0),
+ PassingDeclsToConsumer(false), NumCXXBaseSpecifiersLoaded(0),
+ ReadingKind(Read_None) {
SourceMgr.setExternalSLocEntrySource(this);
}
ASTReader::~ASTReader() {
+ if (OwnsDeserializationListener)
+ delete DeserializationListener;
+
for (DeclContextVisibleUpdatesPending::iterator
I = PendingVisibleUpdates.begin(),
E = PendingVisibleUpdates.end();
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index b8102d84173e..9ed1bf97ec7a 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -99,16 +99,19 @@ namespace clang {
Module *readModule(const RecordData &R, unsigned &I) {
return Reader.getSubmodule(readSubmoduleID(R, I));
}
-
+
+ void ReadCXXRecordDefinition(CXXRecordDecl *D);
void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data,
const RecordData &R, unsigned &I);
+ void MergeDefinitionData(CXXRecordDecl *D,
+ struct CXXRecordDecl::DefinitionData &NewDD);
/// \brief RAII class used to capture the first ID within a redeclaration
/// chain and to introduce it into the list of pending redeclaration chains
/// on destruction.
///
- /// The caller can choose not to introduce this ID into the redeclaration
- /// chain by calling \c suppress().
+ /// The caller can choose not to introduce this ID into the list of pending
+ /// redeclaration chains by calling \c suppress().
class RedeclarableResult {
ASTReader &Reader;
GlobalDeclID FirstID;
@@ -160,8 +163,8 @@ namespace clang {
public:
FindExistingResult(ASTReader &Reader)
- : Reader(Reader), New(0), Existing(0), AddResult(false) { }
-
+ : Reader(Reader), New(nullptr), Existing(nullptr), AddResult(false) {}
+
FindExistingResult(ASTReader &Reader, NamedDecl *New, NamedDecl *Existing)
: Reader(Reader), New(New), Existing(Existing), AddResult(true) { }
@@ -195,9 +198,20 @@ namespace clang {
RawLocation(RawLocation), Record(Record), Idx(Idx),
TypeIDForTypeDecl(0), HasPendingBody(false) { }
+ template <typename DeclT>
+ static void attachPreviousDeclImpl(Redeclarable<DeclT> *D, Decl *Previous);
+ static void attachPreviousDeclImpl(...);
static void attachPreviousDecl(Decl *D, Decl *previous);
+
+ template <typename DeclT>
+ static void attachLatestDeclImpl(Redeclarable<DeclT> *D, Decl *Latest);
+ static void attachLatestDeclImpl(...);
static void attachLatestDecl(Decl *D, Decl *latest);
+ template <typename DeclT>
+ static void markIncompleteDeclChainImpl(Redeclarable<DeclT> *D);
+ static void markIncompleteDeclChainImpl(...);
+
/// \brief Determine whether this declaration has a pending body.
bool hasPendingBody() const { return HasPendingBody; }
@@ -264,7 +278,7 @@ namespace clang {
void VisitImplicitParamDecl(ImplicitParamDecl *PD);
void VisitParmVarDecl(ParmVarDecl *PD);
void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
- void VisitTemplateDecl(TemplateDecl *D);
+ DeclID VisitTemplateDecl(TemplateDecl *D);
RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
void VisitVarTemplateDecl(VarTemplateDecl *D);
@@ -285,20 +299,26 @@ namespace clang {
void VisitEmptyDecl(EmptyDecl *D);
std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
-
- template<typename T>
+
+ template<typename T>
RedeclarableResult VisitRedeclarable(Redeclarable<T> *D);
template<typename T>
- void mergeRedeclarable(Redeclarable<T> *D, RedeclarableResult &Redecl);
+ void mergeRedeclarable(Redeclarable<T> *D, RedeclarableResult &Redecl,
+ DeclID TemplatePatternID = 0);
template<typename T>
void mergeRedeclarable(Redeclarable<T> *D, T *Existing,
- RedeclarableResult &Redecl);
+ RedeclarableResult &Redecl,
+ DeclID TemplatePatternID = 0);
template<typename T>
void mergeMergeable(Mergeable<T> *D);
+ void mergeTemplatePattern(RedeclarableTemplateDecl *D,
+ RedeclarableTemplateDecl *Existing,
+ DeclID DsID);
+
// FIXME: Reorder according to DeclNodes.td?
void VisitObjCMethodDecl(ObjCMethodDecl *D);
void VisitObjCContainerDecl(ObjCContainerDecl *D);
@@ -337,7 +357,7 @@ void ASTDeclReader::Visit(Decl *D) {
}
if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) {
- // if we have a fully initialized TypeDecl, we can safely read its type now.
+ // We have a fully initialized TypeDecl. Read its type now.
TD->setTypeForDecl(Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull());
} else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
// if we have a fully initialized TypeDecl, we can safely read its type now.
@@ -356,11 +376,14 @@ void ASTDeclReader::Visit(Decl *D) {
}
void ASTDeclReader::VisitDecl(Decl *D) {
- if (D->isTemplateParameter()) {
+ if (D->isTemplateParameter() || D->isTemplateParameterPack() ||
+ isa<ParmVarDecl>(D)) {
// We don't want to deserialize the DeclContext of a template
- // parameter immediately, because the template parameter might be
- // used in the formulation of its DeclContext. Use the translation
- // unit DeclContext as a placeholder.
+ // parameter or of a parameter of a function template immediately. These
+ // entities might be used in the formulation of its DeclContext (for
+ // example, a function parameter can be used in decltype() in trailing
+ // return type of the function). Use the translation unit DeclContext as a
+ // placeholder.
GlobalDeclID SemaDCIDForTemplateParmDecl = ReadDeclID(Record, Idx);
GlobalDeclID LexicalDCIDForTemplateParmDecl = ReadDeclID(Record, Idx);
Reader.addPendingDeclContextInfo(D,
@@ -409,7 +432,7 @@ void ASTDeclReader::VisitDecl(Decl *D) {
// Note that this declaration was hidden because its owning module is
// not yet visible.
- Reader.HiddenNamesMap[Owner].push_back(D);
+ Reader.HiddenNamesMap[Owner].HiddenDecls.push_back(D);
}
}
}
@@ -471,7 +494,8 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitTagDecl(TagDecl *TD) {
} else
TD->NamedDeclOrQualifier = ReadDeclAs<NamedDecl>(Record, Idx);
- mergeRedeclarable(TD, Redecl);
+ if (!isa<CXXRecordDecl>(TD))
+ mergeRedeclarable(TD, Redecl);
return Redecl;
}
@@ -573,9 +597,10 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
switch ((FunctionDecl::TemplatedKind)Record[Idx++]) {
case FunctionDecl::TK_NonTemplate:
- mergeRedeclarable(FD, Redecl);
+ mergeRedeclarable(FD, Redecl);
break;
case FunctionDecl::TK_FunctionTemplate:
+ // Merged when we merge the template.
FD->setDescribedFunctionTemplate(ReadDeclAs<FunctionTemplateDecl>(Record,
Idx));
break;
@@ -585,6 +610,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
SourceLocation POI = ReadSourceLocation(Record, Idx);
FD->setInstantiationOfMemberFunction(Reader.getContext(), InstFD, TSK);
FD->getMemberSpecializationInfo()->setPointOfInstantiation(POI);
+ mergeRedeclarable(FD, Redecl);
break;
}
case FunctionDecl::TK_FunctionTemplateSpecialization: {
@@ -622,7 +648,8 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FunctionTemplateSpecializationInfo *FTInfo
= FunctionTemplateSpecializationInfo::Create(C, FD, Template, TSK,
TemplArgList,
- HasTemplateArgumentsAsWritten ? &TemplArgsInfo : 0,
+ HasTemplateArgumentsAsWritten ? &TemplArgsInfo
+ : nullptr,
POI);
FD->TemplateOrSpecialization = FTInfo;
@@ -637,9 +664,8 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
// We avoid getASTContext because a decl in the parent hierarchy may
// be initializing.
llvm::FoldingSetNodeID ID;
- FunctionTemplateSpecializationInfo::Profile(ID, TemplArgs.data(),
- TemplArgs.size(), C);
- void *InsertPos = 0;
+ FunctionTemplateSpecializationInfo::Profile(ID, TemplArgs, C);
+ void *InsertPos = nullptr;
FunctionTemplateDecl::Common *CommonPtr = CanonTemplate->getCommonPtr();
CommonPtr->Specializations.FindNodeOrInsertPos(ID, InsertPos);
if (InsertPos)
@@ -670,6 +696,8 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->setDependentTemplateSpecialization(Reader.getContext(),
TemplDecls, TemplArgs);
+
+ // FIXME: Merging.
break;
}
}
@@ -709,8 +737,8 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]);
MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
MD->SetRelatedResultType(Record[Idx++]);
- MD->setResultType(Reader.readType(F, Record, Idx));
- MD->setResultTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
+ MD->setReturnType(Reader.readType(F, Record, Idx));
+ MD->setReturnTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
MD->DeclEndLoc = ReadSourceLocation(Record, Idx);
unsigned NumParams = Record[Idx++];
SmallVector<ParmVarDecl *, 16> Params;
@@ -755,6 +783,7 @@ void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
Data.SuperClassLoc = ReadSourceLocation(Record, Idx);
Data.EndLoc = ReadSourceLocation(Record, Idx);
+ Data.HasDesignatedInitializers = Record[Idx++];
// Read the directly referenced protocols and their SourceLocations.
unsigned NumProtocols = Record[Idx++];
@@ -779,8 +808,8 @@ void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
Reader.getContext());
// We will rebuild this list lazily.
- ID->setIvarList(0);
-
+ ID->setIvarList(nullptr);
+
// Note that we have deserialized a definition.
Reader.PendingDefinitions.insert(ID);
@@ -795,11 +824,9 @@ void ASTDeclReader::VisitObjCIvarDecl(ObjCIvarDecl *IVD) {
VisitFieldDecl(IVD);
IVD->setAccessControl((ObjCIvarDecl::AccessControl)Record[Idx++]);
// This field will be built lazily.
- IVD->setNextIvar(0);
+ IVD->setNextIvar(nullptr);
bool synth = Record[Idx++];
IVD->setSynthesize(synth);
- bool backingIvarReferencedInAccessor = Record[Idx++];
- IVD->setBackingIvarReferencedInAccessor(backingIvarReferencedInAccessor);
}
void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) {
@@ -907,8 +934,8 @@ void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
D->setIvarRBraceLoc(ReadSourceLocation(Record, Idx));
D->setHasNonZeroConstructors(Record[Idx++]);
D->setHasDestructors(Record[Idx++]);
- llvm::tie(D->IvarInitializers, D->NumIvarInitializers)
- = Reader.ReadCXXCtorInitializers(F, Record, Idx);
+ std::tie(D->IvarInitializers, D->NumIvarInitializers) =
+ Reader.ReadCXXCtorInitializers(F, Record, Idx);
}
@@ -971,14 +998,10 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
VD->setCachedLinkage(VarLinkage);
// Reconstruct the one piece of the IdentifierNamespace that we need.
- if (VarLinkage != NoLinkage &&
+ if (VD->getStorageClass() == SC_Extern && VarLinkage != NoLinkage &&
VD->getLexicalDeclContext()->isFunctionOrMethod())
VD->setLocalExternDecl();
- // Only true variables (not parameters or implicit parameters) can be merged.
- if (VD->getKind() != Decl::ParmVar && VD->getKind() != Decl::ImplicitParam)
- mergeRedeclarable(VD, Redecl);
-
if (uint64_t Val = Record[Idx++]) {
VD->setInit(Reader.ReadExpr(F));
if (Val > 1) {
@@ -993,8 +1016,13 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
};
switch ((VarKind)Record[Idx++]) {
case VarNotTemplate:
+ // Only true variables (not parameters or implicit parameters) can be merged
+ if (VD->getKind() != Decl::ParmVar && VD->getKind() != Decl::ImplicitParam &&
+ !isa<VarTemplateSpecializationDecl>(VD))
+ mergeRedeclarable(VD, Redecl);
break;
case VarTemplate:
+ // Merged when we merge the template.
VD->setDescribedVarTemplate(ReadDeclAs<VarTemplateDecl>(Record, Idx));
break;
case StaticDataMemberSpecialization: { // HasMemberSpecializationInfo.
@@ -1002,6 +1030,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
SourceLocation POI = ReadSourceLocation(Record, Idx);
Reader.getContext().setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI);
+ mergeRedeclarable(VD, Redecl);
break;
}
}
@@ -1065,7 +1094,7 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) {
unsigned flags = Record[Idx++];
bool byRef = (flags & 1);
bool nested = (flags & 2);
- Expr *copyExpr = ((flags & 4) ? Reader.ReadExpr(F) : 0);
+ Expr *copyExpr = ((flags & 4) ? Reader.ReadExpr(F) : nullptr);
captures.push_back(BlockDecl::Capture(decl, byRef, nested, copyExpr));
}
@@ -1075,9 +1104,15 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) {
void ASTDeclReader::VisitCapturedDecl(CapturedDecl *CD) {
VisitDecl(CD);
+ unsigned ContextParamPos = Record[Idx++];
+ CD->setNothrow(Record[Idx++] != 0);
// Body is set by VisitCapturedStmt.
- for (unsigned i = 0; i < CD->NumParams; ++i)
- CD->setParam(i, ReadDeclAs<ImplicitParamDecl>(Record, Idx));
+ for (unsigned I = 0; I < CD->NumParams; ++I) {
+ if (I != ContextParamPos)
+ CD->setParam(I, ReadDeclAs<ImplicitParamDecl>(Record, Idx));
+ else
+ CD->setContextParam(I, ReadDeclAs<ImplicitParamDecl>(Record, Idx));
+ }
}
void ASTDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
@@ -1099,8 +1134,6 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
D->setInline(Record[Idx++]);
D->LocStart = ReadSourceLocation(Record, Idx);
D->RBraceLoc = ReadSourceLocation(Record, Idx);
- // FIXME: At the point of this call, D->getCanonicalDecl() returns 0.
- mergeRedeclarable(D, Redecl);
if (Redecl.getFirstID() == ThisDeclID) {
// Each module has its own anonymous namespace, which is disjoint from
@@ -1114,6 +1147,8 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
// been deserialized.
D->AnonOrFirstNamespaceAndInline.setPointer(D->getFirstDecl());
}
+
+ mergeRedeclarable(D, Redecl);
}
void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
@@ -1186,6 +1221,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.HasProtectedFields = Record[Idx++];
Data.HasPublicFields = Record[Idx++];
Data.HasMutableFields = Record[Idx++];
+ Data.HasVariantMembers = Record[Idx++];
Data.HasOnlyCMembers = Record[Idx++];
Data.HasInClassInitializer = Record[Idx++];
Data.HasUninitializedReferenceMember = Record[Idx++];
@@ -1196,6 +1232,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.DefaultedMoveAssignmentIsDeleted = Record[Idx++];
Data.DefaultedDestructorIsDeleted = Record[Idx++];
Data.HasTrivialSpecialMembers = Record[Idx++];
+ Data.DeclaredNonTrivialSpecialMembers = Record[Idx++];
Data.HasIrrelevantDestructor = Record[Idx++];
Data.HasConstexprNonCopyMoveConstructor = Record[Idx++];
Data.DefaultedDefaultConstructorIsConstexpr = Record[Idx++];
@@ -1222,7 +1259,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.FirstFriend = ReadDeclID(Record, Idx);
if (Data.IsLambda) {
- typedef LambdaExpr::Capture Capture;
+ typedef LambdaCapture Capture;
CXXRecordDecl::LambdaDefinitionData &Lambda
= static_cast<CXXRecordDecl::LambdaDefinitionData &>(Data);
Lambda.Dependent = Record[Idx++];
@@ -1242,7 +1279,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
LambdaCaptureKind Kind = static_cast<LambdaCaptureKind>(Record[Idx++]);
switch (Kind) {
case LCK_This:
- *ToCapture++ = Capture(Loc, IsImplicit, Kind, 0, SourceLocation());
+ *ToCapture++ = Capture(Loc, IsImplicit, Kind, nullptr,SourceLocation());
break;
case LCK_ByCopy:
case LCK_ByRef:
@@ -1255,61 +1292,172 @@ void ASTDeclReader::ReadCXXDefinitionData(
}
}
+void ASTDeclReader::MergeDefinitionData(
+ CXXRecordDecl *D, struct CXXRecordDecl::DefinitionData &MergeDD) {
+ assert(D->DefinitionData.getNotUpdated() &&
+ "merging class definition into non-definition");
+ auto &DD = *D->DefinitionData.getNotUpdated();
+
+ // If the new definition has new special members, let the name lookup
+ // code know that it needs to look in the new definition too.
+ if ((MergeDD.DeclaredSpecialMembers & ~DD.DeclaredSpecialMembers) &&
+ DD.Definition != MergeDD.Definition) {
+ Reader.MergedLookups[DD.Definition].push_back(MergeDD.Definition);
+ DD.Definition->setHasExternalVisibleStorage();
+ }
+
+ // FIXME: Move this out into a .def file?
+ // FIXME: Issue a diagnostic on a mismatched MATCH_FIELD, rather than
+ // asserting; this can happen in the case of an ODR violation.
+ bool DetectedOdrViolation = false;
+#define OR_FIELD(Field) DD.Field |= MergeDD.Field;
+#define MATCH_FIELD(Field) \
+ DetectedOdrViolation |= DD.Field != MergeDD.Field; \
+ OR_FIELD(Field)
+ MATCH_FIELD(UserDeclaredConstructor)
+ MATCH_FIELD(UserDeclaredSpecialMembers)
+ MATCH_FIELD(Aggregate)
+ MATCH_FIELD(PlainOldData)
+ MATCH_FIELD(Empty)
+ MATCH_FIELD(Polymorphic)
+ MATCH_FIELD(Abstract)
+ MATCH_FIELD(IsStandardLayout)
+ MATCH_FIELD(HasNoNonEmptyBases)
+ MATCH_FIELD(HasPrivateFields)
+ MATCH_FIELD(HasProtectedFields)
+ MATCH_FIELD(HasPublicFields)
+ MATCH_FIELD(HasMutableFields)
+ MATCH_FIELD(HasVariantMembers)
+ MATCH_FIELD(HasOnlyCMembers)
+ MATCH_FIELD(HasInClassInitializer)
+ MATCH_FIELD(HasUninitializedReferenceMember)
+ MATCH_FIELD(NeedOverloadResolutionForMoveConstructor)
+ MATCH_FIELD(NeedOverloadResolutionForMoveAssignment)
+ MATCH_FIELD(NeedOverloadResolutionForDestructor)
+ MATCH_FIELD(DefaultedMoveConstructorIsDeleted)
+ MATCH_FIELD(DefaultedMoveAssignmentIsDeleted)
+ MATCH_FIELD(DefaultedDestructorIsDeleted)
+ OR_FIELD(HasTrivialSpecialMembers)
+ OR_FIELD(DeclaredNonTrivialSpecialMembers)
+ MATCH_FIELD(HasIrrelevantDestructor)
+ OR_FIELD(HasConstexprNonCopyMoveConstructor)
+ MATCH_FIELD(DefaultedDefaultConstructorIsConstexpr)
+ OR_FIELD(HasConstexprDefaultConstructor)
+ MATCH_FIELD(HasNonLiteralTypeFieldsOrBases)
+ // ComputedVisibleConversions is handled below.
+ MATCH_FIELD(UserProvidedDefaultConstructor)
+ OR_FIELD(DeclaredSpecialMembers)
+ MATCH_FIELD(ImplicitCopyConstructorHasConstParam)
+ MATCH_FIELD(ImplicitCopyAssignmentHasConstParam)
+ OR_FIELD(HasDeclaredCopyConstructorWithConstParam)
+ OR_FIELD(HasDeclaredCopyAssignmentWithConstParam)
+ MATCH_FIELD(IsLambda)
+#undef OR_FIELD
+#undef MATCH_FIELD
+
+ if (DD.NumBases != MergeDD.NumBases || DD.NumVBases != MergeDD.NumVBases)
+ DetectedOdrViolation = true;
+ // FIXME: Issue a diagnostic if the base classes don't match when we come
+ // to lazily load them.
+
+ // FIXME: Issue a diagnostic if the list of conversion functions doesn't
+ // match when we come to lazily load them.
+ if (MergeDD.ComputedVisibleConversions && !DD.ComputedVisibleConversions) {
+ DD.VisibleConversions = std::move(MergeDD.VisibleConversions);
+ DD.ComputedVisibleConversions = true;
+ }
+
+ // FIXME: Issue a diagnostic if FirstFriend doesn't match when we come to
+ // lazily load it.
+
+ if (DD.IsLambda) {
+ // FIXME: ODR-checking for merging lambdas (this happens, for instance,
+ // when they occur within the body of a function template specialization).
+ }
+
+ if (DetectedOdrViolation)
+ Reader.PendingOdrMergeFailures[DD.Definition].push_back(MergeDD.Definition);
+}
+
+void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D) {
+ struct CXXRecordDecl::DefinitionData *DD;
+ ASTContext &C = Reader.getContext();
+
+ // Determine whether this is a lambda closure type, so that we can
+ // allocate the appropriate DefinitionData structure.
+ bool IsLambda = Record[Idx++];
+ if (IsLambda)
+ DD = new (C) CXXRecordDecl::LambdaDefinitionData(D, nullptr, false, false,
+ LCD_None);
+ else
+ DD = new (C) struct CXXRecordDecl::DefinitionData(D);
+
+ ReadCXXDefinitionData(*DD, Record, Idx);
+
+ // If we're reading an update record, we might already have a definition for
+ // this record. If so, just merge into it.
+ if (D->DefinitionData.getNotUpdated()) {
+ MergeDefinitionData(D, *DD);
+ return;
+ }
+
+ // Propagate the DefinitionData pointer to the canonical declaration, so
+ // that all other deserialized declarations will see it.
+ CXXRecordDecl *Canon = D->getCanonicalDecl();
+ if (Canon == D) {
+ D->DefinitionData = DD;
+ D->IsCompleteDefinition = true;
+ } else if (auto *CanonDD = Canon->DefinitionData.getNotUpdated()) {
+ // We have already deserialized a definition of this record. This
+ // definition is no longer really a definition. Note that the pre-existing
+ // definition is the *real* definition.
+ Reader.MergedDeclContexts.insert(
+ std::make_pair(D, CanonDD->Definition));
+ D->DefinitionData = Canon->DefinitionData;
+ D->IsCompleteDefinition = false;
+ MergeDefinitionData(D, *DD);
+ } else {
+ Canon->DefinitionData = DD;
+ D->DefinitionData = Canon->DefinitionData;
+ D->IsCompleteDefinition = true;
+
+ // Note that we have deserialized a definition. Any declarations
+ // deserialized before this one will be be given the DefinitionData
+ // pointer at the end.
+ Reader.PendingDefinitions.insert(D);
+ }
+}
+
ASTDeclReader::RedeclarableResult
ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
RedeclarableResult Redecl = VisitRecordDeclImpl(D);
ASTContext &C = Reader.getContext();
- bool WasDefinition = Record[Idx++];
- if (WasDefinition) {
- // Determine whether this is a lambda closure type, so that we can
- // allocate the appropriate DefinitionData structure.
- bool IsLambda = Record[Idx++];
- if (IsLambda)
- D->DefinitionData = new (C) CXXRecordDecl::LambdaDefinitionData(D, 0,
- false,
- false, LCD_None);
- else
- D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D);
-
- ReadCXXDefinitionData(*D->DefinitionData, Record, Idx);
-
- // Propagate the DefinitionData pointer to the canonical declaration, so
- // that all other deserialized declarations will see it.
- CXXRecordDecl *Canon = D->getCanonicalDecl();
- if (Canon == D) {
- // Nothing to do.
- } else if (!Canon->DefinitionData) {
- Canon->DefinitionData = D->DefinitionData;
-
- // Note that we have deserialized a definition. Any declarations
- // deserialized before this one will be be given the DefinitionData
- // pointer at the end.
- Reader.PendingDefinitions.insert(D);
- } else {
- // We have already deserialized a definition of this record. This
- // definition is no longer really a definition. Note that the pre-existing
- // definition is the *real* definition.
- // FIXME: Check DefinitionData for consistency with prior definition.
- Reader.MergedDeclContexts.insert(
- std::make_pair(D, D->getCanonicalDecl()->DefinitionData->Definition));
- D->IsCompleteDefinition = false;
- D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
- }
- } else {
- // Propagate DefinitionData pointer from the canonical declaration.
- D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
- }
enum CXXRecKind {
CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization
};
switch ((CXXRecKind)Record[Idx++]) {
case CXXRecNotTemplate:
+ // Merged when we merge the folding set entry in the primary template.
+ if (!isa<ClassTemplateSpecializationDecl>(D))
+ mergeRedeclarable(D, Redecl);
+ break;
+ case CXXRecTemplate: {
+ // Merged when we merge the template.
+ ClassTemplateDecl *Template = ReadDeclAs<ClassTemplateDecl>(Record, Idx);
+ D->TemplateOrInstantiation = Template;
+ if (!Template->getTemplatedDecl()) {
+ // We've not actually loaded the ClassTemplateDecl yet, because we're
+ // currently being loaded as its pattern. Rely on it to set up our
+ // TypeForDecl (see VisitClassTemplateDecl).
+ //
+ // Beware: we do not yet know our canonical declaration, and may still
+ // get merged once the surrounding class template has got off the ground.
+ TypeIDForTypeDecl = 0;
+ }
break;
- case CXXRecTemplate:
- D->TemplateOrInstantiation = ReadDeclAs<ClassTemplateDecl>(Record, Idx);
- break;
+ }
case CXXRecMemberSpecialization: {
CXXRecordDecl *RD = ReadDeclAs<CXXRecordDecl>(Record, Idx);
TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
@@ -1317,15 +1465,26 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
MemberSpecializationInfo *MSI = new (C) MemberSpecializationInfo(RD, TSK);
MSI->setPointOfInstantiation(POI);
D->TemplateOrInstantiation = MSI;
+ mergeRedeclarable(D, Redecl);
break;
}
}
+ bool WasDefinition = Record[Idx++];
+ if (WasDefinition)
+ ReadCXXRecordDefinition(D);
+ else
+ // Propagate DefinitionData pointer from the canonical declaration.
+ D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
+
// Lazily load the key function to avoid deserializing every method so we can
// compute it.
if (WasDefinition) {
DeclID KeyFn = ReadDeclID(Record, Idx);
if (KeyFn && D->IsCompleteDefinition)
+ // FIXME: This is wrong for the ARM ABI, where some other module may have
+ // made this function no longer be a key function. We need an update
+ // record or similar for that case.
C.KeyFunctions[D] = KeyFn;
}
@@ -1345,10 +1504,13 @@ void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
VisitCXXMethodDecl(D);
-
+
+ if (auto *CD = ReadDeclAs<CXXConstructorDecl>(Record, Idx))
+ D->setInheritedConstructor(CD);
D->IsExplicitSpecified = Record[Idx++];
- llvm::tie(D->CtorInitializers, D->NumCtorInitializers)
- = Reader.ReadCXXCtorInitializers(F, Record, Idx);
+ // FIXME: We should defer loading this until we need the constructor's body.
+ std::tie(D->CtorInitializers, D->NumCtorInitializers) =
+ Reader.ReadCXXCtorInitializers(F, Record, Idx);
}
void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
@@ -1404,16 +1566,19 @@ void ASTDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
D->FriendLoc = ReadSourceLocation(Record, Idx);
}
-void ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
+DeclID ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
VisitNamedDecl(D);
- NamedDecl *TemplatedDecl = ReadDeclAs<NamedDecl>(Record, Idx);
+ DeclID PatternID = ReadDeclID(Record, Idx);
+ NamedDecl *TemplatedDecl = cast_or_null<NamedDecl>(Reader.GetDecl(PatternID));
TemplateParameterList* TemplateParams
= Reader.ReadTemplateParameterList(F, Record, Idx);
D->init(TemplatedDecl, TemplateParams);
// FIXME: If this is a redeclaration of a template from another module, handle
// inheritance of default template arguments.
+
+ return PatternID;
}
ASTDeclReader::RedeclarableResult
@@ -1442,10 +1607,10 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
}
}
- VisitTemplateDecl(D);
+ DeclID PatternID = VisitTemplateDecl(D);
D->IdentifierNamespace = Record[Idx++];
- mergeRedeclarable(D, Redecl);
+ mergeRedeclarable(D, Redecl, PatternID);
// If we merged the template with a prior declaration chain, merge the common
// pointer.
@@ -1486,8 +1651,14 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
memcpy(CommonPtr->LazySpecializations, SpecIDs.data(),
SpecIDs.size() * sizeof(DeclID));
}
-
- CommonPtr->InjectedClassNameType = Reader.readType(F, Record, Idx);
+ }
+
+ if (D->getTemplatedDecl()->TemplateOrInstantiation) {
+ // We were loaded before our templated declaration was. We've not set up
+ // its corresponding type yet (see VisitCXXRecordDeclImpl), so reconstruct
+ // it now.
+ Reader.Context.getInjectedClassNameType(
+ D->getTemplatedDecl(), D->getInjectedClassNameSpecialization());
}
}
@@ -1580,18 +1751,18 @@ ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
// This declaration might be a definition. Merge with any existing
// definition.
- if (D->DefinitionData) {
- if (!CanonSpec->DefinitionData) {
- CanonSpec->DefinitionData = D->DefinitionData;
- } else {
- // FIXME: Check DefinitionData for consistency with prior definition
+ if (auto *DDD = D->DefinitionData.getNotUpdated()) {
+ if (auto *CanonDD = CanonSpec->DefinitionData.getNotUpdated()) {
+ MergeDefinitionData(CanonSpec, *DDD);
Reader.PendingDefinitions.erase(D);
Reader.MergedDeclContexts.insert(
- std::make_pair(D, CanonSpec->DefinitionData->Definition));
+ std::make_pair(D, CanonDD->Definition));
D->IsCompleteDefinition = false;
- D->DefinitionData = CanonSpec->DefinitionData;
+ } else {
+ CanonSpec->DefinitionData = D->DefinitionData;
}
}
+ D->DefinitionData = CanonSpec->DefinitionData;
}
}
}
@@ -1838,65 +2009,111 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
/// \brief Attempts to merge the given declaration (D) with another declaration
/// of the same entity.
template<typename T>
-void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
- RedeclarableResult &Redecl) {
+void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase,
+ RedeclarableResult &Redecl,
+ DeclID TemplatePatternID) {
+ T *D = static_cast<T*>(DBase);
+ T *DCanon = D->getCanonicalDecl();
+ if (D != DCanon &&
+ (!Reader.getContext().getLangOpts().Modules ||
+ Reader.getOwningModuleFile(DCanon) == Reader.getOwningModuleFile(D))) {
+ // All redeclarations between this declaration and its originally-canonical
+ // declaration get pulled in when we load DCanon; we don't need to
+ // perform any more merging now.
+ Redecl.suppress();
+ }
+
// If modules are not available, there is no reason to perform this merge.
if (!Reader.getContext().getLangOpts().Modules)
return;
- if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D)))
+ if (FindExistingResult ExistingRes = findExisting(D))
if (T *Existing = ExistingRes)
- mergeRedeclarable(D, Existing, Redecl);
+ mergeRedeclarable(D, Existing, Redecl, TemplatePatternID);
+}
+
+/// \brief "Cast" to type T, asserting if we don't have an implicit conversion.
+/// We use this to put code in a template that will only be valid for certain
+/// instantiations.
+template<typename T> static T assert_cast(T t) { return t; }
+template<typename T> static T assert_cast(...) {
+ llvm_unreachable("bad assert_cast");
+}
+
+/// \brief Merge together the pattern declarations from two template
+/// declarations.
+void ASTDeclReader::mergeTemplatePattern(RedeclarableTemplateDecl *D,
+ RedeclarableTemplateDecl *Existing,
+ DeclID DsID) {
+ auto *DPattern = D->getTemplatedDecl();
+ auto *ExistingPattern = Existing->getTemplatedDecl();
+ RedeclarableResult Result(Reader, DPattern->getCanonicalDecl()->getGlobalID(),
+ DPattern->getKind());
+ if (auto *DClass = dyn_cast<CXXRecordDecl>(DPattern)) {
+ // Merge with any existing definition.
+ // FIXME: This is duplicated in several places. Refactor.
+ auto *ExistingClass =
+ cast<CXXRecordDecl>(ExistingPattern)->getCanonicalDecl();
+ if (auto *DDD = DClass->DefinitionData.getNotUpdated()) {
+ if (auto *ExistingDD = ExistingClass->DefinitionData.getNotUpdated()) {
+ MergeDefinitionData(ExistingClass, *DDD);
+ Reader.PendingDefinitions.erase(DClass);
+ Reader.MergedDeclContexts.insert(
+ std::make_pair(DClass, ExistingDD->Definition));
+ DClass->IsCompleteDefinition = false;
+ } else {
+ ExistingClass->DefinitionData = DClass->DefinitionData;
+ }
+ }
+ DClass->DefinitionData = ExistingClass->DefinitionData;
+
+ return mergeRedeclarable(DClass, cast<TagDecl>(ExistingPattern),
+ Result);
+ }
+ if (auto *DFunction = dyn_cast<FunctionDecl>(DPattern))
+ return mergeRedeclarable(DFunction, cast<FunctionDecl>(ExistingPattern),
+ Result);
+ if (auto *DVar = dyn_cast<VarDecl>(DPattern))
+ return mergeRedeclarable(DVar, cast<VarDecl>(ExistingPattern), Result);
+ llvm_unreachable("merged an unknown kind of redeclarable template");
}
/// \brief Attempts to merge the given declaration (D) with another declaration
/// of the same entity.
template<typename T>
-void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D, T *Existing,
- RedeclarableResult &Redecl) {
+void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase, T *Existing,
+ RedeclarableResult &Redecl,
+ DeclID TemplatePatternID) {
+ T *D = static_cast<T*>(DBase);
T *ExistingCanon = Existing->getCanonicalDecl();
- T *DCanon = static_cast<T*>(D)->getCanonicalDecl();
+ T *DCanon = D->getCanonicalDecl();
if (ExistingCanon != DCanon) {
+ assert(DCanon->getGlobalID() == Redecl.getFirstID());
+
// Have our redeclaration link point back at the canonical declaration
- // of the existing declaration, so that this declaration has the
+ // of the existing declaration, so that this declaration has the
// appropriate canonical declaration.
D->RedeclLink = Redeclarable<T>::PreviousDeclLink(ExistingCanon);
// When we merge a namespace, update its pointer to the first namespace.
- if (NamespaceDecl *Namespace
- = dyn_cast<NamespaceDecl>(static_cast<T*>(D))) {
+ if (auto *Namespace = dyn_cast<NamespaceDecl>(D))
Namespace->AnonOrFirstNamespaceAndInline.setPointer(
- static_cast<NamespaceDecl *>(static_cast<void*>(ExistingCanon)));
- }
+ assert_cast<NamespaceDecl*>(ExistingCanon));
- // Don't introduce DCanon into the set of pending declaration chains.
- Redecl.suppress();
-
- // Introduce ExistingCanon into the set of pending declaration chains,
- // if in fact it came from a module file.
- if (ExistingCanon->isFromASTFile()) {
- GlobalDeclID ExistingCanonID = ExistingCanon->getGlobalID();
- assert(ExistingCanonID && "Unrecorded canonical declaration ID?");
- if (Reader.PendingDeclChainsKnown.insert(ExistingCanonID))
- Reader.PendingDeclChains.push_back(ExistingCanonID);
- }
+ // When we merge a template, merge its pattern.
+ if (auto *DTemplate = dyn_cast<RedeclarableTemplateDecl>(D))
+ mergeTemplatePattern(
+ DTemplate, assert_cast<RedeclarableTemplateDecl*>(ExistingCanon),
+ TemplatePatternID);
// If this declaration was the canonical declaration, make a note of
// that. We accept the linear algorithm here because the number of
// unique canonical declarations of an entity should always be tiny.
- if (DCanon == static_cast<T*>(D)) {
+ if (DCanon == D) {
SmallVectorImpl<DeclID> &Merged = Reader.MergedDecls[ExistingCanon];
if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID())
== Merged.end())
Merged.push_back(Redecl.getFirstID());
-
- // If ExistingCanon did not come from a module file, introduce the
- // first declaration that *does* come from a module file to the
- // set of pending declaration chains, so that we merge this
- // declaration.
- if (!ExistingCanon->isFromASTFile() &&
- Reader.PendingDeclChainsKnown.insert(Redecl.getFirstID()))
- Reader.PendingDeclChains.push_back(Merged[0]);
}
}
}
@@ -1942,7 +2159,7 @@ void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
void ASTReader::ReadAttributes(ModuleFile &F, AttrVec &Attrs,
const RecordData &Record, unsigned &Idx) {
for (unsigned i = 0, e = Record[Idx++]; i != e; ++i) {
- Attr *New = 0;
+ Attr *New = nullptr;
attr::Kind Kind = (attr::Kind)Record[Idx++];
SourceRange Range = ReadSourceRange(F, Record, Idx);
@@ -1981,7 +2198,8 @@ static bool isConsumerInterestedIn(Decl *D, bool HasBody) {
if (isa<FileScopeAsmDecl>(D) ||
isa<ObjCProtocolDecl>(D) ||
- isa<ObjCImplDecl>(D))
+ isa<ObjCImplDecl>(D) ||
+ isa<ImportDecl>(D))
return true;
if (VarDecl *Var = dyn_cast<VarDecl>(D))
return Var->isFileVarDecl() &&
@@ -2143,9 +2361,7 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
// Fields with the same name and the same type match.
if (FieldDecl *FDX = dyn_cast<FieldDecl>(X)) {
FieldDecl *FDY = cast<FieldDecl>(Y);
- // FIXME: Diagnose if the types don't match. More generally, diagnose if we
- // get a declaration in a class definition that isn't in the canonical class
- // definition.
+ // FIXME: Diagnose if the types don't match.
// FIXME: Also check the bitwidth is odr-equivalent, if any.
return X->getASTContext().hasSameType(FDX->getType(), FDY->getType());
}
@@ -2175,9 +2391,10 @@ static DeclContext *getPrimaryContextForMerging(DeclContext *DC) {
return RD->getDefinition();
if (EnumDecl *ED = dyn_cast<EnumDecl>(DC))
- return ED->getASTContext().getLangOpts().CPlusPlus? ED->getDefinition() : 0;
+ return ED->getASTContext().getLangOpts().CPlusPlus? ED->getDefinition()
+ : nullptr;
- return 0;
+ return nullptr;
}
ASTDeclReader::FindExistingResult::~FindExistingResult() {
@@ -2198,7 +2415,9 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
DeclarationName Name = D->getDeclName();
if (!Name) {
// Don't bother trying to find unnamed declarations.
- FindExistingResult Result(Reader, D, /*Existing=*/0);
+ FindExistingResult Result(Reader, D, /*Existing=*/nullptr);
+ // FIXME: We may still need to pull in the redeclaration chain; there can
+ // be redeclarations via 'decltype'.
Result.suppress();
return Result;
}
@@ -2252,33 +2471,34 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
// If this declaration is from a merged context, make a note that we need to
// check that the canonical definition of that context contains the decl.
+ //
+ // FIXME: We should do something similar if we merge two definitions of the
+ // same template specialization into the same CXXRecordDecl.
if (Reader.MergedDeclContexts.count(D->getLexicalDeclContext()))
Reader.PendingOdrMergeChecks.push_back(D);
- return FindExistingResult(Reader, D, /*Existing=*/0);
+ return FindExistingResult(Reader, D, /*Existing=*/nullptr);
}
-void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) {
- assert(D && previous);
- if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
- TD->RedeclLink.setNext(cast<TagDecl>(previous));
- } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- FD->RedeclLink.setNext(cast<FunctionDecl>(previous));
- } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
- VD->RedeclLink.setNext(cast<VarDecl>(previous));
- } else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
- TD->RedeclLink.setNext(cast<TypedefNameDecl>(previous));
- } else if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D)) {
- USD->RedeclLink.setNext(cast<UsingShadowDecl>(previous));
- } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
- ID->RedeclLink.setNext(cast<ObjCInterfaceDecl>(previous));
- } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
- PD->RedeclLink.setNext(cast<ObjCProtocolDecl>(previous));
- } else if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D)) {
- ND->RedeclLink.setNext(cast<NamespaceDecl>(previous));
- } else {
- RedeclarableTemplateDecl *TD = cast<RedeclarableTemplateDecl>(D);
- TD->RedeclLink.setNext(cast<RedeclarableTemplateDecl>(previous));
+template<typename DeclT>
+void ASTDeclReader::attachPreviousDeclImpl(Redeclarable<DeclT> *D,
+ Decl *Previous) {
+ D->RedeclLink.setPrevious(cast<DeclT>(Previous));
+}
+void ASTDeclReader::attachPreviousDeclImpl(...) {
+ llvm_unreachable("attachPreviousDecl on non-redeclarable declaration");
+}
+
+void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *Previous) {
+ assert(D && Previous);
+
+ switch (D->getKind()) {
+#define ABSTRACT_DECL(TYPE)
+#define DECL(TYPE, BASE) \
+ case Decl::TYPE: \
+ attachPreviousDeclImpl(cast<TYPE##Decl>(D), Previous); \
+ break;
+#include "clang/AST/DeclNodes.inc"
}
// If the declaration was visible in one module, a redeclaration of it in
@@ -2287,46 +2507,78 @@ void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) {
// FIXME: In this case, the declaration should only be visible if a module
// that makes it visible has been imported.
D->IdentifierNamespace |=
- previous->IdentifierNamespace &
+ Previous->IdentifierNamespace &
(Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type);
+
+ // If the previous declaration is marked as used, then this declaration should
+ // be too.
+ if (Previous->Used)
+ D->Used = true;
+
+ // If the previous declaration is an inline function declaration, then this
+ // declaration is too.
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (cast<FunctionDecl>(Previous)->IsInline != FD->IsInline) {
+ // FIXME: [dcl.fct.spec]p4:
+ // If a function with external linkage is declared inline in one
+ // translation unit, it shall be declared inline in all translation
+ // units in which it appears.
+ //
+ // Be careful of this case:
+ //
+ // module A:
+ // template<typename T> struct X { void f(); };
+ // template<typename T> inline void X<T>::f() {}
+ //
+ // module B instantiates the declaration of X<int>::f
+ // module C instantiates the definition of X<int>::f
+ //
+ // If module B and C are merged, we do not have a violation of this rule.
+ //
+ //if (!FD->IsInline || Previous->getOwningModule())
+ // Diag(FD->getLocation(), diag::err_odr_differing_inline);
+ FD->IsInline = true;
+ }
+ }
+}
+
+template<typename DeclT>
+void ASTDeclReader::attachLatestDeclImpl(Redeclarable<DeclT> *D, Decl *Latest) {
+ D->RedeclLink.setLatest(cast<DeclT>(Latest));
+}
+void ASTDeclReader::attachLatestDeclImpl(...) {
+ llvm_unreachable("attachLatestDecl on non-redeclarable declaration");
}
void ASTDeclReader::attachLatestDecl(Decl *D, Decl *Latest) {
assert(D && Latest);
- if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
- TD->RedeclLink
- = Redeclarable<TagDecl>::LatestDeclLink(cast<TagDecl>(Latest));
- } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- FD->RedeclLink
- = Redeclarable<FunctionDecl>::LatestDeclLink(cast<FunctionDecl>(Latest));
- } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
- VD->RedeclLink
- = Redeclarable<VarDecl>::LatestDeclLink(cast<VarDecl>(Latest));
- } else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) {
- TD->RedeclLink
- = Redeclarable<TypedefNameDecl>::LatestDeclLink(
- cast<TypedefNameDecl>(Latest));
- } else if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D)) {
- USD->RedeclLink
- = Redeclarable<UsingShadowDecl>::LatestDeclLink(
- cast<UsingShadowDecl>(Latest));
- } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
- ID->RedeclLink
- = Redeclarable<ObjCInterfaceDecl>::LatestDeclLink(
- cast<ObjCInterfaceDecl>(Latest));
- } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
- PD->RedeclLink
- = Redeclarable<ObjCProtocolDecl>::LatestDeclLink(
- cast<ObjCProtocolDecl>(Latest));
- } else if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D)) {
- ND->RedeclLink
- = Redeclarable<NamespaceDecl>::LatestDeclLink(
- cast<NamespaceDecl>(Latest));
- } else {
- RedeclarableTemplateDecl *TD = cast<RedeclarableTemplateDecl>(D);
- TD->RedeclLink
- = Redeclarable<RedeclarableTemplateDecl>::LatestDeclLink(
- cast<RedeclarableTemplateDecl>(Latest));
+
+ switch (D->getKind()) {
+#define ABSTRACT_DECL(TYPE)
+#define DECL(TYPE, BASE) \
+ case Decl::TYPE: \
+ attachLatestDeclImpl(cast<TYPE##Decl>(D), Latest); \
+ break;
+#include "clang/AST/DeclNodes.inc"
+ }
+}
+
+template<typename DeclT>
+void ASTDeclReader::markIncompleteDeclChainImpl(Redeclarable<DeclT> *D) {
+ D->RedeclLink.markIncomplete();
+}
+void ASTDeclReader::markIncompleteDeclChainImpl(...) {
+ llvm_unreachable("markIncompleteDeclChain on non-redeclarable declaration");
+}
+
+void ASTReader::markIncompleteDeclChain(Decl *D) {
+ switch (D->getKind()) {
+#define ABSTRACT_DECL(TYPE)
+#define DECL(TYPE, BASE) \
+ case Decl::TYPE: \
+ ASTDeclReader::markIncompleteDeclChainImpl(cast<TYPE##Decl>(D)); \
+ break;
+#include "clang/AST/DeclNodes.inc"
}
}
@@ -2374,7 +2626,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
unsigned Idx = 0;
ASTDeclReader Reader(*this, *Loc.F, ID, RawLocation, Record,Idx);
- Decl *D = 0;
+ Decl *D = nullptr;
switch ((DeclCode)DeclsCursor.readRecord(Code, Record)) {
case DECL_CONTEXT_LEXICAL:
case DECL_CONTEXT_VISIBLE:
@@ -2556,7 +2808,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
break;
case DECL_CXX_BASE_SPECIFIERS:
Error("attempt to read a C++ base-specifier record as a declaration");
- return 0;
+ return nullptr;
case DECL_IMPORT:
// Note: last entry of the ImportDecl record is the number of stored source
// locations.
@@ -2595,7 +2847,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
LookupDC->setHasExternalVisibleStorage(true);
if (ReadDeclContextStorage(*Loc.F, DeclsCursor, Offsets,
Loc.F->DeclContextInfos[DC]))
- return 0;
+ return nullptr;
}
// Now add the pending visible updates for this decl context, if it has any.
@@ -2605,12 +2857,10 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
// There are updates. This means the context has external visible
// storage, even if the original stored version didn't.
LookupDC->setHasExternalVisibleStorage(true);
- DeclContextVisibleUpdates &U = I->second;
- for (DeclContextVisibleUpdates::iterator UI = U.begin(), UE = U.end();
- UI != UE; ++UI) {
- DeclContextInfo &Info = UI->second->DeclContextInfos[DC];
+ for (const auto &Update : I->second) {
+ DeclContextInfo &Info = Update.second->DeclContextInfos[DC];
delete Info.NameLookupTableData;
- Info.NameLookupTableData = UI->first;
+ Info.NameLookupTableData = Update.first;
}
PendingVisibleUpdates.erase(I);
}
@@ -2618,7 +2868,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
assert(Idx == Record.size());
// Load any relevant update records.
- loadDeclUpdateRecords(ID, D);
+ PendingUpdateRecords.push_back(std::make_pair(ID, D));
// Load the categories after recursive loading is finished.
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(D))
@@ -2642,6 +2892,7 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID);
if (UpdI != DeclUpdateOffsets.end()) {
FileOffsetsTy &UpdateOffsets = UpdI->second;
+ bool WasInteresting = isConsumerInterestedIn(D, false);
for (FileOffsetsTy::iterator
I = UpdateOffsets.begin(), E = UpdateOffsets.end(); I != E; ++I) {
ModuleFile *F = I->first;
@@ -2654,33 +2905,23 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
unsigned RecCode = Cursor.readRecord(Code, Record);
(void)RecCode;
assert(RecCode == DECL_UPDATES && "Expected DECL_UPDATES record!");
-
+
unsigned Idx = 0;
ASTDeclReader Reader(*this, *F, ID, 0, Record, Idx);
Reader.UpdateDecl(D, *F, Record);
+
+ // We might have made this declaration interesting. If so, remember that
+ // we need to hand it off to the consumer.
+ if (!WasInteresting &&
+ isConsumerInterestedIn(D, Reader.hasPendingBody())) {
+ InterestingDecls.push_back(D);
+ WasInteresting = true;
+ }
}
}
}
namespace {
- struct CompareLocalRedeclarationsInfoToID {
- bool operator()(const LocalRedeclarationsInfo &X, DeclID Y) {
- return X.FirstID < Y;
- }
-
- bool operator()(DeclID X, const LocalRedeclarationsInfo &Y) {
- return X < Y.FirstID;
- }
-
- bool operator()(const LocalRedeclarationsInfo &X,
- const LocalRedeclarationsInfo &Y) {
- return X.FirstID < Y.FirstID;
- }
- bool operator()(DeclID X, DeclID Y) {
- return X < Y;
- }
- };
-
/// \brief Module visitor class that finds all of the redeclarations of a
///
class RedeclChainVisitor {
@@ -2724,10 +2965,11 @@ namespace {
// Perform a binary search to find the local redeclarations for this
// declaration (if any).
+ const LocalRedeclarationsInfo Compare = { ID, 0 };
const LocalRedeclarationsInfo *Result
= std::lower_bound(M.RedeclarationsMap,
M.RedeclarationsMap + M.LocalNumRedeclarationsInMap,
- ID, CompareLocalRedeclarationsInfoToID());
+ Compare);
if (Result == M.RedeclarationsMap + M.LocalNumRedeclarationsInMap ||
Result->FirstID != ID) {
// If we have a previously-canonical singleton declaration that was
@@ -2755,6 +2997,8 @@ namespace {
// Visit each of the declarations.
for (unsigned I = 0, N = SearchDecls.size(); I != N; ++I)
searchForID(M, SearchDecls[I]);
+ // FIXME: If none of the SearchDecls had local IDs in this module, can
+ // we avoid searching any ancestor module files?
return false;
}
@@ -2802,24 +3046,6 @@ void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) {
}
namespace {
- struct CompareObjCCategoriesInfo {
- bool operator()(const ObjCCategoriesInfo &X, DeclID Y) {
- return X.DefinitionID < Y;
- }
-
- bool operator()(DeclID X, const ObjCCategoriesInfo &Y) {
- return X < Y.DefinitionID;
- }
-
- bool operator()(const ObjCCategoriesInfo &X,
- const ObjCCategoriesInfo &Y) {
- return X.DefinitionID < Y.DefinitionID;
- }
- bool operator()(DeclID X, DeclID Y) {
- return X < Y;
- }
- };
-
/// \brief Given an ObjC interface, goes through the modules and links to the
/// interface all the categories for it.
class ObjCCategoriesVisitor {
@@ -2878,18 +3104,15 @@ namespace {
unsigned PreviousGeneration)
: Reader(Reader), InterfaceID(InterfaceID), Interface(Interface),
Deserialized(Deserialized), PreviousGeneration(PreviousGeneration),
- Tail(0)
+ Tail(nullptr)
{
// Populate the name -> category map with the set of known categories.
- for (ObjCInterfaceDecl::known_categories_iterator
- Cat = Interface->known_categories_begin(),
- CatEnd = Interface->known_categories_end();
- Cat != CatEnd; ++Cat) {
+ for (auto *Cat : Interface->known_categories()) {
if (Cat->getDeclName())
- NameCategoryMap[Cat->getDeclName()] = *Cat;
+ NameCategoryMap[Cat->getDeclName()] = Cat;
// Keep track of the tail of the category list.
- Tail = *Cat;
+ Tail = Cat;
}
}
@@ -2912,10 +3135,11 @@ namespace {
// Perform a binary search to find the local redeclarations for this
// declaration (if any).
+ const ObjCCategoriesInfo Compare = { LocalID, 0 };
const ObjCCategoriesInfo *Result
= std::lower_bound(M.ObjCCategoriesMap,
M.ObjCCategoriesMap + M.LocalNumObjCCategoriesInMap,
- LocalID, CompareObjCCategoriesInfo());
+ Compare);
if (Result == M.ObjCCategoriesMap + M.LocalNumObjCCategoriesInMap ||
Result->DefinitionID != LocalID) {
// We didn't find anything. If the class definition is in this module
@@ -2946,12 +3170,14 @@ void ASTReader::loadObjCCategories(serialization::GlobalDeclID ID,
void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
const RecordData &Record) {
- unsigned Idx = 0;
while (Idx < Record.size()) {
switch ((DeclUpdateKind)Record[Idx++]) {
- case UPD_CXX_ADDED_IMPLICIT_MEMBER:
- cast<CXXRecordDecl>(D)->addedMember(Reader.ReadDecl(ModuleFile, Record, Idx));
+ case UPD_CXX_ADDED_IMPLICIT_MEMBER: {
+ Decl *MD = Reader.ReadDecl(ModuleFile, Record, Idx);
+ assert(MD && "couldn't read decl from update record");
+ cast<CXXRecordDecl>(D)->addedMember(MD);
break;
+ }
case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
// It will be added to the template's specializations set when loaded.
@@ -2979,6 +3205,96 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
Reader.ReadSourceLocation(ModuleFile, Record, Idx));
break;
+ case UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION: {
+ FunctionDecl *FD = cast<FunctionDecl>(D);
+ if (Reader.PendingBodies[FD]) {
+ // FIXME: Maybe check for ODR violations.
+ // It's safe to stop now because this update record is always last.
+ return;
+ }
+
+ if (Record[Idx++]) {
+ // Maintain AST consistency: any later redeclarations of this function
+ // are inline if this one is. (We might have merged another declaration
+ // into this one.)
+ for (auto *D = FD->getMostRecentDecl(); /**/;
+ D = D->getPreviousDecl()) {
+ D->setImplicitlyInline();
+ if (D == FD)
+ break;
+ }
+ }
+ FD->setInnerLocStart(Reader.ReadSourceLocation(ModuleFile, Record, Idx));
+ if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
+ std::tie(CD->CtorInitializers, CD->NumCtorInitializers) =
+ Reader.ReadCXXCtorInitializers(ModuleFile, Record, Idx);
+ // Store the offset of the body so we can lazily load it later.
+ Reader.PendingBodies[FD] = GetCurrentCursorOffset();
+ HasPendingBody = true;
+ assert(Idx == Record.size() && "lazy body must be last");
+ break;
+ }
+
+ case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: {
+ auto *RD = cast<CXXRecordDecl>(D);
+ bool HadDefinition = RD->getDefinition();
+ ReadCXXRecordDefinition(RD);
+ // Visible update is handled separately.
+ uint64_t LexicalOffset = Record[Idx++];
+ if (!HadDefinition && LexicalOffset) {
+ RD->setHasExternalLexicalStorage(true);
+ Reader.ReadDeclContextStorage(ModuleFile, ModuleFile.DeclsCursor,
+ std::make_pair(LexicalOffset, 0),
+ ModuleFile.DeclContextInfos[RD]);
+ }
+
+ auto TSK = (TemplateSpecializationKind)Record[Idx++];
+ SourceLocation POI = Reader.ReadSourceLocation(ModuleFile, Record, Idx);
+ if (MemberSpecializationInfo *MSInfo =
+ RD->getMemberSpecializationInfo()) {
+ MSInfo->setTemplateSpecializationKind(TSK);
+ MSInfo->setPointOfInstantiation(POI);
+ } else {
+ ClassTemplateSpecializationDecl *Spec =
+ cast<ClassTemplateSpecializationDecl>(RD);
+ Spec->setTemplateSpecializationKind(TSK);
+ Spec->setPointOfInstantiation(POI);
+
+ if (Record[Idx++]) {
+ auto PartialSpec =
+ ReadDeclAs<ClassTemplatePartialSpecializationDecl>(Record, Idx);
+ SmallVector<TemplateArgument, 8> TemplArgs;
+ Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
+ auto *TemplArgList = TemplateArgumentList::CreateCopy(
+ Reader.getContext(), TemplArgs.data(), TemplArgs.size());
+ Spec->setInstantiationOf(PartialSpec, TemplArgList);
+ }
+ }
+
+ RD->setTagKind((TagTypeKind)Record[Idx++]);
+ RD->setLocation(Reader.ReadSourceLocation(ModuleFile, Record, Idx));
+ RD->setLocStart(Reader.ReadSourceLocation(ModuleFile, Record, Idx));
+ RD->setRBraceLoc(Reader.ReadSourceLocation(ModuleFile, Record, Idx));
+
+ if (Record[Idx++]) {
+ AttrVec Attrs;
+ Reader.ReadAttributes(F, Attrs, Record, Idx);
+ D->setAttrsImpl(Attrs, Reader.getContext());
+ }
+ break;
+ }
+
+ case UPD_CXX_RESOLVED_EXCEPTION_SPEC: {
+ auto *FD = cast<FunctionDecl>(D);
+ auto *FPT = FD->getType()->castAs<FunctionProtoType>();
+ auto EPI = FPT->getExtProtoInfo();
+ SmallVector<QualType, 8> ExceptionStorage;
+ Reader.readExceptionSpec(ModuleFile, ExceptionStorage, EPI, Record, Idx);
+ FD->setType(Reader.Context.getFunctionType(FPT->getReturnType(),
+ FPT->getParamTypes(), EPI));
+ break;
+ }
+
case UPD_CXX_DEDUCED_RETURN_TYPE: {
FunctionDecl *FD = cast<FunctionDecl>(D);
Reader.Context.adjustDeducedFunctionResultType(
@@ -2989,9 +3305,28 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
case UPD_DECL_MARKED_USED: {
// FIXME: This doesn't send the right notifications if there are
// ASTMutationListeners other than an ASTWriter.
- D->Used = true;
+
+ // FIXME: We can't both pull in declarations (and thus create new pending
+ // redeclaration chains) *and* walk redeclaration chains in this function.
+ // We should defer the updates that require walking redecl chains.
+
+ // Maintain AST consistency: any later redeclarations are used too.
+ for (auto *Redecl = D->getMostRecentDecl(); /**/;
+ Redecl = Redecl->getPreviousDecl()) {
+ Redecl->Used = true;
+ if (Redecl == D)
+ break;
+ }
break;
}
+
+ case UPD_MANGLING_NUMBER:
+ Reader.Context.setManglingNumber(cast<NamedDecl>(D), Record[Idx++]);
+ break;
+
+ case UPD_STATIC_LOCAL_NUMBER:
+ Reader.Context.setStaticLocalNumber(cast<VarDecl>(D), Record[Idx++]);
+ break;
}
}
}
diff --git a/lib/Serialization/ASTReaderInternals.h b/lib/Serialization/ASTReaderInternals.h
index 9149b18480f9..a63e362eb64f 100644
--- a/lib/Serialization/ASTReaderInternals.h
+++ b/lib/Serialization/ASTReaderInternals.h
@@ -14,10 +14,9 @@
#define LLVM_CLANG_SERIALIZATION_ASTREADER_INTERNALS_H
#include "clang/AST/DeclarationName.h"
-#include "clang/Basic/OnDiskHashTable.h"
#include "clang/Serialization/ASTBitCodes.h"
#include "llvm/Support/Endian.h"
-#include <sys/stat.h>
+#include "llvm/Support/OnDiskHashTable.h"
#include <utility>
namespace clang {
@@ -46,6 +45,8 @@ public:
/// particular lookup t
typedef llvm::support::ulittle32_t LE32DeclID;
typedef std::pair<LE32DeclID *, LE32DeclID *> data_type;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
/// \brief Special internal key for declaration names.
/// The hash table creates keys for comparison; we do not create
@@ -67,7 +68,7 @@ public:
return a.Kind == b.Kind && a.Data == b.Data;
}
- unsigned ComputeHash(const DeclNameKey &Key) const;
+ hash_value_type ComputeHash(const DeclNameKey &Key) const;
internal_key_type GetInternalKey(const external_key_type& Name) const;
static std::pair<unsigned, unsigned>
@@ -92,13 +93,14 @@ class ASTIdentifierLookupTraitBase {
public:
typedef StringRef external_key_type;
typedef StringRef internal_key_type;
-
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
static bool EqualKey(const internal_key_type& a, const internal_key_type& b) {
return a == b;
}
- static unsigned ComputeHash(const internal_key_type& a);
+ static hash_value_type ComputeHash(const internal_key_type& a);
static std::pair<unsigned, unsigned>
ReadKeyDataLength(const unsigned char*& d);
@@ -126,11 +128,11 @@ class ASTIdentifierLookupTrait : public ASTIdentifierLookupTraitBase {
public:
typedef IdentifierInfo * data_type;
-
+
ASTIdentifierLookupTrait(ASTReader &Reader, ModuleFile &F,
- IdentifierInfo *II = 0)
+ IdentifierInfo *II = nullptr)
: Reader(Reader), F(F), KnownII(II) { }
-
+
data_type ReadData(const internal_key_type& k,
const unsigned char* d,
unsigned DataLen);
@@ -140,7 +142,7 @@ public:
/// \brief The on-disk hash table used to contain information about
/// all of the identifiers in the program.
-typedef OnDiskChainedHashTable<ASTIdentifierLookupTrait>
+typedef llvm::OnDiskIterableChainedHashTable<ASTIdentifierLookupTrait>
ASTIdentifierLookupTable;
/// \brief Class that performs lookup for a selector's entries in the global
@@ -160,6 +162,8 @@ public:
typedef Selector external_key_type;
typedef external_key_type internal_key_type;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
ASTSelectorLookupTrait(ASTReader &Reader, ModuleFile &F)
: Reader(Reader), F(F) { }
@@ -169,7 +173,7 @@ public:
return a == b;
}
- static unsigned ComputeHash(Selector Sel);
+ static hash_value_type ComputeHash(Selector Sel);
static const internal_key_type&
GetInternalKey(const external_key_type& x) { return x; }
@@ -182,7 +186,7 @@ public:
};
/// \brief The on-disk hash table used for the global method pool.
-typedef OnDiskChainedHashTable<ASTSelectorLookupTrait>
+typedef llvm::OnDiskChainedHashTable<ASTSelectorLookupTrait>
ASTSelectorLookupTable;
/// \brief Trait class used to search the on-disk hash table containing all of
@@ -211,12 +215,14 @@ public:
typedef const internal_key_type &internal_key_ref;
typedef HeaderFileInfo data_type;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
HeaderFileInfoTrait(ASTReader &Reader, ModuleFile &M, HeaderSearch *HS,
const char *FrameworkStrings)
: Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings) { }
- static unsigned ComputeHash(internal_key_ref ikey);
+ static hash_value_type ComputeHash(internal_key_ref ikey);
static internal_key_type GetInternalKey(const FileEntry *FE);
bool EqualKey(internal_key_ref a, internal_key_ref b);
@@ -229,7 +235,7 @@ public:
};
/// \brief The on-disk hash table used for known header files.
-typedef OnDiskChainedHashTable<HeaderFileInfoTrait>
+typedef llvm::OnDiskChainedHashTable<HeaderFileInfoTrait>
HeaderFileInfoLookupTable;
} // end namespace clang::serialization::reader
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 1115e8fd4f45..8bf17d51b3e8 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -176,7 +176,7 @@ void ASTStmtReader::VisitAttributedStmt(AttributedStmt *S) {
(void)NumAttrs;
assert(NumAttrs == S->NumAttrs);
assert(NumAttrs == Attrs.size());
- std::copy(Attrs.begin(), Attrs.end(), S->Attrs);
+ std::copy(Attrs.begin(), Attrs.end(), S->getAttrArrayPtr());
S->SubStmt = Reader.ReadSubStmt();
S->AttrLoc = ReadSourceLocation(Record, Idx);
}
@@ -202,7 +202,7 @@ void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) {
if (Record[Idx++])
S->setAllEnumCasesCovered();
- SwitchCase *PrevSC = 0;
+ SwitchCase *PrevSC = nullptr;
for (unsigned N = Record.size(); Idx != N; ++Idx) {
SwitchCase *SC = Reader.getSwitchCaseWithID(Record[Idx]);
if (PrevSC)
@@ -399,13 +399,11 @@ void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
S->getCapturedDecl()->setBody(S->getCapturedStmt());
// Captures
- for (CapturedStmt::capture_iterator I = S->capture_begin(),
- E = S->capture_end();
- I != E; ++I) {
- I->VarAndKind.setPointer(ReadDeclAs<VarDecl>(Record, Idx));
- I->VarAndKind
+ for (auto &I : S->captures()) {
+ I.VarAndKind.setPointer(ReadDeclAs<VarDecl>(Record, Idx));
+ I.VarAndKind
.setInt(static_cast<CapturedStmt::VariableCaptureKind>(Record[Idx++]));
- I->Loc = ReadSourceLocation(Record, Idx);
+ I.Loc = ReadSourceLocation(Record, Idx);
}
}
@@ -718,7 +716,7 @@ void ASTStmtReader::VisitInitListExpr(InitListExpr *E) {
E->setLBraceLoc(ReadSourceLocation(Record, Idx));
E->setRBraceLoc(ReadSourceLocation(Record, Idx));
bool isArrayFiller = Record[Idx++];
- Expr *filler = 0;
+ Expr *filler = nullptr;
if (isArrayFiller) {
filler = Reader.ReadSubExpr();
E->ArrayFillerOrUnionFieldInit = filler;
@@ -1198,6 +1196,7 @@ void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
E->setElidable(Record[Idx++]);
E->setHadMultipleCandidates(Record[Idx++]);
E->setListInitialization(Record[Idx++]);
+ E->setStdInitListInitialization(Record[Idx++]);
E->setRequiresZeroInitialization(Record[Idx++]);
E->setConstructionKind((CXXConstructExpr::ConstructionKind)Record[Idx++]);
E->ParenOrBraceRange = ReadSourceRange(Record, Idx);
@@ -1484,33 +1483,15 @@ void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
E->NamingClass = ReadDeclAs<CXXRecordDecl>(Record, Idx);
}
-void ASTStmtReader::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
- VisitExpr(E);
- E->UTT = (UnaryTypeTrait)Record[Idx++];
- E->Value = (bool)Record[Idx++];
- SourceRange Range = ReadSourceRange(Record, Idx);
- E->Loc = Range.getBegin();
- E->RParen = Range.getEnd();
- E->QueriedType = GetTypeSourceInfo(Record, Idx);
-}
-
-void ASTStmtReader::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
- VisitExpr(E);
- E->BTT = (BinaryTypeTrait)Record[Idx++];
- E->Value = (bool)Record[Idx++];
- SourceRange Range = ReadSourceRange(Record, Idx);
- E->Loc = Range.getBegin();
- E->RParen = Range.getEnd();
- E->LhsType = GetTypeSourceInfo(Record, Idx);
- E->RhsType = GetTypeSourceInfo(Record, Idx);
-}
-
void ASTStmtReader::VisitTypeTraitExpr(TypeTraitExpr *E) {
VisitExpr(E);
E->TypeTraitExprBits.NumArgs = Record[Idx++];
E->TypeTraitExprBits.Kind = Record[Idx++];
E->TypeTraitExprBits.Value = Record[Idx++];
-
+ SourceRange Range = ReadSourceRange(Record, Idx);
+ E->Loc = Range.getBegin();
+ E->RParenLoc = Range.getEnd();
+
TypeSourceInfo **Args = E->getTypeSourceInfos();
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
Args[I] = GetTypeSourceInfo(Record, Idx);
@@ -1592,8 +1573,10 @@ void ASTStmtReader::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
VisitExpr(E);
- E->Temporary = Reader.ReadSubExpr();
- E->ExtendingDecl = ReadDeclAs<ValueDecl>(Record, Idx);
+ E->State = Reader.ReadSubExpr();
+ auto VD = ReadDeclAs<ValueDecl>(Record, Idx);
+ unsigned ManglingNumber = Record[Idx++];
+ E->setExtendingDecl(VD, ManglingNumber);
}
void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
@@ -1627,6 +1610,11 @@ void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) {
E->setExprOperand(Reader.ReadSubExpr());
}
+void ASTStmtReader::VisitSEHLeaveStmt(SEHLeaveStmt *S) {
+ VisitStmt(S);
+ S->setLeaveLoc(ReadSourceLocation(Record, Idx));
+}
+
void ASTStmtReader::VisitSEHExceptStmt(SEHExceptStmt *S) {
VisitStmt(S);
S->Loc = ReadSourceLocation(Record, Idx);
@@ -1691,18 +1679,72 @@ public:
OMPClause *OMPClauseReader::readClause() {
OMPClause *C;
switch (Record[Idx++]) {
+ case OMPC_if:
+ C = new (Context) OMPIfClause();
+ break;
+ case OMPC_final:
+ C = new (Context) OMPFinalClause();
+ break;
+ case OMPC_num_threads:
+ C = new (Context) OMPNumThreadsClause();
+ break;
+ case OMPC_safelen:
+ C = new (Context) OMPSafelenClause();
+ break;
+ case OMPC_collapse:
+ C = new (Context) OMPCollapseClause();
+ break;
case OMPC_default:
C = new (Context) OMPDefaultClause();
break;
+ case OMPC_proc_bind:
+ C = new (Context) OMPProcBindClause();
+ break;
+ case OMPC_schedule:
+ C = new (Context) OMPScheduleClause();
+ break;
+ case OMPC_ordered:
+ C = new (Context) OMPOrderedClause();
+ break;
+ case OMPC_nowait:
+ C = new (Context) OMPNowaitClause();
+ break;
+ case OMPC_untied:
+ C = new (Context) OMPUntiedClause();
+ break;
+ case OMPC_mergeable:
+ C = new (Context) OMPMergeableClause();
+ break;
case OMPC_private:
C = OMPPrivateClause::CreateEmpty(Context, Record[Idx++]);
break;
case OMPC_firstprivate:
C = OMPFirstprivateClause::CreateEmpty(Context, Record[Idx++]);
break;
+ case OMPC_lastprivate:
+ C = OMPLastprivateClause::CreateEmpty(Context, Record[Idx++]);
+ break;
case OMPC_shared:
C = OMPSharedClause::CreateEmpty(Context, Record[Idx++]);
break;
+ case OMPC_reduction:
+ C = OMPReductionClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ case OMPC_linear:
+ C = OMPLinearClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ case OMPC_aligned:
+ C = OMPAlignedClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ case OMPC_copyin:
+ C = OMPCopyinClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ case OMPC_copyprivate:
+ C = OMPCopyprivateClause::CreateEmpty(Context, Record[Idx++]);
+ break;
+ case OMPC_flush:
+ C = OMPFlushClause::CreateEmpty(Context, Record[Idx++]);
+ break;
}
Visit(C);
C->setLocStart(Reader->ReadSourceLocation(Record, Idx));
@@ -1711,6 +1753,31 @@ OMPClause *OMPClauseReader::readClause() {
return C;
}
+void OMPClauseReader::VisitOMPIfClause(OMPIfClause *C) {
+ C->setCondition(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPFinalClause(OMPFinalClause *C) {
+ C->setCondition(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) {
+ C->setNumThreads(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPSafelenClause(OMPSafelenClause *C) {
+ C->setSafelen(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPCollapseClause(OMPCollapseClause *C) {
+ C->setNumForLoops(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
void OMPClauseReader::VisitOMPDefaultClause(OMPDefaultClause *C) {
C->setDefaultKind(
static_cast<OpenMPDefaultClauseKind>(Record[Idx++]));
@@ -1718,6 +1785,30 @@ void OMPClauseReader::VisitOMPDefaultClause(OMPDefaultClause *C) {
C->setDefaultKindKwLoc(Reader->ReadSourceLocation(Record, Idx));
}
+void OMPClauseReader::VisitOMPProcBindClause(OMPProcBindClause *C) {
+ C->setProcBindKind(
+ static_cast<OpenMPProcBindClauseKind>(Record[Idx++]));
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setProcBindKindKwLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPScheduleClause(OMPScheduleClause *C) {
+ C->setScheduleKind(
+ static_cast<OpenMPScheduleClauseKind>(Record[Idx++]));
+ C->setChunkSize(Reader->Reader.ReadSubExpr());
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setScheduleKindLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setCommaLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
+void OMPClauseReader::VisitOMPOrderedClause(OMPOrderedClause *) {}
+
+void OMPClauseReader::VisitOMPNowaitClause(OMPNowaitClause *) {}
+
+void OMPClauseReader::VisitOMPUntiedClause(OMPUntiedClause *) {}
+
+void OMPClauseReader::VisitOMPMergeableClause(OMPMergeableClause *) {}
+
void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) {
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
unsigned NumVars = C->varlist_size();
@@ -1738,6 +1829,16 @@ void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
C->setVarRefs(Vars);
}
+void OMPClauseReader::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+}
+
void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) {
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
unsigned NumVars = C->varlist_size();
@@ -1748,12 +1849,82 @@ void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) {
C->setVarRefs(Vars);
}
+void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setColonLoc(Reader->ReadSourceLocation(Record, Idx));
+ NestedNameSpecifierLoc NNSL =
+ Reader->Reader.ReadNestedNameSpecifierLoc(Reader->F, Record, Idx);
+ DeclarationNameInfo DNI;
+ Reader->ReadDeclarationNameInfo(DNI, Record, Idx);
+ C->setQualifierLoc(NNSL);
+ C->setNameInfo(DNI);
+
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+}
+
+void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setColonLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+ C->setStep(Reader->Reader.ReadSubExpr());
+}
+
+void OMPClauseReader::VisitOMPAlignedClause(OMPAlignedClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setColonLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+ C->setAlignment(Reader->Reader.ReadSubExpr());
+}
+
+void OMPClauseReader::VisitOMPCopyinClause(OMPCopyinClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+}
+
+void OMPClauseReader::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+}
+
+void OMPClauseReader::VisitOMPFlushClause(OMPFlushClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+}
+
//===----------------------------------------------------------------------===//
// OpenMP Directives.
//===----------------------------------------------------------------------===//
void ASTStmtReader::VisitOMPExecutableDirective(OMPExecutableDirective *E) {
- VisitStmt(E);
- ++Idx;
E->setLocStart(ReadSourceLocation(Record, Idx));
E->setLocEnd(ReadSourceLocation(Record, Idx));
OMPClauseReader ClauseReader(this, Reader.getContext(), Record, Idx);
@@ -1761,10 +1932,102 @@ void ASTStmtReader::VisitOMPExecutableDirective(OMPExecutableDirective *E) {
for (unsigned i = 0; i < E->getNumClauses(); ++i)
Clauses.push_back(ClauseReader.readClause());
E->setClauses(Clauses);
- E->setAssociatedStmt(Reader.ReadSubStmt());
+ if (E->hasAssociatedStmt())
+ E->setAssociatedStmt(Reader.ReadSubStmt());
}
void ASTStmtReader::VisitOMPParallelDirective(OMPParallelDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPSimdDirective(OMPSimdDirective *D) {
+ VisitStmt(D);
+ // Two fields (NumClauses and CollapsedNum) were read in ReadStmtFromStream.
+ Idx += 2;
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPForDirective(OMPForDirective *D) {
+ VisitStmt(D);
+ // Two fields (NumClauses and CollapsedNum) were read in ReadStmtFromStream.
+ Idx += 2;
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPSectionsDirective(OMPSectionsDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPSectionDirective(OMPSectionDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPSingleDirective(OMPSingleDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPMasterDirective(OMPMasterDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPCriticalDirective(OMPCriticalDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ ReadDeclarationNameInfo(D->DirName, Record, Idx);
+}
+
+void ASTStmtReader::VisitOMPParallelForDirective(OMPParallelForDirective *D) {
+ VisitStmt(D);
+ // Two fields (NumClauses and CollapsedNum) were read in ReadStmtFromStream.
+ Idx += 2;
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPParallelSectionsDirective(
+ OMPParallelSectionsDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPTaskDirective(OMPTaskDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPTaskyieldDirective(OMPTaskyieldDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPBarrierDirective(OMPBarrierDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+}
+
+void ASTStmtReader::VisitOMPFlushDirective(OMPFlushDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ ++Idx;
VisitOMPExecutableDirective(D);
}
@@ -1826,7 +2089,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
case llvm::BitstreamEntry::SubBlock: // Handled for us already.
case llvm::BitstreamEntry::Error:
Error("malformed block record in AST file");
- return 0;
+ return nullptr;
case llvm::BitstreamEntry::EndBlock:
goto Done;
case llvm::BitstreamEntry::Record:
@@ -1834,8 +2097,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
}
-
- Stmt *S = 0;
+ Stmt *S = nullptr;
Idx = 0;
Record.clear();
bool Finished = false;
@@ -1853,7 +2115,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
case STMT_NULL_PTR:
- S = 0;
+ S = nullptr;
break;
case STMT_NULL:
@@ -2044,7 +2306,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = MemberExpr::Create(Context, Base, IsArrow, QualifierLoc,
TemplateKWLoc, MemberD, FoundDecl, MemberNameInfo,
- HasTemplateKWAndArgsInfo ? &ArgInfo : 0,
+ HasTemplateKWAndArgsInfo ? &ArgInfo : nullptr,
T, VK, OK);
ReadDeclarationNameLoc(F, cast<MemberExpr>(S)->MemberDNLoc,
MemberD->getDeclName(), Record, Idx);
@@ -2212,6 +2474,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
case EXPR_OBJC_BOOL_LITERAL:
S = new (Context) ObjCBoolLiteralExpr(Empty);
break;
+ case STMT_SEH_LEAVE:
+ S = new (Context) SEHLeaveStmt(Empty);
+ break;
case STMT_SEH_EXCEPT:
S = new (Context) SEHExceptStmt(Empty);
break;
@@ -2238,15 +2503,89 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) MSDependentExistsStmt(SourceLocation(), true,
NestedNameSpecifierLoc(),
DeclarationNameInfo(),
- 0);
+ nullptr);
break;
+
case STMT_OMP_PARALLEL_DIRECTIVE:
S =
OMPParallelDirective::CreateEmpty(Context,
Record[ASTStmtReader::NumStmtFields],
Empty);
break;
-
+
+ case STMT_OMP_SIMD_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
+ S = OMPSimdDirective::CreateEmpty(Context, NumClauses,
+ CollapsedNum, Empty);
+ break;
+ }
+
+ case STMT_OMP_FOR_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
+ S = OMPForDirective::CreateEmpty(Context, NumClauses, CollapsedNum,
+ Empty);
+ break;
+ }
+
+ case STMT_OMP_SECTIONS_DIRECTIVE:
+ S = OMPSectionsDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
+ case STMT_OMP_SECTION_DIRECTIVE:
+ S = OMPSectionDirective::CreateEmpty(Context, Empty);
+ break;
+
+ case STMT_OMP_SINGLE_DIRECTIVE:
+ S = OMPSingleDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
+ case STMT_OMP_MASTER_DIRECTIVE:
+ S = OMPMasterDirective::CreateEmpty(Context, Empty);
+ break;
+
+ case STMT_OMP_CRITICAL_DIRECTIVE:
+ S = OMPCriticalDirective::CreateEmpty(Context, Empty);
+ break;
+
+ case STMT_OMP_PARALLEL_FOR_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
+ S = OMPParallelForDirective::CreateEmpty(Context, NumClauses,
+ CollapsedNum, Empty);
+ break;
+ }
+
+ case STMT_OMP_PARALLEL_SECTIONS_DIRECTIVE:
+ S = OMPParallelSectionsDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
+ case STMT_OMP_TASK_DIRECTIVE:
+ S = OMPTaskDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
+ case STMT_OMP_TASKYIELD_DIRECTIVE:
+ S = OMPTaskyieldDirective::CreateEmpty(Context, Empty);
+ break;
+
+ case STMT_OMP_BARRIER_DIRECTIVE:
+ S = OMPBarrierDirective::CreateEmpty(Context, Empty);
+ break;
+
+ case STMT_OMP_TASKWAIT_DIRECTIVE:
+ S = OMPTaskwaitDirective::CreateEmpty(Context, Empty);
+ break;
+
+ case STMT_OMP_FLUSH_DIRECTIVE:
+ S = OMPFlushDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
case EXPR_CXX_OPERATOR_CALL:
S = new (Context) CXXOperatorCallExpr(Context, Empty);
break;
@@ -2254,11 +2593,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
case EXPR_CXX_MEMBER_CALL:
S = new (Context) CXXMemberCallExpr(Context, Empty);
break;
-
+
case EXPR_CXX_CONSTRUCT:
S = new (Context) CXXConstructExpr(Empty);
break;
-
+
case EXPR_CXX_TEMPORARY_OBJECT:
S = new (Context) CXXTemporaryObjectExpr(Empty);
break;
@@ -2327,7 +2666,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
bool HasOtherExprStored = Record[ASTStmtReader::NumExprFields];
if (HasOtherExprStored) {
Expr *SubExpr = ReadSubExpr();
- S = CXXDefaultArgExpr::Create(Context, SourceLocation(), 0, SubExpr);
+ S = CXXDefaultArgExpr::Create(Context, SourceLocation(), nullptr,
+ SubExpr);
} else
S = new (Context) CXXDefaultArgExpr(Empty);
break;
@@ -2393,14 +2733,6 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
? Record[ASTStmtReader::NumExprFields + 1]
: 0);
break;
-
- case EXPR_CXX_UNARY_TYPE_TRAIT:
- S = new (Context) UnaryTypeTraitExpr(Empty);
- break;
-
- case EXPR_BINARY_TYPE_TRAIT:
- S = new (Context) BinaryTypeTraitExpr(Empty);
- break;
case EXPR_TYPE_TRAIT:
S = TypeTraitExpr::CreateDeserialized(Context,
@@ -2491,7 +2823,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
StmtStack.push_back(S);
}
Done:
- assert(StmtStack.size() > PrevNumStmts && "Read too many sub stmts!");
+ assert(StmtStack.size() > PrevNumStmts && "Read too many sub-stmts!");
assert(StmtStack.size() == PrevNumStmts + 1 && "Extra expressions on stack!");
return StmtStack.pop_back_val();
}
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 405488c35716..0f52a9fd0408 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -17,14 +17,15 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclFriend.h"
+#include "clang/AST/DeclLookups.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
-#include "clang/Basic/OnDiskHashTable.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManagerInternals.h"
#include "clang/Basic/TargetInfo.h"
@@ -45,8 +46,10 @@
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/Support/EndianStream.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/OnDiskHashTable.h"
#include "llvm/Support/Path.h"
#include <algorithm>
#include <cstdio>
@@ -113,6 +116,12 @@ void ASTTypeWriter::VisitDecayedType(const DecayedType *T) {
Code = TYPE_DECAYED;
}
+void ASTTypeWriter::VisitAdjustedType(const AdjustedType *T) {
+ Writer.AddTypeRef(T->getOriginalType(), Record);
+ Writer.AddTypeRef(T->getAdjustedType(), Record);
+ Code = TYPE_ADJUSTED;
+}
+
void ASTTypeWriter::VisitBlockPointerType(const BlockPointerType *T) {
Writer.AddTypeRef(T->getPointeeType(), Record);
Code = TYPE_BLOCK_POINTER;
@@ -173,7 +182,7 @@ void ASTTypeWriter::VisitExtVectorType(const ExtVectorType *T) {
}
void ASTTypeWriter::VisitFunctionType(const FunctionType *T) {
- Writer.AddTypeRef(T->getResultType(), Record);
+ Writer.AddTypeRef(T->getReturnType(), Record);
FunctionType::ExtInfo C = T->getExtInfo();
Record.push_back(C.getNoReturn());
Record.push_back(C.getHasRegParm());
@@ -188,15 +197,8 @@ void ASTTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
Code = TYPE_FUNCTION_NO_PROTO;
}
-void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
- VisitFunctionType(T);
- Record.push_back(T->getNumArgs());
- for (unsigned I = 0, N = T->getNumArgs(); I != N; ++I)
- Writer.AddTypeRef(T->getArgType(I), Record);
- Record.push_back(T->isVariadic());
- Record.push_back(T->hasTrailingReturn());
- Record.push_back(T->getTypeQuals());
- Record.push_back(static_cast<unsigned>(T->getRefQualifier()));
+static void addExceptionSpec(ASTWriter &Writer, const FunctionProtoType *T,
+ ASTWriter::RecordDataImpl &Record) {
Record.push_back(T->getExceptionSpecType());
if (T->getExceptionSpecType() == EST_Dynamic) {
Record.push_back(T->getNumExceptions());
@@ -210,6 +212,18 @@ void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
} else if (T->getExceptionSpecType() == EST_Unevaluated) {
Writer.AddDeclRef(T->getExceptionSpecDecl(), Record);
}
+}
+
+void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
+ VisitFunctionType(T);
+ Record.push_back(T->getNumParams());
+ for (unsigned I = 0, N = T->getNumParams(); I != N; ++I)
+ Writer.AddTypeRef(T->getParamType(I), Record);
+ Record.push_back(T->isVariadic());
+ Record.push_back(T->hasTrailingReturn());
+ Record.push_back(T->getTypeQuals());
+ Record.push_back(static_cast<unsigned>(T->getRefQualifier()));
+ addExceptionSpec(Writer, T, Record);
Code = TYPE_FUNCTION_PROTO;
}
@@ -395,9 +409,8 @@ void ASTTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
void ASTTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) {
Writer.AddTypeRef(T->getBaseType(), Record);
Record.push_back(T->getNumProtocols());
- for (ObjCObjectType::qual_iterator I = T->qual_begin(),
- E = T->qual_end(); I != E; ++I)
- Writer.AddDeclRef(*I, Record);
+ for (const auto *I : T->quals())
+ Writer.AddDeclRef(I, Record);
Code = TYPE_OBJC_OBJECT;
}
@@ -455,6 +468,9 @@ void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) {
void TypeLocWriter::VisitDecayedTypeLoc(DecayedTypeLoc TL) {
// nothing to do
}
+void TypeLocWriter::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
+ // nothing to do
+}
void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
Writer.AddSourceLocation(TL.getCaretLoc(), Record);
}
@@ -503,8 +519,8 @@ void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) {
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
Writer.AddSourceLocation(TL.getLocalRangeEnd(), Record);
- for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
- Writer.AddDeclRef(TL.getArg(i), Record);
+ for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i)
+ Writer.AddDeclRef(TL.getParam(i), Record);
}
void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
VisitFunctionTypeLoc(TL);
@@ -645,7 +661,8 @@ static void EmitBlockID(unsigned ID, const char *Name,
Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
// Emit the block name if present.
- if (Name == 0 || Name[0] == 0) return;
+ if (!Name || Name[0] == 0)
+ return;
Record.clear();
while (*Name)
Record.push_back(*Name++);
@@ -764,10 +781,8 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(EXPR_CXX_UNRESOLVED_CONSTRUCT);
RECORD(EXPR_CXX_UNRESOLVED_MEMBER);
RECORD(EXPR_CXX_UNRESOLVED_LOOKUP);
- RECORD(EXPR_CXX_UNARY_TYPE_TRAIT);
RECORD(EXPR_CXX_NOEXCEPT);
RECORD(EXPR_OPAQUE_VALUE);
- RECORD(EXPR_BINARY_TYPE_TRAIT);
RECORD(EXPR_PACK_EXPANSION);
RECORD(EXPR_SIZEOF_PACK);
RECORD(EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK);
@@ -785,6 +800,8 @@ void ASTWriter::WriteBlockInfoBlock() {
// Control Block.
BLOCK(CONTROL_BLOCK);
RECORD(METADATA);
+ RECORD(MODULE_NAME);
+ RECORD(MODULE_MAP_FILE);
RECORD(IMPORTS);
RECORD(LANGUAGE_OPTIONS);
RECORD(TARGET_OPTIONS);
@@ -806,7 +823,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(DECL_OFFSET);
RECORD(IDENTIFIER_OFFSET);
RECORD(IDENTIFIER_TABLE);
- RECORD(EXTERNAL_DEFINITIONS);
+ RECORD(EAGERLY_DESERIALIZED_DECLS);
RECORD(SPECIAL_TYPES);
RECORD(STATISTICS);
RECORD(TENTATIVE_DEFINITIONS);
@@ -849,6 +866,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(MACRO_OFFSET);
RECORD(MACRO_TABLE);
RECORD(LATE_PARSED_TEMPLATE);
+ RECORD(OPTIMIZE_PRAGMA_OPTIONS);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -1037,10 +1055,35 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record,
getClangFullRepositoryVersion());
+ // Module name
+ if (WritingModule) {
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(MODULE_NAME));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
+ RecordData Record;
+ Record.push_back(MODULE_NAME);
+ Stream.EmitRecordWithBlob(AbbrevCode, Record, WritingModule->Name);
+ }
+
+ // Module map file
+ if (WritingModule) {
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(MODULE_MAP_FILE));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Filename
+ unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
+
+ assert(WritingModule->ModuleMap && "missing module map");
+ SmallString<128> ModuleMap(WritingModule->ModuleMap->getName());
+ llvm::sys::fs::make_absolute(ModuleMap);
+ RecordData Record;
+ Record.push_back(MODULE_MAP_FILE);
+ Stream.EmitRecordWithBlob(AbbrevCode, Record, ModuleMap.str());
+ }
+
// Imports
if (Chain) {
serialization::ModuleManager &Mgr = Chain->getModuleManager();
- SmallVector<char, 128> ModulePaths;
Record.clear();
for (ModuleManager::ModuleIterator M = Mgr.begin(), MEnd = Mgr.end();
@@ -1053,7 +1096,6 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
AddSourceLocation((*M)->ImportLoc, Record);
Record.push_back((*M)->File->getSize());
Record.push_back((*M)->File->getModificationTime());
- // FIXME: This writes the absolute path for AST files we depend on.
const std::string &FileName = (*M)->FileName;
Record.push_back(FileName.size());
Record.append(FileName.begin(), FileName.end());
@@ -1097,8 +1139,6 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
AddString(TargetOpts.Triple, Record);
AddString(TargetOpts.CPU, Record);
AddString(TargetOpts.ABI, Record);
- AddString(TargetOpts.CXXABI, Record);
- AddString(TargetOpts.LinkerVersion, Record);
Record.push_back(TargetOpts.FeaturesAsWritten.size());
for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size(); I != N; ++I) {
AddString(TargetOpts.FeaturesAsWritten[I], Record);
@@ -1120,6 +1160,9 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
Record.push_back(DiagOpts.Warnings.size());
for (unsigned I = 0, N = DiagOpts.Warnings.size(); I != N; ++I)
AddString(DiagOpts.Warnings[I], Record);
+ Record.push_back(DiagOpts.Remarks.size());
+ for (unsigned I = 0, N = DiagOpts.Remarks.size(); I != N; ++I)
+ AddString(DiagOpts.Remarks[I], Record);
// Note: we don't serialize the log or serialization file names, because they
// are generally transient files and will almost always be overridden.
Stream.EmitRecord(DIAGNOSTIC_OPTIONS, Record);
@@ -1156,6 +1199,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
AddString(HSOpts.ResourceDir, Record);
AddString(HSOpts.ModuleCachePath, Record);
+ AddString(HSOpts.ModuleUserBuildPath, Record);
Record.push_back(HSOpts.DisableModuleHash);
Record.push_back(HSOpts.UseBuiltinIncludes);
Record.push_back(HSOpts.UseStandardSystemIncludes);
@@ -1294,33 +1338,6 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
SortedFiles.push_front(Entry);
}
- // If we have an isysroot for a Darwin SDK, include its SDKSettings.plist in
- // the set of (non-system) input files. This is simple heuristic for
- // detecting whether the system headers may have changed, because it is too
- // expensive to stat() all of the system headers.
- FileManager &FileMgr = SourceMgr.getFileManager();
- if (!HSOpts.Sysroot.empty() && !Chain) {
- llvm::SmallString<128> SDKSettingsFileName(HSOpts.Sysroot);
- llvm::sys::path::append(SDKSettingsFileName, "SDKSettings.plist");
- if (const FileEntry *SDKSettingsFile = FileMgr.getFile(SDKSettingsFileName)) {
- InputFileEntry Entry = { SDKSettingsFile, false, false };
- SortedFiles.push_front(Entry);
- }
- }
-
- // Add the compiler's own module.map in the set of (non-system) input files.
- // This is a simple heuristic for detecting whether the compiler's headers
- // have changed, because we don't want to stat() all of them.
- if (Modules && !Chain) {
- SmallString<128> P = StringRef(HSOpts.ResourceDir);
- llvm::sys::path::append(P, "include");
- llvm::sys::path::append(P, "module.map");
- if (const FileEntry *ModuleMapFile = FileMgr.getFile(P)) {
- InputFileEntry Entry = { ModuleMapFile, false, false };
- SortedFiles.push_front(Entry);
- }
- }
-
unsigned UserFilesNum = 0;
// Write out all of the input files.
std::vector<uint32_t> InputFileOffsets;
@@ -1357,7 +1374,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
// Ask the file manager to fixup the relative path for us. This will
// honor the working directory.
- FileMgr.FixupRelativePath(FilePath);
+ SourceMgr.getFileManager().FixupRelativePath(FilePath);
// FIXME: This call to make_absolute shouldn't be necessary, the
// call to FixupRelativePath should always return an absolute path.
@@ -1470,8 +1487,10 @@ namespace {
typedef HeaderFileInfo data_type;
typedef const data_type &data_type_ref;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
- static unsigned ComputeHash(key_type_ref key) {
+ static hash_value_type ComputeHash(key_type_ref key) {
// The hash is based only on size/time of the file, so that the reader can
// match even when symlinking or excess path elements ("foo/../", "../")
// change the form of the name. However, complete path is still the key.
@@ -1481,26 +1500,31 @@ namespace {
std::pair<unsigned,unsigned>
EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) {
+ using namespace llvm::support;
+ endian::Writer<little> Writer(Out);
unsigned KeyLen = strlen(key.Filename) + 1 + 8 + 8;
- clang::io::Emit16(Out, KeyLen);
+ Writer.write<uint16_t>(KeyLen);
unsigned DataLen = 1 + 2 + 4 + 4;
if (Data.isModuleHeader)
DataLen += 4;
- clang::io::Emit8(Out, DataLen);
+ Writer.write<uint8_t>(DataLen);
return std::make_pair(KeyLen, DataLen);
}
void EmitKey(raw_ostream& Out, key_type_ref key, unsigned KeyLen) {
- clang::io::Emit64(Out, key.FE->getSize());
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+ LE.write<uint64_t>(key.FE->getSize());
KeyLen -= 8;
- clang::io::Emit64(Out, key.FE->getModificationTime());
+ LE.write<uint64_t>(key.FE->getModificationTime());
KeyLen -= 8;
Out.write(key.Filename, KeyLen);
}
void EmitData(raw_ostream &Out, key_type_ref key,
data_type_ref Data, unsigned DataLen) {
- using namespace clang::io;
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
uint64_t Start = Out.tell(); (void)Start;
unsigned char Flags = (Data.HeaderRole << 6)
@@ -1509,13 +1533,13 @@ namespace {
| (Data.DirInfo << 2)
| (Data.Resolved << 1)
| Data.IndexHeaderMapHeader;
- Emit8(Out, (uint8_t)Flags);
- Emit16(Out, (uint16_t) Data.NumIncludes);
+ LE.write<uint8_t>(Flags);
+ LE.write<uint16_t>(Data.NumIncludes);
if (!Data.ControllingMacro)
- Emit32(Out, (uint32_t)Data.ControllingMacroID);
+ LE.write<uint32_t>(Data.ControllingMacroID);
else
- Emit32(Out, (uint32_t)Writer.getIdentifierRef(Data.ControllingMacro));
+ LE.write<uint32_t>(Writer.getIdentifierRef(Data.ControllingMacro));
unsigned Offset = 0;
if (!Data.Framework.empty()) {
@@ -1532,11 +1556,11 @@ namespace {
} else
Offset = Pos->second;
}
- Emit32(Out, Offset);
+ LE.write<uint32_t>(Offset);
if (Data.isModuleHeader) {
Module *Mod = HS.findModuleForHeader(key.FE).getModule();
- Emit32(Out, Writer.getExistingSubmoduleID(Mod));
+ LE.write<uint32_t>(Writer.getExistingSubmoduleID(Mod));
}
assert(Out.tell() - Start == DataLen && "Wrong data length");
@@ -1558,7 +1582,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
FilesByUID.resize(HS.header_file_size());
HeaderFileInfoTrait GeneratorTrait(*this, HS);
- OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator;
+ llvm::OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator;
SmallVector<const char *, 4> SavedStrings;
unsigned NumHeaderSearchEntries = 0;
for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) {
@@ -1568,10 +1592,10 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
// Use HeaderSearch's getFileInfo to make sure we get the HeaderFileInfo
// from the external source if it was not provided already.
- const HeaderFileInfo &HFI = HS.getFileInfo(File);
- if (HFI.External && Chain)
- continue;
- if (HFI.isModuleHeader && !HFI.isCompilingModuleHeader)
+ HeaderFileInfo HFI;
+ if (!HS.tryGetFileInfo(File, HFI) ||
+ (HFI.External && Chain) ||
+ (HFI.isModuleHeader && !HFI.isCompilingModuleHeader))
continue;
// Turn the file name into an absolute path, if it isn't already.
@@ -1594,9 +1618,10 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
SmallString<4096> TableData;
uint32_t BucketOffset;
{
+ using namespace llvm::support;
llvm::raw_svector_ostream Out(TableData);
// Make sure that no bucket is at offset 0
- clang::io::Emit32(Out, 0);
+ endian::Writer<little>(Out).write<uint32_t>(0);
BucketOffset = Generator.Emit(Out, GeneratorTrait);
}
@@ -1837,8 +1862,10 @@ public:
typedef Data data_type;
typedef const data_type &data_type_ref;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
- static unsigned ComputeHash(IdentID IdID) {
+ static hash_value_type ComputeHash(IdentID IdID) {
return llvm::hash_value(IdID);
}
@@ -1851,12 +1878,14 @@ public:
}
static void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) {
- clang::io::Emit32(Out, Key);
+ using namespace llvm::support;
+ endian::Writer<little>(Out).write<uint32_t>(Key);
}
static void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data,
unsigned) {
- clang::io::Emit32(Out, Data.MacroDirectivesOffset);
+ using namespace llvm::support;
+ endian::Writer<little>(Out).write<uint32_t>(Data.MacroDirectivesOffset);
}
};
} // end anonymous namespace
@@ -1874,6 +1903,12 @@ static bool shouldIgnoreMacro(MacroDirective *MD, bool IsModule,
return true;
if (IsModule) {
+ // Re-export any imported directives.
+ // FIXME: Also ensure we re-export imported #undef directives.
+ if (auto *DMD = dyn_cast<DefMacroDirective>(MD))
+ if (DMD->isImported())
+ return false;
+
SourceLocation Loc = MD->getLocation();
if (Loc.isInvalid())
return true;
@@ -1928,7 +1963,7 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
llvm::array_pod_sort(MacroDirectives.begin(), MacroDirectives.end(),
&compareMacroDirectives);
- OnDiskChainedHashTableGenerator<ASTMacroTableTrait> Generator;
+ llvm::OnDiskChainedHashTableGenerator<ASTMacroTableTrait> Generator;
// Emit the macro directives as a list and associate the offset with the
// identifier they belong to.
@@ -1946,8 +1981,6 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
// Emit the macro directives in reverse source order.
for (; MD; MD = MD->getPrevious()) {
- if (MD->isHidden())
- continue;
if (shouldIgnoreMacro(MD, IsModule, PP))
continue;
@@ -2012,6 +2045,7 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
AddSourceLocation(MI->getDefinitionLoc(), Record);
AddSourceLocation(MI->getDefinitionEndLoc(), Record);
Record.push_back(MI->isUsed());
+ Record.push_back(MI->isUsedForHeaderGuard());
unsigned Code;
if (MI->isObjectLike()) {
Code = PP_MACRO_OBJECT_LIKE;
@@ -2054,9 +2088,10 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
SmallString<4096> MacroTable;
uint32_t BucketOffset;
{
+ using namespace llvm::support;
llvm::raw_svector_ostream Out(MacroTable);
// Make sure that no bucket is at offset 0
- clang::io::Emit32(Out, 0);
+ endian::Writer<little>(Out).write<uint32_t>(0);
BucketOffset = Generator.Emit(Out);
}
@@ -2227,9 +2262,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
// other consumers of this information.
SourceManager &SrcMgr = PP->getSourceManager();
ModuleMap &ModMap = PP->getHeaderSearchInfo().getModuleMap();
- for (ASTContext::import_iterator I = Context->local_import_begin(),
- IEnd = Context->local_import_end();
- I != IEnd; ++I) {
+ for (const auto *I : Context->local_imports()) {
if (Module *ImportedFrom
= ModMap.inferModuleFromLocation(FullSourceLoc(I->getLocation(),
SrcMgr))) {
@@ -2248,7 +2281,8 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystem
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystem
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExternC
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferSubmodules...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild...
@@ -2336,6 +2370,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Record.push_back(Mod->IsFramework);
Record.push_back(Mod->IsExplicit);
Record.push_back(Mod->IsSystem);
+ Record.push_back(Mod->IsExternC);
Record.push_back(Mod->InferSubmodules);
Record.push_back(Mod->InferExplicitSubmodules);
Record.push_back(Mod->InferExportWildcard);
@@ -2516,7 +2551,7 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
I = point.State->begin(), E = point.State->end(); I != E; ++I) {
if (I->second.isPragma()) {
Record.push_back(I->first);
- Record.push_back(I->second.getMapping());
+ Record.push_back((unsigned)I->second.getSeverity());
}
}
Record.push_back(-1); // mark the end of the diag/map pairs for this
@@ -2618,9 +2653,8 @@ uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context,
RecordData Record;
Record.push_back(DECL_CONTEXT_LEXICAL);
SmallVector<KindDeclIDPair, 64> Decls;
- for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end();
- D != DEnd; ++D)
- Decls.push_back(std::make_pair((*D)->getKind(), GetDeclRef(*D)));
+ for (const auto *D : DC->decls())
+ Decls.push_back(std::make_pair(D->getKind(), GetDeclRef(D)));
++NumLexicalDeclContexts;
Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record, data(Decls));
@@ -2719,17 +2753,22 @@ public:
};
typedef const data_type& data_type_ref;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
explicit ASTMethodPoolTrait(ASTWriter &Writer) : Writer(Writer) { }
- static unsigned ComputeHash(Selector Sel) {
+ static hash_value_type ComputeHash(Selector Sel) {
return serialization::ComputeHash(Sel);
}
std::pair<unsigned,unsigned>
EmitKeyDataLength(raw_ostream& Out, Selector Sel,
data_type_ref Methods) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
unsigned KeyLen = 2 + (Sel.getNumArgs()? Sel.getNumArgs() * 4 : 4);
- clang::io::Emit16(Out, KeyLen);
+ LE.write<uint16_t>(KeyLen);
unsigned DataLen = 4 + 2 + 2; // 2 bytes for each of the method counts
for (const ObjCMethodList *Method = &Methods.Instance; Method;
Method = Method->getNext())
@@ -2739,27 +2778,31 @@ public:
Method = Method->getNext())
if (Method->Method)
DataLen += 4;
- clang::io::Emit16(Out, DataLen);
+ LE.write<uint16_t>(DataLen);
return std::make_pair(KeyLen, DataLen);
}
void EmitKey(raw_ostream& Out, Selector Sel, unsigned) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
uint64_t Start = Out.tell();
assert((Start >> 32) == 0 && "Selector key offset too large");
Writer.SetSelectorOffset(Sel, Start);
unsigned N = Sel.getNumArgs();
- clang::io::Emit16(Out, N);
+ LE.write<uint16_t>(N);
if (N == 0)
N = 1;
for (unsigned I = 0; I != N; ++I)
- clang::io::Emit32(Out,
- Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I)));
+ LE.write<uint32_t>(
+ Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I)));
}
void EmitData(raw_ostream& Out, key_type_ref,
data_type_ref Methods, unsigned DataLen) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
uint64_t Start = Out.tell(); (void)Start;
- clang::io::Emit32(Out, Methods.ID);
+ LE.write<uint32_t>(Methods.ID);
unsigned NumInstanceMethods = 0;
for (const ObjCMethodList *Method = &Methods.Instance; Method;
Method = Method->getNext())
@@ -2779,16 +2822,16 @@ public:
unsigned FactoryBits = Methods.Factory.getBits();
assert(FactoryBits < 4);
unsigned NumFactoryMethodsAndBits = (NumFactoryMethods << 2) | FactoryBits;
- clang::io::Emit16(Out, NumInstanceMethodsAndBits);
- clang::io::Emit16(Out, NumFactoryMethodsAndBits);
+ LE.write<uint16_t>(NumInstanceMethodsAndBits);
+ LE.write<uint16_t>(NumFactoryMethodsAndBits);
for (const ObjCMethodList *Method = &Methods.Instance; Method;
Method = Method->getNext())
if (Method->Method)
- clang::io::Emit32(Out, Writer.getDeclID(Method->Method));
+ LE.write<uint32_t>(Writer.getDeclID(Method->Method));
for (const ObjCMethodList *Method = &Methods.Factory; Method;
Method = Method->getNext())
if (Method->Method)
- clang::io::Emit32(Out, Writer.getDeclID(Method->Method));
+ LE.write<uint32_t>(Writer.getDeclID(Method->Method));
assert(Out.tell() - Start == DataLen && "Data length is wrong");
}
@@ -2809,7 +2852,7 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) {
unsigned NumTableEntries = 0;
// Create and write out the blob that contains selectors and the method pool.
{
- OnDiskChainedHashTableGenerator<ASTMethodPoolTrait> Generator;
+ llvm::OnDiskChainedHashTableGenerator<ASTMethodPoolTrait> Generator;
ASTMethodPoolTrait Trait(*this);
// Create the on-disk hash table representation. We walk through every
@@ -2857,10 +2900,11 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) {
SmallString<4096> MethodPool;
uint32_t BucketOffset;
{
+ using namespace llvm::support;
ASTMethodPoolTrait Trait(*this);
llvm::raw_svector_ostream Out(MethodPool);
// Make sure that no bucket is at offset 0
- clang::io::Emit32(Out, 0);
+ endian::Writer<little>(Out).write<uint32_t>(0);
BucketOffset = Generator.Emit(Out, Trait);
}
@@ -2959,83 +3003,110 @@ class ASTIdentifierTableTrait {
return false;
}
- DefMacroDirective *getFirstPublicSubmoduleMacro(MacroDirective *MD,
- SubmoduleID &ModID) {
+ typedef llvm::SmallVectorImpl<SubmoduleID> OverriddenList;
+
+ MacroDirective *
+ getFirstPublicSubmoduleMacro(MacroDirective *MD, SubmoduleID &ModID) {
ModID = 0;
- if (DefMacroDirective *DefMD = getPublicSubmoduleMacro(MD, ModID))
- if (!shouldIgnoreMacro(DefMD, IsModule, PP))
- return DefMD;
- return 0;
+ llvm::SmallVector<SubmoduleID, 1> Overridden;
+ if (MacroDirective *NextMD = getPublicSubmoduleMacro(MD, ModID, Overridden))
+ if (!shouldIgnoreMacro(NextMD, IsModule, PP))
+ return NextMD;
+ return nullptr;
}
- DefMacroDirective *getNextPublicSubmoduleMacro(DefMacroDirective *MD,
- SubmoduleID &ModID) {
- if (DefMacroDirective *
- DefMD = getPublicSubmoduleMacro(MD->getPrevious(), ModID))
- if (!shouldIgnoreMacro(DefMD, IsModule, PP))
- return DefMD;
- return 0;
+ MacroDirective *
+ getNextPublicSubmoduleMacro(MacroDirective *MD, SubmoduleID &ModID,
+ OverriddenList &Overridden) {
+ if (MacroDirective *NextMD =
+ getPublicSubmoduleMacro(MD->getPrevious(), ModID, Overridden))
+ if (!shouldIgnoreMacro(NextMD, IsModule, PP))
+ return NextMD;
+ return nullptr;
}
/// \brief Traverses the macro directives history and returns the latest
- /// macro that is public and not undefined in the same submodule.
- /// A macro that is defined in submodule A and undefined in submodule B,
+ /// public macro definition or undefinition that is not in ModID.
+ /// A macro that is defined in submodule A and undefined in submodule B
/// will still be considered as defined/exported from submodule A.
- DefMacroDirective *getPublicSubmoduleMacro(MacroDirective *MD,
- SubmoduleID &ModID) {
+ /// ModID is updated to the module containing the returned directive.
+ ///
+ /// FIXME: This process breaks down if a module defines a macro, imports
+ /// another submodule that changes the macro, then changes the
+ /// macro again itself.
+ MacroDirective *getPublicSubmoduleMacro(MacroDirective *MD,
+ SubmoduleID &ModID,
+ OverriddenList &Overridden) {
+ Overridden.clear();
if (!MD)
- return 0;
+ return nullptr;
SubmoduleID OrigModID = ModID;
- bool isUndefined = false;
- Optional<bool> isPublic;
+ Optional<bool> IsPublic;
for (; MD; MD = MD->getPrevious()) {
- if (MD->isHidden())
- continue;
-
SubmoduleID ThisModID = getSubmoduleID(MD);
if (ThisModID == 0) {
- isUndefined = false;
- isPublic = Optional<bool>();
+ IsPublic = Optional<bool>();
+
+ // If we have no directive location, this macro was installed when
+ // finalizing the ASTReader.
+ if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD))
+ if (DefMD->getInfo()->getOwningModuleID())
+ return MD;
+ // Skip imports that only produce #undefs for now.
+ // FIXME: We should still re-export them!
+
continue;
}
- if (ThisModID != ModID){
+ if (ThisModID != ModID) {
ModID = ThisModID;
- isUndefined = false;
- isPublic = Optional<bool>();
+ IsPublic = Optional<bool>();
}
+
+ // If this is a definition from a submodule import, that submodule's
+ // definition is overridden by the definition or undefinition that we
+ // started with.
+ // FIXME: This should only apply to macros defined in OrigModID.
+ // We can't do that currently, because a #include of a different submodule
+ // of the same module just leaks through macros instead of providing new
+ // DefMacroDirectives for them.
+ if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) {
+ // Figure out which submodule the macro was originally defined within.
+ SubmoduleID SourceID = DefMD->getInfo()->getOwningModuleID();
+ if (!SourceID) {
+ SourceLocation DefLoc = DefMD->getInfo()->getDefinitionLoc();
+ if (DefLoc == MD->getLocation())
+ SourceID = ThisModID;
+ else
+ SourceID = Writer.inferSubmoduleIDFromLocation(DefLoc);
+ }
+ if (OrigModID && SourceID != OrigModID)
+ Overridden.push_back(SourceID);
+ }
+
// We are looking for a definition in a different submodule than the one
// that we started with. If a submodule has re-definitions of the same
// macro, only the last definition will be used as the "exported" one.
if (ModID == OrigModID)
continue;
- if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) {
- if (!isUndefined && (!isPublic.hasValue() || isPublic.getValue()))
- return DefMD;
- continue;
- }
-
- if (isa<UndefMacroDirective>(MD)) {
- isUndefined = true;
- continue;
+ // The latest visibility directive for a name in a submodule affects all
+ // the directives that come before it.
+ if (VisibilityMacroDirective *VisMD =
+ dyn_cast<VisibilityMacroDirective>(MD)) {
+ if (!IsPublic.hasValue())
+ IsPublic = VisMD->isPublic();
+ } else if (!IsPublic.hasValue() || IsPublic.getValue()) {
+ // FIXME: If we find an imported macro, we should include its list of
+ // overrides in our export.
+ return MD;
}
-
- VisibilityMacroDirective *VisMD = cast<VisibilityMacroDirective>(MD);
- if (!isPublic.hasValue())
- isPublic = VisMD->isPublic();
}
- return 0;
+ return nullptr;
}
SubmoduleID getSubmoduleID(MacroDirective *MD) {
- if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) {
- MacroInfo *MI = DefMD->getInfo();
- if (unsigned ID = MI->getOwningModuleID())
- return ID;
- return Writer.inferSubmoduleIDFromLocation(MI->getDefinitionLoc());
- }
return Writer.inferSubmoduleIDFromLocation(MD->getLocation());
}
@@ -3046,11 +3117,14 @@ public:
typedef IdentID data_type;
typedef data_type data_type_ref;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP,
IdentifierResolver &IdResolver, bool IsModule)
: Writer(Writer), PP(PP), IdResolver(IdResolver), IsModule(IsModule) { }
- static unsigned ComputeHash(const IdentifierInfo* II) {
+ static hash_value_type ComputeHash(const IdentifierInfo* II) {
return llvm::HashString(II->getName());
}
@@ -3058,7 +3132,7 @@ public:
EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) {
unsigned KeyLen = II->getLength() + 1;
unsigned DataLen = 4; // 4 bytes for the persistent ID << 1
- MacroDirective *Macro = 0;
+ MacroDirective *Macro = nullptr;
if (isInterestingIdentifier(II, Macro)) {
DataLen += 2; // 2 bytes for builtin ID
DataLen += 2; // 2 bytes for flags
@@ -3066,11 +3140,18 @@ public:
DataLen += 4; // MacroDirectives offset.
if (IsModule) {
SubmoduleID ModID;
- for (DefMacroDirective *
- DefMD = getFirstPublicSubmoduleMacro(Macro, ModID);
- DefMD; DefMD = getNextPublicSubmoduleMacro(DefMD, ModID)) {
- DataLen += 4; // MacroInfo ID.
+ llvm::SmallVector<SubmoduleID, 4> Overridden;
+ for (MacroDirective *
+ MD = getFirstPublicSubmoduleMacro(Macro, ModID);
+ MD; MD = getNextPublicSubmoduleMacro(MD, ModID, Overridden)) {
+ // Previous macro's overrides.
+ if (!Overridden.empty())
+ DataLen += 4 * (1 + Overridden.size());
+ DataLen += 4; // MacroInfo ID or ModuleID.
}
+ // Previous macro's overrides.
+ if (!Overridden.empty())
+ DataLen += 4 * (1 + Overridden.size());
DataLen += 4;
}
}
@@ -3080,11 +3161,14 @@ public:
D != DEnd; ++D)
DataLen += sizeof(DeclID);
}
- clang::io::Emit16(Out, DataLen);
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+
+ LE.write<uint16_t>(DataLen);
// We emit the key length after the data length so that every
// string is preceded by a 16-bit length. This matches the PTH
// format for storing identifiers.
- clang::io::Emit16(Out, KeyLen);
+ LE.write<uint16_t>(KeyLen);
return std::make_pair(KeyLen, DataLen);
}
@@ -3096,18 +3180,31 @@ public:
Out.write(II->getNameStart(), KeyLen);
}
+ static void emitMacroOverrides(raw_ostream &Out,
+ ArrayRef<SubmoduleID> Overridden) {
+ if (!Overridden.empty()) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+ LE.write<uint32_t>(Overridden.size() | 0x80000000U);
+ for (unsigned I = 0, N = Overridden.size(); I != N; ++I)
+ LE.write<uint32_t>(Overridden[I]);
+ }
+ }
+
void EmitData(raw_ostream& Out, IdentifierInfo* II,
IdentID ID, unsigned) {
- MacroDirective *Macro = 0;
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+ MacroDirective *Macro = nullptr;
if (!isInterestingIdentifier(II, Macro)) {
- clang::io::Emit32(Out, ID << 1);
+ LE.write<uint32_t>(ID << 1);
return;
}
- clang::io::Emit32(Out, (ID << 1) | 0x01);
+ LE.write<uint32_t>((ID << 1) | 0x01);
uint32_t Bits = (uint32_t)II->getObjCOrBuiltinID();
assert((Bits & 0xffff) == Bits && "ObjCOrBuiltinID too big for ASTReader.");
- clang::io::Emit16(Out, Bits);
+ LE.write<uint16_t>(Bits);
Bits = 0;
bool HadMacroDefinition = hadMacroDefinition(II, Macro);
Bits = (Bits << 1) | unsigned(HadMacroDefinition);
@@ -3116,21 +3213,30 @@ public:
Bits = (Bits << 1) | unsigned(II->isPoisoned());
Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier());
Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword());
- clang::io::Emit16(Out, Bits);
+ LE.write<uint16_t>(Bits);
if (HadMacroDefinition) {
- clang::io::Emit32(Out, Writer.getMacroDirectivesOffset(II));
+ LE.write<uint32_t>(Writer.getMacroDirectivesOffset(II));
if (IsModule) {
// Write the IDs of macros coming from different submodules.
SubmoduleID ModID;
- for (DefMacroDirective *
- DefMD = getFirstPublicSubmoduleMacro(Macro, ModID);
- DefMD; DefMD = getNextPublicSubmoduleMacro(DefMD, ModID)) {
- MacroID InfoID = Writer.getMacroID(DefMD->getInfo());
- assert(InfoID);
- clang::io::Emit32(Out, InfoID);
+ llvm::SmallVector<SubmoduleID, 4> Overridden;
+ for (MacroDirective *
+ MD = getFirstPublicSubmoduleMacro(Macro, ModID);
+ MD; MD = getNextPublicSubmoduleMacro(MD, ModID, Overridden)) {
+ MacroID InfoID = 0;
+ emitMacroOverrides(Out, Overridden);
+ if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) {
+ InfoID = Writer.getMacroID(DefMD->getInfo());
+ assert(InfoID);
+ LE.write<uint32_t>(InfoID << 1);
+ } else {
+ assert(isa<UndefMacroDirective>(MD));
+ LE.write<uint32_t>((ModID << 1) | 1);
+ }
}
- clang::io::Emit32(Out, 0);
+ emitMacroOverrides(Out, Overridden);
+ LE.write<uint32_t>(0);
}
}
@@ -3145,7 +3251,7 @@ public:
for (SmallVectorImpl<Decl *>::reverse_iterator D = Decls.rbegin(),
DEnd = Decls.rend();
D != DEnd; ++D)
- clang::io::Emit32(Out, Writer.getDeclID(getMostRecentLocalDecl(*D)));
+ LE.write<uint32_t>(Writer.getDeclID(getMostRecentLocalDecl(*D)));
}
/// \brief Returns the most recent local decl or the given decl if there are
@@ -3184,7 +3290,7 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,
// Create and write out the blob that contains the identifier
// strings.
{
- OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator;
+ llvm::OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator;
ASTIdentifierTableTrait Trait(*this, PP, IdResolver, IsModule);
// Look for any identifiers that were named while processing the
@@ -3214,10 +3320,11 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,
SmallString<4096> IdentifierTable;
uint32_t BucketOffset;
{
+ using namespace llvm::support;
ASTIdentifierTableTrait Trait(*this, PP, IdResolver, IsModule);
llvm::raw_svector_ostream Out(IdentifierTable);
// Make sure that no bucket is at offset 0
- clang::io::Emit32(Out, 0);
+ endian::Writer<little>(Out).write<uint32_t>(0);
BucketOffset = Generator.Emit(Out, Trait);
}
@@ -3272,9 +3379,12 @@ public:
typedef DeclContext::lookup_result data_type;
typedef const data_type& data_type_ref;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
explicit ASTDeclContextNameLookupTrait(ASTWriter &Writer) : Writer(Writer) { }
- unsigned ComputeHash(DeclarationName Name) {
+ hash_value_type ComputeHash(DeclarationName Name) {
llvm::FoldingSetNodeID ID;
ID.AddInteger(Name.getNameKind());
@@ -3306,6 +3416,8 @@ public:
std::pair<unsigned,unsigned>
EmitKeyDataLength(raw_ostream& Out, DeclarationName Name,
data_type_ref Lookup) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
unsigned KeyLen = 1;
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
@@ -3324,35 +3436,35 @@ public:
case DeclarationName::CXXUsingDirective:
break;
}
- clang::io::Emit16(Out, KeyLen);
+ LE.write<uint16_t>(KeyLen);
// 2 bytes for num of decls and 4 for each DeclID.
unsigned DataLen = 2 + 4 * Lookup.size();
- clang::io::Emit16(Out, DataLen);
+ LE.write<uint16_t>(DataLen);
return std::make_pair(KeyLen, DataLen);
}
void EmitKey(raw_ostream& Out, DeclarationName Name, unsigned) {
- using namespace clang::io;
-
- Emit8(Out, Name.getNameKind());
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+ LE.write<uint8_t>(Name.getNameKind());
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
- Emit32(Out, Writer.getIdentifierRef(Name.getAsIdentifierInfo()));
+ LE.write<uint32_t>(Writer.getIdentifierRef(Name.getAsIdentifierInfo()));
return;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
- Emit32(Out, Writer.getSelectorRef(Name.getObjCSelector()));
+ LE.write<uint32_t>(Writer.getSelectorRef(Name.getObjCSelector()));
return;
case DeclarationName::CXXOperatorName:
assert(Name.getCXXOverloadedOperator() < NUM_OVERLOADED_OPERATORS &&
"Invalid operator?");
- Emit8(Out, Name.getCXXOverloadedOperator());
+ LE.write<uint8_t>(Name.getCXXOverloadedOperator());
return;
case DeclarationName::CXXLiteralOperatorName:
- Emit32(Out, Writer.getIdentifierRef(Name.getCXXLiteralIdentifier()));
+ LE.write<uint32_t>(Writer.getIdentifierRef(Name.getCXXLiteralIdentifier()));
return;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
@@ -3366,17 +3478,134 @@ public:
void EmitData(raw_ostream& Out, key_type_ref,
data_type Lookup, unsigned DataLen) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
uint64_t Start = Out.tell(); (void)Start;
- clang::io::Emit16(Out, Lookup.size());
+ LE.write<uint16_t>(Lookup.size());
for (DeclContext::lookup_iterator I = Lookup.begin(), E = Lookup.end();
I != E; ++I)
- clang::io::Emit32(Out, Writer.GetDeclRef(*I));
+ LE.write<uint32_t>(Writer.GetDeclRef(*I));
assert(Out.tell() - Start == DataLen && "Data length is wrong");
}
};
} // end anonymous namespace
+template<typename Visitor>
+static void visitLocalLookupResults(const DeclContext *ConstDC,
+ bool NeedToReconcileExternalVisibleStorage,
+ Visitor AddLookupResult) {
+ // FIXME: We need to build the lookups table, which is logically const.
+ DeclContext *DC = const_cast<DeclContext*>(ConstDC);
+ assert(DC == DC->getPrimaryContext() && "only primary DC has lookup table");
+
+ SmallVector<DeclarationName, 16> ExternalNames;
+ for (auto &Lookup : *DC->buildLookup()) {
+ if (Lookup.second.hasExternalDecls() ||
+ NeedToReconcileExternalVisibleStorage) {
+ // We don't know for sure what declarations are found by this name,
+ // because the external source might have a different set from the set
+ // that are in the lookup map, and we can't update it now without
+ // risking invalidating our lookup iterator. So add it to a queue to
+ // deal with later.
+ ExternalNames.push_back(Lookup.first);
+ continue;
+ }
+
+ AddLookupResult(Lookup.first, Lookup.second.getLookupResult());
+ }
+
+ // Add the names we needed to defer. Note, this shouldn't add any new decls
+ // to the list we need to serialize: any new declarations we find here should
+ // be imported from an external source.
+ // FIXME: What if the external source isn't an ASTReader?
+ for (const auto &Name : ExternalNames)
+ AddLookupResult(Name, DC->lookup(Name));
+}
+
+void ASTWriter::AddUpdatedDeclContext(const DeclContext *DC) {
+ if (UpdatedDeclContexts.insert(DC) && WritingAST) {
+ // Ensure we emit all the visible declarations.
+ visitLocalLookupResults(DC, DC->NeedToReconcileExternalVisibleStorage,
+ [&](DeclarationName Name,
+ DeclContext::lookup_const_result Result) {
+ for (auto *Decl : Result)
+ GetDeclRef(Decl);
+ });
+ }
+}
+
+uint32_t
+ASTWriter::GenerateNameLookupTable(const DeclContext *DC,
+ llvm::SmallVectorImpl<char> &LookupTable) {
+ assert(!DC->LookupPtr.getInt() && "must call buildLookups first");
+
+ llvm::OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait>
+ Generator;
+ ASTDeclContextNameLookupTrait Trait(*this);
+
+ // Create the on-disk hash table representation.
+ DeclarationName ConstructorName;
+ DeclarationName ConversionName;
+ SmallVector<NamedDecl *, 8> ConstructorDecls;
+ SmallVector<NamedDecl *, 4> ConversionDecls;
+
+ visitLocalLookupResults(DC, DC->NeedToReconcileExternalVisibleStorage,
+ [&](DeclarationName Name,
+ DeclContext::lookup_result Result) {
+ if (Result.empty())
+ return;
+
+ // Different DeclarationName values of certain kinds are mapped to
+ // identical serialized keys, because we don't want to use type
+ // identifiers in the keys (since type ids are local to the module).
+ switch (Name.getNameKind()) {
+ case DeclarationName::CXXConstructorName:
+ // There may be different CXXConstructorName DeclarationName values
+ // in a DeclContext because a UsingDecl that inherits constructors
+ // has the DeclarationName of the inherited constructors.
+ if (!ConstructorName)
+ ConstructorName = Name;
+ ConstructorDecls.append(Result.begin(), Result.end());
+ return;
+
+ case DeclarationName::CXXConversionFunctionName:
+ if (!ConversionName)
+ ConversionName = Name;
+ ConversionDecls.append(Result.begin(), Result.end());
+ return;
+
+ default:
+ break;
+ }
+
+ Generator.insert(Name, Result, Trait);
+ });
+
+ // Add the constructors.
+ if (!ConstructorDecls.empty()) {
+ Generator.insert(ConstructorName,
+ DeclContext::lookup_result(ConstructorDecls.begin(),
+ ConstructorDecls.end()),
+ Trait);
+ }
+
+ // Add the conversion functions.
+ if (!ConversionDecls.empty()) {
+ Generator.insert(ConversionName,
+ DeclContext::lookup_result(ConversionDecls.begin(),
+ ConversionDecls.end()),
+ Trait);
+ }
+
+ // Create the on-disk hash table in a buffer.
+ llvm::raw_svector_ostream Out(LookupTable);
+ // Make sure that no bucket is at offset 0
+ using namespace llvm::support;
+ endian::Writer<little>(Out).write<uint32_t>(0);
+ return Generator.Emit(Out, Trait);
+}
+
/// \brief Write the block containing all of the declaration IDs
/// visible from the given DeclContext.
///
@@ -3407,50 +3636,9 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
if (!Map || Map->empty())
return 0;
- OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait> Generator;
- ASTDeclContextNameLookupTrait Trait(*this);
-
- // Create the on-disk hash table representation.
- DeclarationName ConversionName;
- SmallVector<NamedDecl *, 4> ConversionDecls;
- for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end();
- D != DEnd; ++D) {
- DeclarationName Name = D->first;
- DeclContext::lookup_result Result = D->second.getLookupResult();
- if (!Result.empty()) {
- if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
- // Hash all conversion function names to the same name. The actual
- // type information in conversion function name is not used in the
- // key (since such type information is not stable across different
- // modules), so the intended effect is to coalesce all of the conversion
- // functions under a single key.
- if (!ConversionName)
- ConversionName = Name;
- ConversionDecls.append(Result.begin(), Result.end());
- continue;
- }
-
- Generator.insert(Name, Result, Trait);
- }
- }
-
- // Add the conversion functions
- if (!ConversionDecls.empty()) {
- Generator.insert(ConversionName,
- DeclContext::lookup_result(ConversionDecls.begin(),
- ConversionDecls.end()),
- Trait);
- }
-
// Create the on-disk hash table in a buffer.
SmallString<4096> LookupTable;
- uint32_t BucketOffset;
- {
- llvm::raw_svector_ostream Out(LookupTable);
- // Make sure that no bucket is at offset 0
- clang::io::Emit32(Out, 0);
- BucketOffset = Generator.Emit(Out, Trait);
- }
+ uint32_t BucketOffset = GenerateNameLookupTable(DC, LookupTable);
// Write the lookup table
RecordData Record;
@@ -3471,33 +3659,13 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
/// (in C++), for namespaces, and for classes with forward-declared unscoped
/// enumeration members (in C++11).
void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) {
- StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(DC->getLookupPtr());
+ StoredDeclsMap *Map = DC->getLookupPtr();
if (!Map || Map->empty())
return;
- OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait> Generator;
- ASTDeclContextNameLookupTrait Trait(*this);
-
- // Create the hash table.
- for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end();
- D != DEnd; ++D) {
- DeclarationName Name = D->first;
- DeclContext::lookup_result Result = D->second.getLookupResult();
- // For any name that appears in this table, the results are complete, i.e.
- // they overwrite results from previous PCHs. Merging is always a mess.
- if (!Result.empty())
- Generator.insert(Name, Result, Trait);
- }
-
// Create the on-disk hash table in a buffer.
SmallString<4096> LookupTable;
- uint32_t BucketOffset;
- {
- llvm::raw_svector_ostream Out(LookupTable);
- // Make sure that no bucket is at offset 0
- clang::io::Emit32(Out, 0);
- BucketOffset = Generator.Emit(Out, Trait);
- }
+ uint32_t BucketOffset = GenerateNameLookupTable(DC, LookupTable);
// Write the lookup table
RecordData Record;
@@ -3667,7 +3835,7 @@ void ASTWriter::WriteMergedDecls() {
IEnd = Chain->MergedDecls.end();
I != IEnd; ++I) {
DeclID CanonID = I->first->isFromASTFile()? I->first->getGlobalID()
- : getDeclID(I->first);
+ : GetDeclRef(I->first);
assert(CanonID && "Merged declaration not known?");
Record.push_back(CanonID);
@@ -3701,6 +3869,14 @@ void ASTWriter::WriteLateParsedTemplates(Sema &SemaRef) {
Stream.EmitRecord(LATE_PARSED_TEMPLATE, Record);
}
+/// \brief Write the state of 'pragma clang optimize' at the end of the module.
+void ASTWriter::WriteOptimizePragmaOptions(Sema &SemaRef) {
+ RecordData Record;
+ SourceLocation PragmaLoc = SemaRef.getOptimizeOffPragmaLocation();
+ AddSourceLocation(PragmaLoc, Record);
+ Stream.EmitRecord(OPTIMIZE_PRAGMA_OPTIONS, Record);
+}
+
//===----------------------------------------------------------------------===//
// General Serialization Routines
//===----------------------------------------------------------------------===//
@@ -3774,8 +3950,8 @@ void ASTWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
}
ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
- : Stream(Stream), Context(0), PP(0), Chain(0), WritingModule(0),
- WritingAST(false), DoneWritingDeclsAndTypes(false),
+ : Stream(Stream), Context(nullptr), PP(nullptr), Chain(nullptr),
+ WritingModule(nullptr), WritingAST(false), DoneWritingDeclsAndTypes(false),
ASTHasCompilerErrors(false),
FirstDeclID(NUM_PREDEF_DECL_IDS), NextDeclID(FirstDeclID),
FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID),
@@ -3799,9 +3975,7 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
}
ASTWriter::~ASTWriter() {
- for (FileDeclIDsTy::iterator
- I = FileDeclIDs.begin(), E = FileDeclIDs.end(); I != E; ++I)
- delete I->second;
+ llvm::DeleteContainerSeconds(FileDeclIDs);
}
void ASTWriter::WriteAST(Sema &SemaRef,
@@ -3824,18 +3998,18 @@ void ASTWriter::WriteAST(Sema &SemaRef,
PP = &SemaRef.PP;
this->WritingModule = WritingModule;
WriteASTCore(SemaRef, isysroot, OutputFile, WritingModule);
- Context = 0;
- PP = 0;
- this->WritingModule = 0;
-
+ Context = nullptr;
+ PP = nullptr;
+ this->WritingModule = nullptr;
+
WritingAST = false;
}
template<typename Vector>
static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec,
ASTWriter::RecordData &Record) {
- for (typename Vector::iterator I = Vec.begin(0, true), E = Vec.end();
- I != E; ++I) {
+ for (typename Vector::iterator I = Vec.begin(nullptr, true), E = Vec.end();
+ I != E; ++I) {
Writer.AddDeclRef(*I, Record);
}
}
@@ -3846,7 +4020,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Module *WritingModule) {
using namespace llvm;
- bool isModule = WritingModule != 0;
+ bool isModule = WritingModule != nullptr;
// Make sure that the AST reader knows to finalize itself.
if (Chain)
@@ -3906,6 +4080,15 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
}
}
+ // If we saw any DeclContext updates before we started writing the AST file,
+ // make sure all visible decls in those DeclContexts are written out.
+ if (!UpdatedDeclContexts.empty()) {
+ auto OldUpdatedDeclContexts = std::move(UpdatedDeclContexts);
+ UpdatedDeclContexts.clear();
+ for (auto *DC : OldUpdatedDeclContexts)
+ AddUpdatedDeclContext(DC);
+ }
+
// Build a record containing all of the tentative definitions in this file, in
// TentativeDefinitions order. Generally, this record will be empty for
// headers.
@@ -4032,11 +4215,9 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
// translation unit that do not come from other AST files.
const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
SmallVector<KindDeclIDPair, 64> NewGlobalDecls;
- for (DeclContext::decl_iterator I = TU->noload_decls_begin(),
- E = TU->noload_decls_end();
- I != E; ++I) {
- if (!(*I)->isFromASTFile())
- NewGlobalDecls.push_back(std::make_pair((*I)->getKind(), GetDeclRef(*I)));
+ for (const auto *I : TU->noload_decls()) {
+ if (!I->isFromASTFile())
+ NewGlobalDecls.push_back(std::make_pair(I->getKind(), GetDeclRef(I)));
}
llvm::BitCodeAbbrev *Abv = new llvm::BitCodeAbbrev();
@@ -4059,14 +4240,25 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
// If the translation unit has an anonymous namespace, and we don't already
// have an update block for it, write it as an update block.
+ // FIXME: Why do we not do this if there's already an update block?
if (NamespaceDecl *NS = TU->getAnonymousNamespace()) {
ASTWriter::UpdateRecord &Record = DeclUpdates[TU];
- if (Record.empty()) {
- Record.push_back(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE);
- Record.push_back(reinterpret_cast<uint64_t>(NS));
- }
+ if (Record.empty())
+ Record.push_back(DeclUpdate(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, NS));
}
+ // Add update records for all mangling numbers and static local numbers.
+ // These aren't really update records, but this is a convenient way of
+ // tagging this rare extra data onto the declarations.
+ for (const auto &Number : Context.MangleNumbers)
+ if (!Number.first->isFromASTFile())
+ DeclUpdates[Number.first].push_back(DeclUpdate(UPD_MANGLING_NUMBER,
+ Number.second));
+ for (const auto &Number : Context.StaticLocalNumbers)
+ if (!Number.first->isFromASTFile())
+ DeclUpdates[Number.first].push_back(DeclUpdate(UPD_STATIC_LOCAL_NUMBER,
+ Number.second));
+
// Make sure visible decls, added to DeclContexts previously loaded from
// an AST file, are registered for serialization.
for (SmallVectorImpl<const Decl *>::iterator
@@ -4090,9 +4282,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
}
}
- // Resolve any declaration pointers within the declaration updates block.
- ResolveDeclUpdatesBlocks();
-
// Form the record of special types.
RecordData SpecialTypes;
AddTypeRef(Context.getRawCFConstantStringType(), SpecialTypes);
@@ -4104,30 +4293,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
AddTypeRef(Context.ObjCSelRedefinitionType, SpecialTypes);
AddTypeRef(Context.getucontext_tType(), SpecialTypes);
- // Keep writing types and declarations until all types and
- // declarations have been written.
- Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
- WriteDeclsBlockAbbrevs();
- for (DeclsToRewriteTy::iterator I = DeclsToRewrite.begin(),
- E = DeclsToRewrite.end();
- I != E; ++I)
- DeclTypesToEmit.push(const_cast<Decl*>(*I));
- while (!DeclTypesToEmit.empty()) {
- DeclOrType DOT = DeclTypesToEmit.front();
- DeclTypesToEmit.pop();
- if (DOT.isType())
- WriteType(DOT.getType());
- else
- WriteDecl(Context, DOT.getDecl());
- }
- Stream.ExitBlock();
-
- DoneWritingDeclsAndTypes = true;
-
- WriteFileDeclIDsMap();
- WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
- WriteComments();
-
if (Chain) {
// Write the mapping information describing our module dependencies and how
// each of those modules were mapped into our own offset/ID space, so that
@@ -4154,17 +4319,19 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
for (ModuleManager::ModuleConstIterator M = Chain->ModuleMgr.begin(),
MEnd = Chain->ModuleMgr.end();
M != MEnd; ++M) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
StringRef FileName = (*M)->FileName;
- io::Emit16(Out, FileName.size());
+ LE.write<uint16_t>(FileName.size());
Out.write(FileName.data(), FileName.size());
- io::Emit32(Out, (*M)->SLocEntryBaseOffset);
- io::Emit32(Out, (*M)->BaseIdentifierID);
- io::Emit32(Out, (*M)->BaseMacroID);
- io::Emit32(Out, (*M)->BasePreprocessedEntityID);
- io::Emit32(Out, (*M)->BaseSubmoduleID);
- io::Emit32(Out, (*M)->BaseSelectorID);
- io::Emit32(Out, (*M)->BaseDeclID);
- io::Emit32(Out, (*M)->BaseTypeIndex);
+ LE.write<uint32_t>((*M)->SLocEntryBaseOffset);
+ LE.write<uint32_t>((*M)->BaseIdentifierID);
+ LE.write<uint32_t>((*M)->BaseMacroID);
+ LE.write<uint32_t>((*M)->BasePreprocessedEntityID);
+ LE.write<uint32_t>((*M)->BaseSubmoduleID);
+ LE.write<uint32_t>((*M)->BaseSelectorID);
+ LE.write<uint32_t>((*M)->BaseDeclID);
+ LE.write<uint32_t>((*M)->BaseTypeIndex);
}
}
Record.clear();
@@ -4172,6 +4339,41 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record,
Buffer.data(), Buffer.size());
}
+
+ RecordData DeclUpdatesOffsetsRecord;
+
+ // Keep writing types, declarations, and declaration update records
+ // until we've emitted all of them.
+ Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
+ WriteDeclsBlockAbbrevs();
+ for (DeclsToRewriteTy::iterator I = DeclsToRewrite.begin(),
+ E = DeclsToRewrite.end();
+ I != E; ++I)
+ DeclTypesToEmit.push(const_cast<Decl*>(*I));
+ do {
+ WriteDeclUpdatesBlocks(DeclUpdatesOffsetsRecord);
+ while (!DeclTypesToEmit.empty()) {
+ DeclOrType DOT = DeclTypesToEmit.front();
+ DeclTypesToEmit.pop();
+ if (DOT.isType())
+ WriteType(DOT.getType());
+ else
+ WriteDecl(Context, DOT.getDecl());
+ }
+ } while (!DeclUpdates.empty());
+ Stream.ExitBlock();
+
+ DoneWritingDeclsAndTypes = true;
+
+ // These things can only be done once we've written out decls and types.
+ WriteTypeDeclOffsets();
+ if (!DeclUpdatesOffsetsRecord.empty())
+ Stream.EmitRecord(DECL_UPDATE_OFFSETS, DeclUpdatesOffsetsRecord);
+ WriteCXXBaseSpecifiersOffsets();
+ WriteFileDeclIDsMap();
+ WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
+
+ WriteComments();
WritePreprocessor(PP, isModule);
WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot);
WriteSelectors(SemaRef);
@@ -4179,12 +4381,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
WriteIdentifierTable(PP, SemaRef.IdResolver, isModule);
WriteFPPragmaOptions(SemaRef.getFPOptions());
WriteOpenCLExtensions(SemaRef);
-
- WriteTypeDeclOffsets();
WritePragmaDiagnosticMappings(Context.getDiagnostics(), isModule);
- WriteCXXBaseSpecifiersOffsets();
-
// If we're emitting a module, write out the submodule information.
if (WritingModule)
WriteSubmodules(WritingModule);
@@ -4192,8 +4390,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Stream.EmitRecord(SPECIAL_TYPES, SpecialTypes);
// Write the record containing external, unnamed definitions.
- if (!ExternalDefinitions.empty())
- Stream.EmitRecord(EXTERNAL_DEFINITIONS, ExternalDefinitions);
+ if (!EagerlyDeserializedDecls.empty())
+ Stream.EmitRecord(EAGERLY_DESERIALIZED_DECLS, EagerlyDeserializedDecls);
// Write the record containing tentative definitions.
if (!TentativeDefinitions.empty())
@@ -4250,40 +4448,53 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Stream.EmitRecord(UNDEFINED_BUT_USED, UndefinedButUsed);
// Write the visible updates to DeclContexts.
- for (llvm::SmallPtrSet<const DeclContext *, 16>::iterator
- I = UpdatedDeclContexts.begin(),
- E = UpdatedDeclContexts.end();
- I != E; ++I)
- WriteDeclContextVisibleUpdate(*I);
+ for (auto *DC : UpdatedDeclContexts)
+ WriteDeclContextVisibleUpdate(DC);
if (!WritingModule) {
// Write the submodules that were imported, if any.
- RecordData ImportedModules;
- for (ASTContext::import_iterator I = Context.local_import_begin(),
- IEnd = Context.local_import_end();
- I != IEnd; ++I) {
+ struct ModuleInfo {
+ uint64_t ID;
+ Module *M;
+ ModuleInfo(uint64_t ID, Module *M) : ID(ID), M(M) {}
+ };
+ llvm::SmallVector<ModuleInfo, 64> Imports;
+ for (const auto *I : Context.local_imports()) {
assert(SubmoduleIDs.find(I->getImportedModule()) != SubmoduleIDs.end());
- ImportedModules.push_back(SubmoduleIDs[I->getImportedModule()]);
+ Imports.push_back(ModuleInfo(SubmoduleIDs[I->getImportedModule()],
+ I->getImportedModule()));
}
- if (!ImportedModules.empty()) {
- // Sort module IDs.
- llvm::array_pod_sort(ImportedModules.begin(), ImportedModules.end());
-
- // Unique module IDs.
- ImportedModules.erase(std::unique(ImportedModules.begin(),
- ImportedModules.end()),
- ImportedModules.end());
-
+
+ if (!Imports.empty()) {
+ auto Cmp = [](const ModuleInfo &A, const ModuleInfo &B) {
+ return A.ID < B.ID;
+ };
+
+ // Sort and deduplicate module IDs.
+ std::sort(Imports.begin(), Imports.end(), Cmp);
+ Imports.erase(std::unique(Imports.begin(), Imports.end(), Cmp),
+ Imports.end());
+
+ RecordData ImportedModules;
+ for (const auto &Import : Imports) {
+ ImportedModules.push_back(Import.ID);
+ // FIXME: If the module has macros imported then later has declarations
+ // imported, this location won't be the right one as a location for the
+ // declaration imports.
+ AddSourceLocation(Import.M->MacroVisibilityLoc, ImportedModules);
+ }
+
Stream.EmitRecord(IMPORTED_MODULES, ImportedModules);
}
}
- WriteDeclUpdatesBlocks();
WriteDeclReplacementsBlock();
WriteRedeclarations();
WriteMergedDecls();
WriteObjCCategories();
WriteLateParsedTemplates(SemaRef);
+ if(!WritingModule)
+ WriteOptimizePragmaOptions(SemaRef);
// Some simple statistics
Record.clear();
@@ -4295,64 +4506,129 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Stream.ExitBlock();
}
-/// \brief Go through the declaration update blocks and resolve declaration
-/// pointers into declaration IDs.
-void ASTWriter::ResolveDeclUpdatesBlocks() {
- for (DeclUpdateMap::iterator
- I = DeclUpdates.begin(), E = DeclUpdates.end(); I != E; ++I) {
- const Decl *D = I->first;
- UpdateRecord &URec = I->second;
-
+void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
+ if (DeclUpdates.empty())
+ return;
+
+ DeclUpdateMap LocalUpdates;
+ LocalUpdates.swap(DeclUpdates);
+
+ for (auto &DeclUpdate : LocalUpdates) {
+ const Decl *D = DeclUpdate.first;
if (isRewritten(D))
- continue; // The decl will be written completely
+ continue; // The decl will be written completely,no need to store updates.
- unsigned Idx = 0, N = URec.size();
- while (Idx < N) {
- switch ((DeclUpdateKind)URec[Idx++]) {
+ bool HasUpdatedBody = false;
+ RecordData Record;
+ for (auto &Update : DeclUpdate.second) {
+ DeclUpdateKind Kind = (DeclUpdateKind)Update.getKind();
+
+ Record.push_back(Kind);
+ switch (Kind) {
case UPD_CXX_ADDED_IMPLICIT_MEMBER:
case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE:
- URec[Idx] = GetDeclRef(reinterpret_cast<Decl *>(URec[Idx]));
- ++Idx;
+ assert(Update.getDecl() && "no decl to add?");
+ Record.push_back(GetDeclRef(Update.getDecl()));
break;
case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
- case UPD_DECL_MARKED_USED:
- ++Idx;
+ AddSourceLocation(Update.getLoc(), Record);
+ break;
+
+ case UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION:
+ // An updated body is emitted last, so that the reader doesn't need
+ // to skip over the lazy body to reach statements for other records.
+ Record.pop_back();
+ HasUpdatedBody = true;
+ break;
+
+ case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: {
+ auto *RD = cast<CXXRecordDecl>(D);
+ AddUpdatedDeclContext(RD->getPrimaryContext());
+ AddCXXDefinitionData(RD, Record);
+ Record.push_back(WriteDeclContextLexicalBlock(
+ *Context, const_cast<CXXRecordDecl *>(RD)));
+
+ // This state is sometimes updated by template instantiation, when we
+ // switch from the specialization referring to the template declaration
+ // to it referring to the template definition.
+ if (auto *MSInfo = RD->getMemberSpecializationInfo()) {
+ Record.push_back(MSInfo->getTemplateSpecializationKind());
+ AddSourceLocation(MSInfo->getPointOfInstantiation(), Record);
+ } else {
+ auto *Spec = cast<ClassTemplateSpecializationDecl>(RD);
+ Record.push_back(Spec->getTemplateSpecializationKind());
+ AddSourceLocation(Spec->getPointOfInstantiation(), Record);
+
+ // The instantiation might have been resolved to a partial
+ // specialization. If so, record which one.
+ auto From = Spec->getInstantiatedFrom();
+ if (auto PartialSpec =
+ From.dyn_cast<ClassTemplatePartialSpecializationDecl*>()) {
+ Record.push_back(true);
+ AddDeclRef(PartialSpec, Record);
+ AddTemplateArgumentList(&Spec->getTemplateInstantiationArgs(),
+ Record);
+ } else {
+ Record.push_back(false);
+ }
+ }
+ Record.push_back(RD->getTagKind());
+ AddSourceLocation(RD->getLocation(), Record);
+ AddSourceLocation(RD->getLocStart(), Record);
+ AddSourceLocation(RD->getRBraceLoc(), Record);
+
+ // Instantiation may change attributes; write them all out afresh.
+ Record.push_back(D->hasAttrs());
+ if (Record.back())
+ WriteAttributes(ArrayRef<const Attr*>(D->getAttrs().begin(),
+ D->getAttrs().size()), Record);
+
+ // FIXME: Ensure we don't get here for explicit instantiations.
+ break;
+ }
+
+ case UPD_CXX_RESOLVED_EXCEPTION_SPEC:
+ addExceptionSpec(
+ *this,
+ cast<FunctionDecl>(D)->getType()->castAs<FunctionProtoType>(),
+ Record);
break;
case UPD_CXX_DEDUCED_RETURN_TYPE:
- URec[Idx] = GetOrCreateTypeID(
- QualType::getFromOpaquePtr(reinterpret_cast<void *>(URec[Idx])));
- ++Idx;
+ Record.push_back(GetOrCreateTypeID(Update.getType()));
+ break;
+
+ case UPD_DECL_MARKED_USED:
+ break;
+
+ case UPD_MANGLING_NUMBER:
+ case UPD_STATIC_LOCAL_NUMBER:
+ Record.push_back(Update.getNumber());
break;
}
}
- }
-}
-void ASTWriter::WriteDeclUpdatesBlocks() {
- if (DeclUpdates.empty())
- return;
+ if (HasUpdatedBody) {
+ const FunctionDecl *Def = cast<FunctionDecl>(D);
+ Record.push_back(UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION);
+ Record.push_back(Def->isInlined());
+ AddSourceLocation(Def->getInnerLocStart(), Record);
+ AddFunctionDefinition(Def, Record);
+ }
- RecordData OffsetsRecord;
- Stream.EnterSubblock(DECL_UPDATES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
- for (DeclUpdateMap::iterator
- I = DeclUpdates.begin(), E = DeclUpdates.end(); I != E; ++I) {
- const Decl *D = I->first;
- UpdateRecord &URec = I->second;
+ OffsetsRecord.push_back(GetDeclRef(D));
+ OffsetsRecord.push_back(Stream.GetCurrentBitNo());
- if (isRewritten(D))
- continue; // The decl will be written completely,no need to store updates.
+ Stream.EmitRecord(DECL_UPDATES, Record);
- uint64_t Offset = Stream.GetCurrentBitNo();
- Stream.EmitRecord(DECL_UPDATES, URec);
+ // Flush any statements that were written as part of this update record.
+ FlushStmts();
- OffsetsRecord.push_back(GetDeclRef(D));
- OffsetsRecord.push_back(Offset);
+ // Flush C++ base specifiers, if there are any.
+ FlushCXXBaseSpecifiers();
}
- Stream.ExitBlock();
- Stream.EmitRecord(DECL_UPDATE_OFFSETS, OffsetsRecord);
}
void ASTWriter::WriteDeclReplacementsBlock() {
@@ -4398,7 +4674,7 @@ void ASTWriter::AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Recor
}
IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) {
- if (II == 0)
+ if (!II)
return 0;
IdentID &ID = IdentifierIDs[II];
@@ -4411,7 +4687,7 @@ MacroID ASTWriter::getMacroRef(MacroInfo *MI, const IdentifierInfo *Name) {
// Don't emit builtin macros like __LINE__ to the AST file unless they
// have been redefined by the header (in which case they are not
// isBuiltinMacro).
- if (MI == 0 || MI->isBuiltinMacro())
+ if (!MI || MI->isBuiltinMacro())
return 0;
MacroID &ID = MacroIDs[MI];
@@ -4424,7 +4700,7 @@ MacroID ASTWriter::getMacroRef(MacroInfo *MI, const IdentifierInfo *Name) {
}
MacroID ASTWriter::getMacroID(MacroInfo *MI) {
- if (MI == 0 || MI->isBuiltinMacro())
+ if (!MI || MI->isBuiltinMacro())
return 0;
assert(MacroIDs.find(MI) != MacroIDs.end() && "Macro not emitted!");
@@ -4441,7 +4717,7 @@ void ASTWriter::AddSelectorRef(const Selector SelRef, RecordDataImpl &Record) {
}
SelectorID ASTWriter::getSelectorRef(Selector Sel) {
- if (Sel.getAsOpaquePtr() == 0) {
+ if (Sel.getAsOpaquePtr() == nullptr) {
return 0;
}
@@ -4519,7 +4795,7 @@ void ASTWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg,
void ASTWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo,
RecordDataImpl &Record) {
- if (TInfo == 0) {
+ if (!TInfo) {
AddTypeRef(QualType(), Record);
return;
}
@@ -4587,8 +4863,8 @@ void ASTWriter::AddDeclRef(const Decl *D, RecordDataImpl &Record) {
DeclID ASTWriter::GetDeclRef(const Decl *D) {
assert(WritingAST && "Cannot request a declaration ID before AST writing");
-
- if (D == 0) {
+
+ if (!D) {
return 0;
}
@@ -4615,7 +4891,7 @@ DeclID ASTWriter::GetDeclRef(const Decl *D) {
}
DeclID ASTWriter::getDeclID(const Decl *D) {
- if (D == 0)
+ if (!D)
return 0;
// If D comes from an AST file, its declaration ID is already known and
@@ -4648,7 +4924,7 @@ void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) {
assert(SM.isLocalSourceLocation(FileLoc));
FileID FID;
unsigned Offset;
- llvm::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc);
+ std::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc);
if (FID.isInvalid())
return;
assert(SM.getSLocEntry(FID).isFile());
@@ -4934,9 +5210,8 @@ void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg,
break;
case TemplateArgument::Pack:
Record.push_back(Arg.pack_size());
- for (TemplateArgument::pack_iterator I=Arg.pack_begin(), E=Arg.pack_end();
- I != E; ++I)
- AddTemplateArgument(*I, Record);
+ for (const auto &P : Arg.pack_elements())
+ AddTemplateArgument(P, Record);
break;
}
}
@@ -5068,8 +5343,7 @@ void ASTWriter::AddCXXCtorInitializers(
}
void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Record) {
- assert(D->DefinitionData);
- struct CXXRecordDecl::DefinitionData &Data = *D->DefinitionData;
+ auto &Data = D->data();
Record.push_back(Data.IsLambda);
Record.push_back(Data.UserDeclaredConstructor);
Record.push_back(Data.UserDeclaredSpecialMembers);
@@ -5084,6 +5358,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Data.HasProtectedFields);
Record.push_back(Data.HasPublicFields);
Record.push_back(Data.HasMutableFields);
+ Record.push_back(Data.HasVariantMembers);
Record.push_back(Data.HasOnlyCMembers);
Record.push_back(Data.HasInClassInitializer);
Record.push_back(Data.HasUninitializedReferenceMember);
@@ -5094,6 +5369,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Data.DefaultedMoveAssignmentIsDeleted);
Record.push_back(Data.DefaultedDestructorIsDeleted);
Record.push_back(Data.HasTrivialSpecialMembers);
+ Record.push_back(Data.DeclaredNonTrivialSpecialMembers);
Record.push_back(Data.HasIrrelevantDestructor);
Record.push_back(Data.HasConstexprNonCopyMoveConstructor);
Record.push_back(Data.DefaultedDefaultConstructorIsConstexpr);
@@ -5126,7 +5402,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
// Add lambda-specific data.
if (Data.IsLambda) {
- CXXRecordDecl::LambdaDefinitionData &Lambda = D->getLambdaData();
+ auto &Lambda = D->getLambdaData();
Record.push_back(Lambda.Dependent);
Record.push_back(Lambda.IsGenericLambda);
Record.push_back(Lambda.CaptureDefault);
@@ -5136,7 +5412,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
AddDeclRef(Lambda.ContextDecl, Record);
AddTypeSourceInfo(Lambda.MethodTyInfo, Record);
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
- LambdaExpr::Capture &Capture = Lambda.Captures[I];
+ const LambdaCapture &Capture = Lambda.Captures[I];
AddSourceLocation(Capture.getLocation(), Record);
Record.push_back(Capture.isImplicit());
Record.push_back(Capture.getCaptureKind());
@@ -5146,7 +5422,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
case LCK_ByCopy:
case LCK_ByRef:
VarDecl *Var =
- Capture.capturesVariable() ? Capture.getCapturedVar() : 0;
+ Capture.capturesVariable() ? Capture.getCapturedVar() : nullptr;
AddDeclRef(Var, Record);
AddSourceLocation(Capture.isPackExpansion() ? Capture.getEllipsisLoc()
: SourceLocation(),
@@ -5236,7 +5512,10 @@ void ASTWriter::CompletedTagDefinition(const TagDecl *D) {
// A forward reference was mutated into a definition. Rewrite it.
// FIXME: This happens during template instantiation, should we
// have created a new definition decl instead ?
- RewriteDecl(RD);
+ assert(isTemplateInstantiation(RD->getTemplateSpecializationKind()) &&
+ "completed a tag from another module but not by instantiation?");
+ DeclUpdates[RD].push_back(
+ DeclUpdate(UPD_CXX_INSTANTIATED_CLASS_DEFINITION));
}
}
}
@@ -5266,9 +5545,7 @@ void ASTWriter::AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) {
// A decl coming from PCH was modified.
assert(RD->isCompleteDefinition());
- UpdateRecord &Record = DeclUpdates[RD];
- Record.push_back(UPD_CXX_ADDED_IMPLICIT_MEMBER);
- Record.push_back(reinterpret_cast<uint64_t>(D));
+ DeclUpdates[RD].push_back(DeclUpdate(UPD_CXX_ADDED_IMPLICIT_MEMBER, D));
}
void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
@@ -5279,9 +5556,8 @@ void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD,
if (!(!D->isFromASTFile() && TD->isFromASTFile()))
return; // Not a source specialization added to a template from PCH.
- UpdateRecord &Record = DeclUpdates[TD];
- Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION);
- Record.push_back(reinterpret_cast<uint64_t>(D));
+ DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
+ D));
}
void ASTWriter::AddedCXXTemplateSpecialization(
@@ -5292,9 +5568,8 @@ void ASTWriter::AddedCXXTemplateSpecialization(
if (!(!D->isFromASTFile() && TD->isFromASTFile()))
return; // Not a source specialization added to a template from PCH.
- UpdateRecord &Record = DeclUpdates[TD];
- Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION);
- Record.push_back(reinterpret_cast<uint64_t>(D));
+ DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
+ D));
}
void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
@@ -5305,9 +5580,17 @@ void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
if (!(!D->isFromASTFile() && TD->isFromASTFile()))
return; // Not a source specialization added to a template from PCH.
- UpdateRecord &Record = DeclUpdates[TD];
- Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION);
- Record.push_back(reinterpret_cast<uint64_t>(D));
+ DeclUpdates[TD].push_back(DeclUpdate(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
+ D));
+}
+
+void ASTWriter::ResolvedExceptionSpec(const FunctionDecl *FD) {
+ assert(!WritingAST && "Already writing the AST!");
+ FD = FD->getCanonicalDecl();
+ if (!FD->isFromASTFile())
+ return; // Not a function declared in PCH and defined outside.
+
+ DeclUpdates[FD].push_back(UPD_CXX_RESOLVED_EXCEPTION_SPEC);
}
void ASTWriter::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) {
@@ -5316,9 +5599,7 @@ void ASTWriter::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) {
if (!FD->isFromASTFile())
return; // Not a function declared in PCH and defined outside.
- UpdateRecord &Record = DeclUpdates[FD];
- Record.push_back(UPD_CXX_DEDUCED_RETURN_TYPE);
- Record.push_back(reinterpret_cast<uint64_t>(ReturnType.getAsOpaquePtr()));
+ DeclUpdates[FD].push_back(DeclUpdate(UPD_CXX_DEDUCED_RETURN_TYPE, ReturnType));
}
void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) {
@@ -5331,6 +5612,17 @@ void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) {
RewriteDecl(D);
}
+void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) {
+ assert(!WritingAST && "Already writing the AST!");
+ if (!D->isFromASTFile())
+ return;
+
+ // Since the actual instantiation is delayed, this really means that we need
+ // to update the instantiation location.
+ DeclUpdates[D].push_back(
+ DeclUpdate(UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION));
+}
+
void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) {
assert(!WritingAST && "Already writing the AST!");
if (!D->isFromASTFile())
@@ -5338,10 +5630,9 @@ void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) {
// Since the actual instantiation is delayed, this really means that we need
// to update the instantiation location.
- UpdateRecord &Record = DeclUpdates[D];
- Record.push_back(UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER);
- AddSourceLocation(
- D->getMemberSpecializationInfo()->getPointOfInstantiation(), Record);
+ DeclUpdates[D].push_back(
+ DeclUpdate(UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER,
+ D->getMemberSpecializationInfo()->getPointOfInstantiation()));
}
void ASTWriter::AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
@@ -5375,6 +5666,5 @@ void ASTWriter::DeclarationMarkedUsed(const Decl *D) {
if (!D->isFromASTFile())
return;
- UpdateRecord &Record = DeclUpdates[D];
- Record.push_back(UPD_DECL_MARKED_USED);
+ DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_USED));
}
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 55f830a4badd..47ce747d5bd3 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -130,6 +130,14 @@ namespace clang {
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
+
+ void AddFunctionDefinition(const FunctionDecl *FD) {
+ assert(FD->doesThisDeclarationHaveABody());
+ if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
+ Writer.AddCXXCtorInitializers(CD->CtorInitializers,
+ CD->NumCtorInitializers, Record);
+ Writer.AddStmt(FD->getBody());
+ }
};
}
@@ -168,6 +176,24 @@ void ASTDeclWriter::VisitDecl(Decl *D) {
Record.push_back(D->getAccess());
Record.push_back(D->isModulePrivate());
Record.push_back(Writer.inferSubmoduleIDFromLocation(D->getLocation()));
+
+ // If this declaration injected a name into a context different from its
+ // lexical context, and that context is an imported namespace, we need to
+ // update its visible declarations to include this name.
+ //
+ // This happens when we instantiate a class with a friend declaration or a
+ // function with a local extern declaration, for instance.
+ if (D->isOutOfLine()) {
+ auto *DC = D->getDeclContext();
+ while (auto *NS = dyn_cast<NamespaceDecl>(DC->getRedeclContext())) {
+ if (!NS->isFromASTFile())
+ break;
+ Writer.AddUpdatedDeclContext(NS->getPrimaryContext());
+ if (!NS->isInlineNamespace())
+ break;
+ DC = NS->getParent();
+ }
+ }
}
void ASTDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
@@ -251,7 +277,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
Record.push_back(MemberInfo->getTemplateSpecializationKind());
Writer.AddSourceLocation(MemberInfo->getPointOfInstantiation(), Record);
} else {
- Writer.AddDeclRef(0, Record);
+ Writer.AddDeclRef(nullptr, Record);
}
if (!D->hasAttrs() &&
@@ -372,7 +398,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Writer.AddTemplateArgumentList(FTSInfo->TemplateArguments, Record);
// Template args as written.
- Record.push_back(FTSInfo->TemplateArgumentsAsWritten != 0);
+ Record.push_back(FTSInfo->TemplateArgumentsAsWritten != nullptr);
if (FTSInfo->TemplateArgumentsAsWritten) {
Record.push_back(FTSInfo->TemplateArgumentsAsWritten->NumTemplateArgs);
for (int i=0, e = FTSInfo->TemplateArgumentsAsWritten->NumTemplateArgs;
@@ -414,9 +440,8 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
}
Record.push_back(D->param_size());
- for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
- P != PEnd; ++P)
- Writer.AddDeclRef(*P, Record);
+ for (auto P : D->params())
+ Writer.AddDeclRef(P, Record);
Code = serialization::DECL_FUNCTION;
}
@@ -424,8 +449,8 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
VisitNamedDecl(D);
// FIXME: convert to LazyStmtPtr?
// Unlike C/C++, method bodies will never be in header files.
- bool HasBodyStuff = D->getBody() != 0 ||
- D->getSelfDecl() != 0 || D->getCmdDecl() != 0;
+ bool HasBodyStuff = D->getBody() != nullptr ||
+ D->getSelfDecl() != nullptr || D->getCmdDecl() != nullptr;
Record.push_back(HasBodyStuff);
if (HasBodyStuff) {
Writer.AddStmt(D->getBody());
@@ -451,13 +476,12 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
// FIXME: stable encoding for in/out/inout/bycopy/byref/oneway
Record.push_back(D->getObjCDeclQualifier());
Record.push_back(D->hasRelatedResultType());
- Writer.AddTypeRef(D->getResultType(), Record);
- Writer.AddTypeSourceInfo(D->getResultTypeSourceInfo(), Record);
+ Writer.AddTypeRef(D->getReturnType(), Record);
+ Writer.AddTypeSourceInfo(D->getReturnTypeSourceInfo(), Record);
Writer.AddSourceLocation(D->getLocEnd(), Record);
Record.push_back(D->param_size());
- for (ObjCMethodDecl::param_iterator P = D->param_begin(),
- PEnd = D->param_end(); P != PEnd; ++P)
- Writer.AddDeclRef(*P, Record);
+ for (const auto *P : D->params())
+ Writer.AddDeclRef(P, Record);
Record.push_back(D->SelLocsKind);
unsigned NumStoredSelLocs = D->getNumStoredSelLocs();
@@ -489,17 +513,14 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
Writer.AddDeclRef(D->getSuperClass(), Record);
Writer.AddSourceLocation(D->getSuperClassLoc(), Record);
Writer.AddSourceLocation(D->getEndOfDefinitionLoc(), Record);
+ Record.push_back(Data.HasDesignatedInitializers);
// Write out the protocols that are directly referenced by the @interface.
Record.push_back(Data.ReferencedProtocols.size());
- for (ObjCInterfaceDecl::protocol_iterator P = D->protocol_begin(),
- PEnd = D->protocol_end();
- P != PEnd; ++P)
- Writer.AddDeclRef(*P, Record);
- for (ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(),
- PLEnd = D->protocol_loc_end();
- PL != PLEnd; ++PL)
- Writer.AddSourceLocation(*PL, Record);
+ for (const auto *P : D->protocols())
+ Writer.AddDeclRef(P, Record);
+ for (const auto &PL : D->protocol_locs())
+ Writer.AddSourceLocation(PL, Record);
// Write out the protocols that are transitively referenced.
Record.push_back(Data.AllReferencedProtocols.size());
@@ -528,7 +549,6 @@ void ASTDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
// FIXME: stable encoding for @public/@private/@protected/@package
Record.push_back(D->getAccessControl());
Record.push_back(D->getSynthesize());
- Record.push_back(D->getBackingIvarReferencedInAccessor());
if (!D->hasAttrs() &&
!D->isImplicit() &&
@@ -551,13 +571,10 @@ void ASTDeclWriter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
Record.push_back(D->isThisDeclarationADefinition());
if (D->isThisDeclarationADefinition()) {
Record.push_back(D->protocol_size());
- for (ObjCProtocolDecl::protocol_iterator
- I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
- Writer.AddDeclRef(*I, Record);
- for (ObjCProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin(),
- PLEnd = D->protocol_loc_end();
- PL != PLEnd; ++PL)
- Writer.AddSourceLocation(*PL, Record);
+ for (const auto *I : D->protocols())
+ Writer.AddDeclRef(I, Record);
+ for (const auto &PL : D->protocol_locs())
+ Writer.AddSourceLocation(PL, Record);
}
Code = serialization::DECL_OBJC_PROTOCOL;
@@ -575,13 +592,10 @@ void ASTDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record);
Writer.AddDeclRef(D->getClassInterface(), Record);
Record.push_back(D->protocol_size());
- for (ObjCCategoryDecl::protocol_iterator
- I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
- Writer.AddDeclRef(*I, Record);
- for (ObjCCategoryDecl::protocol_loc_iterator
- PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end();
- PL != PLEnd; ++PL)
- Writer.AddSourceLocation(*PL, Record);
+ for (const auto *I : D->protocols())
+ Writer.AddDeclRef(I, Record);
+ for (const auto &PL : D->protocol_locs())
+ Writer.AddSourceLocation(PL, Record);
Code = serialization::DECL_OBJC_CATEGORY;
}
@@ -688,10 +702,8 @@ void ASTDeclWriter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
VisitValueDecl(D);
Record.push_back(D->getChainingSize());
- for (IndirectFieldDecl::chain_iterator
- P = D->chain_begin(),
- PEnd = D->chain_end(); P != PEnd; ++P)
- Writer.AddDeclRef(*P, Record);
+ for (const auto *P : D->chain())
+ Writer.AddDeclRef(P, Record);
Code = serialization::DECL_INDIRECTFIELD;
}
@@ -745,7 +757,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
!D->hasExtInfo() &&
D->getFirstDecl() == D->getMostRecentDecl() &&
D->getInitStyle() == VarDecl::CInit &&
- D->getInit() == 0 &&
+ D->getInit() == nullptr &&
!isa<ParmVarDecl>(D) &&
!isa<VarTemplateSpecializationDecl>(D) &&
!D->isConstexpr() &&
@@ -794,7 +806,7 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
D->getObjCDeclQualifier() == 0 &&
!D->isKNRPromoted() &&
!D->hasInheritedDefaultArg() &&
- D->getInit() == 0 &&
+ D->getInit() == nullptr &&
!D->hasUninstantiatedDefaultArg()) // No default expr.
AbbrevToUse = Writer.getDeclParmVarAbbrev();
@@ -803,7 +815,7 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
assert(!D->getTSCSpec() && "PARM_VAR_DECL can't use TLS");
assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private");
assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var");
- assert(D->getPreviousDecl() == 0 && "PARM_VAR_DECL can't be redecl");
+ assert(D->getPreviousDecl() == nullptr && "PARM_VAR_DECL can't be redecl");
assert(!D->isStaticDataMember() &&
"PARM_VAR_DECL can't be static data member");
}
@@ -833,9 +845,7 @@ void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) {
Record.push_back(D->isConversionFromLambda());
Record.push_back(D->capturesCXXThis());
Record.push_back(D->getNumCaptures());
- for (BlockDecl::capture_iterator
- i = D->capture_begin(), e = D->capture_end(); i != e; ++i) {
- const BlockDecl::Capture &capture = *i;
+ for (const auto &capture : D->captures()) {
Writer.AddDeclRef(capture.getVariable(), Record);
unsigned flags = 0;
@@ -853,9 +863,11 @@ void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) {
void ASTDeclWriter::VisitCapturedDecl(CapturedDecl *CD) {
Record.push_back(CD->getNumParams());
VisitDecl(CD);
+ Record.push_back(CD->getContextParamPosition());
+ Record.push_back(CD->isNothrow() ? 1 : 0);
// Body is stored by VisitCapturedStmt.
- for (unsigned i = 0; i < CD->getNumParams(); ++i)
- Writer.AddDeclRef(CD->getParam(i), Record);
+ for (unsigned I = 0; I < CD->getNumParams(); ++I)
+ Writer.AddDeclRef(CD->getParam(I), Record);
Code = serialization::DECL_CAPTURED;
}
@@ -911,9 +923,8 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
Decl *Parent = cast<Decl>(
D->getParent()->getRedeclContext()->getPrimaryContext());
if (Parent->isFromASTFile() || isa<TranslationUnitDecl>(Parent)) {
- ASTWriter::UpdateRecord &Record = Writer.DeclUpdates[Parent];
- Record.push_back(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE);
- Writer.AddDeclRef(D, Record);
+ Writer.DeclUpdates[Parent].push_back(
+ ASTWriter::DeclUpdate(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, D));
}
}
}
@@ -975,9 +986,6 @@ void ASTDeclWriter::VisitUnresolvedUsingTypenameDecl(
void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
VisitRecordDecl(D);
- Record.push_back(D->isThisDeclarationADefinition());
- if (D->isThisDeclarationADefinition())
- Writer.AddCXXDefinitionData(D, Record);
enum {
CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization
@@ -995,6 +1003,10 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
Record.push_back(CXXRecNotTemplate);
}
+ Record.push_back(D->isThisDeclarationADefinition());
+ if (D->isThisDeclarationADefinition())
+ Writer.AddCXXDefinitionData(D, Record);
+
// Store (what we currently believe to be) the key function to avoid
// deserializing every method so we can compute it.
if (D->IsCompleteDefinition)
@@ -1021,6 +1033,7 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
VisitCXXMethodDecl(D);
+ Writer.AddDeclRef(D->getInheritedConstructor(), Record);
Record.push_back(D->IsExplicitSpecified);
Writer.AddCXXCtorInitializers(D->CtorInitializers, D->NumCtorInitializers,
Record);
@@ -1091,7 +1104,7 @@ void ASTDeclWriter::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
Record.push_back(D->getNumTemplateParameters());
for (unsigned i = 0, e = D->getNumTemplateParameters(); i != e; ++i)
Writer.AddTemplateParameterList(D->getTemplateParameterList(i), Record);
- Record.push_back(D->getFriendDecl() != 0);
+ Record.push_back(D->getFriendDecl() != nullptr);
if (D->getFriendDecl())
Writer.AddDeclRef(D->getFriendDecl(), Record);
else
@@ -1143,8 +1156,6 @@ void ASTDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
assert(I->isCanonicalDecl() && "Expected only canonical decls in set");
Writer.AddDeclRef(&*I, Record);
}
-
- Writer.AddTypeRef(D->getCommonPtr()->InjectedClassNameType, Record);
}
Code = serialization::DECL_CLASS_TEMPLATE;
}
@@ -1192,7 +1203,7 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
Writer.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten(), Record);
// These are read/set from/to the first declaration.
- if (D->getPreviousDecl() == 0) {
+ if (D->getPreviousDecl() == nullptr) {
Writer.AddDeclRef(D->getInstantiatedFromMember(), Record);
Record.push_back(D->isMemberSpecialization());
}
@@ -1268,7 +1279,7 @@ void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
Writer.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten(), Record);
// These are read/set from/to the first declaration.
- if (D->getPreviousDecl() == 0) {
+ if (D->getPreviousDecl() == nullptr) {
Writer.AddDeclRef(D->getInstantiatedFromMember(), Record);
Record.push_back(D->isMemberSpecialization());
}
@@ -1335,7 +1346,7 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
} else {
// Rest of NonTypeTemplateParmDecl.
Record.push_back(D->isParameterPack());
- Record.push_back(D->getDefaultArgument() != 0);
+ Record.push_back(D->getDefaultArgument() != nullptr);
if (D->getDefaultArgument()) {
Writer.AddStmt(D->getDefaultArgument());
Record.push_back(D->defaultArgumentWasInherited());
@@ -1429,10 +1440,8 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
Record.push_back(D->varlist_size());
VisitDecl(D);
- for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
- E = D->varlist_end();
- I != E; ++I)
- Writer.AddStmt(*I);
+ for (auto *I : D->varlists())
+ Writer.AddStmt(I);
Code = serialization::DECL_OMP_THREADPRIVATE;
}
@@ -1506,8 +1515,6 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
// ObjC Ivar
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getAccessControl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getSynthesize
- // getBackingIvarReferencedInAccessor
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
// Type Source Info
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
@@ -1817,8 +1824,10 @@ static bool isRequiredDecl(const Decl *D, ASTContext &Context) {
// An ObjCMethodDecl is never considered as "required" because its
// implementation container always is.
- // File scoped assembly or obj-c implementation must be seen.
- if (isa<FileScopeAsmDecl>(D) || isa<ObjCImplDecl>(D))
+ // File scoped assembly or obj-c implementation must be seen. ImportDecl is
+ // used by codegen to determine the set of imported modules to search for
+ // inputs for automatic linking.
+ if (isa<FileScopeAsmDecl>(D) || isa<ObjCImplDecl>(D) || isa<ImportDecl>(D))
return true;
return Context.DeclMustBeEmitted(D);
@@ -1906,10 +1915,16 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
// Flush C++ base specifiers, if there are any.
FlushCXXBaseSpecifiers();
- // Note "external" declarations so that we can add them to a record in the
- // AST file later.
- //
- // FIXME: This should be renamed, the predicate is much more complicated.
+ // Note declarations that should be deserialized eagerly so that we can add
+ // them to a record in the AST file later.
if (isRequiredDecl(D, Context))
- ExternalDefinitions.push_back(ID);
+ EagerlyDeserializedDecls.push_back(ID);
+}
+
+void ASTWriter::AddFunctionDefinition(const FunctionDecl *FD,
+ RecordData &Record) {
+ ClearSwitchCaseIDs();
+
+ ASTDeclWriter W(*this, FD->getASTContext(), Record);
+ W.AddFunctionDefinition(FD);
}
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 072fc98e3910..a43b3527a711 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -71,9 +71,8 @@ void ASTStmtWriter::VisitNullStmt(NullStmt *S) {
void ASTStmtWriter::VisitCompoundStmt(CompoundStmt *S) {
VisitStmt(S);
Record.push_back(S->size());
- for (CompoundStmt::body_iterator CS = S->body_begin(), CSEnd = S->body_end();
- CS != CSEnd; ++CS)
- Writer.AddStmt(*CS);
+ for (auto *CS : S->body())
+ Writer.AddStmt(CS);
Writer.AddSourceLocation(S->getLBracLoc(), Record);
Writer.AddSourceLocation(S->getRBracLoc(), Record);
Code = serialization::STMT_COMPOUND;
@@ -300,24 +299,20 @@ void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {
Writer.AddDeclRef(S->getCapturedRecordDecl(), Record);
// Capture inits
- for (CapturedStmt::capture_init_iterator I = S->capture_init_begin(),
- E = S->capture_init_end();
- I != E; ++I)
- Writer.AddStmt(*I);
+ for (auto *I : S->capture_inits())
+ Writer.AddStmt(I);
// Body
Writer.AddStmt(S->getCapturedStmt());
// Captures
- for (CapturedStmt::capture_iterator I = S->capture_begin(),
- E = S->capture_end();
- I != E; ++I) {
- if (I->capturesThis())
- Writer.AddDeclRef(0, Record);
+ for (const auto &I : S->captures()) {
+ if (I.capturesThis())
+ Writer.AddDeclRef(nullptr, Record);
else
- Writer.AddDeclRef(I->getCapturedVar(), Record);
- Record.push_back(I->getCaptureKind());
- Writer.AddSourceLocation(I->getLocation(), Record);
+ Writer.AddDeclRef(I.getCapturedVar(), Record);
+ Record.push_back(I.getCaptureKind());
+ Writer.AddSourceLocation(I.getLocation(), Record);
}
Code = serialization::STMT_CAPTURED;
@@ -692,7 +687,7 @@ void ASTStmtWriter::VisitInitListExpr(InitListExpr *E) {
// Replace them by 0 to indicate that the filler goes in that place.
Expr *filler = E->getArrayFiller();
for (unsigned I = 0, N = E->getNumInits(); I != N; ++I)
- Writer.AddStmt(E->getInit(I) != filler ? E->getInit(I) : 0);
+ Writer.AddStmt(E->getInit(I) != filler ? E->getInit(I) : nullptr);
} else {
for (unsigned I = 0, N = E->getNumInits(); I != N; ++I)
Writer.AddStmt(E->getInit(I));
@@ -1056,7 +1051,7 @@ void ASTStmtWriter::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
void ASTStmtWriter::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
Record.push_back(S->getNumCatchStmts());
- Record.push_back(S->getFinallyStmt() != 0);
+ Record.push_back(S->getFinallyStmt() != nullptr);
Writer.AddStmt(S->getTryBody());
for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I)
Writer.AddStmt(S->getCatchStmt(I));
@@ -1155,6 +1150,7 @@ void ASTStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) {
Record.push_back(E->isElidable());
Record.push_back(E->hadMultipleCandidates());
Record.push_back(E->isListInitialization());
+ Record.push_back(E->isStdInitListInitialization());
Record.push_back(E->requiresZeroInitialization());
Record.push_back(E->getConstructionKind()); // FIXME: stable encoding
Writer.AddSourceRange(E->getParenOrBraceRange(), Record);
@@ -1402,7 +1398,7 @@ ASTStmtWriter::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){
if (!E->isImplicitAccess())
Writer.AddStmt(E->getBase());
else
- Writer.AddStmt(0);
+ Writer.AddStmt(nullptr);
Writer.AddTypeRef(E->getBaseType(), Record);
Record.push_back(E->isArrow());
Writer.AddSourceLocation(E->getOperatorLoc(), Record);
@@ -1472,7 +1468,7 @@ void ASTStmtWriter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
VisitOverloadExpr(E);
Record.push_back(E->isArrow());
Record.push_back(E->hasUnresolvedUsing());
- Writer.AddStmt(!E->isImplicitAccess() ? E->getBase() : 0);
+ Writer.AddStmt(!E->isImplicitAccess() ? E->getBase() : nullptr);
Writer.AddTypeRef(E->getBaseType(), Record);
Writer.AddSourceLocation(E->getOperatorLoc(), Record);
Code = serialization::EXPR_CXX_UNRESOLVED_MEMBER;
@@ -1486,30 +1482,12 @@ void ASTStmtWriter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
Code = serialization::EXPR_CXX_UNRESOLVED_LOOKUP;
}
-void ASTStmtWriter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
- VisitExpr(E);
- Record.push_back(E->getTrait());
- Record.push_back(E->getValue());
- Writer.AddSourceRange(E->getSourceRange(), Record);
- Writer.AddTypeSourceInfo(E->getQueriedTypeSourceInfo(), Record);
- Code = serialization::EXPR_CXX_UNARY_TYPE_TRAIT;
-}
-
-void ASTStmtWriter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
- VisitExpr(E);
- Record.push_back(E->getTrait());
- Record.push_back(E->getValue());
- Writer.AddSourceRange(E->getSourceRange(), Record);
- Writer.AddTypeSourceInfo(E->getLhsTypeSourceInfo(), Record);
- Writer.AddTypeSourceInfo(E->getRhsTypeSourceInfo(), Record);
- Code = serialization::EXPR_BINARY_TYPE_TRAIT;
-}
-
void ASTStmtWriter::VisitTypeTraitExpr(TypeTraitExpr *E) {
VisitExpr(E);
Record.push_back(E->TypeTraitExprBits.NumArgs);
Record.push_back(E->TypeTraitExprBits.Kind); // FIXME: Stable encoding
Record.push_back(E->TypeTraitExprBits.Value);
+ Writer.AddSourceRange(E->getSourceRange(), Record);
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
Writer.AddTypeSourceInfo(E->getArg(I), Record);
Code = serialization::EXPR_TYPE_TRAIT;
@@ -1590,8 +1568,9 @@ void ASTStmtWriter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
VisitExpr(E);
- Writer.AddStmt(E->Temporary);
- Writer.AddDeclRef(E->ExtendingDecl, Record);
+ Writer.AddStmt(E->getTemporary());
+ Writer.AddDeclRef(E->getExtendingDecl(), Record);
+ Record.push_back(E->getManglingNumber());
Code = serialization::EXPR_MATERIALIZE_TEMPORARY;
}
@@ -1672,6 +1651,12 @@ void ASTStmtWriter::VisitSEHTryStmt(SEHTryStmt *S) {
Code = serialization::STMT_SEH_TRY;
}
+void ASTStmtWriter::VisitSEHLeaveStmt(SEHLeaveStmt *S) {
+ VisitStmt(S);
+ Writer.AddSourceLocation(S->getLeaveLoc(), Record);
+ Code = serialization::STMT_SEH_LEAVE;
+}
+
//===----------------------------------------------------------------------===//
// OpenMP Clauses.
//===----------------------------------------------------------------------===//
@@ -1697,59 +1682,254 @@ void OMPClauseWriter::writeClause(OMPClause *C) {
Writer->Writer.AddSourceLocation(C->getLocEnd(), Record);
}
+void OMPClauseWriter::VisitOMPIfClause(OMPIfClause *C) {
+ Writer->Writer.AddStmt(C->getCondition());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPFinalClause(OMPFinalClause *C) {
+ Writer->Writer.AddStmt(C->getCondition());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) {
+ Writer->Writer.AddStmt(C->getNumThreads());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPSafelenClause(OMPSafelenClause *C) {
+ Writer->Writer.AddStmt(C->getSafelen());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPCollapseClause(OMPCollapseClause *C) {
+ Writer->Writer.AddStmt(C->getNumForLoops());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+}
+
void OMPClauseWriter::VisitOMPDefaultClause(OMPDefaultClause *C) {
Record.push_back(C->getDefaultKind());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
Writer->Writer.AddSourceLocation(C->getDefaultKindKwLoc(), Record);
}
+void OMPClauseWriter::VisitOMPProcBindClause(OMPProcBindClause *C) {
+ Record.push_back(C->getProcBindKind());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getProcBindKindKwLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPScheduleClause(OMPScheduleClause *C) {
+ Record.push_back(C->getScheduleKind());
+ Writer->Writer.AddStmt(C->getChunkSize());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getScheduleKindLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getCommaLoc(), Record);
+}
+
+void OMPClauseWriter::VisitOMPOrderedClause(OMPOrderedClause *) {}
+
+void OMPClauseWriter::VisitOMPNowaitClause(OMPNowaitClause *) {}
+
+void OMPClauseWriter::VisitOMPUntiedClause(OMPUntiedClause *) {}
+
+void OMPClauseWriter::VisitOMPMergeableClause(OMPMergeableClause *) {}
+
void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
- for (OMPPrivateClause::varlist_iterator I = C->varlist_begin(),
- E = C->varlist_end();
- I != E; ++I)
- Writer->Writer.AddStmt(*I);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
}
void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
- for (OMPFirstprivateClause::varlist_iterator I = C->varlist_begin(),
- E = C->varlist_end();
- I != E; ++I)
- Writer->Writer.AddStmt(*I);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+}
+
+void OMPClauseWriter::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
}
void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
- for (OMPSharedClause::varlist_iterator I = C->varlist_begin(),
- E = C->varlist_end();
- I != E; ++I)
- Writer->Writer.AddStmt(*I);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+}
+
+void OMPClauseWriter::VisitOMPReductionClause(OMPReductionClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getColonLoc(), Record);
+ Writer->Writer.AddNestedNameSpecifierLoc(C->getQualifierLoc(), Record);
+ Writer->Writer.AddDeclarationNameInfo(C->getNameInfo(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+}
+
+void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getColonLoc(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+ Writer->Writer.AddStmt(C->getStep());
+}
+
+void OMPClauseWriter::VisitOMPAlignedClause(OMPAlignedClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getColonLoc(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+ Writer->Writer.AddStmt(C->getAlignment());
+}
+
+void OMPClauseWriter::VisitOMPCopyinClause(OMPCopyinClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+}
+
+void OMPClauseWriter::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+}
+
+void OMPClauseWriter::VisitOMPFlushClause(OMPFlushClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
}
//===----------------------------------------------------------------------===//
// OpenMP Directives.
//===----------------------------------------------------------------------===//
void ASTStmtWriter::VisitOMPExecutableDirective(OMPExecutableDirective *E) {
- VisitStmt(E);
- Record.push_back(E->getNumClauses());
Writer.AddSourceLocation(E->getLocStart(), Record);
Writer.AddSourceLocation(E->getLocEnd(), Record);
OMPClauseWriter ClauseWriter(this, Record);
for (unsigned i = 0; i < E->getNumClauses(); ++i) {
ClauseWriter.writeClause(E->getClause(i));
}
- Writer.AddStmt(E->getAssociatedStmt());
+ if (E->hasAssociatedStmt())
+ Writer.AddStmt(E->getAssociatedStmt());
}
void ASTStmtWriter::VisitOMPParallelDirective(OMPParallelDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
VisitOMPExecutableDirective(D);
Code = serialization::STMT_OMP_PARALLEL_DIRECTIVE;
}
+void ASTStmtWriter::VisitOMPSimdDirective(OMPSimdDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ Record.push_back(D->getCollapsedNumber());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_SIMD_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPForDirective(OMPForDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ Record.push_back(D->getCollapsedNumber());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_FOR_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPSectionsDirective(OMPSectionsDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_SECTIONS_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPSectionDirective(OMPSectionDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_SECTION_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPSingleDirective(OMPSingleDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_SINGLE_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPMasterDirective(OMPMasterDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_MASTER_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPCriticalDirective(OMPCriticalDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ Writer.AddDeclarationNameInfo(D->getDirectiveName(), Record);
+ Code = serialization::STMT_OMP_CRITICAL_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPParallelForDirective(OMPParallelForDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ Record.push_back(D->getCollapsedNumber());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_PARALLEL_FOR_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPParallelSectionsDirective(
+ OMPParallelSectionsDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_PARALLEL_SECTIONS_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPTaskDirective(OMPTaskDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_TASK_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPTaskyieldDirective(OMPTaskyieldDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_TASKYIELD_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPBarrierDirective(OMPBarrierDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_BARRIER_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
+ VisitStmt(D);
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_TASKWAIT_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPFlushDirective(OMPFlushDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_FLUSH_DIRECTIVE;
+}
+
//===----------------------------------------------------------------------===//
// ASTWriter Implementation
//===----------------------------------------------------------------------===//
@@ -1812,7 +1992,7 @@ void ASTWriter::WriteSubStmt(Stmt *S,
ParentStmtInserterRAII ParentStmtInserter(S, ParentStmts);
#endif
- // Redirect ASTWriter::AddStmt to collect sub stmts.
+ // Redirect ASTWriter::AddStmt to collect sub-stmts.
SmallVector<Stmt *, 16> SubStmts;
CollectedStmts = &SubStmts;
@@ -1825,16 +2005,16 @@ void ASTWriter::WriteSubStmt(Stmt *S,
SourceManager &SrcMgr
= DeclIDs.begin()->first->getASTContext().getSourceManager();
S->dump(SrcMgr);
- llvm_unreachable("Unhandled sub statement writing AST file");
+ llvm_unreachable("Unhandled sub-statement writing AST file");
}
#endif
// Revert ASTWriter::AddStmt.
CollectedStmts = &StmtsToEmit;
- // Write the sub stmts in reverse order, last to first. When reading them back
+ // Write the sub-stmts in reverse order, last to first. When reading them back
// we will read them in correct order by "pop"ing them from the Stmts stack.
- // This simplifies reading and allows to store a variable number of sub stmts
+ // This simplifies reading and allows to store a variable number of sub-stmts
// without knowing it in advance.
while (!SubStmts.empty())
WriteSubStmt(SubStmts.pop_back_val(), SubStmtEntries, ParentStmts);
@@ -1851,7 +2031,7 @@ void ASTWriter::FlushStmts() {
// We expect to be the only consumer of the two temporary statement maps,
// assert that they are empty.
- assert(SubStmtEntries.empty() && "unexpected entries in sub stmt map");
+ assert(SubStmtEntries.empty() && "unexpected entries in sub-stmt map");
assert(ParentStmts.empty() && "unexpected entries in parent stmt map");
for (unsigned I = 0, N = StmtsToEmit.size(); I != N; ++I) {
diff --git a/lib/Serialization/CMakeLists.txt b/lib/Serialization/CMakeLists.txt
index 3c68b64625e9..d885db22975e 100644
--- a/lib/Serialization/CMakeLists.txt
+++ b/lib/Serialization/CMakeLists.txt
@@ -1,8 +1,10 @@
-set(LLVM_LINK_COMPONENTS bitreader)
+set(LLVM_LINK_COMPONENTS
+ BitReader
+ Support
+ )
+
add_clang_library(clangSerialization
- ASTCommon.h
- ASTReaderInternals.h
ASTCommon.cpp
ASTReader.cpp
ASTReaderDecl.cpp
@@ -14,23 +16,14 @@ add_clang_library(clangSerialization
GlobalModuleIndex.cpp
Module.cpp
ModuleManager.cpp
- )
-add_dependencies(clangSerialization
- ClangAttrClasses
- ClangAttrList
- ClangAttrParsedAttrList
- ClangAttrPCHRead
- ClangAttrPCHWrite
- ClangCommentNodes
- ClangDeclNodes
- ClangDiagnosticCommon
- ClangDiagnosticLex
- ClangDiagnosticSema
- ClangDiagnosticSerialization
- ClangStmtNodes
- )
+ ADDITIONAL_HEADERS
+ ASTCommon.h
+ ASTReaderInternals.h
-target_link_libraries(clangSerialization
+ LINK_LIBS
+ clangAST
+ clangBasic
+ clangLex
clangSema
)
diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp
index 7e8baa2c1095..b5031fdf92a4 100644
--- a/lib/Serialization/GeneratePCH.cpp
+++ b/lib/Serialization/GeneratePCH.cpp
@@ -31,7 +31,7 @@ PCHGenerator::PCHGenerator(const Preprocessor &PP,
raw_ostream *OS, bool AllowASTWithErrors)
: PP(PP), OutputFile(OutputFile), Module(Module),
isysroot(isysroot.str()), Out(OS),
- SemaPtr(0), Stream(Buffer), Writer(Stream),
+ SemaPtr(nullptr), Stream(Buffer), Writer(Stream),
AllowASTWithErrors(AllowASTWithErrors),
HasEmittedPCH(false) {
}
diff --git a/lib/Serialization/GlobalModuleIndex.cpp b/lib/Serialization/GlobalModuleIndex.cpp
index fb647b0be9bc..985812232505 100644
--- a/lib/Serialization/GlobalModuleIndex.cpp
+++ b/lib/Serialization/GlobalModuleIndex.cpp
@@ -13,7 +13,7 @@
#include "ASTReaderInternals.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Lex/HeaderSearch.h"
#include "clang/Serialization/ASTBitCodes.h"
#include "clang/Serialization/GlobalModuleIndex.h"
#include "clang/Serialization/Module.h"
@@ -26,6 +26,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/LockFileManager.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/OnDiskHashTable.h"
#include "llvm/Support/Path.h"
#include <cstdio>
using namespace clang;
@@ -71,20 +72,22 @@ public:
typedef StringRef external_key_type;
typedef StringRef internal_key_type;
typedef SmallVector<unsigned, 2> data_type;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
static bool EqualKey(const internal_key_type& a, const internal_key_type& b) {
return a == b;
}
- static unsigned ComputeHash(const internal_key_type& a) {
+ static hash_value_type ComputeHash(const internal_key_type& a) {
return llvm::HashString(a);
}
static std::pair<unsigned, unsigned>
ReadKeyDataLength(const unsigned char*& d) {
- using namespace clang::io;
- unsigned KeyLen = ReadUnalignedLE16(d);
- unsigned DataLen = ReadUnalignedLE16(d);
+ using namespace llvm::support;
+ unsigned KeyLen = endian::readNext<uint16_t, little, unaligned>(d);
+ unsigned DataLen = endian::readNext<uint16_t, little, unaligned>(d);
return std::make_pair(KeyLen, DataLen);
}
@@ -101,11 +104,11 @@ public:
static data_type ReadData(const internal_key_type& k,
const unsigned char* d,
unsigned DataLen) {
- using namespace clang::io;
+ using namespace llvm::support;
data_type Result;
while (DataLen > 0) {
- unsigned ID = ReadUnalignedLE32(d);
+ unsigned ID = endian::readNext<uint32_t, little, unaligned>(d);
Result.push_back(ID);
DataLen -= 4;
}
@@ -114,7 +117,8 @@ public:
}
};
-typedef OnDiskChainedHashTable<IdentifierIndexReaderTrait> IdentifierIndexTable;
+typedef llvm::OnDiskIterableChainedHashTable<IdentifierIndexReaderTrait>
+ IdentifierIndexTable;
}
@@ -202,7 +206,12 @@ GlobalModuleIndex::GlobalModuleIndex(llvm::MemoryBuffer *Buffer,
assert(Idx == Record.size() && "More module info?");
// Record this module as an unresolved module.
- UnresolvedModules[llvm::sys::path::stem(Modules[ID].FileName)] = ID;
+ // FIXME: this doesn't work correctly for module names containing path
+ // separators.
+ StringRef ModuleName = llvm::sys::path::stem(Modules[ID].FileName);
+ // Remove the -<hash of ModuleMapPath>
+ ModuleName = ModuleName.rsplit('-').first;
+ UnresolvedModules[ModuleName] = ID;
break;
}
@@ -210,16 +219,18 @@ GlobalModuleIndex::GlobalModuleIndex(llvm::MemoryBuffer *Buffer,
// Wire up the identifier index.
if (Record[0]) {
IdentifierIndex = IdentifierIndexTable::Create(
- (const unsigned char *)Blob.data() + Record[0],
- (const unsigned char *)Blob.data(),
- IdentifierIndexReaderTrait());
+ (const unsigned char *)Blob.data() + Record[0],
+ (const unsigned char *)Blob.data() + sizeof(uint32_t),
+ (const unsigned char *)Blob.data(), IdentifierIndexReaderTrait());
}
break;
}
}
}
-GlobalModuleIndex::~GlobalModuleIndex() { }
+GlobalModuleIndex::~GlobalModuleIndex() {
+ delete static_cast<IdentifierIndexTable *>(IdentifierIndex);
+}
std::pair<GlobalModuleIndex *, GlobalModuleIndex::ErrorCode>
GlobalModuleIndex::readIndex(StringRef Path) {
@@ -228,10 +239,11 @@ GlobalModuleIndex::readIndex(StringRef Path) {
IndexPath += Path;
llvm::sys::path::append(IndexPath, IndexFileName);
- llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
- if (llvm::MemoryBuffer::getFile(IndexPath.c_str(), Buffer) !=
- llvm::errc::success)
- return std::make_pair((GlobalModuleIndex *)0, EC_NotFound);
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferOrErr =
+ llvm::MemoryBuffer::getFile(IndexPath.c_str());
+ if (!BufferOrErr)
+ return std::make_pair(nullptr, EC_NotFound);
+ std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(BufferOrErr.get());
/// \brief The bitstream reader from which we'll read the AST file.
llvm::BitstreamReader Reader((const unsigned char *)Buffer->getBufferStart(),
@@ -245,10 +257,11 @@ GlobalModuleIndex::readIndex(StringRef Path) {
Cursor.Read(8) != 'C' ||
Cursor.Read(8) != 'G' ||
Cursor.Read(8) != 'I') {
- return std::make_pair((GlobalModuleIndex *)0, EC_IOError);
+ return std::make_pair(nullptr, EC_IOError);
}
-
- return std::make_pair(new GlobalModuleIndex(Buffer.take(), Cursor), EC_None);
+
+ return std::make_pair(new GlobalModuleIndex(Buffer.release(), Cursor),
+ EC_None);
}
void
@@ -306,7 +319,7 @@ bool GlobalModuleIndex::lookupIdentifier(StringRef Name, HitSet &Hits) {
bool GlobalModuleIndex::loadedModuleFile(ModuleFile *File) {
// Look for the module in the global module index based on the module name.
- StringRef Name = llvm::sys::path::stem(File->FileName);
+ StringRef Name = File->ModuleName;
llvm::StringMap<unsigned>::iterator Known = UnresolvedModules.find(Name);
if (Known == UnresolvedModules.end()) {
return true;
@@ -341,6 +354,19 @@ void GlobalModuleIndex::printStats() {
std::fprintf(stderr, "\n");
}
+void GlobalModuleIndex::dump() {
+ llvm::errs() << "*** Global Module Index Dump:\n";
+ llvm::errs() << "Module files:\n";
+ for (auto &MI : Modules) {
+ llvm::errs() << "** " << MI.FileName << "\n";
+ if (MI.File)
+ MI.File->dump();
+ else
+ llvm::errs() << "\n";
+ }
+ llvm::errs() << "\n";
+}
+
//----------------------------------------------------------------------------//
// Global module index writer.
//----------------------------------------------------------------------------//
@@ -411,7 +437,7 @@ static void emitBlockID(unsigned ID, const char *Name,
Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
// Emit the block name if present.
- if (Name == 0 || Name[0] == 0) return;
+ if (!Name || Name[0] == 0) return;
Record.clear();
while (*Name)
Record.push_back(*Name++);
@@ -458,8 +484,8 @@ namespace {
unsigned DataLen) {
// The first bit indicates whether this identifier is interesting.
// That's all we care about.
- using namespace clang::io;
- unsigned RawID = ReadUnalignedLE32(d);
+ using namespace llvm::support;
+ unsigned RawID = endian::readNext<uint32_t, little, unaligned>(d);
bool IsInteresting = RawID & 0x01;
return std::make_pair(k, IsInteresting);
}
@@ -468,7 +494,7 @@ namespace {
bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
// Open the module file.
- OwningPtr<llvm::MemoryBuffer> Buffer;
+ std::unique_ptr<llvm::MemoryBuffer> Buffer;
std::string ErrorStr;
Buffer.reset(FileMgr.getBufferForFile(File, &ErrorStr, /*isVolatile=*/true));
if (!Buffer) {
@@ -590,12 +616,13 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
// Handle the identifier table
if (State == ASTBlock && Code == IDENTIFIER_TABLE && Record[0] > 0) {
- typedef OnDiskChainedHashTable<InterestingASTIdentifierLookupTrait>
- InterestingIdentifierTable;
- llvm::OwningPtr<InterestingIdentifierTable>
- Table(InterestingIdentifierTable::Create(
- (const unsigned char *)Blob.data() + Record[0],
- (const unsigned char *)Blob.data()));
+ typedef llvm::OnDiskIterableChainedHashTable<
+ InterestingASTIdentifierLookupTrait> InterestingIdentifierTable;
+ std::unique_ptr<InterestingIdentifierTable> Table(
+ InterestingIdentifierTable::Create(
+ (const unsigned char *)Blob.data() + Record[0],
+ (const unsigned char *)Blob.data() + sizeof(uint32_t),
+ (const unsigned char *)Blob.data()));
for (InterestingIdentifierTable::data_iterator D = Table->data_begin(),
DEnd = Table->data_end();
D != DEnd; ++D) {
@@ -623,17 +650,21 @@ public:
typedef StringRef key_type_ref;
typedef SmallVector<unsigned, 2> data_type;
typedef const SmallVector<unsigned, 2> &data_type_ref;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
- static unsigned ComputeHash(key_type_ref Key) {
+ static hash_value_type ComputeHash(key_type_ref Key) {
return llvm::HashString(Key);
}
std::pair<unsigned,unsigned>
EmitKeyDataLength(raw_ostream& Out, key_type_ref Key, data_type_ref Data) {
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
unsigned KeyLen = Key.size();
unsigned DataLen = Data.size() * 4;
- clang::io::Emit16(Out, KeyLen);
- clang::io::Emit16(Out, DataLen);
+ LE.write<uint16_t>(KeyLen);
+ LE.write<uint16_t>(DataLen);
return std::make_pair(KeyLen, DataLen);
}
@@ -643,8 +674,9 @@ public:
void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data,
unsigned DataLen) {
+ using namespace llvm::support;
for (unsigned I = 0, N = Data.size(); I != N; ++I)
- clang::io::Emit32(Out, Data[I]);
+ endian::Writer<little>(Out).write<uint32_t>(Data[I]);
}
};
@@ -692,7 +724,7 @@ void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
// Write the identifier -> module file mapping.
{
- OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait> Generator;
+ llvm::OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait> Generator;
IdentifierIndexWriterTrait Trait;
// Populate the hash table.
@@ -706,9 +738,10 @@ void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
SmallString<4096> IdentifierTable;
uint32_t BucketOffset;
{
+ using namespace llvm::support;
llvm::raw_svector_ostream Out(IdentifierTable);
// Make sure that no bucket is at offset 0
- clang::io::Emit32(Out, 0);
+ endian::Writer<little>(Out).write<uint32_t>(0);
BucketOffset = Generator.Emit(Out, Trait);
}
@@ -756,7 +789,7 @@ GlobalModuleIndex::writeIndex(FileManager &FileMgr, StringRef Path) {
GlobalModuleIndexBuilder Builder(FileMgr);
// Load each of the module files.
- llvm::error_code EC;
+ std::error_code EC;
for (llvm::sys::fs::directory_iterator D(Path, EC), DEnd;
D != DEnd && !EC;
D.increment(EC)) {
@@ -807,13 +840,12 @@ GlobalModuleIndex::writeIndex(FileManager &FileMgr, StringRef Path) {
return EC_IOError;
// Remove the old index file. It isn't relevant any more.
- bool OldIndexExisted;
- llvm::sys::fs::remove(IndexPath.str(), OldIndexExisted);
+ llvm::sys::fs::remove(IndexPath.str());
// Rename the newly-written index file to the proper name.
if (llvm::sys::fs::rename(IndexTmpPath.str(), IndexPath.str())) {
// Rename failed; just remove the
- llvm::sys::fs::remove(IndexTmpPath.str(), OldIndexExisted);
+ llvm::sys::fs::remove(IndexTmpPath.str());
return EC_IOError;
}
@@ -835,7 +867,7 @@ namespace {
End = Idx.key_end();
}
- virtual StringRef Next() {
+ StringRef Next() override {
if (Current == End)
return StringRef();
diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp
index 2eb397176a12..6f2a3c220430 100644
--- a/lib/Serialization/Module.cpp
+++ b/lib/Serialization/Module.cpp
@@ -21,27 +21,27 @@ using namespace serialization;
using namespace reader;
ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation)
- : Kind(Kind), File(0), DirectlyImported(false),
+ : Kind(Kind), File(nullptr), DirectlyImported(false),
Generation(Generation), SizeInBits(0),
LocalNumSLocEntries(0), SLocEntryBaseID(0),
- SLocEntryBaseOffset(0), SLocEntryOffsets(0),
+ SLocEntryBaseOffset(0), SLocEntryOffsets(nullptr),
LocalNumIdentifiers(0),
- IdentifierOffsets(0), BaseIdentifierID(0), IdentifierTableData(0),
- IdentifierLookupTable(0),
- LocalNumMacros(0), MacroOffsets(0),
+ IdentifierOffsets(nullptr), BaseIdentifierID(0),
+ IdentifierTableData(nullptr), IdentifierLookupTable(nullptr),
+ LocalNumMacros(0), MacroOffsets(nullptr),
BasePreprocessedEntityID(0),
- PreprocessedEntityOffsets(0), NumPreprocessedEntities(0),
+ PreprocessedEntityOffsets(nullptr), NumPreprocessedEntities(0),
LocalNumHeaderFileInfos(0),
- HeaderFileInfoTableData(0), HeaderFileInfoTable(0),
+ HeaderFileInfoTableData(nullptr), HeaderFileInfoTable(nullptr),
LocalNumSubmodules(0), BaseSubmoduleID(0),
- LocalNumSelectors(0), SelectorOffsets(0), BaseSelectorID(0),
- SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0),
- DeclOffsets(0), BaseDeclID(0),
- LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0),
- FileSortedDecls(0), NumFileSortedDecls(0),
- RedeclarationsMap(0), LocalNumRedeclarationsInMap(0),
- ObjCCategoriesMap(0), LocalNumObjCCategoriesInMap(0),
- LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0)
+ LocalNumSelectors(0), SelectorOffsets(nullptr), BaseSelectorID(0),
+ SelectorLookupTableData(nullptr), SelectorLookupTable(nullptr),
+ LocalNumDecls(0), DeclOffsets(nullptr), BaseDeclID(0),
+ LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(nullptr),
+ FileSortedDecls(nullptr), NumFileSortedDecls(0),
+ RedeclarationsMap(nullptr), LocalNumRedeclarationsInMap(0),
+ ObjCCategoriesMap(nullptr), LocalNumObjCCategoriesInMap(0),
+ LocalNumTypes(0), TypeOffsets(nullptr), BaseTypeIndex(0)
{}
ModuleFile::~ModuleFile() {
diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp
index 9c4b3d92befe..2c10c119a07b 100644
--- a/lib/Serialization/ModuleManager.cpp
+++ b/lib/Serialization/ModuleManager.cpp
@@ -11,13 +11,14 @@
// modules for the ASTReader.
//
//===----------------------------------------------------------------------===//
+#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/ModuleMap.h"
#include "clang/Serialization/GlobalModuleIndex.h"
#include "clang/Serialization/ModuleManager.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/system_error.h"
+#include <system_error>
#ifndef NDEBUG
#include "llvm/Support/GraphWriter.h"
@@ -32,14 +33,14 @@ ModuleFile *ModuleManager::lookup(StringRef Name) {
if (Entry)
return lookup(Entry);
- return 0;
+ return nullptr;
}
ModuleFile *ModuleManager::lookup(const FileEntry *File) {
llvm::DenseMap<const FileEntry *, ModuleFile *>::iterator Known
= Modules.find(File);
if (Known == Modules.end())
- return 0;
+ return nullptr;
return Known->second;
}
@@ -57,7 +58,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
off_t ExpectedSize, time_t ExpectedModTime,
ModuleFile *&Module,
std::string &ErrorStr) {
- Module = 0;
+ Module = nullptr;
// Look for the file entry. This only fails if the expected size or
// modification time differ.
@@ -86,6 +87,16 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
NewModule = true;
ModuleEntry = New;
+ New->InputFilesValidationTimestamp = 0;
+ if (New->Kind == MK_Module) {
+ std::string TimestampFilename = New->getTimestampFilename();
+ vfs::Status Status;
+ // A cached stat value would be fine as well.
+ if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status))
+ New->InputFilesValidationTimestamp =
+ Status.getLastModificationTime().toEpochTime();
+ }
+
// Load the contents of the module
if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) {
// The buffer was already provided for us.
@@ -93,13 +104,24 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
New->Buffer.reset(Buffer);
} else {
// Open the AST file.
- llvm::error_code ec;
+ std::error_code ec;
if (FileName == "-") {
- ec = llvm::MemoryBuffer::getSTDIN(New->Buffer);
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf =
+ llvm::MemoryBuffer::getSTDIN();
+ ec = Buf.getError();
if (ec)
ErrorStr = ec.message();
- } else
- New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr));
+ else
+ New->Buffer = std::move(Buf.get());
+ } else {
+ // Leave the FileEntry open so if it gets read again by another
+ // ModuleManager it must be the same underlying file.
+ // FIXME: Because FileManager::getFile() doesn't guarantee that it will
+ // give us an open file, this may not be 100% reliable.
+ New->Buffer.reset(FileMgr.getBufferForFile(New->File, &ErrorStr,
+ /*IsVolatile*/false,
+ /*ShouldClose*/false));
+ }
if (!New->Buffer)
return Missing;
@@ -124,24 +146,10 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
return NewModule? NewlyLoaded : AlreadyLoaded;
}
-namespace {
- /// \brief Predicate that checks whether a module file occurs within
- /// the given set.
- class IsInModuleFileSet : public std::unary_function<ModuleFile *, bool> {
- llvm::SmallPtrSet<ModuleFile *, 4> &Removed;
-
- public:
- IsInModuleFileSet(llvm::SmallPtrSet<ModuleFile *, 4> &Removed)
- : Removed(Removed) { }
-
- bool operator()(ModuleFile *MF) const {
- return Removed.count(MF);
- }
- };
-}
-
-void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last,
- ModuleMap *modMap) {
+void ModuleManager::removeModules(
+ ModuleIterator first, ModuleIterator last,
+ llvm::SmallPtrSetImpl<ModuleFile *> &LoadedSuccessfully,
+ ModuleMap *modMap) {
if (first == last)
return;
@@ -149,22 +157,29 @@ void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last,
llvm::SmallPtrSet<ModuleFile *, 4> victimSet(first, last);
// Remove any references to the now-destroyed modules.
- IsInModuleFileSet checkInSet(victimSet);
for (unsigned i = 0, n = Chain.size(); i != n; ++i) {
- Chain[i]->ImportedBy.remove_if(checkInSet);
+ Chain[i]->ImportedBy.remove_if([&](ModuleFile *MF) {
+ return victimSet.count(MF);
+ });
}
// Delete the modules and erase them from the various structures.
for (ModuleIterator victim = first; victim != last; ++victim) {
Modules.erase((*victim)->File);
- FileMgr.invalidateCache((*victim)->File);
if (modMap) {
- StringRef ModuleName = llvm::sys::path::stem((*victim)->FileName);
+ StringRef ModuleName = (*victim)->ModuleName;
if (Module *mod = modMap->findModule(ModuleName)) {
- mod->setASTFile(0);
+ mod->setASTFile(nullptr);
}
}
+
+ // Files that didn't make it through ReadASTCore successfully will be
+ // rebuilt (or there was an error). Invalidate them so that we can load the
+ // new files that will be renamed over the old ones.
+ if (LoadedSuccessfully.count(*victim) == 0)
+ FileMgr.invalidateCache((*victim)->File);
+
delete *victim;
}
@@ -185,7 +200,7 @@ ModuleManager::VisitState *ModuleManager::allocateVisitState() {
if (FirstVisitState) {
VisitState *Result = FirstVisitState;
FirstVisitState = FirstVisitState->NextState;
- Result->NextState = 0;
+ Result->NextState = nullptr;
return Result;
}
@@ -194,7 +209,7 @@ ModuleManager::VisitState *ModuleManager::allocateVisitState() {
}
void ModuleManager::returnVisitState(VisitState *State) {
- assert(State->NextState == 0 && "Visited state is in list?");
+ assert(State->NextState == nullptr && "Visited state is in list?");
State->NextState = FirstVisitState;
FirstVisitState = State;
}
@@ -223,7 +238,7 @@ void ModuleManager::moduleFileAccepted(ModuleFile *MF) {
}
ModuleManager::ModuleManager(FileManager &FileMgr)
- : FileMgr(FileMgr), GlobalIndex(), FirstVisitState(0) { }
+ : FileMgr(FileMgr), GlobalIndex(), FirstVisitState(nullptr) {}
ModuleManager::~ModuleManager() {
for (unsigned i = 0, e = Chain.size(); i != e; ++i)
@@ -283,7 +298,7 @@ ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
assert(VisitOrder.size() == N && "Visitation order is wrong?");
delete FirstVisitState;
- FirstVisitState = 0;
+ FirstVisitState = nullptr;
}
VisitState *State = allocateVisitState();
@@ -385,16 +400,19 @@ bool ModuleManager::lookupModuleFile(StringRef FileName,
off_t ExpectedSize,
time_t ExpectedModTime,
const FileEntry *&File) {
- File = FileMgr.getFile(FileName, /*openFile=*/false, /*cacheFailure=*/false);
+ // Open the file immediately to ensure there is no race between stat'ing and
+ // opening the file.
+ File = FileMgr.getFile(FileName, /*openFile=*/true, /*cacheFailure=*/false);
if (!File && FileName != "-") {
return false;
}
if ((ExpectedSize && ExpectedSize != File->getSize()) ||
- (ExpectedModTime && ExpectedModTime != File->getModificationTime())) {
+ (ExpectedModTime && ExpectedModTime != File->getModificationTime()))
+ // Do not destroy File, as it may be referenced. If we need to rebuild it,
+ // it will be destroyed by removeModules.
return true;
- }
return false;
}
@@ -434,7 +452,7 @@ namespace llvm {
}
std::string getNodeLabel(ModuleFile *M, const ModuleManager&) {
- return llvm::sys::path::stem(M->FileName);
+ return M->ModuleName;
}
};
}
diff --git a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
index 9af0a5ac4fd5..166471aaa1a6 100644
--- a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
@@ -8,8 +8,6 @@
//===----------------------------------------------------------------------===//
// This file reports various statistics about analyzer visitation.
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "StatsChecker"
-
#include "ClangSACheckers.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/SourceManager.h"
@@ -26,6 +24,8 @@
using namespace clang;
using namespace ento;
+#define DEBUG_TYPE "StatsChecker"
+
STATISTIC(NumBlocks,
"The # of blocks in top level functions");
STATISTIC(NumBlocksUnreachable,
@@ -41,7 +41,7 @@ public:
void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
BugReporter &B,
ExprEngine &Eng) const {
- const CFG *C = 0;
+ const CFG *C = nullptr;
const SourceManager &SM = B.getSourceManager();
llvm::SmallPtrSet<const CFGBlock*, 256> reachable;
@@ -112,7 +112,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
<< " | Empty WorkList: "
<< (Eng.hasEmptyWorkList() ? "yes" : "no");
- B.EmitBasicReport(D, "Analyzer Statistics", "Internal Statistics",
+ B.EmitBasicReport(D, this, "Analyzer Statistics", "Internal Statistics",
output.str(), PathDiagnosticLocation(D, SM));
// Emit warning for each block we bailed out on.
@@ -129,7 +129,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
outputI << "(" << NameOfRootFunction << ")" <<
": The analyzer generated a sink at this point";
B.EmitBasicReport(
- D, "Sink Point", "Internal Statistics", outputI.str(),
+ D, this, "Sink Point", "Internal Statistics", outputI.str(),
PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC));
}
}
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
index 312bc749b181..cb5b01009f1d 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
@@ -25,7 +25,8 @@ using namespace ento;
namespace {
class ArrayBoundChecker :
public Checker<check::Location> {
- mutable OwningPtr<BuiltinBug> BT;
+ mutable std::unique_ptr<BuiltinBug> BT;
+
public:
void checkLocation(SVal l, bool isLoad, const Stmt* S,
CheckerContext &C) const;
@@ -66,8 +67,9 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
return;
if (!BT)
- BT.reset(new BuiltinBug("Out-of-bound array access",
- "Access out-of-bound array element (buffer overflow)"));
+ BT.reset(new BuiltinBug(
+ this, "Out-of-bound array access",
+ "Access out-of-bound array element (buffer overflow)"));
// FIXME: It would be nice to eventually make this diagnostic more clear,
// e.g., by referencing the original declaration or by saying *why* this
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index 5e4b824df4b9..20360efccfe4 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -28,8 +28,8 @@ using namespace ento;
namespace {
class ArrayBoundCheckerV2 :
public Checker<check::Location> {
- mutable OwningPtr<BuiltinBug> BT;
-
+ mutable std::unique_ptr<BuiltinBug> BT;
+
enum OOB_Kind { OOB_Precedes, OOB_Excedes, OOB_Tainted };
void reportOOB(CheckerContext &C, ProgramStateRef errorState,
@@ -45,9 +45,9 @@ class RegionRawOffsetV2 {
private:
const SubRegion *baseRegion;
SVal byteOffset;
-
+
RegionRawOffsetV2()
- : baseRegion(0), byteOffset(UnknownVal()) {}
+ : baseRegion(nullptr), byteOffset(UnknownVal()) {}
public:
RegionRawOffsetV2(const SubRegion* base, SVal offset)
@@ -120,7 +120,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
return;
ProgramStateRef state_precedesLowerBound, state_withinLowerBound;
- llvm::tie(state_precedesLowerBound, state_withinLowerBound) =
+ std::tie(state_precedesLowerBound, state_withinLowerBound) =
state->assume(*lowerBoundToCheck);
// Are we constrained enough to definitely precede the lower bound?
@@ -152,7 +152,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
break;
ProgramStateRef state_exceedsUpperBound, state_withinUpperBound;
- llvm::tie(state_exceedsUpperBound, state_withinUpperBound) =
+ std::tie(state_exceedsUpperBound, state_withinUpperBound) =
state->assume(*upperboundToCheck);
// If we are under constrained and the index variables are tainted, report.
@@ -187,7 +187,7 @@ void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext,
return;
if (!BT)
- BT.reset(new BuiltinBug("Out-of-bound access"));
+ BT.reset(new BuiltinBug(this, "Out-of-bound access"));
// FIXME: This diagnostics are preliminary. We should get far better
// diagnostics for explaining buffer overruns.
@@ -311,7 +311,6 @@ RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(ProgramStateRef state,
return RegionRawOffsetV2();
}
-
void ento::registerArrayBoundCheckerV2(CheckerManager &mgr) {
mgr.registerChecker<ArrayBoundCheckerV2>();
}
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index f66f8b75ed38..3fd55760bc5f 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "SelectorExtras.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
@@ -39,7 +40,8 @@ using namespace ento;
namespace {
class APIMisuse : public BugType {
public:
- APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
+ APIMisuse(const CheckerBase *checker, const char *name)
+ : BugType(checker, name, "API Misuse (Apple)") {}
};
} // end anonymous namespace
@@ -94,7 +96,19 @@ namespace {
class NilArgChecker : public Checker<check::PreObjCMessage,
check::PostStmt<ObjCDictionaryLiteral>,
check::PostStmt<ObjCArrayLiteral> > {
- mutable OwningPtr<APIMisuse> BT;
+ mutable std::unique_ptr<APIMisuse> BT;
+
+ mutable llvm::SmallDenseMap<Selector, unsigned, 16> StringSelectors;
+ mutable Selector ArrayWithObjectSel;
+ mutable Selector AddObjectSel;
+ mutable Selector InsertObjectAtIndexSel;
+ mutable Selector ReplaceObjectAtIndexWithObjectSel;
+ mutable Selector SetObjectAtIndexedSubscriptSel;
+ mutable Selector ArrayByAddingObjectSel;
+ mutable Selector DictionaryWithObjectForKeySel;
+ mutable Selector SetObjectForKeySel;
+ mutable Selector SetObjectForKeyedSubscriptSel;
+ mutable Selector RemoveObjectForKeySel;
void warnIfNilExpr(const Expr *E,
const char *Msg,
@@ -170,10 +184,13 @@ void NilArgChecker::warnIfNilArg(CheckerContext &C,
assert(Arg == 1);
os << "Key argument ";
}
- os << "to '" << msg.getSelector().getAsString() << "' cannot be nil";
+ os << "to '";
+ msg.getSelector().print(os);
+ os << "' cannot be nil";
} else {
- os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
- << msg.getSelector().getAsString() << "' cannot be nil";
+ os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '";
+ msg.getSelector().print(os);
+ os << "' cannot be nil";
}
}
@@ -188,7 +205,7 @@ void NilArgChecker::generateBugReport(ExplodedNode *N,
const Expr *E,
CheckerContext &C) const {
if (!BT)
- BT.reset(new APIMisuse("nil argument"));
+ BT.reset(new APIMisuse(this, "nil argument"));
BugReport *R = new BugReport(*BT, Msg, N);
R->addRange(Range);
@@ -210,50 +227,62 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
if (Class == FC_NSString) {
Selector S = msg.getSelector();
-
+
if (S.isUnarySelector())
return;
-
- // FIXME: This is going to be really slow doing these checks with
- // lexical comparisons.
-
- std::string NameStr = S.getAsString();
- StringRef Name(NameStr);
- assert(!Name.empty());
-
- // FIXME: Checking for initWithFormat: will not work in most cases
- // yet because [NSString alloc] returns id, not NSString*. We will
- // need support for tracking expected-type information in the analyzer
- // to find these errors.
- if (Name == "caseInsensitiveCompare:" ||
- Name == "compare:" ||
- Name == "compare:options:" ||
- Name == "compare:options:range:" ||
- Name == "compare:options:range:locale:" ||
- Name == "componentsSeparatedByCharactersInSet:" ||
- Name == "initWithFormat:") {
- Arg = 0;
+
+ if (StringSelectors.empty()) {
+ ASTContext &Ctx = C.getASTContext();
+ Selector Sels[] = {
+ getKeywordSelector(Ctx, "caseInsensitiveCompare", nullptr),
+ getKeywordSelector(Ctx, "compare", nullptr),
+ getKeywordSelector(Ctx, "compare", "options", nullptr),
+ getKeywordSelector(Ctx, "compare", "options", "range", nullptr),
+ getKeywordSelector(Ctx, "compare", "options", "range", "locale",
+ nullptr),
+ getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet",
+ nullptr),
+ getKeywordSelector(Ctx, "initWithFormat",
+ nullptr),
+ getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare", nullptr),
+ getKeywordSelector(Ctx, "localizedCompare", nullptr),
+ getKeywordSelector(Ctx, "localizedStandardCompare", nullptr),
+ };
+ for (Selector KnownSel : Sels)
+ StringSelectors[KnownSel] = 0;
}
+ auto I = StringSelectors.find(S);
+ if (I == StringSelectors.end())
+ return;
+ Arg = I->second;
} else if (Class == FC_NSArray) {
Selector S = msg.getSelector();
if (S.isUnarySelector())
return;
- if (S.getNameForSlot(0).equals("addObject")) {
- Arg = 0;
- } else if (S.getNameForSlot(0).equals("insertObject") &&
- S.getNameForSlot(1).equals("atIndex")) {
+ if (ArrayWithObjectSel.isNull()) {
+ ASTContext &Ctx = C.getASTContext();
+ ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject", nullptr);
+ AddObjectSel = getKeywordSelector(Ctx, "addObject", nullptr);
+ InsertObjectAtIndexSel =
+ getKeywordSelector(Ctx, "insertObject", "atIndex", nullptr);
+ ReplaceObjectAtIndexWithObjectSel =
+ getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject", nullptr);
+ SetObjectAtIndexedSubscriptSel =
+ getKeywordSelector(Ctx, "setObject", "atIndexedSubscript", nullptr);
+ ArrayByAddingObjectSel =
+ getKeywordSelector(Ctx, "arrayByAddingObject", nullptr);
+ }
+
+ if (S == ArrayWithObjectSel || S == AddObjectSel ||
+ S == InsertObjectAtIndexSel || S == ArrayByAddingObjectSel) {
Arg = 0;
- } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") &&
- S.getNameForSlot(1).equals("withObject")) {
- Arg = 1;
- } else if (S.getNameForSlot(0).equals("setObject") &&
- S.getNameForSlot(1).equals("atIndexedSubscript")) {
+ } else if (S == SetObjectAtIndexedSubscriptSel) {
Arg = 0;
CanBeSubscript = true;
- } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) {
- Arg = 0;
+ } else if (S == ReplaceObjectAtIndexWithObjectSel) {
+ Arg = 1;
}
} else if (Class == FC_NSDictionary) {
Selector S = msg.getSelector();
@@ -261,20 +290,26 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
if (S.isUnarySelector())
return;
- if (S.getNameForSlot(0).equals("dictionaryWithObject") &&
- S.getNameForSlot(1).equals("forKey")) {
- Arg = 0;
- warnIfNilArg(C, msg, /* Arg */1, Class);
- } else if (S.getNameForSlot(0).equals("setObject") &&
- S.getNameForSlot(1).equals("forKey")) {
+ if (DictionaryWithObjectForKeySel.isNull()) {
+ ASTContext &Ctx = C.getASTContext();
+ DictionaryWithObjectForKeySel =
+ getKeywordSelector(Ctx, "dictionaryWithObject", "forKey", nullptr);
+ SetObjectForKeySel =
+ getKeywordSelector(Ctx, "setObject", "forKey", nullptr);
+ SetObjectForKeyedSubscriptSel =
+ getKeywordSelector(Ctx, "setObject", "forKeyedSubscript", nullptr);
+ RemoveObjectForKeySel =
+ getKeywordSelector(Ctx, "removeObjectForKey", nullptr);
+ }
+
+ if (S == DictionaryWithObjectForKeySel || S == SetObjectForKeySel) {
Arg = 0;
warnIfNilArg(C, msg, /* Arg */1, Class);
- } else if (S.getNameForSlot(0).equals("setObject") &&
- S.getNameForSlot(1).equals("forKeyedSubscript")) {
+ } else if (S == SetObjectForKeyedSubscriptSel) {
CanBeSubscript = true;
Arg = 0;
warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
- } else if (S.getNameForSlot(0).equals("removeObjectForKey")) {
+ } else if (S == RemoveObjectForKeySel) {
Arg = 0;
}
}
@@ -282,7 +317,6 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
// If argument is '0', report a warning.
if ((Arg != InvalidArgIndex))
warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
-
}
void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
@@ -309,10 +343,10 @@ void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
namespace {
class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > {
- mutable OwningPtr<APIMisuse> BT;
+ mutable std::unique_ptr<APIMisuse> BT;
mutable IdentifierInfo* II;
public:
- CFNumberCreateChecker() : II(0) {}
+ CFNumberCreateChecker() : II(nullptr) {}
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
@@ -480,8 +514,8 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
<< " bits of the input integer will be lost.";
if (!BT)
- BT.reset(new APIMisuse("Bad use of CFNumberCreate"));
-
+ BT.reset(new APIMisuse(this, "Bad use of CFNumberCreate"));
+
BugReport *report = new BugReport(*BT, os.str(), N);
report->addRange(CE->getArg(2)->getSourceRange());
C.emitReport(report);
@@ -489,15 +523,17 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
}
//===----------------------------------------------------------------------===//
-// CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
+// CFRetain/CFRelease/CFMakeCollectable/CFAutorelease checking for null arguments.
//===----------------------------------------------------------------------===//
namespace {
class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
- mutable OwningPtr<APIMisuse> BT;
- mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
+ mutable std::unique_ptr<APIMisuse> BT;
+ mutable IdentifierInfo *Retain, *Release, *MakeCollectable, *Autorelease;
public:
- CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {}
+ CFRetainReleaseChecker()
+ : Retain(nullptr), Release(nullptr), MakeCollectable(nullptr),
+ Autorelease(nullptr) {}
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
};
} // end anonymous namespace
@@ -519,13 +555,15 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
Retain = &Ctx.Idents.get("CFRetain");
Release = &Ctx.Idents.get("CFRelease");
MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
- BT.reset(
- new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable"));
+ Autorelease = &Ctx.Idents.get("CFAutorelease");
+ BT.reset(new APIMisuse(
+ this, "null passed to CF memory management function"));
}
- // Check if we called CFRetain/CFRelease/CFMakeCollectable.
+ // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
const IdentifierInfo *FuncII = FD->getIdentifier();
- if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
+ if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable ||
+ FuncII == Autorelease))
return;
// FIXME: The rest of this just checks that the argument is non-null.
@@ -548,7 +586,7 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
// Are they equal?
ProgramStateRef stateTrue, stateFalse;
- llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
+ std::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
if (stateTrue && !stateFalse) {
ExplodedNode *N = C.generateSink(stateTrue);
@@ -562,6 +600,8 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
description = "Null pointer argument in call to CFRelease";
else if (FuncII == MakeCollectable)
description = "Null pointer argument in call to CFMakeCollectable";
+ else if (FuncII == Autorelease)
+ description = "Null pointer argument in call to CFAutorelease";
else
llvm_unreachable("impossible case");
@@ -586,7 +626,7 @@ class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
mutable Selector retainS;
mutable Selector autoreleaseS;
mutable Selector drainS;
- mutable OwningPtr<BugType> BT;
+ mutable std::unique_ptr<BugType> BT;
public:
void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
@@ -597,9 +637,9 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
CheckerContext &C) const {
if (!BT) {
- BT.reset(new APIMisuse("message incorrectly sent to class instead of class "
- "instance"));
-
+ BT.reset(new APIMisuse(
+ this, "message incorrectly sent to class instead of class instance"));
+
ASTContext &Ctx = C.getASTContext();
releaseS = GetNullarySelector("release", Ctx);
retainS = GetNullarySelector("retain", Ctx);
@@ -620,7 +660,9 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
- os << "The '" << S.getAsString() << "' message should be sent to instances "
+ os << "The '";
+ S.print(os);
+ os << "' message should be sent to instances "
"of class '" << Class->getName()
<< "' and not the class directly";
@@ -643,7 +685,7 @@ class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
mutable Selector orderedSetWithObjectsS;
mutable Selector initWithObjectsS;
mutable Selector initWithObjectsAndKeysS;
- mutable OwningPtr<BugType> BT;
+ mutable std::unique_ptr<BugType> BT;
bool isVariadicMessage(const ObjCMethodCall &msg) const;
@@ -703,7 +745,8 @@ VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
CheckerContext &C) const {
if (!BT) {
- BT.reset(new APIMisuse("Arguments passed to variadic method aren't all "
+ BT.reset(new APIMisuse(this,
+ "Arguments passed to variadic method aren't all "
"Objective-C pointer types"));
ASTContext &Ctx = C.getASTContext();
@@ -733,8 +776,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
// Verify that all arguments have Objective-C types.
Optional<ExplodedNode*> errorNode;
- ProgramStateRef state = C.getState();
-
+
for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
QualType ArgTy = msg.getArgExpr(I)->getType();
if (ArgTy->isObjCObjectPointerType())
@@ -772,8 +814,8 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
else
os << "Argument to method '";
- os << msg.getSelector().getAsString()
- << "' should be an Objective-C pointer type, not '";
+ msg.getSelector().print(os);
+ os << "' should be an Objective-C pointer type, not '";
ArgTy.print(os, C.getLangOpts());
os << "'";
@@ -804,7 +846,7 @@ class ObjCLoopChecker
CheckerContext &C) const;
public:
- ObjCLoopChecker() : CountSelectorII(0) {}
+ ObjCLoopChecker() : CountSelectorII(nullptr) {}
void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
@@ -844,7 +886,7 @@ static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
ProgramStateRef State,
const ObjCForCollectionStmt *FCS) {
if (!State)
- return NULL;
+ return nullptr;
SVal CollectionVal = C.getSVal(FCS->getCollection());
Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
@@ -852,10 +894,10 @@ static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
return State;
ProgramStateRef StNonNil, StNil;
- llvm::tie(StNonNil, StNil) = State->assume(*KnownCollection);
+ std::tie(StNonNil, StNil) = State->assume(*KnownCollection);
if (StNil && !StNonNil) {
// The collection is nil. This path is infeasible.
- return NULL;
+ return nullptr;
}
return StNonNil;
@@ -869,7 +911,7 @@ static ProgramStateRef checkElementNonNil(CheckerContext &C,
ProgramStateRef State,
const ObjCForCollectionStmt *FCS) {
if (!State)
- return NULL;
+ return nullptr;
// See if the collection is one where we /know/ the elements are non-nil.
if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
@@ -882,7 +924,7 @@ static ProgramStateRef checkElementNonNil(CheckerContext &C,
Optional<Loc> ElementLoc;
if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
- assert(ElemDecl->getInit() == 0);
+ assert(ElemDecl->getInit() == nullptr);
ElementLoc = State->getLValue(ElemDecl, LCtx);
} else {
ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
@@ -909,7 +951,7 @@ assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
if (!KnownNonEmpty)
return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
- return (Assumption == *KnownNonEmpty) ? State : NULL;
+ return (Assumption == *KnownNonEmpty) ? State : nullptr;
}
SValBuilder &SvalBuilder = C.getSValBuilder();
@@ -934,7 +976,7 @@ assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
const ObjCForCollectionStmt *FCS,
bool Assumption) {
if (!State)
- return NULL;
+ return nullptr;
SymbolRef CollectionS =
State->getSVal(FCS->getCollection(), C.getLocationContext()).getAsSymbol();
@@ -1049,11 +1091,11 @@ void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) {
const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
if (!Message)
- return 0;
+ return nullptr;
const ObjCMethodDecl *MD = Message->getDecl();
if (!MD)
- return 0;
+ return nullptr;
const ObjCInterfaceDecl *StaticClass;
if (isa<ObjCProtocolDecl>(MD->getDeclContext())) {
@@ -1066,11 +1108,11 @@ static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) {
}
if (!StaticClass)
- return 0;
+ return nullptr;
switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
case FC_None:
- return 0;
+ return nullptr;
case FC_NSArray:
case FC_NSDictionary:
case FC_NSEnumerator:
@@ -1135,7 +1177,10 @@ namespace {
/// \brief The checker restricts the return values of APIs known to
/// never (or almost never) return 'nil'.
class ObjCNonNilReturnValueChecker
- : public Checker<check::PostObjCMessage> {
+ : public Checker<check::PostObjCMessage,
+ check::PostStmt<ObjCArrayLiteral>,
+ check::PostStmt<ObjCDictionaryLiteral>,
+ check::PostStmt<ObjCBoxedExpr> > {
mutable bool Initialized;
mutable Selector ObjectAtIndex;
mutable Selector ObjectAtIndexedSubscript;
@@ -1143,13 +1188,32 @@ class ObjCNonNilReturnValueChecker
public:
ObjCNonNilReturnValueChecker() : Initialized(false) {}
+
+ ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
+ ProgramStateRef State,
+ CheckerContext &C) const;
+ void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const {
+ C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
+ }
+
+ void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const {
+ assumeExprIsNonNull(E, C);
+ }
+ void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const {
+ assumeExprIsNonNull(E, C);
+ }
+ void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const {
+ assumeExprIsNonNull(E, C);
+ }
+
void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
};
}
-static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
- ProgramStateRef State,
- CheckerContext &C) {
+ProgramStateRef
+ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
+ ProgramStateRef State,
+ CheckerContext &C) const {
SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
return State->assume(*DV, true);
@@ -1237,6 +1301,7 @@ void ento::registerObjCLoopChecker(CheckerManager &mgr) {
mgr.registerChecker<ObjCLoopChecker>();
}
-void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
+void
+ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
mgr.registerChecker<ObjCNonNilReturnValueChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
index 5169244a6f90..83a37c978c22 100644
--- a/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
@@ -23,7 +23,7 @@ using namespace ento;
namespace {
class BoolAssignmentChecker : public Checker< check::Bind > {
- mutable OwningPtr<BuiltinBug> BT;
+ mutable std::unique_ptr<BuiltinBug> BT;
void emitReport(ProgramStateRef state, CheckerContext &C) const;
public:
void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const;
@@ -34,7 +34,7 @@ void BoolAssignmentChecker::emitReport(ProgramStateRef state,
CheckerContext &C) const {
if (ExplodedNode *N = C.addTransition(state)) {
if (!BT)
- BT.reset(new BuiltinBug("Assignment of a non-Boolean value"));
+ BT.reset(new BuiltinBug(this, "Assignment of a non-Boolean value"));
C.emitReport(new BugReport(*BT, BT->getDescription(), N));
}
}
@@ -96,7 +96,7 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
}
ProgramStateRef stateLT, stateGE;
- llvm::tie(stateGE, stateLT) = CM.assumeDual(state, *greaterThanEqualToZero);
+ std::tie(stateGE, stateLT) = CM.assumeDual(state, *greaterThanEqualToZero);
// Is it possible for the value to be less than zero?
if (stateLT) {
@@ -132,7 +132,7 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
}
ProgramStateRef stateGT, stateLE;
- llvm::tie(stateLE, stateGT) = CM.assumeDual(state, *lessThanEqToOne);
+ std::tie(stateLE, stateGT) = CM.assumeDual(state, *lessThanEqToOne);
// Is it possible for the value to be greater than one?
if (stateGT) {
diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index ebd337780228..9fb22ecc852b 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -3,6 +3,10 @@ clang_tablegen(Checkers.inc -gen-clang-sa-checkers
SOURCE Checkers.td
TARGET ClangSACheckers)
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
add_clang_library(clangStaticAnalyzerCheckers
AllocationDiagnostics.cpp
AnalyzerStatsChecker.cpp
@@ -32,7 +36,6 @@ add_clang_library(clangStaticAnalyzerCheckers
ExprInspectionChecker.cpp
FixedAddressChecker.cpp
GenericTaintChecker.cpp
- IdempotentOperationChecker.cpp
IdenticalExprChecker.cpp
IvarInvalidationChecker.cpp
LLVMConventionsChecker.cpp
@@ -61,6 +64,7 @@ add_clang_library(clangStaticAnalyzerCheckers
StackAddrEscapeChecker.cpp
StreamChecker.cpp
TaintTesterChecker.cpp
+ TestAfterDivZeroChecker.cpp
TraversalChecker.cpp
UndefBranchChecker.cpp
UndefCapturedBlockVarChecker.cpp
@@ -71,21 +75,13 @@ add_clang_library(clangStaticAnalyzerCheckers
UnreachableCodeChecker.cpp
VLASizeChecker.cpp
VirtualCallChecker.cpp
- )
-add_dependencies(clangStaticAnalyzerCheckers
- clangStaticAnalyzerCore
- ClangAttrClasses
- ClangAttrList
- ClangCommentNodes
- ClangDeclNodes
- ClangDiagnosticCommon
- ClangStmtNodes
+ DEPENDS
ClangSACheckers
- )
-target_link_libraries(clangStaticAnalyzerCheckers
- clangBasic
+ LINK_LIBS
clangAST
+ clangAnalysis
+ clangBasic
clangStaticAnalyzerCore
)
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index c3736d7e5d71..0693bd6fd94d 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -35,11 +35,8 @@ class CStringChecker : public Checker< eval::Call,
check::DeadSymbols,
check::RegionChanges
> {
- mutable OwningPtr<BugType> BT_Null,
- BT_Bounds,
- BT_Overlap,
- BT_NotCString,
- BT_AdditionOverflow;
+ mutable std::unique_ptr<BugType> BT_Null, BT_Bounds, BT_Overlap,
+ BT_NotCString, BT_AdditionOverflow;
mutable const char *CurrentFunctionDescription;
@@ -51,6 +48,11 @@ public:
DefaultBool CheckCStringOutOfBounds;
DefaultBool CheckCStringBufferOverlap;
DefaultBool CheckCStringNotNullTerm;
+
+ CheckName CheckNameCStringNullArg;
+ CheckName CheckNameCStringOutOfBounds;
+ CheckName CheckNameCStringBufferOverlap;
+ CheckName CheckNameCStringNotNullTerm;
};
CStringChecksFilter Filter;
@@ -157,24 +159,24 @@ public:
ProgramStateRef state,
const Expr *S,
SVal l,
- const char *message = NULL) const;
+ const char *message = nullptr) const;
ProgramStateRef CheckBufferAccess(CheckerContext &C,
ProgramStateRef state,
const Expr *Size,
const Expr *FirstBuf,
const Expr *SecondBuf,
- const char *firstMessage = NULL,
- const char *secondMessage = NULL,
+ const char *firstMessage = nullptr,
+ const char *secondMessage = nullptr,
bool WarnAboutSize = false) const;
ProgramStateRef CheckBufferAccess(CheckerContext &C,
ProgramStateRef state,
const Expr *Size,
const Expr *Buf,
- const char *message = NULL,
+ const char *message = nullptr,
bool WarnAboutSize = false) const {
// This is a convenience override.
- return CheckBufferAccess(C, state, Size, Buf, NULL, message, NULL,
+ return CheckBufferAccess(C, state, Size, Buf, nullptr, message, nullptr,
WarnAboutSize);
}
ProgramStateRef CheckOverlap(CheckerContext &C,
@@ -218,22 +220,23 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
const Expr *S, SVal l) const {
// If a previous check has failed, propagate the failure.
if (!state)
- return NULL;
+ return nullptr;
ProgramStateRef stateNull, stateNonNull;
- llvm::tie(stateNull, stateNonNull) = assumeZero(C, state, l, S->getType());
+ std::tie(stateNull, stateNonNull) = assumeZero(C, state, l, S->getType());
if (stateNull && !stateNonNull) {
if (!Filter.CheckCStringNullArg)
- return NULL;
+ return nullptr;
ExplodedNode *N = C.generateSink(stateNull);
if (!N)
- return NULL;
+ return nullptr;
if (!BT_Null)
- BT_Null.reset(new BuiltinBug(categories::UnixAPI,
- "Null pointer argument in call to byte string function"));
+ BT_Null.reset(new BuiltinBug(
+ Filter.CheckNameCStringNullArg, categories::UnixAPI,
+ "Null pointer argument in call to byte string function"));
SmallString<80> buf;
llvm::raw_svector_ostream os(buf);
@@ -247,7 +250,7 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
report->addRange(S->getSourceRange());
bugreporter::trackNullOrUndefValue(N, S, *report);
C.emitReport(report);
- return NULL;
+ return nullptr;
}
// From here on, assume that the value is non-null.
@@ -262,7 +265,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
const char *warningMsg) const {
// If a previous check has failed, propagate the failure.
if (!state)
- return NULL;
+ return nullptr;
// Check for out of bound array element access.
const MemRegion *R = l.getAsRegion();
@@ -291,11 +294,12 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
if (StOutBound && !StInBound) {
ExplodedNode *N = C.generateSink(StOutBound);
if (!N)
- return NULL;
+ return nullptr;
if (!BT_Bounds) {
- BT_Bounds.reset(new BuiltinBug("Out-of-bound array access",
- "Byte string function accesses out-of-bound array element"));
+ BT_Bounds.reset(new BuiltinBug(
+ Filter.CheckNameCStringOutOfBounds, "Out-of-bound array access",
+ "Byte string function accesses out-of-bound array element"));
}
BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Bounds.get());
@@ -321,7 +325,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
report->addRange(S->getSourceRange());
C.emitReport(report);
- return NULL;
+ return nullptr;
}
// Array bound check succeeded. From this point forward the array bound
@@ -339,7 +343,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
bool WarnAboutSize) const {
// If a previous check has failed, propagate the failure.
if (!state)
- return NULL;
+ return nullptr;
SValBuilder &svalBuilder = C.getSValBuilder();
ASTContext &Ctx = svalBuilder.getContext();
@@ -352,7 +356,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
SVal BufVal = state->getSVal(FirstBuf, LCtx);
state = checkNonNull(C, state, FirstBuf, BufVal);
if (!state)
- return NULL;
+ return nullptr;
// If out-of-bounds checking is turned off, skip the rest.
if (!Filter.CheckCStringOutOfBounds)
@@ -382,7 +386,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
// If the buffer isn't large enough, abort.
if (!state)
- return NULL;
+ return nullptr;
}
// If there's a second buffer, check it as well.
@@ -390,7 +394,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
BufVal = state->getSVal(SecondBuf, LCtx);
state = checkNonNull(C, state, SecondBuf, BufVal);
if (!state)
- return NULL;
+ return nullptr;
BufStart = svalBuilder.evalCast(BufVal, PtrTy, SecondBuf->getType());
if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) {
@@ -420,7 +424,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
// If a previous check has failed, propagate the failure.
if (!state)
- return NULL;
+ return nullptr;
ProgramStateRef stateTrue, stateFalse;
@@ -439,13 +443,13 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
// Are the two values the same?
SValBuilder &svalBuilder = C.getSValBuilder();
- llvm::tie(stateTrue, stateFalse) =
+ std::tie(stateTrue, stateFalse) =
state->assume(svalBuilder.evalEQ(state, *firstLoc, *secondLoc));
if (stateTrue && !stateFalse) {
// If the values are known to be equal, that's automatically an overlap.
emitOverlapBug(C, stateTrue, First, Second);
- return NULL;
+ return nullptr;
}
// assume the two expressions are not equal.
@@ -461,7 +465,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
if (!reverseTest)
return state;
- llvm::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
+ std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
if (stateTrue) {
if (stateFalse) {
// If we don't know which one comes first, we can't perform this test.
@@ -506,12 +510,12 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
if (!OverlapTest)
return state;
- llvm::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
+ std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
if (stateTrue && !stateFalse) {
// Overlap!
emitOverlapBug(C, stateTrue, First, Second);
- return NULL;
+ return nullptr;
}
// assume the two expressions don't overlap.
@@ -526,7 +530,8 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state,
return;
if (!BT_Overlap)
- BT_Overlap.reset(new BugType(categories::UnixAPI, "Improper arguments"));
+ BT_Overlap.reset(new BugType(Filter.CheckNameCStringBufferOverlap,
+ categories::UnixAPI, "Improper arguments"));
// Generate a report for this bug.
BugReport *report =
@@ -548,7 +553,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
// If a previous check has failed, propagate the failure.
if (!state)
- return NULL;
+ return nullptr;
SValBuilder &svalBuilder = C.getSValBuilder();
BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
@@ -576,18 +581,19 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
*maxMinusRightNL, cmpTy);
ProgramStateRef stateOverflow, stateOkay;
- llvm::tie(stateOverflow, stateOkay) =
+ std::tie(stateOverflow, stateOkay) =
state->assume(willOverflow.castAs<DefinedOrUnknownSVal>());
if (stateOverflow && !stateOkay) {
// We have an overflow. Emit a bug report.
ExplodedNode *N = C.generateSink(stateOverflow);
if (!N)
- return NULL;
+ return nullptr;
if (!BT_AdditionOverflow)
- BT_AdditionOverflow.reset(new BuiltinBug("API",
- "Sum of expressions causes overflow"));
+ BT_AdditionOverflow.reset(
+ new BuiltinBug(Filter.CheckNameCStringOutOfBounds, "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
@@ -600,7 +606,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
BugReport *report = new BugReport(*BT_AdditionOverflow, warning, N);
C.emitReport(report);
- return NULL;
+ return nullptr;
}
// From now on, assume an overflow didn't occur.
@@ -703,8 +709,9 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
if (ExplodedNode *N = C.addTransition(state)) {
if (!BT_NotCString)
- BT_NotCString.reset(new BuiltinBug(categories::UnixAPI,
- "Argument is not a null-terminated string."));
+ BT_NotCString.reset(new BuiltinBug(
+ Filter.CheckNameCStringNotNullTerm, categories::UnixAPI,
+ "Argument is not a null-terminated string."));
SmallString<120> buf;
llvm::raw_svector_ostream os(buf);
@@ -714,8 +721,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
<< "', which is not a null-terminated string";
// Generate a report for this bug.
- BugReport *report = new BugReport(*BT_NotCString,
- os.str(), N);
+ BugReport *report = new BugReport(*BT_NotCString, os.str(), N);
report->addRange(Ex->getSourceRange());
C.emitReport(report);
@@ -763,8 +769,9 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
if (ExplodedNode *N = C.addTransition(state)) {
if (!BT_NotCString)
- BT_NotCString.reset(new BuiltinBug(categories::UnixAPI,
- "Argument is not a null-terminated string."));
+ BT_NotCString.reset(new BuiltinBug(
+ Filter.CheckNameCStringNotNullTerm, categories::UnixAPI,
+ "Argument is not a null-terminated string."));
SmallString<120> buf;
llvm::raw_svector_ostream os(buf);
@@ -795,7 +802,7 @@ const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,
// Get the memory region pointed to by the val.
const MemRegion *bufRegion = val.getAsRegion();
if (!bufRegion)
- return NULL;
+ return nullptr;
// Strip casts off the memory region.
bufRegion = bufRegion->StripCasts();
@@ -803,7 +810,7 @@ const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,
// Cast the memory region to a string region.
const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
if (!strRegion)
- return NULL;
+ return nullptr;
// Return the actual string in the string region.
return strRegion->getStringLiteral();
@@ -845,7 +852,8 @@ ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
}
return state->invalidateRegions(R, E, C.blockCount(), LCtx,
- CausesPointerEscape, 0, 0, &ITraits);
+ CausesPointerEscape, nullptr, nullptr,
+ &ITraits);
}
// If we have a non-region value by chance, just remove the binding.
@@ -909,7 +917,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
QualType sizeTy = Size->getType();
ProgramStateRef stateZeroSize, stateNonZeroSize;
- llvm::tie(stateZeroSize, stateNonZeroSize) =
+ std::tie(stateZeroSize, stateNonZeroSize) =
assumeZero(C, state, sizeVal, sizeTy);
// Get the value of the Dest.
@@ -946,7 +954,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
const char * const writeWarning =
"Memory copy function overflows destination buffer";
state = CheckBufferAccess(C, state, Size, Dest, Source,
- writeWarning, /* sourceWarning = */ NULL);
+ writeWarning, /* sourceWarning = */ nullptr);
if (Restricted)
state = CheckOverlap(C, state, Size, Dest, Source);
@@ -971,7 +979,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
} else {
// If we don't know how much we copied, we can at least
// conjure a return value for later.
- SVal result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx,
+ SVal result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx,
C.blockCount());
state = state->BindExpr(CE, LCtx, result);
}
@@ -1066,7 +1074,7 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
QualType sizeTy = Size->getType();
ProgramStateRef stateZeroSize, stateNonZeroSize;
- llvm::tie(stateZeroSize, stateNonZeroSize) =
+ std::tie(stateZeroSize, stateNonZeroSize) =
assumeZero(C, state, sizeVal, sizeTy);
// If the size can be zero, the result will be 0 in that case, and we don't
@@ -1092,7 +1100,7 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
// See if they are the same.
DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
ProgramStateRef StSameBuf, StNotSameBuf;
- llvm::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
+ std::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.
@@ -1113,7 +1121,8 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
state = CheckBufferAccess(C, state, Size, Left, Right);
if (state) {
// The return value is the comparison result, which we don't know.
- SVal CmpV = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount());
+ SVal CmpV = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx,
+ C.blockCount());
state = state->BindExpr(CE, LCtx, CmpV);
C.addTransition(state);
}
@@ -1150,7 +1159,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
ProgramStateRef stateZeroSize, stateNonZeroSize;
- llvm::tie(stateZeroSize, stateNonZeroSize) =
+ std::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
@@ -1204,10 +1213,10 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
ProgramStateRef stateStringTooLong, stateStringNotTooLong;
// Check if the strLength is greater than the maxlen.
- llvm::tie(stateStringTooLong, stateStringNotTooLong) =
- state->assume(C.getSValBuilder().evalBinOpNN(
- state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
- .castAs<DefinedOrUnknownSVal>());
+ std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
+ C.getSValBuilder()
+ .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
+ .castAs<DefinedOrUnknownSVal>());
if (stateStringTooLong && !stateStringNotTooLong) {
// If the string is longer than maxlen, return maxlen.
@@ -1223,7 +1232,8 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// 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.
- result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx, C.blockCount());
+ result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx,
+ C.blockCount());
NonLoc resultNL = result.castAs<NonLoc>();
if (strLengthNL) {
@@ -1246,7 +1256,8 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// 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()) {
- result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx, C.blockCount());
+ result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx,
+ C.blockCount());
}
}
@@ -1349,7 +1360,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// - potential overflows caused by a bound that could exceed the destination
SVal amountCopied = UnknownVal();
SVal maxLastElementIndex = UnknownVal();
- const char *boundWarning = NULL;
+ const char *boundWarning = nullptr;
// If the function is strncpy, strncat, etc... it is bounded.
if (isBounded) {
@@ -1371,7 +1382,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// 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(
+ std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
svalBuilder.evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
.castAs<DefinedOrUnknownSVal>());
@@ -1418,7 +1429,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// case strncpy will do no work at all. Our bounds check uses n-1
// as the last element accessed, so n == 0 is problematic.
ProgramStateRef StateZeroSize, StateNonZeroSize;
- llvm::tie(StateZeroSize, StateNonZeroSize) =
+ std::tie(StateZeroSize, StateNonZeroSize) =
assumeZero(C, state, *lenValNL, sizeTy);
// If the size is known to be zero, we're done.
@@ -1629,7 +1640,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// 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()) {
- Result = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount());
+ Result = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
}
// Set the return value.
@@ -1711,7 +1722,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
SValBuilder &svalBuilder = C.getSValBuilder();
DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
ProgramStateRef StSameBuf, StNotSameBuf;
- llvm::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
+ std::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.
@@ -1786,7 +1797,8 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
if (!canComputeResult) {
// Conjure a symbolic value. It's the best we can do.
- SVal resultVal = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount());
+ SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx,
+ C.blockCount());
state = state->BindExpr(CE, LCtx, resultVal);
}
@@ -1843,7 +1855,7 @@ void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const {
} else {
assert(SearchStrVal.isUnknown());
// Conjure a symbolic value. It's the best we can do.
- Result = SVB.conjureSymbolVal(0, CE, LCtx, C.blockCount());
+ Result = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
}
// Set the return value, and finish.
@@ -1863,7 +1875,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
return false;
// FIXME: Poorly-factored string switches are slow.
- FnCheck evalFunction = 0;
+ FnCheck evalFunction = nullptr;
if (C.isCLibraryFunction(FDecl, "memcpy"))
evalFunction = &CStringChecker::evalMemcpy;
else if (C.isCLibraryFunction(FDecl, "mempcpy"))
@@ -1907,7 +1919,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
// Make sure each function sets its own description.
// (But don't bother in a release build.)
- assert(!(CurrentFunctionDescription = NULL));
+ assert(!(CurrentFunctionDescription = nullptr));
// Check and evaluate the call.
(this->*evalFunction)(C, CE);
@@ -1928,9 +1940,8 @@ void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
// Record string length for char a[] = "abc";
ProgramStateRef state = C.getState();
- for (DeclStmt::const_decl_iterator I = DS->decl_begin(), E = DS->decl_end();
- I != E; ++I) {
- const VarDecl *D = dyn_cast<VarDecl>(*I);
+ for (const auto *I : DS->decls()) {
+ const VarDecl *D = dyn_cast<VarDecl>(I);
if (!D)
continue;
@@ -2057,10 +2068,12 @@ void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
C.addTransition(state);
}
-#define REGISTER_CHECKER(name) \
-void ento::register##name(CheckerManager &mgr) {\
- mgr.registerChecker<CStringChecker>()->Filter.Check##name = true; \
-}
+#define REGISTER_CHECKER(name) \
+ void ento::register##name(CheckerManager &mgr) { \
+ CStringChecker *checker = mgr.registerChecker<CStringChecker>(); \
+ checker->Filter.Check##name = true; \
+ checker->Filter.CheckName##name = mgr.getCurrentCheckName(); \
+ }
REGISTER_CHECKER(CStringNullArg)
REGISTER_CHECKER(CStringOutOfBounds)
diff --git a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
index d29a12a90eeb..abfb971d4ccc 100644
--- a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
@@ -31,6 +31,7 @@ using namespace ento;
namespace {
class WalkAST: public StmtVisitor<WalkAST> {
+ const CheckerBase *Checker;
BugReporter &BR;
AnalysisDeclContext* AC;
@@ -81,9 +82,8 @@ class WalkAST: public StmtVisitor<WalkAST> {
bool containsBadStrncatPattern(const CallExpr *CE);
public:
- WalkAST(BugReporter &br, AnalysisDeclContext* ac) :
- BR(br), AC(ac) {
- }
+ WalkAST(const CheckerBase *checker, BugReporter &br, AnalysisDeclContext *ac)
+ : Checker(checker), BR(br), AC(ac) {}
// Statement visitor methods.
void VisitChildren(Stmt *S);
@@ -157,8 +157,9 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
os << "U";
os << "se a safer 'strlcat' API";
- BR.EmitBasicReport(FD, "Anti-pattern in the argument", "C String API",
- os.str(), Loc, LenArg->getSourceRange());
+ BR.EmitBasicReport(FD, Checker, "Anti-pattern in the argument",
+ "C String API", os.str(), Loc,
+ LenArg->getSourceRange());
}
}
@@ -179,7 +180,7 @@ public:
void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
BugReporter &BR) const {
- WalkAST walker(BR, Mgr.getAnalysisDeclContext(D));
+ WalkAST walker(this, BR, Mgr.getAnalysisDeclContext(D));
walker.Visit(D->getBody());
}
};
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index fefcbe7b09cb..adb7a54900e0 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -27,24 +27,35 @@ using namespace clang;
using namespace ento;
namespace {
+
+struct ChecksFilter {
+ DefaultBool Check_CallAndMessageUnInitRefArg;
+ DefaultBool Check_CallAndMessageChecker;
+
+ CheckName CheckName_CallAndMessageUnInitRefArg;
+ CheckName CheckName_CallAndMessageChecker;
+};
+
class CallAndMessageChecker
: public Checker< check::PreStmt<CallExpr>,
check::PreStmt<CXXDeleteExpr>,
check::PreObjCMessage,
check::PreCall > {
- mutable OwningPtr<BugType> BT_call_null;
- mutable OwningPtr<BugType> BT_call_undef;
- mutable OwningPtr<BugType> BT_cxx_call_null;
- mutable OwningPtr<BugType> BT_cxx_call_undef;
- mutable OwningPtr<BugType> BT_call_arg;
- mutable OwningPtr<BugType> BT_cxx_delete_undef;
- mutable OwningPtr<BugType> BT_msg_undef;
- mutable OwningPtr<BugType> BT_objc_prop_undef;
- mutable OwningPtr<BugType> BT_objc_subscript_undef;
- mutable OwningPtr<BugType> BT_msg_arg;
- mutable OwningPtr<BugType> BT_msg_ret;
- mutable OwningPtr<BugType> BT_call_few_args;
+ mutable std::unique_ptr<BugType> BT_call_null;
+ mutable std::unique_ptr<BugType> BT_call_undef;
+ mutable std::unique_ptr<BugType> BT_cxx_call_null;
+ mutable std::unique_ptr<BugType> BT_cxx_call_undef;
+ mutable std::unique_ptr<BugType> BT_call_arg;
+ mutable std::unique_ptr<BugType> BT_cxx_delete_undef;
+ mutable std::unique_ptr<BugType> BT_msg_undef;
+ mutable std::unique_ptr<BugType> BT_objc_prop_undef;
+ mutable std::unique_ptr<BugType> BT_objc_subscript_undef;
+ mutable std::unique_ptr<BugType> BT_msg_arg;
+ mutable std::unique_ptr<BugType> BT_msg_ret;
+ mutable std::unique_ptr<BugType> BT_call_few_args;
+
public:
+ ChecksFilter Filter;
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
@@ -52,10 +63,11 @@ public:
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
private:
- static bool PreVisitProcessArg(CheckerContext &C, SVal V,
- SourceRange argRange, const Expr *argEx,
- bool IsFirstArgument, bool checkUninitFields,
- const CallEvent &Call, OwningPtr<BugType> &BT);
+ bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange ArgRange,
+ const Expr *ArgEx, bool IsFirstArgument,
+ bool CheckUninitFields, const CallEvent &Call,
+ std::unique_ptr<BugType> &BT,
+ const ParmVarDecl *ParamDecl) const;
static void emitBadCall(BugType *BT, CheckerContext &C, const Expr *BadE);
void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg,
@@ -65,10 +77,14 @@ private:
ProgramStateRef state,
const ObjCMethodCall &msg) const;
- static void LazyInit_BT(const char *desc, OwningPtr<BugType> &BT) {
+ void LazyInit_BT(const char *desc, std::unique_ptr<BugType> &BT) const {
if (!BT)
- BT.reset(new BuiltinBug(desc));
+ BT.reset(new BuiltinBug(this, desc));
}
+ bool uninitRefOrPointer(CheckerContext &C, const SVal &V,
+ const SourceRange &ArgRange,
+ const Expr *ArgEx, std::unique_ptr<BugType> &BT,
+ const ParmVarDecl *ParamDecl, const char *BD) const;
};
} // end anonymous namespace
@@ -113,30 +129,86 @@ static StringRef describeUninitializedArgumentInCall(const CallEvent &Call,
}
}
+bool CallAndMessageChecker::uninitRefOrPointer(CheckerContext &C,
+ const SVal &V,
+ const SourceRange &ArgRange,
+ const Expr *ArgEx,
+ std::unique_ptr<BugType> &BT,
+ const ParmVarDecl *ParamDecl,
+ const char *BD) const {
+ if (!Filter.Check_CallAndMessageUnInitRefArg)
+ return false;
+
+ // No parameter declaration available, i.e. variadic function argument.
+ if(!ParamDecl)
+ return false;
+
+ // If parameter is declared as pointer to const in function declaration,
+ // then check if corresponding argument in function call is
+ // pointing to undefined symbol value (uninitialized memory).
+ StringRef Message;
+
+ if (ParamDecl->getType()->isPointerType()) {
+ Message = "Function call argument is a pointer to uninitialized value";
+ } else if (ParamDecl->getType()->isReferenceType()) {
+ Message = "Function call argument is an uninitialized value";
+ } else
+ return false;
+
+ if(!ParamDecl->getType()->getPointeeType().isConstQualified())
+ return false;
+
+ if (const MemRegion *SValMemRegion = V.getAsRegion()) {
+ const ProgramStateRef State = C.getState();
+ const SVal PSV = State->getSVal(SValMemRegion);
+ if (PSV.isUndef()) {
+ if (ExplodedNode *N = C.generateSink()) {
+ LazyInit_BT(BD, BT);
+ BugReport *R = new BugReport(*BT, Message, N);
+ R->addRange(ArgRange);
+ if (ArgEx) {
+ bugreporter::trackNullOrUndefValue(N, ArgEx, *R);
+ }
+ C.emitReport(R);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
- SVal V, SourceRange argRange,
- const Expr *argEx,
+ SVal V,
+ SourceRange ArgRange,
+ const Expr *ArgEx,
bool IsFirstArgument,
- bool checkUninitFields,
+ bool CheckUninitFields,
const CallEvent &Call,
- OwningPtr<BugType> &BT) {
+ std::unique_ptr<BugType> &BT,
+ const ParmVarDecl *ParamDecl
+ ) const {
+ const char *BD = "Uninitialized argument value";
+
+ if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD))
+ return true;
+
if (V.isUndef()) {
if (ExplodedNode *N = C.generateSink()) {
- LazyInit_BT("Uninitialized argument value", BT);
+ LazyInit_BT(BD, BT);
// Generate a report for this bug.
- StringRef Desc = describeUninitializedArgumentInCall(Call,
- IsFirstArgument);
+ StringRef Desc =
+ describeUninitializedArgumentInCall(Call, IsFirstArgument);
BugReport *R = new BugReport(*BT, Desc, N);
- R->addRange(argRange);
- if (argEx)
- bugreporter::trackNullOrUndefValue(N, argEx, *R);
+ R->addRange(ArgRange);
+ if (ArgEx)
+ bugreporter::trackNullOrUndefValue(N, ArgEx, *R);
C.emitReport(R);
}
return true;
}
- if (!checkUninitFields)
+ if (!CheckUninitFields)
return false;
if (Optional<nonloc::LazyCompoundVal> LV =
@@ -159,10 +231,9 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
if (const RecordType *RT = T->getAsStructureType()) {
const RecordDecl *RD = RT->getDecl()->getDefinition();
assert(RD && "Referred record has no definition");
- for (RecordDecl::field_iterator I =
- RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
- const FieldRegion *FR = MrMgr.getFieldRegion(*I, R);
- FieldChain.push_back(*I);
+ for (const auto *I : RD->fields()) {
+ const FieldRegion *FR = MrMgr.getFieldRegion(I, R);
+ FieldChain.push_back(I);
T = I->getType();
if (T->getAsStructureType()) {
if (Find(FR))
@@ -188,7 +259,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
if (F.Find(D->getRegion())) {
if (ExplodedNode *N = C.generateSink()) {
- LazyInit_BT("Uninitialized argument value", BT);
+ LazyInit_BT(BD, BT);
SmallString<512> Str;
llvm::raw_svector_ostream os(Str);
os << "Passed-by-value struct argument contains uninitialized data";
@@ -211,7 +282,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
// Generate a report for this bug.
BugReport *R = new BugReport(*BT, os.str(), N);
- R->addRange(argRange);
+ R->addRange(ArgRange);
// FIXME: enhance track back for uninitialized value for arbitrary
// memregions
@@ -234,20 +305,19 @@ void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
if (L.isUndef()) {
if (!BT_call_undef)
- BT_call_undef.reset(new BuiltinBug("Called function pointer is an "
- "uninitalized pointer value"));
+ BT_call_undef.reset(new BuiltinBug(
+ this, "Called function pointer is an uninitalized pointer value"));
emitBadCall(BT_call_undef.get(), C, Callee);
return;
}
ProgramStateRef StNonNull, StNull;
- llvm::tie(StNonNull, StNull) =
- State->assume(L.castAs<DefinedOrUnknownSVal>());
+ std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());
if (StNull && !StNonNull) {
if (!BT_call_null)
- BT_call_null.reset(
- new BuiltinBug("Called function pointer is null (null dereference)"));
+ BT_call_null.reset(new BuiltinBug(
+ this, "Called function pointer is null (null dereference)"));
emitBadCall(BT_call_null.get(), C, Callee);
return;
}
@@ -265,7 +335,8 @@ void CallAndMessageChecker::checkPreStmt(const CXXDeleteExpr *DE,
if (!N)
return;
if (!BT_cxx_delete_undef)
- BT_cxx_delete_undef.reset(new BuiltinBug("Uninitialized argument value"));
+ BT_cxx_delete_undef.reset(
+ new BuiltinBug(this, "Uninitialized argument value"));
if (DE->isArrayFormAsWritten())
Desc = "Argument to 'delete[]' is uninitialized";
else
@@ -289,20 +360,20 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
SVal V = CC->getCXXThisVal();
if (V.isUndef()) {
if (!BT_cxx_call_undef)
- BT_cxx_call_undef.reset(new BuiltinBug("Called C++ object pointer is "
- "uninitialized"));
+ BT_cxx_call_undef.reset(
+ new BuiltinBug(this, "Called C++ object pointer is uninitialized"));
emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
return;
}
ProgramStateRef StNonNull, StNull;
- llvm::tie(StNonNull, StNull) =
+ std::tie(StNonNull, StNull) =
State->assume(V.castAs<DefinedOrUnknownSVal>());
if (StNull && !StNonNull) {
if (!BT_cxx_call_null)
- BT_cxx_call_null.reset(new BuiltinBug("Called C++ object pointer "
- "is null"));
+ BT_cxx_call_null.reset(
+ new BuiltinBug(this, "Called C++ object pointer is null"));
emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
return;
}
@@ -311,7 +382,8 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
}
const Decl *D = Call.getDecl();
- if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+ const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
+ if (FD) {
// If we have a declaration, we can make sure we pass enough parameters to
// the function.
unsigned Params = FD->getNumParams();
@@ -340,17 +412,21 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
const bool checkUninitFields =
!(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));
- OwningPtr<BugType> *BT;
+ std::unique_ptr<BugType> *BT;
if (isa<ObjCMethodCall>(Call))
BT = &BT_msg_arg;
else
BT = &BT_call_arg;
- for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i)
+ for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) {
+ const ParmVarDecl *ParamDecl = nullptr;
+ if(FD && i < FD->getNumParams())
+ ParamDecl = FD->getParamDecl(i);
if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
Call.getArgExpr(i), /*IsFirstArgument=*/i == 0,
- checkUninitFields, Call, *BT))
+ checkUninitFields, Call, *BT, ParamDecl))
return;
+ }
// If we make it here, record our assumptions about the callee.
C.addTransition(State);
@@ -361,26 +437,25 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
SVal recVal = msg.getReceiverSVal();
if (recVal.isUndef()) {
if (ExplodedNode *N = C.generateSink()) {
- BugType *BT = 0;
+ BugType *BT = nullptr;
switch (msg.getMessageKind()) {
case OCM_Message:
if (!BT_msg_undef)
- BT_msg_undef.reset(new BuiltinBug("Receiver in message expression "
+ BT_msg_undef.reset(new BuiltinBug(this,
+ "Receiver in message expression "
"is an uninitialized value"));
BT = BT_msg_undef.get();
break;
case OCM_PropertyAccess:
if (!BT_objc_prop_undef)
- BT_objc_prop_undef.reset(new BuiltinBug("Property access on an "
- "uninitialized object "
- "pointer"));
+ BT_objc_prop_undef.reset(new BuiltinBug(
+ this, "Property access on an uninitialized object pointer"));
BT = BT_objc_prop_undef.get();
break;
case OCM_Subscript:
if (!BT_objc_subscript_undef)
- BT_objc_subscript_undef.reset(new BuiltinBug("Subscript access on an "
- "uninitialized object "
- "pointer"));
+ BT_objc_subscript_undef.reset(new BuiltinBug(
+ this, "Subscript access on an uninitialized object pointer"));
BT = BT_objc_subscript_undef.get();
break;
}
@@ -402,7 +477,7 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
ProgramStateRef state = C.getState();
ProgramStateRef notNilState, nilState;
- llvm::tie(notNilState, nilState) = state->assume(receiverVal);
+ std::tie(notNilState, nilState) = state->assume(receiverVal);
// Handle receiver must be nil.
if (nilState && !notNilState) {
@@ -418,7 +493,7 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
if (!BT_msg_ret)
BT_msg_ret.reset(
- new BuiltinBug("Receiver in message expression is 'nil'"));
+ new BuiltinBug(this, "Receiver in message expression is 'nil'"));
const ObjCMessageExpr *ME = msg.getOriginExpr();
@@ -426,8 +501,9 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
- os << "The receiver of message '" << ME->getSelector().getAsString()
- << "' is nil";
+ os << "The receiver of message '";
+ ME->getSelector().print(os);
+ os << "' is nil";
if (ResTy->isReferenceType()) {
os << ", which results in forming a null reference";
} else {
@@ -454,7 +530,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
ProgramStateRef state,
const ObjCMethodCall &Msg) const {
ASTContext &Ctx = C.getASTContext();
- static SimpleProgramPointTag Tag("CallAndMessageChecker : NilReceiver");
+ static CheckerProgramPointTag Tag(this, "NilReceiver");
// Check the return type of the message expression. A message to nil will
// return different values depending on the return type and the architecture.
@@ -484,7 +560,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
Ctx.LongDoubleTy == CanRetTy ||
Ctx.LongLongTy == CanRetTy ||
Ctx.UnsignedLongLongTy == CanRetTy)))) {
- if (ExplodedNode *N = C.generateSink(state, 0 , &Tag))
+ if (ExplodedNode *N = C.generateSink(state, nullptr, &Tag))
emitNilReceiverBug(C, Msg, N);
return;
}
@@ -510,6 +586,13 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
C.addTransition(state);
}
-void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
- mgr.registerChecker<CallAndMessageChecker>();
-}
+#define REGISTER_CHECKER(name) \
+ void ento::register##name(CheckerManager &mgr) { \
+ CallAndMessageChecker *Checker = \
+ mgr.registerChecker<CallAndMessageChecker>(); \
+ Checker->Filter.Check_##name = true; \
+ Checker->Filter.CheckName_##name = mgr.getCurrentCheckName(); \
+ }
+
+REGISTER_CHECKER(CallAndMessageUnInitRefArg)
+REGISTER_CHECKER(CallAndMessageChecker)
diff --git a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
index 5e6e10541483..3ba063ddc821 100644
--- a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
@@ -23,12 +23,71 @@ using namespace ento;
namespace {
class CastSizeChecker : public Checker< check::PreStmt<CastExpr> > {
- mutable OwningPtr<BuiltinBug> BT;
+ mutable std::unique_ptr<BuiltinBug> BT;
+
public:
void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
};
}
+/// Check if we are casting to a struct with a flexible array at the end.
+/// \code
+/// struct foo {
+/// size_t len;
+/// struct bar data[];
+/// };
+/// \endcode
+/// or
+/// \code
+/// struct foo {
+/// size_t len;
+/// struct bar data[0];
+/// }
+/// \endcode
+/// In these cases it is also valid to allocate size of struct foo + a multiple
+/// of struct bar.
+static bool evenFlexibleArraySize(ASTContext &Ctx, CharUnits RegionSize,
+ CharUnits TypeSize, QualType ToPointeeTy) {
+ const RecordType *RT = ToPointeeTy->getAs<RecordType>();
+ if (!RT)
+ return false;
+
+ const RecordDecl *RD = RT->getDecl();
+ RecordDecl::field_iterator Iter(RD->field_begin());
+ RecordDecl::field_iterator End(RD->field_end());
+ const FieldDecl *Last = nullptr;
+ for (; Iter != End; ++Iter)
+ Last = *Iter;
+ assert(Last && "empty structs should already be handled");
+
+ const Type *ElemType = Last->getType()->getArrayElementTypeNoTypeQual();
+ CharUnits FlexSize;
+ if (const ConstantArrayType *ArrayTy =
+ Ctx.getAsConstantArrayType(Last->getType())) {
+ FlexSize = Ctx.getTypeSizeInChars(ElemType);
+ if (ArrayTy->getSize() == 1 && TypeSize > FlexSize)
+ TypeSize -= FlexSize;
+ else if (ArrayTy->getSize() != 0)
+ return false;
+ } else if (RD->hasFlexibleArrayMember()) {
+ FlexSize = Ctx.getTypeSizeInChars(ElemType);
+ } else {
+ return false;
+ }
+
+ if (FlexSize.isZero())
+ return false;
+
+ CharUnits Left = RegionSize - TypeSize;
+ if (Left.isNegative())
+ return false;
+
+ if (Left % FlexSize == 0)
+ return true;
+
+ return false;
+}
+
void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
const Expr *E = CE->getSubExpr();
ASTContext &Ctx = C.getASTContext();
@@ -46,11 +105,11 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
ProgramStateRef state = C.getState();
const MemRegion *R = state->getSVal(E, C.getLocationContext()).getAsRegion();
- if (R == 0)
+ if (!R)
return;
const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
- if (SR == 0)
+ if (!SR)
return;
SValBuilder &svalBuilder = C.getSValBuilder();
@@ -66,21 +125,23 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
if (typeSize.isZero())
return;
- if (regionSize % typeSize != 0) {
- if (ExplodedNode *errorNode = C.generateSink()) {
- if (!BT)
- BT.reset(new BuiltinBug("Cast region with wrong size.",
- "Cast a region whose size is not a multiple of the"
- " destination type size."));
- BugReport *R = new BugReport(*BT, BT->getDescription(),
- errorNode);
- R->addRange(CE->getSourceRange());
- C.emitReport(R);
- }
+ if (regionSize % typeSize == 0)
+ return;
+
+ if (evenFlexibleArraySize(Ctx, regionSize, typeSize, ToPointeeTy))
+ return;
+
+ if (ExplodedNode *errorNode = C.generateSink()) {
+ if (!BT)
+ BT.reset(new BuiltinBug(this, "Cast region with wrong size.",
+ "Cast a region whose size is not a multiple"
+ " of the destination type size."));
+ BugReport *R = new BugReport(*BT, BT->getDescription(), errorNode);
+ R->addRange(CE->getSourceRange());
+ C.emitReport(R);
}
}
-
void ento::registerCastSizeChecker(CheckerManager &mgr) {
- mgr.registerChecker<CastSizeChecker>();
+ mgr.registerChecker<CastSizeChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
index 60348c73584b..d765315bb57b 100644
--- a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
@@ -24,7 +24,7 @@ using namespace ento;
namespace {
class CastToStructChecker : public Checker< check::PreStmt<CastExpr> > {
- mutable OwningPtr<BuiltinBug> BT;
+ mutable std::unique_ptr<BuiltinBug> BT;
public:
void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
@@ -58,10 +58,11 @@ void CastToStructChecker::checkPreStmt(const CastExpr *CE,
if (!OrigPointeeTy->isRecordType()) {
if (ExplodedNode *N = C.addTransition()) {
if (!BT)
- BT.reset(new BuiltinBug("Cast from non-struct type to struct type",
- "Casting a non-structure type to a structure type "
- "and accessing a field can lead to memory access "
- "errors or data corruption."));
+ BT.reset(
+ new BuiltinBug(this, "Cast from non-struct type to struct type",
+ "Casting a non-structure type to a structure type "
+ "and accessing a field can lead to memory access "
+ "errors or data corruption."));
BugReport *R = new BugReport(*BT,BT->getDescription(), N);
R->addRange(CE->getSourceRange());
C.emitReport(R);
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index 3f9b3cc7f805..d186144b9ddd 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -97,8 +97,9 @@ static bool scan_ivar_release(Stmt *S, ObjCIvarDecl *ID,
return false;
}
-static void checkObjCDealloc(const ObjCImplementationDecl *D,
- const LangOptions& LOpts, BugReporter& BR) {
+static void checkObjCDealloc(const CheckerBase *Checker,
+ const ObjCImplementationDecl *D,
+ const LangOptions &LOpts, BugReporter &BR) {
assert (LOpts.getGC() != LangOptions::GCOnly);
@@ -112,15 +113,12 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D,
bool containsPointerIvar = false;
- for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end();
- I!=E; ++I) {
-
- ObjCIvarDecl *ID = *I;
- QualType T = ID->getType();
+ for (const auto *Ivar : ID->ivars()) {
+ QualType T = Ivar->getType();
if (!T->isObjCObjectPointerType() ||
- ID->getAttr<IBOutletAttr>() || // Skip IBOutlets.
- ID->getAttr<IBOutletCollectionAttr>()) // Skip IBOutletCollections.
+ Ivar->hasAttr<IBOutletAttr>() || // Skip IBOutlets.
+ Ivar->hasAttr<IBOutletCollectionAttr>()) // Skip IBOutletCollections.
continue;
containsPointerIvar = true;
@@ -155,14 +153,12 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D,
// Get the "dealloc" selector.
IdentifierInfo* II = &Ctx.Idents.get("dealloc");
Selector S = Ctx.Selectors.getSelector(0, &II);
- ObjCMethodDecl *MD = 0;
+ const ObjCMethodDecl *MD = nullptr;
// Scan the instance methods for "dealloc".
- for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
- E = D->instmeth_end(); I!=E; ++I) {
-
- if ((*I)->getSelector() == S) {
- MD = *I;
+ for (const auto *I : D->instance_methods()) {
+ if (I->getSelector() == S) {
+ MD = I;
break;
}
}
@@ -180,7 +176,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D,
llvm::raw_string_ostream os(buf);
os << "Objective-C class '" << *D << "' lacks a 'dealloc' instance method";
- BR.EmitBasicReport(D, name, categories::CoreFoundationObjectiveC,
+ BR.EmitBasicReport(D, Checker, name, categories::CoreFoundationObjectiveC,
os.str(), DLoc);
return;
}
@@ -198,7 +194,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D,
<< "' does not send a 'dealloc' message to its super class"
" (missing [super dealloc])";
- BR.EmitBasicReport(MD, name, categories::CoreFoundationObjectiveC,
+ BR.EmitBasicReport(MD, Checker, name, categories::CoreFoundationObjectiveC,
os.str(), DLoc);
return;
}
@@ -212,9 +208,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D,
// Scan for missing and extra releases of ivars used by implementations
// of synthesized properties
- for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(),
- E = D->propimpl_end(); I!=E; ++I) {
-
+ for (const auto *I : D->property_impls()) {
// We can only check the synthesized properties
if (I->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
continue;
@@ -239,7 +233,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D,
bool requiresRelease = PD->getSetterKind() != ObjCPropertyDecl::Assign;
if (scan_ivar_release(MD->getBody(), ID, PD, RS, SelfII, Ctx)
!= requiresRelease) {
- const char *name = 0;
+ const char *name = nullptr;
std::string buf;
llvm::raw_string_ostream os(buf);
@@ -262,10 +256,10 @@ static void checkObjCDealloc(const ObjCImplementationDecl *D,
}
PathDiagnosticLocation SDLoc =
- PathDiagnosticLocation::createBegin(*I, BR.getSourceManager());
+ PathDiagnosticLocation::createBegin(I, BR.getSourceManager());
- BR.EmitBasicReport(MD, name, categories::CoreFoundationObjectiveC,
- os.str(), SDLoc);
+ BR.EmitBasicReport(MD, Checker, name,
+ categories::CoreFoundationObjectiveC, os.str(), SDLoc);
}
}
}
@@ -282,7 +276,8 @@ public:
BugReporter &BR) const {
if (mgr.getLangOpts().getGC() == LangOptions::GCOnly)
return;
- checkObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOpts(), BR);
+ checkObjCDealloc(this, cast<ObjCImplementationDecl>(D), mgr.getLangOpts(),
+ BR);
}
};
}
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
index 9cb1d2d6909b..cc4c0c3db846 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
@@ -40,10 +40,11 @@ static bool AreTypesCompatible(QualType Derived, QualType Ancestor,
static void CompareReturnTypes(const ObjCMethodDecl *MethDerived,
const ObjCMethodDecl *MethAncestor,
BugReporter &BR, ASTContext &Ctx,
- const ObjCImplementationDecl *ID) {
+ const ObjCImplementationDecl *ID,
+ const CheckerBase *Checker) {
- QualType ResDerived = MethDerived->getResultType();
- QualType ResAncestor = MethAncestor->getResultType();
+ QualType ResDerived = MethDerived->getReturnType();
+ QualType ResAncestor = MethAncestor->getReturnType();
if (!AreTypesCompatible(ResDerived, ResAncestor, Ctx)) {
std::string sbuf;
@@ -53,9 +54,9 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived,
<< *MethDerived->getClassInterface()
<< "', which is derived from class '"
<< *MethAncestor->getClassInterface()
- << "', defines the instance method '"
- << MethDerived->getSelector().getAsString()
- << "' whose return type is '"
+ << "', defines the instance method '";
+ MethDerived->getSelector().print(os);
+ os << "' whose return type is '"
<< ResDerived.getAsString()
<< "'. A method with the same name (same selector) is also defined in "
"class '"
@@ -69,15 +70,15 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived,
PathDiagnosticLocation::createBegin(MethDerived,
BR.getSourceManager());
- BR.EmitBasicReport(MethDerived,
- "Incompatible instance method return type",
- categories::CoreFoundationObjectiveC,
- os.str(), MethDLoc);
+ BR.EmitBasicReport(
+ MethDerived, Checker, "Incompatible instance method return type",
+ categories::CoreFoundationObjectiveC, os.str(), MethDLoc);
}
}
static void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID,
- BugReporter& BR) {
+ BugReporter &BR,
+ const CheckerBase *Checker) {
const ObjCInterfaceDecl *D = ID->getClassInterface();
const ObjCInterfaceDecl *C = D->getSuperClass();
@@ -92,10 +93,7 @@ static void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID,
MapTy IMeths;
unsigned NumMethods = 0;
- for (ObjCImplementationDecl::instmeth_iterator I=ID->instmeth_begin(),
- E=ID->instmeth_end(); I!=E; ++I) {
-
- ObjCMethodDecl *M = *I;
+ for (auto *M : ID->instance_methods()) {
IMeths[M->getSelector()] = M;
++NumMethods;
}
@@ -103,22 +101,19 @@ static void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID,
// Now recurse the class hierarchy chain looking for methods with the
// same signatures.
while (C && NumMethods) {
- for (ObjCInterfaceDecl::instmeth_iterator I=C->instmeth_begin(),
- E=C->instmeth_end(); I!=E; ++I) {
-
- ObjCMethodDecl *M = *I;
+ for (const auto *M : C->instance_methods()) {
Selector S = M->getSelector();
MapTy::iterator MI = IMeths.find(S);
- if (MI == IMeths.end() || MI->second == 0)
+ if (MI == IMeths.end() || MI->second == nullptr)
continue;
--NumMethods;
ObjCMethodDecl *MethDerived = MI->second;
- MI->second = 0;
+ MI->second = nullptr;
- CompareReturnTypes(MethDerived, M, BR, Ctx, ID);
+ CompareReturnTypes(MethDerived, M, BR, Ctx, ID, Checker);
}
C = C->getSuperClass();
@@ -135,7 +130,7 @@ class ObjCMethSigsChecker : public Checker<
public:
void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr,
BugReporter &BR) const {
- CheckObjCInstMethSignature(D, BR);
+ CheckObjCInstMethSignature(D, BR, this);
}
};
}
diff --git a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index 415d3ecc39b5..45768b2cdf76 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -46,8 +46,18 @@ struct ChecksFilter {
DefaultBool check_vfork;
DefaultBool check_FloatLoopCounter;
DefaultBool check_UncheckedReturn;
+
+ CheckName checkName_gets;
+ CheckName checkName_getpw;
+ CheckName checkName_mktemp;
+ CheckName checkName_mkstemp;
+ CheckName checkName_strcpy;
+ CheckName checkName_rand;
+ CheckName checkName_vfork;
+ CheckName checkName_FloatLoopCounter;
+ CheckName checkName_UncheckedReturn;
};
-
+
class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
AnalysisDeclContext* AC;
@@ -139,7 +149,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
.Case("rand_r", &WalkAST::checkCall_rand)
.Case("random", &WalkAST::checkCall_random)
.Case("vfork", &WalkAST::checkCall_vfork)
- .Default(NULL);
+ .Default(nullptr);
// If the callee isn't defined, it is not of security concern.
// Check and evaluate the call.
@@ -179,7 +189,7 @@ getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
B->getOpcode() == BO_Comma))
- return NULL;
+ return nullptr;
if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y))
return lhs;
@@ -187,19 +197,19 @@ getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y))
return rhs;
- return NULL;
+ return nullptr;
}
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
const NamedDecl *ND = DR->getDecl();
- return ND == x || ND == y ? DR : NULL;
+ return ND == x || ND == y ? DR : nullptr;
}
if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
return U->isIncrementDecrementOp()
- ? getIncrementedVar(U->getSubExpr(), x, y) : NULL;
+ ? getIncrementedVar(U->getSubExpr(), x, y) : nullptr;
- return NULL;
+ return nullptr;
}
/// CheckLoopConditionForFloat - This check looks for 'for' statements that
@@ -243,14 +253,14 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
// Does at least one of the variables have a floating point type?
- drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : NULL;
- drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : NULL;
+ drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : nullptr;
+ drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : nullptr;
if (!drLHS && !drRHS)
return;
- const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : NULL;
- const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : NULL;
+ const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : nullptr;
+ const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : nullptr;
if (!vdLHS && !vdRHS)
return;
@@ -281,7 +291,7 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
PathDiagnosticLocation FSLoc =
PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
- BR.EmitBasicReport(AC->getDecl(),
+ BR.EmitBasicReport(AC->getDecl(), filter.checkName_FloatLoopCounter,
bugType, "Security", os.str(),
FSLoc, ranges);
}
@@ -302,11 +312,11 @@ void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
return;
// Verify that the function takes a single argument.
- if (FPT->getNumArgs() != 1)
+ if (FPT->getNumParams() != 1)
return;
// Is the argument a 'char*'?
- const PointerType *PT = FPT->getArgType(0)->getAs<PointerType>();
+ const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
if (!PT)
return;
@@ -316,7 +326,7 @@ void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
// Issue a warning.
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport(AC->getDecl(),
+ BR.EmitBasicReport(AC->getDecl(), filter.checkName_gets,
"Potential buffer overflow in call to 'gets'",
"Security",
"Call to function 'gets' is extremely insecure as it can "
@@ -338,15 +348,15 @@ void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
return;
// Verify that the function takes two arguments.
- if (FPT->getNumArgs() != 2)
+ if (FPT->getNumParams() != 2)
return;
// Verify the first argument type is integer.
- if (!FPT->getArgType(0)->isIntegralOrUnscopedEnumerationType())
+ if (!FPT->getParamType(0)->isIntegralOrUnscopedEnumerationType())
return;
// Verify the second argument type is char*.
- const PointerType *PT = FPT->getArgType(1)->getAs<PointerType>();
+ const PointerType *PT = FPT->getParamType(1)->getAs<PointerType>();
if (!PT)
return;
@@ -356,7 +366,7 @@ void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
// Issue a warning.
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport(AC->getDecl(),
+ BR.EmitBasicReport(AC->getDecl(), filter.checkName_getpw,
"Potential buffer overflow in call to 'getpw'",
"Security",
"The getpw() function is dangerous as it may overflow the "
@@ -382,11 +392,11 @@ void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
return;
// Verify that the function takes a single argument.
- if (FPT->getNumArgs() != 1)
+ if (FPT->getNumParams() != 1)
return;
// Verify that the argument is Pointer Type.
- const PointerType *PT = FPT->getArgType(0)->getAs<PointerType>();
+ const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
if (!PT)
return;
@@ -394,10 +404,10 @@ void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
return;
- // Issue a waring.
+ // Issue a warning.
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport(AC->getDecl(),
+ BR.EmitBasicReport(AC->getDecl(), filter.checkName_mktemp,
"Potential insecure temporary file in call 'mktemp'",
"Security",
"Call to function 'mktemp' is insecure as it always "
@@ -483,7 +493,7 @@ void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
out << " used as a suffix";
}
out << ')';
- BR.EmitBasicReport(AC->getDecl(),
+ BR.EmitBasicReport(AC->getDecl(), filter.checkName_mkstemp,
"Insecure temporary file creation", "Security",
out.str(), CELoc, strArg->getSourceRange());
}
@@ -504,7 +514,7 @@ void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
// Issue a warning.
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport(AC->getDecl(),
+ BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
"Potential insecure memory buffer bounds restriction in "
"call 'strcpy'",
"Security",
@@ -531,7 +541,7 @@ void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
// Issue a warning.
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport(AC->getDecl(),
+ BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
"Potential insecure memory buffer bounds restriction in "
"call 'strcat'",
"Security",
@@ -551,14 +561,14 @@ bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
return false;
// Verify the function takes two arguments, three in the _chk version.
- int numArgs = FPT->getNumArgs();
+ int numArgs = FPT->getNumParams();
if (numArgs != 2 && numArgs != 3)
return false;
// Verify the type for both arguments.
for (int i = 0; i < 2; i++) {
// Verify that the arguments are pointers.
- const PointerType *PT = FPT->getArgType(i)->getAs<PointerType>();
+ const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
if (!PT)
return false;
@@ -584,17 +594,16 @@ void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
if (!FTP)
return;
- if (FTP->getNumArgs() == 1) {
+ if (FTP->getNumParams() == 1) {
// Is the argument an 'unsigned short *'?
// (Actually any integer type is allowed.)
- const PointerType *PT = FTP->getArgType(0)->getAs<PointerType>();
+ const PointerType *PT = FTP->getParamType(0)->getAs<PointerType>();
if (!PT)
return;
if (! PT->getPointeeType()->isIntegralOrUnscopedEnumerationType())
return;
- }
- else if (FTP->getNumArgs() != 0)
+ } else if (FTP->getNumParams() != 0)
return;
// Issue a warning.
@@ -610,8 +619,9 @@ void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport(AC->getDecl(), os1.str(), "Security", os2.str(),
- CELoc, CE->getCallee()->getSourceRange());
+ BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, os1.str(),
+ "Security", os2.str(), CELoc,
+ CE->getCallee()->getSourceRange());
}
//===----------------------------------------------------------------------===//
@@ -628,13 +638,13 @@ void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
return;
// Verify that the function takes no argument.
- if (FTP->getNumArgs() != 0)
+ if (FTP->getNumParams() != 0)
return;
// Issue a warning.
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport(AC->getDecl(),
+ BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand,
"'random' is not a secure random number generator",
"Security",
"The 'random' function produces a sequence of values that "
@@ -654,7 +664,7 @@ void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
// All calls to vfork() are insecure, issue a warning.
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport(AC->getDecl(),
+ BR.EmitBasicReport(AC->getDecl(), filter.checkName_vfork,
"Potential insecure implementation-specific behavior in "
"call 'vfork'",
"Security",
@@ -678,7 +688,7 @@ void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
if (!FD)
return;
- if (II_setid[0] == NULL) {
+ if (II_setid[0] == nullptr) {
static const char * const identifiers[num_setids] = {
"setuid", "setgid", "seteuid", "setegid",
"setreuid", "setregid"
@@ -704,12 +714,12 @@ void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
// Verify that the function takes one or two arguments (depending on
// the function).
- if (FTP->getNumArgs() != (identifierid < 4 ? 1 : 2))
+ if (FTP->getNumParams() != (identifierid < 4 ? 1 : 2))
return;
// The arguments must be integers.
- for (unsigned i = 0; i < FTP->getNumArgs(); i++)
- if (! FTP->getArgType(i)->isIntegralOrUnscopedEnumerationType())
+ for (unsigned i = 0; i < FTP->getNumParams(); i++)
+ if (!FTP->getParamType(i)->isIntegralOrUnscopedEnumerationType())
return;
// Issue a warning.
@@ -725,8 +735,9 @@ void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport(AC->getDecl(), os1.str(), "Security", os2.str(),
- CELoc, CE->getCallee()->getSourceRange());
+ BR.EmitBasicReport(AC->getDecl(), filter.checkName_UncheckedReturn, os1.str(),
+ "Security", os2.str(), CELoc,
+ CE->getCallee()->getSourceRange());
}
//===----------------------------------------------------------------------===//
@@ -746,10 +757,13 @@ public:
};
}
-#define REGISTER_CHECKER(name) \
-void ento::register##name(CheckerManager &mgr) {\
- mgr.registerChecker<SecuritySyntaxChecker>()->filter.check_##name = true;\
-}
+#define REGISTER_CHECKER(name) \
+ void ento::register##name(CheckerManager &mgr) { \
+ SecuritySyntaxChecker *checker = \
+ mgr.registerChecker<SecuritySyntaxChecker>(); \
+ checker->filter.check_##name = true; \
+ checker->filter.checkName_##name = mgr.getCurrentCheckName(); \
+ }
REGISTER_CHECKER(gets)
REGISTER_CHECKER(getpw)
diff --git a/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp b/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
index 1207b67c97fa..a61e658f69c9 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
@@ -24,10 +24,12 @@ using namespace ento;
namespace {
class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
+ const CheckerBase *Checker;
AnalysisDeclContext* AC;
public:
- WalkAST(BugReporter &br, AnalysisDeclContext* ac) : BR(br), AC(ac) {}
+ WalkAST(BugReporter &br, const CheckerBase *checker, AnalysisDeclContext *ac)
+ : BR(br), Checker(checker), AC(ac) {}
void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
void VisitStmt(Stmt *S) { VisitChildren(S); }
void VisitChildren(Stmt *S);
@@ -45,7 +47,7 @@ void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
if (E->getKind() != UETT_SizeOf)
return;
- // If an explicit type is used in the code, usually the coder knows what he is
+ // If an explicit type is used in the code, usually the coder knows what they are
// doing.
if (E->isArgumentType())
return;
@@ -62,7 +64,7 @@ void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
PathDiagnosticLocation ELoc =
PathDiagnosticLocation::createBegin(E, BR.getSourceManager(), AC);
- BR.EmitBasicReport(AC->getDecl(),
+ BR.EmitBasicReport(AC->getDecl(), Checker,
"Potential unintended use of sizeof() on pointer type",
categories::LogicError,
"The code calls sizeof() on a pointer type. "
@@ -80,7 +82,7 @@ class SizeofPointerChecker : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
- WalkAST walker(BR, mgr.getAnalysisDeclContext(D));
+ WalkAST walker(BR, this, mgr.getAnalysisDeclContext(D));
walker.Visit(D->getBody());
}
};
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index 862212d532fd..44eb64187bfb 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -120,6 +120,14 @@ def SizeofPointerChecker : Checker<"SizeofPtr">,
HelpText<"Warn about unintended use of sizeof() on pointer expressions">,
DescFile<"CheckSizeofPointer.cpp">;
+def CallAndMessageUnInitRefArg : Checker<"CallAndMessageUnInitRefArg">,
+ HelpText<"Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers, and pointer to undefined variables)">,
+ DescFile<"CallAndMessageChecker.cpp">;
+
+def TestAfterDivZeroChecker : Checker<"TestAfterDivZero">,
+ HelpText<"Check for division by variable that is later compared against 0. Either the comparison is useless or there is division by zero.">,
+ DescFile<"TestAfterDivZeroChecker.cpp">;
+
} // end "alpha.core"
//===----------------------------------------------------------------------===//
@@ -203,10 +211,6 @@ def DeadStoresChecker : Checker<"DeadStores">,
let ParentPackage = DeadCodeAlpha in {
-def IdempotentOperationChecker : Checker<"IdempotentOperations">,
- HelpText<"Warn about idempotent operations">,
- DescFile<"IdempotentOperationChecker.cpp">;
-
def UnreachableCodeChecker : Checker<"UnreachableCode">,
HelpText<"Check unreachable code">,
DescFile<"UnreachableCodeChecker.cpp">;
@@ -416,6 +420,10 @@ def ObjCNonNilReturnValueChecker : Checker<"NonNilReturnValue">,
HelpText<"Model the APIs that are guaranteed to return a non-nil value">,
DescFile<"BasicObjCFoundationChecks.cpp">;
+def ObjCSuperCallChecker : Checker<"MissingSuperCall">,
+ HelpText<"Warn about Objective-C methods that lack a necessary call to super">,
+ DescFile<"ObjCMissingSuperCallChecker.cpp">;
+
def NSErrorChecker : Checker<"NSError">,
HelpText<"Check usage of NSError** parameters">,
DescFile<"NSErrorChecker.cpp">;
@@ -448,10 +456,6 @@ def DirectIvarAssignmentForAnnotatedFunctions : Checker<"DirectIvarAssignmentFor
HelpText<"Check for direct assignments to instance variables in the methods annotated with objc_no_direct_instance_variable_assignment">,
DescFile<"DirectIvarAssignment.cpp">;
-def ObjCSuperCallChecker : Checker<"MissingSuperCall">,
- HelpText<"Warn about Objective-C methods that lack a necessary call to super">,
- DescFile<"ObjCMissingSuperCallChecker.cpp">;
-
} // end "alpha.osx.cocoa"
let ParentPackage = CoreFoundation in {
diff --git a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index 991296538a5b..ad415770e5e5 100644
--- a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
@@ -41,11 +41,11 @@ bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; }
class ChrootChecker : public Checker<eval::Call, check::PreStmt<CallExpr> > {
mutable IdentifierInfo *II_chroot, *II_chdir;
// This bug refers to possibly break out of a chroot() jail.
- mutable OwningPtr<BuiltinBug> BT_BreakJail;
+ mutable std::unique_ptr<BuiltinBug> BT_BreakJail;
public:
- ChrootChecker() : II_chroot(0), II_chdir(0) {}
-
+ ChrootChecker() : II_chroot(nullptr), II_chdir(nullptr) {}
+
static void *getTag() {
static int x;
return &x;
@@ -142,9 +142,9 @@ void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
if (isRootChanged((intptr_t) *k))
if (ExplodedNode *N = C.addTransition()) {
if (!BT_BreakJail)
- BT_BreakJail.reset(new BuiltinBug("Break out of jail",
- "No call of chdir(\"/\") immediately "
- "after chroot"));
+ BT_BreakJail.reset(new BuiltinBug(
+ this, "Break out of jail", "No call of chdir(\"/\") immediately "
+ "after chroot"));
BugReport *R = new BugReport(*BT_BreakJail,
BT_BreakJail->getDescription(), N);
C.emitReport(R);
diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index 9d855ce649ac..c1ea76735c41 100644
--- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -124,21 +124,23 @@ class DeadStoreObs : public LiveVariables::Observer {
const CFG &cfg;
ASTContext &Ctx;
BugReporter& BR;
+ const CheckerBase *Checker;
AnalysisDeclContext* AC;
ParentMap& Parents;
llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
- OwningPtr<ReachableCode> reachableCode;
+ std::unique_ptr<ReachableCode> reachableCode;
const CFGBlock *currentBlock;
- OwningPtr<llvm::DenseSet<const VarDecl *> > InEH;
+ std::unique_ptr<llvm::DenseSet<const VarDecl *>> InEH;
enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
public:
- DeadStoreObs(const CFG &cfg, ASTContext &ctx,
- BugReporter& br, AnalysisDeclContext* ac, ParentMap& parents,
- llvm::SmallPtrSet<const VarDecl*, 20> &escaped)
- : cfg(cfg), Ctx(ctx), BR(br), AC(ac), Parents(parents),
- Escaped(escaped), currentBlock(0) {}
+ DeadStoreObs(const CFG &cfg, ASTContext &ctx, BugReporter &br,
+ const CheckerBase *checker, AnalysisDeclContext *ac,
+ ParentMap &parents,
+ llvm::SmallPtrSet<const VarDecl *, 20> &escaped)
+ : cfg(cfg), Ctx(ctx), BR(br), Checker(checker), AC(ac), Parents(parents),
+ Escaped(escaped), currentBlock(nullptr) {}
virtual ~DeadStoreObs() {}
@@ -176,7 +178,7 @@ public:
SmallString<64> buf;
llvm::raw_svector_ostream os(buf);
- const char *BugType = 0;
+ const char *BugType = nullptr;
switch (dsk) {
case DeadInit:
@@ -199,7 +201,8 @@ public:
return;
}
- BR.EmitBasicReport(AC->getDecl(), BugType, "Dead store", os.str(), L, R);
+ BR.EmitBasicReport(AC->getDecl(), Checker, BugType, "Dead store", os.str(),
+ L, R);
}
void CheckVarDecl(const VarDecl *VD, const Expr *Ex, const Expr *Val,
@@ -214,7 +217,8 @@ public:
return;
if (!isLive(Live, VD) &&
- !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>())) {
+ !(VD->hasAttr<UnusedAttr>() || VD->hasAttr<BlocksAttr>() ||
+ VD->hasAttr<ObjCPreciseLifetimeAttr>())) {
PathDiagnosticLocation ExLoc =
PathDiagnosticLocation::createBegin(Ex, BR.getSourceManager(), AC);
@@ -251,8 +255,8 @@ public:
return false;
}
- virtual void observeStmt(const Stmt *S, const CFGBlock *block,
- const LiveVariables::LivenessValues &Live) {
+ void observeStmt(const Stmt *S, const CFGBlock *block,
+ const LiveVariables::LivenessValues &Live) override {
currentBlock = block;
@@ -309,10 +313,8 @@ public:
else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S))
// Iterate through the decls. Warn if any initializers are complex
// expressions that are not live (never used).
- for (DeclStmt::const_decl_iterator DI=DS->decl_begin(), DE=DS->decl_end();
- DI != DE; ++DI) {
-
- VarDecl *V = dyn_cast<VarDecl>(*DI);
+ for (const auto *DI : DS->decls()) {
+ const auto *V = dyn_cast<VarDecl>(DI);
if (!V)
continue;
@@ -339,8 +341,10 @@ public:
// A dead initialization is a variable that is dead after it
// is initialized. We don't flag warnings for those variables
- // marked 'unused'.
- if (!isLive(Live, V) && V->getAttr<UnusedAttr>() == 0) {
+ // marked 'unused' or 'objc_precise_lifetime'.
+ if (!isLive(Live, V) &&
+ !V->hasAttr<UnusedAttr>() &&
+ !V->hasAttr<ObjCPreciseLifetimeAttr>()) {
// Special case: check for initializations with constants.
//
// e.g. : int x = 0;
@@ -436,7 +440,7 @@ public:
ParentMap &pmap = mgr.getParentMap(D);
FindEscaped FS;
cfg.VisitBlockStmts(FS);
- DeadStoreObs A(cfg, BR.getContext(), BR, AC, pmap, FS.Escaped);
+ DeadStoreObs A(cfg, BR.getContext(), BR, this, AC, pmap, FS.Escaped);
L->runOnAllBlocks(A);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
index a2c8d1fd8f39..51e7a3d3ce34 100644
--- a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
+++ b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
@@ -95,6 +95,11 @@ class CFGDumper : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
+ PrintingPolicy Policy(mgr.getLangOpts());
+ Policy.TerseOutput = true;
+ Policy.PolishForDeclaration = true;
+ D->print(llvm::errs(), Policy);
+
if (CFG *cfg = mgr.getCFG(D)) {
cfg->dump(mgr.getLangOpts(),
llvm::sys::Process::StandardErrHasColors());
diff --git a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index 72d46c50e109..4ee02230649d 100644
--- a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -29,8 +29,8 @@ class DereferenceChecker
: public Checker< check::Location,
check::Bind,
EventDispatcher<ImplicitNullDerefEvent> > {
- mutable OwningPtr<BuiltinBug> BT_null;
- mutable OwningPtr<BuiltinBug> BT_undef;
+ mutable std::unique_ptr<BuiltinBug> BT_null;
+ mutable std::unique_ptr<BuiltinBug> BT_undef;
void reportBug(ProgramStateRef State, const Stmt *S, CheckerContext &C,
bool IsBind = false) const;
@@ -97,7 +97,7 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
// We know that 'location' cannot be non-null. This is what
// we call an "explicit" null dereference.
if (!BT_null)
- BT_null.reset(new BuiltinBug("Dereference of null pointer"));
+ BT_null.reset(new BuiltinBug(this, "Dereference of null pointer"));
SmallString<100> buf;
llvm::raw_svector_ostream os(buf);
@@ -126,7 +126,7 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
os << "Array access";
const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
- State.getPtr(), N->getLocationContext());
+ State.get(), N->getLocationContext());
os << " results in a null pointer dereference";
break;
}
@@ -134,7 +134,7 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
os << "Dereference of null pointer";
const UnaryOperator *U = cast<UnaryOperator>(S);
AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
- State.getPtr(), N->getLocationContext(), true);
+ State.get(), N->getLocationContext(), true);
break;
}
case Stmt::MemberExprClass: {
@@ -143,7 +143,7 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
os << "Access to field '" << M->getMemberNameInfo()
<< "' results in a dereference of a null pointer";
AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(),
- State.getPtr(), N->getLocationContext(), true);
+ State.get(), N->getLocationContext(), true);
}
break;
}
@@ -152,7 +152,7 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
os << "Access to instance variable '" << *IV->getDecl()
<< "' results in a dereference of a null pointer";
AddDerefSource(os, Ranges, IV->getBase()->IgnoreParenCasts(),
- State.getPtr(), N->getLocationContext(), true);
+ State.get(), N->getLocationContext(), true);
break;
}
default:
@@ -180,7 +180,8 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
if (l.isUndef()) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT_undef)
- BT_undef.reset(new BuiltinBug("Dereference of undefined pointer value"));
+ BT_undef.reset(
+ new BuiltinBug(this, "Dereference of undefined pointer value"));
BugReport *report =
new BugReport(*BT_undef, BT_undef->getDescription(), N);
@@ -200,7 +201,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
ProgramStateRef state = C.getState();
ProgramStateRef notNullState, nullState;
- llvm::tie(notNullState, nullState) = state->assume(location);
+ std::tie(notNullState, nullState) = state->assume(location);
// The explicit NULL case.
if (nullState) {
@@ -239,8 +240,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
ProgramStateRef State = C.getState();
ProgramStateRef StNonNull, StNull;
- llvm::tie(StNonNull, StNull) =
- State->assume(V.castAs<DefinedOrUnknownSVal>());
+ std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());
if (StNull) {
if (!StNonNull) {
diff --git a/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp b/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
index b43dc18c2179..0bcebf6e7744 100644
--- a/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
+++ b/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
@@ -63,13 +63,15 @@ class DirectIvarAssignment :
const ObjCMethodDecl *MD;
const ObjCInterfaceDecl *InterfD;
BugReporter &BR;
+ const CheckerBase *Checker;
LocationOrAnalysisDeclContext DCtx;
public:
MethodCrawler(const IvarToPropertyMapTy &InMap, const ObjCMethodDecl *InMD,
- const ObjCInterfaceDecl *InID,
- BugReporter &InBR, AnalysisDeclContext *InDCtx)
- : IvarToPropMap(InMap), MD(InMD), InterfD(InID), BR(InBR), DCtx(InDCtx) {}
+ const ObjCInterfaceDecl *InID, BugReporter &InBR,
+ const CheckerBase *Checker, AnalysisDeclContext *InDCtx)
+ : IvarToPropMap(InMap), MD(InMD), InterfD(InID), BR(InBR),
+ Checker(Checker), DCtx(InDCtx) {}
void VisitStmt(const Stmt *S) { VisitChildren(S); }
@@ -122,10 +124,7 @@ void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D,
IvarToPropertyMapTy IvarToPropMap;
// Find all properties for this class.
- for (ObjCInterfaceDecl::prop_iterator I = InterD->prop_begin(),
- E = InterD->prop_end(); I != E; ++I) {
- ObjCPropertyDecl *PD = *I;
-
+ for (const auto *PD : InterD->properties()) {
// Find the corresponding IVar.
const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterD,
Mgr.getASTContext());
@@ -140,10 +139,7 @@ void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D,
if (IvarToPropMap.empty())
return;
- for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
- E = D->instmeth_end(); I != E; ++I) {
-
- ObjCMethodDecl *M = *I;
+ for (const auto *M : D->instance_methods()) {
AnalysisDeclContext *DCtx = Mgr.getAnalysisDeclContext(M);
if ((*ShouldSkipMethod)(M))
@@ -152,20 +148,17 @@ void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D,
const Stmt *Body = M->getBody();
assert(Body);
- MethodCrawler MC(IvarToPropMap, M->getCanonicalDecl(), InterD, BR, DCtx);
+ MethodCrawler MC(IvarToPropMap, M->getCanonicalDecl(), InterD, BR, this,
+ DCtx);
MC.VisitStmt(Body);
}
}
static bool isAnnotatedToAllowDirectAssignment(const Decl *D) {
- for (specific_attr_iterator<AnnotateAttr>
- AI = D->specific_attr_begin<AnnotateAttr>(),
- AE = D->specific_attr_end<AnnotateAttr>(); AI != AE; ++AI) {
- const AnnotateAttr *Ann = *AI;
+ for (const auto *Ann : D->specific_attrs<AnnotateAttr>())
if (Ann->getAnnotation() ==
"objc_allow_direct_instance_variable_assignment")
return true;
- }
return false;
}
@@ -204,13 +197,11 @@ void DirectIvarAssignment::MethodCrawler::VisitBinaryOperator(
if (GetterMethod && GetterMethod->getCanonicalDecl() == MD)
return;
- BR.EmitBasicReport(MD,
- "Property access",
- categories::CoreFoundationObjectiveC,
+ BR.EmitBasicReport(
+ MD, Checker, "Property access", categories::CoreFoundationObjectiveC,
"Direct assignment to an instance variable backing a property; "
- "use the setter instead", PathDiagnosticLocation(IvarRef,
- BR.getSourceManager(),
- DCtx));
+ "use the setter instead",
+ PathDiagnosticLocation(IvarRef, BR.getSourceManager(), DCtx));
}
}
}
@@ -225,14 +216,9 @@ void ento::registerDirectIvarAssignment(CheckerManager &mgr) {
// Register the checker that checks for direct accesses in functions annotated
// with __attribute__((annotate("objc_no_direct_instance_variable_assignment"))).
static bool AttrFilter(const ObjCMethodDecl *M) {
- for (specific_attr_iterator<AnnotateAttr>
- AI = M->specific_attr_begin<AnnotateAttr>(),
- AE = M->specific_attr_end<AnnotateAttr>();
- AI != AE; ++AI) {
- const AnnotateAttr *Ann = *AI;
+ for (const auto *Ann : M->specific_attrs<AnnotateAttr>())
if (Ann->getAnnotation() == "objc_no_direct_instance_variable_assignment")
return false;
- }
return true;
}
diff --git a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
index 93daf94fbe32..e060c36184c4 100644
--- a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
@@ -23,7 +23,7 @@ using namespace ento;
namespace {
class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > {
- mutable OwningPtr<BuiltinBug> BT;
+ mutable std::unique_ptr<BuiltinBug> BT;
void reportBug(const char *Msg,
ProgramStateRef StateZero,
CheckerContext &C) const ;
@@ -37,7 +37,7 @@ void DivZeroChecker::reportBug(const char *Msg,
CheckerContext &C) const {
if (ExplodedNode *N = C.generateSink(StateZero)) {
if (!BT)
- BT.reset(new BuiltinBug("Division by zero"));
+ BT.reset(new BuiltinBug(this, "Division by zero"));
BugReport *R = new BugReport(*BT, Msg, N);
bugreporter::trackNullOrUndefValue(N, bugreporter::GetDenomExpr(N), *R);
@@ -68,7 +68,7 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
// Check for divide by zero.
ConstraintManager &CM = C.getConstraintManager();
ProgramStateRef stateNotZero, stateZero;
- llvm::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);
+ std::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);
if (!stateNotZero) {
assert(stateZero);
diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
index 7116e4dcd885..43a281218775 100644
--- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -223,7 +223,7 @@ DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
const Expr *RecE = MsgE->getInstanceReceiver();
if (!RecE)
- return 0;
+ return nullptr;
RecE= RecE->IgnoreParenImpCasts();
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) {
@@ -237,7 +237,7 @@ DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE,
return ObjTy;
}
}
- return 0;
+ return nullptr;
}
// Return a better dynamic type if one can be derived from the cast.
@@ -253,7 +253,7 @@ DynamicTypePropagation::getBetterObjCType(const Expr *CastE,
const ObjCObjectPointerType *NewTy =
CastE->getType()->getAs<ObjCObjectPointerType>();
if (!NewTy)
- return 0;
+ return nullptr;
QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType();
if (OldDTy.isNull()) {
return NewTy;
@@ -261,7 +261,7 @@ DynamicTypePropagation::getBetterObjCType(const Expr *CastE,
const ObjCObjectPointerType *OldTy =
OldDTy->getAs<ObjCObjectPointerType>();
if (!OldTy)
- return 0;
+ return nullptr;
// Id the old type is 'id', the new one is more precise.
if (OldTy->isObjCIdType() && !NewTy->isObjCIdType())
@@ -273,7 +273,7 @@ DynamicTypePropagation::getBetterObjCType(const Expr *CastE,
if (ToI && FromI && FromI->isSuperClassOf(ToI))
return NewTy;
- return 0;
+ return nullptr;
}
void ento::registerDynamicTypePropagation(CheckerManager &mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index 3ed2435b92ed..f36ec2c687f5 100644
--- a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -18,7 +18,7 @@ using namespace ento;
namespace {
class ExprInspectionChecker : public Checker< eval::Call > {
- mutable OwningPtr<BugType> BT;
+ mutable std::unique_ptr<BugType> BT;
void analyzerEval(const CallExpr *CE, CheckerContext &C) const;
void analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const;
@@ -43,7 +43,7 @@ bool ExprInspectionChecker::evalCall(const CallExpr *CE,
&ExprInspectionChecker::analyzerCheckInlined)
.Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash)
.Case("clang_analyzer_warnIfReached", &ExprInspectionChecker::analyzerWarnIfReached)
- .Default(0);
+ .Default(nullptr);
if (!Handler)
return false;
@@ -68,7 +68,7 @@ static const char *getArgumentValueString(const CallExpr *CE,
return "UNDEFINED";
ProgramStateRef StTrue, StFalse;
- llvm::tie(StTrue, StFalse) =
+ std::tie(StTrue, StFalse) =
State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>());
if (StTrue) {
@@ -91,11 +91,11 @@ void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
// A specific instantiation of an inlined function may have more constrained
// values than can generally be assumed. Skip the check.
- if (LC->getCurrentStackFrame()->getParent() != 0)
+ if (LC->getCurrentStackFrame()->getParent() != nullptr)
return;
if (!BT)
- BT.reset(new BugType("Checking analyzer assumptions", "debug"));
+ BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N);
C.emitReport(R);
@@ -106,7 +106,7 @@ void ExprInspectionChecker::analyzerWarnIfReached(const CallExpr *CE,
ExplodedNode *N = C.getPredecessor();
if (!BT)
- BT.reset(new BugType("Checking analyzer assumptions", "debug"));
+ BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
BugReport *R = new BugReport(*BT, "REACHABLE", N);
C.emitReport(R);
@@ -122,11 +122,11 @@ void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
// when we are analyzing it as an inlined function. This means that
// clang_analyzer_checkInlined(true) should always print TRUE, but
// clang_analyzer_checkInlined(false) should never actually print anything.
- if (LC->getCurrentStackFrame()->getParent() == 0)
+ if (LC->getCurrentStackFrame()->getParent() == nullptr)
return;
if (!BT)
- BT.reset(new BugType("Checking analyzer assumptions", "debug"));
+ BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N);
C.emitReport(R);
diff --git a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
index 085a991f7866..60bb03654f5d 100644
--- a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
@@ -25,7 +25,7 @@ using namespace ento;
namespace {
class FixedAddressChecker
: public Checker< check::PreStmt<BinaryOperator> > {
- mutable OwningPtr<BuiltinBug> BT;
+ mutable std::unique_ptr<BuiltinBug> BT;
public:
void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
@@ -52,10 +52,11 @@ void FixedAddressChecker::checkPreStmt(const BinaryOperator *B,
if (ExplodedNode *N = C.addTransition()) {
if (!BT)
- BT.reset(new BuiltinBug("Use fixed address",
- "Using a fixed address is not portable because that "
- "address will probably not be valid in all "
- "environments or platforms."));
+ BT.reset(
+ new BuiltinBug(this, "Use fixed address",
+ "Using a fixed address is not portable because that "
+ "address will probably not be valid in all "
+ "environments or platforms."));
BugReport *R = new BugReport(*BT, BT->getDescription(), N);
R->addRange(B->getRHS()->getSourceRange());
C.emitReport(R);
diff --git a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index 1dc60c6dbddc..08ba26a53037 100644
--- a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -34,7 +34,6 @@ public:
static void *getTag() { static int Tag; return &Tag; }
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
- void checkPostStmt(const DeclRefExpr *DRE, CheckerContext &C) const;
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
@@ -43,10 +42,10 @@ private:
/// Denotes the return vale.
static const unsigned ReturnValueIndex = UINT_MAX - 1;
- mutable OwningPtr<BugType> BT;
+ mutable std::unique_ptr<BugType> BT;
inline void initBugType() const {
if (!BT)
- BT.reset(new BugType("Use of Untrusted Data", "Untrusted Data"));
+ BT.reset(new BugType(this, "Use of Untrusted Data", "Untrusted Data"));
}
/// \brief Catch taint related bugs. Check if tainted data is passed to a
@@ -292,7 +291,7 @@ void GenericTaintChecker::checkPostStmt(const CallExpr *CE,
void GenericTaintChecker::addSourcesPre(const CallExpr *CE,
CheckerContext &C) const {
- ProgramStateRef State = 0;
+ ProgramStateRef State = nullptr;
const FunctionDecl *FDecl = C.getCalleeDecl(CE);
if (!FDecl || FDecl->getKind() != Decl::Function)
return;
@@ -315,7 +314,7 @@ void GenericTaintChecker::addSourcesPre(const CallExpr *CE,
// Otherwise, check if we have custom pre-processing implemented.
FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
.Case("fscanf", &GenericTaintChecker::preFscanf)
- .Default(0);
+ .Default(nullptr);
// Check and evaluate the call.
if (evalFunction)
State = (this->*evalFunction)(CE, C);
@@ -389,11 +388,11 @@ void GenericTaintChecker::addSourcesPost(const CallExpr *CE,
.Case("getch", &GenericTaintChecker::postRetTaint)
.Case("wgetch", &GenericTaintChecker::postRetTaint)
.Case("socket", &GenericTaintChecker::postSocket)
- .Default(0);
+ .Default(nullptr);
// If the callee isn't defined, it is not of security concern.
// Check and evaluate the call.
- ProgramStateRef State = 0;
+ ProgramStateRef State = nullptr;
if (evalFunction)
State = (this->*evalFunction)(CE, C);
if (!State)
@@ -429,11 +428,11 @@ SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C,
ProgramStateRef State = C.getState();
SVal AddrVal = State->getSVal(Arg->IgnoreParens(), C.getLocationContext());
if (AddrVal.isUnknownOrUndef())
- return 0;
+ return nullptr;
Optional<Loc> AddrLoc = AddrVal.getAs<Loc>();
if (!AddrLoc)
- return 0;
+ return nullptr;
const PointerType *ArgTy =
dyn_cast<PointerType>(Arg->getType().getCanonicalType().getTypePtr());
@@ -527,7 +526,7 @@ ProgramStateRef GenericTaintChecker::preFscanf(const CallExpr *CE,
return State;
}
- return 0;
+ return nullptr;
}
@@ -613,11 +612,7 @@ static bool getPrintfFormatArgumentNum(const CallExpr *CE,
const FunctionDecl *FDecl = C.getCalleeDecl(CE);
if (!FDecl)
return false;
- for (specific_attr_iterator<FormatAttr>
- i = FDecl->specific_attr_begin<FormatAttr>(),
- e = FDecl->specific_attr_end<FormatAttr>(); i != e ; ++i) {
-
- const FormatAttr *Format = *i;
+ for (const auto *Format : FDecl->specific_attrs<FormatAttr>()) {
ArgNum = Format->getFormatIdx() - 1;
if ((Format->getType()->getName() == "printf") &&
CE->getNumArgs() > ArgNum)
diff --git a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
deleted file mode 100644
index 4997f8d04ae8..000000000000
--- a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
+++ /dev/null
@@ -1,737 +0,0 @@
-//==- IdempotentOperationChecker.cpp - Idempotent Operations ----*- C++ -*-==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a set of path-sensitive checks for idempotent and/or
-// tautological operations. Each potential operation is checked along all paths
-// to see if every path results in a pointless operation.
-// +-------------------------------------------+
-// |Table of idempotent/tautological operations|
-// +-------------------------------------------+
-//+--------------------------------------------------------------------------+
-//|Operator | x op x | x op 1 | 1 op x | x op 0 | 0 op x | x op ~0 | ~0 op x |
-//+--------------------------------------------------------------------------+
-// +, += | | | | x | x | |
-// -, -= | | | | x | -x | |
-// *, *= | | x | x | 0 | 0 | |
-// /, /= | 1 | x | | N/A | 0 | |
-// &, &= | x | | | 0 | 0 | x | x
-// |, |= | x | | | x | x | ~0 | ~0
-// ^, ^= | 0 | | | x | x | |
-// <<, <<= | | | | x | 0 | |
-// >>, >>= | | | | x | 0 | |
-// || | x | 1 | 1 | x | x | 1 | 1
-// && | x | x | x | 0 | 0 | x | x
-// = | x | | | | | |
-// == | 1 | | | | | |
-// >= | 1 | | | | | |
-// <= | 1 | | | | | |
-// > | 0 | | | | | |
-// < | 0 | | | | | |
-// != | 0 | | | | | |
-//===----------------------------------------------------------------------===//
-//
-// Things TODO:
-// - Improved error messages
-// - Handle mixed assumptions (which assumptions can belong together?)
-// - Finer grained false positive control (levels)
-// - Handling ~0 values
-
-#include "ClangSACheckers.h"
-#include "clang/AST/Stmt.h"
-#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
-#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
-#include "clang/Analysis/CFGStmtMap.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class IdempotentOperationChecker
- : public Checker<check::PreStmt<BinaryOperator>,
- check::PostStmt<BinaryOperator>,
- check::EndAnalysis> {
-public:
- void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
- void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const;
- void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const;
-
-private:
- // Our assumption about a particular operation.
- enum Assumption { Possible = 0, Impossible, Equal, LHSis1, RHSis1, LHSis0,
- RHSis0 };
-
- static void UpdateAssumption(Assumption &A, const Assumption &New);
-
- // False positive reduction methods
- static bool isSelfAssign(const Expr *LHS, const Expr *RHS);
- static bool isUnused(const Expr *E, AnalysisDeclContext *AC);
- static bool isTruncationExtensionAssignment(const Expr *LHS,
- const Expr *RHS);
- static bool pathWasCompletelyAnalyzed(AnalysisDeclContext *AC,
- const CFGBlock *CB,
- const CoreEngine &CE);
- static bool CanVary(const Expr *Ex,
- AnalysisDeclContext *AC);
- static bool isConstantOrPseudoConstant(const DeclRefExpr *DR,
- AnalysisDeclContext *AC);
- static bool containsNonLocalVarDecl(const Stmt *S);
-
- // Hash table and related data structures
- struct BinaryOperatorData {
- BinaryOperatorData() : assumption(Possible) {}
-
- Assumption assumption;
- ExplodedNodeSet explodedNodes; // Set of ExplodedNodes that refer to a
- // BinaryOperator
- };
- typedef llvm::DenseMap<const BinaryOperator *, BinaryOperatorData>
- AssumptionMap;
- mutable AssumptionMap hash;
- mutable OwningPtr<BugType> BT;
-};
-}
-
-void IdempotentOperationChecker::checkPreStmt(const BinaryOperator *B,
- CheckerContext &C) const {
- // Find or create an entry in the hash for this BinaryOperator instance.
- // If we haven't done a lookup before, it will get default initialized to
- // 'Possible'. At this stage we do not store the ExplodedNode, as it has not
- // been created yet.
- BinaryOperatorData &Data = hash[B];
- Assumption &A = Data.assumption;
- AnalysisDeclContext *AC = C.getCurrentAnalysisDeclContext();
-
- // If we already have visited this node on a path that does not contain an
- // idempotent operation, return immediately.
- if (A == Impossible)
- return;
-
- // Retrieve both sides of the operator and determine if they can vary (which
- // may mean this is a false positive.
- const Expr *LHS = B->getLHS();
- const Expr *RHS = B->getRHS();
-
- // At this stage we can calculate whether each side contains a false positive
- // that applies to all operators. We only need to calculate this the first
- // time.
- bool LHSContainsFalsePositive = false, RHSContainsFalsePositive = false;
- if (A == Possible) {
- // An expression contains a false positive if it can't vary, or if it
- // contains a known false positive VarDecl.
- LHSContainsFalsePositive = !CanVary(LHS, AC)
- || containsNonLocalVarDecl(LHS);
- RHSContainsFalsePositive = !CanVary(RHS, AC)
- || containsNonLocalVarDecl(RHS);
- }
-
- ProgramStateRef state = C.getState();
- const LocationContext *LCtx = C.getLocationContext();
- SVal LHSVal = state->getSVal(LHS, LCtx);
- SVal RHSVal = state->getSVal(RHS, LCtx);
-
- // If either value is unknown, we can't be 100% sure of all paths.
- if (LHSVal.isUnknownOrUndef() || RHSVal.isUnknownOrUndef()) {
- A = Impossible;
- return;
- }
- BinaryOperator::Opcode Op = B->getOpcode();
-
- // Dereference the LHS SVal if this is an assign operation
- switch (Op) {
- default:
- break;
-
- // Fall through intentional
- case BO_AddAssign:
- case BO_SubAssign:
- case BO_MulAssign:
- case BO_DivAssign:
- case BO_AndAssign:
- case BO_OrAssign:
- case BO_XorAssign:
- case BO_ShlAssign:
- case BO_ShrAssign:
- case BO_Assign:
- // Assign statements have one extra level of indirection
- if (!LHSVal.getAs<Loc>()) {
- A = Impossible;
- return;
- }
- LHSVal = state->getSVal(LHSVal.castAs<Loc>(), LHS->getType());
- }
-
-
- // We now check for various cases which result in an idempotent operation.
-
- // x op x
- switch (Op) {
- default:
- break; // We don't care about any other operators.
-
- // Fall through intentional
- case BO_Assign:
- // x Assign x can be used to silence unused variable warnings intentionally.
- // If this is a self assignment and the variable is referenced elsewhere,
- // and the assignment is not a truncation or extension, then it is a false
- // positive.
- if (isSelfAssign(LHS, RHS)) {
- if (!isUnused(LHS, AC) && !isTruncationExtensionAssignment(LHS, RHS)) {
- UpdateAssumption(A, Equal);
- return;
- }
- else {
- A = Impossible;
- return;
- }
- }
-
- case BO_SubAssign:
- case BO_DivAssign:
- case BO_AndAssign:
- case BO_OrAssign:
- case BO_XorAssign:
- case BO_Sub:
- case BO_Div:
- case BO_And:
- case BO_Or:
- case BO_Xor:
- case BO_LOr:
- case BO_LAnd:
- case BO_EQ:
- case BO_NE:
- if (LHSVal != RHSVal || LHSContainsFalsePositive
- || RHSContainsFalsePositive)
- break;
- UpdateAssumption(A, Equal);
- return;
- }
-
- // x op 1
- switch (Op) {
- default:
- break; // We don't care about any other operators.
-
- // Fall through intentional
- case BO_MulAssign:
- case BO_DivAssign:
- case BO_Mul:
- case BO_Div:
- case BO_LOr:
- case BO_LAnd:
- if (!RHSVal.isConstant(1) || RHSContainsFalsePositive)
- break;
- UpdateAssumption(A, RHSis1);
- return;
- }
-
- // 1 op x
- switch (Op) {
- default:
- break; // We don't care about any other operators.
-
- // Fall through intentional
- case BO_MulAssign:
- case BO_Mul:
- case BO_LOr:
- case BO_LAnd:
- if (!LHSVal.isConstant(1) || LHSContainsFalsePositive)
- break;
- UpdateAssumption(A, LHSis1);
- return;
- }
-
- // x op 0
- switch (Op) {
- default:
- break; // We don't care about any other operators.
-
- // Fall through intentional
- case BO_AddAssign:
- case BO_SubAssign:
- case BO_MulAssign:
- case BO_AndAssign:
- case BO_OrAssign:
- case BO_XorAssign:
- case BO_Add:
- case BO_Sub:
- case BO_Mul:
- case BO_And:
- case BO_Or:
- case BO_Xor:
- case BO_Shl:
- case BO_Shr:
- case BO_LOr:
- case BO_LAnd:
- if (!RHSVal.isConstant(0) || RHSContainsFalsePositive)
- break;
- UpdateAssumption(A, RHSis0);
- return;
- }
-
- // 0 op x
- switch (Op) {
- default:
- break; // We don't care about any other operators.
-
- // Fall through intentional
- //case BO_AddAssign: // Common false positive
- case BO_SubAssign: // Check only if unsigned
- case BO_MulAssign:
- case BO_DivAssign:
- case BO_AndAssign:
- //case BO_OrAssign: // Common false positive
- //case BO_XorAssign: // Common false positive
- case BO_ShlAssign:
- case BO_ShrAssign:
- case BO_Add:
- case BO_Sub:
- case BO_Mul:
- case BO_Div:
- case BO_And:
- case BO_Or:
- case BO_Xor:
- case BO_Shl:
- case BO_Shr:
- case BO_LOr:
- case BO_LAnd:
- if (!LHSVal.isConstant(0) || LHSContainsFalsePositive)
- break;
- UpdateAssumption(A, LHSis0);
- return;
- }
-
- // If we get to this point, there has been a valid use of this operation.
- A = Impossible;
-}
-
-// At the post visit stage, the predecessor ExplodedNode will be the
-// BinaryOperator that was just created. We use this hook to collect the
-// ExplodedNode.
-void IdempotentOperationChecker::checkPostStmt(const BinaryOperator *B,
- CheckerContext &C) const {
- // Add the ExplodedNode we just visited
- BinaryOperatorData &Data = hash[B];
-
- const Stmt *predStmt =
- C.getPredecessor()->getLocation().castAs<StmtPoint>().getStmt();
-
- // Ignore implicit calls to setters.
- if (!isa<BinaryOperator>(predStmt))
- return;
-
- Data.explodedNodes.Add(C.getPredecessor());
-}
-
-void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G,
- BugReporter &BR,
- ExprEngine &Eng) const {
- if (!BT)
- BT.reset(new BugType("Idempotent operation", "Dead code"));
-
- // Iterate over the hash to see if we have any paths with definite
- // idempotent operations.
- for (AssumptionMap::const_iterator i = hash.begin(); i != hash.end(); ++i) {
- // Unpack the hash contents
- const BinaryOperatorData &Data = i->second;
- const Assumption &A = Data.assumption;
- const ExplodedNodeSet &ES = Data.explodedNodes;
-
- // If there are no nodes accosted with the expression, nothing to report.
- // FIXME: This is possible because the checker does part of processing in
- // checkPreStmt and part in checkPostStmt.
- if (ES.begin() == ES.end())
- continue;
-
- const BinaryOperator *B = i->first;
-
- if (A == Impossible)
- continue;
-
- // If the analyzer did not finish, check to see if we can still emit this
- // warning
- if (Eng.hasWorkRemaining()) {
- // If we can trace back
- AnalysisDeclContext *AC = (*ES.begin())->getLocationContext()
- ->getAnalysisDeclContext();
- if (!pathWasCompletelyAnalyzed(AC,
- AC->getCFGStmtMap()->getBlock(B),
- Eng.getCoreEngine()))
- continue;
- }
-
- // Select the error message and SourceRanges to report.
- SmallString<128> buf;
- llvm::raw_svector_ostream os(buf);
- bool LHSRelevant = false, RHSRelevant = false;
- switch (A) {
- case Equal:
- LHSRelevant = true;
- RHSRelevant = true;
- if (B->getOpcode() == BO_Assign)
- os << "Assigned value is always the same as the existing value";
- else
- os << "Both operands to '" << B->getOpcodeStr()
- << "' always have the same value";
- break;
- case LHSis1:
- LHSRelevant = true;
- os << "The left operand to '" << B->getOpcodeStr() << "' is always 1";
- break;
- case RHSis1:
- RHSRelevant = true;
- os << "The right operand to '" << B->getOpcodeStr() << "' is always 1";
- break;
- case LHSis0:
- LHSRelevant = true;
- os << "The left operand to '" << B->getOpcodeStr() << "' is always 0";
- break;
- case RHSis0:
- RHSRelevant = true;
- os << "The right operand to '" << B->getOpcodeStr() << "' is always 0";
- break;
- case Possible:
- llvm_unreachable("Operation was never marked with an assumption");
- case Impossible:
- llvm_unreachable(0);
- }
-
- // Add a report for each ExplodedNode
- for (ExplodedNodeSet::iterator I = ES.begin(), E = ES.end(); I != E; ++I) {
- BugReport *report = new BugReport(*BT, os.str(), *I);
-
- // Add source ranges and visitor hooks
- if (LHSRelevant) {
- const Expr *LHS = i->first->getLHS();
- report->addRange(LHS->getSourceRange());
- FindLastStoreBRVisitor::registerStatementVarDecls(*report, LHS, false);
- }
- if (RHSRelevant) {
- const Expr *RHS = i->first->getRHS();
- report->addRange(i->first->getRHS()->getSourceRange());
- FindLastStoreBRVisitor::registerStatementVarDecls(*report, RHS, false);
- }
-
- BR.emitReport(report);
- }
- }
-
- hash.clear();
-}
-
-// Updates the current assumption given the new assumption
-inline void IdempotentOperationChecker::UpdateAssumption(Assumption &A,
- const Assumption &New) {
-// If the assumption is the same, there is nothing to do
- if (A == New)
- return;
-
- switch (A) {
- // If we don't currently have an assumption, set it
- case Possible:
- A = New;
- return;
-
- // If we have determined that a valid state happened, ignore the new
- // assumption.
- case Impossible:
- return;
-
- // Any other case means that we had a different assumption last time. We don't
- // currently support mixing assumptions for diagnostic reasons, so we set
- // our assumption to be impossible.
- default:
- A = Impossible;
- return;
- }
-}
-
-// Check for a statement where a variable is self assigned to possibly avoid an
-// unused variable warning.
-bool IdempotentOperationChecker::isSelfAssign(const Expr *LHS, const Expr *RHS) {
- LHS = LHS->IgnoreParenCasts();
- RHS = RHS->IgnoreParenCasts();
-
- const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS);
- if (!LHS_DR)
- return false;
-
- const VarDecl *VD = dyn_cast<VarDecl>(LHS_DR->getDecl());
- if (!VD)
- return false;
-
- const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS);
- if (!RHS_DR)
- return false;
-
- if (VD != RHS_DR->getDecl())
- return false;
-
- return true;
-}
-
-// Returns true if the Expr points to a VarDecl that is not read anywhere
-// outside of self-assignments.
-bool IdempotentOperationChecker::isUnused(const Expr *E,
- AnalysisDeclContext *AC) {
- if (!E)
- return false;
-
- const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts());
- if (!DR)
- return false;
-
- const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
- if (!VD)
- return false;
-
- if (AC->getPseudoConstantAnalysis()->wasReferenced(VD))
- return false;
-
- return true;
-}
-
-// Check for self casts truncating/extending a variable
-bool IdempotentOperationChecker::isTruncationExtensionAssignment(
- const Expr *LHS,
- const Expr *RHS) {
-
- const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS->IgnoreParenCasts());
- if (!LHS_DR)
- return false;
-
- const VarDecl *VD = dyn_cast<VarDecl>(LHS_DR->getDecl());
- if (!VD)
- return false;
-
- const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS->IgnoreParenCasts());
- if (!RHS_DR)
- return false;
-
- if (VD != RHS_DR->getDecl())
- return false;
-
- return dyn_cast<DeclRefExpr>(RHS->IgnoreParenLValueCasts()) == NULL;
-}
-
-// Returns false if a path to this block was not completely analyzed, or true
-// otherwise.
-bool
-IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisDeclContext *AC,
- const CFGBlock *CB,
- const CoreEngine &CE) {
-
- CFGReverseBlockReachabilityAnalysis *CRA = AC->getCFGReachablityAnalysis();
-
- // Test for reachability from any aborted blocks to this block
- typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator;
- for (ExhaustedIterator I = CE.blocks_exhausted_begin(),
- E = CE.blocks_exhausted_end(); I != E; ++I) {
- const BlockEdge &BE = I->first;
-
- // The destination block on the BlockEdge is the first block that was not
- // analyzed. If we can reach this block from the aborted block, then this
- // block was not completely analyzed.
- //
- // Also explicitly check if the current block is the destination block.
- // While technically reachable, it means we aborted the analysis on
- // a path that included that block.
- const CFGBlock *destBlock = BE.getDst();
- if (destBlock == CB || CRA->isReachable(destBlock, CB))
- return false;
- }
-
- // Test for reachability from blocks we just gave up on.
- typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator;
- for (AbortedIterator I = CE.blocks_aborted_begin(),
- E = CE.blocks_aborted_end(); I != E; ++I) {
- const CFGBlock *destBlock = I->first;
- if (destBlock == CB || CRA->isReachable(destBlock, CB))
- return false;
- }
-
- // For the items still on the worklist, see if they are in blocks that
- // can eventually reach 'CB'.
- class VisitWL : public WorkList::Visitor {
- const CFGStmtMap *CBM;
- const CFGBlock *TargetBlock;
- CFGReverseBlockReachabilityAnalysis &CRA;
- public:
- VisitWL(const CFGStmtMap *cbm, const CFGBlock *targetBlock,
- CFGReverseBlockReachabilityAnalysis &cra)
- : CBM(cbm), TargetBlock(targetBlock), CRA(cra) {}
- virtual bool visit(const WorkListUnit &U) {
- ProgramPoint P = U.getNode()->getLocation();
- const CFGBlock *B = 0;
- if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
- B = CBM->getBlock(SP->getStmt());
- } else if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
- B = BE->getDst();
- } else if (Optional<BlockEntrance> BEnt = P.getAs<BlockEntrance>()) {
- B = BEnt->getBlock();
- } else if (Optional<BlockExit> BExit = P.getAs<BlockExit>()) {
- B = BExit->getBlock();
- }
- if (!B)
- return true;
-
- return B == TargetBlock || CRA.isReachable(B, TargetBlock);
- }
- };
- VisitWL visitWL(AC->getCFGStmtMap(), CB, *CRA);
- // Were there any items in the worklist that could potentially reach
- // this block?
- if (CE.getWorkList()->visitItemsInWorkList(visitWL))
- return false;
-
- // Verify that this block is reachable from the entry block
- if (!CRA->isReachable(&AC->getCFG()->getEntry(), CB))
- return false;
-
- // If we get to this point, there is no connection to the entry block or an
- // aborted block. This path is unreachable and we can report the error.
- return true;
-}
-
-// Recursive function that determines whether an expression contains any element
-// that varies. This could be due to a compile-time constant like sizeof. An
-// expression may also involve a variable that behaves like a constant. The
-// function returns true if the expression varies, and false otherwise.
-bool IdempotentOperationChecker::CanVary(const Expr *Ex,
- AnalysisDeclContext *AC) {
- // Parentheses and casts are irrelevant here
- Ex = Ex->IgnoreParenCasts();
-
- if (Ex->getLocStart().isMacroID())
- return false;
-
- switch (Ex->getStmtClass()) {
- // Trivially true cases
- case Stmt::ArraySubscriptExprClass:
- case Stmt::MemberExprClass:
- case Stmt::StmtExprClass:
- case Stmt::CallExprClass:
- case Stmt::VAArgExprClass:
- case Stmt::ShuffleVectorExprClass:
- return true;
- default:
- return true;
-
- // Trivially false cases
- case Stmt::IntegerLiteralClass:
- case Stmt::CharacterLiteralClass:
- case Stmt::FloatingLiteralClass:
- case Stmt::PredefinedExprClass:
- case Stmt::ImaginaryLiteralClass:
- case Stmt::StringLiteralClass:
- case Stmt::OffsetOfExprClass:
- case Stmt::CompoundLiteralExprClass:
- case Stmt::AddrLabelExprClass:
- case Stmt::BinaryTypeTraitExprClass:
- case Stmt::GNUNullExprClass:
- case Stmt::InitListExprClass:
- case Stmt::DesignatedInitExprClass:
- case Stmt::BlockExprClass:
- return false;
-
- // Cases requiring custom logic
- case Stmt::UnaryExprOrTypeTraitExprClass: {
- const UnaryExprOrTypeTraitExpr *SE =
- cast<const UnaryExprOrTypeTraitExpr>(Ex);
- if (SE->getKind() != UETT_SizeOf)
- return false;
- return SE->getTypeOfArgument()->isVariableArrayType();
- }
- case Stmt::DeclRefExprClass:
- // Check for constants/pseudoconstants
- return !isConstantOrPseudoConstant(cast<DeclRefExpr>(Ex), AC);
-
- // The next cases require recursion for subexpressions
- case Stmt::BinaryOperatorClass: {
- const BinaryOperator *B = cast<const BinaryOperator>(Ex);
-
- // Exclude cases involving pointer arithmetic. These are usually
- // false positives.
- if (B->getOpcode() == BO_Sub || B->getOpcode() == BO_Add)
- if (B->getLHS()->getType()->getAs<PointerType>())
- return false;
-
- return CanVary(B->getRHS(), AC)
- || CanVary(B->getLHS(), AC);
- }
- case Stmt::UnaryOperatorClass:
- return CanVary(cast<UnaryOperator>(Ex)->getSubExpr(), AC);
- case Stmt::ConditionalOperatorClass:
- case Stmt::BinaryConditionalOperatorClass:
- return CanVary(cast<AbstractConditionalOperator>(Ex)->getCond(), AC);
- }
-}
-
-// Returns true if a DeclRefExpr is or behaves like a constant.
-bool IdempotentOperationChecker::isConstantOrPseudoConstant(
- const DeclRefExpr *DR,
- AnalysisDeclContext *AC) {
- // Check if the type of the Decl is const-qualified
- if (DR->getType().isConstQualified())
- return true;
-
- // Check for an enum
- if (isa<EnumConstantDecl>(DR->getDecl()))
- return true;
-
- const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
- if (!VD)
- return true;
-
- // Check if the Decl behaves like a constant. This check also takes care of
- // static variables, which can only change between function calls if they are
- // modified in the AST.
- PseudoConstantAnalysis *PCA = AC->getPseudoConstantAnalysis();
- if (PCA->isPseudoConstant(VD))
- return true;
-
- return false;
-}
-
-// Recursively find any substatements containing VarDecl's with storage other
-// than local
-bool IdempotentOperationChecker::containsNonLocalVarDecl(const Stmt *S) {
- const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S);
-
- if (DR)
- if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
- if (!VD->hasLocalStorage())
- return true;
-
- for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
- ++I)
- if (const Stmt *child = *I)
- if (containsNonLocalVarDecl(child))
- return true;
-
- return false;
-}
-
-
-void ento::registerIdempotentOperationChecker(CheckerManager &mgr) {
- mgr.registerChecker<IdempotentOperationChecker>();
-}
diff --git a/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp b/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
index e696e38597bc..d5c52b4c6a31 100644
--- a/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
@@ -11,22 +11,23 @@
/// \brief This defines IdenticalExprChecker, a check that warns about
/// unintended use of identical expressions.
///
-/// It checks for use of identical expressions with comparison operators.
+/// It checks for use of identical expressions with comparison operators and
+/// inside conditional expressions.
///
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/AST/RecursiveASTVisitor.h"
using namespace clang;
using namespace ento;
-static bool isIdenticalExpr(const ASTContext &Ctx, const Expr *Expr1,
- const Expr *Expr2);
+static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
+ const Stmt *Stmt2, bool IgnoreSideEffects = false);
//===----------------------------------------------------------------------===//
// FindIdenticalExprVisitor - Identify nodes using identical expressions.
//===----------------------------------------------------------------------===//
@@ -34,23 +35,153 @@ static bool isIdenticalExpr(const ASTContext &Ctx, const Expr *Expr1,
namespace {
class FindIdenticalExprVisitor
: public RecursiveASTVisitor<FindIdenticalExprVisitor> {
+ BugReporter &BR;
+ const CheckerBase *Checker;
+ AnalysisDeclContext *AC;
public:
- explicit FindIdenticalExprVisitor(BugReporter &B, AnalysisDeclContext *A)
- : BR(B), AC(A) {}
+ explicit FindIdenticalExprVisitor(BugReporter &B,
+ const CheckerBase *Checker,
+ AnalysisDeclContext *A)
+ : BR(B), Checker(Checker), AC(A) {}
// FindIdenticalExprVisitor only visits nodes
- // that are binary operators.
+ // that are binary operators, if statements or
+ // conditional operators.
bool VisitBinaryOperator(const BinaryOperator *B);
+ bool VisitIfStmt(const IfStmt *I);
+ bool VisitConditionalOperator(const ConditionalOperator *C);
private:
- BugReporter &BR;
- AnalysisDeclContext *AC;
+ void reportIdenticalExpr(const BinaryOperator *B, bool CheckBitwise,
+ ArrayRef<SourceRange> Sr);
+ void checkBitwiseOrLogicalOp(const BinaryOperator *B, bool CheckBitwise);
+ void checkComparisonOp(const BinaryOperator *B);
};
} // end anonymous namespace
+void FindIdenticalExprVisitor::reportIdenticalExpr(const BinaryOperator *B,
+ bool CheckBitwise,
+ ArrayRef<SourceRange> Sr) {
+ StringRef Message;
+ if (CheckBitwise)
+ Message = "identical expressions on both sides of bitwise operator";
+ else
+ Message = "identical expressions on both sides of logical operator";
+
+ PathDiagnosticLocation ELoc =
+ PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
+ BR.EmitBasicReport(AC->getDecl(), Checker,
+ "Use of identical expressions",
+ categories::LogicError,
+ Message, ELoc, Sr);
+}
+
+void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(const BinaryOperator *B,
+ bool CheckBitwise) {
+ SourceRange Sr[2];
+
+ const Expr *LHS = B->getLHS();
+ const Expr *RHS = B->getRHS();
+
+ // Split operators as long as we still have operators to split on. We will
+ // get called for every binary operator in an expression so there is no need
+ // to check every one against each other here, just the right most one with
+ // the others.
+ while (const BinaryOperator *B2 = dyn_cast<BinaryOperator>(LHS)) {
+ if (B->getOpcode() != B2->getOpcode())
+ break;
+ if (isIdenticalStmt(AC->getASTContext(), RHS, B2->getRHS())) {
+ Sr[0] = RHS->getSourceRange();
+ Sr[1] = B2->getRHS()->getSourceRange();
+ reportIdenticalExpr(B, CheckBitwise, Sr);
+ }
+ LHS = B2->getLHS();
+ }
+
+ if (isIdenticalStmt(AC->getASTContext(), RHS, LHS)) {
+ Sr[0] = RHS->getSourceRange();
+ Sr[1] = LHS->getSourceRange();
+ reportIdenticalExpr(B, CheckBitwise, Sr);
+ }
+}
+
+bool FindIdenticalExprVisitor::VisitIfStmt(const IfStmt *I) {
+ const Stmt *Stmt1 = I->getThen();
+ const Stmt *Stmt2 = I->getElse();
+
+ // Check for identical conditions:
+ //
+ // if (b) {
+ // foo1();
+ // } else if (b) {
+ // foo2();
+ // }
+ if (Stmt1 && Stmt2) {
+ const Expr *Cond1 = I->getCond();
+ const Stmt *Else = Stmt2;
+ while (const IfStmt *I2 = dyn_cast_or_null<IfStmt>(Else)) {
+ const Expr *Cond2 = I2->getCond();
+ if (isIdenticalStmt(AC->getASTContext(), Cond1, Cond2, false)) {
+ SourceRange Sr = Cond1->getSourceRange();
+ PathDiagnosticLocation ELoc(Cond2, BR.getSourceManager(), AC);
+ BR.EmitBasicReport(AC->getDecl(), Checker, "Identical conditions",
+ categories::LogicError,
+ "expression is identical to previous condition",
+ ELoc, Sr);
+ }
+ Else = I2->getElse();
+ }
+ }
+
+ if (!Stmt1 || !Stmt2)
+ return true;
+
+ // Special handling for code like:
+ //
+ // if (b) {
+ // i = 1;
+ // } else
+ // i = 1;
+ if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt1)) {
+ if (CompStmt->size() == 1)
+ Stmt1 = CompStmt->body_back();
+ }
+ if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt2)) {
+ if (CompStmt->size() == 1)
+ Stmt2 = CompStmt->body_back();
+ }
+
+ if (isIdenticalStmt(AC->getASTContext(), Stmt1, Stmt2, true)) {
+ PathDiagnosticLocation ELoc =
+ PathDiagnosticLocation::createBegin(I, BR.getSourceManager(), AC);
+ BR.EmitBasicReport(AC->getDecl(), Checker,
+ "Identical branches",
+ categories::LogicError,
+ "true and false branches are identical", ELoc);
+ }
+ return true;
+}
+
bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) {
BinaryOperator::Opcode Op = B->getOpcode();
- if (!BinaryOperator::isComparisonOp(Op))
- return true;
+
+ if (BinaryOperator::isBitwiseOp(Op))
+ checkBitwiseOrLogicalOp(B, true);
+
+ if (BinaryOperator::isLogicalOp(Op))
+ checkBitwiseOrLogicalOp(B, false);
+
+ if (BinaryOperator::isComparisonOp(Op))
+ checkComparisonOp(B);
+
+ // We want to visit ALL nodes (subexpressions of binary comparison
+ // expressions too) that contains comparison operators.
+ // True is always returned to traverse ALL nodes.
+ return true;
+}
+
+void FindIdenticalExprVisitor::checkComparisonOp(const BinaryOperator *B) {
+ BinaryOperator::Opcode Op = B->getOpcode();
+
//
// Special case for floating-point representation.
//
@@ -83,26 +214,26 @@ bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) {
(DeclRef2->getType()->hasFloatingRepresentation())) {
if (DeclRef1->getDecl() == DeclRef2->getDecl()) {
if ((Op == BO_EQ) || (Op == BO_NE)) {
- return true;
+ return;
}
}
}
} else if ((FloatLit1) && (FloatLit2)) {
if (FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue())) {
if ((Op == BO_EQ) || (Op == BO_NE)) {
- return true;
+ return;
}
}
} else if (LHS->getType()->hasFloatingRepresentation()) {
// If any side of comparison operator still has floating-point
// representation, then it's an expression. Don't warn.
// Here only LHS is checked since RHS will be implicit casted to float.
- return true;
+ return;
} else {
// No special case with floating-point representation, report as usual.
}
- if (isIdenticalExpr(AC->getASTContext(), B->getLHS(), B->getRHS())) {
+ if (isIdenticalStmt(AC->getASTContext(), B->getLHS(), B->getRHS())) {
PathDiagnosticLocation ELoc =
PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
StringRef Message;
@@ -110,15 +241,41 @@ bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) {
Message = "comparison of identical expressions always evaluates to true";
else
Message = "comparison of identical expressions always evaluates to false";
- BR.EmitBasicReport(AC->getDecl(), "Compare of identical expressions",
+ BR.EmitBasicReport(AC->getDecl(), Checker,
+ "Compare of identical expressions",
categories::LogicError, Message, ELoc);
}
- // We want to visit ALL nodes (subexpressions of binary comparison
- // expressions too) that contains comparison operators.
- // True is always returned to traverse ALL nodes.
+}
+
+bool FindIdenticalExprVisitor::VisitConditionalOperator(
+ const ConditionalOperator *C) {
+
+ // Check if expressions in conditional expression are identical
+ // from a symbolic point of view.
+
+ if (isIdenticalStmt(AC->getASTContext(), C->getTrueExpr(),
+ C->getFalseExpr(), true)) {
+ PathDiagnosticLocation ELoc =
+ PathDiagnosticLocation::createConditionalColonLoc(
+ C, BR.getSourceManager());
+
+ SourceRange Sr[2];
+ Sr[0] = C->getTrueExpr()->getSourceRange();
+ Sr[1] = C->getFalseExpr()->getSourceRange();
+ BR.EmitBasicReport(
+ AC->getDecl(), Checker,
+ "Identical expressions in conditional expression",
+ categories::LogicError,
+ "identical expressions on both sides of ':' in conditional expression",
+ ELoc, Sr);
+ }
+ // We want to visit ALL nodes (expressions in conditional
+ // expressions too) that contains conditional operators,
+ // thus always return true to traverse ALL nodes.
return true;
}
-/// \brief Determines whether two expression trees are identical regarding
+
+/// \brief Determines whether two statement trees are identical regarding
/// operators and symbols.
///
/// Exceptions: expressions containing macros or functions with possible side
@@ -126,82 +283,189 @@ bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) {
/// Limitations: (t + u) and (u + t) are not considered identical.
/// t*(u + t) and t*u + t*t are not considered identical.
///
-static bool isIdenticalExpr(const ASTContext &Ctx, const Expr *Expr1,
- const Expr *Expr2) {
- // If Expr1 & Expr2 are of different class then they are not
- // identical expression.
- if (Expr1->getStmtClass() != Expr2->getStmtClass())
- return false;
- // If Expr1 has side effects then don't warn even if expressions
- // are identical.
- if (Expr1->HasSideEffects(Ctx))
- return false;
- // Is expression is based on macro then don't warn even if
- // the expressions are identical.
- if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID()))
- return false;
- // If all children of two expressions are identical, return true.
- Expr::const_child_iterator I1 = Expr1->child_begin();
- Expr::const_child_iterator I2 = Expr2->child_begin();
- while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) {
- const Expr *Child1 = dyn_cast<Expr>(*I1);
- const Expr *Child2 = dyn_cast<Expr>(*I2);
- if (!Child1 || !Child2 || !isIdenticalExpr(Ctx, Child1, Child2))
- return false;
- ++I1;
- ++I2;
- }
- // If there are different number of children in the expressions, return false.
- // (TODO: check if this is a redundant condition.)
- if (I1 != Expr1->child_end())
+static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
+ const Stmt *Stmt2, bool IgnoreSideEffects) {
+
+ if (!Stmt1 || !Stmt2) {
+ if (!Stmt1 && !Stmt2)
+ return true;
return false;
- if (I2 != Expr2->child_end())
+ }
+
+ // If Stmt1 & Stmt2 are of different class then they are not
+ // identical statements.
+ if (Stmt1->getStmtClass() != Stmt2->getStmtClass())
return false;
- switch (Expr1->getStmtClass()) {
+ const Expr *Expr1 = dyn_cast<Expr>(Stmt1);
+ const Expr *Expr2 = dyn_cast<Expr>(Stmt2);
+
+ if (Expr1 && Expr2) {
+ // If Stmt1 has side effects then don't warn even if expressions
+ // are identical.
+ if (!IgnoreSideEffects && Expr1->HasSideEffects(Ctx))
+ return false;
+ // If either expression comes from a macro then don't warn even if
+ // the expressions are identical.
+ if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID()))
+ return false;
+
+ // If all children of two expressions are identical, return true.
+ Expr::const_child_iterator I1 = Expr1->child_begin();
+ Expr::const_child_iterator I2 = Expr2->child_begin();
+ while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) {
+ if (!*I1 || !*I2 || !isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
+ return false;
+ ++I1;
+ ++I2;
+ }
+ // If there are different number of children in the statements, return
+ // false.
+ if (I1 != Expr1->child_end())
+ return false;
+ if (I2 != Expr2->child_end())
+ return false;
+ }
+
+ switch (Stmt1->getStmtClass()) {
default:
return false;
+ case Stmt::CallExprClass:
case Stmt::ArraySubscriptExprClass:
- case Stmt::CStyleCastExprClass:
case Stmt::ImplicitCastExprClass:
case Stmt::ParenExprClass:
+ case Stmt::BreakStmtClass:
+ case Stmt::ContinueStmtClass:
+ case Stmt::NullStmtClass:
+ return true;
+ case Stmt::CStyleCastExprClass: {
+ const CStyleCastExpr* CastExpr1 = cast<CStyleCastExpr>(Stmt1);
+ const CStyleCastExpr* CastExpr2 = cast<CStyleCastExpr>(Stmt2);
+
+ return CastExpr1->getTypeAsWritten() == CastExpr2->getTypeAsWritten();
+ }
+ case Stmt::ReturnStmtClass: {
+ const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1);
+ const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2);
+
+ return isIdenticalStmt(Ctx, ReturnStmt1->getRetValue(),
+ ReturnStmt2->getRetValue(), IgnoreSideEffects);
+ }
+ case Stmt::ForStmtClass: {
+ const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1);
+ const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2);
+
+ if (!isIdenticalStmt(Ctx, ForStmt1->getInit(), ForStmt2->getInit(),
+ IgnoreSideEffects))
+ return false;
+ if (!isIdenticalStmt(Ctx, ForStmt1->getCond(), ForStmt2->getCond(),
+ IgnoreSideEffects))
+ return false;
+ if (!isIdenticalStmt(Ctx, ForStmt1->getInc(), ForStmt2->getInc(),
+ IgnoreSideEffects))
+ return false;
+ if (!isIdenticalStmt(Ctx, ForStmt1->getBody(), ForStmt2->getBody(),
+ IgnoreSideEffects))
+ return false;
+ return true;
+ }
+ case Stmt::DoStmtClass: {
+ const DoStmt *DStmt1 = cast<DoStmt>(Stmt1);
+ const DoStmt *DStmt2 = cast<DoStmt>(Stmt2);
+
+ if (!isIdenticalStmt(Ctx, DStmt1->getCond(), DStmt2->getCond(),
+ IgnoreSideEffects))
+ return false;
+ if (!isIdenticalStmt(Ctx, DStmt1->getBody(), DStmt2->getBody(),
+ IgnoreSideEffects))
+ return false;
+ return true;
+ }
+ case Stmt::WhileStmtClass: {
+ const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1);
+ const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2);
+
+ if (!isIdenticalStmt(Ctx, WStmt1->getCond(), WStmt2->getCond(),
+ IgnoreSideEffects))
+ return false;
+ if (!isIdenticalStmt(Ctx, WStmt1->getBody(), WStmt2->getBody(),
+ IgnoreSideEffects))
+ return false;
return true;
+ }
+ case Stmt::IfStmtClass: {
+ const IfStmt *IStmt1 = cast<IfStmt>(Stmt1);
+ const IfStmt *IStmt2 = cast<IfStmt>(Stmt2);
+
+ if (!isIdenticalStmt(Ctx, IStmt1->getCond(), IStmt2->getCond(),
+ IgnoreSideEffects))
+ return false;
+ if (!isIdenticalStmt(Ctx, IStmt1->getThen(), IStmt2->getThen(),
+ IgnoreSideEffects))
+ return false;
+ if (!isIdenticalStmt(Ctx, IStmt1->getElse(), IStmt2->getElse(),
+ IgnoreSideEffects))
+ return false;
+ return true;
+ }
+ case Stmt::CompoundStmtClass: {
+ const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1);
+ const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2);
+
+ if (CompStmt1->size() != CompStmt2->size())
+ return false;
+
+ CompoundStmt::const_body_iterator I1 = CompStmt1->body_begin();
+ CompoundStmt::const_body_iterator I2 = CompStmt2->body_begin();
+ while (I1 != CompStmt1->body_end() && I2 != CompStmt2->body_end()) {
+ if (!isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
+ return false;
+ ++I1;
+ ++I2;
+ }
+
+ return true;
+ }
+ case Stmt::CompoundAssignOperatorClass:
case Stmt::BinaryOperatorClass: {
- const BinaryOperator *BinOp1 = dyn_cast<BinaryOperator>(Expr1);
- const BinaryOperator *BinOp2 = dyn_cast<BinaryOperator>(Expr2);
+ const BinaryOperator *BinOp1 = cast<BinaryOperator>(Stmt1);
+ const BinaryOperator *BinOp2 = cast<BinaryOperator>(Stmt2);
return BinOp1->getOpcode() == BinOp2->getOpcode();
}
case Stmt::CharacterLiteralClass: {
- const CharacterLiteral *CharLit1 = dyn_cast<CharacterLiteral>(Expr1);
- const CharacterLiteral *CharLit2 = dyn_cast<CharacterLiteral>(Expr2);
+ const CharacterLiteral *CharLit1 = cast<CharacterLiteral>(Stmt1);
+ const CharacterLiteral *CharLit2 = cast<CharacterLiteral>(Stmt2);
return CharLit1->getValue() == CharLit2->getValue();
}
case Stmt::DeclRefExprClass: {
- const DeclRefExpr *DeclRef1 = dyn_cast<DeclRefExpr>(Expr1);
- const DeclRefExpr *DeclRef2 = dyn_cast<DeclRefExpr>(Expr2);
+ const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1);
+ const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2);
return DeclRef1->getDecl() == DeclRef2->getDecl();
}
case Stmt::IntegerLiteralClass: {
- const IntegerLiteral *IntLit1 = dyn_cast<IntegerLiteral>(Expr1);
- const IntegerLiteral *IntLit2 = dyn_cast<IntegerLiteral>(Expr2);
+ const IntegerLiteral *IntLit1 = cast<IntegerLiteral>(Stmt1);
+ const IntegerLiteral *IntLit2 = cast<IntegerLiteral>(Stmt2);
return IntLit1->getValue() == IntLit2->getValue();
}
case Stmt::FloatingLiteralClass: {
- const FloatingLiteral *FloatLit1 = dyn_cast<FloatingLiteral>(Expr1);
- const FloatingLiteral *FloatLit2 = dyn_cast<FloatingLiteral>(Expr2);
+ const FloatingLiteral *FloatLit1 = cast<FloatingLiteral>(Stmt1);
+ const FloatingLiteral *FloatLit2 = cast<FloatingLiteral>(Stmt2);
return FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue());
}
+ case Stmt::StringLiteralClass: {
+ const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1);
+ const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2);
+ return StringLit1->getString() == StringLit2->getString();
+ }
case Stmt::MemberExprClass: {
- const MemberExpr *MemberExpr1 = dyn_cast<MemberExpr>(Expr1);
- const MemberExpr *MemberExpr2 = dyn_cast<MemberExpr>(Expr2);
- return MemberExpr1->getMemberDecl() == MemberExpr2->getMemberDecl();
+ const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1);
+ const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2);
+ return MemberStmt1->getMemberDecl() == MemberStmt2->getMemberDecl();
}
case Stmt::UnaryOperatorClass: {
- const UnaryOperator *UnaryOp1 = dyn_cast<UnaryOperator>(Expr1);
- const UnaryOperator *UnaryOp2 = dyn_cast<UnaryOperator>(Expr2);
- if (UnaryOp1->getOpcode() != UnaryOp2->getOpcode())
- return false;
- return !UnaryOp1->isIncrementDecrementOp();
+ const UnaryOperator *UnaryOp1 = cast<UnaryOperator>(Stmt1);
+ const UnaryOperator *UnaryOp2 = cast<UnaryOperator>(Stmt2);
+ return UnaryOp1->getOpcode() == UnaryOp2->getOpcode();
}
}
}
@@ -215,7 +479,7 @@ class FindIdenticalExprChecker : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
BugReporter &BR) const {
- FindIdenticalExprVisitor Visitor(BR, Mgr.getAnalysisDeclContext(D));
+ FindIdenticalExprVisitor Visitor(BR, this, Mgr.getAnalysisDeclContext(D));
Visitor.TraverseDecl(const_cast<Decl *>(D));
}
};
diff --git a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
index cc940be7b187..1926600b6d6e 100644
--- a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
@@ -49,6 +49,9 @@ struct ChecksFilter {
DefaultBool check_MissingInvalidationMethod;
/// Check that all ivars are invalidated.
DefaultBool check_InstanceVariableInvalidation;
+
+ CheckName checkName_MissingInvalidationMethod;
+ CheckName checkName_InstanceVariableInvalidation;
};
class IvarInvalidationCheckerImpl {
@@ -154,7 +157,7 @@ class IvarInvalidationCheckerImpl {
PropertySetterToIvarMap(InPropertySetterToIvarMap),
PropertyGetterToIvarMap(InPropertyGetterToIvarMap),
PropertyToIvarMap(InPropertyToIvarMap),
- InvalidationMethod(0),
+ InvalidationMethod(nullptr),
Ctx(InCtx) {}
void VisitStmt(const Stmt *S) { VisitChildren(S); }
@@ -200,7 +203,8 @@ class IvarInvalidationCheckerImpl {
const ObjCIvarDecl *IvarDecl,
const IvarToPropMapTy &IvarToPopertyMap);
- void reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl,
+ void reportNoInvalidationMethod(CheckName CheckName,
+ const ObjCIvarDecl *FirstIvarDecl,
const IvarToPropMapTy &IvarToPopertyMap,
const ObjCInterfaceDecl *InterfaceD,
bool MissingDeclaration) const;
@@ -223,10 +227,7 @@ public:
};
static bool isInvalidationMethod(const ObjCMethodDecl *M, bool LookForPartial) {
- for (specific_attr_iterator<AnnotateAttr>
- AI = M->specific_attr_begin<AnnotateAttr>(),
- AE = M->specific_attr_end<AnnotateAttr>(); AI != AE; ++AI) {
- const AnnotateAttr *Ann = *AI;
+ for (const auto *Ann : M->specific_attrs<AnnotateAttr>()) {
if (!LookForPartial &&
Ann->getAnnotation() == "objc_instance_variable_invalidator")
return true;
@@ -247,33 +248,22 @@ void IvarInvalidationCheckerImpl::containsInvalidationMethod(
// TODO: Cache the results.
// Check all methods.
- for (ObjCContainerDecl::method_iterator
- I = D->meth_begin(),
- E = D->meth_end(); I != E; ++I) {
- const ObjCMethodDecl *MDI = *I;
- if (isInvalidationMethod(MDI, Partial))
- OutInfo.addInvalidationMethod(
- cast<ObjCMethodDecl>(MDI->getCanonicalDecl()));
- }
+ for (const auto *MDI : D->methods())
+ if (isInvalidationMethod(MDI, Partial))
+ OutInfo.addInvalidationMethod(
+ cast<ObjCMethodDecl>(MDI->getCanonicalDecl()));
// If interface, check all parent protocols and super.
if (const ObjCInterfaceDecl *InterfD = dyn_cast<ObjCInterfaceDecl>(D)) {
// Visit all protocols.
- for (ObjCInterfaceDecl::protocol_iterator
- I = InterfD->protocol_begin(),
- E = InterfD->protocol_end(); I != E; ++I) {
- containsInvalidationMethod((*I)->getDefinition(), OutInfo, Partial);
- }
+ for (const auto *I : InterfD->protocols())
+ containsInvalidationMethod(I->getDefinition(), OutInfo, Partial);
// Visit all categories in case the invalidation method is declared in
// a category.
- for (ObjCInterfaceDecl::visible_extensions_iterator
- Ext = InterfD->visible_extensions_begin(),
- ExtEnd = InterfD->visible_extensions_end();
- Ext != ExtEnd; ++Ext) {
- containsInvalidationMethod(*Ext, OutInfo, Partial);
- }
+ for (const auto *Ext : InterfD->visible_extensions())
+ containsInvalidationMethod(Ext, OutInfo, Partial);
containsInvalidationMethod(InterfD->getSuperClass(), OutInfo, Partial);
return;
@@ -281,10 +271,8 @@ void IvarInvalidationCheckerImpl::containsInvalidationMethod(
// If protocol, check all parent protocols.
if (const ObjCProtocolDecl *ProtD = dyn_cast<ObjCProtocolDecl>(D)) {
- for (ObjCInterfaceDecl::protocol_iterator
- I = ProtD->protocol_begin(),
- E = ProtD->protocol_end(); I != E; ++I) {
- containsInvalidationMethod((*I)->getDefinition(), OutInfo, Partial);
+ for (const auto *I : ProtD->protocols()) {
+ containsInvalidationMethod(I->getDefinition(), OutInfo, Partial);
}
return;
}
@@ -318,7 +306,7 @@ const ObjCIvarDecl *IvarInvalidationCheckerImpl::findPropertyBackingIvar(
const ObjCInterfaceDecl *InterfaceD,
IvarSet &TrackedIvars,
const ObjCIvarDecl **FirstIvarDecl) {
- const ObjCIvarDecl *IvarD = 0;
+ const ObjCIvarDecl *IvarD = nullptr;
// Lookup for the synthesized case.
IvarD = Prop->getPropertyIvarDecl();
@@ -355,7 +343,7 @@ const ObjCIvarDecl *IvarInvalidationCheckerImpl::findPropertyBackingIvar(
// Note, this is a possible source of false positives. We could look at the
// getter implementation to find the ivar when its name is not derived from
// the property name.
- return 0;
+ return nullptr;
}
void IvarInvalidationCheckerImpl::printIvar(llvm::raw_svector_ostream &os,
@@ -379,7 +367,7 @@ visit(const ObjCImplementationDecl *ImplD) const {
// Record the first Ivar needing invalidation; used in reporting when only
// one ivar is sufficient. Cannot grab the first on the Ivars set to ensure
// deterministic output.
- const ObjCIvarDecl *FirstIvarDecl = 0;
+ const ObjCIvarDecl *FirstIvarDecl = nullptr;
const ObjCInterfaceDecl *InterfaceD = ImplD->getClassInterface();
// Collect ivars declared in this class, its extensions and its implementation
@@ -476,7 +464,8 @@ visit(const ObjCImplementationDecl *ImplD) const {
// Report an error in case none of the invalidation methods are declared.
if (!Info.needsInvalidation() && !PartialInfo.needsInvalidation()) {
if (Filter.check_MissingInvalidationMethod)
- reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD,
+ reportNoInvalidationMethod(Filter.checkName_MissingInvalidationMethod,
+ FirstIvarDecl, IvarToPopertyMap, InterfaceD,
/*MissingDeclaration*/ true);
// If there are no invalidation methods, there is no ivar validation work
// to be done.
@@ -529,20 +518,20 @@ visit(const ObjCImplementationDecl *ImplD) const {
// invalidation methods.
for (IvarSet::const_iterator
I = Ivars.begin(), E = Ivars.end(); I != E; ++I)
- reportIvarNeedsInvalidation(I->first, IvarToPopertyMap, 0);
+ reportIvarNeedsInvalidation(I->first, IvarToPopertyMap, nullptr);
} else {
// Otherwise, no invalidation methods were implemented.
- reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD,
+ reportNoInvalidationMethod(Filter.checkName_InstanceVariableInvalidation,
+ FirstIvarDecl, IvarToPopertyMap, InterfaceD,
/*MissingDeclaration*/ false);
}
}
}
-void IvarInvalidationCheckerImpl::
-reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl,
- const IvarToPropMapTy &IvarToPopertyMap,
- const ObjCInterfaceDecl *InterfaceD,
- bool MissingDeclaration) const {
+void IvarInvalidationCheckerImpl::reportNoInvalidationMethod(
+ CheckName CheckName, const ObjCIvarDecl *FirstIvarDecl,
+ const IvarToPropMapTy &IvarToPopertyMap,
+ const ObjCInterfaceDecl *InterfaceD, bool MissingDeclaration) const {
SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
assert(FirstIvarDecl);
@@ -557,7 +546,7 @@ reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl,
PathDiagnosticLocation IvarDecLocation =
PathDiagnosticLocation::createBegin(FirstIvarDecl, BR.getSourceManager());
- BR.EmitBasicReport(FirstIvarDecl, "Incomplete invalidation",
+ BR.EmitBasicReport(FirstIvarDecl, CheckName, "Incomplete invalidation",
categories::CoreFoundationObjectiveC, os.str(),
IvarDecLocation);
}
@@ -575,15 +564,16 @@ reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD,
PathDiagnosticLocation::createEnd(MethodD->getBody(),
BR.getSourceManager(),
Mgr.getAnalysisDeclContext(MethodD));
- BR.EmitBasicReport(MethodD, "Incomplete invalidation",
+ BR.EmitBasicReport(MethodD, Filter.checkName_InstanceVariableInvalidation,
+ "Incomplete invalidation",
categories::CoreFoundationObjectiveC, os.str(),
MethodDecLocation);
} else {
- BR.EmitBasicReport(IvarD, "Incomplete invalidation",
- categories::CoreFoundationObjectiveC, os.str(),
- PathDiagnosticLocation::createBegin(IvarD,
- BR.getSourceManager()));
-
+ BR.EmitBasicReport(
+ IvarD, Filter.checkName_InstanceVariableInvalidation,
+ "Incomplete invalidation", categories::CoreFoundationObjectiveC,
+ os.str(),
+ PathDiagnosticLocation::createBegin(IvarD, BR.getSourceManager()));
}
}
@@ -727,7 +717,7 @@ void IvarInvalidationCheckerImpl::MethodCrawler::VisitObjCMessageExpr(
if (Receiver) {
InvalidationMethod = MD;
check(Receiver->IgnoreParenCasts());
- InvalidationMethod = 0;
+ InvalidationMethod = nullptr;
}
VisitStmt(ME);
@@ -750,10 +740,13 @@ public:
};
}
-#define REGISTER_CHECKER(name) \
-void ento::register##name(CheckerManager &mgr) {\
- mgr.registerChecker<IvarInvalidationChecker>()->Filter.check_##name = true;\
-}
+#define REGISTER_CHECKER(name) \
+ void ento::register##name(CheckerManager &mgr) { \
+ IvarInvalidationChecker *checker = \
+ mgr.registerChecker<IvarInvalidationChecker>(); \
+ checker->Filter.check_##name = true; \
+ checker->Filter.checkName_##name = mgr.getCurrentCheckName(); \
+ }
REGISTER_CHECKER(InstanceVariableInvalidation)
REGISTER_CHECKER(MissingInvalidationMethod)
diff --git a/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
index 02a7cc34e4d4..0b7375a4b614 100644
--- a/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
@@ -58,7 +58,7 @@ static bool IsStdString(QualType T) {
const TypedefNameDecl *TD = TT->getDecl();
- if (!InNamespace(TD, "std"))
+ if (!TD->isInStdNamespace())
return false;
return TD->getName() == "string";
@@ -115,11 +115,14 @@ static bool IsSmallVector(QualType T) {
namespace {
class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> {
- BugReporter &BR;
const Decl *DeclWithIssue;
+ BugReporter &BR;
+ const CheckerBase *Checker;
+
public:
- StringRefCheckerVisitor(const Decl *declWithIssue, BugReporter &br)
- : BR(br), DeclWithIssue(declWithIssue) {}
+ StringRefCheckerVisitor(const Decl *declWithIssue, BugReporter &br,
+ const CheckerBase *checker)
+ : DeclWithIssue(declWithIssue), BR(br), Checker(checker) {}
void VisitChildren(Stmt *S) {
for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ;
I != E; ++I)
@@ -133,16 +136,17 @@ private:
};
} // end anonymous namespace
-static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR) {
- StringRefCheckerVisitor walker(D, BR);
+static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR,
+ const CheckerBase *Checker) {
+ StringRefCheckerVisitor walker(D, BR, Checker);
walker.Visit(D->getBody());
}
void StringRefCheckerVisitor::VisitDeclStmt(DeclStmt *S) {
VisitChildren(S);
- for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end();I!=E; ++I)
- if (VarDecl *VD = dyn_cast<VarDecl>(*I))
+ for (auto *I : S->decls())
+ if (VarDecl *VD = dyn_cast<VarDecl>(I))
VisitVarDecl(VD);
}
@@ -179,7 +183,7 @@ void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) {
"std::string that it outlives";
PathDiagnosticLocation VDLoc =
PathDiagnosticLocation::createBegin(VD, BR.getSourceManager());
- BR.EmitBasicReport(DeclWithIssue, desc, "LLVM Conventions", desc,
+ BR.EmitBasicReport(DeclWithIssue, Checker, desc, "LLVM Conventions", desc,
VDLoc, Init->getSourceRange());
}
@@ -197,9 +201,7 @@ static bool IsPartOfAST(const CXXRecordDecl *R) {
if (IsClangStmt(R) || IsClangType(R) || IsClangDecl(R) || IsClangAttr(R))
return true;
- for (CXXRecordDecl::base_class_const_iterator I = R->bases_begin(),
- E = R->bases_end(); I!=E; ++I) {
- CXXBaseSpecifier BS = *I;
+ for (const auto &BS : R->bases()) {
QualType T = BS.getType();
if (const RecordType *baseT = T->getAs<RecordType>()) {
CXXRecordDecl *baseD = cast<CXXRecordDecl>(baseT->getDecl());
@@ -216,23 +218,26 @@ class ASTFieldVisitor {
SmallVector<FieldDecl*, 10> FieldChain;
const CXXRecordDecl *Root;
BugReporter &BR;
+ const CheckerBase *Checker;
+
public:
- ASTFieldVisitor(const CXXRecordDecl *root, BugReporter &br)
- : Root(root), BR(br) {}
+ ASTFieldVisitor(const CXXRecordDecl *root, BugReporter &br,
+ const CheckerBase *checker)
+ : Root(root), BR(br), Checker(checker) {}
void Visit(FieldDecl *D);
void ReportError(QualType T);
};
} // end anonymous namespace
-static void CheckASTMemory(const CXXRecordDecl *R, BugReporter &BR) {
+static void CheckASTMemory(const CXXRecordDecl *R, BugReporter &BR,
+ const CheckerBase *Checker) {
if (!IsPartOfAST(R))
return;
- for (RecordDecl::field_iterator I = R->field_begin(), E = R->field_end();
- I != E; ++I) {
- ASTFieldVisitor walker(R, BR);
- walker.Visit(*I);
+ for (auto *I : R->fields()) {
+ ASTFieldVisitor walker(R, BR, Checker);
+ walker.Visit(I);
}
}
@@ -246,9 +251,8 @@ void ASTFieldVisitor::Visit(FieldDecl *D) {
if (const RecordType *RT = T->getAs<RecordType>()) {
const RecordDecl *RD = RT->getDecl()->getDefinition();
- for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
- I != E; ++I)
- Visit(*I);
+ for (auto *I : RD->fields())
+ Visit(I);
}
FieldChain.pop_back();
@@ -284,8 +288,8 @@ void ASTFieldVisitor::ReportError(QualType T) {
// the class may be in the header file, for example).
PathDiagnosticLocation L = PathDiagnosticLocation::createBegin(
FieldChain.front(), BR.getSourceManager());
- BR.EmitBasicReport(Root, "AST node allocates heap memory", "LLVM Conventions",
- os.str(), L);
+ BR.EmitBasicReport(Root, Checker, "AST node allocates heap memory",
+ "LLVM Conventions", os.str(), L);
}
//===----------------------------------------------------------------------===//
@@ -300,12 +304,12 @@ public:
void checkASTDecl(const CXXRecordDecl *R, AnalysisManager& mgr,
BugReporter &BR) const {
if (R->isCompleteDefinition())
- CheckASTMemory(R, BR);
+ CheckASTMemory(R, BR, this);
}
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
- CheckStringRefAssignedTemporary(D, BR);
+ CheckStringRefAssignedTemporary(D, BR, this);
}
};
}
diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index f1f06c798cde..0f227bba0000 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -29,7 +29,7 @@ namespace {
class MacOSKeychainAPIChecker : public Checker<check::PreStmt<CallExpr>,
check::PostStmt<CallExpr>,
check::DeadSymbols> {
- mutable OwningPtr<BugType> BT;
+ mutable std::unique_ptr<BugType> BT;
public:
/// AllocationState is a part of the checker specific state together with the
@@ -91,7 +91,7 @@ private:
inline void initBugType() const {
if (!BT)
- BT.reset(new BugType("Improper use of SecKeychain API",
+ BT.reset(new BugType(this, "Improper use of SecKeychain API",
"API Misuse (Apple)"));
}
@@ -139,7 +139,7 @@ private:
SecKeychainBugVisitor(SymbolRef S) : Sym(S) {}
virtual ~SecKeychainBugVisitor() {}
- void Profile(llvm::FoldingSetNodeID &ID) const {
+ void Profile(llvm::FoldingSetNodeID &ID) const override {
static int X = 0;
ID.AddPointer(&X);
ID.AddPointer(Sym);
@@ -148,7 +148,7 @@ private:
PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext &BRC,
- BugReport &BR);
+ BugReport &BR) override;
};
};
}
@@ -224,7 +224,7 @@ static SymbolRef getAsPointeeSymbol(const Expr *Expr,
if (sym)
return sym;
}
- return 0;
+ return nullptr;
}
// When checking for error code, we need to consider the following cases:
@@ -458,7 +458,7 @@ void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
// If the argument entered as an enclosing function parameter, skip it to
// avoid false positives.
if (isEnclosingFunctionParam(ArgExpr) &&
- C.getLocationContext()->getParent() == 0)
+ C.getLocationContext()->getParent() == nullptr)
return;
if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) {
@@ -503,7 +503,7 @@ MacOSKeychainAPIChecker::getAllocationNode(const ExplodedNode *N,
// symbol was tracked.
if (N->getLocationContext() == LeakContext)
AllocNode = N;
- N = N->pred_empty() ? NULL : *(N->pred_begin());
+ N = N->pred_empty() ? nullptr : *(N->pred_begin());
}
return AllocNode;
@@ -525,7 +525,7 @@ BugReport *MacOSKeychainAPIChecker::
// allocated, and only report a single path.
PathDiagnosticLocation LocUsedForUniqueing;
const ExplodedNode *AllocNode = getAllocationNode(N, AP.first, C);
- const Stmt *AllocStmt = 0;
+ const Stmt *AllocStmt = nullptr;
ProgramPoint P = AllocNode->getLocation();
if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>())
AllocStmt = Exit->getCalleeContext()->getCallSite();
@@ -575,7 +575,7 @@ void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
return;
}
- static SimpleProgramPointTag Tag("MacOSKeychainAPIChecker : DeadSymbolsLeak");
+ static CheckerProgramPointTag Tag(this, "DeadSymbolsLeak");
ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
// Generate the error reports.
@@ -596,10 +596,10 @@ PathDiagnosticPiece *MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode(
BugReport &BR) {
const AllocationState *AS = N->getState()->get<AllocatedData>(Sym);
if (!AS)
- return 0;
+ return nullptr;
const AllocationState *ASPrev = PrevN->getState()->get<AllocatedData>(Sym);
if (ASPrev)
- return 0;
+ return nullptr;
// (!ASPrev && AS) ~ We started tracking symbol in node N, it must be the
// allocation site.
diff --git a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 32ebb51226bb..13a401d1e675 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -31,7 +31,7 @@ using namespace ento;
namespace {
class MacOSXAPIChecker : public Checker< check::PreStmt<CallExpr> > {
- mutable OwningPtr<BugType> BT_dispatchOnce;
+ mutable std::unique_ptr<BugType> BT_dispatchOnce;
public:
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
@@ -67,7 +67,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
return;
if (!BT_dispatchOnce)
- BT_dispatchOnce.reset(new BugType("Improper use of 'dispatch_once'",
+ BT_dispatchOnce.reset(new BugType(this, "Improper use of 'dispatch_once'",
"API Misuse (Apple)"));
// Handle _dispatch_once. In some versions of the OS X SDK we have the case
@@ -113,7 +113,7 @@ void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE,
"_dispatch_once",
"dispatch_once_f",
&MacOSXAPIChecker::CheckDispatchOnce)
- .Default(NULL);
+ .Default(nullptr);
if (SC)
(this->*SC)(C, CE, Name);
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index c7aa0fb150cb..a03fa259005a 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -16,6 +16,7 @@
#include "InterCheckerAPI.h"
#include "clang/AST/Attr.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
@@ -48,7 +49,7 @@ class RefState {
Allocated,
// Reference to released/freed memory.
Released,
- // The responsibility for freeing resources has transfered from
+ // The responsibility for freeing resources has transferred from
// this reference. A relinquished symbol should not be freed.
Relinquished,
// We are no longer guaranteed to have observed all manipulations
@@ -100,17 +101,16 @@ public:
}
void dump(raw_ostream &OS) const {
- static const char *const Table[] = {
- "Allocated",
- "Released",
- "Relinquished"
- };
- OS << Table[(unsigned) K];
+ switch (static_cast<Kind>(K)) {
+#define CASE(ID) case ID: OS << #ID; break;
+ CASE(Allocated)
+ CASE(Released)
+ CASE(Relinquished)
+ CASE(Escaped)
+ }
}
- LLVM_ATTRIBUTE_USED void dump() const {
- dump(llvm::errs());
- }
+ LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }
};
enum ReallocPairKind {
@@ -156,30 +156,25 @@ class MallocChecker : public Checker<check::DeadSymbols,
check::Location,
eval::Assume>
{
- mutable OwningPtr<BugType> BT_DoubleFree;
- mutable OwningPtr<BugType> BT_Leak;
- mutable OwningPtr<BugType> BT_UseFree;
- mutable OwningPtr<BugType> BT_BadFree;
- mutable OwningPtr<BugType> BT_MismatchedDealloc;
- mutable OwningPtr<BugType> BT_OffsetFree;
- mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc,
- *II_valloc, *II_reallocf, *II_strndup, *II_strdup;
-
public:
- MallocChecker() : II_malloc(0), II_free(0), II_realloc(0), II_calloc(0),
- II_valloc(0), II_reallocf(0), II_strndup(0), II_strdup(0) {}
+ MallocChecker()
+ : II_malloc(nullptr), II_free(nullptr), II_realloc(nullptr),
+ II_calloc(nullptr), II_valloc(nullptr), II_reallocf(nullptr),
+ II_strndup(nullptr), II_strdup(nullptr), II_kmalloc(nullptr) {}
/// In pessimistic mode, the checker assumes that it does not know which
/// functions might free the memory.
- struct ChecksFilter {
- DefaultBool CMallocPessimistic;
- DefaultBool CMallocOptimistic;
- DefaultBool CNewDeleteChecker;
- DefaultBool CNewDeleteLeaksChecker;
- DefaultBool CMismatchedDeallocatorChecker;
+ enum CheckKind {
+ CK_MallocPessimistic,
+ CK_MallocOptimistic,
+ CK_NewDeleteChecker,
+ CK_NewDeleteLeaksChecker,
+ CK_MismatchedDeallocatorChecker,
+ CK_NumCheckKinds
};
- ChecksFilter Filter;
+ DefaultBool ChecksEnabled[CK_NumCheckKinds];
+ CheckName CheckNames[CK_NumCheckKinds];
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
@@ -204,9 +199,21 @@ public:
PointerEscapeKind Kind) const;
void printState(raw_ostream &Out, ProgramStateRef State,
- const char *NL, const char *Sep) const;
+ const char *NL, const char *Sep) const override;
private:
+ mutable std::unique_ptr<BugType> BT_DoubleFree[CK_NumCheckKinds];
+ mutable std::unique_ptr<BugType> BT_DoubleDelete;
+ mutable std::unique_ptr<BugType> BT_Leak[CK_NumCheckKinds];
+ mutable std::unique_ptr<BugType> BT_UseFree[CK_NumCheckKinds];
+ mutable std::unique_ptr<BugType> BT_BadFree[CK_NumCheckKinds];
+ mutable std::unique_ptr<BugType> BT_MismatchedDealloc;
+ mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
+ mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc,
+ *II_valloc, *II_reallocf, *II_strndup, *II_strdup,
+ *II_kmalloc;
+ mutable Optional<uint64_t> KernelZeroFlagVal;
+
void initIdentifierInfo(ASTContext &C) const;
/// \brief Determine family of a deallocation expression.
@@ -234,9 +241,9 @@ private:
bool isAllocationFunction(const FunctionDecl *FD, ASTContext &C) const;
bool isStandardNewDelete(const FunctionDecl *FD, ASTContext &C) const;
///@}
- static ProgramStateRef MallocMemReturnsAttr(CheckerContext &C,
- const CallExpr *CE,
- const OwnershipAttr* Att);
+ ProgramStateRef MallocMemReturnsAttr(CheckerContext &C,
+ const CallExpr *CE,
+ const OwnershipAttr* Att) const;
static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
const Expr *SizeEx, SVal Init,
ProgramStateRef State,
@@ -251,6 +258,12 @@ private:
ProgramStateRef State,
AllocationFamily Family = AF_Malloc);
+ // Check if this malloc() for special flags. At present that means M_ZERO or
+ // __GFP_ZERO (in which case, treat it like calloc).
+ llvm::Optional<ProgramStateRef>
+ performKernelMalloc(const CallExpr *CE, CheckerContext &C,
+ const ProgramStateRef &State) const;
+
/// Update the RefState to reflect the new memory allocation.
static ProgramStateRef
MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State,
@@ -279,6 +292,8 @@ private:
bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;
+ bool checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const;
+
/// Check if the function is known free memory, or if it is
/// "interesting" and should be modeled explicitly.
///
@@ -302,10 +317,12 @@ private:
///@{
/// Tells if a given family/call/symbol is tracked by the current checker.
- bool isTrackedByCurrentChecker(AllocationFamily Family) const;
- bool isTrackedByCurrentChecker(CheckerContext &C,
- const Stmt *AllocDeallocStmt) const;
- bool isTrackedByCurrentChecker(CheckerContext &C, SymbolRef Sym) const;
+ /// Sets CheckKind to the kind of the checker responsible for this
+ /// family/call/symbol.
+ Optional<CheckKind> getCheckIfTracked(AllocationFamily Family) const;
+ Optional<CheckKind> getCheckIfTracked(CheckerContext &C,
+ const Stmt *AllocDeallocStmt) const;
+ Optional<CheckKind> getCheckIfTracked(CheckerContext &C, SymbolRef Sym) const;
///@}
static bool SummarizeValue(raw_ostream &os, SVal V);
static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
@@ -316,12 +333,14 @@ private:
SymbolRef Sym, bool OwnershipTransferred) const;
void ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
const Expr *DeallocExpr,
- const Expr *AllocExpr = 0) const;
+ const Expr *AllocExpr = nullptr) const;
void ReportUseAfterFree(CheckerContext &C, SourceRange Range,
SymbolRef Sym) const;
void ReportDoubleFree(CheckerContext &C, SourceRange Range, bool Released,
SymbolRef Sym, SymbolRef PrevSym) const;
+ void ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const;
+
/// Find the location of the allocation for Sym on the path leading to the
/// exploded node N.
LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
@@ -352,11 +371,11 @@ private:
public:
MallocBugVisitor(SymbolRef S, bool isLeak = false)
- : Sym(S), Mode(Normal), FailedReallocSymbol(0), IsLeak(isLeak) {}
+ : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr), IsLeak(isLeak) {}
virtual ~MallocBugVisitor() {}
- void Profile(llvm::FoldingSetNodeID &ID) const {
+ void Profile(llvm::FoldingSetNodeID &ID) const override {
static int X = 0;
ID.AddPointer(&X);
ID.AddPointer(Sym);
@@ -398,13 +417,13 @@ private:
PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext &BRC,
- BugReport &BR);
+ BugReport &BR) override;
PathDiagnosticPiece* getEndPath(BugReporterContext &BRC,
const ExplodedNode *EndPathNode,
- BugReport &BR) {
+ BugReport &BR) override {
if (!IsLeak)
- return 0;
+ return nullptr;
PathDiagnosticLocation L =
PathDiagnosticLocation::createEndOfPath(EndPathNode,
@@ -420,7 +439,8 @@ private:
StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M)
: StackHintGeneratorForSymbol(S, M) {}
- virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) {
+ std::string getMessageForArg(const Expr *ArgE,
+ unsigned ArgIndex) override {
// Printed parameters start at 1, not 0.
++ArgIndex;
@@ -433,7 +453,7 @@ private:
return os.str();
}
- virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
+ std::string getMessageForReturn(const CallExpr *CallExpr) override {
return "Reallocation of returned value failed";
}
};
@@ -455,7 +475,7 @@ public:
StopTrackingCallback(ProgramStateRef st) : state(st) {}
ProgramStateRef getState() const { return state; }
- bool VisitSymbol(SymbolRef sym) {
+ bool VisitSymbol(SymbolRef sym) override {
state = state->remove<RegionState>(sym);
return true;
}
@@ -473,6 +493,7 @@ void MallocChecker::initIdentifierInfo(ASTContext &Ctx) const {
II_valloc = &Ctx.Idents.get("valloc");
II_strdup = &Ctx.Idents.get("strdup");
II_strndup = &Ctx.Idents.get("strndup");
+ II_kmalloc = &Ctx.Idents.get("kmalloc");
}
bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
@@ -499,16 +520,13 @@ bool MallocChecker::isAllocationFunction(const FunctionDecl *FD,
if (FunI == II_malloc || FunI == II_realloc ||
FunI == II_reallocf || FunI == II_calloc || FunI == II_valloc ||
- FunI == II_strdup || FunI == II_strndup)
+ FunI == II_strdup || FunI == II_strndup || FunI == II_kmalloc)
return true;
}
- if (Filter.CMallocOptimistic && FD->hasAttrs())
- for (specific_attr_iterator<OwnershipAttr>
- i = FD->specific_attr_begin<OwnershipAttr>(),
- e = FD->specific_attr_end<OwnershipAttr>();
- i != e; ++i)
- if ((*i)->getOwnKind() == OwnershipAttr::Returns)
+ if (ChecksEnabled[CK_MallocOptimistic] && FD->hasAttrs())
+ for (const auto *I : FD->specific_attrs<OwnershipAttr>())
+ if (I->getOwnKind() == OwnershipAttr::Returns)
return true;
return false;
}
@@ -525,13 +543,10 @@ bool MallocChecker::isFreeFunction(const FunctionDecl *FD, ASTContext &C) const
return true;
}
- if (Filter.CMallocOptimistic && FD->hasAttrs())
- for (specific_attr_iterator<OwnershipAttr>
- i = FD->specific_attr_begin<OwnershipAttr>(),
- e = FD->specific_attr_end<OwnershipAttr>();
- i != e; ++i)
- if ((*i)->getOwnKind() == OwnershipAttr::Takes ||
- (*i)->getOwnKind() == OwnershipAttr::Holds)
+ if (ChecksEnabled[CK_MallocOptimistic] && FD->hasAttrs())
+ for (const auto *I : FD->specific_attrs<OwnershipAttr>())
+ if (I->getOwnKind() == OwnershipAttr::Takes ||
+ I->getOwnKind() == OwnershipAttr::Holds)
return true;
return false;
}
@@ -569,10 +584,88 @@ bool MallocChecker::isStandardNewDelete(const FunctionDecl *FD,
return true;
}
+llvm::Optional<ProgramStateRef> MallocChecker::performKernelMalloc(
+ const CallExpr *CE, CheckerContext &C, const ProgramStateRef &State) const {
+ // 3-argument malloc(), as commonly used in {Free,Net,Open}BSD Kernels:
+ //
+ // void *malloc(unsigned long size, struct malloc_type *mtp, int flags);
+ //
+ // One of the possible flags is M_ZERO, which means 'give me back an
+ // allocation which is already zeroed', like calloc.
+
+ // 2-argument kmalloc(), as used in the Linux kernel:
+ //
+ // void *kmalloc(size_t size, gfp_t flags);
+ //
+ // Has the similar flag value __GFP_ZERO.
+
+ // This logic is largely cloned from O_CREAT in UnixAPIChecker, maybe some
+ // code could be shared.
+
+ ASTContext &Ctx = C.getASTContext();
+ llvm::Triple::OSType OS = Ctx.getTargetInfo().getTriple().getOS();
+
+ if (!KernelZeroFlagVal.hasValue()) {
+ if (OS == llvm::Triple::FreeBSD)
+ KernelZeroFlagVal = 0x0100;
+ else if (OS == llvm::Triple::NetBSD)
+ KernelZeroFlagVal = 0x0002;
+ else if (OS == llvm::Triple::OpenBSD)
+ KernelZeroFlagVal = 0x0008;
+ else if (OS == llvm::Triple::Linux)
+ // __GFP_ZERO
+ KernelZeroFlagVal = 0x8000;
+ else
+ // FIXME: We need a more general way of getting the M_ZERO value.
+ // See also: O_CREAT in UnixAPIChecker.cpp.
+
+ // Fall back to normal malloc behavior on platforms where we don't
+ // know M_ZERO.
+ return None;
+ }
+
+ // We treat the last argument as the flags argument, and callers fall-back to
+ // normal malloc on a None return. This works for the FreeBSD kernel malloc
+ // as well as Linux kmalloc.
+ if (CE->getNumArgs() < 2)
+ return None;
+
+ const Expr *FlagsEx = CE->getArg(CE->getNumArgs() - 1);
+ const SVal V = State->getSVal(FlagsEx, C.getLocationContext());
+ if (!V.getAs<NonLoc>()) {
+ // The case where 'V' can be a location can only be due to a bad header,
+ // so in this case bail out.
+ return None;
+ }
+
+ NonLoc Flags = V.castAs<NonLoc>();
+ NonLoc ZeroFlag = C.getSValBuilder()
+ .makeIntVal(KernelZeroFlagVal.getValue(), FlagsEx->getType())
+ .castAs<NonLoc>();
+ SVal MaskedFlagsUC = C.getSValBuilder().evalBinOpNN(State, BO_And,
+ Flags, ZeroFlag,
+ FlagsEx->getType());
+ if (MaskedFlagsUC.isUnknownOrUndef())
+ return None;
+ DefinedSVal MaskedFlags = MaskedFlagsUC.castAs<DefinedSVal>();
+
+ // Check if maskedFlags is non-zero.
+ ProgramStateRef TrueState, FalseState;
+ std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
+
+ // If M_ZERO is set, treat this like calloc (initialized).
+ if (TrueState && !FalseState) {
+ SVal ZeroVal = C.getSValBuilder().makeZeroVal(Ctx.CharTy);
+ return MallocMemAux(C, CE, CE->getArg(0), ZeroVal, TrueState);
+ }
+
+ return None;
+}
+
void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
if (C.wasInlined)
return;
-
+
const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD)
return;
@@ -584,7 +677,27 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
initIdentifierInfo(C.getASTContext());
IdentifierInfo *FunI = FD->getIdentifier();
- if (FunI == II_malloc || FunI == II_valloc) {
+ if (FunI == II_malloc) {
+ if (CE->getNumArgs() < 1)
+ return;
+ if (CE->getNumArgs() < 3) {
+ State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
+ } else if (CE->getNumArgs() == 3) {
+ llvm::Optional<ProgramStateRef> MaybeState =
+ performKernelMalloc(CE, C, State);
+ if (MaybeState.hasValue())
+ State = MaybeState.getValue();
+ else
+ State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
+ }
+ } else if (FunI == II_kmalloc) {
+ llvm::Optional<ProgramStateRef> MaybeState =
+ performKernelMalloc(CE, C, State);
+ if (MaybeState.hasValue())
+ State = MaybeState.getValue();
+ else
+ State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
+ } else if (FunI == II_valloc) {
if (CE->getNumArgs() < 1)
return;
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
@@ -620,21 +733,19 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
}
}
- if (Filter.CMallocOptimistic || Filter.CMismatchedDeallocatorChecker) {
+ if (ChecksEnabled[CK_MallocOptimistic] ||
+ ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
// Check all the attributes, if there are any.
// There can be multiple of these attributes.
if (FD->hasAttrs())
- for (specific_attr_iterator<OwnershipAttr>
- i = FD->specific_attr_begin<OwnershipAttr>(),
- e = FD->specific_attr_end<OwnershipAttr>();
- i != e; ++i) {
- switch ((*i)->getOwnKind()) {
+ for (const auto *I : FD->specific_attrs<OwnershipAttr>()) {
+ switch (I->getOwnKind()) {
case OwnershipAttr::Returns:
- State = MallocMemReturnsAttr(C, CE, *i);
+ State = MallocMemReturnsAttr(C, CE, I);
break;
case OwnershipAttr::Takes:
case OwnershipAttr::Holds:
- State = FreeMemAttr(C, CE, *i);
+ State = FreeMemAttr(C, CE, I);
break;
}
}
@@ -667,7 +778,7 @@ void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
void MallocChecker::checkPreStmt(const CXXDeleteExpr *DE,
CheckerContext &C) const {
- if (!Filter.CNewDeleteChecker)
+ if (!ChecksEnabled[CK_NewDeleteChecker])
if (SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol())
checkUseAfterFree(Sym, C, DE->getArgument());
@@ -729,11 +840,11 @@ void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
C.addTransition(State);
}
-ProgramStateRef MallocChecker::MallocMemReturnsAttr(CheckerContext &C,
- const CallExpr *CE,
- const OwnershipAttr* Att) {
- if (Att->getModule() != "malloc")
- return 0;
+ProgramStateRef
+MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
+ const OwnershipAttr *Att) const {
+ if (Att->getModule() != II_malloc)
+ return nullptr;
OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
if (I != E) {
@@ -760,7 +871,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
// We expect the malloc functions to return a pointer.
if (!RetVal.getAs<Loc>())
- return 0;
+ return nullptr;
// Fill the region with the initialization value.
State = State->bindDefault(RetVal, Init);
@@ -769,7 +880,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
const SymbolicRegion *R =
dyn_cast_or_null<SymbolicRegion>(RetVal.getAsRegion());
if (!R)
- return 0;
+ return nullptr;
if (Optional<DefinedOrUnknownSVal> DefinedSize =
Size.getAs<DefinedOrUnknownSVal>()) {
SValBuilder &svalBuilder = C.getSValBuilder();
@@ -793,7 +904,7 @@ ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C,
// We expect the malloc functions to return a pointer.
if (!retVal.getAs<Loc>())
- return 0;
+ return nullptr;
SymbolRef Sym = retVal.getAsLocSymbol();
assert(Sym);
@@ -804,16 +915,15 @@ ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C,
ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
const CallExpr *CE,
- const OwnershipAttr* Att) const {
- if (Att->getModule() != "malloc")
- return 0;
+ const OwnershipAttr *Att) const {
+ if (Att->getModule() != II_malloc)
+ return nullptr;
ProgramStateRef State = C.getState();
bool ReleasedAllocated = false;
- for (OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
- I != E; ++I) {
- ProgramStateRef StateI = FreeMemAux(C, CE, State, *I,
+ for (const auto &Arg : Att->args()) {
+ ProgramStateRef StateI = FreeMemAux(C, CE, State, Arg,
Att->getOwnKind() == OwnershipAttr::Holds,
ReleasedAllocated);
if (StateI)
@@ -830,7 +940,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
bool &ReleasedAllocated,
bool ReturnsNullOnFailure) const {
if (CE->getNumArgs() < (Num + 1))
- return 0;
+ return nullptr;
return FreeMemAux(C, CE->getArg(Num), CE, state, Hold,
ReleasedAllocated, ReturnsNullOnFailure);
@@ -909,7 +1019,7 @@ bool MallocChecker::printAllocDeallocName(raw_ostream &os, CheckerContext &C,
os << "-";
else
os << "+";
- os << Msg->getSelector().getAsString();
+ Msg->getSelector().print(os);
return true;
}
@@ -962,23 +1072,23 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
SVal ArgVal = State->getSVal(ArgExpr, C.getLocationContext());
if (!ArgVal.getAs<DefinedOrUnknownSVal>())
- return 0;
+ return nullptr;
DefinedOrUnknownSVal location = ArgVal.castAs<DefinedOrUnknownSVal>();
// Check for null dereferences.
if (!location.getAs<Loc>())
- return 0;
+ return nullptr;
// The explicit NULL case, no operation is performed.
ProgramStateRef notNullState, nullState;
- llvm::tie(notNullState, nullState) = State->assume(location);
+ std::tie(notNullState, nullState) = State->assume(location);
if (nullState && !notNullState)
- return 0;
+ return nullptr;
// Unknown values could easily be okay
// Undefined values are handled elsewhere
if (ArgVal.isUnknownOrUndef())
- return 0;
+ return nullptr;
const MemRegion *R = ArgVal.getAsRegion();
@@ -986,7 +1096,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
// Non-region locations (labels and fixed addresses) also shouldn't be freed.
if (!R) {
ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
- return 0;
+ return nullptr;
}
R = R->StripCasts();
@@ -994,7 +1104,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
// Blocks might show up as heap data, but should not be free()d
if (isa<BlockDataRegion>(R)) {
ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
- return 0;
+ return nullptr;
}
const MemSpaceRegion *MS = R->getMemorySpace();
@@ -1011,18 +1121,18 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
// False negatives are better than false positives.
ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
- return 0;
+ return nullptr;
}
const SymbolicRegion *SrBase = dyn_cast<SymbolicRegion>(R->getBaseRegion());
// Various cases could lead to non-symbol values here.
// For now, ignore them.
if (!SrBase)
- return 0;
+ return nullptr;
SymbolRef SymBase = SrBase->getSymbol();
const RefState *RsBase = State->get<RegionState>(SymBase);
- SymbolRef PreviousRetStatusSymbol = 0;
+ SymbolRef PreviousRetStatusSymbol = nullptr;
if (RsBase) {
@@ -1031,7 +1141,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
!didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) {
ReportDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(),
SymBase, PreviousRetStatusSymbol);
- return 0;
+ return nullptr;
// If the pointer is allocated or escaped, but we are now trying to free it,
// check that the call to free is proper.
@@ -1043,7 +1153,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
if (!DeallocMatchesAlloc) {
ReportMismatchedDealloc(C, ArgExpr->getSourceRange(),
ParentExpr, RsBase, SymBase, Hold);
- return 0;
+ return nullptr;
}
// Check if the memory location being freed is the actual location
@@ -1055,12 +1165,12 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
AllocExpr);
- return 0;
+ return nullptr;
}
}
}
- ReleasedAllocated = (RsBase != 0) && RsBase->isAllocated();
+ ReleasedAllocated = (RsBase != nullptr) && RsBase->isAllocated();
// Clean out the info on previous call to free return info.
State = State->remove<FreeReturnValue>(SymBase);
@@ -1088,18 +1198,23 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
RefState::getReleased(Family, ParentExpr));
}
-bool MallocChecker::isTrackedByCurrentChecker(AllocationFamily Family) const {
+Optional<MallocChecker::CheckKind>
+MallocChecker::getCheckIfTracked(AllocationFamily Family) const {
switch (Family) {
case AF_Malloc: {
- if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic)
- return false;
- return true;
+ if (ChecksEnabled[CK_MallocOptimistic]) {
+ return CK_MallocOptimistic;
+ } else if (ChecksEnabled[CK_MallocPessimistic]) {
+ return CK_MallocPessimistic;
+ }
+ return Optional<MallocChecker::CheckKind>();
}
case AF_CXXNew:
case AF_CXXNewArray: {
- if (!Filter.CNewDeleteChecker)
- return false;
- return true;
+ if (ChecksEnabled[CK_NewDeleteChecker]) {
+ return CK_NewDeleteChecker;
+ }
+ return Optional<MallocChecker::CheckKind>();
}
case AF_None: {
llvm_unreachable("no family");
@@ -1108,18 +1223,18 @@ bool MallocChecker::isTrackedByCurrentChecker(AllocationFamily Family) const {
llvm_unreachable("unhandled family");
}
-bool
-MallocChecker::isTrackedByCurrentChecker(CheckerContext &C,
- const Stmt *AllocDeallocStmt) const {
- return isTrackedByCurrentChecker(getAllocationFamily(C, AllocDeallocStmt));
+Optional<MallocChecker::CheckKind>
+MallocChecker::getCheckIfTracked(CheckerContext &C,
+ const Stmt *AllocDeallocStmt) const {
+ return getCheckIfTracked(getAllocationFamily(C, AllocDeallocStmt));
}
-bool MallocChecker::isTrackedByCurrentChecker(CheckerContext &C,
- SymbolRef Sym) const {
+Optional<MallocChecker::CheckKind>
+MallocChecker::getCheckIfTracked(CheckerContext &C, SymbolRef Sym) const {
const RefState *RS = C.getState()->get<RegionState>(Sym);
assert(RS);
- return isTrackedByCurrentChecker(RS->getAllocationFamily());
+ return getCheckIfTracked(RS->getAllocationFamily());
}
bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
@@ -1162,8 +1277,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
if (VR)
VD = VR->getDecl();
else
- VD = NULL;
-
+ VD = nullptr;
+
if (VD)
os << "the address of the local variable '" << VD->getName() << "'";
else
@@ -1177,8 +1292,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
if (VR)
VD = VR->getDecl();
else
- VD = NULL;
-
+ VD = nullptr;
+
if (VD)
os << "the address of the parameter '" << VD->getName() << "'";
else
@@ -1192,8 +1307,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
if (VR)
VD = VR->getDecl();
else
- VD = NULL;
-
+ VD = nullptr;
+
if (VD) {
if (VD->isStaticLocal())
os << "the address of the static variable '" << VD->getName() << "'";
@@ -1213,17 +1328,21 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
SourceRange Range,
const Expr *DeallocExpr) const {
- if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
- !Filter.CNewDeleteChecker)
+ if (!ChecksEnabled[CK_MallocOptimistic] &&
+ !ChecksEnabled[CK_MallocPessimistic] &&
+ !ChecksEnabled[CK_NewDeleteChecker])
return;
- if (!isTrackedByCurrentChecker(C, DeallocExpr))
+ Optional<MallocChecker::CheckKind> CheckKind =
+ getCheckIfTracked(C, DeallocExpr);
+ if (!CheckKind.hasValue())
return;
if (ExplodedNode *N = C.generateSink()) {
- if (!BT_BadFree)
- BT_BadFree.reset(new BugType("Bad free", "Memory Error"));
-
+ if (!BT_BadFree[*CheckKind])
+ BT_BadFree[*CheckKind].reset(
+ new BugType(CheckNames[*CheckKind], "Bad free", "Memory Error"));
+
SmallString<100> buf;
llvm::raw_svector_ostream os(buf);
@@ -1249,7 +1368,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
printExpectedAllocName(os, C, DeallocExpr);
}
- BugReport *R = new BugReport(*BT_BadFree, os.str(), N);
+ BugReport *R = new BugReport(*BT_BadFree[*CheckKind], os.str(), N);
R->markInteresting(MR);
R->addRange(Range);
C.emitReport(R);
@@ -1263,14 +1382,15 @@ void MallocChecker::ReportMismatchedDealloc(CheckerContext &C,
SymbolRef Sym,
bool OwnershipTransferred) const {
- if (!Filter.CMismatchedDeallocatorChecker)
+ if (!ChecksEnabled[CK_MismatchedDeallocatorChecker])
return;
if (ExplodedNode *N = C.generateSink()) {
if (!BT_MismatchedDealloc)
- BT_MismatchedDealloc.reset(new BugType("Bad deallocator",
- "Memory Error"));
-
+ BT_MismatchedDealloc.reset(
+ new BugType(CheckNames[CK_MismatchedDeallocatorChecker],
+ "Bad deallocator", "Memory Error"));
+
SmallString<100> buf;
llvm::raw_svector_ostream os(buf);
@@ -1314,19 +1434,23 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
SourceRange Range, const Expr *DeallocExpr,
const Expr *AllocExpr) const {
- if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
- !Filter.CNewDeleteChecker)
+ if (!ChecksEnabled[CK_MallocOptimistic] &&
+ !ChecksEnabled[CK_MallocPessimistic] &&
+ !ChecksEnabled[CK_NewDeleteChecker])
return;
- if (!isTrackedByCurrentChecker(C, AllocExpr))
+ Optional<MallocChecker::CheckKind> CheckKind =
+ getCheckIfTracked(C, AllocExpr);
+ if (!CheckKind.hasValue())
return;
ExplodedNode *N = C.generateSink();
- if (N == NULL)
+ if (!N)
return;
- if (!BT_OffsetFree)
- BT_OffsetFree.reset(new BugType("Offset free", "Memory Error"));
+ if (!BT_OffsetFree[*CheckKind])
+ BT_OffsetFree[*CheckKind].reset(
+ new BugType(CheckNames[*CheckKind], "Offset free", "Memory Error"));
SmallString<100> buf;
llvm::raw_svector_ostream os(buf);
@@ -1357,7 +1481,7 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
else
os << "allocated memory";
- BugReport *R = new BugReport(*BT_OffsetFree, os.str(), N);
+ BugReport *R = new BugReport(*BT_OffsetFree[*CheckKind], os.str(), N);
R->markInteresting(MR->getBaseRegion());
R->addRange(Range);
C.emitReport(R);
@@ -1366,18 +1490,21 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range,
SymbolRef Sym) const {
- if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
- !Filter.CNewDeleteChecker)
+ if (!ChecksEnabled[CK_MallocOptimistic] &&
+ !ChecksEnabled[CK_MallocPessimistic] &&
+ !ChecksEnabled[CK_NewDeleteChecker])
return;
- if (!isTrackedByCurrentChecker(C, Sym))
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
+ if (!CheckKind.hasValue())
return;
if (ExplodedNode *N = C.generateSink()) {
- if (!BT_UseFree)
- BT_UseFree.reset(new BugType("Use-after-free", "Memory Error"));
+ if (!BT_UseFree[*CheckKind])
+ BT_UseFree[*CheckKind].reset(new BugType(
+ CheckNames[*CheckKind], "Use-after-free", "Memory Error"));
- BugReport *R = new BugReport(*BT_UseFree,
+ BugReport *R = new BugReport(*BT_UseFree[*CheckKind],
"Use of memory after it is freed", N);
R->markInteresting(Sym);
@@ -1391,21 +1518,25 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range,
bool Released, SymbolRef Sym,
SymbolRef PrevSym) const {
- if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
- !Filter.CNewDeleteChecker)
+ if (!ChecksEnabled[CK_MallocOptimistic] &&
+ !ChecksEnabled[CK_MallocPessimistic] &&
+ !ChecksEnabled[CK_NewDeleteChecker])
return;
- if (!isTrackedByCurrentChecker(C, Sym))
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
+ if (!CheckKind.hasValue())
return;
if (ExplodedNode *N = C.generateSink()) {
- if (!BT_DoubleFree)
- BT_DoubleFree.reset(new BugType("Double free", "Memory Error"));
-
- BugReport *R = new BugReport(*BT_DoubleFree,
- (Released ? "Attempt to free released memory"
- : "Attempt to free non-owned memory"),
- N);
+ if (!BT_DoubleFree[*CheckKind])
+ BT_DoubleFree[*CheckKind].reset(
+ new BugType(CheckNames[*CheckKind], "Double free", "Memory Error"));
+
+ BugReport *R =
+ new BugReport(*BT_DoubleFree[*CheckKind],
+ (Released ? "Attempt to free released memory"
+ : "Attempt to free non-owned memory"),
+ N);
R->addRange(Range);
R->markInteresting(Sym);
if (PrevSym)
@@ -1415,18 +1546,42 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range,
}
}
+void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const {
+
+ if (!ChecksEnabled[CK_NewDeleteChecker])
+ return;
+
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
+ if (!CheckKind.hasValue())
+ return;
+ assert(*CheckKind == CK_NewDeleteChecker && "invalid check kind");
+
+ if (ExplodedNode *N = C.generateSink()) {
+ if (!BT_DoubleDelete)
+ BT_DoubleDelete.reset(new BugType(CheckNames[CK_NewDeleteChecker],
+ "Double delete", "Memory Error"));
+
+ BugReport *R = new BugReport(*BT_DoubleDelete,
+ "Attempt to delete released memory", N);
+
+ R->markInteresting(Sym);
+ R->addVisitor(new MallocBugVisitor(Sym));
+ C.emitReport(R);
+ }
+}
+
ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
const CallExpr *CE,
bool FreesOnFail) const {
if (CE->getNumArgs() < 2)
- return 0;
+ return nullptr;
ProgramStateRef state = C.getState();
const Expr *arg0Expr = CE->getArg(0);
const LocationContext *LCtx = C.getLocationContext();
SVal Arg0Val = state->getSVal(arg0Expr, LCtx);
if (!Arg0Val.getAs<DefinedOrUnknownSVal>())
- return 0;
+ return nullptr;
DefinedOrUnknownSVal arg0Val = Arg0Val.castAs<DefinedOrUnknownSVal>();
SValBuilder &svalBuilder = C.getSValBuilder();
@@ -1437,12 +1592,12 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
// Get the size argument. If there is no size arg then give up.
const Expr *Arg1 = CE->getArg(1);
if (!Arg1)
- return 0;
+ return nullptr;
// Get the value of the size argument.
SVal Arg1ValG = state->getSVal(Arg1, LCtx);
if (!Arg1ValG.getAs<DefinedOrUnknownSVal>())
- return 0;
+ return nullptr;
DefinedOrUnknownSVal Arg1Val = Arg1ValG.castAs<DefinedOrUnknownSVal>();
// Compare the size argument to 0.
@@ -1451,9 +1606,9 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
svalBuilder.makeIntValWithPtrWidth(0, false));
ProgramStateRef StatePtrIsNull, StatePtrNotNull;
- llvm::tie(StatePtrIsNull, StatePtrNotNull) = state->assume(PtrEQ);
+ std::tie(StatePtrIsNull, StatePtrNotNull) = state->assume(PtrEQ);
ProgramStateRef StateSizeIsZero, StateSizeNotZero;
- llvm::tie(StateSizeIsZero, StateSizeNotZero) = state->assume(SizeZero);
+ std::tie(StateSizeIsZero, StateSizeNotZero) = state->assume(SizeZero);
// We only assume exceptional states if they are definitely true; if the
// state is under-constrained, assume regular realloc behavior.
bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
@@ -1468,7 +1623,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
}
if (PrtIsNull && SizeIsZero)
- return 0;
+ return nullptr;
// Get the from and to pointer symbols as in toPtr = realloc(fromPtr, size).
assert(!PrtIsNull);
@@ -1476,7 +1631,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
SVal RetVal = state->getSVal(CE, LCtx);
SymbolRef ToPtr = RetVal.getAsSymbol();
if (!FromPtr || !ToPtr)
- return 0;
+ return nullptr;
bool ReleasedAllocated = false;
@@ -1498,7 +1653,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
ProgramStateRef stateRealloc = MallocMemAux(C, CE, CE->getArg(1),
UnknownVal(), stateFree);
if (!stateRealloc)
- return 0;
+ return nullptr;
ReallocPairKind Kind = RPToBeFreedAfterFailure;
if (FreesOnFail)
@@ -1514,12 +1669,12 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
return stateRealloc;
}
- return 0;
+ return nullptr;
}
ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE){
if (CE->getNumArgs() < 2)
- return 0;
+ return nullptr;
ProgramStateRef state = C.getState();
SValBuilder &svalBuilder = C.getSValBuilder();
@@ -1540,7 +1695,7 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
// Walk the ExplodedGraph backwards and find the first node that referred to
// the tracked symbol.
const ExplodedNode *AllocNode = N;
- const MemRegion *ReferenceRegion = 0;
+ const MemRegion *ReferenceRegion = nullptr;
while (N) {
ProgramStateRef State = N->getState();
@@ -1567,7 +1722,7 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
// symbol was tracked.
if (N->getLocationContext() == LeakContext)
AllocNode = N;
- N = N->pred_empty() ? NULL : *(N->pred_begin());
+ N = N->pred_empty() ? nullptr : *(N->pred_begin());
}
return LeakInfo(AllocNode, ReferenceRegion);
@@ -1576,43 +1731,46 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
CheckerContext &C) const {
- if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
- !Filter.CNewDeleteLeaksChecker)
+ if (!ChecksEnabled[CK_MallocOptimistic] &&
+ !ChecksEnabled[CK_MallocPessimistic] &&
+ !ChecksEnabled[CK_NewDeleteLeaksChecker])
return;
const RefState *RS = C.getState()->get<RegionState>(Sym);
assert(RS && "cannot leak an untracked symbol");
AllocationFamily Family = RS->getAllocationFamily();
- if (!isTrackedByCurrentChecker(Family))
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
+ if (!CheckKind.hasValue())
return;
// Special case for new and new[]; these are controlled by a separate checker
// flag so that they can be selectively disabled.
if (Family == AF_CXXNew || Family == AF_CXXNewArray)
- if (!Filter.CNewDeleteLeaksChecker)
+ if (!ChecksEnabled[CK_NewDeleteLeaksChecker])
return;
assert(N);
- if (!BT_Leak) {
- BT_Leak.reset(new BugType("Memory leak", "Memory Error"));
+ if (!BT_Leak[*CheckKind]) {
+ BT_Leak[*CheckKind].reset(
+ new BugType(CheckNames[*CheckKind], "Memory leak", "Memory Error"));
// Leaks should not be reported if they are post-dominated by a sink:
// (1) Sinks are higher importance bugs.
// (2) NoReturnFunctionChecker uses sink nodes to represent paths ending
// with __noreturn functions such as assert() or exit(). We choose not
// to report leaks on such paths.
- BT_Leak->setSuppressOnSink(true);
+ BT_Leak[*CheckKind]->setSuppressOnSink(true);
}
// Most bug reports are cached at the location where they occurred.
// With leaks, we want to unique them by the location where they were
// allocated, and only report a single path.
PathDiagnosticLocation LocUsedForUniqueing;
- const ExplodedNode *AllocNode = 0;
- const MemRegion *Region = 0;
- llvm::tie(AllocNode, Region) = getAllocationSite(N, Sym, C);
+ const ExplodedNode *AllocNode = nullptr;
+ const MemRegion *Region = nullptr;
+ std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C);
ProgramPoint P = AllocNode->getLocation();
- const Stmt *AllocationStmt = 0;
+ const Stmt *AllocationStmt = nullptr;
if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>())
AllocationStmt = Exit->getCalleeContext()->getCallSite();
else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
@@ -1631,9 +1789,9 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
os << "Potential memory leak";
}
- BugReport *R = new BugReport(*BT_Leak, os.str(), N,
- LocUsedForUniqueing,
- AllocNode->getLocationContext()->getDecl());
+ BugReport *R =
+ new BugReport(*BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,
+ AllocNode->getLocationContext()->getDecl());
R->markInteresting(Sym);
R->addVisitor(new MallocBugVisitor(Sym, true));
C.emitReport(R);
@@ -1681,7 +1839,7 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
// Generate leak node.
ExplodedNode *N = C.getPredecessor();
if (!Errors.empty()) {
- static SimpleProgramPointTag Tag("MallocChecker : DeadSymbolsLeak");
+ static CheckerProgramPointTag Tag("MallocChecker", "DeadSymbolsLeak");
N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
for (SmallVectorImpl<SymbolRef>::iterator
I = Errors.begin(), E = Errors.end(); I != E; ++I) {
@@ -1695,17 +1853,24 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
void MallocChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
+ if (const CXXDestructorCall *DC = dyn_cast<CXXDestructorCall>(&Call)) {
+ SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
+ if (!Sym || checkDoubleDelete(Sym, C))
+ return;
+ }
+
// We will check for double free in the post visit.
if (const AnyFunctionCall *FC = dyn_cast<AnyFunctionCall>(&Call)) {
const FunctionDecl *FD = FC->getDecl();
if (!FD)
return;
- if ((Filter.CMallocOptimistic || Filter.CMallocPessimistic) &&
+ if ((ChecksEnabled[CK_MallocOptimistic] ||
+ ChecksEnabled[CK_MallocPessimistic]) &&
isFreeFunction(FD, C.getASTContext()))
return;
- if (Filter.CNewDeleteChecker &&
+ if (ChecksEnabled[CK_NewDeleteChecker] &&
isStandardNewDelete(FD, C.getASTContext()))
return;
}
@@ -1803,8 +1968,7 @@ bool MallocChecker::isReleased(SymbolRef Sym, CheckerContext &C) const {
bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
const Stmt *S) const {
- // FIXME: Handle destructor called from delete more precisely.
- if (isReleased(Sym, C) && S) {
+ if (isReleased(Sym, C)) {
ReportUseAfterFree(C, S->getSourceRange(), Sym);
return true;
}
@@ -1812,6 +1976,15 @@ bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
return false;
}
+bool MallocChecker::checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const {
+
+ if (isReleased(Sym, C)) {
+ ReportDoubleDelete(C, Sym);
+ return true;
+ }
+ return false;
+}
+
// Check if the location is a freed symbolic region.
void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S,
CheckerContext &C) const {
@@ -1867,13 +2040,13 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
ProgramStateRef State,
SymbolRef &EscapingSymbol) const {
assert(Call);
- EscapingSymbol = 0;
-
- // For now, assume that any C++ call can free memory.
+ EscapingSymbol = nullptr;
+
+ // For now, assume that any C++ or block call can free memory.
// TODO: If we want to be more optimistic here, we'll need to make sure that
// regions escape to C++ containers. They seem to do that even now, but for
// mysterious reasons.
- if (!(isa<FunctionCall>(Call) || isa<ObjCMethodCall>(Call)))
+ if (!(isa<SimpleFunctionCall>(Call) || isa<ObjCMethodCall>(Call)))
return true;
// Check Objective-C messages by selector name.
@@ -1909,7 +2082,8 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
// that the pointers get freed by following the container itself.
if (FirstSlot.startswith("addPointer") ||
FirstSlot.startswith("insertPointer") ||
- FirstSlot.startswith("replacePointer")) {
+ FirstSlot.startswith("replacePointer") ||
+ FirstSlot.equals("valueWithPointer")) {
return true;
}
@@ -1927,7 +2101,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
}
// At this point the only thing left to handle is straight function calls.
- const FunctionDecl *FD = cast<FunctionCall>(Call)->getDecl();
+ const FunctionDecl *FD = cast<SimpleFunctionCall>(Call)->getDecl();
if (!FD)
return true;
@@ -2043,7 +2217,7 @@ ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State,
bool(*CheckRefState)(const RefState*)) const {
// If we know that the call does not free memory, or we want to process the
// call later, keep tracking the top level arguments.
- SymbolRef EscapingSymbol = 0;
+ SymbolRef EscapingSymbol = nullptr;
if (Kind == PSK_DirectEscapeOnCall &&
!mayFreeAnyEscapedMemoryOrIsModeledExplicitly(Call, State,
EscapingSymbol) &&
@@ -2081,7 +2255,7 @@ static SymbolRef findFailedReallocSymbol(ProgramStateRef currState,
return sym;
}
- return NULL;
+ return nullptr;
}
PathDiagnosticPiece *
@@ -2095,11 +2269,11 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N,
const RefState *RS = state->get<RegionState>(Sym);
const RefState *RSPrev = statePrev->get<RegionState>(Sym);
if (!RS)
- return 0;
+ return nullptr;
- const Stmt *S = 0;
- const char *Msg = 0;
- StackHintGeneratorForSymbol *StackHint = 0;
+ const Stmt *S = nullptr;
+ const char *Msg = nullptr;
+ StackHintGeneratorForSymbol *StackHint = nullptr;
// Retrieve the associated statement.
ProgramPoint ProgLoc = N->getLocation();
@@ -2114,7 +2288,7 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N,
}
if (!S)
- return 0;
+ return nullptr;
// FIXME: We will eventually need to handle non-statement-based events
// (__attribute__((cleanup))).
@@ -2130,7 +2304,7 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N,
StackHint = new StackHintGeneratorForSymbol(Sym,
"Returning; memory was released");
} else if (isRelinquished(RS, RSPrev, S)) {
- Msg = "Memory ownership is transfered";
+ Msg = "Memory ownership is transferred";
StackHint = new StackHintGeneratorForSymbol(Sym, "");
} else if (isReallocFailedCheck(RS, RSPrev, S)) {
Mode = ReallocationFailed;
@@ -2157,13 +2331,13 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N,
Msg = "Attempt to reallocate memory";
StackHint = new StackHintGeneratorForSymbol(Sym,
"Returned reallocated memory");
- FailedReallocSymbol = NULL;
+ FailedReallocSymbol = nullptr;
Mode = Normal;
}
}
if (!Msg)
- return 0;
+ return nullptr;
assert(StackHint);
// Generate the extra diagnostic.
@@ -2178,11 +2352,17 @@ void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
RegionStateTy RS = State->get<RegionState>();
if (!RS.isEmpty()) {
- Out << Sep << "MallocChecker:" << NL;
+ Out << Sep << "MallocChecker :" << NL;
for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
+ const RefState *RefS = State->get<RegionState>(I.getKey());
+ AllocationFamily Family = RefS->getAllocationFamily();
+ Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
+
I.getKey()->dumpToStream(Out);
Out << " : ";
I.getData().dump(Out);
+ if (CheckKind.hasValue())
+ Out << " (" << CheckNames[*CheckKind].getName() << ")";
Out << NL;
}
}
@@ -2190,17 +2370,23 @@ void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
void ento::registerNewDeleteLeaksChecker(CheckerManager &mgr) {
registerCStringCheckerBasic(mgr);
- mgr.registerChecker<MallocChecker>()->Filter.CNewDeleteLeaksChecker = true;
+ MallocChecker *checker = mgr.registerChecker<MallocChecker>();
+ checker->ChecksEnabled[MallocChecker::CK_NewDeleteLeaksChecker] = true;
+ checker->CheckNames[MallocChecker::CK_NewDeleteLeaksChecker] =
+ mgr.getCurrentCheckName();
// We currently treat NewDeleteLeaks checker as a subchecker of NewDelete
// checker.
- mgr.registerChecker<MallocChecker>()->Filter.CNewDeleteChecker = true;
+ if (!checker->ChecksEnabled[MallocChecker::CK_NewDeleteChecker])
+ checker->ChecksEnabled[MallocChecker::CK_NewDeleteChecker] = true;
}
-#define REGISTER_CHECKER(name) \
-void ento::register##name(CheckerManager &mgr) {\
- registerCStringCheckerBasic(mgr); \
- mgr.registerChecker<MallocChecker>()->Filter.C##name = true;\
-}
+#define REGISTER_CHECKER(name) \
+ void ento::register##name(CheckerManager &mgr) { \
+ registerCStringCheckerBasic(mgr); \
+ MallocChecker *checker = mgr.registerChecker<MallocChecker>(); \
+ checker->ChecksEnabled[MallocChecker::CK_##name] = true; \
+ checker->CheckNames[MallocChecker::CK_##name] = mgr.getCurrentCheckName(); \
+ }
REGISTER_CHECKER(MallocPessimistic)
REGISTER_CHECKER(MallocOptimistic)
diff --git a/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
index 0cdf911bb4b1..f38ce77dc6b6 100644
--- a/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
@@ -65,7 +65,7 @@ void MallocOverflowSecurityChecker::CheckMallocArgument(
conditional expression, an operation that could reduce the range
of the result, or anything too complicated :-). */
const Expr * e = TheArgument;
- const BinaryOperator * mulop = NULL;
+ const BinaryOperator * mulop = nullptr;
for (;;) {
e = e->IgnoreParenImpCasts();
@@ -73,7 +73,7 @@ void MallocOverflowSecurityChecker::CheckMallocArgument(
const BinaryOperator * binop = dyn_cast<BinaryOperator>(e);
BinaryOperatorKind opc = binop->getOpcode();
// TODO: ignore multiplications by 1, reject if multiplied by 0.
- if (mulop == NULL && opc == BO_Mul)
+ if (mulop == nullptr && opc == BO_Mul)
mulop = binop;
if (opc != BO_Mul && opc != BO_Add && opc != BO_Sub && opc != BO_Shl)
return;
@@ -94,7 +94,7 @@ void MallocOverflowSecurityChecker::CheckMallocArgument(
return;
}
- if (mulop == NULL)
+ if (mulop == nullptr)
return;
// We've found the right structure of malloc argument, now save
@@ -213,11 +213,12 @@ void MallocOverflowSecurityChecker::OutputPossibleOverflows(
e = PossibleMallocOverflows.end();
i != e;
++i) {
- BR.EmitBasicReport(D, "malloc() size overflow", categories::UnixAPI,
- "the computation of the size of the memory allocation may overflow",
- PathDiagnosticLocation::createOperatorLoc(i->mulop,
- BR.getSourceManager()),
- i->mulop->getSourceRange());
+ BR.EmitBasicReport(
+ D, this, "malloc() size overflow", categories::UnixAPI,
+ "the computation of the size of the memory allocation may overflow",
+ PathDiagnosticLocation::createOperatorLoc(i->mulop,
+ BR.getSourceManager()),
+ i->mulop->getSourceRange());
}
}
@@ -262,6 +263,7 @@ void MallocOverflowSecurityChecker::checkASTCodeBody(const Decl *D,
OutputPossibleOverflows(PossibleMallocOverflows, D, BR, mgr);
}
-void ento::registerMallocOverflowSecurityChecker(CheckerManager &mgr) {
+void
+ento::registerMallocOverflowSecurityChecker(CheckerManager &mgr) {
mgr.registerChecker<MallocOverflowSecurityChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
index 6c776eb9ebb5..4a50d9362874 100644
--- a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
@@ -95,15 +95,14 @@ public:
if (FD) {
IdentifierInfo *II = FD->getIdentifier();
if (II == II_malloc || II == II_calloc || II == II_realloc)
- return TypeCallPair((const TypeSourceInfo *)0, E);
+ return TypeCallPair((const TypeSourceInfo *)nullptr, E);
}
return TypeCallPair();
}
TypeCallPair VisitDeclStmt(const DeclStmt *S) {
- for (DeclStmt::const_decl_iterator I = S->decl_begin(), E = S->decl_end();
- I!=E; ++I)
- if (const VarDecl *VD = dyn_cast<VarDecl>(*I))
+ for (const auto *I : S->decls())
+ if (const VarDecl *VD = dyn_cast<VarDecl>(I))
if (const Expr *Init = VD->getInit())
VisitChild(VD, Init);
return TypeCallPair();
@@ -206,7 +205,7 @@ public:
if (compatibleWithArrayType(BR.getContext(), PointeeType, SizeofType))
continue;
- const TypeSourceInfo *TSI = 0;
+ const TypeSourceInfo *TSI = nullptr;
if (i->CastedExprParent.is<const VarDecl *>()) {
TSI =
i->CastedExprParent.get<const VarDecl *>()->getTypeSourceInfo();
@@ -236,10 +235,8 @@ public:
PathDiagnosticLocation::createBegin(i->AllocCall->getCallee(),
BR.getSourceManager(), ADC);
- BR.EmitBasicReport(D, "Allocator sizeof operand mismatch",
- categories::UnixAPI,
- OS.str(),
- L, Ranges);
+ BR.EmitBasicReport(D, this, "Allocator sizeof operand mismatch",
+ categories::UnixAPI, OS.str(), L, Ranges);
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
index fc28e1fb7f49..b180c03f0871 100644
--- a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
@@ -32,7 +32,7 @@ using namespace ento;
namespace {
class NSAutoreleasePoolChecker
: public Checker<check::PreObjCMessage> {
- mutable OwningPtr<BugType> BT;
+ mutable std::unique_ptr<BugType> BT;
mutable Selector releaseS;
public:
@@ -59,7 +59,7 @@ void NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
return;
if (!BT)
- BT.reset(new BugType("Use -drain instead of -release",
+ BT.reset(new BugType(this, "Use -drain instead of -release",
"API Upgrade (Apple)"));
ExplodedNode *N = C.addTransition();
diff --git a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 9f01522eadbd..2be7f1d4ab8c 100644
--- a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -42,7 +42,7 @@ class NSErrorMethodChecker
mutable IdentifierInfo *II;
public:
- NSErrorMethodChecker() : II(0) { }
+ NSErrorMethodChecker() : II(nullptr) {}
void checkASTDecl(const ObjCMethodDecl *D,
AnalysisManager &mgr, BugReporter &BR) const;
@@ -54,16 +54,15 @@ void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D,
BugReporter &BR) const {
if (!D->isThisDeclarationADefinition())
return;
- if (!D->getResultType()->isVoidType())
+ if (!D->getReturnType()->isVoidType())
return;
if (!II)
II = &D->getASTContext().Idents.get("NSError");
bool hasNSError = false;
- for (ObjCMethodDecl::param_const_iterator
- I = D->param_begin(), E = D->param_end(); I != E; ++I) {
- if (IsNSError((*I)->getType(), II)) {
+ for (const auto *I : D->params()) {
+ if (IsNSError(I->getType(), II)) {
hasNSError = true;
break;
}
@@ -75,7 +74,7 @@ void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D,
"error occurred";
PathDiagnosticLocation L =
PathDiagnosticLocation::create(D, BR.getSourceManager());
- BR.EmitBasicReport(D, "Bad return type when passing NSError**",
+ BR.EmitBasicReport(D, this, "Bad return type when passing NSError**",
"Coding conventions (Apple)", err, L);
}
}
@@ -90,7 +89,7 @@ class CFErrorFunctionChecker
mutable IdentifierInfo *II;
public:
- CFErrorFunctionChecker() : II(0) { }
+ CFErrorFunctionChecker() : II(nullptr) {}
void checkASTDecl(const FunctionDecl *D,
AnalysisManager &mgr, BugReporter &BR) const;
@@ -102,16 +101,15 @@ void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D,
BugReporter &BR) const {
if (!D->doesThisDeclarationHaveABody())
return;
- if (!D->getResultType()->isVoidType())
+ if (!D->getReturnType()->isVoidType())
return;
if (!II)
II = &D->getASTContext().Idents.get("CFErrorRef");
bool hasCFError = false;
- for (FunctionDecl::param_const_iterator
- I = D->param_begin(), E = D->param_end(); I != E; ++I) {
- if (IsCFError((*I)->getType(), II)) {
+ for (auto I : D->params()) {
+ if (IsCFError(I->getType(), II)) {
hasCFError = true;
break;
}
@@ -123,7 +121,7 @@ void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D,
"error occurred";
PathDiagnosticLocation L =
PathDiagnosticLocation::create(D, BR.getSourceManager());
- BR.EmitBasicReport(D, "Bad return type when passing CFErrorRef*",
+ BR.EmitBasicReport(D, this, "Bad return type when passing CFErrorRef*",
"Coding conventions (Apple)", err, L);
}
}
@@ -136,14 +134,16 @@ namespace {
class NSErrorDerefBug : public BugType {
public:
- NSErrorDerefBug() : BugType("NSError** null dereference",
- "Coding conventions (Apple)") {}
+ NSErrorDerefBug(const CheckerBase *Checker)
+ : BugType(Checker, "NSError** null dereference",
+ "Coding conventions (Apple)") {}
};
class CFErrorDerefBug : public BugType {
public:
- CFErrorDerefBug() : BugType("CFErrorRef* null dereference",
- "Coding conventions (Apple)") {}
+ CFErrorDerefBug(const CheckerBase *Checker)
+ : BugType(Checker, "CFErrorRef* null dereference",
+ "Coding conventions (Apple)") {}
};
}
@@ -153,9 +153,11 @@ class NSOrCFErrorDerefChecker
: public Checker< check::Location,
check::Event<ImplicitNullDerefEvent> > {
mutable IdentifierInfo *NSErrorII, *CFErrorII;
+ mutable std::unique_ptr<NSErrorDerefBug> NSBT;
+ mutable std::unique_ptr<CFErrorDerefBug> CFBT;
public:
bool ShouldCheckNSError, ShouldCheckCFError;
- NSOrCFErrorDerefChecker() : NSErrorII(0), CFErrorII(0),
+ NSOrCFErrorDerefChecker() : NSErrorII(nullptr), CFErrorII(nullptr),
ShouldCheckNSError(0), ShouldCheckCFError(0) { }
void checkLocation(SVal loc, bool isLoad, const Stmt *S,
@@ -262,13 +264,18 @@ void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const {
os << " may be null";
- BugType *bug = 0;
- if (isNSError)
- bug = new NSErrorDerefBug();
- else
- bug = new CFErrorDerefBug();
- BugReport *report = new BugReport(*bug, os.str(),
- event.SinkNode);
+ BugType *bug = nullptr;
+ if (isNSError) {
+ if (!NSBT)
+ NSBT.reset(new NSErrorDerefBug(this));
+ bug = NSBT.get();
+ }
+ else {
+ if (!CFBT)
+ CFBT.reset(new CFErrorDerefBug(this));
+ bug = CFBT.get();
+ }
+ BugReport *report = new BugReport(*bug, os.str(), event.SinkNode);
BR.emitReport(report);
}
@@ -305,14 +312,14 @@ static bool IsCFError(QualType T, IdentifierInfo *II) {
void ento::registerNSErrorChecker(CheckerManager &mgr) {
mgr.registerChecker<NSErrorMethodChecker>();
- NSOrCFErrorDerefChecker *
- checker = mgr.registerChecker<NSOrCFErrorDerefChecker>();
+ NSOrCFErrorDerefChecker *checker =
+ mgr.registerChecker<NSOrCFErrorDerefChecker>();
checker->ShouldCheckNSError = true;
}
void ento::registerCFErrorChecker(CheckerManager &mgr) {
mgr.registerChecker<CFErrorFunctionChecker>();
- NSOrCFErrorDerefChecker *
- checker = mgr.registerChecker<NSOrCFErrorDerefChecker>();
+ NSOrCFErrorDerefChecker *checker =
+ mgr.registerChecker<NSOrCFErrorDerefChecker>();
checker->ShouldCheckCFError = true;
}
diff --git a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
index 0e1064ef53a6..ba82d1d1d41f 100644
--- a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "SelectorExtras.h"
#include "clang/AST/Attr.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
@@ -28,6 +29,8 @@ namespace {
class NoReturnFunctionChecker : public Checker< check::PostCall,
check::PostObjCMessage > {
+ mutable Selector HandleFailureInFunctionSel;
+ mutable Selector HandleFailureInMethodSel;
public:
void checkPostCall(const CallEvent &CE, CheckerContext &C) const;
void checkPostObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
@@ -37,11 +40,10 @@ public:
void NoReturnFunctionChecker::checkPostCall(const CallEvent &CE,
CheckerContext &C) const {
- ProgramStateRef state = C.getState();
bool BuildSinks = false;
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE.getDecl()))
- BuildSinks = FD->getAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn();
+ BuildSinks = FD->hasAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn();
const Expr *Callee = CE.getOriginExpr();
if (!BuildSinks && Callee)
@@ -82,24 +84,6 @@ void NoReturnFunctionChecker::checkPostCall(const CallEvent &CE,
C.generateSink();
}
-static bool END_WITH_NULL isMultiArgSelector(const Selector *Sel, ...) {
- va_list argp;
- va_start(argp, Sel);
-
- unsigned Slot = 0;
- const char *Arg;
- while ((Arg = va_arg(argp, const char *))) {
- if (!Sel->getNameForSlot(Slot).equals(Arg))
- break; // still need to va_end!
- ++Slot;
- }
-
- va_end(argp);
-
- // We only succeeded if we made it to the end of the argument list.
- return (Arg == NULL);
-}
-
void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
CheckerContext &C) const {
// Check if the method is annotated with analyzer_noreturn.
@@ -136,13 +120,17 @@ void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
default:
return;
case 4:
- if (!isMultiArgSelector(&Sel, "handleFailureInFunction", "file",
- "lineNumber", "description", NULL))
+ lazyInitKeywordSelector(HandleFailureInFunctionSel, C.getASTContext(),
+ "handleFailureInFunction", "file", "lineNumber",
+ "description", nullptr);
+ if (Sel != HandleFailureInFunctionSel)
return;
break;
case 5:
- if (!isMultiArgSelector(&Sel, "handleFailureInMethod", "object", "file",
- "lineNumber", "description", NULL))
+ lazyInitKeywordSelector(HandleFailureInMethodSel, C.getASTContext(),
+ "handleFailureInMethod", "object", "file",
+ "lineNumber", "description", nullptr);
+ if (Sel != HandleFailureInMethodSel)
return;
break;
}
@@ -151,7 +139,6 @@ void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
C.generateSink();
}
-
void ento::registerNoReturnFunctionChecker(CheckerManager &mgr) {
mgr.registerChecker<NoReturnFunctionChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
index 273a7a38824a..61d2b87cb0c0 100644
--- a/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
@@ -29,8 +29,9 @@ using namespace ento;
namespace {
class NonNullParamChecker
: public Checker< check::PreCall > {
- mutable OwningPtr<BugType> BTAttrNonNull;
- mutable OwningPtr<BugType> BTNullRefArg;
+ mutable std::unique_ptr<BugType> BTAttrNonNull;
+ mutable std::unique_ptr<BugType> BTNullRefArg;
+
public:
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
@@ -43,7 +44,7 @@ public:
} // end anonymous namespace
void NonNullParamChecker::checkPreCall(const CallEvent &Call,
- CheckerContext &C) const {
+ CheckerContext &C) const {
const Decl *FD = Call.getDecl();
if (!FD)
return;
@@ -66,6 +67,12 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call,
}
bool haveAttrNonNull = Att && Att->isNonNull(idx);
+ if (!haveAttrNonNull) {
+ // Check if the parameter is also marked 'nonnull'.
+ ArrayRef<ParmVarDecl*> parms = Call.parameters();
+ if (idx < parms.size())
+ haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>();
+ }
if (!haveRefTypeParam && !haveAttrNonNull)
continue;
@@ -98,7 +105,9 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call,
V = *CSV_I;
DV = V.getAs<DefinedSVal>();
assert(++CSV_I == CSV->end());
- if (!DV)
+ // FIXME: Handle (some_union){ some_other_union_val }, which turns into
+ // a LazyCompoundVal inside a CompoundVal.
+ if (!V.getAs<Loc>())
continue;
// Retrieve the corresponding expression.
if (const CompoundLiteralExpr *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
@@ -114,14 +123,14 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call,
ConstraintManager &CM = C.getConstraintManager();
ProgramStateRef stateNotNull, stateNull;
- llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
+ std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
if (stateNull && !stateNotNull) {
// Generate an error node. Check for a null node in case
// we cache out.
if (ExplodedNode *errorNode = C.generateSink(stateNull)) {
- BugReport *R = 0;
+ BugReport *R = nullptr;
if (haveAttrNonNull)
R = genReportNullAttrNonNull(errorNode, ArgE);
else if (haveRefTypeParam)
@@ -156,8 +165,7 @@ BugReport *NonNullParamChecker::genReportNullAttrNonNull(
// the BugReport is passed to 'EmitWarning'.
if (!BTAttrNonNull)
BTAttrNonNull.reset(new BugType(
- "Argument with 'nonnull' attribute passed null",
- "API"));
+ this, "Argument with 'nonnull' attribute passed null", "API"));
BugReport *R = new BugReport(*BTAttrNonNull,
"Null pointer passed as an argument to a 'nonnull' parameter",
@@ -171,14 +179,14 @@ BugReport *NonNullParamChecker::genReportNullAttrNonNull(
BugReport *NonNullParamChecker::genReportReferenceToNullPointer(
const ExplodedNode *ErrorNode, const Expr *ArgE) const {
if (!BTNullRefArg)
- BTNullRefArg.reset(new BuiltinBug("Dereference of null pointer"));
+ BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer"));
BugReport *R = new BugReport(*BTNullRefArg,
"Forming reference to null pointer",
ErrorNode);
if (ArgE) {
const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
- if (ArgEDeref == 0)
+ if (!ArgEDeref)
ArgEDeref = ArgE;
bugreporter::trackNullOrUndefValue(ErrorNode,
ArgEDeref,
diff --git a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
index 4018a66ecf57..fbf2d73dd86c 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
@@ -26,8 +26,8 @@ using namespace ento;
namespace {
class ObjCAtSyncChecker
: public Checker< check::PreStmt<ObjCAtSynchronizedStmt> > {
- mutable OwningPtr<BuiltinBug> BT_null;
- mutable OwningPtr<BuiltinBug> BT_undef;
+ mutable std::unique_ptr<BuiltinBug> BT_null;
+ mutable std::unique_ptr<BuiltinBug> BT_undef;
public:
void checkPreStmt(const ObjCAtSynchronizedStmt *S, CheckerContext &C) const;
@@ -45,8 +45,8 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
if (V.getAs<UndefinedVal>()) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT_undef)
- BT_undef.reset(new BuiltinBug("Uninitialized value used as mutex "
- "for @synchronized"));
+ BT_undef.reset(new BuiltinBug(this, "Uninitialized value used as mutex "
+ "for @synchronized"));
BugReport *report =
new BugReport(*BT_undef, BT_undef->getDescription(), N);
bugreporter::trackNullOrUndefValue(N, Ex, *report);
@@ -60,7 +60,7 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
// Check for null mutexes.
ProgramStateRef notNullState, nullState;
- llvm::tie(notNullState, nullState) = state->assume(V.castAs<DefinedSVal>());
+ std::tie(notNullState, nullState) = state->assume(V.castAs<DefinedSVal>());
if (nullState) {
if (!notNullState) {
@@ -68,8 +68,9 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
// a null mutex just means no synchronization occurs.
if (ExplodedNode *N = C.addTransition(nullState)) {
if (!BT_null)
- BT_null.reset(new BuiltinBug("Nil value used as mutex for @synchronized() "
- "(no synchronization will occur)"));
+ BT_null.reset(new BuiltinBug(
+ this, "Nil value used as mutex for @synchronized() "
+ "(no synchronization will occur)"));
BugReport *report =
new BugReport(*BT_null, BT_null->getDescription(), N);
bugreporter::trackNullOrUndefValue(N, Ex, *report);
diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
index 503b1b501a71..e3fc611a7e00 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
@@ -27,6 +27,7 @@ using namespace ento;
namespace {
class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
+ const CheckerBase *Checker;
AnalysisDeclContext* AC;
ASTContext &ASTC;
uint64_t PtrWidth;
@@ -71,9 +72,9 @@ class WalkAST : public StmtVisitor<WalkAST> {
}
public:
- WalkAST(BugReporter &br, AnalysisDeclContext* ac)
- : BR(br), AC(ac), ASTC(AC->getASTContext()),
- PtrWidth(ASTC.getTargetInfo().getPointerWidth(0)) {}
+ WalkAST(BugReporter &br, const CheckerBase *checker, AnalysisDeclContext *ac)
+ : BR(br), Checker(checker), AC(ac), ASTC(AC->getASTContext()),
+ PtrWidth(ASTC.getTargetInfo().getPointerWidth(0)) {}
// Statement visitor methods.
void VisitChildren(Stmt *S);
@@ -99,7 +100,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
if (Name.empty())
return;
- const Expr *Arg = 0;
+ const Expr *Arg = nullptr;
unsigned ArgNum;
if (Name.equals("CFArrayCreate") || Name.equals("CFSetCreate")) {
@@ -142,9 +143,9 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
- BR.EmitBasicReport(AC->getDecl(),
- OsName.str(), categories::CoreFoundationObjectiveC,
- Os.str(), CELoc, Arg->getSourceRange());
+ BR.EmitBasicReport(AC->getDecl(), Checker, OsName.str(),
+ categories::CoreFoundationObjectiveC, Os.str(), CELoc,
+ Arg->getSourceRange());
}
// Recurse and check children.
@@ -163,7 +164,7 @@ public:
void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
BugReporter &BR) const {
- WalkAST walker(BR, Mgr.getAnalysisDeclContext(D));
+ WalkAST walker(BR, this, Mgr.getAnalysisDeclContext(D));
walker.Visit(D->getBody());
}
};
diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
index b9e96ee99fc6..8e51154fc3a1 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
@@ -30,10 +30,10 @@ using namespace ento;
namespace {
class ObjCContainersChecker : public Checker< check::PreStmt<CallExpr>,
check::PostStmt<CallExpr> > {
- mutable OwningPtr<BugType> BT;
+ mutable std::unique_ptr<BugType> BT;
inline void initBugType() const {
if (!BT)
- BT.reset(new BugType("CFArray API",
+ BT.reset(new BugType(this, "CFArray API",
categories::CoreFoundationObjectiveC));
}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
index 789b9f4cc19c..a2cf8e10d09b 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
@@ -181,16 +181,12 @@ void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
// Iterate over all instance methods.
- for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
- E = D->instmeth_end();
- I != E; ++I) {
- Selector S = (*I)->getSelector();
+ for (auto *MD : D->instance_methods()) {
+ Selector S = MD->getSelector();
// Find out whether this is a selector that we want to check.
if (!SelectorsForClass[SuperclassName].count(S))
continue;
- ObjCMethodDecl *MD = *I;
-
// Check if the method calls its superclass implementation.
if (MD->getBody())
{
@@ -212,7 +208,7 @@ void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
<< "' instance method in " << SuperclassName.str() << " subclass '"
<< *D << "' is missing a [super " << S.getAsString() << "] call";
- BR.EmitBasicReport(MD, Name, categories::CoreFoundationObjectiveC,
+ BR.EmitBasicReport(MD, this, Name, categories::CoreFoundationObjectiveC,
os.str(), DLoc);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index 8506e08b2b98..51bc7e66dce2 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -62,7 +62,13 @@ class ObjCSelfInitChecker : public Checker< check::PostObjCMessage,
check::PostCall,
check::Location,
check::Bind > {
+ mutable std::unique_ptr<BugType> BT;
+
+ void checkForInvalidSelf(const Expr *E, CheckerContext &C,
+ const char *errorStr) const;
+
public:
+ ObjCSelfInitChecker() {}
void checkPostObjCMessage(const ObjCMethodCall &Msg, CheckerContext &C) const;
void checkPostStmt(const ObjCIvarRefExpr *E, CheckerContext &C) const;
void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
@@ -74,22 +80,11 @@ public:
void checkPostCall(const CallEvent &CE, CheckerContext &C) const;
void printState(raw_ostream &Out, ProgramStateRef State,
- const char *NL, const char *Sep) const;
+ const char *NL, const char *Sep) const override;
};
} // end anonymous namespace
namespace {
-
-class InitSelfBug : public BugType {
- const std::string desc;
-public:
- InitSelfBug() : BugType("Missing \"self = [(super or self) init...]\"",
- categories::CoreFoundationObjectiveC) {}
-};
-
-} // end anonymous namespace
-
-namespace {
enum SelfFlagEnum {
/// \brief No flag set.
SelfFlag_None = 0x0,
@@ -146,8 +141,8 @@ static bool isInvalidSelf(const Expr *E, CheckerContext &C) {
return true;
}
-static void checkForInvalidSelf(const Expr *E, CheckerContext &C,
- const char *errorStr) {
+void ObjCSelfInitChecker::checkForInvalidSelf(const Expr *E, CheckerContext &C,
+ const char *errorStr) const {
if (!E)
return;
@@ -162,8 +157,10 @@ static void checkForInvalidSelf(const Expr *E, CheckerContext &C,
if (!N)
return;
- BugReport *report =
- new BugReport(*new InitSelfBug(), errorStr, N);
+ if (!BT)
+ BT.reset(new BugType(this, "Missing \"self = [(super or self) init...]\"",
+ categories::CoreFoundationObjectiveC));
+ BugReport *report = new BugReport(*BT, errorStr, N);
C.emitReport(report);
}
@@ -205,9 +202,10 @@ void ObjCSelfInitChecker::checkPostStmt(const ObjCIvarRefExpr *E,
C.getCurrentAnalysisDeclContext()->getDecl())))
return;
- checkForInvalidSelf(E->getBase(), C,
- "Instance variable used while 'self' is not set to the result of "
- "'[(super or self) init...]'");
+ checkForInvalidSelf(
+ E->getBase(), C,
+ "Instance variable used while 'self' is not set to the result of "
+ "'[(super or self) init...]'");
}
void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S,
@@ -218,8 +216,8 @@ void ObjCSelfInitChecker::checkPreStmt(const ReturnStmt *S,
return;
checkForInvalidSelf(S->getRetValue(), C,
- "Returning 'self' while it is not set to the result of "
- "'[(super or self) init...]'");
+ "Returning 'self' while it is not set to the result of "
+ "'[(super or self) init...]'");
}
// When a call receives a reference to 'self', [Pre/Post]Call pass
@@ -347,7 +345,7 @@ void ObjCSelfInitChecker::printState(raw_ostream &Out, ProgramStateRef State,
if (FlagMap.isEmpty() && !DidCallInit && !PreCallFlags)
return;
- Out << Sep << NL << "ObjCSelfInitChecker:" << NL;
+ Out << Sep << NL << *this << " :" << NL;
if (DidCallInit)
Out << " An init method has been called." << NL;
diff --git a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
index c66c7d019350..d3b17534fdac 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
@@ -77,22 +77,17 @@ static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl *D) {
static void Scan(IvarUsageMap& M, const ObjCContainerDecl *D) {
// Scan the methods for accesses.
- for (ObjCContainerDecl::instmeth_iterator I = D->instmeth_begin(),
- E = D->instmeth_end(); I!=E; ++I)
- Scan(M, (*I)->getBody());
+ for (const auto *I : D->instance_methods())
+ Scan(M, I->getBody());
if (const ObjCImplementationDecl *ID = dyn_cast<ObjCImplementationDecl>(D)) {
// Scan for @synthesized property methods that act as setters/getters
// to an ivar.
- for (ObjCImplementationDecl::propimpl_iterator I = ID->propimpl_begin(),
- E = ID->propimpl_end(); I!=E; ++I)
- Scan(M, *I);
+ for (const auto *I : ID->property_impls())
+ Scan(M, I);
// Scan the associated categories as well.
- for (ObjCInterfaceDecl::visible_categories_iterator
- Cat = ID->getClassInterface()->visible_categories_begin(),
- CatEnd = ID->getClassInterface()->visible_categories_end();
- Cat != CatEnd; ++Cat) {
+ for (const auto *Cat : ID->getClassInterface()->visible_categories()) {
if (const ObjCCategoryImplDecl *CID = Cat->getImplementation())
Scan(M, CID);
}
@@ -101,9 +96,8 @@ static void Scan(IvarUsageMap& M, const ObjCContainerDecl *D) {
static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID,
SourceManager &SM) {
- for (DeclContext::decl_iterator I=C->decls_begin(), E=C->decls_end();
- I!=E; ++I)
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
+ for (const auto *I : C->decls())
+ if (const auto *FD = dyn_cast<FunctionDecl>(I)) {
SourceLocation L = FD->getLocStart();
if (SM.getFileID(L) == FID)
Scan(M, FD->getBody());
@@ -111,29 +105,26 @@ static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID,
}
static void checkObjCUnusedIvar(const ObjCImplementationDecl *D,
- BugReporter &BR) {
+ BugReporter &BR,
+ const CheckerBase *Checker) {
const ObjCInterfaceDecl *ID = D->getClassInterface();
IvarUsageMap M;
// Iterate over the ivars.
- for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(),
- E=ID->ivar_end(); I!=E; ++I) {
-
- const ObjCIvarDecl *ID = *I;
-
+ for (const auto *Ivar : ID->ivars()) {
// Ignore ivars that...
// (a) aren't private
// (b) explicitly marked unused
// (c) are iboutlets
// (d) are unnamed bitfields
- if (ID->getAccessControl() != ObjCIvarDecl::Private ||
- ID->getAttr<UnusedAttr>() || ID->getAttr<IBOutletAttr>() ||
- ID->getAttr<IBOutletCollectionAttr>() ||
- ID->isUnnamedBitfield())
+ if (Ivar->getAccessControl() != ObjCIvarDecl::Private ||
+ Ivar->hasAttr<UnusedAttr>() || Ivar->hasAttr<IBOutletAttr>() ||
+ Ivar->hasAttr<IBOutletCollectionAttr>() ||
+ Ivar->isUnnamedBitfield())
continue;
- M[ID] = Unused;
+ M[Ivar] = Unused;
}
if (M.empty())
@@ -172,7 +163,7 @@ static void checkObjCUnusedIvar(const ObjCImplementationDecl *D,
PathDiagnosticLocation L =
PathDiagnosticLocation::create(I->first, BR.getSourceManager());
- BR.EmitBasicReport(D, "Unused instance variable", "Optimization",
+ BR.EmitBasicReport(D, Checker, "Unused instance variable", "Optimization",
os.str(), L);
}
}
@@ -187,7 +178,7 @@ class ObjCUnusedIvarsChecker : public Checker<
public:
void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr,
BugReporter &BR) const {
- checkObjCUnusedIvar(D, BR);
+ checkObjCUnusedIvar(D, BR, this);
}
};
}
diff --git a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
index bcbfacdb1774..00480e4abf12 100644
--- a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
@@ -24,7 +24,7 @@ using namespace ento;
namespace {
class PointerArithChecker
: public Checker< check::PreStmt<BinaryOperator> > {
- mutable OwningPtr<BuiltinBug> BT;
+ mutable std::unique_ptr<BuiltinBug> BT;
public:
void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
@@ -53,10 +53,11 @@ void PointerArithChecker::checkPreStmt(const BinaryOperator *B,
if (ExplodedNode *N = C.addTransition()) {
if (!BT)
- BT.reset(new BuiltinBug("Dangerous pointer arithmetic",
- "Pointer arithmetic done on non-array variables "
- "means reliance on memory layout, which is "
- "dangerous."));
+ BT.reset(
+ new BuiltinBug(this, "Dangerous pointer arithmetic",
+ "Pointer arithmetic done on non-array variables "
+ "means reliance on memory layout, which is "
+ "dangerous."));
BugReport *R = new BugReport(*BT, BT->getDescription(), N);
R->addRange(B->getSourceRange());
C.emitReport(R);
diff --git a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index 07c82d461941..fbb2628a9ce5 100644
--- a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -25,7 +25,7 @@ using namespace ento;
namespace {
class PointerSubChecker
: public Checker< check::PreStmt<BinaryOperator> > {
- mutable OwningPtr<BuiltinBug> BT;
+ mutable std::unique_ptr<BuiltinBug> BT;
public:
void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
@@ -62,9 +62,10 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
if (ExplodedNode *N = C.addTransition()) {
if (!BT)
- BT.reset(new BuiltinBug("Pointer subtraction",
- "Subtraction of two pointers that do not point to "
- "the same memory chunk may cause incorrect result."));
+ BT.reset(
+ new BuiltinBug(this, "Pointer subtraction",
+ "Subtraction of two pointers that do not point to "
+ "the same memory chunk may cause incorrect result."));
BugReport *R = new BugReport(*BT, BT->getDescription(), N);
R->addRange(B->getSourceRange());
C.emitReport(R);
diff --git a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index ffb8cf20207b..1ede3a2a5126 100644
--- a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -24,9 +24,37 @@ using namespace clang;
using namespace ento;
namespace {
+
+struct LockState {
+ enum Kind { Destroyed, Locked, Unlocked } K;
+
+private:
+ LockState(Kind K) : K(K) {}
+
+public:
+ static LockState getLocked(void) { return LockState(Locked); }
+ static LockState getUnlocked(void) { return LockState(Unlocked); }
+ static LockState getDestroyed(void) { return LockState(Destroyed); }
+
+ bool operator==(const LockState &X) const {
+ return K == X.K;
+ }
+
+ bool isLocked() const { return K == Locked; }
+ bool isUnlocked() const { return K == Unlocked; }
+ bool isDestroyed() const { return K == Destroyed; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(K);
+ }
+};
+
class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > {
- mutable OwningPtr<BugType> BT_doublelock;
- mutable OwningPtr<BugType> BT_lor;
+ mutable std::unique_ptr<BugType> BT_doublelock;
+ mutable std::unique_ptr<BugType> BT_doubleunlock;
+ mutable std::unique_ptr<BugType> BT_destroylock;
+ mutable std::unique_ptr<BugType> BT_initlock;
+ mutable std::unique_ptr<BugType> BT_lor;
enum LockingSemantics {
NotApplicable = 0,
PthreadSemantics,
@@ -39,12 +67,16 @@ public:
bool isTryLock, enum LockingSemantics semantics) const;
void ReleaseLock(CheckerContext &C, const CallExpr *CE, SVal lock) const;
+ void DestroyLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const;
+ void InitLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const;
+ void reportUseDestroyedBug(CheckerContext &C, const CallExpr *CE) const;
};
} // end anonymous namespace
// GDM Entry for tracking lock state.
REGISTER_LIST_WITH_PROGRAMSTATE(LockSet, const MemRegion *)
+REGISTER_MAP_WITH_PROGRAMSTATE(LockMap, const MemRegion *, LockState)
void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
CheckerContext &C) const {
@@ -54,7 +86,7 @@ void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
if (FName.empty())
return;
- if (CE->getNumArgs() != 1)
+ if (CE->getNumArgs() != 1 && CE->getNumArgs() != 2)
return;
if (FName == "pthread_mutex_lock" ||
@@ -69,7 +101,7 @@ void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
false, XNUSemantics);
else if (FName == "pthread_mutex_trylock" ||
FName == "pthread_rwlock_tryrdlock" ||
- FName == "pthread_rwlock_tryrwlock")
+ FName == "pthread_rwlock_trywrlock")
AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
true, PthreadSemantics);
else if (FName == "lck_mtx_try_lock" ||
@@ -82,6 +114,11 @@ void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
FName == "lck_mtx_unlock" ||
FName == "lck_rw_done")
ReleaseLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
+ else if (FName == "pthread_mutex_destroy" ||
+ FName == "lck_mtx_destroy")
+ DestroyLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
+ else if (FName == "pthread_mutex_init")
+ InitLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
}
void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
@@ -100,18 +137,24 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
DefinedSVal retVal = X.castAs<DefinedSVal>();
- if (state->contains<LockSet>(lockR)) {
- if (!BT_doublelock)
- BT_doublelock.reset(new BugType("Double locking", "Lock checker"));
- ExplodedNode *N = C.generateSink();
- if (!N)
+ if (const LockState *LState = state->get<LockMap>(lockR)) {
+ if (LState->isLocked()) {
+ if (!BT_doublelock)
+ BT_doublelock.reset(new BugType(this, "Double locking",
+ "Lock checker"));
+ ExplodedNode *N = C.generateSink();
+ if (!N)
+ return;
+ BugReport *report = new BugReport(*BT_doublelock,
+ "This lock has already been acquired",
+ N);
+ report->addRange(CE->getArg(0)->getSourceRange());
+ C.emitReport(report);
return;
- BugReport *report = new BugReport(*BT_doublelock,
- "This lock has already "
- "been acquired", N);
- report->addRange(CE->getArg(0)->getSourceRange());
- C.emitReport(report);
- return;
+ } else if (LState->isDestroyed()) {
+ reportUseDestroyedBug(C, CE);
+ return;
+ }
}
ProgramStateRef lockSucc = state;
@@ -120,10 +163,10 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
ProgramStateRef lockFail;
switch (semantics) {
case PthreadSemantics:
- llvm::tie(lockFail, lockSucc) = state->assume(retVal);
+ std::tie(lockFail, lockSucc) = state->assume(retVal);
break;
case XNUSemantics:
- llvm::tie(lockSucc, lockFail) = state->assume(retVal);
+ std::tie(lockSucc, lockFail) = state->assume(retVal);
break;
default:
llvm_unreachable("Unknown tryLock locking semantics");
@@ -144,6 +187,7 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
// Record that the lock was acquired.
lockSucc = lockSucc->add<LockSet>(lockR);
+ lockSucc = lockSucc->set<LockMap>(lockR, LockState::getLocked());
C.addTransition(lockSucc);
}
@@ -155,35 +199,140 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
return;
ProgramStateRef state = C.getState();
+
+ if (const LockState *LState = state->get<LockMap>(lockR)) {
+ if (LState->isUnlocked()) {
+ if (!BT_doubleunlock)
+ BT_doubleunlock.reset(new BugType(this, "Double unlocking",
+ "Lock checker"));
+ ExplodedNode *N = C.generateSink();
+ if (!N)
+ return;
+ BugReport *Report = new BugReport(*BT_doubleunlock,
+ "This lock has already been unlocked",
+ N);
+ Report->addRange(CE->getArg(0)->getSourceRange());
+ C.emitReport(Report);
+ return;
+ } else if (LState->isDestroyed()) {
+ reportUseDestroyedBug(C, CE);
+ return;
+ }
+ }
+
LockSetTy LS = state->get<LockSet>();
// FIXME: Better analysis requires IPA for wrappers.
- // FIXME: check for double unlocks
- if (LS.isEmpty())
- return;
-
- const MemRegion *firstLockR = LS.getHead();
- if (firstLockR != lockR) {
- if (!BT_lor)
- BT_lor.reset(new BugType("Lock order reversal", "Lock checker"));
- ExplodedNode *N = C.generateSink();
- if (!N)
+
+ if (!LS.isEmpty()) {
+ const MemRegion *firstLockR = LS.getHead();
+ if (firstLockR != lockR) {
+ if (!BT_lor)
+ BT_lor.reset(new BugType(this, "Lock order reversal", "Lock checker"));
+ ExplodedNode *N = C.generateSink();
+ if (!N)
+ return;
+ BugReport *report = new BugReport(*BT_lor,
+ "This was not the most recently "
+ "acquired lock. Possible lock order "
+ "reversal",
+ N);
+ report->addRange(CE->getArg(0)->getSourceRange());
+ C.emitReport(report);
return;
- BugReport *report = new BugReport(*BT_lor,
- "This was not the most "
- "recently acquired lock. "
- "Possible lock order "
- "reversal", N);
- report->addRange(CE->getArg(0)->getSourceRange());
- C.emitReport(report);
- return;
+ }
+ // Record that the lock was released.
+ state = state->set<LockSet>(LS.getTail());
}
- // Record that the lock was released.
- state = state->set<LockSet>(LS.getTail());
+ state = state->set<LockMap>(lockR, LockState::getUnlocked());
C.addTransition(state);
}
+void PthreadLockChecker::DestroyLock(CheckerContext &C, const CallExpr *CE,
+ SVal Lock) const {
+
+ const MemRegion *LockR = Lock.getAsRegion();
+ if (!LockR)
+ return;
+
+ ProgramStateRef State = C.getState();
+
+ const LockState *LState = State->get<LockMap>(LockR);
+ if (!LState || LState->isUnlocked()) {
+ State = State->set<LockMap>(LockR, LockState::getDestroyed());
+ C.addTransition(State);
+ return;
+ }
+
+ StringRef Message;
+
+ if (LState->isLocked()) {
+ Message = "This lock is still locked";
+ } else {
+ Message = "This lock has already been destroyed";
+ }
+
+ if (!BT_destroylock)
+ BT_destroylock.reset(new BugType(this, "Destroy invalid lock",
+ "Lock checker"));
+ ExplodedNode *N = C.generateSink();
+ if (!N)
+ return;
+ BugReport *Report = new BugReport(*BT_destroylock, Message, N);
+ Report->addRange(CE->getArg(0)->getSourceRange());
+ C.emitReport(Report);
+}
+
+void PthreadLockChecker::InitLock(CheckerContext &C, const CallExpr *CE,
+ SVal Lock) const {
+
+ const MemRegion *LockR = Lock.getAsRegion();
+ if (!LockR)
+ return;
+
+ ProgramStateRef State = C.getState();
+
+ const struct LockState *LState = State->get<LockMap>(LockR);
+ if (!LState || LState->isDestroyed()) {
+ State = State->set<LockMap>(LockR, LockState::getUnlocked());
+ C.addTransition(State);
+ return;
+ }
+
+ StringRef Message;
+
+ if (LState->isLocked()) {
+ Message = "This lock is still being held";
+ } else {
+ Message = "This lock has already been initialized";
+ }
+
+ if (!BT_initlock)
+ BT_initlock.reset(new BugType(this, "Init invalid lock",
+ "Lock checker"));
+ ExplodedNode *N = C.generateSink();
+ if (!N)
+ return;
+ BugReport *Report = new BugReport(*BT_initlock, Message, N);
+ Report->addRange(CE->getArg(0)->getSourceRange());
+ C.emitReport(Report);
+}
+
+void PthreadLockChecker::reportUseDestroyedBug(CheckerContext &C,
+ const CallExpr *CE) const {
+ if (!BT_destroylock)
+ BT_destroylock.reset(new BugType(this, "Use destroyed lock",
+ "Lock checker"));
+ ExplodedNode *N = C.generateSink();
+ if (!N)
+ return;
+ BugReport *Report = new BugReport(*BT_destroylock,
+ "This lock has already been destroyed",
+ N);
+ Report->addRange(CE->getArg(0)->getSourceRange());
+ C.emitReport(Report);
+}
void ento::registerPthreadLockChecker(CheckerManager &mgr) {
mgr.registerChecker<PthreadLockChecker>();
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index c474e78310fa..eb699d694087 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -13,6 +13,8 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "AllocationDiagnostics.h"
+#include "SelectorExtras.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -20,6 +22,7 @@
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Checkers/ObjCRetainCount.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
@@ -28,7 +31,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
-#include "clang/StaticAnalyzer/Checkers/ObjCRetainCount.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
@@ -38,8 +40,6 @@
#include "llvm/ADT/StringExtras.h"
#include <cstdarg>
-#include "AllocationDiagnostics.h"
-
using namespace clang;
using namespace ento;
using namespace objc_retain;
@@ -95,29 +95,70 @@ public:
};
private:
- Kind kind;
- RetEffect::ObjKind okind;
+ /// The number of outstanding retains.
unsigned Cnt;
+ /// The number of outstanding autoreleases.
unsigned ACnt;
+ /// The (static) type of the object at the time we started tracking it.
QualType T;
- RefVal(Kind k, RetEffect::ObjKind o, unsigned cnt, unsigned acnt, QualType t)
- : kind(k), okind(o), Cnt(cnt), ACnt(acnt), T(t) {}
+ /// The current state of the object.
+ ///
+ /// See the RefVal::Kind enum for possible values.
+ unsigned RawKind : 5;
+
+ /// The kind of object being tracked (CF or ObjC), if known.
+ ///
+ /// See the RetEffect::ObjKind enum for possible values.
+ unsigned RawObjectKind : 2;
+
+ /// True if the current state and/or retain count may turn out to not be the
+ /// best possible approximation of the reference counting state.
+ ///
+ /// If true, the checker may decide to throw away ("override") this state
+ /// in favor of something else when it sees the object being used in new ways.
+ ///
+ /// This setting should not be propagated to state derived from this state.
+ /// Once we start deriving new states, it would be inconsistent to override
+ /// them.
+ unsigned IsOverridable : 1;
+
+ RefVal(Kind k, RetEffect::ObjKind o, unsigned cnt, unsigned acnt, QualType t,
+ bool Overridable = false)
+ : Cnt(cnt), ACnt(acnt), T(t), RawKind(static_cast<unsigned>(k)),
+ RawObjectKind(static_cast<unsigned>(o)), IsOverridable(Overridable) {
+ assert(getKind() == k && "not enough bits for the kind");
+ assert(getObjKind() == o && "not enough bits for the object kind");
+ }
public:
- Kind getKind() const { return kind; }
+ Kind getKind() const { return static_cast<Kind>(RawKind); }
- RetEffect::ObjKind getObjKind() const { return okind; }
+ RetEffect::ObjKind getObjKind() const {
+ return static_cast<RetEffect::ObjKind>(RawObjectKind);
+ }
unsigned getCount() const { return Cnt; }
unsigned getAutoreleaseCount() const { return ACnt; }
unsigned getCombinedCounts() const { return Cnt + ACnt; }
- void clearCounts() { Cnt = 0; ACnt = 0; }
- void setCount(unsigned i) { Cnt = i; }
- void setAutoreleaseCount(unsigned i) { ACnt = i; }
+ void clearCounts() {
+ Cnt = 0;
+ ACnt = 0;
+ IsOverridable = false;
+ }
+ void setCount(unsigned i) {
+ Cnt = i;
+ IsOverridable = false;
+ }
+ void setAutoreleaseCount(unsigned i) {
+ ACnt = i;
+ IsOverridable = false;
+ }
QualType getType() const { return T; }
+ bool isOverridable() const { return IsOverridable; }
+
bool isOwned() const {
return getKind() == Owned;
}
@@ -134,20 +175,31 @@ public:
return getKind() == ReturnedNotOwned;
}
+ /// Create a state for an object whose lifetime is the responsibility of the
+ /// current function, at least partially.
+ ///
+ /// Most commonly, this is an owned object with a retain count of +1.
static RefVal makeOwned(RetEffect::ObjKind o, QualType t,
unsigned Count = 1) {
return RefVal(Owned, o, Count, 0, t);
}
+ /// Create a state for an object whose lifetime is not the responsibility of
+ /// the current function.
+ ///
+ /// Most commonly, this is an unowned object with a retain count of +0.
static RefVal makeNotOwned(RetEffect::ObjKind o, QualType t,
unsigned Count = 0) {
return RefVal(NotOwned, o, Count, 0, t);
}
- // Comparison, profiling, and pretty-printing.
-
- bool operator==(const RefVal& X) const {
- return kind == X.kind && Cnt == X.Cnt && T == X.T && ACnt == X.ACnt;
+ /// Create an "overridable" state for an unowned object at +0.
+ ///
+ /// An overridable state is one that provides a good approximation of the
+ /// reference counting state now, but which may be discarded later if the
+ /// checker sees the object being used in new ways.
+ static RefVal makeOverridableNotOwned(RetEffect::ObjKind o, QualType t) {
+ return RefVal(NotOwned, o, 0, 0, t, /*Overridable=*/true);
}
RefVal operator-(size_t i) const {
@@ -170,11 +222,24 @@ public:
getType());
}
+ // Comparison, profiling, and pretty-printing.
+
+ bool hasSameState(const RefVal &X) const {
+ return getKind() == X.getKind() && Cnt == X.Cnt && ACnt == X.ACnt;
+ }
+
+ bool operator==(const RefVal& X) const {
+ return T == X.T && hasSameState(X) && getObjKind() == X.getObjKind() &&
+ IsOverridable == X.IsOverridable;
+ }
+
void Profile(llvm::FoldingSetNodeID& ID) const {
- ID.AddInteger((unsigned) kind);
+ ID.Add(T);
+ ID.AddInteger(RawKind);
ID.AddInteger(Cnt);
ID.AddInteger(ACnt);
- ID.Add(T);
+ ID.AddInteger(RawObjectKind);
+ ID.AddBoolean(IsOverridable);
}
void print(raw_ostream &Out) const;
@@ -184,6 +249,9 @@ void RefVal::print(raw_ostream &Out) const {
if (!T.isNull())
Out << "Tracked " << T.getAsString() << '/';
+ if (isOverridable())
+ Out << "(overridable) ";
+
switch (getKind()) {
default: llvm_unreachable("Invalid RefVal kind");
case Owned: {
@@ -383,10 +451,10 @@ public:
: II(ii), S(s) {}
ObjCSummaryKey(const ObjCInterfaceDecl *d, Selector s)
- : II(d ? d->getIdentifier() : 0), S(s) {}
+ : II(d ? d->getIdentifier() : nullptr), S(s) {}
ObjCSummaryKey(Selector s)
- : II(0), S(s) {}
+ : II(nullptr), S(s) {}
IdentifierInfo *getIdentifier() const { return II; }
Selector getSelector() const { return S; }
@@ -435,7 +503,7 @@ public:
if (I != M.end())
return I->second;
if (!D)
- return NULL;
+ return nullptr;
// Walk the super chain. If we find a hit with a parent, we'll end
// up returning that summary. We actually allow that key (null,S), as
@@ -448,7 +516,7 @@ public:
break;
if (!C)
- return NULL;
+ return nullptr;
}
// Cache the summary with original key to make the next lookup faster
@@ -466,7 +534,7 @@ public:
if (I == M.end())
I = M.find(ObjCSummaryKey(S));
- return I == M.end() ? NULL : I->second;
+ return I == M.end() ? nullptr : I->second;
}
const RetainSummary *& operator[](ObjCSummaryKey K) {
@@ -608,18 +676,9 @@ private:
ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
}
- Selector generateSelector(va_list argp) {
- SmallVector<IdentifierInfo*, 10> II;
-
- while (const char* s = va_arg(argp, const char*))
- II.push_back(&Ctx.Idents.get(s));
-
- return Ctx.Selectors.getSelector(II.size(), &II[0]);
- }
-
- void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy& Summaries,
- const RetainSummary * Summ, va_list argp) {
- Selector S = generateSelector(argp);
+ void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy &Summaries,
+ const RetainSummary *Summ, va_list argp) {
+ Selector S = getKeywordSelector(Ctx, argp);
Summaries[ObjCSummaryKey(ClsII, S)] = Summ;
}
@@ -653,18 +712,18 @@ public:
AF(BPAlloc), ScratchArgs(AF.getEmptyMap()),
ObjCAllocRetE(gcenabled
? RetEffect::MakeGCNotOwned()
- : (usesARC ? RetEffect::MakeARCNotOwned()
+ : (usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC)
: RetEffect::MakeOwned(RetEffect::ObjC, true))),
ObjCInitRetE(gcenabled
? RetEffect::MakeGCNotOwned()
- : (usesARC ? RetEffect::MakeARCNotOwned()
+ : (usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC)
: RetEffect::MakeOwnedWhenTrackedReceiver())) {
InitializeClassMethodSummaries();
InitializeMethodSummaries();
}
const RetainSummary *getSummary(const CallEvent &Call,
- ProgramStateRef State = 0);
+ ProgramStateRef State = nullptr);
const RetainSummary *getFunctionSummary(const FunctionDecl *FD);
@@ -689,7 +748,7 @@ public:
const RetainSummary *getMethodSummary(const ObjCMethodDecl *MD) {
const ObjCInterfaceDecl *ID = MD->getClassInterface();
Selector S = MD->getSelector();
- QualType ResultTy = MD->getResultType();
+ QualType ResultTy = MD->getReturnType();
ObjCMethodSummariesTy *CachedSummaries;
if (MD->isInstanceMethod())
@@ -861,7 +920,7 @@ void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S,
// Special cases where the callback argument CANNOT free the return value.
// This can generally only happen if we know that the callback will only be
// called when the return value is already being deallocated.
- if (const FunctionCall *FC = dyn_cast<FunctionCall>(&Call)) {
+ if (const SimpleFunctionCall *FC = dyn_cast<SimpleFunctionCall>(&Call)) {
if (IdentifierInfo *Name = FC->getDecl()->getIdentifier()) {
// When the CGBitmapContext is deallocated, the callback here will free
// the associated data buffer.
@@ -909,7 +968,7 @@ RetainSummaryManager::getSummary(const CallEvent &Call,
const RetainSummary *Summ;
switch (Call.getKind()) {
case CE_Function:
- Summ = getFunctionSummary(cast<FunctionCall>(Call).getDecl());
+ Summ = getFunctionSummary(cast<SimpleFunctionCall>(Call).getDecl());
break;
case CE_CXXMember:
case CE_CXXMemberOperator:
@@ -947,7 +1006,7 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
return I->second;
// No summary? Generate one.
- const RetainSummary *S = 0;
+ const RetainSummary *S = nullptr;
bool AllowAnnotations = true;
do {
@@ -971,7 +1030,7 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
FName = FName.substr(FName.find_first_not_of('_'));
// Inspect the result type.
- QualType RetTy = FT->getResultType();
+ QualType RetTy = FT->getReturnType();
// FIXME: This should all be refactored into a chain of "summary lookup"
// filters.
@@ -1102,7 +1161,7 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
break;
}
- if (FD->getAttr<CFAuditedTransferAttr>()) {
+ if (FD->hasAttr<CFAuditedTransferAttr>()) {
S = getCFCreateGetRuleSummary(FD);
break;
}
@@ -1175,7 +1234,7 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT,
// Sanity check that this is *really* a unary function. This can
// happen if people do weird things.
const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT);
- if (!FTP || FTP->getNumArgs() != 1)
+ if (!FTP || FTP->getNumParams() != 1)
return getPersistentStopSummary();
assert (ScratchArgs.isEmpty());
@@ -1214,21 +1273,21 @@ Optional<RetEffect>
RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,
const Decl *D) {
if (cocoa::isCocoaObjectRef(RetTy)) {
- if (D->getAttr<NSReturnsRetainedAttr>())
+ if (D->hasAttr<NSReturnsRetainedAttr>())
return ObjCAllocRetE;
- if (D->getAttr<NSReturnsNotRetainedAttr>() ||
- D->getAttr<NSReturnsAutoreleasedAttr>())
+ if (D->hasAttr<NSReturnsNotRetainedAttr>() ||
+ D->hasAttr<NSReturnsAutoreleasedAttr>())
return RetEffect::MakeNotOwned(RetEffect::ObjC);
} else if (!RetTy->isPointerType()) {
return None;
}
- if (D->getAttr<CFReturnsRetainedAttr>())
+ if (D->hasAttr<CFReturnsRetainedAttr>())
return RetEffect::MakeOwned(RetEffect::CF, true);
- if (D->getAttr<CFReturnsNotRetainedAttr>())
+ if (D->hasAttr<CFReturnsNotRetainedAttr>())
return RetEffect::MakeNotOwned(RetEffect::CF);
return None;
@@ -1248,13 +1307,13 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
for (FunctionDecl::param_const_iterator pi = FD->param_begin(),
pe = FD->param_end(); pi != pe; ++pi, ++parm_idx) {
const ParmVarDecl *pd = *pi;
- if (pd->getAttr<NSConsumedAttr>())
+ if (pd->hasAttr<NSConsumedAttr>())
Template->addArg(AF, parm_idx, DecRefMsg);
- else if (pd->getAttr<CFConsumedAttr>())
+ else if (pd->hasAttr<CFConsumedAttr>())
Template->addArg(AF, parm_idx, DecRef);
}
-
- QualType RetTy = FD->getResultType();
+
+ QualType RetTy = FD->getReturnType();
if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD))
Template->setRetEffect(*RetE);
}
@@ -1269,7 +1328,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
RetainSummaryTemplate Template(Summ, *this);
// Effects on the receiver.
- if (MD->getAttr<NSConsumesSelfAttr>())
+ if (MD->hasAttr<NSConsumesSelfAttr>())
Template->setReceiverEffect(DecRefMsg);
// Effects on the parameters.
@@ -1278,14 +1337,14 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
pi=MD->param_begin(), pe=MD->param_end();
pi != pe; ++pi, ++parm_idx) {
const ParmVarDecl *pd = *pi;
- if (pd->getAttr<NSConsumedAttr>())
+ if (pd->hasAttr<NSConsumedAttr>())
Template->addArg(AF, parm_idx, DecRefMsg);
- else if (pd->getAttr<CFConsumedAttr>()) {
+ else if (pd->hasAttr<CFConsumedAttr>()) {
Template->addArg(AF, parm_idx, DecRef);
}
}
-
- QualType RetTy = MD->getResultType();
+
+ QualType RetTy = MD->getReturnType();
if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD))
Template->setRetEffect(*RetE);
}
@@ -1388,7 +1447,7 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
const RetainSummary *
RetainSummaryManager::getInstanceMethodSummary(const ObjCMethodCall &Msg,
ProgramStateRef State) {
- const ObjCInterfaceDecl *ReceiverClass = 0;
+ const ObjCInterfaceDecl *ReceiverClass = nullptr;
// We do better tracking of the type of the object than the core ExprEngine.
// See if we have its type in our private state.
@@ -1507,6 +1566,11 @@ void RetainSummaryManager::InitializeMethodSummaries() {
// as for NSWindow objects.
addClassMethSummary("NSPanel", "alloc", NoTrackYet);
+ // For NSNull, objects returned by +null are singletons that ignore
+ // retain/release semantics. Just don't track them.
+ // <rdar://problem/12858915>
+ addClassMethSummary("NSNull", "null", NoTrackYet);
+
// Don't track allocated autorelease pools, as it is okay to prematurely
// exit a method.
addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet);
@@ -1543,8 +1607,9 @@ namespace {
class CFRefBug : public BugType {
protected:
- CFRefBug(StringRef name)
- : BugType(name, categories::MemoryCoreFoundationObjectiveC) {}
+ CFRefBug(const CheckerBase *checker, StringRef name)
+ : BugType(checker, name, categories::MemoryCoreFoundationObjectiveC) {}
+
public:
// FIXME: Eventually remove.
@@ -1555,18 +1620,19 @@ namespace {
class UseAfterRelease : public CFRefBug {
public:
- UseAfterRelease() : CFRefBug("Use-after-release") {}
+ UseAfterRelease(const CheckerBase *checker)
+ : CFRefBug(checker, "Use-after-release") {}
- const char *getDescription() const {
+ const char *getDescription() const override {
return "Reference-counted object is used after it is released";
}
};
class BadRelease : public CFRefBug {
public:
- BadRelease() : CFRefBug("Bad release") {}
+ BadRelease(const CheckerBase *checker) : CFRefBug(checker, "Bad release") {}
- const char *getDescription() const {
+ const char *getDescription() const override {
return "Incorrect decrement of the reference count of an object that is "
"not owned at this point by the caller";
}
@@ -1574,40 +1640,40 @@ namespace {
class DeallocGC : public CFRefBug {
public:
- DeallocGC()
- : CFRefBug("-dealloc called while using garbage collection") {}
+ DeallocGC(const CheckerBase *checker)
+ : CFRefBug(checker, "-dealloc called while using garbage collection") {}
- const char *getDescription() const {
+ const char *getDescription() const override {
return "-dealloc called while using garbage collection";
}
};
class DeallocNotOwned : public CFRefBug {
public:
- DeallocNotOwned()
- : CFRefBug("-dealloc sent to non-exclusively owned object") {}
+ DeallocNotOwned(const CheckerBase *checker)
+ : CFRefBug(checker, "-dealloc sent to non-exclusively owned object") {}
- const char *getDescription() const {
+ const char *getDescription() const override {
return "-dealloc sent to object that may be referenced elsewhere";
}
};
class OverAutorelease : public CFRefBug {
public:
- OverAutorelease()
- : CFRefBug("Object autoreleased too many times") {}
+ OverAutorelease(const CheckerBase *checker)
+ : CFRefBug(checker, "Object autoreleased too many times") {}
- const char *getDescription() const {
+ const char *getDescription() const override {
return "Object autoreleased too many times";
}
};
class ReturnedNotOwnedForOwned : public CFRefBug {
public:
- ReturnedNotOwnedForOwned()
- : CFRefBug("Method should return an owned object") {}
+ ReturnedNotOwnedForOwned(const CheckerBase *checker)
+ : CFRefBug(checker, "Method should return an owned object") {}
- const char *getDescription() const {
+ const char *getDescription() const override {
return "Object with a +0 retain count returned to caller where a +1 "
"(owning) retain count is expected";
}
@@ -1615,15 +1681,14 @@ namespace {
class Leak : public CFRefBug {
public:
- Leak(StringRef name)
- : CFRefBug(name) {
+ Leak(const CheckerBase *checker, StringRef name) : CFRefBug(checker, name) {
// Leaks should not be reported if they are post-dominated by a sink.
setSuppressOnSink(true);
}
- const char *getDescription() const { return ""; }
+ const char *getDescription() const override { return ""; }
- bool isLeak() const { return true; }
+ bool isLeak() const override { return true; }
};
//===---------===//
@@ -1640,20 +1705,20 @@ namespace {
CFRefReportVisitor(SymbolRef sym, bool gcEnabled, const SummaryLogTy &log)
: Sym(sym), SummaryLog(log), GCEnabled(gcEnabled) {}
- virtual void Profile(llvm::FoldingSetNodeID &ID) const {
+ void Profile(llvm::FoldingSetNodeID &ID) const override {
static int x = 0;
ID.AddPointer(&x);
ID.AddPointer(Sym);
}
- virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
- const ExplodedNode *PrevN,
- BugReporterContext &BRC,
- BugReport &BR);
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) override;
- virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
- const ExplodedNode *N,
- BugReport &BR);
+ PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR) override;
};
class CFRefLeakReportVisitor : public CFRefReportVisitor {
@@ -1664,9 +1729,9 @@ namespace {
PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
const ExplodedNode *N,
- BugReport &BR);
+ BugReport &BR) override;
- virtual BugReporterVisitor *clone() const {
+ BugReporterVisitor *clone() const override {
// The curiously-recurring template pattern only works for one level of
// subclassing. Rather than make a new template base for
// CFRefReportVisitor, we simply override clone() to do the right thing.
@@ -1697,7 +1762,7 @@ namespace {
addGCModeDescription(LOpts, GCEnabled);
}
- virtual std::pair<ranges_iterator, ranges_iterator> getRanges() {
+ std::pair<ranges_iterator, ranges_iterator> getRanges() override {
const CFRefBug& BugTy = static_cast<CFRefBug&>(getBugType());
if (!BugTy.isLeak())
return BugReport::getRanges();
@@ -1714,7 +1779,7 @@ namespace {
CheckerContext &Ctx,
bool IncludeAllocationLine);
- PathDiagnosticLocation getLocation(const SourceManager &SM) const {
+ PathDiagnosticLocation getLocation(const SourceManager &SM) const override {
assert(Location.isValid());
return Location;
}
@@ -1723,7 +1788,7 @@ namespace {
void CFRefReport::addGCModeDescription(const LangOptions &LOpts,
bool GCEnabled) {
- const char *GCModeDescription = 0;
+ const char *GCModeDescription = nullptr;
switch (LOpts.getGC()) {
case LangOptions::GCOnly:
@@ -1770,7 +1835,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
// FIXME: We will eventually need to handle non-statement-based events
// (__attribute__((cleanup))).
if (!N->getLocation().getAs<StmtPoint>())
- return NULL;
+ return nullptr;
// Check if the type state has changed.
ProgramStateRef PrevSt = PrevN->getState();
@@ -1778,7 +1843,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
const LocationContext *LCtx = N->getLocationContext();
const RefVal* CurrT = getRefBinding(CurrSt, Sym);
- if (!CurrT) return NULL;
+ if (!CurrT) return nullptr;
const RefVal &CurrV = *CurrT;
const RefVal *PrevT = getRefBinding(PrevSt, Sym);
@@ -1803,7 +1868,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
if (isNumericLiteralExpression(BL->getSubExpr()))
os << "NSNumber literal is an object with a +0 retain count";
else {
- const ObjCInterfaceDecl *BoxClass = 0;
+ const ObjCInterfaceDecl *BoxClass = nullptr;
if (const ObjCMethodDecl *Method = BL->getBoxingMethod())
BoxClass = Method->getClassInterface();
@@ -1918,7 +1983,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
if (!GCEnabled && std::find(AEffects.begin(), AEffects.end(), Dealloc) !=
AEffects.end()) {
// Determine if the object's reference count was pushed to zero.
- assert(!(PrevV == CurrV) && "The typestate *must* have changed.");
+ assert(!PrevV.hasSameState(CurrV) && "The state should have changed.");
// We may not have transitioned to 'release' if we hit an error.
// This case is handled elsewhere.
if (CurrV.getKind() == RefVal::Released) {
@@ -1939,7 +2004,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
if (GCEnabled) {
// Determine if the object's reference count was pushed to zero.
- assert(!(PrevV == CurrV) && "The typestate *must* have changed.");
+ assert(!PrevV.hasSameState(CurrV) && "The state should have changed.");
os << "In GC mode a call to '" << *FD
<< "' decrements an object's retain count and registers the "
@@ -1964,7 +2029,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
}
// Determine if the typestate has changed.
- if (!(PrevV == CurrV))
+ if (!PrevV.hasSameState(CurrV))
switch (CurrV.getKind()) {
case RefVal::Owned:
case RefVal::NotOwned:
@@ -1972,7 +2037,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
if (PrevV.getCount() == CurrV.getCount()) {
// Did an autorelease message get sent?
if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount())
- return 0;
+ return nullptr;
assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount());
os << "Object autoreleased";
@@ -2002,7 +2067,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
case RefVal::ReturnedOwned:
// Autoreleases can be applied after marking a node ReturnedOwned.
if (CurrV.getAutoreleaseCount())
- return NULL;
+ return nullptr;
os << "Object returned to caller as an owning reference (single "
"retain count transferred to caller)";
@@ -2013,7 +2078,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
break;
default:
- return NULL;
+ return nullptr;
}
// Emit any remaining diagnostics for the argument effects (if any).
@@ -2038,7 +2103,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
} while (0);
if (os.str().empty())
- return 0; // We have nothing to say!
+ return nullptr; // We have nothing to say!
const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
@@ -2078,12 +2143,12 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N,
SymbolRef Sym) {
const ExplodedNode *AllocationNode = N;
const ExplodedNode *AllocationNodeInCurrentContext = N;
- const MemRegion* FirstBinding = 0;
+ const MemRegion *FirstBinding = nullptr;
const LocationContext *LeakContext = N->getLocationContext();
// The location context of the init method called on the leaked object, if
// available.
- const LocationContext *InitMethodContext = 0;
+ const LocationContext *InitMethodContext = nullptr;
while (N) {
ProgramStateRef St = N->getState();
@@ -2127,12 +2192,12 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N,
}
}
- N = N->pred_empty() ? NULL : *(N->pred_begin());
+ N = N->pred_empty() ? nullptr : *(N->pred_begin());
}
// If we are reporting a leak of the object that was allocated with alloc,
// mark its init method as interesting.
- const LocationContext *InterestingMethodContext = 0;
+ const LocationContext *InterestingMethodContext = nullptr;
if (InitMethodContext) {
const ProgramPoint AllocPP = AllocationNode->getLocation();
if (Optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>())
@@ -2145,7 +2210,7 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N,
// do not report the binding.
assert(N && "Could not find allocation node");
if (N->getLocationContext() != LeakContext) {
- FirstBinding = 0;
+ FirstBinding = nullptr;
}
return AllocationInfo(AllocationNodeInCurrentContext,
@@ -2212,9 +2277,9 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
os << (isa<ObjCMethodDecl>(D) ? " is returned from a method "
: " is returned from a function ");
- if (D->getAttr<CFReturnsNotRetainedAttr>())
+ if (D->hasAttr<CFReturnsNotRetainedAttr>())
os << "that is annotated as CF_RETURNS_NOT_RETAINED";
- else if (D->getAttr<NSReturnsNotRetainedAttr>())
+ else if (D->hasAttr<NSReturnsNotRetainedAttr>())
os << "that is annotated as NS_RETURNS_NOT_RETAINED";
else {
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
@@ -2262,7 +2327,7 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
// Note that this is *not* the trimmed graph; we are guaranteed, however,
// that all ancestor nodes that represent the allocation site have the
// same SourceLocation.
- const ExplodedNode *AllocNode = 0;
+ const ExplodedNode *AllocNode = nullptr;
const SourceManager& SMgr = Ctx.getSourceManager();
@@ -2275,14 +2340,27 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
// Get the SourceLocation for the allocation site.
// FIXME: This will crash the analyzer if an allocation comes from an
- // implicit call. (Currently there are no such allocations in Cocoa, though.)
- const Stmt *AllocStmt;
+ // implicit call (ex: a destructor call).
+ // (Currently there are no such allocations in Cocoa, though.)
+ const Stmt *AllocStmt = 0;
ProgramPoint P = AllocNode->getLocation();
if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>())
AllocStmt = Exit->getCalleeContext()->getCallSite();
- else
- AllocStmt = P.castAs<PostStmt>().getStmt();
- assert(AllocStmt && "All allocations must come from explicit calls");
+ else {
+ // We are going to get a BlockEdge when the leak and allocation happen in
+ // different, non-nested frames (contexts). For example, the case where an
+ // allocation happens in a block that captures a reference to it and
+ // that reference is overwritten/dropped by another call to the block.
+ if (Optional<BlockEdge> Edge = P.getAs<BlockEdge>()) {
+ if (Optional<CFGStmt> St = Edge->getDst()->front().getAs<CFGStmt>()) {
+ AllocStmt = St->getStmt();
+ }
+ }
+ else {
+ AllocStmt = P.castAs<PostStmt>().getStmt();
+ }
+ }
+ assert(AllocStmt && "Cannot find allocation statement");
PathDiagnosticLocation AllocLocation =
PathDiagnosticLocation::createBegin(AllocStmt, SMgr,
@@ -2328,24 +2406,25 @@ class RetainCountChecker
check::PostStmt<ObjCArrayLiteral>,
check::PostStmt<ObjCDictionaryLiteral>,
check::PostStmt<ObjCBoxedExpr>,
+ check::PostStmt<ObjCIvarRefExpr>,
check::PostCall,
check::PreStmt<ReturnStmt>,
check::RegionChanges,
eval::Assume,
eval::Call > {
- mutable OwningPtr<CFRefBug> useAfterRelease, releaseNotOwned;
- mutable OwningPtr<CFRefBug> deallocGC, deallocNotOwned;
- mutable OwningPtr<CFRefBug> overAutorelease, returnNotOwnedForOwned;
- mutable OwningPtr<CFRefBug> leakWithinFunction, leakAtReturn;
- mutable OwningPtr<CFRefBug> leakWithinFunctionGC, leakAtReturnGC;
+ mutable std::unique_ptr<CFRefBug> useAfterRelease, releaseNotOwned;
+ mutable std::unique_ptr<CFRefBug> deallocGC, deallocNotOwned;
+ mutable std::unique_ptr<CFRefBug> overAutorelease, returnNotOwnedForOwned;
+ mutable std::unique_ptr<CFRefBug> leakWithinFunction, leakAtReturn;
+ mutable std::unique_ptr<CFRefBug> leakWithinFunctionGC, leakAtReturnGC;
- typedef llvm::DenseMap<SymbolRef, const SimpleProgramPointTag *> SymbolTagMap;
+ typedef llvm::DenseMap<SymbolRef, const CheckerProgramPointTag *> SymbolTagMap;
// This map is only used to ensure proper deletion of any allocated tags.
mutable SymbolTagMap DeadSymbolTags;
- mutable OwningPtr<RetainSummaryManager> Summaries;
- mutable OwningPtr<RetainSummaryManager> SummariesGC;
+ mutable std::unique_ptr<RetainSummaryManager> Summaries;
+ mutable std::unique_ptr<RetainSummaryManager> SummariesGC;
mutable SummaryLogTy SummaryLog;
mutable bool ShouldResetSummaryLog;
@@ -2402,17 +2481,18 @@ public:
bool GCEnabled) const {
if (GCEnabled) {
if (!leakWithinFunctionGC)
- leakWithinFunctionGC.reset(new Leak("Leak of object when using "
- "garbage collection"));
+ leakWithinFunctionGC.reset(new Leak(this, "Leak of object when using "
+ "garbage collection"));
return leakWithinFunctionGC.get();
} else {
if (!leakWithinFunction) {
if (LOpts.getGC() == LangOptions::HybridGC) {
- leakWithinFunction.reset(new Leak("Leak of object when not using "
+ leakWithinFunction.reset(new Leak(this,
+ "Leak of object when not using "
"garbage collection (GC) in "
"dual GC/non-GC code"));
} else {
- leakWithinFunction.reset(new Leak("Leak"));
+ leakWithinFunction.reset(new Leak(this, "Leak"));
}
}
return leakWithinFunction.get();
@@ -2422,17 +2502,19 @@ public:
CFRefBug *getLeakAtReturnBug(const LangOptions &LOpts, bool GCEnabled) const {
if (GCEnabled) {
if (!leakAtReturnGC)
- leakAtReturnGC.reset(new Leak("Leak of returned object when using "
+ leakAtReturnGC.reset(new Leak(this,
+ "Leak of returned object when using "
"garbage collection"));
return leakAtReturnGC.get();
} else {
if (!leakAtReturn) {
if (LOpts.getGC() == LangOptions::HybridGC) {
- leakAtReturn.reset(new Leak("Leak of returned object when not using "
+ leakAtReturn.reset(new Leak(this,
+ "Leak of returned object when not using "
"garbage collection (GC) in dual "
"GC/non-GC code"));
} else {
- leakAtReturn.reset(new Leak("Leak of returned object"));
+ leakAtReturn.reset(new Leak(this, "Leak of returned object"));
}
}
return leakAtReturn.get();
@@ -2464,7 +2546,7 @@ public:
}
void printState(raw_ostream &Out, ProgramStateRef State,
- const char *NL, const char *Sep) const;
+ const char *NL, const char *Sep) const override;
void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const;
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
@@ -2474,6 +2556,8 @@ public:
void checkPostStmt(const ObjCDictionaryLiteral *DL, CheckerContext &C) const;
void checkPostStmt(const ObjCBoxedExpr *BE, CheckerContext &C) const;
+ void checkPostStmt(const ObjCIvarRefExpr *IRE, CheckerContext &C) const;
+
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
void checkSummary(const RetainSummary &Summ, const CallEvent &Call,
@@ -2531,7 +2615,7 @@ public:
ExplodedNode *processLeaks(ProgramStateRef state,
SmallVectorImpl<SymbolRef> &Leaked,
CheckerContext &Ctx,
- ExplodedNode *Pred = 0) const;
+ ExplodedNode *Pred = nullptr) const;
};
} // end anonymous namespace
@@ -2542,7 +2626,7 @@ public:
StopTrackingCallback(ProgramStateRef st) : state(st) {}
ProgramStateRef getState() const { return state; }
- bool VisitSymbol(SymbolRef sym) {
+ bool VisitSymbol(SymbolRef sym) override {
state = state->remove<RefBindings>(sym);
return true;
}
@@ -2691,6 +2775,20 @@ void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex,
C.addTransition(State);
}
+void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ // If an instance variable was previously accessed through a property,
+ // it may have a synthesized refcount of +0. Override right now that we're
+ // doing direct access.
+ if (Optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>())
+ if (SymbolRef Sym = State->getSVal(*IVarLoc).getAsSymbol())
+ if (const RefVal *RV = getRefBinding(State, Sym))
+ if (RV->isOverridable())
+ State = removeRefBinding(State, Sym);
+ C.addTransition(State);
+}
+
void RetainCountChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
RetainSummaryManager &Summaries = getSummaryManager(C);
@@ -2731,6 +2829,16 @@ static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) {
return RetTy;
}
+static bool wasSynthesizedProperty(const ObjCMethodCall *Call,
+ ExplodedNode *N) {
+ if (!Call || !Call->getDecl()->isPropertyAccessor())
+ return false;
+
+ CallExitEnd PP = N->getLocation().castAs<CallExitEnd>();
+ const StackFrameContext *Frame = PP.getCalleeContext();
+ return Frame->getAnalysisDeclContext()->isBodyAutosynthesized();
+}
+
// We don't always get the exact modeling of the function with regards to the
// retain count checker even when the function is inlined. For example, we need
// to stop tracking the symbols which were marked with StopTrackingHard.
@@ -2765,6 +2873,19 @@ void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ,
SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol();
if (Sym)
state = removeRefBinding(state, Sym);
+ } else if (RE.getKind() == RetEffect::NotOwnedSymbol) {
+ if (wasSynthesizedProperty(MsgInvocation, C.getPredecessor())) {
+ // Believe the summary if we synthesized the body of a property getter
+ // and the return value is currently untracked. If the corresponding
+ // instance variable is later accessed directly, however, we're going to
+ // want to override this state, so that the owning object can perform
+ // reference counting operations on its own ivars.
+ SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol();
+ if (Sym && !getRefBinding(state, Sym))
+ state = setRefBinding(state, Sym,
+ RefVal::makeOverridableNotOwned(RE.getObjKind(),
+ Sym->getType()));
+ }
}
C.addTransition(state);
@@ -2778,7 +2899,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
// Evaluate the effect of the arguments.
RefVal::Kind hasErr = (RefVal::Kind) 0;
SourceRange ErrorRange;
- SymbolRef ErrorSym = 0;
+ SymbolRef ErrorSym = nullptr;
for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
SVal V = CallOrMsg.getArgSVal(idx);
@@ -2857,7 +2978,6 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
}
case RetEffect::GCNotOwnedSymbol:
- case RetEffect::ARCNotOwnedSymbol:
case RetEffect::NotOwnedSymbol: {
const Expr *Ex = CallOrMsg.getOriginExpr();
SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol();
@@ -3053,22 +3173,22 @@ void RetainCountChecker::processNonLeakError(ProgramStateRef St,
llvm_unreachable("Unhandled error.");
case RefVal::ErrorUseAfterRelease:
if (!useAfterRelease)
- useAfterRelease.reset(new UseAfterRelease());
+ useAfterRelease.reset(new UseAfterRelease(this));
BT = &*useAfterRelease;
break;
case RefVal::ErrorReleaseNotOwned:
if (!releaseNotOwned)
- releaseNotOwned.reset(new BadRelease());
+ releaseNotOwned.reset(new BadRelease(this));
BT = &*releaseNotOwned;
break;
case RefVal::ErrorDeallocGC:
if (!deallocGC)
- deallocGC.reset(new DeallocGC());
+ deallocGC.reset(new DeallocGC(this));
BT = &*deallocGC;
break;
case RefVal::ErrorDeallocNotOwned:
if (!deallocNotOwned)
- deallocNotOwned.reset(new DeallocNotOwned());
+ deallocNotOwned.reset(new DeallocNotOwned(this));
BT = &*deallocNotOwned;
break;
}
@@ -3135,7 +3255,7 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
if (RetVal.isUnknown()) {
// If the receiver is unknown, conjure a return value.
SValBuilder &SVB = C.getSValBuilder();
- RetVal = SVB.conjureSymbolVal(0, CE, LCtx, ResultTy, C.blockCount());
+ RetVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount());
}
state = state->BindExpr(CE, LCtx, RetVal, false);
@@ -3144,7 +3264,7 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
if (const MemRegion *ArgRegion = RetVal.getAsRegion()) {
// Save the refcount status of the argument.
SymbolRef Sym = RetVal.getAsLocSymbol();
- const RefVal *Binding = 0;
+ const RefVal *Binding = nullptr;
if (Sym)
Binding = getRefBinding(state, Sym);
@@ -3232,8 +3352,7 @@ void RetainCountChecker::checkPreStmt(const ReturnStmt *S,
return;
// Update the autorelease counts.
- static SimpleProgramPointTag
- AutoreleaseTag("RetainCountChecker : Autorelease");
+ static CheckerProgramPointTag AutoreleaseTag(this, "Autorelease");
state = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag, C, Sym, X);
// Did we cache out?
@@ -3294,8 +3413,7 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
// Generate an error node.
state = setRefBinding(state, Sym, X);
- static SimpleProgramPointTag
- ReturnOwnLeakTag("RetainCountChecker : ReturnsOwnLeak");
+ static CheckerProgramPointTag ReturnOwnLeakTag(this, "ReturnsOwnLeak");
ExplodedNode *N = C.addTransition(state, Pred, &ReturnOwnLeakTag);
if (N) {
const LangOptions &LOpts = C.getASTContext().getLangOpts();
@@ -3315,12 +3433,12 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
// owned object.
state = setRefBinding(state, Sym, X ^ RefVal::ErrorReturnedNotOwned);
- static SimpleProgramPointTag
- ReturnNotOwnedTag("RetainCountChecker : ReturnNotOwnedForOwned");
+ static CheckerProgramPointTag ReturnNotOwnedTag(this,
+ "ReturnNotOwnedForOwned");
ExplodedNode *N = C.addTransition(state, Pred, &ReturnNotOwnedTag);
if (N) {
if (!returnNotOwnedForOwned)
- returnNotOwnedForOwned.reset(new ReturnedNotOwnedForOwned());
+ returnNotOwnedForOwned.reset(new ReturnedNotOwnedForOwned(this));
CFRefReport *report =
new CFRefReport(*returnNotOwnedForOwned,
@@ -3375,7 +3493,7 @@ void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S,
// false positives.
if (const VarRegion *LVR = dyn_cast_or_null<VarRegion>(loc.getAsRegion())) {
const VarDecl *VD = LVR->getDecl();
- if (VD->getAttr<CleanupAttr>()) {
+ if (VD->hasAttr<CleanupAttr>()) {
escapes = true;
}
}
@@ -3508,7 +3626,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
os << "has a +" << V.getCount() << " retain count";
if (!overAutorelease)
- overAutorelease.reset(new OverAutorelease());
+ overAutorelease.reset(new OverAutorelease(this));
const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
CFRefReport *report =
@@ -3517,7 +3635,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
Ctx.emitReport(report);
}
- return 0;
+ return nullptr;
}
ProgramStateRef
@@ -3578,7 +3696,7 @@ void RetainCountChecker::checkEndFunction(CheckerContext &Ctx) const {
}
for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- state = handleAutoreleaseCounts(state, Pred, /*Tag=*/0, Ctx,
+ state = handleAutoreleaseCounts(state, Pred, /*Tag=*/nullptr, Ctx,
I->first, I->second);
if (!state)
return;
@@ -3602,13 +3720,13 @@ void RetainCountChecker::checkEndFunction(CheckerContext &Ctx) const {
const ProgramPointTag *
RetainCountChecker::getDeadSymbolTag(SymbolRef sym) const {
- const SimpleProgramPointTag *&tag = DeadSymbolTags[sym];
+ const CheckerProgramPointTag *&tag = DeadSymbolTags[sym];
if (!tag) {
SmallString<64> buf;
llvm::raw_svector_ostream out(buf);
- out << "RetainCountChecker : Dead Symbol : ";
+ out << "Dead Symbol : ";
sym->dumpToStream(out);
- tag = new SimpleProgramPointTag(out.str());
+ tag = new CheckerProgramPointTag(this, out.str());
}
return tag;
}
diff --git a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
index fe253b719b50..b1cde6b897cb 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
@@ -25,7 +25,8 @@ using namespace ento;
namespace {
class ReturnPointerRangeChecker :
public Checker< check::PreStmt<ReturnStmt> > {
- mutable OwningPtr<BuiltinBug> BT;
+ mutable std::unique_ptr<BuiltinBug> BT;
+
public:
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
};
@@ -69,9 +70,10 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
// FIXME: This bug correspond to CWE-466. Eventually we should have bug
// types explicitly reference such exploit categories (when applicable).
if (!BT)
- BT.reset(new BuiltinBug("Return of pointer value outside of expected range",
- "Returned pointer value points outside the original object "
- "(potential buffer overflow)"));
+ BT.reset(new BuiltinBug(
+ this, "Return of pointer value outside of expected range",
+ "Returned pointer value points outside the original object "
+ "(potential buffer overflow)"));
// FIXME: It would be nice to eventually make this diagnostic more clear,
// e.g., by referencing the original declaration or by saying *why* this
diff --git a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
index ed96c401a7aa..6622313c991f 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
@@ -25,8 +25,8 @@ using namespace ento;
namespace {
class ReturnUndefChecker : public Checker< check::PreStmt<ReturnStmt> > {
- mutable OwningPtr<BuiltinBug> BT_Undef;
- mutable OwningPtr<BuiltinBug> BT_NullReference;
+ mutable std::unique_ptr<BuiltinBug> BT_Undef;
+ mutable std::unique_ptr<BuiltinBug> BT_NullReference;
void emitUndef(CheckerContext &C, const Expr *RetE) const;
void checkReference(CheckerContext &C, const Expr *RetE,
@@ -79,7 +79,7 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
}
static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE,
- const Expr *TrackingE = 0) {
+ const Expr *TrackingE = nullptr) {
ExplodedNode *N = C.generateSink();
if (!N)
return;
@@ -94,16 +94,16 @@ static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE,
void ReturnUndefChecker::emitUndef(CheckerContext &C, const Expr *RetE) const {
if (!BT_Undef)
- BT_Undef.reset(new BuiltinBug("Garbage return value",
- "Undefined or garbage value "
- "returned to caller"));
+ BT_Undef.reset(
+ new BuiltinBug(this, "Garbage return value",
+ "Undefined or garbage value returned to caller"));
emitBug(C, *BT_Undef, RetE);
}
void ReturnUndefChecker::checkReference(CheckerContext &C, const Expr *RetE,
DefinedOrUnknownSVal RetVal) const {
ProgramStateRef StNonNull, StNull;
- llvm::tie(StNonNull, StNull) = C.getState()->assume(RetVal);
+ std::tie(StNonNull, StNull) = C.getState()->assume(RetVal);
if (StNonNull) {
// Going forward, assume the location is non-null.
@@ -113,7 +113,7 @@ void ReturnUndefChecker::checkReference(CheckerContext &C, const Expr *RetE,
// The return value is known to be null. Emit a bug report.
if (!BT_NullReference)
- BT_NullReference.reset(new BuiltinBug("Returning null reference"));
+ BT_NullReference.reset(new BuiltinBug(this, "Returning null reference"));
emitBug(C, *BT_NullReference, RetE, bugreporter::getDerefExpr(RetE));
}
diff --git a/lib/StaticAnalyzer/Checkers/SelectorExtras.h b/lib/StaticAnalyzer/Checkers/SelectorExtras.h
new file mode 100644
index 000000000000..48d96eb42234
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/SelectorExtras.h
@@ -0,0 +1,68 @@
+//=== SelectorExtras.h - Helpers for checkers using selectors -----*- 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_SA_CHECKERS_SELECTOREXTRAS
+#define LLVM_CLANG_SA_CHECKERS_SELECTOREXTRAS
+
+#include "clang/AST/ASTContext.h"
+#include <cstdarg>
+
+namespace clang {
+namespace ento {
+
+static inline Selector getKeywordSelectorImpl(ASTContext &Ctx,
+ const char *First,
+ va_list argp) {
+ SmallVector<IdentifierInfo*, 10> II;
+ II.push_back(&Ctx.Idents.get(First));
+
+ while (const char *s = va_arg(argp, const char *))
+ II.push_back(&Ctx.Idents.get(s));
+
+ return Ctx.Selectors.getSelector(II.size(), &II[0]);
+}
+
+static inline Selector getKeywordSelector(ASTContext &Ctx, va_list argp) {
+ const char *First = va_arg(argp, const char *);
+ assert(First && "keyword selectors must have at least one argument");
+ return getKeywordSelectorImpl(Ctx, First, argp);
+}
+
+END_WITH_NULL
+static inline Selector getKeywordSelector(ASTContext &Ctx,
+ const char *First, ...) {
+ va_list argp;
+ va_start(argp, First);
+ Selector result = getKeywordSelectorImpl(Ctx, First, argp);
+ va_end(argp);
+ return result;
+}
+
+END_WITH_NULL
+static inline void lazyInitKeywordSelector(Selector &Sel, ASTContext &Ctx,
+ const char *First, ...) {
+ if (!Sel.isNull())
+ return;
+ va_list argp;
+ va_start(argp, First);
+ Sel = getKeywordSelectorImpl(Ctx, First, argp);
+ va_end(argp);
+}
+
+static inline void lazyInitNullarySelector(Selector &Sel, ASTContext &Ctx,
+ const char *Name) {
+ if (!Sel.isNull())
+ return;
+ Sel = GetNullarySelector(Name, Ctx);
+}
+
+} // end namespace ento
+} // end namespace clang
+
+#endif
diff --git a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
index 9ca0ab5d7fb7..3e9b57bdc507 100644
--- a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
@@ -54,8 +54,8 @@ class SimpleStreamChecker : public Checker<check::PostCall,
mutable IdentifierInfo *IIfopen, *IIfclose;
- OwningPtr<BugType> DoubleCloseBugType;
- OwningPtr<BugType> LeakBugType;
+ std::unique_ptr<BugType> DoubleCloseBugType;
+ std::unique_ptr<BugType> LeakBugType;
void initIdentifierInfo(ASTContext &Ctx) const;
@@ -99,21 +99,21 @@ public:
StopTrackingCallback(ProgramStateRef st) : state(st) {}
ProgramStateRef getState() const { return state; }
- bool VisitSymbol(SymbolRef sym) {
+ bool VisitSymbol(SymbolRef sym) override {
state = state->remove<StreamMap>(sym);
return true;
}
};
} // end anonymous namespace
-
-SimpleStreamChecker::SimpleStreamChecker() : IIfopen(0), IIfclose(0) {
+SimpleStreamChecker::SimpleStreamChecker()
+ : IIfopen(nullptr), IIfclose(nullptr) {
// Initialize the bug types.
- DoubleCloseBugType.reset(new BugType("Double fclose",
- "Unix Stream API Error"));
+ DoubleCloseBugType.reset(
+ new BugType(this, "Double fclose", "Unix Stream API Error"));
- LeakBugType.reset(new BugType("Resource Leak",
- "Unix Stream API Error"));
+ LeakBugType.reset(
+ new BugType(this, "Resource Leak", "Unix Stream API Error"));
// Sinks are higher importance bugs as well as calls to assert() or exit(0).
LeakBugType->setSuppressOnSink(true);
}
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 4fd778ef58ca..327a9e0ac435 100644
--- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -28,8 +28,8 @@ using namespace ento;
namespace {
class StackAddrEscapeChecker : public Checker< check::PreStmt<ReturnStmt>,
check::EndFunction > {
- mutable OwningPtr<BuiltinBug> BT_stackleak;
- mutable OwningPtr<BuiltinBug> BT_returnstack;
+ mutable std::unique_ptr<BuiltinBug> BT_stackleak;
+ mutable std::unique_ptr<BuiltinBug> BT_returnstack;
public:
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
@@ -100,8 +100,8 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *
return;
if (!BT_returnstack)
- BT_returnstack.reset(
- new BuiltinBug("Return of address to stack-allocated memory"));
+ BT_returnstack.reset(
+ new BuiltinBug(this, "Return of address to stack-allocated memory"));
// Generate a report for this bug.
SmallString<512> buf;
@@ -177,8 +177,8 @@ void StackAddrEscapeChecker::checkEndFunction(CheckerContext &Ctx) const {
{}
bool HandleBinding(StoreManager &SMgr, Store store,
- const MemRegion *region, SVal val) {
-
+ const MemRegion *region, SVal val) override {
+
if (!isa<GlobalsSpaceRegion>(region->getMemorySpace()))
return true;
@@ -217,11 +217,11 @@ void StackAddrEscapeChecker::checkEndFunction(CheckerContext &Ctx) const {
if (!BT_stackleak)
BT_stackleak.reset(
- new BuiltinBug("Stack address stored into global variable",
- "Stack address was saved into a global variable. "
- "This is dangerous because the address will become "
- "invalid after returning from the function"));
-
+ new BuiltinBug(this, "Stack address stored into global variable",
+ "Stack address was saved into a global variable. "
+ "This is dangerous because the address will become "
+ "invalid after returning from the function"));
+
for (unsigned i = 0, e = cb.V.size(); i != e; ++i) {
// Generate a report for this bug.
SmallString<512> buf;
diff --git a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index ffdf2d54b4ce..894765a785ea 100644
--- a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -62,14 +62,16 @@ class StreamChecker : public Checker<eval::Call,
*II_fwrite,
*II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos,
*II_clearerr, *II_feof, *II_ferror, *II_fileno;
- mutable OwningPtr<BuiltinBug> BT_nullfp, BT_illegalwhence,
- BT_doubleclose, BT_ResourceLeak;
+ mutable std::unique_ptr<BuiltinBug> BT_nullfp, BT_illegalwhence,
+ BT_doubleclose, BT_ResourceLeak;
public:
StreamChecker()
- : II_fopen(0), II_tmpfile(0) ,II_fclose(0), II_fread(0), II_fwrite(0),
- II_fseek(0), II_ftell(0), II_rewind(0), II_fgetpos(0), II_fsetpos(0),
- II_clearerr(0), II_feof(0), II_ferror(0), II_fileno(0) {}
+ : II_fopen(nullptr), II_tmpfile(nullptr), II_fclose(nullptr),
+ II_fread(nullptr), II_fwrite(nullptr), II_fseek(nullptr),
+ II_ftell(nullptr), II_rewind(nullptr), II_fgetpos(nullptr),
+ II_fsetpos(nullptr), II_clearerr(nullptr), II_feof(nullptr),
+ II_ferror(nullptr), II_fileno(nullptr) {}
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
@@ -210,7 +212,8 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
ProgramStateRef state = C.getState();
SValBuilder &svalBuilder = C.getSValBuilder();
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
- DefinedSVal RetVal = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount())
+ DefinedSVal RetVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx,
+ C.blockCount())
.castAs<DefinedSVal>();
state = state->BindExpr(CE, C.getLocationContext(), RetVal);
@@ -218,7 +221,7 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
// Bifurcate the state into two: one with a valid FILE* pointer, the other
// with a NULL.
ProgramStateRef stateNotNull, stateNull;
- llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal);
+ std::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal);
if (SymbolRef Sym = RetVal.getAsSymbol()) {
// if RetVal is not NULL, set the symbol's state to Opened.
@@ -270,9 +273,10 @@ void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
if (ExplodedNode *N = C.addTransition(state)) {
if (!BT_illegalwhence)
- BT_illegalwhence.reset(new BuiltinBug("Illegal whence argument",
- "The whence argument to fseek() should be "
- "SEEK_SET, SEEK_END, or SEEK_CUR."));
+ BT_illegalwhence.reset(
+ new BuiltinBug(this, "Illegal whence argument",
+ "The whence argument to fseek() should be "
+ "SEEK_SET, SEEK_END, or SEEK_CUR."));
BugReport *R = new BugReport(*BT_illegalwhence,
BT_illegalwhence->getDescription(), N);
C.emitReport(R);
@@ -339,21 +343,21 @@ ProgramStateRef StreamChecker::CheckNullStream(SVal SV, ProgramStateRef state,
CheckerContext &C) const {
Optional<DefinedSVal> DV = SV.getAs<DefinedSVal>();
if (!DV)
- return 0;
+ return nullptr;
ConstraintManager &CM = C.getConstraintManager();
ProgramStateRef stateNotNull, stateNull;
- llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
+ std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
if (!stateNotNull && stateNull) {
if (ExplodedNode *N = C.generateSink(stateNull)) {
if (!BT_nullfp)
- BT_nullfp.reset(new BuiltinBug("NULL stream pointer",
- "Stream pointer might be NULL."));
+ BT_nullfp.reset(new BuiltinBug(this, "NULL stream pointer",
+ "Stream pointer might be NULL."));
BugReport *R =new BugReport(*BT_nullfp, BT_nullfp->getDescription(), N);
C.emitReport(R);
}
- return 0;
+ return nullptr;
}
return stateNotNull;
}
@@ -378,14 +382,14 @@ ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE,
ExplodedNode *N = C.generateSink();
if (N) {
if (!BT_doubleclose)
- BT_doubleclose.reset(new BuiltinBug("Double fclose",
- "Try to close a file Descriptor already"
- " closed. Cause undefined behaviour."));
+ BT_doubleclose.reset(new BuiltinBug(
+ this, "Double fclose", "Try to close a file Descriptor already"
+ " closed. Cause undefined behaviour."));
BugReport *R = new BugReport(*BT_doubleclose,
BT_doubleclose->getDescription(), N);
C.emitReport(R);
}
- return NULL;
+ return nullptr;
}
// Close the File Descriptor.
@@ -407,8 +411,9 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
ExplodedNode *N = C.generateSink();
if (N) {
if (!BT_ResourceLeak)
- BT_ResourceLeak.reset(new BuiltinBug("Resource Leak",
- "Opened File never closed. Potential Resource leak."));
+ BT_ResourceLeak.reset(new BuiltinBug(
+ this, "Resource Leak",
+ "Opened File never closed. Potential Resource leak."));
BugReport *R = new BugReport(*BT_ResourceLeak,
BT_ResourceLeak->getDescription(), N);
C.emitReport(R);
diff --git a/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp b/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
index 264f7f9fdb92..d33c977826a5 100644
--- a/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
@@ -22,7 +22,7 @@ using namespace ento;
namespace {
class TaintTesterChecker : public Checker< check::PostStmt<Expr> > {
- mutable OwningPtr<BugType> BT;
+ mutable std::unique_ptr<BugType> BT;
void initBugType() const;
/// Given a pointer argument, get the symbol of the value it contains
@@ -38,7 +38,7 @@ public:
inline void TaintTesterChecker::initBugType() const {
if (!BT)
- BT.reset(new BugType("Tainted data", "General"));
+ BT.reset(new BugType(this, "Tainted data", "General"));
}
void TaintTesterChecker::checkPostStmt(const Expr *E,
diff --git a/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp b/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
new file mode 100644
index 000000000000..dad5c0d3bab8
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
@@ -0,0 +1,264 @@
+//== TestAfterDivZeroChecker.cpp - Test after division by zero checker --*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines TestAfterDivZeroChecker, a builtin check that performs checks
+// for division by zero where the division occurs before comparison with zero.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/ADT/FoldingSet.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class ZeroState {
+private:
+ SymbolRef ZeroSymbol;
+ unsigned BlockID;
+ const StackFrameContext *SFC;
+
+public:
+ ZeroState(SymbolRef S, unsigned B, const StackFrameContext *SFC)
+ : ZeroSymbol(S), BlockID(B), SFC(SFC) {}
+
+ const StackFrameContext *getStackFrameContext() const { return SFC; }
+
+ bool operator==(const ZeroState &X) const {
+ return BlockID == X.BlockID && SFC == X.SFC && ZeroSymbol == X.ZeroSymbol;
+ }
+
+ bool operator<(const ZeroState &X) const {
+ if (BlockID != X.BlockID)
+ return BlockID < X.BlockID;
+ if (SFC != X.SFC)
+ return SFC < X.SFC;
+ return ZeroSymbol < X.ZeroSymbol;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(BlockID);
+ ID.AddPointer(SFC);
+ ID.AddPointer(ZeroSymbol);
+ }
+};
+
+class DivisionBRVisitor : public BugReporterVisitorImpl<DivisionBRVisitor> {
+private:
+ SymbolRef ZeroSymbol;
+ const StackFrameContext *SFC;
+ bool Satisfied;
+
+public:
+ DivisionBRVisitor(SymbolRef ZeroSymbol, const StackFrameContext *SFC)
+ : ZeroSymbol(ZeroSymbol), SFC(SFC), Satisfied(false) {}
+
+ void Profile(llvm::FoldingSetNodeID &ID) const override {
+ ID.Add(ZeroSymbol);
+ ID.Add(SFC);
+ }
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
+ BugReporterContext &BRC,
+ BugReport &BR) override;
+};
+
+class TestAfterDivZeroChecker
+ : public Checker<check::PreStmt<BinaryOperator>, check::BranchCondition,
+ check::EndFunction> {
+ mutable std::unique_ptr<BuiltinBug> DivZeroBug;
+ void reportBug(SVal Val, CheckerContext &C) const;
+
+public:
+ void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
+ void checkBranchCondition(const Stmt *Condition, CheckerContext &C) const;
+ void checkEndFunction(CheckerContext &C) const;
+ void setDivZeroMap(SVal Var, CheckerContext &C) const;
+ bool hasDivZeroMap(SVal Var, const CheckerContext &C) const;
+ bool isZero(SVal S, CheckerContext &C) const;
+};
+} // end anonymous namespace
+
+REGISTER_SET_WITH_PROGRAMSTATE(DivZeroMap, ZeroState)
+
+PathDiagnosticPiece *DivisionBRVisitor::VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ if (Satisfied)
+ return nullptr;
+
+ const Expr *E = nullptr;
+
+ if (Optional<PostStmt> P = Succ->getLocationAs<PostStmt>())
+ if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) {
+ BinaryOperator::Opcode Op = BO->getOpcode();
+ if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign ||
+ Op == BO_RemAssign) {
+ E = BO->getRHS();
+ }
+ }
+
+ if (!E)
+ return nullptr;
+
+ ProgramStateRef State = Succ->getState();
+ SVal S = State->getSVal(E, Succ->getLocationContext());
+ if (ZeroSymbol == S.getAsSymbol() && SFC == Succ->getStackFrame()) {
+ Satisfied = true;
+
+ // Construct a new PathDiagnosticPiece.
+ ProgramPoint P = Succ->getLocation();
+ PathDiagnosticLocation L =
+ PathDiagnosticLocation::create(P, BRC.getSourceManager());
+
+ if (!L.isValid() || !L.asLocation().isValid())
+ return nullptr;
+
+ return new PathDiagnosticEventPiece(
+ L, "Division with compared value made here");
+ }
+
+ return nullptr;
+}
+
+bool TestAfterDivZeroChecker::isZero(SVal S, CheckerContext &C) const {
+ Optional<DefinedSVal> DSV = S.getAs<DefinedSVal>();
+
+ if (!DSV)
+ return false;
+
+ ConstraintManager &CM = C.getConstraintManager();
+ return !CM.assume(C.getState(), *DSV, true);
+}
+
+void TestAfterDivZeroChecker::setDivZeroMap(SVal Var, CheckerContext &C) const {
+ SymbolRef SR = Var.getAsSymbol();
+ if (!SR)
+ return;
+
+ ProgramStateRef State = C.getState();
+ State =
+ State->add<DivZeroMap>(ZeroState(SR, C.getBlockID(), C.getStackFrame()));
+ C.addTransition(State);
+}
+
+bool TestAfterDivZeroChecker::hasDivZeroMap(SVal Var,
+ const CheckerContext &C) const {
+ SymbolRef SR = Var.getAsSymbol();
+ if (!SR)
+ return false;
+
+ ZeroState ZS(SR, C.getBlockID(), C.getStackFrame());
+ return C.getState()->contains<DivZeroMap>(ZS);
+}
+
+void TestAfterDivZeroChecker::reportBug(SVal Val, CheckerContext &C) const {
+ if (ExplodedNode *N = C.generateSink(C.getState())) {
+ if (!DivZeroBug)
+ DivZeroBug.reset(new BuiltinBug(this, "Division by zero"));
+
+ BugReport *R =
+ new BugReport(*DivZeroBug, "Value being compared against zero has "
+ "already been used for division",
+ N);
+
+ R->addVisitor(new DivisionBRVisitor(Val.getAsSymbol(), C.getStackFrame()));
+ C.emitReport(R);
+ }
+}
+
+void TestAfterDivZeroChecker::checkEndFunction(CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+
+ DivZeroMapTy DivZeroes = State->get<DivZeroMap>();
+ if (DivZeroes.isEmpty())
+ return;
+
+ DivZeroMapTy::Factory &F = State->get_context<DivZeroMap>();
+ for (llvm::ImmutableSet<ZeroState>::iterator I = DivZeroes.begin(),
+ E = DivZeroes.end();
+ I != E; ++I) {
+ ZeroState ZS = *I;
+ if (ZS.getStackFrameContext() == C.getStackFrame())
+ DivZeroes = F.remove(DivZeroes, ZS);
+ }
+ C.addTransition(State->set<DivZeroMap>(DivZeroes));
+}
+
+void TestAfterDivZeroChecker::checkPreStmt(const BinaryOperator *B,
+ CheckerContext &C) const {
+ BinaryOperator::Opcode Op = B->getOpcode();
+ if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign ||
+ Op == BO_RemAssign) {
+ SVal S = C.getSVal(B->getRHS());
+
+ if (!isZero(S, C))
+ setDivZeroMap(S, C);
+ }
+}
+
+void TestAfterDivZeroChecker::checkBranchCondition(const Stmt *Condition,
+ CheckerContext &C) const {
+ if (const BinaryOperator *B = dyn_cast<BinaryOperator>(Condition)) {
+ if (B->isComparisonOp()) {
+ const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(B->getRHS());
+ bool LRHS = true;
+ if (!IntLiteral) {
+ IntLiteral = dyn_cast<IntegerLiteral>(B->getLHS());
+ LRHS = false;
+ }
+
+ if (!IntLiteral || IntLiteral->getValue() != 0)
+ return;
+
+ SVal Val = C.getSVal(LRHS ? B->getLHS() : B->getRHS());
+ if (hasDivZeroMap(Val, C))
+ reportBug(Val, C);
+ }
+ } else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(Condition)) {
+ if (U->getOpcode() == UO_LNot) {
+ SVal Val;
+ if (const ImplicitCastExpr *I =
+ dyn_cast<ImplicitCastExpr>(U->getSubExpr()))
+ Val = C.getSVal(I->getSubExpr());
+
+ if (hasDivZeroMap(Val, C))
+ reportBug(Val, C);
+ else {
+ Val = C.getSVal(U->getSubExpr());
+ if (hasDivZeroMap(Val, C))
+ reportBug(Val, C);
+ }
+ }
+ } else if (const ImplicitCastExpr *IE =
+ dyn_cast<ImplicitCastExpr>(Condition)) {
+ SVal Val = C.getSVal(IE->getSubExpr());
+
+ if (hasDivZeroMap(Val, C))
+ reportBug(Val, C);
+ else {
+ SVal Val = C.getSVal(Condition);
+
+ if (hasDivZeroMap(Val, C))
+ reportBug(Val, C);
+ }
+ }
+}
+
+void ento::registerTestAfterDivZeroChecker(CheckerManager &mgr) {
+ mgr.registerChecker<TestAfterDivZeroChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp b/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp
index 57c9ed4ce289..d02d2df1c507 100644
--- a/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp
@@ -72,7 +72,7 @@ public:
void CallDumper::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
unsigned Indentation = 0;
for (const LocationContext *LC = C.getLocationContext()->getParent();
- LC != 0; LC = LC->getParent())
+ LC != nullptr; LC = LC->getParent())
++Indentation;
// It is mildly evil to print directly to llvm::outs() rather than emitting
@@ -89,7 +89,7 @@ void CallDumper::checkPostCall(const CallEvent &Call, CheckerContext &C) const {
unsigned Indentation = 0;
for (const LocationContext *LC = C.getLocationContext()->getParent();
- LC != 0; LC = LC->getParent())
+ LC != nullptr; LC = LC->getParent())
++Indentation;
// It is mildly evil to print directly to llvm::outs() rather than emitting
diff --git a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
index 8235e68937af..fc49a46eae58 100644
--- a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
@@ -24,7 +24,7 @@ using namespace ento;
namespace {
class UndefBranchChecker : public Checker<check::BranchCondition> {
- mutable OwningPtr<BuiltinBug> BT;
+ mutable std::unique_ptr<BuiltinBug> BT;
struct FindUndefExpr {
ProgramStateRef St;
@@ -35,7 +35,7 @@ class UndefBranchChecker : public Checker<check::BranchCondition> {
const Expr *FindExpr(const Expr *Ex) {
if (!MatchesCriteria(Ex))
- return 0;
+ return nullptr;
for (Stmt::const_child_iterator I = Ex->child_begin(),
E = Ex->child_end();I!=E;++I)
@@ -67,8 +67,8 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
ExplodedNode *N = Ctx.generateSink();
if (N) {
if (!BT)
- BT.reset(
- new BuiltinBug("Branch condition evaluates to a garbage value"));
+ BT.reset(new BuiltinBug(
+ this, "Branch condition evaluates to a garbage value"));
// What's going on here: we want to highlight the subexpression of the
// condition that is the most likely source of the "uninitialized
diff --git a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
index 93812f714856..93687db073f9 100644
--- a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
@@ -27,7 +27,7 @@ using namespace ento;
namespace {
class UndefCapturedBlockVarChecker
: public Checker< check::PostStmt<BlockExpr> > {
- mutable OwningPtr<BugType> BT;
+ mutable std::unique_ptr<BugType> BT;
public:
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
@@ -48,7 +48,7 @@ static const DeclRefExpr *FindBlockDeclRefExpr(const Stmt *S,
return BR;
}
- return NULL;
+ return nullptr;
}
void
@@ -71,7 +71,7 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
const VarRegion *VR = I.getCapturedRegion();
const VarDecl *VD = VR->getDecl();
- if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage())
+ if (VD->hasAttr<BlocksAttr>() || !VD->hasLocalStorage())
continue;
// Get the VarRegion associated with VD in the local stack frame.
@@ -79,7 +79,8 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
state->getSVal(I.getOriginalRegion()).getAs<UndefinedVal>()) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT)
- BT.reset(new BuiltinBug("uninitialized variable captured by block"));
+ BT.reset(
+ new BuiltinBug(this, "uninitialized variable captured by block"));
// Generate a bug report.
SmallString<128> buf;
diff --git a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index 3f6549de56b0..f3f4dce8b17d 100644
--- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
@@ -28,8 +28,8 @@ namespace {
class UndefResultChecker
: public Checker< check::PostStmt<BinaryOperator> > {
- mutable OwningPtr<BugType> BT;
-
+ mutable std::unique_ptr<BugType> BT;
+
public:
void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const;
};
@@ -55,11 +55,12 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
return;
if (!BT)
- BT.reset(new BuiltinBug("Result of operation is garbage or undefined"));
+ BT.reset(
+ new BuiltinBug(this, "Result of operation is garbage or undefined"));
SmallString<256> sbuf;
llvm::raw_svector_ostream OS(sbuf);
- const Expr *Ex = NULL;
+ const Expr *Ex = nullptr;
bool isLeft = true;
if (state->getSVal(B->getLHS(), LCtx).isUndef()) {
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
index 5df8846766e1..e952671efffc 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
@@ -25,7 +25,7 @@ using namespace ento;
namespace {
class UndefinedArraySubscriptChecker
: public Checker< check::PreStmt<ArraySubscriptExpr> > {
- mutable OwningPtr<BugType> BT;
+ mutable std::unique_ptr<BugType> BT;
public:
void checkPreStmt(const ArraySubscriptExpr *A, CheckerContext &C) const;
@@ -50,7 +50,7 @@ UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
if (!N)
return;
if (!BT)
- BT.reset(new BuiltinBug("Array subscript is undefined"));
+ BT.reset(new BuiltinBug(this, "Array subscript is undefined"));
// Generate a report for this bug.
BugReport *R = new BugReport(*BT, BT->getName(), N);
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index 016e3c804592..bd4493d55605 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
@@ -24,7 +24,7 @@ using namespace ento;
namespace {
class UndefinedAssignmentChecker
: public Checker<check::Bind> {
- mutable OwningPtr<BugType> BT;
+ mutable std::unique_ptr<BugType> BT;
public:
void checkBind(SVal location, SVal val, const Stmt *S,
@@ -54,10 +54,10 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
const char *str = "Assigned value is garbage or undefined";
if (!BT)
- BT.reset(new BuiltinBug(str));
+ BT.reset(new BuiltinBug(this, str));
// Generate a report for this bug.
- const Expr *ex = 0;
+ const Expr *ex = nullptr;
while (StoreE) {
if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) {
diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 4ea07e29ebbb..4887d804c607 100644
--- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -30,7 +30,7 @@ using namespace ento;
namespace {
class UnixAPIChecker : public Checker< check::PreStmt<CallExpr> > {
- mutable OwningPtr<BugType> BT_open, BT_pthreadOnce, BT_mallocZero;
+ mutable std::unique_ptr<BugType> BT_open, BT_pthreadOnce, BT_mallocZero;
mutable Optional<uint64_t> Val_O_CREAT;
public:
@@ -57,21 +57,15 @@ private:
const unsigned numArgs,
const unsigned sizeArg,
const char *fn) const;
+ void LazyInitialize(std::unique_ptr<BugType> &BT, const char *name) const {
+ if (BT)
+ return;
+ BT.reset(new BugType(this, name, categories::UnixAPI));
+ }
};
} //end anonymous namespace
//===----------------------------------------------------------------------===//
-// Utility functions.
-//===----------------------------------------------------------------------===//
-
-static inline void LazyInitialize(OwningPtr<BugType> &BT,
- const char *name) {
- if (BT)
- return;
- BT.reset(new BugType(name, categories::UnixAPI));
-}
-
-//===----------------------------------------------------------------------===//
// "open" (man 2 open)
//===----------------------------------------------------------------------===//
@@ -86,6 +80,7 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
// FIXME: We need a more general way of getting the O_CREAT value.
// We could possibly grovel through the preprocessor state, but
// that would require passing the Preprocessor object to the ExprEngine.
+ // See also: MallocChecker.cpp / M_ZERO.
return;
}
}
@@ -119,7 +114,7 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
// Check if maskedFlags is non-zero.
ProgramStateRef trueState, falseState;
- llvm::tie(trueState, falseState) = state->assume(maskedFlags);
+ std::tie(trueState, falseState) = state->assume(maskedFlags);
// Only emit an error if the value of 'maskedFlags' is properly
// constrained;
@@ -199,7 +194,7 @@ static bool IsZeroByteAllocation(ProgramStateRef state,
const SVal argVal,
ProgramStateRef *trueState,
ProgramStateRef *falseState) {
- llvm::tie(*trueState, *falseState) =
+ std::tie(*trueState, *falseState) =
state->assume(argVal.castAs<DefinedSVal>());
return (*falseState && !*trueState);
@@ -207,7 +202,7 @@ static bool IsZeroByteAllocation(ProgramStateRef state,
// Generates an error report, indicating that the function whose name is given
// will perform a zero byte allocation.
-// Returns false if an error occured, true otherwise.
+// Returns false if an error occurred, true otherwise.
bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C,
ProgramStateRef falseState,
const Expr *arg,
@@ -217,7 +212,7 @@ bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C,
return false;
LazyInitialize(BT_mallocZero,
- "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
+ "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
SmallString<256> S;
llvm::raw_svector_ostream os(S);
@@ -244,7 +239,7 @@ void UnixAPIChecker::BasicAllocationCheck(CheckerContext &C,
// Check if the allocation size is 0.
ProgramStateRef state = C.getState();
- ProgramStateRef trueState = NULL, falseState = NULL;
+ ProgramStateRef trueState = nullptr, falseState = nullptr;
const Expr *arg = CE->getArg(sizeArg);
SVal argVal = state->getSVal(arg, C.getLocationContext());
@@ -269,7 +264,7 @@ void UnixAPIChecker::CheckCallocZero(CheckerContext &C,
return;
ProgramStateRef state = C.getState();
- ProgramStateRef trueState = NULL, falseState = NULL;
+ ProgramStateRef trueState = nullptr, falseState = nullptr;
unsigned int i;
for (i = 0; i < nArgs; i++) {
@@ -348,7 +343,7 @@ void UnixAPIChecker::checkPreStmt(const CallExpr *CE,
.Case("reallocf", &UnixAPIChecker::CheckReallocfZero)
.Cases("alloca", "__builtin_alloca", &UnixAPIChecker::CheckAllocaZero)
.Case("valloc", &UnixAPIChecker::CheckVallocZero)
- .Default(NULL);
+ .Default(nullptr);
if (SC)
(this->*SC)(C, CE);
diff --git a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
index a40b5a3e8378..d78de3c6f3a8 100644
--- a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
@@ -58,10 +58,10 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
if (Eng.hasWorkRemaining())
return;
- const Decl *D = 0;
- CFG *C = 0;
- ParentMap *PM = 0;
- const LocationContext *LC = 0;
+ const Decl *D = nullptr;
+ CFG *C = nullptr;
+ ParentMap *PM = nullptr;
+ const LocationContext *LC = nullptr;
// Iterate over ExplodedGraph
for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end();
I != E; ++I) {
@@ -136,7 +136,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
ci != ce; ++ci) {
if (Optional<CFGStmt> S = (*ci).getAs<CFGStmt>())
if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) {
- if (CE->isBuiltinCall() == Builtin::BI__builtin_unreachable) {
+ if (CE->getBuiltinCallee() == Builtin::BI__builtin_unreachable) {
foundUnreachable = true;
break;
}
@@ -165,7 +165,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL))
continue;
- B.EmitBasicReport(D, "Unreachable code", "Dead code",
+ B.EmitBasicReport(D, this, "Unreachable code", "Dead code",
"This statement is never executed", DL, SR);
}
}
@@ -178,6 +178,9 @@ void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB,
for (CFGBlock::const_pred_iterator I = CB->pred_begin(), E = CB->pred_end();
I != E; ++I) {
+ if (!*I)
+ continue;
+
if (!reachable.count((*I)->getBlockID())) {
// If we find an unreachable predecessor, mark this block as reachable so
// we don't report this block
@@ -198,7 +201,7 @@ const Stmt *UnreachableCodeChecker::getUnreachableStmt(const CFGBlock *CB) {
if (const Stmt *S = CB->getTerminator())
return S;
else
- return 0;
+ return nullptr;
}
// Determines if the path to this CFGBlock contained an element that infers this
@@ -219,6 +222,8 @@ bool UnreachableCodeChecker::isInvalidPath(const CFGBlock *CB,
return false;
const CFGBlock *pred = *CB->pred_begin();
+ if (!pred)
+ return false;
// Get the predecessor block's terminator conditon
const Stmt *cond = pred->getTerminatorCondition();
@@ -240,9 +245,9 @@ bool UnreachableCodeChecker::isInvalidPath(const CFGBlock *CB,
// Returns true if the given CFGBlock is empty
bool UnreachableCodeChecker::isEmptyCFGBlock(const CFGBlock *CB) {
- return CB->getLabel() == 0 // No labels
+ return CB->getLabel() == nullptr // No labels
&& CB->size() == 0 // No statements
- && CB->getTerminator() == 0; // No terminator
+ && !CB->getTerminator(); // No terminator
}
void ento::registerUnreachableCodeChecker(CheckerManager &mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
index 30aef060690d..198a6285c908 100644
--- a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
@@ -29,7 +29,7 @@ using namespace ento;
namespace {
class VLASizeChecker : public Checker< check::PreStmt<DeclStmt> > {
- mutable OwningPtr<BugType> BT;
+ mutable std::unique_ptr<BugType> BT;
enum VLASize_Kind { VLA_Garbage, VLA_Zero, VLA_Tainted };
void reportBug(VLASize_Kind Kind,
@@ -51,7 +51,8 @@ void VLASizeChecker::reportBug(VLASize_Kind Kind,
return;
if (!BT)
- BT.reset(new BuiltinBug("Dangerous variable-length array (VLA) declaration"));
+ BT.reset(new BuiltinBug(
+ this, "Dangerous variable-length array (VLA) declaration"));
SmallString<256> buf;
llvm::raw_svector_ostream os(buf);
@@ -105,7 +106,7 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
// Check if the size is tainted.
if (state->isTainted(sizeV)) {
- reportBug(VLA_Tainted, SE, 0, C);
+ reportBug(VLA_Tainted, SE, nullptr, C);
return;
}
@@ -113,7 +114,7 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
DefinedSVal sizeD = sizeV.castAs<DefinedSVal>();
ProgramStateRef stateNotZero, stateZero;
- llvm::tie(stateNotZero, stateZero) = state->assume(sizeD);
+ std::tie(stateNotZero, stateZero) = state->assume(sizeD);
if (stateZero && !stateNotZero) {
reportBug(VLA_Zero, SE, stateZero, C);
diff --git a/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
index 7b6adbfad87c..f8f5cf93ca89 100644
--- a/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
@@ -28,6 +28,7 @@ using namespace ento;
namespace {
class WalkAST : public StmtVisitor<WalkAST> {
+ const CheckerBase *Checker;
BugReporter &BR;
AnalysisDeclContext *AC;
@@ -58,11 +59,10 @@ class WalkAST : public StmtVisitor<WalkAST> {
const CallExpr *visitingCallExpr;
public:
- WalkAST(BugReporter &br, AnalysisDeclContext *ac)
- : BR(br),
- AC(ac),
- visitingCallExpr(0) {}
-
+ WalkAST(const CheckerBase *checker, BugReporter &br,
+ AnalysisDeclContext *ac)
+ : Checker(checker), BR(br), AC(ac), visitingCallExpr(nullptr) {}
+
bool hasWork() const { return !WList.empty(); }
/// This method adds a CallExpr to the worklist and marks the callee as
@@ -187,21 +187,19 @@ void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) {
if (isPure) {
os << "\n" << "Call pure virtual functions during construction or "
<< "destruction may leads undefined behaviour";
- BR.EmitBasicReport(AC->getDecl(),
+ BR.EmitBasicReport(AC->getDecl(), Checker,
"Call pure virtual function during construction or "
"Destruction",
- "Cplusplus",
- os.str(), CELoc, R);
+ "Cplusplus", os.str(), CELoc, R);
return;
}
else {
os << "\n" << "Call virtual functions during construction or "
<< "destruction will never go to a more derived class";
- BR.EmitBasicReport(AC->getDecl(),
+ BR.EmitBasicReport(AC->getDecl(), Checker,
"Call virtual function during construction or "
"Destruction",
- "Cplusplus",
- os.str(), CELoc, R);
+ "Cplusplus", os.str(), CELoc, R);
return;
}
}
@@ -215,11 +213,10 @@ class VirtualCallChecker : public Checker<check::ASTDecl<CXXRecordDecl> > {
public:
void checkASTDecl(const CXXRecordDecl *RD, AnalysisManager& mgr,
BugReporter &BR) const {
- WalkAST walker(BR, mgr.getAnalysisDeclContext(RD));
+ WalkAST walker(this, BR, mgr.getAnalysisDeclContext(RD));
// Check the constructors.
- for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(), E = RD->ctor_end();
- I != E; ++I) {
+ for (const auto *I : RD->ctors()) {
if (!I->isCopyOrMoveConstructor())
if (Stmt *Body = I->getBody()) {
walker.Visit(Body);
diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index 9dcf58babd27..7944c7eb0003 100644
--- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -39,7 +39,7 @@ IPAKind AnalyzerOptions::getIPAMode() {
// Use the User Mode to set the default IPA value.
// Note, we have to add the string to the Config map for the ConfigDumper
// checker to function properly.
- const char *DefaultIPA = 0;
+ const char *DefaultIPA = nullptr;
UserModeKind HighLevelMode = getUserMode();
if (HighLevelMode == UMK_Shallow)
DefaultIPA = "inlining";
@@ -134,8 +134,14 @@ bool AnalyzerOptions::mayInlineTemplateFunctions() {
/*Default=*/true);
}
-bool AnalyzerOptions::mayInlineCXXContainerCtorsAndDtors() {
- return getBooleanOption(InlineCXXContainerCtorsAndDtors,
+bool AnalyzerOptions::mayInlineCXXAllocator() {
+ return getBooleanOption(InlineCXXAllocator,
+ "c++-allocator-inlining",
+ /*Default=*/false);
+}
+
+bool AnalyzerOptions::mayInlineCXXContainerMethods() {
+ return getBooleanOption(InlineCXXContainerMethods,
"c++-container-inlining",
/*Default=*/false);
}
@@ -183,6 +189,13 @@ bool AnalyzerOptions::shouldReportIssuesInMainSourceFile() {
/* Default = */ false);
}
+
+bool AnalyzerOptions::shouldWriteStableReportFilename() {
+ return getBooleanOption(StableReportFilename,
+ "stable-report-filename",
+ /* Default = */ false);
+}
+
int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) {
SmallString<10> StrBuf;
llvm::raw_svector_ostream OS(StrBuf);
diff --git a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
index a6c400f3704d..0e90566839ca 100644
--- a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -173,12 +173,12 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op,
// FIXME: Expand these checks to include all undefined behavior.
if (V2.isSigned() && V2.isNegative())
- return NULL;
+ return nullptr;
uint64_t Amt = V2.getZExtValue();
- if (Amt > V1.getBitWidth())
- return NULL;
+ if (Amt >= V1.getBitWidth())
+ return nullptr;
return &getValue( V1.operator<<( (unsigned) Amt ));
}
@@ -191,12 +191,12 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op,
// FIXME: Expand these checks to include all undefined behavior.
if (V2.isSigned() && V2.isNegative())
- return NULL;
+ return nullptr;
uint64_t Amt = V2.getZExtValue();
- if (Amt > V1.getBitWidth())
- return NULL;
+ if (Amt >= V1.getBitWidth())
+ return nullptr;
return &getValue( V1.operator>>( (unsigned) Amt ));
}
diff --git a/lib/StaticAnalyzer/Core/BlockCounter.cpp b/lib/StaticAnalyzer/Core/BlockCounter.cpp
index 74d761e1ecc1..c1ac03d5ab97 100644
--- a/lib/StaticAnalyzer/Core/BlockCounter.cpp
+++ b/lib/StaticAnalyzer/Core/BlockCounter.cpp
@@ -34,8 +34,7 @@ public:
}
bool operator<(const CountKey &RHS) const {
- return (CallSite == RHS.CallSite) ? (BlockID < RHS.BlockID)
- : (CallSite < RHS.CallSite);
+ return std::tie(CallSite, BlockID) < std::tie(RHS.CallSite, RHS.BlockID);
}
void Profile(llvm::FoldingSetNodeID &ID) const {
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 1940fa79fda3..141a48ba10b3 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -12,16 +12,14 @@
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "BugReporter"
-
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ParentMap.h"
-#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Basic/SourceManager.h"
@@ -30,16 +28,18 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/raw_ostream.h"
+#include <memory>
#include <queue>
using namespace clang;
using namespace ento;
+#define DEBUG_TYPE "BugReporter"
+
STATISTIC(MaxBugClassSize,
"The maximum number of bug reports in the same equivalence class");
STATISTIC(MaxValidBugClassSize,
@@ -59,7 +59,7 @@ static const Stmt *GetPreviousStmt(const ExplodedNode *N) {
if (const Stmt *S = PathDiagnosticLocation::getStmt(N))
return S;
- return 0;
+ return nullptr;
}
static inline const Stmt*
@@ -83,15 +83,15 @@ eventsDescribeSameCondition(PathDiagnosticEventPiece *X,
const void *tagLesser = TrackConstraintBRVisitor::getTag();
if (X->getLocation() != Y->getLocation())
- return 0;
-
+ return nullptr;
+
if (X->getTag() == tagPreferred && Y->getTag() == tagLesser)
return X;
if (Y->getTag() == tagPreferred && X->getTag() == tagLesser)
return Y;
-
- return 0;
+
+ return nullptr;
}
/// An optimization pass over PathPieces that removes redundant diagnostics
@@ -125,7 +125,7 @@ static void removeRedundantMsgs(PathPieces &path) {
break;
if (PathDiagnosticEventPiece *nextEvent =
- dyn_cast<PathDiagnosticEventPiece>(path.front().getPtr())) {
+ dyn_cast<PathDiagnosticEventPiece>(path.front().get())) {
PathDiagnosticEventPiece *event =
cast<PathDiagnosticEventPiece>(piece);
// Check to see if we should keep one of the two pieces. If we
@@ -214,8 +214,9 @@ static bool hasImplicitBody(const Decl *D) {
/// Recursively scan through a path and make sure that all call pieces have
/// valid locations.
-static void adjustCallLocations(PathPieces &Pieces,
- PathDiagnosticLocation *LastCallLocation = 0) {
+static void
+adjustCallLocations(PathPieces &Pieces,
+ PathDiagnosticLocation *LastCallLocation = nullptr) {
for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E; ++I) {
PathDiagnosticCallPiece *Call = dyn_cast<PathDiagnosticCallPiece>(*I);
@@ -265,7 +266,7 @@ static void removeEdgesToDefaultInitializers(PathPieces &Pieces) {
I = Pieces.erase(I);
continue;
} else if (End && isa<CXXDefaultInitExpr>(End)) {
- PathPieces::iterator Next = llvm::next(I);
+ PathPieces::iterator Next = std::next(I);
if (Next != E) {
if (PathDiagnosticControlFlowPiece *NextCF =
dyn_cast<PathDiagnosticControlFlowPiece>(*Next)) {
@@ -311,7 +312,7 @@ class NodeMapClosure : public BugReport::NodeResolver {
public:
NodeMapClosure(InterExplodedGraphMap &m) : M(m) {}
- const ExplodedNode *getOriginalNode(const ExplodedNode *N) {
+ const ExplodedNode *getOriginalNode(const ExplodedNode *N) override {
return M.lookup(N);
}
};
@@ -345,7 +346,7 @@ public:
return getParentMap().getParent(S);
}
- virtual NodeMapClosure& getNodeResolver() { return NMC; }
+ NodeMapClosure& getNodeResolver() override { return NMC; }
PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S);
@@ -405,7 +406,7 @@ static const Stmt *getEnclosingParent(const Stmt *S, const ParentMap &PM) {
const Stmt *Parent = PM.getParentIgnoreParens(S);
if (!Parent)
- return 0;
+ return nullptr;
switch (Parent->getStmtClass()) {
case Stmt::ForStmtClass:
@@ -418,7 +419,7 @@ static const Stmt *getEnclosingParent(const Stmt *S, const ParentMap &PM) {
break;
}
- return 0;
+ return nullptr;
}
static PathDiagnosticLocation
@@ -564,7 +565,7 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
SourceManager& SMgr = PDB.getSourceManager();
const LocationContext *LC = PDB.LC;
const ExplodedNode *NextNode = N->pred_empty()
- ? NULL : *(N->pred_begin());
+ ? nullptr : *(N->pred_begin());
StackDiagVector CallStack;
@@ -1263,8 +1264,8 @@ static void reversePropagateIntererstingSymbols(BugReport &R,
SVal ChildV = State->getSVal(child, LCtx);
R.markInteresting(ChildV);
}
- break;
}
+ break;
}
}
@@ -1351,11 +1352,11 @@ static const Stmt *getStmtBeforeCond(ParentMap &PM, const Stmt *Term,
}
N = N->getFirstPred();
}
- return 0;
+ return nullptr;
}
static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term) {
- const Stmt *LoopBody = 0;
+ const Stmt *LoopBody = nullptr;
switch (Term->getStmtClass()) {
case Stmt::CXXForRangeStmtClass: {
const CXXForRangeStmt *FR = cast<CXXForRangeStmt>(Term);
@@ -1401,7 +1402,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
StackDiagVector CallStack;
InterestingExprs IE;
- const ExplodedNode *NextNode = N->pred_empty() ? NULL : *(N->pred_begin());
+ const ExplodedNode *NextNode = N->pred_empty() ? nullptr : *(N->pred_begin());
while (NextNode) {
N = NextNode;
NextNode = N->getFirstPred();
@@ -1411,7 +1412,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
if (Optional<PostStmt> PS = P.getAs<PostStmt>()) {
if (const Expr *Ex = PS->getStmtAs<Expr>())
reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
- N->getState().getPtr(), Ex,
+ N->getState().get(), Ex,
N->getLocationContext());
}
@@ -1419,7 +1420,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
const Stmt *S = CE->getCalleeContext()->getCallSite();
if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
- N->getState().getPtr(), Ex,
+ N->getState().get(), Ex,
N->getLocationContext());
}
@@ -1490,7 +1491,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
const LocationContext *CalleeCtx = PDB.LC;
if (CallerCtx != CalleeCtx) {
reversePropagateInterestingSymbols(*PDB.getBugReport(), IE,
- N->getState().getPtr(),
+ N->getState().get(),
CalleeCtx, CallerCtx);
}
}
@@ -1498,7 +1499,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
// Are we jumping to the head of a loop? Add a special diagnostic.
if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
PathDiagnosticLocation L(Loop, SM, PDB.LC);
- const CompoundStmt *CS = NULL;
+ const CompoundStmt *CS = nullptr;
if (const ForStmt *FS = dyn_cast<ForStmt>(Loop))
CS = dyn_cast<CompoundStmt>(FS->getBody());
@@ -1673,7 +1674,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticCallPiece *C;
if (VisitedEntireCall) {
- PathDiagnosticPiece *P = PD.getActivePath().front().getPtr();
+ PathDiagnosticPiece *P = PD.getActivePath().front().get();
C = cast<PathDiagnosticCallPiece>(P);
} else {
const Decl *Caller = CE->getLocationContext()->getDecl();
@@ -1683,11 +1684,11 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD,
// reset the mapping from active to location context.
assert(PD.getActivePath().size() == 1 &&
PD.getActivePath().front() == C);
- LCM[&PD.getActivePath()] = 0;
+ LCM[&PD.getActivePath()] = nullptr;
// Record the location context mapping for the path within
// the call.
- assert(LCM[&C->path] == 0 ||
+ assert(LCM[&C->path] == nullptr ||
LCM[&C->path] == CE->getCalleeContext());
LCM[&C->path] = CE->getCalleeContext();
@@ -1727,7 +1728,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD,
// Propagate the interesting symbols accordingly.
if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
- N->getState().getPtr(), Ex,
+ N->getState().get(), Ex,
N->getLocationContext());
}
@@ -1755,7 +1756,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD,
// interesting symbols correctly.
if (const Expr *Ex = PS->getStmtAs<Expr>())
reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
- N->getState().getPtr(), Ex,
+ N->getState().get(), Ex,
N->getLocationContext());
// Add an edge. If this is an ObjCForCollectionStmt do
@@ -1778,7 +1779,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD,
const LocationContext *CalleeCtx = PDB.LC;
if (CallerCtx != CalleeCtx) {
reversePropagateInterestingSymbols(*PDB.getBugReport(), IE,
- N->getState().getPtr(),
+ N->getState().get(),
CalleeCtx, CallerCtx);
}
}
@@ -1786,7 +1787,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD,
// Are we jumping to the head of a loop? Add a special diagnostic.
if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
PathDiagnosticLocation L(Loop, SM, PDB.LC);
- const Stmt *Body = NULL;
+ const Stmt *Body = nullptr;
if (const ForStmt *FS = dyn_cast<ForStmt>(Loop))
Body = FS->getBody();
@@ -1827,7 +1828,7 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD,
bool IsInLoopBody =
isInLoopBody(PM, getStmtBeforeCond(PM, TermCond, N), Term);
- const char *str = 0;
+ const char *str = nullptr;
if (isJumpToFalseBranch(&*BE)) {
if (!IsInLoopBody) {
@@ -1890,13 +1891,13 @@ GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD,
static const Stmt *getLocStmt(PathDiagnosticLocation L) {
if (!L.isValid())
- return 0;
+ return nullptr;
return L.asStmt();
}
static const Stmt *getStmtParent(const Stmt *S, const ParentMap &PM) {
if (!S)
- return 0;
+ return nullptr;
while (true) {
S = PM.getParentIgnoreParens(S);
@@ -1988,7 +1989,7 @@ static void addContextEdges(PathPieces &pieces, SourceManager &SM,
SmallVector<PathDiagnosticLocation, 4> SrcContexts;
PathDiagnosticLocation NextSrcContext = SrcLoc;
- const Stmt *InnerStmt = 0;
+ const Stmt *InnerStmt = nullptr;
while (NextSrcContext.isValid() && NextSrcContext.asStmt() != InnerStmt) {
SrcContexts.push_back(NextSrcContext);
InnerStmt = NextSrcContext.asStmt();
@@ -2073,7 +2074,7 @@ static void simplifySimpleBranches(PathPieces &pieces) {
if (NextI == E)
break;
- PathDiagnosticControlFlowPiece *PieceNextI = 0;
+ PathDiagnosticControlFlowPiece *PieceNextI = nullptr;
while (true) {
if (NextI == E)
@@ -2579,8 +2580,8 @@ const Decl *BugReport::getDeclWithIssue() const {
const ExplodedNode *N = getErrorNode();
if (!N)
- return 0;
-
+ return nullptr;
+
const LocationContext *LC = N->getLocationContext();
return LC->getCurrentStackFrame()->getDecl();
}
@@ -2703,10 +2704,10 @@ void BugReport::popInterestingSymbolsAndRegions() {
const Stmt *BugReport::getStmt() const {
if (!ErrorNode)
- return 0;
+ return nullptr;
ProgramPoint ProgP = ErrorNode->getLocation();
- const Stmt *S = NULL;
+ const Stmt *S = nullptr;
if (Optional<BlockEntrance> BE = ProgP.getAs<BlockEntrance>()) {
CFGBlock &Exit = ProgP.getLocationContext()->getCFG()->getExit();
@@ -2742,12 +2743,10 @@ PathDiagnosticLocation BugReport::getLocation(const SourceManager &SM) const {
assert(!Location.isValid() &&
"Either Location or ErrorNode should be specified but not both.");
return PathDiagnosticLocation::createEndOfPath(ErrorNode, SM);
- } else {
- assert(Location.isValid());
- return Location;
}
- return PathDiagnosticLocation();
+ assert(Location.isValid());
+ return Location;
}
//===----------------------------------------------------------------------===//
@@ -2802,9 +2801,7 @@ void BugReporter::FlushReports() {
// EmitBasicReport.
// FIXME: There are leaks from checkers that assume that the BugTypes they
// create will be destroyed by the BugReporter.
- for (llvm::StringMap<BugType*>::iterator
- I = StrBugTypes.begin(), E = StrBugTypes.end(); I != E; ++I)
- delete I->second;
+ llvm::DeleteContainerSeconds(StrBugTypes);
// Remove all references to the BugType objects.
BugTypes = F.getEmptySet();
@@ -2820,7 +2817,7 @@ namespace {
class ReportGraph {
public:
InterExplodedGraphMap BackMap;
- OwningPtr<ExplodedGraph> Graph;
+ std::unique_ptr<ExplodedGraph> Graph;
const ExplodedNode *ErrorNode;
size_t Index;
};
@@ -2835,7 +2832,7 @@ class TrimmedGraph {
typedef std::pair<const ExplodedNode *, size_t> NodeIndexPair;
SmallVector<NodeIndexPair, 32> ReportNodes;
- OwningPtr<ExplodedGraph> G;
+ std::unique_ptr<ExplodedGraph> G;
/// A helper class for sorting ExplodedNodes by priority.
template <bool Descending>
@@ -2906,7 +2903,7 @@ TrimmedGraph::TrimmedGraph(const ExplodedGraph *OriginalGraph,
PriorityMapTy::iterator PriorityEntry;
bool IsNew;
- llvm::tie(PriorityEntry, IsNew) =
+ std::tie(PriorityEntry, IsNew) =
PriorityMap.insert(std::make_pair(Node, Priority));
++Priority;
@@ -2935,7 +2932,7 @@ bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) {
return false;
const ExplodedNode *OrigN;
- llvm::tie(OrigN, GraphWrapper.Index) = ReportNodes.pop_back_val();
+ std::tie(OrigN, GraphWrapper.Index) = ReportNodes.pop_back_val();
assert(PriorityMap.find(OrigN) != PriorityMap.end() &&
"error node not accessible from root");
@@ -2947,7 +2944,7 @@ bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) {
// Now walk from the error node up the BFS path, always taking the
// predeccessor with the lowest number.
- ExplodedNode *Succ = 0;
+ ExplodedNode *Succ = nullptr;
while (true) {
// Create the equivalent node in the new graph with the same state
// and location.
@@ -2998,7 +2995,7 @@ static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM) {
for (PathPieces::const_iterator I = path.begin(), E = path.end();
I!=E; ++I) {
- PathDiagnosticPiece *piece = I->getPtr();
+ PathDiagnosticPiece *piece = I->get();
// Recursively compact calls.
if (PathDiagnosticCallPiece *call=dyn_cast<PathDiagnosticCallPiece>(piece)){
@@ -3095,7 +3092,7 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD,
} else {
// Keep the errorNodes list in sync with the bugReports list.
HasInvalid = true;
- errorNodes.push_back(0);
+ errorNodes.push_back(nullptr);
}
}
@@ -3153,21 +3150,21 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD,
// Generate the very last diagnostic piece - the piece is visible before
// the trace is expanded.
- PathDiagnosticPiece *LastPiece = 0;
+ std::unique_ptr<PathDiagnosticPiece> LastPiece;
for (BugReport::visitor_iterator I = visitors.begin(), E = visitors.end();
I != E; ++I) {
if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) {
assert (!LastPiece &&
"There can only be one final piece in a diagnostic.");
- LastPiece = Piece;
+ LastPiece.reset(Piece);
}
}
if (ActiveScheme != PathDiagnosticConsumer::None) {
if (!LastPiece)
- LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R);
+ LastPiece.reset(BugReporterVisitor::getDefaultEndPath(PDB, N, *R));
assert(LastPiece);
- PD.setEndOfPath(LastPiece);
+ PD.setEndOfPath(LastPiece.release());
}
// Make sure we get a clean location context map so we don't
@@ -3247,6 +3244,9 @@ void BugReporter::Register(BugType *BT) {
}
void BugReporter::emitReport(BugReport* R) {
+ // To guarantee memory release.
+ std::unique_ptr<BugReport> UniqueR(R);
+
// Defensive checking: throw the bug away if it comes from a BodyFarm-
// generated body. We do this very early because report processing relies
// on the report's location being valid.
@@ -3277,12 +3277,12 @@ void BugReporter::emitReport(BugReport* R) {
BugReportEquivClass* EQ = EQClasses.FindNodeOrInsertPos(ID, InsertPos);
if (!EQ) {
- EQ = new BugReportEquivClass(R);
+ EQ = new BugReportEquivClass(UniqueR.release());
EQClasses.InsertNode(EQ, InsertPos);
EQClassesVector.push_back(EQ);
}
else
- EQ->AddReport(R);
+ EQ->AddReport(UniqueR.release());
}
@@ -3329,7 +3329,7 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
// DFS traversal of the ExplodedGraph to find a non-sink node. We could write
// this as a recursive function, but we don't want to risk blowing out the
// stack for very long paths.
- BugReport *exampleReport = 0;
+ BugReport *exampleReport = nullptr;
for (; I != E; ++I) {
const ExplodedNode *errorNode = I->getErrorNode();
@@ -3403,10 +3403,8 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
SmallVector<BugReport*, 10> bugReports;
BugReport *exampleReport = FindReportInEquivalenceClass(EQ, bugReports);
if (exampleReport) {
- const PathDiagnosticConsumers &C = getPathDiagnosticConsumers();
- for (PathDiagnosticConsumers::const_iterator I=C.begin(),
- E=C.end(); I != E; ++I) {
- FlushReport(exampleReport, **I, bugReports);
+ for (PathDiagnosticConsumer *PDC : getPathDiagnosticConsumers()) {
+ FlushReport(exampleReport, *PDC, bugReports);
}
}
}
@@ -3419,14 +3417,13 @@ void BugReporter::FlushReport(BugReport *exampleReport,
// Probably doesn't make a difference in practice.
BugType& BT = exampleReport->getBugType();
- OwningPtr<PathDiagnostic>
- D(new PathDiagnostic(exampleReport->getDeclWithIssue(),
- exampleReport->getBugType().getName(),
- exampleReport->getDescription(),
- exampleReport->getShortDescription(/*Fallback=*/false),
- BT.getCategory(),
- exampleReport->getUniqueingLocation(),
- exampleReport->getUniqueingDecl()));
+ std::unique_ptr<PathDiagnostic> D(new PathDiagnostic(
+ exampleReport->getBugType().getCheckName(),
+ exampleReport->getDeclWithIssue(), exampleReport->getBugType().getName(),
+ exampleReport->getDescription(),
+ exampleReport->getShortDescription(/*Fallback=*/false), BT.getCategory(),
+ exampleReport->getUniqueingLocation(),
+ exampleReport->getUniqueingDecl()));
MaxBugClassSize = std::max(bugReports.size(),
static_cast<size_t>(MaxBugClassSize));
@@ -3455,7 +3452,7 @@ void BugReporter::FlushReport(BugReport *exampleReport,
PathDiagnosticPiece *piece =
new PathDiagnosticEventPiece(L, exampleReport->getDescription());
BugReport::ranges_iterator Beg, End;
- llvm::tie(Beg, End) = exampleReport->getRanges();
+ std::tie(Beg, End) = exampleReport->getRanges();
for ( ; Beg != End; ++Beg)
piece->addRange(*Beg);
D->setEndOfPath(piece);
@@ -3468,17 +3465,25 @@ void BugReporter::FlushReport(BugReport *exampleReport,
D->addMeta(*i);
}
- PD.HandlePathDiagnostic(D.take());
+ PD.HandlePathDiagnostic(D.release());
}
void BugReporter::EmitBasicReport(const Decl *DeclWithIssue,
- StringRef name,
- StringRef category,
+ const CheckerBase *Checker,
+ StringRef Name, StringRef Category,
+ StringRef Str, PathDiagnosticLocation Loc,
+ ArrayRef<SourceRange> Ranges) {
+ EmitBasicReport(DeclWithIssue, Checker->getCheckName(), Name, Category, Str,
+ Loc, Ranges);
+}
+void BugReporter::EmitBasicReport(const Decl *DeclWithIssue,
+ CheckName CheckName,
+ StringRef name, StringRef category,
StringRef str, PathDiagnosticLocation Loc,
ArrayRef<SourceRange> Ranges) {
// 'BT' is owned by BugReporter.
- BugType *BT = getBugTypeForName(name, category);
+ BugType *BT = getBugTypeForName(CheckName, name, category);
BugReport *R = new BugReport(*BT, str, Loc);
R->setDeclWithIssue(DeclWithIssue);
for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
@@ -3487,22 +3492,22 @@ void BugReporter::EmitBasicReport(const Decl *DeclWithIssue,
emitReport(R);
}
-BugType *BugReporter::getBugTypeForName(StringRef name,
+BugType *BugReporter::getBugTypeForName(CheckName CheckName, StringRef name,
StringRef category) {
SmallString<136> fullDesc;
- llvm::raw_svector_ostream(fullDesc) << name << ":" << category;
+ llvm::raw_svector_ostream(fullDesc) << CheckName.getName() << ":" << name
+ << ":" << category;
llvm::StringMapEntry<BugType *> &
entry = StrBugTypes.GetOrCreateValue(fullDesc);
BugType *BT = entry.getValue();
if (!BT) {
- BT = new BugType(name, category);
+ BT = new BugType(CheckName, name, category);
entry.setValue(BT);
}
return BT;
}
-
-void PathPieces::dump() const {
+LLVM_DUMP_METHOD void PathPieces::dump() const {
unsigned index = 0;
for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
llvm::errs() << "[" << index++ << "] ";
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index e1a92b30c6be..0503acec051a 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -45,7 +45,7 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) {
// a[0], p->f, *p
const Expr *E = dyn_cast<Expr>(S);
if (!E)
- return 0;
+ return nullptr;
E = E->IgnoreParenCasts();
while (true) {
@@ -79,21 +79,21 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) {
break;
}
- return NULL;
+ return nullptr;
}
const Stmt *bugreporter::GetDenomExpr(const ExplodedNode *N) {
const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S))
return BE->getRHS();
- return NULL;
+ return nullptr;
}
const Stmt *bugreporter::GetRetValExpr(const ExplodedNode *N) {
const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(S))
return RS->getRetValue();
- return NULL;
+ return nullptr;
}
//===----------------------------------------------------------------------===//
@@ -104,7 +104,7 @@ PathDiagnosticPiece*
BugReporterVisitor::getEndPath(BugReporterContext &BRC,
const ExplodedNode *EndPathNode,
BugReport &BR) {
- return 0;
+ return nullptr;
}
PathDiagnosticPiece*
@@ -115,7 +115,7 @@ BugReporterVisitor::getDefaultEndPath(BugReporterContext &BRC,
PathDiagnosticLocation::createEndOfPath(EndPathNode,BRC.getSourceManager());
BugReport::ranges_iterator Beg, End;
- llvm::tie(Beg, End) = BR.getRanges();
+ std::tie(Beg, End) = BR.getRanges();
// Only add the statement itself as a range if we didn't specify any
// special ranges for this report.
@@ -156,7 +156,7 @@ public:
return static_cast<void *>(&Tag);
}
- virtual void Profile(llvm::FoldingSetNodeID &ID) const {
+ void Profile(llvm::FoldingSetNodeID &ID) const override {
ID.AddPointer(ReturnVisitor::getTag());
ID.AddPointer(StackFrame);
ID.AddBoolean(EnableNullFPSuppression);
@@ -237,22 +237,22 @@ public:
BugReport &BR) {
// Only print a message at the interesting return statement.
if (N->getLocationContext() != StackFrame)
- return 0;
+ return nullptr;
Optional<StmtPoint> SP = N->getLocationAs<StmtPoint>();
if (!SP)
- return 0;
+ return nullptr;
const ReturnStmt *Ret = dyn_cast<ReturnStmt>(SP->getStmt());
if (!Ret)
- return 0;
+ return nullptr;
// Okay, we're at the right return statement, but do we have the return
// value available?
ProgramStateRef State = N->getState();
SVal V = State->getSVal(Ret, StackFrame);
if (V.isUnknownOrUndef())
- return 0;
+ return nullptr;
// Don't print any more notes after this one.
Mode = Satisfied;
@@ -273,7 +273,7 @@ public:
// Ignore aggregate rvalues.
if (V.getAs<nonloc::LazyCompoundVal>() ||
V.getAs<nonloc::CompoundVal>())
- return 0;
+ return nullptr;
RetE = RetE->IgnoreParenCasts();
@@ -283,7 +283,7 @@ public:
BR.markInteresting(V);
ReturnVisitor::addVisitorIfNecessary(N, RetE, BR,
EnableNullFPSuppression);
- return 0;
+ return nullptr;
}
// If we're returning 0, we should track where that 0 came from.
@@ -343,10 +343,10 @@ public:
// Are we at the entry node for this call?
Optional<CallEnter> CE = N->getLocationAs<CallEnter>();
if (!CE)
- return 0;
+ return nullptr;
if (CE->getCalleeContext() != StackFrame)
- return 0;
+ return nullptr;
Mode = Satisfied;
@@ -380,20 +380,20 @@ public:
// (We will still look at the other arguments, though.)
}
- return 0;
+ return nullptr;
}
PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext &BRC,
- BugReport &BR) {
+ BugReport &BR) override {
switch (Mode) {
case Initial:
return visitNodeInitial(N, PrevN, BRC, BR);
case MaybeUnsuppress:
return visitNodeMaybeUnsuppress(N, PrevN, BRC, BR);
case Satisfied:
- return 0;
+ return nullptr;
}
llvm_unreachable("Invalid visit mode!");
@@ -401,10 +401,10 @@ public:
PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
const ExplodedNode *N,
- BugReport &BR) {
+ BugReport &BR) override {
if (EnableNullFPSuppression)
BR.markInvalid(ReturnVisitor::getTag(), StackFrame);
- return 0;
+ return nullptr;
}
};
} // end anonymous namespace
@@ -453,10 +453,10 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
BugReport &BR) {
if (Satisfied)
- return NULL;
+ return nullptr;
- const ExplodedNode *StoreSite = 0;
- const Expr *InitE = 0;
+ const ExplodedNode *StoreSite = nullptr;
+ const Expr *InitE = nullptr;
bool IsParam = false;
// First see if we reached the declaration of the region.
@@ -484,12 +484,12 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
// the same binding was re-assigned here.
if (!StoreSite) {
if (Succ->getState()->getSVal(R) != V)
- return NULL;
+ return nullptr;
if (Pred->getState()->getSVal(R) == V) {
Optional<PostStore> PS = Succ->getLocationAs<PostStore>();
if (!PS || PS->getLocationValue() != R)
- return NULL;
+ return nullptr;
}
StoreSite = Succ;
@@ -526,7 +526,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
}
if (!StoreSite)
- return NULL;
+ return nullptr;
Satisfied = true;
// If we have an expression that provided the value, try to track where it
@@ -550,7 +550,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
if (Optional<PostStmt> PS = StoreSite->getLocationAs<PostStmt>()) {
const Stmt *S = PS->getStmt();
- const char *action = 0;
+ const char *action = nullptr;
const DeclStmt *DS = dyn_cast<DeclStmt>(S);
const VarRegion *VR = dyn_cast<VarRegion>(R);
@@ -703,7 +703,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
L = PathDiagnosticLocation::create(P, BRC.getSourceManager());
if (!L.isValid() || !L.asLocation().isValid())
- return NULL;
+ return nullptr;
return new PathDiagnosticEventPiece(L, os.str());
}
@@ -724,7 +724,7 @@ const char *TrackConstraintBRVisitor::getTag() {
bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const {
if (IsZeroCheck)
return N->getState()->isNull(Constraint).isUnderconstrained();
- return N->getState()->assume(Constraint, !Assumption);
+ return (bool)N->getState()->assume(Constraint, !Assumption);
}
PathDiagnosticPiece *
@@ -733,7 +733,7 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
BugReport &BR) {
if (IsSatisfied)
- return NULL;
+ return nullptr;
// Start tracking after we see the first state in which the value is
// constrained.
@@ -741,7 +741,7 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
if (!isUnderconstrained(N))
IsTrackingTurnedOn = true;
if (!IsTrackingTurnedOn)
- return 0;
+ return nullptr;
// Check if in the previous state it was feasible for this constraint
// to *not* be true.
@@ -765,21 +765,21 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
}
if (os.str().empty())
- return NULL;
+ return nullptr;
// Construct a new PathDiagnosticPiece.
ProgramPoint P = N->getLocation();
PathDiagnosticLocation L =
PathDiagnosticLocation::create(P, BRC.getSourceManager());
if (!L.isValid())
- return NULL;
-
+ return nullptr;
+
PathDiagnosticEventPiece *X = new PathDiagnosticEventPiece(L, os.str());
X->setTag(getTag());
return X;
}
- return NULL;
+ return nullptr;
}
SuppressInlineDefensiveChecksVisitor::
@@ -813,14 +813,14 @@ SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ,
BugReporterContext &BRC,
BugReport &BR) {
if (IsSatisfied)
- return 0;
+ return nullptr;
// Start tracking after we see the first state in which the value is null.
if (!IsTrackingTurnedOn)
if (Succ->getState()->isNull(V).isConstrainedTrue())
IsTrackingTurnedOn = true;
if (!IsTrackingTurnedOn)
- return 0;
+ return nullptr;
// Check if in the previous state it was feasible for this value
// to *not* be null.
@@ -835,7 +835,7 @@ SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ,
if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC))
BR.markInvalid("Suppress IDC", CurLC);
}
- return 0;
+ return nullptr;
}
static const MemRegion *getLocationRegionIfReference(const Expr *E,
@@ -843,7 +843,7 @@ static const MemRegion *getLocationRegionIfReference(const Expr *E,
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) {
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
if (!VD->getType()->isReferenceType())
- return 0;
+ return nullptr;
ProgramStateManager &StateMgr = N->getState()->getStateManager();
MemRegionManager &MRMgr = StateMgr.getRegionManager();
return MRMgr.getVarRegion(VD, N->getLocationContext());
@@ -856,7 +856,7 @@ static const MemRegion *getLocationRegionIfReference(const Expr *E,
// Wrapper w = { *(int *)0 };
// w.ref = 1;
- return 0;
+ return nullptr;
}
static const Expr *peelOffOuterExpr(const Expr *Ex,
@@ -869,7 +869,7 @@ static const Expr *peelOffOuterExpr(const Expr *Ex,
// Peel off the ternary operator.
if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(Ex)) {
- // Find a node where the branching occured and find out which branch
+ // Find a node where the branching occurred and find out which branch
// we took (true/false) by looking at the ExplodedGraph.
const ExplodedNode *NI = N;
do {
@@ -906,7 +906,7 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
S = PeeledEx;
}
- const Expr *Inner = 0;
+ const Expr *Inner = nullptr;
if (const Expr *Ex = dyn_cast<Expr>(S)) {
Ex = Ex->IgnoreParenCasts();
if (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex))
@@ -948,7 +948,7 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
// See if the expression we're interested refers to a variable.
// If so, we can track both its contents and constraints on its value.
if (Inner && ExplodedGraph::isInterestingLValueExpr(Inner)) {
- const MemRegion *R = 0;
+ const MemRegion *R = nullptr;
// Find the ExplodedNode where the lvalue (the value of 'Ex')
// was computed. We need this for getting the location value.
@@ -1060,14 +1060,14 @@ const Expr *NilReceiverBRVisitor::getNilReceiver(const Stmt *S,
const ExplodedNode *N) {
const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S);
if (!ME)
- return 0;
+ return nullptr;
if (const Expr *Receiver = ME->getInstanceReceiver()) {
ProgramStateRef state = N->getState();
SVal V = state->getSVal(Receiver, N->getLocationContext());
if (state->isNull(V).isConstrainedTrue())
return Receiver;
}
- return 0;
+ return nullptr;
}
PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N,
@@ -1076,18 +1076,20 @@ PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N,
BugReport &BR) {
Optional<PreStmt> P = N->getLocationAs<PreStmt>();
if (!P)
- return 0;
+ return nullptr;
const Stmt *S = P->getStmt();
const Expr *Receiver = getNilReceiver(S, N);
if (!Receiver)
- return 0;
+ return nullptr;
llvm::SmallString<256> Buf;
llvm::raw_svector_ostream OS(Buf);
if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
- OS << "'" << ME->getSelector().getAsString() << "' not called";
+ OS << "'";
+ ME->getSelector().print(OS);
+ OS << "' not called";
}
else {
OS << "No method is called";
@@ -1179,15 +1181,15 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
// were generated by the analyzer engine proper, not checkers.
if (CurrentState->getGDM().getRoot() ==
PrevState->getGDM().getRoot())
- return 0;
-
+ return nullptr;
+
// If an assumption was made on a branch, it should be caught
// here by looking at the state transition.
if (Optional<BlockEdge> BE = progPoint.getAs<BlockEdge>()) {
const CFGBlock *srcBlk = BE->getSrc();
if (const Stmt *term = srcBlk->getTerminator())
return VisitTerminator(term, N, srcBlk, BE->getDst(), BR, BRC);
- return 0;
+ return nullptr;
}
if (Optional<PostStmt> PS = progPoint.getAs<PostStmt>()) {
@@ -1204,11 +1206,11 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
if (tag == tags.second)
return VisitTrueTest(cast<Expr>(PS->getStmt()), false,
BRC, BR, N);
-
- return 0;
+
+ return nullptr;
}
-
- return 0;
+
+ return nullptr;
}
PathDiagnosticPiece *
@@ -1218,11 +1220,11 @@ ConditionBRVisitor::VisitTerminator(const Stmt *Term,
const CFGBlock *dstBlk,
BugReport &R,
BugReporterContext &BRC) {
- const Expr *Cond = 0;
-
+ const Expr *Cond = nullptr;
+
switch (Term->getStmtClass()) {
default:
- return 0;
+ return nullptr;
case Stmt::IfStmtClass:
Cond = cast<IfStmt>(Term)->getCond();
break;
@@ -1250,7 +1252,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
Ex = Ex->IgnoreParenCasts();
switch (Ex->getStmtClass()) {
default:
- return 0;
+ return nullptr;
case Stmt::BinaryOperatorClass:
return VisitTrueTest(Cond, cast<BinaryOperator>(Ex), tookTrue, BRC,
R, N);
@@ -1264,7 +1266,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
Ex = UO->getSubExpr();
continue;
}
- return 0;
+ return nullptr;
}
}
}
@@ -1283,13 +1285,13 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex, raw_ostream &Out,
if (quotes) {
Out << '\'';
const LocationContext *LCtx = N->getLocationContext();
- const ProgramState *state = N->getState().getPtr();
+ const ProgramState *state = N->getState().get();
if (const MemRegion *R = state->getLValue(cast<VarDecl>(DR->getDecl()),
LCtx).getAsRegion()) {
if (report.isInteresting(R))
prunable = false;
else {
- const ProgramState *state = N->getState().getPtr();
+ const ProgramState *state = N->getState().get();
SVal V = state->getSVal(R);
if (report.isInteresting(V))
prunable = false;
@@ -1359,8 +1361,8 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
// both the LHS and RHS.
if (LhsString.empty() || RhsString.empty() ||
!BinaryOperator::isComparisonOp(Op))
- return 0;
-
+ return nullptr;
+
// Should we invert the strings if the LHS is not a variable name?
SmallString<256> buf;
llvm::raw_svector_ostream Out(buf);
@@ -1385,7 +1387,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
case BO_LE: Op = BO_GT; break;
case BO_GE: Op = BO_LT; break;
default:
- return 0;
+ return nullptr;
}
switch (Op) {
@@ -1435,7 +1437,7 @@ ConditionBRVisitor::VisitConditionVariable(StringRef LhsString,
else if (Ty->isIntegralOrEnumerationType())
Out << (tookTrue ? "non-zero" : "zero");
else
- return 0;
+ return nullptr;
const LocationContext *LCtx = N->getLocationContext();
PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LCtx);
@@ -1444,7 +1446,7 @@ ConditionBRVisitor::VisitConditionVariable(StringRef LhsString,
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(CondVarExpr)) {
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- const ProgramState *state = N->getState().getPtr();
+ const ProgramState *state = N->getState().get();
if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) {
if (report.isInteresting(R))
event->setPrunable(false);
@@ -1465,8 +1467,8 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
if (!VD)
- return 0;
-
+ return nullptr;
+
SmallString<256> Buf;
llvm::raw_svector_ostream Out(Buf);
@@ -1481,14 +1483,14 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
else if (VDTy->isScalarType())
Out << (tookTrue ? "not equal to 0" : "0");
else
- return 0;
-
+ return nullptr;
+
const LocationContext *LCtx = N->getLocationContext();
PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
PathDiagnosticEventPiece *event =
new PathDiagnosticEventPiece(Loc, Out.str());
- const ProgramState *state = N->getState().getPtr();
+ const ProgramState *state = N->getState().get();
if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) {
if (report.isInteresting(R))
event->setPrunable(false);
@@ -1512,7 +1514,7 @@ static bool isInStdNamespace(const Decl *D) {
while (const NamespaceDecl *Parent = dyn_cast<NamespaceDecl>(ND->getParent()))
ND = Parent;
- return ND->getName() == "std";
+ return ND->isStdNamespace();
}
@@ -1532,8 +1534,8 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC,
// Note that this will not help for any other data structure libraries, like
// TR1, Boost, or llvm/ADT.
if (Options.shouldSuppressFromCXXStandardLibrary()) {
- BR.markInvalid(getTag(), 0);
- return 0;
+ BR.markInvalid(getTag(), nullptr);
+ return nullptr;
} else {
// If the the complete 'std' suppression is not enabled, suppress reports
@@ -1545,8 +1547,8 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC,
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
const CXXRecordDecl *CD = MD->getParent();
if (CD->getName() == "list") {
- BR.markInvalid(getTag(), 0);
- return 0;
+ BR.markInvalid(getTag(), nullptr);
+ return nullptr;
}
}
@@ -1556,25 +1558,18 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC,
// std::u16string s; s += u'a';
// because we cannot reason about the internal invariants of the
// datastructure.
- const LocationContext *LCtx = N->getLocationContext();
- do {
+ for (const LocationContext *LCtx = N->getLocationContext(); LCtx;
+ LCtx = LCtx->getParent()) {
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
if (!MD)
- break;
+ continue;
const CXXRecordDecl *CD = MD->getParent();
if (CD->getName() == "basic_string") {
- BR.markInvalid(getTag(), 0);
- return 0;
- } else if (CD->getName().find("allocator") == StringRef::npos) {
- // Only keep searching if the current method is in a class with the
- // word "allocator" in its name, e.g. std::allocator or
- // allocator_traits.
- break;
+ BR.markInvalid(getTag(), nullptr);
+ return nullptr;
}
-
- LCtx = LCtx->getParent();
- } while (LCtx);
+ }
}
}
@@ -1585,12 +1580,12 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC,
while (Loc.isMacroID()) {
Loc = Loc.getSpellingLoc();
if (SM.getFilename(Loc).endswith("sys/queue.h")) {
- BR.markInvalid(getTag(), 0);
- return 0;
+ BR.markInvalid(getTag(), nullptr);
+ return nullptr;
}
}
- return 0;
+ return nullptr;
}
PathDiagnosticPiece *
@@ -1605,14 +1600,16 @@ UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N,
// We are only interested in visiting CallEnter nodes.
Optional<CallEnter> CEnter = ProgLoc.getAs<CallEnter>();
if (!CEnter)
- return 0;
+ return nullptr;
// Check if one of the arguments is the region the visitor is tracking.
CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager();
CallEventRef<> Call = CEMgr.getCaller(CEnter->getCalleeContext(), State);
unsigned Idx = 0;
- for (CallEvent::param_iterator I = Call->param_begin(),
- E = Call->param_end(); I != E; ++I, ++Idx) {
+ ArrayRef<ParmVarDecl*> parms = Call->parameters();
+
+ for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end();
+ I != E; ++I, ++Idx) {
const MemRegion *ArgReg = Call->getArgSVal(Idx).getAsRegion();
// Are we tracking the argument or its subregion?
@@ -1639,8 +1636,8 @@ UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N,
SVal BoundVal = State->getSVal(R);
if (BoundVal.isUndef() || BoundVal.isZeroConstant()) {
BR.markInteresting(CEnter->getCalleeContext());
- return 0;
+ return nullptr;
}
}
- return 0;
+ return nullptr;
}
diff --git a/lib/StaticAnalyzer/Core/CMakeLists.txt b/lib/StaticAnalyzer/Core/CMakeLists.txt
index 013f8a56b433..59a6b6fbc595 100644
--- a/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -39,21 +39,11 @@ add_clang_library(clangStaticAnalyzerCore
Store.cpp
SubEngine.cpp
SymbolManager.cpp
- )
-
-add_dependencies(clangStaticAnalyzerCore
- ClangAttrClasses
- ClangAttrList
- ClangCommentNodes
- ClangDeclNodes
- ClangDiagnosticCommon
- ClangStmtNodes
- )
-target_link_libraries(clangStaticAnalyzerCore
+ LINK_LIBS
+ clangAST
+ clangAnalysis
clangBasic
clangLex
- clangAST
- clangFrontend
- clangRewriteCore
+ clangRewrite
)
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index a3b34f4790a9..7e0670a06608 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -68,8 +68,7 @@ static bool isCallbackArg(SVal V, QualType T) {
if (const RecordType *RT = T->getAsStructureType()) {
const RecordDecl *RD = RT->getDecl();
- for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
- I != E; ++I) {
+ for (const auto *I : RD->fields()) {
QualType FieldT = I->getType();
if (FieldT->isBlockPointerType() || FieldT->isFunctionPointerType())
return true;
@@ -140,6 +139,11 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
ProgramStateRef Orig) const {
ProgramStateRef Result = (Orig ? Orig : getState());
+ // Don't invalidate anything if the callee is marked pure/const.
+ if (const Decl *callee = getDecl())
+ if (callee->hasAttr<PureAttr>() || callee->hasAttr<ConstAttr>())
+ return Result;
+
SmallVector<SVal, 8> ValuesToInvalidate;
RegionAndSymbolInvalidationTraits ETraits;
@@ -168,7 +172,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
return Result->invalidateRegions(ValuesToInvalidate, getOriginExpr(),
BlockCount, getLocationContext(),
/*CausedByPointerEscape*/ true,
- /*Symbols=*/0, this, &ETraits);
+ /*Symbols=*/nullptr, this, &ETraits);
}
ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
@@ -209,14 +213,12 @@ SVal CallEvent::getReturnValue() const {
return getSVal(E);
}
-void CallEvent::dump() const {
- dump(llvm::errs());
-}
+LLVM_DUMP_METHOD void CallEvent::dump() const { dump(llvm::errs()); }
void CallEvent::dump(raw_ostream &Out) const {
ASTContext &Ctx = getState()->getStateManager().getContext();
if (const Expr *E = getOriginExpr()) {
- E->printPretty(Out, 0, Ctx.getPrintingPolicy());
+ E->printPretty(Out, nullptr, Ctx.getPrintingPolicy());
Out << "\n";
return;
}
@@ -241,9 +243,9 @@ bool CallEvent::isCallStmt(const Stmt *S) {
QualType CallEvent::getDeclaredResultType(const Decl *D) {
assert(D);
if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D))
- return FD->getResultType();
+ return FD->getReturnType();
if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(D))
- return MD->getResultType();
+ return MD->getReturnType();
if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
// Blocks are difficult because the return type may not be stored in the
// BlockDecl itself. The AST should probably be enhanced, but for now we
@@ -256,7 +258,7 @@ QualType CallEvent::getDeclaredResultType(const Decl *D) {
if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten()) {
QualType Ty = TSI->getType();
if (const FunctionType *FT = Ty->getAs<FunctionType>())
- Ty = FT->getResultType();
+ Ty = FT->getReturnType();
if (!Ty->isDependentType())
return Ty;
}
@@ -284,14 +286,14 @@ static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx,
CallEvent::BindingsTy &Bindings,
SValBuilder &SVB,
const CallEvent &Call,
- CallEvent::param_iterator I,
- CallEvent::param_iterator E) {
+ ArrayRef<ParmVarDecl*> parameters) {
MemRegionManager &MRMgr = SVB.getRegionManager();
// If the function has fewer parameters than the call has arguments, we simply
// do not bind any values to them.
unsigned NumArgs = Call.getNumArgs();
unsigned Idx = 0;
+ ArrayRef<ParmVarDecl*>::iterator I = parameters.begin(), E = parameters.end();
for (; I != E && Idx < NumArgs; ++I, ++Idx) {
const ParmVarDecl *ParamDecl = *I;
assert(ParamDecl && "Formal parameter has no decl?");
@@ -306,21 +308,11 @@ static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx,
// FIXME: Variadic arguments are not handled at all right now.
}
-
-CallEvent::param_iterator AnyFunctionCall::param_begin() const {
- const FunctionDecl *D = getDecl();
- if (!D)
- return 0;
-
- return D->param_begin();
-}
-
-CallEvent::param_iterator AnyFunctionCall::param_end() const {
+ArrayRef<ParmVarDecl*> AnyFunctionCall::parameters() const {
const FunctionDecl *D = getDecl();
if (!D)
- return 0;
-
- return D->param_end();
+ return None;
+ return D->parameters();
}
void AnyFunctionCall::getInitialStackFrameContents(
@@ -329,7 +321,7 @@ void AnyFunctionCall::getInitialStackFrameContents(
const FunctionDecl *D = cast<FunctionDecl>(CalleeCtx->getDecl());
SValBuilder &SVB = getState()->getStateManager().getSValBuilder();
addParameterValuesToBindings(CalleeCtx, Bindings, SVB, *this,
- D->param_begin(), D->param_end());
+ D->parameters());
}
bool AnyFunctionCall::argumentsMayEscape() const {
@@ -389,7 +381,7 @@ bool AnyFunctionCall::argumentsMayEscape() const {
}
-const FunctionDecl *SimpleCall::getDecl() const {
+const FunctionDecl *SimpleFunctionCall::getDecl() const {
const FunctionDecl *D = getOriginExpr()->getDirectCallee();
if (D)
return D;
@@ -484,7 +476,7 @@ RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const {
// that ExprEngine can decide what to do with it.
if (DynType.canBeASubClass())
return RuntimeDefinition(Definition, R->StripCasts());
- return RuntimeDefinition(Definition, /*DispatchRegion=*/0);
+ return RuntimeDefinition(Definition, /*DispatchRegion=*/nullptr);
}
void CXXInstanceCall::getInitialStackFrameContents(
@@ -550,18 +542,11 @@ const BlockDataRegion *BlockCall::getBlockRegion() const {
return dyn_cast_or_null<BlockDataRegion>(DataReg);
}
-CallEvent::param_iterator BlockCall::param_begin() const {
- const BlockDecl *D = getBlockDecl();
+ArrayRef<ParmVarDecl*> BlockCall::parameters() const {
+ const BlockDecl *D = getDecl();
if (!D)
- return 0;
- return D->param_begin();
-}
-
-CallEvent::param_iterator BlockCall::param_end() const {
- const BlockDecl *D = getBlockDecl();
- if (!D)
- return 0;
- return D->param_end();
+ return nullptr;
+ return D->parameters();
}
void BlockCall::getExtraInvalidatedValues(ValueList &Values) const {
@@ -575,7 +560,7 @@ void BlockCall::getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
const BlockDecl *D = cast<BlockDecl>(CalleeCtx->getDecl());
SValBuilder &SVB = getState()->getStateManager().getSValBuilder();
addParameterValuesToBindings(CalleeCtx, Bindings, SVB, *this,
- D->param_begin(), D->param_end());
+ D->parameters());
}
@@ -604,8 +589,6 @@ void CXXConstructorCall::getInitialStackFrameContents(
}
}
-
-
SVal CXXDestructorCall::getCXXThisVal() const {
if (Data)
return loc::MemRegionVal(DtorDataTy::getFromOpaqueValue(Data).getPointer());
@@ -621,21 +604,11 @@ RuntimeDefinition CXXDestructorCall::getRuntimeDefinition() const {
return CXXInstanceCall::getRuntimeDefinition();
}
-
-CallEvent::param_iterator ObjCMethodCall::param_begin() const {
+ArrayRef<ParmVarDecl*> ObjCMethodCall::parameters() const {
const ObjCMethodDecl *D = getDecl();
if (!D)
- return 0;
-
- return D->param_begin();
-}
-
-CallEvent::param_iterator ObjCMethodCall::param_end() const {
- const ObjCMethodDecl *D = getDecl();
- if (!D)
- return 0;
-
- return D->param_end();
+ return ArrayRef<ParmVarDecl*>();
+ return D->parameters();
}
void
@@ -694,13 +667,13 @@ SourceRange ObjCMethodCall::getSourceRange() const {
typedef llvm::PointerIntPair<const PseudoObjectExpr *, 2> ObjCMessageDataTy;
const PseudoObjectExpr *ObjCMethodCall::getContainingPseudoObjectExpr() const {
- assert(Data != 0 && "Lazy lookup not yet performed.");
+ assert(Data && "Lazy lookup not yet performed.");
assert(getMessageKind() != OCM_Message && "Explicit message send.");
return ObjCMessageDataTy::getFromOpaqueValue(Data).getPointer();
}
ObjCMessageKind ObjCMethodCall::getMessageKind() const {
- if (Data == 0) {
+ if (!Data) {
// Find the parent, ignoring implicit casts.
ParentMap &PM = getLocationContext()->getParentMap();
@@ -738,7 +711,7 @@ ObjCMessageKind ObjCMethodCall::getMessageKind() const {
}
const_cast<ObjCMethodCall *>(this)->Data
- = ObjCMessageDataTy(0, 1).getOpaqueValue();
+ = ObjCMessageDataTy(nullptr, 1).getOpaqueValue();
assert(getMessageKind() == OCM_Message);
return OCM_Message;
}
@@ -774,7 +747,7 @@ bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
// Find the first declaration in the class hierarchy that declares
// the selector.
- ObjCMethodDecl *D = 0;
+ ObjCMethodDecl *D = nullptr;
while (true) {
D = IDecl->lookupMethod(Sel, true);
@@ -813,10 +786,10 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
if (E->isInstanceMessage()) {
// Find the the receiver type.
- const ObjCObjectPointerType *ReceiverT = 0;
+ const ObjCObjectPointerType *ReceiverT = nullptr;
bool CanBeSubClassed = false;
QualType SupersType = E->getSuperType();
- const MemRegion *Receiver = 0;
+ const MemRegion *Receiver = nullptr;
if (!SupersType.isNull()) {
// Super always means the type of immediate predecessor to the method
@@ -865,14 +838,22 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
Optional<const ObjCMethodDecl *> &Val = PMC[std::make_pair(IDecl, Sel)];
// Query lookupPrivateMethod() if the cache does not hit.
- if (!Val.hasValue())
+ if (!Val.hasValue()) {
Val = IDecl->lookupPrivateMethod(Sel);
+ // If the method is a property accessor, we should try to "inline" it
+ // even if we don't actually have an implementation.
+ if (!*Val)
+ if (const ObjCMethodDecl *CompileTimeMD = E->getMethodDecl())
+ if (CompileTimeMD->isPropertyAccessor())
+ Val = IDecl->lookupInstanceMethod(Sel);
+ }
+
const ObjCMethodDecl *MD = Val.getValue();
if (CanBeSubClassed)
return RuntimeDefinition(MD, Receiver);
else
- return RuntimeDefinition(MD, 0);
+ return RuntimeDefinition(MD, nullptr);
}
} else {
@@ -888,13 +869,24 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
return RuntimeDefinition();
}
+bool ObjCMethodCall::argumentsMayEscape() const {
+ if (isInSystemHeader() && !isInstanceMessage()) {
+ Selector Sel = getSelector();
+ if (Sel.getNumArgs() == 1 &&
+ Sel.getIdentifierInfoForSlot(0)->isStr("valueWithPointer"))
+ return true;
+ }
+
+ return CallEvent::argumentsMayEscape();
+}
+
void ObjCMethodCall::getInitialStackFrameContents(
const StackFrameContext *CalleeCtx,
BindingsTy &Bindings) const {
const ObjCMethodDecl *D = cast<ObjCMethodDecl>(CalleeCtx->getDecl());
SValBuilder &SVB = getState()->getStateManager().getSValBuilder();
addParameterValuesToBindings(CalleeCtx, Bindings, SVB, *this,
- D->param_begin(), D->param_end());
+ D->parameters());
SVal SelfVal = getReceiverSVal();
if (!SelfVal.isUnknown()) {
@@ -923,7 +915,7 @@ CallEventManager::getSimpleCall(const CallExpr *CE, ProgramStateRef State,
// Otherwise, it's a normal function call, static member function call, or
// something we can't reason about.
- return create<FunctionCall>(CE, State, LCtx);
+ return create<SimpleFunctionCall>(CE, State, LCtx);
}
diff --git a/lib/StaticAnalyzer/Core/Checker.cpp b/lib/StaticAnalyzer/Core/Checker.cpp
index 07e0aac2d429..1a3965acaf42 100644
--- a/lib/StaticAnalyzer/Core/Checker.cpp
+++ b/lib/StaticAnalyzer/Core/Checker.cpp
@@ -18,8 +18,23 @@ using namespace clang;
using namespace ento;
StringRef CheckerBase::getTagDescription() const {
- // FIXME: We want to return the package + name of the checker here.
- return "A Checker";
+ return getCheckName().getName();
+}
+
+CheckName CheckerBase::getCheckName() const { return Name; }
+
+CheckerProgramPointTag::CheckerProgramPointTag(StringRef CheckerName,
+ StringRef Msg)
+ : SimpleProgramPointTag(CheckerName, Msg) {}
+
+CheckerProgramPointTag::CheckerProgramPointTag(const CheckerBase *Checker,
+ StringRef Msg)
+ : SimpleProgramPointTag(Checker->getCheckName().getName(), Msg) {}
+
+raw_ostream& clang::ento::operator<<(raw_ostream &Out,
+ const CheckerBase &Checker) {
+ Out << Checker.getCheckName().getName();
+ return Out;
}
void Checker<check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index c1ae7e9d812c..2684cc78be75 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -58,7 +58,7 @@ void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,
assert(D);
unsigned DeclKind = D->getKind();
- CachedDeclCheckers *checkers = 0;
+ CachedDeclCheckers *checkers = nullptr;
CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind);
if (CCI != CachedDeclCheckersMap.end()) {
checkers = &(CCI->second);
@@ -109,7 +109,7 @@ static void expandGraphWithCheckers(CHECK_CTX checkCtx,
const ExplodedNodeSet *PrevSet = &Src;
for (; I != E; ++I) {
- ExplodedNodeSet *CurrSet = 0;
+ ExplodedNodeSet *CurrSet = nullptr;
if (I+1 == E)
CurrSet = &Dst;
else {
@@ -477,7 +477,7 @@ CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
// If any checker declares the state infeasible (or if it starts that way),
// bail out.
if (!state)
- return NULL;
+ return nullptr;
state = RegionChangesCheckers[i].CheckFn(state, invalidated,
ExplicitRegions, Regions, Call);
}
@@ -491,7 +491,7 @@ CheckerManager::runCheckersForPointerEscape(ProgramStateRef State,
const CallEvent *Call,
PointerEscapeKind Kind,
RegionAndSymbolInvalidationTraits *ETraits) {
- assert((Call != NULL ||
+ assert((Call != nullptr ||
(Kind != PSK_DirectEscapeOnCall &&
Kind != PSK_IndirectEscapeOnCall)) &&
"Call must not be NULL when escaping on call");
@@ -499,7 +499,7 @@ CheckerManager::runCheckersForPointerEscape(ProgramStateRef State,
// If any checker declares the state infeasible (or if it starts that
// way), bail out.
if (!State)
- return NULL;
+ return nullptr;
State = PointerEscapeCheckers[i](State, Escaped, Call, Kind, ETraits);
}
return State;
@@ -513,7 +513,7 @@ CheckerManager::runCheckersForEvalAssume(ProgramStateRef state,
// If any checker declares the state infeasible (or if it starts that way),
// bail out.
if (!state)
- return NULL;
+ return nullptr;
state = EvalAssumeCheckers[i](state, Cond, Assumption);
}
return state;
diff --git a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
index 47299030cc45..b64e30b31007 100644
--- a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
@@ -45,7 +45,7 @@ static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers,
const llvm::StringMap<size_t> &packageSizes,
CheckerOptInfo &opt, CheckerInfoSet &collected) {
// Use a binary search to find the possible start of the package.
- CheckerRegistry::CheckerInfo packageInfo(NULL, opt.getName(), "");
+ CheckerRegistry::CheckerInfo packageInfo(nullptr, opt.getName(), "");
CheckerRegistry::CheckerInfoList::const_iterator e = checkers.end();
CheckerRegistry::CheckerInfoList::const_iterator i =
std::lower_bound(checkers.begin(), e, packageInfo, checkerNameLT);
@@ -84,10 +84,10 @@ void CheckerRegistry::addChecker(InitializationFunction fn, StringRef name,
// Record the presence of the checker in its packages.
StringRef packageName, leafName;
- llvm::tie(packageName, leafName) = name.rsplit(PackageSeparator);
+ std::tie(packageName, leafName) = name.rsplit(PackageSeparator);
while (!leafName.empty()) {
Packages[packageName] += 1;
- llvm::tie(packageName, leafName) = packageName.rsplit(PackageSeparator);
+ std::tie(packageName, leafName) = packageName.rsplit(PackageSeparator);
}
}
@@ -106,6 +106,7 @@ void CheckerRegistry::initializeManager(CheckerManager &checkerMgr,
// Initialize the CheckerManager with all enabled checkers.
for (CheckerInfoSet::iterator
i = enabledCheckers.begin(), e = enabledCheckers.end(); i != e; ++i) {
+ checkerMgr.setCurrentCheckName(CheckName((*i)->FullName));
(*i)->Initialize(checkerMgr);
}
}
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp
index b09b2c2ddfab..4623c358a9e2 100644
--- a/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -12,8 +12,6 @@
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "CoreEngine"
-
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
#include "clang/AST/Expr.h"
#include "clang/AST/StmtCXX.h"
@@ -26,6 +24,8 @@
using namespace clang;
using namespace ento;
+#define DEBUG_TYPE "CoreEngine"
+
STATISTIC(NumSteps,
"The # of steps executed.");
STATISTIC(NumReachedMaxSteps,
@@ -43,22 +43,22 @@ namespace {
class DFS : public WorkList {
SmallVector<WorkListUnit,20> Stack;
public:
- virtual bool hasWork() const {
+ bool hasWork() const override {
return !Stack.empty();
}
- virtual void enqueue(const WorkListUnit& U) {
+ void enqueue(const WorkListUnit& U) override {
Stack.push_back(U);
}
- virtual WorkListUnit dequeue() {
+ WorkListUnit dequeue() override {
assert (!Stack.empty());
const WorkListUnit& U = Stack.back();
Stack.pop_back(); // This technically "invalidates" U, but we are fine.
return U;
}
-
- virtual bool visitItemsInWorkList(Visitor &V) {
+
+ bool visitItemsInWorkList(Visitor &V) override {
for (SmallVectorImpl<WorkListUnit>::iterator
I = Stack.begin(), E = Stack.end(); I != E; ++I) {
if (V.visit(*I))
@@ -71,21 +71,21 @@ public:
class BFS : public WorkList {
std::deque<WorkListUnit> Queue;
public:
- virtual bool hasWork() const {
+ bool hasWork() const override {
return !Queue.empty();
}
- virtual void enqueue(const WorkListUnit& U) {
+ void enqueue(const WorkListUnit& U) override {
Queue.push_back(U);
}
- virtual WorkListUnit dequeue() {
+ WorkListUnit dequeue() override {
WorkListUnit U = Queue.front();
Queue.pop_front();
return U;
}
-
- virtual bool visitItemsInWorkList(Visitor &V) {
+
+ bool visitItemsInWorkList(Visitor &V) override {
for (std::deque<WorkListUnit>::iterator
I = Queue.begin(), E = Queue.end(); I != E; ++I) {
if (V.visit(*I))
@@ -109,18 +109,18 @@ namespace {
std::deque<WorkListUnit> Queue;
SmallVector<WorkListUnit,20> Stack;
public:
- virtual bool hasWork() const {
+ bool hasWork() const override {
return !Queue.empty() || !Stack.empty();
}
- virtual void enqueue(const WorkListUnit& U) {
+ void enqueue(const WorkListUnit& U) override {
if (U.getNode()->getLocation().getAs<BlockEntrance>())
Queue.push_front(U);
else
Stack.push_back(U);
}
- virtual WorkListUnit dequeue() {
+ WorkListUnit dequeue() override {
// Process all basic blocks to completion.
if (!Stack.empty()) {
const WorkListUnit& U = Stack.back();
@@ -135,7 +135,7 @@ namespace {
Queue.pop_front();
return U;
}
- virtual bool visitItemsInWorkList(Visitor &V) {
+ bool visitItemsInWorkList(Visitor &V) override {
for (SmallVectorImpl<WorkListUnit>::iterator
I = Stack.begin(), E = Stack.end(); I != E; ++I) {
if (V.visit(*I))
@@ -192,9 +192,9 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
if (!InitState)
// Generate the root.
- generateNode(StartLoc, SubEng.getInitialState(L), 0);
+ generateNode(StartLoc, SubEng.getInitialState(L), nullptr);
else
- generateNode(StartLoc, InitState, 0);
+ generateNode(StartLoc, InitState, nullptr);
}
// Check if we have a steps limit
@@ -532,11 +532,16 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N,
return;
}
+ if ((*Block)[Idx].getKind() == CFGElement::NewAllocator) {
+ WList->enqueue(N, Block, Idx+1);
+ return;
+ }
+
// At this point, we know we're processing a normal statement.
CFGStmt CS = (*Block)[Idx].castAs<CFGStmt>();
PostStmt Loc(CS.getStmt(), N->getLocationContext());
- if (Loc == N->getLocation()) {
+ if (Loc == N->getLocation().withTag(nullptr)) {
// Note: 'N' should be a fresh node because otherwise it shouldn't be
// a member of Deferred.
WList->enqueue(N, Block, Idx+1);
@@ -562,7 +567,7 @@ ExplodedNode *CoreEngine::generateCallExitBeginNode(ExplodedNode *N) {
bool isNew;
ExplodedNode *Node = G->getNode(Loc, N->getState(), false, &isNew);
Node->addPredecessor(N, *G);
- return isNew ? Node : 0;
+ return isNew ? Node : nullptr;
}
@@ -611,7 +616,7 @@ ExplodedNode* NodeBuilder::generateNodeImpl(const ProgramPoint &Loc,
Frontier.erase(FromN);
if (!IsNew)
- return 0;
+ return nullptr;
if (!MarkAsSink)
Frontier.Add(N);
@@ -635,7 +640,7 @@ ExplodedNode *BranchNodeBuilder::generateNode(ProgramStateRef State,
ExplodedNode *NodePred) {
// If the branch has been marked infeasible we should not generate a node.
if (!isFeasible(branch))
- return NULL;
+ return nullptr;
ProgramPoint Loc = BlockEdge(C.Block, branch ? DstT:DstF,
NodePred->getLocationContext());
@@ -654,7 +659,7 @@ IndirectGotoNodeBuilder::generateNode(const iterator &I,
Succ->addPredecessor(Pred, *Eng.G);
if (!IsNew)
- return 0;
+ return nullptr;
if (!IsSink)
Eng.WList->enqueue(Succ);
@@ -673,7 +678,7 @@ SwitchNodeBuilder::generateCaseStmtNode(const iterator &I,
false, &IsNew);
Succ->addPredecessor(Pred, *Eng.G);
if (!IsNew)
- return 0;
+ return nullptr;
Eng.WList->enqueue(Succ);
return Succ;
@@ -690,8 +695,8 @@ SwitchNodeBuilder::generateDefaultCaseNode(ProgramStateRef St,
// Sanity check for default blocks that are unreachable and not caught
// by earlier stages.
if (!DefaultBlock)
- return NULL;
-
+ return nullptr;
+
bool IsNew;
ExplodedNode *Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock,
Pred->getLocationContext()), St,
@@ -699,7 +704,7 @@ SwitchNodeBuilder::generateDefaultCaseNode(ProgramStateRef St,
Succ->addPredecessor(Pred, *Eng.G);
if (!IsNew)
- return 0;
+ return nullptr;
if (!IsSink)
Eng.WList->enqueue(Succ);
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index 7b133f6bf645..ae5a4cc8b4aa 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -54,7 +54,8 @@ static const Stmt *ignoreTransparentExprs(const Stmt *S) {
EnvironmentEntry::EnvironmentEntry(const Stmt *S, const LocationContext *L)
: std::pair<const Stmt *,
const StackFrameContext *>(ignoreTransparentExprs(S),
- L ? L->getCurrentStackFrame() : 0) {}
+ L ? L->getCurrentStackFrame()
+ : nullptr) {}
SVal Environment::lookupExpr(const EnvironmentEntry &E) const {
const SVal* X = ExprBindings.lookup(E);
@@ -123,11 +124,11 @@ class MarkLiveCallback : public SymbolVisitor {
SymbolReaper &SymReaper;
public:
MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {}
- bool VisitSymbol(SymbolRef sym) {
+ bool VisitSymbol(SymbolRef sym) override {
SymReaper.markLive(sym);
return true;
}
- bool VisitMemRegion(const MemRegion *R) {
+ bool VisitMemRegion(const MemRegion *R) override {
SymReaper.markLive(R);
return true;
}
@@ -204,11 +205,12 @@ void Environment::print(raw_ostream &Out, const char *NL,
}
const Stmt *S = En.getStmt();
-
+ assert(S != nullptr && "Expected non-null Stmt");
+
Out << " (" << (const void*) En.getLocationContext() << ','
<< (const void*) S << ") ";
LangOptions LO; // FIXME.
- S->printPretty(Out, 0, PrintingPolicy(LO));
+ S->printPretty(Out, nullptr, PrintingPolicy(LO));
Out << " : " << I.getData();
}
}
diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index e9c4a35de6e8..1c9a282b8298 100644
--- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -34,7 +34,7 @@ using namespace ento;
ExplodedNode::Auditor::~Auditor() {}
#ifndef NDEBUG
-static ExplodedNode::Auditor* NodeAuditor = 0;
+static ExplodedNode::Auditor* NodeAuditor = nullptr;
#endif
void ExplodedNode::SetAuditor(ExplodedNode::Auditor* A) {
@@ -90,8 +90,9 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
// (7) The LocationContext is the same as the predecessor.
// (8) Expressions that are *not* lvalue expressions.
// (9) The PostStmt isn't for a non-consumed Stmt or Expr.
- // (10) The successor is not a CallExpr StmtPoint (so that we would
- // be able to find it when retrying a call with no inlining).
+ // (10) The successor is neither a CallExpr StmtPoint nor a CallEnter or
+ // PreImplicitCall (so that we would be able to find it when retrying a
+ // call with no inlining).
// FIXME: It may be safe to reclaim PreCall and PostCall nodes as well.
// Conditions 1 and 2.
@@ -153,6 +154,10 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
if (CallEvent::isCallStmt(SP->getStmt()))
return false;
+ // Condition 10, continuation.
+ if (SuccLoc.getAs<CallEnter>() || SuccLoc.getAs<PreImplicitCall>())
+ return false;
+
return true;
}
@@ -271,11 +276,11 @@ unsigned ExplodedNode::NodeGroup::size() const {
ExplodedNode * const *ExplodedNode::NodeGroup::begin() const {
if (getFlag())
- return 0;
+ return nullptr;
const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P);
if (Storage.isNull())
- return 0;
+ return nullptr;
if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>())
return V->begin();
return Storage.getAddrOfPtr1();
@@ -283,11 +288,11 @@ ExplodedNode * const *ExplodedNode::NodeGroup::begin() const {
ExplodedNode * const *ExplodedNode::NodeGroup::end() const {
if (getFlag())
- return 0;
+ return nullptr;
const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P);
if (Storage.isNull())
- return 0;
+ return nullptr;
if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>())
return V->end();
return Storage.getAddrOfPtr1() + 1;
@@ -299,7 +304,7 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
bool* IsNew) {
// Profile 'State' to determine if we already have an existing node.
llvm::FoldingSetNodeID profile;
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
NodeTy::Profile(profile, L, State, IsSink);
NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos);
@@ -337,7 +342,7 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
InterExplodedGraphMap *InverseMap) const{
if (Nodes.empty())
- return 0;
+ return nullptr;
typedef llvm::DenseSet<const ExplodedNode*> Pass1Ty;
Pass1Ty Pass1;
@@ -380,7 +385,7 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
// We didn't hit a root? Return with a null pointer for the new graph.
if (WL2.empty())
- return 0;
+ return nullptr;
// Create an empty graph.
ExplodedGraph* G = MakeEmptyGraph();
@@ -395,7 +400,8 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
// Create the corresponding node in the new graph and record the mapping
// from the old node to the new node.
- ExplodedNode *NewN = G->getNode(N->getLocation(), N->State, N->isSink(), 0);
+ ExplodedNode *NewN = G->getNode(N->getLocation(), N->State, N->isSink(),
+ nullptr);
Pass2[N] = NewN;
// Also record the reverse mapping from the new node to the old node.
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 9907d0cbf9b8..4e4095c5e0d8 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -13,8 +13,6 @@
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "ExprEngine"
-
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "PrettyStackTraceLocationContext.h"
#include "clang/AST/CharUnits.h"
@@ -40,6 +38,8 @@ using namespace clang;
using namespace ento;
using llvm::APSInt;
+#define DEBUG_TYPE "ExprEngine"
+
STATISTIC(NumRemoveDeadBindings,
"The # of times RemoveDeadBindings is called");
STATISTIC(NumMaxBlockCountReached,
@@ -55,6 +55,8 @@ STATISTIC(NumTimesRetriedWithoutInlining,
// Engine construction and deletion.
//===----------------------------------------------------------------------===//
+static const char* TagProviderName = "ExprEngine";
+
ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled,
SetOfConstDecls *VisitedCalleesIn,
FunctionSummariesTy *FS,
@@ -68,7 +70,7 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled,
this),
SymMgr(StateMgr.getSymbolManager()),
svalBuilder(StateMgr.getSValBuilder()),
- currStmtIdx(0), currBldrCtx(0),
+ currStmtIdx(0), currBldrCtx(nullptr),
ObjCNoRet(mgr.getASTContext()),
ObjCGCEnabled(gcEnabled), BR(mgr, *this),
VisitedCallees(VisitedCalleesIn),
@@ -118,7 +120,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
SVal V = state->getSVal(loc::MemRegionVal(R));
SVal Constraint_untested = evalBinOp(state, BO_GT, V,
svalBuilder.makeZeroVal(T),
- getContext().IntTy);
+ svalBuilder.getConditionType());
Optional<DefinedOrUnknownSVal> Constraint =
Constraint_untested.getAs<DefinedOrUnknownSVal>();
@@ -153,7 +155,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
// top-level function. This is our starting assumption for
// analyzing an "open" program.
const StackFrameContext *SFC = InitLoc->getCurrentStackFrame();
- if (SFC->getParent() == 0) {
+ if (SFC->getParent() == nullptr) {
loc::MemRegionVal L = svalBuilder.getCXXThis(MD, SFC);
SVal V = state->getSVal(L);
if (Optional<Loc> LV = V.getAs<Loc>()) {
@@ -209,7 +211,7 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State,
// Create a temporary object region for the inner expression (which may have
// a more derived type) and bind the value into it.
- const TypedValueRegion *TR = NULL;
+ const TypedValueRegion *TR = nullptr;
if (const MaterializeTemporaryExpr *MT =
dyn_cast<MaterializeTemporaryExpr>(Result)) {
StorageDuration SD = MT->getStorageDuration();
@@ -286,6 +288,10 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
case CFGElement::Initializer:
ProcessInitializer(E.castAs<CFGInitializer>().getInitializer(), Pred);
return;
+ case CFGElement::NewAllocator:
+ ProcessNewAllocator(E.castAs<CFGNewAllocator>().getAllocatorExpr(),
+ Pred);
+ return;
case CFGElement::AutomaticObjectDtor:
case CFGElement::DeleteDtor:
case CFGElement::BaseDtor:
@@ -329,7 +335,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
const Stmt *DiagnosticStmt,
ProgramPoint::Kind K) {
assert((K == ProgramPoint::PreStmtPurgeDeadSymbolsKind ||
- ReferenceStmt == 0 || isa<ReturnStmt>(ReferenceStmt))
+ ReferenceStmt == nullptr || isa<ReturnStmt>(ReferenceStmt))
&& "PostStmt is not generally supported by the SymbolReaper yet");
assert(LC && "Must pass the current (or expiring) LocationContext");
@@ -350,7 +356,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
LC = LC->getParent();
}
- const StackFrameContext *SFC = LC ? LC->getCurrentStackFrame() : 0;
+ const StackFrameContext *SFC = LC ? LC->getCurrentStackFrame() : nullptr;
SymbolReaper SymReaper(SFC, ReferenceStmt, SymMgr, getStoreManager());
getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper);
@@ -362,7 +368,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
// Process any special transfer function for dead symbols.
// A tag to track convenience transitions, which can be removed at cleanup.
- static SimpleProgramPointTag cleanupTag("ExprEngine : Clean Node");
+ static SimpleProgramPointTag cleanupTag(TagProviderName, "Clean Node");
if (!SymReaper.hasDeadSymbols()) {
// Generate a CleanedNode that has the environment and store cleaned
// up. Since no symbols are dead, we can optimize and not clean out
@@ -547,6 +553,25 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
}
+void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE,
+ ExplodedNode *Pred) {
+ ExplodedNodeSet Dst;
+ AnalysisManager &AMgr = getAnalysisManager();
+ AnalyzerOptions &Opts = AMgr.options;
+ // TODO: We're not evaluating allocators for all cases just yet as
+ // we're not handling the return value correctly, which causes false
+ // positives when the alpha.cplusplus.NewDeleteLeaks check is on.
+ if (Opts.mayInlineCXXAllocator())
+ VisitCXXNewAllocatorCall(NE, Pred, Dst);
+ else {
+ NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+ const LocationContext *LCtx = Pred->getLocationContext();
+ PostImplicitCall PP(NE->getOperatorNew(), NE->getLocStart(), LCtx);
+ Bldr.generateNode(PP, Pred->getState(), Pred);
+ }
+ Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
+}
+
void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
@@ -598,7 +623,6 @@ void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor,
void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
const LocationContext *LCtx = Pred->getLocationContext();
- ProgramStateRef State = Pred->getState();
const CXXDestructorDecl *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl());
Loc ThisPtr = getSValBuilder().getCXXThis(CurDtor,
@@ -640,7 +664,7 @@ void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
// FIXME: Inlining of temporary destructors is not supported yet anyway, so we
// just put a NULL region for now. This will need to be changed later.
- VisitCXXDestructor(varType, NULL, D.getBindTemporaryExpr(),
+ VisitCXXDestructor(varType, nullptr, D.getBindTemporaryExpr(),
/*IsBase=*/ false, Pred, Dst);
}
@@ -664,8 +688,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::MSPropertyRefExprClass:
case Stmt::CXXUnresolvedConstructExprClass:
case Stmt::DependentScopeDeclRefExprClass:
- case Stmt::UnaryTypeTraitExprClass:
- case Stmt::BinaryTypeTraitExprClass:
case Stmt::TypeTraitExprClass:
case Stmt::ArrayTypeTraitExprClass:
case Stmt::ExpressionTraitExprClass:
@@ -677,6 +699,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::FunctionParmPackExprClass:
case Stmt::SEHTryStmtClass:
case Stmt::SEHExceptStmtClass:
+ case Stmt::SEHLeaveStmtClass:
case Stmt::LambdaExprClass:
case Stmt::SEHFinallyStmtClass: {
const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState());
@@ -709,6 +732,20 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Expr::MSDependentExistsStmtClass:
case Stmt::CapturedStmtClass:
case Stmt::OMPParallelDirectiveClass:
+ case Stmt::OMPSimdDirectiveClass:
+ case Stmt::OMPForDirectiveClass:
+ case Stmt::OMPSectionsDirectiveClass:
+ case Stmt::OMPSectionDirectiveClass:
+ case Stmt::OMPSingleDirectiveClass:
+ case Stmt::OMPMasterDirectiveClass:
+ case Stmt::OMPCriticalDirectiveClass:
+ case Stmt::OMPParallelForDirectiveClass:
+ case Stmt::OMPParallelSectionsDirectiveClass:
+ case Stmt::OMPTaskDirectiveClass:
+ case Stmt::OMPTaskyieldDirectiveClass:
+ case Stmt::OMPBarrierDirectiveClass:
+ case Stmt::OMPTaskwaitDirectiveClass:
+ case Stmt::OMPFlushDirectiveClass:
llvm_unreachable("Stmt should not be in analyzer evaluation loop");
case Stmt::ObjCSubscriptRefExprClass:
@@ -848,7 +885,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
it != et; ++it) {
ExplodedNode *N = *it;
const LocationContext *LCtx = N->getLocationContext();
- SVal result = svalBuilder.conjureSymbolVal(0, Ex, LCtx, resultType,
+ SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx,
+ resultType,
currBldrCtx->blockCount());
ProgramStateRef state = N->getState()->BindExpr(Ex, LCtx, result);
Bldr2.generateNode(S, N, state);
@@ -928,7 +966,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
ProgramStateRef NewState =
createTemporaryRegionIfNeeded(State, LCtx, OCE->getArg(0));
if (NewState != State) {
- Pred = Bldr.generateNode(OCE, Pred, NewState, /*Tag=*/0,
+ Pred = Bldr.generateNode(OCE, Pred, NewState, /*Tag=*/nullptr,
ProgramPoint::PreStmtKind);
// Did we cache out?
if (!Pred)
@@ -1187,14 +1225,14 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
const StackFrameContext *CalleeSF = CalleeLC->getCurrentStackFrame();
const StackFrameContext *CallerSF = CalleeSF->getParent()->getCurrentStackFrame();
assert(CalleeSF && CallerSF);
- ExplodedNode *BeforeProcessingCall = 0;
+ ExplodedNode *BeforeProcessingCall = nullptr;
const Stmt *CE = CalleeSF->getCallSite();
// Find the first node before we started processing the call expression.
while (N) {
ProgramPoint L = N->getLocation();
BeforeProcessingCall = N;
- N = N->pred_empty() ? NULL : *(N->pred_begin());
+ N = N->pred_empty() ? nullptr : *(N->pred_begin());
// Skip the nodes corresponding to the inlined code.
if (L.getLocationContext()->getCurrentStackFrame() != CallerSF)
@@ -1253,7 +1291,7 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
// FIXME: Refactor this into a checker.
if (nodeBuilder.getContext().blockCount() >= AMgr.options.maxBlockVisitOnPath) {
- static SimpleProgramPointTag tag("ExprEngine : Block count exceeded");
+ static SimpleProgramPointTag tag(TagProviderName, "Block count exceeded");
const ExplodedNode *Sink =
nodeBuilder.generateSink(Pred->getState(), Pred, &tag);
@@ -1329,6 +1367,33 @@ static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr,
return state->getSVal(Ex, LCtx);
}
+#ifndef NDEBUG
+static const Stmt *getRightmostLeaf(const Stmt *Condition) {
+ while (Condition) {
+ const BinaryOperator *BO = dyn_cast<BinaryOperator>(Condition);
+ if (!BO || !BO->isLogicalOp()) {
+ return Condition;
+ }
+ Condition = BO->getRHS()->IgnoreParens();
+ }
+ return nullptr;
+}
+#endif
+
+// Returns the condition the branch at the end of 'B' depends on and whose value
+// has been evaluated within 'B'.
+// In most cases, the terminator condition of 'B' will be evaluated fully in
+// the last statement of 'B'; in those cases, the resolved condition is the
+// given 'Condition'.
+// If the condition of the branch is a logical binary operator tree, the CFG is
+// optimized: in that case, we know that the expression formed by all but the
+// rightmost leaf of the logical binary operator tree must be true, and thus
+// the branch condition is at this point equivalent to the truth value of that
+// rightmost leaf; the CFG block thus only evaluates this rightmost leaf
+// expression in its final statement. As the full condition in that case was
+// not evaluated, and is thus not in the SVal cache, we need to use that leaf
+// expression to evaluate the truth value of the condition in the current state
+// space.
static const Stmt *ResolveCondition(const Stmt *Condition,
const CFGBlock *B) {
if (const Expr *Ex = dyn_cast<Expr>(Condition))
@@ -1338,6 +1403,12 @@ static const Stmt *ResolveCondition(const Stmt *Condition,
if (!BO || !BO->isLogicalOp())
return Condition;
+ // FIXME: This is a workaround until we handle temporary destructor branches
+ // correctly; currently, temporary destructor branches lead to blocks that
+ // only have a terminator (and no statements). These blocks violate the
+ // invariant this function assumes.
+ if (B->getTerminator().isTemporaryDtorsBranch()) return Condition;
+
// For logical operations, we still have the case where some branches
// use the traditional "merge" approach and others sink the branch
// directly into the basic blocks representing the logical operation.
@@ -1352,18 +1423,9 @@ static const Stmt *ResolveCondition(const Stmt *Condition,
Optional<CFGStmt> CS = Elem.getAs<CFGStmt>();
if (!CS)
continue;
- if (CS->getStmt() != Condition)
- break;
- return Condition;
- }
-
- assert(I != E);
-
- while (Condition) {
- BO = dyn_cast<BinaryOperator>(Condition);
- if (!BO || !BO->isLogicalOp())
- return Condition;
- Condition = BO->getRHS()->IgnoreParens();
+ const Stmt *LastStmt = CS->getStmt();
+ assert(LastStmt == Condition || LastStmt == getRightmostLeaf(Condition));
+ return LastStmt;
}
llvm_unreachable("could not resolve condition");
}
@@ -1443,7 +1505,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
DefinedSVal V = X.castAs<DefinedSVal>();
ProgramStateRef StTrue, StFalse;
- tie(StTrue, StFalse) = PrevState->assume(V);
+ std::tie(StTrue, StFalse) = PrevState->assume(V);
// Process the true branch.
if (builder.isFeasible(true)) {
@@ -1461,7 +1523,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
builder.markInfeasible(false);
}
}
- currBldrCtx = 0;
+ currBldrCtx = nullptr;
}
/// The GDM component containing the set of global variables which have been
@@ -1490,7 +1552,7 @@ void ExprEngine::processStaticInitializer(const DeclStmt *DS,
builder.generateNode(state, initHasRun, Pred);
builder.markInfeasible(!initHasRun);
- currBldrCtx = 0;
+ currBldrCtx = nullptr;
}
/// processIndirectGoto - Called by CoreEngine. Used to generate successor
@@ -1631,7 +1693,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
}
else {
defaultIsFeasible = false;
- DefaultSt = NULL;
+ DefaultSt = nullptr;
}
}
@@ -1692,7 +1754,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
V = UnknownVal();
}
- Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0,
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr,
ProgramPoint::PostLValueKind);
return;
}
@@ -1704,7 +1766,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
}
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
SVal V = svalBuilder.getFunctionPointer(FD);
- Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0,
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr,
ProgramPoint::PostLValueKind);
return;
}
@@ -1715,7 +1777,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
SVal V = svalBuilder.conjureSymbolVal(Ex, LCtx, getContext().VoidPtrTy,
currBldrCtx->blockCount());
state = state->assume(V.castAs<DefinedOrUnknownSVal>(), true);
- Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0,
+ Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr,
ProgramPoint::PostLValueKind);
return;
}
@@ -1745,82 +1807,91 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A,
state->getSVal(Idx, LCtx),
state->getSVal(Base, LCtx));
assert(A->isGLValue());
- Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V), 0,
+ Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V), nullptr,
ProgramPoint::PostLValueKind);
}
}
/// VisitMemberExpr - Transfer function for member expressions.
void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
- ExplodedNodeSet &TopDst) {
+ ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, TopDst, *currBldrCtx);
- ExplodedNodeSet Dst;
+ // FIXME: Prechecks eventually go in ::Visit().
+ ExplodedNodeSet CheckedSet;
+ getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, M, *this);
+
+ ExplodedNodeSet EvalSet;
ValueDecl *Member = M->getMemberDecl();
// Handle static member variables and enum constants accessed via
// member syntax.
if (isa<VarDecl>(Member) || isa<EnumConstantDecl>(Member)) {
- Bldr.takeNodes(Pred);
- VisitCommonDeclRefExpr(M, Member, Pred, Dst);
- Bldr.addNodes(Dst);
- return;
- }
-
- ProgramStateRef state = Pred->getState();
- const LocationContext *LCtx = Pred->getLocationContext();
- Expr *BaseExpr = M->getBase();
+ ExplodedNodeSet Dst;
+ for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
+ I != E; ++I) {
+ VisitCommonDeclRefExpr(M, Member, Pred, EvalSet);
+ }
+ } else {
+ StmtNodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx);
+ ExplodedNodeSet Tmp;
- // Handle C++ method calls.
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) {
- if (MD->isInstance())
- state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr);
+ for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
+ I != E; ++I) {
+ ProgramStateRef state = (*I)->getState();
+ const LocationContext *LCtx = (*I)->getLocationContext();
+ Expr *BaseExpr = M->getBase();
- SVal MDVal = svalBuilder.getFunctionPointer(MD);
- state = state->BindExpr(M, LCtx, MDVal);
+ // Handle C++ method calls.
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) {
+ if (MD->isInstance())
+ state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr);
- Bldr.generateNode(M, Pred, state);
- return;
- }
+ SVal MDVal = svalBuilder.getFunctionPointer(MD);
+ state = state->BindExpr(M, LCtx, MDVal);
- // Handle regular struct fields / member variables.
- state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr);
- SVal baseExprVal = state->getSVal(BaseExpr, LCtx);
-
- FieldDecl *field = cast<FieldDecl>(Member);
- SVal L = state->getLValue(field, baseExprVal);
-
- if (M->isGLValue() || M->getType()->isArrayType()) {
-
- // We special case rvalue of array type because the analyzer cannot reason
- // about it, since we expect all regions to be wrapped in Locs. So we will
- // treat these as lvalues assuming that they will decay to pointers as soon
- // as they are used.
- if (!M->isGLValue()) {
- assert(M->getType()->isArrayType());
- const ImplicitCastExpr *PE =
- dyn_cast<ImplicitCastExpr>(Pred->getParentMap().getParent(M));
- if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) {
- assert(false &&
- "We assume that array is always wrapped in ArrayToPointerDecay");
- L = UnknownVal();
+ Bldr.generateNode(M, *I, state);
+ continue;
}
- }
- if (field->getType()->isReferenceType()) {
- if (const MemRegion *R = L.getAsRegion())
- L = state->getSVal(R);
- else
- L = UnknownVal();
- }
+ // Handle regular struct fields / member variables.
+ state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr);
+ SVal baseExprVal = state->getSVal(BaseExpr, LCtx);
+
+ FieldDecl *field = cast<FieldDecl>(Member);
+ SVal L = state->getLValue(field, baseExprVal);
+
+ if (M->isGLValue() || M->getType()->isArrayType()) {
+ // We special-case rvalues of array type because the analyzer cannot
+ // reason about them, since we expect all regions to be wrapped in Locs.
+ // We instead treat these as lvalues and assume that they will decay to
+ // pointers as soon as they are used.
+ if (!M->isGLValue()) {
+ assert(M->getType()->isArrayType());
+ const ImplicitCastExpr *PE =
+ dyn_cast<ImplicitCastExpr>((*I)->getParentMap().getParent(M));
+ if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) {
+ llvm_unreachable("should always be wrapped in ArrayToPointerDecay");
+ }
+ }
- Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, L), 0,
- ProgramPoint::PostLValueKind);
- } else {
- Bldr.takeNodes(Pred);
- evalLoad(Dst, M, M, Pred, state, L);
- Bldr.addNodes(Dst);
+ if (field->getType()->isReferenceType()) {
+ if (const MemRegion *R = L.getAsRegion())
+ L = state->getSVal(R);
+ else
+ L = UnknownVal();
+ }
+
+ Bldr.generateNode(M, *I, state->BindExpr(M, LCtx, L), nullptr,
+ ProgramPoint::PostLValueKind);
+ } else {
+ Bldr.takeNodes(*I);
+ evalLoad(Tmp, M, M, *I, state, L);
+ Bldr.addNodes(Tmp);
+ }
+ }
}
+
+ getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, M, *this);
}
namespace {
@@ -1830,7 +1901,7 @@ public:
CollectReachableSymbolsCallback(ProgramStateRef State) {}
const InvalidatedSymbols &getSymbols() const { return Symbols; }
- bool VisitSymbol(SymbolRef Sym) {
+ bool VisitSymbol(SymbolRef Sym) override {
Symbols.insert(Sym);
return true;
}
@@ -1876,9 +1947,9 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State,
const InvalidatedSymbols &EscapedSymbols = Scanner.getSymbols();
State = getCheckerManager().runCheckersForPointerEscape(State,
EscapedSymbols,
- /*CallEvent*/ 0,
+ /*CallEvent*/ nullptr,
PSK_EscapeOnBind,
- 0);
+ nullptr);
return State;
}
@@ -1897,7 +1968,7 @@ ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State,
if (!Call)
return getCheckerManager().runCheckersForPointerEscape(State,
*Invalidated,
- 0,
+ nullptr,
PSK_EscapeOther,
&ITraits);
@@ -1954,7 +2025,8 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
// If the location is not a 'Loc', it will already be handled by
// the checkers. There is nothing left to do.
if (!location.getAs<Loc>()) {
- const ProgramPoint L = PostStore(StoreE, LC, /*Loc*/0, /*tag*/0);
+ const ProgramPoint L = PostStore(StoreE, LC, /*Loc*/nullptr,
+ /*tag*/nullptr);
ProgramStateRef state = Pred->getState();
state = processPointerEscapedOnBind(state, location, Val);
Bldr.generateNode(L, state, Pred);
@@ -1975,13 +2047,13 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
state = state->bindLoc(location.castAs<Loc>(),
Val, /* notifyChanges = */ !atDeclInit);
- const MemRegion *LocReg = 0;
+ const MemRegion *LocReg = nullptr;
if (Optional<loc::MemRegionVal> LocRegVal =
location.getAs<loc::MemRegionVal>()) {
LocReg = LocRegVal->getRegion();
}
-
- const ProgramPoint L = PostStore(StoreE, LC, LocReg, 0);
+
+ const ProgramPoint L = PostStore(StoreE, LC, LocReg, nullptr);
Bldr.generateNode(L, state, PredI);
}
}
@@ -2037,7 +2109,7 @@ void ExprEngine::evalLoad(ExplodedNodeSet &Dst,
QualType ValTy = TR->getValueType();
if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) {
static SimpleProgramPointTag
- loadReferenceTag("ExprEngine : Load Reference");
+ loadReferenceTag(TagProviderName, "Load Reference");
ExplodedNodeSet Tmp;
evalLoadCommon(Tmp, NodeEx, BoundEx, Pred, state,
location, &loadReferenceTag,
@@ -2120,7 +2192,7 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
// instead "int *p" is noted as
// "Variable 'p' initialized to a null pointer value"
- static SimpleProgramPointTag tag("ExprEngine: Location");
+ static SimpleProgramPointTag tag(TagProviderName, "Location");
Bldr.generateNode(NodeEx, Pred, state, &tag);
}
ExplodedNodeSet Tmp;
@@ -2132,8 +2204,10 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
std::pair<const ProgramPointTag *, const ProgramPointTag*>
ExprEngine::geteagerlyAssumeBinOpBifurcationTags() {
static SimpleProgramPointTag
- eagerlyAssumeBinOpBifurcationTrue("ExprEngine : Eagerly Assume True"),
- eagerlyAssumeBinOpBifurcationFalse("ExprEngine : Eagerly Assume False");
+ eagerlyAssumeBinOpBifurcationTrue(TagProviderName,
+ "Eagerly Assume True"),
+ eagerlyAssumeBinOpBifurcationFalse(TagProviderName,
+ "Eagerly Assume False");
return std::make_pair(&eagerlyAssumeBinOpBifurcationTrue,
&eagerlyAssumeBinOpBifurcationFalse);
}
@@ -2161,7 +2235,7 @@ void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst,
geteagerlyAssumeBinOpBifurcationTags();
ProgramStateRef StateTrue, StateFalse;
- tie(StateTrue, StateFalse) = state->assume(*SEV);
+ std::tie(StateTrue, StateFalse) = state->assume(*SEV);
// First assume that the condition is true.
if (StateTrue) {
@@ -2192,9 +2266,8 @@ void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
ProgramStateRef state = Pred->getState();
- for (GCCAsmStmt::const_outputs_iterator OI = A->begin_outputs(),
- OE = A->end_outputs(); OI != OE; ++OI) {
- SVal X = state->getSVal(*OI, Pred->getLocationContext());
+ for (const Expr *O : A->outputs()) {
+ SVal X = state->getSVal(O, Pred->getLocationContext());
assert (!X.getAs<NonLoc>()); // Should be an Lval, or unknown, undef.
if (Optional<Loc> LV = X.getAs<Loc>())
@@ -2368,11 +2441,12 @@ struct DOTGraphTraits<ExplodedNode*> :
if (const CaseStmt *C = dyn_cast<CaseStmt>(Label)) {
Out << "\\lcase ";
LangOptions LO; // FIXME.
- C->getLHS()->printPretty(Out, 0, PrintingPolicy(LO));
+ if (C->getLHS())
+ C->getLHS()->printPretty(Out, nullptr, PrintingPolicy(LO));
if (const Stmt *RHS = C->getRHS()) {
Out << " .. ";
- RHS->printPretty(Out, 0, PrintingPolicy(LO));
+ RHS->printPretty(Out, nullptr, PrintingPolicy(LO));
}
Out << ":";
@@ -2411,10 +2485,11 @@ struct DOTGraphTraits<ExplodedNode*> :
default: {
const Stmt *S = Loc.castAs<StmtPoint>().getStmt();
+ assert(S != nullptr && "Expecting non-null Stmt");
Out << S->getStmtClassName() << ' ' << (const void*) S << ' ';
LangOptions LO; // FIXME.
- S->printPretty(Out, 0, PrintingPolicy(LO));
+ S->printPretty(Out, nullptr, PrintingPolicy(LO));
printLocation(Out, S->getLocStart());
if (Loc.getAs<PreStmt>())
@@ -2452,7 +2527,7 @@ struct DOTGraphTraits<ExplodedNode*> :
}
ProgramStateRef state = N->getState();
- Out << "\\|StateID: " << (const void*) state.getPtr()
+ Out << "\\|StateID: " << (const void*) state.get()
<< " NodeID: " << (const void*) N << "\\|";
state->printDOT(Out);
@@ -2504,8 +2579,8 @@ void ExprEngine::ViewGraph(bool trim) {
llvm::ViewGraph(*G.roots_begin(), "ExprEngine");
- GraphPrintCheckerState = NULL;
- GraphPrintSourceManager = NULL;
+ GraphPrintCheckerState = nullptr;
+ GraphPrintSourceManager = nullptr;
}
#endif
}
@@ -2515,14 +2590,14 @@ void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode*> Nodes) {
GraphPrintCheckerState = this;
GraphPrintSourceManager = &getContext().getSourceManager();
- OwningPtr<ExplodedGraph> TrimmedG(G.trim(Nodes));
+ std::unique_ptr<ExplodedGraph> TrimmedG(G.trim(Nodes));
if (!TrimmedG.get())
llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n";
else
llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedExprEngine");
- GraphPrintCheckerState = NULL;
- GraphPrintSourceManager = NULL;
+ GraphPrintCheckerState = nullptr;
+ GraphPrintSourceManager = nullptr;
#endif
}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 983fda00a2ff..ffda52709dc2 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -47,7 +47,8 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
// FIXME: Handle structs.
if (RightV.isUnknown()) {
unsigned Count = currBldrCtx->blockCount();
- RightV = svalBuilder.conjureSymbolVal(0, B->getRHS(), LCtx, Count);
+ RightV = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx,
+ Count);
}
// Simulate the effects of a "store": bind the value of the RHS
// to the L-Value represented by the LHS.
@@ -81,6 +82,12 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
}
}
+ // Although we don't yet model pointers-to-members, we do need to make
+ // sure that the members of temporaries have a valid 'this' pointer for
+ // other checks.
+ if (B->getOpcode() == BO_PtrMemD)
+ state = createTemporaryRegionIfNeeded(state, LCtx, LHS);
+
// Process non-assignments except commas or short-circuited
// logical expressions (LAnd and LOr).
SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType());
@@ -151,7 +158,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
// The symbolic value is actually for the type of the left-hand side
// expression, not the computation type, as this is the value the
// LValue on the LHS will bind to.
- LHSVal = svalBuilder.conjureSymbolVal(0, B->getRHS(), LCtx, LTy,
+ LHSVal = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx, LTy,
currBldrCtx->blockCount());
// However, we need to convert the symbol to the computation type.
Result = svalBuilder.evalCast(LHSVal, CTy, LTy);
@@ -211,8 +218,8 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
Bldr.generateNode(BE, Pred,
State->BindExpr(BE, Pred->getLocationContext(), V),
- 0, ProgramPoint::PostLValueKind);
-
+ nullptr, ProgramPoint::PostLValueKind);
+
// FIXME: Move all post/pre visits to ::Visit().
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this);
}
@@ -286,6 +293,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_Dependent:
case CK_ArrayToPointerDecay:
case CK_BitCast:
+ case CK_AddressSpaceConversion:
case CK_IntegralCast:
case CK_NullToPointer:
case CK_IntegralToPointer:
@@ -360,7 +368,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
// If we don't know if the cast succeeded, conjure a new symbol.
if (val.isUnknown()) {
DefinedOrUnknownSVal NewSym =
- svalBuilder.conjureSymbolVal(0, CastE, LCtx, resultType,
+ svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType,
currBldrCtx->blockCount());
state = state->BindExpr(CastE, LCtx, NewSym);
} else
@@ -388,7 +396,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
QualType resultType = CastE->getType();
if (CastE->isGLValue())
resultType = getContext().getPointerType(resultType);
- SVal result = svalBuilder.conjureSymbolVal(0, CastE, LCtx,
+ SVal result = svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx,
resultType,
currBldrCtx->blockCount());
state = state->BindExpr(CastE, LCtx, result);
@@ -486,7 +494,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
Ty = getContext().getPointerType(Ty);
}
- InitVal = svalBuilder.conjureSymbolVal(0, InitEx, LC, Ty,
+ InitVal = svalBuilder.conjureSymbolVal(nullptr, InitEx, LC, Ty,
currBldrCtx->blockCount());
}
@@ -554,7 +562,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
} else {
DefinedOrUnknownSVal DefinedRHS = RHSVal.castAs<DefinedOrUnknownSVal>();
ProgramStateRef StTrue, StFalse;
- llvm::tie(StTrue, StFalse) = N->getState()->assume(DefinedRHS);
+ std::tie(StTrue, StFalse) = N->getState()->assume(DefinedRHS);
if (StTrue) {
if (StFalse) {
// We can't constrain the value to 0 or 1.
@@ -633,7 +641,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
StmtNodeBuilder B(Pred, Dst, *currBldrCtx);
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
- const CFGBlock *SrcBlock = 0;
+ const CFGBlock *SrcBlock = nullptr;
// Find the predecessor block.
ProgramStateRef SrcState = state;
@@ -678,7 +686,8 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
}
if (!hasValue)
- V = svalBuilder.conjureSymbolVal(0, Ex, LCtx, currBldrCtx->blockCount());
+ V = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx,
+ currBldrCtx->blockCount());
// Generate a new node with the binding from the appropriate path.
B.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V, true));
@@ -707,34 +716,43 @@ void ExprEngine::
VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+ // FIXME: Prechecks eventually go in ::Visit().
+ ExplodedNodeSet CheckedSet;
+ getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, Ex, *this);
+
+ ExplodedNodeSet EvalSet;
+ StmtNodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx);
QualType T = Ex->getTypeOfArgument();
-
- if (Ex->getKind() == UETT_SizeOf) {
- if (!T->isIncompleteType() && !T->isConstantSizeType()) {
- assert(T->isVariableArrayType() && "Unknown non-constant-sized type.");
-
- // FIXME: Add support for VLA type arguments and VLA expressions.
- // When that happens, we should probably refactor VLASizeChecker's code.
- return;
- }
- else if (T->getAs<ObjCObjectType>()) {
- // Some code tries to take the sizeof an ObjCObjectType, relying that
- // the compiler has laid out its representation. Just report Unknown
- // for these.
- return;
+
+ for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
+ I != E; ++I) {
+ if (Ex->getKind() == UETT_SizeOf) {
+ if (!T->isIncompleteType() && !T->isConstantSizeType()) {
+ assert(T->isVariableArrayType() && "Unknown non-constant-sized type.");
+
+ // FIXME: Add support for VLA type arguments and VLA expressions.
+ // When that happens, we should probably refactor VLASizeChecker's code.
+ continue;
+ } else if (T->getAs<ObjCObjectType>()) {
+ // Some code tries to take the sizeof an ObjCObjectType, relying that
+ // the compiler has laid out its representation. Just report Unknown
+ // for these.
+ continue;
+ }
}
+
+ APSInt Value = Ex->EvaluateKnownConstInt(getContext());
+ CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue());
+
+ ProgramStateRef state = (*I)->getState();
+ state = state->BindExpr(Ex, (*I)->getLocationContext(),
+ svalBuilder.makeIntVal(amt.getQuantity(),
+ Ex->getType()));
+ Bldr.generateNode(Ex, *I, state);
}
-
- APSInt Value = Ex->EvaluateKnownConstInt(getContext());
- CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue());
-
- ProgramStateRef state = Pred->getState();
- state = state->BindExpr(Ex, Pred->getLocationContext(),
- svalBuilder.makeIntVal(amt.getQuantity(),
- Ex->getType()));
- Bldr.generateNode(Ex, Pred, state);
+
+ getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this);
}
void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
@@ -919,7 +937,8 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
// Conjure a new symbol if necessary to recover precision.
if (Result.isUnknown()){
DefinedOrUnknownSVal SymVal =
- svalBuilder.conjureSymbolVal(0, Ex, LCtx, currBldrCtx->blockCount());
+ svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx,
+ currBldrCtx->blockCount());
Result = SymVal;
// If the value is a location, ++/-- should always preserve
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index eba4f94d80e6..2a766218aaeb 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -91,12 +91,6 @@ void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
/// If the type is not an array type at all, the original value is returned.
static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue,
QualType &Ty) {
- // FIXME: This check is just a temporary workaround, because
- // ProcessTemporaryDtor sends us NULL regions. It will not be necessary once
- // we can properly process temporary destructors.
- if (!LValue.getAsRegion())
- return LValue;
-
SValBuilder &SVB = State->getStateManager().getSValBuilder();
ASTContext &Ctx = SVB.getContext();
@@ -108,13 +102,85 @@ static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue,
return LValue;
}
+
+static const MemRegion *getRegionForConstructedObject(
+ const CXXConstructExpr *CE, ExplodedNode *Pred, ExprEngine &Eng,
+ unsigned int CurrStmtIdx) {
+ const LocationContext *LCtx = Pred->getLocationContext();
+ ProgramStateRef State = Pred->getState();
+ const NodeBuilderContext &CurrBldrCtx = Eng.getBuilderContext();
+
+ // See if we're constructing an existing region by looking at the next
+ // element in the CFG.
+ const CFGBlock *B = CurrBldrCtx.getBlock();
+ unsigned int NextStmtIdx = CurrStmtIdx + 1;
+ if (NextStmtIdx < B->size()) {
+ CFGElement Next = (*B)[NextStmtIdx];
+
+ // Is this a destructor? If so, we might be in the middle of an assignment
+ // to a local or member: look ahead one more element to see what we find.
+ while (Next.getAs<CFGImplicitDtor>() && NextStmtIdx + 1 < B->size()) {
+ ++NextStmtIdx;
+ Next = (*B)[NextStmtIdx];
+ }
+
+ // Is this a constructor for a local variable?
+ if (Optional<CFGStmt> StmtElem = Next.getAs<CFGStmt>()) {
+ if (const DeclStmt *DS = dyn_cast<DeclStmt>(StmtElem->getStmt())) {
+ if (const VarDecl *Var = dyn_cast<VarDecl>(DS->getSingleDecl())) {
+ if (Var->getInit() && Var->getInit()->IgnoreImplicit() == CE) {
+ SVal LValue = State->getLValue(Var, LCtx);
+ QualType Ty = Var->getType();
+ LValue = makeZeroElementRegion(State, LValue, Ty);
+ return LValue.getAsRegion();
+ }
+ }
+ }
+ }
+
+ // Is this a constructor for a member?
+ if (Optional<CFGInitializer> InitElem = Next.getAs<CFGInitializer>()) {
+ const CXXCtorInitializer *Init = InitElem->getInitializer();
+ assert(Init->isAnyMemberInitializer());
+
+ const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
+ Loc ThisPtr = Eng.getSValBuilder().getCXXThis(CurCtor,
+ LCtx->getCurrentStackFrame());
+ SVal ThisVal = State->getSVal(ThisPtr);
+
+ const ValueDecl *Field;
+ SVal FieldVal;
+ if (Init->isIndirectMemberInitializer()) {
+ Field = Init->getIndirectMember();
+ FieldVal = State->getLValue(Init->getIndirectMember(), ThisVal);
+ } else {
+ Field = Init->getMember();
+ FieldVal = State->getLValue(Init->getMember(), ThisVal);
+ }
+
+ QualType Ty = Field->getType();
+ FieldVal = makeZeroElementRegion(State, FieldVal, Ty);
+ return FieldVal.getAsRegion();
+ }
+
+ // FIXME: This will eventually need to handle new-expressions as well.
+ // Don't forget to update the pre-constructor initialization code in
+ // ExprEngine::VisitCXXConstructExpr.
+ }
+
+ // If we couldn't find an existing region to construct into, assume we're
+ // constructing a temporary.
+ MemRegionManager &MRMgr = Eng.getSValBuilder().getRegionManager();
+ return MRMgr.getCXXTempObjectRegion(CE, LCtx);
+}
+
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
ExplodedNode *Pred,
ExplodedNodeSet &destNodes) {
const LocationContext *LCtx = Pred->getLocationContext();
ProgramStateRef State = Pred->getState();
- const MemRegion *Target = 0;
+ const MemRegion *Target = nullptr;
// FIXME: Handle arrays, which run the same constructor for every element.
// For now, we just run the first constructor (which should still invalidate
@@ -122,62 +188,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
switch (CE->getConstructionKind()) {
case CXXConstructExpr::CK_Complete: {
- // See if we're constructing an existing region by looking at the next
- // element in the CFG.
- const CFGBlock *B = currBldrCtx->getBlock();
- if (currStmtIdx + 1 < B->size()) {
- CFGElement Next = (*B)[currStmtIdx+1];
-
- // Is this a constructor for a local variable?
- if (Optional<CFGStmt> StmtElem = Next.getAs<CFGStmt>()) {
- if (const DeclStmt *DS = dyn_cast<DeclStmt>(StmtElem->getStmt())) {
- if (const VarDecl *Var = dyn_cast<VarDecl>(DS->getSingleDecl())) {
- if (Var->getInit()->IgnoreImplicit() == CE) {
- SVal LValue = State->getLValue(Var, LCtx);
- QualType Ty = Var->getType();
- LValue = makeZeroElementRegion(State, LValue, Ty);
- Target = LValue.getAsRegion();
- }
- }
- }
- }
-
- // Is this a constructor for a member?
- if (Optional<CFGInitializer> InitElem = Next.getAs<CFGInitializer>()) {
- const CXXCtorInitializer *Init = InitElem->getInitializer();
- assert(Init->isAnyMemberInitializer());
-
- const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
- Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor,
- LCtx->getCurrentStackFrame());
- SVal ThisVal = State->getSVal(ThisPtr);
-
- const ValueDecl *Field;
- SVal FieldVal;
- if (Init->isIndirectMemberInitializer()) {
- Field = Init->getIndirectMember();
- FieldVal = State->getLValue(Init->getIndirectMember(), ThisVal);
- } else {
- Field = Init->getMember();
- FieldVal = State->getLValue(Init->getMember(), ThisVal);
- }
-
- QualType Ty = Field->getType();
- FieldVal = makeZeroElementRegion(State, FieldVal, Ty);
- Target = FieldVal.getAsRegion();
- }
-
- // FIXME: This will eventually need to handle new-expressions as well.
- // Don't forget to update the pre-constructor initialization code below.
- }
-
- // If we couldn't find an existing region to construct into, assume we're
- // constructing a temporary.
- if (!Target) {
- MemRegionManager &MRMgr = getSValBuilder().getRegionManager();
- Target = MRMgr.getCXXTempObjectRegion(CE, LCtx);
- }
-
+ Target = getRegionForConstructedObject(CE, Pred, *this, currStmtIdx);
break;
}
case CXXConstructExpr::CK_VirtualBase:
@@ -251,7 +262,8 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
// since it's then possible to be initializing one part of a multi-
// dimensional array.
State = State->bindDefault(loc::MemRegionVal(Target), ZeroVal);
- Bldr.generateNode(CE, *I, State, /*tag=*/0, ProgramPoint::PreStmtKind);
+ Bldr.generateNode(CE, *I, State, /*tag=*/nullptr,
+ ProgramPoint::PreStmtKind);
}
}
}
@@ -329,6 +341,32 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
*Call, *this);
}
+void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ ProgramStateRef State = Pred->getState();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
+ CNE->getStartLoc(),
+ "Error evaluating New Allocator Call");
+ CallEventManager &CEMgr = getStateManager().getCallEventManager();
+ CallEventRef<CXXAllocatorCall> Call =
+ CEMgr.getCXXAllocatorCall(CNE, State, LCtx);
+
+ ExplodedNodeSet DstPreCall;
+ getCheckerManager().runCheckersForPreCall(DstPreCall, Pred,
+ *Call, *this);
+
+ ExplodedNodeSet DstInvalidated;
+ StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
+ for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
+ I != E; ++I)
+ defaultEvalCall(Bldr, *I, *Call);
+ getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
+ *Call, *this);
+}
+
+
void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
// FIXME: Much of this should eventually migrate to CXXAllocatorCall.
@@ -360,7 +398,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
if (IsStandardGlobalOpNewFunction)
symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount);
else
- symVal = svalBuilder.conjureSymbolVal(0, CNE, LCtx, CNE->getType(),
+ symVal = svalBuilder.conjureSymbolVal(nullptr, CNE, LCtx, CNE->getType(),
blockCount);
ProgramStateRef State = Pred->getState();
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 06328e4ffce9..3f608ba79ebc 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -11,8 +11,6 @@
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "ExprEngine"
-
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "PrettyStackTraceLocationContext.h"
#include "clang/AST/CXXInheritance.h"
@@ -28,6 +26,8 @@
using namespace clang;
using namespace ento;
+#define DEBUG_TYPE "ExprEngine"
+
STATISTIC(NumOfDynamicDispatchPathSplits,
"The # of times we split the path due to imprecise dynamic dispatch info");
@@ -49,7 +49,7 @@ void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
assert(Entry->empty());
assert(Entry->succ_size() == 1);
- // Get the solitary sucessor.
+ // Get the solitary successor.
const CFGBlock *Succ = *(Entry->succ_begin());
// Construct an edge representing the starting location in the callee.
@@ -69,8 +69,8 @@ void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
// corresponding Block.
static std::pair<const Stmt*,
const CFGBlock*> getLastStmt(const ExplodedNode *Node) {
- const Stmt *S = 0;
- const CFGBlock *Blk = 0;
+ const Stmt *S = nullptr;
+ const CFGBlock *Blk = nullptr;
const StackFrameContext *SF =
Node->getLocation().getLocationContext()->getCurrentStackFrame();
@@ -108,12 +108,12 @@ static std::pair<const Stmt*,
}
if (Node->pred_empty())
- return std::pair<const Stmt*, const CFGBlock*>((Stmt*)0, (CFGBlock*)0);
+ return std::make_pair(nullptr, nullptr);
Node = *Node->pred_begin();
}
- return std::pair<const Stmt*, const CFGBlock*>(S, Blk);
+ return std::make_pair(S, Blk);
}
/// Adjusts a return value when the called function's return type does not
@@ -160,9 +160,9 @@ void ExprEngine::removeDeadOnEndOfFunction(NodeBuilderContext& BC,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
// Find the last statement in the function and the corresponding basic block.
- const Stmt *LastSt = 0;
- const CFGBlock *Blk = 0;
- llvm::tie(LastSt, Blk) = getLastStmt(Pred);
+ const Stmt *LastSt = nullptr;
+ const CFGBlock *Blk = nullptr;
+ std::tie(LastSt, Blk) = getLastStmt(Pred);
if (!Blk || !LastSt) {
Dst.Add(Pred);
return;
@@ -229,9 +229,9 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
const Stmt *CE = calleeCtx->getCallSite();
ProgramStateRef state = CEBNode->getState();
// Find the last statement in the function and the corresponding basic block.
- const Stmt *LastSt = 0;
- const CFGBlock *Blk = 0;
- llvm::tie(LastSt, Blk) = getLastStmt(CEBNode);
+ const Stmt *LastSt = nullptr;
+ const CFGBlock *Blk = nullptr;
+ std::tie(LastSt, Blk) = getLastStmt(CEBNode);
// Generate a CallEvent /before/ cleaning the state, so that we can get the
// correct value for 'this' (if necessary).
@@ -282,7 +282,7 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
// they occurred.
ExplodedNodeSet CleanedNodes;
if (LastSt && Blk && AMgr.options.AnalysisPurgeOpt != PurgeNone) {
- static SimpleProgramPointTag retValBind("ExprEngine : Bind Return Value");
+ static SimpleProgramPointTag retValBind("ExprEngine", "Bind Return Value");
PostStmt Loc(LastSt, calleeCtx, &retValBind);
bool isNew;
ExplodedNode *BindedRetNode = G.getNode(Loc, state, false, &isNew);
@@ -296,10 +296,10 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
// context, telling it to clean up everything in the callee's context
// (and its children). We use the callee's function body as a diagnostic
// statement, with which the program point will be associated.
- removeDead(BindedRetNode, CleanedNodes, 0, calleeCtx,
+ removeDead(BindedRetNode, CleanedNodes, nullptr, calleeCtx,
calleeCtx->getAnalysisDeclContext()->getBody(),
ProgramPoint::PostStmtPurgeDeadSymbolsKind);
- currBldrCtx = 0;
+ currBldrCtx = nullptr;
} else {
CleanedNodes.Add(CEBNode);
}
@@ -387,14 +387,14 @@ static bool IsInStdNamespace(const FunctionDecl *FD) {
const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
if (!ND)
return false;
-
+
while (const DeclContext *Parent = ND->getParent()) {
if (!isa<NamespaceDecl>(Parent))
break;
ND = cast<NamespaceDecl>(Parent);
}
- return ND->getName() == "std";
+ return ND->isStdNamespace();
}
// The GDM component containing the dynamic dispatch bifurcation info. When
@@ -471,7 +471,7 @@ static ProgramStateRef getInlineFailedState(ProgramStateRef State,
const Stmt *CallE) {
const void *ReplayState = State->get<ReplayWithoutInlining>();
if (!ReplayState)
- return 0;
+ return nullptr;
assert(ReplayState == CallE && "Backtracked to the wrong call.");
(void)CallE;
@@ -565,7 +565,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
QualType ResultTy = Call.getResultType();
SValBuilder &SVB = getSValBuilder();
unsigned Count = currBldrCtx->blockCount();
- SVal R = SVB.conjureSymbolVal(0, E, LCtx, ResultTy, Count);
+ SVal R = SVB.conjureSymbolVal(nullptr, E, LCtx, ResultTy, Count);
return State->BindExpr(E, LCtx, R);
}
@@ -664,6 +664,8 @@ static CallInlinePolicy mayInlineCallKind(const CallEvent &Call,
break;
}
case CE_CXXAllocator:
+ if (Opts.mayInlineCXXAllocator())
+ break;
// Do not inline allocators until we model deallocators.
// This is unfortunate, but basically necessary for smart pointers and such.
return CIP_DisallowedAlways;
@@ -706,18 +708,16 @@ static bool isContainerClass(const ASTContext &Ctx, const CXXRecordDecl *RD) {
hasMember(Ctx, RD, "iterator_category");
}
-/// Returns true if the given function refers to a constructor or destructor of
-/// a C++ container or iterator.
+/// Returns true if the given function refers to a method of a C++ container
+/// or iterator.
///
-/// We generally do a poor job modeling most containers right now, and would
-/// prefer not to inline their setup and teardown.
-static bool isContainerCtorOrDtor(const ASTContext &Ctx,
- const FunctionDecl *FD) {
- if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD)))
- return false;
-
- const CXXRecordDecl *RD = cast<CXXMethodDecl>(FD)->getParent();
- return isContainerClass(Ctx, RD);
+/// We generally do a poor job modeling most containers right now, and might
+/// prefer not to inline their methods.
+static bool isContainerMethod(const ASTContext &Ctx,
+ const FunctionDecl *FD) {
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
+ return isContainerClass(Ctx, MD->getParent());
+ return false;
}
/// Returns true if the given function is the destructor of a class named
@@ -763,9 +763,9 @@ static bool mayInlineDecl(AnalysisDeclContext *CalleeADC,
// Conditionally control the inlining of methods on objects that look
// like C++ containers.
- if (!Opts.mayInlineCXXContainerCtorsAndDtors())
+ if (!Opts.mayInlineCXXContainerMethods())
if (!Ctx.getSourceManager().isInMainFile(FD->getLocation()))
- if (isContainerCtorOrDtor(Ctx, FD))
+ if (isContainerMethod(Ctx, FD))
return false;
// Conditionally control the inlining of the destructor of C++ shared_ptr.
diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index d276d9244614..a6611e050dc9 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -77,7 +77,7 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) {
const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl());
- assert(elemD->getInit() == 0);
+ assert(elemD->getInit() == nullptr);
elementV = state->getLValue(elemD, Pred->getLocationContext());
}
else {
@@ -85,7 +85,7 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
}
ExplodedNodeSet dstLocation;
- evalLocation(dstLocation, S, elem, Pred, state, elementV, NULL, false);
+ evalLocation(dstLocation, S, elem, Pred, state, elementV, nullptr, false);
ExplodedNodeSet Tmp;
StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
@@ -165,7 +165,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
recVal.castAs<DefinedOrUnknownSVal>();
ProgramStateRef notNilState, nilState;
- llvm::tie(notNilState, nilState) = State->assume(receiverVal);
+ std::tie(notNilState, nilState) = State->assume(receiverVal);
// There are three cases: can be nil or non-nil, must be nil, must be
// non-nil. We ignore must be nil, and merge the rest two into non-nil.
diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index 365f6ab70de7..b1e9f06cae00 100644
--- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -20,11 +20,13 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Core/HTMLRewrite.h"
#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
+#include <sstream>
using namespace clang;
using namespace ento;
@@ -39,15 +41,16 @@ class HTMLDiagnostics : public PathDiagnosticConsumer {
std::string Directory;
bool createdDir, noDir;
const Preprocessor &PP;
+ AnalyzerOptions &AnalyzerOpts;
public:
- HTMLDiagnostics(const std::string& prefix, const Preprocessor &pp);
+ HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string& prefix, const Preprocessor &pp);
- virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); }
+ virtual ~HTMLDiagnostics() { FlushDiagnostics(nullptr); }
- virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
- FilesMade *filesMade);
+ void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
+ FilesMade *filesMade) override;
- virtual StringRef getName() const {
+ StringRef getName() const override {
return "HTMLDiagnostics";
}
@@ -68,16 +71,17 @@ public:
} // end anonymous namespace
-HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix,
+HTMLDiagnostics::HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts,
+ const std::string& prefix,
const Preprocessor &pp)
- : Directory(prefix), createdDir(false), noDir(false), PP(pp) {
+ : Directory(prefix), createdDir(false), noDir(false), PP(pp), AnalyzerOpts(AnalyzerOpts) {
}
void ento::createHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
PathDiagnosticConsumers &C,
const std::string& prefix,
const Preprocessor &PP) {
- C.push_back(new HTMLDiagnostics(prefix, PP));
+ C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP));
}
//===----------------------------------------------------------------------===//
@@ -95,13 +99,11 @@ void HTMLDiagnostics::FlushDiagnosticsImpl(
void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
FilesMade *filesMade) {
-
+
// Create the HTML directory if it is missing.
if (!createdDir) {
createdDir = true;
- bool existed;
- if (llvm::error_code ec =
- llvm::sys::fs::create_directories(Directory, existed)) {
+ if (std::error_code ec = llvm::sys::fs::create_directories(Directory)) {
llvm::errs() << "warning: could not create directory '"
<< Directory << "': " << ec.message() << '\n';
@@ -128,11 +130,30 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
// Create a new rewriter to generate HTML.
Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOpts());
+ // Get the function/method name
+ SmallString<128> declName("unknown");
+ int offsetDecl = 0;
+ if (const Decl *DeclWithIssue = D.getDeclWithIssue()) {
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) {
+ declName = ND->getDeclName().getAsString();
+ }
+
+ if (const Stmt *Body = DeclWithIssue->getBody()) {
+ // Retrieve the relative position of the declaration which will be used
+ // for the file name
+ FullSourceLoc L(
+ SMgr.getExpansionLoc((*path.rbegin())->getLocation().asLocation()),
+ SMgr);
+ FullSourceLoc FunL(SMgr.getExpansionLoc(Body->getLocStart()), SMgr);
+ offsetDecl = L.getExpansionLineNumber() - FunL.getExpansionLineNumber();
+ }
+ }
+
// Process the path.
unsigned n = path.size();
unsigned max = n;
- for (PathPieces::const_reverse_iterator I = path.rbegin(),
+ for (PathPieces::const_reverse_iterator I = path.rbegin(),
E = path.rend();
I != E; ++I, --n)
HandlePiece(R, FID, **I, n, max);
@@ -165,6 +186,9 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
DirName += '/';
}
+ int LineNumber = (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber();
+ int ColumnNumber = (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber();
+
// Add the name of the file as an <h1> tag.
{
@@ -178,9 +202,9 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
<< html::EscapeText(Entry->getName())
<< "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>"
"<a href=\"#EndPath\">line "
- << (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber()
+ << LineNumber
<< ", column "
- << (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber()
+ << ColumnNumber
<< "</a></td></tr>\n"
"<tr><td class=\"rowname\">Description:</td><td>"
<< D.getVerboseDescription() << "</td></tr>\n";
@@ -217,12 +241,16 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n";
+ os << "\n<!-- FILENAME " << llvm::sys::path::filename(Entry->getName()) << " -->\n";
+
+ os << "\n<!-- FUNCTIONNAME " << declName << " -->\n";
+
os << "\n<!-- BUGLINE "
- << path.back()->getLocation().asLocation().getExpansionLineNumber()
+ << LineNumber
<< " -->\n";
os << "\n<!-- BUGCOLUMN "
- << path.back()->getLocation().asLocation().getExpansionColumnNumber()
+ << ColumnNumber
<< " -->\n";
os << "\n<!-- BUGPATHLENGTH " << path.size() << " -->\n";
@@ -249,13 +277,42 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
// Create a path for the target HTML file.
int FD;
SmallString<128> Model, ResultPath;
- llvm::sys::path::append(Model, Directory, "report-%%%%%%.html");
- if (llvm::error_code EC =
+ if (!AnalyzerOpts.shouldWriteStableReportFilename()) {
+ llvm::sys::path::append(Model, Directory, "report-%%%%%%.html");
+
+ if (std::error_code EC =
llvm::sys::fs::createUniqueFile(Model.str(), FD, ResultPath)) {
- llvm::errs() << "warning: could not create file in '" << Directory
- << "': " << EC.message() << '\n';
- return;
+ llvm::errs() << "warning: could not create file in '" << Directory
+ << "': " << EC.message() << '\n';
+ return;
+ }
+
+ } else {
+ int i = 1;
+ std::error_code EC;
+ do {
+ // Find a filename which is not already used
+ std::stringstream filename;
+ Model = "";
+ filename << "report-"
+ << llvm::sys::path::filename(Entry->getName()).str()
+ << "-" << declName.c_str()
+ << "-" << offsetDecl
+ << "-" << i << ".html";
+ llvm::sys::path::append(Model, Directory,
+ filename.str());
+ EC = llvm::sys::fs::openFileForWrite(Model.str(),
+ FD,
+ llvm::sys::fs::F_RW |
+ llvm::sys::fs::F_Excl);
+ if (EC && EC != std::errc::file_exists) {
+ llvm::errs() << "warning: could not create file '" << Model.str()
+ << "': " << EC.message() << '\n';
+ return;
+ }
+ i++;
+ } while (EC);
}
llvm::raw_fd_ostream os(FD, true);
@@ -309,7 +366,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
// Create the html for the message.
- const char *Kind = 0;
+ const char *Kind = nullptr;
switch (P.getKind()) {
case PathDiagnosticPiece::Call:
llvm_unreachable("Calls should already be handled");
@@ -460,7 +517,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
<< (num + 1)
<< ")\">&#x2192;</a></div></td>";
}
-
+
os << "</tr></table>";
}
}
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index 162cd3326495..22711f54239a 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -148,7 +148,7 @@ MemRegionManager::~MemRegionManager() {
bool SubRegion::isSubRegionOf(const MemRegion* R) const {
const MemRegion* r = getSuperRegion();
- while (r != 0) {
+ while (r != nullptr) {
if (r == R)
return true;
if (const SubRegion* sr = dyn_cast<SubRegion>(r))
@@ -173,7 +173,7 @@ MemRegionManager* SubRegion::getMemRegionManager() const {
const StackFrameContext *VarRegion::getStackFrame() const {
const StackSpaceRegion *SSR = dyn_cast<StackSpaceRegion>(getMemorySpace());
- return SSR ? SSR->getStackFrame() : NULL;
+ return SSR ? SSR->getStackFrame() : nullptr;
}
//===----------------------------------------------------------------------===//
@@ -508,11 +508,13 @@ void ObjCIvarRegion::dumpToStream(raw_ostream &os) const {
}
void StringRegion::dumpToStream(raw_ostream &os) const {
- Str->printPretty(os, 0, PrintingPolicy(getContext().getLangOpts()));
+ assert(Str != nullptr && "Expecting non-null StringLiteral");
+ Str->printPretty(os, nullptr, PrintingPolicy(getContext().getLangOpts()));
}
void ObjCStringRegion::dumpToStream(raw_ostream &os) const {
- Str->printPretty(os, 0, PrintingPolicy(getContext().getLangOpts()));
+ assert(Str != nullptr && "Expecting non-null ObjCStringLiteral");
+ Str->printPretty(os, nullptr, PrintingPolicy(getContext().getLangOpts()));
}
void SymbolicRegion::dumpToStream(raw_ostream &os) const {
@@ -757,12 +759,12 @@ getStackOrCaptureRegionForDeclContext(const LocationContext *LC,
LC = LC->getParent();
}
- return (const StackFrameContext*)0;
+ return (const StackFrameContext *)nullptr;
}
const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
const LocationContext *LC) {
- const MemRegion *sReg = 0;
+ const MemRegion *sReg = nullptr;
if (D->hasGlobalStorage() && !D->isStaticLocal()) {
@@ -850,7 +852,7 @@ const BlockDataRegion *
MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC,
const LocationContext *LC,
unsigned blockCount) {
- const MemRegion *sReg = 0;
+ const MemRegion *sReg = nullptr;
const BlockDecl *BD = BC->getDecl();
if (!BD->hasCaptures()) {
// This handles 'static' blocks.
@@ -877,14 +879,14 @@ MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC,
const CXXTempObjectRegion *
MemRegionManager::getCXXStaticTempObjectRegion(const Expr *Ex) {
return getSubRegion<CXXTempObjectRegion>(
- Ex, getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, NULL));
+ Ex, getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, nullptr));
}
const CompoundLiteralRegion*
MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr *CL,
const LocationContext *LC) {
- const MemRegion *sReg = 0;
+ const MemRegion *sReg = nullptr;
if (CL->isFileScope())
sReg = getGlobalsRegion();
@@ -975,10 +977,8 @@ static bool isValidBaseClass(const CXXRecordDecl *BaseClass,
if (IsVirtual)
return Class->isVirtuallyDerivedFrom(BaseClass);
- for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(),
- E = Class->bases_end();
- I != E; ++I) {
- if (I->getType()->getAsCXXRecordDecl()->getCanonicalDecl() == BaseClass)
+ for (const auto &I : Class->bases()) {
+ if (I.getType()->getAsCXXRecordDecl()->getCanonicalDecl() == BaseClass)
return true;
}
@@ -1113,7 +1113,7 @@ const SymbolicRegion *MemRegion::getSymbolicBase() const {
return SymR;
SubR = dyn_cast<SubRegion>(SubR->getSuperRegion());
}
- return 0;
+ return nullptr;
}
// FIXME: Merge with the implementation of the same method in Store.cpp
@@ -1130,7 +1130,7 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
RegionRawOffset ElementRegion::getAsArrayOffset() const {
CharUnits offset = CharUnits::Zero();
const ElementRegion *ER = this;
- const MemRegion *superR = NULL;
+ const MemRegion *superR = nullptr;
ASTContext &C = getContext();
// FIXME: Handle multi-dimensional arrays.
@@ -1162,7 +1162,7 @@ RegionRawOffset ElementRegion::getAsArrayOffset() const {
continue;
}
- return NULL;
+ return nullptr;
}
assert(superR && "super region cannot be NULL");
@@ -1176,10 +1176,8 @@ static bool isImmediateBase(const CXXRecordDecl *Child,
// Note that we do NOT canonicalize the base class here, because
// ASTRecordLayout doesn't either. If that leads us down the wrong path,
// so be it; at least we won't crash.
- for (CXXRecordDecl::base_class_const_iterator I = Child->bases_begin(),
- E = Child->bases_end();
- I != E; ++I) {
- if (I->getType()->getAsCXXRecordDecl() == Base)
+ for (const auto &I : Child->bases()) {
+ if (I.getType()->getAsCXXRecordDecl() == Base)
return true;
}
@@ -1188,7 +1186,7 @@ static bool isImmediateBase(const CXXRecordDecl *Child,
RegionOffset MemRegion::getAsOffset() const {
const MemRegion *R = this;
- const MemRegion *SymbolicOffsetBase = 0;
+ const MemRegion *SymbolicOffsetBase = nullptr;
int64_t Offset = 0;
while (1) {
@@ -1360,10 +1358,10 @@ RegionOffset MemRegion::getAsOffset() const {
std::pair<const VarRegion *, const VarRegion *>
BlockDataRegion::getCaptureRegions(const VarDecl *VD) {
MemRegionManager &MemMgr = *getMemRegionManager();
- const VarRegion *VR = 0;
- const VarRegion *OriginalVR = 0;
+ const VarRegion *VR = nullptr;
+ const VarRegion *OriginalVR = nullptr;
- if (!VD->getAttr<BlocksAttr>() && VD->hasLocalStorage()) {
+ if (!VD->hasAttr<BlocksAttr>() && VD->hasLocalStorage()) {
VR = MemMgr.getVarRegion(VD, this);
OriginalVR = MemMgr.getVarRegion(VD, LC);
}
@@ -1386,7 +1384,7 @@ void BlockDataRegion::LazyInitializeReferencedVars() {
AnalysisDeclContext *AC = getCodeRegion()->getAnalysisDeclContext();
AnalysisDeclContext::referenced_decls_iterator I, E;
- llvm::tie(I, E) = AC->getReferencedBlockVars(BC->getDecl());
+ std::tie(I, E) = AC->getReferencedBlockVars(BC->getDecl());
if (I == E) {
ReferencedVars = (void*) 0x1;
@@ -1404,9 +1402,9 @@ void BlockDataRegion::LazyInitializeReferencedVars() {
new (BVOriginal) VarVec(BC, E - I);
for ( ; I != E; ++I) {
- const VarRegion *VR = 0;
- const VarRegion *OriginalVR = 0;
- llvm::tie(VR, OriginalVR) = getCaptureRegions(*I);
+ const VarRegion *VR = nullptr;
+ const VarRegion *OriginalVR = nullptr;
+ std::tie(VR, OriginalVR) = getCaptureRegions(*I);
assert(VR);
assert(OriginalVR);
BV->push_back(VR, BC);
@@ -1425,8 +1423,8 @@ BlockDataRegion::referenced_vars_begin() const {
static_cast<BumpVector<const MemRegion*>*>(ReferencedVars);
if (Vec == (void*) 0x1)
- return BlockDataRegion::referenced_vars_iterator(0, 0);
-
+ return BlockDataRegion::referenced_vars_iterator(nullptr, nullptr);
+
BumpVector<const MemRegion*> *VecOriginal =
static_cast<BumpVector<const MemRegion*>*>(OriginalVars);
@@ -1442,8 +1440,8 @@ BlockDataRegion::referenced_vars_end() const {
static_cast<BumpVector<const MemRegion*>*>(ReferencedVars);
if (Vec == (void*) 0x1)
- return BlockDataRegion::referenced_vars_iterator(0, 0);
-
+ return BlockDataRegion::referenced_vars_iterator(nullptr, nullptr);
+
BumpVector<const MemRegion*> *VecOriginal =
static_cast<BumpVector<const MemRegion*>*>(OriginalVars);
@@ -1458,7 +1456,7 @@ const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const {
if (I.getCapturedRegion() == R)
return I.getOriginalRegion();
}
- return 0;
+ return nullptr;
}
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index b504db6349ee..fd25bd8e3af3 100644
--- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/SourceManager.h"
@@ -66,7 +67,7 @@ PathPieces::~PathPieces() {}
void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
bool ShouldFlattenMacros) const {
for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
- PathDiagnosticPiece *Piece = I->getPtr();
+ PathDiagnosticPiece *Piece = I->get();
switch (Piece->getKind()) {
case PathDiagnosticPiece::Call: {
@@ -106,12 +107,13 @@ void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
PathDiagnostic::~PathDiagnostic() {}
-PathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
+PathDiagnostic::PathDiagnostic(StringRef CheckName, const Decl *declWithIssue,
StringRef bugtype, StringRef verboseDesc,
StringRef shortDesc, StringRef category,
PathDiagnosticLocation LocationToUnique,
const Decl *DeclToUnique)
- : DeclWithIssue(declWithIssue),
+ : CheckName(CheckName),
+ DeclWithIssue(declWithIssue),
BugType(StripTrailingDots(bugtype)),
VerboseDesc(StripTrailingDots(verboseDesc)),
ShortDesc(StripTrailingDots(shortDesc)),
@@ -127,7 +129,7 @@ getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP,
// If the call is within a macro, don't do anything (for now).
if (CallLoc.isMacroID())
- return 0;
+ return nullptr;
assert(SMgr.isInMainFile(CallLoc) &&
"The call piece should be in the main file.");
@@ -138,7 +140,7 @@ getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP,
const PathPieces &Path = CP->path;
if (Path.empty())
- return 0;
+ return nullptr;
// Check if the last piece in the callee path is a call to a function outside
// of the main file.
@@ -148,14 +150,14 @@ getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP,
}
// Otherwise, the last piece is in the main file.
- return 0;
+ return nullptr;
}
void PathDiagnostic::resetDiagnosticLocationToMainFile() {
if (path.empty())
return;
- PathDiagnosticPiece *LastP = path.back().getPtr();
+ PathDiagnosticPiece *LastP = path.back().get();
assert(LastP);
const SourceManager &SMgr = LastP->getLocation().getManager();
@@ -196,8 +198,8 @@ PathDiagnosticConsumer::~PathDiagnosticConsumer() {
}
void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
- OwningPtr<PathDiagnostic> OwningD(D);
-
+ std::unique_ptr<PathDiagnostic> OwningD(D);
+
if (!D || D->path.empty())
return;
@@ -220,7 +222,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E;
++I) {
- const PathDiagnosticPiece *piece = I->getPtr();
+ const PathDiagnosticPiece *piece = I->get();
FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
if (FID.isInvalid()) {
@@ -258,7 +260,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
// Profile the node to see if we already have something matching it
llvm::FoldingSetNodeID profile;
D->Profile(profile);
- void *InsertPos = 0;
+ void *InsertPos = nullptr;
if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
// Keep the PathDiagnostic with the shorter path.
@@ -274,8 +276,8 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
Diags.RemoveNode(orig);
delete orig;
}
-
- Diags.InsertNode(OwningD.take());
+
+ Diags.InsertNode(OwningD.release());
}
static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y);
@@ -415,17 +417,6 @@ static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
return b.getValue();
}
-namespace {
-struct CompareDiagnostics {
- // Compare if 'X' is "<" than 'Y'.
- bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
- if (X == Y)
- return false;
- return compare(*X, *Y);
- }
-};
-}
-
void PathDiagnosticConsumer::FlushDiagnostics(
PathDiagnosticConsumer::FilesMade *Files) {
if (flushed)
@@ -443,8 +434,11 @@ void PathDiagnosticConsumer::FlushDiagnostics(
// Sort the diagnostics so that they are always emitted in a deterministic
// order.
if (!BatchDiags.empty())
- std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics());
-
+ std::sort(BatchDiags.begin(), BatchDiags.end(),
+ [](const PathDiagnostic *X, const PathDiagnostic *Y) {
+ return X != Y && compare(*X, *Y);
+ });
+
FlushDiagnosticsImpl(BatchDiags, Files);
// Delete the flushed diagnostics.
@@ -458,6 +452,11 @@ void PathDiagnosticConsumer::FlushDiagnostics(
Diags.clear();
}
+PathDiagnosticConsumer::FilesMade::~FilesMade() {
+ for (PDFileEntry &Entry : *this)
+ Entry.~PDFileEntry();
+}
+
void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
StringRef ConsumerName,
StringRef FileName) {
@@ -487,7 +486,7 @@ PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
void *InsertPos;
PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
if (!Entry)
- return 0;
+ return nullptr;
return &Entry->files;
}
@@ -571,6 +570,7 @@ getLocationForCaller(const StackFrameContext *SFC,
return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
}
case CFGElement::TemporaryDtor:
+ case CFGElement::NewAllocator:
llvm_unreachable("not yet implemented!");
}
@@ -610,6 +610,14 @@ PathDiagnosticLocation
}
PathDiagnosticLocation
+ PathDiagnosticLocation::createConditionalColonLoc(
+ const ConditionalOperator *CO,
+ const SourceManager &SM) {
+ return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK);
+}
+
+
+PathDiagnosticLocation
PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
const SourceManager &SM) {
return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
@@ -654,7 +662,7 @@ PathDiagnosticLocation
PathDiagnosticLocation::create(const ProgramPoint& P,
const SourceManager &SMng) {
- const Stmt* S = 0;
+ const Stmt* S = nullptr;
if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
const CFGBlock *BSrc = BE->getSrc();
S = BSrc->getTerminatorCondition();
@@ -695,7 +703,7 @@ const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) {
if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>())
return PIPP->getInitializer()->getInit();
- return 0;
+ return nullptr;
}
const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) {
@@ -722,7 +730,7 @@ const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) {
}
}
- return 0;
+ return nullptr;
}
PathDiagnosticLocation
@@ -731,8 +739,12 @@ PathDiagnosticLocation
assert(N && "Cannot create a location with a null node.");
const Stmt *S = getStmt(N);
- if (!S)
+ if (!S) {
+ // If this is an implicit call, return the implicit call point location.
+ if (Optional<PreImplicitCall> PIE = N->getLocationAs<PreImplicitCall>())
+ return PathDiagnosticLocation(PIE->getLocation(), SM);
S = getNextStmt(N);
+ }
if (S) {
ProgramPoint P = N->getLocation();
@@ -853,13 +865,13 @@ PathDiagnosticRange
void PathDiagnosticLocation::flatten() {
if (K == StmtK) {
K = RangeK;
- S = 0;
- D = 0;
+ S = nullptr;
+ D = nullptr;
}
else if (K == DeclK) {
K = SingleLocK;
- S = 0;
- D = 0;
+ S = nullptr;
+ D = nullptr;
}
}
@@ -969,7 +981,7 @@ static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
IntrusiveRefCntPtr<PathDiagnosticEventPiece>
PathDiagnosticCallPiece::getCallEnterEvent() const {
if (!Callee)
- return 0;
+ return nullptr;
SmallString<256> buf;
llvm::raw_svector_ostream Out(buf);
@@ -984,12 +996,12 @@ PathDiagnosticCallPiece::getCallEnterEvent() const {
IntrusiveRefCntPtr<PathDiagnosticEventPiece>
PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
if (!callEnterWithin.asLocation().isValid())
- return 0;
+ return nullptr;
if (Callee->isImplicit() || !Callee->hasBody())
- return 0;
+ return nullptr;
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee))
if (MD->isDefaulted())
- return 0;
+ return nullptr;
SmallString<256> buf;
llvm::raw_svector_ostream Out(buf);
@@ -1003,7 +1015,7 @@ PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
IntrusiveRefCntPtr<PathDiagnosticEventPiece>
PathDiagnosticCallPiece::getCallExitEvent() const {
if (NoExit)
- return 0;
+ return nullptr;
SmallString<256> buf;
llvm::raw_svector_ostream Out(buf);
@@ -1025,7 +1037,7 @@ PathDiagnosticCallPiece::getCallExitEvent() const {
static void compute_path_size(const PathPieces &pieces, unsigned &size) {
for (PathPieces::const_iterator it = pieces.begin(),
et = pieces.end(); it != et; ++it) {
- const PathDiagnosticPiece *piece = it->getPtr();
+ const PathDiagnosticPiece *piece = it->get();
if (const PathDiagnosticCallPiece *cp =
dyn_cast<PathDiagnosticCallPiece>(piece)) {
compute_path_size(cp->path, size);
diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index 5dca811722ac..ba3ad2ef16c5 100644
--- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -13,6 +13,7 @@
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/PlistSupport.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Version.h"
#include "clang/Lex/Preprocessor.h"
@@ -21,12 +22,9 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
-#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
-
-typedef llvm::DenseMap<FileID, unsigned> FIDMap;
-
+using namespace markup;
namespace {
class PlistDiagnostics : public PathDiagnosticConsumer {
@@ -42,15 +40,17 @@ namespace {
virtual ~PlistDiagnostics() {}
void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
- FilesMade *filesMade);
-
- virtual StringRef getName() const {
+ FilesMade *filesMade) override;
+
+ virtual StringRef getName() const override {
return "PlistDiagnostics";
}
- PathGenerationScheme getGenerationScheme() const { return Extensive; }
- bool supportsLogicalOpControlFlow() const { return true; }
- virtual bool supportsCrossFileDiagnostics() const {
+ PathGenerationScheme getGenerationScheme() const override {
+ return Extensive;
+ }
+ bool supportsLogicalOpControlFlow() const override { return true; }
+ bool supportsCrossFileDiagnostics() const override {
return SupportsCrossFileDiagnostics;
}
};
@@ -80,84 +80,6 @@ void ento::createPlistMultiFileDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
PP.getLangOpts(), true));
}
-static void AddFID(FIDMap &FIDs, SmallVectorImpl<FileID> &V,
- const SourceManager* SM, SourceLocation L) {
-
- FileID FID = SM->getFileID(SM->getExpansionLoc(L));
- FIDMap::iterator I = FIDs.find(FID);
- if (I != FIDs.end()) return;
- FIDs[FID] = V.size();
- V.push_back(FID);
-}
-
-static unsigned GetFID(const FIDMap& FIDs, const SourceManager &SM,
- SourceLocation L) {
- FileID FID = SM.getFileID(SM.getExpansionLoc(L));
- FIDMap::const_iterator I = FIDs.find(FID);
- assert(I != FIDs.end());
- return I->second;
-}
-
-static raw_ostream &Indent(raw_ostream &o, const unsigned indent) {
- for (unsigned i = 0; i < indent; ++i) o << ' ';
- return o;
-}
-
-static void EmitLocation(raw_ostream &o, const SourceManager &SM,
- const LangOptions &LangOpts,
- SourceLocation L, const FIDMap &FM,
- unsigned indent, bool extend = false) {
-
- FullSourceLoc Loc(SM.getExpansionLoc(L), const_cast<SourceManager&>(SM));
-
- // Add in the length of the token, so that we cover multi-char tokens.
- unsigned offset =
- extend ? Lexer::MeasureTokenLength(Loc, SM, LangOpts) - 1 : 0;
-
- Indent(o, indent) << "<dict>\n";
- Indent(o, indent) << " <key>line</key><integer>"
- << Loc.getExpansionLineNumber() << "</integer>\n";
- Indent(o, indent) << " <key>col</key><integer>"
- << Loc.getExpansionColumnNumber() + offset << "</integer>\n";
- Indent(o, indent) << " <key>file</key><integer>"
- << GetFID(FM, SM, Loc) << "</integer>\n";
- Indent(o, indent) << "</dict>\n";
-}
-
-static void EmitLocation(raw_ostream &o, const SourceManager &SM,
- const LangOptions &LangOpts,
- const PathDiagnosticLocation &L, const FIDMap& FM,
- unsigned indent, bool extend = false) {
- EmitLocation(o, SM, LangOpts, L.asLocation(), FM, indent, extend);
-}
-
-static void EmitRange(raw_ostream &o, const SourceManager &SM,
- const LangOptions &LangOpts,
- PathDiagnosticRange R, const FIDMap &FM,
- unsigned indent) {
- Indent(o, indent) << "<array>\n";
- EmitLocation(o, SM, LangOpts, R.getBegin(), FM, indent+1);
- EmitLocation(o, SM, LangOpts, R.getEnd(), FM, indent+1, !R.isPoint);
- Indent(o, indent) << "</array>\n";
-}
-
-static raw_ostream &EmitString(raw_ostream &o, StringRef s) {
- o << "<string>";
- for (StringRef::const_iterator I = s.begin(), E = s.end(); I != E; ++I) {
- char c = *I;
- switch (c) {
- default: o << c; break;
- case '&': o << "&amp;"; break;
- case '<': o << "&lt;"; break;
- case '>': o << "&gt;"; break;
- case '\'': o << "&apos;"; break;
- case '\"': o << "&quot;"; break;
- }
- }
- o << "</string>";
- return o;
-}
-
static void ReportControlFlow(raw_ostream &o,
const PathDiagnosticControlFlowPiece& P,
const FIDMap& FM,
@@ -185,11 +107,13 @@ static void ReportControlFlow(raw_ostream &o,
// logic for clients.
Indent(o, indent) << "<key>start</key>\n";
SourceLocation StartEdge = I->getStart().asRange().getBegin();
- EmitRange(o, SM, LangOpts, SourceRange(StartEdge, StartEdge), FM, indent+1);
+ EmitRange(o, SM, LangOpts, CharSourceRange::getTokenRange(StartEdge), FM,
+ indent + 1);
Indent(o, indent) << "<key>end</key>\n";
SourceLocation EndEdge = I->getEnd().asRange().getBegin();
- EmitRange(o, SM, LangOpts, SourceRange(EndEdge, EndEdge), FM, indent+1);
+ EmitRange(o, SM, LangOpts, CharSourceRange::getTokenRange(EndEdge), FM,
+ indent + 1);
--indent;
Indent(o, indent) << "</dict>\n";
@@ -241,15 +165,16 @@ static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P,
++indent;
for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
I != E; ++I) {
- EmitRange(o, SM, LangOpts, *I, FM, indent+1);
+ EmitRange(o, SM, LangOpts, CharSourceRange::getTokenRange(*I), FM,
+ indent + 1);
}
--indent;
Indent(o, indent) << "</array>\n";
}
// Output the call depth.
- Indent(o, indent) << "<key>depth</key>"
- << "<integer>" << depth << "</integer>\n";
+ Indent(o, indent) << "<key>depth</key>";
+ EmitInteger(o, depth) << '\n';
// Output the text.
assert(!P.getString().empty());
@@ -367,7 +292,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
// ranges of the diagnostics.
FIDMap FM;
SmallVector<FileID, 10> Fids;
- const SourceManager* SM = 0;
+ const SourceManager* SM = nullptr;
if (!Diags.empty())
SM = &(*(*Diags.begin())->path.begin())->getLocation().getManager();
@@ -386,13 +311,13 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E;
++I) {
- const PathDiagnosticPiece *piece = I->getPtr();
- AddFID(FM, Fids, SM, piece->getLocation().asLocation());
+ const PathDiagnosticPiece *piece = I->get();
+ AddFID(FM, Fids, *SM, piece->getLocation().asLocation());
ArrayRef<SourceRange> Ranges = piece->getRanges();
for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
E = Ranges.end(); I != E; ++I) {
- AddFID(FM, Fids, SM, I->getBegin());
- AddFID(FM, Fids, SM, I->getEnd());
+ AddFID(FM, Fids, *SM, I->getBegin());
+ AddFID(FM, Fids, *SM, I->getEnd());
}
if (const PathDiagnosticCallPiece *call =
@@ -400,7 +325,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
IntrusiveRefCntPtr<PathDiagnosticEventPiece>
callEnterWithin = call->getCallEnterWithinCallerEvent();
if (callEnterWithin)
- AddFID(FM, Fids, SM, callEnterWithin->getLocation().asLocation());
+ AddFID(FM, Fids, *SM, callEnterWithin->getLocation().asLocation());
WorkList.push_back(&call->path);
}
@@ -414,17 +339,13 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
// Open the file.
std::string ErrMsg;
- llvm::raw_fd_ostream o(OutputFile.c_str(), ErrMsg);
+ llvm::raw_fd_ostream o(OutputFile.c_str(), ErrMsg, llvm::sys::fs::F_Text);
if (!ErrMsg.empty()) {
llvm::errs() << "warning: could not create file: " << OutputFile << '\n';
return;
}
- // Write the plist header.
- o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
- "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
- "<plist version=\"1.0\">\n";
+ EmitPlistHeader(o);
// Write the root object: a <dict> containing...
// - "clang_version", the string representation of clang version
@@ -436,11 +357,8 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
o << " <key>files</key>\n"
" <array>\n";
- for (SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end();
- I!=E; ++I) {
- o << " ";
- EmitString(o, SM->getFileEntryForID(*I)->getName()) << '\n';
- }
+ for (FileID FID : Fids)
+ EmitString(o << " ", SM->getFileEntryForID(FID)->getName()) << '\n';
o << " </array>\n"
" <key>diagnostics</key>\n"
@@ -535,7 +453,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
// Output the location of the bug.
o << " <key>location</key>\n";
- EmitLocation(o, *SM, LangOpts, D->getLocation(), FM, 2);
+ EmitLocation(o, *SM, LangOpts, D->getLocation().asLocation(), FM, 2);
// Output the diagnostic to the sub-diagnostic client, if any.
if (!filesMade->empty()) {
diff --git a/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h b/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h
index ed64fcbec761..c2af36f40704 100644
--- a/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h
+++ b/lib/StaticAnalyzer/Core/PrettyStackTraceLocationContext.h
@@ -33,7 +33,7 @@ public:
assert(LCtx);
}
- virtual void print(raw_ostream &OS) const {
+ void print(raw_ostream &OS) const override {
OS << "While analyzing stack: \n";
LCtx->dumpStack(OS, "\t");
}
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index 6e2366814406..1714a2744a1a 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -175,7 +175,6 @@ ProgramState::invalidateRegionsImpl(ValueList Values,
const CallEvent *Call) const {
ProgramStateManager &Mgr = getStateManager();
SubEngine* Eng = Mgr.getOwningEngine();
- InvalidatedSymbols ConstIS;
InvalidatedSymbols Invalidated;
if (!IS)
@@ -208,7 +207,7 @@ ProgramState::invalidateRegionsImpl(ValueList Values,
const StoreRef &newStore =
Mgr.StoreMgr->invalidateRegions(getStore(), Values, E, Count, LCtx, Call,
- *IS, *ITraits, NULL, NULL);
+ *IS, *ITraits, nullptr, nullptr);
return makeWithStore(newStore);
}
@@ -388,7 +387,7 @@ ProgramStateRef ProgramStateManager::getPersistentState(ProgramState &State) {
if (ProgramState *I = StateSet.FindNodeOrInsertPos(ID, InsertPos))
return I;
- ProgramState *newState = 0;
+ ProgramState *newState = nullptr;
if (!freeStates.empty()) {
newState = freeStates.back();
freeStates.pop_back();
diff --git a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 3606e099cec2..77578d378fb3 100644
--- a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -45,7 +45,7 @@ public:
return *second;
}
const llvm::APSInt *getConcreteValue() const {
- return &From() == &To() ? &From() : NULL;
+ return &From() == &To() ? &From() : nullptr;
}
void Profile(llvm::FoldingSetNodeID &ID) const {
@@ -98,7 +98,7 @@ public:
/// constant then this method returns that value. Otherwise, it returns
/// NULL.
const llvm::APSInt* getConcreteValue() const {
- return ranges.isSingleton() ? ranges.begin()->getConcreteValue() : 0;
+ return ranges.isSingleton() ? ranges.begin()->getConcreteValue() : nullptr;
}
private:
@@ -290,35 +290,37 @@ public:
ProgramStateRef assumeSymNE(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
- const llvm::APSInt& Adjustment);
+ const llvm::APSInt& Adjustment) override;
ProgramStateRef assumeSymEQ(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
- const llvm::APSInt& Adjustment);
+ const llvm::APSInt& Adjustment) override;
ProgramStateRef assumeSymLT(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
- const llvm::APSInt& Adjustment);
+ const llvm::APSInt& Adjustment) override;
ProgramStateRef assumeSymGT(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
- const llvm::APSInt& Adjustment);
+ const llvm::APSInt& Adjustment) override;
ProgramStateRef assumeSymGE(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
- const llvm::APSInt& Adjustment);
+ const llvm::APSInt& Adjustment) override;
ProgramStateRef assumeSymLE(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
- const llvm::APSInt& Adjustment);
+ const llvm::APSInt& Adjustment) override;
- const llvm::APSInt* getSymVal(ProgramStateRef St, SymbolRef sym) const;
- ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym);
+ const llvm::APSInt* getSymVal(ProgramStateRef St,
+ SymbolRef sym) const override;
+ ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym) override;
- ProgramStateRef removeDeadBindings(ProgramStateRef St, SymbolReaper& SymReaper);
+ ProgramStateRef removeDeadBindings(ProgramStateRef St,
+ SymbolReaper& SymReaper) override;
void print(ProgramStateRef St, raw_ostream &Out,
- const char* nl, const char *sep);
+ const char* nl, const char *sep) override;
private:
RangeSet::Factory F;
@@ -334,7 +336,7 @@ ento::CreateRangeConstraintManager(ProgramStateManager &StMgr, SubEngine *Eng) {
const llvm::APSInt* RangeConstraintManager::getSymVal(ProgramStateRef St,
SymbolRef sym) const {
const ConstraintRangeTy::data_type *T = St->get<ConstraintRange>(sym);
- return T ? T->getConcreteValue() : NULL;
+ return T ? T->getConcreteValue() : nullptr;
}
ConditionTruthVal RangeConstraintManager::checkNull(ProgramStateRef State,
@@ -430,7 +432,7 @@ RangeConstraintManager::assumeSymNE(ProgramStateRef St, SymbolRef Sym,
// [Int-Adjustment+1, Int-Adjustment-1]
// Notice that the lower bound is greater than the upper bound.
RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Upper, Lower);
- return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New);
+ return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
}
ProgramStateRef
@@ -440,12 +442,12 @@ RangeConstraintManager::assumeSymEQ(ProgramStateRef St, SymbolRef Sym,
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
if (AdjustmentType.testInRange(Int, true) != APSIntType::RTR_Within)
- return NULL;
+ return nullptr;
// [Int-Adjustment, Int-Adjustment]
llvm::APSInt AdjInt = AdjustmentType.convert(Int) - Adjustment;
RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, AdjInt, AdjInt);
- return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New);
+ return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
}
ProgramStateRef
@@ -456,7 +458,7 @@ RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym,
APSIntType AdjustmentType(Adjustment);
switch (AdjustmentType.testInRange(Int, true)) {
case APSIntType::RTR_Below:
- return NULL;
+ return nullptr;
case APSIntType::RTR_Within:
break;
case APSIntType::RTR_Above:
@@ -467,14 +469,14 @@ RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym,
llvm::APSInt ComparisonVal = AdjustmentType.convert(Int);
llvm::APSInt Min = AdjustmentType.getMinValue();
if (ComparisonVal == Min)
- return NULL;
+ return nullptr;
llvm::APSInt Lower = Min-Adjustment;
llvm::APSInt Upper = ComparisonVal-Adjustment;
--Upper;
RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper);
- return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New);
+ return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
}
ProgramStateRef
@@ -489,21 +491,21 @@ RangeConstraintManager::assumeSymGT(ProgramStateRef St, SymbolRef Sym,
case APSIntType::RTR_Within:
break;
case APSIntType::RTR_Above:
- return NULL;
+ return nullptr;
}
// Special case for Int == Max. This is always false.
llvm::APSInt ComparisonVal = AdjustmentType.convert(Int);
llvm::APSInt Max = AdjustmentType.getMaxValue();
if (ComparisonVal == Max)
- return NULL;
+ return nullptr;
llvm::APSInt Lower = ComparisonVal-Adjustment;
llvm::APSInt Upper = Max-Adjustment;
++Lower;
RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper);
- return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New);
+ return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
}
ProgramStateRef
@@ -518,7 +520,7 @@ RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym,
case APSIntType::RTR_Within:
break;
case APSIntType::RTR_Above:
- return NULL;
+ return nullptr;
}
// Special case for Int == Min. This is always feasible.
@@ -532,7 +534,7 @@ RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym,
llvm::APSInt Upper = Max-Adjustment;
RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper);
- return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New);
+ return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
}
ProgramStateRef
@@ -543,7 +545,7 @@ RangeConstraintManager::assumeSymLE(ProgramStateRef St, SymbolRef Sym,
APSIntType AdjustmentType(Adjustment);
switch (AdjustmentType.testInRange(Int, true)) {
case APSIntType::RTR_Below:
- return NULL;
+ return nullptr;
case APSIntType::RTR_Within:
break;
case APSIntType::RTR_Above:
@@ -561,7 +563,7 @@ RangeConstraintManager::assumeSymLE(ProgramStateRef St, SymbolRef Sym,
llvm::APSInt Upper = ComparisonVal-Adjustment;
RangeSet New = GetRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper);
- return New.isEmpty() ? NULL : St->set<ConstraintRange>(Sym, New);
+ return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
}
//===------------------------------------------------------------------------===
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index 0b519768aa04..3bbbb3430792 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -104,7 +104,7 @@ public:
Data == X.Data;
}
- LLVM_ATTRIBUTE_USED void dump() const;
+ void dump() const;
};
} // end anonymous namespace
@@ -133,9 +133,7 @@ namespace llvm {
};
} // end llvm namespace
-void BindingKey::dump() const {
- llvm::errs() << *this;
-}
+LLVM_DUMP_METHOD void BindingKey::dump() const { llvm::errs() << *this; }
//===----------------------------------------------------------------------===//
// Actual Store type.
@@ -224,9 +222,7 @@ public:
}
}
- LLVM_ATTRIBUTE_USED void dump() const {
- dump(llvm::errs(), "\n");
- }
+ LLVM_DUMP_METHOD void dump() const { dump(llvm::errs(), "\n"); }
};
} // end anonymous namespace
@@ -266,7 +262,7 @@ RegionBindingsRef RegionBindingsRef::addBinding(const MemRegion *R,
const SVal *RegionBindingsRef::lookup(BindingKey K) const {
const ClusterBindings *Cluster = lookup(K.getBaseRegion());
if (!Cluster)
- return 0;
+ return nullptr;
return Cluster->lookup(K);
}
@@ -376,9 +372,9 @@ public:
/// version of that lvalue (i.e., a pointer to the first element of
/// the array). This is called by ExprEngine when evaluating
/// casts from arrays to pointers.
- SVal ArrayToPointer(Loc Array, QualType ElementTy);
+ SVal ArrayToPointer(Loc Array, QualType ElementTy) override;
- StoreRef getInitialStore(const LocationContext *InitLoc) {
+ StoreRef getInitialStore(const LocationContext *InitLoc) override {
return StoreRef(RBFactory.getEmptyMap().getRootWithoutRetain(), *this);
}
@@ -400,24 +396,24 @@ public:
InvalidatedSymbols &IS,
RegionAndSymbolInvalidationTraits &ITraits,
InvalidatedRegions *Invalidated,
- InvalidatedRegions *InvalidatedTopLevel);
+ InvalidatedRegions *InvalidatedTopLevel) override;
bool scanReachableSymbols(Store S, const MemRegion *R,
- ScanReachableSymbols &Callbacks);
+ ScanReachableSymbols &Callbacks) override;
RegionBindingsRef removeSubRegionBindings(RegionBindingsConstRef B,
const SubRegion *R);
public: // Part of public interface to class.
- virtual StoreRef Bind(Store store, Loc LV, SVal V) {
+ StoreRef Bind(Store store, Loc LV, SVal V) override {
return StoreRef(bind(getRegionBindings(store), LV, V).asStore(), *this);
}
RegionBindingsRef bind(RegionBindingsConstRef B, Loc LV, SVal V);
// BindDefault is only used to initialize a region with a default value.
- StoreRef BindDefault(Store store, const MemRegion *R, SVal V) {
+ StoreRef BindDefault(Store store, const MemRegion *R, SVal V) override {
RegionBindingsRef B = getRegionBindings(store);
assert(!B.lookup(R, BindingKey::Direct));
@@ -471,20 +467,20 @@ public: // Part of public interface to class.
/// \brief Create a new store with the specified binding removed.
/// \param ST the original store, that is the basis for the new store.
/// \param L the location whose binding should be removed.
- virtual StoreRef killBinding(Store ST, Loc L);
+ StoreRef killBinding(Store ST, Loc L) override;
- void incrementReferenceCount(Store store) {
+ void incrementReferenceCount(Store store) override {
getRegionBindings(store).manualRetain();
}
/// If the StoreManager supports it, decrement the reference count of
/// the specified Store object. If the reference count hits 0, the memory
/// associated with the object is recycled.
- void decrementReferenceCount(Store store) {
+ void decrementReferenceCount(Store store) override {
getRegionBindings(store).manualRelease();
}
-
- bool includedInBindings(Store store, const MemRegion *region) const;
+
+ bool includedInBindings(Store store, const MemRegion *region) const override;
/// \brief Return the value bound to specified location in a given state.
///
@@ -499,7 +495,7 @@ public: // Part of public interface to class.
/// return undefined
/// else
/// return symbolic
- virtual SVal getBinding(Store S, Loc L, QualType T) {
+ SVal getBinding(Store S, Loc L, QualType T) override {
return getBinding(getRegionBindings(S), L, T);
}
@@ -564,15 +560,16 @@ public: // Part of public interface to class.
/// removeDeadBindings - Scans the RegionStore of 'state' for dead values.
/// It returns a new Store with these values removed.
StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx,
- SymbolReaper& SymReaper);
-
+ SymbolReaper& SymReaper) override;
+
//===------------------------------------------------------------------===//
// Region "extents".
//===------------------------------------------------------------------===//
// FIXME: This method will soon be eliminated; see the note in Store.h.
DefinedOrUnknownSVal getSizeInElements(ProgramStateRef state,
- const MemRegion* R, QualType EleTy);
+ const MemRegion* R,
+ QualType EleTy) override;
//===------------------------------------------------------------------===//
// Utility methods.
@@ -585,9 +582,9 @@ public: // Part of public interface to class.
}
void print(Store store, raw_ostream &Out, const char* nl,
- const char *sep);
+ const char *sep) override;
- void iterBindings(Store store, BindingsHandler& f) {
+ void iterBindings(Store store, BindingsHandler& f) override {
RegionBindingsRef B = getRegionBindings(store);
for (RegionBindingsRef::iterator I = B.begin(), E = B.end(); I != E; ++I) {
const ClusterBindings &Cluster = I.getData();
@@ -1016,7 +1013,7 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
BI != BE; ++BI) {
const VarRegion *VR = BI.getCapturedRegion();
const VarDecl *VD = VR->getDecl();
- if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage()) {
+ if (VD->hasAttr<BlocksAttr>() || !VD->hasLocalStorage()) {
AddToWorkList(VR);
}
else if (Loc::isLocType(VR->getValueType())) {
@@ -1628,9 +1625,9 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
// getBindingForField if 'R' has a direct binding.
// Lazy binding?
- Store lazyBindingStore = NULL;
- const SubRegion *lazyBindingRegion = NULL;
- llvm::tie(lazyBindingStore, lazyBindingRegion) = findLazyBinding(B, R, R);
+ Store lazyBindingStore = nullptr;
+ const SubRegion *lazyBindingRegion = nullptr;
+ std::tie(lazyBindingStore, lazyBindingRegion) = findLazyBinding(B, R, R);
if (lazyBindingRegion)
return getLazyBinding(lazyBindingRegion,
getRegionBindings(lazyBindingStore));
@@ -1791,7 +1788,7 @@ RegionStoreManager::getInterestingValues(nonloc::LazyCompoundVal LCV) {
// values to return.
const ClusterBindings *Cluster = B.lookup(LazyR->getBaseRegion());
if (!Cluster)
- return (LazyBindingsMap[LCV.getCVData()] = llvm_move(List));
+ return (LazyBindingsMap[LCV.getCVData()] = std::move(List));
SmallVector<BindingPair, 32> Bindings;
collectSubRegionBindings(Bindings, svalBuilder, *Cluster, LazyR,
@@ -1813,7 +1810,7 @@ RegionStoreManager::getInterestingValues(nonloc::LazyCompoundVal LCV) {
List.push_back(V);
}
- return (LazyBindingsMap[LCV.getCVData()] = llvm_move(List));
+ return (LazyBindingsMap[LCV.getCVData()] = std::move(List));
}
NonLoc RegionStoreManager::createLazyBinding(RegionBindingsConstRef B,
@@ -2066,9 +2063,7 @@ RegionStoreManager::tryBindSmallStruct(RegionBindingsConstRef B,
if (Class->getNumBases() != 0 || Class->getNumVBases() != 0)
return None;
- for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
- I != E; ++I) {
- const FieldDecl *FD = *I;
+ for (const auto *FD : RD->fields()) {
if (FD->isUnnamedBitfield())
continue;
@@ -2081,7 +2076,7 @@ RegionStoreManager::tryBindSmallStruct(RegionBindingsConstRef B,
if (!(Ty->isScalarType() || Ty->isReferenceType()))
return None;
- Fields.push_back(*I);
+ Fields.push_back(FD);
}
RegionBindingsRef NewB = B;
@@ -2296,7 +2291,7 @@ bool removeDeadBindingsWorker::UpdatePostponed() {
if (const SymbolicRegion *SR = *I) {
if (SymReaper.isLive(SR->getSymbol())) {
changed |= AddToWorkList(SR);
- *I = NULL;
+ *I = nullptr;
}
}
}
diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp
index adc54659911a..3ed2bde1e4f8 100644
--- a/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -362,7 +362,7 @@ SVal SValBuilder::evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
DefinedOrUnknownSVal SValBuilder::evalEQ(ProgramStateRef state,
DefinedOrUnknownSVal lhs,
DefinedOrUnknownSVal rhs) {
- return evalBinOp(state, BO_EQ, lhs, rhs, Context.IntTy)
+ return evalBinOp(state, BO_EQ, lhs, rhs, getConditionType())
.castAs<DefinedOrUnknownSVal>();
}
@@ -376,7 +376,7 @@ static bool shouldBeModeledWithNoOp(ASTContext &Context, QualType ToTy,
ToTy = Context.getUnqualifiedArrayType(ToTy, Quals1);
FromTy = Context.getUnqualifiedArrayType(FromTy, Quals2);
- // Make sure that non cvr-qualifiers the other qualifiers (e.g., address
+ // Make sure that non-cvr-qualifiers the other qualifiers (e.g., address
// spaces) are identical.
Quals1.removeCVRQualifiers();
Quals2.removeCVRQualifiers();
diff --git a/lib/StaticAnalyzer/Core/SVals.cpp b/lib/StaticAnalyzer/Core/SVals.cpp
index 650691535f7e..8de939f47d86 100644
--- a/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/lib/StaticAnalyzer/Core/SVals.cpp
@@ -56,7 +56,7 @@ const FunctionDecl *SVal::getAsFunctionDecl() const {
return FD;
}
- return 0;
+ return nullptr;
}
/// \brief If this SVal is a location (subclasses Loc) and wraps a symbol,
@@ -78,7 +78,7 @@ SymbolRef SVal::getAsLocSymbol(bool IncludeBaseRegions) const {
dyn_cast<SymbolicRegion>(R->StripCasts()))
return SymR->getSymbol();
}
- return 0;
+ return nullptr;
}
/// Get the symbol in the SVal or its base region.
@@ -86,7 +86,7 @@ SymbolRef SVal::getLocSymbolInBase() const {
Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>();
if (!X)
- return 0;
+ return nullptr;
const MemRegion *R = X->getRegion();
@@ -97,7 +97,7 @@ SymbolRef SVal::getLocSymbolInBase() const {
R = SR->getSuperRegion();
}
- return 0;
+ return nullptr;
}
// TODO: The next 3 functions have to be simplified.
@@ -139,12 +139,12 @@ const MemRegion *SVal::getAsRegion() const {
if (Optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>())
return X->getLoc().getAsRegion();
- return 0;
+ return nullptr;
}
const MemRegion *loc::MemRegionVal::stripCasts(bool StripBaseCasts) const {
const MemRegion *R = getRegion();
- return R ? R->StripCasts(StripBaseCasts) : NULL;
+ return R ? R->StripCasts(StripBaseCasts) : nullptr;
}
const void *nonloc::LazyCompoundVal::getStore() const {
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
index e6653ae6e4b5..35930e47f82a 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
@@ -181,7 +181,7 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
case nonloc::ConcreteIntKind: {
bool b = Cond.castAs<nonloc::ConcreteInt>().getValue() != 0;
bool isFeasible = b ? Assumption : !Assumption;
- return isFeasible ? state : NULL;
+ return isFeasible ? state : nullptr;
}
case nonloc::LocAsIntegerKind:
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
index 28a9a4ded9de..21e2283511ae 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
@@ -34,7 +34,7 @@ public:
//===------------------------------------------------------------------===//
ProgramStateRef assume(ProgramStateRef state, DefinedSVal Cond,
- bool Assumption);
+ bool Assumption) override;
ProgramStateRef assume(ProgramStateRef state, NonLoc Cond, bool Assumption);
@@ -82,7 +82,7 @@ protected:
BasicValueFactory &getBasicVals() const { return SVB.getBasicValueFactory(); }
SymbolManager &getSymbolManager() const { return SVB.getSymbolManager(); }
- bool canReasonAbout(SVal X) const;
+ bool canReasonAbout(SVal X) const override;
ProgramStateRef assumeAux(ProgramStateRef state,
NonLoc Cond,
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index cc0ee0b5c7a9..df9e4d6f9199 100644
--- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -21,9 +21,9 @@ using namespace ento;
namespace {
class SimpleSValBuilder : public SValBuilder {
protected:
- virtual SVal dispatchCast(SVal val, QualType castTy);
- virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy);
- virtual SVal evalCastFromLoc(Loc val, QualType castTy);
+ SVal dispatchCast(SVal val, QualType castTy) override;
+ SVal evalCastFromNonLoc(NonLoc val, QualType castTy) override;
+ SVal evalCastFromLoc(Loc val, QualType castTy) override;
public:
SimpleSValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
@@ -31,19 +31,19 @@ public:
: SValBuilder(alloc, context, stateMgr) {}
virtual ~SimpleSValBuilder() {}
- virtual SVal evalMinus(NonLoc val);
- virtual SVal evalComplement(NonLoc val);
- virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op,
- NonLoc lhs, NonLoc rhs, QualType resultTy);
- virtual SVal evalBinOpLL(ProgramStateRef state, BinaryOperator::Opcode op,
- Loc lhs, Loc rhs, QualType resultTy);
- virtual SVal evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op,
- Loc lhs, NonLoc rhs, QualType resultTy);
+ SVal evalMinus(NonLoc val) override;
+ SVal evalComplement(NonLoc val) override;
+ SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op,
+ NonLoc lhs, NonLoc rhs, QualType resultTy) override;
+ SVal evalBinOpLL(ProgramStateRef state, BinaryOperator::Opcode op,
+ Loc lhs, Loc rhs, QualType resultTy) override;
+ SVal evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op,
+ Loc lhs, NonLoc rhs, QualType resultTy) override;
/// getKnownValue - evaluates a given SVal. If the SVal has only one possible
/// (integer) value, that value is returned. Otherwise, returns NULL.
- virtual const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal V);
-
+ const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal V) override;
+
SVal MakeSymIntVal(const SymExpr *LHS, BinaryOperator::Opcode op,
const llvm::APSInt &RHS, QualType resultTy);
};
@@ -97,7 +97,7 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
return UnknownVal();
}
- // If value is a non integer constant, produce unknown.
+ // If value is a non-integer constant, produce unknown.
if (!val.getAs<nonloc::ConcreteInt>())
return UnknownVal();
@@ -108,7 +108,7 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
}
// Only handle casts from integers to integers - if val is an integer constant
- // being cast to a non integer type, produce unknown.
+ // being cast to a non-integer type, produce unknown.
if (!isLocType && !castTy->isIntegralOrEnumerationType())
return UnknownVal();
@@ -158,7 +158,7 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) {
}
case loc::GotoLabelKind:
- // Labels and non symbolic memory regions are always true.
+ // Labels and non-symbolic memory regions are always true.
return makeTruthVal(true, castTy);
}
}
@@ -569,11 +569,10 @@ static SVal evalBinOpFieldRegionFieldRegion(const FieldRegion *LeftFR,
// members and the units in which bit-fields reside have addresses that
// increase in the order in which they are declared."
bool leftFirst = (op == BO_LT || op == BO_LE);
- for (RecordDecl::field_iterator I = RD->field_begin(),
- E = RD->field_end(); I!=E; ++I) {
- if (*I == LeftFD)
+ for (const auto *I : RD->fields()) {
+ if (I == LeftFD)
return SVB.makeTruthVal(leftFirst, resultTy);
- if (*I == RightFD)
+ if (I == RightFD)
return SVB.makeTruthVal(!leftFirst, resultTy);
}
@@ -818,7 +817,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
RegionOffset LeftOffset = LeftMR->getAsOffset();
RegionOffset RightOffset = RightMR->getAsOffset();
- if (LeftOffset.getRegion() != NULL &&
+ if (LeftOffset.getRegion() != nullptr &&
LeftOffset.getRegion() == RightOffset.getRegion() &&
!LeftOffset.hasSymbolicOffset() && !RightOffset.hasSymbolicOffset()) {
int64_t left = LeftOffset.getOffset();
@@ -901,7 +900,7 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
if (const MemRegion *region = lhs.getAsRegion()) {
rhs = convertToArrayIndex(rhs).castAs<NonLoc>();
SVal index = UnknownVal();
- const MemRegion *superR = 0;
+ const MemRegion *superR = nullptr;
QualType elementType;
if (const ElementRegion *elemReg = dyn_cast<ElementRegion>(region)) {
@@ -929,7 +928,7 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state,
SVal V) {
if (V.isUnknownOrUndef())
- return NULL;
+ return nullptr;
if (Optional<loc::ConcreteInt> X = V.getAs<loc::ConcreteInt>())
return &X->getValue();
@@ -941,5 +940,5 @@ const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state,
return state->getConstraintManager().getSymVal(state, Sym);
// FIXME: Add support for SymExprs.
- return NULL;
+ return nullptr;
}
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index 0beb9dbbc5be..e38be3e0b7dd 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/lib/StaticAnalyzer/Core/Store.cpp
@@ -88,7 +88,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
// We don't know what to make of it. Return a NULL region, which
// will be interpretted as UnknownVal.
- return NULL;
+ return nullptr;
}
// Now assume we are casting from pointer to pointer. Other cases should
@@ -166,7 +166,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
// If we cannot compute a raw offset, throw up our hands and return
// a NULL MemRegion*.
if (!baseR)
- return NULL;
+ return nullptr;
CharUnits off = rawOff.getOffset();
@@ -193,7 +193,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
// Compute the index for the new ElementRegion.
int64_t newIndex = 0;
- const MemRegion *newSuperR = 0;
+ const MemRegion *newSuperR = nullptr;
// We can only compute sizeof(PointeeTy) if it is a complete type.
if (IsCompleteType(Ctx, PointeeTy)) {
@@ -300,7 +300,7 @@ static const CXXRecordDecl *getCXXRecordType(const MemRegion *MR) {
return TVR->getValueType()->getAsCXXRecordDecl();
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
return SR->getSymbol()->getType()->getPointeeCXXRecordDecl();
- return 0;
+ return nullptr;
}
SVal StoreManager::evalDynamicCast(SVal Base, QualType TargetType,
@@ -401,7 +401,7 @@ SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) {
return Base;
Loc BaseL = Base.castAs<Loc>();
- const MemRegion* BaseR = 0;
+ const MemRegion* BaseR = nullptr;
switch (BaseL.getSubKind()) {
case loc::MemRegionKind:
diff --git a/lib/StaticAnalyzer/Core/SymbolManager.cpp b/lib/StaticAnalyzer/Core/SymbolManager.cpp
index 1b56f82dc60f..cca0461a4748 100644
--- a/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -326,11 +326,7 @@ QualType SymbolRegionValue::getType() const {
}
SymbolManager::~SymbolManager() {
- for (SymbolDependTy::const_iterator I = SymbolDependencies.begin(),
- E = SymbolDependencies.end(); I != E; ++I) {
- delete I->second;
- }
-
+ llvm::DeleteContainerSeconds(SymbolDependencies);
}
bool SymbolManager::canSymbolicate(QualType T) {
@@ -351,7 +347,7 @@ bool SymbolManager::canSymbolicate(QualType T) {
void SymbolManager::addSymbolDependency(const SymbolRef Primary,
const SymbolRef Dependent) {
SymbolDependTy::iterator I = SymbolDependencies.find(Primary);
- SymbolRefSmallVectorTy *dependencies = 0;
+ SymbolRefSmallVectorTy *dependencies = nullptr;
if (I == SymbolDependencies.end()) {
dependencies = new SymbolRefSmallVectorTy();
SymbolDependencies[Primary] = dependencies;
@@ -365,7 +361,7 @@ const SymbolRefSmallVectorTy *SymbolManager::getDependentSymbols(
const SymbolRef Primary) {
SymbolDependTy::const_iterator I = SymbolDependencies.find(Primary);
if (I == SymbolDependencies.end())
- return 0;
+ return nullptr;
return I->second;
}
@@ -491,7 +487,7 @@ bool SymbolReaper::isLive(SymbolRef sym) {
bool
SymbolReaper::isLive(const Stmt *ExprVal, const LocationContext *ELCtx) const {
- if (LCtx == 0)
+ if (LCtx == nullptr)
return false;
if (LCtx != ELCtx) {
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 9efe99767e4c..f0dd2742352b 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -11,15 +11,13 @@
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "AnalysisConsumer"
-
-#include "AnalysisConsumer.h"
+#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DataRecursiveASTVisitor.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ParentMap.h"
-#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CallGraph.h"
@@ -36,7 +34,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
#include "llvm/ADT/DepthFirstIterator.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
@@ -45,12 +42,15 @@
#include "llvm/Support/Program.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
+#include <memory>
#include <queue>
using namespace clang;
using namespace ento;
using llvm::SmallPtrSet;
+#define DEBUG_TYPE "AnalysisConsumer"
+
static ExplodedNode::Auditor* CreateUbiViz();
STATISTIC(NumFunctionTopLevel, "The # of functions at top level.");
@@ -90,12 +90,12 @@ public:
ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag)
: Diag(Diag), IncludePath(false) {}
virtual ~ClangDiagPathDiagConsumer() {}
- virtual StringRef getName() const { return "ClangDiags"; }
+ StringRef getName() const override { return "ClangDiags"; }
- virtual bool supportsLogicalOpControlFlow() const { return true; }
- virtual bool supportsCrossFileDiagnostics() const { return true; }
+ bool supportsLogicalOpControlFlow() const override { return true; }
+ bool supportsCrossFileDiagnostics() const override { return true; }
- virtual PathGenerationScheme getGenerationScheme() const {
+ PathGenerationScheme getGenerationScheme() const override {
return IncludePath ? Minimal : None;
}
@@ -103,35 +103,17 @@ public:
IncludePath = true;
}
- void emitDiag(SourceLocation L, unsigned DiagID,
- ArrayRef<SourceRange> Ranges) {
- DiagnosticBuilder DiagBuilder = Diag.Report(L, DiagID);
-
- for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
- I != E; ++I) {
- DiagBuilder << *I;
- }
- }
-
void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
- FilesMade *filesMade) {
+ FilesMade *filesMade) override {
+ unsigned WarnID = Diag.getCustomDiagID(DiagnosticsEngine::Warning, "%0");
+ unsigned NoteID = Diag.getCustomDiagID(DiagnosticsEngine::Note, "%0");
+
for (std::vector<const PathDiagnostic*>::iterator I = Diags.begin(),
E = Diags.end(); I != E; ++I) {
const PathDiagnostic *PD = *I;
- StringRef desc = PD->getShortDescription();
- SmallString<512> TmpStr;
- llvm::raw_svector_ostream Out(TmpStr);
- for (StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I) {
- if (*I == '%')
- Out << "%%";
- else
- Out << *I;
- }
- Out.flush();
- unsigned ErrorDiag = Diag.getCustomDiagID(DiagnosticsEngine::Warning,
- TmpStr);
- SourceLocation L = PD->getLocation().asLocation();
- emitDiag(L, ErrorDiag, PD->path.back()->getRanges());
+ SourceLocation WarnLoc = PD->getLocation().asLocation();
+ Diag.Report(WarnLoc, WarnID) << PD->getShortDescription()
+ << PD->path.back()->getRanges();
if (!IncludePath)
continue;
@@ -140,11 +122,9 @@ public:
for (PathPieces::const_iterator PI = FlatPath.begin(),
PE = FlatPath.end();
PI != PE; ++PI) {
- unsigned NoteID = Diag.getCustomDiagID(DiagnosticsEngine::Note,
- (*PI)->getString());
-
SourceLocation NoteLoc = (*PI)->getLocation().asLocation();
- emitDiag(NoteLoc, NoteID, (*PI)->getRanges());
+ Diag.Report(NoteLoc, NoteID) << (*PI)->getString()
+ << (*PI)->getRanges();
}
}
}
@@ -157,8 +137,8 @@ public:
namespace {
-class AnalysisConsumer : public ASTConsumer,
- public RecursiveASTVisitor<AnalysisConsumer> {
+class AnalysisConsumer : public AnalysisASTConsumer,
+ public DataRecursiveASTVisitor<AnalysisConsumer> {
enum {
AM_None = 0,
AM_Syntax = 0x1,
@@ -191,8 +171,8 @@ public:
StoreManagerCreator CreateStoreMgr;
ConstraintManagerCreator CreateConstraintMgr;
- OwningPtr<CheckerManager> checkerMgr;
- OwningPtr<AnalysisManager> Mgr;
+ std::unique_ptr<CheckerManager> checkerMgr;
+ std::unique_ptr<AnalysisManager> Mgr;
/// Time the analyzes time of each translation unit.
static llvm::Timer* TUTotalTimer;
@@ -205,8 +185,8 @@ public:
const std::string& outdir,
AnalyzerOptionsRef opts,
ArrayRef<std::string> plugins)
- : RecVisitorMode(0), RecVisitorBR(0),
- Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins) {
+ : RecVisitorMode(0), RecVisitorBR(nullptr),
+ Ctx(nullptr), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins) {
DigestAnalyzerOptions();
if (Opts->PrintStats) {
llvm::EnableStatistics();
@@ -220,21 +200,24 @@ public:
}
void DigestAnalyzerOptions() {
- // Create the PathDiagnosticConsumer.
- ClangDiagPathDiagConsumer *clangDiags =
- new ClangDiagPathDiagConsumer(PP.getDiagnostics());
- PathConsumers.push_back(clangDiags);
-
- if (Opts->AnalysisDiagOpt == PD_TEXT) {
- clangDiags->enablePaths();
-
- } else if (!OutDir.empty()) {
- switch (Opts->AnalysisDiagOpt) {
- default:
-#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \
- case PD_##NAME: CREATEFN(*Opts.getPtr(), PathConsumers, OutDir, PP);\
- break;
+ if (Opts->AnalysisDiagOpt != PD_NONE) {
+ // Create the PathDiagnosticConsumer.
+ ClangDiagPathDiagConsumer *clangDiags =
+ new ClangDiagPathDiagConsumer(PP.getDiagnostics());
+ PathConsumers.push_back(clangDiags);
+
+ if (Opts->AnalysisDiagOpt == PD_TEXT) {
+ clangDiags->enablePaths();
+
+ } else if (!OutDir.empty()) {
+ switch (Opts->AnalysisDiagOpt) {
+ default:
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \
+ case PD_##NAME: \
+ CREATEFN(*Opts.get(), PathConsumers, OutDir, PP); \
+ break;
#include "clang/StaticAnalyzer/Core/Analyses.def"
+ }
}
}
@@ -299,7 +282,7 @@ public:
}
}
- virtual void Initialize(ASTContext &Context) {
+ void Initialize(ASTContext &Context) override {
Ctx = &Context;
checkerMgr.reset(createCheckerManager(*Opts, PP.getLangOpts(), Plugins,
PP.getDiagnostics()));
@@ -315,16 +298,16 @@ public:
/// \brief Store the top level decls in the set to be processed later on.
/// (Doing this pre-processing avoids deserialization of data from PCH.)
- virtual bool HandleTopLevelDecl(DeclGroupRef D);
- virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D);
+ bool HandleTopLevelDecl(DeclGroupRef D) override;
+ void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override;
- virtual void HandleTranslationUnit(ASTContext &C);
+ void HandleTranslationUnit(ASTContext &C) override;
/// \brief Determine which inlining mode should be used when this function is
/// analyzed. This allows to redefine the default inlining policies when
/// analyzing a given function.
ExprEngine::InliningModes
- getInliningModeForFunction(const Decl *D, SetOfConstDecls Visited);
+ getInliningModeForFunction(const Decl *D, const SetOfConstDecls &Visited);
/// \brief Build the call graph for all the top level decls of this TU and
/// use it to define the order in which the functions should be visited.
@@ -338,7 +321,7 @@ public:
/// given root function.
void HandleCode(Decl *D, AnalysisMode Mode,
ExprEngine::InliningModes IMode = ExprEngine::Inline_Minimal,
- SetOfConstDecls *VisitedCallees = 0);
+ SetOfConstDecls *VisitedCallees = nullptr);
void RunPathSensitiveChecks(Decl *D,
ExprEngine::InliningModes IMode,
@@ -389,6 +372,11 @@ public:
return true;
}
+ virtual void
+ AddDiagnosticConsumer(PathDiagnosticConsumer *Consumer) override {
+ PathConsumers.push_back(Consumer);
+ }
+
private:
void storeTopLevelDecls(DeclGroupRef DG);
@@ -402,7 +390,7 @@ private:
//===----------------------------------------------------------------------===//
// AnalysisConsumer implementation.
//===----------------------------------------------------------------------===//
-llvm::Timer* AnalysisConsumer::TUTotalTimer = 0;
+llvm::Timer* AnalysisConsumer::TUTotalTimer = nullptr;
bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) {
storeTopLevelDecls(DG);
@@ -426,8 +414,8 @@ void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) {
}
static bool shouldSkipFunction(const Decl *D,
- SetOfConstDecls Visited,
- SetOfConstDecls VisitedAsTopLevel) {
+ const SetOfConstDecls &Visited,
+ const SetOfConstDecls &VisitedAsTopLevel) {
if (VisitedAsTopLevel.count(D))
return true;
@@ -447,7 +435,7 @@ static bool shouldSkipFunction(const Decl *D,
ExprEngine::InliningModes
AnalysisConsumer::getInliningModeForFunction(const Decl *D,
- SetOfConstDecls Visited) {
+ const SetOfConstDecls &Visited) {
// We want to reanalyze all ObjC methods as top level to report Retain
// Count naming convention errors more aggressively. But we should tune down
// inlining when reanalyzing an already inlined function.
@@ -501,7 +489,7 @@ void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
SetOfConstDecls VisitedCallees;
HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited),
- (Mgr->options.InliningMode == All ? 0 : &VisitedCallees));
+ (Mgr->options.InliningMode == All ? nullptr : &VisitedCallees));
// Add the visited callees to the global visited set.
for (SetOfConstDecls::iterator I = VisitedCallees.begin(),
@@ -551,14 +539,14 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
// After all decls handled, run checkers on the entire TranslationUnit.
checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
- RecVisitorBR = 0;
+ RecVisitorBR = nullptr;
}
// Explicitly destroy the PathDiagnosticConsumer. This will flush its output.
// FIXME: This should be replaced with something that doesn't rely on
// side-effects in PathDiagnosticConsumer's destructor. This is required when
// used with option -disable-free.
- Mgr.reset(NULL);
+ Mgr.reset();
if (TUTotalTimer) TUTotalTimer->stopTimer();
@@ -653,7 +641,7 @@ void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries,IMode);
// Set the graph auditor.
- OwningPtr<ExplodedNode::Auditor> Auditor;
+ std::unique_ptr<ExplodedNode::Auditor> Auditor;
if (Mgr->options.visualizeExplodedGraphWithUbiGraph) {
Auditor.reset(CreateUbiViz());
ExplodedNode::SetAuditor(Auditor.get());
@@ -665,7 +653,7 @@ void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
// Release the auditor (if any) so that it doesn't monitor the graph
// created BugReporter.
- ExplodedNode::SetAuditor(0);
+ ExplodedNode::SetAuditor(nullptr);
// Visualize the exploded graph.
if (Mgr->options.visualizeExplodedGraphWithGraphViz)
@@ -699,10 +687,10 @@ void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
// AnalysisConsumer creation.
//===----------------------------------------------------------------------===//
-ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
- const std::string& outDir,
- AnalyzerOptionsRef opts,
- ArrayRef<std::string> plugins) {
+AnalysisASTConsumer *
+ento::CreateAnalysisConsumer(const Preprocessor &pp, const std::string &outDir,
+ AnalyzerOptionsRef opts,
+ ArrayRef<std::string> plugins) {
// Disable the effects of '-Werror' when using the AnalysisConsumer.
pp.getDiagnostics().setWarningsAsErrors(false);
@@ -716,7 +704,7 @@ ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
namespace {
class UbigraphViz : public ExplodedNode::Auditor {
- OwningPtr<raw_ostream> Out;
+ std::unique_ptr<raw_ostream> Out;
std::string Filename;
unsigned Cntr;
@@ -724,11 +712,11 @@ class UbigraphViz : public ExplodedNode::Auditor {
VMap M;
public:
- UbigraphViz(raw_ostream *Out, StringRef Filename);
+ UbigraphViz(std::unique_ptr<raw_ostream> Out, StringRef Filename);
~UbigraphViz();
- virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst);
+ void AddEdge(ExplodedNode *Src, ExplodedNode *Dst) override;
};
} // end anonymous namespace
@@ -739,10 +727,9 @@ static ExplodedNode::Auditor* CreateUbiViz() {
llvm::sys::fs::createTemporaryFile("llvm_ubi", "", FD, P);
llvm::errs() << "Writing '" << P.str() << "'.\n";
- OwningPtr<llvm::raw_fd_ostream> Stream;
- Stream.reset(new llvm::raw_fd_ostream(FD, true));
+ auto Stream = llvm::make_unique<llvm::raw_fd_ostream>(FD, true);
- return new UbigraphViz(Stream.take(), P);
+ return new UbigraphViz(std::move(Stream), P);
}
void UbigraphViz::AddEdge(ExplodedNode *Src, ExplodedNode *Dst) {
@@ -779,8 +766,8 @@ void UbigraphViz::AddEdge(ExplodedNode *Src, ExplodedNode *Dst) {
<< ", ('arrow','true'), ('oriented', 'true'))\n";
}
-UbigraphViz::UbigraphViz(raw_ostream *Out, StringRef Filename)
- : Out(Out), Filename(Filename), Cntr(0) {
+UbigraphViz::UbigraphViz(std::unique_ptr<raw_ostream> Out, StringRef Filename)
+ : Out(std::move(Out)), Filename(Filename), Cntr(0) {
*Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
*Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
@@ -788,16 +775,17 @@ UbigraphViz::UbigraphViz(raw_ostream *Out, StringRef Filename)
}
UbigraphViz::~UbigraphViz() {
- Out.reset(0);
+ Out.reset();
llvm::errs() << "Running 'ubiviz' program... ";
std::string ErrMsg;
std::string Ubiviz = llvm::sys::FindProgramByName("ubiviz");
std::vector<const char*> args;
args.push_back(Ubiviz.c_str());
args.push_back(Filename.c_str());
- args.push_back(0);
+ args.push_back(nullptr);
- if (llvm::sys::ExecuteAndWait(Ubiviz, &args[0], 0, 0, 0, 0, &ErrMsg)) {
+ if (llvm::sys::ExecuteAndWait(Ubiviz, &args[0], nullptr, nullptr, 0, 0,
+ &ErrMsg)) {
llvm::errs() << "Error viewing graph: " << ErrMsg << "\n";
}
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h
deleted file mode 100644
index b75220b62de3..000000000000
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h
+++ /dev/null
@@ -1,43 +0,0 @@
-//===--- AnalysisConsumer.h - Front-end Analysis Engine Hooks ---*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This header contains the functions necessary for a front-end to run various
-// analyses.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_GR_ANALYSISCONSUMER_H
-#define LLVM_CLANG_GR_ANALYSISCONSUMER_H
-
-#include "clang/Basic/LLVM.h"
-#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
-#include <string>
-
-namespace clang {
-
-class ASTConsumer;
-class Preprocessor;
-class DiagnosticsEngine;
-
-namespace ento {
-class CheckerManager;
-
-/// CreateAnalysisConsumer - Creates an ASTConsumer to run various code
-/// analysis passes. (The set of analyses run is controlled by command-line
-/// options.)
-ASTConsumer* CreateAnalysisConsumer(const Preprocessor &pp,
- const std::string &output,
- AnalyzerOptionsRef opts,
- ArrayRef<std::string> plugins);
-
-} // end GR namespace
-
-} // end clang namespace
-
-#endif
diff --git a/lib/StaticAnalyzer/Frontend/CMakeLists.txt b/lib/StaticAnalyzer/Frontend/CMakeLists.txt
index aafb249c587f..5349ed93e2c4 100644
--- a/lib/StaticAnalyzer/Frontend/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Frontend/CMakeLists.txt
@@ -1,31 +1,19 @@
-set(LLVM_NO_RTTI 1)
-
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/../Checkers )
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
add_clang_library(clangStaticAnalyzerFrontend
AnalysisConsumer.cpp
CheckerRegistration.cpp
FrontendActions.cpp
- )
-add_dependencies(clangStaticAnalyzerFrontend
- clangStaticAnalyzerCheckers
- clangStaticAnalyzerCore
- ClangAttrClasses
- ClangAttrList
- ClangCommentNodes
- ClangDeclNodes
- ClangDiagnosticCommon
- ClangDiagnosticFrontend
- ClangStmtNodes
- )
-
-target_link_libraries(clangStaticAnalyzerFrontend
- clangBasic
- clangLex
+ LINK_LIBS
clangAST
+ clangAnalysis
+ clangBasic
clangFrontend
- clangRewriteCore
- clangRewriteFrontend
clangStaticAnalyzerCheckers
+ clangStaticAnalyzerCore
)
diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
index e7def0881964..e2577c3c729f 100644
--- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
+++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
@@ -20,11 +20,11 @@
#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
+#include <memory>
using namespace clang;
using namespace ento;
@@ -40,7 +40,7 @@ class ClangCheckerRegistry : public CheckerRegistry {
public:
ClangCheckerRegistry(ArrayRef<std::string> plugins,
- DiagnosticsEngine *diags = 0);
+ DiagnosticsEngine *diags = nullptr);
};
} // end anonymous namespace
@@ -73,7 +73,7 @@ ClangCheckerRegistry::ClangCheckerRegistry(ArrayRef<std::string> plugins,
bool ClangCheckerRegistry::isCompatibleAPIVersion(const char *versionString) {
// If the version string is null, it's not an analyzer plugin.
- if (versionString == 0)
+ if (!versionString)
return false;
// For now, none of the static analyzer API is considered stable.
@@ -104,8 +104,8 @@ CheckerManager *ento::createCheckerManager(AnalyzerOptions &opts,
const LangOptions &langOpts,
ArrayRef<std::string> plugins,
DiagnosticsEngine &diags) {
- OwningPtr<CheckerManager> checkerMgr(new CheckerManager(langOpts,
- &opts));
+ std::unique_ptr<CheckerManager> checkerMgr(
+ new CheckerManager(langOpts, &opts));
SmallVector<CheckerOptInfo, 8> checkerOpts;
for (unsigned i = 0, e = opts.CheckersControlList.size(); i != e; ++i) {
@@ -123,7 +123,7 @@ CheckerManager *ento::createCheckerManager(AnalyzerOptions &opts,
<< checkerOpts[i].getName();
}
- return checkerMgr.take();
+ return checkerMgr.release();
}
void ento::printCheckerHelp(raw_ostream &out, ArrayRef<std::string> plugins) {
diff --git a/lib/StaticAnalyzer/Frontend/FrontendActions.cpp b/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
index 13971af9afad..aa3807732632 100644
--- a/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
+++ b/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
@@ -8,8 +8,8 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
-#include "AnalysisConsumer.h"
#include "clang/Frontend/CompilerInstance.h"
+#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
using namespace clang;
using namespace ento;
diff --git a/lib/Tooling/CMakeLists.txt b/lib/Tooling/CMakeLists.txt
index d29e564e34fe..2bf9652fa376 100644
--- a/lib/Tooling/CMakeLists.txt
+++ b/lib/Tooling/CMakeLists.txt
@@ -9,22 +9,13 @@ add_clang_library(clangTooling
Refactoring.cpp
RefactoringCallbacks.cpp
Tooling.cpp
- )
-
-add_dependencies(clangTooling
- ClangAttrClasses
- ClangAttrList
- ClangDeclNodes
- ClangDiagnosticCommon
- ClangDiagnosticFrontend
- ClangStmtNodes
- )
-target_link_libraries(clangTooling
- clangBasic
- clangFrontend
+ LINK_LIBS
clangAST
clangASTMatchers
- clangRewriteCore
- clangRewriteFrontend
+ clangBasic
+ clangDriver
+ clangFrontend
+ clangLex
+ clangRewrite
)
diff --git a/lib/Tooling/CommonOptionsParser.cpp b/lib/Tooling/CommonOptionsParser.cpp
index cce4816aa675..e0b844c067d4 100644
--- a/lib/Tooling/CommonOptionsParser.cpp
+++ b/lib/Tooling/CommonOptionsParser.cpp
@@ -54,12 +54,26 @@ const char *const CommonOptionsParser::HelpMessage =
"\n";
CommonOptionsParser::CommonOptionsParser(int &argc, const char **argv,
+ cl::OptionCategory &Category,
const char *Overview) {
- static cl::opt<std::string> BuildPath(
- "p", cl::desc("Build path"), cl::Optional);
+ static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
+
+ static cl::opt<std::string> BuildPath("p", cl::desc("Build path"),
+ cl::Optional, cl::cat(Category));
static cl::list<std::string> SourcePaths(
- cl::Positional, cl::desc("<source0> [... <sourceN>]"), cl::OneOrMore);
+ cl::Positional, cl::desc("<source0> [... <sourceN>]"), cl::OneOrMore,
+ cl::cat(Category));
+
+ // Hide unrelated options.
+ StringMap<cl::Option*> Options;
+ cl::getRegisteredOptions(Options);
+ for (StringMap<cl::Option *>::iterator I = Options.begin(), E = Options.end();
+ I != E; ++I) {
+ if (I->second->Category != &Category && I->first() != "help" &&
+ I->first() != "version")
+ I->second->setHiddenFlag(cl::ReallyHidden);
+ }
Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc,
argv));
diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp
index c962055de795..4b776bf3c73d 100644
--- a/lib/Tooling/CompilationDatabase.cpp
+++ b/lib/Tooling/CompilationDatabase.cpp
@@ -13,22 +13,22 @@
//===----------------------------------------------------------------------===//
#include "clang/Tooling/CompilationDatabase.h"
-#include "clang/Tooling/CompilationDatabasePluginRegistry.h"
-#include "clang/Tooling/Tooling.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/system_error.h"
-#include <sstream>
-
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Driver/Action.h"
+#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Job.h"
-#include "clang/Driver/Compilation.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "llvm/Support/Host.h"
+#include "clang/Tooling/CompilationDatabasePluginRegistry.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Option/Arg.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
+#include <sstream>
+#include <system_error>
namespace clang {
namespace tooling {
@@ -44,7 +44,7 @@ CompilationDatabase::loadFromDirectory(StringRef BuildDirectory,
Ie = CompilationDatabasePluginRegistry::end();
It != Ie; ++It) {
std::string DatabaseErrorMessage;
- OwningPtr<CompilationDatabasePlugin> Plugin(It->instantiate());
+ std::unique_ptr<CompilationDatabasePlugin> Plugin(It->instantiate());
if (CompilationDatabase *DB =
Plugin->loadFromDirectory(BuildDirectory, DatabaseErrorMessage))
return DB;
@@ -52,7 +52,7 @@ CompilationDatabase::loadFromDirectory(StringRef BuildDirectory,
ErrorStream << It->getName() << ": " << DatabaseErrorMessage << "\n";
}
ErrorMessage = ErrorStream.str();
- return NULL;
+ return nullptr;
}
static CompilationDatabase *
@@ -76,7 +76,7 @@ findCompilationDatabaseFromDirectory(StringRef Directory,
Directory = llvm::sys::path::parent_path(Directory);
}
ErrorMessage = ErrorStream.str();
- return NULL;
+ return nullptr;
}
CompilationDatabase *
@@ -151,14 +151,14 @@ private:
// options.
class UnusedInputDiagConsumer : public DiagnosticConsumer {
public:
- UnusedInputDiagConsumer() : Other(0) {}
+ UnusedInputDiagConsumer() : Other(nullptr) {}
// Useful for debugging, chain diagnostics to another consumer after
// recording for our own purposes.
UnusedInputDiagConsumer(DiagnosticConsumer *Other) : Other(Other) {}
virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
- const Diagnostic &Info) LLVM_OVERRIDE {
+ const Diagnostic &Info) override {
if (Info.getID() == clang::diag::warn_drv_input_file_unused) {
// Arg 1 for this diagnostic is the option that didn't get used.
UnusedInputs.push_back(Info.getArgStdStr(0));
@@ -204,19 +204,19 @@ private:
/// \li true if successful.
/// \li false if \c Args cannot be used for compilation jobs (e.g.
/// contains an option like -E or -version).
-bool stripPositionalArgs(std::vector<const char *> Args,
- std::vector<std::string> &Result) {
+static bool stripPositionalArgs(std::vector<const char *> Args,
+ std::vector<std::string> &Result) {
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
UnusedInputDiagConsumer DiagClient;
DiagnosticsEngine Diagnostics(
IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()),
&*DiagOpts, &DiagClient, false);
- // Neither clang executable nor default image name are required since the
- // jobs the driver builds will not be executed.
- OwningPtr<driver::Driver> NewDriver(new driver::Driver(
+ // The clang executable path isn't required since the jobs the driver builds
+ // will not be executed.
+ std::unique_ptr<driver::Driver> NewDriver(new driver::Driver(
/* ClangExecutable= */ "", llvm::sys::getDefaultTargetTriple(),
- /* DefaultImageName= */ "", Diagnostics));
+ Diagnostics));
NewDriver->setCheckInputsExist(false);
// This becomes the new argv[0]. The value is actually not important as it
@@ -237,7 +237,13 @@ bool stripPositionalArgs(std::vector<const char *> Args,
// up with no jobs but then this is the user's fault.
Args.push_back("placeholder.cpp");
- const OwningPtr<driver::Compilation> Compilation(
+ // Remove -no-integrated-as; it's not used for syntax checking,
+ // and it confuses targets which don't support this option.
+ Args.erase(std::remove_if(Args.begin(), Args.end(),
+ MatchesAny(std::string("-no-integrated-as"))),
+ Args.end());
+
+ const std::unique_ptr<driver::Compilation> Compilation(
NewDriver->BuildCompilation(Args));
const driver::JobList &Jobs = Compilation->getJobs();
@@ -271,6 +277,7 @@ bool stripPositionalArgs(std::vector<const char *> Args,
End = std::remove_if(Args.begin(), End, MatchesAny(DiagClient.UnusedInputs));
// Remove the -c add above as well. It will be at the end right now.
+ assert(strcmp(*(End - 1), "-c") == 0);
--End;
Result = std::vector<std::string>(Args.begin() + 1, End);
@@ -283,13 +290,13 @@ FixedCompilationDatabase::loadFromCommandLine(int &Argc,
Twine Directory) {
const char **DoubleDash = std::find(Argv, Argv + Argc, StringRef("--"));
if (DoubleDash == Argv + Argc)
- return NULL;
+ return nullptr;
std::vector<const char *> CommandLine(DoubleDash + 1, Argv + Argc);
Argc = DoubleDash - Argv;
std::vector<std::string> StrippedArgs;
if (!stripPositionalArgs(CommandLine, StrippedArgs))
- return 0;
+ return nullptr;
return new FixedCompilationDatabase(Directory, StrippedArgs);
}
@@ -298,7 +305,8 @@ FixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine) {
std::vector<std::string> ToolCommandLine(1, "clang-tool");
ToolCommandLine.insert(ToolCommandLine.end(),
CommandLine.begin(), CommandLine.end());
- CompileCommands.push_back(CompileCommand(Directory, ToolCommandLine));
+ CompileCommands.push_back(
+ CompileCommand(Directory, std::move(ToolCommandLine)));
}
std::vector<CompileCommand>
diff --git a/lib/Tooling/FileMatchTrie.cpp b/lib/Tooling/FileMatchTrie.cpp
index 89979a84f940..dc9999ef965a 100644
--- a/lib/Tooling/FileMatchTrie.cpp
+++ b/lib/Tooling/FileMatchTrie.cpp
@@ -24,7 +24,7 @@ namespace tooling {
/// \brief Default \c PathComparator using \c llvm::sys::fs::equivalent().
struct DefaultPathComparator : public PathComparator {
virtual ~DefaultPathComparator() {}
- virtual bool equivalent(StringRef FileA, StringRef FileB) const {
+ bool equivalent(StringRef FileA, StringRef FileB) const override {
return FileA == FileB || llvm::sys::fs::equivalent(FileA, FileB);
}
};
diff --git a/lib/Tooling/JSONCompilationDatabase.cpp b/lib/Tooling/JSONCompilationDatabase.cpp
index 1e33b418af4e..8b8bd293851f 100644
--- a/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/lib/Tooling/JSONCompilationDatabase.cpp
@@ -17,7 +17,7 @@
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/system_error.h"
+#include <system_error>
namespace clang {
namespace tooling {
@@ -118,15 +118,15 @@ std::vector<std::string> unescapeCommandLine(
}
class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
- virtual CompilationDatabase *loadFromDirectory(
- StringRef Directory, std::string &ErrorMessage) {
+ CompilationDatabase *loadFromDirectory(StringRef Directory,
+ std::string &ErrorMessage) override {
SmallString<1024> JSONDatabasePath(Directory);
llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
- OwningPtr<CompilationDatabase> Database(
+ std::unique_ptr<CompilationDatabase> Database(
JSONCompilationDatabase::loadFromFile(JSONDatabasePath, ErrorMessage));
if (!Database)
- return NULL;
- return Database.take();
+ return nullptr;
+ return Database.release();
}
};
@@ -144,37 +144,36 @@ volatile int JSONAnchorSource = 0;
JSONCompilationDatabase *
JSONCompilationDatabase::loadFromFile(StringRef FilePath,
std::string &ErrorMessage) {
- OwningPtr<llvm::MemoryBuffer> DatabaseBuffer;
- llvm::error_code Result =
- llvm::MemoryBuffer::getFile(FilePath, DatabaseBuffer);
- if (Result != 0) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> DatabaseBuffer =
+ llvm::MemoryBuffer::getFile(FilePath);
+ if (std::error_code Result = DatabaseBuffer.getError()) {
ErrorMessage = "Error while opening JSON database: " + Result.message();
- return NULL;
+ return nullptr;
}
- OwningPtr<JSONCompilationDatabase> Database(
- new JSONCompilationDatabase(DatabaseBuffer.take()));
+ std::unique_ptr<JSONCompilationDatabase> Database(
+ new JSONCompilationDatabase(DatabaseBuffer->release()));
if (!Database->parse(ErrorMessage))
- return NULL;
- return Database.take();
+ return nullptr;
+ return Database.release();
}
JSONCompilationDatabase *
JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
std::string &ErrorMessage) {
- OwningPtr<llvm::MemoryBuffer> DatabaseBuffer(
+ std::unique_ptr<llvm::MemoryBuffer> DatabaseBuffer(
llvm::MemoryBuffer::getMemBuffer(DatabaseString));
- OwningPtr<JSONCompilationDatabase> Database(
- new JSONCompilationDatabase(DatabaseBuffer.take()));
+ std::unique_ptr<JSONCompilationDatabase> Database(
+ new JSONCompilationDatabase(DatabaseBuffer.release()));
if (!Database->parse(ErrorMessage))
- return NULL;
- return Database.take();
+ return nullptr;
+ return Database.release();
}
std::vector<CompileCommand>
JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
SmallString<128> NativeFilePath;
llvm::sys::path::native(FilePath, NativeFilePath);
- std::vector<StringRef> PossibleMatches;
+
std::string Error;
llvm::raw_string_ostream ES(Error);
StringRef Match = MatchTrie.findEquivalent(NativeFilePath.str(), ES);
@@ -235,12 +234,12 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
return false;
}
llvm::yaml::Node *Root = I->getRoot();
- if (Root == NULL) {
+ if (!Root) {
ErrorMessage = "Error while parsing YAML.";
return false;
}
llvm::yaml::SequenceNode *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
- if (Array == NULL) {
+ if (!Array) {
ErrorMessage = "Expected array.";
return false;
}
@@ -248,30 +247,30 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
AE = Array->end();
AI != AE; ++AI) {
llvm::yaml::MappingNode *Object = dyn_cast<llvm::yaml::MappingNode>(&*AI);
- if (Object == NULL) {
+ if (!Object) {
ErrorMessage = "Expected object.";
return false;
}
- llvm::yaml::ScalarNode *Directory = NULL;
- llvm::yaml::ScalarNode *Command = NULL;
- llvm::yaml::ScalarNode *File = NULL;
+ llvm::yaml::ScalarNode *Directory = nullptr;
+ llvm::yaml::ScalarNode *Command = nullptr;
+ llvm::yaml::ScalarNode *File = nullptr;
for (llvm::yaml::MappingNode::iterator KVI = Object->begin(),
KVE = Object->end();
KVI != KVE; ++KVI) {
llvm::yaml::Node *Value = (*KVI).getValue();
- if (Value == NULL) {
+ if (!Value) {
ErrorMessage = "Expected value.";
return false;
}
llvm::yaml::ScalarNode *ValueString =
dyn_cast<llvm::yaml::ScalarNode>(Value);
- if (ValueString == NULL) {
+ if (!ValueString) {
ErrorMessage = "Expected string as value.";
return false;
}
llvm::yaml::ScalarNode *KeyString =
dyn_cast<llvm::yaml::ScalarNode>((*KVI).getKey());
- if (KeyString == NULL) {
+ if (!KeyString) {
ErrorMessage = "Expected strings as key.";
return false;
}
diff --git a/lib/Tooling/Refactoring.cpp b/lib/Tooling/Refactoring.cpp
index e165c12e0009..c96b8c92a905 100644
--- a/lib/Tooling/Refactoring.cpp
+++ b/lib/Tooling/Refactoring.cpp
@@ -18,9 +18,9 @@
#include "clang/Lex/Lexer.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/Refactoring.h"
-#include "llvm/Support/raw_os_ostream.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_os_ostream.h"
namespace clang {
namespace tooling {
@@ -35,12 +35,13 @@ Replacement::Replacement(StringRef FilePath, unsigned Offset, unsigned Length,
: FilePath(FilePath), ReplacementRange(Offset, Length),
ReplacementText(ReplacementText) {}
-Replacement::Replacement(SourceManager &Sources, SourceLocation Start,
+Replacement::Replacement(const SourceManager &Sources, SourceLocation Start,
unsigned Length, StringRef ReplacementText) {
setFromSourceLocation(Sources, Start, Length, ReplacementText);
}
-Replacement::Replacement(SourceManager &Sources, const CharSourceRange &Range,
+Replacement::Replacement(const SourceManager &Sources,
+ const CharSourceRange &Range,
StringRef ReplacementText) {
setFromSourceRange(Sources, Range, ReplacementText);
}
@@ -52,7 +53,7 @@ bool Replacement::isApplicable() const {
bool Replacement::apply(Rewriter &Rewrite) const {
SourceManager &SM = Rewrite.getSourceMgr();
const FileEntry *Entry = SM.getFileManager().getFile(FilePath);
- if (Entry == NULL)
+ if (!Entry)
return false;
FileID ID;
// FIXME: Use SM.translateFile directly.
@@ -99,17 +100,17 @@ bool operator==(const Replacement &LHS, const Replacement &RHS) {
LHS.getReplacementText() == RHS.getReplacementText();
}
-void Replacement::setFromSourceLocation(SourceManager &Sources,
+void Replacement::setFromSourceLocation(const SourceManager &Sources,
SourceLocation Start, unsigned Length,
StringRef ReplacementText) {
const std::pair<FileID, unsigned> DecomposedLocation =
Sources.getDecomposedLoc(Start);
const FileEntry *Entry = Sources.getFileEntryForID(DecomposedLocation.first);
- if (Entry != NULL) {
+ if (Entry) {
// Make FilePath absolute so replacements can be applied correctly when
// relative paths for files are used.
llvm::SmallString<256> FilePath(Entry->getName());
- llvm::error_code EC = llvm::sys::fs::make_absolute(FilePath);
+ std::error_code EC = llvm::sys::fs::make_absolute(FilePath);
this->FilePath = EC ? FilePath.c_str() : Entry->getName();
} else {
this->FilePath = InvalidLocation;
@@ -121,7 +122,8 @@ void Replacement::setFromSourceLocation(SourceManager &Sources,
// FIXME: This should go into the Lexer, but we need to figure out how
// to handle ranges for refactoring in general first - there is no obvious
// good way how to integrate this into the Lexer yet.
-static int getRangeSize(SourceManager &Sources, const CharSourceRange &Range) {
+static int getRangeSize(const SourceManager &Sources,
+ const CharSourceRange &Range) {
SourceLocation SpellingBegin = Sources.getSpellingLoc(Range.getBegin());
SourceLocation SpellingEnd = Sources.getSpellingLoc(Range.getEnd());
std::pair<FileID, unsigned> Start = Sources.getDecomposedLoc(SpellingBegin);
@@ -133,7 +135,7 @@ static int getRangeSize(SourceManager &Sources, const CharSourceRange &Range) {
return End.second - Start.second;
}
-void Replacement::setFromSourceRange(SourceManager &Sources,
+void Replacement::setFromSourceRange(const SourceManager &Sources,
const CharSourceRange &Range,
StringRef ReplacementText) {
setFromSourceLocation(Sources, Sources.getSpellingLoc(Range.getBegin()),
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
index a58854d1af30..0db38db3c91e 100644
--- a/lib/Tooling/Tooling.cpp
+++ b/lib/Tooling/Tooling.cpp
@@ -24,6 +24,7 @@
#include "clang/Tooling/ArgumentsAdjusters.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
@@ -31,12 +32,14 @@
#include "llvm/Support/raw_ostream.h"
// For chdir, see the comment in ClangTool::run for more information.
-#ifdef _WIN32
+#ifdef LLVM_ON_WIN32
# include <direct.h>
#else
# include <unistd.h>
#endif
+#define DEBUG_TYPE "clang-tooling"
+
namespace clang {
namespace tooling {
@@ -51,10 +54,8 @@ FrontendActionFactory::~FrontendActionFactory() {}
/// \brief Builds a clang driver initialized for running clang tools.
static clang::driver::Driver *newDriver(clang::DiagnosticsEngine *Diagnostics,
const char *BinaryName) {
- const std::string DefaultOutputName = "a.out";
clang::driver::Driver *CompilerDriver = new clang::driver::Driver(
- BinaryName, llvm::sys::getDefaultTargetTriple(),
- DefaultOutputName, *Diagnostics);
+ BinaryName, llvm::sys::getDefaultTargetTriple(), *Diagnostics);
CompilerDriver->setTitle("clang_based_tool");
return CompilerDriver;
}
@@ -74,7 +75,7 @@ static const llvm::opt::ArgStringList *getCC1Arguments(
Jobs.Print(error_stream, "; ", true);
Diagnostics->Report(clang::diag::err_fe_expected_compiler_job)
<< error_stream.str();
- return NULL;
+ return nullptr;
}
// The one job we find should be to invoke clang again.
@@ -82,7 +83,7 @@ static const llvm::opt::ArgStringList *getCC1Arguments(
cast<clang::driver::Command>(*Jobs.begin());
if (StringRef(Cmd->getCreator().getName()) != "clang") {
Diagnostics->Report(clang::diag::err_fe_expected_clang_command);
- return NULL;
+ return nullptr;
}
return &Cmd->getArguments();
@@ -99,6 +100,7 @@ static clang::CompilerInvocation *newInvocation(
*Diagnostics);
Invocation->getFrontendOpts().DisableFree = false;
Invocation->getCodeGenOpts().DisableFree = false;
+ Invocation->getDependencyOutputOpts() = DependencyOutputOptions();
return Invocation;
}
@@ -127,7 +129,7 @@ bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
llvm::IntrusiveRefCntPtr<FileManager> Files(
new FileManager(FileSystemOptions()));
ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), ToolAction,
- Files.getPtr());
+ Files.get());
SmallString<1024> CodeStorage;
Invocation.mapVirtualFile(FileNameRef,
@@ -143,7 +145,7 @@ std::string getAbsolutePath(StringRef File) {
}
SmallString<1024> AbsolutePath = RelativePath;
- llvm::error_code EC = llvm::sys::fs::make_absolute(AbsolutePath);
+ std::error_code EC = llvm::sys::fs::make_absolute(AbsolutePath);
assert(!EC);
(void)EC;
llvm::sys::path::native(AbsolutePath);
@@ -158,26 +160,26 @@ class SingleFrontendActionFactory : public FrontendActionFactory {
public:
SingleFrontendActionFactory(FrontendAction *Action) : Action(Action) {}
- FrontendAction *create() { return Action; }
+ FrontendAction *create() override { return Action; }
};
}
-ToolInvocation::ToolInvocation(ArrayRef<std::string> CommandLine,
+ToolInvocation::ToolInvocation(std::vector<std::string> CommandLine,
ToolAction *Action, FileManager *Files)
- : CommandLine(CommandLine.vec()),
+ : CommandLine(std::move(CommandLine)),
Action(Action),
OwnsAction(false),
Files(Files),
- DiagConsumer(NULL) {}
+ DiagConsumer(nullptr) {}
-ToolInvocation::ToolInvocation(ArrayRef<std::string> CommandLine,
+ToolInvocation::ToolInvocation(std::vector<std::string> CommandLine,
FrontendAction *FAction, FileManager *Files)
- : CommandLine(CommandLine.vec()),
+ : CommandLine(std::move(CommandLine)),
Action(new SingleFrontendActionFactory(FAction)),
OwnsAction(true),
Files(Files),
- DiagConsumer(NULL) {}
+ DiagConsumer(nullptr) {}
ToolInvocation::~ToolInvocation() {
if (OwnsAction)
@@ -196,8 +198,8 @@ void ToolInvocation::mapVirtualFile(StringRef FilePath, StringRef Content) {
bool ToolInvocation::run() {
std::vector<const char*> Argv;
- for (int I = 0, E = CommandLine.size(); I != E; ++I)
- Argv.push_back(CommandLine[I].c_str());
+ for (const std::string &Str : CommandLine)
+ Argv.push_back(Str.c_str());
const char *const BinaryName = Argv[0];
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticPrinter DiagnosticPrinter(
@@ -206,28 +208,25 @@ bool ToolInvocation::run() {
IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false);
- const OwningPtr<clang::driver::Driver> Driver(
+ const std::unique_ptr<clang::driver::Driver> Driver(
newDriver(&Diagnostics, BinaryName));
// Since the input might only be virtual, don't check whether it exists.
Driver->setCheckInputsExist(false);
- const OwningPtr<clang::driver::Compilation> Compilation(
+ const std::unique_ptr<clang::driver::Compilation> Compilation(
Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
const llvm::opt::ArgStringList *const CC1Args = getCC1Arguments(
&Diagnostics, Compilation.get());
- if (CC1Args == NULL) {
+ if (!CC1Args) {
return false;
}
- OwningPtr<clang::CompilerInvocation> Invocation(
+ std::unique_ptr<clang::CompilerInvocation> Invocation(
newInvocation(&Diagnostics, *CC1Args));
- for (llvm::StringMap<StringRef>::const_iterator
- It = MappedFileContents.begin(), End = MappedFileContents.end();
- It != End; ++It) {
+ for (const auto &It : MappedFileContents) {
// Inject the code as the given file name into the preprocessor options.
- const llvm::MemoryBuffer *Input =
- llvm::MemoryBuffer::getMemBuffer(It->getValue());
- Invocation->getPreprocessorOpts().addRemappedFile(It->getKey(), Input);
+ auto *Input = llvm::MemoryBuffer::getMemBuffer(It.getValue());
+ Invocation->getPreprocessorOpts().addRemappedFile(It.getKey(), Input);
}
- return runInvocation(BinaryName, Compilation.get(), Invocation.take());
+ return runInvocation(BinaryName, Compilation.get(), Invocation.release());
}
bool ToolInvocation::runInvocation(
@@ -254,10 +253,10 @@ bool FrontendActionFactory::runInvocation(CompilerInvocation *Invocation,
// The FrontendAction can have lifetime requirements for Compiler or its
// members, and we need to ensure it's deleted earlier than Compiler. So we
- // pass it to an OwningPtr declared after the Compiler variable.
- OwningPtr<FrontendAction> ScopedToolAction(create());
+ // pass it to an std::unique_ptr declared after the Compiler variable.
+ std::unique_ptr<FrontendAction> ScopedToolAction(create());
- // Create the compilers actual diagnostics engine.
+ // Create the compiler's actual diagnostics engine.
Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false);
if (!Compiler.hasDiagnostics())
return false;
@@ -272,18 +271,18 @@ bool FrontendActionFactory::runInvocation(CompilerInvocation *Invocation,
ClangTool::ClangTool(const CompilationDatabase &Compilations,
ArrayRef<std::string> SourcePaths)
- : Files(new FileManager(FileSystemOptions())), DiagConsumer(NULL) {
+ : Files(new FileManager(FileSystemOptions())), DiagConsumer(nullptr) {
ArgsAdjusters.push_back(new ClangStripOutputAdjuster());
ArgsAdjusters.push_back(new ClangSyntaxOnlyAdjuster());
- for (unsigned I = 0, E = SourcePaths.size(); I != E; ++I) {
- SmallString<1024> File(getAbsolutePath(SourcePaths[I]));
+ for (const auto &SourcePath : SourcePaths) {
+ std::string File(getAbsolutePath(SourcePath));
std::vector<CompileCommand> CompileCommandsForFile =
- Compilations.getCompileCommands(File.str());
+ Compilations.getCompileCommands(File);
if (!CompileCommandsForFile.empty()) {
- for (int I = 0, E = CompileCommandsForFile.size(); I != E; ++I) {
- CompileCommands.push_back(std::make_pair(File.str(),
- CompileCommandsForFile[I]));
+ for (CompileCommand &CompileCommand : CompileCommandsForFile) {
+ CompileCommands.push_back(
+ std::make_pair(File, std::move(CompileCommand)));
}
} else {
// FIXME: There are two use cases here: doing a fuzzy
@@ -291,7 +290,7 @@ ClangTool::ClangTool(const CompilationDatabase &Compilations,
// about the .cc files that were not found, and the use case where I
// specify all files I want to run over explicitly, where this should
// be an error. We'll want to add an option for this.
- llvm::outs() << "Skipping " << File << ". Command line not found.\n";
+ llvm::errs() << "Skipping " << File << ". Compile command not found.\n";
}
}
}
@@ -332,8 +331,7 @@ int ClangTool::run(ToolAction *Action) {
llvm::sys::fs::getMainExecutable("clang_tool", &StaticSymbol);
bool ProcessingFailed = false;
- for (unsigned I = 0; I < CompileCommands.size(); ++I) {
- std::string File = CompileCommands[I].first;
+ for (const auto &Command : CompileCommands) {
// FIXME: chdir is thread hostile; on the other hand, creating the same
// behavior as chdir is complex: chdir resolves the path once, thus
// guaranteeing that all subsequent relative path operations work
@@ -341,28 +339,27 @@ int ClangTool::run(ToolAction *Action) {
// for example on network filesystems, where symlinks might be switched
// during runtime of the tool. Fixing this depends on having a file system
// abstraction that allows openat() style interactions.
- if (chdir(CompileCommands[I].second.Directory.c_str()))
+ if (chdir(Command.second.Directory.c_str()))
llvm::report_fatal_error("Cannot chdir into \"" +
- CompileCommands[I].second.Directory + "\n!");
- std::vector<std::string> CommandLine = CompileCommands[I].second.CommandLine;
- for (unsigned I = 0, E = ArgsAdjusters.size(); I != E; ++I)
- CommandLine = ArgsAdjusters[I]->Adjust(CommandLine);
+ Twine(Command.second.Directory) + "\n!");
+ std::vector<std::string> CommandLine = Command.second.CommandLine;
+ for (ArgumentsAdjuster *Adjuster : ArgsAdjusters)
+ CommandLine = Adjuster->Adjust(CommandLine);
assert(!CommandLine.empty());
CommandLine[0] = MainExecutable;
// FIXME: We need a callback mechanism for the tool writer to output a
// customized message for each file.
DEBUG({
- llvm::dbgs() << "Processing: " << File << ".\n";
+ llvm::dbgs() << "Processing: " << Command.first << ".\n";
});
- ToolInvocation Invocation(CommandLine, Action, Files.getPtr());
+ ToolInvocation Invocation(std::move(CommandLine), Action, Files.get());
Invocation.setDiagnosticConsumer(DiagConsumer);
- for (int I = 0, E = MappedFileContents.size(); I != E; ++I) {
- Invocation.mapVirtualFile(MappedFileContents[I].first,
- MappedFileContents[I].second);
+ for (const auto &MappedFile : MappedFileContents) {
+ Invocation.mapVirtualFile(MappedFile.first, MappedFile.second);
}
if (!Invocation.run()) {
// FIXME: Diagnostics should be used instead.
- llvm::errs() << "Error while processing " << File << ".\n";
+ llvm::errs() << "Error while processing " << Command.first << ".\n";
ProcessingFailed = true;
}
}
@@ -372,55 +369,58 @@ int ClangTool::run(ToolAction *Action) {
namespace {
class ASTBuilderAction : public ToolAction {
- std::vector<ASTUnit *> &ASTs;
+ std::vector<std::unique_ptr<ASTUnit>> &ASTs;
public:
- ASTBuilderAction(std::vector<ASTUnit *> &ASTs) : ASTs(ASTs) {}
+ ASTBuilderAction(std::vector<std::unique_ptr<ASTUnit>> &ASTs) : ASTs(ASTs) {}
bool runInvocation(CompilerInvocation *Invocation, FileManager *Files,
- DiagnosticConsumer *DiagConsumer) {
+ DiagnosticConsumer *DiagConsumer) override {
// FIXME: This should use the provided FileManager.
- ASTUnit *AST = ASTUnit::LoadFromCompilerInvocation(
+ std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
Invocation, CompilerInstance::createDiagnostics(
&Invocation->getDiagnosticOpts(), DiagConsumer,
/*ShouldOwnClient=*/false));
if (!AST)
return false;
- ASTs.push_back(AST);
+ ASTs.push_back(std::move(AST));
return true;
}
};
}
-int ClangTool::buildASTs(std::vector<ASTUnit *> &ASTs) {
+int ClangTool::buildASTs(std::vector<std::unique_ptr<ASTUnit>> &ASTs) {
ASTBuilderAction Action(ASTs);
return run(&Action);
}
-ASTUnit *buildASTFromCode(const Twine &Code, const Twine &FileName) {
+std::unique_ptr<ASTUnit> buildASTFromCode(const Twine &Code,
+ const Twine &FileName) {
return buildASTFromCodeWithArgs(Code, std::vector<std::string>(), FileName);
}
-ASTUnit *buildASTFromCodeWithArgs(const Twine &Code,
- const std::vector<std::string> &Args,
- const Twine &FileName) {
+std::unique_ptr<ASTUnit>
+buildASTFromCodeWithArgs(const Twine &Code,
+ const std::vector<std::string> &Args,
+ const Twine &FileName) {
SmallString<16> FileNameStorage;
StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
- std::vector<ASTUnit *> ASTs;
+ std::vector<std::unique_ptr<ASTUnit>> ASTs;
ASTBuilderAction Action(ASTs);
- ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), &Action, 0);
+ ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), &Action,
+ nullptr);
SmallString<1024> CodeStorage;
Invocation.mapVirtualFile(FileNameRef,
Code.toNullTerminatedStringRef(CodeStorage));
if (!Invocation.run())
- return 0;
+ return nullptr;
assert(ASTs.size() == 1);
- return ASTs[0];
+ return std::move(ASTs[0]);
}
} // end namespace tooling